1 /*
2 * Author Jerry Lundström <jerry@dns-oarc.net>
3 * Copyright (c) 2017, OARC, Inc.
4 * All rights reserved.
5 *
6 * This file is part of omg-dns.
7 *
8 * omg-dns is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * omg-dns is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with omg-dns. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #if HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "omg_dns.h"
26
27 /*
28 * Version
29 */
30
31 static const char* _version = OMG_DNS_VERSION_STR;
omg_dns_version_str(void)32 inline const char* omg_dns_version_str(void) {
33 return _version;
34 }
35
omg_dns_version_major(void)36 inline int omg_dns_version_major(void) {
37 return OMG_DNS_VERSION_MAJOR;
38 }
39
omg_dns_version_minor(void)40 inline int omg_dns_version_minor(void) {
41 return OMG_DNS_VERSION_MINOR;
42 }
43
omg_dns_version_patch(void)44 inline int omg_dns_version_patch(void) {
45 return OMG_DNS_VERSION_PATCH;
46 }
47
48 /*
49 * Buffer inlines and macros
50 */
51
52 #define need8(v, p, l) \
53 if (l < 1) { \
54 return OMG_DNS_EINCOMP; \
55 } \
56 v = *p; \
57 p += 1; \
58 l -= 1
59
60 #define need16(v, p, l) \
61 if (l < 2) { \
62 return OMG_DNS_EINCOMP; \
63 } \
64 v = ( *p << 8 ) + *(p+1); \
65 p += 2; \
66 l -= 2
67
68 #define need32(v, p, l) \
69 if (l < 4) { \
70 return OMG_DNS_EINCOMP; \
71 } \
72 v = ( *p << 24 ) + ( *(p+1) << 16 ) + ( *(p+2) << 8 ) + *(p+3); \
73 p += 4; \
74 l -= 4
75
76 #define need64(v, p, l) \
77 if (l < 8) { \
78 return OMG_DNS_EINCOMP; \
79 } \
80 v = ( *p << 56 ) + ( *(p+1) << 48 ) + ( *(p+2) << 40 ) + ( *(p+3) << 32 ) + ( *(p+4) << 24 ) + ( *(p+5) << 16 ) + ( *(p+6) << 8 ) + *(p+7); \
81 p += 8; \
82 l -= 8
83
84 #define needxb(b, x, p, l) \
85 if (l < x) { \
86 return OMG_DNS_EINCOMP; \
87 } \
88 memcpy(b, p, x); \
89 p += x; \
90 l -= x
91
92 #define advancexb(x, p, l) \
93 if (l < x) { \
94 return OMG_DNS_EINCOMP; \
95 } \
96 p += x; \
97 l -= x
98
99 /*
100 * Label structure functions
101 */
102
omg_dns_label_is_end(const omg_dns_label_t * label)103 inline int omg_dns_label_is_end(const omg_dns_label_t* label) {
104 omg_dns_assert(label);
105 return label->is_end;
106 }
107
omg_dns_label_have_length(const omg_dns_label_t * label)108 inline int omg_dns_label_have_length(const omg_dns_label_t* label) {
109 omg_dns_assert(label);
110 return label->have_length;
111 }
112
omg_dns_label_have_offset(const omg_dns_label_t * label)113 inline int omg_dns_label_have_offset(const omg_dns_label_t* label) {
114 omg_dns_assert(label);
115 return label->have_offset;
116 }
117
omg_dns_label_have_extension_bits(const omg_dns_label_t * label)118 inline int omg_dns_label_have_extension_bits(const omg_dns_label_t* label) {
119 omg_dns_assert(label);
120 return label->have_extension_bits;
121 }
122
omg_dns_label_have_dn(const omg_dns_label_t * label)123 inline int omg_dns_label_have_dn(const omg_dns_label_t* label) {
124 omg_dns_assert(label);
125 return label->have_dn;
126 }
127
omg_dns_label_is_complete(const omg_dns_label_t * label)128 inline int omg_dns_label_is_complete(const omg_dns_label_t* label) {
129 omg_dns_assert(label);
130 return label->is_complete;
131 }
132
omg_dns_label_length(const omg_dns_label_t * label)133 inline uint8_t omg_dns_label_length(const omg_dns_label_t* label) {
134 omg_dns_assert(label);
135 return label->length;
136 }
137
omg_dns_label_offset(const omg_dns_label_t * label)138 inline uint16_t omg_dns_label_offset(const omg_dns_label_t* label) {
139 omg_dns_assert(label);
140 return label->offset;
141 }
142
omg_dns_label_extension_bits(const omg_dns_label_t * label)143 inline unsigned short omg_dns_label_extension_bits(const omg_dns_label_t* label) {
144 omg_dns_assert(label);
145 return label->extension_bits;
146 }
147
omg_dns_label_dn_offset(const omg_dns_label_t * label)148 inline size_t omg_dns_label_dn_offset(const omg_dns_label_t* label) {
149 omg_dns_assert(label);
150 return label->dn_offset;
151 }
152
153
154 /*
155 * Resource record structure callback functions
156 */
157
omg_dns_rr_label_callback(const omg_dns_rr_t * rr)158 inline omg_dns_label_callback_t omg_dns_rr_label_callback(const omg_dns_rr_t* rr) {
159 omg_dns_assert(rr);
160 return rr->label_callback;
161 }
162
omg_dns_rr_label_callback_context(const omg_dns_rr_t * rr)163 inline void* omg_dns_rr_label_callback_context(const omg_dns_rr_t* rr) {
164 omg_dns_assert(rr);
165 return rr->label_callback_context;
166 }
167
omg_dns_rr_set_label_callback(omg_dns_rr_t * rr,omg_dns_label_callback_t label_callback,void * label_callback_context)168 inline void omg_dns_rr_set_label_callback(omg_dns_rr_t* rr, omg_dns_label_callback_t label_callback, void* label_callback_context) {
169 omg_dns_assert(rr);
170 rr->label_callback = label_callback;
171 rr->label_callback_context = label_callback_context;
172 }
173
174 /*
175 * Resource record structure functions
176 */
177
omg_dns_rr_is_question(const omg_dns_rr_t * rr)178 inline int omg_dns_rr_is_question(const omg_dns_rr_t* rr) {
179 omg_dns_assert(rr);
180 return rr->is_question;
181 }
182
omg_dns_rr_have_labels(const omg_dns_rr_t * rr)183 inline int omg_dns_rr_have_labels(const omg_dns_rr_t* rr) {
184 omg_dns_assert(rr);
185 return rr->have_labels;
186 }
187
omg_dns_rr_have_type(const omg_dns_rr_t * rr)188 inline int omg_dns_rr_have_type(const omg_dns_rr_t* rr) {
189 omg_dns_assert(rr);
190 return rr->have_type;
191 }
192
omg_dns_rr_have_class(const omg_dns_rr_t * rr)193 inline int omg_dns_rr_have_class(const omg_dns_rr_t* rr) {
194 omg_dns_assert(rr);
195 return rr->have_class;
196 }
197
omg_dns_rr_have_ttl(const omg_dns_rr_t * rr)198 inline int omg_dns_rr_have_ttl(const omg_dns_rr_t* rr) {
199 omg_dns_assert(rr);
200 return rr->have_ttl;
201 }
202
omg_dns_rr_have_rdlength(const omg_dns_rr_t * rr)203 inline int omg_dns_rr_have_rdlength(const omg_dns_rr_t* rr) {
204 omg_dns_assert(rr);
205 return rr->have_rdlength;
206 }
207
omg_dns_rr_have_rdata(const omg_dns_rr_t * rr)208 inline int omg_dns_rr_have_rdata(const omg_dns_rr_t* rr) {
209 omg_dns_assert(rr);
210 return rr->have_rdata;
211 }
212
omg_dns_rr_have_rdata_labels(const omg_dns_rr_t * rr)213 inline int omg_dns_rr_have_rdata_labels(const omg_dns_rr_t* rr) {
214 omg_dns_assert(rr);
215 return rr->have_rdata_labels;
216 }
217
omg_dns_rr_have_padding(const omg_dns_rr_t * rr)218 inline int omg_dns_rr_have_padding(const omg_dns_rr_t* rr) {
219 omg_dns_assert(rr);
220 return rr->have_padding;
221 }
222
omg_dns_rr_is_complete(const omg_dns_rr_t * rr)223 inline int omg_dns_rr_is_complete(const omg_dns_rr_t* rr) {
224 omg_dns_assert(rr);
225 return rr->is_complete;
226 }
227
omg_dns_rr_bytes_parsed(const omg_dns_rr_t * rr)228 inline size_t omg_dns_rr_bytes_parsed(const omg_dns_rr_t* rr) {
229 omg_dns_assert(rr);
230 return rr->bytes_parsed;
231 }
232
omg_dns_rr_labels(const omg_dns_rr_t * rr)233 inline size_t omg_dns_rr_labels(const omg_dns_rr_t* rr) {
234 omg_dns_assert(rr);
235 return rr->labels;
236 }
237
omg_dns_rr_type(const omg_dns_rr_t * rr)238 inline uint16_t omg_dns_rr_type(const omg_dns_rr_t* rr) {
239 omg_dns_assert(rr);
240 return rr->type;
241 }
242
omg_dns_rr_class(const omg_dns_rr_t * rr)243 inline uint16_t omg_dns_rr_class(const omg_dns_rr_t* rr) {
244 omg_dns_assert(rr);
245 return rr->class;
246 }
247
omg_dns_rr_ttl(const omg_dns_rr_t * rr)248 inline uint32_t omg_dns_rr_ttl(const omg_dns_rr_t* rr) {
249 omg_dns_assert(rr);
250 return rr->ttl;
251 }
252
omg_dns_rr_rdlength(const omg_dns_rr_t * rr)253 inline uint16_t omg_dns_rr_rdlength(const omg_dns_rr_t* rr) {
254 omg_dns_assert(rr);
255 return rr->rdlength;
256 }
257
omg_dns_rr_rdata_offset(const omg_dns_rr_t * rr)258 inline size_t omg_dns_rr_rdata_offset(const omg_dns_rr_t* rr) {
259 omg_dns_assert(rr);
260 return rr->rdata_offset;
261 }
262
omg_dns_rr_rdata_labels(const omg_dns_rr_t * rr)263 inline size_t omg_dns_rr_rdata_labels(const omg_dns_rr_t* rr) {
264 omg_dns_assert(rr);
265 return rr->rdata_labels;
266 }
267
omg_dns_rr_padding_offset(const omg_dns_rr_t * rr)268 inline size_t omg_dns_rr_padding_offset(const omg_dns_rr_t* rr) {
269 omg_dns_assert(rr);
270 return rr->padding_offset;
271 }
272
omg_dns_rr_padding_length(const omg_dns_rr_t * rr)273 inline size_t omg_dns_rr_padding_length(const omg_dns_rr_t* rr) {
274 omg_dns_assert(rr);
275 return rr->padding_length;
276 }
277
omg_dns_rr_num_rdata_labels(const omg_dns_rr_t * rr)278 inline size_t omg_dns_rr_num_rdata_labels(const omg_dns_rr_t* rr) {
279 omg_dns_assert(rr);
280
281 switch (rr->type) {
282 case OMG_DNS_TYPE_NS:
283 case OMG_DNS_TYPE_MD:
284 case OMG_DNS_TYPE_MF:
285 case OMG_DNS_TYPE_CNAME:
286 case OMG_DNS_TYPE_MB:
287 case OMG_DNS_TYPE_MG:
288 case OMG_DNS_TYPE_MR:
289 case OMG_DNS_TYPE_PTR:
290 case OMG_DNS_TYPE_NXT:
291 case OMG_DNS_TYPE_DNAME:
292 case OMG_DNS_TYPE_NSEC:
293 case OMG_DNS_TYPE_TKEY:
294 case OMG_DNS_TYPE_TSIG:
295 return 1;
296
297 case OMG_DNS_TYPE_SOA:
298 case OMG_DNS_TYPE_MINFO:
299 case OMG_DNS_TYPE_RP:
300 case OMG_DNS_TYPE_TALINK:
301 return 2;
302
303 case OMG_DNS_TYPE_MX:
304 case OMG_DNS_TYPE_AFSDB:
305 case OMG_DNS_TYPE_RT:
306 case OMG_DNS_TYPE_KX:
307 case OMG_DNS_TYPE_LP:
308 return 1;
309
310 case OMG_DNS_TYPE_PX:
311 return 2;
312
313 case OMG_DNS_TYPE_SIG:
314 case OMG_DNS_TYPE_RRSIG:
315 return 1;
316
317 case OMG_DNS_TYPE_SRV:
318 return 1;
319
320 case OMG_DNS_TYPE_NAPTR:
321 return 1;
322
323 case OMG_DNS_TYPE_HIP:
324 return 1;
325
326 default:
327 break;
328 }
329
330 return 0;
331 }
332
333 /*
334 * DNS structure callback functions
335 */
336
omg_dns_label_callback(const omg_dns_t * dns)337 inline omg_dns_label_callback_t omg_dns_label_callback(const omg_dns_t* dns) {
338 omg_dns_assert(dns);
339 return dns->label_callback;
340 }
341
omg_dns_label_callback_context(const omg_dns_t * dns)342 inline void* omg_dns_label_callback_context(const omg_dns_t* dns) {
343 omg_dns_assert(dns);
344 return dns->label_callback_context;
345 }
346
omg_dns_set_label_callback(omg_dns_t * dns,omg_dns_label_callback_t label_callback,void * label_callback_context)347 inline void omg_dns_set_label_callback(omg_dns_t* dns, omg_dns_label_callback_t label_callback, void* label_callback_context) {
348 omg_dns_assert(dns);
349 dns->label_callback = label_callback;
350 dns->label_callback_context = label_callback_context;
351 }
352
omg_dns_rr_callback(const omg_dns_t * dns)353 inline omg_dns_rr_callback_t omg_dns_rr_callback(const omg_dns_t* dns) {
354 omg_dns_assert(dns);
355 return dns->rr_callback;
356 }
357
omg_dns_rr_callback_context(const omg_dns_t * dns)358 inline void* omg_dns_rr_callback_context(const omg_dns_t* dns) {
359 omg_dns_assert(dns);
360 return dns->rr_callback_context;
361 }
362
omg_dns_set_rr_callback(omg_dns_t * dns,omg_dns_rr_callback_t rr_callback,void * rr_callback_context)363 inline void omg_dns_set_rr_callback(omg_dns_t* dns, omg_dns_rr_callback_t rr_callback, void* rr_callback_context) {
364 omg_dns_assert(dns);
365 dns->rr_callback = rr_callback;
366 dns->rr_callback_context = rr_callback_context;
367 }
368
369 /*
370 * DNS structure functions
371 */
372
omg_dns_have_id(const omg_dns_t * dns)373 inline int omg_dns_have_id(const omg_dns_t* dns) {
374 omg_dns_assert(dns);
375 return dns->have_id;
376 }
377
omg_dns_have_qr(const omg_dns_t * dns)378 inline int omg_dns_have_qr(const omg_dns_t* dns) {
379 omg_dns_assert(dns);
380 return dns->have_qr;
381 }
382
omg_dns_have_opcode(const omg_dns_t * dns)383 inline int omg_dns_have_opcode(const omg_dns_t* dns) {
384 omg_dns_assert(dns);
385 return dns->have_opcode;
386 }
387
omg_dns_have_aa(const omg_dns_t * dns)388 inline int omg_dns_have_aa(const omg_dns_t* dns) {
389 omg_dns_assert(dns);
390 return dns->have_aa;
391 }
392
omg_dns_have_tc(const omg_dns_t * dns)393 inline int omg_dns_have_tc(const omg_dns_t* dns) {
394 omg_dns_assert(dns);
395 return dns->have_tc;
396 }
397
omg_dns_have_rd(const omg_dns_t * dns)398 inline int omg_dns_have_rd(const omg_dns_t* dns) {
399 omg_dns_assert(dns);
400 return dns->have_rd;
401 }
402
omg_dns_have_ra(const omg_dns_t * dns)403 inline int omg_dns_have_ra(const omg_dns_t* dns) {
404 omg_dns_assert(dns);
405 return dns->have_ra;
406 }
407
omg_dns_have_z(const omg_dns_t * dns)408 inline int omg_dns_have_z(const omg_dns_t* dns) {
409 omg_dns_assert(dns);
410 return dns->have_z;
411 }
412
omg_dns_have_ad(const omg_dns_t * dns)413 inline int omg_dns_have_ad(const omg_dns_t* dns) {
414 omg_dns_assert(dns);
415 return dns->have_ad;
416 }
417
omg_dns_have_cd(const omg_dns_t * dns)418 inline int omg_dns_have_cd(const omg_dns_t* dns) {
419 omg_dns_assert(dns);
420 return dns->have_cd;
421 }
422
omg_dns_have_rcode(const omg_dns_t * dns)423 inline int omg_dns_have_rcode(const omg_dns_t* dns) {
424 omg_dns_assert(dns);
425 return dns->have_rcode;
426 }
427
omg_dns_have_qdcount(const omg_dns_t * dns)428 inline int omg_dns_have_qdcount(const omg_dns_t* dns) {
429 omg_dns_assert(dns);
430 return dns->have_qdcount;
431 }
432
omg_dns_have_ancount(const omg_dns_t * dns)433 inline int omg_dns_have_ancount(const omg_dns_t* dns) {
434 omg_dns_assert(dns);
435 return dns->have_ancount;
436 }
437
omg_dns_have_nscount(const omg_dns_t * dns)438 inline int omg_dns_have_nscount(const omg_dns_t* dns) {
439 omg_dns_assert(dns);
440 return dns->have_nscount;
441 }
442
omg_dns_have_arcount(const omg_dns_t * dns)443 inline int omg_dns_have_arcount(const omg_dns_t* dns) {
444 omg_dns_assert(dns);
445 return dns->have_arcount;
446 }
447
omg_dns_have_questions(const omg_dns_t * dns)448 inline int omg_dns_have_questions(const omg_dns_t* dns) {
449 omg_dns_assert(dns);
450 return dns->have_questions;
451 }
452
omg_dns_have_answers(const omg_dns_t * dns)453 inline int omg_dns_have_answers(const omg_dns_t* dns) {
454 omg_dns_assert(dns);
455 return dns->have_answers;
456 }
457
omg_dns_have_authorities(const omg_dns_t * dns)458 inline int omg_dns_have_authorities(const omg_dns_t* dns) {
459 omg_dns_assert(dns);
460 return dns->have_authorities;
461 }
462
omg_dns_have_additionals(const omg_dns_t * dns)463 inline int omg_dns_have_additionals(const omg_dns_t* dns) {
464 omg_dns_assert(dns);
465 return dns->have_additionals;
466 }
467
omg_dns_have_padding(const omg_dns_t * dns)468 inline int omg_dns_have_padding(const omg_dns_t* dns) {
469 omg_dns_assert(dns);
470 return dns->have_padding;
471 }
472
omg_dns_is_complete(const omg_dns_t * dns)473 inline int omg_dns_is_complete(const omg_dns_t* dns) {
474 omg_dns_assert(dns);
475 return dns->is_complete;
476 }
477
omg_dns_bytes_parsed(const omg_dns_t * dns)478 inline size_t omg_dns_bytes_parsed(const omg_dns_t* dns) {
479 omg_dns_assert(dns);
480 return dns->bytes_parsed;
481 }
482
omg_dns_id(const omg_dns_t * dns)483 inline uint16_t omg_dns_id(const omg_dns_t* dns) {
484 omg_dns_assert(dns);
485 return dns->id;
486 }
487
omg_dns_qr(const omg_dns_t * dns)488 inline int omg_dns_qr(const omg_dns_t* dns) {
489 omg_dns_assert(dns);
490 return dns->qr;
491 }
492
omg_dns_opcode(const omg_dns_t * dns)493 inline int omg_dns_opcode(const omg_dns_t* dns) {
494 omg_dns_assert(dns);
495 return dns->opcode;
496 }
497
omg_dns_aa(const omg_dns_t * dns)498 inline int omg_dns_aa(const omg_dns_t* dns) {
499 omg_dns_assert(dns);
500 return dns->aa;
501 }
502
omg_dns_tc(const omg_dns_t * dns)503 inline int omg_dns_tc(const omg_dns_t* dns) {
504 omg_dns_assert(dns);
505 return dns->tc;
506 }
507
omg_dns_rd(const omg_dns_t * dns)508 inline int omg_dns_rd(const omg_dns_t* dns) {
509 omg_dns_assert(dns);
510 return dns->rd;
511 }
512
omg_dns_ra(const omg_dns_t * dns)513 inline int omg_dns_ra(const omg_dns_t* dns) {
514 omg_dns_assert(dns);
515 return dns->ra;
516 }
517
omg_dns_z(const omg_dns_t * dns)518 inline int omg_dns_z(const omg_dns_t* dns) {
519 omg_dns_assert(dns);
520 return dns->z;
521 }
522
omg_dns_ad(const omg_dns_t * dns)523 inline int omg_dns_ad(const omg_dns_t* dns) {
524 omg_dns_assert(dns);
525 return dns->ad;
526 }
527
omg_dns_cd(const omg_dns_t * dns)528 inline int omg_dns_cd(const omg_dns_t* dns) {
529 omg_dns_assert(dns);
530 return dns->cd;
531 }
532
omg_dns_rcode(const omg_dns_t * dns)533 inline int omg_dns_rcode(const omg_dns_t* dns) {
534 omg_dns_assert(dns);
535 return dns->rcode;
536 }
537
omg_dns_qdcount(const omg_dns_t * dns)538 inline uint16_t omg_dns_qdcount(const omg_dns_t* dns) {
539 omg_dns_assert(dns);
540 return dns->qdcount;
541 }
542
omg_dns_ancount(const omg_dns_t * dns)543 inline uint16_t omg_dns_ancount(const omg_dns_t* dns) {
544 omg_dns_assert(dns);
545 return dns->ancount;
546 }
547
omg_dns_nscount(const omg_dns_t * dns)548 inline uint16_t omg_dns_nscount(const omg_dns_t* dns) {
549 omg_dns_assert(dns);
550 return dns->nscount;
551 }
552
omg_dns_arcount(const omg_dns_t * dns)553 inline uint16_t omg_dns_arcount(const omg_dns_t* dns) {
554 omg_dns_assert(dns);
555 return dns->arcount;
556 }
557
omg_dns_questions(const omg_dns_t * dns)558 inline size_t omg_dns_questions(const omg_dns_t* dns) {
559 omg_dns_assert(dns);
560 return dns->questions;
561 }
562
omg_dns_answers(const omg_dns_t * dns)563 inline size_t omg_dns_answers(const omg_dns_t* dns) {
564 omg_dns_assert(dns);
565 return dns->answers;
566 }
567
omg_dns_authorities(const omg_dns_t * dns)568 inline size_t omg_dns_authorities(const omg_dns_t* dns) {
569 omg_dns_assert(dns);
570 return dns->authorities;
571 }
572
omg_dns_additionals(const omg_dns_t * dns)573 inline size_t omg_dns_additionals(const omg_dns_t* dns) {
574 omg_dns_assert(dns);
575 return dns->additionals;
576 }
577
omg_dns_padding_offset(const omg_dns_t * dns)578 inline size_t omg_dns_padding_offset(const omg_dns_t* dns) {
579 omg_dns_assert(dns);
580 return dns->padding_offset;
581 }
582
omg_dns_padding_length(const omg_dns_t * dns)583 inline size_t omg_dns_padding_length(const omg_dns_t* dns) {
584 omg_dns_assert(dns);
585 return dns->padding_length;
586 }
587
588 /*
589 * Parsers
590 */
591
omg_dns_parse_header(omg_dns_t * dns,const uint8_t * buffer,size_t length)592 int omg_dns_parse_header(omg_dns_t* dns, const uint8_t* buffer, size_t length) {
593 uint8_t byte;
594
595 if (!dns) {
596 return OMG_DNS_EINVAL;
597 }
598
599 need16(dns->id, buffer, length);
600 dns->bytes_parsed += 2;
601 dns->have_id = 1;
602
603 need8(byte, buffer, length);
604 dns->bytes_parsed += 1;
605 dns->qr = byte & (1 << 7) ? 1 : 0;
606 dns->opcode = ( byte >> 3 ) & 0xf;
607 dns->aa = byte & (1 << 2) ? 1 : 0;
608 dns->tc = byte & (1 << 1) ? 1 : 0;
609 dns->rd = byte & (1 << 0) ? 1 : 0;
610 dns->have_qr =
611 dns->have_opcode =
612 dns->have_aa =
613 dns->have_tc =
614 dns->have_rd = 1;
615
616 need8(byte, buffer, length);
617 dns->bytes_parsed += 1;
618 dns->ra = byte & (1 << 7) ? 1 : 0;
619 dns->z = byte & (1 << 6) ? 1 : 0;
620 dns->ad = byte & (1 << 5) ? 1 : 0;
621 dns->cd = byte & (1 << 4) ? 1 : 0;
622 dns->rcode = byte & 0xf;
623 dns->have_ra =
624 dns->have_z =
625 dns->have_ad =
626 dns->have_cd =
627 dns->have_rcode = 1;
628
629 need16(dns->qdcount, buffer, length);
630 dns->bytes_parsed += 2;
631 dns->have_qdcount = 1;
632
633 need16(dns->ancount, buffer, length);
634 dns->bytes_parsed += 2;
635 dns->have_ancount = 1;
636
637 need16(dns->nscount, buffer, length);
638 dns->bytes_parsed += 2;
639 dns->have_nscount = 1;
640
641 need16(dns->arcount, buffer, length);
642 dns->bytes_parsed += 2;
643 dns->have_arcount = 1;
644
645 return OMG_DNS_OK;
646 }
647
omg_dns_parse(omg_dns_t * dns,const uint8_t * buffer,size_t length)648 int omg_dns_parse(omg_dns_t* dns, const uint8_t* buffer, size_t length) {
649 size_t n;
650 int ret;
651
652 if (!dns) {
653 return OMG_DNS_EINVAL;
654 }
655
656 if ((ret = omg_dns_parse_header(dns, buffer, length)) != OMG_DNS_OK) {
657 return ret;
658 }
659 buffer += dns->bytes_parsed;
660 length -= dns->bytes_parsed;
661
662 for (n = dns->qdcount; n; n--) {
663 omg_dns_rr_t rr = OMG_DNS_RR_T_INIT;
664
665 rr._offset = dns->bytes_parsed;
666 rr.is_question = 1;
667 if (dns->label_callback)
668 omg_dns_rr_set_label_callback(&rr, dns->label_callback, dns->label_callback_context);
669 ret = omg_dns_parse_rr(&rr, buffer, length);
670 if (dns->rr_callback)
671 ret = dns->rr_callback(ret, &rr, dns->rr_callback_context);
672 if (ret != OMG_DNS_OK)
673 return ret;
674
675 buffer += rr.bytes_parsed;
676 length -= rr.bytes_parsed;
677 dns->bytes_parsed += rr.bytes_parsed;
678
679 dns->questions++;
680 }
681 dns->have_questions = 1;
682
683 for (n = dns->ancount; n; n--) {
684 omg_dns_rr_t rr = OMG_DNS_RR_T_INIT;
685
686 rr._offset = dns->bytes_parsed;
687 if (dns->label_callback)
688 omg_dns_rr_set_label_callback(&rr, dns->label_callback, dns->label_callback_context);
689 ret = omg_dns_parse_rr(&rr, buffer, length);
690 if (dns->rr_callback)
691 ret = dns->rr_callback(ret, &rr, dns->rr_callback_context);
692 if (ret != OMG_DNS_OK)
693 return ret;
694
695 buffer += rr.bytes_parsed;
696 length -= rr.bytes_parsed;
697 dns->bytes_parsed += rr.bytes_parsed;
698
699 dns->answers++;
700 }
701 dns->have_answers = 1;
702
703 for (n = dns->nscount; n; n--) {
704 omg_dns_rr_t rr = OMG_DNS_RR_T_INIT;
705
706 rr._offset = dns->bytes_parsed;
707 if (dns->label_callback)
708 omg_dns_rr_set_label_callback(&rr, dns->label_callback, dns->label_callback_context);
709 ret = omg_dns_parse_rr(&rr, buffer, length);
710 if (dns->rr_callback)
711 ret = dns->rr_callback(ret, &rr, dns->rr_callback_context);
712 if (ret != OMG_DNS_OK)
713 return ret;
714
715 buffer += rr.bytes_parsed;
716 length -= rr.bytes_parsed;
717 dns->bytes_parsed += rr.bytes_parsed;
718
719 dns->authorities++;
720 }
721 dns->have_authorities = 1;
722
723 for (n = dns->arcount; n; n--) {
724 omg_dns_rr_t rr = OMG_DNS_RR_T_INIT;
725
726 rr._offset = dns->bytes_parsed;
727 if (dns->label_callback)
728 omg_dns_rr_set_label_callback(&rr, dns->label_callback, dns->label_callback_context);
729 ret = omg_dns_parse_rr(&rr, buffer, length);
730 if (dns->rr_callback)
731 ret = dns->rr_callback(ret, &rr, dns->rr_callback_context);
732 if (ret != OMG_DNS_OK)
733 return ret;
734
735 buffer += rr.bytes_parsed;
736 length -= rr.bytes_parsed;
737 dns->bytes_parsed += rr.bytes_parsed;
738
739 dns->additionals++;
740 }
741 dns->have_additionals = 1;
742
743 if (length) {
744 dns->padding_offset = dns->bytes_parsed;
745 dns->padding_length = length;
746 dns->have_padding = 1;
747 }
748
749 dns->is_complete = 1;
750
751 return OMG_DNS_OK;
752 }
753
omg_dns_parse_rr(omg_dns_rr_t * rr,const uint8_t * buffer,size_t length)754 int omg_dns_parse_rr(omg_dns_rr_t* rr, const uint8_t* buffer, size_t length) {
755 int ret;
756 size_t labels;
757
758 if (!rr) {
759 return OMG_DNS_EINVAL;
760 }
761
762 while (length) {
763 omg_dns_label_t label = OMG_DNS_LABEL_T_INIT;
764
765 label._offset = rr->_offset + rr->bytes_parsed;
766 need8(label.length, buffer, length);
767 rr->bytes_parsed += 1;
768
769 if ((label.length & 0xc0) == 0xc0) {
770 need8(label.offset, buffer, length);
771 label.offset |= (label.length & 0x3f) << 8;
772 rr->bytes_parsed += 1;
773 label.have_offset = 1;
774
775 label.is_complete = 1;
776 if (rr->label_callback) {
777 ret = rr->label_callback(&label, rr->label_callback_context);
778 if (ret != OMG_DNS_OK)
779 return ret;
780 }
781 rr->labels++;
782 break;
783 }
784 else if (label.length & 0xc0) {
785 label.extension_bits = label.length >> 6;
786 label.have_extension_bits = 1;
787
788 label.is_complete = 1;
789 if (rr->label_callback) {
790 ret = rr->label_callback(&label, rr->label_callback_context);
791 if (ret != OMG_DNS_OK)
792 return ret;
793 }
794 rr->labels++;
795 break;
796 }
797 else if (label.length) {
798 label.have_length = 1;
799
800 label.offset = label._offset;
801 label.dn_offset = label._offset + 1;
802 advancexb(label.length, buffer, length);
803 rr->bytes_parsed += label.length;
804 label.have_dn = 1;
805
806 label.is_complete = 1;
807 if (rr->label_callback) {
808 ret = rr->label_callback(&label, rr->label_callback_context);
809 if (ret != OMG_DNS_OK)
810 return ret;
811 }
812 rr->labels++;
813 }
814 else {
815 label.is_end = 1;
816 label.is_complete = 1;
817 if (rr->label_callback) {
818 ret = rr->label_callback(&label, rr->label_callback_context);
819 if (ret != OMG_DNS_OK)
820 return ret;
821 }
822 break;
823 }
824 }
825 rr->have_labels = 1;
826
827 need16(rr->type, buffer, length);
828 rr->bytes_parsed += 2;
829 rr->have_type = 1;
830
831 need16(rr->class, buffer, length);
832 rr->bytes_parsed += 2;
833 rr->have_class = 1;
834
835 if (rr->is_question) {
836 rr->is_complete = 1;
837 return OMG_DNS_OK;
838 }
839
840 need32(rr->ttl, buffer, length);
841 rr->bytes_parsed += 4;
842 rr->have_ttl = 1;
843
844 need16(rr->rdlength, buffer, length);
845 rr->bytes_parsed += 2;
846 rr->have_rdlength = 1;
847
848 rr->rdata_offset = rr->_offset + rr->bytes_parsed;
849
850 if ((labels = omg_dns_rr_num_rdata_labels(rr))) {
851 size_t bytes_parsed = 0;
852
853 switch (rr->type) {
854 case OMG_DNS_TYPE_MX:
855 case OMG_DNS_TYPE_AFSDB:
856 case OMG_DNS_TYPE_RT:
857 case OMG_DNS_TYPE_KX:
858 case OMG_DNS_TYPE_LP:
859 case OMG_DNS_TYPE_PX:
860 advancexb(2, buffer, length);
861 rr->bytes_parsed += 2;
862 bytes_parsed += 2;
863 break;
864
865 case OMG_DNS_TYPE_SIG:
866 case OMG_DNS_TYPE_RRSIG:
867 advancexb(18, buffer, length);
868 rr->bytes_parsed += 18;
869 bytes_parsed += 18;
870 break;
871
872 case OMG_DNS_TYPE_SRV:
873 advancexb(6, buffer, length);
874 rr->bytes_parsed += 6;
875 bytes_parsed += 6;
876 break;
877
878 case OMG_DNS_TYPE_NAPTR:
879 {
880 uint8_t naptr_length;
881
882 /* 2x 16 bits */
883 advancexb(4, buffer, length);
884 rr->bytes_parsed += 4;
885 bytes_parsed += 4;
886
887 need8(naptr_length, buffer, length);
888 rr->bytes_parsed += 1;
889 bytes_parsed += 1;
890 advancexb(naptr_length, buffer, length);
891 rr->bytes_parsed += naptr_length;
892 bytes_parsed += naptr_length;
893
894 need8(naptr_length, buffer, length);
895 rr->bytes_parsed += 1;
896 bytes_parsed += 1;
897 advancexb(naptr_length, buffer, length);
898 rr->bytes_parsed += naptr_length;
899 bytes_parsed += naptr_length;
900
901 need8(naptr_length, buffer, length);
902 rr->bytes_parsed += 1;
903 bytes_parsed += 1;
904 advancexb(naptr_length, buffer, length);
905 rr->bytes_parsed += naptr_length;
906 bytes_parsed += naptr_length;
907 }
908 break;
909
910 case OMG_DNS_TYPE_HIP:
911 {
912 uint8_t hit_length;
913 uint16_t pk_length;
914
915 need8(hit_length, buffer, length);
916 rr->bytes_parsed += 1;
917 bytes_parsed += 1;
918
919 advancexb(1, buffer, length);
920 rr->bytes_parsed += 1;
921 bytes_parsed += 1;
922
923 need16(pk_length, buffer, length);
924 rr->bytes_parsed += 2;
925 bytes_parsed += 2;
926
927 advancexb(hit_length, buffer, length);
928 rr->bytes_parsed += hit_length;
929 bytes_parsed += hit_length;
930
931 advancexb(pk_length, buffer, length);
932 rr->bytes_parsed += pk_length;
933 bytes_parsed += pk_length;
934
935 if (rr->bytes_parsed >= rr->rdlength)
936 labels = 0;
937 }
938 break;
939 }
940
941 while (labels) {
942 omg_dns_label_t label = OMG_DNS_LABEL_T_INIT;
943
944 label._offset = rr->_offset + rr->bytes_parsed;
945 need8(label.length, buffer, length);
946 rr->bytes_parsed += 1;
947 bytes_parsed += 1;
948
949 if ((label.length & 0xc0) == 0xc0) {
950 need8(label.offset, buffer, length);
951 label.offset |= (label.length & 0x3f) << 8;
952 rr->bytes_parsed += 1;
953 bytes_parsed += 1;
954 label.have_offset = 1;
955
956 label.is_complete = 1;
957 if (rr->label_callback) {
958 ret = rr->label_callback(&label, rr->label_callback_context);
959 if (ret != OMG_DNS_OK)
960 return ret;
961 }
962 rr->rdata_labels++;
963 labels--;
964 if (rr->type == OMG_DNS_TYPE_HIP && rr->bytes_parsed < rr->rdlength)
965 labels++;
966 continue;
967 }
968 else if (label.length & 0xc0) {
969 label.extension_bits = label.length >> 6;
970 label.have_extension_bits = 1;
971
972 label.is_complete = 1;
973 if (rr->label_callback) {
974 ret = rr->label_callback(&label, rr->label_callback_context);
975 if (ret != OMG_DNS_OK)
976 return ret;
977 }
978 rr->rdata_labels++;
979 labels--;
980 if (rr->type == OMG_DNS_TYPE_HIP && rr->bytes_parsed < rr->rdlength)
981 labels++;
982 continue;
983 }
984 else if (label.length) {
985 label.have_length = 1;
986
987 label.offset = label._offset;
988 label.dn_offset = label._offset + 1;
989 advancexb(label.length, buffer, length);
990 rr->bytes_parsed += label.length;
991 bytes_parsed += label.length;
992 label.have_dn = 1;
993
994 label.is_complete = 1;
995 if (rr->label_callback) {
996 ret = rr->label_callback(&label, rr->label_callback_context);
997 if (ret != OMG_DNS_OK)
998 return ret;
999 }
1000 rr->rdata_labels++;
1001 }
1002 else {
1003 label.is_end = 1;
1004 label.is_complete = 1;
1005 if (rr->label_callback) {
1006 ret = rr->label_callback(&label, rr->label_callback_context);
1007 if (ret != OMG_DNS_OK)
1008 return ret;
1009 }
1010 labels--;
1011 if (rr->type == OMG_DNS_TYPE_HIP && rr->bytes_parsed < rr->rdlength)
1012 labels++;
1013 continue;
1014 }
1015 }
1016 rr->have_rdata_labels = 1;
1017
1018 if (bytes_parsed < rr->rdlength) {
1019 rr->padding_offset = rr->rdata_offset + bytes_parsed;
1020 rr->padding_length = rr->rdlength - bytes_parsed;
1021
1022 advancexb(rr->padding_length, buffer, length);
1023 rr->bytes_parsed += rr->padding_length;
1024
1025 /*
1026 * TODO:
1027 *
1028 * This can indicate padding but we do not set that we have padding
1029 * yet because we need to fully understand all record types before
1030 * that and process valid data after the labels
1031 *
1032 rr->have_padding = 1;
1033 */
1034 }
1035 else if (bytes_parsed > rr->rdlength) {
1036 return OMG_DNS_EOVERRUN;
1037 }
1038
1039 rr->have_rdata = 1;
1040 }
1041 else {
1042 advancexb(rr->rdlength, buffer, length);
1043 rr->bytes_parsed += rr->rdlength;
1044 rr->have_rdata = 1;
1045 }
1046
1047 rr->is_complete = 1;
1048
1049 return OMG_DNS_OK;
1050 }
1051