fix: populate ldns submodule and add autotools to LDNS build stage

- Re-cloned zonemaster-ldns with --recurse-submodules so the bundled
  ldns C library source (including Changelog and configure.ac) is present
- Added autoconf, automake, libtool to Dockerfile.backend ldns-build stage
  so libtoolize + autoreconf can generate ldns/configure during make

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 08:33:38 +02:00
parent 8d4eaa1489
commit eaaa8f6a11
541 changed files with 138189 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
--------- Drill now is a subdirectory in ldns. To make life easier
--------- we are using ldns' version numbering for drill from now on.
--------- Sadly this means we GO BACKWARDS in the versions
--------- This ChangeLog will not be updated anymore - all changes are
--------- documented in ldns' ChangeLog
1.0-pre3: to be released: drill-team
* Secure tracing works
* Added section about DNSSEC in the manual page
* Allow the class information to be given to do_chase()
* Lint fixes for the code
* Bugzilla was setup for drill
* Bug #97 (drill); -S crash was fixed
* Add -Q (quiet) flag was added. This suppresses output from drill.
1.0-pre2: 20 Jun 2005: drill-team
* Second prerelease
* Bugs where fix in the chasing functionality
1.0-pre1: 1 Jun 2005: drill-team
* First drill release based on ldns
* drill's core code is not much more simple, as
all the difficult stuff is moved to ldns.
* Much saner argument parsing
---------- Above Newer drill based on ldns --------------
---------- Below Older drill with it's own DNS handling --------------
0.9.2: Feb 3 2005: drill-team
* Added two more options (borrowed from dig)
--rd, don't set the RD bit in queries
--fail, don't query the next nameserver on SERVFAIL
* Fixed handling of obscure data types
* Handle classes other the 'IN' when making a query
* For people using FreeBSD: drill is now in the ports
(Thanks to Jaap Akkerhuis)
0.9.1: Jan 5 2005: drill-team
* Makefile tweaks
* drill ns . works
* re-check the root in when tracing
* added handling for some lesser known types (including WKS)
0.9: Dec 6 2004: drill-team
* big configure.ac and Makefile.in updates (made more general)
* escapes in names argument and txt and dname data
* gcc 2(.95) support
* packet wire data is now checked for dangerous elements (like
looping compression etc)
* (Multiple) Octal char representation
* Responses can be saved to file
* 'Answers' can be read from file instead of server
* Lots and lots of bugfixes and improvements
0.8.1: Oct 27 2004: Miek
* configure.ac updates
* secure resolving updates (still doesn't work)
* printing additions
- CERT RR supported
- LOC RR support
* All non supported RRs are handled as unknown
* If no nameservers found in /etc/resolv.conf
default to 127.0.0.1
* Various bugs fixed
- Close sockets after using them
- Some memory leaks were plugged
0.8: Oct 26 2004: Miek
* Lots of features added. Drill is almost feature complete
* Unknown RR's are supported
* Numerous smaller updates in documentation
* Numerous code cleanups
* Dig is no longer needed to build drill
0.7: Oct 21 2004: Miek
* reworked internal code
* DNSSEC is working, except the secure resolving
* build updates
* more sane options parsing
* more sane argument handling
0.6-alpha: Oct 2004: Jelte
* No log
0.5-alpha: Sept 22 2004: Miek
* most of the DNS stuff is working
* moved to configure
* tested on Linux/FreeBSD
* fully IPV6 capable
* new DNSSEC types supported
* DNSSEC somewhat working
* gcc => 3 is needed for building
0.4-alpha: Sept 9 2004: Miek
* moved to autoconf for building
* lots of various updates
* really a workable program now
0.3-alpha: Sept 6 2004: Miek
* IPv6 support
* automatic secure resolving
* --trace updates
* --chase updates
* more checks

View File

@@ -0,0 +1,12 @@
QUICK INSTALL GUIDE
drill is a subdirectory in ldns.
To compile drill you need:
autoreconf && ./configure && make
If ldns is installed in a different location, use --with-ldns=directory
See also ./configure --help
In the first case you must run drill as:
LD_LIBRARY_PATH=../.libs ./drill <options>

View File

@@ -0,0 +1,25 @@
REGRESSIONS
This version of drill is based on ldns and as such some things
are slightly changed. This file documents the changes.
o When tracing (-T option) we use the local resolver (as specified
in /etc/resolv.conf) to lookup names. This increases the speed
dramatically, but you obviously need to be able to reach a recursive
server/cache.
Previously drill would try to resolve the names by itself.
o Printing of DSs after DNSKEY records. Because we don't parse our
own packets anymore, we cannot print the DS directly after the DNSKEY
record. The DSs are now printed AFTER the packet.
o The long options are removed.
o The chase function has a different output, and will be subject to change
in the near future.
o The useless (for jokes only) -I option was dropped.
FIXED:
o the argument parsing is much smarter, the order doesn't matter (much)
anymore

View File

@@ -0,0 +1,507 @@
/*
* chasetrace.c
* Where all the hard work concerning chasing
* and tracing is done
* (c) 2005, 2006 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#include "drill.h"
#include <ldns/ldns.h>
/* Cache all RRs from rr_list "rr_list" to "referrals" database for lookup
* later on. Print the NS RRs that were not already present.
*/
static void add_rr_list_to_referrals(
ldns_dnssec_zone *referrals, ldns_rr_list *rr_list)
{
size_t i;
ldns_rr *rr;
ldns_dnssec_rrsets *rrset;
ldns_dnssec_rrs *rrs;
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
rr = ldns_rr_list_rr(rr_list, i);
/* Check if a RR equal to "rr" is present in "referrals" */
rrset = ldns_dnssec_zone_find_rrset(
referrals, ldns_rr_owner(rr), ldns_rr_get_type(rr));
if (rrset) {
for (rrs = rrset->rrs; rrs; rrs = rrs->next)
if (ldns_rr_compare(rr, rrs->rr) == 0)
break;
if (rrs) continue; /* "rr" is present, next! */
}
if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NS && verbosity != -1)
ldns_rr_print(stdout, rr);
(void) ldns_dnssec_zone_add_rr(referrals, rr);
}
}
/* Cache all RRs from packet "p" to "referrals" database for lookup later on.
* Print the NS RRs that were not already present.
*/
static void add_referrals(ldns_dnssec_zone *referrals, ldns_pkt *p)
{
ldns_rr_list *l = ldns_pkt_all_noquestion(p);
if (l) {
add_rr_list_to_referrals(referrals, l);
ldns_rr_list_free(l);
}
}
/* Equip name-server "res" with the name-servers authoritative for as much
* of "name" as possible. Lookup addresses if needed.
*/
static bool set_nss_for_name(
ldns_resolver *res, ldns_dnssec_zone *referrals, ldns_rdf *name,
ldns_resolver *local_res, ldns_rr_class c)
{
ldns_dnssec_rrsets *nss = NULL;
ldns_dnssec_rrs *nss_rrs;
ldns_dnssec_rrsets *as = NULL;
ldns_dnssec_rrs *as_rrs;
ldns_rdf *lookup = ldns_rdf_clone(name);
ldns_rdf *new_lookup;
ldns_rdf *addr;
ldns_rr_list *addrs;
/* nss will become the rrset of as much of "name" as possible */
for (;;) {
nss = ldns_dnssec_zone_find_rrset(
referrals, lookup, LDNS_RR_TYPE_NS);
if (nss != NULL) {
ldns_rdf_deep_free(lookup);
break;
}
new_lookup = ldns_dname_left_chop(lookup);
ldns_rdf_deep_free(lookup);
lookup = new_lookup;
if (!lookup) {
error("No referrals for name found");
return false;
}
}
/* remove the old nameserver from the resolver */
while ((addr = ldns_resolver_pop_nameserver(res)))
ldns_rdf_deep_free(addr);
/* Find and add the address records for the rrset as name-servers */
for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
if ((as = ldns_dnssec_zone_find_rrset(
referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_A)))
for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
(void) ldns_resolver_push_nameserver(
res, ldns_rr_rdf(as_rrs->rr, 0));
if ((as = ldns_dnssec_zone_find_rrset(
referrals, ldns_rr_rdf(nss_rrs->rr, 0), LDNS_RR_TYPE_AAAA)))
for (as_rrs = as->rrs; as_rrs; as_rrs = as_rrs->next)
(void) ldns_resolver_push_nameserver(
res, ldns_rr_rdf(as_rrs->rr, 0));
}
/* Is our resolver equipped with name-servers? Good! We're done */
if (ldns_resolver_nameserver_count(res) > 0)
return true;
/* Lookup addresses with local resolver add add to "referrals" database */
addrs = ldns_rr_list_new();
for (nss_rrs = nss->rrs; nss_rrs; nss_rrs = nss_rrs->next) {
ldns_rr_list *addrs_by_name =
ldns_get_rr_list_addr_by_name(
local_res, ldns_rr_rdf(nss_rrs->rr, 0), c, 0);
ldns_rr_list_cat(addrs, addrs_by_name);
ldns_rr_list_free(addrs_by_name);
}
if (ldns_rr_list_rr_count(addrs) == 0)
error("Could not find the nameserver ip addr; abort");
else if (ldns_resolver_push_nameserver_rr_list(res, addrs) !=
LDNS_STATUS_OK)
error("Error adding new nameservers");
else {
ldns_rr_list_deep_free(addrs);
return true;
}
add_rr_list_to_referrals(referrals, addrs);
ldns_rr_list_deep_free(addrs);
return false;
}
/**
* trace down from the root to name
*/
/* same naive method as in drill0.9
* We resolve _ALL_ the names, which is of course not needed.
* We _do_ use the local resolver to do that, so it still is
* fast, but it can be made to run much faster.
*/
void
do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
ldns_rr_class c)
{
static uint8_t zero[1] = { 0 };
static const ldns_rdf root_dname = { 1, LDNS_RDF_TYPE_DNAME, &zero };
ldns_resolver *res = NULL;
ldns_pkt *p = NULL;
ldns_rr_list *final_answer;
ldns_rr_list *new_nss;
ldns_rr_list *cname = NULL;
ldns_rr_list *answers = NULL;
uint16_t loop_count;
ldns_status status;
ldns_dnssec_zone* referrals = NULL;
ldns_rdf *addr;
loop_count = 0;
final_answer = NULL;
res = ldns_resolver_new();
if (!res) {
error("Memory allocation failed");
goto cleanup;
}
/* transfer some properties of local_res to res,
* because they were given on the command line */
ldns_resolver_set_ip6(res,
ldns_resolver_ip6(local_res));
ldns_resolver_set_port(res,
ldns_resolver_port(local_res));
ldns_resolver_set_debug(res,
ldns_resolver_debug(local_res));
ldns_resolver_set_dnssec(res,
ldns_resolver_dnssec(local_res));
ldns_resolver_set_fail(res,
ldns_resolver_fail(local_res));
ldns_resolver_set_usevc(res,
ldns_resolver_usevc(local_res));
ldns_resolver_set_random(res,
ldns_resolver_random(local_res));
ldns_resolver_set_source(res,
ldns_resolver_source(local_res));
ldns_resolver_set_recursive(res, false);
/* setup the root nameserver in the new resolver */
status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
if (status != LDNS_STATUS_OK) {
fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status));
ldns_rr_list_print(stdout, global_dns_root);
goto cleanup;
}
/* this must be a real query to local_res */
status = ldns_resolver_send(&p, res, &root_dname, LDNS_RR_TYPE_NS, c, 0);
/* p can still be NULL */
if (ldns_pkt_empty(p)) {
warning("No root server information received");
}
if (status == LDNS_STATUS_OK) {
if (!ldns_pkt_empty(p)) {
drill_pkt_print(stdout, local_res, p);
}
referrals = ldns_dnssec_zone_new();
add_referrals(referrals, p);
} else {
error("cannot use local resolver");
goto cleanup;
}
if (! set_nss_for_name(res, referrals, name, local_res, c)) {
goto cleanup;
}
ldns_pkt_free(p);
p = NULL;
status = ldns_resolver_send(&p, res, name, t, c, 0);
while(status == LDNS_STATUS_OK &&
ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) {
if (!p) {
/* some error occurred -- bail out */
goto cleanup;
}
add_referrals(referrals, p);
/* checks itself for verbosity */
drill_pkt_print_footer(stdout, local_res, p);
if (! set_nss_for_name(res, referrals, name, local_res, c)) {
goto cleanup;
}
if (loop_count++ > 20) {
/* unlikely that we are doing anything useful */
error("Looks like we are looping");
goto cleanup;
}
ldns_pkt_free(p);
p = NULL;
status = ldns_resolver_send(&p, res, name, t, c, 0);
/* Exit trace on error */
if (status != LDNS_STATUS_OK)
break;
/* An answer might be the desired answer (and no referral) */
if (ldns_pkt_reply_type(p) != LDNS_PACKET_ANSWER)
continue;
/* Exit trace when the requested type is found */
answers = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANSWER);
if (answers && ldns_rr_list_rr_count(answers) > 0) {
ldns_rr_list_free(answers);
answers = NULL;
break;
}
ldns_rr_list_free(answers);
answers = NULL;
/* Get the CNAMEs from the answer */
cname = ldns_pkt_rr_list_by_type(
p, LDNS_RR_TYPE_CNAME, LDNS_SECTION_ANSWER);
/* No CNAME either: exit trace */
if (ldns_rr_list_rr_count(cname) == 0)
break;
/* Print CNAME referral */
ldns_rr_list_print(stdout, cname);
/* restart with the CNAME */
name = ldns_rr_rdf(ldns_rr_list_rr(cname, 0), 0);
ldns_rr_list_free(cname);
cname = NULL;
/* remove the old nameserver from the resolver */
while((addr = ldns_resolver_pop_nameserver(res)))
ldns_rdf_deep_free(addr);
/* Restart trace from the root up */
(void) ldns_resolver_push_nameserver_rr_list(
res, global_dns_root);
ldns_pkt_free(p);
p = NULL;
status = ldns_resolver_send(&p, res, name, t, c, 0);
}
ldns_pkt_free(p);
p = NULL;
(void) ldns_resolver_send(&p, res, name, t, c, 0);
if (!p) {
goto cleanup;
}
new_nss = ldns_pkt_authority(p);
final_answer = ldns_pkt_answer(p);
if (verbosity != -1) {
ldns_rr_list_print(stdout, final_answer);
ldns_rr_list_print(stdout, new_nss);
}
drill_pkt_print_footer(stdout, local_res, p);
cleanup:
if (res) {
while((addr = ldns_resolver_pop_nameserver(res)))
ldns_rdf_deep_free(addr);
ldns_resolver_free(res);
}
if (referrals)
ldns_dnssec_zone_deep_free(referrals);
if (p)
ldns_pkt_free(p);
}
/**
* Chase the given rr to a known and trusted key
*
* Based on drill 0.9
*
* the last argument prev_key_list, if not null, and type == DS, then the ds
* rr list we have must all be a ds for the keys in this list
*/
#ifdef HAVE_SSL
ldns_status
do_chase(ldns_resolver *res,
ldns_rdf *name,
ldns_rr_type type,
ldns_rr_class c,
ldns_rr_list *trusted_keys,
ldns_pkt *pkt_o,
uint16_t qflags,
ldns_rr_list * ATTR_UNUSED(prev_key_list))
{
ldns_rr_list *rrset = NULL;
ldns_status result;
ldns_rr *orig_rr = NULL;
/*
ldns_rr_list *sigs;
ldns_rr *cur_sig;
uint16_t sig_i;
ldns_rr_list *keys;
*/
ldns_pkt *pkt;
ldns_status tree_result;
ldns_dnssec_data_chain *chain;
ldns_dnssec_trust_tree *tree;
const ldns_rr_descriptor *descriptor;
descriptor = ldns_rr_descript(type);
ldns_dname2canonical(name);
pkt = ldns_pkt_clone(pkt_o);
if (!name) {
mesg("No name to chase");
ldns_pkt_free(pkt);
return LDNS_STATUS_EMPTY_LABEL;
}
if (verbosity != -1) {
printf(";; Chasing: ");
ldns_rdf_print(stdout, name);
if (descriptor && descriptor->_name) {
printf(" %s\n", descriptor->_name);
} else {
printf(" type %d\n", type);
}
}
if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) {
warning("No trusted keys specified");
}
if (pkt) {
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
name,
type,
LDNS_SECTION_ANSWER
);
if (!rrset) {
/* nothing in answer, try authority */
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
name,
type,
LDNS_SECTION_AUTHORITY
);
}
/* answer might be a cname, chase that first, then chase
cname target? (TODO) */
if (!rrset) {
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
name,
LDNS_RR_TYPE_CNAME,
LDNS_SECTION_ANSWER
);
if (!rrset) {
/* nothing in answer, try authority */
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
name,
LDNS_RR_TYPE_CNAME,
LDNS_SECTION_AUTHORITY
);
}
}
} else {
/* no packet? */
if (verbosity >= 0) {
fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR));
fprintf(stderr, "\n");
}
return LDNS_STATUS_MEM_ERR;
}
if (!rrset) {
/* not found in original packet, try again */
ldns_pkt_free(pkt);
pkt = NULL;
pkt = ldns_resolver_query(res, name, type, c, qflags);
if (!pkt) {
if (verbosity >= 0) {
fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR));
fprintf(stderr, "\n");
}
return LDNS_STATUS_NETWORK_ERR;
}
if (verbosity >= 5) {
ldns_pkt_print(stdout, pkt);
}
rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
name,
type,
LDNS_SECTION_ANSWER
);
}
orig_rr = ldns_rr_new();
/* if the answer had no answer section, we need to construct our own rr (for instance if
* the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */
if (ldns_pkt_ancount(pkt) < 1) {
ldns_rr_set_type(orig_rr, type);
ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name));
chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr));
} else {
/* chase the first answer */
chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL);
}
if (verbosity >= 4) {
printf("\n\nDNSSEC Data Chain:\n");
ldns_dnssec_data_chain_print(stdout, chain);
}
result = LDNS_STATUS_OK;
tree = ldns_dnssec_derive_trust_tree(chain, NULL);
if (verbosity >= 2) {
printf("\n\nDNSSEC Trust tree:\n");
ldns_dnssec_trust_tree_print(stdout, tree, 0, true);
}
if (ldns_rr_list_rr_count(trusted_keys) > 0) {
tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys);
if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) {
if (verbosity >= 1) {
printf("Existence denied or verifiably insecure\n");
}
result = LDNS_STATUS_OK;
} else if (tree_result != LDNS_STATUS_OK) {
if (verbosity >= 1) {
printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result));
}
result = tree_result;
}
} else {
if (verbosity >= 0) {
printf("You have not provided any trusted keys.\n");
}
}
ldns_rr_free(orig_rr);
ldns_dnssec_trust_tree_free(tree);
ldns_dnssec_data_chain_deep_free(chain);
ldns_rr_list_deep_free(rrset);
ldns_pkt_free(pkt);
/* ldns_rr_free(orig_rr);*/
return result;
}
#endif /* HAVE_SSL */

