24 RCSID(
"$Id: 8a0e7fc9879c6f8fef0e2c2340d41930588e503b $")
26 #include <freeradius-devel/libradius.h>
27 #include <freeradius-devel/udpfromto.h>
28 #include <freeradius-devel/dhcp.h>
29 #include <freeradius-devel/net.h>
30 #include <freeradius-devel/pcap.h>
33 # include <sys/ioctl.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 # include <sys/socket.h>
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
43 #ifdef HAVE_LINUX_IF_PACKET_H
44 # include <linux/if_packet.h>
45 # include <linux/if_ether.h>
49 # include <net/if_arp.h>
52 #define DHCP_CHADDR_LEN (16)
53 #define DHCP_SNAME_LEN (64)
54 #define DHCP_FILE_LEN (128)
55 #define DHCP_VEND_LEN (308)
56 #define DHCP_OPTION_MAGIC_NUMBER (0x63825363)
58 #ifndef INADDR_BROADCAST
59 # define INADDR_BROADCAST INADDR_NONE
63 # define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log
65 #if defined(HAVE_PCAP_H) || defined(HAVE_LINUX_IF_PACKET_H)
66 # define ETH_TYPE_IP 0x0800
67 # define IP_HDR_SIZE 20
68 # define UDP_HDR_SIZE 8
69 # define ETH_ADDR_LEN 6
72 #ifdef HAVE_LINUX_IF_PACKET_H
73 # define ETH_HDR_SIZE 14
74 static uint8_t eth_bcast[ETH_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
77 # define DISCARD_RP(...) { \
78 if (fr_debug_lvl > 2) { \
79 fprintf(stdout, "dhcpclient: discarding received packet: "); \
80 fprintf(stdout, ## __VA_ARGS__); \
81 fprintf(stdout, "\n"); \
83 fr_radius_free(&packet); \
89 uint16_t src_port,
fr_ipaddr_t dst_ipaddr, uint16_t dst_port);
123 "DHCP-Hardware-Type",
124 "DHCP-Hardware-Address-Length",
126 "DHCP-Transaction-Id",
127 "DHCP-Number-of-Seconds",
129 "DHCP-Client-IP-Address",
130 "DHCP-Your-IP-Address",
131 "DHCP-Server-IP-Address",
132 "DHCP-Gateway-IP-Address",
133 "DHCP-Client-Hardware-Address",
134 "DHCP-Server-Host-Name",
135 "DHCP-Boot-Filename",
152 "DHCP-Lease-Unassigned",
153 "DHCP-Lease-Unknown",
155 "DHCP-Bulk-Lease-Query",
156 "DHCP-Lease-Query-Done"
159 #define DHCP_MAX_MESSAGE_TYPE (sizeof(dhcp_message_types) / sizeof(dhcp_message_types[0]))
174 #define MIN_PACKET_SIZE (244)
175 #define DEFAULT_PACKET_SIZE (300)
176 #define MAX_PACKET_SIZE (1500 - 40)
178 #define DHCP_OPTION_FIELD (0)
179 #define DHCP_FILE_FIELD (1)
180 #define DHCP_SNAME_FIELD (2)
191 data = &packet->
options[where];
193 while (where < size) {
199 if (data[0] == 255) {
204 size =
sizeof(packet->
file);
208 }
else if ((field == DHCP_FILE_FIELD) &&
210 data = packet->
sname;
212 size =
sizeof(packet->
sname);
223 if ((where + 2) > size) {
225 (
unsigned int) (data - (uint8_t
const *) packet));
229 if ((where + 2 + data[1]) > size) {
231 (
unsigned int) (data - (uint8_t
const *) packet));
235 if (data[0] == option)
return data;
241 where += data[1] + 2;
257 struct sockaddr_storage src;
258 struct sockaddr_storage dst;
259 socklen_t sizeof_src;
260 socklen_t sizeof_dst;
265 uint16_t src_port, dst_port;
275 sizeof_src =
sizeof(src);
276 #ifdef WITH_UDPFROMTO
277 sizeof_dst =
sizeof(dst);
279 (
struct sockaddr *)&src, &sizeof_src,
280 (
struct sockaddr *)&dst, &sizeof_dst, &if_index, &when);
283 (
struct sockaddr *)&src, &sizeof_src);
292 if (!
fr_assert(data_len <= (ssize_t)talloc_array_length(data))) {
296 sizeof_dst =
sizeof(dst);
298 #ifndef WITH_UDPFROMTO
302 if (getsockname(sockfd, (
struct sockaddr *) &dst, &sizeof_dst) < 0) {
312 packet =
fr_dhcp_packet_ok(data, data_len, src_ipaddr, src_port, dst_ipaddr, dst_port);
314 talloc_steal(packet, data);
339 uint16_t src_port,
fr_ipaddr_t dst_ipaddr, uint16_t dst_port)
357 fr_strerror_printf(
"DHCP can only process ethernet requests, not type %02x", data[1]);
361 if ((data[2] != 0) && (data[2] != 6)) {
366 memcpy(&magic, data + 236, 4);
367 magic = ntohl(magic);
376 memcpy(&magic, data + 4, 4);
377 pkt_id = ntohl(magic);
419 memcpy(packet->
vector, data + 28, data[2]);
420 packet->
vector[data[2]] = packet->
code & 0xff;
448 uint16_t src_port, dst_port;
449 struct pcap_pkthdr *header;
450 ssize_t link_len, len;
462 ret = pcap_next_ex(pcap->handle, &header, &data);
464 DEBUG(
"DHCP: No packet received");
468 fr_strerror_printf(
"Error requesting next packet, got (%i): %s", ret, pcap_geterr(pcap->handle));
483 version = (p[0] & 0xf0) >> 4;
487 len = (0x0f & ip->ip_vhl) * 4;
492 DEBUG(
"DHCP: IPv6 not supported");
496 DEBUG(
"DHCP: IP version invalid %i", version);
501 if (ip->ip_p != IPPROTO_UDP) {
502 DEBUG(
"DHCP: IP protocol (%d) != UDP", ip->ip_p);
509 len = (p -
data) + UDP_HDR_SIZE;
510 if ((
size_t) len > header->caplen) {
511 DEBUG(
"DHCP: Payload (%d) smaller than required for layers 2+3+4", (
int)len);
522 }
else if (ret > 0) {
530 data_len = ntohs(udp->len);
532 dst_port = ntohs(udp->dst);
533 src_port = ntohs(udp->src);
535 src_ipaddr.
af = AF_INET;
536 src_ipaddr.
ipaddr.ip4addr = ip->ip_src;
539 dst_ipaddr.
af = AF_INET;
540 dst_ipaddr.
ipaddr.ip4addr = ip->ip_dst;
544 packet =
fr_dhcp_packet_ok(p, data_len, src_ipaddr, src_port, dst_ipaddr, dst_port);
546 packet->
data = talloc_memdup(packet, p, packet->
data_len);
564 struct sockaddr_storage dst;
565 socklen_t sizeof_dst;
566 #ifdef WITH_UDPFROMTO
567 struct sockaddr_storage src;
568 socklen_t sizeof_src;
581 #ifndef WITH_UDPFROMTO
585 ret = sendto(packet->
sockfd, packet->
data, packet->
data_len, 0, (
struct sockaddr *)&dst, sizeof_dst);
588 ret = sendfromto(packet->
sockfd, packet->
data, packet->
data_len, 0, (
struct sockaddr *)&src, sizeof_src,
589 (
struct sockaddr *)&dst, sizeof_dst, packet->
if_index);
606 int fr_dhcp_send_pcap(fr_pcap_t *pcap, uint8_t *dst_ether_addr,
RADIUS_PACKET *packet)
609 uint8_t dhcp_packet[1518] = { 0 };
615 uint8_t *end = dhcp_packet;
620 memcpy(eth_hdr->ether_dst, dst_ether_addr, ETH_ADDR_LEN);
621 memcpy(eth_hdr->ether_src, pcap->ether_addr, ETH_ADDR_LEN);
622 eth_hdr->ether_type = htons(ETH_TYPE_IP);
623 end += ETH_ADDR_LEN + ETH_ADDR_LEN +
sizeof(eth_hdr->ether_type);
627 ip_hdr->ip_vhl =
IP_VHL(4, 5);
629 ip_hdr->ip_len = htons(IP_HDR_SIZE + UDP_HDR_SIZE + packet->
data_len);
646 udp_hdr->src = htons(packet->
src_port);
647 udp_hdr->dst = htons(packet->
dst_port);
648 l4_len = (UDP_HDR_SIZE + packet->
data_len);
649 udp_hdr->len = htons(l4_len);
650 udp_hdr->checksum = 0;
659 udp_hdr->checksum =
fr_udp_checksum((uint8_t
const *)udp_hdr, ntohs(udp_hdr->len), udp_hdr->checksum,
663 ret = pcap_inject(pcap->handle, dhcp_packet, (end - dhcp_packet + packet->
data_len));
665 fr_strerror_printf(
"DHCP: Error sending packet with pcap: %d, %s", ret, pcap_geterr(pcap->handle));
674 uint8_t
const *data,
size_t data_len);
677 fr_dict_attr_t const *parent, uint8_t
const *data,
size_t data_len);
698 num_entries = len >> 1;
705 num_entries = len >> 2;
710 num_entries = len >> 4;
725 uint8_t
const *data,
size_t data_len)
728 uint8_t
const *p =
data;
730 FR_PROTO_TRACE(
"%s called to parse %zu bytes", __FUNCTION__, data_len);
747 if (data_len != 1)
goto raw;
753 if (data_len != 2)
goto raw;
754 memcpy(&vp->vp_short, p, 2);
755 vp->vp_short = ntohs(vp->vp_short);
760 if (data_len != 4)
goto raw;
761 memcpy(&vp->vp_integer, p, 4);
762 vp->vp_integer = ntohl(vp->vp_integer);
767 if (data_len != 4)
goto raw;
771 memcpy(&vp->vp_ipaddr, p, 4);
777 if (data_len != 16)
goto raw;
781 memcpy(&vp->vp_ipaddr, p, 16);
792 uint8_t
const *q, *end;
794 q = end = data + data_len;
806 q = memchr(p,
'\0', q - p);
828 memcpy(vp->vp_ether, data,
sizeof(vp->vp_ether));
829 vp->vp_length =
sizeof(vp->vp_ether);
830 p +=
sizeof(vp->vp_ether);
842 if (data_len > UINT8_MAX)
return -1;
853 FR_PROTO_TRACE(
"decoding value complete, adding new pair and returning %zu byte(s)", p - data);
896 uint8_t
const *data,
size_t data_len)
898 uint8_t
const *p =
data;
899 uint8_t
const *end = data + data_len;
902 if (data_len < 3)
return -1;
904 FR_PROTO_TRACE(
"%s called to parse %zu byte(s)", __FUNCTION__, data_len);
934 __FUNCTION__, (end - p));
938 if (p[1] > (end - p)) {
939 fr_strerror_printf(
"%s: Suboption would overflow option. Remaining option data %zu byte(s) "
940 "(from %zu), Suboption length %u", __FUNCTION__, (end - p), data_len, p[1]);
954 if (!unknown_child)
return -1;
955 child = unknown_child;
961 tlv_len =
decode_value(ctx, cursor, child, p + 2, p[1]);
967 FR_PROTO_TRACE(
"decode_value returned %zu, adding 2 (for header)", tlv_len);
970 FR_PROTO_TRACE(
"tlv parsing complete, returning %zu byte(s)", p - data);
976 fr_dict_attr_t const *parent, uint8_t
const *data,
size_t data_len)
978 unsigned int values, i;
979 uint8_t
const *p =
data;
983 FR_PROTO_TRACE(
"%s called to parse %zu byte(s)", __FUNCTION__, data_len);
996 FR_PROTO_TRACE(
"found %u coalesced values (%zu bytes each)", values, value_len);
998 if ((values * value_len) != data_len) {
1000 "length (probably trailing garbage)");
1009 for (i = 0, p = data; i < values; i++) {
1011 if (len <= 0)
return len;
1012 if (len != (ssize_t)value_len) {
1032 fr_dict_attr_t const *parent, uint8_t
const *data,
size_t data_len,
1033 UNUSED void *decoder_ctx)
1036 uint8_t
const *p =
data;
1039 FR_PROTO_TRACE(
"%s called to parse %zu byte(s)", __FUNCTION__, data_len);
1041 if (data_len == 0)
return 0;
1063 if (p[0] == 0)
return 1;
1066 fr_strerror_printf(
"%s: Got end of options signifier, but more data to parse", __FUNCTION__);
1075 if ((data_len < 2) || (data[1] > data_len)) {
1087 if (!child)
return -1;
1093 ret =
decode_value(ctx, cursor, child, data + 2, data[1]);
1099 FR_PROTO_TRACE(
"decoding option complete, returning %zu byte(s)", ret);
1115 if (packet->
data[1] > 1) {
1124 for (i = 0; i < 14; i++) {
1144 if ((packet->
data[1] == 0) || (packet->
data[2] == 0))
continue;
1146 if ((packet->
data[1] == 1) && (packet->
data[2] !=
sizeof(vp->vp_ether))) {
1150 vp->da->
vendor, vp->da->attr);
1158 switch (vp->da->type) {
1165 vp->vp_short = (p[0] << 8) | p[1];
1170 memcpy(&vp->vp_integer, p, 4);
1171 vp->vp_integer = ntohl(vp->vp_integer);
1176 memcpy(&vp->vp_ipaddr, p, 4);
1181 q = talloc_array(vp,
char, dhcp_header_sizes[i] + 1);
1182 memcpy(q, p, dhcp_header_sizes[i]);
1183 q[dhcp_header_sizes[i]] =
'\0';
1190 if (packet->
data[2] == 0)
break;
1196 memcpy(vp->vp_ether, p,
sizeof(vp->vp_ether));
1197 vp->vp_length =
sizeof(vp->vp_ether);
1205 p += dhcp_header_sizes[i];
1224 p = packet->
data + 240;
1225 end = p + (packet->
data_len - 240);
1236 p, ((end - p) > UINT8_MAX) ? UINT8_MAX : (end - p), NULL);
1254 memcpy(&giaddr, packet->
data + 24,
sizeof(giaddr));
1255 if (giaddr == htonl(INADDR_ANY)) {
1260 if (vp && vp->vp_integer == 3) {
1265 if (vp && (strcmp(vp->vp_strvalue,
"MSFT 98") == 0)) {
1271 if (vp) vp->vp_short |= 0x8000;
1272 packet->
data[10] |= 0x80;
1291 fr_strerror_printf(
"Client says MTU is smaller than minimum permitted by the specification");
1304 if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) maxms->vp_integer = mtu->vp_integer;
1360 switch (tlv_stack[depth]->type) {
1367 p[0] = (vp->vp_short >> 8) & 0xff;
1368 p[1] = vp->vp_short & 0xff;
1373 lvalue = htonl(vp->vp_integer);
1374 memcpy(p, &lvalue, 4);
1379 memcpy(p, &vp->vp_ipaddr, 4);
1384 memcpy(p, &vp->vp_ipv6addr, 16);
1389 memcpy(p, vp->vp_ether, 6);
1394 memcpy(p, vp->vp_strvalue, vp->vp_length);
1399 memcpy(p, vp->vp_octets, vp->vp_length);
1439 if (outlen < 3)
return 0;
1446 out[0] = da->
attr & 0xff;
1455 if (outlen > UINT8_MAX) outlen = UINT8_MAX;
1467 len =
encode_value(p, outlen - out[1], tlv_stack, depth, cursor);
1468 if (len < 0)
return len;
1481 FR_PROTO_TRACE(
"%zu byte(s) available in option", outlen - out[1]);
1484 if (!next || (vp->
da != next->
da))
break;
1511 if (outlen < 5)
return 0;
1518 out[0] = da->
attr & 0xff;
1527 if (outlen > UINT8_MAX) outlen = UINT8_MAX;
1532 while (outlen >= 3) {
1537 len =
encode_tlv_hdr(p, outlen - out[1], tlv_stack, depth + 1, cursor);
1539 len =
encode_rfc_hdr(p, outlen - out[1], tlv_stack, depth + 1, cursor);
1541 if (len < 0)
return len;
1542 if (len == 0)
break;
1560 if (da != tlv_stack[depth])
break;
1581 unsigned int depth = 0;
1611 switch (tlv_stack[depth]->type) {
1621 if (len < 0)
return len;
1639 if (packet->
data)
return 0;
1642 packet->
data = talloc_zero_array(packet, uint8_t, packet->
data_len);
1649 packet->
id = vp->vp_integer;
1670 if (vp && (vp->vp_integer > mms)) {
1671 mms = vp->vp_integer;
1679 *p++ = vp->vp_integer & 0xff;
1705 lvalue = htonl(packet->
id);
1706 memcpy(p, &lvalue, 4);
1711 svalue = htons(vp->vp_short);
1712 memcpy(p, &svalue, 2);
1718 svalue = htons(vp->vp_short);
1719 memcpy(p, &svalue, 2);
1725 memcpy(p, &vp->vp_ipaddr, 4);
1731 lvalue = vp->vp_ipaddr;
1733 lvalue = htonl(INADDR_ANY);
1735 memcpy(p, &lvalue, 4);
1741 lvalue = vp->vp_ipaddr;
1743 lvalue = htonl(INADDR_ANY);
1745 memcpy(p, &lvalue, 4);
1752 lvalue = vp->vp_ipaddr;
1754 lvalue = htonl(INADDR_ANY);
1756 memcpy(p, &lvalue, 4);
1761 if (vp->vp_length ==
sizeof(vp->vp_ether)) {
1766 packet->
data[1] = 1;
1767 packet->
data[2] = 6;
1769 memcpy(p, vp->vp_ether, vp->vp_length);
1779 memcpy(p, vp->vp_strvalue, vp->vp_length);
1800 memcpy(p, vp->vp_strvalue, vp->vp_length);
1807 memcpy(p, &lvalue, 4);
1835 dhcp_size = p - packet->
data;
1865 struct sockaddr_in *sin;
1880 if (macaddr->vp_length >
sizeof(req.arp_ha.sa_data)) {
1881 fr_strerror_printf(
"arp sa_data field too small (%zu octets) to contain chaddr (%zu octets)",
1882 sizeof(req.arp_ha.sa_data), macaddr->vp_length);
1886 memset(&req, 0,
sizeof(req));
1887 sin = (
struct sockaddr_in *) &req.arp_pa;
1888 sin->sin_family = AF_INET;
1889 sin->sin_addr.s_addr = ip->vp_ipaddr;
1891 strlcpy(req.arp_dev, interface,
sizeof(req.arp_dev));
1894 memcpy(&req.arp_ha.sa_data, macaddr->vp_ether,
sizeof(macaddr->vp_ether));
1896 memcpy(&req.arp_ha.sa_data, macaddr->vp_octets, macaddr->vp_length);
1899 req.arp_flags = ATF_COM;
1900 if (ioctl(fd, SIOCSARP, &req) < 0) {
1917 #ifdef HAVE_LINUX_IF_PACKET_H
1922 int fr_socket_packet(
int if_index,
struct sockaddr_ll *link_layer)
1930 lsock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
1937 memset(link_layer, 0,
sizeof(
struct sockaddr_ll));
1939 link_layer->sll_family = AF_PACKET;
1940 link_layer->sll_protocol = htons(ETH_P_ALL);
1941 link_layer->sll_ifindex = if_index;
1942 link_layer->sll_hatype = ARPHRD_ETHER;
1943 link_layer->sll_pkttype = PACKET_OTHERHOST;
1944 link_layer->sll_halen = 6;
1946 if (bind(lsock_fd, (
struct sockaddr *)link_layer,
sizeof(
struct sockaddr_ll)) < 0) {
1958 int fr_dhcp_send_raw_packet(
int sockfd,
struct sockaddr_ll *link_layer,
RADIUS_PACKET *packet)
1960 uint8_t dhcp_packet[1518] = { 0 };
1966 uint16_t l4_len = (UDP_HDR_SIZE + packet->
data_len);
1970 uint8_t dhmac[ETH_ADDR_LEN] = { 0 };
1972 if (vp->vp_length ==
sizeof(vp->vp_ether)) memcpy(dhmac, vp->vp_ether, vp->vp_length);
1976 memcpy(eth_hdr->ether_dst, eth_bcast, ETH_ADDR_LEN);
1977 memcpy(eth_hdr->ether_src, dhmac, ETH_ADDR_LEN);
1978 eth_hdr->ether_type = htons(ETH_TYPE_IP);
1981 ip_hdr->ip_vhl =
IP_VHL(4, 5);
1983 ip_hdr->ip_len = htons(IP_HDR_SIZE + UDP_HDR_SIZE + packet->
data_len);
1986 ip_hdr->ip_ttl = 64;
1999 udp_hdr->src = htons(packet->
src_port);
2000 udp_hdr->dst = htons(packet->
dst_port);
2002 udp_hdr->len = htons(l4_len);
2003 udp_hdr->checksum = 0;
2011 udp_hdr->checksum =
fr_udp_checksum((uint8_t
const *)(dhcp_packet + ETH_HDR_SIZE + IP_HDR_SIZE),
2012 ntohs(udp_hdr->len), udp_hdr->checksum,
2015 return sendto(sockfd, dhcp_packet, (ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE + packet->
data_len),
2016 0, (
struct sockaddr *) link_layer,
sizeof(
struct sockaddr_ll));
2022 static char *ether_addr_print(
const uint8_t *addr,
char *buf)
2024 sprintf(buf,
"%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
2038 uint8_t
const *code;
2039 uint32_t magic, xid;
2042 uint8_t *raw_packet;
2047 uint16_t udp_src_port;
2048 uint16_t udp_dst_port;
2049 size_t dhcp_data_len;
2068 sock_len =
sizeof(
struct sockaddr_ll);
2069 data_len = recvfrom(sockfd, raw_packet,
MAX_PACKET_SIZE, 0, (
struct sockaddr *)link_layer, &sock_len);
2071 uint8_t data_offset = ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE;
2073 if (data_len <= data_offset) DISCARD_RP(
"Payload (%d) smaller than required for layers 2+3+4", (
int)data_len);
2081 if (ntohs(eth_hdr->ether_type) != ETH_TYPE_IP) DISCARD_RP(
"Ethernet type (%d) != IP",
2082 ntohs(eth_hdr->ether_type));
2088 if ((memcmp(ð_bcast, ð_hdr->ether_dst, ETH_ADDR_LEN) != 0) &&
2090 (vp->vp_length ==
sizeof(vp->vp_ether)) && (memcmp(vp->vp_ether, ð_hdr->ether_dst, ETH_ADDR_LEN) != 0)) {
2091 char eth_dest[17 + 1];
2092 char eth_req_src[17 + 1];
2095 DISCARD_RP(
"Ethernet destination (%s) is not broadcast and doesn't match request source (%s)",
2096 ether_addr_print(eth_hdr->ether_dst, eth_dest),
2097 ether_addr_print(vp->vp_ether, eth_req_src));
2103 ip_hdr = (
ip_header_t *)(raw_packet + ETH_HDR_SIZE);
2108 if (ip_hdr->ip_p != IPPROTO_UDP) DISCARD_RP(
"IP protocol (%d) != UDP", ip_hdr->ip_p);
2119 udp_hdr = (
udp_header_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE);
2124 udp_src_port = ntohs(udp_hdr->src);
2125 udp_dst_port = ntohs(udp_hdr->dst);
2130 dhcp_data_len = data_len - data_offset;
2132 if (dhcp_data_len <
MIN_PACKET_SIZE) DISCARD_RP(
"DHCP packet is too small (%zu < %i)",
2134 if (dhcp_data_len >
MAX_PACKET_SIZE) DISCARD_RP(
"DHCP packet is too large (%zu > %i)",
2137 dhcp_hdr = (
dhcp_packet_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE);
2139 if (dhcp_hdr->
htype != 1) DISCARD_RP(
"DHCP hardware type (%d) != Ethernet (1)", dhcp_hdr->
htype);
2140 if (dhcp_hdr->
hlen != 6) DISCARD_RP(
"DHCP hardware address length (%d) != 6", dhcp_hdr->
hlen);
2150 xid = ntohl(dhcp_hdr->
xid);
2151 if (xid != (uint32_t)request->
id) DISCARD_RP(
"DHCP transaction ID (0x%04x) != xid from request (0x%04x)",
2155 packet->data_len = dhcp_data_len;
2156 packet->data = talloc_memdup(packet, raw_packet + data_offset, dhcp_data_len);
2157 TALLOC_FREE(raw_packet);
2167 if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
int fr_dhcp_send_socket(RADIUS_PACKET *packet)
Send DHCP packet using socket.
int sockfd
Socket this packet was read from.
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
ssize_t fr_dhcp_encode_option(uint8_t *out, size_t outlen, vp_cursor_t *cursor, UNUSED void *encoder_ctx)
Encode a DHCP option and any sub-options.
fr_dict_attr_t * fr_dict_unknown_afrom_fields(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor, unsigned int attr) CC_HINT(nonnull)
Allocates an unknown attribute.
int id
Packet ID (used to link requests/responses).
struct timeval timestamp
When we received the packet.
#define DHCP_MAX_MESSAGE_TYPE
uint8_t options[DHCP_VEND_LEN]
uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum, struct in_addr const src_addr, struct in_addr const dst_addr)
Calculate UDP checksum.
unsigned int array
Pack multiples into 1 attr.
#define PW_DHCP_OPTION_82
int fr_ipaddr_from_sockaddr(struct sockaddr_storage const *sa, socklen_t salen, fr_ipaddr_t *ipaddr, uint16_t *port)
uint32_t fr_rand(void)
Return a 32-bit random number.
fr_ipaddr_t src_ipaddr
Src IP address of packet.
static uint8_t const * dhcp_get_option(dhcp_packet_t const *packet, size_t packet_size, unsigned int option)
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
ssize_t fr_link_layer_offset(uint8_t const *data, size_t len, int link_layer)
Returns the length of the link layer header.
int fr_dhcp_add_arp_entry(UNUSED int fd, UNUSED char const *interface, UNUSED VALUE_PAIR *macaddr, UNUSED VALUE_PAIR *ip)
int fr_dhcp_decode(RADIUS_PACKET *packet)
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define DHCP_OPTION_MAGIC_NUMBER
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
uint8_t * data
Packet data (body).
uint16_t dst_port
DST Port of packet.
static RADIUS_PACKET * fr_dhcp_packet_ok(uint8_t const *data, ssize_t data_len, fr_ipaddr_t src_ipaddr, uint16_t src_port, fr_ipaddr_t dst_ipaddr, uint16_t dst_port)
Check reveived DHCP request is valid and build RADIUS_PACKET structure if it is.
uint16_t src_port
Src port of packet.
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
fr_dict_attr_flags_t flags
Flags.
uint8_t file[DHCP_FILE_LEN]
RADIUS_PACKET * fr_dhcp_recv_socket(int sockfd)
Receive DHCP packet using socket.
uint8_t sname[DHCP_SNAME_LEN]
uint8_t chaddr[DHCP_CHADDR_LEN]
void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src)
Reparent an allocated char buffer to a VALUE_PAIR.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
unsigned int is_unknown
Attribute number or vendor is unknown.
static ssize_t encode_rfc_hdr(uint8_t *out, ssize_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor)
Write out an RFC option header and option data.
void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp)
Merges multiple VALUE_PAIR into the cursor.
ssize_t fr_dhcp_decode_option(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, UNUSED void *decoder_ctx)
Decode DHCP option.
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
static int fr_dhcp_array_members(size_t *out, size_t len, fr_dict_attr_t const *da)
Returns the number of array members for arrays with fixed element sizes.
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
unsigned int attr
Attribute number.
union fr_ipaddr_t::@1 ipaddr
unsigned int code
Packet code (type).
#define FR_PROTO_TRACE(_x,...)
#define DHCP_OPTION_FIELD
unsigned int vendor
Vendor that defines this attribute.
int fr_dhcp_encode(RADIUS_PACKET *packet)
Stores an attribute, a value and various bits of other data.
VALUE_PAIR * fr_cursor_current(vp_cursor_t *cursor)
Return the VALUE_PAIR the cursor current points to.
#define DHCP_BASE_ATTR(x)
struct dhcp_option_t dhcp_option_t
static ssize_t decode_value_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *da, uint8_t const *data, size_t data_len)
int fr_udp_header_check(uint8_t const *data, uint16_t remaining, ip_header_t const *ip)
Check UDP header is valid.
static int dhcp_header_sizes[]
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
char const * fr_strerror(void)
Get the last library error.
#define FR_PROTO_HEX_DUMP(_x, _y, _z)
#define FR_PROTO_STACK_PRINT(_x, _y)
int if_index
Index of receiving interface.
static ssize_t decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len)
RFC 4243 Vendor Specific Suboptions.
char name[1]
Attribute name.
uint32_t zone_id
A host may have multiple link-local interfaces the scope ID allows the application to specify which o...
static ssize_t encode_tlv_hdr(uint8_t *out, ssize_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor)
Write out a TLV header (and any sub TLVs or values)
void fr_pair_list_sort(VALUE_PAIR **vps, fr_cmp_t cmp)
Sort a linked list of VALUE_PAIRs using merge sort.
int fr_pair_to_unknown(VALUE_PAIR *vp)
Mark malformed or unrecognised attributed as unknown.
uint16_t fr_ip_header_checksum(uint8_t const *data, uint8_t ihl)
Calculate IP header checksum.
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
static ssize_t encode_value(uint8_t *out, size_t outlen, fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor)
Write DHCP option value into buffer.
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
char const * dhcp_header_names[]
int8_t fr_dhcp_attr_cmp(void const *a, void const *b)
size_t data_len
Length of packet data.
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
#define DHCP_MAGIC_VENDOR
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
#define DEFAULT_PACKET_SIZE
size_t strlcpy(char *dst, char const *src, size_t siz)
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
String of printable characters.
Contains nested attributes.
void fr_proto_tlv_stack_build(fr_dict_attr_t const **tlv_stack, fr_dict_attr_t const *da)
#define PW_DHCP_MESSAGE_TYPE
fr_dict_t * fr_dict_internal
Internal server dictionary.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
VALUE_PAIR * fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op)
Create a VALUE_PAIR from ASCII strings.
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
int fr_ipaddr_to_sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port, struct sockaddr_storage *sa, socklen_t *salen)
static ssize_t decode_value(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len)
struct dhcp_packet_t dhcp_packet_t
char const * dhcp_message_types[]