clientpacket.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /* vi: set sw=4 ts=4: */
  2. /* clientpacket.c
  3. *
  4. * Packet generation and dispatching functions for the DHCP client.
  5. *
  6. * Russ Dill <Russ.Dill@asu.edu> July 2001
  7. *
  8. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  9. */
  10. #include <features.h>
  11. #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
  12. #include <netpacket/packet.h>
  13. #include <net/ethernet.h>
  14. #else
  15. #include <asm/types.h>
  16. #include <linux/if_packet.h>
  17. #include <linux/if_ether.h>
  18. #endif
  19. #include "common.h"
  20. #include "dhcpd.h"
  21. #include "dhcpc.h"
  22. #include "options.h"
  23. /* Create a random xid */
  24. uint32_t random_xid(void)
  25. {
  26. static smallint initialized;
  27. if (!initialized) {
  28. srand(monotonic_us());
  29. initialized = 1;
  30. }
  31. return rand();
  32. }
  33. /* initialize a packet with the proper defaults */
  34. static void init_packet(struct dhcpMessage *packet, char type)
  35. {
  36. udhcp_init_header(packet, type);
  37. memcpy(packet->chaddr, client_config.arp, 6);
  38. if (client_config.clientid)
  39. add_option_string(packet->options, client_config.clientid);
  40. if (client_config.hostname)
  41. add_option_string(packet->options, client_config.hostname);
  42. if (client_config.fqdn)
  43. add_option_string(packet->options, client_config.fqdn);
  44. if ((type != DHCPDECLINE) && (type != DHCPRELEASE))
  45. add_option_string(packet->options, client_config.vendorclass);
  46. }
  47. /* Add a parameter request list for stubborn DHCP servers. Pull the data
  48. * from the struct in options.c. Don't do bounds checking here because it
  49. * goes towards the head of the packet. */
  50. static void add_param_req_option(struct dhcpMessage *packet)
  51. {
  52. uint8_t c;
  53. int end = end_option(packet->options);
  54. int i, len = 0;
  55. packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
  56. for (i = 0; (c = dhcp_options[i].code) != 0; i++) {
  57. if ((dhcp_options[i].flags & OPTION_REQ)
  58. || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
  59. ) {
  60. packet->options[end + OPT_DATA + len] = c;
  61. len++;
  62. }
  63. }
  64. packet->options[end + OPT_LEN] = len;
  65. packet->options[end + OPT_DATA + len] = DHCP_END;
  66. }
  67. #if ENABLE_FEATURE_UDHCPC_ARPING
  68. /* Unicast a DHCP decline message */
  69. int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
  70. {
  71. struct dhcpMessage packet;
  72. init_packet(&packet, DHCPDECLINE);
  73. packet.xid = xid;
  74. add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
  75. add_simple_option(packet.options, DHCP_SERVER_ID, server);
  76. bb_info_msg("Sending decline...");
  77. return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
  78. SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
  79. }
  80. #endif
  81. /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
  82. int send_discover(uint32_t xid, uint32_t requested)
  83. {
  84. struct dhcpMessage packet;
  85. init_packet(&packet, DHCPDISCOVER);
  86. packet.xid = xid;
  87. if (requested)
  88. add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
  89. /* Explicitly saying that we want RFC-compliant packets helps
  90. * some buggy DHCP servers to NOT send bigger packets */
  91. add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576));
  92. add_param_req_option(&packet);
  93. bb_info_msg("Sending discover...");
  94. return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
  95. SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
  96. }
  97. /* Broadcasts a DHCP request message */
  98. int send_selecting(uint32_t xid, uint32_t server, uint32_t requested)
  99. {
  100. struct dhcpMessage packet;
  101. struct in_addr addr;
  102. init_packet(&packet, DHCPREQUEST);
  103. packet.xid = xid;
  104. add_simple_option(packet.options, DHCP_REQUESTED_IP, requested);
  105. add_simple_option(packet.options, DHCP_SERVER_ID, server);
  106. add_param_req_option(&packet);
  107. addr.s_addr = requested;
  108. bb_info_msg("Sending select for %s...", inet_ntoa(addr));
  109. return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
  110. SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
  111. }
  112. /* Unicasts or broadcasts a DHCP renew message */
  113. int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
  114. {
  115. struct dhcpMessage packet;
  116. init_packet(&packet, DHCPREQUEST);
  117. packet.xid = xid;
  118. packet.ciaddr = ciaddr;
  119. add_param_req_option(&packet);
  120. bb_info_msg("Sending renew...");
  121. if (server)
  122. return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
  123. return udhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST,
  124. SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex);
  125. }
  126. /* Unicasts a DHCP release message */
  127. int send_release(uint32_t server, uint32_t ciaddr)
  128. {
  129. struct dhcpMessage packet;
  130. init_packet(&packet, DHCPRELEASE);
  131. packet.xid = random_xid();
  132. packet.ciaddr = ciaddr;
  133. add_simple_option(packet.options, DHCP_SERVER_ID, server);
  134. bb_info_msg("Sending release...");
  135. return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
  136. }
  137. /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
  138. int get_raw_packet(struct dhcpMessage *payload, int fd)
  139. {
  140. int bytes;
  141. struct udp_dhcp_packet packet;
  142. uint16_t check;
  143. memset(&packet, 0, sizeof(packet));
  144. bytes = safe_read(fd, &packet, sizeof(packet));
  145. if (bytes < 0) {
  146. DEBUG("Cannot read on raw listening socket - ignoring");
  147. sleep(1); /* possible down interface, looping condition */
  148. return bytes; /* returns -1 */
  149. }
  150. if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
  151. DEBUG("Packet is too short, ignoring");
  152. return -2;
  153. }
  154. if (bytes < ntohs(packet.ip.tot_len)) {
  155. /* packet is bigger than sizeof(packet), we did partial read */
  156. DEBUG("Oversized packet, ignoring");
  157. return -2;
  158. }
  159. /* ignore any extra garbage bytes */
  160. bytes = ntohs(packet.ip.tot_len);
  161. /* make sure its the right packet for us, and that it passes sanity checks */
  162. if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
  163. || packet.ip.ihl != (sizeof(packet.ip) >> 2)
  164. || packet.udp.dest != htons(CLIENT_PORT)
  165. /* || bytes > (int) sizeof(packet) - can't happen */
  166. || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
  167. ) {
  168. DEBUG("Unrelated/bogus packet");
  169. return -2;
  170. }
  171. /* verify IP checksum */
  172. check = packet.ip.check;
  173. packet.ip.check = 0;
  174. if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
  175. DEBUG("Bad IP header checksum, ignoring");
  176. return -2;
  177. }
  178. /* verify UDP checksum. IP header has to be modified for this */
  179. memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
  180. /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
  181. packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
  182. check = packet.udp.check;
  183. packet.udp.check = 0;
  184. if (check && check != udhcp_checksum(&packet, bytes)) {
  185. bb_error_msg("packet with bad UDP checksum received, ignoring");
  186. return -2;
  187. }
  188. memcpy(payload, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
  189. if (payload->cookie != htonl(DHCP_MAGIC)) {
  190. bb_error_msg("received bogus message (bad magic), ignoring");
  191. return -2;
  192. }
  193. DEBUG("Got valid DHCP packet");
  194. return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
  195. }