View File

@@ -0,0 +1,534 @@
/*
* dnssec.c
* Some DNSSEC helper function are defined here
* and tracing is done
* (c) 2005 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#include "drill.h"
#include <ldns/ldns.h>
/* get rr_type from a server from a server */
ldns_rr_list *
get_rr(ldns_resolver *res, ldns_rdf *zname, ldns_rr_type t, ldns_rr_class c)
{
/* query, retrieve, extract and return */
ldns_pkt *p;
ldns_rr_list *found;
p = ldns_pkt_new();
found = NULL;
if (ldns_resolver_send(&p, res, zname, t, c, 0) == LDNS_STATUS_OK) {
found = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANY_NOQUESTION);
}
ldns_pkt_free(p);
return found;
}
void
drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p)
{
ldns_rr_list *new_nss;
ldns_rr_list *hostnames;
char *answerfrom_str;
if (verbosity < 5) {
return;
}
hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
new_nss = ldns_pkt_rr_list_by_type(p,
LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
ldns_rr_list_print(fd, new_nss);
ldns_rr_list_deep_free(new_nss);
fprintf(fd, ";; Received %d bytes from %s#%d(",
(int) ldns_pkt_size(p),
ldns_rdf2str(ldns_pkt_answerfrom(p)),
(int) ldns_resolver_port(r));
/* if we can resolve this print it, other print the ip again */
if (hostnames) {
ldns_rdf_print(fd,
ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
ldns_rr_list_deep_free(hostnames);
} else {
answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
if (answerfrom_str) {
fprintf(fd, "%s", answerfrom_str);
LDNS_FREE(answerfrom_str);
}
}
fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
}
void
drill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p)
{
ldns_rr_list *hostnames;
char *answerfrom_str;
if (verbosity < 5) {
return;
}
hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
fprintf(fd, ";; Received %d bytes from %s#%d(",
(int) ldns_pkt_size(p),
ldns_rdf2str(ldns_pkt_answerfrom(p)),
(int) ldns_resolver_port(r));
/* if we can resolve this print it, other print the ip again */
if (hostnames) {
ldns_rdf_print(fd,
ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
ldns_rr_list_deep_free(hostnames);
} else {
answerfrom_str = ldns_rdf2str(ldns_pkt_answerfrom(p));
if (answerfrom_str) {
fprintf(fd, "%s", answerfrom_str);
LDNS_FREE(answerfrom_str);
}
}
fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
}
/*
* generic function to get some RRset from a nameserver
* and possible some signatures too (that would be the day...)
*/
ldns_pkt_type
get_dnssec_rr(ldns_pkt *p, ldns_rdf *name, ldns_rr_type t,
ldns_rr_list **rrlist, ldns_rr_list **sig)
{
ldns_pkt_type pt = LDNS_PACKET_UNKNOWN;
ldns_rr_list *sigs = NULL;
size_t i;
if (!p) {
if (rrlist) {
*rrlist = NULL;
}
return LDNS_PACKET_UNKNOWN;
}
pt = ldns_pkt_reply_type(p);
if (name) {
if (rrlist) {
*rrlist = ldns_pkt_rr_list_by_name_and_type(p, name, t,
LDNS_SECTION_ANSWER);
if (!*rrlist) {
*rrlist = ldns_pkt_rr_list_by_name_and_type(
p, name, t,
LDNS_SECTION_AUTHORITY);
}
}
if (sig) {
sigs = ldns_pkt_rr_list_by_name_and_type(p, name,
LDNS_RR_TYPE_RRSIG,
LDNS_SECTION_ANSWER);
if (!sigs) {
sigs = ldns_pkt_rr_list_by_name_and_type(
p, name, LDNS_RR_TYPE_RRSIG,
LDNS_SECTION_AUTHORITY);
}
}
} else {
/* A DS-referral - get the DS records if they are there */
if (rrlist) {
*rrlist = ldns_pkt_rr_list_by_type(
p, t, LDNS_SECTION_AUTHORITY);
}
if (sig) {
sigs = ldns_pkt_rr_list_by_type(p,
LDNS_RR_TYPE_RRSIG,
LDNS_SECTION_AUTHORITY);
}
}
if (sig) {
*sig = ldns_rr_list_new();
for (i = 0; i < ldns_rr_list_rr_count(sigs); i++) {
/* only add the sigs that cover this type */
if (t == ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(
ldns_rr_list_rr(sigs, i)))) {
ldns_rr_list_push_rr(*sig,
ldns_rr_clone(
ldns_rr_list_rr(
sigs, i)));
}
}
}
ldns_rr_list_deep_free(sigs);
if (pt == LDNS_PACKET_NXDOMAIN || pt == LDNS_PACKET_NODATA) {
return pt;
} else {
return LDNS_PACKET_ANSWER;
}
}
ldns_status
ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
{
#ifdef HAVE_SSL
uint16_t nsec_i;
ldns_rr_list *nsecs;
ldns_status result;
const ldns_rr_descriptor *descriptor;
if (!pkt) {
descriptor = ldns_rr_descript(type);
printf("NETWORk ERROR! Cannot verify denial for: ");
ldns_rdf_print(stdout, name);
printf(" type ");
if (descriptor && descriptor->_name)
printf("%s", descriptor->_name);
else
printf("TYPE%u", type);
return LDNS_STATUS_CRYPTO_NO_RRSIG;
}
if (verbosity >= 5) {
printf("VERIFY DENIAL FROM:\n");
ldns_pkt_print(stdout, pkt);
}
result = LDNS_STATUS_CRYPTO_NO_RRSIG;
/* Try to see if there are NSECS in the packet */
nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
if (nsecs) {
for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
/* there are four options:
* - name equals ownername and is covered by the type bitmap
* - name equals ownername but is not covered by the type bitmap
* - name falls within nsec coverage but is not equal to the owner name
* - name falls outside of nsec coverage
*/
if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
/*
printf("CHECKING NSEC:\n");
ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
printf("DAWASEM\n");
*/
if (ldns_nsec_bitmap_covers_type(
ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
nsec_i)),
type)) {
/* Error, according to the nsec this rrset is signed */
result = LDNS_STATUS_CRYPTO_NO_RRSIG;
} else {
/* ok nsec denies existence */
if (verbosity >= 3) {
printf(";; Existence of data set with this type denied by NSEC\n");
}
/*printf(";; Verifiably insecure.\n");*/
if (nsec_rrs && nsec_rr_sigs) {
(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
}
ldns_rr_list_deep_free(nsecs);
return LDNS_STATUS_OK;
}
} else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
if (verbosity >= 3) {
printf(";; Existence of data set with this name denied by NSEC\n");
}
if (nsec_rrs && nsec_rr_sigs) {
(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
}
ldns_rr_list_deep_free(nsecs);
return LDNS_STATUS_OK;
} else {
/* nsec has nothing to do with this data */
}
}
ldns_rr_list_deep_free(nsecs);
} else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
ldns_rr* q = ldns_rr_new();
ldns_rr* match = NULL;
if(!sigs) {
if (q) {
ldns_rr_free(q);
}
ldns_rr_list_deep_free(nsecs);
return LDNS_STATUS_MEM_ERR;
}
if(!q) {
ldns_rr_list_deep_free(nsecs);
ldns_rr_list_deep_free(sigs);
return LDNS_STATUS_MEM_ERR;
}
ldns_rr_set_question(q, 1);
ldns_rr_set_ttl(q, 0);
ldns_rr_set_owner(q, ldns_rdf_clone(name));
if(!ldns_rr_owner(q)) {
ldns_rr_free(q);
ldns_rr_list_deep_free(sigs);
ldns_rr_list_deep_free(nsecs);
return LDNS_STATUS_MEM_ERR;
}
ldns_rr_set_type(q, type);
/* result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0); */
result = ldns_dnssec_verify_denial_nsec3_match(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0, &match);
if (result == LDNS_STATUS_OK && match && nsec_rrs && nsec_rr_sigs) {
(void) get_dnssec_rr(pkt, ldns_rr_owner(match), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
}
ldns_rr_free(q);
ldns_rr_list_deep_free(nsecs);
ldns_rr_list_deep_free(sigs);
}
return result;
#else
(void)pkt;
(void)name;
(void)type;
(void)nsec_rrs;
(void)nsec_rr_sigs;
return LDNS_STATUS_ERR;
#endif /* HAVE_SSL */
}
/* NSEC3 draft -07 */
/*return hash name match*/
ldns_rr *
ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
uint8_t algorithm;
uint32_t iterations;
uint8_t salt_length;
uint8_t *salt;
ldns_rdf *sname = NULL, *hashed_sname = NULL;
size_t nsec_i;
ldns_rr *nsec;
ldns_rr *result = NULL;
const ldns_rr_descriptor *descriptor;
ldns_rdf *zone_name = NULL;
if (verbosity >= 4) {
printf(";; finding exact match for ");
descriptor = ldns_rr_descript(qtype);
if (descriptor && descriptor->_name) {
printf("%s ", descriptor->_name);
} else {
printf("TYPE%d ", qtype);
}
ldns_rdf_print(stdout, qname);
printf("\n");
}
if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
if (verbosity >= 4) {
printf("no qname, nsec3s or list empty\n");
}
return NULL;
}
nsec = ldns_rr_list_rr(nsec3s, 0);
algorithm = ldns_nsec3_algorithm(nsec);
salt_length = ldns_nsec3_salt_length(nsec);
salt = ldns_nsec3_salt_data(nsec);
iterations = ldns_nsec3_iterations(nsec);
if (salt == NULL) {
goto done;
}
sname = ldns_rdf_clone(qname);
if (sname == NULL) {
goto done;
}
if (verbosity >= 4) {
printf(";; owner name hashes to: ");
}
hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
if (hashed_sname == NULL) {
goto done;
}
zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
if (zone_name == NULL) {
goto done;
}
if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK) {
goto done;
};
if (verbosity >= 4) {
ldns_rdf_print(stdout, hashed_sname);
printf("\n");
}
for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
nsec = ldns_rr_list_rr(nsec3s, nsec_i);
/* check values of iterations etc! */
/* exact match? */
if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
result = nsec;
goto done;
}
}
done:
ldns_rdf_deep_free(zone_name);
ldns_rdf_deep_free(sname);
ldns_rdf_deep_free(hashed_sname);
LDNS_FREE(salt);
if (verbosity >= 4) {
if (result) {
printf(";; Found.\n");
} else {
printf(";; Not foud.\n");
}
}
return result;
}
/*return the owner name of the closest encloser for name from the list of rrs */
/* this is NOT the hash, but the original name! */
ldns_rdf *
ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
{
/* remember parameters, they must match */
uint8_t algorithm;
uint32_t iterations;
uint8_t salt_length;
uint8_t *salt;
ldns_rdf *sname = NULL, *hashed_sname = NULL, *tmp;
bool flag;
bool exact_match_found;
bool in_range_found;
ldns_rdf *zone_name = NULL;
size_t nsec_i;
ldns_rr *nsec;
ldns_rdf *result = NULL;
if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
return NULL;
}
if (verbosity >= 4) {
printf(";; finding closest encloser for type %d ", qtype);
ldns_rdf_print(stdout, qname);
printf("\n");
}
nsec = ldns_rr_list_rr(nsec3s, 0);
algorithm = ldns_nsec3_algorithm(nsec);
salt_length = ldns_nsec3_salt_length(nsec);
salt = ldns_nsec3_salt_data(nsec);
iterations = ldns_nsec3_iterations(nsec);
if (salt == NULL) {
goto done;
}
sname = ldns_rdf_clone(qname);
if (sname == NULL) {
goto done;
}
flag = false;
zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
if (zone_name == NULL) {
goto done;
}
/* algorithm from nsec3-07 8.3 */
while (ldns_dname_label_count(sname) > 0) {
exact_match_found = false;
in_range_found = false;
if (verbosity >= 3) {
printf(";; ");
ldns_rdf_print(stdout, sname);
printf(" hashes to: ");
}
hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
if (hashed_sname == NULL) {
goto done;
}
if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK){
ldns_rdf_deep_free(hashed_sname);
goto done;
}
if (verbosity >= 3) {
ldns_rdf_print(stdout, hashed_sname);
printf("\n");
}
for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
nsec = ldns_rr_list_rr(nsec3s, nsec_i);
/* check values of iterations etc! */
/* exact match? */
if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
if (verbosity >= 4) {
printf(";; exact match found\n");
}
exact_match_found = true;
} else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
if (verbosity >= 4) {
printf(";; in range of an nsec\n");
}
in_range_found = true;
}
}
if (!exact_match_found && in_range_found) {
flag = true;
} else if (exact_match_found && flag) {
result = ldns_rdf_clone(sname);
} else if (exact_match_found && !flag) {
// error!
if (verbosity >= 4) {
printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
}
ldns_rdf_deep_free(hashed_sname);
goto done;
} else {
flag = false;
}
ldns_rdf_deep_free(hashed_sname);
tmp = sname;
sname = ldns_dname_left_chop(sname);
ldns_rdf_deep_free(tmp);
if (sname == NULL) {
goto done;
}
}
done:
LDNS_FREE(salt);
ldns_rdf_deep_free(zone_name);
ldns_rdf_deep_free(sname);
if (!result) {
if (verbosity >= 4) {
printf(";; no closest encloser found\n");
}
}
/* todo checks from end of 6.2. here or in caller? */
return result;
}

