]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
added drill-trunk to ldns - rm-ed the old .svn dir btw
authorMiek Gieben <miekg@NLnetLabs.nl>
Wed, 31 Aug 2005 08:29:34 +0000 (08:29 +0000)
committerMiek Gieben <miekg@NLnetLabs.nl>
Wed, 31 Aug 2005 08:29:34 +0000 (08:29 +0000)
16 files changed:
drill/ChangeLog [new file with mode: 0644]
drill/Makefile.in [new file with mode: 0644]
drill/README [new file with mode: 0644]
drill/REGRESSIONS [new file with mode: 0644]
drill/chasetrace.c [new file with mode: 0644]
drill/configure.ac [new file with mode: 0644]
drill/dnssec.c [new file with mode: 0644]
drill/drill.1 [new file with mode: 0644]
drill/drill.c [new file with mode: 0644]
drill/drill.h.in [new file with mode: 0644]
drill/drill_util.c [new file with mode: 0644]
drill/drill_util.h [new file with mode: 0644]
drill/error.c [new file with mode: 0644]
drill/install-sh [new file with mode: 0755]
drill/root.c [new file with mode: 0644]
drill/work.c [new file with mode: 0644]

diff --git a/drill/ChangeLog b/drill/ChangeLog
new file mode 100644 (file)
index 0000000..fef63ff
--- /dev/null
@@ -0,0 +1,99 @@
+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 supresses 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 namservers 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 interal 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
diff --git a/drill/Makefile.in b/drill/Makefile.in
new file mode 100644 (file)
index 0000000..157bd4c
--- /dev/null
@@ -0,0 +1,104 @@
+# Standard installation pathnames
+# See the file LICENSE for the license
+SHELL = @SHELL@
+VERSION = @PACKAGE_VERSION@
+basesrcdir = $(shell basename `pwd`)
+srcdir = @srcdir@
+prefix  = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+mandir = @mandir@
+includedir = @INCLUDEDIR@
+
+LDNSDIR = @LDNSDIR@
+CC = @CC@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+INSTALL = $(srcdir)/install-sh -c
+INSTALL_PROGRAM = $(INSTALL)
+
+COMPILE         = $(CC) -Wall $(CPPFLAGS) $(CFLAGS) 
+LINK            = $(CC) $(CFLAGS) $(LDFLAGS) 
+
+LINT            = splint
+LINTFLAGS       = +quiet -weak -warnposix -unrecog -Din_addr_t=uint32_t -Du_int=unsigned -Du_char=uint8_t
+
+LIBOBJ=drill.o drill_util.o error.o root.o work.o chasetrace.o dnssec.o
+LIBSRC=$(LIBOBJ:.o=.c)
+
+HEADER=drill.h drill_util.h
+
+.PHONY:        all clean allclean docclean doc release tags install
+
+all:   drill 
+
+release:       clean docclean tarclean
+       (rm -rf ../drill-$(VERSION)/)
+       (cd .. ; cp -r $(basesrcdir)/ drill-$(VERSION)/)
+       (cd .. ; tar --verbose --exclude ".svn" --create --gzip --file drill-$(VERSION).tar.bz2 drill-$(VERSION)/)
+       (rm -rf ../drill-$(VERSION)/)
+
+tags:  
+       ctags *.[ch]
+
+drill: $(LIBOBJ)
+       $(LINK) -o $@ $(LIBOBJ) $(LIBS)
+
+## implicit rule
+%.o:    %.c $(HEADER)
+       $(COMPILE) -c $<
+
+clean:
+       rm -f *.o
+       rm -f drill
+       rm -f *core
+       rm -f config.h.in~
+       rm -f config.log
+       rm -f config.guess
+       rm -f config.status
+
+docclean:
+       rm -rf doxydoc
+
+allclean: clean docclean
+       rm -f tags
+       rm -f config.log
+       rm -f config.status
+       rm -rf autom4te.cache
+       rm -f config.h
+       rm -f config.h.in
+       rm -f drill.h
+       rm -f configure
+       rm -f Makefile  
+       rm -f aclocal.m4
+
+# exclude configure here
+tarclean: 
+       rm -f tags
+       rm -f config.log
+       rm -f config.status
+       rm -rf autom4te.cache
+       rm -f config.h
+       rm -f drill.h
+       rm -f Makefile  
+
+doc:   
+       doxygen drill.doxygen
+
+install: all
+       $(INSTALL) -d $(DESTDIR)$(bindir)
+       $(INSTALL) drill $(DESTDIR)$(bindir)/drill
+       $(INSTALL) -m 644 drill.1 $(DESTDIR)$(mandir)/man1/drill.1
+
+uninstall:
+       @echo
+       rm -f -- $(bindir)/drill
+       rm -f -- $(mandir)/man1/drill.1
+       @echo
+
+lint:
+       @for i in $(LIBSRC) ; do \
+                $(LINT) $(LINTFLAGS) -I$(LDNSDIR) -I$(srcdir) $(srcdir)/$$i ; \
+                if [ $$? -ne 0 ] ; then exit 1 ; fi ; \
+        done
diff --git a/drill/README b/drill/README
new file mode 100644 (file)
index 0000000..28ce100
--- /dev/null
@@ -0,0 +1,11 @@
+QUICK INSTALL GUIDE
+
+* First install ldns
+  http://www.nlnetlabs.nl/ldns
+
+  and follow the instructions
+
+* Now configure drill and compile it:
+  autoreconf && ./configure --with-ldns && make
+
+  or --with-ldns=<path>, also see ./configure --help
diff --git a/drill/REGRESSIONS b/drill/REGRESSIONS
new file mode 100644 (file)
index 0000000..b8f6be9
--- /dev/null
@@ -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
diff --git a/drill/chasetrace.c b/drill/chasetrace.c
new file mode 100644 (file)
index 0000000..41e8a4e
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * chasetrace.c
+ * Where all the hard work concerning chasing
+ * and tracing is done
+ * (c) 2005 NLnet Labs
+ *
+ * See the file LICENSE for the license
+ *
+ */
+
+#include "drill.h"
+#include <ldns/dns.h>
+
+/**
+ * trace down from the root to name
+ */
+
+/* same naive method as in drill0.9 
+ * We resolver _ALL_ the names, which is ofcourse 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
+ */
+ldns_pkt *
+do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t,
+               ldns_rr_class c)
+{
+       ldns_resolver *res;
+       ldns_pkt *p;
+       ldns_rr_list *new_nss_a;
+       ldns_rr_list *new_nss_aaaa;
+       ldns_rr_list *final_answer;
+       ldns_rr_list *new_nss;
+       ldns_rr_list *hostnames;
+       ldns_rr_list *ns_addr;
+       uint16_t loop_count;
+       ldns_rdf *pop; 
+       ldns_status status;
+       size_t i;
+       
+       res = ldns_resolver_new();
+       /* transfer some properties of local_res to res,
+        * because they were given on the commandline */
+       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));
+
+       loop_count = 0;
+       new_nss_a = NULL;
+       new_nss_aaaa = NULL;
+       new_nss = NULL;
+       ns_addr = NULL;
+       final_answer = NULL;
+       p = ldns_pkt_new();
+
+       /* setup the root nameserver in the new resolver */
+       if (ldns_resolver_push_nameserver_rr_list(res, global_dns_root) != LDNS_STATUS_OK) {
+               return NULL;
+       }
+
+       /* this must be a real query to local_res */
+       status = ldns_resolver_send(&p, local_res, ldns_dname_new_frm_str("."), LDNS_RR_TYPE_NS, c, 0);
+
+       if (status == LDNS_STATUS_OK) {
+               drill_pkt_print(stdout, local_res, p);
+       } else {
+               printf("cannot use local resolver\n");
+               return 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 */
+                       return NULL;
+               }
+
+               new_nss_a = ldns_pkt_rr_list_by_type(p,
+                               LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL);
+               new_nss_aaaa = ldns_pkt_rr_list_by_type(p,
+                               LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL);
+               new_nss = ldns_pkt_rr_list_by_type(p,
+                               LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY);
+
+               if (qdebug != -1) {
+                       ldns_rr_list_print(stdout, new_nss);
+               }
+               /* checks itself for qdebug */
+               drill_pkt_print_footer(stdout, local_res, p);
+               
+               /* remove the old nameserver from the resolver */
+               while((pop = ldns_resolver_pop_nameserver(res))) { /* do it */ }
+
+               if (!new_nss_aaaa && !new_nss_a) {
+                       /* 
+                        * no nameserver found!!! 
+                        * try to resolve the names we do got 
+                        */
+                       for(i = 0; i < ldns_rr_list_rr_count(new_nss); i++) {
+                               /* get the name of the nameserver */
+                               pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0);
+                               /* retrieve it's addresses */
+                               ns_addr = ldns_rr_list_cat_clone(ns_addr,
+                                       ldns_get_rr_list_addr_by_name(local_res, pop, c, 0));
+                       }
+                       if (ns_addr) {
+                               if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) != 
+                                               LDNS_STATUS_OK) {
+                                       error("Error adding new nameservers");
+                                       ldns_pkt_free(p); 
+                                       return NULL;
+                               }
+                       } else {
+                               error("%s", "Could not find the ip addr; abort");
+                               ldns_pkt_free(p);
+                               return NULL;
+                       }
+               }
+
+               /* add the new ones */
+               if (new_nss_aaaa) {
+                       if (ldns_resolver_push_nameserver_rr_list(res, new_nss_aaaa) != 
+                                       LDNS_STATUS_OK) {
+                               error("%s", "adding new nameservers");
+                               ldns_pkt_free(p); 
+                               return NULL;
+                       }
+               }
+               if (new_nss_a) {
+                       if (ldns_resolver_push_nameserver_rr_list(res, new_nss_a) != 
+                                       LDNS_STATUS_OK) {
+                               error("adding new nameservers");
+                               ldns_pkt_free(p); 
+                               return NULL;
+                       }
+               }
+
+               if (loop_count++ > 20) {
+                       /* unlikely that we are doing something usefull */
+                       error("Looks like we are looping");
+                       ldns_pkt_free(p); 
+                       return NULL;
+               }
+               
+               status = ldns_resolver_send(&p, res, name, t, c, 0);
+               new_nss_aaaa = NULL;
+               new_nss_a = NULL;
+               ns_addr = NULL;
+       }
+       /* mesg("Came out of recursion"); */
+
+       status = ldns_resolver_send(&p, res, name, t, c, 0);
+
+       if (!p) {
+               return NULL;
+       }
+
+       hostnames = ldns_get_rr_list_name_by_addr(local_res, 
+                       ldns_pkt_answerfrom(p), 0, 0);
+
+       new_nss = ldns_pkt_authority(p);
+       final_answer = ldns_pkt_answer(p);
+
+       if (qdebug != -1) {
+               ldns_rr_list_print(stdout, final_answer);
+               ldns_rr_list_print(stdout, new_nss);
+
+       }
+       drill_pkt_print_footer(stdout, local_res, p);
+       ldns_pkt_free(p); 
+       return NULL;
+}
+
+
+/* do a secure trace from the root down to the local leaf node 
+ * requested.
+ *
+ * this alg is complicated. We try to do it all in one go, resolving
+ * and keeping track of the security information
+ *
+ * update this some more. Miek; TODO
+ */
+ldns_status
+do_secure_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, 
+               ldns_rr_class c, ldns_rr_list *trusted_keys)
+{
+       ldns_resolver *res;
+       ldns_pkt *p;
+
+       ldns_rdf   *cur_zone;
+       uint16_t loop_count;
+       ldns_rr_list *keys;
+       ldns_status status;
+       bool secure;
+
+       /* always as for dnskey records, but when secure is true also
+        * ask for DS
+        */
+       
+       secure = true;
+       cur_zone = ldns_dname_new_frm_data(1, ".");
+       res = ldns_resolver_new();
+
+       /* transfer some properties of local_res to res,
+        * because they were given on the commandline */
+       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));
+
+       loop_count = 0;
+       p = ldns_pkt_new();
+
+       /* setup the root nameserver in the new resolver */
+       if (ldns_resolver_push_nameserver_rr_list(res, global_dns_root) != LDNS_STATUS_OK) {
+               return LDNS_STATUS_ERR;
+       }
+
+       cur_zone = ldns_dname_new_frm_str(".");
+       
+       /* this must be a real query to local_res */
+       status = ldns_resolver_send(&p, local_res, cur_zone, LDNS_RR_TYPE_NS, c, 0);
+
+       if (status == LDNS_STATUS_OK) {
+               drill_pkt_print(stdout, local_res, p);
+       } else {
+               printf("cannot use local resolver\n");
+               return LDNS_STATUS_ERR;
+       }
+       /* next ask the for keys */
+       keys = get_rr(res, cur_zone, LDNS_RR_TYPE_DNSKEY, c);
+       if (keys) {
+               ldns_rr_list_print(stdout, keys);
+       } else {
+               secure = false;
+       }
+       if (secure) {
+               /* if true get the DS for the child zone */
+       }
+
+       /* we can now start our decent to the zone we're looking
+        * and query for ds/dnskey along the way
+        */
+       
+
+       return LDNS_STATUS_ERR; /* need to finish this function */
+}
+
+/**
+ * Chase the given rr to a known key
+ *
+ * Based on drill 0.9
+ * pkt optional?
+ * TODO: lots 
+       keys
+       status codes
+       helper functions (for instance for rrset owner retrieval
+       rest ;)
+       if this is moved to the library, status codes should be added and prints removed
+ */
+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 *rrset = NULL;
+       ldns_status result;
+       
+       ldns_rr_list *sigs;
+       ldns_rr *cur_sig;
+       uint16_t sig_i;
+       ldns_rr_list *keys;
+       uint16_t key_i;
+       uint16_t tkey_i;
+       ldns_pkt *pkt;
+       
+       pkt = ldns_pkt_clone(pkt_o);
+       
+       if (!name) {
+               mesg("no name to chase\n");
+               ldns_pkt_free(pkt);
+               return LDNS_STATUS_EMPTY_LABEL;
+       }
+       
+       if (pkt) {
+               rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
+                               name,
+                               type,
+                               LDNS_SECTION_ANSWER
+                               );
+       } else {
+               /* no packet? */
+               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) {
+                       return LDNS_STATUS_NETWORK_ERR;
+               }
+               rrset = ldns_pkt_rr_list_by_name_and_type(pkt,
+                               name,
+                               type,
+                               LDNS_SECTION_ANSWER
+                               );
+       }
+
+       sigs = ldns_pkt_rr_list_by_name_and_type(pkt,
+                       name,
+                       LDNS_RR_TYPE_RRSIG,
+                       LDNS_SECTION_ANY_NOQUESTION
+                       );
+       
+       for (sig_i = 0; sig_i < ldns_rr_list_rr_count(sigs); sig_i++) {
+               cur_sig = ldns_rr_clone(ldns_rr_list_rr(sigs, sig_i));
+               
+               keys = ldns_pkt_rr_list_by_name_and_type(pkt,
+                               ldns_rr_rdf(cur_sig, 7),
+                               LDNS_RR_TYPE_DNSKEY,
+                               LDNS_SECTION_ANY_NOQUESTION
+                               );
+               
+               if (qdebug != -1) {
+                       printf(";; Signed by: ");
+                       ldns_rdf_print(stdout, ldns_rr_rdf(cur_sig, 7));
+                       printf("\n");
+               }
+
+               if (!keys) {
+                       ldns_pkt_free(pkt);
+                       pkt = NULL;
+                       pkt = ldns_resolver_query(res,
+                                       ldns_rr_rdf(cur_sig, 7),
+                                       LDNS_RR_TYPE_DNSKEY, c, qflags);
+                       if (!pkt) {
+                               ldns_rr_list_deep_free(rrset);
+                               ldns_rr_list_deep_free(sigs);
+                               return LDNS_STATUS_NETWORK_ERR;
+                       }
+
+                       keys = ldns_pkt_rr_list_by_name_and_type(pkt,
+                                       ldns_rr_rdf(cur_sig, 7),
+                                       LDNS_RR_TYPE_DNSKEY,
+                                       LDNS_SECTION_ANY_NOQUESTION
+                                       );
+               }
+               if(!keys) {
+                       mesg("No key for data found in that zone!\n");
+                       ldns_rr_list_deep_free(rrset);
+                       ldns_rr_list_deep_free(sigs);
+                       ldns_pkt_free(pkt);
+                       ldns_rr_free(cur_sig);
+                       return LDNS_STATUS_CRYPTO_NO_DNSKEY;
+               } else {
+                       for (key_i = 0; key_i < ldns_rr_list_rr_count(keys); key_i++) {
+                               if (ldns_verify_rrsig(rrset, cur_sig, ldns_rr_list_rr(keys, key_i))) {
+                                       for (tkey_i = 0; tkey_i < ldns_rr_list_rr_count(trusted_keys); tkey_i++) {
+                                               if (ldns_rr_compare_ds(ldns_rr_list_rr(keys, key_i),
+                                                                  ldns_rr_list_rr(trusted_keys, tkey_i)
+                                                                 )) {
+                                                       mesg("Key is trusted\n");
+                                                       ldns_rr_list_deep_free(rrset);
+                                                       ldns_rr_list_deep_free(sigs);
+                                                       ldns_rr_list_deep_free(keys);
+                                                       ldns_pkt_free(pkt);
+                                                       ldns_rr_free(cur_sig);
+                                                       return LDNS_STATUS_OK;
+                                               }
+                                       }
+                                       result = do_chase(res, ldns_rr_rdf(cur_sig, 7), LDNS_RR_TYPE_DS, c, trusted_keys, pkt, qflags);
+                                       ldns_rr_list_deep_free(rrset);
+                                       ldns_rr_list_deep_free(sigs);
+                                       ldns_rr_list_deep_free(keys);
+                                       ldns_pkt_free(pkt);
+                                       ldns_rr_free(cur_sig);
+                                       return result;
+                               } else {
+                                       mesg("Bad signature of wrong key\n");
+                               }
+                       }
+                       ldns_rr_list_deep_free(keys);
+               }
+               ldns_rr_free(cur_sig);
+       }
+       ldns_rr_list_deep_free(rrset);
+       ldns_pkt_free(pkt);
+       if (ldns_rr_list_rr_count(sigs) > 0) {
+               ldns_rr_list_deep_free(sigs);
+               return LDNS_STATUS_CRYPTO_NO_TRUSTED_DNSKEY;
+       } else {
+               return LDNS_STATUS_CRYPTO_NO_RRSIG;
+       }
+}
diff --git a/drill/configure.ac b/drill/configure.ac
new file mode 100644 (file)
index 0000000..dc6e95f
--- /dev/null
@@ -0,0 +1,89 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.57)
+AC_INIT(drill, 1.0-pre3, drill@nlnetlabs.nl, drill1.0-pre)
+AC_CONFIG_SRCDIR([drill_util.h])
+
+AC_AIX
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_MAKE_SET
+
+# Checks for libraries.
+# Checks for header files.
+#AC_HEADER_STDC
+#AC_HEADER_SYS_WAIT
+# do the very minimum - we can always extend this
+AC_CHECK_HEADERS([getopt.h stdlib.h stdio.h assert.h netinet/in.hctype.h])
+AC_CHECK_HEADERS(sys/param.h sys/mount.h,,,
+[
+  [
+   #if HAVE_SYS_PARAM_H
+   # include <sys/param.h>
+   #endif
+  ]
+])
+
+# ripped from http://autoconf-archive.cryp.to/check_ssl.html
+# check for ldns
+AC_ARG_WITH(ldns, AC_HELP_STRING([--with-ldns=PATHNAME],[]))
+AC_MSG_CHECKING(for ldns/dns.h)
+#echo "[" $withval "]"
+for dir in $withval /usr/local/ldns /usr/lib/ldns /usr/ldns /usr/pkg /usr/local /usr; do
+ldnsdir="$dir"
+#echo "$dir/include/ldns/dns.h"
+#echo "$dir/ldns/dns.h"
+if test -f "$dir/include/ldns/dns.h"; then
+    found_ldns="yes";
+    LDNSDIR="$ldnsdir/include/"
+    CFLAGS="$CFLAGS -I$LDNSDIR -DHAVE_LDNS";
+    CXXFLAGS="$CXXFLAGS -I$ldnsdir/include/ -DHAVE_LDNS";
+    break;
+fi
+if test -f "$dir/ldns/dns.h"; then
+    found_ldns="yes";
+    LDNSDIR="$ldnsdir/"
+    CFLAGS="$CFLAGS -I$LDNSDIR -DHAVE_LDNS";
+    CXXFLAGS="$CXXFLAGS -I$ldnsdir/ -DHAVE_LDNS";
+    break
+fi
+done
+if test x_$found_ldns != x_yes; then
+        AC_MSG_RESULT(no)
+       AC_MSG_ERROR(Cannot find ldns libraries)
+else
+#        printf "ldns found in $ldnsdir\n";
+       LIBS="$LIBS -lldns";
+       LDFLAGS="$LDFLAGS -L$ldnsdir/lib";
+       LDFLAGS="$LDFLAGS -L$ldnsdir/.libs"; # hack for dev.
+       HAVE_LDNS=yes
+        AC_MSG_RESULT(yes)
+fi
+AC_SUBST(HAVE_LDNS)
+AC_SUBST(LDNSDIR, [$LDNSDIR])
+
+# I don't use these
+# Checks for typedefs, structures, and compiler characteristics.
+#AC_TYPE_UID_T
+#AC_TYPE_MODE_T
+#AC_TYPE_OFF_T
+#AC_TYPE_SIZE_T
+#AC_STRUCT_TM
+
+# Checks for library functions.
+# check for ldns
+#AC_FUNC_CHOWN
+#AC_FUNC_FORK
+#AC_FUNC_MALLOC
+#AC_FUNC_MKTIME
+#AC_FUNC_STAT
+#AC_CHECK_FUNCS([mkdir rmdir strchr strrchr strstr])
+
+#AC_DEFINE_UNQUOTED(SYSCONFDIR, "$sysconfdir")
+
+AC_CONFIG_FILES([Makefile
+                drill.h
+                 ])
+AC_CONFIG_HEADER([config.h])
+AC_OUTPUT
diff --git a/drill/dnssec.c b/drill/dnssec.c
new file mode 100644 (file)
index 0000000..ee615ca
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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/dns.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) {
+               /* oops */
+               return NULL;
+       } else {
+               found = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANY_NOQUESTION);
+       }
+       return found;
+}
+
+void
+drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p)
+{
+       ldns_rr_list *new_nss;
+       ldns_rr_list *hostnames;
+
+       if (qdebug == -1) {
+               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);
+
+       /* new_nss can be empty.... */
+
+       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 {
+               fprintf(fd, "%s", ldns_rdf2str(ldns_pkt_answerfrom(p)));
+       }
+       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;
+
+       if (qdebug == -1) {
+               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 {
+               fprintf(fd, "%s", ldns_rdf2str(ldns_pkt_answerfrom(p)));
+       }
+       fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
+}
diff --git a/drill/drill.1 b/drill/drill.1
new file mode 100644 (file)
index 0000000..d8d1799
--- /dev/null
@@ -0,0 +1,181 @@
+.\" @(#)drill.1 1.7.0 14-Jul-2004 OF; 
+.TH drill 1 "28 Apr 2005"
+.SH NAME
+drill \- get (debug) information out of DNS(SEC)
+.SH SYNOPSIS
+.B drill
+[
+.IR OPTION
+]
+.IR name
+[
+.IR @server
+]
+[
+.IR type
+]
+[
+.IR class
+]
+
+.SH DESCRIPTION
+\fBdrill\fR is a tool to designed to get all sorts of information out of the
+DNS. It is specificly 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
+The arguments to \fBdrill\fR may be placed in any order. 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
+\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 to reverse lookup there is defaults to 'PTR'.
+
+.PP
+\fIname\fR
+Ask for this name.
+
+.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 a the jelte.nlnetlab.nl domain.
+
+.TP
+\fBdrill -TD www.example.com\fR
+Do a DNSSEC (-D) trace (-T) from the rootservers down to www.example.com.
+
+.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 automaticly enabled.
+
+.TP
+\fB\-S
+Chase the signature(s) of 'name' to a known key or as high up in
+the tree as possible.
+
+.TP
+\fB\-T
+Trace \fIname\fR from the root down. When using this option the @server and
+the type arguments are not used.
+
+.TP
+\fB\-V
+Be more verbose. Enable once for more messages on the screen. Enable twice
+for a hexdump of the packets sent.
+
+.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
+Don't try the next nameserver on SERVFAIL. The default is to do this.
+
+.TP
+\fB\-b \fIsize\fR
+
+
+.TP
+\fB\-c
+Use TCP/IP when querying a server.
+
+
+.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\-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.
+
+.TP
+\fB\-p \fIport\fR
+Use this port instead of the DNS default of 53.
+
+.TP
+\fB\-r
+Don't set the RD bit in the query - the default is yes.
+
+.TP
+\fB\-s
+When encountering a DNSKEY print the DS also.
+
+.TP
+\fB\-u
+Use UDP when querying a server. This is the default.
+
+.TP
+\fB\-v
+
+.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 loopup. The type argument is not used, it is preset to PTR.
+
+.SH DNSSEC
+When calling \fBdrill\fR with \fI-S\fR it chases down signatures (RRSIG) to
+a known key. This uses a bottom-up approach.
+[Jelte please fill in the blanks here] 
+.PP
+With \fI-TD\fR (trace + DNSSEC) \fBdrill\fR will securely trace from the 
+root down. If the optional \fI-k\fR argument is given a genuine chain of
+trust can be established.
+[bla bla, Miek please add more]
+
+.SH AUTHOR
+Jelte Jansen and Miek Gieben. Both of NLnet Labs.
+
+.SH REPORTING BUGS
+Report bugs to <drill@nlnetlabs.nl>.
+
+.SH BUGS
+
+.SH LIMITATIONS
+None - you can do \fIeverything\fR with it, including washing your car.
+
+.SH COPYRIGHT
+Copyright (c) 2004 NLnet Labs.
+Licensed under the GPL 2. 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.
diff --git a/drill/drill.c b/drill/drill.c
new file mode 100644 (file)
index 0000000..fd53e46
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * drill.c
+ * the main file of drill
+ * (c) 2005 NLnet Labs
+ *
+ * See the file LICENSE for the license
+ *
+ */
+
+#include "drill.h"
+#include <ldns/dns.h>
+
+/* query debug, 2 hex dumps */
+int8_t         qdebug; /* -1, be quiet, 1 show question, 2 show hex */
+
+static void
+usage(FILE *stream, const char *progname)
+{
+       fprintf(stream, "  Usage: %s name [@server] [type] [class]\n", progname);
+       fprintf(stream, "\t<name>  can be a domain name or an IP address (-x lookups)\n");
+       fprintf(stream, "\t<type>  defaults to A\n");
+       fprintf(stream, "\t<class> defaults to IN\n");
+       fprintf(stream, "\n\targuments may be placed in random order\n");
+       fprintf(stream, "\n  Options:\n");
+       fprintf(stream, "\t-D\t\tenable DNSSEC (DO bit)\n");
+       fprintf(stream, "\t-T\t\ttrace from the root down to <name>\n");
+       fprintf(stream, "\t-S\t\tchase signature(s) from <name> to a know key [*]\n");
+       fprintf(stream, "\t-V\t\tverbose mode (once shows question, twice for hexdumps)\n");
+       fprintf(stream, "\t-Q\t\tquiet mode (overrules -V)\n");
+       fprintf(stream, "\n");
+       fprintf(stream, "\t-f file\t\tread packet from file and send it\n");
+       fprintf(stream, "\t-i file\t\tread packet from file and print it\n");
+       fprintf(stream, "\t-w file\t\twrite answer packet to file\n");
+       fprintf(stream, "\t-q file\t\twrite query packet to file\n");
+       fprintf(stream, "\t-h\t\tshow this help\n");
+       fprintf(stream, "\t-v\t\tshow version\n");
+       fprintf(stream, "\n  Query options:\n");
+       fprintf(stream, "\t-4\t\tstay on ip4\n");
+       fprintf(stream, "\t-6\t\tstay on ip6\n");
+       fprintf(stream, "\t-a\t\tonly query the first nameserver (default is to try all)\n");
+       fprintf(stream, "\t-b <bufsize>\tuse <bufsize> as the buffer size (defaults to 512 b)\n");
+       fprintf(stream, "\t-c\t\tsend the query with tcp (connected)\n");
+       fprintf(stream, "\t-k <file>\tspecify a file that contains a trusted DNSSEC key [**]\n");
+       fprintf(stream, "\t\t\tused to verify any signatures in the current answer\n");
+       fprintf(stream, "\t-p <port>\tuse <port> as remote port number\n");
+       fprintf(stream, "\t-r\t\tdon't set the RD bit in queries (default is on)\n");
+       fprintf(stream, "\t-s\t\tshow the DS RR for each key in a packet\n");
+       fprintf(stream, "\t-u\t\tsend the query with udp (the default)\n");
+       fprintf(stream, "\t-x\t\tdo a reverse (PTR) lookup\n");
+        fprintf(stream, "\t-y <name:key[:algo]>\tspecify named base64 tsig key, and optional an\n\t\t\talgorithm (defaults to hmac-md5.sig-alg.reg.int)\n");
+       fprintf(stream, "\t-z\t\tdon't randomize the nameservers before use\n");
+       fprintf(stream, "\n  [*] = enables/implies DNSSEC\n");
+       fprintf(stream, "  [**] = can be given more than once\n");
+       fprintf(stream, "\n  drill@nlnetlabs.nl | www.nlnetlabs.nl/dnssec/drill.html\n");
+}
+
+/**
+ * Prints the drill version to stderr
+ */
+static void
+version(FILE *stream, const char *progname)
+{
+        fprintf(stream, "%s version %s\n", progname, DRILL_VERSION);
+        fprintf(stream, "Written by NLnet Labs.\n");
+        fprintf(stream, "\nCopyright (c) 2004, 2005 NLnet Labs.\n");
+        fprintf(stream, "Licensed under the GPL 2.\n");
+        fprintf(stream, "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n");
+        fprintf(stream, "FOR A PARTICULAR PURPOSE.\n");
+}
+
+
+/**
+ * Main function of drill
+ * parse the arguments and prepare a query
+ */
+int
+main(int argc, char *argv[])
+{
+        ldns_resolver  *res = NULL;
+        ldns_resolver   *cmdline_res = NULL; /* only used to resolv @name names */
+       ldns_rr_list    *cmdline_rr_list = NULL;
+       ldns_rdf        *cmdline_dname = NULL;
+        ldns_rdf       *qname, *qname_tmp;
+        ldns_pkt       *pkt;
+        ldns_pkt       *qpkt;
+        char           *serv;
+        char           *name;
+       char            *progname;
+       char            *query_file = NULL;
+       char            *answer_file = NULL;
+       ldns_rdf        *serv_rdf;
+        ldns_rr_type   type;
+        ldns_rr_class  clas;
+       int             i, c;
+       int             int_type;
+       int             int_clas;
+       int             PURPOSE;
+       char            *tsig_name = NULL;
+       char            *tsig_data = NULL;
+       char            *tsig_algorithm = NULL;
+       ldns_rr         *dnssec_key = NULL;
+       size_t          tsig_separator;
+       size_t          tsig_separator2;
+       ldns_rr         *axfr_rr;
+       
+       /* list of keys used in dnssec operations */
+       ldns_rr_list    *key_list = ldns_rr_list_new(); 
+       /* what key verify the current answer */
+       ldns_rr_list    *key_verified;
+
+       /* resolver options */
+       uint16_t        qflags;
+       uint16_t        qbuf;
+       uint16_t        qport;
+       uint8_t         qfamily;
+       bool            qdnssec;
+       bool            qfail;
+       bool            qds;
+       bool            qusevc;
+       bool            qrandom;
+
+       int             result = 0;
+       
+       int_type = -1; serv = NULL; type = 0; 
+       int_clas = -1; name = NULL; clas = 0;
+       qname = NULL; 
+       progname = strdup(argv[0]);
+       
+       PURPOSE = DRILL_QUERY;
+       qflags = LDNS_RD;
+       qport = LDNS_PORT;
+       qdebug = 0;
+       qdnssec = false;
+       qfamily = LDNS_RESOLV_INETANY;
+       qfail = false;
+       qds = false;
+       qbuf = 0;
+       qusevc = false;
+       qrandom = true;
+       key_verified = NULL;
+
+       if (argc == 0) {
+               usage(stdout, progname);
+               result = EXIT_FAILURE;
+               goto exit;
+       }
+
+       /* string from orig drill: "i:w:I46Sk:TNp:b:DsvhVcuaq:f:xr" */
+       /* global first, query opt next, option with parm's last
+        * and sorted */
+       while ((c = getopt(argc, argv, "46DITSVQf:i:w:q:achruvxzy:sp:b:k:")) != -1) {
+               switch(c) {
+                       /* global options */
+                       case '4':
+                               qfamily = LDNS_RESOLV_INET;
+                               break;
+                       case '6':
+                               qfamily = LDNS_RESOLV_INET6;
+                               break;
+                       case 'D':
+                               qdnssec = true;
+                               break;
+                       case 'I':
+                               /* reserved for backward compatibility */
+                               break;
+                       case 'T':
+                               PURPOSE = DRILL_TRACE;
+                               break;
+                       case 'S':
+                               PURPOSE = DRILL_CHASE;
+                               break;
+                       case 'V':
+                               if (qdebug != -1) {
+                                       qdebug++;
+                               }
+                               break;
+                       case 'Q':
+                               qdebug = -1;
+                       case 'f':
+                               query_file = optarg;
+                               break;
+                       case 'i':
+                               answer_file = optarg;
+                               PURPOSE = DRILL_AFROMFILE;
+                               break;
+                       case 'w':
+                               answer_file = optarg;
+                               break;
+                       case 'q':
+                               query_file = optarg;
+                               PURPOSE = DRILL_QTOFILE;
+                       /* query options */
+                       case 'a':
+                               qfail = true;
+                               break;
+                       case 'b':
+                               qbuf = (uint16_t)atoi(optarg);
+                               if (qbuf == 0) {
+                                       error("%s", "<bufsize> could not be converted");
+                                       result = EXIT_FAILURE;
+                                       goto exit;
+                               }
+                               break;
+                       case 'c':
+                               qusevc = true;
+                               break;
+                       case 'k':
+                               dnssec_key = read_key_file(optarg);
+                               if (!dnssec_key) {
+                                       result = EXIT_FAILURE;
+                                       goto exit;
+                               }
+                               ldns_rr_list_push_rr(key_list, dnssec_key);
+                               qdnssec = true; /* enable that too */
+                               break;
+                       case 'p':
+                               qport = (uint16_t)atoi(optarg);
+                               if (qport == 0) {
+                                       error("%s", "<port> could not be converted");
+                                       result = EXIT_FAILURE;
+                                       goto exit;
+                               }
+                               break;
+                       case 's':
+                               qds = true;
+                               break;
+                       case 'r':
+                               qflags = qflags & ~LDNS_RD; 
+                               break;
+                       case 'u':
+                               qusevc = false;
+                               break;
+                       case 'v':
+                               version(stdout, progname);
+                               result = EXIT_SUCCESS;
+                               goto exit;
+                       case 'x':
+                               type = LDNS_RR_TYPE_PTR;
+                               int_type = 1; /* set this so the type does not change */
+                               PURPOSE = DRILL_REVERSE;
+                               break;
+                       case 'y':
+                               if (strchr(optarg, ':')) {
+                                       tsig_separator = (size_t) (strchr(optarg, ':') - optarg);
+                                       if (strchr(optarg + tsig_separator + 1, ':')) {
+                                               tsig_separator2 = (size_t) (strchr(optarg + tsig_separator + 1, ':') - optarg);
+                                               tsig_algorithm = xmalloc(strlen(optarg) - tsig_separator2);
+                                               strncpy(tsig_algorithm, optarg + tsig_separator2 + 1, strlen(optarg) - tsig_separator2);
+                                               tsig_algorithm[strlen(optarg) - tsig_separator2 - 1] = '\0';
+                                       } else {
+                                               tsig_separator2 = strlen(optarg);
+                                               tsig_algorithm = xmalloc(26);
+                                               strncpy(tsig_algorithm, "hmac-md5.sig-alg.reg.int.", 25);
+                                               tsig_algorithm[25] = '\0';
+                                       }
+                                       tsig_name = xmalloc(tsig_separator + 1);
+                                       tsig_data = xmalloc(tsig_separator2 - tsig_separator);
+                                       strncpy(tsig_name, optarg, tsig_separator);
+                                       strncpy(tsig_data, optarg + tsig_separator + 1, tsig_separator2 - tsig_separator - 1);
+                                       /* strncpy does not append \0 if source is longer than n */
+                                       tsig_name[tsig_separator] = '\0';
+                                       tsig_data[ tsig_separator2 - tsig_separator - 1] = '\0';
+                               }
+                               break;
+                       case 'z':
+                               qrandom = false;
+                               break;
+                       case 'h':
+                       default:
+                               usage(stdout, progname);
+                               result = EXIT_SUCCESS;
+                               goto exit;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       /* do a secure trace when requested */
+       if (PURPOSE == DRILL_TRACE && qdnssec) {
+               if (ldns_rr_list_rr_count(key_list) == 0) {
+                       warning("%s", "No keys were given. Will not be able to verify authenticity!");
+               }
+               PURPOSE = DRILL_SECTRACE;
+       }
+
+       /* parse the arguments, with multiple arguments, the last argument
+        * found is used */
+       for(i = 0; i < argc; i++) {
+
+               /* if ^@ then it's a server */
+               if (argv[i][0] == '@') {
+                       serv = argv[i] + 1;
+                       continue;
+               }
+               /* if has a dot, it's a name */
+               if (strchr(argv[i], '.')) {
+                       name = argv[i];
+                       continue;
+               }
+               /* if it matches a type, it's a type */
+               if (int_type == -1) {
+                       type = ldns_get_rr_type_by_name(argv[i]);
+                       if (type != 0) {
+                               int_type = 0;
+                               continue;
+                       }
+               }
+               /* if it matches a class, it's a class */
+               if (int_clas == -1) {
+                       clas = ldns_get_rr_class_by_name(argv[i]);
+                       if (clas != 0) {
+                               int_clas = 0;
+                               continue;
+                       }
+               }
+               /* it all fails assume it's a name */
+               name = argv[i];
+       }
+       /* defaults if not given */
+       if (int_clas == -1) {
+               clas = LDNS_RR_CLASS_IN;
+       }
+       if (int_type == -1) {
+               type = LDNS_RR_TYPE_A;
+       }
+
+       /* if we're asking for DNSSEC record, act as if -D with given */
+       if (type == LDNS_RR_TYPE_DNSKEY ||
+                       type == LDNS_RR_TYPE_RRSIG ||
+                       type == LDNS_RR_TYPE_NSEC) {
+               qdnssec = true;
+       }
+
+       /* set the nameserver to use */
+       if (!serv) {
+               /* no server given make a resolver from /etc/resolv.conf */
+               res = ldns_resolver_new_frm_file(NULL);
+               if (!res) {
+                       result = EXIT_FAILURE;
+                       goto exit;
+               }
+       } else {
+               res = ldns_resolver_new();
+               if (!res) {
+                       result = EXIT_FAILURE;
+                       goto exit;
+               }
+               /* add the nameserver */
+               serv_rdf = ldns_rdf_new_addr_frm_str(serv);
+               if (!serv_rdf) {
+                       /* try to resolv the name if possible */
+                       cmdline_res = ldns_resolver_new_frm_file(NULL);
+                       
+                       if (!cmdline_res) {
+                               error("%s", "@server ip could not be converted");
+                               result = EXIT_FAILURE;
+                               goto exit;
+                       }
+                       ldns_resolver_set_dnssec(cmdline_res, qdnssec);
+                       ldns_resolver_set_ip6(cmdline_res, qfamily);
+                       ldns_resolver_set_fail(cmdline_res, qfail);
+                       ldns_resolver_set_usevc(cmdline_res, qusevc);
+
+                       cmdline_dname = ldns_dname_new_frm_str(serv);
+                       cmdline_rr_list = ldns_get_rr_list_addr_by_name(
+                                               cmdline_res, 
+                                               cmdline_dname,
+                                               clas,
+                                               qflags);
+                       ldns_rdf_deep_free(cmdline_dname);
+                       if (!cmdline_rr_list) {
+                               error("%s", "could not find any address for the name");
+                               result = EXIT_FAILURE;
+                               goto exit;
+                       } else {
+                               if (ldns_resolver_push_nameserver_rr_list(
+                                               res, 
+                                               cmdline_rr_list
+                                       ) != LDNS_STATUS_OK) {
+                                       error("%s", "pushing nameserver");
+                                       result = EXIT_FAILURE;
+                                       goto exit;
+                               }
+                       }
+               } else {
+                       if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) {
+                               error("%s", "pushing nameserver");
+                               result = EXIT_FAILURE;
+                               goto exit;
+                       } else {
+                               ldns_rdf_deep_free(serv_rdf);
+                       }
+               }
+       }
+       /* set the resolver options */
+       ldns_resolver_set_port(res, qport);
+       if (qdebug > 0 && qdebug != -1) {
+               ldns_resolver_set_debug(res, true);
+       } else {
+               ldns_resolver_set_debug(res, false);
+       }
+       ldns_resolver_set_dnssec(res, qdnssec);
+       ldns_resolver_set_dnssec_cd(res, qdnssec);
+       ldns_resolver_set_ip6(res, qfamily);
+       ldns_resolver_set_fail(res, qfail);
+       ldns_resolver_set_usevc(res, qusevc);
+       ldns_resolver_set_random(res, qrandom);
+       if (qbuf != 0) {
+               ldns_resolver_set_edns_udp_size(res, qbuf);
+       }
+
+       if (!name && 
+           PURPOSE != DRILL_AFROMFILE &&
+           !query_file
+          ) {
+               usage(stdout, progname);
+               result = EXIT_FAILURE;
+               goto exit;
+       }
+
+       if (tsig_name && tsig_data) {
+               ldns_resolver_set_tsig_keyname(res, tsig_name);
+               ldns_resolver_set_tsig_keydata(res, tsig_data);
+               ldns_resolver_set_tsig_algorithm(res, tsig_algorithm);
+       }
+       
+       /* main switching part of drill */
+       switch(PURPOSE) {
+               case DRILL_TRACE:
+                       /* do a trace from the root down */
+                       init_root();
+                       qname = ldns_dname_new_frm_str(name);
+                       /* don't care about return packet */
+                       (void)do_trace(res, qname, type, clas);
+                       break;
+               case DRILL_SECTRACE:
+                       /* do a secure trace from the root down */
+                       init_root();
+                       qname = ldns_dname_new_frm_str(name);
+                       /* don't care about return packet */
+                       result = do_secure_trace(res, qname, type, clas, key_list);
+                       break;
+               case DRILL_CHASE:
+                       qname = ldns_dname_new_frm_str(name);
+                       
+                       ldns_resolver_set_dnssec(res, true);
+                       ldns_resolver_set_dnssec_cd(res, true);
+                       /* set dnssec implies udp_size of 4096 */
+                       ldns_resolver_set_edns_udp_size(res, 4096);
+                       if (!qname) {
+                               error("%s", "making qname");
+                               result = EXIT_FAILURE;
+                               goto exit;
+                       }
+                       pkt = ldns_resolver_query(res, qname, type, clas, qflags);
+                       
+                       if (!pkt) {
+                               error("%s", "error pkt sending");
+                               result = EXIT_FAILURE;
+                       } else {
+                               if (qdebug != -1) {
+                                       ldns_pkt_print(stdout, pkt);
+                               }
+                               
+                               if (!ldns_pkt_answer(pkt)) {
+                                       mesg("%s", "No answer in packet");
+                               } else {
+                                       result = do_chase(res, qname, type,
+                                                         clas, key_list, 
+                                                         pkt, qflags);
+                                       if (result == LDNS_STATUS_OK) {
+                                               if (qdebug != -1) {
+                                                       mesg("%s", "Chase successful");
+                                               }
+                                               result = 0;
+                                       } else {
+                                               if (qdebug != -1) {
+                                                       mesg("Chase failed: %s", ldns_get_errorstr_by_id(result));
+                                               }
+                                               /*result = EXIT_FAILURE;*/
+                                       }
+                               }
+                               ldns_pkt_free(pkt);
+                       }
+                       break;
+               case DRILL_AFROMFILE:
+                       pkt = read_hex_pkt(answer_file);
+                       if (pkt) {
+                               if (qdebug != -1) {
+                                       ldns_pkt_print(stdout, pkt);
+                               }
+                               ldns_pkt_free(pkt);
+                       }
+                       
+                       break;
+               case DRILL_QTOFILE:
+                       qname = ldns_dname_new_frm_str(name);
+                       if (!qname) {
+                               error("%s", "making qname\n");
+                               result = EXIT_FAILURE;
+                               goto exit;
+                       }
+
+                       qpkt = ldns_pkt_query_new(qname, type, clas, qflags);
+                       
+                       dump_hex(qpkt, query_file);
+                       
+                       ldns_pkt_free(qpkt);
+                       break;
+               case DRILL_NSEC:
+                       break;
+               case DRILL_REVERSE:
+                       /* name should be an ip addr */
+                       qname = ldns_rdf_new_addr_frm_str(name);
+                       if (!qname) {
+                               error("%s", "-x implies an ip address");
+                               result = EXIT_FAILURE;
+                               goto exit;
+                       }
+                       qname_tmp = qname;
+                       qname = ldns_rdf_address_reverse(qname);
+                       ldns_rdf_deep_free(qname_tmp);
+                       
+                       /* create a packet and set the RD flag on it */
+                       pkt = ldns_resolver_query(res, qname, type, clas, qflags);
+                       if (!pkt)  {
+                               error("%s", "pkt sending\n");
+                               result = EXIT_FAILURE;
+                       } else {
+                               if (qdebug != -1) {
+                                       ldns_pkt_print(stdout, pkt);
+                               }
+                               ldns_pkt_free(pkt);
+                       }
+                       break;
+               case DRILL_QUERY:
+               default:
+                       if (query_file) {
+                               qpkt = read_hex_pkt(query_file);
+                               if (qpkt) {
+                                       (void) ldns_resolver_send_pkt(&pkt, res, qpkt);
+                               }
+                       } else {
+                               qname = ldns_dname_new_frm_str(name);
+                               if (!qname) {
+                                       error("%s", "error in making qname\n");
+                                       result = EXIT_FAILURE;
+                                       goto exit;
+                               }
+
+                               if (type == LDNS_RR_TYPE_AXFR) {
+                                       (void) ldns_axfr_start(res, qname, clas);
+
+                                       axfr_rr = ldns_axfr_next(res);
+                                       while (axfr_rr) {
+                                               if (qdebug != -1) {
+                                                       ldns_rr_print(stdout, axfr_rr);
+                                                       printf("\n");
+                                               }
+                                               ldns_rr_free(axfr_rr);
+                                               axfr_rr = ldns_axfr_next(res);
+                                       }
+
+                                       goto exit;
+                               } else {
+                                       /* create a packet and set the RD flag on it */
+                                       pkt = ldns_resolver_query(res, qname, type, clas, qflags);
+                               }
+                       }
+                       
+                       if (!pkt)  {
+                               error("%s", "no packet received\n");
+                               result = EXIT_FAILURE;
+                       } else {
+                               if (qdebug != -1) {
+                                       ldns_pkt_print(stdout, pkt);
+                               }
+                               if (qds) {
+                                       if (qdebug != -1) {
+                                               print_ds_of_keys(pkt);
+                                               printf("\n");
+                                       }
+                               }
+                       
+                               if (ldns_rr_list_rr_count(key_list) > 0) {
+                                       /* -k's were given on the cmd line */
+                                       ldns_rr_list *rrset_verified;
+                                       uint16_t key_count;
+
+                                       rrset_verified = ldns_pkt_rr_list_by_name_and_type(
+                                                       pkt, qname, type, 
+                                                       LDNS_SECTION_ANY_NOQUESTION);
+
+                                       if (type == LDNS_RR_TYPE_ANY) {
+                                               /* don't verify this */
+                                               break;
+                                       }
+
+                                       if (qdebug != -1) {
+                                               printf("; ");
+                                               ldns_rr_list_print(stdout, rrset_verified);
+                                       }
+
+                                       /* verify */
+                                       key_verified = ldns_pkt_verify(pkt, type, qname, key_list, NULL);
+
+                                       if (key_verified) {
+                                               for(key_count = 0; key_count < ldns_rr_list_rr_count(key_verified);
+                                                               key_count++) {
+                                                       if (qdebug != -1) {
+                                                               mesg("VALIDATED by id = %d, owner = ",
+                                                                               (int)ldns_calc_keytag(
+                                                                                                     ldns_rr_list_rr(key_verified, key_count)));
+                                                               ldns_rdf_print(stdout, ldns_rr_owner(
+                                                                                       ldns_rr_list_rr(key_list, key_count)));
+                                                               printf("\n");
+                                                       }
+                                               }
+                                       } else {
+                                               for(key_count = 0; key_count < ldns_rr_list_rr_count(key_list);
+                                                               key_count++) {
+                                                       if (qdebug != -1) {
+                                                               mesg("BOGUS by id = %d, owner = ",
+                                                                               (int)ldns_calc_keytag(
+                                                                                                     ldns_rr_list_rr(key_list, key_count)));
+                                                               ldns_rdf_print(stdout, ldns_rr_owner(
+                                                                                       ldns_rr_list_rr(key_list, key_count)));
+                                                               printf("\n");
+                                                       }
+                                               }
+
+                                       }
+
+                               }
+                               if (answer_file) {
+                                       dump_hex(pkt, answer_file);
+                               }
+                               ldns_pkt_free(pkt); 
+                       }
+                       
+                       break;
+       }
+
+       exit:
+       ldns_rdf_deep_free(qname);
+       ldns_resolver_deep_free(res);
+       ldns_resolver_deep_free(cmdline_res);
+       ldns_rr_list_deep_free(key_list);
+       ldns_rr_list_deep_free(cmdline_rr_list);
+       xfree(progname);
+/*
+       xfree(tsig_name);
+*/
+       xfree(tsig_data);
+       xfree(tsig_algorithm);
+       return result;
+}
diff --git a/drill/drill.h.in b/drill/drill.h.in
new file mode 100644 (file)
index 0000000..a189835
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * drill.h
+ * the main header file of drill
+ * (c) 2005 NLnet Labs
+ *
+ * See the file LICENSE for the license
+ *
+ */
+#ifndef _DRILL_H_
+#define _DRILL_H_
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif /* HAVE_STDINT_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_REVERSE  6
+#define DRILL_SECTRACE         7
+
+extern ldns_rr_list *global_dns_root;
+extern bool qds;
+
+extern int8_t qdebug;
+
+ldns_pkt       *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_status    do_secure_trace(ldns_resolver *res, ldns_rdf *name, ldns_rr_type type, 
+               ldns_rr_class c, ldns_rr_list *trusted_keys);
+/* dnssec.c */
+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_rr        *read_key_file(const char *filename);
+ldns_pkt       *read_hex_pkt(char *filename);
+void           init_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, ...);
+#endif /* _DRILL_H_ */
diff --git a/drill/drill_util.c b/drill/drill_util.c
new file mode 100644 (file)
index 0000000..122b3bf
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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/dns.h>
+
+/* lnds_rr_new_frm_fp?? */
+ldns_rr *
+read_key_file(const char *filename)
+{
+       FILE *fp;
+       char line[LDNS_MAX_PACKETLEN];
+       char c;
+       size_t i = 0;
+       
+       fp = fopen(filename, "r");
+       if (!fp) {
+               fprintf(stderr, "Unable to open %s: ", filename);
+               perror("");
+               return NULL;
+       }
+       
+       while ((c = fgetc(fp)) && i < LDNS_MAX_PACKETLEN && c != EOF) {
+               line[i] = c;
+               i++;
+       }
+       line[i] = '\0';
+       
+       fclose(fp);
+       
+       if (i <= 0) {
+               return NULL;
+       } else {
+               return ldns_rr_new_frm_str(line, 0, NULL);
+       }
+}
+
+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;
+}
+
+/*
+ * 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++) {
+                       ds = ldns_key_rr2ds(ldns_rr_list_rr(keys, i));
+                       if (ds) {
+                               printf("; ");
+                               ldns_rr_print(stdout, ds);
+                               printf("\n");
+                       }
+               }
+       }
+}
+
+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);
+       }
+}
diff --git a/drill/drill_util.h b/drill/drill_util.h
new file mode 100644 (file)
index 0000000..eebfe45
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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/dns.h>
+
+/**
+ * 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);
+
+/**
+ * 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_ */
diff --git a/drill/error.c b/drill/error.c
new file mode 100644 (file)
index 0000000..1981df0
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+ * error.c
+ *
+ * error reporting routines
+ * basicly wrappers around printf
+ *
+ * (c) 2005 NLnet Labs
+ *
+ * See the file LICENSE for the license
+ *
+ */
+
+#include "drill.h"
+#include <ldns/dns.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 (qdebug == -1) {
+               return;
+       }
+       fprintf(stdout, ";; ");
+       va_start(args, fmt);
+       verbose_va_list(fmt, args);
+       va_end(args);
+}
+
+/* print stuff when in verbose mode (1) */
+void
+verbose(const char *fmt, ...)
+{
+       va_list args;
+       if (qdebug < 1) {
+               return;
+       }
+
+       va_start(args, fmt);
+       verbose_va_list(fmt, args);
+       va_end(args);
+}
+
+/* print stuff when in vverbose mode (2) */
+void
+vverbose(const char *fmt, ...)
+{
+       va_list args;
+       if (qdebug < 2) {
+               return;
+       }
+
+       va_start(args, fmt);
+       verbose_va_list(fmt, args);
+       va_end(args);
+}
+
+static void
+debug_va_list(const char *fmt, va_list args)
+{
+        vfprintf(stderr, fmt, args);
+        fprintf(stderr, "\n");
+}
+
+void
+debug(const char *fmt, ...)
+{
+       va_list args;
+       fprintf(stderr, "[DEBUG] ");
+       va_start(args, fmt);
+       debug_va_list(fmt, args);
+       va_end(args);
+}
diff --git a/drill/install-sh b/drill/install-sh
new file mode 100755 (executable)
index 0000000..6ce63b9
--- /dev/null
@@ -0,0 +1,294 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+#
+# 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.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+       -c) instcmd=$cpprog
+           shift
+           continue;;
+
+       -d) dir_arg=true
+           shift
+           continue;;
+
+       -m) chmodcmd="$chmodprog $2"
+           shift
+           shift
+           continue;;
+
+       -o) chowncmd="$chownprog $2"
+           shift
+           shift
+           continue;;
+
+       -g) chgrpcmd="$chgrpprog $2"
+           shift
+           shift
+           continue;;
+
+       -s) stripcmd=$stripprog
+           shift
+           continue;;
+
+       -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+           shift
+           continue;;
+
+       -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+           shift
+           continue;;
+
+       *)  if [ x"$src" = x ]
+           then
+               src=$1
+           else
+               # this colon is to work around a 386BSD /bin/sh bug
+               :
+               dst=$1
+           fi
+           shift
+           continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+       echo "$0: no input file specified" >&2
+       exit 1
+else
+       :
+fi
+
+if [ x"$dir_arg" != x ]; then
+       dst=$src
+       src=""
+
+       if [ -d "$dst" ]; then
+               instcmd=:
+               chmodcmd=""
+       else
+               instcmd=$mkdirprog
+       fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+       if [ -f "$src" ] || [ -d "$src" ]
+       then
+               :
+       else
+               echo "$0: $src does not exist" >&2
+               exit 1
+       fi
+
+       if [ x"$dst" = x ]
+       then
+               echo "$0: no destination specified" >&2
+               exit 1
+       else
+               :
+       fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+       if [ -d "$dst" ]
+       then
+               dst=$dst/`basename "$src"`
+       else
+               :
+       fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+       '
+IFS="${IFS-$defaultIFS}"
+
+oIFS=$IFS
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS=$oIFS
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+       pathcomp=$pathcomp$1
+       shift
+
+       if [ ! -d "$pathcomp" ] ;
+        then
+               $mkdirprog "$pathcomp"
+       else
+               :
+       fi
+
+       pathcomp=$pathcomp/
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+       $doit $instcmd "$dst" &&
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+       if [ x"$transformarg" = x ]
+       then
+               dstfile=`basename "$dst"`
+       else
+               dstfile=`basename "$dst" $transformbasename |
+                       sed $transformarg`$transformbasename
+       fi
+
+# don't allow the sed command to completely eliminate the filename
+
+       if [ x"$dstfile" = x ]
+       then
+               dstfile=`basename "$dst"`
+       else
+               :
+       fi
+
+# Make a couple of temp file names in the proper directory.
+
+       dsttmp=$dstdir/_inst.$$_
+       rmtmp=$dstdir/_rm.$$_
+
+# Trap to clean up temp files at exit.
+
+       trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+       trap '(exit $?); exit' 1 2 13 15
+
+# Move or copy the file name to the temp name
+
+       $doit $instcmd "$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 $instcmd $src $dsttmp" command.
+
+       if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
+       if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
+       if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
+       if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
+
+# 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.
+
+{
+       if [ -f "$dstdir/$dstfile" ]
+       then
+               $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
+               $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
+               {
+                 echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+                 (exit 1); exit
+               }
+       else
+               :
+       fi
+} &&
+
+# Now rename the file to the real destination.
+
+       $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+
+{
+       (exit 0); exit
+}
diff --git a/drill/root.c b/drill/root.c
new file mode 100644 (file)
index 0000000..db54f42
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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/dns.h>
+
+/* a global list of the root-servers */
+ldns_rr_list *global_dns_root;
+
+/* 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();
+
+       r = ldns_rr_new_frm_str("a.root-servers.net 3600 IN A 198.41.0.4", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+
+       r = ldns_rr_new_frm_str("b.root-servers.net 3600 IN A 192.228.79.201", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+
+       r = ldns_rr_new_frm_str("c.root-servers.net 3600 IN A 192.33.4.12", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("d.root-servers.net 3600 IN A 128.8.10.90", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("e.root-servers.net 3600 IN A 192.203.230.10", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("f.root-servers.net 3600 IN A 192.5.5.241", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("g.root-servers.net 3600 IN A 192.112.36.4", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("h.root-servers.net 3600 IN A 128.63.2.53", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("i.root-servers.net 3600 IN A 192.36.148.17", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("j.root-servers.net 3600 IN A 192.58.128.30", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("k.root-servers.net 3600 IN A 193.0.14.129", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("l.root-servers.net 3600 IN A 198.32.64.12", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+       
+       r = ldns_rr_new_frm_str("m.root-servers.net 3600 IN A 202.12.27.33", 0, NULL);
+       ldns_rr_list_push_rr(global_dns_root, r);
+}
diff --git a/drill/work.c b/drill/work.c
new file mode 100644 (file)
index 0000000..ca14ca1
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * 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/dns.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
+ */
+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 {
+                               /*
+                               warning("Error in reading hex data: \n");
+                               warning("%s ('%c' at %d, should read %d bytes)\n", hexstr, c, i, len);
+                               */
+                               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 {
+                                       fprintf(stderr, "Buffer too small in hexstr2bin\n");
+                                       exit(1);
+                               }
+                       }
+               }
+        }
+        return bufpos;
+}
+
+size_t
+packetbuffromfile(char *filename, uint8_t *wire)
+{
+       FILE *fp = NULL;
+       char 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;
+                       default:
+                               fprintf(stderr, "unknown state while reading %s\n", filename);
+                               xfree(hexbuf);
+                               return 0;
+                               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;
+       }
+       xfree(hexbuf);
+       return wirelen;
+}      
+
+ldns_pkt *
+read_hex_pkt(char *filename)
+{
+       uint8_t *wire;
+       size_t wiresize;
+       
+       ldns_pkt *pkt = NULL;
+       
+       ldns_status status;
+       FILE *fp;
+       
+       fp = fopen(filename, "r");
+       
+       if (fp == NULL) {
+               fprintf(stderr, "Unable to open %s\n", filename);
+               perror("");
+               return NULL;
+       }
+       
+       wire = xmalloc(LDNS_MAX_PACKETLEN);
+       
+       wiresize = packetbuffromfile(filename, wire);
+       
+       if (wiresize > 0) {
+               status = ldns_wire2pkt(&pkt, wire, wiresize);
+       }
+       
+       xfree(wire);
+       
+       return pkt;
+}
+
+void
+dump_hex(const ldns_pkt *pkt, const char *filename)
+{
+       uint8_t *wire;// = xmalloc((packet->udppacketsize)*21);
+       size_t size, i;
+       FILE *fp;
+       ldns_status status;
+       
+       fp = fopen(filename, "w");
+       
+       if (fp == NULL) {
+               fprintf(stderr, "Unable to open %s for writing", filename);
+               return;
+       }
+       
+       status = ldns_pkt2wire(&wire, pkt, &size);
+       
+       if (status != LDNS_STATUS_OK) {
+               fprintf(stderr, "Unable to convert packet: error code %u\n", status);
+               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]);
+       }
+       fclose(fp);
+}