dhcpd.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /* vi: set sw=4 ts=4: */
  2. /* dhcpd.c
  3. *
  4. * udhcp Server
  5. * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
  6. * Chris Trew <ctrew@moreton.com.au>
  7. *
  8. * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
  9. *
  10. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  11. */
  12. #include "common.h"
  13. #include "dhcpd.h"
  14. #include "options.h"
  15. /* globals */
  16. struct dhcpOfferedAddr *leases;
  17. struct server_config_t server_config;
  18. int udhcpd_main(int argc, char *argv[])
  19. {
  20. fd_set rfds;
  21. struct timeval tv;
  22. int server_socket = -1, bytes, retval, max_sock;
  23. struct dhcpMessage packet;
  24. uint8_t *state, *server_id, *requested;
  25. uint32_t server_id_align, requested_align, static_lease_ip;
  26. unsigned long timeout_end, num_ips;
  27. struct option_set *option;
  28. struct dhcpOfferedAddr *lease, static_lease;
  29. read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]);
  30. /* Start the log, sanitize fd's, and write a pid file */
  31. udhcp_start_log_and_pid(server_config.pidfile);
  32. if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
  33. memcpy(&server_config.lease, option->data + 2, 4);
  34. server_config.lease = ntohl(server_config.lease);
  35. }
  36. else server_config.lease = LEASE_TIME;
  37. /* Sanity check */
  38. num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1;
  39. if (server_config.max_leases > num_ips) {
  40. bb_error_msg("max_leases value (%lu) not sane, "
  41. "setting to %lu instead",
  42. server_config.max_leases, num_ips);
  43. server_config.max_leases = num_ips;
  44. }
  45. leases = xzalloc(server_config.max_leases * sizeof(struct dhcpOfferedAddr));
  46. read_leases(server_config.lease_file);
  47. if (read_interface(server_config.interface, &server_config.ifindex,
  48. &server_config.server, server_config.arp) < 0)
  49. return 1;
  50. if (!ENABLE_FEATURE_UDHCP_DEBUG)
  51. udhcp_background(server_config.pidfile); /* hold lock during fork. */
  52. /* Setup the signal pipe */
  53. udhcp_sp_setup();
  54. timeout_end = time(0) + server_config.auto_time;
  55. while (1) { /* loop until universe collapses */
  56. if (server_socket < 0) {
  57. server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface);
  58. }
  59. max_sock = udhcp_sp_fd_set(&rfds, server_socket);
  60. if (server_config.auto_time) {
  61. tv.tv_sec = timeout_end - time(0);
  62. tv.tv_usec = 0;
  63. }
  64. if (!server_config.auto_time || tv.tv_sec > 0) {
  65. retval = select(max_sock + 1, &rfds, NULL, NULL,
  66. server_config.auto_time ? &tv : NULL);
  67. } else retval = 0; /* If we already timed out, fall through */
  68. if (retval == 0) {
  69. write_leases();
  70. timeout_end = time(0) + server_config.auto_time;
  71. continue;
  72. } else if (retval < 0 && errno != EINTR) {
  73. DEBUG("error on select");
  74. continue;
  75. }
  76. switch (udhcp_sp_read(&rfds)) {
  77. case SIGUSR1:
  78. bb_info_msg("Received a SIGUSR1");
  79. write_leases();
  80. /* why not just reset the timeout, eh */
  81. timeout_end = time(0) + server_config.auto_time;
  82. continue;
  83. case SIGTERM:
  84. bb_info_msg("Received a SIGTERM");
  85. return 0;
  86. case 0: break; /* no signal */
  87. default: continue; /* signal or error (probably EINTR) */
  88. }
  89. if ((bytes = udhcp_get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
  90. if (bytes == -1 && errno != EINTR) {
  91. DEBUG("error on read, %s, reopening socket", strerror(errno));
  92. close(server_socket);
  93. server_socket = -1;
  94. }
  95. continue;
  96. }
  97. if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
  98. bb_error_msg("cannot get option from packet, ignoring");
  99. continue;
  100. }
  101. /* Look for a static lease */
  102. static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);
  103. if (static_lease_ip) {
  104. bb_info_msg("Found static lease: %x", static_lease_ip);
  105. memcpy(&static_lease.chaddr, &packet.chaddr, 16);
  106. static_lease.yiaddr = static_lease_ip;
  107. static_lease.expires = 0;
  108. lease = &static_lease;
  109. } else {
  110. lease = find_lease_by_chaddr(packet.chaddr);
  111. }
  112. switch (state[0]) {
  113. case DHCPDISCOVER:
  114. DEBUG("Received DISCOVER");
  115. if (sendOffer(&packet) < 0) {
  116. bb_error_msg("send OFFER failed");
  117. }
  118. break;
  119. case DHCPREQUEST:
  120. DEBUG("received REQUEST");
  121. requested = get_option(&packet, DHCP_REQUESTED_IP);
  122. server_id = get_option(&packet, DHCP_SERVER_ID);
  123. if (requested) memcpy(&requested_align, requested, 4);
  124. if (server_id) memcpy(&server_id_align, server_id, 4);
  125. if (lease) {
  126. if (server_id) {
  127. /* SELECTING State */
  128. DEBUG("server_id = %08x", ntohl(server_id_align));
  129. if (server_id_align == server_config.server && requested &&
  130. requested_align == lease->yiaddr) {
  131. sendACK(&packet, lease->yiaddr);
  132. }
  133. } else {
  134. if (requested) {
  135. /* INIT-REBOOT State */
  136. if (lease->yiaddr == requested_align)
  137. sendACK(&packet, lease->yiaddr);
  138. else sendNAK(&packet);
  139. } else {
  140. /* RENEWING or REBINDING State */
  141. if (lease->yiaddr == packet.ciaddr)
  142. sendACK(&packet, lease->yiaddr);
  143. else {
  144. /* don't know what to do!!!! */
  145. sendNAK(&packet);
  146. }
  147. }
  148. }
  149. /* what to do if we have no record of the client */
  150. } else if (server_id) {
  151. /* SELECTING State */
  152. } else if (requested) {
  153. /* INIT-REBOOT State */
  154. if ((lease = find_lease_by_yiaddr(requested_align))) {
  155. if (lease_expired(lease)) {
  156. /* probably best if we drop this lease */
  157. memset(lease->chaddr, 0, 16);
  158. /* make some contention for this address */
  159. } else sendNAK(&packet);
  160. } else if (requested_align < server_config.start ||
  161. requested_align > server_config.end) {
  162. sendNAK(&packet);
  163. } /* else remain silent */
  164. } else {
  165. /* RENEWING or REBINDING State */
  166. }
  167. break;
  168. case DHCPDECLINE:
  169. DEBUG("Received DECLINE");
  170. if (lease) {
  171. memset(lease->chaddr, 0, 16);
  172. lease->expires = time(0) + server_config.decline_time;
  173. }
  174. break;
  175. case DHCPRELEASE:
  176. DEBUG("Received RELEASE");
  177. if (lease) lease->expires = time(0);
  178. break;
  179. case DHCPINFORM:
  180. DEBUG("Received INFORM");
  181. send_inform(&packet);
  182. break;
  183. default:
  184. bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);
  185. }
  186. }
  187. return 0;
  188. }