2 * dhcp.c Functions to send/receive dhcp packets.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008 Alan DeKok <aland@deployingradius.com>
24 #include <freeradius-devel/ident.h>
27 #include <freeradius-devel/libradius.h>
28 #include <freeradius-devel/udpfromto.h>
29 #include <freeradius-devel/dhcp.h>
32 #define DHCP_CHADDR_LEN (16)
33 #define DHCP_SNAME_LEN (64)
34 #define DHCP_FILE_LEN (128)
35 #define DHCP_VEND_LEN (308)
36 #define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
38 typedef struct dhcp_packet_t {
44 uint16_t secs; /* 8 */
46 uint32_t ciaddr; /* 12 */
47 uint32_t yiaddr; /* 16 */
48 uint32_t siaddr; /* 20 */
49 uint32_t giaddr; /* 24 */
50 uint8_t chaddr[DHCP_CHADDR_LEN]; /* 28 */
51 char sname[DHCP_SNAME_LEN]; /* 44 */
52 char file[DHCP_FILE_LEN]; /* 108 */
53 uint32_t option_format; /* 236 */
54 uint8_t options[DHCP_VEND_LEN];
58 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
59 * INADDR_BROADCAST : 68 <- SERVER_IP : 67 OFFER
60 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
61 * INADDR_BROADCAST : 68 <- SERVER_IP : 67 ACK
63 static const char *dhcp_header_names[] = {
66 "DHCP-Hardware-Address-Length",
68 "DHCP-Transaction-Id",
69 "DHCP-Number-of-Seconds",
71 "DHCP-Client-IP-Address",
72 "DHCP-Your-IP-Address",
73 "DHCP-Server-IP-Address",
74 "DHCP-Gateway-IP-Address",
75 "DHCP-Client-Hardware-Address",
76 "DHCP-Server-Host-Name",
82 static const char *dhcp_message_types[] = {
95 static int dhcp_header_sizes[] = {
106 * Some clients silently ignore responses less than 300 bytes.
108 #define MIN_PACKET_SIZE (244)
109 #define DEFAULT_PACKET_SIZE (300)
110 #define MAX_PACKET_SIZE (1500 - 40)
113 * DHCPv4 is only for IPv4. Broadcast only works if udpfromto is
116 RADIUS_PACKET *fr_dhcp_recv(int sockfd)
119 struct sockaddr_storage src;
120 struct sockaddr_storage dst;
121 socklen_t sizeof_src;
122 socklen_t sizeof_dst;
123 RADIUS_PACKET *packet;
126 packet = rad_alloc(0);
127 if (!packet) return NULL;
128 memset(packet, 0, sizeof(packet));
130 packet->data = malloc(MAX_PACKET_SIZE);
136 packet->sockfd = sockfd;
137 sizeof_src = sizeof(src);
138 packet->data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
139 (struct sockaddr *)&src, &sizeof_src);
140 if (packet->data_len <= 0) {
141 fprintf(stderr, "Failed reading DHCP socket: %s", strerror(errno));
146 if (packet->data_len < MIN_PACKET_SIZE) {
147 fprintf(stderr, "DHCP packet is too small (%d < %d)",
148 packet->data_len, MIN_PACKET_SIZE);
153 if (packet->data[0] != 1) {
154 fprintf(stderr, "Cannot receive DHCP server messages");
159 if (packet->data[1] != 1) {
160 fprintf(stderr, "DHCP can only receive ethernet requests, not type %02x",
166 if (packet->data[2] != 6) {
167 fprintf(stderr, "Ethernet HW length is wrong length %d\n",
173 memcpy(&magic, packet->data + 236, 4);
174 magic = ntohl(magic);
175 if (magic != DHCP_OPTION_MAGIC_NUMBER) {
176 fprintf(stderr, "Cannot do BOOTP\n");
182 * Create unique keys for the packet.
184 memcpy(&magic, packet->data + 4, 4);
185 packet->id = ntohl(magic);
188 * Check that it's a known packet type.
190 if ((packet->data[240] != 53) ||
191 (packet->data[241] != 1) ||
192 (packet->data[242] == 0) ||
193 (packet->data[242] > 8)) {
194 fprintf(stderr, "Unknown, or badly formatted DHCP packet\n");
200 * Create a unique vector from the MAC address and the
201 * DHCP opcode. This is a hack for the RADIUS
202 * infrastructure in the rest of the server.
204 * Note: packet->data[2] == 6, which is smaller than
205 * sizeof(packet->vector)
207 * FIXME: Look for client-identifier in packet,
210 memset(packet->vector, 0, sizeof(packet->vector));
211 memcpy(packet->vector, packet->data + 28, packet->data[2]);
212 packet->vector[packet->data[2]] = packet->data[242];
215 * FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
216 * FIXME: for OFFER / ACK : src_port = dst_port - 1
219 packet->code = PW_DHCP_OFFSET | packet->data[242];
222 * Unique keys are xid, client mac, and client ID?
226 * FIXME: More checks, like DHCP packet type?
229 sizeof_dst = sizeof(dst);
231 * This should never fail...
233 getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst);
235 fr_sockaddr2ipaddr(&src, sizeof_src, &packet->src_ipaddr, &port);
236 packet->src_port = port;
238 fr_sockaddr2ipaddr(&dst, sizeof_dst, &packet->dst_ipaddr, &port);
239 packet->dst_port = port;
241 if (librad_debug > 1) {
243 const char *name = type_buf;
244 char src_ip_buf[256], dst_ip_buf[256];
246 if ((packet->code >= PW_DHCP_DISCOVER) &&
247 (packet->code <= PW_DHCP_INFORM)) {
248 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
250 snprintf(type_buf, sizeof(type_buf), "%d",
251 packet->code - PW_DHCP_OFFSET);
254 printf("Received %s of id %u from %s:%d to %s:%d\n",
255 name, (unsigned int) packet->id,
256 inet_ntop(packet->src_ipaddr.af,
257 &packet->src_ipaddr.ipaddr,
258 src_ip_buf, sizeof(src_ip_buf)),
260 inet_ntop(packet->dst_ipaddr.af,
261 &packet->dst_ipaddr.ipaddr,
262 dst_ip_buf, sizeof(dst_ip_buf)),
272 * Send a DHCP packet.
274 int fr_dhcp_send(RADIUS_PACKET *packet)
276 struct sockaddr_storage dst;
277 struct sockaddr_storage src;
278 socklen_t sizeof_dst;
279 socklen_t sizeof_src;
281 fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
285 * Currently unused...
287 fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
291 * Assume that the packet is encoded before sending it.
293 return sendto(packet->sockfd, packet->data, packet->data_len, 0,
294 (struct sockaddr *)&dst, sizeof_dst);
298 int fr_dhcp_decode(RADIUS_PACKET *packet)
304 VALUE_PAIR *head, *vp, **tail;
305 VALUE_PAIR *maxms, *mtu;
312 if ((librad_debug > 2) && fr_log_fp) {
313 for (i = 0; i < packet->data_len; i++) {
314 if ((i & 0x0f) == 0x00) fprintf(stderr, "%d: ", i);
315 fprintf(fr_log_fp, "%02x ", packet->data[i]);
316 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
318 fprintf(fr_log_fp, "\n");
321 if (packet->data[1] != 1) {
322 fprintf(stderr, "Packet is not Ethernet: %u\n",
330 for (i = 0; i < 14; i++) {
331 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
333 fprintf(stderr, "Parse error %s\n", librad_errstr);
340 (packet->data[1] == 1) &&
341 (packet->data[2] == 6)) {
342 vp->type = PW_TYPE_ETHERNET;
347 vp->vp_integer = p[0];
352 vp->vp_integer = (p[0] << 8) | p[1];
356 case PW_TYPE_INTEGER:
357 memcpy(&vp->vp_integer, p, 4);
358 vp->vp_integer = ntohl(vp->vp_integer);
363 memcpy(&vp->vp_ipaddr, p, 4);
368 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
369 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
370 vp->length = strlen(vp->vp_strvalue);
371 if (vp->length == 0) {
377 memcpy(vp->vp_octets, p, packet->data[2]);
378 vp->length = packet->data[2];
381 case PW_TYPE_ETHERNET:
382 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
383 vp->length = sizeof(vp->vp_ether);
387 fprintf(stderr, "BAD TYPE %d\n", vp->type);
391 p += dhcp_header_sizes[i];
395 if (librad_debug > 1) {
396 vp_prints(buffer, sizeof(buffer), vp);
397 fprintf(stderr, "\t%s\n", buffer);
404 * Loop over the options.
406 p = packet->data + 240;
407 total = packet->data_len - 240;
410 int num_entries, alen;
414 if (*p == 255) break; /* end of options signifier */
417 fprintf(stderr, "Attribute too long %u %u\n",
422 da = dict_attrbyvalue(DHCP2ATTR(p[0]));
424 fprintf(stderr, "Attribute not in our dictionary: %u\n",
439 if (da->flags.array) {
447 if ((alen & 0x01) != 0) goto raw;
448 num_entries = alen / 2;
453 case PW_TYPE_INTEGER:
455 if ((alen & 0x03) != 0) goto raw;
456 num_entries = alen / 4;
461 break; /* really an internal sanity failure */
468 if (alen != 1) goto raw;
472 if (alen != 2) goto raw;
476 case PW_TYPE_INTEGER:
478 if (alen != 4) goto raw;
486 for (i = 0; i < num_entries; i++) {
487 vp = pairmake(da->name, NULL, T_OP_EQ);
489 fprintf(stderr, "Cannot build attribute %s\n",
496 * Hacks for ease of use.
498 if ((da->attr == DHCP2ATTR(0x3d)) &&
500 (alen == 7) && (*p == 1) && (num_entries == 1)) {
501 vp->type = PW_TYPE_ETHERNET;
502 memcpy(vp->vp_octets, p + 1, 6);
507 vp->vp_integer = p[0];
511 vp->vp_integer = (p[0] << 8) | p[1];
514 case PW_TYPE_INTEGER:
515 memcpy(&vp->vp_integer, p, 4);
516 vp->vp_integer = ntohl(vp->vp_integer);
520 memcpy(&vp->vp_ipaddr, p , 4);
525 memcpy(vp->vp_strvalue, p , alen);
526 vp->vp_strvalue[alen] = '\0';
530 vp = pairmake(da->name, NULL, T_OP_EQ);
532 fprintf(stderr, "Cannot build attribute %s\n", librad_errstr);
537 vp->type = PW_TYPE_OCTETS;
540 memcpy(vp->vp_octets, p, alen);
544 fprintf(stderr, "Internal sanity check %d %d\n", vp->type, __LINE__);
547 } /* switch over type */
551 if (librad_debug > 1) {
552 vp_prints(buffer, sizeof(buffer), vp);
553 fprintf(stderr, "\t%s\n", buffer);
559 } /* loop over array entries */
562 total -= (alen * num_entries);
566 * If DHCP request, set ciaddr to zero.
570 * Set broadcast flag for broken vendors, but only if
573 memcpy(&giaddr, packet->data + 24, sizeof(giaddr));
574 if (giaddr == htonl(INADDR_ANY)) {
576 * DHCP Opcode is request
578 vp = pairfind(head, DHCP2ATTR(256));
579 if (vp && vp->lvalue == 3) {
581 * Vendor is "MSFT 98"
583 vp = pairfind(head, DHCP2ATTR(63));
584 if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
585 vp = pairfind(head, DHCP2ATTR(262));
588 * Reply should be broadcast.
590 if (vp) vp->lvalue |= 0x8000;
591 packet->data[10] |= 0x80;
597 * FIXME: Nuke attributes that aren't used in the normal
598 * header for discover/requests.
603 * Client can request a LARGER size, but not a smaller
604 * one. They also cannot request a size larger than MTU.
606 maxms = pairfind(packet->vps, DHCP2ATTR(57));
607 mtu = pairfind(packet->vps, DHCP2ATTR(26));
609 if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
610 fprintf(stderr, "DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");
614 if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) {
615 fprintf(stderr, "DHCP WARNING: Client says maximum message size is smaller than minimum permitted by the specification: fixing it");
616 maxms->vp_integer = DEFAULT_PACKET_SIZE;
619 if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) {
620 fprintf(stderr, "DHCP WARNING: Client says MTU is smaller than maximum message size: fixing it");
621 maxms->vp_integer = mtu->vp_integer;
624 if (librad_debug) fflush(stdout);
630 static int attr_cmp(const void *one, const void *two)
632 const VALUE_PAIR * const *a = one;
633 const VALUE_PAIR * const *b = two;
636 * DHCP-Message-Type is first, for simplicity.
638 if (((*a)->attribute == DHCP2ATTR(53)) &&
639 (*b)->attribute != DHCP2ATTR(53)) return -1;
642 * Relay-Agent is last
644 if (((*a)->attribute == DHCP2ATTR(82)) &&
645 (*b)->attribute != DHCP2ATTR(82)) return +1;
647 return ((*a)->attribute - (*b)->attribute);
651 static size_t fr_dhcp_vp2attr(VALUE_PAIR *vp, uint8_t *p, size_t room)
659 room = room; /* -Wunused */
662 * Search for all attributes of the same
663 * type, and pack them into the same
669 *p = vp->vp_integer & 0xff;
674 p[0] = (vp->vp_integer >> 8) & 0xff;
675 p[1] = vp->vp_integer & 0xff;
678 case PW_TYPE_INTEGER:
680 lvalue = htonl(vp->vp_integer);
681 memcpy(p, &lvalue, 4);
686 memcpy(p, &vp->vp_ipaddr, 4);
689 case PW_TYPE_ETHERNET:
691 memcpy(p, &vp->vp_ether, 6);
695 memcpy(p, vp->vp_strvalue, vp->length);
700 memcpy(p, vp->vp_octets, vp->length);
705 fprintf(stderr, "BAD TYPE2 %d\n", vp->type);
713 int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
718 uint32_t lvalue, mms;
719 size_t dhcp_size, length;
723 if (packet->data) return 0;
725 packet->data = malloc(MAX_PACKET_SIZE);
726 if (!packet->data) return -1;
728 packet->data_len = MAX_PACKET_SIZE;
730 if (packet->code == 0) packet->code = PW_DHCP_NAK;
733 * FIXME: allow it to send client packets.
736 librad_log("Need original to send response!");
740 if (librad_debug > 1) {
742 const char *name = type_buf;
743 char src_ip_buf[256], dst_ip_buf[256];
745 if ((packet->code >= PW_DHCP_DISCOVER) &&
746 (packet->code <= PW_DHCP_INFORM)) {
747 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
749 snprintf(type_buf, sizeof(type_buf), "%d",
750 packet->code - PW_DHCP_OFFSET);
753 printf("Sending %s of id %u from %s:%d to %s:%d\n",
754 name, (unsigned int) packet->id,
755 inet_ntop(packet->src_ipaddr.af,
756 &packet->src_ipaddr.ipaddr,
757 src_ip_buf, sizeof(src_ip_buf)),
759 inet_ntop(packet->dst_ipaddr.af,
760 &packet->dst_ipaddr.ipaddr,
761 dst_ip_buf, sizeof(dst_ip_buf)),
768 mms = DEFAULT_PACKET_SIZE; /* maximum message size */
771 * Client can request a LARGER size, but not a smaller
772 * one. They also cannot request a size larger than MTU.
774 vp = pairfind(original->vps, DHCP2ATTR(57));
775 if (vp && (vp->vp_integer > mms)) {
776 mms = vp->vp_integer;
778 if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
782 * RFC 3118: Authentication option.
784 vp = pairfind(packet->vps, DHCP2ATTR(90));
786 if (vp->length < 2) {
787 memset(vp->vp_octets + vp->length, 0,
792 if (vp->length < 3) {
795 gettimeofday(&tv, NULL);
796 vp->vp_octets[2] = 0;
797 timeval2ntp(&tv, vp->vp_octets + 3);
802 * Configuration token (clear-text token)
804 if (vp->vp_octets[0] == 0) {
806 vp->vp_octets[1] = 0;
808 pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD);
810 length = pass->length;
811 if ((length + 11) > sizeof(vp->vp_octets)) {
812 length -= ((length + 11) - sizeof(vp->vp_octets));
814 memcpy(vp->vp_octets + 11, pass->vp_strvalue,
816 vp->length = length + 11;
819 memset(vp->vp_octets + 11, 8, 0);
822 } else { /* we don't support this type! */
823 fprintf(stderr, "DHCP-Authentication %d unsupported\n",
829 *p++ = 1; /* client message */
831 *p++ = 2; /* server message */
833 *p++ = 1; /* hardware type = ethernet */
834 *p++ = original->data[2];
837 if (!original) { /* Xid */
839 memcpy(p, &lvalue, 4);
841 memcpy(p, original->data + 4, 4);
845 memset(p, 0, 2); /* secs are zero */
848 memcpy(p, original->data + 10, 6); /* copy flags && ciaddr */
851 * Allow the admin to set the broadcast flag.
853 vp = pairfind(packet->vps, DHCP2ATTR(262));
855 p[0] |= (vp->vp_integer & 0xff00) >> 8;
856 p[1] |= (vp->vp_integer & 0xff);
862 * Set client IP address.
864 vp = pairfind(packet->vps, DHCP2ATTR(264)); /* Your IP address */
866 lvalue = vp->vp_ipaddr;
868 lvalue = htonl(INADDR_ANY);
870 memcpy(p, &lvalue, 4); /* your IP address */
873 memset(p, 0, 4); /* siaddr is zero */
876 memcpy(p, original->data + 24, 4); /* copy gateway IP address */
879 memcpy(p, original->data + 28, DHCP_CHADDR_LEN);
880 p += DHCP_CHADDR_LEN;
882 memset(p, 0, 192); /* bootp legacy */
885 lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER); /* DHCP magic number */
886 memcpy(p, &lvalue, 4);
892 if (librad_debug > 1) {
897 for (i = 0; i < 14; i++) {
898 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
900 fprintf(stderr, "Parse error %s\n", librad_errstr);
906 vp->vp_integer = p[0];
911 vp->vp_integer = (p[0] << 8) | p[1];
915 case PW_TYPE_INTEGER:
916 memcpy(&vp->vp_integer, p, 4);
917 vp->vp_integer = ntohl(vp->vp_integer);
922 memcpy(&vp->vp_ipaddr, p, 4);
927 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
928 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
929 vp->length = strlen(vp->vp_strvalue);
932 case PW_TYPE_OCTETS: /* only for Client HW Address */
933 memcpy(vp->vp_octets, p, packet->data[2]);
934 vp->length = packet->data[2];
937 case PW_TYPE_ETHERNET: /* only for Client HW Address */
938 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
939 vp->length = sizeof(vp->vp_ether);
943 fprintf(stderr, "Internal sanity check failed %d %d\n", vp->type, __LINE__);
948 p += dhcp_header_sizes[i];
950 vp_prints(buffer, sizeof(buffer), vp);
951 fprintf(stderr, "\t%s\n", buffer);
956 * Jump over DHCP magic number, response, etc.
962 * Before packing the attributes, re-order them so that
963 * the array ones are all contiguous. This simplifies
967 for (vp = packet->vps; vp != NULL; vp = vp->next) {
971 VALUE_PAIR **array, **last;
973 array = malloc(num_vps * sizeof(VALUE_PAIR *));
976 for (vp = packet->vps; vp != NULL; vp = vp->next) {
981 * Sort the attributes.
983 qsort(array, (size_t) num_vps, sizeof(VALUE_PAIR *),
987 for (i = 0; i < num_vps; i++) {
989 array[i]->next = NULL;
990 last = &(array[i]->next);
995 p[0] = 0x35; /* DHCP-Message-Type */
997 p[2] = packet->code - PW_DHCP_OFFSET;
1001 * Pack in the attributes.
1005 int num_entries = 1;
1008 uint8_t *plength, *pattr;
1010 if (!IS_DHCP_ATTR(vp)) goto next;
1011 if (((vp->attribute & 0xffff) > 255) &&
1012 (DHCP_BASE_ATTR(vp->attribute) != PW_DHCP_OPTION_82)) goto next;
1014 length = vp->length;
1016 for (same = vp->next; same != NULL; same = same->next) {
1017 if (same->attribute != vp->attribute) break;
1022 * For client-identifier
1024 if ((vp->type == PW_TYPE_ETHERNET) &&
1025 (vp->length == 6) &&
1026 (num_entries == 1)) {
1027 vp->type = PW_TYPE_OCTETS;
1028 memmove(vp->vp_octets + 1, vp->vp_octets, 6);
1029 vp->vp_octets[0] = 1;
1033 *(p++) = vp->attribute & 0xff;
1035 *(p++) = 0; /* header isn't included in attr length */
1037 if (DHCP_BASE_ATTR(vp->attribute) == PW_DHCP_OPTION_82) {
1038 *(p++) = DHCP_UNPACK_OPTION1(vp->attribute);
1043 for (i = 0; i < num_entries; i++) {
1044 if (librad_debug > 1) {
1045 vp_prints(buffer, sizeof(buffer), vp);
1046 fprintf(stderr, "\t%s\n", buffer);
1049 length = fr_dhcp_vp2attr(vp, p, 0);
1052 * This will never happen due to FreeRADIUS
1053 * limitations: sizeof(vp->vp_octets) < 255
1056 fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);
1061 * More than one attribute of the same type
1062 * in a row: they are packed together
1063 * into the same TLV. If we overflow,
1066 if ((*plength + length) > 255) {
1067 fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);
1075 (vp->next->attribute == vp->attribute))
1077 } /* loop over num_entries */
1079 if (DHCP_BASE_ATTR(vp->attribute) == PW_DHCP_OPTION_82) {
1080 plength[2] = plength[0] - 2;
1087 p[0] = 0xff; /* end of option option */
1090 dhcp_size = p - packet->data;
1093 * FIXME: if (dhcp_size > mms),
1094 * then we put the extra options into the "sname" and "file"
1095 * fields, AND set the "end option option" in the "options"
1096 * field. We also set the "overload option",
1097 * and put options into the "file" field, followed by
1098 * the "sname" field. Where each option is completely
1099 * enclosed in the "file" and/or "sname" field, AND
1100 * followed by the "end of option", and MUST be followed
1101 * by padding option.
1103 * Yuck. That sucks...
1105 packet->data_len = dhcp_size;
1107 packet->dst_ipaddr.af = AF_INET;
1108 packet->src_ipaddr.af = AF_INET;
1110 packet->dst_port = original->src_port;
1111 packet->src_port = original->dst_port;
1114 * Note that for DHCP, we NEVER send the response to the
1115 * source IP address of the request. It may have
1116 * traversed multiple relays, and we need to send the request
1117 * to the relay closest to the client.
1119 * if giaddr, send to giaddr.
1120 * if NAK, send broadcast packet
1121 * if ciaddr, unicast to ciaddr
1122 * if flags & 0x8000, broadcast (client request)
1123 * if sent from 0.0.0.0, broadcast response
1124 * unicast to client yiaddr
1128 * FIXME: alignment issues. We likely don't want to
1129 * de-reference the packet structure directly..
1131 dhcp = (dhcp_packet_t *) original->data;
1133 if (dhcp->giaddr != htonl(INADDR_ANY)) {
1134 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr;
1137 * Gateways send FROM 68 to 67, and we
1138 * respond FROM 67 to 67... not to 68.
1140 packet->dst_port = original->dst_port;
1142 } else if (packet->code == PW_DHCP_NAK) {
1143 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
1145 } else if (dhcp->ciaddr != htonl(INADDR_ANY)) {
1146 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr;
1148 } else if ((dhcp->flags & 0x8000) != 0) {
1149 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
1151 } else if (packet->dst_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY)) {
1152 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
1155 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->yiaddr;
1159 * FIXME: This may set it to broadcast, which we don't
1160 * want. Instead, set it to the real address of the
1163 packet->src_ipaddr = original->dst_ipaddr;
1165 packet->sockfd = original->sockfd;
1167 if (packet->data_len < DEFAULT_PACKET_SIZE) {
1168 memset(packet->data + packet->data_len, 0,
1169 DEFAULT_PACKET_SIZE - packet->data_len);
1170 packet->data_len = DEFAULT_PACKET_SIZE;
1173 if ((librad_debug > 2) && fr_log_fp) {
1174 for (i = 0; i < packet->data_len; i++) {
1175 if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", i);
1176 fprintf(fr_log_fp, "%02x ", packet->data[i]);
1177 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
1179 fprintf(fr_log_fp, "\n");
1184 #endif /* WITH_DHCP */