--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+# -*- 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
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+.\" @(#)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.
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/**
+ * 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);
+}
--- /dev/null
+#!/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
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}