View File

@@ -0,0 +1,262 @@
.\" @(#)drill.1 1.7.0 14-Jul-2004 OF;
.TH drill 1 "28 May 2006"
.SH NAME
drill \- get (debug) information out of DNS(SEC)
.SH SYNOPSIS
.B drill
[
.IR OPTIONS
]
.IR name
[
.IR @server
]
[
.IR type
]
[
.IR class
]
.SH DESCRIPTION
\fBdrill\fR is a tool designed to get all sorts of information out of the
DNS. It is specifically designed to be used with DNSSEC.
.PP
The name \fBdrill\fR is a pun on \fBdig\fR. With \fBdrill\fR you should be able
get even more information than with \fBdig\fR.
.PP
If no arguments are given class defaults to 'IN' and type to 'A'. The
server(s) specified in /etc/resolv.conf are used to query against.
.PP
\fIname\fR
Ask for this name.
.PP
\fI@server\fR
Send to query to this server. If not specified use the nameservers from
\fI/etc/resolv.conf\fR.
.PP
\fItype\fR
Ask for this RR type. If type is not given on the command line it defaults
to 'A'. Except when doing a reverse lookup when it defaults to 'PTR'.
.PP
\fIclass\fR
Use this class when querying.
.SH SAMPLE USAGE
\fBdrill mx miek.nl\fR
Show the MX records of the domain miek.nl
.TP
\fBdrill \-S jelte.nlnetlabs.nl\fR
Chase any signatures in the jelte.nlnetlab.nl domain. This option is
only available when ldns has been compiled with openssl-support.
.TP
\fBdrill \-TD www.example.com\fR
Do a DNSSEC (\-D) trace (\-T) from the rootservers down to www.example.com.
This option only works when ldns has been compiled with openssl support.
.TP
\fBdrill \-s dnskey jelte.nlnetlabs.nl\fR
Show the DNSKEY record(s) for jelte.nlnetlabs.nl. For each found DNSKEY
record also print the DS record.
.SH OPTIONS
.TP
\fB\-D
Enable DNSSEC in the query. When querying for DNSSEC types (DNSKEY, RRSIG,
DS and NSEC) this is \fInot\fR automatically enabled.
.TP
\fB\-T
Trace \fIname\fR from the root down. When using this option the @server
arguments is not used.
.TP
\fB\-S
Chase the signature(s) of 'name' to a known key or as high up in
the tree as possible.
.TP
\fB\-I \fIIPv4 or IPv6 address\fR
Source address to query from. The source address has to be present
on an interface of the host running drill.
.TP
\fB\-V \fIlevel\fR
Be more verbose. Set level to 5 to see the actual query that is sent.
.TP
\fB\-Q
Quiet mode, this overrules \-V.
.TP
\fB\-f \fIfile\fR
Read the query from a file. The query must be dumped with \-w.
.TP
\fB\-i \fIfile\fR
read the answer from the file instead from the network. This aids
in debugging and can be used to check if a query on disk is valid.
If the file contains binary data it is assumed to be a query in
network order.
.TP
\fB\-w \fIfile\fR
Write an answer packet to file.
.TP
\fB\-q \fIfile\fR
Write the query packet to file.
.TP
\fB\-v
Show drill's version.
.TP
\fB\-h
Show a short help message.
.SS QUERY OPTIONS
.TP
\fB\-4
Stay on ip4. Only send queries to ip4 enabled nameservers.
.TP
\fB\-6
Stay on ip6. Only send queries to ip6 enabled nameservers.
.TP
\fB\-a
Use the resolver structure's fallback mechanism if the answer
is truncated (TC=1). If a truncated packet is received and this
option is set, drill will first send a new query with EDNS0
buffer size 4096.
If the EDNS0 buffer size was already set to 512+ bytes, or the
above retry also results in a truncated answer, the resolver
structure will fall back to TCP.
.TP
\fB\-b \fIsize\fR
Use size as the buffer size in the EDNS0 pseudo RR.
.TP
\fB\-c \fIfile\fR
Use file instead of /etc/resolv.conf for nameserver configuration.
.TP
\fB\-d \fIdomain\fR
When tracing (\-T), start from this domain instead of the root.
.TP
\fB\-t
Use TCP/IP when querying a server
.TP
\fB\-k \fIkeyfile\fR
Use this file to read a (trusted) key from. When this options is
given \fBdrill\fR tries to validate the current answer with this
key. No chasing is done. When \fBdrill\fR is doing a secure trace, this
key will be used as trust anchor. Can contain a DNSKEY or a DS record.
Alternatively, when DNSSEC enabled tracing (\fB-TD\fR) or signature
chasing (\fB-S\fR), if \fB-k\fR is not specified, and a default trust anchor
(@LDNS_TRUST_ANCHOR_FILE@) exists and contains a valid DNSKEY or DS record,
it will be used as the trust anchor.
.TP
\fB\-o \fImnemonic\fR
Use this option to set or unset specific header bits. A bit is
set by using the bit mnemonic in CAPITAL letters. A bit is unset when
the mnemonic is given in lowercase. The following mnemonics are
understood by \fBdrill\fR:
QR, qr: set, unset QueRy (default: on)
AA, aa: set, unset Authoritative Answer (default: off)
TC, tc: set, unset TrunCated (default: off)
RD, rd: set, unset Recursion Desired (default: on)
CD, cd: set, unset Checking Disabled (default: off)
RA, ra: set, unset Recursion Available (default: off)
AD, ad: set, unset Authenticated Data (default: off)
Thus: \fB-o CD\fR, will enable Checking Disabled, which instructs the
cache to not validate the answers it gives out.
.TP
\fB\-p \fIport\fR
Use this port instead of the default of 53.
.TP
\fB\-r \fIfile\fR
When tracing (\-T), use file as a root servers hint file.
.TP
\fB\-s
When encountering a DNSKEY print the equivalent DS also.
.TP
\fB\-u
Use UDP when querying a server. This is the default.
.TP
\fB\-w \fIfile\fR
write the answer to a file. The file will contain a hexadecimal dump
of the query. This can be used in conjunction with \-f.
.TP
\fB\-x
Do a reverse lookup. The type argument is not used, it is preset to PTR.
.TP
\fB\-y \fI<name:key[:algo]>\fR
specify named base64 tsig key, and optional an algorithm (defaults to hmac-md5.sig-alg.reg.int)
.TP
\fB\-z \fR
don't randomize the nameserver list before sending queries.
.SS EDNS QUERY OPTIONS
.TP
\fB\+nsid \fR
When set, this EDNS option includes an EDNS name server ID request in the query.
.SH "EXIT STATUS"
The exit status is 0 if the looked up answer is secure and trusted,
or insecure.
The exit status is not 0 if the looked up answer is untrusted or bogus,
or an error occurred while performing the lookup.
.SH "FILES"
.TP
@LDNS_TRUST_ANCHOR_FILE@
The file from which trusted keys are loaded when no \fB-k\fR option is given.
.SH "SEE ALSO"
.LP
unbound-anchor(8)
.SH AUTHOR
Jelte Jansen and Miek Gieben. Both of NLnet Labs.
.SH REPORTING BUGS
Report bugs to <dns-team@nlnetlabs.nl>.
.SH BUGS
.SH COPYRIGHT
Copyright (c) 2004-2008 NLnet Labs.
Licensed under the revised BSD license. There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
.SH SEE ALSO
\fBdig\fR(1), \fIRFC403{3,4,5}\fR.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
/*
* drill.h
* the main header file of drill
* (c) 2005, 2006 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#ifndef _DRILL_H_
#define _DRILL_H_
#include "config.h"
#include "drill_util.h"
#define DRILL_VERSION PACKAGE_VERSION
/* what kind of stuff do we allow */
#define DRILL_QUERY 0
#define DRILL_TRACE 1
#define DRILL_CHASE 2
#define DRILL_AFROMFILE 3
#define DRILL_QTOFILE 4
#define DRILL_NSEC 5
#define DRILL_SECTRACE 7
#define DRILL_ON(VAR, BIT) \
(VAR) = (VAR) | (BIT)
#define DRILL_OFF(VAR, BIT) \
(VAR) = (VAR) & ~(BIT)
extern ldns_rr_list *global_dns_root;
extern int verbosity;
void do_trace(ldns_resolver *res,
ldns_rdf *name,
ldns_rr_type type,
ldns_rr_class c);
ldns_status do_chase(ldns_resolver *res,
ldns_rdf *name,
ldns_rr_type type,
ldns_rr_class c,
ldns_rr_list *trusted_keys,
ldns_pkt *pkt_o,
uint16_t qflags,
ldns_rr_list *prev_key_list);
int do_secure_trace(ldns_resolver *res,
ldns_rdf *name,
ldns_rr_type type,
ldns_rr_class c,
ldns_rr_list *trusted_keys,
ldns_rdf *start_name);
ldns_rr_list * get_rr(ldns_resolver *res,
ldns_rdf *zname,
ldns_rr_type t,
ldns_rr_class c);
void drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p);
void drill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p);
ldns_pkt_type get_dnssec_rr(ldns_pkt *p,
ldns_rdf *name,
ldns_rr_type t,
ldns_rr_list **rrlist,
ldns_rr_list **sig);
ldns_rr *ldns_nsec3_exact_match(ldns_rdf *qname,
ldns_rr_type qtype,
ldns_rr_list *nsec3s);
ldns_rdf *ldns_nsec3_closest_encloser(ldns_rdf *qname,
ldns_rr_type qtype,
ldns_rr_list *nsec3s);
/* verifies denial of existence of *name in *pkt (must contain NSEC or NSEC3 records
* if *nsec_rrs and *nsec_rr_sigs are given, pointers to the relevant nsecs and their signatures are
* placed there
*/
ldns_status ldns_verify_denial(ldns_pkt *pkt,
ldns_rdf *name,
ldns_rr_type type,
ldns_rr_list **nsec_rrs,
ldns_rr_list **nsec_rr_sigs);
ldns_pkt *read_hex_pkt(char *filename);
ldns_buffer *read_hex_buffer(char *filename);
void init_root(void);
ldns_rr_list *read_root_hints(const char *filename);
void clear_root(void);
void dump_hex(const ldns_pkt *pkt, const char *file);
void warning(const char *fmt, ...);
void error(const char *fmt, ...);
void mesg(const char *fmt, ...);
/* screen.c */
void resolver_print_nameservers(ldns_resolver *r);
void print_dnskey(ldns_rr_list *key_list);
void print_ds(ldns_rr_list *ds_list);
#endif /* _DRILL_H_ */

