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