The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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 */
26RCSID("$Id: e8695b051da97b131601c6bb93906ae1577d2440 $")
27
28#include "dns.h"
29#include "attrs.h"
30
32
37
39
40static _Thread_local fr_dns_labels_t fr_dns_labels;
41static _Thread_local fr_dns_block_t fr_dns_blocks[256];
42static _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
77FR_DICT_ATTR_FLAG_FUNC(fr_dns_attr_flags_t, dns_label_uncompressed)
78
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
86static 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
108bool 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
365next:
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
383fr_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) {
416 return 0;
417 }
418
420
421 if (fr_dict_autoload(dns_dict) < 0) {
422 fail:
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
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
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:483
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define NUM_ELEMENTS(_t)
Definition build.h:337
#define fr_dict_autofree(_to_free)
Definition dict.h:853
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
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:850
char const * name
name of this protocol
Definition dict.h:430
#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:408
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
Protocol specific custom flag definitnion.
Definition dict.h:398
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:429
static uint32_t instance_count
Definition base.c:44
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 num
number of used labels
Definition dns.h:39
unsigned short uint16_t
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
unsigned char uint8_t
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:146
static fr_dict_t const * dict_dns
Definition base.c:38
#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
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
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.
#define fr_assert(_expr)
Definition rad_assert.h:38
return count
Definition module.c:163
#define fr_strerror_const(_msg)
Definition strerror.h:223