29 #include <freeradius-devel/util/net.h>
30 #include <freeradius-devel/util/pair.h>
31 #include <freeradius-devel/util/proto.h>
32 #include <freeradius-devel/util/syserror.h>
33 #include <freeradius-devel/util/udpfromto.h>
35 #include <sys/ioctl.h>
37 #ifdef HAVE_SYS_SOCKET_H
39 #ifdef HAVE_SYS_TYPES_H
42 #ifdef HAVE_LINUX_IF_PACKET_H
43 # include <linux/if_ether.h>
46 #include <net/if_arp.h>
48 #ifdef HAVE_LINUX_IF_PACKET_H
58 int fr_dhcpv4_raw_socket_open(
struct sockaddr_ll *link_layer,
int ifindex)
66 fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
73 memset(link_layer, 0,
sizeof(
struct sockaddr_ll));
75 link_layer->sll_family = AF_PACKET;
76 link_layer->sll_protocol = htons(ETH_P_ALL);
77 link_layer->sll_ifindex = ifindex;
78 link_layer->sll_hatype = ARPHRD_ETHER;
79 link_layer->sll_pkttype = PACKET_OTHERHOST;
80 link_layer->sll_halen = 6;
82 if (bind(fd, (
struct sockaddr *)link_layer,
sizeof(
struct sockaddr_ll)) < 0) {
101 int fr_dhcpv4_raw_packet_send(
int sockfd,
struct sockaddr_ll *link_layer,
104 uint8_t dhcp_packet[1518] = { 0 };
127 ip_hdr->
ip_len = htons(IP_HDR_SIZE + UDP_HDR_SIZE + packet->
data_len);
135 ip_hdr->ip_src.s_addr = packet->
socket.inet.src_ipaddr.addr.v4.s_addr;
138 ip_hdr->
ip_dst.s_addr = packet->
socket.inet.dst_ipaddr.addr.v4.s_addr;
143 udp_hdr->
src = htons(packet->
socket.inet.src_port);
144 udp_hdr->
dst = htons(packet->
socket.inet.dst_port);
146 udp_hdr->
len = htons(l4_len);
157 packet->
socket.inet.src_ipaddr.addr.v4, packet->
socket.inet.dst_ipaddr.addr.v4);
159 return sendto(
sockfd, dhcp_packet, (ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE + packet->
data_len),
160 0, (
struct sockaddr *) link_layer,
sizeof(
struct sockaddr_ll));
169 fr_packet_t *fr_dhcpv4_raw_packet_recv(
int sockfd,
struct sockaddr_ll *link_layer,
186 size_t dhcp_data_len;
206 sock_len =
sizeof(
struct sockaddr_ll);
207 data_len = recvfrom(
sockfd, raw_packet,
MAX_PACKET_SIZE, 0, (
struct sockaddr *)link_layer, &sock_len);
209 data_offset = ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE;
211 if (data_len <= data_offset) DISCARD_RP(
"Payload (%d) smaller than required for layers 2+3+4", (
int)data_len);
219 if (ntohs(eth_hdr->
ether_type) != ETH_TYPE_IP) DISCARD_RP(
"Ethernet type (%d) != IP",
231 DISCARD_RP(
"Ethernet destination (%pV) is not broadcast and doesn't match request source (%pV)",
238 ip_hdr = (
ip_header_t *)(raw_packet + ETH_HDR_SIZE);
243 if (ip_hdr->
ip_p != IPPROTO_UDP) DISCARD_RP(
"IP protocol (%d) != UDP", ip_hdr->
ip_p);
254 udp_hdr = (
udp_header_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE);
259 udp_src_port = ntohs(udp_hdr->
src);
260 udp_dst_port = ntohs(udp_hdr->
dst);
265 dhcp_data_len = data_len - data_offset;
267 if (dhcp_data_len <
MIN_PACKET_SIZE) DISCARD_RP(
"DHCP packet is too small (%zu < %i)",
269 if (dhcp_data_len >
MAX_PACKET_SIZE) DISCARD_RP(
"DHCP packet is too large (%zu > %i)",
272 dhcp_hdr = (
dhcp_packet_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE);
274 if (dhcp_hdr->
htype != 1) DISCARD_RP(
"DHCP hardware type (%d) != Ethernet (1)", dhcp_hdr->
htype);
275 if (dhcp_hdr->
hlen != 6) DISCARD_RP(
"DHCP hardware address length (%d) != 6", dhcp_hdr->
hlen);
285 xid = ntohl(dhcp_hdr->
xid);
286 if (xid != (
uint32_t)request->
id) DISCARD_RP(
"DHCP transaction ID (0x%04x) != xid from request (0x%04x)",
298 packet->data_len = dhcp_data_len;
299 dhcp_data = talloc_memdup(packet, raw_packet + data_offset, dhcp_data_len);
301 TALLOC_FREE(raw_packet);
312 if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
318 packet->
code = code[2];
320 packet->
socket.inet.src_port = udp_src_port;
321 packet->
socket.inet.dst_port = udp_dst_port;
323 packet->
socket.inet.src_ipaddr.
af = AF_INET;
324 packet->
socket.inet.src_ipaddr.addr.v4.s_addr = ip_hdr->ip_src.s_addr;
325 packet->
socket.inet.dst_ipaddr.
af = AF_INET;
326 packet->
socket.inet.dst_ipaddr.addr.v4.s_addr = ip_hdr->
ip_dst.s_addr;
static fr_dict_attr_t const * attr_dhcp_message_type
Implementation of the DHCPv4 protocol.
#define DHCP_OPTION_MAGIC_NUMBER
uint8_t const * fr_dhcpv4_packet_get_option(dhcp_packet_t const *packet, size_t packet_size, fr_dict_attr_t const *da)
Retrieve a DHCP option from a raw packet buffer.
uint8_t dst_addr[ETHER_ADDR_LEN]
uint8_t src_addr[ETHER_ADDR_LEN]
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
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.
uint16_t fr_ip_header_checksum(uint8_t const *data, uint8_t ihl)
Calculate IP header checksum.
uint8_t ip_tos
Type of service.
uint16_t ip_len
Total length.
uint16_t ip_id
identification.
uint8_t ip_ttl
Time To Live.
uint16_t ip_off
Fragment offset field.
uint16_t dst
Destination port.
uint16_t checksum
UDP checksum.
struct in_addr ip_src ip_dst
Src and Dst address.
uint8_t ip_vhl
Header length, version.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
HIDDEN fr_dict_attr_t const * attr_dhcp_client_hardware_address
uint8_t eth_bcast[ETH_ADDR_LEN]
Stores an attribute, a value and various bits of other data.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
unsigned int code
Packet code (type).
fr_socket_t socket
This packet was received on.
int id
Packet ID (used to link requests/responses).
uint8_t * data
Packet data (body).
size_t data_len
Length of packet data.
int af
AF_INET, AF_INET6, or AF_UNIX.
int fd
File descriptor if this is a live socket.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
#define fr_box_ether(_val)