View File

@@ -0,0 +1,311 @@
/*
* util.c
* some handy function needed in drill and not implemented
* in ldns
* (c) 2005 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#include "drill.h"
#include <ldns/ldns.h>
#include <errno.h>
static int
read_line(FILE *input, char *line, size_t len)
{
int i;
int c;
for (i = 0; i < (int)len-1; i++) {
c = getc(input);
if (c == EOF) {
return -1;
} else if (c != '\n') {
line[i] = c;
} else {
break;
}
}
line[i] = '\0';
return i;
}
/* key_list must be initialized with ldns_rr_list_new() */
ldns_status
read_key_file(const char *filename, ldns_rr_list *key_list, bool silently)
{
int line_len = 0;
int line_nr = 0;
int key_count = 0;
char line[LDNS_MAX_LINELEN];
ldns_status status;
FILE *input_file;
ldns_rr *rr;
input_file = fopen(filename, "r");
if (!input_file) {
if (! silently) {
fprintf(stderr, "Error opening %s: %s\n",
filename, strerror(errno));
}
return LDNS_STATUS_ERR;
}
while (line_len >= 0) {
line_len = (int) read_line(input_file, line, sizeof(line));
line_nr++;
if (line_len > 0 && line[0] != ';') {
status = ldns_rr_new_frm_str(&rr, line, 0, NULL, NULL);
if (status != LDNS_STATUS_OK) {
if (! silently) {
fprintf(stderr,
"Error parsing DNSKEY RR "
"in line %d: %s\n", line_nr,
ldns_get_errorstr_by_id(status)
);
}
} else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY ||
ldns_rr_get_type(rr) == LDNS_RR_TYPE_DS) {
ldns_rr_list_push_rr(key_list, rr);
key_count++;
} else {
ldns_rr_free(rr);
}
}
}
fclose(input_file);
if (key_count > 0) {
return LDNS_STATUS_OK;
} else {
/*fprintf(stderr, "No keys read\n");*/
return LDNS_STATUS_ERR;
}
}
ldns_rdf *
ldns_rdf_new_addr_frm_str(char *str)
{
ldns_rdf *a;
a = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, str);
if (!a) {
/* maybe ip6 */
a = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, str);
if (!a) {
return NULL;
}
}
return a;
}
static inline void
local_print_ds(FILE* out, const char* pre, ldns_rr* ds)
{
if (out && ds) {
fprintf(out, "%s", pre);
ldns_rr_print(out, ds);
ldns_rr_free(ds);
}
}
/*
* For all keys in a packet print the DS
*/
void
print_ds_of_keys(ldns_pkt *p)
{
ldns_rr_list *keys;
uint16_t i;
ldns_rr *ds;
/* TODO fix the section stuff, here or in ldns */
keys = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_DNSKEY,
LDNS_SECTION_ANSWER);
/* this also returns the question section rr, which does not
* have any data.... and this inturn crashes everything */
if (keys) {
for (i = 0; i < ldns_rr_list_rr_count(keys); i++) {
fprintf(stdout, ";\n; equivalent DS records for key %u:\n",
(unsigned int)ldns_calc_keytag(ldns_rr_list_rr(keys, i)));
ds = ldns_key_rr2ds(ldns_rr_list_rr(keys, i), LDNS_SHA1);
local_print_ds(stdout, "; sha1: ", ds);
ds = ldns_key_rr2ds(ldns_rr_list_rr(keys, i), LDNS_SHA256);
local_print_ds(stdout, "; sha256: ", ds);
}
ldns_rr_list_deep_free(keys);
}
}
static void
print_class_type(FILE *fp, ldns_rr *r)
{
ldns_lookup_table *lt;
lt = ldns_lookup_by_id(ldns_rr_classes, ldns_rr_get_class(r));
if (lt) {
fprintf(fp, " %s", lt->name);
} else {
fprintf(fp, " CLASS%d", ldns_rr_get_class(r));
}
/* okay not THE way - but the quickest */
switch (ldns_rr_get_type(r)) {
case LDNS_RR_TYPE_RRSIG:
fprintf(fp, " RRSIG ");
break;
case LDNS_RR_TYPE_DNSKEY:
fprintf(fp, " DNSKEY ");
break;
case LDNS_RR_TYPE_DS:
fprintf(fp, " DS ");
break;
default:
break;
}
}
void
print_ds_abbr(FILE *fp, ldns_rr *ds)
{
if (!ds || (ldns_rr_get_type(ds) != LDNS_RR_TYPE_DS)) {
return;
}
ldns_rdf_print(fp, ldns_rr_owner(ds));
fprintf(fp, " %d", (int)ldns_rr_ttl(ds));
print_class_type(fp, ds);
ldns_rdf_print(fp, ldns_rr_rdf(ds, 0)); fprintf(fp, " ");
ldns_rdf_print(fp, ldns_rr_rdf(ds, 1)); fprintf(fp, " ");
ldns_rdf_print(fp, ldns_rr_rdf(ds, 2)); fprintf(fp, " ");
ldns_rdf_print(fp, ldns_rr_rdf(ds, 3)); fprintf(fp, " ");
}
/* print some of the elements of a signature */
void
print_rrsig_abbr(FILE *fp, ldns_rr *sig) {
if (!sig || (ldns_rr_get_type(sig) != LDNS_RR_TYPE_RRSIG)) {
return;
}
ldns_rdf_print(fp, ldns_rr_owner(sig));
fprintf(fp, " %d", (int)ldns_rr_ttl(sig));
print_class_type(fp, sig);
/* print a number of rdf's */
/* typecovered */
ldns_rdf_print(fp, ldns_rr_rdf(sig, 0)); fprintf(fp, " ");
/* algo */
ldns_rdf_print(fp, ldns_rr_rdf(sig, 1)); fprintf(fp, " ");
/* labels */
ldns_rdf_print(fp, ldns_rr_rdf(sig, 2)); fprintf(fp, " (\n\t\t\t");
/* expir */
ldns_rdf_print(fp, ldns_rr_rdf(sig, 4)); fprintf(fp, " ");
/* incep */
ldns_rdf_print(fp, ldns_rr_rdf(sig, 5)); fprintf(fp, " ");
/* key-id */
ldns_rdf_print(fp, ldns_rr_rdf(sig, 6)); fprintf(fp, " ");
/* key owner */
ldns_rdf_print(fp, ldns_rr_rdf(sig, 7)); fprintf(fp, ")");
}
void
print_dnskey_abbr(FILE *fp, ldns_rr *key)
{
if (!key || (ldns_rr_get_type(key) != LDNS_RR_TYPE_DNSKEY)) {
return;
}
ldns_rdf_print(fp, ldns_rr_owner(key));
fprintf(fp, " %d", (int)ldns_rr_ttl(key));
print_class_type(fp, key);
/* print a number of rdf's */
/* flags */
ldns_rdf_print(fp, ldns_rr_rdf(key, 0)); fprintf(fp, " ");
/* proto */
ldns_rdf_print(fp, ldns_rr_rdf(key, 1)); fprintf(fp, " ");
/* algo */
ldns_rdf_print(fp, ldns_rr_rdf(key, 2));
if (ldns_rdf2native_int16(ldns_rr_rdf(key, 0)) == 256) {
fprintf(fp, " ;{id = %u (zsk), size = %db}", (unsigned int)ldns_calc_keytag(key),
(int)ldns_rr_dnskey_key_size(key));
return;
}
if (ldns_rdf2native_int16(ldns_rr_rdf(key, 0)) == 257) {
fprintf(fp, " ;{id = %u (ksk), size = %db}", (unsigned int)ldns_calc_keytag(key),
(int)ldns_rr_dnskey_key_size(key));
return;
}
fprintf(fp, " ;{id = %u, size = %db}", (unsigned int)ldns_calc_keytag(key),
(int)ldns_rr_dnskey_key_size(key));
}
void
print_rr_list_abbr(FILE *fp, ldns_rr_list *rrlist, const char *usr)
{
size_t i;
ldns_rr_type tp;
for(i = 0; i < ldns_rr_list_rr_count(rrlist); i++) {
tp = ldns_rr_get_type(ldns_rr_list_rr(rrlist, i));
if (i == 0 && tp != LDNS_RR_TYPE_RRSIG) {
if (usr) {
fprintf(fp, "%s ", usr);
}
}
switch(tp) {
case LDNS_RR_TYPE_DNSKEY:
print_dnskey_abbr(fp, ldns_rr_list_rr(rrlist, i));
break;
case LDNS_RR_TYPE_RRSIG:
print_rrsig_abbr(fp, ldns_rr_list_rr(rrlist, i));
break;
case LDNS_RR_TYPE_DS:
print_ds_abbr(fp, ldns_rr_list_rr(rrlist, i));
break;
default:
/* not handled */
break;
}
fputs("\n", fp);
}
}
void *
xmalloc(size_t s)
{
void *p;
p = malloc(s);
if (!p) {
printf("Mem failure\n");
exit(EXIT_FAILURE);
}
return p;
}
void *
xrealloc(void *p, size_t size)
{
void *q;
q = realloc(p, size);
if (!q) {
printf("Mem failure\n");
exit(EXIT_FAILURE);
}
return q;
}
void
xfree(void *p)
{
if (p) {
free(p);
}
}

