All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dhcp.c
Go to the documentation of this file.
1 /*
2  * dhcp.c Functions to send/receive dhcp packets.
3  *
4  * Version: $Id: 8a0e7fc9879c6f8fef0e2c2340d41930588e503b $
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2008 The FreeRADIUS server project
21  * Copyright 2008 Alan DeKok <aland@deployingradius.com>
22  */
23 
24 RCSID("$Id: 8a0e7fc9879c6f8fef0e2c2340d41930588e503b $")
25 
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>
31 
32 #ifndef __MINGW32__
33 # include <sys/ioctl.h>
34 #endif
35 
36 #ifdef HAVE_SYS_SOCKET_H
37 # include <sys/socket.h>
38 #endif
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42 
43 #ifdef HAVE_LINUX_IF_PACKET_H
44 # include <linux/if_packet.h>
45 # include <linux/if_ether.h>
46 #endif
47 
48 #ifndef __MINGW32__
49 # include <net/if_arp.h>
50 #endif
51 
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)
57 
58 #ifndef INADDR_BROADCAST
59 # define INADDR_BROADCAST INADDR_NONE
60 #endif
61 
62 /* @todo: this is a hack */
63 # define DEBUG if (fr_debug_lvl && fr_log_fp) fr_printf_log
64 
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
70 #endif
71 
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 };
75 
76 /* Discard raw packets which we are not interested in. Allow to trace why we discard. */
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"); \
82  } \
83  fr_radius_free(&packet); \
84  return NULL; \
85 }
86 #endif
87 
88 static RADIUS_PACKET *fr_dhcp_packet_ok(uint8_t const *data, ssize_t data_len, fr_ipaddr_t src_ipaddr,
89  uint16_t src_port, fr_ipaddr_t dst_ipaddr, uint16_t dst_port);
90 
91 typedef struct dhcp_packet_t {
92  uint8_t opcode;
93  uint8_t htype;
94  uint8_t hlen;
95  uint8_t hops;
96  uint32_t xid; /* 4 */
97  uint16_t secs; /* 8 */
98  uint16_t flags;
99  uint32_t ciaddr; /* 12 */
100  uint32_t yiaddr; /* 16 */
101  uint32_t siaddr; /* 20 */
102  uint32_t giaddr; /* 24 */
103  uint8_t chaddr[DHCP_CHADDR_LEN]; /* 28 */
104  uint8_t sname[DHCP_SNAME_LEN]; /* 44 */
105  uint8_t file[DHCP_FILE_LEN]; /* 108 */
106  uint32_t option_format; /* 236 */
108 } dhcp_packet_t;
109 
110 typedef struct dhcp_option_t {
111  uint8_t code;
112  uint8_t length;
113 } dhcp_option_t;
114 
115 /*
116  * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
117  * INADDR_BROADCAST : 68 <- SERVER_IP : 67 OFFER
118  * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
119  * INADDR_BROADCAST : 68 <- SERVER_IP : 67 ACK
120  */
121 char const *dhcp_header_names[] = {
122  "DHCP-Opcode",
123  "DHCP-Hardware-Type",
124  "DHCP-Hardware-Address-Length",
125  "DHCP-Hop-Count",
126  "DHCP-Transaction-Id",
127  "DHCP-Number-of-Seconds",
128  "DHCP-Flags",
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",
136 
137  NULL
138 };
139 
140 char const *dhcp_message_types[] = {
141  "invalid",
142  "DHCP-Discover",
143  "DHCP-Offer",
144  "DHCP-Request",
145  "DHCP-Decline",
146  "DHCP-Ack",
147  "DHCP-NAK",
148  "DHCP-Release",
149  "DHCP-Inform",
150  "DHCP-Force-Renew",
151  "DHCP-Lease-Query",
152  "DHCP-Lease-Unassigned",
153  "DHCP-Lease-Unknown",
154  "DHCP-Lease-Active",
155  "DHCP-Bulk-Lease-Query",
156  "DHCP-Lease-Query-Done"
157 };
158 
159 #define DHCP_MAX_MESSAGE_TYPE (sizeof(dhcp_message_types) / sizeof(dhcp_message_types[0]))
160 
161 static int dhcp_header_sizes[] = {
162  1, 1, 1, 1,
163  4, 2, 2, 4,
164  4, 4, 4,
168 };
169 
170 
171 /*
172  * Some clients silently ignore responses less than 300 bytes.
173  */
174 #define MIN_PACKET_SIZE (244)
175 #define DEFAULT_PACKET_SIZE (300)
176 #define MAX_PACKET_SIZE (1500 - 40)
177 
178 #define DHCP_OPTION_FIELD (0)
179 #define DHCP_FILE_FIELD (1)
180 #define DHCP_SNAME_FIELD (2)
181 
182 static uint8_t const *dhcp_get_option(dhcp_packet_t const *packet, size_t packet_size, unsigned int option)
183 {
184  int overload = 0;
185  int field = DHCP_OPTION_FIELD;
186  size_t where, size;
187  uint8_t const *data;
188 
189  where = 0;
190  size = packet_size - offsetof(dhcp_packet_t, options);
191  data = &packet->options[where];
192 
193  while (where < size) {
194  if (data[0] == 0) { /* padding */
195  where++;
196  continue;
197  }
198 
199  if (data[0] == 255) { /* end of options */
200  if ((field == DHCP_OPTION_FIELD) &&
201  (overload & DHCP_FILE_FIELD)) {
202  data = packet->file;
203  where = 0;
204  size = sizeof(packet->file);
205  field = DHCP_FILE_FIELD;
206  continue;
207 
208  } else if ((field == DHCP_FILE_FIELD) &&
209  (overload & DHCP_SNAME_FIELD)) {
210  data = packet->sname;
211  where = 0;
212  size = sizeof(packet->sname);
213  field = DHCP_SNAME_FIELD;
214  continue;
215  }
216 
217  return NULL;
218  }
219 
220  /*
221  * We MUST have a real option here.
222  */
223  if ((where + 2) > size) {
224  fr_strerror_printf("Options overflow field at %u",
225  (unsigned int) (data - (uint8_t const *) packet));
226  return NULL;
227  }
228 
229  if ((where + 2 + data[1]) > size) {
230  fr_strerror_printf("Option length overflows field at %u",
231  (unsigned int) (data - (uint8_t const *) packet));
232  return NULL;
233  }
234 
235  if (data[0] == option) return data;
236 
237  if (data[0] == 52) { /* overload sname and/or file */
238  overload = data[3];
239  }
240 
241  where += data[1] + 2;
242  data += data[1] + 2;
243  }
244 
245  return NULL;
246 }
247 
248 /** Receive DHCP packet using socket
249  *
250  * @param sockfd handle.
251  * @return
252  * - pointer to RADIUS_PACKET if successful.
253  * - NULL if failed.
254  */
256 {
257  struct sockaddr_storage src;
258  struct sockaddr_storage dst;
259  socklen_t sizeof_src;
260  socklen_t sizeof_dst;
261  RADIUS_PACKET *packet;
262  uint8_t *data;
263  ssize_t data_len;
264  fr_ipaddr_t src_ipaddr, dst_ipaddr;
265  uint16_t src_port, dst_port;
266  int if_index = 0;
267  struct timeval when;
268 
269  data = talloc_zero_array(NULL, uint8_t, MAX_PACKET_SIZE);
270  if (!data) {
271  fr_strerror_printf("Out of memory");
272  return NULL;
273  }
274 
275  sizeof_src = sizeof(src);
276 #ifdef WITH_UDPFROMTO
277  sizeof_dst = sizeof(dst);
278  data_len = recvfromto(sockfd, data, MAX_PACKET_SIZE, 0,
279  (struct sockaddr *)&src, &sizeof_src,
280  (struct sockaddr *)&dst, &sizeof_dst, &if_index, &when);
281 #else
282  data_len = recvfrom(sockfd, data, MAX_PACKET_SIZE, 0,
283  (struct sockaddr *)&src, &sizeof_src);
284 #endif
285 
286  if (data_len <= 0) {
287  fr_strerror_printf("Failed reading data from DHCP socket: %s", fr_syserror(errno));
288  talloc_free(data);
289  return NULL;
290  }
291 
292  if (!fr_assert(data_len <= (ssize_t)talloc_array_length(data))) {
293  talloc_free(data); /* Bounds check for tainted scalar (Coverity) */
294  return NULL;
295  }
296  sizeof_dst = sizeof(dst);
297 
298 #ifndef WITH_UDPFROMTO
299  /*
300  * This should never fail...
301  */
302  if (getsockname(sockfd, (struct sockaddr *) &dst, &sizeof_dst) < 0) {
303  fr_strerror_printf("getsockname failed: %s", fr_syserror(errno));
304  talloc_free(data);
305  return NULL;
306  }
307 #endif
308 
309  fr_ipaddr_from_sockaddr(&dst, sizeof_dst, &dst_ipaddr, &dst_port);
310  fr_ipaddr_from_sockaddr(&src, sizeof_src, &src_ipaddr, &src_port);
311 
312  packet = fr_dhcp_packet_ok(data, data_len, src_ipaddr, src_port, dst_ipaddr, dst_port);
313  if (packet) {
314  talloc_steal(packet, data);
315  packet->data = data;
316  packet->sockfd = sockfd;
317  packet->if_index = if_index;
318  packet->timestamp = when;
319  return packet;
320  }
321 
322  return NULL;
323 }
324 
325 /** Check reveived DHCP request is valid and build RADIUS_PACKET structure if it is
326  *
327  * @param data pointer to received packet.
328  * @param data_len length of received data.
329  * @param src_ipaddr source ip address.
330  * @param src_port source port address.
331  * @param dst_ipaddr destination ip address.
332  * @param dst_port destination port address.
333  *
334  * @return
335  * - RADIUS_PACKET pointer if valid
336  * - NULL if invalid
337  */
338 RADIUS_PACKET *fr_dhcp_packet_ok(uint8_t const *data, ssize_t data_len, fr_ipaddr_t src_ipaddr,
339  uint16_t src_port, fr_ipaddr_t dst_ipaddr, uint16_t dst_port)
340 {
341  uint32_t magic;
342  uint8_t const *code;
343  int pkt_id;
344  RADIUS_PACKET *packet;
345 
346  if (data_len < MIN_PACKET_SIZE) {
347  fr_strerror_printf("DHCP packet is too small (%zu < %d)", data_len, MIN_PACKET_SIZE);
348  return NULL;
349  }
350 
351  if (data_len > MAX_PACKET_SIZE) {
352  fr_strerror_printf("DHCP packet is too large (%zx > %d)", data_len, MAX_PACKET_SIZE);
353  return NULL;
354  }
355 
356  if (data[1] > 1) {
357  fr_strerror_printf("DHCP can only process ethernet requests, not type %02x", data[1]);
358  return NULL;
359  }
360 
361  if ((data[2] != 0) && (data[2] != 6)) {
362  fr_strerror_printf("Ethernet HW length incorrect. Expected 6 got %d", data[2]);
363  return NULL;
364  }
365 
366  memcpy(&magic, data + 236, 4);
367  magic = ntohl(magic);
368  if (magic != DHCP_OPTION_MAGIC_NUMBER) {
369  fr_strerror_printf("BOOTP not supported");
370  return NULL;
371  }
372 
373  /*
374  * Create unique keys for the packet.
375  */
376  memcpy(&magic, data + 4, 4);
377  pkt_id = ntohl(magic);
378 
379  code = dhcp_get_option((dhcp_packet_t const *) data, data_len, PW_DHCP_MESSAGE_TYPE);
380  if (!code) {
381  fr_strerror_printf("No message-type option was found in the packet");
382  return NULL;
383  }
384 
385  if ((code[1] < 1) || (code[2] == 0) || (code[2] >= DHCP_MAX_MESSAGE_TYPE)) {
386  fr_strerror_printf("Unknown value %d for message-type option", code[2]);
387  return NULL;
388  }
389 
390  /* Now that checks are done, allocate packet */
391  packet = fr_radius_alloc(NULL, false);
392  if (!packet) {
393  fr_strerror_printf("Failed allocating packet");
394  return NULL;
395  }
396 
397  packet->data_len = data_len;
398  packet->code = code[2] | PW_DHCP_OFFSET;
399  packet->id = pkt_id;
400 
401  packet->dst_port = dst_port;
402  packet->src_port = src_port;
403 
404  packet->src_ipaddr = src_ipaddr;
405  packet->dst_ipaddr = dst_ipaddr;
406 
407  /*
408  * Create a unique vector from the MAC address and the
409  * DHCP opcode. This is a hack for the RADIUS
410  * infrastructure in the rest of the server.
411  *
412  * Note: data[2] == 6, which is smaller than
413  * sizeof(packet->vector)
414  *
415  * FIXME: Look for client-identifier in packet,
416  * and use that, too?
417  */
418  memset(packet->vector, 0, sizeof(packet->vector));
419  memcpy(packet->vector, data + 28, data[2]);
420  packet->vector[data[2]] = packet->code & 0xff;
421 
422  /*
423  * FIXME: for DISCOVER / REQUEST: src_port == dst_port + 1
424  * FIXME: for OFFER / ACK : src_port = dst_port - 1
425  */
426 
427  /*
428  * Unique keys are xid, client mac, and client ID?
429  */
430  return packet;
431 }
432 
433 #ifdef HAVE_PCAP_H
434 /** Receive DHCP packet using PCAP
435  *
436  * @param pcap handle
437  * @return
438  * - pointer to RADIUS_PACKET if successful.
439  * - NULL if failed.
440  */
441 RADIUS_PACKET *fr_dhcp_recv_pcap(fr_pcap_t *pcap)
442 {
443  int ret;
444 
445  uint8_t const *data;
446  ssize_t data_len;
447  fr_ipaddr_t src_ipaddr, dst_ipaddr;
448  uint16_t src_port, dst_port;
449  struct pcap_pkthdr *header;
450  ssize_t link_len, len;
451  RADIUS_PACKET *packet;
452 
453  /*
454  * Pointers into the packet data we just received
455  */
456  uint8_t const *p;
457 
458  ip_header_t const *ip = NULL; /* The IP header */
459  udp_header_t const *udp; /* The UDP header */
460  uint8_t version; /* IP header version */
461 
462  ret = pcap_next_ex(pcap->handle, &header, &data);
463  if (ret == 0) {
464  DEBUG("DHCP: No packet received");
465  return NULL; /* no packet */
466  }
467  if (ret < 0) {
468  fr_strerror_printf("Error requesting next packet, got (%i): %s", ret, pcap_geterr(pcap->handle));
469  return NULL;
470  }
471 
472  link_len = fr_link_layer_offset(data, header->caplen, pcap->link_layer);
473  if (link_len < 0) {
474  fr_strerror_printf("Failed determining link layer header offset: %s", fr_strerror());
475  return NULL;
476  }
477 
478  p = data;
479 
480  /* Skip ethernet header */
481  p += link_len;
482 
483  version = (p[0] & 0xf0) >> 4;
484  switch (version) {
485  case 4:
486  ip = (ip_header_t const *)p;
487  len = (0x0f & ip->ip_vhl) * 4; /* ip_hl specifies length in 32bit words */
488  p += len;
489  break;
490 
491  case 6:
492  DEBUG("DHCP: IPv6 not supported");
493  return NULL;
494 
495  default:
496  DEBUG("DHCP: IP version invalid %i", version);
497  return NULL;
498  }
499 
500  /* Check IPv4 layer data (L3) */
501  if (ip->ip_p != IPPROTO_UDP) {
502  DEBUG("DHCP: IP protocol (%d) != UDP", ip->ip_p);
503  return NULL;
504  }
505 
506  /*
507  * End of variable length bits, do basic check now to see if packet looks long enough
508  */
509  len = (p - data) + UDP_HDR_SIZE; /* length value */
510  if ((size_t) len > header->caplen) {
511  DEBUG("DHCP: Payload (%d) smaller than required for layers 2+3+4", (int)len);
512  return NULL;
513  }
514 
515  /*
516  * UDP header validation.
517  */
518  ret = fr_udp_header_check(p, (header->caplen - (p - data)), ip);
519  if (ret < 0) {
520  DEBUG("DHCP: %s", fr_strerror());
521  return NULL;
522  } else if (ret > 0) {
523  /* Not a fatal error */
524  DEBUG("DHCP: %s", fr_strerror());
525  }
526 
527  udp = (udp_header_t const *)p;
528  p += sizeof(udp_header_t);
529 
530  data_len = ntohs(udp->len);
531 
532  dst_port = ntohs(udp->dst);
533  src_port = ntohs(udp->src);
534 
535  src_ipaddr.af = AF_INET;
536  src_ipaddr.ipaddr.ip4addr = ip->ip_src;
537  src_ipaddr.prefix = 32;
538  src_ipaddr.zone_id = 0;
539  dst_ipaddr.af = AF_INET;
540  dst_ipaddr.ipaddr.ip4addr = ip->ip_dst;
541  dst_ipaddr.prefix = 32;
542  dst_ipaddr.zone_id = 0;
543 
544  packet = fr_dhcp_packet_ok(p, data_len, src_ipaddr, src_port, dst_ipaddr, dst_port);
545  if (packet) {
546  packet->data = talloc_memdup(packet, p, packet->data_len);
547  return packet;
548  }
549 
550  return NULL;
551 }
552 #endif /* HAVE_PCAP_H */
553 
554 /** Send DHCP packet using socket
555  *
556  * @param packet to send
557  * @return
558  * - >= 0 if successful.
559  * - < 0 if failed.
560  */
562 {
563  int ret;
564  struct sockaddr_storage dst;
565  socklen_t sizeof_dst;
566 #ifdef WITH_UDPFROMTO
567  struct sockaddr_storage src;
568  socklen_t sizeof_src;
569 
570  fr_ipaddr_to_sockaddr(&packet->src_ipaddr, packet->src_port, &src, &sizeof_src);
571 #endif
572 
573  fr_ipaddr_to_sockaddr(&packet->dst_ipaddr, packet->dst_port, &dst, &sizeof_dst);
574  if (packet->data_len == 0) {
575  fr_strerror_printf("No data to send");
576  return -1;
577  }
578 
579  errno = 0;
580 
581 #ifndef WITH_UDPFROMTO
582  /*
583  * Assume that the packet is encoded before sending it.
584  */
585  ret = sendto(packet->sockfd, packet->data, packet->data_len, 0, (struct sockaddr *)&dst, sizeof_dst);
586 #else
587 
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);
590 #endif
591  if ((ret < 0) && errno) fr_strerror_printf("dhcp_send_socket: %s", fr_syserror(errno));
592 
593  return ret;
594 }
595 
596 #ifdef HAVE_PCAP_H
597 /** Send DHCP packet using PCAP
598  *
599  * @param pcap handle
600  * @param dst_ether_addr MAC address to send packet to
601  * @param packet to send
602  * @return
603  * - -1 on failure.
604  * - 0 on success.
605  */
606 int fr_dhcp_send_pcap(fr_pcap_t *pcap, uint8_t *dst_ether_addr, RADIUS_PACKET *packet)
607 {
608  int ret;
609  uint8_t dhcp_packet[1518] = { 0 };
610  ethernet_header_t *eth_hdr;
611  ip_header_t *ip_hdr;
612  udp_header_t *udp_hdr;
613  dhcp_packet_t *dhcp;
614  /* Pointer to the current position in the frame */
615  uint8_t *end = dhcp_packet;
616  uint16_t l4_len;
617 
618  /* fill in Ethernet layer (L2) */
619  eth_hdr = (ethernet_header_t *)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);
624 
625  /* fill in IP layer (L3) */
626  ip_hdr = (ip_header_t *)(end);
627  ip_hdr->ip_vhl = IP_VHL(4, 5);
628  ip_hdr->ip_tos = 0;
629  ip_hdr->ip_len = htons(IP_HDR_SIZE + UDP_HDR_SIZE + packet->data_len);
630  ip_hdr->ip_id = 0;
631  ip_hdr->ip_off = 0;
632  ip_hdr->ip_ttl = 64;
633  ip_hdr->ip_p = 17;
634  ip_hdr->ip_sum = 0; /* Filled later */
635 
636  ip_hdr->ip_src.s_addr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
637  ip_hdr->ip_dst.s_addr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
638 
639  /* IP header checksum */
640  ip_hdr->ip_sum = fr_ip_header_checksum((uint8_t const *)ip_hdr, 5);
641  end += IP_HDR_SIZE;
642 
643  /* fill in UDP layer (L4) */
644  udp_hdr = (udp_header_t *)end;
645 
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; /* UDP checksum will be done after dhcp header */
651  end += UDP_HDR_SIZE;
652 
653  /* DHCP layer (L7) */
654  dhcp = (dhcp_packet_t *)end;
655  /* just copy what FreeRADIUS has encoded for us. */
656  memcpy(dhcp, packet->data, packet->data_len);
657 
658  /* UDP checksum is done here */
659  udp_hdr->checksum = fr_udp_checksum((uint8_t const *)udp_hdr, ntohs(udp_hdr->len), udp_hdr->checksum,
660  packet->src_ipaddr.ipaddr.ip4addr,
661  packet->dst_ipaddr.ipaddr.ip4addr);
662 
663  ret = pcap_inject(pcap->handle, dhcp_packet, (end - dhcp_packet + packet->data_len));
664  if (ret < 0) {
665  fr_strerror_printf("DHCP: Error sending packet with pcap: %d, %s", ret, pcap_geterr(pcap->handle));
666  return -1;
667  }
668 
669  return 0;
670 }
671 #endif /* HAVE_PCAP_H */
672 
673 static ssize_t decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent,
674  uint8_t const *data, size_t data_len);
675 
676 static ssize_t decode_value(TALLOC_CTX *ctx, vp_cursor_t *cursor,
677  fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len);
678 
679 /** Returns the number of array members for arrays with fixed element sizes
680  *
681  */
682 static int fr_dhcp_array_members(size_t *out, size_t len, fr_dict_attr_t const *da)
683 {
684  int num_entries = 1;
685 
686  *out = len;
687 
688  /*
689  * Could be an array of bytes, integers, etc.
690  */
691  if (da->flags.array) switch (da->type) {
692  case PW_TYPE_BYTE:
693  num_entries = len;
694  *out = 1;
695  break;
696 
697  case PW_TYPE_SHORT: /* ignore any trailing data */
698  num_entries = len >> 1;
699  *out = 2;
700  break;
701 
702  case PW_TYPE_IPV4_ADDR:
703  case PW_TYPE_INTEGER:
704  case PW_TYPE_DATE: /* ignore any trailing data */
705  num_entries = len >> 2;
706  *out = 4;
707  break;
708 
709  case PW_TYPE_IPV6_ADDR:
710  num_entries = len >> 4;
711  *out = 16;
712  break;
713 
714  default:
715  break;
716  }
717 
718  return num_entries;
719 }
720 
721 /*
722  * Decode ONE value into a VP
723  */
724 static ssize_t decode_value_internal(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *da,
725  uint8_t const *data, size_t data_len)
726 {
727  VALUE_PAIR *vp;
728  uint8_t const *p = data;
729 
730  FR_PROTO_TRACE("%s called to parse %zu bytes", __FUNCTION__, data_len);
731  FR_PROTO_HEX_DUMP(NULL, data, data_len);
732 
733  vp = fr_pair_afrom_da(ctx, da);
734  if (!vp) return -1;
735 
736  /*
737  * Unknown attributes always get converted to
738  * octet types, so there's no way there could
739  * be multiple attributes, so its safe to
740  * steal the unknown attribute into the context
741  * of the pair.
742  */
743  if (da->flags.is_unknown) talloc_steal(vp, da);
744 
745  switch (da->type) {
746  case PW_TYPE_BYTE:
747  if (data_len != 1) goto raw;
748  vp->vp_byte = p[0];
749  p++;
750  break;
751 
752  case PW_TYPE_SHORT:
753  if (data_len != 2) goto raw;
754  memcpy(&vp->vp_short, p, 2);
755  vp->vp_short = ntohs(vp->vp_short);
756  p += 2;
757  break;
758 
759  case PW_TYPE_INTEGER:
760  if (data_len != 4) goto raw;
761  memcpy(&vp->vp_integer, p, 4);
762  vp->vp_integer = ntohl(vp->vp_integer);
763  p += 4;
764  break;
765 
766  case PW_TYPE_IPV4_ADDR:
767  if (data_len != 4) goto raw;
768  /*
769  * Keep value in Network Order!
770  */
771  memcpy(&vp->vp_ipaddr, p, 4);
772  vp->vp_length = 4;
773  p += 4;
774  break;
775 
776  case PW_TYPE_IPV6_ADDR:
777  if (data_len != 16) goto raw;
778  /*
779  * Keep value in Network Order!
780  */
781  memcpy(&vp->vp_ipaddr, p, 16);
782  vp->vp_length = 16;
783  p += 16;
784  break;
785 
786  /*
787  * In DHCPv4, string options which can also be arrays,
788  * have their values '\0' delimited.
789  */
790  case PW_TYPE_STRING:
791  {
792  uint8_t const *q, *end;
793 
794  q = end = data + data_len;
795 
796  /*
797  * Not allowed to be an array, copy the whole value
798  */
799  if (!vp->da->flags.array) {
800  fr_pair_value_bstrncpy(vp, (char const *)p, end - p);
801  p = end;
802  break;
803  }
804 
805  for (;;) {
806  q = memchr(p, '\0', q - p);
807 
808  /* Malformed but recoverable */
809  if (!q) q = end;
810 
811  fr_pair_value_bstrncpy(vp, (char const *)p, q - p);
812  p = q + 1;
813 
814  /* Need another VP for the next round */
815  if (p < end) {
816  fr_cursor_insert(cursor, vp);
817 
818  vp = fr_pair_afrom_da(ctx, da);
819  if (!vp) return -1;
820  continue;
821  }
822  break;
823  }
824  }
825  break;
826 
827  case PW_TYPE_ETHERNET:
828  memcpy(vp->vp_ether, data, sizeof(vp->vp_ether));
829  vp->vp_length = sizeof(vp->vp_ether);
830  p += sizeof(vp->vp_ether);
831  break;
832 
833  /*
834  * Value doesn't match up with attribute type, overwrite the
835  * vp's original fr_dict_attr_t with an unknown one.
836  */
837  raw:
838  FR_PROTO_TRACE("decoding as unknown type");
839  if (fr_pair_to_unknown(vp) < 0) return -1;
840 
841  case PW_TYPE_OCTETS:
842  if (data_len > UINT8_MAX) return -1;
843  fr_pair_value_memcpy(vp, data, data_len);
844  p += data_len;
845  break;
846 
847  default:
848  fr_strerror_printf("Internal sanity check %d %d", vp->da->type, __LINE__);
849  talloc_free(vp);
850  return -1;
851  } /* switch over type */
852 
853  FR_PROTO_TRACE("decoding value complete, adding new pair and returning %zu byte(s)", p - data);
854  fr_cursor_insert(cursor, vp);
855 
856  return p - data;
857 }
858 
859 
860 /** RFC 4243 Vendor Specific Suboptions
861  *
862  * Vendor specific suboptions are in the format.
863  @verbatim
864  0 1 2 3
865  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
866  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
867  | Enterprise Number 0 |
868  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
869  | Len 0 | /
870  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
871  / Suboption Data 0 /
872  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
873  | Enterprise Number n |
874  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
875  | Len n | /
876  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
877  / Suboption Data n /
878  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
879  @endverbatim
880  *
881  * So although the vendor is identified, the format of the data isn't
882  * specified so we can't actually resolve the suboption to an
883  * attribute. For now, we just convert it to an attribute of
884  * DHCP-Vendor-Specific-Information with raw octets contents.
885  */
886 
887 /** Decode DHCP suboptions
888  *
889  * @param[in] ctx context to alloc new attributes in.
890  * @param[in,out] cursor Where to write the decoded options.
891  * @param[in] parent of sub TLVs.
892  * @param[in] data to parse.
893  * @param[in] data_len of data parsed.
894  */
895 static ssize_t decode_tlv(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent,
896  uint8_t const *data, size_t data_len)
897 {
898  uint8_t const *p = data;
899  uint8_t const *end = data + data_len;
900  fr_dict_attr_t const *child;
901 
902  if (data_len < 3) return -1; /* type, length, value */
903 
904  FR_PROTO_TRACE("%s called to parse %zu byte(s)", __FUNCTION__, data_len);
905  FR_PROTO_HEX_DUMP(NULL, data, data_len);
906 
907  /*
908  * Each TLV may contain multiple children
909  */
910  while (p < end) {
911  ssize_t tlv_len;
912 
913  if (p[0] == 0) {
914  p++;
915  continue;
916  }
917 
918  /*
919  * RFC 3046 is very specific about not allowing termination
920  * with a 255 sub-option. But it's required for decoding
921  * option 43, and vendors will probably screw it up
922  * anyway.
923  */
924  if (p[0] == 255) {
925  p++;
926  return p - data;
927  }
928 
929  /*
930  * Everything else should be real options
931  */
932  if ((end - p) < 2) {
933  fr_strerror_printf("%s: Insufficient data: Needed at least 2 bytes, got %zu",
934  __FUNCTION__, (end - p));
935  return -1;
936  }
937 
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]);
941  return -1;
942  }
943 
944  child = fr_dict_attr_child_by_num(parent, p[0]);
945  if (!child) {
946  fr_dict_attr_t *unknown_child;
947 
948  FR_PROTO_TRACE("failed to find child %u of TLV %s", p[0], parent->name);
949 
950  /*
951  * Build an unknown attr
952  */
953  unknown_child = fr_dict_unknown_afrom_fields(ctx, parent, parent->vendor, p[0]);
954  if (!unknown_child) return -1;
955  child = unknown_child;
956  }
957  FR_PROTO_TRACE("decode context changed %s:%s -> %s:%s",
958  fr_int2str(dict_attr_types, parent->type, "<invalid>"), parent->name,
959  fr_int2str(dict_attr_types, child->type, "<invalid>"), child->name);
960 
961  tlv_len = decode_value(ctx, cursor, child, p + 2, p[1]);
962  if (tlv_len <= 0) {
963  fr_dict_unknown_free(&child);
964  return tlv_len;
965  }
966  p += tlv_len + 2;
967  FR_PROTO_TRACE("decode_value returned %zu, adding 2 (for header)", tlv_len);
968  FR_PROTO_TRACE("remaining TLV data %zu byte(s)" , end - p);
969  }
970  FR_PROTO_TRACE("tlv parsing complete, returning %zu byte(s)", p - data);
971 
972  return p - data;
973 }
974 
975 static ssize_t decode_value(TALLOC_CTX *ctx, vp_cursor_t *cursor,
976  fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len)
977 {
978  unsigned int values, i; /* How many values we need to decode */
979  uint8_t const *p = data;
980  size_t value_len;
981  ssize_t len;
982 
983  FR_PROTO_TRACE("%s called to parse %zu byte(s)", __FUNCTION__, data_len);
984  FR_PROTO_HEX_DUMP(NULL, data, data_len);
985 
986  /*
987  * TLVs can't be coalesced as they're variable length
988  */
989  if (parent->type == PW_TYPE_TLV) return decode_tlv(ctx, cursor, parent, data, data_len);
990 
991  /*
992  * Values with a fixed length may be coalesced into a single option
993  */
994  values = fr_dhcp_array_members(&value_len, data_len, parent);
995  if (values) {
996  FR_PROTO_TRACE("found %u coalesced values (%zu bytes each)", values, value_len);
997 
998  if ((values * value_len) != data_len) {
999  fr_strerror_printf("Option length not divisible by its fixed value "
1000  "length (probably trailing garbage)");
1001  return -1;
1002  }
1003  }
1004 
1005  /*
1006  * Decode each of the (maybe) coalesced values as its own
1007  * attribute.
1008  */
1009  for (i = 0, p = data; i < values; i++) {
1010  len = decode_value_internal(ctx, cursor, parent, p, value_len);
1011  if (len <= 0) return len;
1012  if (len != (ssize_t)value_len) {
1013  fr_strerror_printf("Failed decoding complete option value");
1014  return -1;
1015  }
1016  p += len;
1017  }
1018 
1019  return p - data;
1020 }
1021 
1022 /** Decode DHCP option
1023  *
1024  * @param[in] ctx context to alloc new attributes in.
1025  * @param[in,out] cursor Where to write the decoded options.
1026  * @param[in] parent The root of the protocol dictionary used to decode DHCP attributes.
1027  * @param[in] data to parse.
1028  * @param[in] data_len of data to parse.
1029  * @param[in] decoder_ctx Unused.
1030  */
1031 ssize_t fr_dhcp_decode_option(TALLOC_CTX *ctx, vp_cursor_t *cursor,
1032  fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len,
1033  UNUSED void *decoder_ctx)
1034 {
1035  ssize_t ret;
1036  uint8_t const *p = data;
1037  fr_dict_attr_t const *child;
1038 
1039  FR_PROTO_TRACE("%s called to parse %zu byte(s)", __FUNCTION__, data_len);
1040 
1041  if (data_len == 0) return 0;
1042 
1043  FR_PROTO_HEX_DUMP(NULL, data, data_len);
1044 
1045  /*
1046  * Stupid hacks until we have protocol specific dictionaries
1047  */
1048  parent = fr_dict_attr_child_by_num(parent, PW_VENDOR_SPECIFIC);
1049  if (!parent) {
1050  fr_strerror_printf("Can't find Vendor-Specific (26)");
1051  return -1;
1052  }
1053 
1054  parent = fr_dict_attr_child_by_num(parent, DHCP_MAGIC_VENDOR);
1055  if (!parent) {
1056  fr_strerror_printf("Can't find DHCP vendor");
1057  return -1;
1058  }
1059 
1060  /*
1061  * Padding / End of options
1062  */
1063  if (p[0] == 0) return 1; /* 0x00 - Padding option */
1064  if (p[0] == 255) { /* 0xff - End of options signifier */
1065  if (data_len > 1) {
1066  fr_strerror_printf("%s: Got end of options signifier, but more data to parse", __FUNCTION__);
1067  return -1;
1068  }
1069  return 1;
1070  }
1071 
1072  /*
1073  * Everything else should be real options
1074  */
1075  if ((data_len < 2) || (data[1] > data_len)) {
1076  fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
1077  return -1;
1078  }
1079 
1080  child = fr_dict_attr_child_by_num(parent, p[0]);
1081  if (!child) {
1082  /*
1083  * Unknown attribute, create an octets type
1084  * attribute with the contents of the sub-option.
1085  */
1086  child = fr_dict_unknown_afrom_fields(ctx, parent, DHCP_MAGIC_VENDOR, p[0]);
1087  if (!child) return -1;
1088  }
1089  FR_PROTO_TRACE("decode context changed %s:%s -> %s:%s",
1090  fr_int2str(dict_attr_types, parent->type, "<invalid>"), parent->name,
1091  fr_int2str(dict_attr_types, child->type, "<invalid>"), child->name);
1092 
1093  ret = decode_value(ctx, cursor, child, data + 2, data[1]);
1094  if (ret < 0) {
1095  fr_dict_unknown_free(&child);
1096  return ret;
1097  }
1098  ret += 2; /* For header */
1099  FR_PROTO_TRACE("decoding option complete, returning %zu byte(s)", ret);
1100  return ret;
1101 }
1102 
1104 {
1105  size_t i;
1106  uint8_t *p;
1107  uint32_t giaddr;
1108  vp_cursor_t cursor;
1109  VALUE_PAIR *head = NULL, *vp;
1110  VALUE_PAIR *maxms, *mtu;
1111 
1112  fr_cursor_init(&cursor, &head);
1113  p = packet->data;
1114 
1115  if (packet->data[1] > 1) {
1116  fr_strerror_printf("Packet is not Ethernet: %u",
1117  packet->data[1]);
1118  return -1;
1119  }
1120 
1121  /*
1122  * Decode the header.
1123  */
1124  for (i = 0; i < 14; i++) {
1125  char *q;
1126 
1127  vp = fr_pair_make(packet, NULL, dhcp_header_names[i], NULL, T_OP_EQ);
1128  if (!vp) {
1129  char buffer[256];
1130  strlcpy(buffer, fr_strerror(), sizeof(buffer));
1131  fr_strerror_printf("Cannot decode packet due to internal error: %s", buffer);
1132  fr_pair_list_free(&head);
1133  return -1;
1134  }
1135 
1136  /*
1137  * If chaddr != 6 bytes it's probably not ethernet, and we should store
1138  * it as an opaque type (octets).
1139  */
1140  if (i == 11) {
1141  /*
1142  * Skip chaddr if it doesn't exist.
1143  */
1144  if ((packet->data[1] == 0) || (packet->data[2] == 0)) continue;
1145 
1146  if ((packet->data[1] == 1) && (packet->data[2] != sizeof(vp->vp_ether))) {
1147  fr_dict_attr_t const *da;
1148 
1150  vp->da->vendor, vp->da->attr);
1151  if (!da) {
1152  return -1;
1153  }
1154  vp->da = da;
1155  }
1156  }
1157 
1158  switch (vp->da->type) {
1159  case PW_TYPE_BYTE:
1160  vp->vp_byte = p[0];
1161  vp->vp_length = 1;
1162  break;
1163 
1164  case PW_TYPE_SHORT:
1165  vp->vp_short = (p[0] << 8) | p[1];
1166  vp->vp_length = 2;
1167  break;
1168 
1169  case PW_TYPE_INTEGER:
1170  memcpy(&vp->vp_integer, p, 4);
1171  vp->vp_integer = ntohl(vp->vp_integer);
1172  vp->vp_length = 4;
1173  break;
1174 
1175  case PW_TYPE_IPV4_ADDR:
1176  memcpy(&vp->vp_ipaddr, p, 4);
1177  vp->vp_length = 4;
1178  break;
1179 
1180  case PW_TYPE_STRING:
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';
1184  fr_pair_value_strsteal(vp, q);
1185 
1186  if (vp->vp_length == 0) fr_pair_list_free(&vp);
1187  break;
1188 
1189  case PW_TYPE_OCTETS:
1190  if (packet->data[2] == 0) break;
1191 
1192  fr_pair_value_memcpy(vp, p, packet->data[2]);
1193  break;
1194 
1195  case PW_TYPE_ETHERNET:
1196  memcpy(vp->vp_ether, p, sizeof(vp->vp_ether));
1197  vp->vp_length = sizeof(vp->vp_ether);
1198  break;
1199 
1200  default:
1201  fr_strerror_printf("BAD TYPE %d", vp->da->type);
1202  fr_pair_list_free(&vp);
1203  break;
1204  }
1205  p += dhcp_header_sizes[i];
1206 
1207  if (!vp) continue;
1208 
1209  fr_cursor_insert(&cursor, vp);
1210  }
1211 
1212  /*
1213  * Loop over the options.
1214  */
1215 
1216  /*
1217  * Nothing uses tail after this call, if it does in the future
1218  * it'll need to find the new tail...
1219  */
1220  {
1221  uint8_t const *end;
1222  ssize_t len;
1223 
1224  p = packet->data + 240;
1225  end = p + (packet->data_len - 240);
1226 
1227  /*
1228  * Loop over all the options data
1229  */
1230  while (p < end) {
1231  VALUE_PAIR *options = NULL;
1232  vp_cursor_t options_cursor;
1233 
1234  fr_cursor_init(&options_cursor, &options);
1235  len = fr_dhcp_decode_option(packet, &options_cursor, fr_dict_root(fr_dict_internal),
1236  p, ((end - p) > UINT8_MAX) ? UINT8_MAX : (end - p), NULL);
1237  if (len <= 0) {
1238  fr_pair_list_free(&options);
1239  return len;
1240  }
1241  p += len;
1242  if (options) fr_cursor_merge(&cursor, options);
1243  }
1244  }
1245 
1246  /*
1247  * If DHCP request, set ciaddr to zero.
1248  */
1249 
1250  /*
1251  * Set broadcast flag for broken vendors, but only if
1252  * giaddr isn't set.
1253  */
1254  memcpy(&giaddr, packet->data + 24, sizeof(giaddr));
1255  if (giaddr == htonl(INADDR_ANY)) {
1256  /*
1257  * DHCP Opcode is request
1258  */
1259  vp = fr_pair_find_by_num(head, DHCP_MAGIC_VENDOR, 256, TAG_ANY);
1260  if (vp && vp->vp_integer == 3) {
1261  /*
1262  * Vendor is "MSFT 98"
1263  */
1265  if (vp && (strcmp(vp->vp_strvalue, "MSFT 98") == 0)) {
1266  vp = fr_pair_find_by_num(head, DHCP_MAGIC_VENDOR, 262, TAG_ANY);
1267 
1268  /*
1269  * Reply should be broadcast.
1270  */
1271  if (vp) vp->vp_short |= 0x8000;
1272  packet->data[10] |= 0x80;
1273  }
1274  }
1275  }
1276 
1277  /*
1278  * FIXME: Nuke attributes that aren't used in the normal
1279  * header for discover/requests.
1280  */
1281  packet->vps = head;
1282 
1283  /*
1284  * Client can request a LARGER size, but not a smaller
1285  * one. They also cannot request a size larger than MTU.
1286  */
1287  maxms = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 57, TAG_ANY);
1288  mtu = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 26, TAG_ANY);
1289 
1290  if (mtu && (mtu->vp_integer < DEFAULT_PACKET_SIZE)) {
1291  fr_strerror_printf("Client says MTU is smaller than minimum permitted by the specification");
1292  return -1;
1293  }
1294 
1295  /*
1296  * Client says maximum message size is smaller than minimum permitted
1297  * by the specification: fixing it.
1298  */
1299  if (maxms && (maxms->vp_integer < DEFAULT_PACKET_SIZE)) maxms->vp_integer = DEFAULT_PACKET_SIZE;
1300 
1301  /*
1302  * Client says MTU is smaller than maximum message size: fixing it
1303  */
1304  if (maxms && mtu && (maxms->vp_integer > mtu->vp_integer)) maxms->vp_integer = mtu->vp_integer;
1305 
1306  return 0;
1307 }
1308 
1309 int8_t fr_dhcp_attr_cmp(void const *a, void const *b)
1310 {
1311  VALUE_PAIR const *my_a = a;
1312  VALUE_PAIR const *my_b = b;
1313 
1314  VERIFY_VP(my_a);
1315  VERIFY_VP(my_b);
1316 
1317  /*
1318  * DHCP-Message-Type is first, for simplicity.
1319  */
1320  if ((my_a->da->attr == PW_DHCP_MESSAGE_TYPE) && (my_b->da->attr != PW_DHCP_MESSAGE_TYPE)) return -1;
1321 
1322  /*
1323  * Relay-Agent is last
1324  */
1325  if ((my_a->da->attr == PW_DHCP_OPTION_82) && (my_b->da->attr != PW_DHCP_OPTION_82)) return 1;
1326  if (my_a->da->attr < my_b->da->attr) return -1;
1327  if (my_a->da->attr > my_b->da->attr) return 1;
1328 
1329  return 0;
1330 }
1331 
1332 /** Write DHCP option value into buffer
1333  *
1334  * Does not include DHCP option length or number.
1335  *
1336  * @param[in,out] out buffer to write the option to.
1337  * @param[out] outlen length of the output buffer.
1338  * @param[in] tlv_stack Describing nesting of options.
1339  * @param[in] depth in tlv_stack.
1340  * @param[in,out] cursor Current attribute we're encoding.
1341  * @return
1342  * - The length of data writen.
1343  * - -1 if out of buffer.
1344  * - -2 if unsupported type.
1345  */
1346 static ssize_t encode_value(uint8_t *out, size_t outlen,
1347  fr_dict_attr_t const **tlv_stack, unsigned int depth,
1348  vp_cursor_t *cursor)
1349 {
1350  uint32_t lvalue;
1351 
1352  VALUE_PAIR *vp = fr_cursor_current(cursor);
1353  uint8_t *p = out;
1354 
1355  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1356  FR_PROTO_TRACE("%zu byte(s) available for value", outlen);
1357 
1358  if (outlen < vp->vp_length) return 0;
1359 
1360  switch (tlv_stack[depth]->type) {
1361  case PW_TYPE_BYTE:
1362  p[0] = vp->vp_byte;
1363  p ++;
1364  break;
1365 
1366  case PW_TYPE_SHORT:
1367  p[0] = (vp->vp_short >> 8) & 0xff;
1368  p[1] = vp->vp_short & 0xff;
1369  p += 2;
1370  break;
1371 
1372  case PW_TYPE_INTEGER:
1373  lvalue = htonl(vp->vp_integer);
1374  memcpy(p, &lvalue, 4);
1375  p += 4;
1376  break;
1377 
1378  case PW_TYPE_IPV4_ADDR:
1379  memcpy(p, &vp->vp_ipaddr, 4);
1380  p += 4;
1381  break;
1382 
1383  case PW_TYPE_IPV6_ADDR:
1384  memcpy(p, &vp->vp_ipv6addr, 16);
1385  p += 16;
1386  break;
1387 
1388  case PW_TYPE_ETHERNET:
1389  memcpy(p, vp->vp_ether, 6);
1390  p += 6;
1391  break;
1392 
1393  case PW_TYPE_STRING:
1394  memcpy(p, vp->vp_strvalue, vp->vp_length);
1395  p += vp->vp_length;
1396  break;
1397 
1398  case PW_TYPE_OCTETS:
1399  memcpy(p, vp->vp_octets, vp->vp_length);
1400  p += vp->vp_length;
1401  break;
1402 
1403  default:
1404  fr_strerror_printf("Unsupported option type %d", vp->da->type);
1405  (void)fr_cursor_next(cursor);
1406  return -2;
1407  }
1408  vp = fr_cursor_next(cursor); /* We encoded a leaf, advance the cursor */
1409  fr_proto_tlv_stack_build(tlv_stack, vp ? vp->da : NULL);
1410 
1411  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1412  FR_PROTO_HEX_DUMP("Value", out, (p - out));
1413 
1414  return p - out;
1415 }
1416 
1417 /** Write out an RFC option header and option data
1418  *
1419  * @note May coalesce options with fixed width values
1420  *
1421  * @param[in,out] out buffer to write the TLV to.
1422  * @param[out] outlen length of the output buffer.
1423  * @param[in] tlv_stack Describing nesting of options.
1424  * @param[in] depth in the tlv_stack.
1425  * @param[in,out] cursor Current attribute we're encoding.
1426  * @return
1427  * - >0 length of data encoded.
1428  * - 0 if we ran out of space.
1429  * - < 0 on error.
1430  */
1431 static ssize_t encode_rfc_hdr(uint8_t *out, ssize_t outlen,
1432  fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor)
1433 {
1434  ssize_t len;
1435  uint8_t *p = out;
1436  fr_dict_attr_t const *da = tlv_stack[depth];
1437  VALUE_PAIR *vp = fr_cursor_current(cursor);
1438 
1439  if (outlen < 3) return 0; /* No space */
1440 
1441  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1442 
1443  /*
1444  * Write out the option number
1445  */
1446  out[0] = da->attr & 0xff;
1447  out[1] = 0; /* Length of the value only (unlike RADIUS) */
1448 
1449  outlen -= 2;
1450  p += 2;
1451 
1452  /*
1453  * Check here so we get the full 255 bytes
1454  */
1455  if (outlen > UINT8_MAX) outlen = UINT8_MAX;
1456 
1457  /*
1458  * DHCP options with the same number (and array flag set)
1459  * get coalesced into a single option.
1460  *
1461  * Note: This only works with fixed length attributes,
1462  * because there's no separate length fields.
1463  */
1464  do {
1465  VALUE_PAIR *next;
1466 
1467  len = encode_value(p, outlen - out[1], tlv_stack, depth, cursor);
1468  if (len < 0) return len;
1469  if (len == 0) {
1470  FR_PROTO_TRACE("No more space in option");
1471  break; /* Packed as much as we can */
1472  }
1473 
1474  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1475  FR_PROTO_TRACE("Encoded value is %zu byte(s)", len);
1476  FR_PROTO_HEX_DUMP(NULL, out, (p - out));
1477 
1478  p += len;
1479  out[1] += len;
1480 
1481  FR_PROTO_TRACE("%zu byte(s) available in option", outlen - out[1]);
1482 
1483  next = fr_cursor_current(cursor);
1484  if (!next || (vp->da != next->da)) break;
1485  vp = next;
1486  } while (vp->da->flags.array);
1487 
1488  return p - out;
1489 }
1490 
1491 /** Write out a TLV header (and any sub TLVs or values)
1492  *
1493  * @param[in,out] out buffer to write the TLV to.
1494  * @param[out] outlen length of the output buffer.
1495  * @param[in] tlv_stack Describing nesting of options.
1496  * @param[in] depth in the tlv_stack.
1497  * @param[in,out] cursor Current attribute we're encoding.
1498  * @return
1499  * - >0 length of data encoded.
1500  * - 0 if we ran out of space.
1501  * - < 0 on error.
1502  */
1503 static ssize_t encode_tlv_hdr(uint8_t *out, ssize_t outlen,
1504  fr_dict_attr_t const **tlv_stack, unsigned int depth, vp_cursor_t *cursor)
1505 {
1506  ssize_t len;
1507  uint8_t *p = out;
1508  VALUE_PAIR const *vp = fr_cursor_current(cursor);
1509  fr_dict_attr_t const *da = tlv_stack[depth];
1510 
1511  if (outlen < 5) return 0; /* No space */
1512 
1513  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1514 
1515  /*
1516  * Write out the option number
1517  */
1518  out[0] = da->attr & 0xff;
1519  out[1] = 0; /* Length of the value only (unlike RADIUS) */
1520 
1521  outlen -= 2;
1522  p += 2;
1523 
1524  /*
1525  * Check here so we get the full 255 bytes
1526  */
1527  if (outlen > UINT8_MAX) outlen = UINT8_MAX;
1528 
1529  /*
1530  * Encode any sub TLVs or values
1531  */
1532  while (outlen >= 3) {
1533  /*
1534  * Determine the nested type and call the appropriate encoder
1535  */
1536  if (tlv_stack[depth + 1]->type == PW_TYPE_TLV) {
1537  len = encode_tlv_hdr(p, outlen - out[1], tlv_stack, depth + 1, cursor);
1538  } else {
1539  len = encode_rfc_hdr(p, outlen - out[1], tlv_stack, depth + 1, cursor);
1540  }
1541  if (len < 0) return len;
1542  if (len == 0) break; /* Insufficient space */
1543 
1544  p += len;
1545  out[1] += len;
1546 
1547  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1548  FR_PROTO_HEX_DUMP("TLV header and sub TLVs", out, (p - out));
1549 
1550  /*
1551  * If nothing updated the attribute, stop
1552  */
1553  if (!fr_cursor_current(cursor) || (vp == fr_cursor_current(cursor))) break;
1554 
1555  /*
1556  * We can encode multiple sub TLVs, if after
1557  * rebuilding the TLV Stack, the attribute
1558  * at this depth is the same.
1559  */
1560  if (da != tlv_stack[depth]) break;
1561  vp = fr_cursor_current(cursor);
1562  }
1563 
1564  return p - out;
1565 }
1566 
1567 /** Encode a DHCP option and any sub-options.
1568  *
1569  * @param out Where to write encoded DHCP attributes.
1570  * @param outlen Length of out buffer.
1571  * @param cursor with current VP set to the option to be encoded. Will be advanced to the next option to encode.
1572  * @param encoder_ctx Unused.
1573  * @return
1574  * - > 0 length of data written.
1575  * - < 0 error.
1576  * - 0 not valid option for DHCP (skipping).
1577  */
1578 ssize_t fr_dhcp_encode_option(uint8_t *out, size_t outlen, vp_cursor_t *cursor, UNUSED void *encoder_ctx)
1579 {
1580  VALUE_PAIR *vp;
1581  unsigned int depth = 0;
1582  fr_dict_attr_t const *tlv_stack[FR_DICT_MAX_TLV_STACK + 1];
1583  ssize_t len;
1584 
1585  vp = fr_cursor_current(cursor);
1586  if (!vp) return -1;
1587 
1588  if (vp->da->vendor != DHCP_MAGIC_VENDOR) goto next; /* not a DHCP option */
1589  if (vp->da->attr == PW_DHCP_MESSAGE_TYPE) goto next; /* already done */
1590  if ((vp->da->attr > 255) && (DHCP_BASE_ATTR(vp->da->attr) != PW_DHCP_OPTION_82)) {
1591  next:
1592  fr_strerror_printf("Attribute \"%s\" is not a DHCP option", vp->da->name);
1593  fr_cursor_next(cursor);
1594  return 0;
1595  }
1596 
1597  fr_proto_tlv_stack_build(tlv_stack, vp->da);
1598 
1599  /*
1600  * Because of the stupid DHCP vendor hack we use,
1601  * we've got to jump a few places up in the stack
1602  * before starting. Once we have protocol dictionaries
1603  * this must be removed.
1604  */
1605  depth += 2;
1606  FR_PROTO_STACK_PRINT(tlv_stack, depth);
1607 
1608  /*
1609  * We only have two types of options in DHCPv4
1610  */
1611  switch (tlv_stack[depth]->type) {
1612  case PW_TYPE_TLV:
1613  len = encode_tlv_hdr(out, outlen, tlv_stack, depth, cursor);
1614  break;
1615 
1616  default:
1617  len = encode_rfc_hdr(out, outlen, tlv_stack, depth, cursor);
1618  break;
1619  }
1620 
1621  if (len < 0) return len;
1622 
1623  FR_PROTO_TRACE("Complete option is %zu byte(s)", len);
1624  FR_PROTO_HEX_DUMP(NULL, out, len);
1625 
1626  return len;
1627 }
1628 
1630 {
1631  uint8_t *p;
1632  vp_cursor_t cursor;
1633  VALUE_PAIR *vp;
1634  uint32_t lvalue;
1635  uint16_t svalue;
1636  size_t dhcp_size;
1637  ssize_t len;
1638 
1639  if (packet->data) return 0;
1640 
1641  packet->data_len = MAX_PACKET_SIZE;
1642  packet->data = talloc_zero_array(packet, uint8_t, packet->data_len);
1643 
1644  /* XXX Ugly ... should be set by the caller */
1645  if (packet->code == 0) packet->code = PW_DHCP_NAK;
1646 
1647  /* store xid */
1648  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 260, TAG_ANY))) {
1649  packet->id = vp->vp_integer;
1650  } else {
1651  packet->id = fr_rand();
1652  }
1653 
1654  p = packet->data;
1655 
1656  /*
1657  * @todo: Make this work again.
1658  */
1659 #if 0
1660  mms = DEFAULT_PACKET_SIZE; /* maximum message size */
1661 
1662  /*
1663  * Clients can request a LARGER size, but not a
1664  * smaller one. They also cannot request a size
1665  * larger than MTU.
1666  */
1667 
1668  /* DHCP-DHCP-Maximum-Msg-Size */
1669  vp = fr_pair_find_by_num(packet->vps, 57, DHCP_MAGIC_VENDOR, TAG_ANY);
1670  if (vp && (vp->vp_integer > mms)) {
1671  mms = vp->vp_integer;
1672 
1673  if (mms > MAX_PACKET_SIZE) mms = MAX_PACKET_SIZE;
1674  }
1675 #endif
1676 
1677  vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 256, TAG_ANY);
1678  if (vp) {
1679  *p++ = vp->vp_integer & 0xff;
1680  } else {
1681  *p++ = 1; /* client message */
1682  }
1683 
1684  /* DHCP-Hardware-Type */
1685  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 257, TAG_ANY))) {
1686  *p++ = vp->vp_byte;
1687  } else {
1688  *p++ = 1; /* hardware type = ethernet */
1689  }
1690 
1691  /* DHCP-Hardware-Address-len */
1692  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 258, TAG_ANY))) {
1693  *p++ = vp->vp_byte;
1694  } else {
1695  *p++ = 6; /* 6 bytes of ethernet */
1696  }
1697 
1698  /* DHCP-Hop-Count */
1699  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 259, TAG_ANY))) {
1700  *p = vp->vp_byte;
1701  }
1702  p++;
1703 
1704  /* DHCP-Transaction-Id */
1705  lvalue = htonl(packet->id);
1706  memcpy(p, &lvalue, 4);
1707  p += 4;
1708 
1709  /* DHCP-Number-of-Seconds */
1710  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 261, TAG_ANY))) {
1711  svalue = htons(vp->vp_short);
1712  memcpy(p, &svalue, 2);
1713  }
1714  p += 2;
1715 
1716  /* DHCP-Flags */
1717  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 262, TAG_ANY))) {
1718  svalue = htons(vp->vp_short);
1719  memcpy(p, &svalue, 2);
1720  }
1721  p += 2;
1722 
1723  /* DHCP-Client-IP-Address */
1724  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 263, TAG_ANY))) {
1725  memcpy(p, &vp->vp_ipaddr, 4);
1726  }
1727  p += 4;
1728 
1729  /* DHCP-Your-IP-address */
1730  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 264, TAG_ANY))) {
1731  lvalue = vp->vp_ipaddr;
1732  } else {
1733  lvalue = htonl(INADDR_ANY);
1734  }
1735  memcpy(p, &lvalue, 4);
1736  p += 4;
1737 
1738  /* DHCP-Server-IP-Address */
1739  vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 265, TAG_ANY);
1740  if (vp) {
1741  lvalue = vp->vp_ipaddr;
1742  } else {
1743  lvalue = htonl(INADDR_ANY);
1744  }
1745  memcpy(p, &lvalue, 4);
1746  p += 4;
1747 
1748  /*
1749  * DHCP-Gateway-IP-Address
1750  */
1751  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 266, TAG_ANY))) {
1752  lvalue = vp->vp_ipaddr;
1753  } else {
1754  lvalue = htonl(INADDR_ANY);
1755  }
1756  memcpy(p, &lvalue, 4);
1757  p += 4;
1758 
1759  /* DHCP-Client-Hardware-Address */
1760  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 267, TAG_ANY))) {
1761  if (vp->vp_length == sizeof(vp->vp_ether)) {
1762  /*
1763  * Ensure that we mark the packet as being Ethernet.
1764  * This is mainly for DHCP-Lease-Query responses.
1765  */
1766  packet->data[1] = 1;
1767  packet->data[2] = 6;
1768 
1769  memcpy(p, vp->vp_ether, vp->vp_length);
1770  } /* else ignore it */
1771  }
1772  p += DHCP_CHADDR_LEN;
1773 
1774  /* DHCP-Server-Host-Name */
1775  if ((vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 268, TAG_ANY))) {
1776  if (vp->vp_length > DHCP_SNAME_LEN) {
1777  memcpy(p, vp->vp_strvalue, DHCP_SNAME_LEN);
1778  } else {
1779  memcpy(p, vp->vp_strvalue, vp->vp_length);
1780  }
1781  }
1782  p += DHCP_SNAME_LEN;
1783 
1784  /*
1785  * Copy over DHCP-Boot-Filename.
1786  *
1787  * FIXME: This copy should be delayed until AFTER the options
1788  * have been processed. If there are too many options for
1789  * the packet, then they go into the sname && filename fields.
1790  * When that happens, the boot filename is passed as an option,
1791  * instead of being placed verbatim in the filename field.
1792  */
1793 
1794  /* DHCP-Boot-Filename */
1795  vp = fr_pair_find_by_num(packet->vps, DHCP_MAGIC_VENDOR, 269, TAG_ANY);
1796  if (vp) {
1797  if (vp->vp_length > DHCP_FILE_LEN) {
1798  memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
1799  } else {
1800  memcpy(p, vp->vp_strvalue, vp->vp_length);
1801  }
1802  }
1803  p += DHCP_FILE_LEN;
1804 
1805  /* DHCP magic number */
1806  lvalue = htonl(DHCP_OPTION_MAGIC_NUMBER);
1807  memcpy(p, &lvalue, 4);
1808  p += 4;
1809 
1810  p[0] = 0x35; /* DHCP-Message-Type */
1811  p[1] = 1;
1812  p[2] = packet->code - PW_DHCP_OFFSET;
1813  p += 3;
1814 
1815  /*
1816  * Pre-sort attributes into contiguous blocks so that fr_dhcp_encode_option
1817  * operates correctly. This changes the order of the list, but never mind...
1818  */
1820  fr_cursor_init(&cursor, &packet->vps);
1821 
1822  /*
1823  * Each call to fr_dhcp_encode_option will encode one complete DHCP option,
1824  * and sub options.
1825  */
1826  while ((vp = fr_cursor_current(&cursor))) {
1827  len = fr_dhcp_encode_option(p, packet->data_len - (p - packet->data), &cursor, NULL);
1828  if (len < 0) break;
1829  p += len;
1830  };
1831 
1832  p[0] = 0xff; /* end of option option */
1833  p[1] = 0x00;
1834  p += 2;
1835  dhcp_size = p - packet->data;
1836 
1837  /*
1838  * FIXME: if (dhcp_size > mms),
1839  * then we put the extra options into the "sname" and "file"
1840  * fields, AND set the "end option option" in the "options"
1841  * field. We also set the "overload option",
1842  * and put options into the "file" field, followed by
1843  * the "sname" field. Where each option is completely
1844  * enclosed in the "file" and/or "sname" field, AND
1845  * followed by the "end of option", and MUST be followed
1846  * by padding option.
1847  *
1848  * Yuck. That sucks...
1849  */
1850  packet->data_len = dhcp_size;
1851 
1852  if (packet->data_len < DEFAULT_PACKET_SIZE) {
1853  memset(packet->data + packet->data_len, 0,
1854  DEFAULT_PACKET_SIZE - packet->data_len);
1855  packet->data_len = DEFAULT_PACKET_SIZE;
1856  }
1857 
1858  return 0;
1859 }
1860 
1861 #ifdef SIOCSARP
1862 int fr_dhcp_add_arp_entry(int fd, char const *interface,
1863  VALUE_PAIR *macaddr, VALUE_PAIR *ip)
1864 {
1865  struct sockaddr_in *sin;
1866  struct arpreq req;
1867 
1868  if (!interface) {
1869  fr_strerror_printf("No interface specified. Cannot update ARP table");
1870  return -1;
1871  }
1872 
1873  if (!fr_assert(macaddr) ||
1874  !fr_assert((macaddr->da->type == PW_TYPE_ETHERNET) || (macaddr->da->type == PW_TYPE_OCTETS))) {
1875  fr_strerror_printf("Wrong VP type (%s) for chaddr",
1876  fr_int2str(dict_attr_types, macaddr->da->type, "<invalid>"));
1877  return -1;
1878  }
1879 
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);
1883  return -1;
1884  }
1885 
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;
1890 
1891  strlcpy(req.arp_dev, interface, sizeof(req.arp_dev));
1892 
1893  if (macaddr->da->type == PW_TYPE_ETHERNET) {
1894  memcpy(&req.arp_ha.sa_data, macaddr->vp_ether, sizeof(macaddr->vp_ether));
1895  } else {
1896  memcpy(&req.arp_ha.sa_data, macaddr->vp_octets, macaddr->vp_length);
1897  }
1898 
1899  req.arp_flags = ATF_COM;
1900  if (ioctl(fd, SIOCSARP, &req) < 0) {
1901  fr_strerror_printf("Failed to add entry in ARP cache: %s (%d)", fr_syserror(errno), errno);
1902  return -1;
1903  }
1904 
1905  return 0;
1906 }
1907 #else
1908 int fr_dhcp_add_arp_entry(UNUSED int fd, UNUSED char const *interface,
1909  UNUSED VALUE_PAIR *macaddr, UNUSED VALUE_PAIR *ip)
1910 {
1911  fr_strerror_printf("Adding ARP entry is unsupported on this system");
1912  return -1;
1913 }
1914 #endif
1915 
1916 
1917 #ifdef HAVE_LINUX_IF_PACKET_H
1918 /*
1919  * Open a packet interface raw socket.
1920  * Bind it to the specified interface using a device independent physical layer address.
1921  */
1922 int fr_socket_packet(int if_index, struct sockaddr_ll *link_layer)
1923 {
1924  int lsock_fd;
1925 
1926  /*
1927  * PF_PACKET - packet interface on device level.
1928  * using a raw socket allows packet data to be unchanged by the device driver.
1929  */
1930  lsock_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
1931  if (lsock_fd < 0) {
1932  fr_strerror_printf("cannot open socket: %s", fr_syserror(errno));
1933  return lsock_fd;
1934  }
1935 
1936  /* Set link layer parameters */
1937  memset(link_layer, 0, sizeof(struct sockaddr_ll));
1938 
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;
1945 
1946  if (bind(lsock_fd, (struct sockaddr *)link_layer, sizeof(struct sockaddr_ll)) < 0) {
1947  close(lsock_fd);
1948  fr_strerror_printf("cannot bind raw socket: %s", fr_syserror(errno));
1949  return -1;
1950  }
1951 
1952  return lsock_fd;
1953 }
1954 
1955 /*
1956  * Encode and send a DHCP packet on a raw packet socket.
1957  */
1958 int fr_dhcp_send_raw_packet(int sockfd, struct sockaddr_ll *link_layer, RADIUS_PACKET *packet)
1959 {
1960  uint8_t dhcp_packet[1518] = { 0 };
1961  ethernet_header_t *eth_hdr = (ethernet_header_t *)dhcp_packet;
1962  ip_header_t *ip_hdr = (ip_header_t *)(dhcp_packet + ETH_HDR_SIZE);
1963  udp_header_t *udp_hdr = (udp_header_t *) (dhcp_packet + ETH_HDR_SIZE + IP_HDR_SIZE);
1964  dhcp_packet_t *dhcp = (dhcp_packet_t *)(dhcp_packet + ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE);
1965 
1966  uint16_t l4_len = (UDP_HDR_SIZE + packet->data_len);
1967  VALUE_PAIR *vp;
1968 
1969  /* set ethernet source address to our MAC address (DHCP-Client-Hardware-Address). */
1970  uint8_t dhmac[ETH_ADDR_LEN] = { 0 };
1971  if ((vp = fr_pair_find_by_num(packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY))) {
1972  if (vp->vp_length == sizeof(vp->vp_ether)) memcpy(dhmac, vp->vp_ether, vp->vp_length);
1973  }
1974 
1975  /* fill in Ethernet layer (L2) */
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);
1979 
1980  /* fill in IP layer (L3) */
1981  ip_hdr->ip_vhl = IP_VHL(4, 5);
1982  ip_hdr->ip_tos = 0;
1983  ip_hdr->ip_len = htons(IP_HDR_SIZE + UDP_HDR_SIZE + packet->data_len);
1984  ip_hdr->ip_id = 0;
1985  ip_hdr->ip_off = 0;
1986  ip_hdr->ip_ttl = 64;
1987  ip_hdr->ip_p = 17;
1988  ip_hdr->ip_sum = 0; /* Filled later */
1989 
1990  /* saddr: Packet-Src-IP-Address (default: 0.0.0.0). */
1991  ip_hdr->ip_src.s_addr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;
1992 
1993  /* daddr: packet destination IP addr (should be 255.255.255.255 for broadcast). */
1994  ip_hdr->ip_dst.s_addr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
1995 
1996  /* IP header checksum */
1997  ip_hdr->ip_sum = fr_ip_header_checksum((uint8_t const *)ip_hdr, 5);
1998 
1999  udp_hdr->src = htons(packet->src_port);
2000  udp_hdr->dst = htons(packet->dst_port);
2001 
2002  udp_hdr->len = htons(l4_len);
2003  udp_hdr->checksum = 0; /* UDP checksum will be done after dhcp header */
2004 
2005  /* DHCP layer (L7) */
2006 
2007  /* just copy what FreeRADIUS has encoded for us. */
2008  memcpy(dhcp, packet->data, packet->data_len);
2009 
2010  /* UDP checksum is done here */
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,
2013  packet->src_ipaddr.ipaddr.ip4addr, packet->dst_ipaddr.ipaddr.ip4addr);
2014 
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));
2017 }
2018 
2019 /*
2020  * print an ethernet address in a buffer
2021  */
2022 static char *ether_addr_print(const uint8_t *addr, char *buf)
2023 {
2024  sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
2025  return buf;
2026 }
2027 
2028 /*
2029  * For a client, receive a DHCP packet from a raw packet
2030  * socket. Make sure it matches the ongoing request.
2031  *
2032  * FIXME: split this into two, recv_raw_packet, and verify(packet, original)
2033  */
2034 RADIUS_PACKET *fr_dhcp_recv_raw_packet(int sockfd, struct sockaddr_ll *link_layer, RADIUS_PACKET *request)
2035 {
2036  VALUE_PAIR *vp;
2037  RADIUS_PACKET *packet;
2038  uint8_t const *code;
2039  uint32_t magic, xid;
2040  ssize_t data_len;
2041 
2042  uint8_t *raw_packet;
2043  ethernet_header_t *eth_hdr;
2044  ip_header_t *ip_hdr;
2045  udp_header_t *udp_hdr;
2046  dhcp_packet_t *dhcp_hdr;
2047  uint16_t udp_src_port;
2048  uint16_t udp_dst_port;
2049  size_t dhcp_data_len;
2050  socklen_t sock_len;
2051 
2052  packet = fr_radius_alloc(NULL, false);
2053  if (!packet) {
2054  fr_strerror_printf("Failed allocating packet");
2055  return NULL;
2056  }
2057 
2058  raw_packet = talloc_zero_array(packet, uint8_t, MAX_PACKET_SIZE);
2059  if (!raw_packet) {
2060  fr_strerror_printf("Out of memory");
2061  fr_radius_free(&packet);
2062  return NULL;
2063  }
2064 
2065  packet->sockfd = sockfd;
2066 
2067  /* a packet was received (but maybe it is not for us) */
2068  sock_len = sizeof(struct sockaddr_ll);
2069  data_len = recvfrom(sockfd, raw_packet, MAX_PACKET_SIZE, 0, (struct sockaddr *)link_layer, &sock_len);
2070 
2071  uint8_t data_offset = ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE; /* DHCP data datas after Ethernet, IP, UDP */
2072 
2073  if (data_len <= data_offset) DISCARD_RP("Payload (%d) smaller than required for layers 2+3+4", (int)data_len);
2074 
2075  /* map raw packet to packet header of the different layers (Ethernet, IP, UDP) */
2076  eth_hdr = (ethernet_header_t *)raw_packet;
2077 
2078  /*
2079  * Check Ethernet layer data (L2)
2080  */
2081  if (ntohs(eth_hdr->ether_type) != ETH_TYPE_IP) DISCARD_RP("Ethernet type (%d) != IP",
2082  ntohs(eth_hdr->ether_type));
2083 
2084  /*
2085  * If Ethernet destination is not broadcast (ff:ff:ff:ff:ff:ff)
2086  * Check if it matches the source HW address used (DHCP-Client-Hardware-Address = 267)
2087  */
2088  if ((memcmp(&eth_bcast, &eth_hdr->ether_dst, ETH_ADDR_LEN) != 0) &&
2089  (vp = fr_pair_find_by_num(request->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY)) &&
2090  (vp->vp_length == sizeof(vp->vp_ether)) && (memcmp(vp->vp_ether, &eth_hdr->ether_dst, ETH_ADDR_LEN) != 0)) {
2091  char eth_dest[17 + 1];
2092  char eth_req_src[17 + 1];
2093 
2094  /* No match. */
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));
2098  }
2099 
2100  /*
2101  * Ethernet is OK. Now look at IP.
2102  */
2103  ip_hdr = (ip_header_t *)(raw_packet + ETH_HDR_SIZE);
2104 
2105  /*
2106  * Check IPv4 layer data (L3)
2107  */
2108  if (ip_hdr->ip_p != IPPROTO_UDP) DISCARD_RP("IP protocol (%d) != UDP", ip_hdr->ip_p);
2109 
2110  /*
2111  * note: checking the destination IP address is not
2112  * useful (it would be the offered IP address - which we
2113  * don't know beforehand, or the broadcast address).
2114  */
2115 
2116  /*
2117  * Now check UDP.
2118  */
2119  udp_hdr = (udp_header_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE);
2120 
2121  /*
2122  * Check UDP layer data (L4)
2123  */
2124  udp_src_port = ntohs(udp_hdr->src);
2125  udp_dst_port = ntohs(udp_hdr->dst);
2126 
2127  /*
2128  * Check DHCP layer data
2129  */
2130  dhcp_data_len = data_len - data_offset;
2131 
2132  if (dhcp_data_len < MIN_PACKET_SIZE) DISCARD_RP("DHCP packet is too small (%zu < %i)",
2133  dhcp_data_len, MIN_PACKET_SIZE);
2134  if (dhcp_data_len > MAX_PACKET_SIZE) DISCARD_RP("DHCP packet is too large (%zu > %i)",
2135  dhcp_data_len, MAX_PACKET_SIZE);
2136 
2137  dhcp_hdr = (dhcp_packet_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE);
2138 
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);
2141 
2142  magic = ntohl(dhcp_hdr->option_format);
2143 
2144  if (magic != DHCP_OPTION_MAGIC_NUMBER) DISCARD_RP("DHCP magic cookie (0x%04x) != DHCP (0x%04x)",
2145  magic, DHCP_OPTION_MAGIC_NUMBER);
2146 
2147  /*
2148  * Reply transaction id must match value from request.
2149  */
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)",
2152  xid, request->id)
2153 
2154  /* all checks ok! this is a DHCP reply we're interested in. */
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);
2158  packet->id = xid;
2159 
2160  code = dhcp_get_option((dhcp_packet_t const *) packet->data, packet->data_len, PW_DHCP_MESSAGE_TYPE);
2161  if (!code) {
2162  fr_strerror_printf("No message-type option was found in the packet");
2163  fr_radius_free(&packet);
2164  return NULL;
2165  }
2166 
2167  if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
2168  fr_strerror_printf("Unknown value for message-type option");
2169  fr_radius_free(&packet);
2170  return NULL;
2171  }
2172 
2173  packet->code = code[2] | PW_DHCP_OFFSET;
2174 
2175  /*
2176  * Create a unique vector from the MAC address and the
2177  * DHCP opcode. This is a hack for the RADIUS
2178  * infrastructure in the rest of the server.
2179  *
2180  * Note: packet->data[2] == 6, which is smaller than
2181  * sizeof(packet->vector)
2182  *
2183  * FIXME: Look for client-identifier in packet,
2184  * and use that, too?
2185  */
2186  memset(packet->vector, 0, sizeof(packet->vector));
2187  memcpy(packet->vector, packet->data + 28, packet->data[2]);
2188  packet->vector[packet->data[2]] = packet->code & 0xff;
2189 
2190  packet->src_port = udp_src_port;
2191  packet->dst_port = udp_dst_port;
2192 
2193  packet->src_ipaddr.af = AF_INET;
2194  packet->src_ipaddr.ipaddr.ip4addr.s_addr = ip_hdr->ip_src.s_addr;
2195  packet->dst_ipaddr.af = AF_INET;
2196  packet->dst_ipaddr.ipaddr.ip4addr.s_addr = ip_hdr->ip_dst.s_addr;
2197 
2198  return packet;
2199 }
2200 #endif
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
Definition: pair.c:544
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.
Definition: dict.c:3611
int fr_dhcp_send_socket(RADIUS_PACKET *packet)
Send DHCP packet using socket.
Definition: dhcp.c:561
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
static int sockfd
Definition: radclient.c:59
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict.c:2426
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.
Definition: dhcp.c:1578
128 Bit IPv6 Address.
Definition: radius.h:40
#define DHCP_SNAME_LEN
Definition: dhcp.c:53
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.
Definition: dict.c:2613
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
struct timeval timestamp
When we received the packet.
Definition: libradius.h:159
#define DHCP_MAX_MESSAGE_TYPE
Definition: dhcp.c:159
uint8_t options[DHCP_VEND_LEN]
Definition: dhcp.c:107
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.
Definition: net.c:240
uint32_t yiaddr
Definition: dhcp.c:100
unsigned int array
Pack multiples into 1 attr.
Definition: dict.h:47
uint32_t xid
Definition: dhcp.c:96
#define PW_DHCP_OPTION_82
Definition: dhcp.h:99
uint32_t siaddr
Definition: dhcp.c:101
Dictionary attribute.
Definition: dict.h:77
int fr_ipaddr_from_sockaddr(struct sockaddr_storage const *sa, socklen_t salen, fr_ipaddr_t *ipaddr, uint16_t *port)
Definition: inet.c:1095
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
static uint8_t const * dhcp_get_option(dhcp_packet_t const *packet, size_t packet_size, unsigned int option)
Definition: dhcp.c:182
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
#define MAX_PACKET_SIZE
Definition: dhcp.c:176
ssize_t fr_link_layer_offset(uint8_t const *data, size_t len, int link_layer)
Returns the length of the link layer header.
Definition: net.c:95
int fr_dhcp_add_arp_entry(UNUSED int fd, UNUSED char const *interface, UNUSED VALUE_PAIR *macaddr, UNUSED VALUE_PAIR *ip)
Definition: dhcp.c:1908
int fr_dhcp_decode(RADIUS_PACKET *packet)
Definition: dhcp.c:1103
udp_header_t
Definition: net.h:134
#define VERIFY_VP(_x)
Definition: pair.h:44
#define UNUSED
Definition: libradius.h:134
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
Definition: dict.h:123
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
uint8_t hops
Definition: dhcp.c:95
#define DHCP_OPTION_MAGIC_NUMBER
Definition: dhcp.c:56
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
uint16_t secs
Definition: dhcp.c:97
uint8_t length
Definition: dhcp.c:112
Definition: token.h:46
uint8_t * data
Packet data (body).
Definition: libradius.h:160
uint32_t option_format
Definition: dhcp.c:106
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
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.
Definition: dhcp.c:338
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
uint32_t ciaddr
Definition: dhcp.c:99
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
fr_dict_attr_flags_t flags
Flags.
Definition: dict.h:88
uint8_t file[DHCP_FILE_LEN]
Definition: dhcp.c:105
RADIUS_PACKET * fr_dhcp_recv_socket(int sockfd)
Receive DHCP packet using socket.
Definition: dhcp.c:255
uint8_t sname[DHCP_SNAME_LEN]
Definition: dhcp.c:104
uint8_t chaddr[DHCP_CHADDR_LEN]
Definition: dhcp.c:103
unsigned int version
Definition: proto_bfd.c:192
#define DHCP_VEND_LEN
Definition: dhcp.c:55
void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src)
Reparent an allocated char buffer to a VALUE_PAIR.
Definition: pair.c:1955
int af
Address family.
Definition: inet.h:42
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
uint8_t opcode
Definition: dhcp.c:92
8 Bit unsigned integer.
Definition: radius.h:42
unsigned int is_unknown
Attribute number or vendor is unknown.
Definition: dict.h:42
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.
Definition: dhcp.c:1431
#define DHCP_FILE_FIELD
Definition: dhcp.c:179
void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp)
Merges multiple VALUE_PAIR into the cursor.
Definition: cursor.c:394
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.
Definition: dhcp.c:1031
uint8_t code
Definition: dhcp.c:111
uint8_t hlen
Definition: dhcp.c:94
#define DHCP_FILE_LEN
Definition: dhcp.c:54
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
Definition: cursor.c:321
#define DHCP_CHADDR_LEN
Definition: dhcp.c:52
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
Definition: dict.c:85
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.
Definition: dhcp.c:682
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
Definition: radius.c:1651
unsigned int attr
Attribute number.
Definition: dict.h:79
union fr_ipaddr_t::@1 ipaddr
unsigned int code
Packet code (type).
Definition: libradius.h:155
#define FR_PROTO_TRACE(_x,...)
Definition: proto.h:36
#define fr_assert(_x)
Definition: libradius.h:505
#define DHCP_OPTION_FIELD
Definition: dhcp.c:178
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
int fr_dhcp_encode(RADIUS_PACKET *packet)
Definition: dhcp.c:1629
48 Bit Mac-Address.
Definition: radius.h:44
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
VALUE_PAIR * fr_cursor_current(vp_cursor_t *cursor)
Return the VALUE_PAIR the cursor current points to.
Definition: cursor.c:304
#define DHCP_BASE_ATTR(x)
Definition: dhcp.h:101
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)
Definition: dhcp.c:724
int fr_udp_header_check(uint8_t const *data, uint16_t remaining, ip_header_t const *ip)
Check UDP header is valid.
Definition: net.c:186
#define DEBUG
Definition: dhcp.c:63
static int dhcp_header_sizes[]
Definition: dhcp.c:161
32 Bit unsigned integer.
Definition: radius.h:34
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
Definition: libradius.h:157
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
#define FR_PROTO_HEX_DUMP(_x, _y, _z)
Definition: proto.h:37
#define IP_VHL(v, hl)
Definition: net.h:83
#define FR_PROTO_STACK_PRINT(_x, _y)
Definition: proto.h:38
ethernet_header_t
Definition: net.h:96
int if_index
Index of receiving interface.
Definition: libradius.h:148
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.
Definition: dhcp.c:895
char name[1]
Attribute name.
Definition: dict.h:89
uint8_t data[]
Definition: eap_pwd.h:625
uint32_t zone_id
A host may have multiple link-local interfaces the scope ID allows the application to specify which o...
Definition: inet.h:48
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)
Definition: dhcp.c:1503
#define TAG_ANY
Definition: pair.h:191
void fr_pair_list_sort(VALUE_PAIR **vps, fr_cmp_t cmp)
Sort a linked list of VALUE_PAIRs using merge sort.
Definition: pair.c:1036
32 Bit Unix timestamp.
Definition: radius.h:36
int fr_pair_to_unknown(VALUE_PAIR *vp)
Mark malformed or unrecognised attributed as unknown.
Definition: pair.c:570
#define MIN_PACKET_SIZE
Definition: dhcp.c:174
uint16_t fr_ip_header_checksum(uint8_t const *data, uint8_t ihl)
Calculate IP header checksum.
Definition: net.c:275
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
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.
Definition: dhcp.c:1346
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
Definition: radius.c:1727
char const * dhcp_header_names[]
Definition: dhcp.c:121
int8_t fr_dhcp_attr_cmp(void const *a, void const *b)
Definition: dhcp.c:1309
size_t data_len
Length of packet data.
Definition: libradius.h:161
uint32_t giaddr
Definition: dhcp.c:102
uint16_t flags
Definition: dhcp.c:98
uint8_t htype
Definition: dhcp.c:93
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
#define DHCP_MAGIC_VENDOR
Definition: dhcp.h:97
ip_header_t
Definition: net.h:113
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.
Definition: pair.c:639
#define DEFAULT_PACKET_SIZE
Definition: dhcp.c:175
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
Definition: pair.c:58
IPv4/6 prefix.
Definition: inet.h:41
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
#define DHCP_SNAME_FIELD
Definition: dhcp.c:180
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
Definition: pair.c:2043
String of printable characters.
Definition: radius.h:33
Contains nested attributes.
Definition: radius.h:47
#define vp_length
Definition: pair.h:182
PW_TYPE type
Value type.
Definition: dict.h:80
#define RCSID(id)
Definition: build.h:135
void fr_proto_tlv_stack_build(fr_dict_attr_t const **tlv_stack, fr_dict_attr_t const *da)
Definition: proto.c:94
#define PW_DHCP_MESSAGE_TYPE
Definition: dhcp.h:104
32 Bit IPv4 Address.
Definition: radius.h:35
fr_dict_t * fr_dict_internal
Internal server dictionary.
Definition: dict.c:81
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict.c:2339
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.
Definition: pair.c:338
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
#define PW_DHCP_OFFSET
Definition: dhcp.h:73
int fr_ipaddr_to_sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port, struct sockaddr_storage *sa, socklen_t *salen)
Definition: inet.c:1057
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)
Definition: dhcp.c:975
struct dhcp_packet_t dhcp_packet_t
char const * dhcp_message_types[]
Definition: dhcp.c:140