files.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * DHCP server config and lease file manipulation
  4. *
  5. * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
  6. *
  7. * Licensed under GPLv2, see file LICENSE in this source tree.
  8. */
  9. #include <netinet/ether.h>
  10. #include "common.h"
  11. #include "dhcpd.h"
  12. /* on these functions, make sure your datatype matches */
  13. static int FAST_FUNC read_str(const char *line, void *arg)
  14. {
  15. char **dest = arg;
  16. free(*dest);
  17. *dest = xstrdup(line);
  18. return 1;
  19. }
  20. static int FAST_FUNC read_u32(const char *line, void *arg)
  21. {
  22. *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
  23. return errno == 0;
  24. }
  25. static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
  26. {
  27. char *line;
  28. char *mac_string;
  29. char *ip_string;
  30. struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */
  31. uint32_t nip;
  32. /* Read mac */
  33. line = (char *) const_line;
  34. mac_string = strtok_r(line, " \t", &line);
  35. if (!mac_string || !ether_aton_r(mac_string, &mac_bytes))
  36. return 0;
  37. /* Read ip */
  38. ip_string = strtok_r(NULL, " \t", &line);
  39. if (!ip_string || !udhcp_str2nip(ip_string, &nip))
  40. return 0;
  41. add_static_lease(arg, (uint8_t*) &mac_bytes, nip);
  42. log_static_leases(arg);
  43. return 1;
  44. }
  45. struct config_keyword {
  46. const char *keyword;
  47. int (*handler)(const char *line, void *var) FAST_FUNC;
  48. void *var;
  49. const char *def;
  50. };
  51. static const struct config_keyword keywords[] = {
  52. /* keyword handler variable address default */
  53. {"start" , udhcp_str2nip , &server_config.start_ip , "192.168.0.20"},
  54. {"end" , udhcp_str2nip , &server_config.end_ip , "192.168.0.254"},
  55. {"interface" , read_str , &server_config.interface , "eth0"},
  56. /* Avoid "max_leases value not sane" warning by setting default
  57. * to default_end_ip - default_start_ip + 1: */
  58. {"max_leases" , read_u32 , &server_config.max_leases , "235"},
  59. {"auto_time" , read_u32 , &server_config.auto_time , "7200"},
  60. {"decline_time" , read_u32 , &server_config.decline_time , "3600"},
  61. {"conflict_time", read_u32 , &server_config.conflict_time, "3600"},
  62. {"offer_time" , read_u32 , &server_config.offer_time , "60"},
  63. {"min_lease" , read_u32 , &server_config.min_lease_sec, "60"},
  64. {"lease_file" , read_str , &server_config.lease_file , LEASES_FILE},
  65. {"pidfile" , read_str , &server_config.pidfile , "/var/run/udhcpd.pid"},
  66. {"siaddr" , udhcp_str2nip , &server_config.siaddr_nip , "0.0.0.0"},
  67. /* keywords with no defaults must be last! */
  68. {"option" , udhcp_str2optset, &server_config.options , ""},
  69. {"opt" , udhcp_str2optset, &server_config.options , ""},
  70. {"notify_file" , read_str , &server_config.notify_file , NULL},
  71. {"sname" , read_str , &server_config.sname , NULL},
  72. {"boot_file" , read_str , &server_config.boot_file , NULL},
  73. {"static_lease" , read_staticlease, &server_config.static_leases, ""},
  74. };
  75. enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
  76. void FAST_FUNC read_config(const char *file)
  77. {
  78. parser_t *parser;
  79. const struct config_keyword *k;
  80. unsigned i;
  81. char *token[2];
  82. for (i = 0; i < KWS_WITH_DEFAULTS; i++)
  83. keywords[i].handler(keywords[i].def, keywords[i].var);
  84. parser = config_open(file);
  85. while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
  86. for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
  87. if (strcasecmp(token[0], k->keyword) == 0) {
  88. if (!k->handler(token[1], k->var)) {
  89. bb_error_msg("can't parse line %u in %s",
  90. parser->lineno, file);
  91. /* reset back to the default value */
  92. k->handler(k->def, k->var);
  93. }
  94. break;
  95. }
  96. }
  97. }
  98. config_close(parser);
  99. server_config.start_ip = ntohl(server_config.start_ip);
  100. server_config.end_ip = ntohl(server_config.end_ip);
  101. }
  102. void FAST_FUNC write_leases(void)
  103. {
  104. int fd;
  105. unsigned i;
  106. leasetime_t curr;
  107. int64_t written_at;
  108. fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
  109. if (fd < 0)
  110. return;
  111. curr = written_at = time(NULL);
  112. written_at = SWAP_BE64(written_at);
  113. full_write(fd, &written_at, sizeof(written_at));
  114. for (i = 0; i < server_config.max_leases; i++) {
  115. leasetime_t tmp_time;
  116. if (g_leases[i].lease_nip == 0)
  117. continue;
  118. /* Screw with the time in the struct, for easier writing */
  119. tmp_time = g_leases[i].expires;
  120. g_leases[i].expires -= curr;
  121. if ((signed_leasetime_t) g_leases[i].expires < 0)
  122. g_leases[i].expires = 0;
  123. g_leases[i].expires = htonl(g_leases[i].expires);
  124. /* No error check. If the file gets truncated,
  125. * we lose some leases on restart. Oh well. */
  126. full_write(fd, &g_leases[i], sizeof(g_leases[i]));
  127. /* Then restore it when done */
  128. g_leases[i].expires = tmp_time;
  129. }
  130. close(fd);
  131. if (server_config.notify_file) {
  132. char *argv[3];
  133. argv[0] = server_config.notify_file;
  134. argv[1] = server_config.lease_file;
  135. argv[2] = NULL;
  136. spawn_and_wait(argv);
  137. }
  138. }
  139. void FAST_FUNC read_leases(const char *file)
  140. {
  141. struct dyn_lease lease;
  142. int64_t written_at, time_passed;
  143. int fd;
  144. #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
  145. unsigned i = 0;
  146. #endif
  147. fd = open_or_warn(file, O_RDONLY);
  148. if (fd < 0)
  149. return;
  150. if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
  151. goto ret;
  152. written_at = SWAP_BE64(written_at);
  153. time_passed = time(NULL) - written_at;
  154. /* Strange written_at, or lease file from old version of udhcpd
  155. * which had no "written_at" field? */
  156. if ((uint64_t)time_passed > 12 * 60 * 60)
  157. goto ret;
  158. while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
  159. //FIXME: what if it matches some static lease?
  160. uint32_t y = ntohl(lease.lease_nip);
  161. if (y >= server_config.start_ip && y <= server_config.end_ip) {
  162. signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
  163. if (expires <= 0)
  164. continue;
  165. /* NB: add_lease takes "relative time", IOW,
  166. * lease duration, not lease deadline. */
  167. if (add_lease(lease.lease_mac, lease.lease_nip,
  168. expires,
  169. lease.hostname, sizeof(lease.hostname)
  170. ) == 0
  171. ) {
  172. bb_error_msg("too many leases while loading %s", file);
  173. break;
  174. }
  175. #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
  176. i++;
  177. #endif
  178. }
  179. }
  180. log1("Read %d leases", i);
  181. ret:
  182. close(fd);
  183. }