files.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. unsigned ofs;
  49. const char *def;
  50. };
  51. #define OFS(field) offsetof(struct server_config_t, field)
  52. static const struct config_keyword keywords[] = {
  53. /* keyword handler variable address default */
  54. {"start" , udhcp_str2nip , OFS(start_ip ), "192.168.0.20"},
  55. {"end" , udhcp_str2nip , OFS(end_ip ), "192.168.0.254"},
  56. {"interface" , read_str , OFS(interface ), "eth0"},
  57. /* Avoid "max_leases value not sane" warning by setting default
  58. * to default_end_ip - default_start_ip + 1: */
  59. {"max_leases" , read_u32 , OFS(max_leases ), "235"},
  60. {"auto_time" , read_u32 , OFS(auto_time ), "7200"},
  61. {"decline_time" , read_u32 , OFS(decline_time ), "3600"},
  62. {"conflict_time", read_u32 , OFS(conflict_time), "3600"},
  63. {"offer_time" , read_u32 , OFS(offer_time ), "60"},
  64. {"min_lease" , read_u32 , OFS(min_lease_sec), "60"},
  65. {"lease_file" , read_str , OFS(lease_file ), LEASES_FILE},
  66. {"pidfile" , read_str , OFS(pidfile ), "/var/run/udhcpd.pid"},
  67. {"siaddr" , udhcp_str2nip , OFS(siaddr_nip ), "0.0.0.0"},
  68. /* keywords with no defaults must be last! */
  69. {"option" , udhcp_str2optset, OFS(options ), ""},
  70. {"opt" , udhcp_str2optset, OFS(options ), ""},
  71. {"notify_file" , read_str , OFS(notify_file ), NULL},
  72. {"sname" , read_str , OFS(sname ), NULL},
  73. {"boot_file" , read_str , OFS(boot_file ), NULL},
  74. {"static_lease" , read_staticlease, OFS(static_leases), ""},
  75. };
  76. enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
  77. void FAST_FUNC read_config(const char *file)
  78. {
  79. parser_t *parser;
  80. const struct config_keyword *k;
  81. unsigned i;
  82. char *token[2];
  83. for (i = 0; i < KWS_WITH_DEFAULTS; i++)
  84. keywords[i].handler(keywords[i].def, (char*)&server_config + keywords[i].ofs);
  85. parser = config_open(file);
  86. while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
  87. for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
  88. if (strcasecmp(token[0], k->keyword) == 0) {
  89. if (!k->handler(token[1], (char*)&server_config + k->ofs)) {
  90. bb_error_msg("can't parse line %u in %s",
  91. parser->lineno, file);
  92. /* reset back to the default value */
  93. k->handler(k->def, (char*)&server_config + k->ofs);
  94. }
  95. break;
  96. }
  97. }
  98. }
  99. config_close(parser);
  100. server_config.start_ip = ntohl(server_config.start_ip);
  101. server_config.end_ip = ntohl(server_config.end_ip);
  102. }
  103. void FAST_FUNC write_leases(void)
  104. {
  105. int fd;
  106. unsigned i;
  107. leasetime_t curr;
  108. int64_t written_at;
  109. fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
  110. if (fd < 0)
  111. return;
  112. curr = written_at = time(NULL);
  113. written_at = SWAP_BE64(written_at);
  114. full_write(fd, &written_at, sizeof(written_at));
  115. for (i = 0; i < server_config.max_leases; i++) {
  116. leasetime_t tmp_time;
  117. if (g_leases[i].lease_nip == 0)
  118. continue;
  119. /* Screw with the time in the struct, for easier writing */
  120. tmp_time = g_leases[i].expires;
  121. g_leases[i].expires -= curr;
  122. if ((signed_leasetime_t) g_leases[i].expires < 0)
  123. g_leases[i].expires = 0;
  124. g_leases[i].expires = htonl(g_leases[i].expires);
  125. /* No error check. If the file gets truncated,
  126. * we lose some leases on restart. Oh well. */
  127. full_write(fd, &g_leases[i], sizeof(g_leases[i]));
  128. /* Then restore it when done */
  129. g_leases[i].expires = tmp_time;
  130. }
  131. close(fd);
  132. if (server_config.notify_file) {
  133. char *argv[3];
  134. argv[0] = server_config.notify_file;
  135. argv[1] = server_config.lease_file;
  136. argv[2] = NULL;
  137. spawn_and_wait(argv);
  138. }
  139. }
  140. void FAST_FUNC read_leases(const char *file)
  141. {
  142. struct dyn_lease lease;
  143. int64_t written_at, time_passed;
  144. int fd;
  145. #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
  146. unsigned i = 0;
  147. #endif
  148. fd = open_or_warn(file, O_RDONLY);
  149. if (fd < 0)
  150. return;
  151. if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
  152. goto ret;
  153. written_at = SWAP_BE64(written_at);
  154. time_passed = time(NULL) - written_at;
  155. /* Strange written_at, or lease file from old version of udhcpd
  156. * which had no "written_at" field? */
  157. if ((uint64_t)time_passed > 12 * 60 * 60)
  158. goto ret;
  159. while (full_read(fd, &lease, sizeof(lease)) == sizeof(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. uint32_t static_nip;
  164. if (expires <= 0)
  165. /* We keep expired leases: add_lease() will add
  166. * a lease with 0 seconds remaining.
  167. * Fewer IP address changes this way for mass reboot scenario.
  168. */
  169. expires = 0;
  170. /* Check if there is a different static lease for this IP or MAC */
  171. static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac);
  172. if (static_nip) {
  173. /* NB: we do not add lease even if static_nip == lease.lease_nip.
  174. */
  175. continue;
  176. }
  177. if (is_nip_reserved(server_config.static_leases, lease.lease_nip))
  178. continue;
  179. /* NB: add_lease takes "relative time", IOW,
  180. * lease duration, not lease deadline. */
  181. if (add_lease(lease.lease_mac, lease.lease_nip,
  182. expires,
  183. lease.hostname, sizeof(lease.hostname)
  184. ) == 0
  185. ) {
  186. bb_error_msg("too many leases while loading %s", file);
  187. break;
  188. }
  189. #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
  190. i++;
  191. #endif
  192. }
  193. }
  194. log1("read %d leases", i);
  195. ret:
  196. close(fd);
  197. }