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