The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
base.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: e8695b051da97b131601c6bb93906ae1577d2440 $
19  *
20  * @file protocols/dns/base.c
21  * @brief Functions to send/receive dns packets.
22  *
23  * @copyright 2008 The FreeRADIUS server project
24  * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
25  */
26 RCSID("$Id: e8695b051da97b131601c6bb93906ae1577d2440 $")
27 
28 #include "dns.h"
29 #include "attrs.h"
30 
32 
33 typedef struct {
36 } dns_option_t;
37 
39 
40 static _Thread_local fr_dns_labels_t fr_dns_labels;
41 static _Thread_local fr_dns_block_t fr_dns_blocks[256];
42 static _Thread_local uint8_t fr_dns_marker[65536];
43 
46  { .out = &dict_dns, .proto = "dns" },
47  { NULL }
48 };
49 
50 //fr_dict_attr_t const *attr_dns_packet_type;
56 
59 // { .out = &attr_dns_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT16, .dict = &dict_dns },
60  { .out = &attr_dns_packet, .name = "Header", .type = FR_TYPE_STRUCT, .dict = &dict_dns },
61  { .out = &attr_dns_question, .name = "Question", .type = FR_TYPE_STRUCT, .dict = &dict_dns },
62  { .out = &attr_dns_rr, .name = "Resource-Record", .type = FR_TYPE_STRUCT, .dict = &dict_dns },
63  { .out = &attr_dns_ns, .name = "Name-Server", .type = FR_TYPE_STRUCT, .dict = &dict_dns },
64  { .out = &attr_dns_ar, .name = "Additional-Record", .type = FR_TYPE_STRUCT, .dict = &dict_dns },
65  { NULL }
66 };
67 
69  [FR_DNS_QUERY] = "Query",
70  [FR_DNS_INVERSE_QUERY] = "Inverse-Query",
71  [FR_DNS_STATUS] = "Status",
72  [FR_DNS_UPDATE] = "Update",
73  [FR_DNS_STATEFUL_OPERATION] = "Stateful-Operation",
74 };
75 
77 FR_DICT_ATTR_FLAG_FUNC(fr_dns_attr_flags_t, dns_label_uncompressed)
78 
79 static fr_dict_flag_parser_t const dns_flags[] = {
80  { L("dns_label"), { .func = dict_flag_dns_label } },
81  { L("dns_label_uncompressed"), { .func = dict_flag_dns_label_uncompressed } }
82 };
83 
84 #define DECODE_FAIL(_reason) if (reason) *reason = FR_DNS_DECODE_FAIL_ ## _reason
85 
86 static bool fr_dns_tlv_ok(uint8_t const *p, uint8_t const *end, fr_dns_decode_fail_t *reason)
87 {
88  uint16_t len;
89 
90  while (p < end) {
91  if ((p + 4) > end) {
92  DECODE_FAIL(MISSING_TLV_HEADER);
93  return false;
94  }
95 
96  len = fr_nbo_to_uint16(p + 2);
97  if ((p + 4 + len) > end) {
98  DECODE_FAIL(TLV_OVERFLOWS_RR);
99  return false;
100  }
101 
102  p += 4 + len;
103  }
104 
105  return true;
106 }
107 
108 bool fr_dns_packet_ok(uint8_t const *packet, size_t packet_len, bool query, fr_dns_decode_fail_t *reason)
109 {
110  uint8_t const *p, *end;
111  int qdcount, count, expected;
112 
113  if (packet_len <= DNS_HDR_LEN) {
114  DECODE_FAIL(MIN_LENGTH_PACKET);
115  return false;
116  }
117 
118  if (packet_len > 65535) {
119  DECODE_FAIL(MAX_LENGTH_PACKET);
120  return false;
121  }
122 
123  /*
124  * query=0, response=1
125  */
126  if (((packet[2] & 0x80) == 0) != query) {
127  DECODE_FAIL(UNEXPECTED);
128  return false;
129  }
130 
131  qdcount = fr_nbo_to_uint16(packet + 4);
132 
133  if (query) {
134  /*
135  * There should be at least one query, and no
136  * replies in the query.
137  *
138  * @todo - unless it's an IQUERY, in which case
139  * there should be no questions, and at least one
140  * answer.
141  */
142  if (!qdcount) {
143  DECODE_FAIL(NO_QUESTIONS);
144  return false;
145  }
146  if (fr_nbo_to_uint16(packet + 6) != 0) {
147  DECODE_FAIL(NS_IN_QUESTION);
148  return false;
149  }
150  if (fr_nbo_to_uint16(packet + 8) != 0) {
151  DECODE_FAIL(ANSWERS_IN_QUESTION);
152  return false;
153  }
154  // additional records can exist!
155 
156  } else {
157  /*
158  * Replies _usually_ copy the query. But not
159  * always And replies can have zero or more answers.
160  */
161  }
162 
163  expected = fr_nbo_to_uint16(packet + 4) + fr_nbo_to_uint16(packet + 6) + fr_nbo_to_uint16(packet + 8) + fr_nbo_to_uint16(packet + 10);
164  count = 0;
165 
166  p = packet + DNS_HDR_LEN;
167  end = packet + packet_len;
168 
169  /*
170  * We track valid label targets in a simple array (up to
171  * 2^14 bits of compressed pointer).
172  *
173  * Note that some labels might appear in the RRDATA
174  * field, and we don't verify those here. However, this
175  * function will verify the most common packets. As a
176  * result, any issues with overflow, etc. are more
177  * difficult to exploit.
178  */
179  memset(fr_dns_marker, 0, packet_len < (1 << 14) ? packet_len : (1 << 14));
180 
181  /*
182  * Check for wildly fake packets, by making rough
183  * estimations. This way we don't actually have to walk
184  * the packet.
185  */
186  if (p + (qdcount * 5) > end) {
187  DECODE_FAIL(TOO_MANY_RRS);
188  return false;
189  }
190  p += (qdcount * 5);
191 
192  if ((p + ((expected - qdcount) * (1 + 8 + 2))) > end) {
193  DECODE_FAIL(TOO_MANY_RRS);
194  return false;
195  }
196 
197  /*
198  * The counts are at least vaguely OK, let's walk over the whole packet.
199  */
200  p = packet + DNS_HDR_LEN;
201 
202  /*
203  * Check that lengths of RRs match.
204  */
205  while (p < end) {
206  uint16_t len = 0;
207  uint8_t const *start = p;
208  bool is_opt = false;
209 
210  /*
211  * Simple DNS label decoder
212  *
213  * @todo - move this to src/lib/util/dns.c,
214  * perhaps as fr_dns_label_verify(), and then
215  * have it also return a pointer to the next
216  * label? fr_dns_label_uncompressed_length()
217  * does similar but slightly different things.
218  */
219  while (p < end) {
220  /*
221  * 0x00 is "end of label"
222  */
223  if (!*p) {
224  p++;
225  break;
226  }
227 
228  /*
229  * 2 octets of 14-bit pointer, which must
230  * be at least somewhat sane.
231  */
232  if (*p >= 0xc0) {
233  ptrdiff_t offset;
234 
235  if ((p + 2) > end) {
236  DECODE_FAIL(POINTER_OVERFLOWS_PACKET);
237  return false;
238  }
239 
240  offset = p[1];
241  offset += ((*p & ~0xc0) << 8);
242 
243  /*
244  * Can't point to the header.
245  */
246  if (offset < 12) {
247  DECODE_FAIL(POINTER_TO_HEADER);
248  return false;
249  }
250 
251  /*
252  * Can't point to the current label.
253  */
254  if (offset >= (start - packet)) {
255  DECODE_FAIL(POINTER_LOOPS);
256  return false;
257  }
258 
259  if (!fr_dns_marker[offset]) {
260  DECODE_FAIL(POINTER_TO_NON_LABEL);
261  return false;
262  }
263 
264  /*
265  * A compressed pointer is the end of the current label.
266  */
267  p += 2;
268  break;
269  }
270 
271  /*
272  * 0b10 and 0b10 are forbidden
273  */
274  if (*p > 63) {
275  DECODE_FAIL(INVALID_POINTER);
276  return false;
277  }
278 
279  /*
280  * It must be a length byte, which doesn't cause overflow.
281  */
282  if ((p + *p + 1) > end) {
283  DECODE_FAIL(LABEL_OVERFLOWS_PACKET);
284  return false;
285  }
286 
287  /*
288  * Total length of labels can't be too high.
289  */
290  len += *p;
291  if (len >= 256) {
292  DECODE_FAIL(LABEL_TOO_LONG);
293  return false;
294  }
295 
296  /*
297  * Remember that this is where we have a
298  * label.
299  */
300  fr_dns_marker[p - packet] = 1;
301 
302  /*
303  * Go to the next label.
304  */
305  p += *p + 1;
306  }
307 
308  if (qdcount) {
309  /*
310  * qtype + qclass
311  */
312  if ((p + 4) > end) {
313  DECODE_FAIL(MISSING_QD_HEADER);
314  return false;
315  }
316 
317  p += 4;
318  qdcount--;
319  goto next;
320  }
321 
322  /*
323  * type (2) + class (2) + TTL (4)
324  *
325  * These are overloaded for the OPT RR
326  * and possibly others, but the basic
327  * idea is the same.
328  */
329  if ((p + 8) > end) {
330  DECODE_FAIL(MISSING_RR_HEADER);
331  return false;
332  }
333  is_opt = (p[0] == 0) && (p[1] == 41);
334  p += 8;
335 
336  /*
337  * rr_len
338  */
339  if ((p + 2) > end) {
340  DECODE_FAIL(MISSING_RR_LEN);
341  return false;
342  }
343 
344  len = fr_nbo_to_uint16(p);
345  if (!is_opt && (len == 0)) {
346  DECODE_FAIL(ZERO_RR_LEN);
347  return false;
348  }
349 
350  p += 2;
351  if ((p + len) > end) {
352  DECODE_FAIL(RR_OVERFLOWS_PACKET);
353  return false;
354  }
355 
356  /*
357  * Verify the TLVs, too.
358  */
359  if (is_opt && !fr_dns_tlv_ok(p, p + len, reason)) {
360  return false;
361  }
362 
363  p += len;
364 
365 next:
366  count++;
367 
368  if (count > expected) {
369  DECODE_FAIL(TOO_MANY_RRS);
370  return false;
371  }
372  }
373 
374  if (count != expected) {
375  DECODE_FAIL(TOO_FEW_RRS);
376  return false;
377  }
378 
379  DECODE_FAIL(NONE);
380  return true;
381 }
382 
383 fr_dns_labels_t *fr_dns_labels_get(uint8_t const *packet, size_t packet_len, bool init_mark)
384 {
386 
387  lb->max = 256;
388  lb->mark = fr_dns_marker;
389  lb->blocks = fr_dns_blocks;
390 
391  lb->start = packet;
392  lb->end = packet + packet_len;
393 
394  lb->num = 1;
395  lb->blocks[0].start = DNS_HDR_LEN;
396  lb->blocks[0].end = DNS_HDR_LEN;
397 
398  if (init_mark) {
399  fr_assert(packet_len <= 65535);
400  memset(lb->mark, 0, packet_len);
401  }
402 
403  return lb;
404 }
405 
406 /** Resolve/cache attributes in the DNS dictionary
407  *
408  * @return
409  * - 0 on success.
410  * - -1 on failure.
411  */
413 {
414  if (instance_count > 0) {
415  instance_count++;
416  return 0;
417  }
418 
419  instance_count++;
420 
421  if (fr_dict_autoload(dns_dict) < 0) {
422  fail:
423  instance_count--;
424  return -1;
425  }
428  goto fail;
429  }
430 
431  return 0;
432 }
433 
435 {
437 
438  if (--instance_count > 0) return;
439 
441 }
442 
443 static bool attr_valid(fr_dict_attr_t *da)
444 {
445  /*
446  * "arrays" of string/octets are encoded as a 16-bit
447  * length, followed by the actual data.
448  */
449  if (da->flags.array && ((da->type == FR_TYPE_STRING) || (da->type == FR_TYPE_OCTETS))) {
450  da->flags.is_known_width = true;
451  }
452 
453  if (fr_dns_flag_dns_label_any(da)) {
454  if (da->type != FR_TYPE_STRING) {
455  fr_strerror_const("The 'dns_label' flag can only be used with attributes of type 'string'");
456  return false;
457  }
458  da->flags.is_known_width = true; /* Lie so we don't trip up the main validation checks */
459  }
460 
461  return true;
462 }
463 
466  .name = "dns",
467  .default_type_size = 2,
468  .default_type_length = 2,
469  .attr = {
470  .flags = {
471  .table = dns_flags,
472  .table_len = NUM_ELEMENTS(dns_flags),
473  .len = sizeof(fr_dns_attr_flags_t)
474  },
475  .valid = attr_valid
476  },
477 
478  .init = fr_dns_global_init,
479  .free = fr_dns_global_free,
480 };
#define RCSID(id)
Definition: build.h:481
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define NUM_ELEMENTS(_t)
Definition: build.h:335
next
Definition: dcursor.h:178
#define fr_dict_autofree(_to_free)
Definition: dict.h:850
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition: dict_util.c:4090
#define fr_dict_autoload(_to_load)
Definition: dict.h:847
char const * name
name of this protocol
Definition: dict.h:428
#define FR_DICT_ATTR_FLAG_FUNC(_struct, _name)
Define a flag setting function, which sets one bit in a fr_dict_attr_flags_t.
Definition: dict.h:406
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
Protocol specific custom flag definitnion.
Definition: dict.h:396
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition: dict.h:427
uint16_t start
Definition: dns.h:31
uint8_t const * start
start of packet
Definition: dns.h:36
uint8_t const * end
end of the packet
Definition: dns.h:37
fr_dns_block_t * blocks
maximum number of labels
Definition: dns.h:41
uint8_t * mark
markup buffer used for decoding.
Definition: dns.h:38
uint16_t end
Definition: dns.h:32
int max
Definition: dns.h:40
int num
number of used labels
Definition: dns.h:39
unsigned short uint16_t
Definition: merged_model.c:31
@ 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_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition: nbo.h:144
#define DECODE_FAIL(_reason)
Definition: base.c:84
fr_dict_attr_autoload_t dns_dict_attr[]
Definition: base.c:58
int fr_dns_global_init(void)
Resolve/cache attributes in the DNS dictionary.
Definition: base.c:412
fr_dict_protocol_t libfreeradius_dns_dict_protocol
Definition: base.c:465
static _Thread_local fr_dns_block_t fr_dns_blocks[256]
Definition: base.c:41
fr_dict_attr_t const * attr_dns_ns
Definition: base.c:54
uint16_t code
Definition: base.c:34
static _Thread_local fr_dns_labels_t fr_dns_labels
Definition: base.c:40
static _Thread_local uint8_t fr_dns_marker[65536]
Definition: base.c:42
static uint32_t instance_count
Definition: base.c:31
uint16_t length
Definition: base.c:35
static bool attr_valid(fr_dict_attr_t *da)
Definition: base.c:443
fr_dict_attr_t const * attr_dns_packet
Definition: base.c:51
void fr_dns_global_free(void)
Definition: base.c:434
fr_dict_attr_t const * attr_dns_question
Definition: base.c:52
fr_dict_autoload_t dns_dict[]
Definition: base.c:45
fr_dns_labels_t * fr_dns_labels_get(uint8_t const *packet, size_t packet_len, bool init_mark)
Definition: base.c:383
fr_dict_attr_t const * attr_dns_ar
Definition: base.c:55
fr_dict_attr_t const * attr_dns_rr
Definition: base.c:53
char const * fr_dns_packet_names[FR_DNS_CODE_MAX]
Definition: base.c:68
static fr_dict_flag_parser_t const dns_flags[]
Definition: base.c:79
static bool fr_dns_tlv_ok(uint8_t const *p, uint8_t const *end, fr_dns_decode_fail_t *reason)
Definition: base.c:86
fr_dict_t const * dict_dns
Definition: base.c:38
bool fr_dns_packet_ok(uint8_t const *packet, size_t packet_len, bool query, fr_dns_decode_fail_t *reason)
Definition: base.c:108
static bool fr_dns_flag_dns_label_any(fr_dict_attr_t const *da)
Definition: dns.h:144
@ FR_DNS_STATEFUL_OPERATION
Definition: dns.h:89
@ FR_DNS_QUERY
Definition: dns.h:84
@ FR_DNS_INVERSE_QUERY
Definition: dns.h:85
@ FR_DNS_STATUS
Definition: dns.h:86
@ FR_DNS_UPDATE
Definition: dns.h:88
@ FR_DNS_CODE_MAX
Definition: dns.h:90
#define DNS_HDR_LEN
Definition: dns.h:132
fr_dns_decode_fail_t
Definition: dns.h:102
VQP attributes.
return count
Definition: module.c:163
fr_assert(0)
#define fr_strerror_const(_msg)
Definition: strerror.h:223