2 * dhcp.c Functions to send/receive dhcp packets.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; 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>
33 #include <sys/ioctl.h>
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
42 #include <net/if_arp.h>
45 #define DHCP_CHADDR_LEN (16)
46 #define DHCP_SNAME_LEN (64)
47 #define DHCP_FILE_LEN (128)
48 #define DHCP_VEND_LEN (308)
49 #define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
51 #ifndef INADDR_BROADCAST
52 #define INADDR_BROADCAST INADDR_NONE
55 typedef struct dhcp_packet_t {
61 uint16_t secs; /* 8 */
63 uint32_t ciaddr; /* 12 */
64 uint32_t yiaddr; /* 16 */
65 uint32_t siaddr; /* 20 */
66 uint32_t giaddr; /* 24 */
67 uint8_t chaddr[DHCP_CHADDR_LEN]; /* 28 */
68 uint8_t sname[DHCP_SNAME_LEN]; /* 44 */
69 uint8_t file[DHCP_FILE_LEN]; /* 108 */
70 uint32_t option_format; /* 236 */
71 uint8_t options[DHCP_VEND_LEN];
74 typedef struct dhcp_option_t {
80 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
81 * INADDR_BROADCAST : 68 <- SERVER_IP : 67 OFFER
82 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
83 * INADDR_BROADCAST : 68 <- SERVER_IP : 67 ACK
85 static const char *dhcp_header_names[] = {
88 "DHCP-Hardware-Address-Length",
90 "DHCP-Transaction-Id",
91 "DHCP-Number-of-Seconds",
93 "DHCP-Client-IP-Address",
94 "DHCP-Your-IP-Address",
95 "DHCP-Server-IP-Address",
96 "DHCP-Gateway-IP-Address",
97 "DHCP-Client-Hardware-Address",
98 "DHCP-Server-Host-Name",
104 static const char *dhcp_message_types[] = {
117 static int dhcp_header_sizes[] = {
128 * Some clients silently ignore responses less than 300 bytes.
130 #define MIN_PACKET_SIZE (244)
131 #define DEFAULT_PACKET_SIZE (300)
132 #define MAX_PACKET_SIZE (1500 - 40)
134 #define DHCP_OPTION_FIELD (0)
135 #define DHCP_FILE_FIELD (1)
136 #define DHCP_SNAME_FIELD (2)
138 static uint8_t *dhcp_get_option(dhcp_packet_t *packet, size_t packet_size,
142 int field = DHCP_OPTION_FIELD;
147 size = packet_size - offsetof(dhcp_packet_t, options);
148 data = &packet->options[where];
150 while (where < size) {
151 if (data[0] == 0) { /* padding */
156 if (data[0] == 255) { /* end of options */
157 if ((field == DHCP_OPTION_FIELD) &&
158 (overload & DHCP_FILE_FIELD)) {
161 size = sizeof(packet->file);
162 field = DHCP_FILE_FIELD;
165 } else if ((field == DHCP_FILE_FIELD) &&
166 (overload & DHCP_SNAME_FIELD)) {
167 data = packet->sname;
169 size = sizeof(packet->sname);
170 field = DHCP_SNAME_FIELD;
178 * We MUST have a real option here.
180 if ((where + 2) > size) {
181 fr_strerror_printf("Options overflow field at %u",
182 (unsigned int) (data - (uint8_t *) packet));
186 if ((where + 2 + data[1]) > size) {
187 fr_strerror_printf("Option length overflows field at %u",
188 (unsigned int) (data - (uint8_t *) packet));
192 if (data[0] == option) return data;
194 if (data[0] == 52) { /* overload sname and/or file */
198 where += data[1] + 2;
206 * DHCPv4 is only for IPv4. Broadcast only works if udpfromto is
209 RADIUS_PACKET *fr_dhcp_recv(int sockfd)
212 struct sockaddr_storage src;
213 struct sockaddr_storage dst;
214 socklen_t sizeof_src;
215 socklen_t sizeof_dst;
216 RADIUS_PACKET *packet;
221 packet = rad_alloc(0);
223 fr_strerror_printf("Failed allocating packet");
226 memset(packet, 0, sizeof(*packet));
228 packet->data = malloc(MAX_PACKET_SIZE);
230 fr_strerror_printf("Failed in malloc");
235 packet->sockfd = sockfd;
236 sizeof_src = sizeof(src);
237 #ifdef WITH_UDPFROMTO
238 sizeof_dst = sizeof(dst);
239 data_len = recvfromto(sockfd, packet->data, MAX_PACKET_SIZE, 0,
240 (struct sockaddr *)&src, &sizeof_src,
241 (struct sockaddr *)&dst, &sizeof_dst);
243 data_len = recvfrom(sockfd, packet->data, MAX_PACKET_SIZE, 0,
244 (struct sockaddr *)&src, &sizeof_src);
248 fr_strerror_printf("Failed reading DHCP socket: %s", strerror(errno));
253 packet->data_len = data_len;
254 if (packet->data_len < MIN_PACKET_SIZE) {
255 fr_strerror_printf("DHCP packet is too small (%d < %d)",
256 packet->data_len, MIN_PACKET_SIZE);
261 if (packet->data[1] != 1) {
262 fr_strerror_printf("DHCP can only receive ethernet requests, not type %02x",
268 if (packet->data[2] != 6) {
269 fr_strerror_printf("Ethernet HW length is wrong length %d",
275 memcpy(&magic, packet->data + 236, 4);
276 magic = ntohl(magic);
277 if (magic != DHCP_OPTION_MAGIC_NUMBER) {
278 fr_strerror_printf("Cannot do BOOTP");
284 * Create unique keys for the packet.
286 memcpy(&magic, packet->data + 4, 4);
287 packet->id = ntohl(magic);
289 code = dhcp_get_option((dhcp_packet_t *) packet->data,
290 packet->data_len, 53);
292 fr_strerror_printf("No message-type option was found in the packet");
297 if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
298 fr_strerror_printf("Unknown value for message-type option");
303 packet->code = code[2] | PW_DHCP_OFFSET;
306 * Create a unique vector from the MAC address and the
307 * DHCP opcode. This is a hack for the RADIUS
308 * infrastructure in the rest of the server.
310 * Note: packet->data[2] == 6, which is smaller than
311 * sizeof(packet->vector)
313 * FIXME: Look for client-identifier in packet,
316 memset(packet->vector, 0, sizeof(packet->vector));
317 memcpy(packet->vector, packet->data + 28, packet->data[2]);
318 packet->vector[packet->data[2]] = packet->code & 0xff;
321 * FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
322 * FIXME: for OFFER / ACK : src_port = dst_port - 1
326 * Unique keys are xid, client mac, and client ID?
330 * FIXME: More checks, like DHCP packet type?
333 sizeof_dst = sizeof(dst);
335 #ifndef WITH_UDPFROMTO
337 * This should never fail...
339 if (getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst) < 0) {
340 fr_strerror_printf("getsockname failed: %s", strerror(errno));
346 fr_sockaddr2ipaddr(&dst, sizeof_dst, &packet->dst_ipaddr, &port);
347 packet->dst_port = port;
349 fr_sockaddr2ipaddr(&src, sizeof_src, &packet->src_ipaddr, &port);
350 packet->src_port = port;
352 if (fr_debug_flag > 1) {
354 const char *name = type_buf;
355 char src_ip_buf[256], dst_ip_buf[256];
357 if ((packet->code >= PW_DHCP_DISCOVER) &&
358 (packet->code <= PW_DHCP_INFORM)) {
359 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
361 snprintf(type_buf, sizeof(type_buf), "%d",
362 packet->code - PW_DHCP_OFFSET);
365 DEBUG("Received %s of id %08x from %s:%d to %s:%d\n",
366 name, (unsigned int) packet->id,
367 inet_ntop(packet->src_ipaddr.af,
368 &packet->src_ipaddr.ipaddr,
369 src_ip_buf, sizeof(src_ip_buf)),
371 inet_ntop(packet->dst_ipaddr.af,
372 &packet->dst_ipaddr.ipaddr,
373 dst_ip_buf, sizeof(dst_ip_buf)),
382 * Send a DHCP packet.
384 int fr_dhcp_send(RADIUS_PACKET *packet)
386 struct sockaddr_storage dst;
387 socklen_t sizeof_dst;
388 #ifdef WITH_UDPFROMTO
389 struct sockaddr_storage src;
390 socklen_t sizeof_src;
392 fr_ipaddr2sockaddr(&packet->src_ipaddr, packet->src_port,
396 fr_ipaddr2sockaddr(&packet->dst_ipaddr, packet->dst_port,
399 if (fr_debug_flag > 1) {
401 const char *name = type_buf;
402 #ifdef WITH_UDPFROMTO
403 char src_ip_buf[256];
405 char dst_ip_buf[256];
407 if ((packet->code >= PW_DHCP_DISCOVER) &&
408 (packet->code <= PW_DHCP_INFORM)) {
409 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
411 snprintf(type_buf, sizeof(type_buf), "%d",
412 packet->code - PW_DHCP_OFFSET);
416 #ifdef WITH_UDPFROMTO
417 "Sending %s of id %08x from %s:%d to %s:%d\n",
419 "Sending %s of id %08x to %s:%d\n",
421 name, (unsigned int) packet->id,
422 #ifdef WITH_UDPFROMTO
423 inet_ntop(packet->src_ipaddr.af,
424 &packet->src_ipaddr.ipaddr,
425 src_ip_buf, sizeof(src_ip_buf)),
428 inet_ntop(packet->dst_ipaddr.af,
429 &packet->dst_ipaddr.ipaddr,
430 dst_ip_buf, sizeof(dst_ip_buf)),
434 #ifndef WITH_UDPFROMTO
436 * Assume that the packet is encoded before sending it.
438 return sendto(packet->sockfd, packet->data, packet->data_len, 0,
439 (struct sockaddr *)&dst, sizeof_dst);
442 return sendfromto(packet->sockfd, packet->data, packet->data_len, 0,
443 (struct sockaddr *)&src, sizeof_src,
444 (struct sockaddr *)&dst, sizeof_dst);
448 static int fr_dhcp_attr2vp(VALUE_PAIR *vp, const uint8_t *p, size_t alen);
450 static int decode_tlv(VALUE_PAIR *tlv, const uint8_t *data, size_t data_len)
453 VALUE_PAIR *head, **tail, *vp;
456 * Take a pass at parsing it.
459 while (p < (data + data_len)) {
460 if ((p + 2) > (data + data_len)) goto make_tlv;
462 if ((p + p[1] + 2) > (data + data_len)) goto make_tlv;
467 * Got here... must be well formed.
473 while (p < (data + data_len)) {
474 vp = paircreate(tlv->attribute | (p[0] << 8), PW_TYPE_OCTETS);
480 if (fr_dhcp_attr2vp(vp, p + 2, p[1]) < 0) {
487 while (*tail) tail = &((*tail)->next);
492 * The caller allocated TLV, so we need to copy the FIRST
493 * attribute over top of that.
496 memcpy(tlv, head, sizeof(*tlv));
498 if (head->type == PW_TYPE_TLV) head->vp_tlv = NULL;
505 if (data_len > sizeof(tlv->vp_octets)) data_len = sizeof(tlv->vp_octets);
506 memcpy(tlv->vp_octets, data, data_len);
507 tlv->length = data_len;
508 tlv->type = PW_TYPE_OCTETS;
515 * Decode ONE value into a VP
517 static int fr_dhcp_attr2vp(VALUE_PAIR *vp, const uint8_t *p, size_t alen)
521 if (alen != 1) goto raw;
522 vp->vp_integer = p[0];
526 if (alen != 2) goto raw;
527 memcpy(&vp->vp_integer, p, 2);
528 vp->vp_integer = ntohs(vp->vp_integer);
531 case PW_TYPE_INTEGER:
532 if (alen != 4) goto raw;
533 memcpy(&vp->vp_integer, p, 4);
534 vp->vp_integer = ntohl(vp->vp_integer);
538 if (alen != 4) goto raw;
540 * Keep value in Network Order!
542 memcpy(&vp->vp_ipaddr, p , 4);
547 if (alen > 253) return -1;
548 memcpy(vp->vp_strvalue, p , alen);
549 vp->vp_strvalue[alen] = '\0';
553 vp->type = PW_TYPE_OCTETS;
556 if (alen > 253) return -1;
557 memcpy(vp->vp_octets, p, alen);
561 return decode_tlv(vp, p, alen);
564 fr_strerror_printf("Internal sanity check %d %d", vp->type, __LINE__);
566 } /* switch over type */
572 ssize_t fr_dhcp_decode_options(uint8_t *data, size_t len, VALUE_PAIR **head)
575 VALUE_PAIR *vp, **tail;
581 while (next < (data + len)) {
582 int num_entries, alen;
587 if (*p == 0) { /* 0x00 - Padding option */
591 if (*p == 255) break; /* 0xff - End of options signifier */
592 if ((p + 2) > (data + len)) break;
597 fr_strerror_printf("Attribute too long %u %u",
602 da = dict_attrbyvalue(DHCP2ATTR(p[0]));
604 fr_strerror_printf("Attribute not in our dictionary: %u",
615 * Could be an array of bytes, integers, etc.
617 if (da->flags.array) {
624 case PW_TYPE_SHORT: /* ignore any trailing data */
625 num_entries = alen >> 1;
630 case PW_TYPE_INTEGER:
631 case PW_TYPE_DATE: /* ignore any trailing data */
632 num_entries = alen >> 2;
638 break; /* really an internal sanity failure */
643 * Loop over all of the entries, building VPs
645 for (i = 0; i < num_entries; i++) {
646 vp = pairmake(da->name, NULL, T_OP_ADD);
648 fr_strerror_printf("Cannot build attribute %s",
655 * Hack for ease of use.
657 if ((da->attr == DHCP2ATTR(0x3d)) &&
659 (alen == 7) && (*p == 1) && (num_entries == 1)) {
660 vp->type = PW_TYPE_ETHERNET;
661 memcpy(vp->vp_octets, p + 1, 6);
664 } else if (fr_dhcp_attr2vp(vp, p, alen) < 0) {
673 tail = &(*tail)->next;
676 } /* loop over array entries */
677 } /* loop over the entire packet */
682 int fr_dhcp_decode(RADIUS_PACKET *packet)
687 VALUE_PAIR *head, *vp, **tail;
688 VALUE_PAIR *maxms, *mtu;
694 if ((fr_debug_flag > 2) && fr_log_fp) {
695 for (i = 0; i < packet->data_len; i++) {
696 if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", (int) i);
697 fprintf(fr_log_fp, "%02x ", packet->data[i]);
698 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
700 fprintf(fr_log_fp, "\n");
703 if (packet->data[1] != 1) {
704 fr_strerror_printf("Packet is not Ethernet: %u",
712 for (i = 0; i < 14; i++) {
713 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
716 strlcpy(buffer, fr_strerror(), sizeof(buffer));
717 fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
723 (packet->data[1] == 1) &&
724 (packet->data[2] == 6)) {
725 vp->type = PW_TYPE_ETHERNET;
730 vp->vp_integer = p[0];
735 vp->vp_integer = (p[0] << 8) | p[1];
739 case PW_TYPE_INTEGER:
740 memcpy(&vp->vp_integer, p, 4);
741 vp->vp_integer = ntohl(vp->vp_integer);
746 memcpy(&vp->vp_ipaddr, p, 4);
751 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
752 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
753 vp->length = strlen(vp->vp_strvalue);
754 if (vp->length == 0) {
760 memcpy(vp->vp_octets, p, packet->data[2]);
761 vp->length = packet->data[2];
764 case PW_TYPE_ETHERNET:
765 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
766 vp->length = sizeof(vp->vp_ether);
770 fr_strerror_printf("BAD TYPE %d", vp->type);
774 p += dhcp_header_sizes[i];
784 * Loop over the options.
788 * Nothing uses tail after this call, if it does in the future
789 * it'll need to find the new tail...
790 * FIXME: This should also check sname && file fields.
791 * See the dhcp_get_option() function above.
793 if (fr_dhcp_decode_options(packet->data + 240, packet->data_len - 240,
799 * If DHCP request, set ciaddr to zero.
803 * Set broadcast flag for broken vendors, but only if
806 memcpy(&giaddr, packet->data + 24, sizeof(giaddr));
807 if (giaddr == htonl(INADDR_ANY)) {
809 * DHCP Opcode is request
811 vp = pairfind(head, DHCP2ATTR(256));
812 if (vp && vp->lvalue == 3) {
814 * Vendor is "MSFT 98"
816 vp = pairfind(head, DHCP2ATTR(63));
817 if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
818 vp = pairfind(head, DHCP2ATTR(262));
821 * Reply should be broadcast.
823 if (vp) vp->lvalue |= 0x8000;
824 packet->data[10] |= 0x80;
830 * FIXME: Nuke attributes that aren't used in the normal
831 * header for discover/requests.
836 * Client can request a LARGER size, but not a smaller
837 * one. They also cannot request a size larger than MTU.
839 maxms = pairfind(packet->vps, DHCP2ATTR(57));
840 mtu = pairfind(packet->vps, DHCP2ATTR(26));
842 if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
843 fr_strerror_printf("DHCP Fatal: Client says MTU is smaller than minimum permitted by the specification.");
847 if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) {
848 fr_strerror_printf("DHCP WARNING: Client says maximum message size is smaller than minimum permitted by the specification: fixing it");
849 maxms->vp_integer = DEFAULT_PACKET_SIZE;
852 if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) {
853 fr_strerror_printf("DHCP WARNING: Client says MTU is smaller than maximum message size: fixing it");
854 maxms->vp_integer = mtu->vp_integer;
857 if (fr_debug_flag > 0) {
858 for (vp = packet->vps; vp != NULL; vp = vp->next) {
863 if (fr_debug_flag) fflush(stdout);
869 static int attr_cmp(const void *one, const void *two)
871 const VALUE_PAIR * const *a = one;
872 const VALUE_PAIR * const *b = two;
875 * DHCP-Message-Type is first, for simplicity.
877 if (((*a)->attribute == DHCP2ATTR(53)) &&
878 (*b)->attribute != DHCP2ATTR(53)) return -1;
881 * Relay-Agent is last
883 if (((*a)->attribute == DHCP2ATTR(82)) &&
884 (*b)->attribute != DHCP2ATTR(82)) return +1;
886 return ((*a)->attribute - (*b)->attribute);
890 static size_t fr_dhcp_vp2attr(VALUE_PAIR *vp, uint8_t *p, size_t room)
898 room = room; /* -Wunused */
901 * Search for all attributes of the same
902 * type, and pack them into the same
908 *p = vp->vp_integer & 0xff;
913 lvalue = htons(vp->vp_integer);
914 memcpy(p, &lvalue, 2);
917 case PW_TYPE_INTEGER:
919 lvalue = htonl(vp->vp_integer);
920 memcpy(p, &lvalue, 4);
925 memcpy(p, &vp->vp_ipaddr, 4);
928 case PW_TYPE_ETHERNET:
930 memcpy(p, &vp->vp_ether, 6);
934 memcpy(p, vp->vp_strvalue, vp->length);
938 case PW_TYPE_TLV: /* FIXME: split it on 255? */
939 memcpy(p, vp->vp_tlv, vp->length);
944 memcpy(p, vp->vp_octets, vp->length);
949 fr_strerror_printf("BAD TYPE2 %d", vp->type);
957 static VALUE_PAIR *fr_dhcp_vp2suboption(VALUE_PAIR *vps)
960 unsigned int attribute;
962 VALUE_PAIR *vp, *tlv;
964 attribute = vps->attribute & 0xffff00ff;
966 tlv = paircreate(attribute, PW_TYPE_TLV);
967 if (!tlv) return NULL;
970 for (vp = vps; vp != NULL; vp = vp->next) {
972 * Group the attributes ONLY until we see a
975 if (!vp->flags.is_tlv ||
977 ((vp->attribute & 0xffff00ff) != attribute)) {
981 tlv->length += vp->length + 2;
989 tlv->vp_tlv = malloc(tlv->length);
996 for (vp = vps; vp != NULL; vp = vp->next) {
997 if (!vp->flags.is_tlv ||
999 ((vp->attribute & 0xffff00ff) != attribute)) {
1003 length = fr_dhcp_vp2attr(vp, ptr + 2,
1004 tlv->vp_tlv + tlv->length - ptr);
1011 * Pack the attribute.
1013 ptr[0] = (vp->attribute & 0xff00) >> 8;
1017 vp->flags.encoded = 1;
1023 int fr_dhcp_encode(RADIUS_PACKET *packet)
1028 uint32_t lvalue, mms;
1029 size_t dhcp_size, length;
1032 #ifdef WITH_UDPFROMTO
1033 char src_ip_buf[256];
1035 char dst_ip_buf[256];
1038 if (packet->data) free(packet->data);
1040 packet->data = malloc(MAX_PACKET_SIZE);
1041 packet->data_len = MAX_PACKET_SIZE;
1042 memset(packet->data, 0, packet->data_len);
1044 /* XXX Ugly ... should be set by the caller */
1045 if (packet->code == 0) packet->code = PW_DHCP_NAK;
1048 if ((packet->code >= PW_DHCP_DISCOVER) &&
1049 (packet->code <= PW_DHCP_INFORM)) {
1050 name = dhcp_message_types[packet->code - PW_DHCP_OFFSET];
1056 #ifdef WITH_UDPFROMTO
1057 "Encoding %s of id %08x from %s:%d to %s:%d\n",
1059 "Encoding %s of id %08x to %s:%d\n",
1061 name, (unsigned int) packet->id,
1062 #ifdef WITH_UDPFROMTO
1063 inet_ntop(packet->src_ipaddr.af,
1064 &packet->src_ipaddr.ipaddr,
1065 src_ip_buf, sizeof(src_ip_buf)),
1068 inet_ntop(packet->dst_ipaddr.af,
1069 &packet->dst_ipaddr.ipaddr,
1070 dst_ip_buf, sizeof(dst_ip_buf)),
1076 mms = DEFAULT_PACKET_SIZE; /* maximum message size */
1079 * Clients can request a LARGER size, but not a
1080 * smaller one. They also cannot request a size
1084 /* DHCP-DHCP-Maximum-Msg-Size */
1085 vp = pairfind(packet->vps, DHCP2ATTR(57));
1086 if (vp && (vp->vp_integer > mms)) {
1087 mms = vp->vp_integer;
1089 if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
1093 * RFC 3118: Authentication option.
1095 vp = pairfind(packet->vps, DHCP2ATTR(90));
1097 if (vp->length < 2) {
1098 memset(vp->vp_octets + vp->length, 0,
1103 if (vp->length < 3) {
1106 gettimeofday(&tv, NULL);
1107 vp->vp_octets[2] = 0;
1108 timeval2ntp(&tv, vp->vp_octets + 3);
1113 * Configuration token (clear-text token)
1115 if (vp->vp_octets[0] == 0) {
1117 vp->vp_octets[1] = 0;
1119 pass = pairfind(packet->vps, PW_CLEARTEXT_PASSWORD);
1121 length = pass->length;
1122 if ((length + 11) > sizeof(vp->vp_octets)) {
1123 length -= ((length + 11) - sizeof(vp->vp_octets));
1125 memcpy(vp->vp_octets + 11, pass->vp_strvalue,
1127 vp->length = length + 11;
1129 vp->length = 11 + 8;
1130 memset(vp->vp_octets + 11, 0, 8);
1131 vp->length = 11 + 8;
1133 } else { /* we don't support this type! */
1134 fr_strerror_printf("DHCP-Authentication %d unsupported",
1140 if ((vp = pairfind(packet->vps, DHCP2ATTR(256)))) {
1141 *p++ = vp->vp_integer & 0xff;
1143 *p++ = 1; /* client message */
1146 /* DHCP-Hardware-Type */
1147 if ((vp = pairfind(packet->vps, DHCP2ATTR(257)))) {
1148 *p++ = vp->vp_integer & 0xFF;
1150 *p++ = 1; /* hardware type = ethernet */
1153 /* DHCP-Hardware-Address-Length */
1154 if ((vp = pairfind(packet->vps, DHCP2ATTR(258)))) {
1155 *p++ = vp->vp_integer & 0xFF;
1157 *p++ = 6; /* 6 bytes of ethernet */
1160 /* DHCP-Hop-Count */
1161 if ((vp = pairfind(packet->vps, DHCP2ATTR(259)))) {
1162 *p = vp->vp_integer & 0xff;
1166 /* DHCP-Transaction-Id */
1167 if ((vp = pairfind(packet->vps, DHCP2ATTR(260)))) {
1168 lvalue = htonl(vp->vp_integer);
1172 memcpy(p, &lvalue, 4);
1175 /* DHCP-Number-of-Seconds */
1176 if ((vp = pairfind(packet->vps, DHCP2ATTR(261)))) {
1177 lvalue = htonl(vp->vp_integer);
1178 memcpy(p, &lvalue, 2);
1183 if ((vp = pairfind(packet->vps, DHCP2ATTR(262)))) {
1184 lvalue = htons(vp->vp_integer);
1185 memcpy(p, &lvalue, 2);
1189 /* DHCP-Client-IP-Address */
1190 if ((vp = pairfind(packet->vps, DHCP2ATTR(263)))) {
1191 memcpy(p, &vp->vp_ipaddr, 4);
1195 /* DHCP-Your-IP-address */
1196 if ((vp = pairfind(packet->vps, DHCP2ATTR(264)))) {
1197 lvalue = vp->vp_ipaddr;
1199 lvalue = htonl(INADDR_ANY);
1201 memcpy(p, &lvalue, 4);
1204 /* DHCP-Server-IP-Address */
1205 vp = pairfind(packet->vps, DHCP2ATTR(265));
1207 lvalue = vp->vp_ipaddr;
1209 lvalue = htonl(INADDR_ANY);
1211 memcpy(p, &lvalue, 4);
1215 * DHCP-Gateway-IP-Address
1217 if (vp = pairfind(packet->vps, DHCP2ATTR(266))) {
1218 lvalue = vp->vp_ipaddr;
1220 lvalue = htonl(INADDR_ANY);
1222 memcpy(p, &lvalue, 4);
1225 /* DHCP-Client-Hardware-Address */
1226 if ((vp = pairfind(packet->vps, DHCP2ATTR(267)))) {
1227 if (vp->length > DHCP_CHADDR_LEN) {
1228 memcpy(p, vp->vp_octets, DHCP_CHADDR_LEN);
1230 memcpy(p, vp->vp_octets, vp->length);
1233 p += DHCP_CHADDR_LEN;
1235 /* DHCP-Server-Host-Name */
1236 if ((vp = pairfind(packet->vps, DHCP2ATTR(268)))) {
1237 if (vp->length > DHCP_SNAME_LEN) {
1238 memcpy(p, vp->vp_strvalue, DHCP_SNAME_LEN);
1240 memcpy(p, vp->vp_strvalue, vp->length);
1243 p += DHCP_SNAME_LEN;
1246 * Copy over DHCP-Boot-Filename.
1248 * FIXME: This copy should be delayed until AFTER the options
1249 * have been processed. If there are too many options for
1250 * the packet, then they go into the sname && filename fields.
1251 * When that happens, the boot filename is passed as an option,
1252 * instead of being placed verbatim in the filename field.
1255 /* DHCP-Boot-Filename */
1256 if ((vp = pairfind(packet->vps, DHCP2ATTR(269)))) {
1257 if (vp->length > DHCP_FILE_LEN) {
1258 memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
1260 memcpy(p, vp->vp_strvalue, vp->length);
1265 /* DHCP magic number */
1266 lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER);
1267 memcpy(p, &lvalue, 4);
1273 if (fr_debug_flag > 1) {
1278 for (i = 0; i < 14; i++) {
1279 vp = pairmake(dhcp_header_names[i], NULL, T_OP_EQ);
1282 strlcpy(buffer, fr_strerror(), sizeof(buffer));
1283 fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
1289 vp->vp_integer = p[0];
1294 memcpy(&vp->vp_integer, p, 2);
1295 vp->vp_integer = ntohs(vp->vp_integer);
1299 case PW_TYPE_INTEGER:
1300 memcpy(&vp->vp_integer, p, 4);
1301 vp->vp_integer = ntohl(vp->vp_integer);
1305 case PW_TYPE_IPADDR:
1306 memcpy(&vp->vp_ipaddr, p, 4);
1310 case PW_TYPE_STRING:
1311 memcpy(vp->vp_strvalue, p, dhcp_header_sizes[i]);
1312 vp->vp_strvalue[dhcp_header_sizes[i]] = '\0';
1313 vp->length = strlen(vp->vp_strvalue);
1316 case PW_TYPE_OCTETS: /* only for Client HW Address */
1317 memcpy(vp->vp_octets, p, packet->data[2]);
1318 vp->length = packet->data[2];
1321 case PW_TYPE_ETHERNET: /* only for Client HW Address */
1322 memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
1323 vp->length = sizeof(vp->vp_ether);
1327 fr_strerror_printf("Internal sanity check failed %d %d", vp->type, __LINE__);
1332 p += dhcp_header_sizes[i];
1339 * Jump over DHCP magic number, response, etc.
1345 * Before packing the attributes, re-order them so that
1346 * the array ones are all contiguous. This simplifies
1350 for (vp = packet->vps; vp != NULL; vp = vp->next) {
1354 VALUE_PAIR **array, **last;
1356 array = malloc(num_vps * sizeof(VALUE_PAIR *));
1359 for (vp = packet->vps; vp != NULL; vp = vp->next) {
1364 * Sort the attributes.
1366 qsort(array, (size_t) num_vps, sizeof(VALUE_PAIR *),
1369 last = &packet->vps;
1370 for (i = 0; i < num_vps; i++) {
1372 array[i]->next = NULL;
1373 last = &(array[i]->next);
1378 p[0] = 0x35; /* DHCP-Message-Type */
1380 p[2] = packet->code - PW_DHCP_OFFSET;
1384 * Pack in the attributes.
1388 int num_entries = 1;
1390 uint8_t *plength, *pattr;
1392 if (!IS_DHCP_ATTR(vp)) goto next;
1394 /* DHCP-Message-Type (already done) */
1395 if (vp->attribute == DHCP2ATTR(53)) goto next;
1396 if (((vp->attribute & 0xffff) > 255) &&
1397 (DHCP_BASE_ATTR(vp->attribute) != PW_DHCP_OPTION_82)) goto next;
1400 if (vp->flags.encoded) goto next;
1402 length = vp->length;
1404 for (same = vp->next; same != NULL; same = same->next) {
1405 if (same->attribute != vp->attribute) break;
1410 * For client-identifier
1412 if ((vp->type == PW_TYPE_ETHERNET) &&
1413 (vp->length == 6) &&
1414 (num_entries == 1)) {
1415 vp->type = PW_TYPE_OCTETS;
1416 memmove(vp->vp_octets + 1, vp->vp_octets, 6);
1417 vp->vp_octets[0] = 1;
1421 *(p++) = vp->attribute & 0xff;
1423 *(p++) = 0; /* header isn't included in attr length */
1425 for (i = 0; i < num_entries; i++) {
1426 if (i != 0) debug_pair(vp);
1428 if (vp->flags.is_tlv) {
1432 * Should NOT have been encoded yet!
1434 tlv = fr_dhcp_vp2suboption(vp);
1437 * Ignore it if there's an issue
1440 if (!tlv) goto next;
1442 tlv->next = vp->next;
1447 length = fr_dhcp_vp2attr(vp, p, 0);
1450 * This will never happen due to FreeRADIUS
1451 * limitations: sizeof(vp->vp_octets) < 255
1454 fr_strerror_printf("WARNING Ignoring too long attribute %s!", vp->name);
1459 * More than one attribute of the same type
1460 * in a row: they are packed together
1461 * into the same TLV. If we overflow,
1464 if ((*plength + length) > 255) {
1465 fr_strerror_printf("WARNING Ignoring too long attribute %s!", vp->name);
1473 (vp->next->attribute == vp->attribute))
1475 } /* loop over num_entries */
1481 p[0] = 0xff; /* end of option option */
1484 dhcp_size = p - packet->data;
1487 * FIXME: if (dhcp_size > mms),
1488 * then we put the extra options into the "sname" and "file"
1489 * fields, AND set the "end option option" in the "options"
1490 * field. We also set the "overload option",
1491 * and put options into the "file" field, followed by
1492 * the "sname" field. Where each option is completely
1493 * enclosed in the "file" and/or "sname" field, AND
1494 * followed by the "end of option", and MUST be followed
1495 * by padding option.
1497 * Yuck. That sucks...
1499 packet->data_len = dhcp_size;
1501 if (packet->data_len < DEFAULT_PACKET_SIZE) {
1502 memset(packet->data + packet->data_len, 0,
1503 DEFAULT_PACKET_SIZE - packet->data_len);
1504 packet->data_len = DEFAULT_PACKET_SIZE;
1507 if ((fr_debug_flag > 2) && fr_log_fp) {
1508 for (i = 0; i < packet->data_len; i++) {
1509 if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "%d: ", i);
1510 fprintf(fr_log_fp, "%02x ", packet->data[i]);
1511 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
1513 fprintf(fr_log_fp, "\n");
1519 int fr_dhcp_add_arp_entry(int fd, const char *interface,
1520 VALUE_PAIR *macaddr, VALUE_PAIR *ip)
1523 struct sockaddr_in *sin;
1527 fr_strerror_printf("No interface specified. Cannot update ARP table");
1531 if (macaddr->length > sizeof (req.arp_ha.sa_data)) {
1532 fr_strerror_printf("ERROR: DHCP only supports up to %zu octets for "
1533 "Client Hardware Address (got %zu octets)\n",
1534 sizeof(req.arp_ha.sa_data),
1539 memset(&req, 0, sizeof(req));
1540 sin = (struct sockaddr_in *) &req.arp_pa;
1541 sin->sin_family = AF_INET;
1542 sin->sin_addr.s_addr = ip->vp_ipaddr;
1543 strlcpy(req.arp_dev, interface, sizeof(req.arp_dev));
1544 memcpy(&req.arp_ha.sa_data, macaddr->vp_octets, macaddr->length);
1546 req.arp_flags = ATF_COM;
1547 if (ioctl(fd, SIOCSARP, &req) < 0) {
1548 fr_strerror_printf("DHCP: Failed to add entry in ARP cache: %s (%d)",
1549 strerror(errno), errno);
1556 interface = interface;
1560 fr_strerror_printf("Adding ARP entry is unsupported on this system");
1565 #endif /* WITH_DHCP */