View File

@@ -0,0 +1,65 @@
/*
* util.h
* util.c header file
* in ldns
* (c) 2005 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#ifndef _DRILL_UTIL_H_
#define _DRILL_UTIL_H_
#include <ldns/ldns.h>
/**
* Read keys from filename and append to key_list.
*/
ldns_status read_key_file(const char *filename, ldns_rr_list *key_list,
bool silently);
/**
* return a address rdf, either A or AAAA
* NULL if anything goes wrong
*/
ldns_rdf * ldns_rdf_new_addr_frm_str(char *);
/**
* print all the ds of the keys in the packet
*/
void print_ds_of_keys(ldns_pkt *p);
/**
* print some rdfs of a signature
*/
void print_rrsig_abbr(FILE *fp, ldns_rr *sig);
/**
* print some rdfs of a dnskey
*/
void print_dnskey_abbr(FILE *fp, ldns_rr *key);
/**
* print some rdfs of a ds
*/
void print_ds_abbr(FILE *fp, ldns_rr *ds);
/**
* print some rdfs of a rr in a rr_list
*/
void print_rr_list_abbr(FILE *fp, ldns_rr_list *sig, const char *usr);
/**
* Alloc some memory, with error checking
*/
void *xmalloc(size_t s);
/**
* Realloc some memory, with error checking
*/
void *xrealloc(void *p, size_t s);
/**
* Free the data
*/
void xfree(void *q);
#endif /* _DRILL_UTIL_H_ */

View File

@@ -0,0 +1,86 @@
/**
* error.c
*
* error reporting routines
* basically wrappers around printf
*
* (c) 2005 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#include "drill.h"
#include <ldns/ldns.h>
static void
warning_va_list(const char *fmt, va_list args)
{
fprintf(stderr, "Warning: ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
}
void
warning(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
warning_va_list(fmt, args);
va_end(args);
}
static void
error_va_list(const char *fmt, va_list args)
{
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
}
void
error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
error_va_list(fmt, args);
va_end(args);
exit(EXIT_FAILURE);
}
static void
verbose_va_list(const char *fmt, va_list args)
{
vfprintf(stdout, fmt, args);
fprintf(stdout, "\n");
}
/* print stuff */
void
mesg(const char *fmt, ...)
{
va_list args;
if (verbosity == -1) {
return;
}
fprintf(stdout, ";; ");
va_start(args, fmt);
verbose_va_list(fmt, args);
va_end(args);
}
#if 0
/* print stuff when in verbose mode (1) */
void
verbose(const char *fmt, ...)
{
va_list args;
if (verbosity < 1) {
return;
}
va_start(args, fmt);
verbose_va_list(fmt, args);
va_end(args);
}
#endif

View File

