Coverage Report

Created: 2024-08-28 06:17

/src/freeradius-server/src/protocols/dns/encode.c
Line
Count
Source (jump to first uncovered line)
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: 7007cca77cf00bc2916b078683003bd36e32913a $
19
 *
20
 * @file protocols/dns/encode.c
21
 * @brief Functions to encode DNS packets
22
 *
23
 * @author Alan DeKok (aland@freeradius.org)
24
 *
25
 * @copyright 2021 NetworkRADIUS SARL (legal@networkradius.com)
26
 */
27
#include <freeradius-devel/io/test_point.h>
28
#include <freeradius-devel/util/dbuff.h>
29
#include <freeradius-devel/util/dns.h>
30
#include <freeradius-devel/util/proto.h>
31
#include <freeradius-devel/util/struct.h>
32
#include <freeradius-devel/util/encode.h>
33
34
#include "dns.h"
35
#include "attrs.h"
36
37
0
#define DNS_OPT_HDR_LEN (4)
38
39
static ssize_t encode_value(fr_dbuff_t *dbuff,
40
          fr_da_stack_t *da_stack, unsigned int depth,
41
          fr_dcursor_t *cursor, void *encode_ctx);
42
43
static ssize_t encode_rfc(fr_dbuff_t *dbuff,
44
            fr_da_stack_t *da_stack, unsigned int depth,
45
            fr_dcursor_t *cursor, void *encode_ctx);
46
47
static ssize_t encode_tlv(fr_dbuff_t *dbuff,
48
            fr_da_stack_t *da_stack, unsigned int depth,
49
            fr_dcursor_t *cursor, void *encode_ctx);
50
51
static ssize_t encode_child(fr_dbuff_t *dbuff,
52
           fr_da_stack_t *da_stack, unsigned int depth,
53
           fr_dcursor_t *cursor, void *encode_ctx);
54
55
/** Macro-like function for encoding an option header
56
 *
57
 *    0                   1                   2                   3
58
 *    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
59
 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60
 *   |          option-code          |           option-len          |
61
 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62
 *
63
 * @param[out] m    Where to write the 4 byte option header.
64
 * @param[in] option    The option number (host byte order).
65
 * @param[in] data_len    The length of the option (host byte order).
66
 * @return
67
 *  - <0  How much data would have been required as a negative value.
68
 *  - 4 The length of data written.
69
 */
70
static inline ssize_t encode_option_hdr(fr_dbuff_marker_t *m, uint16_t option, size_t data_len)
71
0
{
72
0
  FR_DBUFF_IN_RETURN(m, option);
73
0
  FR_DBUFF_IN_RETURN(m, (uint16_t) data_len);
74
75
0
  return sizeof(option) + sizeof(uint16_t);
76
0
}
77
78
79
static ssize_t encode_value(fr_dbuff_t *dbuff,
80
          fr_da_stack_t *da_stack, unsigned int depth,
81
          fr_dcursor_t *cursor, void *encode_ctx)
82
0
{
83
0
  ssize_t     slen;
84
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
85
0
  fr_pair_t const   *vp = fr_dcursor_current(cursor);
86
0
  fr_dict_attr_t const  *da = da_stack->da[depth];
87
0
  fr_dns_ctx_t  *packet_ctx = encode_ctx;
88
89
0
  PAIR_VERIFY(vp);
90
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
91
92
  /*
93
   *  Nested structs
94
   */
95
0
  if (vp->vp_type == FR_TYPE_STRUCT) {
96
0
    fr_dcursor_t child_cursor;
97
98
0
    fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
99
100
0
    slen = fr_struct_to_network(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx, encode_value, encode_child);
101
0
    if (slen < 0) return slen;
102
103
    /*
104
     *  Rebuild the da_stack for the next option.
105
     */
106
0
    vp = fr_dcursor_next(cursor);
107
0
    fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
108
0
    return fr_dbuff_set(dbuff, &work_dbuff);
109
0
  }
110
111
  /*
112
   *  Flat-list
113
   */
114
0
  if (da->type == FR_TYPE_STRUCT) {
115
0
    slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value, encode_child);
116
0
    if (slen <= 0) return slen;
117
118
    /*
119
     *  Rebuild the da_stack for the next option.
120
     */
121
0
    vp = fr_dcursor_current(cursor);
122
0
    fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
123
0
    return fr_dbuff_set(dbuff, &work_dbuff);
124
0
  }
