Coverage Report

Created: 2026-02-26 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeradius-server/src/protocols/dhcpv4/decode.c
Line
Count
Source
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: 968f784d79c62029261742542bda8ca8b50e264b $
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
4.45k
{
43
4.45k
  uint8_t const *p = data;
44
4.45k
  uint8_t const *end = data + data_len;
45
46
8.83k
  while (p < end) {
47
6.42k
    if ((end - p) < 2) return false;
48
49
5.18k
    if ((p + 2 + p[1]) > end) return false;
50
51
4.38k
    p += 2 + p[1];
52
4.38k
  }
53
54
2.41k
  return true;
55
4.45k
}
56
57
static ssize_t decode_tlv_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out,
58
             fr_dict_attr_t const *parent,
59
             uint8_t const *data, size_t const data_len, void *decode_ctx)
60
691
{
61
691
  return fr_pair_tlvs_from_network(ctx, out, parent, data, data_len, decode_ctx, decode_option, verify_tlvs, true);
62
691
}
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
 */
70
static ssize_t decode_value_trampoline(TALLOC_CTX *ctx, fr_pair_list_t *out,
71
               fr_dict_attr_t const *parent,
72
               uint8_t const *data, size_t const data_len, void *decode_ctx)
73
16.3k
{
74
16.3k
  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
   */
79
16.3k
  if ((parent->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(parent)) {
80
522
    return fr_pair_dns_labels_from_network(ctx, out, parent, data, data, data_len, NULL, false);
81
522
  }
82
83
15.8k
  return decode_value(ctx, out, parent, data, data_len, decode_ctx);
84
16.3k
}
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
44.8k
{
92
44.8k
  ssize_t slen;
93
44.8k
  fr_pair_t *vp;
94
44.8k
  uint8_t const *p = data;
95
44.8k
  uint8_t const *end = data + data_len;
96
44.8k
  bool exact = !da->flags.array;
97
98
44.8k
  FR_PROTO_TRACE("%s called to parse %zu bytes from %s", __FUNCTION__, data_len, da->name);
99
44.8k
  FR_PROTO_HEX_DUMP(data, data_len, NULL);
100
101
  /*
102
   *  Structs create their own VP wrapper.
103
   */
104
44.8k
  if (da->type == FR_TYPE_STRUCT) {
105
10.8k
    slen = fr_struct_from_network(ctx, out, da, data, data_len,
106
10.8k
                decode_ctx, decode_value_trampoline, decode_tlv_trampoline);
107
10.8k
    if (slen < 0) return slen;
108
109
6.70k
    if (!exact) return slen;
110
111
2.73k
    return data_len;
112
6.70k
  }
113
114
  /*
115
   *  These are always raw.
116
   */
117
33.9k
  if (da->flags.is_unknown) {
118
0
    return fr_pair_raw_from_network(ctx, out, da, data, data_len);
119
0
  }
120
121
33.9k
  vp = fr_pair_afrom_da(ctx, da);
122
33.9k
  if (!vp) return PAIR_DECODE_OOM;
123
33.9k
  PAIR_ALLOCED(vp);
124
125
  /*
126
   *  string / octets / bool can be empty.  Other data types are
127
   *  raw if they're empty.
128
   */
129
33.9k
  if (data_len == 0) {
130
3.51k
    if (da->type == FR_TYPE_BOOL) {
131
242
      vp->vp_bool = true;
132
242
      goto finish;
133
242
    }
134
135
3.27k
    if ((da->type == FR_TYPE_OCTETS) || (da->type == FR_TYPE_STRING)) {
136
1.87k
      goto finish;
137
1.87k
    }
138
139
3.27k
    talloc_free(vp);
140
1.40k
    return fr_pair_raw_from_network(ctx, out, da, data, 0);
141
3.27k
  }
142
143
30.4k
  switch (vp->vp_type) {
144
7.28k
  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
7.28k
    end = p + 1;
153
154
7.28k
    fr_assert(da->parent->flags.is_root);
155
156
7.28k
    slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, da->parent,
157
7.28k
             &FR_DBUFF_TMP(p, end - p), end - p, true);
158
7.28k
    if (slen <= 0) goto raw;
159
160
7.28k
    p++;
161
7.28k
    break;
162
163
  /*
164
   *  Doesn't include scope, whereas the generic format can.
165
   */
166
789
  case FR_TYPE_IPV6_ADDR:
167
789
    slen = fr_value_box_ipaddr_from_network(&vp->data, da->type, da,
168
789
              128, p, (size_t) (end - p),
169
789
              exact, true);
170
789
    if (slen < 0) goto raw;
171
365
    fr_assert(slen == sizeof(vp->vp_ipv6addr));
172
173
365
    p += sizeof(vp->vp_ipv6addr);
174
365
    break;
175
176
0
  case FR_TYPE_IPV6_PREFIX:
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
0
    if ((end - p) < 1) goto raw;
183
184
0
    slen = fr_value_box_ipaddr_from_network(&vp->data, da->type, da,
185
0
              p[0], p + 1, ((size_t) (end - p)) - 1,
186
0
              exact, true);
187
0
    if (slen < 0) goto raw;
188
189
0
    p += slen + 1;
190
0
    break;
191
192
0
  case FR_TYPE_STRUCTURAL:
193
0
    fr_strerror_printf("Cannot decode type '%s' as value", fr_type_to_str(vp->vp_type));
194
0
    talloc_free(vp);
195
0
    return 0;
196
197
3.76k
  case FR_TYPE_IPV4_PREFIX:
198
3.76k
    fr_value_box_init(&vp->data, FR_TYPE_IPV4_PREFIX, vp->da, true);
199
3.76k
    vp->vp_ip.af = AF_INET;
200
201
    /*
202
     *  4 octets of address
203
     *  4 octets of mask
204
     */
205
3.76k
    if (fr_dhcpv4_flag_prefix_split(da)) {
206
863
      uint32_t ipaddr, mask;
207
208
863
      if (data_len < 8) goto raw;
209
210
384
      ipaddr = fr_nbo_to_uint32(p);
211
384
      mask = fr_nbo_to_uint32(p + 4);
212
384
      p += 8;
213
214
      /*
215
       *  0/0 means a prefix of 0, too.
216
       */
217
384
      if (!mask) {
218
130
        break;
219
130
      }
220
221
      /*
222
       *  Try to figure out the prefix value from the mask.
223
       */
224
7.40k
      while (mask) {
225
7.15k
        vp->vp_ip.prefix++;
226
7.15k
        mask <<= 1;
227
7.15k
      }
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
254
      mask = ~(uint32_t) 0;
235
254
      mask <<= (32 - vp->vp_ip.prefix);
236
237
254
      vp->vp_ipv4addr = htonl(ipaddr & mask);
238
254
      break;
239
384
    }
240
241
2.90k
    if (fr_dhcpv4_flag_prefix_bits(vp->da)) {
242
2.90k
      size_t needs;
243
244
2.90k
      if ((data_len == 0) || (*p > 32)) goto raw;
245
246
2.28k
      needs = 1 + ((*p + 0x07) >> 3);
247
2.28k
      if (data_len < needs) goto raw;
248
249
      /*
250
       *  Don't do exact checks here, as the content is variable-sized.
251
       */
252
253
1.82k
      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
1.82k
      if (vp->vp_ip.prefix) {
259
1.28k
        uint32_t ipaddr, mask;
260
261
1.28k
        mask = ~(uint32_t) 0;
262
1.28k
        mask <<= (32 - vp->vp_ip.prefix);
263
264
1.28k
        if (*p > 24) {
265
224
          ipaddr = fr_nbo_to_uint32(p + 1);
266
267
1.05k
        } else if (*p > 16) {
268
229
          ipaddr = fr_nbo_to_uint24(p + 1);
269
229
          ipaddr <<= 8;
270
271
828
        } else if (*p > 8) {
272
251
          ipaddr = fr_nbo_to_uint16(p + 1);
273
251
          ipaddr <<= 16;
274
275
577
        } else { /* 1..8 */
276
577
          ipaddr = p[1];
277
577
          ipaddr <<= 24;
278
577
        }
279
280
1.28k
        vp->vp_ipv4addr = htonl(ipaddr & mask);
281
1.28k
      } /* else *p==0, and we leave ipaddr set to zero */
282
283
1.82k
      p += needs;
284
1.82k
      break;
285
2.28k
    }
286
287
0
    FALL_THROUGH;
288
289
18.6k
  default:
290
18.6k
    slen = fr_value_box_from_network(vp, &vp->data, vp->vp_type, da,
291
18.6k
             &FR_DBUFF_TMP(p, end - p), end - p, true);
292
18.6k
    if (slen < 0) {
293
6.72k
    raw:
294
6.72k
      FR_PROTO_TRACE("decoding as unknown type");
295
6.72k
      if (fr_pair_raw_afrom_pair(vp, p, (end - p)) < 0) {
296
0
        return -1;
297
0
      }
298
6.72k
      p = end;
299
6.72k
      break;
300
6.72k
    }
301
302
13.9k
    if (exact && (slen != (end - p))) {
303
74
      goto raw;
304
74
    }
305
306
13.8k
    p += (size_t) slen;
307
13.8k
    break;
308
30.4k
  }
309
310
32.5k
finish:
311
32.5k
  FR_PROTO_TRACE("decoding value complete, adding new pair and returning %zu byte(s)", (size_t) (p - data));
312
32.5k
  fr_pair_append(out, vp);
313
314
32.5k
  return p - data;
315
30.4k
}
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
 */
