Commit | Line | Data |
---|---|---|
825eb42b JL |
1 | /* |
2 | * packet.c | |
3 | * | |
4 | * dns packet implementation | |
5 | * | |
6 | * a Net::DNS like library for C | |
7 | * | |
8 | * (c) NLnet Labs, 2004-2006 | |
9 | * | |
10 | * See the file LICENSE for the license | |
11 | */ | |
12 | ||
13 | #include <ldns/config.h> | |
14 | ||
15 | #include <ldns/ldns.h> | |
16 | ||
17 | #include <strings.h> | |
18 | #include <limits.h> | |
19 | ||
20 | #ifdef HAVE_SSL | |
21 | #include <openssl/rand.h> | |
22 | #endif | |
23 | ||
24 | /* Access functions | |
25 | * do this as functions to get type checking | |
26 | */ | |
27 | ||
28 | #define LDNS_EDNS_MASK_DO_BIT 0x8000 | |
29 | ||
30 | /* TODO defines for 3600 */ | |
31 | /* convert to and from numerical flag values */ | |
32 | ldns_lookup_table ldns_edns_flags[] = { | |
33 | { 3600, "do"}, | |
34 | { 0, NULL} | |
35 | }; | |
36 | ||
37 | /* read */ | |
38 | uint16_t | |
39 | ldns_pkt_id(const ldns_pkt *packet) | |
40 | { | |
41 | return packet->_header->_id; | |
42 | } | |
43 | ||
44 | bool | |
45 | ldns_pkt_qr(const ldns_pkt *packet) | |
46 | { | |
47 | return packet->_header->_qr; | |
48 | } | |
49 | ||
50 | bool | |
51 | ldns_pkt_aa(const ldns_pkt *packet) | |
52 | { | |
53 | return packet->_header->_aa; | |
54 | } | |
55 | ||
56 | bool | |
57 | ldns_pkt_tc(const ldns_pkt *packet) | |
58 | { | |
59 | return packet->_header->_tc; | |
60 | } | |
61 | ||
62 | bool | |
63 | ldns_pkt_rd(const ldns_pkt *packet) | |
64 | { | |
65 | return packet->_header->_rd; | |
66 | } | |
67 | ||
68 | bool | |
69 | ldns_pkt_cd(const ldns_pkt *packet) | |
70 | { | |
71 | return packet->_header->_cd; | |
72 | } | |
73 | ||
74 | bool | |
75 | ldns_pkt_ra(const ldns_pkt *packet) | |
76 | { | |
77 | return packet->_header->_ra; | |
78 | } | |
79 | ||
80 | bool | |
81 | ldns_pkt_ad(const ldns_pkt *packet) | |
82 | { | |
83 | return packet->_header->_ad; | |
84 | } | |
85 | ||
86 | ldns_pkt_opcode | |
87 | ldns_pkt_get_opcode(const ldns_pkt *packet) | |
88 | { | |
89 | return packet->_header->_opcode; | |
90 | } | |
91 | ||
92 | ldns_pkt_rcode | |
93 | ldns_pkt_get_rcode(const ldns_pkt *packet) | |
94 | { | |
95 | return packet->_header->_rcode; | |
96 | } | |
97 | ||
98 | uint16_t | |
99 | ldns_pkt_qdcount(const ldns_pkt *packet) | |
100 | { | |
101 | return packet->_header->_qdcount; | |
102 | } | |
103 | ||
104 | uint16_t | |
105 | ldns_pkt_ancount(const ldns_pkt *packet) | |
106 | { | |
107 | return packet->_header->_ancount; | |
108 | } | |
109 | ||
110 | uint16_t | |
111 | ldns_pkt_nscount(const ldns_pkt *packet) | |
112 | { | |
113 | return packet->_header->_nscount; | |
114 | } | |
115 | ||
116 | uint16_t | |
117 | ldns_pkt_arcount(const ldns_pkt *packet) | |
118 | { | |
119 | return packet->_header->_arcount; | |
120 | } | |
121 | ||
122 | ldns_rr_list * | |
123 | ldns_pkt_question(const ldns_pkt *packet) | |
124 | { | |
125 | return packet->_question; | |
126 | } | |
127 | ||
128 | ldns_rr_list * | |
129 | ldns_pkt_answer(const ldns_pkt *packet) | |
130 | { | |
131 | return packet->_answer; | |
132 | } | |
133 | ||
134 | ldns_rr_list * | |
135 | ldns_pkt_authority(const ldns_pkt *packet) | |
136 | { | |
137 | return packet->_authority; | |
138 | } | |
139 | ||
140 | ldns_rr_list * | |
141 | ldns_pkt_additional(const ldns_pkt *packet) | |
142 | { | |
143 | return packet->_additional; | |
144 | } | |
145 | ||
146 | /* return ALL section concatenated */ | |
147 | ldns_rr_list * | |
148 | ldns_pkt_all(const ldns_pkt *packet) | |
149 | { | |
150 | ldns_rr_list *all, *prev_all; | |
151 | ||
152 | all = ldns_rr_list_cat_clone( | |
153 | ldns_pkt_question(packet), | |
154 | ldns_pkt_answer(packet)); | |
155 | prev_all = all; | |
156 | all = ldns_rr_list_cat_clone(all, | |
157 | ldns_pkt_authority(packet)); | |
158 | ldns_rr_list_deep_free(prev_all); | |
159 | prev_all = all; | |
160 | all = ldns_rr_list_cat_clone(all, | |
161 | ldns_pkt_additional(packet)); | |
162 | ldns_rr_list_deep_free(prev_all); | |
163 | return all; | |
164 | } | |
165 | ||
166 | ldns_rr_list * | |
167 | ldns_pkt_all_noquestion(const ldns_pkt *packet) | |
168 | { | |
169 | ldns_rr_list *all, *all2; | |
170 | ||
171 | all = ldns_rr_list_cat_clone( | |
172 | ldns_pkt_answer(packet), | |
173 | ldns_pkt_authority(packet)); | |
174 | all2 = ldns_rr_list_cat_clone(all, | |
175 | ldns_pkt_additional(packet)); | |
176 | ||
177 | ldns_rr_list_deep_free(all); | |
178 | return all2; | |
179 | } | |
180 | ||
181 | size_t | |
182 | ldns_pkt_size(const ldns_pkt *packet) | |
183 | { | |
184 | return packet->_size; | |
185 | } | |
186 | ||
187 | uint32_t | |
188 | ldns_pkt_querytime(const ldns_pkt *packet) | |
189 | { | |
190 | return packet->_querytime; | |
191 | } | |
192 | ||
193 | ldns_rdf * | |
194 | ldns_pkt_answerfrom(const ldns_pkt *packet) | |
195 | { | |
196 | return packet->_answerfrom; | |
197 | } | |
198 | ||
199 | struct timeval | |
200 | ldns_pkt_timestamp(const ldns_pkt *packet) | |
201 | { | |
202 | return packet->timestamp; | |
203 | } | |
204 | ||
205 | uint16_t | |
206 | ldns_pkt_edns_udp_size(const ldns_pkt *packet) | |
207 | { | |
208 | return packet->_edns_udp_size; | |
209 | } | |
210 | ||
211 | uint8_t | |
212 | ldns_pkt_edns_extended_rcode(const ldns_pkt *packet) | |
213 | { | |
214 | return packet->_edns_extended_rcode; | |
215 | } | |
216 | ||
217 | uint8_t | |
218 | ldns_pkt_edns_version(const ldns_pkt *packet) | |
219 | { | |
220 | return packet->_edns_version; | |
221 | } | |
222 | ||
223 | uint16_t | |
224 | ldns_pkt_edns_z(const ldns_pkt *packet) | |
225 | { | |
226 | return packet->_edns_z; | |
227 | } | |
228 | ||
229 | bool | |
230 | ldns_pkt_edns_do(const ldns_pkt *packet) | |
231 | { | |
232 | return (packet->_edns_z & LDNS_EDNS_MASK_DO_BIT); | |
233 | } | |
234 | ||
235 | void | |
236 | ldns_pkt_set_edns_do(ldns_pkt *packet, bool value) | |
237 | { | |
238 | if (value) { | |
239 | packet->_edns_z = packet->_edns_z | LDNS_EDNS_MASK_DO_BIT; | |
240 | } else { | |
241 | packet->_edns_z = packet->_edns_z & ~LDNS_EDNS_MASK_DO_BIT; | |
242 | } | |
243 | } | |
244 | ||
245 | ldns_rdf * | |
246 | ldns_pkt_edns_data(const ldns_pkt *packet) | |
247 | { | |
248 | return packet->_edns_data; | |
249 | } | |
250 | ||
251 | /* return only those rr that share the ownername */ | |
252 | ldns_rr_list * | |
253 | ldns_pkt_rr_list_by_name(ldns_pkt *packet, | |
254 | ldns_rdf *ownername, | |
255 | ldns_pkt_section sec) | |
256 | { | |
257 | ldns_rr_list *rrs; | |
825eb42b JL |
258 | ldns_rr_list *ret; |
259 | uint16_t i; | |
260 | ||
261 | if (!packet) { | |
262 | return NULL; | |
263 | } | |
264 | ||
265 | rrs = ldns_pkt_get_section_clone(packet, sec); | |
825eb42b JL |
266 | ret = NULL; |
267 | ||
268 | for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { | |
269 | if (ldns_rdf_compare(ldns_rr_owner( | |
270 | ldns_rr_list_rr(rrs, i)), | |
271 | ownername) == 0) { | |
272 | /* owner names match */ | |
d1b2b5ca JM |
273 | if (ret == NULL) { |
274 | ret = ldns_rr_list_new(); | |
275 | } | |
276 | ldns_rr_list_push_rr(ret, ldns_rr_list_rr(rrs, i)); | |
825eb42b JL |
277 | } |
278 | } | |
279 | return ret; | |
280 | } | |
281 | ||
282 | /* return only those rr that share a type */ | |
283 | ldns_rr_list * | |
284 | ldns_pkt_rr_list_by_type(const ldns_pkt *packet, | |
285 | ldns_rr_type type, | |
286 | ldns_pkt_section sec) | |
287 | { | |
288 | ldns_rr_list *rrs; | |
289 | ldns_rr_list *new; | |
290 | uint16_t i; | |
291 | ||
292 | if(!packet) { | |
293 | return NULL; | |
294 | } | |
295 | ||
296 | rrs = ldns_pkt_get_section_clone(packet, sec); | |
297 | new = ldns_rr_list_new(); | |
298 | ||
299 | for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { | |
300 | if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i))) { | |
301 | /* types match */ | |
302 | ldns_rr_list_push_rr(new, | |
303 | ldns_rr_clone( | |
304 | ldns_rr_list_rr(rrs, i)) | |
305 | ); | |
306 | } | |
307 | } | |
308 | ldns_rr_list_deep_free(rrs); | |
309 | ||
310 | if (ldns_rr_list_rr_count(new) == 0) { | |
311 | ldns_rr_list_free(new); | |
312 | return NULL; | |
313 | } else { | |
314 | return new; | |
315 | } | |
316 | } | |
317 | ||
318 | /* return only those rrs that share name and type */ | |
319 | ldns_rr_list * | |
320 | ldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet, | |
321 | const ldns_rdf *ownername, | |
322 | ldns_rr_type type, | |
323 | ldns_pkt_section sec) | |
324 | { | |
325 | ldns_rr_list *rrs; | |
326 | ldns_rr_list *new; | |
327 | ldns_rr_list *ret; | |
328 | uint16_t i; | |
329 | ||
330 | if(!packet) { | |
331 | return NULL; | |
332 | } | |
333 | ||
334 | rrs = ldns_pkt_get_section_clone(packet, sec); | |
335 | new = ldns_rr_list_new(); | |
336 | ret = NULL; | |
337 | ||
338 | for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { | |
339 | if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i)) && | |
340 | ldns_rdf_compare(ldns_rr_owner(ldns_rr_list_rr(rrs, i)), | |
341 | ownername | |
342 | ) == 0 | |
343 | ) { | |
344 | /* types match */ | |
345 | ldns_rr_list_push_rr(new, ldns_rr_clone(ldns_rr_list_rr(rrs, i))); | |
346 | ret = new; | |
347 | } | |
348 | } | |
349 | ldns_rr_list_deep_free(rrs); | |
350 | if (!ret) { | |
351 | ldns_rr_list_free(new); | |
352 | } | |
353 | return ret; | |
354 | } | |
355 | ||
356 | bool | |
357 | ldns_pkt_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr) | |
358 | { | |
359 | bool result = false; | |
360 | ||
361 | switch (sec) { | |
362 | case LDNS_SECTION_QUESTION: | |
363 | return ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr); | |
364 | case LDNS_SECTION_ANSWER: | |
365 | return ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr); | |
366 | case LDNS_SECTION_AUTHORITY: | |
367 | return ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr); | |
368 | case LDNS_SECTION_ADDITIONAL: | |
369 | return ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr); | |
370 | case LDNS_SECTION_ANY: | |
371 | result = ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr); | |
372 | case LDNS_SECTION_ANY_NOQUESTION: | |
373 | result = result | |
374 | || ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr) | |
375 | || ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr) | |
376 | || ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr); | |
377 | } | |
378 | ||
379 | return result; | |
380 | } | |
381 | ||
382 | uint16_t | |
383 | ldns_pkt_section_count(const ldns_pkt *packet, ldns_pkt_section s) | |
384 | { | |
385 | switch(s) { | |
386 | case LDNS_SECTION_QUESTION: | |
387 | return ldns_pkt_qdcount(packet); | |
388 | case LDNS_SECTION_ANSWER: | |
389 | return ldns_pkt_ancount(packet); | |
390 | case LDNS_SECTION_AUTHORITY: | |
391 | return ldns_pkt_nscount(packet); | |
392 | case LDNS_SECTION_ADDITIONAL: | |
393 | return ldns_pkt_arcount(packet); | |
394 | case LDNS_SECTION_ANY: | |
395 | return ldns_pkt_qdcount(packet) + | |
396 | ldns_pkt_ancount(packet) + | |
397 | ldns_pkt_nscount(packet) + | |
398 | ldns_pkt_arcount(packet); | |
399 | case LDNS_SECTION_ANY_NOQUESTION: | |
400 | return ldns_pkt_ancount(packet) + | |
401 | ldns_pkt_nscount(packet) + | |
402 | ldns_pkt_arcount(packet); | |
403 | default: | |
404 | return 0; | |
405 | } | |
406 | } | |
407 | ||
408 | bool | |
409 | ldns_pkt_empty(ldns_pkt *p) | |
410 | { | |
411 | if (!p) { | |
412 | return true; /* NULL is empty? */ | |
413 | } | |
414 | if (ldns_pkt_section_count(p, LDNS_SECTION_ANY) > 0) { | |
825eb42b | 415 | return false; |
ac996e71 JL |
416 | } else { |
417 | return true; | |
418 | } | |
825eb42b JL |
419 | } |
420 | ||
421 | ||
422 | ldns_rr_list * | |
423 | ldns_pkt_get_section_clone(const ldns_pkt *packet, ldns_pkt_section s) | |
424 | { | |
425 | switch(s) { | |
426 | case LDNS_SECTION_QUESTION: | |
427 | return ldns_rr_list_clone(ldns_pkt_question(packet)); | |
428 | case LDNS_SECTION_ANSWER: | |
429 | return ldns_rr_list_clone(ldns_pkt_answer(packet)); | |
430 | case LDNS_SECTION_AUTHORITY: | |
431 | return ldns_rr_list_clone(ldns_pkt_authority(packet)); | |
432 | case LDNS_SECTION_ADDITIONAL: | |
433 | return ldns_rr_list_clone(ldns_pkt_additional(packet)); | |
434 | case LDNS_SECTION_ANY: | |
435 | /* these are already clones */ | |
436 | return ldns_pkt_all(packet); | |
437 | case LDNS_SECTION_ANY_NOQUESTION: | |
438 | return ldns_pkt_all_noquestion(packet); | |
439 | default: | |
440 | return NULL; | |
441 | } | |
442 | } | |
443 | ||
444 | ldns_rr *ldns_pkt_tsig(const ldns_pkt *pkt) { | |
445 | return pkt->_tsig_rr; | |
446 | } | |
447 | ||
448 | /* write */ | |
449 | void | |
450 | ldns_pkt_set_id(ldns_pkt *packet, uint16_t id) | |
451 | { | |
452 | packet->_header->_id = id; | |
453 | } | |
454 | ||
455 | void | |
456 | ldns_pkt_set_random_id(ldns_pkt *packet) | |
457 | { | |
ac996e71 | 458 | uint16_t rid = ldns_get_random(); |
825eb42b JL |
459 | ldns_pkt_set_id(packet, rid); |
460 | } | |
461 | ||
462 | ||
463 | void | |
464 | ldns_pkt_set_qr(ldns_pkt *packet, bool qr) | |
465 | { | |
466 | packet->_header->_qr = qr; | |
467 | } | |
468 | ||
469 | void | |
470 | ldns_pkt_set_aa(ldns_pkt *packet, bool aa) | |
471 | { | |
472 | packet->_header->_aa = aa; | |
473 | } | |
474 | ||
475 | void | |
476 | ldns_pkt_set_tc(ldns_pkt *packet, bool tc) | |
477 | { | |
478 | packet->_header->_tc = tc; | |
479 | } | |
480 | ||
481 | void | |
482 | ldns_pkt_set_rd(ldns_pkt *packet, bool rd) | |
483 | { | |
484 | packet->_header->_rd = rd; | |
485 | } | |
486 | ||
487 | void | |
488 | ldns_pkt_set_additional(ldns_pkt *p, ldns_rr_list *rr) | |
489 | { | |
490 | p->_additional = rr; | |
491 | } | |
492 | ||
493 | void | |
494 | ldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr) | |
495 | { | |
496 | p->_question = rr; | |
497 | } | |
498 | ||
499 | void | |
500 | ldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr) | |
501 | { | |
502 | p->_answer = rr; | |
503 | } | |
504 | ||
505 | void | |
506 | ldns_pkt_set_authority(ldns_pkt *p, ldns_rr_list *rr) | |
507 | { | |
508 | p->_authority = rr; | |
509 | } | |
510 | ||
511 | void | |
512 | ldns_pkt_set_cd(ldns_pkt *packet, bool cd) | |
513 | { | |
514 | packet->_header->_cd = cd; | |
515 | } | |
516 | ||
517 | void | |
518 | ldns_pkt_set_ra(ldns_pkt *packet, bool ra) | |
519 | { | |
520 | packet->_header->_ra = ra; | |
521 | } | |
522 | ||
523 | void | |
524 | ldns_pkt_set_ad(ldns_pkt *packet, bool ad) | |
525 | { | |
526 | packet->_header->_ad = ad; | |
527 | } | |
528 | ||
529 | void | |
530 | ldns_pkt_set_opcode(ldns_pkt *packet, ldns_pkt_opcode opcode) | |
531 | { | |
532 | packet->_header->_opcode = opcode; | |
533 | } | |
534 | ||
535 | void | |
536 | ldns_pkt_set_rcode(ldns_pkt *packet, uint8_t rcode) | |
537 | { | |
538 | packet->_header->_rcode = rcode; | |
539 | } | |
540 | ||
541 | void | |
542 | ldns_pkt_set_qdcount(ldns_pkt *packet, uint16_t qdcount) | |
543 | { | |
544 | packet->_header->_qdcount = qdcount; | |
545 | } | |
546 | ||
547 | void | |
548 | ldns_pkt_set_ancount(ldns_pkt *packet, uint16_t ancount) | |
549 | { | |
550 | packet->_header->_ancount = ancount; | |
551 | } | |
552 | ||
553 | void | |
554 | ldns_pkt_set_nscount(ldns_pkt *packet, uint16_t nscount) | |
555 | { | |
556 | packet->_header->_nscount = nscount; | |
557 | } | |
558 | ||
559 | void | |
560 | ldns_pkt_set_arcount(ldns_pkt *packet, uint16_t arcount) | |
561 | { | |
562 | packet->_header->_arcount = arcount; | |
563 | } | |
564 | ||
565 | void | |
566 | ldns_pkt_set_querytime(ldns_pkt *packet, uint32_t time) | |
567 | { | |
568 | packet->_querytime = time; | |
569 | } | |
570 | ||
571 | void | |
572 | ldns_pkt_set_answerfrom(ldns_pkt *packet, ldns_rdf *answerfrom) | |
573 | { | |
574 | packet->_answerfrom = answerfrom; | |
575 | } | |
576 | ||
577 | void | |
578 | ldns_pkt_set_timestamp(ldns_pkt *packet, struct timeval timeval) | |
579 | { | |
580 | packet->timestamp.tv_sec = timeval.tv_sec; | |
581 | packet->timestamp.tv_usec = timeval.tv_usec; | |
582 | } | |
583 | ||
584 | void | |
585 | ldns_pkt_set_size(ldns_pkt *packet, size_t s) | |
586 | { | |
587 | packet->_size = s; | |
588 | } | |
589 | ||
590 | void | |
591 | ldns_pkt_set_edns_udp_size(ldns_pkt *packet, uint16_t s) | |
592 | { | |
593 | packet->_edns_udp_size = s; | |
594 | } | |
595 | ||
596 | void | |
597 | ldns_pkt_set_edns_extended_rcode(ldns_pkt *packet, uint8_t c) | |
598 | { | |
599 | packet->_edns_extended_rcode = c; | |
600 | } | |
601 | ||
602 | void | |
603 | ldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v) | |
604 | { | |
605 | packet->_edns_version = v; | |
606 | } | |
607 | ||
608 | void | |
609 | ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z) | |
610 | { | |
611 | packet->_edns_z = z; | |
612 | } | |
613 | ||
614 | void | |
615 | ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data) | |
616 | { | |
617 | packet->_edns_data = data; | |
618 | } | |
619 | ||
620 | void | |
621 | ldns_pkt_set_section_count(ldns_pkt *packet, ldns_pkt_section s, uint16_t count) | |
622 | { | |
623 | switch(s) { | |
624 | case LDNS_SECTION_QUESTION: | |
625 | ldns_pkt_set_qdcount(packet, count); | |
626 | break; | |
627 | case LDNS_SECTION_ANSWER: | |
628 | ldns_pkt_set_ancount(packet, count); | |
629 | break; | |
630 | case LDNS_SECTION_AUTHORITY: | |
631 | ldns_pkt_set_nscount(packet, count); | |
632 | break; | |
633 | case LDNS_SECTION_ADDITIONAL: | |
634 | ldns_pkt_set_arcount(packet, count); | |
635 | break; | |
636 | case LDNS_SECTION_ANY: | |
637 | case LDNS_SECTION_ANY_NOQUESTION: | |
638 | break; | |
639 | } | |
640 | } | |
641 | ||
642 | void ldns_pkt_set_tsig(ldns_pkt *pkt, ldns_rr *rr) | |
643 | { | |
644 | pkt->_tsig_rr = rr; | |
645 | } | |
646 | ||
647 | bool | |
648 | ldns_pkt_push_rr(ldns_pkt *packet, ldns_pkt_section section, ldns_rr *rr) | |
649 | { | |
650 | switch(section) { | |
651 | case LDNS_SECTION_QUESTION: | |
d1b2b5ca JM |
652 | if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) { |
653 | return false; | |
654 | } | |
825eb42b JL |
655 | ldns_pkt_set_qdcount(packet, ldns_pkt_qdcount(packet) + 1); |
656 | break; | |
657 | case LDNS_SECTION_ANSWER: | |
d1b2b5ca JM |
658 | if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) { |
659 | return false; | |
660 | } | |
825eb42b JL |
661 | ldns_pkt_set_ancount(packet, ldns_pkt_ancount(packet) + 1); |
662 | break; | |
663 | case LDNS_SECTION_AUTHORITY: | |
d1b2b5ca JM |
664 | if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) { |
665 | return false; | |
666 | } | |
825eb42b JL |
667 | ldns_pkt_set_nscount(packet, ldns_pkt_nscount(packet) + 1); |
668 | break; | |
669 | case LDNS_SECTION_ADDITIONAL: | |
d1b2b5ca JM |
670 | if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) { |
671 | return false; | |
672 | } | |
825eb42b JL |
673 | ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) + 1); |
674 | break; | |
675 | case LDNS_SECTION_ANY: | |
676 | case LDNS_SECTION_ANY_NOQUESTION: | |
677 | /* shouldn't this error? */ | |
678 | break; | |
679 | } | |
680 | return true; | |
681 | } | |
682 | ||
683 | bool | |
684 | ldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr) | |
685 | { | |
686 | ||
687 | /* check to see if its there */ | |
688 | if (ldns_pkt_rr(pkt, sec, rr)) { | |
689 | /* already there */ | |
690 | return false; | |
691 | } | |
692 | return ldns_pkt_push_rr(pkt, sec, rr); | |
693 | } | |
694 | ||
695 | bool | |
696 | ldns_pkt_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list) | |
697 | { | |
698 | size_t i; | |
699 | for(i = 0; i < ldns_rr_list_rr_count(list); i++) { | |
700 | if (!ldns_pkt_push_rr(p, s, ldns_rr_list_rr(list, i))) { | |
701 | return false; | |
702 | } | |
703 | } | |
704 | return true; | |
705 | } | |
706 | ||
707 | bool | |
708 | ldns_pkt_safe_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list) | |
709 | { | |
710 | size_t i; | |
711 | for(i = 0; i < ldns_rr_list_rr_count(list); i++) { | |
712 | if (!ldns_pkt_safe_push_rr(p, s, ldns_rr_list_rr(list, i))) { | |
713 | return false; | |
714 | } | |
715 | } | |
716 | return true; | |
717 | } | |
718 | ||
719 | bool | |
720 | ldns_pkt_edns(const ldns_pkt *pkt) { | |
721 | return (ldns_pkt_edns_udp_size(pkt) > 0 || | |
722 | ldns_pkt_edns_extended_rcode(pkt) > 0 || | |
723 | ldns_pkt_edns_data(pkt) || | |
724 | ldns_pkt_edns_do(pkt) | |
725 | ); | |
726 | } | |
727 | ||
728 | ||
729 | /* Create/destroy/convert functions | |
730 | */ | |
731 | ldns_pkt * | |
732 | ldns_pkt_new() | |
733 | { | |
734 | ldns_pkt *packet; | |
735 | packet = LDNS_MALLOC(ldns_pkt); | |
736 | if (!packet) { | |
737 | return NULL; | |
738 | } | |
739 | ||
740 | packet->_header = LDNS_MALLOC(ldns_hdr); | |
741 | if (!packet->_header) { | |
742 | LDNS_FREE(packet); | |
743 | return NULL; | |
744 | } | |
745 | ||
746 | packet->_question = ldns_rr_list_new(); | |
747 | packet->_answer = ldns_rr_list_new(); | |
748 | packet->_authority = ldns_rr_list_new(); | |
749 | packet->_additional = ldns_rr_list_new(); | |
750 | ||
751 | /* default everything to false */ | |
752 | ldns_pkt_set_qr(packet, false); | |
753 | ldns_pkt_set_aa(packet, false); | |
754 | ldns_pkt_set_tc(packet, false); | |
755 | ldns_pkt_set_rd(packet, false); | |
756 | ldns_pkt_set_ra(packet, false); | |
757 | ldns_pkt_set_ad(packet, false); | |
758 | ldns_pkt_set_cd(packet, false); | |
759 | ||
760 | ldns_pkt_set_opcode(packet, LDNS_PACKET_QUERY); | |
761 | ldns_pkt_set_rcode(packet, 0); | |
762 | ldns_pkt_set_id(packet, 0); | |
763 | ldns_pkt_set_size(packet, 0); | |
764 | ldns_pkt_set_querytime(packet, 0); | |
765 | memset(&packet->timestamp, 0, sizeof(packet->timestamp)); | |
766 | ldns_pkt_set_answerfrom(packet, NULL); | |
767 | ldns_pkt_set_section_count(packet, LDNS_SECTION_QUESTION, 0); | |
768 | ldns_pkt_set_section_count(packet, LDNS_SECTION_ANSWER, 0); | |
769 | ldns_pkt_set_section_count(packet, LDNS_SECTION_AUTHORITY, 0); | |
770 | ldns_pkt_set_section_count(packet, LDNS_SECTION_ADDITIONAL, 0); | |
771 | ||
772 | ldns_pkt_set_edns_udp_size(packet, 0); | |
773 | ldns_pkt_set_edns_extended_rcode(packet, 0); | |
774 | ldns_pkt_set_edns_version(packet, 0); | |
775 | ldns_pkt_set_edns_z(packet, 0); | |
776 | ldns_pkt_set_edns_data(packet, NULL); | |
777 | ||
778 | ldns_pkt_set_tsig(packet, NULL); | |
779 | ||
780 | return packet; | |
781 | } | |
782 | ||
783 | void | |
784 | ldns_pkt_free(ldns_pkt *packet) | |
785 | { | |
786 | if (packet) { | |
787 | LDNS_FREE(packet->_header); | |
788 | ldns_rr_list_deep_free(packet->_question); | |
789 | ldns_rr_list_deep_free(packet->_answer); | |
790 | ldns_rr_list_deep_free(packet->_authority); | |
791 | ldns_rr_list_deep_free(packet->_additional); | |
792 | ldns_rr_free(packet->_tsig_rr); | |
793 | ldns_rdf_deep_free(packet->_edns_data); | |
d1b2b5ca | 794 | ldns_rdf_deep_free(packet->_answerfrom); |
825eb42b JL |
795 | LDNS_FREE(packet); |
796 | } | |
797 | } | |
798 | ||
799 | bool | |
800 | ldns_pkt_set_flags(ldns_pkt *packet, uint16_t flags) | |
801 | { | |
802 | if (!packet) { | |
803 | return false; | |
804 | } | |
805 | if ((flags & LDNS_QR) == LDNS_QR) { | |
806 | ldns_pkt_set_qr(packet, true); | |
807 | } | |
808 | if ((flags & LDNS_AA) == LDNS_AA) { | |
809 | ldns_pkt_set_aa(packet, true); | |
810 | } | |
811 | if ((flags & LDNS_RD) == LDNS_RD) { | |
812 | ldns_pkt_set_rd(packet, true); | |
813 | } | |
814 | if ((flags & LDNS_TC) == LDNS_TC) { | |
815 | ldns_pkt_set_tc(packet, true); | |
816 | } | |
817 | if ((flags & LDNS_CD) == LDNS_CD) { | |
818 | ldns_pkt_set_cd(packet, true); | |
819 | } | |
820 | if ((flags & LDNS_RA) == LDNS_RA) { | |
821 | ldns_pkt_set_ra(packet, true); | |
822 | } | |
823 | if ((flags & LDNS_AD) == LDNS_AD) { | |
824 | ldns_pkt_set_ad(packet, true); | |
825 | } | |
826 | return true; | |
827 | } | |
828 | ||
d1b2b5ca JM |
829 | |
830 | static ldns_status | |
831 | ldns_pkt_add_authsoa(ldns_pkt* packet, ldns_rdf* rr_name, ldns_rr_class rr_class) | |
832 | { | |
833 | ldns_rr* soa_rr = ldns_rr_new(); | |
834 | ldns_rdf *owner_rdf; | |
835 | ldns_rdf *mname_rdf; | |
836 | ldns_rdf *rname_rdf; | |
837 | ldns_rdf *serial_rdf; | |
838 | ldns_rdf *refresh_rdf; | |
839 | ldns_rdf *retry_rdf; | |
840 | ldns_rdf *expire_rdf; | |
841 | ldns_rdf *minimum_rdf; | |
842 | ||
843 | if (!soa_rr) { | |
844 | return LDNS_STATUS_MEM_ERR; | |
845 | } | |
846 | owner_rdf = ldns_rdf_clone(rr_name); | |
847 | if (!owner_rdf) { | |
848 | ldns_rr_free(soa_rr); | |
849 | return LDNS_STATUS_MEM_ERR; | |
850 | } | |
851 | ||
852 | ldns_rr_set_owner(soa_rr, owner_rdf); | |
853 | ldns_rr_set_type(soa_rr, LDNS_RR_TYPE_SOA); | |
854 | ldns_rr_set_class(soa_rr, rr_class); | |
855 | ldns_rr_set_question(soa_rr, false); | |
856 | ||
857 | if (ldns_str2rdf_dname(&mname_rdf, ".") != LDNS_STATUS_OK) { | |
858 | ldns_rr_free(soa_rr); | |
859 | return LDNS_STATUS_MEM_ERR; | |
860 | } else { | |
861 | ldns_rr_push_rdf(soa_rr, mname_rdf); | |
862 | } | |
863 | if (ldns_str2rdf_dname(&rname_rdf, ".") != LDNS_STATUS_OK) { | |
864 | ldns_rr_free(soa_rr); | |
865 | return LDNS_STATUS_MEM_ERR; | |
866 | } else { | |
867 | ldns_rr_push_rdf(soa_rr, rname_rdf); | |
868 | } | |
869 | serial_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); | |
870 | if (!serial_rdf) { | |
871 | ldns_rr_free(soa_rr); | |
872 | return LDNS_STATUS_MEM_ERR; | |
873 | } else { | |
874 | ldns_rr_push_rdf(soa_rr, serial_rdf); | |
875 | } | |
876 | refresh_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); | |
877 | if (!refresh_rdf) { | |
878 | ldns_rr_free(soa_rr); | |
879 | return LDNS_STATUS_MEM_ERR; | |
880 | } else { | |
881 | ldns_rr_push_rdf(soa_rr, refresh_rdf); | |
882 | } | |
883 | retry_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); | |
884 | if (!retry_rdf) { | |
885 | ldns_rr_free(soa_rr); | |
886 | return LDNS_STATUS_MEM_ERR; | |
887 | } else { | |
888 | ldns_rr_push_rdf(soa_rr, retry_rdf); | |
889 | } | |
890 | expire_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); | |
891 | if (!expire_rdf) { | |
892 | ldns_rr_free(soa_rr); | |
893 | return LDNS_STATUS_MEM_ERR; | |
894 | } else { | |
895 | ldns_rr_push_rdf(soa_rr, expire_rdf); | |
896 | } | |
897 | minimum_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); | |
898 | if (!minimum_rdf) { | |
899 | ldns_rr_free(soa_rr); | |
900 | return LDNS_STATUS_MEM_ERR; | |
901 | } else { | |
902 | ldns_rr_push_rdf(soa_rr, minimum_rdf); | |
903 | } | |
904 | ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, soa_rr); | |
905 | return LDNS_STATUS_OK; | |
906 | } | |
907 | ||
908 | ||
825eb42b JL |
909 | ldns_status |
910 | ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type, | |
911 | ldns_rr_class rr_class, uint16_t flags) | |
912 | { | |
913 | ldns_pkt *packet; | |
914 | ldns_rr *question_rr; | |
915 | ldns_rdf *name_rdf; | |
916 | ||
917 | packet = ldns_pkt_new(); | |
918 | if (!packet) { | |
919 | return LDNS_STATUS_MEM_ERR; | |
920 | } | |
921 | ||
922 | if (!ldns_pkt_set_flags(packet, flags)) { | |
923 | return LDNS_STATUS_ERR; | |
924 | } | |
925 | ||
926 | question_rr = ldns_rr_new(); | |
927 | if (!question_rr) { | |
928 | return LDNS_STATUS_MEM_ERR; | |
929 | } | |
930 | ||
931 | if (rr_type == 0) { | |
932 | rr_type = LDNS_RR_TYPE_A; | |
933 | } | |
934 | if (rr_class == 0) { | |
935 | rr_class = LDNS_RR_CLASS_IN; | |
936 | } | |
937 | ||
938 | if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) { | |
939 | ldns_rr_set_owner(question_rr, name_rdf); | |
940 | ldns_rr_set_type(question_rr, rr_type); | |
941 | ldns_rr_set_class(question_rr, rr_class); | |
942 | ldns_rr_set_question(question_rr, true); | |
d1b2b5ca | 943 | |
825eb42b JL |
944 | ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr); |
945 | } else { | |
946 | ldns_rr_free(question_rr); | |
947 | ldns_pkt_free(packet); | |
948 | return LDNS_STATUS_ERR; | |
949 | } | |
d1b2b5ca JM |
950 | |
951 | /** IXFR? */ | |
952 | if (rr_type == LDNS_RR_TYPE_IXFR) { | |
953 | if (ldns_pkt_add_authsoa(packet, name_rdf, rr_class) != LDNS_STATUS_OK) { | |
954 | ldns_pkt_free(packet); | |
955 | return LDNS_STATUS_ERR; | |
956 | } | |
957 | } | |
958 | ||
825eb42b | 959 | packet->_tsig_rr = NULL; |
825eb42b JL |
960 | ldns_pkt_set_answerfrom(packet, NULL); |
961 | if (p) { | |
962 | *p = packet; | |
963 | return LDNS_STATUS_OK; | |
964 | } else { | |
d1b2b5ca | 965 | ldns_pkt_free(packet); |
825eb42b JL |
966 | return LDNS_STATUS_NULL; |
967 | } | |
968 | } | |
969 | ||
970 | ldns_pkt * | |
971 | ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, | |
972 | uint16_t flags) | |
973 | { | |
974 | ldns_pkt *packet; | |
975 | ldns_rr *question_rr; | |
976 | ||
977 | packet = ldns_pkt_new(); | |
978 | if (!packet) { | |
979 | return NULL; | |
980 | } | |
981 | ||
982 | if (!ldns_pkt_set_flags(packet, flags)) { | |
983 | return NULL; | |
984 | } | |
985 | ||
986 | question_rr = ldns_rr_new(); | |
987 | if (!question_rr) { | |
d1b2b5ca | 988 | ldns_pkt_free(packet); |
825eb42b JL |
989 | return NULL; |
990 | } | |
991 | ||
992 | if (rr_type == 0) { | |
993 | rr_type = LDNS_RR_TYPE_A; | |
994 | } | |
995 | if (rr_class == 0) { | |
996 | rr_class = LDNS_RR_CLASS_IN; | |
997 | } | |
998 | ||
999 | ldns_rr_set_owner(question_rr, rr_name); | |
1000 | ldns_rr_set_type(question_rr, rr_type); | |
1001 | ldns_rr_set_class(question_rr, rr_class); | |
1002 | ldns_rr_set_question(question_rr, true); | |
825eb42b JL |
1003 | ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr); |
1004 | ||
d1b2b5ca JM |
1005 | /** IXFR? */ |
1006 | if (rr_type == LDNS_RR_TYPE_IXFR) { | |
1007 | if (ldns_pkt_add_authsoa(packet, rr_name, rr_class) != LDNS_STATUS_OK) { | |
1008 | ldns_pkt_free(packet); | |
1009 | return NULL; | |
1010 | } | |
1011 | } | |
1012 | ||
1013 | packet->_tsig_rr = NULL; | |
825eb42b JL |
1014 | return packet; |
1015 | } | |
1016 | ||
1017 | ldns_pkt_type | |
1018 | ldns_pkt_reply_type(ldns_pkt *p) | |
1019 | { | |
1020 | ldns_rr_list *tmp; | |
1021 | ||
1022 | if (!p) { | |
1023 | return LDNS_PACKET_UNKNOWN; | |
1024 | } | |
1025 | ||
1026 | if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NXDOMAIN) { | |
1027 | return LDNS_PACKET_NXDOMAIN; | |
1028 | } | |
1029 | ||
1030 | if (ldns_pkt_ancount(p) == 0 && ldns_pkt_arcount(p) == 0 | |
1031 | && ldns_pkt_nscount(p) == 1) { | |
1032 | ||
1033 | /* check for SOA */ | |
1034 | tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SOA, | |
1035 | LDNS_SECTION_AUTHORITY); | |
1036 | if (tmp) { | |
1037 | ldns_rr_list_deep_free(tmp); | |
1038 | return LDNS_PACKET_NODATA; | |
1039 | } else { | |
1040 | /* I have no idea ... */ | |
1041 | } | |
1042 | } | |
1043 | ||
1044 | if (ldns_pkt_ancount(p) == 0 && ldns_pkt_nscount(p) > 0) { | |
1045 | tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS, | |
1046 | LDNS_SECTION_AUTHORITY); | |
1047 | if (tmp) { | |
1048 | /* there are nameservers here */ | |
1049 | ldns_rr_list_deep_free(tmp); | |
1050 | return LDNS_PACKET_REFERRAL; | |
1051 | } else { | |
1052 | /* I have no idea */ | |
1053 | } | |
1054 | ldns_rr_list_deep_free(tmp); | |
1055 | } | |
1056 | ||
1057 | /* if we cannot determine the packet type, we say it's an | |
1058 | * answer... | |
1059 | */ | |
1060 | return LDNS_PACKET_ANSWER; | |
1061 | } | |
1062 | ||
1063 | ldns_pkt * | |
1064 | ldns_pkt_clone(ldns_pkt *pkt) | |
1065 | { | |
1066 | ldns_pkt *new_pkt; | |
1067 | ||
1068 | if (!pkt) { | |
1069 | return NULL; | |
1070 | } | |
1071 | new_pkt = ldns_pkt_new(); | |
1072 | ||
1073 | ldns_pkt_set_id(new_pkt, ldns_pkt_id(pkt)); | |
1074 | ldns_pkt_set_qr(new_pkt, ldns_pkt_qr(pkt)); | |
1075 | ldns_pkt_set_aa(new_pkt, ldns_pkt_aa(pkt)); | |
1076 | ldns_pkt_set_tc(new_pkt, ldns_pkt_tc(pkt)); | |
1077 | ldns_pkt_set_rd(new_pkt, ldns_pkt_rd(pkt)); | |
1078 | ldns_pkt_set_cd(new_pkt, ldns_pkt_cd(pkt)); | |
1079 | ldns_pkt_set_ra(new_pkt, ldns_pkt_ra(pkt)); | |
1080 | ldns_pkt_set_ad(new_pkt, ldns_pkt_ad(pkt)); | |
1081 | ldns_pkt_set_opcode(new_pkt, ldns_pkt_get_opcode(pkt)); | |
1082 | ldns_pkt_set_rcode(new_pkt, ldns_pkt_get_rcode(pkt)); | |
1083 | ldns_pkt_set_qdcount(new_pkt, ldns_pkt_qdcount(pkt)); | |
1084 | ldns_pkt_set_ancount(new_pkt, ldns_pkt_ancount(pkt)); | |
1085 | ldns_pkt_set_nscount(new_pkt, ldns_pkt_nscount(pkt)); | |
1086 | ldns_pkt_set_arcount(new_pkt, ldns_pkt_arcount(pkt)); | |
d1b2b5ca JM |
1087 | if (ldns_pkt_answerfrom(pkt)) |
1088 | ldns_pkt_set_answerfrom(new_pkt, | |
1089 | ldns_rdf_clone(ldns_pkt_answerfrom(pkt))); | |
825eb42b JL |
1090 | ldns_pkt_set_querytime(new_pkt, ldns_pkt_querytime(pkt)); |
1091 | ldns_pkt_set_size(new_pkt, ldns_pkt_size(pkt)); | |
ac996e71 | 1092 | ldns_pkt_set_tsig(new_pkt, ldns_rr_clone(ldns_pkt_tsig(pkt))); |
825eb42b JL |
1093 | |
1094 | ldns_pkt_set_edns_udp_size(new_pkt, ldns_pkt_edns_udp_size(pkt)); | |
1095 | ldns_pkt_set_edns_extended_rcode(new_pkt, | |
1096 | ldns_pkt_edns_extended_rcode(pkt)); | |
1097 | ldns_pkt_set_edns_version(new_pkt, ldns_pkt_edns_version(pkt)); | |
1098 | ldns_pkt_set_edns_z(new_pkt, ldns_pkt_edns_z(pkt)); | |
1099 | if(ldns_pkt_edns_data(pkt)) | |
1100 | ldns_pkt_set_edns_data(new_pkt, | |
1101 | ldns_rdf_clone(ldns_pkt_edns_data(pkt))); | |
1102 | ldns_pkt_set_edns_do(new_pkt, ldns_pkt_edns_do(pkt)); | |
1103 | ||
1104 | ldns_rr_list_deep_free(new_pkt->_question); | |
1105 | ldns_rr_list_deep_free(new_pkt->_answer); | |
1106 | ldns_rr_list_deep_free(new_pkt->_authority); | |
1107 | ldns_rr_list_deep_free(new_pkt->_additional); | |
1108 | new_pkt->_question = ldns_rr_list_clone(ldns_pkt_question(pkt)); | |
1109 | new_pkt->_answer = ldns_rr_list_clone(ldns_pkt_answer(pkt)); | |
1110 | new_pkt->_authority = ldns_rr_list_clone(ldns_pkt_authority(pkt)); | |
1111 | new_pkt->_additional = ldns_rr_list_clone(ldns_pkt_additional(pkt)); | |
1112 | return new_pkt; | |
1113 | } |