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