The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
decode.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: b1ea167299a685e0a27776663cbedc1f91b58187 $
19 *
20 * @file protocols/dhcpv4/decode.c
21 * @brief Functions to decode DHCP options.
22 *
23 * @copyright 2008,2017 The FreeRADIUS server project
24 * @copyright 2008 Alan DeKok (aland@deployingradius.com)
25 * @copyright 2015,2017 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
26 */
27#include <freeradius-devel/io/test_point.h>
28#include <freeradius-devel/util/proto.h>
29#include <freeradius-devel/util/struct.h>
30#include <freeradius-devel/util/dns.h>
31
32#include "dhcpv4.h"
33#include "attrs.h"
34
35static _Thread_local uint8_t concat_buffer[1500]; /* ethernet max */
36
37static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
39 uint8_t const *data, size_t const data_len, void *decode_ctx);
40
41static bool verify_tlvs(uint8_t const *data, size_t data_len)
42{
43 uint8_t const *p = data;
44 uint8_t const *end = data + data_len;
45
46 while (p < end) {
47 if ((end - p) < 2) return false;
48
49 if ((p + p[1]) > end) return false;
50
51 p += 2 + p[1];
52 }
53
54 return true;
55}
56
59 uint8_t const *data, size_t const data_len, void *decode_ctx)
60{
61 return fr_pair_tlvs_from_network(ctx, out, parent, data, data_len, decode_ctx, decode_option, verify_tlvs, true);
62}
63
64static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
65 uint8_t const *data, size_t data_len, void *decode_ctx);
66
67/** Handle arrays of DNS labels for fr_struct_from_network()
68 *
69 */
72 uint8_t const *data, size_t const data_len, void *decode_ctx)
73{
74 FR_PROTO_TRACE("decode_value_trampoline of %s with %zu bytes", parent->name, data_len);
75
76 /*
77 * @todo - we might need to limit this to only one DNS label.
78 */
80 return fr_pair_dns_labels_from_network(ctx, out, parent, data, data, data_len, NULL, false);
81 }
82
83 return decode_value(ctx, out, parent, data, data_len, decode_ctx);
84}
85
86/*
87 * Decode ONE value into a VP
88 */
89static ssize_t decode_value(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *da,
90 uint8_t const *data, size_t data_len, void *decode_ctx)
91{
92 ssize_t slen;
94 uint8_t const *p = data;
95 uint8_t const *end = data + data_len;
96 bool exact = !da->flags.array;
97
98 FR_PROTO_TRACE("%s called to parse %zu bytes from %s", __FUNCTION__, data_len, da->name);
99 FR_PROTO_HEX_DUMP(data, data_len, NULL);
100
101 /*
102 * Structs create their own VP wrapper.
103 */
104 if (da->type == FR_TYPE_STRUCT) {
105 slen = fr_struct_from_network(ctx, out, da, data, data_len,
107 if (slen < 0) return slen;
108
109 if (!exact) return slen;
110
111 return data_len;
112 }
113
114 /*
115 * These are always raw.
116 */
117 if (da->flags.is_unknown) {
118 return fr_pair_raw_from_network(ctx, out, da, data, data_len);
119 }
120
121 vp = fr_pair_afrom_da(ctx, da);
122 if (!vp) return PAIR_DECODE_OOM;
124
125 /*
126 * string / octets / bool can be empty. Other data types are
127 * raw if they're empty.
128 */
129 if (data_len == 0) {
130 if (da->type == FR_TYPE_BOOL) {
131 vp->vp_bool = true;
132 goto finish;
133 }
134
135 if ((da->type == FR_TYPE_OCTETS) || (da->type == FR_TYPE_STRING)) {
136 goto finish;
137 }
138
140 return fr_pair_raw_from_network(ctx, out, da, data, 0);
141 }
142
143 switch (vp->vp_type) {
144 case FR_TYPE_ATTR:
145 /*
146 * Force the length of the data to be one,
147 * otherwise the "from network" call complains.
148 * Because we pass in the enumv as the _parent_
149 * and not the da. The da is marked as "array",
150 * but the parent is not.
151 */
152 end = p + 1;
153
154 fr_assert(da->parent->flags.is_root);
155
156 slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, da->parent,
157 &FR_DBUFF_TMP(p, end - p), end - p, true);
158 if (slen <= 0) goto raw;
159
160 p++;
161 break;
162
163 /*
164 * Doesn't include scope, whereas the generic format can.
165 */
167 slen = fr_value_box_ipaddr_from_network(&vp->data, da->type, da,
168 128, p, (size_t) (end - p),
169 exact, true);
170 if (slen < 0) goto raw;
171 fr_assert(slen == sizeof(vp->vp_ipv6addr));
172
173 p += sizeof(vp->vp_ipv6addr);
174 break;
175
177 /*
178 * Not enough room for the prefix length, that's an issue.
179 *
180 * Note that there's actually no standard for IPv6 prefixes inside of DHCPv4.
181 */
182 if ((end - p) < 1) goto raw;
183
184 slen = fr_value_box_ipaddr_from_network(&vp->data, da->type, da,
185 p[0], p + 1, ((size_t) (end - p)) - 1,
186 exact, true);
187 if (slen < 0) goto raw;
188
189 p += slen + 1;
190 break;
191
193 fr_strerror_printf("Cannot decode type '%s' as value", fr_type_to_str(vp->vp_type));
195 return 0;
196
199 vp->vp_ip.af = AF_INET;
200
201 /*
202 * 4 octets of address
203 * 4 octets of mask
204 */
206 uint32_t ipaddr, mask;
207
208 if (data_len < 8) goto raw;
209
210 ipaddr = fr_nbo_to_uint32(p);
211 mask = fr_nbo_to_uint32(p + 4);
212 p += 8;
213
214 /*
215 * 0/0 means a prefix of 0, too.
216 */
217 if (!mask) {
218 break;
219 }
220
221 /*
222 * Try to figure out the prefix value from the mask.
223 */
224 while (mask) {
225 vp->vp_ip.prefix++;
226 mask <<= 1;
227 }
228
229 /*
230 * Mash the IP based on the calculated mask. We don't really care if the mask
231 * has holes, or if the IP address overlaps with the mask. We just fix it all up
232 * so it's sane.
233 */
234 mask = ~(uint32_t) 0;
235 mask <<= (32 - vp->vp_ip.prefix);
236
237 vp->vp_ipv4addr = htonl(ipaddr & mask);
238 break;
239 }
240
242 size_t needs;
243
244 if ((data_len == 0) || (*p > 32)) goto raw;
245
246 needs = 1 + ((*p + 0x07) >> 3);
247 if (data_len < needs) goto raw;
248
249 /*
250 * Don't do exact checks here, as the content is variable-sized.
251 */
252
253 vp->vp_ip.prefix = *p;
254
255 /*
256 * If the IP address is longer than necessary, then only grab the pieces we need.
257 */
258 if (vp->vp_ip.prefix) {
259 uint32_t ipaddr, mask;
260
261 mask = ~(uint32_t) 0;
262 mask <<= (32 - vp->vp_ip.prefix);
263
264 if (*p > 24) {
265 ipaddr = fr_nbo_to_uint32(p + 1);
266
267 } else if (*p > 16) {
268 ipaddr = fr_nbo_to_uint24(p + 1);
269 ipaddr <<= 8;
270
271 } else if (*p > 8) {
272 ipaddr = fr_nbo_to_uint16(p + 1);
273 ipaddr <<= 16;
274
275 } else { /* 1..8 */
276 ipaddr = p[1];
277 ipaddr <<= 24;
278 }
279
280 vp->vp_ipv4addr = htonl(ipaddr & mask);
281 } /* else *p==0, and we leave ipaddr set to zero */
282
283 p += needs;
284 break;
285 }
286
288
289 default:
290 slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, da,
291 &FR_DBUFF_TMP(p, end - p), end - p, true);
292 if (slen < 0) {
293 raw:
294 FR_PROTO_TRACE("decoding as unknown type");
295 if (fr_pair_raw_afrom_pair(vp, p, (end - p)) < 0) {
296 return -1;
297 }
298 p = end;
299 break;
300 }
301
302 if (exact && (slen != (end - p))) {
303 goto raw;
304 }
305
306 p += (size_t) slen;
307 break;
308 }
309
310finish:
311 FR_PROTO_TRACE("decoding value complete, adding new pair and returning %zu byte(s)", (size_t) (p - data));
313
314 return p - data;
315}
316
317/** RFC 4243 Vendor Specific Suboptions
318 *
319 * Vendor specific suboptions are in the format.
320 @verbatim
321 0 1 2 3
322 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
323 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 | Enterprise Number 0 |
325 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 | Len 0 | /
327 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328 / Suboption Data 0 /
329 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
330 | Enterprise Number n |
331 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
332 | Len n | /
333 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
334 / Suboption Data n /
335 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
336 @endverbatim
337 *
338 * So although the vendor is identified, the format of the data isn't
339 * specified so we can't actually resolve the suboption to an
340 * attribute. For now, we just convert it to an attribute of
341 * Vendor-Specific-Information with raw octets contents.
342 */
343
344
345/*
346 * One VSA option may contain multiple vendors, each vendor
347 * may contain one or more sub-options.
348 *
349 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
350 * | option-code | option-len |
351 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
352 * | enterprise-number1 |
353 * | |
354 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
355 * | data-len1 | |
356 * +-+-+-+-+-+-+-+-+ option-data1 |
357 * / /
358 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ----
359 * | enterprise-number2 | ^
360 * | | |
361 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
362 * | data-len2 | | optional
363 * +-+-+-+-+-+-+-+-+ option-data2 | |
364 * / / |
365 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
366 * ~ ... ~ V
367 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ----
368 */
369static ssize_t decode_vsa(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent,
370 uint8_t const *data, size_t const data_len, void *decode_ctx)
371{
372 ssize_t len;
373 uint8_t option_len;
374 uint32_t pen;
375 fr_pair_t *vp;
376 fr_dict_attr_t const *vendor;
377 uint8_t const *end = data + data_len;
378 uint8_t const *p = data;
379
380 FR_PROTO_HEX_DUMP(data, data_len, "decode_vsa");
381
383 "%s: Internal sanity check failed, attribute \"%s\" is not of type 'vsa'",
384 __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
385
386next:
387 /*
388 * We need at least 4 (PEN) + 1 (data-len) + 1 (vendor option num) to be able to decode vendor
389 * specific attributes. If we don't have that, then we return an error. The caller will free
390 * the VSA, and create a "raw.VSA" attribute.
391 */
392 if ((size_t)(end - p) < (sizeof(uint32_t) + 1 + 1)) {
393 return -1;
394 }
395
396 pen = fr_nbo_to_uint32(p);
397
398 /*
399 * Verify that the parent (which should be a VSA)
400 * contains a fake attribute representing the vendor.
401 *
402 * If it doesn't then this vendor is unknown, but we know
403 * vendor attributes have a standard format, so we can
404 * decode the data anyway.
405 */
406 vendor = fr_dict_attr_child_by_num(parent, pen);
407 if (!vendor) {
409
411 if (!n) return PAIR_DECODE_OOM;
412 vendor = n;
413 }
414 p += sizeof(uint32_t);
415
416 FR_PROTO_TRACE("decode context %s -> %s", parent->name, vendor->name);
417
418 option_len = p[0];
419 if ((p + 1 + option_len) > end) {
420 len = fr_pair_raw_from_network(ctx, out, vendor, p, end - p);
421 if (len < 0) return len;
422
423 return data_len + 2; /* decoded the whole thing */
424 }
425 p++;
426
427 /*
428 * Pathological case of no data.
429 */
430 if (option_len == 0) goto next;
431
432 vp = fr_pair_find_by_da(out, NULL, vendor);
433 if (!vp) {
434 vp = fr_pair_afrom_da(ctx, vendor);
435 if (!vp) return PAIR_DECODE_FATAL_ERROR;
437
439 }
440
441 len = fr_pair_tlvs_from_network(vp, &vp->vp_group, vendor, p, option_len, decode_ctx, decode_option, verify_tlvs, false);
442 if (len < 0) return len;
443
444 p += option_len;
445 if (p < end) goto next;
446
447 /*
448 * Tell the caller we read all of it, even if we didn't.
449 */
450 return data_len + 2;
451}
452
453
454static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
455 fr_dict_attr_t const *parent,
456 uint8_t const *data, size_t const data_len, void *decode_ctx)
457{
458 unsigned int option;
459 size_t len;
460 ssize_t slen;
461 fr_dict_attr_t const *da;
462 fr_dhcpv4_ctx_t *packet_ctx = decode_ctx;
463
464#ifdef STATIC_ANALYZER
465 if (!packet_ctx || !packet_ctx->tmp_ctx) return PAIR_DECODE_FATAL_ERROR;
466#endif
467
468 fr_assert(parent != NULL);
469
470 /*
471 * RFC 3046 is very specific about not allowing termination
472 * with a 255 sub-option. But it's required for decoding
473 * option 43, and vendors will probably screw it up
474 * anyway.
475 *
476 * Similarly, option 0 is sometimes treated as
477 * "end of options".
478 *
479 * @todo - this check is likely correct only when at the
480 * dhcpv4 root, OR inside of option 43. It could be
481 * argued that it's wrong for all other TLVs.
482 */
483 if ((data_len == 1) && ((data[0] == 0) || (data[1] == 255))) return data_len;
484
485 /*
486 * Must have at least an option header.
487 */
488 if (data_len < 2) {
489 fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
490 return -(data_len);
491 }
492
493 option = data[0];
494 len = data[1];
495 if (len > (data_len - 2)) {
496 fr_strerror_printf("%s: Option overflows input. "
497 "Optional length must be less than %zu bytes, got %zu bytes",
498 __FUNCTION__, data_len - 2, len);
500 }
501
502 da = fr_dict_attr_child_by_num(parent, option);
503 if (!da) {
504 da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, parent, option);
505 if (!da) return PAIR_DECODE_OOM;
506
507 slen = fr_pair_raw_from_network(ctx, out, da, data + 2, len);
508
509 } else if ((da->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(da)) {
510 slen = fr_pair_dns_labels_from_network(ctx, out, da, data + 2, data + 2, len, NULL, true);
511
512 } else if (da->flags.array) {
513 slen = fr_pair_array_from_network(ctx, out, da, data + 2, len, decode_ctx, decode_value);
514
515 } else if (da->type == FR_TYPE_VSA) {
516 bool append = false;
517 fr_pair_t *vp;
518
519 vp = fr_pair_find_by_da(out, NULL, da);
520 if (!vp) {
521 vp = fr_pair_afrom_da(ctx, da);
522 if (!vp) return PAIR_DECODE_FATAL_ERROR;
524
525 append = true;
526 }
527
528 slen = decode_vsa(vp, &vp->vp_group, da, data + 2, len, decode_ctx);
529 if (append) {
530 if (slen < 0) {
531 TALLOC_FREE(vp);
532 } else {
534 }
535 }
536
537 } else if (da->type == FR_TYPE_TLV) {
538 slen = fr_pair_tlvs_from_network(ctx, out, da, data + 2, len, decode_ctx, decode_option, verify_tlvs, true);
539
540 } else {
541 slen = decode_value(ctx, out, da, data + 2, len, decode_ctx);
542 }
543
544 if (slen < 0) {
545 slen = fr_pair_raw_from_network(ctx, out, da, data + 2, len);
546 if (slen < 0) return slen;
547 }
548
549 return len + 2;
550}
551
552/** Decode DHCP option
553 *
554 * @param[in] ctx context to alloc new attributes in.
555 * @param[out] out Where to write the decoded options.
556 * @param[in] data to parse.
557 * @param[in] data_len of data to parse.
558 * @param[in] decode_ctx Unused.
559 */
561 uint8_t const *data, size_t data_len, void *decode_ctx)
562{
563 ssize_t slen;
564 uint8_t const *p = data, *end = data + data_len;
565 uint8_t const *next;
566 fr_dhcpv4_ctx_t *packet_ctx = decode_ctx;
567
568 FR_PROTO_TRACE("%s called to parse %zu byte(s)", __FUNCTION__, data_len);
569
570 if (data_len == 0) return 0;
571
572 FR_PROTO_HEX_DUMP(data, data_len, NULL);
573
574 /*
575 * Padding / End of options
576 */
577 if (p[0] == 0) { /* 0x00 - Padding option */
578 data_len = 1; /* Walk over any consecutive 0x00 */
579 p++; /* for efficiency */
580 while ((p < end) && (p[0] == 0)) {
581 p++;
582 data_len ++;
583 }
584 return data_len;
585 }
586 if (p[0] == 255) return data_len; /* 0xff - End of options signifier */
587
588 /*
589 * Everything else should be real options
590 */
591 if ((data_len < 2) || ((size_t) (data[1] + 2) > data_len)) {
592 fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
593 return -1;
594 }
595
596 /*
597 * Check for multiple options of the same type, and concatenate their values together.
598 *
599 * RFC 2131 Section 4.1 says:
600 *
601 * The client concatenates the values of multiple
602 * instances of the same option into a single parameter
603 * list for configuration.
604 *
605 * which presumably also means the same for the server on reception.
606 *
607 * We therefore peek ahead, and concatenate the values into a temporary buffer. The buffer is
608 * allocated only if necessary, and is re-used for the entire packet.
609 *
610 * If the options are *not* consecutive, then we don't concatenate them. Too bad for you!
611 *
612 * Note that we don't (yet) do this for TLVs.
613 */
614 next = data + 2 + data[1];
615 if ((data[1] > 0) && (next < end) && (next[0] == data[0])) {
616 uint8_t *q;
617 fr_dict_attr_t const *da;
618
619 q = concat_buffer;
620
621 for (next = data; next < end; next += 2 + next[1]) {
622 if (next >= end) return -1;
623 if (next[0] != data[0]) break;
624 if ((end - next) < 2) return -1;
625 if ((next + 2 + next[1]) > end) return -1;
626
627 if ((size_t) (q + next[1] - concat_buffer) > sizeof(concat_buffer)) return -1;
628
629 memcpy(q, next + 2, next[1]);
630 q += next[1];
631 }
632
633 if (q == concat_buffer) return 0;
634
635 da = fr_dict_attr_child_by_num(packet_ctx->root, p[0]);
636 if (!da) {
637 da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, packet_ctx->root, p[0]);
638 if (!da) return -1;
639
641
642 } else if (da->type == FR_TYPE_VSA) {
643 slen = decode_vsa(ctx, out, da, concat_buffer, q - concat_buffer, packet_ctx);
644
645 } else if (da->type == FR_TYPE_TLV) {
647 packet_ctx, decode_option, verify_tlvs, true);
648
649 } else if (da->flags.array) {
650 slen = fr_pair_array_from_network(ctx, out, da, concat_buffer, q - concat_buffer, packet_ctx, decode_value);
651
652 } else {
653 slen = decode_value(ctx, out, da, concat_buffer, q - concat_buffer, packet_ctx);
654 }
655 if (slen < 0) return slen;
656
657 /*
658 * The actual amount of data we decoded, including the various headers.
659 */
660 FR_PROTO_TRACE("decoding option complete, %zd decoded, returning %zu byte(s)", slen, (size_t) (next - data));
661 return next - data;
662 }
663
664 slen = decode_option(ctx, out, packet_ctx->root, data, data[1] + 2, decode_ctx);
665 if (slen < 0) return slen;
666
667 FR_PROTO_TRACE("decoding option complete, %zd decoded, returning %u byte(s)", slen, (unsigned int) data[1] + 2);
668 return data[1] + 2;
669}
670
672 uint8_t const *data, size_t data_len)
673{
674 ssize_t slen;
675 uint8_t const *attr, *end;
676
677 fr_dhcpv4_ctx_t decode_ctx = {
679 };
680
681 fr_assert(dict_dhcpv4 != NULL);
682
683 decode_ctx.tmp_ctx = talloc(ctx, uint8_t);
684
685 attr = data;
686 end = data + data_len;
687
688 while (attr < end) {
689 slen = fr_dhcpv4_decode_option(ctx, out, attr, (end - attr), &decode_ctx);
690 if (slen < 0) {
691 talloc_free(decode_ctx.tmp_ctx);
692 return slen;
693 }
694
695 /*
696 * If slen is larger than the room in the packet,
697 * all kinds of bad things happen.
698 */
699 if (!fr_cond_assert(slen <= (end - attr))) {
700 talloc_free(decode_ctx.tmp_ctx);
701 return -slen - (attr - data);
702 }
703
704 attr += slen;
705 talloc_free_children(decode_ctx.tmp_ctx);
706 }
707
708 talloc_free(decode_ctx.tmp_ctx);
709 return data_len;
710}
711
712
713static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
714 fr_dict_attr_t const *root_da)
715{
716 fr_dhcpv4_ctx_t *test_ctx;
717
718 test_ctx = talloc_zero(ctx, fr_dhcpv4_ctx_t);
719 test_ctx->tmp_ctx = talloc(test_ctx, uint8_t);
720 test_ctx->root = root_da ? root_da : fr_dict_root(dict_dhcpv4);
721
722 *out = test_ctx;
723
724 return 0;
725}
726
727
729 uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
730{
731 unsigned int code;
732
733 if (!fr_dhcpv4_ok(data, data_len, NULL, NULL)) return -1;
734
735 if (fr_dhcpv4_decode(ctx, out, data, data_len, &code) < 0) return -1;
736
737 return data_len;
738}
739
741 uint8_t const *data, size_t data_len, void *decode_ctx)
742{
744
745 return fr_dhcpv4_decode_option(ctx, out, data, data_len, decode_ctx);
746}
747
748/*
749 * Test points
750 */
756
int n
Definition acutest.h:579
#define NDEBUG_UNUSED
Definition build.h:328
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:324
#define UNUSED
Definition build.h:317
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition dbuff.h:524
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:148
static fr_dict_t const * dict_dhcpv4
Definition dhcpclient.c:80
Implementation of the DHCPv4 protocol.
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition dhcpv4.h:136
#define fr_dhcpv4_flag_prefix_bits(_da)
Definition dhcpv4.h:161
#define fr_dhcpv4_flag_dns_label(_da)
Definition dhcpv4.h:157
#define fr_dhcpv4_flag_prefix_split(_da)
Definition dhcpv4.h:162
fr_dict_attr_t const * root
Definition dhcpv4.h:135
int fr_dhcpv4_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, unsigned int *code)
Definition packet.c:119
Used as the decoder ctx.
Definition dhcpv4.h:134
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
Definition dict.h:606
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Definition dict.h:613
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2669
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_util.c:3597
#define PAIR_DECODE_OOM
Fatal error - Out of memory.
Definition pair.h:45
#define PAIR_DECODE_FATAL_ERROR
Fatal error - Failed decoding the packet.
Definition pair.h:49
ssize_t fr_pair_tlvs_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx, fr_pair_decode_value_t decode_tlv, fr_pair_tlvs_verify_t verify_tlvs, bool nested)
Decode a list of pairs from the network.
Definition decode.c:149
ssize_t fr_pair_dns_labels_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *start, uint8_t const *data, size_t const data_len, fr_dns_labels_t *lb, bool exact)
Decode a DNS label or a list of DNS labels from the network.
Definition decode.c:246
ssize_t fr_pair_raw_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *da, uint8_t const *data, size_t data_len)
Create a "raw" pair from malformed network data.
Definition decode.c:79
ssize_t fr_pair_array_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value)
Decode an array of values from the network.
Definition decode.c:41
talloc_free(reap)
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
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:146
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:157
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
Definition nbo.h:167
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:703
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:1348
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:289
int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
Definition pair.c:603
static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict, UNUSED fr_dict_attr_t const *root_da)
Definition decode.c:102
bool fr_dhcpv4_ok(uint8_t const *data, ssize_t data_len, uint8_t *message_type, uint32_t *xid)
Check received DHCP request is valid and build fr_packet_t structure if it is.
Definition base.c:248
static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Definition decode.c:454
fr_test_point_pair_decode_t dhcpv4_tp_decode_pair
Definition decode.c:752
fr_test_point_proto_decode_t dhcpv4_tp_decode_proto
Definition decode.c:758
static _Thread_local uint8_t concat_buffer[1500]
Definition decode.c:35
static ssize_t fr_dhcpv4_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
Definition decode.c:728
static bool verify_tlvs(uint8_t const *data, size_t data_len)
Definition decode.c:41
ssize_t fr_dhcpv4_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, void *decode_ctx)
Decode DHCP option.
Definition decode.c:560
static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Handle arrays of DNS labels for fr_struct_from_network()
Definition decode.c:70
static ssize_t decode_option_wrapper(TALLOC_CTX *ctx, fr_pair_list_t *out, NDEBUG_UNUSED fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
Definition decode.c:740
static ssize_t decode_vsa(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
RFC 4243 Vendor Specific Suboptions.
Definition decode.c:369
static ssize_t decode_tlv_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t const data_len, void *decode_ctx)
Definition decode.c:57
ssize_t fr_dhcpv4_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len)
Definition decode.c:671
#define decode_value
Definition decode.c:411
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
static uint32_t mask
Definition rbmonkey.c:39
fr_pair_t * vp
ssize_t fr_struct_from_network(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx, fr_pair_decode_value_t decode_value, fr_pair_decode_value_t decode_tlv)
Convert a STRUCT to one or more VPs.
Definition struct.c:32
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
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:86
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition test_point.h:68
Entry point for pair decoders.
Definition test_point.h:85
Entry point for protocol decoders.
Definition test_point.h:67
#define PAIR_ALLOCED(_x)
Definition pair.h:212
static fr_slen_t parent
Definition pair.h:859
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition proto.h:42
#define FR_PROTO_TRACE(_fmt,...)
Definition proto.h:41
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
@ FR_TYPE_ATTR
A contains an attribute reference.
Definition types.h:84
#define FR_TYPE_STRUCTURAL
Definition types.h:317
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
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:1914
ssize_t fr_value_box_ipaddr_from_network(fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, int prefix_len, uint8_t const *data, size_t data_len, bool fixed, bool tainted)
Decode a fr_value_box_t of type IP address / prefix.
Definition value.c:2318
static fr_slen_t data
Definition value.h:1333
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:611
static size_t char ** out
Definition value.h:1025