Initial vendor import of ldns-1.6.4 into contrib.
[dragonfly.git] / contrib / ldns / drill / chasetrace.c
1 /*
2  * chasetrace.c
3  * Where all the hard work concerning chasing
4  * and tracing is done
5  * (c) 2005, 2006 NLnet Labs
6  *
7  * See the file LICENSE for the license
8  *
9  */
10
11 #include "drill.h"
12 #include <ldns/ldns.h>
13
14 /**
15  * trace down from the root to name
16  */
17
18 /* same naive method as in drill0.9 
19  * We resolver _ALL_ the names, which is ofcourse not needed
20  * We _do_ use the local resolver to do that, so it still is
21  * fast, but it can be made to run much faster
22  */
23 ldns_pkt *
24 do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
25                 ldns_rr_class c)
26 {
27         ldns_resolver *res;
28         ldns_pkt *p;
29         ldns_rr_list *new_nss_a;
30         ldns_rr_list *new_nss_aaaa;
31         ldns_rr_list *final_answer;
32         ldns_rr_list *new_nss;
33         ldns_rr_list *hostnames;
34         ldns_rr_list *ns_addr;
35         uint16_t loop_count;
36         ldns_rdf *pop; 
37         ldns_status status;
38         size_t i;
39         
40         loop_count = 0;
41         new_nss_a = NULL;
42         new_nss_aaaa = NULL;
43         new_nss = NULL;
44         ns_addr = NULL;
45         final_answer = NULL;
46         p = ldns_pkt_new();
47         res = ldns_resolver_new();
48
49         if (!p || !res) {
50                 error("Memory allocation failed");
51                 return NULL;
52         }
53
54         /* transfer some properties of local_res to res,
55          * because they were given on the commandline */
56         ldns_resolver_set_ip6(res, 
57                         ldns_resolver_ip6(local_res));
58         ldns_resolver_set_port(res, 
59                         ldns_resolver_port(local_res));
60         ldns_resolver_set_debug(res, 
61                         ldns_resolver_debug(local_res));
62         ldns_resolver_set_dnssec(res, 
63                         ldns_resolver_dnssec(local_res));
64         ldns_resolver_set_fail(res, 
65                         ldns_resolver_fail(local_res));
66         ldns_resolver_set_usevc(res, 
67                         ldns_resolver_usevc(local_res));
68         ldns_resolver_set_random(res, 
69                         ldns_resolver_random(local_res));
70         ldns_resolver_set_recursive(res, false);
71
72         /* setup the root nameserver in the new resolver */
73         status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
74         if (status != LDNS_STATUS_OK) {
75                 fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status));
76                 ldns_rr_list_print(stdout, global_dns_root);
77                 return NULL;
78         }
79
80         /* this must be a real query to local_res */
81         status = ldns_resolver_send(&p, res, ldns_dname_new_frm_str("."), LDNS_RR_TYPE_NS, c, 0);
82         /* p can still be NULL */
83
84
85         if (ldns_pkt_empty(p)) {
86                 warning("No root server information received");
87         } 
88         
89         if (status == LDNS_STATUS_OK) {
90                 if (!ldns_pkt_empty(p)) {
91                         drill_pkt_print(stdout, local_res, p);
92                 }
93         } else {
94                 error("cannot use local resolver");
95                 return NULL;
96         }
97
98         status = ldns_resolver_send(&p, res, name, t, c, 0);
99
100         while(status == LDNS_STATUS_OK && 
101               ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
102
103                 if (!p) {
104                         /* some error occurred, bail out */
105                         return NULL;
106                 }
107
108                 new_nss_a = ldns_pkt_rr_list_by_type(p,
109                                 LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
110                 new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
111                                 LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
112                 new_nss = ldns_pkt_rr_list_by_type(p,
113                                 LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
114
115                 if (verbosity != -1) {
116                         ldns_rr_list_print(stdout, new_nss);
117                 }
118                 /* checks itself for verbosity */
119                 drill_pkt_print_footer(stdout, local_res, p);
120                 
121                 /* remove the old nameserver from the resolver */
122                 while((pop = ldns_resolver_pop_nameserver(res))) { /* do it */ }
123
124                 /* also check for new_nss emptyness */
125
126                 if (!new_nss_aaaa && !new_nss_a) {
127                         /* 
128                          * no nameserver found!!! 
129                          * try to resolve the names we do got 
130                          */
131                         for(i = 0; i < ldns_rr_list_rr_count(new_nss); i++) {
132                                 /* get the name of the nameserver */
133                                 pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
134                                 if (!pop) {
135                                         break;
136                                 }
137
138                                 ldns_rr_list_print(stdout, new_nss);
139                                 ldns_rdf_print(stdout, pop);
140                                 /* retrieve it's addresses */
141                                 ns_addr = ldns_rr_list_cat_clone(ns_addr,
142                                         ldns_get_rr_list_addr_by_name(local_res, pop, c, 0));
143                         }
144
145                         if (ns_addr) {
146                                 if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) != 
147                                                 LDNS_STATUS_OK) {
148                                         error("Error adding new nameservers");
149                                         ldns_pkt_free(p); 
150                                         return NULL;
151                                 }
152                                 ldns_rr_list_free(ns_addr);
153                         } else {
154                                 ldns_rr_list_print(stdout, ns_addr);
155                                 error("Could not find the nameserver ip addr; abort");
156                                 ldns_pkt_free(p);
157                                 return NULL;
158                         }
159                 }
160
161                 /* add the new ones */
162                 if (new_nss_aaaa) {
163                         if (ldns_resolver_push_nameserver_rr_list(res, new_nss_aaaa) != 
164                                         LDNS_STATUS_OK) {
165                                 error("adding new nameservers");
166                                 ldns_pkt_free(p); 
167                                 return NULL;
168                         }
169                 }
170                 if (new_nss_a) {
171                         if (ldns_resolver_push_nameserver_rr_list(res, new_nss_a) != 
172                                         LDNS_STATUS_OK) {
173                                 error("adding new nameservers");
174                                 ldns_pkt_free(p); 
175                                 return NULL;
176                         }
177                 }
178
179                 if (loop_count++ > 20) {
180                         /* unlikely that we are doing something usefull */
181                         error("Looks like we are looping");
182                         ldns_pkt_free(p); 
183                         return NULL;
184                 }
185                 
186                 status = ldns_resolver_send(&p, res, name, t, c, 0);
187                 new_nss_aaaa = NULL;
188                 new_nss_a = NULL;
189                 ns_addr = NULL;
190         }
191
192         status = ldns_resolver_send(&p, res, name, t, c, 0);
193
194         if (!p) {
195                 return NULL;
196         }
197
198         hostnames = ldns_get_rr_list_name_by_addr(local_res, 
199                         ldns_pkt_answerfrom(p), 0, 0);
200
201         new_nss = ldns_pkt_authority(p);
202         final_answer = ldns_pkt_answer(p);
203
204         if (verbosity != -1) {
205                 ldns_rr_list_print(stdout, final_answer);
206                 ldns_rr_list_print(stdout, new_nss);
207
208         }
209         drill_pkt_print_footer(stdout, local_res, p);
210         ldns_pkt_free(p); 
211         return NULL;
212 }
213
214
215 /**
216  * Chase the given rr to a known and trusted key
217  *
218  * Based on drill 0.9
219  *
220  * the last argument prev_key_list, if not null, and type == DS, then the ds
221  * rr list we have must all be a ds for the keys in this list
222  */
223 #ifdef HAVE_SSL
224 ldns_status
225 do_chase(ldns_resolver *res,
226             ldns_rdf *name,
227             ldns_rr_type type,
228             ldns_rr_class c,
229             ldns_rr_list *trusted_keys,
230             ldns_pkt *pkt_o,
231             uint16_t qflags,
232             ldns_rr_list *prev_key_list,
233             int verbosity)
234 {
235         ldns_rr_list *rrset = NULL;
236         ldns_status result;
237         ldns_rr *orig_rr = NULL;
238         
239         bool cname_followed = false;
240 /*
241         ldns_rr_list *sigs;
242         ldns_rr *cur_sig;
243         uint16_t sig_i;
244         ldns_rr_list *keys;
245 */
246         ldns_pkt *pkt;
247         ldns_status tree_result;
248         ldns_dnssec_data_chain *chain;
249         ldns_dnssec_trust_tree *tree;
250         
251         const ldns_rr_descriptor *descriptor;
252         descriptor = ldns_rr_descript(type);
253
254         ldns_dname2canonical(name);
255         
256         pkt = ldns_pkt_clone(pkt_o);
257         if (!name) {
258                 mesg("No name to chase");
259                 ldns_pkt_free(pkt);
260                 return LDNS_STATUS_EMPTY_LABEL;
261         }
262         if (verbosity != -1) {
263                 printf(";; Chasing: ");
264                         ldns_rdf_print(stdout, name);
265                         if (descriptor && descriptor->_name) {
266                                 printf(" %s\n", descriptor->_name);
267                         } else {
268                                 printf(" type %d\n", type);
269                         }
270         }
271
272         if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
273                 warning("No trusted keys specified");
274         }
275         
276         if (pkt) {
277                 rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
278                                 name,
279                                 type,
280                                 LDNS_SECTION_ANSWER
281                                 );
282                 if (!rrset) {
283                         /* nothing in answer, try authority */
284                         rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
285                                         name,
286                                         type,
287                                         LDNS_SECTION_AUTHORITY
288                                         );
289                 }
290                 /* answer might be a cname, chase that first, then chase
291                    cname target? (TODO) */
292                 if (!rrset) {
293                         cname_followed = true;
294                         rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
295                                         name,
296                                         LDNS_RR_TYPE_CNAME,
297                                         LDNS_SECTION_ANSWER
298                                         );
299                         if (!rrset) {
300                                 /* nothing in answer, try authority */
301                                 rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
302                                                 name,
303                                                 LDNS_RR_TYPE_CNAME,
304                                                 LDNS_SECTION_AUTHORITY
305                                                 );
306                         }
307                 }
308         } else {
309                 /* no packet? */
310                 if (verbosity >= 0) {
311                         fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
312                         fprintf(stderr, "\n");
313                 }
314                 return LDNS_STATUS_MEM_ERR;
315         }
316         
317         if (!rrset) {
318                 /* not found in original packet, try again */
319                 ldns_pkt_free(pkt);
320                 pkt = NULL;
321                 pkt = ldns_resolver_query(res, name, type, c, qflags);
322                 
323                 if (!pkt) {
324                         if (verbosity >= 0) {
325                                 fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
326                                 fprintf(stderr, "\n");
327                         }
328                         return LDNS_STATUS_NETWORK_ERR;
329                 }
330                 if (verbosity >= 5) {
331                         ldns_pkt_print(stdout, pkt);
332                 }
333                 
334                 rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
335                                 name,
336                                 type,
337                                 LDNS_SECTION_ANSWER
338                                 );
339         }
340         
341         orig_rr = ldns_rr_new();
342
343 /* if the answer had no answer section, we need to construct our own rr (for instance if
344  * the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */
345         if (ldns_pkt_ancount(pkt) < 1) {
346                 ldns_rr_set_type(orig_rr, type);
347                 ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name));
348         
349                 chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr));
350         } else {
351                 /* chase the first answer */
352                 chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL);
353         }
354
355         if (verbosity >= 4) {
356                 printf("\n\nDNSSEC Data Chain:\n");
357                 ldns_dnssec_data_chain_print(stdout, chain);
358         }
359         
360         result = LDNS_STATUS_OK;
361
362         tree = ldns_dnssec_derive_trust_tree(chain, NULL);
363
364         if (verbosity >= 2) {
365                 printf("\n\nDNSSEC Trust tree:\n");
366                 ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
367         }
368
369         if (ldns_rr_list_rr_count(trusted_keys) > 0) {
370                 tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);
371
372                 if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
373                         if (verbosity >= 1) {
374                                 printf("Existence denied or verifiably insecure\n");
375                         }
376                         result = LDNS_STATUS_OK;
377                 } else if (tree_result != LDNS_STATUS_OK) {
378                         if (verbosity >= 1) {
379                                 printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result));
380                         }
381                         result = tree_result;
382                 }
383
384         } else {
385                 if (verbosity >= 0) {
386                         printf("You have not provided any trusted keys.\n");
387                 }
388         }
389         
390         ldns_rr_free(orig_rr);
391         ldns_dnssec_trust_tree_free(tree);
392         ldns_dnssec_data_chain_deep_free(chain);
393         
394         ldns_rr_list_deep_free(rrset);
395         ldns_pkt_free(pkt);
396         /*      ldns_rr_free(orig_rr);*/
397
398         return result;
399 }
400 #endif /* HAVE_SSL */
401