packet.c revision 246827
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 *new;
259238104Sdes	ldns_rr_list *ret;
260238104Sdes	uint16_t i;
261238104Sdes
262238104Sdes	if (!packet) {
263238104Sdes		return NULL;
264238104Sdes	}
265238104Sdes
266238104Sdes	rrs = ldns_pkt_get_section_clone(packet, sec);
267238104Sdes	new = ldns_rr_list_new();
268238104Sdes	ret = NULL;
269238104Sdes
270238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) {
271238104Sdes		if (ldns_rdf_compare(ldns_rr_owner(
272238104Sdes						ldns_rr_list_rr(rrs, i)),
273238104Sdes					ownername) == 0) {
274238104Sdes			/* owner names match */
275238104Sdes			ldns_rr_list_push_rr(new, ldns_rr_list_rr(rrs, i));
276238104Sdes			ret = new;
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)) &&
340238104Sdes		    ldns_rdf_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
382246827Sdesstatic uint16_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:
652238104Sdes			ldns_rr_list_push_rr(ldns_pkt_question(packet), rr);
653238104Sdes			ldns_pkt_set_qdcount(packet, ldns_pkt_qdcount(packet) + 1);
654238104Sdes			break;
655238104Sdes		case LDNS_SECTION_ANSWER:
656238104Sdes			ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr);
657238104Sdes			ldns_pkt_set_ancount(packet, ldns_pkt_ancount(packet) + 1);
658238104Sdes			break;
659238104Sdes		case LDNS_SECTION_AUTHORITY:
660238104Sdes			ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr);
661238104Sdes			ldns_pkt_set_nscount(packet, ldns_pkt_nscount(packet) + 1);
662238104Sdes			break;
663238104Sdes		case LDNS_SECTION_ADDITIONAL:
664238104Sdes			ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr);
665238104Sdes			ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) + 1);
666238104Sdes			break;
667238104Sdes		case LDNS_SECTION_ANY:
668238104Sdes		case LDNS_SECTION_ANY_NOQUESTION:
669238104Sdes			/* shouldn't this error? */
670238104Sdes			break;
671238104Sdes	}
672238104Sdes	return true;
673238104Sdes}
674238104Sdes
675238104Sdesbool
676238104Sdesldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr)
677238104Sdes{
678238104Sdes
679238104Sdes	/* check to see if its there */
680238104Sdes	if (ldns_pkt_rr(pkt, sec, rr)) {
681238104Sdes		/* already there */
682238104Sdes		return false;
683238104Sdes	}
684238104Sdes	return ldns_pkt_push_rr(pkt, sec, rr);
685238104Sdes}
686238104Sdes
687238104Sdesbool
688238104Sdesldns_pkt_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list)
689238104Sdes{
690238104Sdes	size_t i;
691238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(list); i++) {
692238104Sdes		if (!ldns_pkt_push_rr(p, s, ldns_rr_list_rr(list, i))) {
693238104Sdes			return false;
694238104Sdes		}
695238104Sdes	}
696238104Sdes	return true;
697238104Sdes}
698238104Sdes
699238104Sdesbool
700238104Sdesldns_pkt_safe_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list)
701238104Sdes{
702238104Sdes	size_t i;
703238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(list); i++) {
704238104Sdes		if (!ldns_pkt_safe_push_rr(p, s, ldns_rr_list_rr(list, i))) {
705238104Sdes			return false;
706238104Sdes		}
707238104Sdes	}
708238104Sdes	return true;
709238104Sdes}
710238104Sdes
711238104Sdesbool
712238104Sdesldns_pkt_edns(const ldns_pkt *pkt) {
713238104Sdes	return (ldns_pkt_edns_udp_size(pkt) > 0 ||
714238104Sdes		ldns_pkt_edns_extended_rcode(pkt) > 0 ||
715238104Sdes		ldns_pkt_edns_data(pkt) ||
716238104Sdes		ldns_pkt_edns_do(pkt)
717238104Sdes	       );
718238104Sdes}
719238104Sdes
720238104Sdes
721238104Sdes/* Create/destroy/convert functions
722238104Sdes */
723238104Sdesldns_pkt *
724246827Sdesldns_pkt_new(void)
725238104Sdes{
726238104Sdes	ldns_pkt *packet;
727238104Sdes	packet = LDNS_MALLOC(ldns_pkt);
728238104Sdes	if (!packet) {
729238104Sdes		return NULL;
730238104Sdes	}
731238104Sdes
732238104Sdes	packet->_header = LDNS_MALLOC(ldns_hdr);
733238104Sdes	if (!packet->_header) {
734238104Sdes		LDNS_FREE(packet);
735238104Sdes		return NULL;
736238104Sdes	}
737238104Sdes
738238104Sdes	packet->_question = ldns_rr_list_new();
739238104Sdes	packet->_answer = ldns_rr_list_new();
740238104Sdes	packet->_authority = ldns_rr_list_new();
741238104Sdes	packet->_additional = ldns_rr_list_new();
742238104Sdes
743238104Sdes	/* default everything to false */
744238104Sdes	ldns_pkt_set_qr(packet, false);
745238104Sdes	ldns_pkt_set_aa(packet, false);
746238104Sdes	ldns_pkt_set_tc(packet, false);
747238104Sdes	ldns_pkt_set_rd(packet, false);
748238104Sdes	ldns_pkt_set_ra(packet, false);
749238104Sdes	ldns_pkt_set_ad(packet, false);
750238104Sdes	ldns_pkt_set_cd(packet, false);
751238104Sdes
752238104Sdes	ldns_pkt_set_opcode(packet, LDNS_PACKET_QUERY);
753238104Sdes	ldns_pkt_set_rcode(packet, 0);
754238104Sdes	ldns_pkt_set_id(packet, 0);
755238104Sdes	ldns_pkt_set_size(packet, 0);
756238104Sdes	ldns_pkt_set_querytime(packet, 0);
757238104Sdes	memset(&packet->timestamp, 0, sizeof(packet->timestamp));
758238104Sdes	ldns_pkt_set_answerfrom(packet, NULL);
759238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_QUESTION, 0);
760238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_ANSWER, 0);
761238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_AUTHORITY, 0);
762238104Sdes	ldns_pkt_set_section_count(packet, LDNS_SECTION_ADDITIONAL, 0);
763238104Sdes
764238104Sdes	ldns_pkt_set_edns_udp_size(packet, 0);
765238104Sdes	ldns_pkt_set_edns_extended_rcode(packet, 0);
766238104Sdes	ldns_pkt_set_edns_version(packet, 0);
767238104Sdes	ldns_pkt_set_edns_z(packet, 0);
768238104Sdes	ldns_pkt_set_edns_data(packet, NULL);
769238104Sdes
770238104Sdes	ldns_pkt_set_tsig(packet, NULL);
771238104Sdes
772238104Sdes	return packet;
773238104Sdes}
774238104Sdes
775238104Sdesvoid
776238104Sdesldns_pkt_free(ldns_pkt *packet)
777238104Sdes{
778238104Sdes	if (packet) {
779238104Sdes		LDNS_FREE(packet->_header);
780238104Sdes		ldns_rr_list_deep_free(packet->_question);
781238104Sdes		ldns_rr_list_deep_free(packet->_answer);
782238104Sdes		ldns_rr_list_deep_free(packet->_authority);
783238104Sdes		ldns_rr_list_deep_free(packet->_additional);
784238104Sdes		ldns_rr_free(packet->_tsig_rr);
785238104Sdes		ldns_rdf_deep_free(packet->_edns_data);
786238104Sdes		LDNS_FREE(packet);
787238104Sdes	}
788238104Sdes}
789238104Sdes
790238104Sdesbool
791238104Sdesldns_pkt_set_flags(ldns_pkt *packet, uint16_t flags)
792238104Sdes{
793238104Sdes	if (!packet) {
794238104Sdes		return false;
795238104Sdes	}
796238104Sdes	if ((flags & LDNS_QR) == LDNS_QR) {
797238104Sdes		ldns_pkt_set_qr(packet, true);
798238104Sdes	}
799238104Sdes	if ((flags & LDNS_AA) == LDNS_AA) {
800238104Sdes		ldns_pkt_set_aa(packet, true);
801238104Sdes	}
802238104Sdes	if ((flags & LDNS_RD) == LDNS_RD) {
803238104Sdes		ldns_pkt_set_rd(packet, true);
804238104Sdes	}
805238104Sdes	if ((flags & LDNS_TC) == LDNS_TC) {
806238104Sdes		ldns_pkt_set_tc(packet, true);
807238104Sdes	}
808238104Sdes	if ((flags & LDNS_CD) == LDNS_CD) {
809238104Sdes		ldns_pkt_set_cd(packet, true);
810238104Sdes	}
811238104Sdes	if ((flags & LDNS_RA) == LDNS_RA) {
812238104Sdes		ldns_pkt_set_ra(packet, true);
813238104Sdes	}
814238104Sdes	if ((flags & LDNS_AD) == LDNS_AD) {
815238104Sdes		ldns_pkt_set_ad(packet, true);
816238104Sdes	}
817238104Sdes	return true;
818238104Sdes}
819238104Sdes
820238104Sdesldns_status
821238104Sdesldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type,
822238104Sdes		ldns_rr_class rr_class, uint16_t flags)
823238104Sdes{
824238104Sdes	ldns_pkt *packet;
825238104Sdes	ldns_rr *question_rr;
826238104Sdes	ldns_rdf *name_rdf;
827238104Sdes
828238104Sdes	packet = ldns_pkt_new();
829238104Sdes	if (!packet) {
830238104Sdes		return LDNS_STATUS_MEM_ERR;
831238104Sdes	}
832238104Sdes
833238104Sdes	if (!ldns_pkt_set_flags(packet, flags)) {
834238104Sdes		return LDNS_STATUS_ERR;
835238104Sdes	}
836238104Sdes
837238104Sdes	question_rr = ldns_rr_new();
838238104Sdes	if (!question_rr) {
839238104Sdes		return LDNS_STATUS_MEM_ERR;
840238104Sdes	}
841238104Sdes
842238104Sdes	if (rr_type == 0) {
843238104Sdes		rr_type = LDNS_RR_TYPE_A;
844238104Sdes	}
845238104Sdes	if (rr_class == 0) {
846238104Sdes		rr_class = LDNS_RR_CLASS_IN;
847238104Sdes	}
848238104Sdes
849238104Sdes	if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) {
850238104Sdes		ldns_rr_set_owner(question_rr, name_rdf);
851238104Sdes		ldns_rr_set_type(question_rr, rr_type);
852238104Sdes		ldns_rr_set_class(question_rr, rr_class);
853238104Sdes                ldns_rr_set_question(question_rr, true);
854238104Sdes
855238104Sdes		ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr);
856238104Sdes	} else {
857238104Sdes		ldns_rr_free(question_rr);
858238104Sdes		ldns_pkt_free(packet);
859238104Sdes		return LDNS_STATUS_ERR;
860238104Sdes	}
861238104Sdes
862238104Sdes	packet->_tsig_rr = NULL;
863238104Sdes
864238104Sdes	ldns_pkt_set_answerfrom(packet, NULL);
865238104Sdes	if (p) {
866238104Sdes		*p = packet;
867238104Sdes		return LDNS_STATUS_OK;
868238104Sdes	} else {
869238104Sdes		return LDNS_STATUS_NULL;
870238104Sdes	}
871238104Sdes}
872238104Sdes
873238104Sdesldns_pkt *
874238104Sdesldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class,
875238104Sdes		uint16_t flags)
876238104Sdes{
877238104Sdes	ldns_pkt *packet;
878238104Sdes	ldns_rr *question_rr;
879238104Sdes
880238104Sdes	packet = ldns_pkt_new();
881238104Sdes	if (!packet) {
882238104Sdes		return NULL;
883238104Sdes	}
884238104Sdes
885238104Sdes	if (!ldns_pkt_set_flags(packet, flags)) {
886238104Sdes		return NULL;
887238104Sdes	}
888238104Sdes
889238104Sdes	question_rr = ldns_rr_new();
890238104Sdes	if (!question_rr) {
891238104Sdes		return NULL;
892238104Sdes	}
893238104Sdes
894238104Sdes	if (rr_type == 0) {
895238104Sdes		rr_type = LDNS_RR_TYPE_A;
896238104Sdes	}
897238104Sdes	if (rr_class == 0) {
898238104Sdes		rr_class = LDNS_RR_CLASS_IN;
899238104Sdes	}
900238104Sdes
901238104Sdes	ldns_rr_set_owner(question_rr, rr_name);
902238104Sdes	ldns_rr_set_type(question_rr, rr_type);
903238104Sdes	ldns_rr_set_class(question_rr, rr_class);
904238104Sdes        ldns_rr_set_question(question_rr, true);
905238104Sdes
906238104Sdes	packet->_tsig_rr = NULL;
907238104Sdes
908238104Sdes	ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr);
909238104Sdes
910238104Sdes	return packet;
911238104Sdes}
912238104Sdes
913238104Sdesldns_pkt_type
914238104Sdesldns_pkt_reply_type(ldns_pkt *p)
915238104Sdes{
916238104Sdes	ldns_rr_list *tmp;
917238104Sdes
918238104Sdes	if (!p) {
919238104Sdes		return LDNS_PACKET_UNKNOWN;
920238104Sdes	}
921238104Sdes
922238104Sdes	if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NXDOMAIN) {
923238104Sdes		return LDNS_PACKET_NXDOMAIN;
924238104Sdes	}
925238104Sdes
926238104Sdes	if (ldns_pkt_ancount(p) == 0 && ldns_pkt_arcount(p) == 0
927238104Sdes			&& ldns_pkt_nscount(p) == 1) {
928238104Sdes
929238104Sdes		/* check for SOA */
930238104Sdes		tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SOA,
931238104Sdes					LDNS_SECTION_AUTHORITY);
932238104Sdes		if (tmp) {
933238104Sdes			ldns_rr_list_deep_free(tmp);
934238104Sdes			return LDNS_PACKET_NODATA;
935238104Sdes		} else {
936238104Sdes			/* I have no idea ... */
937238104Sdes		}
938238104Sdes	}
939238104Sdes
940238104Sdes	if (ldns_pkt_ancount(p) == 0 && ldns_pkt_nscount(p) > 0) {
941238104Sdes		tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS,
942238104Sdes		                               LDNS_SECTION_AUTHORITY);
943238104Sdes		if (tmp) {
944238104Sdes			/* there are nameservers here */
945238104Sdes			ldns_rr_list_deep_free(tmp);
946238104Sdes			return LDNS_PACKET_REFERRAL;
947238104Sdes		} else {
948238104Sdes			/* I have no idea */
949238104Sdes		}
950238104Sdes		ldns_rr_list_deep_free(tmp);
951238104Sdes	}
952238104Sdes
953238104Sdes	/* if we cannot determine the packet type, we say it's an
954238104Sdes	 * answer...
955238104Sdes	 */
956238104Sdes	return LDNS_PACKET_ANSWER;
957238104Sdes}
958238104Sdes
959238104Sdesldns_pkt *
960238104Sdesldns_pkt_clone(ldns_pkt *pkt)
961238104Sdes{
962238104Sdes	ldns_pkt *new_pkt;
963238104Sdes
964238104Sdes	if (!pkt) {
965238104Sdes		return NULL;
966238104Sdes	}
967238104Sdes	new_pkt = ldns_pkt_new();
968238104Sdes
969238104Sdes	ldns_pkt_set_id(new_pkt, ldns_pkt_id(pkt));
970238104Sdes	ldns_pkt_set_qr(new_pkt, ldns_pkt_qr(pkt));
971238104Sdes	ldns_pkt_set_aa(new_pkt, ldns_pkt_aa(pkt));
972238104Sdes	ldns_pkt_set_tc(new_pkt, ldns_pkt_tc(pkt));
973238104Sdes	ldns_pkt_set_rd(new_pkt, ldns_pkt_rd(pkt));
974238104Sdes	ldns_pkt_set_cd(new_pkt, ldns_pkt_cd(pkt));
975238104Sdes	ldns_pkt_set_ra(new_pkt, ldns_pkt_ra(pkt));
976238104Sdes	ldns_pkt_set_ad(new_pkt, ldns_pkt_ad(pkt));
977238104Sdes	ldns_pkt_set_opcode(new_pkt, ldns_pkt_get_opcode(pkt));
978238104Sdes	ldns_pkt_set_rcode(new_pkt, ldns_pkt_get_rcode(pkt));
979238104Sdes	ldns_pkt_set_qdcount(new_pkt, ldns_pkt_qdcount(pkt));
980238104Sdes	ldns_pkt_set_ancount(new_pkt, ldns_pkt_ancount(pkt));
981238104Sdes	ldns_pkt_set_nscount(new_pkt, ldns_pkt_nscount(pkt));
982238104Sdes	ldns_pkt_set_arcount(new_pkt, ldns_pkt_arcount(pkt));
983238104Sdes	ldns_pkt_set_answerfrom(new_pkt, ldns_pkt_answerfrom(pkt));
984238104Sdes	ldns_pkt_set_querytime(new_pkt, ldns_pkt_querytime(pkt));
985238104Sdes	ldns_pkt_set_size(new_pkt, ldns_pkt_size(pkt));
986238104Sdes	ldns_pkt_set_tsig(new_pkt, ldns_rr_clone(ldns_pkt_tsig(pkt)));
987238104Sdes
988238104Sdes	ldns_pkt_set_edns_udp_size(new_pkt, ldns_pkt_edns_udp_size(pkt));
989238104Sdes	ldns_pkt_set_edns_extended_rcode(new_pkt,
990238104Sdes		ldns_pkt_edns_extended_rcode(pkt));
991238104Sdes	ldns_pkt_set_edns_version(new_pkt, ldns_pkt_edns_version(pkt));
992238104Sdes	ldns_pkt_set_edns_z(new_pkt, ldns_pkt_edns_z(pkt));
993238104Sdes	if(ldns_pkt_edns_data(pkt))
994238104Sdes		ldns_pkt_set_edns_data(new_pkt,
995238104Sdes			ldns_rdf_clone(ldns_pkt_edns_data(pkt)));
996238104Sdes	ldns_pkt_set_edns_do(new_pkt, ldns_pkt_edns_do(pkt));
997238104Sdes
998238104Sdes	ldns_rr_list_deep_free(new_pkt->_question);
999238104Sdes	ldns_rr_list_deep_free(new_pkt->_answer);
1000238104Sdes	ldns_rr_list_deep_free(new_pkt->_authority);
1001238104Sdes	ldns_rr_list_deep_free(new_pkt->_additional);
1002238104Sdes	new_pkt->_question = ldns_rr_list_clone(ldns_pkt_question(pkt));
1003238104Sdes	new_pkt->_answer = ldns_rr_list_clone(ldns_pkt_answer(pkt));
1004238104Sdes	new_pkt->_authority = ldns_rr_list_clone(ldns_pkt_authority(pkt));
1005238104Sdes	new_pkt->_additional = ldns_rr_list_clone(ldns_pkt_additional(pkt));
1006238104Sdes	return new_pkt;
1007238104Sdes}
1008