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