resolver.c revision 246827
1238104Sdes/*
2238104Sdes * resolver.c
3238104Sdes *
4238104Sdes * resolver 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#include <strings.h>
17238104Sdes
18238104Sdes/* Access function for reading
19238104Sdes * and setting the different Resolver
20238104Sdes * options */
21238104Sdes
22238104Sdes/* read */
23238104Sdesuint16_t
24238104Sdesldns_resolver_port(const ldns_resolver *r)
25238104Sdes{
26238104Sdes	return r->_port;
27238104Sdes}
28238104Sdes
29238104Sdesuint16_t
30238104Sdesldns_resolver_edns_udp_size(const ldns_resolver *r)
31238104Sdes{
32238104Sdes	        return r->_edns_udp_size;
33238104Sdes}
34238104Sdes
35238104Sdesuint8_t
36238104Sdesldns_resolver_retry(const ldns_resolver *r)
37238104Sdes{
38238104Sdes	return r->_retry;
39238104Sdes}
40238104Sdes
41238104Sdesuint8_t
42238104Sdesldns_resolver_retrans(const ldns_resolver *r)
43238104Sdes{
44238104Sdes	return r->_retrans;
45238104Sdes}
46238104Sdes
47238104Sdesbool
48238104Sdesldns_resolver_fallback(const ldns_resolver *r)
49238104Sdes{
50238104Sdes	return r->_fallback;
51238104Sdes}
52238104Sdes
53238104Sdesuint8_t
54238104Sdesldns_resolver_ip6(const ldns_resolver *r)
55238104Sdes{
56238104Sdes	return r->_ip6;
57238104Sdes}
58238104Sdes
59238104Sdesbool
60238104Sdesldns_resolver_recursive(const ldns_resolver *r)
61238104Sdes{
62238104Sdes	return r->_recursive;
63238104Sdes}
64238104Sdes
65238104Sdesbool
66238104Sdesldns_resolver_debug(const ldns_resolver *r)
67238104Sdes{
68238104Sdes	return r->_debug;
69238104Sdes}
70238104Sdes
71238104Sdesbool
72238104Sdesldns_resolver_dnsrch(const ldns_resolver *r)
73238104Sdes{
74238104Sdes	return r->_dnsrch;
75238104Sdes}
76238104Sdes
77238104Sdesbool
78238104Sdesldns_resolver_fail(const ldns_resolver *r)
79238104Sdes{
80238104Sdes	return r->_fail;
81238104Sdes}
82238104Sdes
83238104Sdesbool
84238104Sdesldns_resolver_defnames(const ldns_resolver *r)
85238104Sdes{
86238104Sdes	return r->_defnames;
87238104Sdes}
88238104Sdes
89238104Sdesldns_rdf *
90238104Sdesldns_resolver_domain(const ldns_resolver *r)
91238104Sdes{
92238104Sdes	return r->_domain;
93238104Sdes}
94238104Sdes
95238104Sdesldns_rdf **
96238104Sdesldns_resolver_searchlist(const ldns_resolver *r)
97238104Sdes{
98238104Sdes	return r->_searchlist;
99238104Sdes}
100238104Sdes
101238104Sdesldns_rdf **
102238104Sdesldns_resolver_nameservers(const ldns_resolver *r)
103238104Sdes{
104238104Sdes	return r->_nameservers;
105238104Sdes}
106238104Sdes
107238104Sdessize_t
108238104Sdesldns_resolver_nameserver_count(const ldns_resolver *r)
109238104Sdes{
110238104Sdes	return r->_nameserver_count;
111238104Sdes}
112238104Sdes
113238104Sdesbool
114238104Sdesldns_resolver_dnssec(const ldns_resolver *r)
115238104Sdes{
116238104Sdes	return r->_dnssec;
117238104Sdes}
118238104Sdes
119238104Sdesbool
120238104Sdesldns_resolver_dnssec_cd(const ldns_resolver *r)
121238104Sdes{
122238104Sdes	return r->_dnssec_cd;
123238104Sdes}
124238104Sdes
125238104Sdesldns_rr_list *
126238104Sdesldns_resolver_dnssec_anchors(const ldns_resolver *r)
127238104Sdes{
128238104Sdes    return r->_dnssec_anchors;
129238104Sdes}
130238104Sdes
131238104Sdesbool
132238104Sdesldns_resolver_trusted_key(const ldns_resolver *r, ldns_rr_list * keys, ldns_rr_list * trusted_keys)
133238104Sdes{
134238104Sdes  size_t i;
135238104Sdes  bool result = false;
136238104Sdes
137238104Sdes  ldns_rr_list * trust_anchors;
138238104Sdes  ldns_rr * cur_rr;
139238104Sdes
140238104Sdes  if (!r || !keys) { return false; }
141238104Sdes
142238104Sdes  trust_anchors = ldns_resolver_dnssec_anchors(r);
143238104Sdes
144238104Sdes  if (!trust_anchors) { return false; }
145238104Sdes
146238104Sdes  for (i = 0; i < ldns_rr_list_rr_count(keys); i++) {
147238104Sdes
148238104Sdes    cur_rr = ldns_rr_list_rr(keys, i);
149238104Sdes    if (ldns_rr_list_contains_rr(trust_anchors, cur_rr)) {
150238104Sdes      if (trusted_keys) { ldns_rr_list_push_rr(trusted_keys, cur_rr); }
151238104Sdes      result = true;
152238104Sdes    }
153238104Sdes  }
154238104Sdes
155238104Sdes  return result;
156238104Sdes}
157238104Sdes
158238104Sdesbool
159238104Sdesldns_resolver_igntc(const ldns_resolver *r)
160238104Sdes{
161238104Sdes	return r->_igntc;
162238104Sdes}
163238104Sdes
164238104Sdesbool
165238104Sdesldns_resolver_usevc(const ldns_resolver *r)
166238104Sdes{
167238104Sdes	return r->_usevc;
168238104Sdes}
169238104Sdes
170238104Sdessize_t *
171238104Sdesldns_resolver_rtt(const ldns_resolver *r)
172238104Sdes{
173238104Sdes	return r->_rtt;
174238104Sdes}
175238104Sdes
176238104Sdessize_t
177238104Sdesldns_resolver_nameserver_rtt(const ldns_resolver *r, size_t pos)
178238104Sdes{
179238104Sdes	size_t *rtt;
180238104Sdes
181238104Sdes	assert(r != NULL);
182238104Sdes
183238104Sdes	rtt = ldns_resolver_rtt(r);
184238104Sdes
185238104Sdes	if (pos >= ldns_resolver_nameserver_count(r)) {
186238104Sdes		/* error ?*/
187238104Sdes		return 0;
188238104Sdes	} else {
189238104Sdes		return rtt[pos];
190238104Sdes	}
191238104Sdes
192238104Sdes}
193238104Sdes
194238104Sdesstruct timeval
195238104Sdesldns_resolver_timeout(const ldns_resolver *r)
196238104Sdes{
197238104Sdes	return r->_timeout;
198238104Sdes}
199238104Sdes
200238104Sdeschar *
201238104Sdesldns_resolver_tsig_keyname(const ldns_resolver *r)
202238104Sdes{
203238104Sdes	return r->_tsig_keyname;
204238104Sdes}
205238104Sdes
206238104Sdeschar *
207238104Sdesldns_resolver_tsig_algorithm(const ldns_resolver *r)
208238104Sdes{
209238104Sdes	return r->_tsig_algorithm;
210238104Sdes}
211238104Sdes
212238104Sdeschar *
213238104Sdesldns_resolver_tsig_keydata(const ldns_resolver *r)
214238104Sdes{
215238104Sdes	return r->_tsig_keydata;
216238104Sdes}
217238104Sdes
218238104Sdesbool
219238104Sdesldns_resolver_random(const ldns_resolver *r)
220238104Sdes{
221238104Sdes	return r->_random;
222238104Sdes}
223238104Sdes
224238104Sdessize_t
225238104Sdesldns_resolver_searchlist_count(const ldns_resolver *r)
226238104Sdes{
227238104Sdes	return r->_searchlist_count;
228238104Sdes}
229238104Sdes
230238104Sdes/* write */
231238104Sdesvoid
232238104Sdesldns_resolver_set_port(ldns_resolver *r, uint16_t p)
233238104Sdes{
234238104Sdes	r->_port = p;
235238104Sdes}
236238104Sdes
237238104Sdesldns_rdf *
238238104Sdesldns_resolver_pop_nameserver(ldns_resolver *r)
239238104Sdes{
240238104Sdes	ldns_rdf **nameservers;
241238104Sdes	ldns_rdf *pop;
242238104Sdes	size_t ns_count;
243238104Sdes	size_t *rtt;
244238104Sdes
245238104Sdes	assert(r != NULL);
246238104Sdes
247238104Sdes	ns_count = ldns_resolver_nameserver_count(r);
248238104Sdes	nameservers = ldns_resolver_nameservers(r);
249238104Sdes	rtt = ldns_resolver_rtt(r);
250238104Sdes	if (ns_count == 0 || !nameservers) {
251238104Sdes		return NULL;
252238104Sdes	}
253238104Sdes
254238104Sdes	pop = nameservers[ns_count - 1];
255238104Sdes
256238104Sdes	nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, (ns_count - 1));
257238104Sdes	rtt = LDNS_XREALLOC(rtt, size_t, (ns_count - 1));
258238104Sdes
259238104Sdes        if(nameservers)
260238104Sdes	        ldns_resolver_set_nameservers(r, nameservers);
261238104Sdes        if(rtt)
262238104Sdes	        ldns_resolver_set_rtt(r, rtt);
263238104Sdes	/* decr the count */
264238104Sdes	ldns_resolver_dec_nameserver_count(r);
265238104Sdes	return pop;
266238104Sdes}
267238104Sdes
268238104Sdesldns_status
269238104Sdesldns_resolver_push_nameserver(ldns_resolver *r, ldns_rdf *n)
270238104Sdes{
271238104Sdes	ldns_rdf **nameservers;
272238104Sdes	size_t ns_count;
273238104Sdes	size_t *rtt;
274238104Sdes
275238104Sdes	if (ldns_rdf_get_type(n) != LDNS_RDF_TYPE_A &&
276238104Sdes			ldns_rdf_get_type(n) != LDNS_RDF_TYPE_AAAA) {
277238104Sdes		return LDNS_STATUS_ERR;
278238104Sdes	}
279238104Sdes
280238104Sdes	ns_count = ldns_resolver_nameserver_count(r);
281238104Sdes	nameservers = ldns_resolver_nameservers(r);
282238104Sdes	rtt = ldns_resolver_rtt(r);
283238104Sdes
284238104Sdes	/* make room for the next one */
285238104Sdes	if (ns_count == 0) {
286238104Sdes		nameservers = LDNS_XMALLOC(ldns_rdf *, 1);
287238104Sdes	} else {
288238104Sdes		nameservers = LDNS_XREALLOC(nameservers, ldns_rdf *, (ns_count + 1));
289238104Sdes	}
290238104Sdes        if(!nameservers)
291238104Sdes                return LDNS_STATUS_MEM_ERR;
292238104Sdes
293238104Sdes	/* set the new value in the resolver */
294238104Sdes	ldns_resolver_set_nameservers(r, nameservers);
295238104Sdes
296238104Sdes	/* don't forget the rtt */
297238104Sdes	if (ns_count == 0) {
298238104Sdes		rtt = LDNS_XMALLOC(size_t, 1);
299238104Sdes	} else {
300238104Sdes		rtt = LDNS_XREALLOC(rtt, size_t, (ns_count + 1));
301238104Sdes	}
302238104Sdes        if(!rtt)
303238104Sdes                return LDNS_STATUS_MEM_ERR;
304238104Sdes
305238104Sdes	/* slide n in its slot. */
306238104Sdes	/* we clone it here, because then we can free the original
307238104Sdes	 * rr's where it stood */
308238104Sdes	nameservers[ns_count] = ldns_rdf_clone(n);
309238104Sdes	rtt[ns_count] = LDNS_RESOLV_RTT_MIN;
310238104Sdes	ldns_resolver_incr_nameserver_count(r);
311238104Sdes	ldns_resolver_set_rtt(r, rtt);
312238104Sdes	return LDNS_STATUS_OK;
313238104Sdes}
314238104Sdes
315238104Sdesldns_status
316238104Sdesldns_resolver_push_nameserver_rr(ldns_resolver *r, ldns_rr *rr)
317238104Sdes{
318238104Sdes	ldns_rdf *address;
319238104Sdes	if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_A &&
320238104Sdes			ldns_rr_get_type(rr) != LDNS_RR_TYPE_AAAA)) {
321238104Sdes		return LDNS_STATUS_ERR;
322238104Sdes	}
323238104Sdes	address = ldns_rr_rdf(rr, 0); /* extract the ip number */
324238104Sdes	if (address) {
325238104Sdes		return ldns_resolver_push_nameserver(r, address);
326238104Sdes	} else {
327238104Sdes		return LDNS_STATUS_ERR;
328238104Sdes	}
329238104Sdes}
330238104Sdes
331238104Sdesldns_status
332238104Sdesldns_resolver_push_nameserver_rr_list(ldns_resolver *r, ldns_rr_list *rrlist)
333238104Sdes{
334238104Sdes	ldns_rr *rr;
335238104Sdes	ldns_status stat;
336238104Sdes	size_t i;
337238104Sdes
338238104Sdes	stat = LDNS_STATUS_OK;
339238104Sdes	if (rrlist) {
340238104Sdes		for(i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
341238104Sdes			rr = ldns_rr_list_rr(rrlist, i);
342238104Sdes			if (ldns_resolver_push_nameserver_rr(r, rr) != LDNS_STATUS_OK) {
343238104Sdes				stat = LDNS_STATUS_ERR;
344238104Sdes				break;
345238104Sdes			}
346238104Sdes		}
347238104Sdes		return stat;
348238104Sdes	} else {
349238104Sdes		return LDNS_STATUS_ERR;
350238104Sdes	}
351238104Sdes}
352238104Sdes
353238104Sdesvoid
354238104Sdesldns_resolver_set_edns_udp_size(ldns_resolver *r, uint16_t s)
355238104Sdes{
356238104Sdes	        r->_edns_udp_size = s;
357238104Sdes}
358238104Sdes
359238104Sdesvoid
360238104Sdesldns_resolver_set_recursive(ldns_resolver *r, bool re)
361238104Sdes{
362238104Sdes	r->_recursive = re;
363238104Sdes}
364238104Sdes
365238104Sdesvoid
366238104Sdesldns_resolver_set_dnssec(ldns_resolver *r, bool d)
367238104Sdes{
368238104Sdes	r->_dnssec = d;
369238104Sdes}
370238104Sdes
371238104Sdesvoid
372238104Sdesldns_resolver_set_dnssec_cd(ldns_resolver *r, bool d)
373238104Sdes{
374238104Sdes	r->_dnssec_cd = d;
375238104Sdes}
376238104Sdes
377238104Sdesvoid
378238104Sdesldns_resolver_set_dnssec_anchors(ldns_resolver *r, ldns_rr_list * l)
379238104Sdes{
380238104Sdes  r->_dnssec_anchors = l;
381238104Sdes}
382238104Sdes
383238104Sdesldns_status
384238104Sdesldns_resolver_push_dnssec_anchor(ldns_resolver *r, ldns_rr *rr)
385238104Sdes{
386238104Sdes  ldns_rr_list * trust_anchors;
387238104Sdes
388238104Sdes  if ((!rr) || (ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY)) {
389238104Sdes    return LDNS_STATUS_ERR;
390238104Sdes  }
391238104Sdes
392238104Sdes  if (!(trust_anchors = ldns_resolver_dnssec_anchors(r))) { /* Initialize */
393238104Sdes    trust_anchors = ldns_rr_list_new();
394238104Sdes    ldns_resolver_set_dnssec_anchors(r, trust_anchors);
395238104Sdes  }
396238104Sdes
397238104Sdes  return (ldns_rr_list_push_rr(trust_anchors, ldns_rr_clone(rr))) ? LDNS_STATUS_OK : LDNS_STATUS_ERR;
398238104Sdes}
399238104Sdes
400238104Sdesvoid
401238104Sdesldns_resolver_set_igntc(ldns_resolver *r, bool i)
402238104Sdes{
403238104Sdes	r->_igntc = i;
404238104Sdes}
405238104Sdes
406238104Sdesvoid
407238104Sdesldns_resolver_set_usevc(ldns_resolver *r, bool vc)
408238104Sdes{
409238104Sdes	r->_usevc = vc;
410238104Sdes}
411238104Sdes
412238104Sdesvoid
413238104Sdesldns_resolver_set_debug(ldns_resolver *r, bool d)
414238104Sdes{
415238104Sdes	r->_debug = d;
416238104Sdes}
417238104Sdes
418238104Sdesvoid
419238104Sdesldns_resolver_set_ip6(ldns_resolver *r, uint8_t ip6)
420238104Sdes{
421238104Sdes	r->_ip6 = ip6;
422238104Sdes}
423238104Sdes
424238104Sdesvoid
425238104Sdesldns_resolver_set_fail(ldns_resolver *r, bool f)
426238104Sdes{
427238104Sdes	r->_fail =f;
428238104Sdes}
429238104Sdes
430246827Sdesstatic void
431238104Sdesldns_resolver_set_searchlist_count(ldns_resolver *r, size_t c)
432238104Sdes{
433238104Sdes	r->_searchlist_count = c;
434238104Sdes}
435238104Sdes
436238104Sdesvoid
437238104Sdesldns_resolver_set_nameserver_count(ldns_resolver *r, size_t c)
438238104Sdes{
439238104Sdes	r->_nameserver_count = c;
440238104Sdes}
441238104Sdes
442238104Sdesvoid
443238104Sdesldns_resolver_set_dnsrch(ldns_resolver *r, bool d)
444238104Sdes{
445238104Sdes	r->_dnsrch = d;
446238104Sdes}
447238104Sdes
448238104Sdesvoid
449238104Sdesldns_resolver_set_retry(ldns_resolver *r, uint8_t retry)
450238104Sdes{
451238104Sdes	r->_retry = retry;
452238104Sdes}
453238104Sdes
454238104Sdesvoid
455238104Sdesldns_resolver_set_retrans(ldns_resolver *r, uint8_t retrans)
456238104Sdes{
457238104Sdes	r->_retrans = retrans;
458238104Sdes}
459238104Sdes
460238104Sdesvoid
461238104Sdesldns_resolver_set_fallback(ldns_resolver *r, bool fallback)
462238104Sdes{
463238104Sdes	r->_fallback = fallback;
464238104Sdes}
465238104Sdes
466238104Sdesvoid
467238104Sdesldns_resolver_set_nameservers(ldns_resolver *r, ldns_rdf **n)
468238104Sdes{
469238104Sdes	r->_nameservers = n;
470238104Sdes}
471238104Sdes
472238104Sdesvoid
473238104Sdesldns_resolver_set_defnames(ldns_resolver *r, bool d)
474238104Sdes{
475238104Sdes	r->_defnames = d;
476238104Sdes}
477238104Sdes
478238104Sdesvoid
479238104Sdesldns_resolver_set_rtt(ldns_resolver *r, size_t *rtt)
480238104Sdes{
481238104Sdes	r->_rtt = rtt;
482238104Sdes}
483238104Sdes
484238104Sdesvoid
485238104Sdesldns_resolver_set_nameserver_rtt(ldns_resolver *r, size_t pos, size_t value)
486238104Sdes{
487238104Sdes	size_t *rtt;
488238104Sdes
489238104Sdes	assert(r != NULL);
490238104Sdes
491238104Sdes	rtt = ldns_resolver_rtt(r);
492238104Sdes
493238104Sdes	if (pos >= ldns_resolver_nameserver_count(r)) {
494238104Sdes		/* error ?*/
495238104Sdes	} else {
496238104Sdes		rtt[pos] = value;
497238104Sdes	}
498238104Sdes
499238104Sdes}
500238104Sdes
501238104Sdesvoid
502238104Sdesldns_resolver_incr_nameserver_count(ldns_resolver *r)
503238104Sdes{
504238104Sdes	size_t c;
505238104Sdes
506238104Sdes	c = ldns_resolver_nameserver_count(r);
507238104Sdes	ldns_resolver_set_nameserver_count(r, ++c);
508238104Sdes}
509238104Sdes
510238104Sdesvoid
511238104Sdesldns_resolver_dec_nameserver_count(ldns_resolver *r)
512238104Sdes{
513238104Sdes	size_t c;
514238104Sdes
515238104Sdes	c = ldns_resolver_nameserver_count(r);
516238104Sdes	if (c == 0) {
517238104Sdes		return;
518238104Sdes	} else {
519238104Sdes		ldns_resolver_set_nameserver_count(r, --c);
520238104Sdes	}
521238104Sdes}
522238104Sdes
523238104Sdesvoid
524238104Sdesldns_resolver_set_domain(ldns_resolver *r, ldns_rdf *d)
525238104Sdes{
526238104Sdes	r->_domain = d;
527238104Sdes}
528238104Sdes
529238104Sdesvoid
530238104Sdesldns_resolver_set_timeout(ldns_resolver *r, struct timeval timeout)
531238104Sdes{
532238104Sdes	r->_timeout.tv_sec = timeout.tv_sec;
533238104Sdes	r->_timeout.tv_usec = timeout.tv_usec;
534238104Sdes}
535238104Sdes
536238104Sdesvoid
537238104Sdesldns_resolver_push_searchlist(ldns_resolver *r, ldns_rdf *d)
538238104Sdes{
539238104Sdes	ldns_rdf **searchlist;
540238104Sdes	size_t list_count;
541238104Sdes
542238104Sdes	if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
543238104Sdes		return;
544238104Sdes	}
545238104Sdes
546238104Sdes	list_count = ldns_resolver_searchlist_count(r);
547238104Sdes	searchlist = ldns_resolver_searchlist(r);
548238104Sdes
549238104Sdes	searchlist = LDNS_XREALLOC(searchlist, ldns_rdf *, (list_count + 1));
550238104Sdes	if (searchlist) {
551238104Sdes		r->_searchlist = searchlist;
552238104Sdes
553238104Sdes		searchlist[list_count] = ldns_rdf_clone(d);
554238104Sdes		ldns_resolver_set_searchlist_count(r, list_count + 1);
555238104Sdes	} /* no way to report mem err */
556238104Sdes}
557238104Sdes
558238104Sdesvoid
559238104Sdesldns_resolver_set_tsig_keyname(ldns_resolver *r, char *tsig_keyname)
560238104Sdes{
561238104Sdes	LDNS_FREE(r->_tsig_keyname);
562238104Sdes	r->_tsig_keyname = strdup(tsig_keyname);
563238104Sdes}
564238104Sdes
565238104Sdesvoid
566238104Sdesldns_resolver_set_tsig_algorithm(ldns_resolver *r, char *tsig_algorithm)
567238104Sdes{
568238104Sdes	LDNS_FREE(r->_tsig_algorithm);
569238104Sdes	r->_tsig_algorithm = strdup(tsig_algorithm);
570238104Sdes}
571238104Sdes
572238104Sdesvoid
573238104Sdesldns_resolver_set_tsig_keydata(ldns_resolver *r, char *tsig_keydata)
574238104Sdes{
575238104Sdes	LDNS_FREE(r->_tsig_keydata);
576238104Sdes	r->_tsig_keydata = strdup(tsig_keydata);
577238104Sdes}
578238104Sdes
579238104Sdesvoid
580238104Sdesldns_resolver_set_random(ldns_resolver *r, bool b)
581238104Sdes{
582238104Sdes	r->_random = b;
583238104Sdes}
584238104Sdes
585238104Sdes/* more sophisticated functions */
586238104Sdesldns_resolver *
587238104Sdesldns_resolver_new(void)
588238104Sdes{
589238104Sdes	ldns_resolver *r;
590238104Sdes
591238104Sdes	r = LDNS_MALLOC(ldns_resolver);
592238104Sdes	if (!r) {
593238104Sdes		return NULL;
594238104Sdes	}
595238104Sdes
596238104Sdes	r->_searchlist = NULL;
597238104Sdes	r->_nameservers = NULL;
598238104Sdes	r->_rtt = NULL;
599238104Sdes
600238104Sdes	/* defaults are filled out */
601238104Sdes	ldns_resolver_set_searchlist_count(r, 0);
602238104Sdes	ldns_resolver_set_nameserver_count(r, 0);
603238104Sdes	ldns_resolver_set_usevc(r, 0);
604238104Sdes	ldns_resolver_set_port(r, LDNS_PORT);
605238104Sdes	ldns_resolver_set_domain(r, NULL);
606238104Sdes	ldns_resolver_set_defnames(r, false);
607238104Sdes	ldns_resolver_set_retry(r, 3);
608238104Sdes	ldns_resolver_set_retrans(r, 2);
609238104Sdes	ldns_resolver_set_fallback(r, true);
610238104Sdes	ldns_resolver_set_fail(r, false);
611238104Sdes	ldns_resolver_set_edns_udp_size(r, 0);
612238104Sdes	ldns_resolver_set_dnssec(r, false);
613238104Sdes	ldns_resolver_set_dnssec_cd(r, false);
614238104Sdes	ldns_resolver_set_dnssec_anchors(r, NULL);
615238104Sdes	ldns_resolver_set_ip6(r, LDNS_RESOLV_INETANY);
616238104Sdes	ldns_resolver_set_igntc(r, false);
617238104Sdes	ldns_resolver_set_recursive(r, false);
618238104Sdes	ldns_resolver_set_dnsrch(r, true);
619238104Sdes
620238104Sdes	/* randomize the nameserver to be queried
621238104Sdes	 * when there are multiple
622238104Sdes	 */
623238104Sdes	ldns_resolver_set_random(r, true);
624238104Sdes
625238104Sdes	ldns_resolver_set_debug(r, 0);
626238104Sdes
627238104Sdes	r->_timeout.tv_sec = LDNS_DEFAULT_TIMEOUT_SEC;
628238104Sdes	r->_timeout.tv_usec = LDNS_DEFAULT_TIMEOUT_USEC;
629238104Sdes
630238104Sdes	/* TODO: fd=0 is actually a valid socket (stdin),
631238104Sdes           replace with -1 */
632238104Sdes	r->_socket = 0;
633238104Sdes	r->_axfr_soa_count = 0;
634238104Sdes	r->_axfr_i = 0;
635238104Sdes	r->_cur_axfr_pkt = NULL;
636238104Sdes
637238104Sdes	r->_tsig_keyname = NULL;
638238104Sdes	r->_tsig_keydata = NULL;
639238104Sdes	r->_tsig_algorithm = NULL;
640238104Sdes	return r;
641238104Sdes}
642238104Sdes
643238104Sdesldns_status
644238104Sdesldns_resolver_new_frm_fp(ldns_resolver **res, FILE *fp)
645238104Sdes{
646238104Sdes	return ldns_resolver_new_frm_fp_l(res, fp, NULL);
647238104Sdes}
648238104Sdes
649238104Sdesldns_status
650238104Sdesldns_resolver_new_frm_fp_l(ldns_resolver **res, FILE *fp, int *line_nr)
651238104Sdes{
652238104Sdes	ldns_resolver *r;
653238104Sdes	const char *keyword[LDNS_RESOLV_KEYWORDS];
654238104Sdes	char word[LDNS_MAX_LINELEN + 1];
655238104Sdes	int8_t expect;
656238104Sdes	uint8_t i;
657238104Sdes	ldns_rdf *tmp;
658238104Sdes#ifdef HAVE_SSL
659238104Sdes	ldns_rr *tmp_rr;
660238104Sdes#endif
661238104Sdes	ssize_t gtr, bgtr;
662238104Sdes	ldns_buffer *b;
663238104Sdes        int lnr = 0, oldline;
664238104Sdes        if(!line_nr) line_nr = &lnr;
665238104Sdes
666238104Sdes	/* do this better
667238104Sdes	 * expect =
668238104Sdes	 * 0: keyword
669238104Sdes	 * 1: default domain dname
670238104Sdes	 * 2: NS aaaa or a record
671238104Sdes	 */
672238104Sdes
673238104Sdes	/* recognized keywords */
674238104Sdes	keyword[LDNS_RESOLV_NAMESERVER] = "nameserver";
675238104Sdes	keyword[LDNS_RESOLV_DEFDOMAIN] = "domain";
676238104Sdes	keyword[LDNS_RESOLV_SEARCH] = "search";
677238104Sdes	/* these two are read but not used atm TODO */
678238104Sdes	keyword[LDNS_RESOLV_SORTLIST] = "sortlist";
679238104Sdes	keyword[LDNS_RESOLV_OPTIONS] = "options";
680238104Sdes	keyword[LDNS_RESOLV_ANCHOR] = "anchor";
681238104Sdes	expect = LDNS_RESOLV_KEYWORD;
682238104Sdes
683238104Sdes	r = ldns_resolver_new();
684238104Sdes	if (!r) {
685238104Sdes		return LDNS_STATUS_MEM_ERR;
686238104Sdes	}
687238104Sdes
688238104Sdes	gtr = 1;
689238104Sdes	word[0] = 0;
690238104Sdes        oldline = *line_nr;
691238104Sdes        expect = LDNS_RESOLV_KEYWORD;
692238104Sdes	while (gtr > 0) {
693238104Sdes		/* check comments */
694238104Sdes		if (word[0] == '#') {
695238104Sdes                        word[0]='x';
696238104Sdes                        if(oldline == *line_nr) {
697238104Sdes                                /* skip until end of line */
698238104Sdes                                int c;
699238104Sdes                                do {
700238104Sdes                                        c = fgetc(fp);
701238104Sdes                                } while(c != EOF && c != '\n');
702238104Sdes                                if(c=='\n' && line_nr) (*line_nr)++;
703238104Sdes                        }
704238104Sdes			/* and read next to prepare for further parsing */
705238104Sdes                        oldline = *line_nr;
706238104Sdes			continue;
707238104Sdes		}
708238104Sdes                oldline = *line_nr;
709238104Sdes		switch(expect) {
710238104Sdes			case LDNS_RESOLV_KEYWORD:
711238104Sdes				/* keyword */
712238104Sdes				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
713238104Sdes				if (gtr != 0) {
714238104Sdes                                        if(word[0] == '#') continue;
715238104Sdes					for(i = 0; i < LDNS_RESOLV_KEYWORDS; i++) {
716238104Sdes						if (strcasecmp(keyword[i], word) == 0) {
717238104Sdes							/* chosen the keyword and
718238104Sdes							 * expect values carefully
719238104Sdes	        					 */
720238104Sdes							expect = i;
721238104Sdes							break;
722238104Sdes						}
723238104Sdes					}
724238104Sdes					/* no keyword recognized */
725238104Sdes					if (expect == LDNS_RESOLV_KEYWORD) {
726238104Sdes						/* skip line */
727238104Sdes						/*
728238104Sdes						ldns_resolver_deep_free(r);
729238104Sdes						return LDNS_STATUS_SYNTAX_KEYWORD_ERR;
730238104Sdes						*/
731238104Sdes					}
732238104Sdes				}
733238104Sdes				break;
734238104Sdes			case LDNS_RESOLV_DEFDOMAIN:
735238104Sdes				/* default domain dname */
736238104Sdes				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
737238104Sdes				if (gtr == 0) {
738238104Sdes					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
739238104Sdes				}
740238104Sdes                                if(word[0] == '#') {
741238104Sdes                                        expect = LDNS_RESOLV_KEYWORD;
742238104Sdes                                        continue;
743238104Sdes                                }
744238104Sdes				tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
745238104Sdes				if (!tmp) {
746238104Sdes					ldns_resolver_deep_free(r);
747238104Sdes					return LDNS_STATUS_SYNTAX_DNAME_ERR;
748238104Sdes				}
749238104Sdes
750238104Sdes				/* DOn't free, because we copy the pointer */
751238104Sdes				ldns_resolver_set_domain(r, tmp);
752238104Sdes				expect = LDNS_RESOLV_KEYWORD;
753238104Sdes				break;
754238104Sdes			case LDNS_RESOLV_NAMESERVER:
755238104Sdes				/* NS aaaa or a record */
756238104Sdes				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
757238104Sdes				if (gtr == 0) {
758238104Sdes					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
759238104Sdes				}
760238104Sdes                                if(word[0] == '#') {
761238104Sdes                                        expect = LDNS_RESOLV_KEYWORD;
762238104Sdes                                        continue;
763238104Sdes                                }
764238104Sdes                                if(strchr(word, '%')) {
765238104Sdes                                        /* snip off interface labels,
766238104Sdes                                         * fe80::222:19ff:fe31:4222%eth0 */
767238104Sdes                                        strchr(word, '%')[0]=0;
768238104Sdes                                }
769238104Sdes				tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, word);
770238104Sdes				if (!tmp) {
771238104Sdes					/* try ip4 */
772238104Sdes					tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, word);
773238104Sdes				}
774238104Sdes				/* could not parse it, exit */
775238104Sdes				if (!tmp) {
776238104Sdes					ldns_resolver_deep_free(r);
777238104Sdes					return LDNS_STATUS_SYNTAX_ERR;
778238104Sdes				}
779238104Sdes				(void)ldns_resolver_push_nameserver(r, tmp);
780238104Sdes				ldns_rdf_deep_free(tmp);
781238104Sdes				expect = LDNS_RESOLV_KEYWORD;
782238104Sdes				break;
783238104Sdes			case LDNS_RESOLV_SEARCH:
784238104Sdes				/* search list domain dname */
785238104Sdes				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
786238104Sdes				b = LDNS_MALLOC(ldns_buffer);
787238104Sdes				if(!b) {
788238104Sdes					ldns_resolver_deep_free(r);
789238104Sdes					return LDNS_STATUS_MEM_ERR;
790238104Sdes				}
791238104Sdes
792238104Sdes				ldns_buffer_new_frm_data(b, word, (size_t) gtr);
793238104Sdes				if(ldns_buffer_status(b) != LDNS_STATUS_OK) {
794238104Sdes					LDNS_FREE(b);
795238104Sdes					ldns_resolver_deep_free(r);
796238104Sdes					return LDNS_STATUS_MEM_ERR;
797238104Sdes				}
798238104Sdes				bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL, (size_t) gtr + 1);
799238104Sdes				while (bgtr > 0) {
800238104Sdes					gtr -= bgtr;
801238104Sdes                                        if(word[0] == '#') {
802238104Sdes                                                expect = LDNS_RESOLV_KEYWORD;
803238104Sdes						ldns_buffer_free(b);
804238104Sdes                                                continue;
805238104Sdes                                        }
806238104Sdes					tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, word);
807238104Sdes					if (!tmp) {
808238104Sdes						ldns_resolver_deep_free(r);
809238104Sdes						ldns_buffer_free(b);
810238104Sdes						return LDNS_STATUS_SYNTAX_DNAME_ERR;
811238104Sdes					}
812238104Sdes
813238104Sdes					ldns_resolver_push_searchlist(r, tmp);
814238104Sdes
815238104Sdes					ldns_rdf_deep_free(tmp);
816238104Sdes					bgtr = ldns_bget_token(b, word, LDNS_PARSE_NORMAL,
817238104Sdes					    (size_t) gtr + 1);
818238104Sdes				}
819238104Sdes				ldns_buffer_free(b);
820238104Sdes				gtr = 1;
821238104Sdes				expect = LDNS_RESOLV_KEYWORD;
822238104Sdes				break;
823238104Sdes			case LDNS_RESOLV_SORTLIST:
824238104Sdes				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
825238104Sdes				/* sortlist not implemented atm */
826238104Sdes				expect = LDNS_RESOLV_KEYWORD;
827238104Sdes				break;
828238104Sdes			case LDNS_RESOLV_OPTIONS:
829238104Sdes				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_SKIP_SPACE, 0, line_nr);
830238104Sdes				/* options not implemented atm */
831238104Sdes				expect = LDNS_RESOLV_KEYWORD;
832238104Sdes				break;
833238104Sdes			case LDNS_RESOLV_ANCHOR:
834238104Sdes				/* a file containing a DNSSEC trust anchor */
835238104Sdes				gtr = ldns_fget_token_l(fp, word, LDNS_PARSE_NORMAL, 0, line_nr);
836238104Sdes				if (gtr == 0) {
837238104Sdes					ldns_resolver_deep_free(r);
838238104Sdes					return LDNS_STATUS_SYNTAX_MISSING_VALUE_ERR;
839238104Sdes				}
840238104Sdes                                if(word[0] == '#') {
841238104Sdes                                        expect = LDNS_RESOLV_KEYWORD;
842238104Sdes                                        continue;
843238104Sdes                                }
844238104Sdes
845238104Sdes#ifdef HAVE_SSL
846238104Sdes				tmp_rr = ldns_read_anchor_file(word);
847238104Sdes				(void) ldns_resolver_push_dnssec_anchor(r, tmp_rr);
848238104Sdes				ldns_rr_free(tmp_rr);
849238104Sdes#endif
850238104Sdes				expect = LDNS_RESOLV_KEYWORD;
851238104Sdes				break;
852238104Sdes		}
853238104Sdes	}
854238104Sdes
855238104Sdes	if (res) {
856238104Sdes		*res = r;
857238104Sdes		return LDNS_STATUS_OK;
858238104Sdes	} else {
859238104Sdes		ldns_resolver_deep_free(r);
860238104Sdes		return LDNS_STATUS_NULL;
861238104Sdes	}
862238104Sdes}
863238104Sdes
864238104Sdesldns_status
865238104Sdesldns_resolver_new_frm_file(ldns_resolver **res, const char *filename)
866238104Sdes{
867238104Sdes	ldns_resolver *r;
868238104Sdes	FILE *fp;
869238104Sdes	ldns_status s;
870238104Sdes
871238104Sdes	if (!filename) {
872238104Sdes		fp = fopen(LDNS_RESOLV_CONF, "r");
873238104Sdes
874238104Sdes	} else {
875238104Sdes		fp = fopen(filename, "r");
876238104Sdes	}
877238104Sdes	if (!fp) {
878238104Sdes		return LDNS_STATUS_FILE_ERR;
879238104Sdes	}
880238104Sdes
881238104Sdes	s = ldns_resolver_new_frm_fp(&r, fp);
882238104Sdes	fclose(fp);
883238104Sdes	if (s == LDNS_STATUS_OK) {
884238104Sdes		if (res) {
885238104Sdes			*res = r;
886238104Sdes			return LDNS_STATUS_OK;
887238104Sdes		} else  {
888238104Sdes			return LDNS_STATUS_NULL;
889238104Sdes		}
890238104Sdes	}
891238104Sdes	return s;
892238104Sdes}
893238104Sdes
894238104Sdesvoid
895238104Sdesldns_resolver_free(ldns_resolver *res)
896238104Sdes{
897238104Sdes	LDNS_FREE(res);
898238104Sdes}
899238104Sdes
900238104Sdesvoid
901238104Sdesldns_resolver_deep_free(ldns_resolver *res)
902238104Sdes{
903238104Sdes	size_t i;
904238104Sdes
905238104Sdes	if (res) {
906238104Sdes		if (res->_searchlist) {
907238104Sdes			for (i = 0; i < ldns_resolver_searchlist_count(res); i++) {
908238104Sdes				ldns_rdf_deep_free(res->_searchlist[i]);
909238104Sdes			}
910238104Sdes			LDNS_FREE(res->_searchlist);
911238104Sdes		}
912238104Sdes		if (res->_nameservers) {
913238104Sdes			for (i = 0; i < res->_nameserver_count; i++) {
914238104Sdes				ldns_rdf_deep_free(res->_nameservers[i]);
915238104Sdes			}
916238104Sdes			LDNS_FREE(res->_nameservers);
917238104Sdes		}
918238104Sdes		if (ldns_resolver_domain(res)) {
919238104Sdes			ldns_rdf_deep_free(ldns_resolver_domain(res));
920238104Sdes		}
921238104Sdes		if (res->_tsig_keyname) {
922238104Sdes			LDNS_FREE(res->_tsig_keyname);
923238104Sdes		}
924238104Sdes		if (res->_tsig_keydata) {
925238104Sdes			LDNS_FREE(res->_tsig_keydata);
926238104Sdes		}
927238104Sdes		if (res->_tsig_algorithm) {
928238104Sdes			LDNS_FREE(res->_tsig_algorithm);
929238104Sdes		}
930238104Sdes
931238104Sdes		if (res->_cur_axfr_pkt) {
932238104Sdes			ldns_pkt_free(res->_cur_axfr_pkt);
933238104Sdes		}
934238104Sdes
935238104Sdes		if (res->_rtt) {
936238104Sdes			LDNS_FREE(res->_rtt);
937238104Sdes		}
938238104Sdes		if (res->_dnssec_anchors) {
939238104Sdes			ldns_rr_list_deep_free(res->_dnssec_anchors);
940238104Sdes		}
941238104Sdes		LDNS_FREE(res);
942238104Sdes	}
943238104Sdes}
944238104Sdes
945238104Sdesldns_pkt *
946238104Sdesldns_resolver_search(const ldns_resolver *r,const  ldns_rdf *name,
947238104Sdes	ldns_rr_type t, ldns_rr_class c, uint16_t flags)
948238104Sdes{
949238104Sdes
950238104Sdes	char *str_dname;
951238104Sdes	ldns_rdf *new_name;
952238104Sdes	ldns_rdf **search_list;
953238104Sdes	size_t i;
954238104Sdes	ldns_pkt *p;
955238104Sdes
956238104Sdes	str_dname = ldns_rdf2str(name);
957238104Sdes
958238104Sdes	if (ldns_dname_str_absolute(str_dname)) {
959238104Sdes		/* query as-is */
960238104Sdes		return ldns_resolver_query(r, name, t, c, flags);
961238104Sdes	} else if (ldns_resolver_dnsrch(r)) {
962238104Sdes		search_list = ldns_resolver_searchlist(r);
963238104Sdes		for (i = 0; i < ldns_resolver_searchlist_count(r); i++) {
964238104Sdes			new_name = ldns_dname_cat_clone(name, search_list[i]);
965238104Sdes
966238104Sdes			p = ldns_resolver_query(r, new_name, t, c, flags);
967238104Sdes			ldns_rdf_free(new_name);
968238104Sdes			if (p) {
969238104Sdes				if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NOERROR) {
970238104Sdes					return p;
971238104Sdes				} else {
972238104Sdes					ldns_pkt_free(p);
973238104Sdes					p = NULL;
974238104Sdes				}
975238104Sdes			}
976238104Sdes		}
977238104Sdes	}
978238104Sdes	return NULL;
979238104Sdes}
980238104Sdes
981238104Sdesldns_pkt *
982238104Sdesldns_resolver_query(const ldns_resolver *r, const ldns_rdf *name,
983238104Sdes	ldns_rr_type t, ldns_rr_class c, uint16_t flags)
984238104Sdes{
985238104Sdes	ldns_rdf *newname;
986238104Sdes	ldns_pkt *pkt;
987238104Sdes	ldns_status status;
988238104Sdes
989238104Sdes	pkt = NULL;
990238104Sdes
991238104Sdes	if (!ldns_resolver_defnames(r)) {
992238104Sdes		status = ldns_resolver_send(&pkt, (ldns_resolver *)r, name,
993238104Sdes				t, c, flags);
994238104Sdes		if (status == LDNS_STATUS_OK) {
995238104Sdes			return pkt;
996238104Sdes		} else {
997238104Sdes			if (pkt) {
998238104Sdes				ldns_pkt_free(pkt);
999238104Sdes			}
1000238104Sdes			return NULL;
1001238104Sdes		}
1002238104Sdes	}
1003238104Sdes
1004238104Sdes	if (!ldns_resolver_domain(r)) {
1005238104Sdes		/* _defnames is set, but the domain is not....?? */
1006238104Sdes		status = ldns_resolver_send(&pkt, (ldns_resolver *)r, name,
1007238104Sdes				t, c, flags);
1008238104Sdes		if (status == LDNS_STATUS_OK) {
1009238104Sdes			return pkt;
1010238104Sdes		} else {
1011238104Sdes			if (pkt) {
1012238104Sdes				ldns_pkt_free(pkt);
1013238104Sdes			}
1014238104Sdes			return NULL;
1015238104Sdes		}
1016238104Sdes	}
1017238104Sdes
1018238104Sdes	newname = ldns_dname_cat_clone((const ldns_rdf*)name, ldns_resolver_domain(r));
1019238104Sdes	if (!newname) {
1020238104Sdes		if (pkt) {
1021238104Sdes			ldns_pkt_free(pkt);
1022238104Sdes		}
1023238104Sdes		return NULL;
1024238104Sdes	}
1025238104Sdes
1026238104Sdes	(void)ldns_resolver_send(&pkt, (ldns_resolver *)r, newname, t, c,
1027238104Sdes			flags);
1028238104Sdes
1029238104Sdes	ldns_rdf_free(newname);
1030238104Sdes
1031238104Sdes	return pkt;
1032238104Sdes}
1033238104Sdes
1034238104Sdesstatic size_t *
1035238104Sdesldns_resolver_backup_rtt(ldns_resolver *r)
1036238104Sdes{
1037238104Sdes	size_t *new_rtt;
1038238104Sdes	size_t *old_rtt = ldns_resolver_rtt(r);
1039238104Sdes
1040238104Sdes	if (old_rtt && ldns_resolver_nameserver_count(r)) {
1041238104Sdes		new_rtt = LDNS_XMALLOC(size_t
1042238104Sdes				, ldns_resolver_nameserver_count(r));
1043238104Sdes		memcpy(new_rtt, old_rtt, sizeof(size_t)
1044238104Sdes				* ldns_resolver_nameserver_count(r));
1045238104Sdes		ldns_resolver_set_rtt(r, new_rtt);
1046238104Sdes		return old_rtt;
1047238104Sdes	}
1048238104Sdes	return NULL;
1049238104Sdes}
1050238104Sdes
1051238104Sdesstatic void
1052238104Sdesldns_resolver_restore_rtt(ldns_resolver *r, size_t *old_rtt)
1053238104Sdes{
1054238104Sdes	size_t *cur_rtt = ldns_resolver_rtt(r);
1055238104Sdes
1056238104Sdes	if (cur_rtt) {
1057238104Sdes		LDNS_FREE(cur_rtt);
1058238104Sdes	}
1059238104Sdes	ldns_resolver_set_rtt(r, old_rtt);
1060238104Sdes}
1061238104Sdes
1062238104Sdesldns_status
1063238104Sdesldns_resolver_send_pkt(ldns_pkt **answer, ldns_resolver *r,
1064238104Sdes				   ldns_pkt *query_pkt)
1065238104Sdes{
1066238104Sdes	ldns_pkt *answer_pkt = NULL;
1067238104Sdes	ldns_status stat = LDNS_STATUS_OK;
1068238104Sdes	size_t *rtt;
1069238104Sdes
1070238104Sdes	stat = ldns_send(&answer_pkt, (ldns_resolver *)r, query_pkt);
1071238104Sdes	if (stat != LDNS_STATUS_OK) {
1072238104Sdes		if(answer_pkt) {
1073238104Sdes			ldns_pkt_free(answer_pkt);
1074238104Sdes			answer_pkt = NULL;
1075238104Sdes		}
1076238104Sdes	} else {
1077238104Sdes		/* if tc=1 fall back to EDNS and/or TCP */
1078238104Sdes		/* check for tcp first (otherwise we don't care about tc=1) */
1079238104Sdes		if (!ldns_resolver_usevc(r) && ldns_resolver_fallback(r)) {
1080238104Sdes			if (ldns_pkt_tc(answer_pkt)) {
1081238104Sdes				/* was EDNS0 set? */
1082238104Sdes				if (ldns_pkt_edns_udp_size(query_pkt) == 0) {
1083238104Sdes					ldns_pkt_set_edns_udp_size(query_pkt
1084238104Sdes							, 4096);
1085238104Sdes					ldns_pkt_free(answer_pkt);
1086238104Sdes					/* Nameservers should not become
1087238104Sdes					 * unreachable because fragments are
1088238104Sdes					 * dropped (network error). We might
1089238104Sdes					 * still have success with TCP.
1090238104Sdes					 * Therefore maintain reachability
1091238104Sdes					 * statuses of the nameservers by
1092238104Sdes					 * backup and restore the rtt list.
1093238104Sdes					 */
1094238104Sdes					rtt = ldns_resolver_backup_rtt(r);
1095238104Sdes					stat = ldns_send(&answer_pkt, r
1096238104Sdes							, query_pkt);
1097238104Sdes					ldns_resolver_restore_rtt(r, rtt);
1098238104Sdes				}
1099238104Sdes				/* either way, if it is still truncated, use TCP */
1100238104Sdes				if (stat != LDNS_STATUS_OK ||
1101238104Sdes				    ldns_pkt_tc(answer_pkt)) {
1102238104Sdes					ldns_resolver_set_usevc(r, true);
1103238104Sdes					ldns_pkt_free(answer_pkt);
1104238104Sdes					stat = ldns_send(&answer_pkt, r, query_pkt);
1105238104Sdes					ldns_resolver_set_usevc(r, false);
1106238104Sdes				}
1107238104Sdes			}
1108238104Sdes		}
1109238104Sdes	}
1110238104Sdes
1111238104Sdes	if (answer) {
1112238104Sdes		*answer = answer_pkt;
1113238104Sdes	}
1114238104Sdes
1115238104Sdes	return stat;
1116238104Sdes}
1117238104Sdes
1118238104Sdesldns_status
1119238104Sdesldns_resolver_prepare_query_pkt(ldns_pkt **query_pkt, ldns_resolver *r,
1120238104Sdes                                const ldns_rdf *name, ldns_rr_type t,
1121238104Sdes                                ldns_rr_class c, uint16_t flags)
1122238104Sdes{
1123238104Sdes	struct timeval now;
1124238104Sdes
1125238104Sdes	/* prepare a question pkt from the parameters
1126238104Sdes	 * and then send this */
1127238104Sdes	*query_pkt = ldns_pkt_query_new(ldns_rdf_clone(name), t, c, flags);
1128238104Sdes	if (!*query_pkt) {
1129238104Sdes		return LDNS_STATUS_ERR;
1130238104Sdes	}
1131238104Sdes
1132238104Sdes	/* set DO bit if necessary */
1133238104Sdes	if (ldns_resolver_dnssec(r)) {
1134238104Sdes		if (ldns_resolver_edns_udp_size(r) == 0) {
1135238104Sdes			ldns_resolver_set_edns_udp_size(r, 4096);
1136238104Sdes		}
1137238104Sdes		ldns_pkt_set_edns_do(*query_pkt, true);
1138238104Sdes		if (ldns_resolver_dnssec_cd(r) || (flags & LDNS_CD)) {
1139238104Sdes			ldns_pkt_set_cd(*query_pkt, true);
1140238104Sdes		}
1141238104Sdes	}
1142238104Sdes
1143238104Sdes	/* transfer the udp_edns_size from the resolver to the packet */
1144238104Sdes	if (ldns_resolver_edns_udp_size(r) != 0) {
1145238104Sdes		ldns_pkt_set_edns_udp_size(*query_pkt, ldns_resolver_edns_udp_size(r));
1146238104Sdes	}
1147238104Sdes
1148238104Sdes	/* set the timestamp */
1149238104Sdes	now.tv_sec = time(NULL);
1150238104Sdes	now.tv_usec = 0;
1151238104Sdes	ldns_pkt_set_timestamp(*query_pkt, now);
1152238104Sdes
1153238104Sdes
1154238104Sdes	if (ldns_resolver_debug(r)) {
1155238104Sdes		ldns_pkt_print(stdout, *query_pkt);
1156238104Sdes	}
1157238104Sdes
1158238104Sdes	/* only set the id if it is not set yet */
1159238104Sdes	if (ldns_pkt_id(*query_pkt) == 0) {
1160238104Sdes		ldns_pkt_set_random_id(*query_pkt);
1161238104Sdes	}
1162238104Sdes
1163238104Sdes	return LDNS_STATUS_OK;
1164238104Sdes}
1165238104Sdes
1166238104Sdes
1167238104Sdesldns_status
1168238104Sdesldns_resolver_send(ldns_pkt **answer, ldns_resolver *r, const ldns_rdf *name,
1169238104Sdes		ldns_rr_type t, ldns_rr_class c, uint16_t flags)
1170238104Sdes{
1171238104Sdes	ldns_pkt *query_pkt;
1172238104Sdes	ldns_pkt *answer_pkt;
1173238104Sdes	ldns_status status;
1174238104Sdes
1175238104Sdes	assert(r != NULL);
1176238104Sdes	assert(name != NULL);
1177238104Sdes
1178238104Sdes	answer_pkt = NULL;
1179238104Sdes
1180238104Sdes	/* do all the preprocessing here, then fire of an query to
1181238104Sdes	 * the network */
1182238104Sdes
1183238104Sdes	if (0 == t) {
1184238104Sdes		t= LDNS_RR_TYPE_A;
1185238104Sdes	}
1186238104Sdes	if (0 == c) {
1187238104Sdes		c= LDNS_RR_CLASS_IN;
1188238104Sdes	}
1189238104Sdes	if (0 == ldns_resolver_nameserver_count(r)) {
1190238104Sdes		return LDNS_STATUS_RES_NO_NS;
1191238104Sdes	}
1192238104Sdes	if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) {
1193238104Sdes		return LDNS_STATUS_RES_QUERY;
1194238104Sdes	}
1195238104Sdes
1196238104Sdes	status = ldns_resolver_prepare_query_pkt(&query_pkt, r, name,
1197238104Sdes	                                         t, c, flags);
1198238104Sdes	if (status != LDNS_STATUS_OK) {
1199238104Sdes		return status;
1200238104Sdes	}
1201238104Sdes
1202238104Sdes	/* if tsig values are set, tsign it */
1203238104Sdes	/* TODO: make last 3 arguments optional too? maybe make complete
1204238104Sdes	         rr instead of seperate values in resolver (and packet)
1205238104Sdes	  Jelte
1206238104Sdes	  should this go in pkt_prepare?
1207238104Sdes	*/
1208238104Sdes	if (ldns_resolver_tsig_keyname(r) && ldns_resolver_tsig_keydata(r)) {
1209238104Sdes#ifdef HAVE_SSL
1210238104Sdes		status = ldns_pkt_tsig_sign(query_pkt,
1211238104Sdes		                            ldns_resolver_tsig_keyname(r),
1212238104Sdes		                            ldns_resolver_tsig_keydata(r),
1213238104Sdes		                            300, ldns_resolver_tsig_algorithm(r), NULL);
1214238104Sdes		if (status != LDNS_STATUS_OK) {
1215238104Sdes			return LDNS_STATUS_CRYPTO_TSIG_ERR;
1216238104Sdes		}
1217238104Sdes#else
1218238104Sdes	        return LDNS_STATUS_CRYPTO_TSIG_ERR;
1219238104Sdes#endif /* HAVE_SSL */
1220238104Sdes	}
1221238104Sdes
1222238104Sdes	status = ldns_resolver_send_pkt(&answer_pkt, r, query_pkt);
1223238104Sdes	ldns_pkt_free(query_pkt);
1224238104Sdes
1225238104Sdes	/* allows answer to be NULL when not interested in return value */
1226238104Sdes	if (answer) {
1227238104Sdes		*answer = answer_pkt;
1228238104Sdes	}
1229238104Sdes	return status;
1230238104Sdes}
1231238104Sdes
1232238104Sdesldns_rr *
1233238104Sdesldns_axfr_next(ldns_resolver *resolver)
1234238104Sdes{
1235238104Sdes	ldns_rr *cur_rr;
1236238104Sdes	uint8_t *packet_wire;
1237238104Sdes	size_t packet_wire_size;
1238238104Sdes	ldns_lookup_table *rcode;
1239238104Sdes	ldns_status status;
1240238104Sdes
1241238104Sdes	/* check if start() has been called */
1242238104Sdes	if (!resolver || resolver->_socket == 0) {
1243238104Sdes		return NULL;
1244238104Sdes	}
1245238104Sdes
1246238104Sdes	if (resolver->_cur_axfr_pkt) {
1247238104Sdes		if (resolver->_axfr_i == ldns_pkt_ancount(resolver->_cur_axfr_pkt)) {
1248238104Sdes			ldns_pkt_free(resolver->_cur_axfr_pkt);
1249238104Sdes			resolver->_cur_axfr_pkt = NULL;
1250238104Sdes			return ldns_axfr_next(resolver);
1251238104Sdes		}
1252238104Sdes		cur_rr = ldns_rr_clone(ldns_rr_list_rr(
1253238104Sdes					ldns_pkt_answer(resolver->_cur_axfr_pkt),
1254238104Sdes					resolver->_axfr_i));
1255238104Sdes		resolver->_axfr_i++;
1256238104Sdes		if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_SOA) {
1257238104Sdes			resolver->_axfr_soa_count++;
1258238104Sdes			if (resolver->_axfr_soa_count >= 2) {
1259238104Sdes#ifndef USE_WINSOCK
1260238104Sdes				close(resolver->_socket);
1261238104Sdes#else
1262238104Sdes				closesocket(resolver->_socket);
1263238104Sdes#endif
1264238104Sdes				resolver->_socket = 0;
1265238104Sdes				ldns_pkt_free(resolver->_cur_axfr_pkt);
1266238104Sdes				resolver->_cur_axfr_pkt = NULL;
1267238104Sdes			}
1268238104Sdes		}
1269238104Sdes		return cur_rr;
1270238104Sdes	} else {
1271238104Sdes		packet_wire = ldns_tcp_read_wire(resolver->_socket, &packet_wire_size);
1272238104Sdes		if(!packet_wire)
1273238104Sdes			return NULL;
1274238104Sdes
1275238104Sdes		status = ldns_wire2pkt(&resolver->_cur_axfr_pkt, packet_wire,
1276238104Sdes				     packet_wire_size);
1277238104Sdes		LDNS_FREE(packet_wire);
1278238104Sdes
1279238104Sdes		resolver->_axfr_i = 0;
1280238104Sdes		if (status != LDNS_STATUS_OK) {
1281238104Sdes			/* TODO: make status return type of this function (...api change) */
1282238104Sdes			fprintf(stderr, "Error parsing rr during AXFR: %s\n", ldns_get_errorstr_by_id(status));
1283238104Sdes
1284238104Sdes			/* RoRi: we must now also close the socket, otherwise subsequent uses of the
1285238104Sdes			   same resolver structure will fail because the link is still open or
1286238104Sdes			   in an undefined state */
1287238104Sdes#ifndef USE_WINSOCK
1288238104Sdes			close(resolver->_socket);
1289238104Sdes#else
1290238104Sdes			closesocket(resolver->_socket);
1291238104Sdes#endif
1292238104Sdes			resolver->_socket = 0;
1293238104Sdes
1294238104Sdes			return NULL;
1295238104Sdes		} else if (ldns_pkt_get_rcode(resolver->_cur_axfr_pkt) != 0) {
1296238104Sdes			rcode = ldns_lookup_by_id(ldns_rcodes, (int) ldns_pkt_get_rcode(resolver->_cur_axfr_pkt));
1297238104Sdes			fprintf(stderr, "Error in AXFR: %s\n", rcode->name);
1298238104Sdes
1299238104Sdes			/* RoRi: we must now also close the socket, otherwise subsequent uses of the
1300238104Sdes			   same resolver structure will fail because the link is still open or
1301238104Sdes			   in an undefined state */
1302238104Sdes#ifndef USE_WINSOCK
1303238104Sdes			close(resolver->_socket);
1304238104Sdes#else
1305238104Sdes			closesocket(resolver->_socket);
1306238104Sdes#endif
1307238104Sdes			resolver->_socket = 0;
1308238104Sdes
1309238104Sdes			return NULL;
1310238104Sdes		} else {
1311238104Sdes			return ldns_axfr_next(resolver);
1312238104Sdes		}
1313238104Sdes
1314238104Sdes	}
1315238104Sdes
1316238104Sdes}
1317238104Sdes
1318238104Sdesbool
1319238104Sdesldns_axfr_complete(const ldns_resolver *res)
1320238104Sdes{
1321238104Sdes	/* complete when soa count is 2? */
1322238104Sdes	return res->_axfr_soa_count == 2;
1323238104Sdes}
1324238104Sdes
1325238104Sdesldns_pkt *
1326238104Sdesldns_axfr_last_pkt(const ldns_resolver *res)
1327238104Sdes{
1328238104Sdes	return res->_cur_axfr_pkt;
1329238104Sdes}
1330238104Sdes
1331238104Sdes/* random isn't really that good */
1332238104Sdesvoid
1333238104Sdesldns_resolver_nameservers_randomize(ldns_resolver *r)
1334238104Sdes{
1335238104Sdes	uint16_t i, j;
1336238104Sdes	ldns_rdf **ns, *tmp;
1337238104Sdes
1338238104Sdes	/* should I check for ldns_resolver_random?? */
1339238104Sdes	assert(r != NULL);
1340238104Sdes
1341238104Sdes	ns = ldns_resolver_nameservers(r);
1342238104Sdes	for (i = 0; i < ldns_resolver_nameserver_count(r); i++) {
1343238104Sdes		j = ldns_get_random() % ldns_resolver_nameserver_count(r);
1344238104Sdes		tmp = ns[i];
1345238104Sdes		ns[i] = ns[j];
1346238104Sdes		ns[j] = tmp;
1347238104Sdes	}
1348238104Sdes	ldns_resolver_set_nameservers(r, ns);
1349238104Sdes}
1350238104Sdes
1351