125
  /*
126
   *  If it's not a TLV, it should be a value type RFC
127
   *  attribute make sure that it is.
128
   */
129
0
  if (da_stack->da[depth + 1] != NULL) {
130
0
    fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
131
0
    return PAIR_ENCODE_FATAL_ERROR;
132
0
  }
133
134
0
  if (vp->da != da) {
135
0
    fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
136
0
    return PAIR_ENCODE_FATAL_ERROR;
137
0
  }
138
139
0
  switch (vp->vp_type) {
140
0
  case FR_TYPE_TLV:
141
0
  case FR_TYPE_VENDOR:
142
0
  case FR_TYPE_VSA:
143
0
  case FR_TYPE_GROUP:
144
0
    fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
145
0
           fr_type_to_str(da->type));
146
0
    return PAIR_ENCODE_FATAL_ERROR;
147
148
0
  case FR_TYPE_STRING:
149
    /*
150
     *  DNS labels get a special encoder.
151
     */
152
0
    if (!da->flags.extra) {
153
0
      fr_dbuff_marker_t last_byte, src;
154
155
0
      fr_assert((da->flags.subtype == FLAG_ENCODE_DNS_LABEL) ||
156
0
          (da->flags.subtype == FLAG_ENCODE_DNS_LABEL_UNCOMPRESSED));
157
158
0
      fr_dbuff_marker(&last_byte, &work_dbuff);
159
0
      fr_dbuff_marker(&src, &work_dbuff);
160
0
      FR_PROTO_TRACE("encode DNS label %s", vp->vp_strvalue);
161
0
      slen = fr_dns_label_from_value_box_dbuff(&work_dbuff, (da->flags.subtype == FLAG_ENCODE_DNS_LABEL),
162
0
                 &vp->data, packet_ctx->lb);
163
0
      if (slen < 0) return slen;
164
0
      break;
165
0
    }
166
0
    goto to_network;
167
168
  /*
169
   *  Common encoder might add scope byte, so we just copy the address portion
170
   */
171
0
  case FR_TYPE_IPV6_ADDR:
172
0
    FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
173
0
    break;
174
175
0
  case FR_TYPE_IPV4_PREFIX:
176
0
    fr_strerror_const("invalid data type - ipv4prefix");
177
0
    return PAIR_ENCODE_FATAL_ERROR;
178
179
0
  case FR_TYPE_IPV6_PREFIX:
180
0
    fr_strerror_const("invalid data type - ipv4prefix");
181
0
    return PAIR_ENCODE_FATAL_ERROR;
182
183
0
  case FR_TYPE_BOOL:
184
    /*
185
     *  Don't encode anything!  The mere existence of
186
     *  the attribute signifies a "true" value.
187
     */
188
0
    break;
189
190
  /*
191
   *  The value_box functions will take care of fixed-width
192
   *  "string" and "octets" options.
193
   */
194
0
  to_network:
195
0
  case FR_TYPE_OCTETS:
196
    /*
197
     *  Hack until we find all places that don't set data.enumv
198
     */
199
0
    if (vp->da->flags.length && (vp->data.enumv != vp->da)) {
200
0
      fr_dict_attr_t const * const *c = &vp->data.enumv;
201
0
      fr_dict_attr_t **u;
202
203
0
      memcpy(&u, &c, sizeof(c)); /* const issues */
204
0
      memcpy(u, &vp->da, sizeof(vp->da));
205
0
    }
206
0
    FALL_THROUGH;
207
208
0
  default:
209
0
    slen = fr_value_box_to_network(&work_dbuff, &vp->data);
210
0
    if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
211
0
    break;
212
0
  }
213
214
  /*
215
   *  Rebuilds the TLV stack for encoding the next attribute
216
   */
217
0
  vp = fr_dcursor_next(cursor);
218
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
219
220
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "done value");
221
222
0
  return fr_dbuff_set(dbuff, &work_dbuff);
223
0
}
224
225
static ssize_t encode_child(fr_dbuff_t *dbuff,
226
          fr_da_stack_t *da_stack, unsigned int depth,
227
          fr_dcursor_t *cursor, void *encode_ctx)
