Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/ldns/drill/chasetrace.c
39482 views
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
/* Cache all RRs from rr_list "rr_list" to "referrals" database for lookup
15
* later on. Print the NS RRs that were not already present.
16
*/
17
static void add_rr_list_to_referrals(
18
ldns_dnssec_zone *referrals, ldns_rr_list *rr_list)
19
{
20
size_t i;
21
ldns_rr *rr;
22
ldns_dnssec_rrsets *rrset;
23
ldns_dnssec_rrs *rrs;
24
25
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
26
rr = ldns_rr_list_rr(rr_list, i);
27
/* Check if a RR equal to "rr" is present in "referrals" */
28
rrset = ldns_dnssec_zone_find_rrset(
29
referrals, ldns_rr_owner(rr), ldns_rr_get_type(rr));
30
if (rrset) {
31
for (rrs = rrset->rrs; rrs; rrs = rrs->next)
32
if (ldns_rr_compare(rr, rrs->rr) == 0)
33
break;
34
if (rrs) continue; /* "rr" is present, next! */
35
}
36
if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS && verbosity != -1)
37
ldns_rr_print(stdout, rr);
38
(void) ldns_dnssec_zone_add_rr(referrals, rr);
39
}
40
}
41
42
/* Cache all RRs from packet "p" to "referrals" database for lookup later on.
43
* Print the NS RRs that were not already present.
44
*/
45
static void add_referrals(ldns_dnssec_zone *referrals, ldns_pkt *p)
46
{
47
ldns_rr_list *l = ldns_pkt_all_noquestion(p);
48
if (l) {
49
add_rr_list_to_referrals(referrals, l);
50
ldns_rr_list_free(l);
51
}
52
}
53
54
/* Equip name-server "res" with the name-servers authoritative for as much
55
* of "name" as possible. Lookup addresses if needed.
56
*/
57
static bool set_nss_for_name(
58
ldns_resolver *res, ldns_dnssec_zone *referrals, ldns_rdf *name,
59
ldns_resolver *local_res, ldns_rr_class c)
60
{
61
ldns_dnssec_rrsets *nss = NULL;
62
ldns_dnssec_rrs *nss_rrs;
63
ldns_dnssec_rrsets *as = NULL;
64
ldns_dnssec_rrs *as_rrs;
65
ldns_rdf *lookup = ldns_rdf_clone(name);
66
ldns_rdf *new_lookup;
67
ldns_rdf *addr;
68
ldns_rr_list *addrs;
69
70
/* nss will become the rrset of as much of "name" as possible */
71
for (;;) {
72
nss = ldns_dnssec_zone_find_rrset(
73
referrals, lookup, LDNS_RR_TYPE_NS);
74
if (nss != NULL) {
75
ldns_rdf_deep_free(lookup);
76
break;
77
}
78
new_lookup = ldns_dname_left_chop(lookup);
79
ldns_rdf_deep_free(lookup);
80
lookup = new_lookup;
81
if (!lookup) {
82
error("No referrals for name found");
83
return false;
84
}
85
}
86
87
/* remove the old nameserver from the resolver */
88
while ((addr = ldns_resolver_pop_nameserver(res)))
89
ldns_rdf_deep_free(addr);
90
91
/* Find and add the address records for the rrset as name-servers */
92
for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
93
94
if ((as = ldns_dnssec_zone_find_rrset(
95
referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_A)))
96
for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
97
(void) ldns_resolver_push_nameserver(
98
res, ldns_rr_rdf(as_rrs->rr, 0));
99
100
if ((as = ldns_dnssec_zone_find_rrset(
101
referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_AAAA)))
102
for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
103
(void) ldns_resolver_push_nameserver(
104
res, ldns_rr_rdf(as_rrs->rr, 0));
105
}
106
/* Is our resolver equipped with name-servers? Good! We're done */
107
if (ldns_resolver_nameserver_count(res) > 0)
108
return true;
109
110
/* Lookup addresses with local resolver add add to "referrals" database */
111
addrs = ldns_rr_list_new();
112
for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
113
ldns_rr_list *addrs_by_name =
114
ldns_get_rr_list_addr_by_name(
115
local_res, ldns_rr_rdf(nss_rrs->rr, 0), c, 0);
116
ldns_rr_list_cat(addrs, addrs_by_name);
117
ldns_rr_list_free(addrs_by_name);
118
}
119
120
if (ldns_rr_list_rr_count(addrs) == 0)
121
error("Could not find the nameserver ip addr; abort");
122
123
else if (ldns_resolver_push_nameserver_rr_list(res, addrs) !=
124
LDNS_STATUS_OK)
125
126
error("Error adding new nameservers");
127
else {
128
ldns_rr_list_deep_free(addrs);
129
return true;
130
}
131
add_rr_list_to_referrals(referrals, addrs);
132
ldns_rr_list_deep_free(addrs);
133
return false;
134
}
135
136
/**
137
* trace down from the root to name
138
*/
139
140
/* same naive method as in drill0.9
141
* We resolve _ALL_ the names, which is of course not needed.
142
* We _do_ use the local resolver to do that, so it still is
143
* fast, but it can be made to run much faster.
144
*/
145
void
146
do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
147
ldns_rr_class c)
148
{
149
150
static uint8_t zero[1] = { 0 };
151
static const ldns_rdf root_dname = { 1, LDNS_RDF_TYPE_DNAME, &zero };
152
153
ldns_resolver *res = NULL;
154
ldns_pkt *p = NULL;
155
ldns_rr_list *final_answer;
156
ldns_rr_list *new_nss;
157
ldns_rr_list *cname = NULL;
158
ldns_rr_list *answers = NULL;
159
uint16_t loop_count;
160
ldns_status status;
161
ldns_dnssec_zone* referrals = NULL;
162
ldns_rdf *addr;
163
164
loop_count = 0;
165
final_answer = NULL;
166
res = ldns_resolver_new();
167
168
if (!res) {
169
error("Memory allocation failed");
170
goto cleanup;
171
}
172
173
/* transfer some properties of local_res to res,
174
* because they were given on the command line */
175
ldns_resolver_set_ip6(res,
176
ldns_resolver_ip6(local_res));
177
ldns_resolver_set_port(res,
178
ldns_resolver_port(local_res));
179
ldns_resolver_set_debug(res,
180
ldns_resolver_debug(local_res));
181
ldns_resolver_set_dnssec(res,
182
ldns_resolver_dnssec(local_res));
183
ldns_resolver_set_fail(res,
184
ldns_resolver_fail(local_res));
185
ldns_resolver_set_usevc(res,
186
ldns_resolver_usevc(local_res));
187
ldns_resolver_set_random(res,
188
ldns_resolver_random(local_res));
189
ldns_resolver_set_source(res,
190
ldns_resolver_source(local_res));
191
ldns_resolver_set_recursive(res, false);
192
193
/* setup the root nameserver in the new resolver */
194
status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
195
if (status != LDNS_STATUS_OK) {
196
fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status));
197
ldns_rr_list_print(stdout, global_dns_root);
198
goto cleanup;
199
}
200
201
/* this must be a real query to local_res */
202
status = ldns_resolver_send(&p, res, &root_dname, LDNS_RR_TYPE_NS, c, 0);
203
/* p can still be NULL */
204
205
if (ldns_pkt_empty(p)) {
206
warning("No root server information received");
207
}
208
209
if (status == LDNS_STATUS_OK) {
210
if (!ldns_pkt_empty(p)) {
211
drill_pkt_print(stdout, local_res, p);
212
}
213
referrals = ldns_dnssec_zone_new();
214
add_referrals(referrals, p);
215
} else {
216
error("cannot use local resolver");
217
goto cleanup;
218
}
219
if (! set_nss_for_name(res, referrals, name, local_res, c)) {
220
goto cleanup;
221
}
222
ldns_pkt_free(p);
223
p = NULL;
224
status = ldns_resolver_send(&p, res, name, t, c, 0);
225
while(status == LDNS_STATUS_OK &&
226
ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
227
228
if (!p) {
229
/* some error occurred -- bail out */
230
goto cleanup;
231
}
232
add_referrals(referrals, p);
233
234
/* checks itself for verbosity */
235
drill_pkt_print_footer(stdout, local_res, p);
236
237
if (! set_nss_for_name(res, referrals, name, local_res, c)) {
238
goto cleanup;
239
}
240
if (loop_count++ > 20) {
241
/* unlikely that we are doing anything useful */
242
error("Looks like we are looping");
243
goto cleanup;
244
}
245
ldns_pkt_free(p);
246
p = NULL;
247
status = ldns_resolver_send(&p, res, name, t, c, 0);
248
249
/* Exit trace on error */
250
if (status != LDNS_STATUS_OK)
251
break;
252
253
/* An answer might be the desired answer (and no referral) */
254
if (ldns_pkt_reply_type(p) != LDNS_PACKET_ANSWER)
255
continue;
256
257
/* Exit trace when the requested type is found */
258
answers = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANSWER);
259
if (answers && ldns_rr_list_rr_count(answers) > 0) {
260
ldns_rr_list_free(answers);
261
answers = NULL;
262
break;
263
}
264
ldns_rr_list_free(answers);
265
answers = NULL;
266
267
/* Get the CNAMEs from the answer */
268
cname = ldns_pkt_rr_list_by_type(
269
p, LDNS_RR_TYPE_CNAME, LDNS_SECTION_ANSWER);
270
271
/* No CNAME either: exit trace */
272
if (ldns_rr_list_rr_count(cname) == 0)
273
break;
274
275
/* Print CNAME referral */
276
ldns_rr_list_print(stdout, cname);
277
278
/* restart with the CNAME */
279
name = ldns_rr_rdf(ldns_rr_list_rr(cname, 0), 0);
280
ldns_rr_list_free(cname);
281
cname = NULL;
282
283
/* remove the old nameserver from the resolver */
284
while((addr = ldns_resolver_pop_nameserver(res)))
285
ldns_rdf_deep_free(addr);
286
287
/* Restart trace from the root up */
288
(void) ldns_resolver_push_nameserver_rr_list(
289
res, global_dns_root);
290
291
ldns_pkt_free(p);
292
p = NULL;
293
status = ldns_resolver_send(&p, res, name, t, c, 0);
294
}
295
296
ldns_pkt_free(p);
297
p = NULL;
298
(void) ldns_resolver_send(&p, res, name, t, c, 0);
299
if (!p) {
300
goto cleanup;
301
}
302
new_nss = ldns_pkt_authority(p);
303
final_answer = ldns_pkt_answer(p);
304
305
if (verbosity != -1) {
306
ldns_rr_list_print(stdout, final_answer);
307
ldns_rr_list_print(stdout, new_nss);
308
309
}
310
drill_pkt_print_footer(stdout, local_res, p);
311
cleanup:
312
if (res) {
313
while((addr = ldns_resolver_pop_nameserver(res)))
314
ldns_rdf_deep_free(addr);
315
ldns_resolver_free(res);
316
}
317
if (referrals)
318
ldns_dnssec_zone_deep_free(referrals);
319
if (p)
320
ldns_pkt_free(p);
321
}
322
323
324
/**
325
* Chase the given rr to a known and trusted key
326
*
327
* Based on drill 0.9
328
*
329
* the last argument prev_key_list, if not null, and type == DS, then the ds
330
* rr list we have must all be a ds for the keys in this list
331
*/
332
#ifdef HAVE_SSL
333
ldns_status
334
do_chase(ldns_resolver *res,
335
ldns_rdf *name,
336
ldns_rr_type type,
337
ldns_rr_class c,
338
ldns_rr_list *trusted_keys,
339
ldns_pkt *pkt_o,
340
uint16_t qflags,
341
ldns_rr_list * ATTR_UNUSED(prev_key_list))
342
{
343
ldns_rr_list *rrset = NULL;
344
ldns_status result;
345
ldns_rr *orig_rr = NULL;
346
347
/*
348
ldns_rr_list *sigs;
349
ldns_rr *cur_sig;
350
uint16_t sig_i;
351
ldns_rr_list *keys;
352
*/
353
ldns_pkt *pkt;
354
ldns_status tree_result;
355
ldns_dnssec_data_chain *chain;
356
ldns_dnssec_trust_tree *tree;
357
358
const ldns_rr_descriptor *descriptor;
359
descriptor = ldns_rr_descript(type);
360
361
ldns_dname2canonical(name);
362
363
pkt = ldns_pkt_clone(pkt_o);
364
if (!name) {
365
mesg("No name to chase");
366
ldns_pkt_free(pkt);
367
return LDNS_STATUS_EMPTY_LABEL;
368
}
369
if (verbosity != -1) {
370
printf(";; Chasing: ");
371
ldns_rdf_print(stdout, name);
372
if (descriptor && descriptor->_name) {
373
printf(" %s\n", descriptor->_name);
374
} else {
375
printf(" type %d\n", type);
376
}
377
}
378
379
if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
380
warning("No trusted keys specified");
381
}
382
383
if (pkt) {
384
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
385
name,
386
type,
387
LDNS_SECTION_ANSWER
388
);
389
if (!rrset) {
390
/* nothing in answer, try authority */
391
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
392
name,
393
type,
394
LDNS_SECTION_AUTHORITY
395
);
396
}
397
/* answer might be a cname, chase that first, then chase
398
cname target? (TODO) */
399
if (!rrset) {
400
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
401
name,
402
LDNS_RR_TYPE_CNAME,
403
LDNS_SECTION_ANSWER
404
);
405
if (!rrset) {
406
/* nothing in answer, try authority */
407
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
408
name,
409
LDNS_RR_TYPE_CNAME,
410
LDNS_SECTION_AUTHORITY
411
);
412
}
413
}
414
} else {
415
/* no packet? */
416
if (verbosity >= 0) {
417
fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
418
fprintf(stderr, "\n");
419
}
420
return LDNS_STATUS_MEM_ERR;
421
}
422
423
if (!rrset) {
424
/* not found in original packet, try again */
425
ldns_pkt_free(pkt);
426
pkt = NULL;
427
pkt = ldns_resolver_query(res, name, type, c, qflags);
428
429
if (!pkt) {
430
if (verbosity >= 0) {
431
fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
432
fprintf(stderr, "\n");
433
}
434
return LDNS_STATUS_NETWORK_ERR;
435
}
436
if (verbosity >= 5) {
437
ldns_pkt_print(stdout, pkt);
438
}
439
440
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
441
name,
442
type,
443
LDNS_SECTION_ANSWER
444
);
445
}
446
447
orig_rr = ldns_rr_new();
448
449
/* if the answer had no answer section, we need to construct our own rr (for instance if
450
* the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */
451
if (ldns_pkt_ancount(pkt) < 1) {
452
ldns_rr_set_type(orig_rr, type);
453
ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name));
454
455
chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr));
456
} else {
457
/* chase the first answer */
458
chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL);
459
}
460
461
if (verbosity >= 4) {
462
printf("\n\nDNSSEC Data Chain:\n");
463
ldns_dnssec_data_chain_print(stdout, chain);
464
}
465
466
result = LDNS_STATUS_OK;
467
468
tree = ldns_dnssec_derive_trust_tree(chain, NULL);
469
470
if (verbosity >= 2) {
471
printf("\n\nDNSSEC Trust tree:\n");
472
ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
473
}
474
475
if (ldns_rr_list_rr_count(trusted_keys) > 0) {
476
tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);
477
478
if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
479
if (verbosity >= 1) {
480
printf("Existence denied or verifiably insecure\n");
481
}
482
result = LDNS_STATUS_OK;
483
} else if (tree_result != LDNS_STATUS_OK) {
484
if (verbosity >= 1) {
485
printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result));
486
}
487
result = tree_result;
488
}
489
490
} else {
491
if (verbosity >= 0) {
492
printf("You have not provided any trusted keys.\n");
493
}
494
}
495
496
ldns_rr_free(orig_rr);
497
ldns_dnssec_trust_tree_free(tree);
498
ldns_dnssec_data_chain_deep_free(chain);
499
500
ldns_rr_list_deep_free(rrset);
501
ldns_pkt_free(pkt);
502
/* ldns_rr_free(orig_rr);*/
503
504
return result;
505
}
506
#endif /* HAVE_SSL */
507
508
509