The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
encode.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: 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 #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 {
72  FR_DBUFF_IN_RETURN(m, option);
73  FR_DBUFF_IN_RETURN(m, (uint16_t) data_len);
74 
75  return sizeof(option) + sizeof(uint16_t);
76 }
77 
78 
80  fr_da_stack_t *da_stack, unsigned int depth,
81  fr_dcursor_t *cursor, void *encode_ctx)
82 {
83  ssize_t slen;
84  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
85  fr_pair_t const *vp = fr_dcursor_current(cursor);
86  fr_dict_attr_t const *da = da_stack->da[depth];
87  fr_dns_ctx_t *packet_ctx = encode_ctx;
88 
89  PAIR_VERIFY(vp);
90  FR_PROTO_STACK_PRINT(da_stack, depth);
91 
92  /*
93  * Nested structs
94  */
95  if (vp->vp_type == FR_TYPE_STRUCT) {
96  fr_dcursor_t child_cursor;
97 
98  fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
99 
100  slen = fr_struct_to_network(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx, encode_value, encode_child);
101  if (slen < 0) return slen;
102 
103  /*
104  * Rebuild the da_stack for the next option.
105  */
106  vp = fr_dcursor_next(cursor);
107  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
108  return fr_dbuff_set(dbuff, &work_dbuff);
109  }
110 
111  /*
112  * Flat-list
113  */
114  if (da->type == FR_TYPE_STRUCT) {
115  slen = fr_struct_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value, encode_child);
116  if (slen <= 0) return slen;
117 
118  /*
119  * Rebuild the da_stack for the next option.
120  */
121  vp = fr_dcursor_current(cursor);
122  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
123  return fr_dbuff_set(dbuff, &work_dbuff);
124  }
125  /*
126  * If it's not a TLV, it should be a value type RFC
127  * attribute make sure that it is.
128  */
129  if (da_stack->da[depth + 1] != NULL) {
130  fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
132  }
133 
134  if (vp->da != da) {
135  fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
137  }
138 
139  switch (vp->vp_type) {
140  case FR_TYPE_TLV:
141  case FR_TYPE_VENDOR:
142  case FR_TYPE_VSA:
143  case FR_TYPE_GROUP:
144  fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
145  fr_type_to_str(da->type));
147 
148  case FR_TYPE_STRING:
149  /*
150  * DNS labels get a special encoder.
151  */
152  if (!da->flags.extra) {
153  fr_dbuff_marker_t last_byte, src;
154 
155  fr_assert((da->flags.subtype == FLAG_ENCODE_DNS_LABEL) ||
156  (da->flags.subtype == FLAG_ENCODE_DNS_LABEL_UNCOMPRESSED));
157 
158  fr_dbuff_marker(&last_byte, &work_dbuff);
159  fr_dbuff_marker(&src, &work_dbuff);
160  FR_PROTO_TRACE("encode DNS label %s", vp->vp_strvalue);
161  slen = fr_dns_label_from_value_box_dbuff(&work_dbuff, (da->flags.subtype == FLAG_ENCODE_DNS_LABEL),
162  &vp->data, packet_ctx->lb);
163  if (slen < 0) return slen;
164  break;
165  }
166  goto to_network;
167 
168  /*
169  * Common encoder might add scope byte, so we just copy the address portion
170  */
171  case FR_TYPE_IPV6_ADDR:
172  FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, vp->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
173  break;
174 
175  case FR_TYPE_IPV4_PREFIX:
176  fr_strerror_const("invalid data type - ipv4prefix");
178 
179  case FR_TYPE_IPV6_PREFIX:
180  fr_strerror_const("invalid data type - ipv4prefix");
182 
183  case FR_TYPE_BOOL:
184  /*
185  * Don't encode anything! The mere existence of
186  * the attribute signifies a "true" value.
187  */
188  break;
189 
190  /*
191  * The value_box functions will take care of fixed-width
192  * "string" and "octets" options.
193  */
194  to_network:
195  case FR_TYPE_OCTETS:
196  /*
197  * Hack until we find all places that don't set data.enumv
198  */
199  if (vp->da->flags.length && (vp->data.enumv != vp->da)) {
200  fr_dict_attr_t const * const *c = &vp->data.enumv;
201  fr_dict_attr_t **u;
202 
203  memcpy(&u, &c, sizeof(c)); /* const issues */
204  memcpy(u, &vp->da, sizeof(vp->da));
205  }
206  FALL_THROUGH;
207 
208  default:
209  slen = fr_value_box_to_network(&work_dbuff, &vp->data);
210  if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
211  break;
212  }
213 
214  /*
215  * Rebuilds the TLV stack for encoding the next attribute
216  */
217  vp = fr_dcursor_next(cursor);
218  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
219 
220  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "done value");
221 
222  return fr_dbuff_set(dbuff, &work_dbuff);
223 }
224 
226  fr_da_stack_t *da_stack, unsigned int depth,
227  fr_dcursor_t *cursor, void *encode_ctx)
228 {
229  ssize_t len;
230  fr_pair_t *vp = fr_dcursor_current(cursor);
231  fr_dcursor_t child_cursor;
232  fr_dbuff_t work_dbuff;
233 
234  if (da_stack->da[depth]) {
235  /*
236  * Determine the nested type and call the appropriate encoder
237  */
238  switch (da_stack->da[depth]->type) {
239  case FR_TYPE_TLV:
240  if (!da_stack->da[depth + 1]) break;
241 
242  return encode_tlv(dbuff, da_stack, depth, cursor, encode_ctx);
243 
244  case FR_TYPE_GROUP:
245  if (!da_stack->da[depth + 1]) break;
246  FALL_THROUGH;
247 
248  default:
249  return encode_rfc(dbuff, da_stack, depth, cursor, encode_ctx);
250  }
251  }
252 
254 
255  fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
256  work_dbuff = FR_DBUFF(dbuff);
257 
258  while ((vp = fr_dcursor_current(&child_cursor)) != NULL) {
259  fr_proto_da_stack_build(da_stack, vp->da);
260 
261  switch (da_stack->da[depth]->type) {
262  case FR_TYPE_TLV:
263  len = encode_tlv(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
264  break;
265 
266  default:
267  len = encode_rfc(&work_dbuff, da_stack, depth, &child_cursor, encode_ctx);
268  break;
269  }
270 
271  if (len <= 0) return len;
272  }
273 
274  /*
275  * Skip over the attribute we just encoded.
276  */
277  vp = fr_dcursor_next(cursor);
278  fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
279 
280  return fr_dbuff_set(dbuff, &work_dbuff);
281 }
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  */
290  fr_da_stack_t *da_stack, unsigned int depth,
291  fr_dcursor_t *cursor, void *encode_ctx)
292 {
293  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
294  fr_dbuff_marker_t hdr;
295  fr_dict_attr_t const *da = da_stack->da[depth];
296  ssize_t len;
297 
298  FR_PROTO_STACK_PRINT(da_stack, depth);
299  fr_dbuff_marker(&hdr, &work_dbuff);
300 
301  /*
302  * Make space for the header...
303  */
305  fr_dbuff_advance(&work_dbuff, DNS_OPT_HDR_LEN);
306 
307  /*
308  * Write out the option's value
309  */
310  if (da->flags.array) {
311  len = fr_pair_array_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_value);
312  } else {
313  len = encode_value(&work_dbuff, da_stack, depth, cursor, encode_ctx);
314  }
315  if (len < 0) return len;
316 
317  /*
318  * Write out the option number and length (before the value we just wrote)
319  */
320  (void) encode_option_hdr(&hdr, (uint16_t)da->attr, (uint16_t) (fr_dbuff_used(&work_dbuff) - DNS_OPT_HDR_LEN));
321 
322  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done RFC header");
323 
324  return fr_dbuff_set(dbuff, &work_dbuff);
325 }
326 
328  fr_da_stack_t *da_stack, unsigned int depth,
329  fr_dcursor_t *cursor, void *encode_ctx)
330 {
331  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
332  fr_dbuff_marker_t hdr;
333  fr_dict_attr_t const *da = da_stack->da[depth];
334  ssize_t len;
335 
336  fr_dbuff_marker(&hdr, &work_dbuff);
338  FR_PROTO_STACK_PRINT(da_stack, depth);
339 
340  if (da_stack->da[depth]->type != FR_TYPE_TLV) {
341  fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
342  fr_type_to_str(da_stack->da[depth]->type));
344  }
345 
346  if (!da_stack->da[depth + 1]) {
347  fr_assert(0);
348  fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
350  }
351 
352  FR_DBUFF_ADVANCE_RETURN(&work_dbuff, DNS_OPT_HDR_LEN); /* Make room for option header */
353 
354  len = fr_pair_cursor_to_network(&work_dbuff, da_stack, depth, cursor, encode_ctx, encode_child);
355  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  (void) encode_option_hdr(&hdr, (uint16_t)da->attr, (uint16_t) (fr_dbuff_used(&work_dbuff) - DNS_OPT_HDR_LEN));
365 
366  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), "Done TLV header");
367 
368  return fr_dbuff_set(dbuff, &work_dbuff);
369 }
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  */
383 {
384  ssize_t slen;
385  fr_pair_t *vp;
386  fr_da_stack_t da_stack;
387  fr_dbuff_t work_dbuff = FR_DBUFF_MAX(dbuff, UINT16_MAX);
388 
390  FR_PROTO_STACK_PRINT(&da_stack, 0);
391 
392  FR_PROTO_TRACE("encode_rr -- remaining %zd", fr_dbuff_remaining(&work_dbuff));
393 
394  vp = fr_dcursor_current(cursor);
395  if (vp->vp_type == FR_TYPE_STRUCT) {
396  fr_dcursor_t child_cursor;
397 
398  fr_pair_dcursor_child_iter_init(&child_cursor, &vp->vp_group, cursor);
399 
400  slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &child_cursor, encode_ctx, encode_value, encode_child);
401  if (slen <= 0) return slen;
402  (void) fr_dcursor_next(cursor);
403 
404  } else {
405  slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, cursor, encode_ctx, encode_value, encode_child);
406  if (slen <= 0) return slen;
407  }
408 
409  FR_PROTO_TRACE("Complete rr is %zu byte(s)", fr_dbuff_used(&work_dbuff));
410  FR_PROTO_HEX_DUMP(fr_dbuff_start(&work_dbuff), fr_dbuff_used(&work_dbuff), NULL);
411 
412  return fr_dbuff_set(dbuff, &work_dbuff);
413 }
414 
416  fr_dict_attr_t const *attr, fr_dns_ctx_t *packet_ctx, uint8_t *counter)
417 {
418  int count;
419  fr_pair_t *vp;
420  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
421  fr_dcursor_t cursor;
422 
423  vp = fr_pair_dcursor_by_da_init(&cursor, vps, attr);
424  if (!vp) {
425  FR_PROTO_TRACE(" %s not found in list", attr->name);
426  return 0;
427  }
428 
429  fr_proto_da_stack_build(da_stack, attr);
430 
431  count = 0;
432  while (count < 65535) {
433  ssize_t slen;
434  fr_dcursor_t child_cursor;
435 
436  fr_pair_dcursor_init(&child_cursor, &vp->vp_group);
437  slen = fr_struct_to_network(&work_dbuff, da_stack, 0, &child_cursor, packet_ctx, encode_value, encode_child);
438  if (slen <= 0) return slen;
439 
440  count++;
441  vp = fr_dcursor_next(&cursor);
442  if (!vp) break;
443  }
444 
445  fr_nbo_from_uint16(counter, count);
446  FR_PROTO_TRACE(" %s encoded %d records", attr->name, count);
447 
448  return fr_dbuff_set(dbuff, &work_dbuff);
449 }
450 
451 /** Encode a DNS packet
452  *
453  */
455 {
456  fr_dbuff_t work_dbuff = FR_DBUFF(dbuff);
457  ssize_t slen;
458  uint8_t *packet;
459  fr_pair_t *vp;
460  fr_dcursor_t cursor, child_cursor;
461  fr_da_stack_t da_stack;
462 
463  packet = fr_dbuff_current(&work_dbuff);
464  fr_assert(packet == packet_ctx->packet);
465 
466  /*
467  * @todo - find maximum packet length, and limit work_dbuff to that.
468  */
470  if (!vp) {
471  fr_pair_list_debug(vps);
472 
473  fr_strerror_const("attribute list does not include DNS packet header");
474  return -1;
475  }
476 
477  /*
478  * Encode the header.
479  */
480  fr_pair_dcursor_init(&child_cursor, &vp->vp_group);
482 
483  slen = fr_struct_to_network(&work_dbuff, &da_stack, 0, &cursor, packet_ctx, encode_value, NULL);
484  if (slen <= 0) return slen;
485 
486  fr_assert(slen == DNS_HDR_LEN);
487 
488  /*
489  * Encode questions
490  */
491  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_question, packet_ctx, packet + 4);
492  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
493 
494  /*
495  * Encode answers
496  */
497  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_rr, packet_ctx, packet + 6);
498  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
499 
500  /*
501  * Encode NS records
502  */
503  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_ns, packet_ctx, packet + 8);
504  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
505 
506  /*
507  * Encode additional records
508  */
509  slen = encode_record(&work_dbuff, &da_stack, vps, attr_dns_ar, packet_ctx, packet + 10);
510  if (slen < 0) return slen - (fr_dbuff_current(&work_dbuff) - packet);
511 
512  return fr_dbuff_set(dbuff, &work_dbuff);
513 }
514 
515 static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
516 {
517  fr_dns_ctx_t *test_ctx;
518 
519  test_ctx = talloc_zero(ctx, fr_dns_ctx_t);
520  if (!test_ctx) return -1;
521 
522  test_ctx->tmp_ctx = talloc(test_ctx, uint8_t);
523 
524  *out = test_ctx;
525 
526  return 0;
527 }
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 {
531  ssize_t slen;
532  fr_dns_ctx_t *packet_ctx = (fr_dns_ctx_t *) proto_ctx;
533 
534  packet_ctx->packet = data;
535  packet_ctx->packet_len = data_len;
536  packet_ctx->lb = fr_dns_labels_get(data, data_len, false);
537  fr_assert(packet_ctx->lb != NULL);
538 
539  slen = fr_dns_encode(&FR_DBUFF_TMP(data, data_len), vps, packet_ctx);
540 
541 #ifndef NDEBUG
542  if (slen <= 0) return slen;
543 
544  if (fr_debug_lvl > 2) {
545 // fr_dns_print_hex(stdout, data, slen);
546  }
547 #endif
548 
549  return slen;
550 }
551 
552 /*
553  * Test points
554  */
558  .func = fr_dns_encode_rr,
559 };
560 
564  .func = fr_dns_encode_proto
565 };
#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_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition: dbuff.h:1067
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition: dbuff.h:762
#define FR_DBUFF_ADVANCE_RETURN(_dbuff_or_marker, _len)
Advance the 'current' position in dbuff or marker by _len bytes returning if _len is out of range.
Definition: dbuff.h:1083
#define FR_DBUFF_EXTEND_LOWAT_OR_RETURN(_dbuff_or_marker, _lowat)
Extend if we're below _lowat and return if we can't extend above _lowat.
Definition: dbuff.h:668
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
Definition: dbuff.h:81
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition: dbuff.h:906
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition: dbuff.h:893
#define fr_dbuff_remaining(_dbuff_or_marker)
Return the number of bytes remaining between the dbuff or marker and the end of the buffer.
Definition: dbuff.h:738
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
Definition: dbuff.h:1377
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
Definition: dbuff.h:1580
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition: dbuff.h:222
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
Definition: dbuff.h:301
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
Definition: dbuff.h:1187
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:509
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
@ FLAG_ENCODE_DNS_LABEL
encode as DNS label
Definition: dhcpv4.h:71
ssize_t fr_dns_label_from_value_box_dbuff(fr_dbuff_t *dbuff, bool compression, fr_value_box_t const *value, fr_dns_labels_t *lb)
Encode a single value box of type string, serializing its contents to a dns label in a dbuff.
Definition: dns.c:604
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
Definition: pair.h:37
ssize_t fr_pair_array_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_value)
Encode an array of values from the network.
Definition: encode.c:42
ssize_t fr_pair_cursor_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx, fr_encode_dbuff_t encode_pair)
Definition: encode.c:71
int fr_debug_lvl
Definition: log.c:42
unsigned short uint16_t
Definition: merged_model.c:31
@ 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_VENDOR
Attribute that represents a vendor in the attribute tree.
Definition: merged_model.c:122
@ 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
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
static void fr_nbo_from_uint16(uint8_t out[static sizeof(uint16_t)], uint16_t num)
Write out an unsigned 16bit integer in wire format (big endian)
Definition: nbo.h:38
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
Definition: proto.c:118
static fr_internal_encode_ctx_t encode_ctx
HIDDEN fr_dict_attr_t const * attr_dns_ar
Definition: base.c:55
HIDDEN fr_dict_attr_t const * attr_dns_ns
Definition: base.c:54
HIDDEN fr_dict_attr_t const * attr_dns_packet
Definition: base.c:51
HIDDEN fr_dict_attr_t const * attr_dns_question
Definition: base.c:52
HIDDEN fr_dict_attr_t const * attr_dns_rr
Definition: base.c:53
fr_dns_labels_t * fr_dns_labels_get(uint8_t const *packet, size_t packet_len, bool init_mark)
Definition: base.c:375
Implementation of the DNS protocol.
size_t packet_len
Definition: dns.h:85
#define DNS_HDR_LEN
Definition: dns.h:141
TALLOC_CTX * tmp_ctx
for temporary things cleaned up during decoding
Definition: dns.h:83
uint8_t const * packet
DNS labels can point anywhere in the packet :(.
Definition: dns.h:84
@ FLAG_ENCODE_DNS_LABEL_UNCOMPRESSED
encode as uncompressed DNS label
Definition: dns.h:79
fr_dns_labels_t * lb
Definition: dns.h:86
fr_test_point_proto_encode_t dns_tp_encode_proto
Definition: encode.c:562
#define DNS_OPT_HDR_LEN
Definition: encode.c:37
static ssize_t encode_option_hdr(fr_dbuff_marker_t *m, uint16_t option, size_t data_len)
Macro-like function for encoding an option header.
Definition: encode.c:70
fr_test_point_pair_encode_t dns_tp_encode_pair
Definition: encode.c:556
static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Definition: encode.c:79
static ssize_t fr_dns_encode_rr(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Encode a Dns option and any sub-options.
Definition: encode.c:382
static ssize_t encode_child(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Definition: encode.c:225
static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Definition: encode.c:327
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)
Definition: encode.c:529
static ssize_t encode_record(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, fr_pair_list_t *vps, fr_dict_attr_t const *attr, fr_dns_ctx_t *packet_ctx, uint8_t *counter)
Definition: encode.c:415
static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
Definition: encode.c:515
ssize_t fr_dns_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_dns_ctx_t *packet_ctx)
Encode a DNS packet.
Definition: encode.c:454
static ssize_t encode_rfc(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode an RFC format TLV.
Definition: encode.c:289
VQP attributes.
return count
Definition: module.c:175
fr_assert(0)
fr_pair_t * vp
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *parent_cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
Definition: struct.c:478
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:92
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Definition: test_point.h:74
Entry point for pair encoders.
Definition: test_point.h:91
Entry point for protocol encoders.
Definition: test_point.h:73
static fr_pair_t * fr_pair_dcursor_child_iter_init(fr_dcursor_t *cursor, fr_pair_list_t const *list, fr_dcursor_t const *parent)
Initializes a child dcursor from a parent cursor, with an iteration function.
Definition: pair.h:610
#define fr_pair_dcursor_by_da_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
Definition: pair.h:627
#define PAIR_VERIFY(_x)
Definition: pair.h:190
void fr_pair_list_debug(fr_pair_list_t const *list)
Dumps a list to the default logging destination - Useful for calling from debuggers.
Definition: pair_print.c:296
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:590
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
Definition: proto.h:41
#define FR_PROTO_TRACE(_fmt,...)
Definition: proto.h:40
#define FR_PROTO_STACK_PRINT(_stack, _depth)
Definition: proto.h:43
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition: proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition: proto.h:54
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
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_is_structural(_x)
Definition: types.h:371
return fr_dbuff_set(dbuff, &our_dbuff)
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
Definition: value.c:1359
static fr_slen_t data
Definition: value.h:1259
static size_t char ** out
Definition: value.h:984