The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 35cc68562350bc12e6c8860fd41b57a61cbeb98d $
19  *
20  * @file protocols/dhcpv6/base.c
21  * @brief Functions to encode DHCP options.
22  *
23  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24  *
25  * @copyright 2018 The FreeRADIUS server project
26  * @copyright 2018 NetworkRADIUS SARL (legal@networkradius.com)
27  */
28 #include <freeradius-devel/io/pair.h>
29 #include <freeradius-devel/protocol/dhcpv6/freeradius.internal.h>
30 #include <freeradius-devel/protocol/dhcpv6/rfc3315.h>
31 #include <freeradius-devel/protocol/dhcpv6/rfc5007.h>
32 #include <freeradius-devel/util/proto.h>
33 #include <freeradius-devel/util/rand.h>
34 
35 #include "dhcpv6.h"
36 #include "attrs.h"
37 
39 
41 
44  { .out = &dict_dhcpv6, .proto = "dhcpv6" },
45  { NULL }
46 };
47 
55 
58  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_dhcpv6 },
59  { .out = &attr_transaction_id, .name = "Transaction-Id", .type = FR_TYPE_OCTETS, .dict = &dict_dhcpv6 },
60  { .out = &attr_hop_count, .name = "Hop-Count", .type = FR_TYPE_UINT8, .dict = &dict_dhcpv6 },
61  { .out = &attr_relay_link_address, .name = "Relay-Link-Address", .type = FR_TYPE_IPV6_ADDR, .dict = &dict_dhcpv6 },
62  { .out = &attr_relay_peer_address, .name = "Relay-Peer-Address", .type = FR_TYPE_IPV6_ADDR, .dict = &dict_dhcpv6 },
63  { .out = &attr_relay_message, .name = "Relay-Message", .type = FR_TYPE_GROUP, .dict = &dict_dhcpv6 },
64  { .out = &attr_option_request, .name = "Option-Request", .type = FR_TYPE_UINT16, .dict = &dict_dhcpv6 },
65  { NULL }
66 };
67 
68 /*
69  * grep VALUE share/dictionary/dhcpv6/dictionary.freeradius.internal | awk '{print "[" $4 "] = \"" $3 "\"," }'
70  */
72  [0] = "invalid",
73  [FR_PACKET_TYPE_VALUE_SOLICIT] = "Solicit",
74  [FR_PACKET_TYPE_VALUE_ADVERTISE] = "Advertise",
75  [FR_PACKET_TYPE_VALUE_REQUEST] = "Request",
76  [FR_PACKET_TYPE_VALUE_CONFIRM] = "Confirm",
77  [FR_PACKET_TYPE_VALUE_RENEW] = "Renew",
78  [FR_PACKET_TYPE_VALUE_REBIND] = "Rebind",
79  [FR_PACKET_TYPE_VALUE_REPLY] = "Reply",
80  [FR_PACKET_TYPE_VALUE_RELEASE] = "Release",
81  [FR_PACKET_TYPE_VALUE_DECLINE] = "Decline",
82  [FR_PACKET_TYPE_VALUE_RECONFIGURE] = "Reconfigure",
83  [FR_PACKET_TYPE_VALUE_INFORMATION_REQUEST] = "Information-Request",
84  [FR_PACKET_TYPE_VALUE_RELAY_FORWARD] = "Relay-Forward",
85  [FR_PACKET_TYPE_VALUE_RELAY_REPLY] = "Relay-Reply",
86  [FR_PACKET_TYPE_VALUE_LEASE_QUERY] = "Lease-Query",
87  [FR_PACKET_TYPE_VALUE_LEASE_QUERY_REPLY] = "Lease-Query-Reply",
88  [FR_PACKET_TYPE_VALUE_LEASE_QUERY_DONE] = "Lease-Query-Done",
89  [FR_PACKET_TYPE_VALUE_LEASE_QUERY_DATA] = "Lease-Query-Data",
90  [FR_PACKET_TYPE_VALUE_RECONFIGURE_REQUEST] = "Reconfigure-Request",
91  [FR_PACKET_TYPE_VALUE_RECONFIGURE_REPLY] = "Reconfigure-Reply",
92  [FR_PACKET_TYPE_VALUE_DHCPV4_QUERY] = "DHCPv4-Query",
93  [FR_PACKET_TYPE_VALUE_DHCPV4_RESPONSE] = "DHCPv4-Response",
94  [FR_PACKET_TYPE_VALUE_ACTIVE_LEASE_QUERY] = "Active-Lease-Query",
95  [FR_PACKET_TYPE_VALUE_START_TLS] = "Start-TLS",
96  [FR_PACKET_TYPE_VALUE_BIND_UPDATE] = "Bind-Update",
97  [FR_PACKET_TYPE_VALUE_BIND_REPLY] = "Bind-Reply",
98  [FR_PACKET_TYPE_VALUE_POOL_REQUEST] = "Pool-Request",
99  [FR_PACKET_TYPE_VALUE_POOL_RESPONSE] = "Pool-Response",
100  [FR_PACKET_TYPE_VALUE_UPDATE_REQUEST] = "Update-Request",
101  [FR_PACKET_TYPE_VALUE_UPDATE_REQUEST_ALL] = "Update-Request-All",
102  [FR_PACKET_TYPE_VALUE_UPDATE_DONE] = "Update-Done",
103  [FR_PACKET_TYPE_VALUE_CONNECT] = "Connect",
104  [FR_PACKET_TYPE_VALUE_CONNECT_REPLY] = "Connect-Reply",
105  [FR_PACKET_TYPE_VALUE_DISCONNECT] = "Disconnect",
106  [FR_PACKET_TYPE_VALUE_STATE] = "State",
107  [FR_PACKET_TYPE_VALUE_CONTACT] = "Contact"
108 };
109 
111  { L("dns_label"), FLAG_ENCODE_DNS_LABEL },
112  { L("partial_dns_label"), FLAG_ENCODE_PARTIAL_DNS_LABEL }
113 };
114 
115 static ssize_t fr_dhcpv6_ok_internal(uint8_t const *packet, uint8_t const *end, size_t max_attributes, int depth);
116 
117 static ssize_t fr_dhcpv6_options_ok(uint8_t const *packet, uint8_t const *end, size_t max_attributes,
118  bool allow_relay, int depth)
119 {
120  size_t attributes;
121  uint8_t const *p;
122 
123  attributes = 0;
124  p = packet;
125 
126  while (p < end) {
127  uint16_t len;
128 
129  if ((size_t)(end - p) < DHCPV6_OPT_HDR_LEN) {
130  fr_strerror_const("Not enough room for option header");
131  return -(p - packet);
132  }
133 
134  len = DHCPV6_GET_OPTION_LEN(p);
135  if ((size_t)(end - p) < (DHCPV6_OPT_HDR_LEN + len)) {
136  fr_strerror_const("Option length overflows the packet");
137  return -(p - packet);
138  }
139 
140  attributes++;
141  if (attributes > (size_t) max_attributes) {
142  fr_strerror_const("Too many attributes");
143  return -(p - packet);
144  }
145 
146  /*
147  * Recurse into the Relay-Message attribute, but
148  * only if the outer packet was a relayed message.
149  */
150  if (allow_relay && (p[0] == 0) && (p[1] == attr_relay_message->attr)) {
151  ssize_t child;
152 
153  /*
154  * Recurse to check the encapsulated packet.
155  */
156  child = fr_dhcpv6_ok_internal(p + 4, p + 4 + len, max_attributes - attributes, depth + 1);
157  if (child <= 0) return -((p + 4) - packet) + child;
158 
159  attributes += child;
160  }
161 
162  p += DHCPV6_OPT_HDR_LEN + len;
163  }
164 
165  return attributes;
166 }
167 
168 static ssize_t fr_dhcpv6_ok_internal(uint8_t const *packet, uint8_t const *end, size_t max_attributes, int depth)
169 {
170  uint8_t const *p;
171  ssize_t attributes;
172  bool allow_relay;
173  size_t packet_len = end - packet;
174 
175  if (end == packet) {
176  fr_strerror_const("Packet is empty");
177  return 0;
178  }
179 
181  fr_strerror_const("Too many layers forwarded packets");
182  return 0;
183  }
184 
185  switch (packet[0]) {
188  if (packet_len < DHCPV6_RELAY_HDR_LEN) {
189  fr_strerror_const("Packet is too small for relay header");
190  return 0;
191  }
192 
193  p = packet + DHCPV6_RELAY_HDR_LEN;
194  allow_relay = true;
195  break;
196 
197  default:
198  /*
199  * 8 bit code + 24 bits of transaction ID
200  */
201  if (packet_len < DHCPV6_HDR_LEN) {
202  fr_strerror_const("Packet is too small for DHCPv6 header");
203  return 0;
204  }
205 
206  p = packet + DHCPV6_HDR_LEN;
207  allow_relay = false;
208  break;
209  }
210 
211  attributes = fr_dhcpv6_options_ok(p, end, max_attributes, allow_relay, depth);
212  if (attributes < 0) return -(p - packet) + attributes;
213 
214  return attributes;
215 }
216 
217 
218 /** See if the data pointed to by PTR is a valid DHCPv6 packet.
219  *
220  * @param[in] packet to check.
221  * @param[in] packet_len The size of the packet data.
222  * @param[in] max_attributes to allow in the packet.
223  * @return
224  * - True on success.
225  * - False on failure.
226  */
227 bool fr_dhcpv6_ok(uint8_t const *packet, size_t packet_len, uint32_t max_attributes)
228 {
229  ssize_t slen;
230 
231  slen = fr_dhcpv6_ok_internal(packet, packet + packet_len, max_attributes, 0);
232  if (slen <= 0) {
233  fr_strerror_printf_push("Invalid DHCPv6 packet starting at offset %zd", -slen);
234  return false;
235  }
236 
237  return true;
238 }
239 
240 /*
241  * Return pointer to a particular option.
242  */
243 uint8_t const *fr_dhcpv6_option_find(uint8_t const *start, uint8_t const *end, unsigned int option)
244 {
245  uint8_t const *p = start;
246 
247  while (p < end) {
248  uint16_t found;
249  uint16_t len;
250 
251  if ((size_t)(end - p) < DHCPV6_OPT_HDR_LEN) return NULL;
252 
253  found = DHCPV6_GET_OPTION_NUM(p);
254  len = DHCPV6_GET_OPTION_LEN(p);
255 
256  if ((p + DHCPV6_OPT_HDR_LEN + len) > end) return NULL;
257 
258  if (found == option) return p;
259 
260  p += DHCPV6_OPT_HDR_LEN + len;
261  }
262 
263  return NULL;
264 }
265 
266 static bool duid_match(uint8_t const *option, fr_dhcpv6_decode_ctx_t const *packet_ctx)
267 {
268  uint16_t len;
269 
270  len = DHCPV6_GET_OPTION_LEN(option);
271  if (len != packet_ctx->duid_len) return false;
272  if (memcmp(option + 4, packet_ctx->duid, packet_ctx->duid_len) != 0) return false;
273 
274  return true;
275 }
276 
277 /** Verify a reply packet from a server to a client
278  *
279  */
280 static bool verify_to_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx)
281 {
282  uint32_t transaction_id;
283  uint8_t const *option;
284  uint8_t const *options = packet + 4;
285  uint8_t const *end = packet + packet_len;
286 
287  switch (packet[0]) {
288  case FR_PACKET_TYPE_VALUE_ADVERTISE:
289  transaction_id = fr_nbo_to_uint24(&packet[1]);
290  if (transaction_id != packet_ctx->transaction_id) {
291  fail_tid:
292  fr_strerror_const("Transaction ID does not match");
293  return false;
294  }
295 
296  if (!fr_dhcpv6_option_find(options, end, FR_SERVER_ID)) {
297  fail_sid:
298  fr_strerror_const("Packet does not contain a Server-Id option");
299  return false;
300  }
301 
302  option = fr_dhcpv6_option_find(options, end, FR_CLIENT_ID);
303  if (!option) {
304  fail_cid:
305  fr_strerror_const("Packet does not contain a Client-Id option");
306  return false;
307  }
308 
309  /*
310  * The DUID MUST exist.
311  */
312  if (!packet_ctx->duid) {
313  fail_duid:
314  fr_strerror_const("Packet context does not contain a DUID");
315  return false;
316  }
317 
318  check_duid:
319  if (!duid_match(option, packet_ctx)) {
320  fail_match:
321  fr_strerror_const("DUID in packet does not match our DUID");
322  return false;
323  }
324  return true;
325 
326  case FR_PACKET_TYPE_VALUE_REPLY:
327  transaction_id = fr_nbo_to_uint24(&packet[1]);
328  if (transaction_id != packet_ctx->transaction_id) goto fail_tid;
329 
330  if (!fr_dhcpv6_option_find(options, end, FR_SERVER_ID)) goto fail_sid;
331 
332  /*
333  * It's OK to not have a client ID in the reply if we didn't send one.
334  */
335  option = fr_dhcpv6_option_find(options, end, FR_CLIENT_ID);
336  if (!option) {
337  if (!packet_ctx->duid) return true;
338  goto fail_cid;
339  }
340  goto check_duid;
341 
342  case FR_PACKET_TYPE_VALUE_RECONFIGURE:
343  if (!fr_dhcpv6_option_find(options, end, FR_SERVER_ID)) goto fail_sid;
344 
345  option = fr_dhcpv6_option_find(options, end, FR_CLIENT_ID);
346  if (!option) goto fail_cid;
347 
348  /*
349  * The DUID MUST exist.
350  */
351  if (!packet_ctx->duid) goto fail_duid;
352  if (!duid_match(option, packet_ctx)) goto fail_match;
353 
354  option = fr_dhcpv6_option_find(options, end, FR_RECONF_MSG);
355  if (!option) {
356  fr_strerror_const("Packet does not contain a Reconf-Msg option");
357  return false;
358  }
359 
360  /*
361  * @todo - check reconfigure message type, and
362  * reject if it doesn't match.
363  */
364 
365  /*
366  * @todo - check for authentication option and
367  * verify it.
368  */
369  break;
370 
372  if (packet_len < DHCPV6_RELAY_HDR_LEN) {
373  fr_strerror_const("Relay-Reply message is too small");
374  return false;
375  }
376 
377  options += (DHCPV6_RELAY_HDR_LEN - 4); /* we assumed it was a normal packet above */
378  option = fr_dhcpv6_option_find(options, end, FR_RELAY_MESSAGE);
379  if (!option) {
380  fr_strerror_const("Packet does not contain a Relay-Message option");
381  return false;
382  }
383  return verify_to_client(option + 4, DHCPV6_GET_OPTION_LEN(option), packet_ctx);
384 
386  transaction_id = fr_nbo_to_uint24(&packet[1]);
387  if (transaction_id != packet_ctx->transaction_id) goto fail_tid;
388 
389  if (!fr_dhcpv6_option_find(options, end, FR_SERVER_ID)) goto fail_sid;
390 
391  option = fr_dhcpv6_option_find(options, end, FR_CLIENT_ID);
392  if (!option) goto fail_cid;
393 
394  /*
395  * The DUID MUST exist.
396  */
397  if (!packet_ctx->duid) goto fail_duid;
398  if (!duid_match(option, packet_ctx)) goto fail_match;
399  break;
400 
401  case FR_PACKET_TYPE_VALUE_REQUEST:
402  case FR_PACKET_TYPE_VALUE_CONFIRM:
403  case FR_PACKET_TYPE_VALUE_RENEW:
404  case FR_PACKET_TYPE_VALUE_REBIND:
405  case FR_PACKET_TYPE_VALUE_RELEASE:
406  case FR_PACKET_TYPE_VALUE_DECLINE:
407  case FR_PACKET_TYPE_VALUE_INFORMATION_REQUEST:
408  default:
409  fr_strerror_const("Invalid message type sent to client");
410  return false;
411  }
412 
413  return true;
414 }
415 
416 
417 /** Verify a packet from a client to a server
418  *
419  */
420 static bool verify_from_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx)
421 {
422  uint8_t const *option;
423  uint8_t const *options = packet + 4;
424  uint8_t const *end = packet + packet_len;
425 
426  /*
427  * Servers MUST have a DUID
428  */
429  if (!packet_ctx->duid) {
430  fr_strerror_const("Packet context does not contain a DUID");
431  return false;
432  }
433 
434  switch (packet[0]) {
435  case FR_PACKET_TYPE_VALUE_SOLICIT:
436  case FR_PACKET_TYPE_VALUE_CONFIRM:
437  case FR_PACKET_TYPE_VALUE_REBIND:
438  if (!fr_dhcpv6_option_find(options, end, FR_CLIENT_ID)) {
439  fail_cid:
440  fr_strerror_const("Packet does not contain a Client-Id option");
441  return false;
442  }
443 
444  if (!fr_dhcpv6_option_find(options, end, FR_SERVER_ID)) {
445  fail_sid:
446  fr_strerror_const("Packet does not contain a Server-Id option");
447  return false;
448  }
449  break;
450 
451  case FR_PACKET_TYPE_VALUE_REQUEST:
452  case FR_PACKET_TYPE_VALUE_RENEW:
453  case FR_PACKET_TYPE_VALUE_DECLINE:
454  case FR_PACKET_TYPE_VALUE_RELEASE:
455  if (!fr_dhcpv6_option_find(options, end, FR_CLIENT_ID)) goto fail_cid;
456 
457  option = fr_dhcpv6_option_find(options, end, FR_SERVER_ID);
458  if (!option) goto fail_sid;
459 
460  if (!duid_match(option, packet_ctx)) {
461  fail_match:
462  fr_strerror_const("DUID in packet does not match our DUID");
463  return false;
464  }
465  break;
466 
467  case FR_PACKET_TYPE_VALUE_INFORMATION_REQUEST:
468  option = fr_dhcpv6_option_find(options, end, FR_SERVER_ID);
469  if (!option) goto fail_sid;
470 
471  if (!duid_match(option, packet_ctx)) goto fail_match;
472 
473  /*
474  * IA options are forbidden.
475  */
476  if (fr_dhcpv6_option_find(options, end, FR_IA_NA)) {
477  fr_strerror_const("Packet contains an IA-NA option");
478  return false;
479  }
480  if (fr_dhcpv6_option_find(options, end, FR_IA_TA)) {
481  fr_strerror_const("Packet contains an IA-TA option");
482  return false;
483  }
484  if (fr_dhcpv6_option_find(options, end, FR_IA_ADDR)) {
485  fr_strerror_const("Packet contains an IA-Addr option");
486  return false;
487  }
488  break;
489 
491  if (packet_len < DHCPV6_RELAY_HDR_LEN) {
492  fr_strerror_const("Relay-Forward message is too small");
493  return false;
494  }
495 
496  options += (DHCPV6_RELAY_HDR_LEN - 4); /* we assumed it was a normal packet above */
497  option = fr_dhcpv6_option_find(options, end, FR_RELAY_MESSAGE);
498  if (!option) {
499  fr_strerror_const("Packet does not contain a Relay-Message option");
500  return false;
501  }
502 
503  return verify_from_client(option + 4, DHCPV6_GET_OPTION_LEN(option), packet_ctx);
504 
505  case FR_PACKET_TYPE_VALUE_LEASE_QUERY:
506  if (!fr_dhcpv6_option_find(options, end, FR_CLIENT_ID)) goto fail_cid;
507 
508  /*
509  * Server-ID is a SHOULD, but if it exists, it
510  * MUST match.
511  */
512  option = fr_dhcpv6_option_find(options, end, FR_SERVER_ID);
513  if (option && !duid_match(option, packet_ctx)) goto fail_match;
514 
515  option = fr_dhcpv6_option_find(options, end, FR_LEASE_QUERY);
516  if (!option) {
517  fr_strerror_const("Packet does not contain a Lease-Query option");
518  return false;
519  }
520  break;
521 
522  case FR_PACKET_TYPE_VALUE_ADVERTISE:
523  case FR_PACKET_TYPE_VALUE_REPLY:
524  case FR_PACKET_TYPE_VALUE_RECONFIGURE:
525  default:
526  fr_strerror_const("Invalid message type sent to server");
527  return false;
528  }
529  return true;
530 }
531 
532 /** Verify the packet under some various circumstances
533  *
534  * @param[in] packet to check.
535  * @param[in] packet_len The size of the packet data.
536  * @param[in] packet_ctx The expected packet_ctx
537  * @param[in] from_server true for packets from a server, false for packets from a client.
538  * @return
539  * - True on success.
540  * - False on failure.
541  *
542  * fr_dhcpv6_ok() SHOULD be called before calling this function.
543  */
544 bool fr_dhcpv6_verify(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx,
545  bool from_server)
546 {
547  if (packet_len < DHCPV6_HDR_LEN) return false;
548 
549  /*
550  * We support up to relaying.
551  */
552  if ((packet[0] == 0) || (packet[0] > FR_PACKET_TYPE_VALUE_RELAY_REPLY)) return false;
553 
554  if (!packet_ctx->duid) return false;
555 
556  if (from_server) return verify_to_client(packet, packet_len, packet_ctx);
557 
558  return verify_from_client(packet, packet_len, packet_ctx);
559 }
560 
561 /*
562 
563  0 1 2 3
564  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
565  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
566  | msg-type | transaction-id |
567  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
568  | |
569  . options .
570  . (variable number and length) .
571  | |
572  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
573 */
574 
575 /** Decode a DHCPv6 packet
576  *
577  */
578 ssize_t fr_dhcpv6_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *packet, size_t packet_len)
579 {
580  ssize_t slen = -1;
581  uint8_t const *p, *end;
582  fr_dhcpv6_decode_ctx_t packet_ctx = {};
583  fr_pair_t *vp;
584  fr_pair_list_t tmp;
585 
586  if (packet_len < DHCPV6_HDR_LEN) return 0; /* protect access to packet[0] */
587 
588  /*
589  * Get the packet type.
590  */
592  if (!vp) return -1;
593 
594  fr_pair_list_init(&tmp);
595  vp->vp_uint32 = packet[0];
596  fr_pair_append(&tmp, vp);
597 
598  switch (packet[0]) {
601  /*
602  * Just for sanity check.
603  */
604  if (packet_len < DHCPV6_RELAY_HDR_LEN) return -1;
605 
606  /*
607  * Decode the header fields.
608  */
610  if (!vp) goto fail;
611  if (fr_value_box_from_network(vp, &vp->data, vp->vp_type, NULL,
612  &FR_DBUFF_TMP(packet + 1, 1), 1, true) < 0) {
613  goto fail;
614  }
615  fr_pair_append(&tmp, vp);
616 
618  if (!vp) goto fail;
619  if (fr_value_box_from_network(vp, &vp->data, vp->vp_type, NULL,
620  &FR_DBUFF_TMP(packet + 2, 16), 16, true) < 0) {
621  goto fail;
622  }
623  fr_pair_append(&tmp, vp);
624 
626  if (!vp) goto fail;
627  if (fr_value_box_from_network(vp, &vp->data, vp->vp_type, NULL,
628  &FR_DBUFF_TMP(packet + 2 + 16, 16), 16, true) < 0) {
629  goto fail;
630  }
631 
632  fr_pair_append(&tmp, vp);
633 
634  p = packet + DHCPV6_RELAY_HDR_LEN;
635  goto decode_options;
636 
637  default:
638  break;
639  }
640 
641  /*
642  * And the transaction ID.
643  */
645  if (!vp) {
646  fail:
647  fr_pair_list_free(&tmp);
648  return slen;
649  }
650 
651  /*
652  * Copy 3 octets over.
653  */
654  (void) fr_pair_value_memdup(vp, packet + 1, 3, false);
655 
656  fr_pair_append(&tmp, vp);
657 
658  p = packet + 4;
659 
660 decode_options:
661  end = packet + packet_len;
662  packet_ctx.tmp_ctx = talloc_init_const("tmp");
663 
664  /*
665  * The caller MUST have called fr_dhcpv6_ok() first. If
666  * he doesn't, all hell breaks loose.
667  */
668  while (p < end) {
669  slen = fr_dhcpv6_decode_option(ctx, &tmp, p, (end - p), &packet_ctx);
670  if (slen < 0) {
671  talloc_free(packet_ctx.tmp_ctx);
672  goto fail;
673  }
674  /*
675  * If slen is larger than the room in the packet,
676  * all kinds of bad things happen.
677  */
678  if (!fr_cond_assert(slen <= (end - p))) {
679  talloc_free(packet_ctx.tmp_ctx);
680  goto fail;
681  }
682 
683  p += slen;
684  talloc_free_children(packet_ctx.tmp_ctx);
685  }
686  fr_pair_list_append(out, &tmp);
687 
688  /*
689  * We've parsed the whole packet, return that.
690  */
691  talloc_free(packet_ctx.tmp_ctx);
692  return packet_len;
693 }
694 
695 /** DHCPV6-specific iterator
696  *
697  */
698 void *fr_dhcpv6_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
699 {
700  fr_pair_t *c = current;
701  fr_dict_t *dict = talloc_get_type_abort(uctx, fr_dict_t);
702 
703  while ((c = fr_dlist_next(list, c))) {
704  PAIR_VERIFY(c);
705  if (c->da->dict != dict || c->da->flags.internal) continue;
706  if (c->vp_type == FR_TYPE_BOOL && !c->vp_bool) continue;
707 
708  break;
709  }
710 
711  return c;
712 }
713 
714 /** Encode a DHCPv6 packet
715  *
716  */
717 ssize_t fr_dhcpv6_encode(fr_dbuff_t *dbuff, uint8_t const *original, size_t length, int msg_type, fr_pair_list_t *vps)
718 {
719  fr_dbuff_t frame_dbuff = FR_DBUFF(dbuff);
720  fr_pair_t *vp;
721  fr_dict_attr_t const *root;
722  ssize_t slen;
723  fr_dcursor_t cursor;
724  fr_dhcpv6_encode_ctx_t packet_ctx;
725 
726  root = fr_dict_root(dict_dhcpv6);
727 
728  if (!msg_type) {
729  vp = fr_pair_find_by_da(vps, NULL, attr_packet_type);
730  if (vp) msg_type = vp->vp_uint32;
731  }
732 
733  if ((msg_type <= 0) || (msg_type > UINT8_MAX)) {
734  fr_strerror_printf("Invalid message type %d", msg_type);
735  return -1;
736  }
737 
738  FR_DBUFF_IN_RETURN(&frame_dbuff, (uint8_t)msg_type);
739 
740  switch (msg_type) {
743  vp = fr_pair_find_by_da(vps, NULL, attr_hop_count);
744  if (likely(vp != NULL)) {
745  FR_VALUE_BOX_TO_NETWORK_RETURN(&frame_dbuff, &vp->data);
746  } else {
748  }
749 
751  if (likely(vp != NULL)) {
752  FR_VALUE_BOX_TO_NETWORK_RETURN(&frame_dbuff, &vp->data);
753  } else {
755  }
756 
758  if (likely(vp != NULL)) {
759  FR_VALUE_BOX_TO_NETWORK_RETURN(&frame_dbuff, &vp->data);
760  } else {
762  }
763  break;
764 
765  default:
766  /*
767  * We can set an XID, or we can pick a random one.
768  */
770  if (vp && (vp->vp_length >= DHCPV6_TRANSACTION_ID_LEN)) {
771  FR_DBUFF_IN_MEMCPY_RETURN(&frame_dbuff, vp->vp_octets, DHCPV6_TRANSACTION_ID_LEN);
772  } else {
775  FR_DBUFF_IN_MEMCPY_RETURN(&frame_dbuff, id, sizeof(id)); /* Need 24 bits of the 32bit integer */
776  }
777  break;
778  }
779 
780  /*
781  * Encode options.
782  */
783  packet_ctx.root = root;
784  packet_ctx.original = original;
785  packet_ctx.original_length = length;
786 
788  while ((fr_dbuff_extend(&frame_dbuff) > 0) && (fr_dcursor_current(&cursor) != NULL)) {
789  slen = fr_dhcpv6_encode_option(&frame_dbuff, &cursor, &packet_ctx);
790  if (slen < 0) return slen - fr_dbuff_used(&frame_dbuff);
791  }
792 
793  return fr_dbuff_set(dbuff, &frame_dbuff);
794 }
795 
796 
797 static char const tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
798 
799 static void print_hex_data(FILE *fp, uint8_t const *ptr, int attrlen, int depth)
800 {
801  int i;
802 
803  for (i = 0; i < attrlen; i++) {
804  if ((i > 0) && ((i & 0x0f) == 0x00))
805  fprintf(fp, "%.*s", depth, tabs);
806  fprintf(fp, "%02x ", ptr[i]);
807  if ((i & 0x0f) == 0x0f) fprintf(fp, "\n");
808  }
809  if ((i & 0x0f) != 0) fprintf(fp, "\n");
810 }
811 
812 static void dhcpv6_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len, int depth)
813 {
814  uint8_t const *option, *end = packet + packet_len;
815 
816  if (packet_len < 4) {
817  fprintf(fp, "%.*s", depth, tabs);
818  fprintf(fp, "???:\t");
819  print_hex_data(fp, packet, packet_len, depth + 1);
820  return;
821  }
822 
823  fprintf(fp, "%.*s", depth, tabs);
824  if ((packet[0] > 0) && (packet[0] < FR_DHCPV6_CODE_MAX)) {
825  fprintf(fp, "packet: %s\n", fr_dhcpv6_packet_names[packet[0]]);
826  } else {
827  fprintf(fp, "packet: %02x\n", packet[0]);
828  }
829 
830  if ((packet[0] == FR_PACKET_TYPE_VALUE_RELAY_FORWARD) ||
831  (packet[0] == FR_PACKET_TYPE_VALUE_RELAY_REPLY)) {
832  if (packet_len < 34) {
833  fprintf(fp, "%.*s", depth, tabs);
834  fprintf(fp, "???:\t");
835  print_hex_data(fp, packet + 1, packet_len - 1, depth + 1);
836  return;
837  }
838 
839  fprintf(fp, "%.*s", depth, tabs);
840  fprintf(fp, "hops: %02x\n", packet[1]);
841  fprintf(fp, "%.*s", depth, tabs);
842  fprintf(fp, "relay link address: ");
843  print_hex_data(fp, packet + 2, 16, depth + 1);
844 
845  fprintf(fp, "%.*s", depth, tabs);
846  fprintf(fp, "peer address: ");
847  print_hex_data(fp, packet + 18, 16, depth + 1);
848  option = packet + 34;
849  } else {
850  fprintf(fp, "%.*s", depth, tabs);
851  fprintf(fp, "transaction id: ");
852  print_hex_data(fp, packet + 1, 3, depth + 1);
853  option = packet + 4;
854  }
855 
856  fprintf(fp, "%.*s", depth, tabs);
857  fprintf(fp, "options\n");
858  while (option < end) {
859  uint16_t length;
860 
861  if ((end - option) < 4) {
862  fprintf(fp, "%.*s", depth + 1, tabs);
863  fprintf(fp, "???:\t");
864  print_hex_data(fp, option, end - option, depth + 2);
865  break;
866  }
867 
868  length = fr_nbo_to_uint16(option + 2);
869  fprintf(fp, "%.*s", depth + 1, tabs);
870  fprintf(fp, "%04x %04x\t", fr_nbo_to_uint16(option), length);
871 
872  if (length > end - (option + 4)) {
873  print_hex_data(fp, option + 4, end - (option + 4), depth + 3);
874  break;
875  }
876 
877  print_hex_data(fp, option + 4, length, depth + 3);
878  if ((option[0] == 0) && (option[1] == attr_relay_message->attr)) {
879  dhcpv6_print_hex(fp, option + 4, length, depth + 2);
880  }
881 
882  option += 4 + length;
883  }
884 
885  fprintf(fp, "\n");
886 }
887 
888 /** Print a raw DHCP packet as hex.
889  *
890  */
891 void fr_dhcpv6_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len)
892 {
893  dhcpv6_print_hex(fp, packet, packet_len, 0);
894 }
895 
897 {
898  fr_dict_attr_t const *child;
900 
901  if (instance_count > 0) {
902  instance_count++;
903  return 0;
904  }
905 
906  instance_count++;
907 
909  fail:
910  instance_count--;
911  return -1;
912  }
913 
916  goto fail;
917  }
918 
919  /*
920  * Fixup dictionary entry for DHCP-Paramter-Request-List adding all the options
921  */
922  child = NULL;
923  while ((child = fr_dict_attr_iterate_children(fr_dict_root(dict_dhcpv6), &child)) != NULL) {
924  if (child->flags.internal) continue;
925 
926  value.vb_uint16 = child->attr;
927 
929  child->name, &value, true, false) < 0) {
931  goto fail;
932  }
933  }
934 
935  return 0;
936 }
937 
939 {
941 
942  if (--instance_count > 0) return;
943 
945 }
946 
948  UNUSED char const *name, UNUSED int attr, fr_type_t type, fr_dict_attr_flags_t *flags)
949 {
950  /*
951  * "arrays" of string/octets are encoded as a 16-bit
952  * length, followed by the actual data.
953  */
954  if (flags->array && ((type == FR_TYPE_STRING) || (type == FR_TYPE_OCTETS))) {
955  flags->is_known_width = true;
956 
957  if (flags->extra && (flags->subtype != FLAG_LENGTH_UINT16)) {
958  fr_strerror_const("string/octets arrays require the 'length=uint16' flag");
959  return false;
960  }
961  }
962 
963  if (flags->extra && (flags->subtype == FLAG_LENGTH_UINT8)) {
964  fr_strerror_const("The 'length=uint8' flag cannot be used for DHCPv6");
965  return false;
966  }
967 
968  /*
969  * "extra" signifies that subtype is being used by the
970  * dictionaries itself.
971  */
972  if (flags->extra || !flags->subtype) return true;
973 
974  if ((type != FR_TYPE_STRING) && ((flags->subtype == FLAG_ENCODE_DNS_LABEL) || (flags->subtype == FLAG_ENCODE_PARTIAL_DNS_LABEL))) {
975  fr_strerror_const("The 'dns_label' flag can only be used with attributes of type 'string'");
976  return false;
977  }
978 
979  flags->is_known_width = true;
980 
981  return true;
982 }
983 
986  .name = "dhcpv6",
987  .default_type_size = 2,
988  .default_type_length = 2,
989  .subtype_table = subtype_table,
990  .subtype_table_len = NUM_ELEMENTS(subtype_table),
991  .attr_valid = attr_valid,
992 
993  .init = fr_dhcpv6_global_init,
994  .free = fr_dhcpv6_global_free,
995 
996  .encode = fr_dhcpv6_encode_foreign,
997  .decode = fr_dhcpv6_decode_foreign,
998 };
static fr_dict_t * dict
Definition: fuzzer.c:46
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition: dbuff.h:762
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
Definition: dbuff.h:1503
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition: dbuff.h:700
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition: dbuff.h:1377
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition: dbuff.h:1580
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
@ FLAG_ENCODE_DNS_LABEL
encode as DNS label
Definition: dhcpv4.h:71
Implementation of the DHCPv6 protocol.
uint32_t transaction_id
previous transaction ID
Definition: dhcpv6.h:142
@ FR_DHCPV6_CODE_MAX
Definition: dhcpv6.h:103
@ FR_DHCPV6_RELAY_FORWARD
Definition: dhcpv6.h:79
@ FR_DHCPV6_RELAY_REPLY
Definition: dhcpv6.h:80
@ FR_DHCPV6_LEASE_QUERY_REPLY
Definition: dhcpv6.h:82
fr_dict_attr_t const * root
Root attribute of the dictionary.
Definition: dhcpv6.h:135
#define DHCPV6_HDR_LEN
Definition: dhcpv6.h:43
#define DHCPV6_GET_OPTION_NUM(_x)
Definition: dhcpv6.h:47
uint8_t * duid
the expected DUID, in wire format
Definition: dhcpv6.h:143
#define DHCPV6_RELAY_HDR_LEN
Definition: dhcpv6.h:44
#define DHCPV6_LINK_ADDRESS_LEN
Definition: dhcpv6.h:40
#define DHCPV6_PEER_ADDRESS_LEN
Definition: dhcpv6.h:41
#define DHCPV6_GET_OPTION_LEN(_x)
Definition: dhcpv6.h:48
uint8_t const * original
original packet
Definition: dhcpv6.h:136
ssize_t fr_dhcpv6_encode_option(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Encode a DHCPv6 option and any sub-options.
Definition: encode.c:670
#define DHCPV6_OPT_HDR_LEN
Definition: dhcpv6.h:45
#define DHCPV6_TRANSACTION_ID_LEN
Definition: dhcpv6.h:37
size_t original_length
length of the original packet
Definition: dhcpv6.h:137
@ FLAG_ENCODE_PARTIAL_DNS_LABEL
encode as a partial DNS label
Definition: dhcpv6.h:117
#define DHCPV6_HOP_COUNT_LEN
Definition: dhcpv6.h:39
size_t duid_len
length of the expected DUID
Definition: dhcpv6.h:144
#define DHCPV6_MAX_RELAY_NESTING
Definition: dhcpv6.h:50
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition: dhcpv6.h:141
ssize_t fr_dhcpv6_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list)
Definition: encode.c:721
int fr_dict_enum_add_name(fr_dict_attr_t *da, char const *name, fr_value_box_t const *value, bool coerce, bool replace)
Add a value name.
Definition: dict_util.c:1535
fr_dict_attr_t * fr_dict_attr_unconst(fr_dict_attr_t const *da)
Coerce to non-const.
Definition: dict_util.c:4191
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
@ FLAG_LENGTH_UINT8
string / octets type is prefixed by uint8 of length
Definition: dict.h:145
@ FLAG_LENGTH_UINT16
string / octets type is prefixed by uint16 of length
Definition: dict.h:146
fr_dict_attr_t const * fr_dict_attr_iterate_children(fr_dict_attr_t const *parent, fr_dict_attr_t const **prev)
Iterate over children of a DA.
Definition: dict_util.c:4290
unsigned int array
Pack multiples into 1 attr.
Definition: dict.h:88
unsigned int extra
really "subtype is used by dict, not by protocol"
Definition: dict.h:109
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition: dict_util.c:3647
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
unsigned int is_known_width
is treated as if it has a known width for structs
Definition: dict.h:90
char const * name
name of this protocol
Definition: dict.h:342
uint8_t subtype
protocol-specific values, OR key fields
Definition: dict.h:118
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Values of the encryption flags.
Definition: merged_model.c:139
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition: dict.h:341
Test enumeration values.
Definition: dict_test.h:92
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
Head of a doubly linked list.
Definition: dlist.h:51
talloc_free(reap)
unsigned short uint16_t
Definition: merged_model.c:31
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
#define UINT8_MAX
Definition: merged_model.c:32
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
static void fr_nbo_from_uint24(uint8_t out[static 3], uint32_t num)
Write out an unsigned 24bit integer in wire format (big endian)
Definition: nbo.h:49
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition: nbo.h:137
static uint32_t fr_nbo_to_uint24(uint8_t const data[static 3])
Read an unsigned 24bit integer from wire format (big endian)
Definition: nbo.h:148
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.
Definition: pair.c:688
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:278
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition: pair.c:2978
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1340
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
fr_dict_attr_t const * attr_packet_type
Definition: base.c:50
fr_dict_attr_t const * attr_option_request
Definition: base.c:54
fr_dict_autoload_t libfreeradius_dhcpv6_dict[]
Definition: base.c:43
uint8_t const * fr_dhcpv6_option_find(uint8_t const *start, uint8_t const *end, unsigned int option)
Definition: base.c:243
fr_dict_attr_t const * attr_hop_count
Definition: base.c:50
fr_dict_attr_t const * attr_relay_link_address
Definition: base.c:51
static bool duid_match(uint8_t const *option, fr_dhcpv6_decode_ctx_t const *packet_ctx)
Definition: base.c:266
void fr_dhcpv6_global_free(void)
Definition: base.c:938
fr_dict_protocol_t libfreeradius_dhcpv6_dict_protocol
Definition: base.c:985
static void print_hex_data(FILE *fp, uint8_t const *ptr, int attrlen, int depth)
Definition: base.c:799
static ssize_t fr_dhcpv6_ok_internal(uint8_t const *packet, uint8_t const *end, size_t max_attributes, int depth)
Definition: base.c:168
static uint32_t instance_count
Definition: base.c:38
static void dhcpv6_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len, int depth)
Definition: base.c:812
bool fr_dhcpv6_ok(uint8_t const *packet, size_t packet_len, uint32_t max_attributes)
See if the data pointed to by PTR is a valid DHCPv6 packet.
Definition: base.c:227
int fr_dhcpv6_global_init(void)
Definition: base.c:896
static ssize_t fr_dhcpv6_options_ok(uint8_t const *packet, uint8_t const *end, size_t max_attributes, bool allow_relay, int depth)
Definition: base.c:117
ssize_t fr_dhcpv6_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *packet, size_t packet_len)
Decode a DHCPv6 packet.
Definition: base.c:578
char const * fr_dhcpv6_packet_names[FR_DHCPV6_CODE_MAX]
Definition: base.c:71
fr_dict_attr_t const * attr_relay_message
Definition: base.c:53
fr_dict_attr_autoload_t libfreeradius_dhcpv6_dict_attr[]
Definition: base.c:57
static bool attr_valid(UNUSED fr_dict_t *dict, UNUSED fr_dict_attr_t const *parent, UNUSED char const *name, UNUSED int attr, fr_type_t type, fr_dict_attr_flags_t *flags)
Definition: base.c:947
static char const tabs[]
Definition: base.c:797
static fr_table_num_ordered_t const subtype_table[]
Definition: base.c:110
fr_dict_t const * dict_dhcpv6
Definition: base.c:40
fr_dict_attr_t const * attr_transaction_id
Definition: base.c:49
void * fr_dhcpv6_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
DHCPV6-specific iterator.
Definition: base.c:698
bool fr_dhcpv6_verify(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx, bool from_server)
Verify the packet under some various circumstances.
Definition: base.c:544
static bool verify_to_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx)
Verify a reply packet from a server to a client.
Definition: base.c:280
static bool verify_from_client(uint8_t const *packet, size_t packet_len, fr_dhcpv6_decode_ctx_t const *packet_ctx)
Verify a packet from a client to a server.
Definition: base.c:420
void fr_dhcpv6_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len)
Print a raw DHCP packet as hex.
Definition: base.c:891
fr_dict_attr_t const * attr_relay_peer_address
Definition: base.c:52
ssize_t fr_dhcpv6_encode(fr_dbuff_t *dbuff, uint8_t const *original, size_t length, int msg_type, fr_pair_list_t *vps)
Encode a DHCPv6 packet.
Definition: base.c:717
ssize_t fr_dhcpv6_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, void *decode_ctx)
Create a "normal" fr_pair_t from the given data.
Definition: decode.c:421
ssize_t fr_dhcpv6_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
Definition: decode.c:436
VQP attributes.
static rc_request_t * current
Definition: radclient-ng.c:97
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
static char const * name
fr_assert(0)
fr_aka_sim_id_type_t type
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
An element in an arbitrarily ordered array of name to num mappings.
Definition: table.h:53
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition: talloc.h:112
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:568
#define PAIR_VERIFY(_x)
Definition: pair.h:190
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
Definition: pair_inline.c:182
static fr_slen_t parent
Definition: pair.h:844
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition: strerror.h:84
#define fr_strerror_const(_msg)
Definition: strerror.h:223
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.
Definition: value.c:1709
return fr_dbuff_set(dbuff, &our_dbuff)
#define fr_box_uint16(_val)
Definition: value.h:304
#define FR_VALUE_BOX_TO_NETWORK_RETURN(_dbuff, _value)
Definition: value.h:994
static size_t char ** out
Definition: value.h:984