@@ -0,0 +1,520 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2009-04-28.21; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
trap '(exit $?); exit' 1 2 13 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names starting with `-'.
case $src in
-*) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
-*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test -z "$d" && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@@ -0,0 +1,134 @@
/*
* root.c
* Function to handle to the rootservers
* and to update and prime them
* (c) 2005 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#include "drill.h"
#include <ldns/ldns.h>
#include <errno.h>
/* a global list of the root-servers */
ldns_rr_list *global_dns_root = NULL;
/* put a hardcoded list in the root and
* init the root rrlist structure */
void
init_root(void)
{
ldns_rr *r;
global_dns_root = ldns_rr_list_new();
(void)ldns_rr_new_frm_str(&r, "A.ROOT-SERVERS.NET. 3600000 A 198.41.0.4", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "A.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:BA3E::2:30", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "B.ROOT-SERVERS.NET. 3600000 A 170.247.170.2", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "B.ROOT-SERVERS.NET. 3600000 AAAA 2801:1b8:10::B", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "C.ROOT-SERVERS.NET. 3600000 A 192.33.4.12", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "C.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2::C", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "D.ROOT-SERVERS.NET. 3600000 A 199.7.91.13", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "D.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2D::D", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "E.ROOT-SERVERS.NET. 3600000 A 192.203.230.10", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "E.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:A8::E", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "F.ROOT-SERVERS.NET. 3600000 A 192.5.5.241", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "F.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:2F::F", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "G.ROOT-SERVERS.NET. 3600000 A 192.112.36.4", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "G.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:12::D0D", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "H.ROOT-SERVERS.NET. 3600000 A 198.97.190.53", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "H.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:1::53", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "I.ROOT-SERVERS.NET. 3600000 A 192.36.148.17", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "I.ROOT-SERVERS.NET. 3600000 AAAA 2001:7FE::53", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "J.ROOT-SERVERS.NET. 3600000 A 192.58.128.30", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "J.ROOT-SERVERS.NET. 3600000 AAAA 2001:503:C27::2:30", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "K.ROOT-SERVERS.NET. 3600000 A 193.0.14.129 ", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "K.ROOT-SERVERS.NET. 3600000 AAAA 2001:7FD::1", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "L.ROOT-SERVERS.NET. 3600000 A 199.7.83.42", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "L.ROOT-SERVERS.NET. 3600000 AAAA 2001:500:9F::42", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "M.ROOT-SERVERS.NET. 3600000 A 202.12.27.33", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
(void)ldns_rr_new_frm_str(&r, "M.ROOT-SERVERS.NET. 3600000 AAAA 2001:DC3::35", 0, NULL, NULL);
ldns_rr_list_push_rr(global_dns_root, r);
}
/*
* Read a hints file as root
*
* The file with the given path should contain a list of NS RRs
* for the root zone and A records for those NS RRs.
* Read them, check them, and append the a records to the rr list given.
*/
ldns_rr_list *
read_root_hints(const char *filename)
{
FILE *fp = NULL;
int line_nr = 0;
ldns_zone *z;
ldns_status status;
ldns_rr_list *addresses = NULL;
ldns_rr *rr;
size_t i;
fp = fopen(filename, "r");
if (!fp) {
fprintf(stderr, "Unable to open %s for reading: %s\n", filename, strerror(errno));
return NULL;
}
status = ldns_zone_new_frm_fp_l(&z, fp, NULL, 0, 0, &line_nr);
fclose(fp);
if (status != LDNS_STATUS_OK) {
fprintf(stderr, "Error reading root hints file: %s\n", ldns_get_errorstr_by_id(status));
return NULL;
} else {
addresses = ldns_rr_list_new();
for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(z)); i++) {
rr = ldns_rr_list_rr(ldns_zone_rrs(z), i);
/*if ((address_family == 0 || address_family == 1) &&
*/
if ( ldns_rr_get_type(rr) == LDNS_RR_TYPE_A ) {
ldns_rr_list_push_rr(addresses, ldns_rr_clone(rr));
}
/*if ((address_family == 0 || address_family == 2) &&*/
if ( ldns_rr_get_type(rr) == LDNS_RR_TYPE_AAAA) {
ldns_rr_list_push_rr(addresses, ldns_rr_clone(rr));
}
}
ldns_zone_deep_free(z);
return addresses;
}
}
void
clear_root(void)
{
ldns_rr_list_deep_free(global_dns_root);
}

View File

@@ -0,0 +1,797 @@
/*
* securechasetrace.c
* Where all the hard work concerning secure tracing is done
*
* (c) 2005, 2006 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#include "drill.h"
#include <ldns/ldns.h>
#define SELF "[S]" /* self sig ok */
#define TRUST "[T]" /* chain from parent */
#define BOGUS "[B]" /* bogus */
#define UNSIGNED "[U]" /* no relevant dnssec data found */
#if 0
/* See if there is a key/ds in trusted that matches
* a ds in *ds.
*/
static ldns_rr_list *
ds_key_match(ldns_rr_list *ds, ldns_rr_list *trusted)
{
size_t i, j;
bool match;
ldns_rr *rr_i, *rr_j;
ldns_rr_list *keys;
if (!trusted || !ds) {
return NULL;
}
match = false;
keys = ldns_rr_list_new();
if (!keys) {
return NULL;
}
if (!ds || !trusted) {
return NULL;
}
for (i = 0; i < ldns_rr_list_rr_count(trusted); i++) {
rr_i = ldns_rr_list_rr(trusted, i);
for (j = 0; j < ldns_rr_list_rr_count(ds); j++) {
rr_j = ldns_rr_list_rr(ds, j);
if (ldns_rr_compare_ds(rr_i, rr_j)) {
match = true;
/* only allow unique RRs to match */
ldns_rr_set_push_rr(keys, rr_i);
}
}
}
if (match) {
return keys;
} else {
return NULL;
}
}
#endif
static ldns_pkt *
get_dnssec_pkt(ldns_resolver *r, ldns_rdf *name, ldns_rr_type t)
{
ldns_pkt *p = NULL;
p = ldns_resolver_query(r, name, t, LDNS_RR_CLASS_IN, 0);
if (!p) {
return NULL;
} else {
if (verbosity >= 5) {
ldns_pkt_print(stdout, p);
}
return p;
}
}
#ifdef HAVE_SSL
/*
* retrieve keys for this zone
*/
static ldns_pkt_type
get_key(ldns_pkt *p, ldns_rdf *apexname, ldns_rr_list **rrlist, ldns_rr_list **opt_sig)
{
return get_dnssec_rr(p, apexname, LDNS_RR_TYPE_DNSKEY, rrlist, opt_sig);
}
/*
* check to see if we can find a DS rrset here which we can then follow
*/
static ldns_pkt_type
get_ds(ldns_pkt *p, ldns_rdf *ownername, ldns_rr_list **rrlist, ldns_rr_list **opt_sig)
{
return get_dnssec_rr(p, ownername, LDNS_RR_TYPE_DS, rrlist, opt_sig);
}
#endif /* HAVE_SSL */
static void
remove_resolver_nameservers(ldns_resolver *res)
{
ldns_rdf *pop;
/* remove the old nameserver from the resolver */
while((pop = ldns_resolver_pop_nameserver(res))) {
ldns_rdf_deep_free(pop);
}
}
/*ldns_pkt **/
#ifdef HAVE_SSL
int
do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
ldns_rr_class c, ldns_rr_list *trusted_keys, ldns_rdf *start_name
)
{
ldns_resolver *res;
ldns_pkt *p, *local_p;
ldns_rr_list *new_nss;
ldns_rr_list *ns_addr;
ldns_rdf *pop;
ldns_rdf **labels = NULL;
ldns_status status, st;
ssize_t i;
size_t j;
size_t k;
size_t l;
uint8_t labels_count = 0;
/* dnssec */
ldns_rr_list *key_list;
ldns_rr_list *key_sig_list;
ldns_rr_list *ds_list;
ldns_rr_list *ds_sig_list;
ldns_rr_list *correct_key_list;
ldns_rr_list *trusted_ds_rrs;
bool new_keys_trusted = false;
ldns_rr_list *current_correct_keys = NULL;
ldns_rr_list *dataset;
ldns_rr_list *nsec_rrs = NULL;
ldns_rr_list *nsec_rr_sigs = NULL;
/* empty non-terminal check */
bool ent;
ldns_rr *nsecrr; /* The nsec that proofs the non-terminal */
ldns_rdf *hashed_name; /* The query hashed with nsec3 params */
ldns_rdf *label0; /* The first label of an nsec3 owner name */
/* glue handling */
ldns_rr_list *new_ns_addr;
ldns_rr_list *old_ns_addr;
ldns_rr *ns_rr;
int result = 0;
/* printing niceness */
const ldns_rr_descriptor *descriptor;
descriptor = ldns_rr_descript(t);
new_nss = NULL;
ns_addr = NULL;
key_list = NULL;
ds_list = NULL;
p = NULL;
local_p = NULL;
res = ldns_resolver_new();
key_sig_list = NULL;
ds_sig_list = NULL;
if (!res) {
error("Memory allocation failed");
result = -1;
return result;
}
correct_key_list = ldns_rr_list_new();
if (!correct_key_list) {
error("Memory allocation failed");
result = -1;
return result;
}
trusted_ds_rrs = ldns_rr_list_new();
if (!trusted_ds_rrs) {
error("Memory allocation failed");
result = -1;
return result;
}
/* Add all preset trusted DS signatures to the list of trusted DS RRs. */
for (j = 0; j < ldns_rr_list_rr_count(trusted_keys); j++) {
ldns_rr* one_rr = ldns_rr_list_rr(trusted_keys, j);
if (ldns_rr_get_type(one_rr) == LDNS_RR_TYPE_DS) {
ldns_rr_list_push_rr(trusted_ds_rrs, ldns_rr_clone(one_rr));
}
}
/* transfer some properties of local_res to res */
ldns_resolver_set_ip6(res,
ldns_resolver_ip6(local_res));
ldns_resolver_set_port(res,
ldns_resolver_port(local_res));
ldns_resolver_set_debug(res,
ldns_resolver_debug(local_res));
ldns_resolver_set_fail(res,
ldns_resolver_fail(local_res));
ldns_resolver_set_usevc(res,
ldns_resolver_usevc(local_res));
ldns_resolver_set_random(res,
ldns_resolver_random(local_res));
ldns_resolver_set_source(res,
ldns_resolver_source(local_res));
ldns_resolver_set_recursive(local_res, true);
ldns_resolver_set_recursive(res, false);
ldns_resolver_set_dnssec_cd(res, false);
ldns_resolver_set_dnssec(res, true);
/* setup the root nameserver in the new resolver */
status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root);
if (status != LDNS_STATUS_OK) {
printf("ERRRRR: %s\n", ldns_get_errorstr_by_id(status));
ldns_rr_list_print(stdout, global_dns_root);
result = status;
goto done;
}
labels_count = ldns_dname_label_count(name);
if (start_name) {
if (ldns_dname_is_subdomain(name, start_name)) {
labels_count -= ldns_dname_label_count(start_name);
} else {
fprintf(stderr, "Error; ");
ldns_rdf_print(stderr, name);
fprintf(stderr, " is not a subdomain of ");
ldns_rdf_print(stderr, start_name);
fprintf(stderr, "\n");
goto done;
}
}
labels = LDNS_CALLOC(ldns_rdf*, labels_count + 2);
if (!labels) {
goto done;
}
labels[0] = ldns_dname_new_frm_str(LDNS_ROOT_LABEL_STR);
labels[1] = ldns_rdf_clone(name);
for(i = 2 ; i < (ssize_t)labels_count + 2; i++) {
labels[i] = ldns_dname_left_chop(labels[i - 1]);
}
/* get the nameserver for the label
* ask: dnskey and ds for the label
*/
for(i = (ssize_t)labels_count + 1; i > 0; i--) {
status = ldns_resolver_send(&local_p, res, labels[i], LDNS_RR_TYPE_NS, c, 0);
if (status != LDNS_STATUS_OK) {
fprintf(stderr, "Error sending query: %s\n", ldns_get_errorstr_by_id(status));
result = status;
goto done;
}
/* TODO: handle status */
if (verbosity >= 5) {
ldns_pkt_print(stdout, local_p);
}
new_nss = ldns_pkt_rr_list_by_type(local_p,
LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
if (!new_nss) {
/* if it's a delegation, servers put them in the auth section */
new_nss = ldns_pkt_rr_list_by_type(local_p,
LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
}
/* if this is the final step there might not be nameserver records
of course if the data is in the apex, there are, so cover both
cases */
if (new_nss || i > 1) {
for(j = 0; j < ldns_rr_list_rr_count(new_nss); j++) {
ns_rr = ldns_rr_list_rr(new_nss, j);
pop = ldns_rr_rdf(ns_rr, 0);
if (!pop) {
printf("nopo\n");
break;
}
/* retrieve it's addresses */
/* trust glue? */
new_ns_addr = NULL;
if (ldns_dname_is_subdomain(pop, labels[i])) {
new_ns_addr = ldns_pkt_rr_list_by_name_and_type(local_p, pop, LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
}
if (!new_ns_addr || ldns_rr_list_rr_count(new_ns_addr) == 0) {
new_ns_addr = ldns_get_rr_list_addr_by_name(res, pop, c, 0);
}
if (!new_ns_addr || ldns_rr_list_rr_count(new_ns_addr) == 0) {
new_ns_addr = ldns_get_rr_list_addr_by_name(local_res, pop, c, 0);
}
if (new_ns_addr) {
old_ns_addr = ns_addr;
ns_addr = ldns_rr_list_cat_clone(ns_addr, new_ns_addr);
ldns_rr_list_deep_free(old_ns_addr);
}
ldns_rr_list_deep_free(new_ns_addr);
}
ldns_rr_list_deep_free(new_nss);
if (ns_addr) {
remove_resolver_nameservers(res);
if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) !=
LDNS_STATUS_OK) {
error("Error adding new nameservers");
ldns_pkt_free(local_p);
goto done;
}
ldns_rr_list_deep_free(ns_addr);
} else {
status = ldns_verify_denial(local_p, labels[i], LDNS_RR_TYPE_NS, &nsec_rrs, &nsec_rr_sigs);
/* verify the nsec3 themselves*/
if (verbosity >= 4) {
printf("NSEC(3) Records to verify:\n");
ldns_rr_list_print(stdout, nsec_rrs);
printf("With signatures:\n");
ldns_rr_list_print(stdout, nsec_rr_sigs);
printf("correct keys:\n");
ldns_rr_list_print(stdout, correct_key_list);
}
if (status == LDNS_STATUS_OK) {
if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, trusted_keys, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", TRUST);
fprintf(stdout, "Existence denied: ");
ldns_rdf_print(stdout, labels[i]);
/*
if (descriptor && descriptor->_name) {
printf(" %s", descriptor->_name);
} else {
printf(" TYPE%u", t);
}
*/ fprintf(stdout, " NS\n");
} else if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, correct_key_list, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", SELF);
fprintf(stdout, "Existence denied: ");
ldns_rdf_print(stdout, labels[i]);
/*
if (descriptor && descriptor->_name) {
printf(" %s", descriptor->_name);
} else {
printf(" TYPE%u", t);
}
*/
fprintf(stdout, " NS\n");
} else {
fprintf(stdout, "%s ", BOGUS);
result = 1;
printf(";; Error verifying denial of existence for name ");
ldns_rdf_print(stdout, labels[i]);
/*
printf(" type ");
if (descriptor && descriptor->_name) {
printf("%s", descriptor->_name);
} else {
printf("TYPE%u", t);
}
*/ printf("NS: %s\n", ldns_get_errorstr_by_id(st));
}
} else {
fprintf(stdout, "%s ", BOGUS);
result = 1;
printf(";; Error verifying denial of existence for name ");
ldns_rdf_print(stdout, labels[i]);
printf("NS: %s\n", ldns_get_errorstr_by_id(status));
}
/* there might be an empty non-terminal, in which case we need to continue */
ent = false;
for (j = 0; j < ldns_rr_list_rr_count(nsec_rrs); j++) {
nsecrr = ldns_rr_list_rr(nsec_rrs, j);
/* For NSEC when the next name is a subdomain of the question */
if (ldns_rr_get_type(nsecrr) == LDNS_RR_TYPE_NSEC &&
ldns_dname_is_subdomain(ldns_rr_rdf(nsecrr, 0), labels[i])) {
ent = true;
/* For NSEC3, the hash matches the name and the type bitmap is empty*/
} else if (ldns_rr_get_type(nsecrr) == LDNS_RR_TYPE_NSEC3) {
hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsecrr, labels[i]);
label0 = ldns_dname_label(ldns_rr_owner(nsecrr), 0);
if (hashed_name && label0 &&
ldns_dname_compare(hashed_name, label0) == 0 &&
ldns_nsec3_bitmap(nsecrr) == NULL) {
ent = true;
}
if (label0) {
LDNS_FREE(label0);
}
if (hashed_name) {
LDNS_FREE(hashed_name);
}
}
}
if (!ent) {
ldns_rr_list_deep_free(nsec_rrs);
ldns_rr_list_deep_free(nsec_rr_sigs);
ldns_pkt_free(local_p);
goto done;
} else {
printf(";; There is an empty non-terminal here, continue\n");
continue;
}
}
if (ldns_resolver_nameserver_count(res) == 0) {
error("No nameservers found for this node");
goto done;
}
}
ldns_pkt_free(local_p);
fprintf(stdout, ";; Domain: ");
ldns_rdf_print(stdout, labels[i]);
fprintf(stdout, "\n");
/* retrieve keys for current domain, and verify them
if they match an already trusted DS, or if one of the
keys used to sign these is trusted, add the keys to
the trusted list */
p = get_dnssec_pkt(res, labels[i], LDNS_RR_TYPE_DNSKEY);
(void) get_key(p, labels[i], &key_list, &key_sig_list);
if (key_sig_list) {
if (key_list) {
current_correct_keys = ldns_rr_list_new();
if ((st = ldns_verify(key_list, key_sig_list, key_list, current_correct_keys)) ==
LDNS_STATUS_OK) {
/* add all signed keys (don't just add current_correct, you'd miss
* the zsk's then */
for (j = 0; j < ldns_rr_list_rr_count(key_list); j++) {
ldns_rr_list_push_rr(correct_key_list, ldns_rr_clone(ldns_rr_list_rr(key_list, j)));
}
/* check whether these keys were signed
* by a trusted keys. if so, these
* keys are also trusted */
new_keys_trusted = false;
for (k = 0; k < ldns_rr_list_rr_count(current_correct_keys); k++) {
for (j = 0; j < ldns_rr_list_rr_count(trusted_ds_rrs); j++) {
if (ldns_rr_compare_ds(ldns_rr_list_rr(current_correct_keys, k),
ldns_rr_list_rr(trusted_ds_rrs, j))) {
new_keys_trusted = true;
}
}
}
/* also all keys are trusted if one of the current correct keys is trusted */
for (k = 0; k < ldns_rr_list_rr_count(current_correct_keys); k++) {
for (j = 0; j < ldns_rr_list_rr_count(trusted_keys); j++) {
if (ldns_rr_compare(ldns_rr_list_rr(current_correct_keys, k),
ldns_rr_list_rr(trusted_keys, j)) == 0) {
new_keys_trusted = true;
}
}
}
if (new_keys_trusted) {
ldns_rr_list_push_rr_list(trusted_keys, key_list);
print_rr_list_abbr(stdout, key_list, TRUST);
ldns_rr_list_free(key_list);
key_list = NULL;
} else {
if (verbosity >= 2) {
printf(";; Signature ok but no chain to a trusted key or ds record\n");
}
print_rr_list_abbr(stdout, key_list, SELF);
ldns_rr_list_deep_free(key_list);
key_list = NULL;
}
} else {
print_rr_list_abbr(stdout, key_list, BOGUS);
result = 2;
ldns_rr_list_deep_free(key_list);
key_list = NULL;
}
ldns_rr_list_free(current_correct_keys);
current_correct_keys = NULL;
} else {
printf(";; No DNSKEY record found for ");
ldns_rdf_print(stdout, labels[i]);
printf("\n");
}
}
ldns_pkt_free(p);
ldns_rr_list_deep_free(key_sig_list);
key_sig_list = NULL;
/* check the DS records for the next child domain */
if (i > 1) {
p = get_dnssec_pkt(res, labels[i-1], LDNS_RR_TYPE_DS);
(void) get_ds(p, labels[i-1], &ds_list, &ds_sig_list);
if (!ds_list) {
ldns_rr_list_deep_free(ds_sig_list);
(void) get_dnssec_rr( p, labels[i-1]
, LDNS_RR_TYPE_CNAME
, &ds_list, &ds_sig_list);
if (ds_list) {
st = ldns_verify( ds_list, ds_sig_list
, correct_key_list
, current_correct_keys);
if (st == LDNS_STATUS_OK) {
printf(";; No DS record found "
"for ");
ldns_rdf_print(stdout,
labels[i-1]);
printf(", but valid CNAME");
} else {
printf(BOGUS " Unable to verify "
"denial of existence for ");
ldns_rdf_print(stdout,
labels[i-1]);
printf(", because of BOGUS CNAME");
}
printf("\n");
ldns_rr_list_deep_free(ds_sig_list);
ldns_pkt_free(p);
ldns_rr_list_deep_free(ds_list);
ds_list = NULL;
ds_sig_list = NULL;
p = NULL;
} else {
ldns_rr_list_deep_free(ds_sig_list);
ldns_pkt_free(p);
p = get_dnssec_pkt(res, name,
LDNS_RR_TYPE_DNSKEY);
(void) get_ds(p, NULL
, &ds_list, &ds_sig_list);
}
}
if (ds_sig_list) {
if (ds_list) {
if (verbosity >= 4) {
printf("VERIFYING:\n");
printf("DS LIST:\n");
ldns_rr_list_print(stdout, ds_list);
printf("SIGS:\n");
ldns_rr_list_print(stdout, ds_sig_list);
printf("KEYS:\n");
ldns_rr_list_print(stdout, correct_key_list);
}
current_correct_keys = ldns_rr_list_new();
if ((st = ldns_verify(ds_list, ds_sig_list, correct_key_list, current_correct_keys)) ==
LDNS_STATUS_OK) {
/* if the ds is signed by a trusted key and a key from correct keys
matches that ds, add that key to the trusted keys */
new_keys_trusted = false;
if (verbosity >= 2) {
printf("Checking if signing key is trusted:\n");
}
for (j = 0; j < ldns_rr_list_rr_count(current_correct_keys); j++) {
if (verbosity >= 2) {
printf("New key: ");
ldns_rr_print(stdout, ldns_rr_list_rr(current_correct_keys, j));
}
for (k = 0; k < ldns_rr_list_rr_count(trusted_keys); k++) {
if (verbosity >= 2) {
printf("\tTrusted key: ");
ldns_rr_print(stdout, ldns_rr_list_rr(trusted_keys, k));
}
if (ldns_rr_compare(ldns_rr_list_rr(current_correct_keys, j),
ldns_rr_list_rr(trusted_keys, k)) == 0) {
if (verbosity >= 2) {
printf("Key is now trusted!\n");
}
for (l = 0; l < ldns_rr_list_rr_count(ds_list); l++) {
ldns_rr_list_push_rr(trusted_ds_rrs, ldns_rr_clone(ldns_rr_list_rr(ds_list, l)));
new_keys_trusted = true;
}
}
}
}
if (new_keys_trusted) {
print_rr_list_abbr(stdout, ds_list, TRUST);
} else {
print_rr_list_abbr(stdout, ds_list, SELF);
}
} else {
result = 3;
print_rr_list_abbr(stdout, ds_list, BOGUS);
}
ldns_rr_list_free(current_correct_keys);
current_correct_keys = NULL;
} else {
/* wait apparently there were no keys either, go back to the ds packet */
ldns_pkt_free(p);
ldns_rr_list_deep_free(ds_sig_list);
p = get_dnssec_pkt(res, labels[i-1], LDNS_RR_TYPE_DS);
(void) get_ds(p, labels[i-1], &ds_list, &ds_sig_list);
status = ldns_verify_denial(p, labels[i-1], LDNS_RR_TYPE_DS, &nsec_rrs, &nsec_rr_sigs);
if (verbosity >= 4) {
printf("NSEC(3) Records to verify:\n");
ldns_rr_list_print(stdout, nsec_rrs);
printf("With signatures:\n");
ldns_rr_list_print(stdout, nsec_rr_sigs);
printf("correct keys:\n");
ldns_rr_list_print(stdout, correct_key_list);
}
if (status == LDNS_STATUS_OK) {
if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, trusted_keys, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", TRUST);
fprintf(stdout, "Existence denied: ");
ldns_rdf_print(stdout, labels[i-1]);
printf(" DS");
fprintf(stdout, "\n");
} else if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, correct_key_list, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", SELF);
fprintf(stdout, "Existence denied: ");
ldns_rdf_print(stdout, labels[i-1]);
printf(" DS");
fprintf(stdout, "\n");
} else {
result = 4;
fprintf(stdout, "%s ", BOGUS);
printf("Error verifying denial of existence for ");
ldns_rdf_print(stdout, labels[i-1]);
printf(" DS");
printf(": %s\n", ldns_get_errorstr_by_id(st));
}
} else {
if (status == LDNS_STATUS_CRYPTO_NO_RRSIG) {
printf(";; No DS for ");
ldns_rdf_print(stdout, labels[i - 1]);
} else {
printf(BOGUS " Unable to verify denial of existence for ");
ldns_rdf_print(stdout, labels[i - 1]);
printf(" DS: %s\n", ldns_get_errorstr_by_id(status));
}
}
if (verbosity >= 2) {
printf(";; No ds record for delegation\n");
}
}
}
ldns_rr_list_deep_free(ds_list);
ldns_pkt_free(p);
} else {
/* if this is the last label, just verify the data and stop */
p = get_dnssec_pkt(res, labels[i], t);
(void) get_dnssec_rr(p, labels[i], t, &dataset, &key_sig_list);
if (dataset && ldns_rr_list_rr_count(dataset) > 0) {
if (key_sig_list && ldns_rr_list_rr_count(key_sig_list) > 0) {
/* If this is a wildcard, you must be able to deny exact match */
if ((st = ldns_verify(dataset, key_sig_list, trusted_keys, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", TRUST);
ldns_rr_list_print(stdout, dataset);
} else if ((st = ldns_verify(dataset, key_sig_list, correct_key_list, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", SELF);
ldns_rr_list_print(stdout, dataset);
} else {
result = 5;
fprintf(stdout, "%s ", BOGUS);
ldns_rr_list_print(stdout, dataset);
printf(";; Error: %s\n", ldns_get_errorstr_by_id(st));
}
} else {
fprintf(stdout, "%s ", UNSIGNED);
ldns_rr_list_print(stdout, dataset);
}
ldns_rr_list_deep_free(dataset);
} else {
status = ldns_verify_denial(p, name, t, &nsec_rrs, &nsec_rr_sigs);
if (status == LDNS_STATUS_OK) {
/* verify the nsec3 themselves*/
if (verbosity >= 5) {
printf("NSEC(3) Records to verify:\n");
ldns_rr_list_print(stdout, nsec_rrs);
printf("With signatures:\n");
ldns_rr_list_print(stdout, nsec_rr_sigs);
printf("correct keys:\n");
ldns_rr_list_print(stdout, correct_key_list);
/*
printf("trusted keys at %p:\n", trusted_keys);
ldns_rr_list_print(stdout, trusted_keys);
*/ }
if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, trusted_keys, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", TRUST);
fprintf(stdout, "Existence denied: ");
ldns_rdf_print(stdout, name);
if (descriptor && descriptor->_name) {
printf(" %s", descriptor->_name);
} else {
printf(" TYPE%u", t);
}
fprintf(stdout, "\n");
} else if ((st = ldns_verify(nsec_rrs, nsec_rr_sigs, correct_key_list, NULL)) == LDNS_STATUS_OK) {
fprintf(stdout, "%s ", SELF);
fprintf(stdout, "Existence denied: ");
ldns_rdf_print(stdout, name);
if (descriptor && descriptor->_name) {
printf(" %s", descriptor->_name);
} else {
printf(" TYPE%u", t);
}
fprintf(stdout, "\n");
} else {
result = 6;
fprintf(stdout, "%s ", BOGUS);
printf("Error verifying denial of existence for ");
ldns_rdf_print(stdout, name);
printf(" type ");
if (descriptor && descriptor->_name) {
printf("%s", descriptor->_name);
} else {
printf("TYPE%u", t);
}
printf(": %s\n", ldns_get_errorstr_by_id(st));
}
ldns_rr_list_deep_free(nsec_rrs);
ldns_rr_list_deep_free(nsec_rr_sigs);
} else {
/*
*/
if (status == LDNS_STATUS_CRYPTO_NO_RRSIG) {
printf("%s ", UNSIGNED);
printf("No data found for: ");
ldns_rdf_print(stdout, name);
printf(" type ");
if (descriptor && descriptor->_name) {
printf("%s", descriptor->_name);
} else {
printf("TYPE%u", t);
}
printf("\n");
} else {
printf(BOGUS " Unable to verify denial of existence for ");
ldns_rdf_print(stdout, name);
printf(" type ");
if (descriptor && descriptor->_name) {
printf("%s", descriptor->_name);
} else {
printf("TYPE%u", t);
}
printf("\n");
}
}
}
ldns_pkt_free(p);
}
new_nss = NULL;
ns_addr = NULL;
ldns_rr_list_deep_free(key_list);
key_list = NULL;
ldns_rr_list_deep_free(key_sig_list);
key_sig_list = NULL;
ds_list = NULL;
ldns_rr_list_deep_free(ds_sig_list);
ds_sig_list = NULL;
}
printf(";;" SELF " self sig OK; " BOGUS " bogus; " TRUST " trusted; " UNSIGNED " unsigned\n");
/* verbose mode?
printf("Trusted keys:\n");
ldns_rr_list_print(stdout, trusted_keys);
printf("trusted dss:\n");
ldns_rr_list_print(stdout, trusted_ds_rrs);
*/
done:
ldns_rr_list_deep_free(trusted_ds_rrs);
ldns_rr_list_deep_free(correct_key_list);
ldns_resolver_deep_free(res);
if (labels) {
for(i = 0 ; i < (ssize_t)labels_count + 2; i++) {
ldns_rdf_deep_free(labels[i]);
}
LDNS_FREE(labels);
}
return result;
}
#endif /* HAVE_SSL */

View File

@@ -0,0 +1,261 @@
/*
* work.c
* Where all the hard work is done
* (c) 2005 NLnet Labs
*
* See the file LICENSE for the license
*
*/
#include "drill.h"
#include <ldns/ldns.h>
/**
* Converts a hex string to binary data
* len is the length of the string
* buf is the buffer to store the result in
* offset is the starting position in the result buffer
*
* This function returns the length of the result
*/
static size_t
hexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len)
{
char c;
int i;
uint8_t int8 = 0;
int sec = 0;
size_t bufpos = 0;
if (len % 2 != 0) {
return 0;
}
for (i=0; i<len; i++) {
c = hexstr[i];
/* case insensitive, skip spaces */
if (c != ' ') {
if (c >= '0' && c <= '9') {
int8 += c & 0x0f;
} else if (c >= 'a' && c <= 'z') {
int8 += (c & 0x0f) + 9;
} else if (c >= 'A' && c <= 'Z') {
int8 += (c & 0x0f) + 9;
} else {
return 0;
}
if (sec == 0) {
int8 = int8 << 4;
sec = 1;
} else {
if (bufpos + offset + 1 <= buf_len) {
buf[bufpos+offset] = int8;
int8 = 0;
sec = 0;
bufpos++;
} else {
error("Buffer too small in hexstr2bin");
}
}
}
}
return bufpos;
}
static size_t
packetbuffromfile(char *filename, uint8_t *wire)
{
FILE *fp = NULL;
int c;
/* stat hack
* 0 = normal
* 1 = comment (skip to end of line)
* 2 = unprintable character found, read binary data directly
*/
int state = 0;
uint8_t *hexbuf = xmalloc(LDNS_MAX_PACKETLEN);
int hexbufpos = 0;
size_t wirelen;
if (strncmp(filename, "-", 2) == 0) {
fp = stdin;
} else {
fp = fopen(filename, "r");
}
if (fp == NULL) {
perror("Unable to open file for reading");
xfree(hexbuf);
return 0;
}
/*verbose("Opened %s\n", filename);*/
c = fgetc(fp);
while (c != EOF && hexbufpos < LDNS_MAX_PACKETLEN) {
if (state < 2 && !isascii(c)) {
/*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/
state = 2;
}
switch (state) {
case 0:
if ( (c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F') )
{
hexbuf[hexbufpos] = (uint8_t) c;
hexbufpos++;
} else if (c == ';') {
state = 1;
} else if (c == ' ' || c == '\t' || c == '\n') {
/* skip whitespace */
}
break;
case 1:
if (c == '\n' || c == EOF) {
state = 0;
}
break;
case 2:
hexbuf[hexbufpos] = (uint8_t) c;
hexbufpos++;
break;
}
c = fgetc(fp);
}
if (c == EOF) {
/*
if (have_drill_opt && drill_opt->verbose) {
verbose("END OF FILE REACHED\n");
if (state < 2) {
verbose("read:\n");
verbose("%s\n", hexbuf);
} else {
verbose("Not printing wire because it contains non ascii data\n");
}
}
*/
}
if (hexbufpos >= LDNS_MAX_PACKETLEN) {
/*verbose("packet size reached\n");*/
}
/* lenient mode: length must be multiple of 2 */
if (hexbufpos % 2 != 0) {
hexbuf[hexbufpos] = (uint8_t) '0';
hexbufpos++;
}
if (state < 2) {
wirelen = hexstr2bin((char *) hexbuf,
hexbufpos,
wire,
0,
LDNS_MAX_PACKETLEN);
} else {
memcpy(wire, hexbuf, (size_t) hexbufpos);
wirelen = (size_t) hexbufpos;
}
if (fp != stdin) {
fclose(fp);
}
xfree(hexbuf);
return wirelen;
}
ldns_buffer *
read_hex_buffer(char *filename)
{
uint8_t *wire;
size_t wiresize;
ldns_buffer *result_buffer = NULL;
wire = xmalloc(LDNS_MAX_PACKETLEN);
wiresize = packetbuffromfile(filename, wire);
result_buffer = LDNS_MALLOC(ldns_buffer);
ldns_buffer_new_frm_data(result_buffer, wire, wiresize);
ldns_buffer_set_position(result_buffer, ldns_buffer_capacity(result_buffer));
xfree(wire);
return result_buffer;
}
ldns_pkt *
read_hex_pkt(char *filename)
{
uint8_t *wire;
size_t wiresize;
ldns_pkt *pkt = NULL;
ldns_status status = LDNS_STATUS_ERR;
wire = xmalloc(LDNS_MAX_PACKETLEN);
wiresize = packetbuffromfile(filename, wire);
if (wiresize > 0) {
status = ldns_wire2pkt(&pkt, wire, wiresize);
}
xfree(wire);
if (status == LDNS_STATUS_OK) {
return pkt;
} else {
fprintf(stderr, "Error parsing hex file: %s\n",
ldns_get_errorstr_by_id(status));
return NULL;
}
}
void
dump_hex(const ldns_pkt *pkt, const char *filename)
{
uint8_t *wire = NULL;
size_t size, i;
FILE *fp;
ldns_status status;
fp = fopen(filename, "w");
if (fp == NULL) {
error("Unable to open %s for writing", filename);
return;
}
status = ldns_pkt2wire(&wire, pkt, &size);
if (status != LDNS_STATUS_OK) {
error("Unable to convert packet: error code %u", status);
LDNS_FREE(wire);
fclose(fp);
return;
}
fprintf(fp, "; 0");
for (i = 1; i < 20; i++) {
fprintf(fp, " %2u", (unsigned int) i);
}
fprintf(fp, "\n");
fprintf(fp, ";--");
for (i = 1; i < 20; i++) {
fprintf(fp, " --");
}
fprintf(fp, "\n");
for (i = 0; i < size; i++) {
if (i % 20 == 0 && i > 0) {
fprintf(fp, "\t;\t%4u-%4u\n", (unsigned int) i-19, (unsigned int) i);
}
fprintf(fp, " %02x", (unsigned int)wire[i]);
}
fprintf(fp, "\n");
fclose(fp);
LDNS_FREE(wire);
}