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 #ifndef INADDR_BROADCAST
39 #define INADDR_BROADCAST INADDR_NONE
42 typedef struct dhcp_packet_t {
48 uint16_t secs; /* 8 */
50 uint32_t ciaddr; /* 12 */
51 uint32_t yiaddr; /* 16 */
52 uint32_t siaddr; /* 20 */
53 uint32_t giaddr; /* 24 */
54 uint8_t chaddr[DHCP_CHADDR_LEN]; /* 28 */
55 char sname[DHCP_SNAME_LEN]; /* 44 */
56 char file[DHCP_FILE_LEN]; /* 108 */
57 uint32_t option_format; /* 236 */
58 uint8_t options[DHCP_VEND_LEN];
62 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
63 * INADDR_BROADCAST : 68 <- SERVER_IP : 67 OFFER
64 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
65 * INADDR_BROADCAST : 68 <- SERVER_IP : 67 ACK
67 static const char *dhcp_header_names[] = {
70 "DHCP-Hardware-Address-Length",
72 "DHCP-Transaction-Id",
73 "DHCP-Number-of-Seconds",
75 "DHCP-Client-IP-Address",
76 "DHCP-Your-IP-Address",
77 "DHCP-Server-IP-Address",
78 "DHCP-Gateway-IP-Address",
79 "DHCP-Client-Hardware-Address",
80 "DHCP-Server-Host-Name",
86 static const char *dhcp_message_types[] = {
99 static int dhcp_header_sizes[] = {
110 * Some clients silently ignore responses less than 300 bytes.
112 #define MIN_PACKET_SIZE (244)
113 #define DEFAULT_PACKET_SIZE (300)
114 #define MAX_PACKET_SIZE (1500 - 40)
116 static int getcode(const uint8_t *data, size_t data_len, unsigned int *code)
118 const uint8_t *end, *p;
120 end = data + data_len;
124 * End of packet or end of options
126 if ((p[0] == 0) || (p[0] == 255)) return 0;
129 * Not enough room for 0x3501cc
131 if ((end - p) < 3) return 0; /* t l v */
134 * Option is larger than the packet.
136 if ((p + p[1] + 2) > end) return 0;
139 * Found it. Ensure it's well formed.
142 if ((p[1] != 1) || (p[2] == 0) || (p[2] > 8)) {
156 * DHCPv4 is only for IPv4. Broadcast only works if udpfromto is
159 RADIUS_PACKET *fr_dhcp_recv(int sockfd)
162 struct sockaddr_storage src;
163 struct sockaddr_storage dst;
164 socklen_t sizeof_src;
165 socklen_t sizeof_dst;
166 RADIUS_PACKET *packet;
169 packet = rad_alloc(0);
170 if (!packet) return NULL;
171 memset(packet, 0, sizeof(packet));
173 packet->data = malloc(MAX_PACKET_SIZE);
179 packet->sockfd = sockfd;
180 sizeof_src = sizeof(src);
181 #ifdef WITH_UDPFROMTO
182 sizeof_dst = sizeof(dst);
183 packet->data_len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
184 (struct sockaddr *)&src, &sizeof_src,
185 (struct sockaddr *)&dst, &sizeof_dst);
187 packet->data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
188 (struct sockaddr *)&src, &sizeof_src);
191 if (packet->data_len <= 0) {
192 fprintf(stderr, "Failed reading DHCP socket: %s", strerror(errno));
197 if (packet->data_len < MIN_PACKET_SIZE) {
198 fprintf(stderr, "DHCP packet is too small (%d < %d)",
199 packet->data_len, MIN_PACKET_SIZE);
204 if (packet->data[0] != 1) {
205 fprintf(stderr, "Cannot receive DHCP server messages");
210 if (packet->data[1] != 1) {
211 fprintf(stderr, "DHCP can only receive ethernet requests, not type %02x",
217 if (packet->data[2] != 6) {
218 fprintf(stderr, "Ethernet HW length is wrong length %d\n",
224 memcpy(&magic, packet->data + 236, 4);
225 magic = ntohl(magic);
226 if (magic != DHCP_OPTION_MAGIC_NUMBER) {
227 fprintf(stderr, "Cannot do BOOTP\n");
233 * Create unique keys for the packet.
235 memcpy(&magic, packet->data + 4, 4);
236 packet->id = ntohl(magic);
239 * Check that it's a known packet type.
241 if ((packet->data[240] != 53) ||
242 (packet->data[241] != 1) ||
243 (packet->data[242] == 0) ||
244 (packet->data[242] > 8)) {
246 * Some clients send the packet type buried
247 * inside of the packet...
249 if (!getcode(packet->data + 240, packet->data_len - 240,
251 fprintf(stderr, "Unknown, or badly formatted DHCP packet\n");
256 packet->code = packet->data[242];
258 packet->code |= PW_DHCP_OFFSET;
261 * Create a unique vector from the MAC address and the
262 * DHCP opcode. This is a hack for the RADIUS
263 * infrastructure in the rest of the server.
265 * Note: packet->data[2] == 6, which is smaller than
266 * sizeof(packet->vector)
268 * FIXME: Look for client-identifier in packet,
271 memset(packet->vector, 0, sizeof(packet->vector));
272 memcpy(packet->vector, packet->data + 28, packet->data[2]);
273 packet->vector[packet->data[2]] = packet->code & 0xff;
276 * FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
277 * FIXME: for OFFER / ACK : src_port = dst_port - 1
281 * Unique keys are xid, client mac, and client ID?
285 * FIXME: More checks, like DHCP packet type?
288 sizeof_dst = sizeof(dst);
290 #ifndef WITH_UDPFROMTO
292 * This should never fail...
294 getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst);
297 fr_sockaddr2ipaddr(&dst, sizeof_dst, &packet->dst_ipaddr, &port);
298 packet->dst_port = port;
300 fr_sockaddr2ipaddr(&src, sizeof_src, &packet->src_ipaddr, &port);
301 packet->src_port = port;
303 if (fr_debug_flag > 1) {
305 const char *name = type_buf;
306 char src_ip_buf[256], dst_ip_buf[256];
308 if ((packet->code >= PW_DHCP_DISCOVER) &&
309 (packet->code <= PW_DHCP_INFORM)) {
310 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
312 snprintf(type_buf, sizeof(type_buf), "%d",
313 packet->code - PW_DHCP_OFFSET);
316 printf("Received %s of id %08x from %s:%d to %s:%d\n",
317 name, (unsigned int) packet->id,
318 inet_ntop(packet->src_ipaddr.af,
319 &packet->src_ipaddr.ipaddr,
320 src_ip_buf, sizeof(src_ip_buf)),
322 inet_ntop(packet->dst_ipaddr.af,
323 &packet->dst_ipaddr.ipaddr,
324 dst_ip_buf, sizeof(dst_ip_buf)),
334 * Send a DHCP packet.
336 int fr_dhcp_send(RADIUS_PACKET *packet)
338 struct sockaddr_storage dst;
339 socklen_t sizeof_dst;
340 #ifdef WITH_UDPFROMTO
341 struct sockaddr_storage src;
342 socklen_t sizeof_src;
345 fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
348 #ifndef WITH_UDPFROMTO
350 * Assume that the packet is encoded before sending it.
352 return sendto(packet->sockfd, packet->data, packet->data_len, 0,
353 (struct sockaddr *)&dst, sizeof_dst);
355 fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
358 return sendfromto(packet->sockfd,
359 packet->data, packet->data_len, 0,
360 (struct sockaddr *)&src, sizeof_src,
361 (struct sockaddr *)&dst, sizeof_dst);
366 int fr_dhcp_decode(RADIUS_PACKET *packet)
372 VALUE_PAIR *head, *vp, **tail;
373 VALUE_PAIR *maxms, *mtu;
380 if ((fr_debug_flag > 2) && fr_log_fp) {
381 for (i = 0; i < packet->data_len; i++) {
382 if ((i & 0x0f) == 0x00) fprintf(stderr, "%d: ", i);
383 fprintf(fr_log_fp, "%02x ", packet->data[i]);
384 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
386 fprintf(fr_log_fp, "\n");
389 if (packet->data[1] != 1) {
390 fprintf(stderr, "Packet is not Ethernet: %u\n",
398 for (i = 0; i < 14; i++) {
399 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
401 fprintf(stderr, "Parse error %s\n", fr_strerror());
408 (packet->data[1] == 1) &&
409 (packet->data[2] == 6)) {
410 vp->type = PW_TYPE_ETHERNET;
415 vp->vp_integer = p[0];
420 vp->vp_integer = (p[0] << 8) | p[1];
424 case PW_TYPE_INTEGER:
425 memcpy(&vp->vp_integer, p, 4);
426 vp->vp_integer = ntohl(vp->vp_integer);
431 memcpy(&vp->vp_ipaddr, p, 4);
436 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
437 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
438 vp->length = strlen(vp->vp_strvalue);
439 if (vp->length == 0) {
445 memcpy(vp->vp_octets, p, packet->data[2]);
446 vp->length = packet->data[2];
449 case PW_TYPE_ETHERNET:
450 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
451 vp->length = sizeof(vp->vp_ether);
455 fprintf(stderr, "BAD TYPE %d\n", vp->type);
459 p += dhcp_header_sizes[i];
463 if (fr_debug_flag > 1) {
464 vp_prints(buffer, sizeof(buffer), vp);
465 fprintf(stderr, "\t%s\n", buffer);
472 * Loop over the options.
474 p = packet->data + 240;
475 total = packet->data_len - 240;
478 int num_entries, alen;
482 if (*p == 255) break; /* end of options signifier */
485 fprintf(stderr, "Attribute too long %u %u\n",
490 da = dict_attrbyvalue(DHCP2ATTR(p[0]));
492 fprintf(stderr, "Attribute not in our dictionary: %u\n",
507 if (da->flags.array) {
515 if ((alen & 0x01) != 0) goto raw;
516 num_entries = alen / 2;
521 case PW_TYPE_INTEGER:
523 if ((alen & 0x03) != 0) goto raw;
524 num_entries = alen / 4;
529 break; /* really an internal sanity failure */
536 if (alen != 1) goto raw;
540 if (alen != 2) goto raw;
544 case PW_TYPE_INTEGER:
546 if (alen != 4) goto raw;
554 for (i = 0; i < num_entries; i++) {
555 vp = pairmake(da->name, NULL, T_OP_EQ);
557 fprintf(stderr, "Cannot build attribute %s\n",
564 * Hacks for ease of use.
566 if ((da->attr == DHCP2ATTR(0x3d)) &&
568 (alen == 7) && (*p == 1) && (num_entries == 1)) {
569 vp->type = PW_TYPE_ETHERNET;
570 memcpy(vp->vp_octets, p + 1, 6);
575 vp->vp_integer = p[0];
579 vp->vp_integer = (p[0] << 8) | p[1];
582 case PW_TYPE_INTEGER:
583 memcpy(&vp->vp_integer, p, 4);
584 vp->vp_integer = ntohl(vp->vp_integer);
588 memcpy(&vp->vp_ipaddr, p , 4);
593 memcpy(vp->vp_strvalue, p , alen);
594 vp->vp_strvalue[alen] = '\0';
598 vp = pairmake(da->name, NULL, T_OP_EQ);
600 fprintf(stderr, "Cannot build attribute %s\n", fr_strerror());
605 vp->type = PW_TYPE_OCTETS;
608 memcpy(vp->vp_octets, p, alen);
612 fprintf(stderr, "Internal sanity check %d %d\n", vp->type, __LINE__);
615 } /* switch over type */
619 if (fr_debug_flag > 1) {
620 vp_prints(buffer, sizeof(buffer), vp);
621 fprintf(stderr, "\t%s\n", buffer);
627 } /* loop over array entries */
630 total -= (alen * num_entries);
634 * If DHCP request, set ciaddr to zero.
638 * Set broadcast flag for broken vendors, but only if
641 memcpy(&giaddr, packet->data + 24, sizeof(giaddr));
642 if (giaddr == htonl(INADDR_ANY)) {
644 * DHCP Opcode is request
646 vp = pairfind(head, DHCP2ATTR(256));
647 if (vp && vp->lvalue == 3) {
649 * Vendor is "MSFT 98"
651 vp = pairfind(head, DHCP2ATTR(63));
652 if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
653 vp = pairfind(head, DHCP2ATTR(262));
656 * Reply should be broadcast.
658 if (vp) vp->lvalue |= 0x8000;
659 packet->data[10] |= 0x80;
665 * FIXME: Nuke attributes that aren't used in the normal
666 * header for discover/requests.
671 * Client can request a LARGER size, but not a smaller
672 * one. They also cannot request a size larger than MTU.
674 maxms = pairfind(packet->vps, DHCP2ATTR(57));
675 mtu = pairfind(packet->vps, DHCP2ATTR(26));
677 if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
678 fprintf(stderr, "DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");
682 if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) {
683 fprintf(stderr, "DHCP WARNING: Client says maximum message size is smaller than minimum permitted by the specification: fixing it");
684 maxms->vp_integer = DEFAULT_PACKET_SIZE;
687 if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) {
688 fprintf(stderr, "DHCP WARNING: Client says MTU is smaller than maximum message size: fixing it");
689 maxms->vp_integer = mtu->vp_integer;
692 if (fr_debug_flag) fflush(stdout);
698 static int attr_cmp(const void *one, const void *two)
700 const VALUE_PAIR * const *a = one;
701 const VALUE_PAIR * const *b = two;
704 * DHCP-Message-Type is first, for simplicity.
706 if (((*a)->attribute == DHCP2ATTR(53)) &&
707 (*b)->attribute != DHCP2ATTR(53)) return -1;
710 * Relay-Agent is last
712 if (((*a)->attribute == DHCP2ATTR(82)) &&
713 (*b)->attribute != DHCP2ATTR(82)) return +1;
715 return ((*a)->attribute - (*b)->attribute);
719 static size_t fr_dhcp_vp2attr(VALUE_PAIR *vp, uint8_t *p, size_t room)
727 room = room; /* -Wunused */
730 * Search for all attributes of the same
731 * type, and pack them into the same
737 *p = vp->vp_integer & 0xff;
742 p[0] = (vp->vp_integer >> 8) & 0xff;
743 p[1] = vp->vp_integer & 0xff;
746 case PW_TYPE_INTEGER:
748 lvalue = htonl(vp->vp_integer);
749 memcpy(p, &lvalue, 4);
754 memcpy(p, &vp->vp_ipaddr, 4);
757 case PW_TYPE_ETHERNET:
759 memcpy(p, &vp->vp_ether, 6);
763 memcpy(p, vp->vp_strvalue, vp->length);
768 memcpy(p, vp->vp_octets, vp->length);
773 fprintf(stderr, "BAD TYPE2 %d\n", vp->type);
781 int fr_dhcp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original)
786 uint32_t lvalue, mms;
787 size_t dhcp_size, length;
791 if (packet->data) return 0;
793 packet->data = malloc(MAX_PACKET_SIZE);
794 if (!packet->data) return -1;
796 packet->data_len = MAX_PACKET_SIZE;
798 if (packet->code == 0) packet->code = PW_DHCP_NAK;
801 * FIXME: allow it to send client packets.
804 fr_strerror_printf("Need original to send response!");
808 packet->dst_ipaddr.af = AF_INET;
809 packet->src_ipaddr.af = AF_INET;
811 packet->dst_port = original->src_port;
812 packet->src_port = original->dst_port;
815 * Note that for DHCP, we NEVER send the response to the
816 * source IP address of the request. It may have
817 * traversed multiple relays, and we need to send the request
818 * to the relay closest to the client.
820 * if giaddr, send to giaddr.
821 * if NAK, send broadcast packet
822 * if ciaddr, unicast to ciaddr
823 * if flags & 0x8000, broadcast (client request)
824 * if sent from 0.0.0.0, broadcast response
825 * unicast to client yiaddr
829 * FIXME: alignment issues. We likely don't want to
830 * de-reference the packet structure directly..
832 dhcp = (dhcp_packet_t *) original->data;
834 if (dhcp->giaddr != htonl(INADDR_ANY)) {
835 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->giaddr;
837 if (dhcp->giaddr != htonl(INADDR_LOOPBACK)) {
838 packet->dst_port = original->dst_port;
840 packet->dst_port = original->src_port; /* debugging */
843 } else if (packet->code == PW_DHCP_NAK) {
844 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
846 } else if (dhcp->ciaddr != htonl(INADDR_ANY)) {
847 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->ciaddr;
849 } else if ((dhcp->flags & 0x8000) != 0) {
850 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
852 } else if (packet->dst_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_ANY)) {
853 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
856 packet->dst_ipaddr.ipaddr.ip4addr.s_addr = dhcp->yiaddr;
860 * Rewrite the source IP to be our own, if we know it.
862 if (packet->src_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_BROADCAST)) {
863 packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_ANY);
866 if (fr_debug_flag > 1) {
868 const char *name = type_buf;
869 char src_ip_buf[256], dst_ip_buf[256];
871 if ((packet->code >= PW_DHCP_DISCOVER) &&
872 (packet->code <= PW_DHCP_INFORM)) {
873 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
875 snprintf(type_buf, sizeof(type_buf), "%d",
876 packet->code - PW_DHCP_OFFSET);
879 printf("Sending %s of id %08x from %s:%d to %s:%d\n",
880 name, (unsigned int) packet->id,
881 inet_ntop(packet->src_ipaddr.af,
882 &packet->src_ipaddr.ipaddr,
883 src_ip_buf, sizeof(src_ip_buf)),
885 inet_ntop(packet->dst_ipaddr.af,
886 &packet->dst_ipaddr.ipaddr,
887 dst_ip_buf, sizeof(dst_ip_buf)),
894 mms = DEFAULT_PACKET_SIZE; /* maximum message size */
897 * Client can request a LARGER size, but not a smaller
898 * one. They also cannot request a size larger than MTU.
900 vp = pairfind(original->vps, DHCP2ATTR(57));
901 if (vp && (vp->vp_integer > mms)) {
902 mms = vp->vp_integer;
904 if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
908 * RFC 3118: Authentication option.
910 vp = pairfind(packet->vps, DHCP2ATTR(90));
912 if (vp->length < 2) {
913 memset(vp->vp_octets + vp->length, 0,
918 if (vp->length < 3) {
921 gettimeofday(&tv, NULL);
922 vp->vp_octets[2] = 0;
923 timeval2ntp(&tv, vp->vp_octets + 3);
928 * Configuration token (clear-text token)
930 if (vp->vp_octets[0] == 0) {
932 vp->vp_octets[1] = 0;
934 pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD);
936 length = pass->length;
937 if ((length + 11) > sizeof(vp->vp_octets)) {
938 length -= ((length + 11) - sizeof(vp->vp_octets));
940 memcpy(vp->vp_octets + 11, pass->vp_strvalue,
942 vp->length = length + 11;
945 memset(vp->vp_octets + 11, 8, 0);
948 } else { /* we don't support this type! */
949 fprintf(stderr, "DHCP-Authentication %d unsupported\n",
955 *p++ = 1; /* client message */
957 *p++ = 2; /* server message */
959 *p++ = 1; /* hardware type = ethernet */
960 *p++ = original->data[2];
963 if (!original) { /* Xid */
965 memcpy(p, &lvalue, 4);
967 memcpy(p, original->data + 4, 4);
971 memset(p, 0, 2); /* secs are zero */
974 memcpy(p, original->data + 10, 6); /* copy flags && ciaddr */
977 * Allow the admin to set the broadcast flag.
979 vp = pairfind(packet->vps, DHCP2ATTR(262));
981 p[0] |= (vp->vp_integer & 0xff00) >> 8;
982 p[1] |= (vp->vp_integer & 0xff);
988 * Set client IP address.
990 vp = pairfind(packet->vps, DHCP2ATTR(264)); /* Your IP address */
992 lvalue = vp->vp_ipaddr;
994 lvalue = htonl(INADDR_ANY);
996 memcpy(p, &lvalue, 4); /* your IP address */
999 memset(p, 0, 4); /* siaddr is zero */
1002 memcpy(p, original->data + 24, 4); /* copy gateway IP address */
1005 memcpy(p, original->data + 28, DHCP_CHADDR_LEN);
1006 p += DHCP_CHADDR_LEN;
1008 memset(p, 0, 192); /* bootp legacy */
1011 lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER); /* DHCP magic number */
1012 memcpy(p, &lvalue, 4);
1018 if (fr_debug_flag > 1) {
1023 for (i = 0; i < 14; i++) {
1024 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
1026 fprintf(stderr, "Parse error %s\n", fr_strerror());
1032 vp->vp_integer = p[0];
1037 vp->vp_integer = (p[0] << 8) | p[1];
1041 case PW_TYPE_INTEGER:
1042 memcpy(&vp->vp_integer, p, 4);
1043 vp->vp_integer = ntohl(vp->vp_integer);
1047 case PW_TYPE_IPADDR:
1048 memcpy(&vp->vp_ipaddr, p, 4);
1052 case PW_TYPE_STRING:
1053 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
1054 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
1055 vp->length = strlen(vp->vp_strvalue);
1058 case PW_TYPE_OCTETS: /* only for Client HW Address */
1059 memcpy(vp->vp_octets, p, packet->data[2]);
1060 vp->length = packet->data[2];
1063 case PW_TYPE_ETHERNET: /* only for Client HW Address */
1064 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
1065 vp->length = sizeof(vp->vp_ether);
1069 fprintf(stderr, "Internal sanity check failed %d %d\n", vp->type, __LINE__);
1074 p += dhcp_header_sizes[i];
1076 vp_prints(buffer, sizeof(buffer), vp);
1077 fprintf(stderr, "\t%s\n", buffer);
1082 * Jump over DHCP magic number, response, etc.
1088 * Before packing the attributes, re-order them so that
1089 * the array ones are all contiguous. This simplifies
1093 for (vp = packet->vps; vp != NULL; vp = vp->next) {
1097 VALUE_PAIR **array, **last;
1099 array = malloc(num_vps * sizeof(VALUE_PAIR *));
1102 for (vp = packet->vps; vp != NULL; vp = vp->next) {
1107 * Sort the attributes.
1109 qsort(array, (size_t) num_vps, sizeof(VALUE_PAIR *),
1112 last = &packet->vps;
1113 for (i = 0; i < num_vps; i++) {
1115 array[i]->next = NULL;
1116 last = &(array[i]->next);
1121 p[0] = 0x35; /* DHCP-Message-Type */
1123 p[2] = packet->code - PW_DHCP_OFFSET;
1127 * Pack in the attributes.
1131 int num_entries = 1;
1134 uint8_t *plength, *pattr;
1136 if (!IS_DHCP_ATTR(vp)) goto next;
1137 if (vp->attribute == DHCP2ATTR(53)) goto next; /* already done */
1138 if (((vp->attribute & 0xffff) > 255) &&
1139 (DHCP_BASE_ATTR(vp->attribute) != PW_DHCP_OPTION_82)) goto next;
1141 length = vp->length;
1143 for (same = vp->next; same != NULL; same = same->next) {
1144 if (same->attribute != vp->attribute) break;
1149 * For client-identifier
1151 if ((vp->type == PW_TYPE_ETHERNET) &&
1152 (vp->length == 6) &&
1153 (num_entries == 1)) {
1154 vp->type = PW_TYPE_OCTETS;
1155 memmove(vp->vp_octets + 1, vp->vp_octets, 6);
1156 vp->vp_octets[0] = 1;
1160 *(p++) = vp->attribute & 0xff;
1162 *(p++) = 0; /* header isn't included in attr length */
1164 if (DHCP_BASE_ATTR(vp->attribute) == PW_DHCP_OPTION_82) {
1165 *(p++) = DHCP_UNPACK_OPTION1(vp->attribute);
1170 for (i = 0; i < num_entries; i++) {
1171 if (fr_debug_flag > 1) {
1172 vp_prints(buffer, sizeof(buffer), vp);
1173 fprintf(stderr, "\t%s\n", buffer);
1176 length = fr_dhcp_vp2attr(vp, p, 0);
1179 * This will never happen due to FreeRADIUS
1180 * limitations: sizeof(vp->vp_octets) < 255
1183 fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);
1188 * More than one attribute of the same type
1189 * in a row: they are packed together
1190 * into the same TLV. If we overflow,
1193 if ((*plength + length) > 255) {
1194 fprintf(stderr, "WARNING Ignoring too long attribute %s!\n", vp->name);
1202 (vp->next->attribute == vp->attribute))
1204 } /* loop over num_entries */
1206 if (DHCP_BASE_ATTR(vp->attribute) == PW_DHCP_OPTION_82) {
1207 plength[2] = plength[0] - 2;
1214 p[0] = 0xff; /* end of option option */
1217 dhcp_size = p - packet->data;
1220 * FIXME: if (dhcp_size > mms),
1221 * then we put the extra options into the "sname" and "file"
1222 * fields, AND set the "end option option" in the "options"
1223 * field. We also set the "overload option",
1224 * and put options into the "file" field, followed by
1225 * the "sname" field. Where each option is completely
1226 * enclosed in the "file" and/or "sname" field, AND
1227 * followed by the "end of option", and MUST be followed
1228 * by padding option.
1230 * Yuck. That sucks...
1232 packet->data_len = dhcp_size;
1235 * FIXME: This may set it to broadcast, which we don't
1236 * want. Instead, set it to the real address of the
1239 packet->src_ipaddr = original->dst_ipaddr;
1241 packet->sockfd = original->sockfd;
1243 if (packet->data_len < DEFAULT_PACKET_SIZE) {
1244 memset(packet->data + packet->data_len, 0,
1245 DEFAULT_PACKET_SIZE - packet->data_len);
1246 packet->data_len = DEFAULT_PACKET_SIZE;
1249 if ((fr_debug_flag > 2) && fr_log_fp) {
1250 for (i = 0; i < packet->data_len; i++) {
1251 if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", i);
1252 fprintf(fr_log_fp, "%02x ", packet->data[i]);
1253 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
1255 fprintf(fr_log_fp, "\n");
1260 #endif /* WITH_DHCP */