228
0
{
229
0
  ssize_t len;
230
0
  fr_pair_t *vp = fr_dcursor_current(cursor);
231
0
  fr_dcursor_t child_cursor;
232
0
  fr_dbuff_t work_dbuff;
233
234
0
  if (da_stack->da[depth]) {
235
    /*
236
     *  Determine the nested type and call the appropriate encoder
237
     */
238
0
    switch (da_stack->da[depth]->type) {
239
0
    case FR_TYPE_TLV:
240
0
      if (!da_stack->da[depth + 1]) break;
241
242
0
      return encode_tlv(dbuff, da_stack, depth, cursor, encode_ctx);
243
244
0
    case FR_TYPE_GROUP:
245
0
      if (!da_stack->da[depth + 1]) break;
246
0
      FALL_THROUGH;
247
248
0
    default:
249
0
      return encode_rfc(dbuff, da_stack, depth, cursor, encode_ctx);
250
0
    }
251
0
  }
252
253
0
  fr_assert(fr_type_is_structural(vp->vp_type));
254
255
0
  fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
256
0
  work_dbuff = FR_DBUFF(dbuff);
257
258
0
  while ((vp = fr_dcursor_current(&child_cursor)) != NULL) {
259
0
    fr_proto_da_stack_build(da_stack, vp->da);
260
261
0
    switch (da_stack->da[depth]->type) {
262
0
    case FR_TYPE_TLV:
263
0
      len = encode_tlv(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
264
0
      break;
265
266
0
    default:
267
0
      len = encode_rfc(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
268
0
      break;
269
0
    }
270
271
0
    if (len <= 0) return len;
272
0
  }
273
274
  /*
275
   *  Skip over the attribute we just encoded.
276
   */
277
0
  vp = fr_dcursor_next(cursor);
278
0
  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
279
280
0
  return fr_dbuff_set(dbuff, &work_dbuff);
281
0
}
282
283
/** Encode an RFC format TLV.
284
 *
285
 * This could be a standard attribute, or a TLV data type.
286
 * If it's a standard attribute, then vp->da->attr == attribute.
287
 * Otherwise, attribute may be something else.
288
 */
289
static ssize_t encode_rfc(fr_dbuff_t *dbuff,
290
            fr_da_stack_t *da_stack, unsigned int depth,
291
            fr_dcursor_t *cursor, void *encode_ctx)
292
0
{
293
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
294
0
  fr_dbuff_marker_t hdr;
295
0
  fr_dict_attr_t const  *da = da_stack->da[depth];
296
0
  ssize_t     len;
297
298
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
299
0
  fr_dbuff_marker(&hdr, &work_dbuff);
300
301
  /*
302
   *  Make space for the header...
303
   */
304
0
  FR_DBUFF_EXTEND_LOWAT_OR_RETURN(&work_dbuff, DNS_OPT_HDR_LEN);
305
0
  fr_dbuff_advance(&work_dbuff, DNS_OPT_HDR_LEN);
306
307
  /*
308
   *  Write out the option's value
309
   */
310
0
  if (da->flags.array) {
311
0
    len = fr_pair_array_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value);
312
0
  } else {
313
0
    len = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx);
314
0
  }
315
0
  if (len < 0) return len;
316
317
  /*
318
   *  Write out the option number and length (before the value we just wrote)
319
   */
320
0
  (void) encode_option_hdr(&hdr, (uint16_t)da->attr, (uint16_t) (fr_dbuff_used(&work_dbuff) - DNS_OPT_HDR_LEN));
321
322
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done RFC header");
323
324
0
  return fr_dbuff_set(dbuff, &work_dbuff);
325
0
}
326
327
static ssize_t encode_tlv(fr_dbuff_t *dbuff,
328
            fr_da_stack_t *da_stack, unsigned int depth,
329
            fr_dcursor_t *cursor, void *encode_ctx)
330
0
{
331
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
332
0
  fr_dbuff_marker_t hdr;
333
0
  fr_dict_attr_t const  *da = da_stack->da[depth];
334
0
  ssize_t     len;
335
336
0
  fr_dbuff_marker(&hdr, &work_dbuff);
337
0
  PAIR_VERIFY(fr_dcursor_current(cursor));
338
0
  FR_PROTO_STACK_PRINT(da_stack, depth);
339
340
0
  if (da_stack->da[depth]->type != FR_TYPE_TLV) {
341
0
    fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
342
0
           fr_type_to_str(da_stack->da[depth]->type));
343
0
    return PAIR_ENCODE_FATAL_ERROR;
344
0
  }