369
static 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
4.46k
{
372
4.46k
  size_t      len;
373
4.46k
  ssize_t     slen;
374
4.46k
  uint8_t     option_len;
375
4.46k
  uint32_t    pen;
376
4.46k
  fr_pair_t   *vp;
377
4.46k
  fr_dict_attr_t const  *vendor;
378
4.46k
  uint8_t const   *end = data + data_len;
379
4.46k
  uint8_t const   *p = data;
380
4.46k
  fr_pair_list_t    list;
381
382
4.46k
  FR_PROTO_HEX_DUMP(data, data_len, "decode_vsa");
383
384
4.46k
  if (!fr_cond_assert_msg(parent->type == FR_TYPE_VSA,
385
4.46k
        "%s: Internal sanity check failed, attribute \"%s\" is not of type 'vsa'",
386
4.46k
        __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
387
388
4.46k
  fr_pair_list_init(&list);
389
390
5.15k
next:
391
  /*
392
   *  RFC 4243 Section 3 says that "the minimum length is 4 bytes."
393
   */
394
5.15k
  len = (size_t) (end - p);
395
5.15k
  if (len < (sizeof(uint32_t))) {
396
3.06k
fail:
397
3.06k
    fr_pair_list_free(&list);
398
3.06k
    return -1;
399
2.83k
  }
400
401
  /*
402
   *  RFC 4243 is silent about this, but we assime that anything with no vendor data means that we
403
   *  ignore it.  i.e. we don't create an empty vendor attribute.
404
   */
405
2.32k
  if (len == (sizeof(uint32_t) + 1)) {
406
    /*
407
     *  There's no more data, so this length field must be zero.
408
     */
409
3
    if (p[4] != 0) goto fail;
410
0
    goto done;
411
3
  }
412
413
2.32k
  pen = fr_nbo_to_uint32(p);
414
415
  /*
416
   *  Verify that the parent (which should be a VSA)
417
   *  contains a fake attribute representing the vendor.
418
   *
419
   *  If it doesn't then this vendor is unknown, but we know
420
   *  vendor attributes have a standard format, so we can
421
   *  decode the data anyway.
422
   */
423
2.32k
  vendor = fr_dict_attr_child_by_num(parent, pen);
424
2.32k
  if (!vendor) {
425
1.85k
    fr_dict_attr_t *n;
426
427
1.85k
    n = fr_dict_attr_unknown_vendor_afrom_num(ctx, parent, pen);
428
1.85k
    if (!n) {
429
0
    oom:
430
0
      fr_pair_list_free(&list);
431
0
      return PAIR_DECODE_OOM;
432
0
    }
433
1.85k
    vendor = n;
434
1.85k
  }
435
2.32k
  p += sizeof(uint32_t);
436
437
2.32k
  FR_PROTO_TRACE("decode context %s -> %s", parent->name, vendor->name);
438
439
2.32k
  option_len = p[0];
440
2.32k
  if ((p + 1 + option_len) > end) {
441
654
    slen = fr_pair_raw_from_network(ctx, out, vendor, p, end - p);
442
654
    if (slen < 0) goto fail;
443
444
654
    goto done;
445
654
  }
446
1.66k
  p++;
447
448
  /*
449
   *  Pathological case of no data.
450
   */
451
1.66k
  if (option_len == 0) goto next;
452
453
1.24k
  vp = fr_pair_find_by_da(out, NULL, vendor);
454
1.24k
  if (!vp) {
455
976
    vp = fr_pair_afrom_da(ctx, vendor);
456
976
    if (!vp) goto oom;
457
976
    PAIR_ALLOCED(vp);
458
459
976
    fr_pair_append(out, vp);
460
976
  }
461
462
1.24k
  slen = fr_pair_tlvs_from_network(vp, &vp->vp_group, vendor, p, option_len, decode_ctx, decode_option, verify_tlvs, false);
463
1.24k
  if (slen < 0) goto fail;
464
465
1.01k
  p += option_len;
466
1.01k
  if (p < end) goto next;
467
468
  /*
469
   *  Tell the caller we read all of it, even if we didn't.
470
   */
471
1.40k
done:
472
1.40k
  fr_pair_list_append(out, &list);
473
1.40k
  return data_len;
474
1.01k
}
475
476
477
static ssize_t decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
478
            fr_dict_attr_t const *parent,
479
            uint8_t const *data, size_t const data_len, void *decode_ctx)
480
28.9k
{
481
28.9k
  unsigned int      option;
482
28.9k
  size_t      len;
483
28.9k
  ssize_t     slen;
484
28.9k
  fr_dict_attr_t const  *da;
485
28.9k
  fr_dhcpv4_ctx_t   *packet_ctx = decode_ctx;
486
487
#ifdef STATIC_ANALYZER
488
  if (!packet_ctx || !packet_ctx->tmp_ctx) return PAIR_DECODE_FATAL_ERROR;
489
#endif
490
491
28.9k
  fr_assert(parent != NULL);
492
493
  /*
494
   *      RFC 3046 is very specific about not allowing termination
495
   *      with a 255 sub-option. But it's required for decoding
496
   *      option 43, and vendors will probably screw it up
497
   *      anyway.
498
   *
499
   *      Similarly, option 0 is sometimes treated as
500
   *      "end of options".
501
   *
502
   *  @todo - this check is likely correct only when at the
503
   *  dhcpv4 root, OR inside of option 43.  It could be
504
   *  argued that it's wrong for all other TLVs.
505
   */
506
28.9k
  if ((data_len == 1) && ((data[0] == 0) || (data[0] == 255))) return data_len;
507
508
  /*
509
   *  Must have at least an option header.
510
   */
511
28.9k
  if (data_len < 2) {
512
0
    fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
513
0
    return -(data_len);
514
0
  }
515
516
28.9k
  option = data[0];
517
28.9k
  len = data[1];
518
28.9k
  if (len > (data_len - 2)) {
519
0
    fr_strerror_printf("%s: Option overflows input.  "
520
0
           "Optional length must be less than %zu bytes, got %zu bytes",
521
0
           __FUNCTION__, data_len - 2, len);
522
0
    return PAIR_DECODE_FATAL_ERROR;
523
0
  }
524
525
28.9k
  da = fr_dict_attr_child_by_num(parent, option);
526
28.9k
  if (!da) {
527
2.86k
    da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, parent, option);
528
2.86k
    if (!da) return PAIR_DECODE_OOM;
529
530
2.86k
    slen = fr_pair_raw_from_network(ctx, out, da, data + 2, len);
531
532
26.1k
  } else if ((da->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(da)) {
533
2.88k
    slen = fr_pair_dns_labels_from_network(ctx, out, da, data + 2, data + 2, len, NULL, true);
534
535
23.2k
  } else if (da->flags.array) {
536
4.27k
    slen = fr_pair_array_from_network(ctx, out, da, data + 2, len, decode_ctx, decode_value);
537
538
18.9k
  } else if (da->type == FR_TYPE_VSA) {
539
3.92k
    bool append = false;
540
3.92k
    fr_pair_t *vp;
541
542
3.92k
    vp = fr_pair_find_by_da(out, NULL, da);
543
3.92k
    if (!vp) {
544
2.12k
      vp = fr_pair_afrom_da(ctx, da);
545
2.12k
      if (!vp) return PAIR_DECODE_FATAL_ERROR;
546
2.12k
      PAIR_ALLOCED(vp);
547
548
2.12k
      append = true;
549
2.12k
    }
550
551
3.92k
    slen = decode_vsa(vp, &vp->vp_group, da, data + 2, len, decode_ctx);
552
3.92k
    if (append) {
553
2.12k
      if (slen < 0) {
554
1.80k
        TALLOC_FREE(vp);
555
1.80k
      } else {
556
323
        fr_pair_append(out, vp);
557
323
      }
558
2.12k
    }
559
560
15.0k
  } else if (da->type == FR_TYPE_TLV) {
561
2.38k
    slen = fr_pair_tlvs_from_network(ctx, out, da, data + 2, len, decode_ctx, decode_option, verify_tlvs, true);
562
563
12.6k
  } else {
564
12.6k
    slen = decode_value(ctx, out, da, data + 2, len, decode_ctx);
565
12.6k
  }
566
567
28.9k
  if (slen < 0) {
568
7.72k
    slen = fr_pair_raw_from_network(ctx, out, da, data + 2, len);
569
7.72k
    if (slen < 0) return slen;
570
7.72k
  }
571
572
28.9k
  return len + 2;
573
28.9k
}
574
575
/** Decode DHCP option
576
 *
577
 * @param[in] ctx context to alloc new attributes in.
578
 * @param[out] out    Where to write the decoded options.
579
 * @param[in] data    to parse.
580
 * @param[in] data_len    of data to parse.
581
 * @param[in] decode_ctx  Unused.
582
 */
583
ssize_t fr_dhcpv4_decode_option(TALLOC_CTX *ctx, fr_pair_list_t *out,
584
              uint8_t const *data, size_t data_len, void *decode_ctx)
585
33.3k
{
586
33.3k
  ssize_t     slen;
587
33.3k
  uint8_t const   *p = data, *end = data + data_len;
588
33.3k
  uint8_t const   *next;
589
33.3k
  fr_dhcpv4_ctx_t   *packet_ctx = decode_ctx;
590
591
33.3k
  FR_PROTO_TRACE("%s called to parse %zu byte(s)", __FUNCTION__, data_len);
592
593
33.3k
  if (data_len == 0) return 0;
594
595
33.3k
  FR_PROTO_HEX_DUMP(data, data_len, NULL);
596
597
  /*
598
   *  Padding / End of options
599
   */
600
33.3k
  if (p[0] == 0) {     /* 0x00 - Padding option    */
601
3.01k
    data_len = 1;     /* Walk over any consecutive 0x00 */
602
3.01k
    p++;        /* for efficiency     */
603
4.83k
    while ((p < end) && (p[0] == 0)) {
604
1.82k
      p++;
605
1.82k
      data_len ++;
606
1.82k
    }
607
3.01k
    return data_len;
608
3.01k
  }
609
30.3k
  if (p[0] == 255) return data_len;  /* 0xff - End of options signifier */
610
611
  /*
612
   *  Everything else should be real options
613
   */
614
30.0k
  if ((data_len < 2) || ((size_t) (data[1] + 2) > data_len)) {
615
1.62k
    fr_strerror_printf("%s: Insufficient data", __FUNCTION__);
616
1.62k
    return -1;
617
1.62k
  }
618
619
  /*
620
   *  Check for multiple options of the same type, and concatenate their values together.
621
   *
622
   *  RFC 2131 Section 4.1 says:
623
   *
624
   *    The client concatenates the values of multiple
625
   *    instances of the same option into a single parameter
626
   *    list for configuration.
627
   *
628
   *  which presumably also means the same for the server on reception.
629
   *
630
   *  We therefore peek ahead, and concatenate the values into a temporary buffer.  The buffer is
631
   *  allocated only if necessary, and is re-used for the entire packet.
632
   *
633
   *  If the options are *not* consecutive, then we don't concatenate them.  Too bad for you!
634
   *
635
   *  Note that we don't (yet) do this for TLVs.
636
   */
637
28.4k
  next = data + 2 + data[1];
638
28.4k
  if ((data[1] > 0) && (next < end) && (next[0] == data[0])) {
639
2.47k
    uint8_t *q;
640
2.47k
    fr_dict_attr_t const *da;
641
642
2.47k
    q = concat_buffer;
643
644
7.89k
    for (next = data; next < end; next += 2 + next[1]) {
645
7.80k
      if (next[0] != data[0]) break;
646
5.57k
      if ((end - next) < 2) return -1;
647
5.53k
      if ((next + 2 + next[1]) > end) return -1;
648
649
5.41k
      if ((size_t) (q + next[1] - concat_buffer) > sizeof(concat_buffer)) return -1;
650
651
5.41k
      memcpy(q, next + 2, next[1]);
652
5.41k
      q += next[1];
653
5.41k
    }
654
655
2.31k
    da = fr_dict_attr_child_by_num(packet_ctx->root, p[0]);
656
2.31k
    if (!da) {
657
315
      da = fr_dict_attr_unknown_raw_afrom_num(packet_ctx->tmp_ctx, packet_ctx->root, p[0]);
658
315
      if (!da) return -1;
659
660
315
      slen = fr_pair_raw_from_network(ctx, out, da, concat_buffer, q - concat_buffer);
661
662
2.00k
    } else if (da->type == FR_TYPE_VSA) {
663
541
      slen = decode_vsa(ctx, out, da, concat_buffer, q - concat_buffer, packet_ctx);
664
665
1.46k
    } else if (da->type == FR_TYPE_TLV) {
666
436
      slen = fr_pair_tlvs_from_network(ctx, out, da, concat_buffer, q - concat_buffer,
667
436
               packet_ctx, decode_option, verify_tlvs, true);
668
669
1.02k
    } else if (da->flags.array) {
670
550
      slen = fr_pair_array_from_network(ctx, out, da, concat_buffer, q - concat_buffer, packet_ctx, decode_value);
671
550
    } else if ((da->type == FR_TYPE_STRING) && fr_dhcpv4_flag_dns_label(da)) {
672
0
      slen = fr_pair_dns_labels_from_network(ctx, out, da, concat_buffer, concat_buffer,
673
0
                     q - concat_buffer, NULL, true);
674
675
475
    } else {
676
475
      slen = decode_value(ctx, out, da, concat_buffer, q - concat_buffer, packet_ctx);
677
475
    }
678
2.31k
    if (slen < 0) return slen;
679
680
    /*
681
     *  The actual amount of data we decoded, including the various headers.
682
     */
683
2.20k
    FR_PROTO_TRACE("decoding option complete, %zd decoded, returning %zu byte(s)", slen, (size_t) (next - data));
684
2.20k
    return next - data;
685
2.31k
  }
686
687
25.9k
  slen = decode_option(ctx, out, packet_ctx->root, data, data[1] + 2, decode_ctx);
688
25.9k
  if (slen < 0) return slen;
689
690
25.9k
  FR_PROTO_TRACE("decoding option complete, %zd decoded, returning %u byte(s)", slen, (unsigned int) data[1] + 2);
691
25.9k
  return data[1] + 2;
692
25.9k
}
693
694
ssize_t fr_dhcpv4_decode_foreign(TALLOC_CTX *ctx, fr_pair_list_t *out,
695
         uint8_t const *data, size_t data_len)
696
2.75k
{
697
2.75k
  ssize_t slen;
698
2.75k
  uint8_t const *attr, *end;
699
700
2.75k
  fr_dhcpv4_ctx_t decode_ctx = {
701
2.75k
    .root = fr_dict_root(dict_dhcpv4)
702
2.75k
  };
703
704
2.75k
  fr_assert(dict_dhcpv4 != NULL);
705
706
2.75k
  decode_ctx.tmp_ctx = talloc(ctx, uint8_t);
707
708
2.75k
  attr = data;
709
2.75k
  end = data + data_len;
710
711
27.8k
  while (attr < end) {
712
26.9k
    slen = fr_dhcpv4_decode_option(ctx, out, attr, (end - attr), &decode_ctx);
713
26.9k
    if (slen < 0) {
714
1.82k
      talloc_free(decode_ctx.tmp_ctx);
715
1.82k
      return slen;
716
1.82k
    }
717
718
    /*
719
     *  If slen is larger than the room in the packet,
720
     *  all kinds of bad things happen.
721
     */
722
25.1k
     if (!fr_cond_assert(slen <= (end - attr))) {
723
0
      talloc_free(decode_ctx.tmp_ctx);
724
0
       return -slen - (attr - data);
725
0
     }
726
727
25.1k
    attr += slen;
728
25.1k
    talloc_free_children(decode_ctx.tmp_ctx);
729
25.1k
  }
730
731
2.75k
  talloc_free(decode_ctx.tmp_ctx);
732
927
  return data_len;
733
2.75k
}
734
735
736
static int decode_test_ctx(void **out, TALLOC_CTX *ctx, UNUSED fr_dict_t const *dict,
737
         fr_dict_attr_t const *root_da)
738
1.23k
{
739
1.23k
  fr_dhcpv4_ctx_t *test_ctx;
740
741
1.23k
  test_ctx = talloc_zero(ctx, fr_dhcpv4_ctx_t);
742
1.23k
  test_ctx->tmp_ctx = talloc(test_ctx, uint8_t);
743
1.23k
  test_ctx->root = root_da ? root_da : fr_dict_root(dict_dhcpv4);
744
745
1.23k
  *out = test_ctx;
746
747
1.23k
  return 0;
748
1.23k
}
749
750
751
static ssize_t fr_dhcpv4_decode_proto(TALLOC_CTX *ctx, fr_pair_list_t *out,
752
              uint8_t const *data, size_t data_len, UNUSED void *proto_ctx)
753
1.23k
{
754
1.23k
  unsigned int  code;
755
756
1.23k
  if (!fr_dhcpv4_ok(data, data_len, NULL, NULL)) return -1;
757
758
200
  if (fr_dhcpv4_decode(ctx, out, data, data_len, &code) < 0) return -1;
759
760
125
  return data_len;
761
200
}
762
763
static ssize_t decode_option_wrapper(TALLOC_CTX *ctx, fr_pair_list_t *out, NDEBUG_UNUSED fr_dict_attr_t const *parent,
764
              uint8_t const *data, size_t data_len, void *decode_ctx)
765
0
{
766
0
  fr_assert(parent == fr_dict_root(dict_dhcpv4));
767
768
0
  return fr_dhcpv4_decode_option(ctx, out, data, data_len, decode_ctx);
769
0
}
770
771
/*
772
 *  Test points
773
 */
774
extern fr_test_point_pair_decode_t dhcpv4_tp_decode_pair;
775
fr_test_point_pair_decode_t dhcpv4_tp_decode_pair = {
776
  .test_ctx = decode_test_ctx,
777
  .func   = decode_option_wrapper
778
};
779
780
extern fr_test_point_proto_decode_t dhcpv4_tp_decode_proto;
781
fr_test_point_proto_decode_t dhcpv4_tp_decode_proto = {
782
  .test_ctx = decode_test_ctx,
783
  .func   = fr_dhcpv4_decode_proto
784
};