serverpacket.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /* serverpacket.c
  2. *
  3. * Construct and send DHCP server packets
  4. *
  5. * Russ Dill <Russ.Dill@asu.edu> July 2001
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <arpa/inet.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include "serverpacket.h"
  27. #include "dhcpd.h"
  28. #include "options.h"
  29. #include "common.h"
  30. #include "static_leases.h"
  31. /* send a packet to giaddr using the kernel ip stack */
  32. static int send_packet_to_relay(struct dhcpMessage *payload)
  33. {
  34. DEBUG(LOG_INFO, "Forwarding packet to relay");
  35. return kernel_packet(payload, server_config.server, SERVER_PORT,
  36. payload->giaddr, SERVER_PORT);
  37. }
  38. /* send a packet to a specific arp address and ip address by creating our own ip packet */
  39. static int send_packet_to_client(struct dhcpMessage *payload, int force_broadcast)
  40. {
  41. uint8_t *chaddr;
  42. uint32_t ciaddr;
  43. if (force_broadcast) {
  44. DEBUG(LOG_INFO, "broadcasting packet to client (NAK)");
  45. ciaddr = INADDR_BROADCAST;
  46. chaddr = MAC_BCAST_ADDR;
  47. } else if (payload->ciaddr) {
  48. DEBUG(LOG_INFO, "unicasting packet to client ciaddr");
  49. ciaddr = payload->ciaddr;
  50. chaddr = payload->chaddr;
  51. } else if (ntohs(payload->flags) & BROADCAST_FLAG) {
  52. DEBUG(LOG_INFO, "broadcasting packet to client (requested)");
  53. ciaddr = INADDR_BROADCAST;
  54. chaddr = MAC_BCAST_ADDR;
  55. } else {
  56. DEBUG(LOG_INFO, "unicasting packet to client yiaddr");
  57. ciaddr = payload->yiaddr;
  58. chaddr = payload->chaddr;
  59. }
  60. return raw_packet(payload, server_config.server, SERVER_PORT,
  61. ciaddr, CLIENT_PORT, chaddr, server_config.ifindex);
  62. }
  63. /* send a dhcp packet, if force broadcast is set, the packet will be broadcast to the client */
  64. static int send_packet(struct dhcpMessage *payload, int force_broadcast)
  65. {
  66. int ret;
  67. if (payload->giaddr)
  68. ret = send_packet_to_relay(payload);
  69. else ret = send_packet_to_client(payload, force_broadcast);
  70. return ret;
  71. }
  72. static void init_packet(struct dhcpMessage *packet, struct dhcpMessage *oldpacket, char type)
  73. {
  74. init_header(packet, type);
  75. packet->xid = oldpacket->xid;
  76. memcpy(packet->chaddr, oldpacket->chaddr, 16);
  77. packet->flags = oldpacket->flags;
  78. packet->giaddr = oldpacket->giaddr;
  79. packet->ciaddr = oldpacket->ciaddr;
  80. add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server);
  81. }
  82. /* add in the bootp options */
  83. static void add_bootp_options(struct dhcpMessage *packet)
  84. {
  85. packet->siaddr = server_config.siaddr;
  86. if (server_config.sname)
  87. strncpy(packet->sname, server_config.sname, sizeof(packet->sname) - 1);
  88. if (server_config.boot_file)
  89. strncpy(packet->file, server_config.boot_file, sizeof(packet->file) - 1);
  90. }
  91. /* send a DHCP OFFER to a DHCP DISCOVER */
  92. int sendOffer(struct dhcpMessage *oldpacket)
  93. {
  94. struct dhcpMessage packet;
  95. struct dhcpOfferedAddr *lease = NULL;
  96. uint32_t req_align, lease_time_align = server_config.lease;
  97. uint8_t *req, *lease_time;
  98. struct option_set *curr;
  99. struct in_addr addr;
  100. uint32_t static_lease_ip;
  101. init_packet(&packet, oldpacket, DHCPOFFER);
  102. static_lease_ip = getIpByMac(server_config.static_leases, oldpacket->chaddr);
  103. /* ADDME: if static, short circuit */
  104. if(!static_lease_ip)
  105. {
  106. /* the client is in our lease/offered table */
  107. if ((lease = find_lease_by_chaddr(oldpacket->chaddr))) {
  108. if (!lease_expired(lease))
  109. lease_time_align = lease->expires - time(0);
  110. packet.yiaddr = lease->yiaddr;
  111. /* Or the client has a requested ip */
  112. } else if ((req = get_option(oldpacket, DHCP_REQUESTED_IP)) &&
  113. /* Don't look here (ugly hackish thing to do) */
  114. memcpy(&req_align, req, 4) &&
  115. /* and the ip is in the lease range */
  116. ntohl(req_align) >= ntohl(server_config.start) &&
  117. ntohl(req_align) <= ntohl(server_config.end) &&
  118. !static_lease_ip && /* Check that its not a static lease */
  119. /* and is not already taken/offered */
  120. ((!(lease = find_lease_by_yiaddr(req_align)) ||
  121. /* or its taken, but expired */ /* ADDME: or maybe in here */
  122. lease_expired(lease)))) {
  123. packet.yiaddr = req_align; /* FIXME: oh my, is there a host using this IP? */
  124. /* otherwise, find a free IP */
  125. } else {
  126. /* Is it a static lease? (No, because find_address skips static lease) */
  127. packet.yiaddr = find_address(0);
  128. /* try for an expired lease */
  129. if (!packet.yiaddr) packet.yiaddr = find_address(1);
  130. }
  131. if(!packet.yiaddr) {
  132. LOG(LOG_WARNING, "no IP addresses to give -- OFFER abandoned");
  133. return -1;
  134. }
  135. if (!add_lease(packet.chaddr, packet.yiaddr, server_config.offer_time)) {
  136. LOG(LOG_WARNING, "lease pool is full -- OFFER abandoned");
  137. return -1;
  138. }
  139. if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
  140. memcpy(&lease_time_align, lease_time, 4);
  141. lease_time_align = ntohl(lease_time_align);
  142. if (lease_time_align > server_config.lease)
  143. lease_time_align = server_config.lease;
  144. }
  145. /* Make sure we aren't just using the lease time from the previous offer */
  146. if (lease_time_align < server_config.min_lease)
  147. lease_time_align = server_config.lease;
  148. }
  149. /* ADDME: end of short circuit */
  150. else
  151. {
  152. /* It is a static lease... use it */
  153. packet.yiaddr = static_lease_ip;
  154. }
  155. add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
  156. curr = server_config.options;
  157. while (curr) {
  158. if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
  159. add_option_string(packet.options, curr->data);
  160. curr = curr->next;
  161. }
  162. add_bootp_options(&packet);
  163. addr.s_addr = packet.yiaddr;
  164. LOG(LOG_INFO, "sending OFFER of %s", inet_ntoa(addr));
  165. return send_packet(&packet, 0);
  166. }
  167. int sendNAK(struct dhcpMessage *oldpacket)
  168. {
  169. struct dhcpMessage packet;
  170. init_packet(&packet, oldpacket, DHCPNAK);
  171. DEBUG(LOG_INFO, "sending NAK");
  172. return send_packet(&packet, 1);
  173. }
  174. int sendACK(struct dhcpMessage *oldpacket, uint32_t yiaddr)
  175. {
  176. struct dhcpMessage packet;
  177. struct option_set *curr;
  178. uint8_t *lease_time;
  179. uint32_t lease_time_align = server_config.lease;
  180. struct in_addr addr;
  181. init_packet(&packet, oldpacket, DHCPACK);
  182. packet.yiaddr = yiaddr;
  183. if ((lease_time = get_option(oldpacket, DHCP_LEASE_TIME))) {
  184. memcpy(&lease_time_align, lease_time, 4);
  185. lease_time_align = ntohl(lease_time_align);
  186. if (lease_time_align > server_config.lease)
  187. lease_time_align = server_config.lease;
  188. else if (lease_time_align < server_config.min_lease)
  189. lease_time_align = server_config.lease;
  190. }
  191. add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_align));
  192. curr = server_config.options;
  193. while (curr) {
  194. if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
  195. add_option_string(packet.options, curr->data);
  196. curr = curr->next;
  197. }
  198. add_bootp_options(&packet);
  199. addr.s_addr = packet.yiaddr;
  200. LOG(LOG_INFO, "sending ACK to %s", inet_ntoa(addr));
  201. if (send_packet(&packet, 0) < 0)
  202. return -1;
  203. add_lease(packet.chaddr, packet.yiaddr, lease_time_align);
  204. return 0;
  205. }
  206. int send_inform(struct dhcpMessage *oldpacket)
  207. {
  208. struct dhcpMessage packet;
  209. struct option_set *curr;
  210. init_packet(&packet, oldpacket, DHCPACK);
  211. curr = server_config.options;
  212. while (curr) {
  213. if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
  214. add_option_string(packet.options, curr->data);
  215. curr = curr->next;
  216. }
  217. add_bootp_options(&packet);
  218. return send_packet(&packet, 0);
  219. }