345
346
0
  if (!da_stack->da[depth + 1]) {
347
0
    fr_assert(0);
348
0
    fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
349
0
    return PAIR_ENCODE_FATAL_ERROR;
350
0
  }
351
352
0
  FR_DBUFF_ADVANCE_RETURN(&work_dbuff, DNS_OPT_HDR_LEN);  /* Make room for option header */
353
354
0
  len = fr_pair_cursor_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_child);
355
0
  if (len < 0) return len;
356
357
  /*
358
   *    0                   1                   2                   3
359
   *    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
360
   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
361
   *   |          option-code          |           option-len          |
362
   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
363
   */
364
0
  (void) encode_option_hdr(&hdr, (uint16_t)da->attr, (uint16_t) (fr_dbuff_used(&work_dbuff) - DNS_OPT_HDR_LEN));
365
366
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV header");
367
368
0
  return fr_dbuff_set(dbuff, &work_dbuff);
369
0
}
370
371
372
/** Encode a Dns option and any sub-options.
373
 *
374
 * @param[out] dbuff    Where to write encoded DHCP attributes.
375
 * @param[in] cursor    with current VP set to the option to be encoded.
376
 *        Will be advanced to the next option to encode.
377
 * @param[in] encode_ctx  containing parameters for the encoder.
378
 * @return
379
 *  - > 0 length of data written.
380
 *  - < 0 error.
381
 */
382
static ssize_t fr_dns_encode_rr(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
383
0
{
384
0
  ssize_t     slen;
385
0
  fr_pair_t   *vp;
386
0
  fr_da_stack_t   da_stack;
387
0
  fr_dbuff_t    work_dbuff = FR_DBUFF_MAX(dbuff, UINT16_MAX);
388
389
0
  fr_proto_da_stack_build(&da_stack, attr_dns_rr);
390
0
  FR_PROTO_STACK_PRINT(&da_stack, 0);
391
392
0
  FR_PROTO_TRACE("encode_rr -- remaining %zd", fr_dbuff_remaining(&work_dbuff));
393
394
0
  vp = fr_dcursor_current(cursor);
395
0
  if (vp->vp_type == FR_TYPE_STRUCT) {
396
0
    fr_dcursor_t child_cursor;
397
398
0
    fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
399
400
0
    slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &child_cursor, encode_ctx, encode_value, encode_child);
401
0
    if (slen <= 0) return slen;
402
0
    (void) fr_dcursor_next(cursor);
403
404
0
  } else {
405
0
    slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, cursor, encode_ctx, encode_value, encode_child);
406
0
    if (slen <= 0) return slen;
407
0
  }
408
409
0
  FR_PROTO_TRACE("Complete rr is %zu byte(s)", fr_dbuff_used(&work_dbuff));
410
0
  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), NULL);
411
412
0
  return fr_dbuff_set(dbuff, &work_dbuff);
413
0
}
414
415
static ssize_t encode_record(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, fr_pair_list_t *vps,
416
           fr_dict_attr_t const *attr, fr_dns_ctx_t *packet_ctx, uint8_t *counter)
417
0
{
418
0
  int   count;
419
0
  fr_pair_t *vp;
420
0
  fr_dbuff_t  work_dbuff = FR_DBUFF(dbuff);
421
0
  fr_dcursor_t  cursor;
422
423
0
  vp = fr_pair_dcursor_by_da_init(&cursor, vps, attr);
424
0
  if (!vp) {
425
0
    FR_PROTO_TRACE("      %s not found in list", attr->name);
426
0
    return 0;
427
0
  }
428
429
0
  fr_proto_da_stack_build(da_stack, attr);
430
431
0
  count = 0;
432
0
  while (count < 65535) {
433
0
    ssize_t slen;
434
0
    fr_dcursor_t child_cursor;
435
436
0
    fr_pair_dcursor_init(&child_cursor, &vp->vp_group);
437
0
    slen = fr_struct_to_network(&work_dbuff, da_stack, 0, &child_cursor, packet_ctx, encode_value, encode_child);
438
0
    if (slen <= 0) return slen;
439
440
0
    count++;
441
0
    vp = fr_dcursor_next(&cursor);
442
0
    if (!vp) break;
443
0
  }
444
445
0
  fr_nbo_from_uint16(counter, count);
446
0
  FR_PROTO_TRACE("      %s encoded %d records", attr->name, count);
447
448
0
  return fr_dbuff_set(dbuff, &work_dbuff);
449
0
}
450
451
/** Encode a DNS packet
452
 *
453
 */
