Coverage Report

Created: 2026-10-18 06:56

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