1238104Sdes/*
2238104Sdes * packet.c
3238104Sdes *
4238104Sdes * dns packet implementation
5238104Sdes *
6238104Sdes * a Net::DNS like library for C
7238104Sdes *
8238104Sdes * (c) NLnet Labs, 2004-2006
9238104Sdes *
10238104Sdes * See the file LICENSE for the license
11238104Sdes */
12238104Sdes
13238104Sdes#include <ldns/config.h>
14238104Sdes
15238104Sdes#include <ldns/ldns.h>
16238104Sdes
17238104Sdes#include <strings.h>
18238104Sdes#include <limits.h>
19238104Sdes
20238104Sdes#ifdef HAVE_SSL
21238104Sdes#include <openssl/rand.h>
22238104Sdes#endif
23238104Sdes
24238104Sdes/* Access functions
25238104Sdes * do this as functions to get type checking
26238104Sdes */
27238104Sdes
28238104Sdes#define LDNS_EDNS_MASK_DO_BIT 0x8000
29238104Sdes
30238104Sdes/* TODO defines for 3600 */
31238104Sdes/* convert to and from numerical flag values */
32238104Sdesldns_lookup_table ldns_edns_flags[] = {
33238104Sdes	{ 3600, "do"},
34238104Sdes	{ 0, NULL}
35238104Sdes};
36238104Sdes
37238104Sdes/* read */
38238104Sdesuint16_t
39238104Sdesldns_pkt_id(const ldns_pkt *packet)
40238104Sdes{
41238104Sdes	return packet->_header->_id;
42238104Sdes}
43238104Sdes
44238104Sdesbool
45238104Sdesldns_pkt_qr(const ldns_pkt *packet)
46238104Sdes{
47238104Sdes	return packet->_header->_qr;
48238104Sdes}
49238104Sdes
50238104Sdesbool
51238104Sdesldns_pkt_aa(const ldns_pkt *packet)
52238104Sdes{
53238104Sdes	return packet->_header->_aa;
54238104Sdes}
55238104Sdes
56238104Sdesbool
57238104Sdesldns_pkt_tc(const ldns_pkt *packet)
58238104Sdes{
59238104Sdes	return packet->_header->_tc;
60238104Sdes}
61238104Sdes
62238104Sdesbool
63238104Sdesldns_pkt_rd(const ldns_pkt *packet)
64238104Sdes{
65238104Sdes	return packet->_header->_rd;
66238104Sdes}
67238104Sdes
68238104Sdesbool
69238104Sdesldns_pkt_cd(const ldns_pkt *packet)
70238104Sdes{
71238104Sdes	return packet->_header->_cd;
72238104Sdes}
73238104Sdes
74238104Sdesbool
75238104Sdesldns_pkt_ra(const ldns_pkt *packet)
76238104Sdes{
77238104Sdes	return packet->_header->_ra;
78238104Sdes}
79238104Sdes
80238104Sdesbool
81238104Sdesldns_pkt_ad(const ldns_pkt *packet)
82238104Sdes{
83238104Sdes	return packet->_header->_ad;
84238104Sdes}
85238104Sdes
86238104Sdesldns_pkt_opcode
87238104Sdesldns_pkt_get_opcode(const ldns_pkt *packet)
88238104Sdes{
89238104Sdes	return packet->_header->_opcode;
90238104Sdes}
91238104Sdes
92238104Sdesldns_pkt_rcode
93238104Sdesldns_pkt_get_rcode(const ldns_pkt *packet)
94238104Sdes{
95238104Sdes	return packet->_header->_rcode;
96238104Sdes}
97238104Sdes
98238104Sdesuint16_t
99238104Sdesldns_pkt_qdcount(const ldns_pkt *packet)
100238104Sdes{
101238104Sdes	return packet->_header->_qdcount;
102238104Sdes}
103238104Sdes
104238104Sdesuint16_t
105238104Sdesldns_pkt_ancount(const ldns_pkt *packet)
106238104Sdes{
107238104Sdes	return packet->_header->_ancount;
108238104Sdes}
109238104Sdes
110238104Sdesuint16_t
111238104Sdesldns_pkt_nscount(const ldns_pkt *packet)
112238104Sdes{
113238104Sdes	return packet->_header->_nscount;
114238104Sdes}
115238104Sdes
116238104Sdesuint16_t
117238104Sdesldns_pkt_arcount(const ldns_pkt *packet)
118238104Sdes{
119238104Sdes	return packet->_header->_arcount;
120238104Sdes}
121238104Sdes
122238104Sdesldns_rr_list *
123238104Sdesldns_pkt_question(const ldns_pkt *packet)
124238104Sdes{
125238104Sdes	return packet->_question;
126238104Sdes}
127238104Sdes
128238104Sdesldns_rr_list *
129238104Sdesldns_pkt_answer(const ldns_pkt *packet)
130238104Sdes{
131238104Sdes	return packet->_answer;
132238104Sdes}
133238104Sdes
134238104Sdesldns_rr_list *
135238104Sdesldns_pkt_authority(const ldns_pkt *packet)
136238104Sdes{
137238104Sdes	return packet->_authority;
138238104Sdes}
139238104Sdes
140238104Sdesldns_rr_list *
141238104Sdesldns_pkt_additional(const ldns_pkt *packet)
142238104Sdes{
143238104Sdes	return packet->_additional;
144238104Sdes}
145238104Sdes
146238104Sdes/* return ALL section concatenated */
147238104Sdesldns_rr_list *
148238104Sdesldns_pkt_all(const ldns_pkt *packet)
149238104Sdes{
150238104Sdes	ldns_rr_list *all, *prev_all;
151238104Sdes
152238104Sdes	all = ldns_rr_list_cat_clone(
153238104Sdes			ldns_pkt_question(packet),
154238104Sdes			ldns_pkt_answer(packet));
155238104Sdes	prev_all = all;
156238104Sdes	all = ldns_rr_list_cat_clone(all,
157238104Sdes			ldns_pkt_authority(packet));
158238104Sdes	ldns_rr_list_deep_free(prev_all);
159238104Sdes	prev_all = all;
160238104Sdes	all = ldns_rr_list_cat_clone(all,
161238104Sdes			ldns_pkt_additional(packet));
162238104Sdes	ldns_rr_list_deep_free(prev_all);
163238104Sdes	return all;
164238104Sdes}
165238104Sdes
166238104Sdesldns_rr_list *
167238104Sdesldns_pkt_all_noquestion(const ldns_pkt *packet)
168238104Sdes{
169238104Sdes	ldns_rr_list *all, *all2;
170238104Sdes
171238104Sdes	all = ldns_rr_list_cat_clone(
172238104Sdes			ldns_pkt_answer(packet),
173238104Sdes			ldns_pkt_authority(packet));
174238104Sdes	all2 = ldns_rr_list_cat_clone(all,
175238104Sdes			ldns_pkt_additional(packet));
176238104Sdes
177238104Sdes	ldns_rr_list_deep_free(all);
178238104Sdes	return all2;
179238104Sdes}
180238104Sdes
181238104Sdessize_t
182238104Sdesldns_pkt_size(const ldns_pkt *packet)
183238104Sdes{
184238104Sdes	return packet->_size;
185238104Sdes}
186238104Sdes
187238104Sdesuint32_t
188238104Sdesldns_pkt_querytime(const ldns_pkt *packet)
189238104Sdes{
190238104Sdes	return packet->_querytime;
191238104Sdes}
192238104Sdes
193238104Sdesldns_rdf *
194238104Sdesldns_pkt_answerfrom(const ldns_pkt *packet)
195238104Sdes{
196238104Sdes	return packet->_answerfrom;
197238104Sdes}
198238104Sdes
199238104Sdesstruct timeval
200238104Sdesldns_pkt_timestamp(const ldns_pkt *packet)
201238104Sdes{
202238104Sdes	return packet->timestamp;
203238104Sdes}
204238104Sdes
205238104Sdesuint16_t
206238104Sdesldns_pkt_edns_udp_size(const ldns_pkt *packet)
207238104Sdes{
208238104Sdes	return packet->_edns_udp_size;
209238104Sdes}
210238104Sdes
211238104Sdesuint8_t
212238104Sdesldns_pkt_edns_extended_rcode(const ldns_pkt *packet)
213238104Sdes{
214238104Sdes	return packet->_edns_extended_rcode;
215238104Sdes}
216238104Sdes
217238104Sdesuint8_t
218238104Sdesldns_pkt_edns_version(const ldns_pkt *packet)
219238104Sdes{
220238104Sdes	return packet->_edns_version;
221238104Sdes}
222238104Sdes
223238104Sdesuint16_t
224238104Sdesldns_pkt_edns_z(const ldns_pkt *packet)
225238104Sdes{
226238104Sdes	return packet->_edns_z;
227238104Sdes}
228238104Sdes
229238104Sdesbool
230238104Sdesldns_pkt_edns_do(const ldns_pkt *packet)
231238104Sdes{
232238104Sdes	return (packet->_edns_z & LDNS_EDNS_MASK_DO_BIT);
233238104Sdes}
234238104Sdes
235238104Sdesvoid
236238104Sdesldns_pkt_set_edns_do(ldns_pkt *packet, bool value)
237238104Sdes{
238238104Sdes	if (value) {
239238104Sdes		packet->_edns_z = packet->_edns_z | LDNS_EDNS_MASK_DO_BIT;
240238104Sdes	} else {
241238104Sdes		packet->_edns_z = packet->_edns_z & ~LDNS_EDNS_MASK_DO_BIT;
242238104Sdes	}
243238104Sdes}
244238104Sdes
245238104Sdesldns_rdf *
246238104Sdesldns_pkt_edns_data(const ldns_pkt *packet)
247238104Sdes{
248238104Sdes	return packet->_edns_data;
249238104Sdes}
250238104Sdes
251238104Sdes/* return only those rr that share the ownername */
252238104Sdesldns_rr_list *
253238104Sdesldns_pkt_rr_list_by_name(ldns_pkt *packet,
254238104Sdes                         ldns_rdf *ownername,
255238104Sdes                         ldns_pkt_section sec)
256238104Sdes{
257238104Sdes	ldns_rr_list *rrs;
258238104Sdes	ldns_rr_list *ret;
259238104Sdes	uint16_t i;
260238104Sdes
261238104Sdes	if (!packet) {
262238104Sdes		return NULL;
263238104Sdes	}
264238104Sdes
265238104Sdes	rrs = ldns_pkt_get_section_clone(packet, sec);
266238104Sdes	ret = NULL;
267238104Sdes
268238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
269266114Sdes		if (ldns_dname_compare(ldns_rr_owner(
270238104Sdes						ldns_rr_list_rr(rrs, i)),
271238104Sdes					ownername) == 0) {
272238104Sdes			/* owner names match */
273246854Sdes			if (ret == NULL) {
274246854Sdes				ret = ldns_rr_list_new();
275246854Sdes			}
276246854Sdes			ldns_rr_list_push_rr(ret, ldns_rr_list_rr(rrs, i));
277238104Sdes		}
278238104Sdes	}
279238104Sdes	return ret;
280238104Sdes}
281238104Sdes
282238104Sdes/* return only those rr that share a type */
283238104Sdesldns_rr_list *
284238104Sdesldns_pkt_rr_list_by_type(const ldns_pkt *packet,
285238104Sdes                         ldns_rr_type type,
286238104Sdes                         ldns_pkt_section sec)
287238104Sdes{
288238104Sdes	ldns_rr_list *rrs;
289238104Sdes	ldns_rr_list *new;
290238104Sdes	uint16_t i;
291238104Sdes
292238104Sdes	if(!packet) {
293238104Sdes		return NULL;
294238104Sdes	}
295238104Sdes
296238104Sdes	rrs = ldns_pkt_get_section_clone(packet, sec);
297238104Sdes	new = ldns_rr_list_new();
298238104Sdes
299238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
300238104Sdes		if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i))) {
301238104Sdes			/* types match */
302238104Sdes			ldns_rr_list_push_rr(new,
303238104Sdes			                     ldns_rr_clone(
304238104Sdes			                     	ldns_rr_list_rr(rrs, i))
305238104Sdes					     );
306238104Sdes		}
307238104Sdes	}
308238104Sdes	ldns_rr_list_deep_free(rrs);
309238104Sdes
310238104Sdes	if (ldns_rr_list_rr_count(new) == 0) {
311238104Sdes		ldns_rr_list_free(new);
312238104Sdes		return NULL;
313238104Sdes	} else {
314238104Sdes		return new;
315238104Sdes	}
316238104Sdes}
317238104Sdes
318238104Sdes/* return only those rrs that share name and type */
319238104Sdesldns_rr_list *
320238104Sdesldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet,
321238104Sdes                                  const ldns_rdf *ownername,
322238104Sdes                                  ldns_rr_type type,
323238104Sdes                                  ldns_pkt_section sec)
324238104Sdes{
325238104Sdes	ldns_rr_list *rrs;
326238104Sdes	ldns_rr_list *new;
327238104Sdes	ldns_rr_list *ret;
328238104Sdes	uint16_t i;
329238104Sdes
330238104Sdes	if(!packet) {
331238104Sdes		return NULL;
332238104Sdes	}
333238104Sdes
334238104Sdes	rrs = ldns_pkt_get_section_clone(packet, sec);
335238104Sdes	new = ldns_rr_list_new();
336238104Sdes	ret = NULL;
337238104Sdes
338238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
339238104Sdes		if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i)) &&
340266114Sdes		    ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(rrs, i)),
341238104Sdes		                     ownername
342238104Sdes		                    ) == 0
343238104Sdes		   ) {
344238104Sdes			/* types match */
345238104Sdes			ldns_rr_list_push_rr(new, ldns_rr_clone(ldns_rr_list_rr(rrs, i)));
346238104Sdes			ret = new;
347238104Sdes		}
348238104Sdes	}
349238104Sdes	ldns_rr_list_deep_free(rrs);
350238104Sdes	if (!ret) {
351238104Sdes		ldns_rr_list_free(new);
352238104Sdes	}
353238104Sdes	return ret;
354238104Sdes}
355238104Sdes
356238104Sdesbool
357238104Sdesldns_pkt_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr)
358238104Sdes{
359238104Sdes	bool result = false;
360238104Sdes
361238104Sdes	switch (sec) {
362238104Sdes	case LDNS_SECTION_QUESTION:
363238104Sdes		return ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr);
364238104Sdes	case LDNS_SECTION_ANSWER:
365238104Sdes		return ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr);
366238104Sdes	case LDNS_SECTION_AUTHORITY:
367238104Sdes		return ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr);
368238104Sdes	case LDNS_SECTION_ADDITIONAL:
369238104Sdes		return ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr);
370238104Sdes	case LDNS_SECTION_ANY:
371238104Sdes		result = ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr);
372238104Sdes	case LDNS_SECTION_ANY_NOQUESTION:
373238104Sdes		result = result
374238104Sdes		    || ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr)
375238104Sdes		    || ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr)
376238104Sdes		    || ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr);
377238104Sdes	}
378238104Sdes
379238104Sdes	return result;
380238104Sdes}
381238104Sdes
382266114Sdesuint16_t
383238104Sdesldns_pkt_section_count(const ldns_pkt *packet, ldns_pkt_section s)
384238104Sdes{
385238104Sdes	switch(s) {
386238104Sdes	case LDNS_SECTION_QUESTION:
387238104Sdes		return ldns_pkt_qdcount(packet);
388238104Sdes	case LDNS_SECTION_ANSWER:
389238104Sdes		return ldns_pkt_ancount(packet);
390238104Sdes	case LDNS_SECTION_AUTHORITY:
391238104Sdes		return ldns_pkt_nscount(packet);
392238104Sdes	case LDNS_SECTION_ADDITIONAL:
393238104Sdes		return ldns_pkt_arcount(packet);
394238104Sdes	case LDNS_SECTION_ANY:
395238104Sdes		return ldns_pkt_qdcount(packet) +
396238104Sdes			ldns_pkt_ancount(packet) +
397238104Sdes			ldns_pkt_nscount(packet) +
398238104Sdes			ldns_pkt_arcount(packet);
399238104Sdes	case LDNS_SECTION_ANY_NOQUESTION:
400238104Sdes		return ldns_pkt_ancount(packet) +
401238104Sdes			ldns_pkt_nscount(packet) +
402238104Sdes			ldns_pkt_arcount(packet);
403238104Sdes	default:
404238104Sdes		return 0;
405238104Sdes	}
406238104Sdes}
407238104Sdes
408238104Sdesbool
409238104Sdesldns_pkt_empty(ldns_pkt *p)
410238104Sdes{
411238104Sdes	if (!p) {
412238104Sdes		return true; /* NULL is empty? */
413238104Sdes	}
414238104Sdes	if (ldns_pkt_section_count(p, LDNS_SECTION_ANY) > 0) {
415238104Sdes		return false;
416238104Sdes	} else {
417238104Sdes		return true;
418238104Sdes    }
419238104Sdes}
420238104Sdes
421238104Sdes
422238104Sdesldns_rr_list *
423238104Sdesldns_pkt_get_section_clone(const ldns_pkt *packet, ldns_pkt_section s)
424238104Sdes{
425238104Sdes	switch(s) {
426238104Sdes	case LDNS_SECTION_QUESTION:
427238104Sdes		return ldns_rr_list_clone(ldns_pkt_question(packet));
428238104Sdes	case LDNS_SECTION_ANSWER:
429238104Sdes		return ldns_rr_list_clone(ldns_pkt_answer(packet));
430238104Sdes	case LDNS_SECTION_AUTHORITY:
431238104Sdes		return ldns_rr_list_clone(ldns_pkt_authority(packet));
432238104Sdes	case LDNS_SECTION_ADDITIONAL:
433238104Sdes		return ldns_rr_list_clone(ldns_pkt_additional(packet));
434238104Sdes	case LDNS_SECTION_ANY:
435238104Sdes		/* these are already clones */
436238104Sdes		return ldns_pkt_all(packet);
437238104Sdes	case LDNS_SECTION_ANY_NOQUESTION:
438238104Sdes		return ldns_pkt_all_noquestion(packet);
439238104Sdes	default:
440238104Sdes		return NULL;
441238104Sdes	}
442238104Sdes}
443238104Sdes
444238104Sdesldns_rr *ldns_pkt_tsig(const ldns_pkt *pkt) {
445238104Sdes	return pkt->_tsig_rr;
446238104Sdes}
447238104Sdes
448238104Sdes/* write */
449238104Sdesvoid
450238104Sdesldns_pkt_set_id(ldns_pkt *packet, uint16_t id)
451238104Sdes{
452238104Sdes	packet->_header->_id = id;
453238104Sdes}
454238104Sdes
455238104Sdesvoid
456238104Sdesldns_pkt_set_random_id(ldns_pkt *packet)
457238104Sdes{
458238104Sdes	uint16_t rid = ldns_get_random();
459238104Sdes	ldns_pkt_set_id(packet, rid);
460238104Sdes}
461238104Sdes
462238104Sdes
463238104Sdesvoid
464238104Sdesldns_pkt_set_qr(ldns_pkt *packet, bool qr)
465238104Sdes{
466238104Sdes	packet->_header->_qr = qr;
467238104Sdes}
468238104Sdes
469238104Sdesvoid
470238104Sdesldns_pkt_set_aa(ldns_pkt *packet, bool aa)
471238104Sdes{
472238104Sdes	packet->_header->_aa = aa;
473238104Sdes}
474238104Sdes
475238104Sdesvoid
476238104Sdesldns_pkt_set_tc(ldns_pkt *packet, bool tc)
477238104Sdes{
478238104Sdes	packet->_header->_tc = tc;
479238104Sdes}
480238104Sdes
481238104Sdesvoid
482238104Sdesldns_pkt_set_rd(ldns_pkt *packet, bool rd)
483238104Sdes{
484238104Sdes	packet->_header->_rd = rd;
485238104Sdes}
486238104Sdes
487238104Sdesvoid
488238104Sdesldns_pkt_set_additional(ldns_pkt *p, ldns_rr_list *rr)
489238104Sdes{
490238104Sdes	p->_additional = rr;
491238104Sdes}
492238104Sdes
493238104Sdesvoid
494238104Sdesldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr)
495238104Sdes{
496238104Sdes	p->_question = rr;
497238104Sdes}
498238104Sdes
499238104Sdesvoid
500238104Sdesldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr)
501238104Sdes{
502238104Sdes	p->_answer = rr;
503238104Sdes}
504238104Sdes
505238104Sdesvoid
506238104Sdesldns_pkt_set_authority(ldns_pkt *p, ldns_rr_list *rr)
507238104Sdes{
508238104Sdes	p->_authority = rr;
509238104Sdes}
510238104Sdes
511238104Sdesvoid
512238104Sdesldns_pkt_set_cd(ldns_pkt *packet, bool cd)
513238104Sdes{
514238104Sdes	packet->_header->_cd = cd;
515238104Sdes}
516238104Sdes
517238104Sdesvoid
518238104Sdesldns_pkt_set_ra(ldns_pkt *packet, bool ra)
519238104Sdes{
520238104Sdes	packet->_header->_ra = ra;
521238104Sdes}
522238104Sdes
523238104Sdesvoid
524238104Sdesldns_pkt_set_ad(ldns_pkt *packet, bool ad)
525238104Sdes{
526238104Sdes	packet->_header->_ad = ad;
527238104Sdes}
528238104Sdes
529238104Sdesvoid
530238104Sdesldns_pkt_set_opcode(ldns_pkt *packet, ldns_pkt_opcode opcode)
531238104Sdes{
532238104Sdes	packet->_header->_opcode = opcode;
533238104Sdes}
534238104Sdes
535238104Sdesvoid
536238104Sdesldns_pkt_set_rcode(ldns_pkt *packet, uint8_t rcode)
537238104Sdes{
538238104Sdes	packet->_header->_rcode = rcode;
539238104Sdes}
540238104Sdes
541238104Sdesvoid
542238104Sdesldns_pkt_set_qdcount(ldns_pkt *packet, uint16_t qdcount)
543238104Sdes{
544238104Sdes	packet->_header->_qdcount = qdcount;
545238104Sdes}
546238104Sdes
547238104Sdesvoid
548238104Sdesldns_pkt_set_ancount(ldns_pkt *packet, uint16_t ancount)
549238104Sdes{
550238104Sdes	packet->_header->_ancount = ancount;
551238104Sdes}
552238104Sdes
553238104Sdesvoid
554238104Sdesldns_pkt_set_nscount(ldns_pkt *packet, uint16_t nscount)
555238104Sdes{
556238104Sdes	packet->_header->_nscount = nscount;
557238104Sdes}
558238104Sdes
559238104Sdesvoid
560238104Sdesldns_pkt_set_arcount(ldns_pkt *packet, uint16_t arcount)
561238104Sdes{
562238104Sdes	packet->_header->_arcount = arcount;
563238104Sdes}
564238104Sdes
565238104Sdesvoid
566238104Sdesldns_pkt_set_querytime(ldns_pkt *packet, uint32_t time)
567238104Sdes{
568238104Sdes	packet->_querytime = time;
569238104Sdes}
570238104Sdes
571238104Sdesvoid
572238104Sdesldns_pkt_set_answerfrom(ldns_pkt *packet, ldns_rdf *answerfrom)
573238104Sdes{
574238104Sdes	packet->_answerfrom = answerfrom;
575238104Sdes}
576238104Sdes
577238104Sdesvoid
578238104Sdesldns_pkt_set_timestamp(ldns_pkt *packet, struct timeval timeval)
579238104Sdes{
580238104Sdes	packet->timestamp.tv_sec = timeval.tv_sec;
581238104Sdes	packet->timestamp.tv_usec = timeval.tv_usec;
582238104Sdes}
583238104Sdes
584238104Sdesvoid
585238104Sdesldns_pkt_set_size(ldns_pkt *packet, size_t s)
586238104Sdes{
587238104Sdes	packet->_size = s;
588238104Sdes}
589238104Sdes
590238104Sdesvoid
591238104Sdesldns_pkt_set_edns_udp_size(ldns_pkt *packet, uint16_t s)
592238104Sdes{
593238104Sdes	packet->_edns_udp_size = s;
594238104Sdes}
595238104Sdes
596238104Sdesvoid
597238104Sdesldns_pkt_set_edns_extended_rcode(ldns_pkt *packet, uint8_t c)
598238104Sdes{
599238104Sdes	packet->_edns_extended_rcode = c;
600238104Sdes}
601238104Sdes
602238104Sdesvoid
603238104Sdesldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v)
604238104Sdes{
605238104Sdes	packet->_edns_version = v;
606238104Sdes}
607238104Sdes
608238104Sdesvoid
609238104Sdesldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z)
610238104Sdes{
611238104Sdes	packet->_edns_z = z;
612238104Sdes}
613238104Sdes
614238104Sdesvoid
615238104Sdesldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data)
616238104Sdes{
617238104Sdes	packet->_edns_data = data;
618238104Sdes}
619238104Sdes
620238104Sdesvoid
621238104Sdesldns_pkt_set_section_count(ldns_pkt *packet, ldns_pkt_section s, uint16_t count)
622238104Sdes{
623238104Sdes	switch(s) {
624238104Sdes		case LDNS_SECTION_QUESTION:
625238104Sdes			ldns_pkt_set_qdcount(packet, count);
626238104Sdes			break;
627238104Sdes		case LDNS_SECTION_ANSWER:
628238104Sdes			ldns_pkt_set_ancount(packet, count);
629238104Sdes			break;
630238104Sdes		case LDNS_SECTION_AUTHORITY:
631238104Sdes			ldns_pkt_set_nscount(packet, count);
632238104Sdes			break;
633238104Sdes		case LDNS_SECTION_ADDITIONAL:
634238104Sdes			ldns_pkt_set_arcount(packet, count);
635238104Sdes			break;
636238104Sdes		case LDNS_SECTION_ANY:
637238104Sdes		case LDNS_SECTION_ANY_NOQUESTION:
638238104Sdes			break;
639238104Sdes	}
640238104Sdes}
641238104Sdes
642238104Sdesvoid ldns_pkt_set_tsig(ldns_pkt *pkt, ldns_rr *rr)
643238104Sdes{
644238104Sdes	pkt->_tsig_rr = rr;
645238104Sdes}
646238104Sdes
647238104Sdesbool
648238104Sdesldns_pkt_push_rr(ldns_pkt *packet, ldns_pkt_section section, ldns_rr *rr)
649238104Sdes{
650238104Sdes	switch(section) {
651238104Sdes		case LDNS_SECTION_QUESTION:
652246854Sdes			if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) {
653246854Sdes				return false;
654246854Sdes			}
655238104Sdes			ldns_pkt_set_qdcount(packet, ldns_pkt_qdcount(packet) + 1);
656238104Sdes			break;
657238104Sdes		case LDNS_SECTION_ANSWER:
658246854Sdes			if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) {
659246854Sdes				return false;
660246854Sdes			}
661238104Sdes			ldns_pkt_set_ancount(packet, ldns_pkt_ancount(packet) + 1);
662238104Sdes			break;
663238104Sdes		case LDNS_SECTION_AUTHORITY:
664246854Sdes			if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) {
665246854Sdes				return false;
666246854Sdes			}
667238104Sdes			ldns_pkt_set_nscount(packet, ldns_pkt_nscount(packet) + 1);
668238104Sdes			break;
669238104Sdes		case LDNS_SECTION_ADDITIONAL:
670246854Sdes			if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) {
671246854Sdes				return false;
672246854Sdes			}
673238104Sdes			ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) + 1);
674238104Sdes			break;
675238104Sdes		case LDNS_SECTION_ANY:
676238104Sdes		case LDNS_SECTION_ANY_NOQUESTION:
677238104Sdes			/* shouldn't this error? */
678238104Sdes			break;
679238104Sdes	}
680238104Sdes	return true;
681238104Sdes}
682238104Sdes
683238104Sdesbool
684238104Sdesldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr)
685238104Sdes{
686238104Sdes
687238104Sdes	/* check to see if its there */
688238104Sdes	if (ldns_pkt_rr(pkt, sec, rr)) {
689238104Sdes		/* already there */
690238104Sdes		return false;
691238104Sdes	}
692238104Sdes	return ldns_pkt_push_rr(pkt, sec, rr);
693238104Sdes}
694238104Sdes
695238104Sdesbool
696238104Sdesldns_pkt_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list)
697238104Sdes{
698238104Sdes	size_t i;
699238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(list); i++) {
700238104Sdes		if (!ldns_pkt_push_rr(p, s, ldns_rr_list_rr(list, i))) {
701238104Sdes			return false;
702238104Sdes		}
703238104Sdes	}
704238104Sdes	return true;
705238104Sdes}
706238104Sdes
707238104Sdesbool
708238104Sdesldns_pkt_safe_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list)
709238104Sdes{
710238104Sdes	size_t i;
711238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(list); i++) {
712238104Sdes		if (!ldns_pkt_safe_push_rr(p, s, ldns_rr_list_rr(list, i))) {
713238104Sdes			return false;
714238104Sdes		}
715238104Sdes	}
716238104Sdes	return true;
717238104Sdes}
718238104Sdes
719238104Sdesbool
720238104Sdesldns_pkt_edns(const ldns_pkt *pkt) {
721238104Sdes	return (ldns_pkt_edns_udp_size(pkt) > 0 ||
722238104Sdes		ldns_pkt_edns_extended_rcode(pkt) > 0 ||
723238104Sdes		ldns_pkt_edns_data(pkt) ||
724238104Sdes		ldns_pkt_edns_do(pkt)
725238104Sdes	       );
726238104Sdes}
727238104Sdes
728238104Sdes
729238104Sdes/* Create/destroy/convert functions
730238104Sdes */
731238104Sdesldns_pkt *
732246827Sdesldns_pkt_new(void)
733238104Sdes{
734238104Sdes	ldns_pkt *packet;
735238104Sdes	packet = LDNS_MALLOC(ldns_pkt);
736238104Sdes	if (!packet) {
737238104Sdes		return NULL;
738238104Sdes	}
739238104Sdes
740238104Sdes	packet->_header = LDNS_MALLOC(ldns_hdr);
741238104Sdes	if (!packet->_header) {
742238104Sdes		LDNS_FREE(packet);
743238104Sdes		return NULL;
744238104Sdes	}
745238104Sdes
746238104Sdes	packet->_question = ldns_rr_list_new();
747238104Sdes	packet->_answer = ldns_rr_list_new();
748238104Sdes	packet->_authority = ldns_rr_list_new();
749238104Sdes	packet->_additional = ldns_rr_list_new();
750238104Sdes
751238104Sdes	/* default everything to false */
752238104Sdes	ldns_pkt_set_qr(packet, false);
753238104Sdes	ldns_pkt_set_aa(packet, false);
754238104Sdes	ldns_pkt_set_tc(packet, false);
755238104Sdes	ldns_pkt_set_rd(packet, false);
756238104Sdes	ldns_pkt_set_ra(packet, false);
757238104Sdes	ldns_pkt_set_ad(packet, false);
758238104Sdes	ldns_pkt_set_cd(packet, false);
759238104Sdes
760238104Sdes	ldns_pkt_set_opcode(packet, LDNS_PACKET_QUERY);
761238104Sdes	ldns_pkt_set_rcode(packet, 0);
762238104Sdes	ldns_pkt_set_id(packet, 0);
763238104Sdes	ldns_pkt_set_size(packet, 0);
764238104Sdes	ldns_pkt_set_querytime(packet, 0);
765238104Sdes	memset(&packet->timestamp, 0, sizeof(packet->timestamp));
766238104Sdes	ldns_pkt_set_answerfrom(packet, NULL);
767238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_QUESTION, 0);
768238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_ANSWER, 0);
769238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_AUTHORITY, 0);
770238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_ADDITIONAL, 0);
771238104Sdes
772238104Sdes	ldns_pkt_set_edns_udp_size(packet, 0);
773238104Sdes	ldns_pkt_set_edns_extended_rcode(packet, 0);
774238104Sdes	ldns_pkt_set_edns_version(packet, 0);
775238104Sdes	ldns_pkt_set_edns_z(packet, 0);
776238104Sdes	ldns_pkt_set_edns_data(packet, NULL);
777238104Sdes
778238104Sdes	ldns_pkt_set_tsig(packet, NULL);
779238104Sdes
780238104Sdes	return packet;
781238104Sdes}
782238104Sdes
783238104Sdesvoid
784238104Sdesldns_pkt_free(ldns_pkt *packet)
785238104Sdes{
786238104Sdes	if (packet) {
787238104Sdes		LDNS_FREE(packet->_header);
788238104Sdes		ldns_rr_list_deep_free(packet->_question);
789238104Sdes		ldns_rr_list_deep_free(packet->_answer);
790238104Sdes		ldns_rr_list_deep_free(packet->_authority);
791238104Sdes		ldns_rr_list_deep_free(packet->_additional);
792238104Sdes		ldns_rr_free(packet->_tsig_rr);
793238104Sdes		ldns_rdf_deep_free(packet->_edns_data);
794246854Sdes		ldns_rdf_deep_free(packet->_answerfrom);
795238104Sdes		LDNS_FREE(packet);
796238104Sdes	}
797238104Sdes}
798238104Sdes
799238104Sdesbool
800238104Sdesldns_pkt_set_flags(ldns_pkt *packet, uint16_t flags)
801238104Sdes{
802238104Sdes	if (!packet) {
803238104Sdes		return false;
804238104Sdes	}
805238104Sdes	if ((flags & LDNS_QR) == LDNS_QR) {
806238104Sdes		ldns_pkt_set_qr(packet, true);
807238104Sdes	}
808238104Sdes	if ((flags & LDNS_AA) == LDNS_AA) {
809238104Sdes		ldns_pkt_set_aa(packet, true);
810238104Sdes	}
811238104Sdes	if ((flags & LDNS_RD) == LDNS_RD) {
812238104Sdes		ldns_pkt_set_rd(packet, true);
813238104Sdes	}
814238104Sdes	if ((flags & LDNS_TC) == LDNS_TC) {
815238104Sdes		ldns_pkt_set_tc(packet, true);
816238104Sdes	}
817238104Sdes	if ((flags & LDNS_CD) == LDNS_CD) {
818238104Sdes		ldns_pkt_set_cd(packet, true);
819238104Sdes	}
820238104Sdes	if ((flags & LDNS_RA) == LDNS_RA) {
821238104Sdes		ldns_pkt_set_ra(packet, true);
822238104Sdes	}
823238104Sdes	if ((flags & LDNS_AD) == LDNS_AD) {
824238104Sdes		ldns_pkt_set_ad(packet, true);
825238104Sdes	}
826238104Sdes	return true;
827238104Sdes}
828238104Sdes
829246854Sdes
830266114Sdesstatic ldns_rr*
831266114Sdesldns_pkt_authsoa(ldns_rdf* rr_name, ldns_rr_class rr_class)
832246854Sdes{
833246854Sdes	ldns_rr* soa_rr = ldns_rr_new();
834246854Sdes	ldns_rdf *owner_rdf;
835246854Sdes	ldns_rdf *mname_rdf;
836246854Sdes	ldns_rdf *rname_rdf;
837246854Sdes	ldns_rdf *serial_rdf;
838246854Sdes	ldns_rdf *refresh_rdf;
839246854Sdes	ldns_rdf *retry_rdf;
840246854Sdes	ldns_rdf *expire_rdf;
841246854Sdes	ldns_rdf *minimum_rdf;
842246854Sdes
843246854Sdes	if (!soa_rr) {
844266114Sdes		return NULL;
845246854Sdes	}
846246854Sdes	owner_rdf = ldns_rdf_clone(rr_name);
847246854Sdes	if (!owner_rdf) {
848246854Sdes		ldns_rr_free(soa_rr);
849266114Sdes		return NULL;
850246854Sdes	}
851246854Sdes
852246854Sdes	ldns_rr_set_owner(soa_rr, owner_rdf);
853246854Sdes	ldns_rr_set_type(soa_rr, LDNS_RR_TYPE_SOA);
854246854Sdes	ldns_rr_set_class(soa_rr, rr_class);
855246854Sdes	ldns_rr_set_question(soa_rr, false);
856246854Sdes
857246854Sdes	if (ldns_str2rdf_dname(&mname_rdf, ".") != LDNS_STATUS_OK) {
858246854Sdes		ldns_rr_free(soa_rr);
859266114Sdes		return NULL;
860246854Sdes	} else {
861246854Sdes		ldns_rr_push_rdf(soa_rr, mname_rdf);
862246854Sdes	}
863246854Sdes	if (ldns_str2rdf_dname(&rname_rdf, ".") != LDNS_STATUS_OK) {
864246854Sdes		ldns_rr_free(soa_rr);
865266114Sdes		return NULL;
866246854Sdes	} else {
867246854Sdes		ldns_rr_push_rdf(soa_rr, rname_rdf);
868246854Sdes	}
869246854Sdes	serial_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0);
870246854Sdes	if (!serial_rdf) {
871246854Sdes		ldns_rr_free(soa_rr);
872266114Sdes		return NULL;
873246854Sdes	} else {
874246854Sdes		ldns_rr_push_rdf(soa_rr, serial_rdf);
875246854Sdes	}
876246854Sdes	refresh_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0);
877246854Sdes	if (!refresh_rdf) {
878246854Sdes		ldns_rr_free(soa_rr);
879266114Sdes		return NULL;
880246854Sdes	} else {
881246854Sdes		ldns_rr_push_rdf(soa_rr, refresh_rdf);
882246854Sdes	}
883246854Sdes	retry_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0);
884246854Sdes	if (!retry_rdf) {
885246854Sdes		ldns_rr_free(soa_rr);
886266114Sdes		return NULL;
887246854Sdes	} else {
888246854Sdes		ldns_rr_push_rdf(soa_rr, retry_rdf);
889246854Sdes	}
890246854Sdes	expire_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0);
891246854Sdes	if (!expire_rdf) {
892246854Sdes		ldns_rr_free(soa_rr);
893266114Sdes		return NULL;
894246854Sdes	} else {
895246854Sdes		ldns_rr_push_rdf(soa_rr, expire_rdf);
896246854Sdes	}
897246854Sdes	minimum_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0);
898246854Sdes	if (!minimum_rdf) {
899246854Sdes		ldns_rr_free(soa_rr);
900266114Sdes		return NULL;
901246854Sdes	} else {
902246854Sdes		ldns_rr_push_rdf(soa_rr, minimum_rdf);
903246854Sdes	}
904266114Sdes	return soa_rr;
905246854Sdes}
906246854Sdes
907246854Sdes
908266114Sdesstatic ldns_status
909266114Sdesldns_pkt_query_new_frm_str_internal(ldns_pkt **p, const char *name,
910266114Sdes	ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags,
911266114Sdes	ldns_rr* authsoa_rr)
912238104Sdes{
913238104Sdes	ldns_pkt *packet;
914238104Sdes	ldns_rr *question_rr;
915238104Sdes	ldns_rdf *name_rdf;
916238104Sdes
917238104Sdes	packet = ldns_pkt_new();
918238104Sdes	if (!packet) {
919238104Sdes		return LDNS_STATUS_MEM_ERR;
920238104Sdes	}
921266114Sdes
922238104Sdes	if (!ldns_pkt_set_flags(packet, flags)) {
923238104Sdes		return LDNS_STATUS_ERR;
924238104Sdes	}
925266114Sdes
926238104Sdes	question_rr = ldns_rr_new();
927238104Sdes	if (!question_rr) {
928238104Sdes		return LDNS_STATUS_MEM_ERR;
929238104Sdes	}
930238104Sdes
931238104Sdes	if (rr_type == 0) {
932238104Sdes		rr_type = LDNS_RR_TYPE_A;
933238104Sdes	}
934238104Sdes	if (rr_class == 0) {
935238104Sdes		rr_class = LDNS_RR_CLASS_IN;
936238104Sdes	}
937238104Sdes
938238104Sdes	if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) {
939238104Sdes		ldns_rr_set_owner(question_rr, name_rdf);
940238104Sdes		ldns_rr_set_type(question_rr, rr_type);
941238104Sdes		ldns_rr_set_class(question_rr, rr_class);
942238104Sdes                ldns_rr_set_question(question_rr, true);
943246854Sdes
944238104Sdes		ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr);
945238104Sdes	} else {
946238104Sdes		ldns_rr_free(question_rr);
947238104Sdes		ldns_pkt_free(packet);
948238104Sdes		return LDNS_STATUS_ERR;
949238104Sdes	}
950246854Sdes
951266114Sdes	if (authsoa_rr) {
952266114Sdes		ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, authsoa_rr);
953246854Sdes	}
954246854Sdes
955238104Sdes	packet->_tsig_rr = NULL;
956238104Sdes	ldns_pkt_set_answerfrom(packet, NULL);
957238104Sdes	if (p) {
958238104Sdes		*p = packet;
959238104Sdes		return LDNS_STATUS_OK;
960238104Sdes	} else {
961246854Sdes		ldns_pkt_free(packet);
962238104Sdes		return LDNS_STATUS_NULL;
963238104Sdes	}
964238104Sdes}
965238104Sdes
966266114Sdesldns_status
967266114Sdesldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name,
968266114Sdes	ldns_rr_type rr_type, ldns_rr_class rr_class, uint16_t flags)
969238104Sdes{
970266114Sdes	return ldns_pkt_query_new_frm_str_internal(p, name, rr_type,
971266114Sdes		rr_class, flags, NULL);
972266114Sdes}
973266114Sdes
974266114Sdesldns_status
975266114Sdesldns_pkt_ixfr_request_new_frm_str(ldns_pkt **p, const char *name,
976266114Sdes	ldns_rr_class rr_class, uint16_t flags, ldns_rr *soa)
977266114Sdes{
978266114Sdes	ldns_rr* authsoa_rr = soa;
979266114Sdes	if (!authsoa_rr) {
980266114Sdes		ldns_rdf *name_rdf;
981266114Sdes		if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) {
982266114Sdes			authsoa_rr = ldns_pkt_authsoa(name_rdf, rr_class);
983266114Sdes		}
984266114Sdes		ldns_rdf_free(name_rdf);
985266114Sdes	}
986266114Sdes	return ldns_pkt_query_new_frm_str_internal(p, name, LDNS_RR_TYPE_IXFR,
987266114Sdes		rr_class, flags, authsoa_rr);
988266114Sdes}
989266114Sdes
990266114Sdesstatic ldns_pkt *
991266114Sdesldns_pkt_query_new_internal(ldns_rdf *rr_name, ldns_rr_type rr_type,
992266114Sdes	ldns_rr_class rr_class,	uint16_t flags, ldns_rr* authsoa_rr)
993266114Sdes{
994238104Sdes	ldns_pkt *packet;
995238104Sdes	ldns_rr *question_rr;
996238104Sdes
997238104Sdes	packet = ldns_pkt_new();
998238104Sdes	if (!packet) {
999238104Sdes		return NULL;
1000238104Sdes	}
1001238104Sdes
1002238104Sdes	if (!ldns_pkt_set_flags(packet, flags)) {
1003238104Sdes		return NULL;
1004238104Sdes	}
1005266114Sdes
1006238104Sdes	question_rr = ldns_rr_new();
1007238104Sdes	if (!question_rr) {
1008246854Sdes		ldns_pkt_free(packet);
1009238104Sdes		return NULL;
1010238104Sdes	}
1011238104Sdes
1012238104Sdes	if (rr_type == 0) {
1013238104Sdes		rr_type = LDNS_RR_TYPE_A;
1014238104Sdes	}
1015238104Sdes	if (rr_class == 0) {
1016238104Sdes		rr_class = LDNS_RR_CLASS_IN;
1017238104Sdes	}
1018238104Sdes
1019238104Sdes	ldns_rr_set_owner(question_rr, rr_name);
1020238104Sdes	ldns_rr_set_type(question_rr, rr_type);
1021238104Sdes	ldns_rr_set_class(question_rr, rr_class);
1022238104Sdes        ldns_rr_set_question(question_rr, true);
1023238104Sdes	ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr);
1024238104Sdes
1025266114Sdes	if (authsoa_rr) {
1026266114Sdes		ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, authsoa_rr);
1027246854Sdes	}
1028246854Sdes
1029246854Sdes	packet->_tsig_rr = NULL;
1030238104Sdes	return packet;
1031238104Sdes}
1032238104Sdes
1033266114Sdesldns_pkt *
1034266114Sdesldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type,
1035266114Sdes	ldns_rr_class rr_class,	uint16_t flags)
1036266114Sdes{
1037266114Sdes	return ldns_pkt_query_new_internal(rr_name, rr_type,
1038266114Sdes		rr_class, flags, NULL);
1039266114Sdes}
1040266114Sdes
1041266114Sdesldns_pkt *
1042266114Sdesldns_pkt_ixfr_request_new(ldns_rdf *rr_name, ldns_rr_class rr_class,
1043266114Sdes	uint16_t flags, ldns_rr* soa)
1044266114Sdes{
1045266114Sdes	ldns_rr* authsoa_rr = soa;
1046266114Sdes	if (!authsoa_rr) {
1047266114Sdes		authsoa_rr = ldns_pkt_authsoa(rr_name, rr_class);
1048266114Sdes	}
1049266114Sdes	return ldns_pkt_query_new_internal(rr_name, LDNS_RR_TYPE_IXFR,
1050266114Sdes		rr_class, flags, authsoa_rr);
1051266114Sdes}
1052266114Sdes
1053238104Sdesldns_pkt_type
1054238104Sdesldns_pkt_reply_type(ldns_pkt *p)
1055238104Sdes{
1056238104Sdes	ldns_rr_list *tmp;
1057238104Sdes
1058238104Sdes	if (!p) {
1059238104Sdes		return LDNS_PACKET_UNKNOWN;
1060238104Sdes	}
1061238104Sdes
1062238104Sdes	if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NXDOMAIN) {
1063238104Sdes		return LDNS_PACKET_NXDOMAIN;
1064238104Sdes	}
1065238104Sdes
1066238104Sdes	if (ldns_pkt_ancount(p) == 0 && ldns_pkt_arcount(p) == 0
1067238104Sdes			&& ldns_pkt_nscount(p) == 1) {
1068238104Sdes
1069238104Sdes		/* check for SOA */
1070238104Sdes		tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SOA,
1071238104Sdes					LDNS_SECTION_AUTHORITY);
1072238104Sdes		if (tmp) {
1073238104Sdes			ldns_rr_list_deep_free(tmp);
1074238104Sdes			return LDNS_PACKET_NODATA;
1075238104Sdes		} else {
1076238104Sdes			/* I have no idea ... */
1077238104Sdes		}
1078238104Sdes	}
1079238104Sdes
1080238104Sdes	if (ldns_pkt_ancount(p) == 0 && ldns_pkt_nscount(p) > 0) {
1081238104Sdes		tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS,
1082238104Sdes		                               LDNS_SECTION_AUTHORITY);
1083238104Sdes		if (tmp) {
1084238104Sdes			/* there are nameservers here */
1085238104Sdes			ldns_rr_list_deep_free(tmp);
1086238104Sdes			return LDNS_PACKET_REFERRAL;
1087238104Sdes		} else {
1088238104Sdes			/* I have no idea */
1089238104Sdes		}
1090238104Sdes		ldns_rr_list_deep_free(tmp);
1091238104Sdes	}
1092238104Sdes
1093238104Sdes	/* if we cannot determine the packet type, we say it's an
1094238104Sdes	 * answer...
1095238104Sdes	 */
1096238104Sdes	return LDNS_PACKET_ANSWER;
1097238104Sdes}
1098238104Sdes
1099238104Sdesldns_pkt *
1100238104Sdesldns_pkt_clone(ldns_pkt *pkt)
1101238104Sdes{
1102238104Sdes	ldns_pkt *new_pkt;
1103238104Sdes
1104238104Sdes	if (!pkt) {
1105238104Sdes		return NULL;
1106238104Sdes	}
1107238104Sdes	new_pkt = ldns_pkt_new();
1108238104Sdes
1109238104Sdes	ldns_pkt_set_id(new_pkt, ldns_pkt_id(pkt));
1110238104Sdes	ldns_pkt_set_qr(new_pkt, ldns_pkt_qr(pkt));
1111238104Sdes	ldns_pkt_set_aa(new_pkt, ldns_pkt_aa(pkt));
1112238104Sdes	ldns_pkt_set_tc(new_pkt, ldns_pkt_tc(pkt));
1113238104Sdes	ldns_pkt_set_rd(new_pkt, ldns_pkt_rd(pkt));
1114238104Sdes	ldns_pkt_set_cd(new_pkt, ldns_pkt_cd(pkt));
1115238104Sdes	ldns_pkt_set_ra(new_pkt, ldns_pkt_ra(pkt));
1116238104Sdes	ldns_pkt_set_ad(new_pkt, ldns_pkt_ad(pkt));
1117238104Sdes	ldns_pkt_set_opcode(new_pkt, ldns_pkt_get_opcode(pkt));
1118238104Sdes	ldns_pkt_set_rcode(new_pkt, ldns_pkt_get_rcode(pkt));
1119238104Sdes	ldns_pkt_set_qdcount(new_pkt, ldns_pkt_qdcount(pkt));
1120238104Sdes	ldns_pkt_set_ancount(new_pkt, ldns_pkt_ancount(pkt));
1121238104Sdes	ldns_pkt_set_nscount(new_pkt, ldns_pkt_nscount(pkt));
1122238104Sdes	ldns_pkt_set_arcount(new_pkt, ldns_pkt_arcount(pkt));
1123246854Sdes	if (ldns_pkt_answerfrom(pkt))
1124246854Sdes		ldns_pkt_set_answerfrom(new_pkt,
1125246854Sdes			ldns_rdf_clone(ldns_pkt_answerfrom(pkt)));
1126238104Sdes	ldns_pkt_set_querytime(new_pkt, ldns_pkt_querytime(pkt));
1127238104Sdes	ldns_pkt_set_size(new_pkt, ldns_pkt_size(pkt));
1128238104Sdes	ldns_pkt_set_tsig(new_pkt, ldns_rr_clone(ldns_pkt_tsig(pkt)));
1129238104Sdes
1130238104Sdes	ldns_pkt_set_edns_udp_size(new_pkt, ldns_pkt_edns_udp_size(pkt));
1131238104Sdes	ldns_pkt_set_edns_extended_rcode(new_pkt,
1132238104Sdes		ldns_pkt_edns_extended_rcode(pkt));
1133238104Sdes	ldns_pkt_set_edns_version(new_pkt, ldns_pkt_edns_version(pkt));
1134238104Sdes	ldns_pkt_set_edns_z(new_pkt, ldns_pkt_edns_z(pkt));
1135238104Sdes	if(ldns_pkt_edns_data(pkt))
1136238104Sdes		ldns_pkt_set_edns_data(new_pkt,
1137238104Sdes			ldns_rdf_clone(ldns_pkt_edns_data(pkt)));
1138238104Sdes	ldns_pkt_set_edns_do(new_pkt, ldns_pkt_edns_do(pkt));
1139238104Sdes
1140238104Sdes	ldns_rr_list_deep_free(new_pkt->_question);
1141238104Sdes	ldns_rr_list_deep_free(new_pkt->_answer);
1142238104Sdes	ldns_rr_list_deep_free(new_pkt->_authority);
1143238104Sdes	ldns_rr_list_deep_free(new_pkt->_additional);
1144238104Sdes	new_pkt->_question = ldns_rr_list_clone(ldns_pkt_question(pkt));
1145238104Sdes	new_pkt->_answer = ldns_rr_list_clone(ldns_pkt_answer(pkt));
1146238104Sdes	new_pkt->_authority = ldns_rr_list_clone(ldns_pkt_authority(pkt));
1147238104Sdes	new_pkt->_additional = ldns_rr_list_clone(ldns_pkt_additional(pkt));
1148238104Sdes	return new_pkt;
1149238104Sdes}
1150