454
ssize_t fr_dns_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_dns_ctx_t *packet_ctx)
455
0
{
456
0
  fr_dbuff_t    work_dbuff = FR_DBUFF(dbuff);
457
0
  ssize_t     slen;
458
0
  uint8_t     *packet;
459
0
  fr_pair_t   *vp;
460
0
  fr_dcursor_t    cursor, child_cursor;
461
0
  fr_da_stack_t   da_stack;
462
463
0
  packet = fr_dbuff_current(&work_dbuff);
464
0
  fr_assert(packet == packet_ctx->packet);
465
466
  /*
467
   *  @todo - find maximum packet length, and limit work_dbuff to that.
468
   */
469
0
  vp = fr_pair_dcursor_by_da_init(&cursor, vps, attr_dns_packet);
470
0
  if (!vp) {
471
0
    fr_pair_list_debug(vps);
472
473
0
    fr_strerror_const("attribute list does not include DNS packet header");
474
0
    return -1;
475
0
  }
476
477
  /*
478
   *  Encode the header.
479
   */
480
0
  fr_pair_dcursor_init(&child_cursor, &vp->vp_group);
481
0
  fr_proto_da_stack_build(&da_stack, attr_dns_packet);
482
483
0
  slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &cursor, packet_ctx, encode_value, NULL);
484
0
  if (slen <= 0) return slen;
485
486
0
  fr_assert(slen == DNS_HDR_LEN);
487
488
  /*
489
   *  Encode questions
490
   */
491
0
  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_question, packet_ctx, packet + 4);
492
0
  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
493
494
  /*
495
   *  Encode answers
496
   */
497
0
  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_rr, packet_ctx, packet + 6);
498
0
  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
499
500
  /*
501
   *  Encode NS records
502
   */
503
0
  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_ns, packet_ctx, packet + 8);
504
0
  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
505
506
  /*
507
   *  Encode additional records
508
   */
509
0
  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_ar, packet_ctx, packet + 10);
510
0
  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
511
512
0
  return fr_dbuff_set(dbuff, &work_dbuff);
513
0
}
514
515
static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
516
0
{
517
0
  fr_dns_ctx_t  *test_ctx;
518
519
0
  test_ctx = talloc_zero(ctx, fr_dns_ctx_t);
520
0
  if (!test_ctx) return -1;
521
522
0
  test_ctx->tmp_ctx = talloc(test_ctx, uint8_t);
523
524
0
  *out = test_ctx;
525
526
0
  return 0;
527
0
}
528
529
static ssize_t fr_dns_encode_proto(UNUSED TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, void *proto_ctx)
530
0
{
531
0
  ssize_t slen;
532
0
  fr_dns_ctx_t *packet_ctx = (fr_dns_ctx_t *) proto_ctx;
533
534
0
  packet_ctx->packet = data;
535
0
  packet_ctx->packet_len = data_len;
536
0
  packet_ctx->lb = fr_dns_labels_get(data, data_len, false);
537
0
  fr_assert(packet_ctx->lb != NULL);
538
539
0
  slen = fr_dns_encode(&FR_DBUFF_TMP(data, data_len), vps, packet_ctx);
540
541
0
#ifndef NDEBUG
542
0
  if (slen <= 0) return slen;
543
544
0
  if (fr_debug_lvl > 2) {
545
//    fr_dns_print_hex(stdout, data, slen);
546
0
  }
547
0
#endif
548
549
0
  return slen;
550
0
}
551
552
/*
553
 *  Test points
554
 */
555
extern fr_test_point_pair_encode_t dns_tp_encode_pair;
556
fr_test_point_pair_encode_t dns_tp_encode_pair = {
557
  .test_ctx = encode_test_ctx,
558
  .func   = fr_dns_encode_rr,
559
};
560
561
extern fr_test_point_proto_encode_t dns_tp_encode_proto;
562
fr_test_point_proto_encode_t dns_tp_encode_proto = {
563
  .test_ctx = encode_test_ctx,
564
  .func   = fr_dns_encode_proto
565
};