]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
unbound-anchor work
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 23 Sep 2010 13:51:29 +0000 (13:51 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 23 Sep 2010 13:51:29 +0000 (13:51 +0000)
git-svn-id: file:///svn/unbound/trunk@2242 be551aaa-1e26-0410-a405-d3ace91eadb9

Makefile.in
config.h.in
configure
configure.ac
doc/Changelog
doc/unbound-anchor.8.in [new file with mode: 0644]
makedist.sh
smallapp/unbound-anchor.c [new file with mode: 0644]
winrc/rsrc_unbound_anchor.rc [new file with mode: 0644]

index e9926fcb1d5da80af6b65a4df9eb2f27a3bbe80f..9c711687406b29615f4b993ddbed2dd36f375942 100644 (file)
@@ -110,6 +110,8 @@ CONTROL_SRC=smallapp/unbound-control.c smallapp/worker_cb.c $(COMMON_SRC)
 CONTROL_OBJ=$(addprefix $(BUILD),$(CONTROL_SRC:.c=.lo)) $(COMPAT_OBJ)
 HOST_SRC=smallapp/unbound-host.c
 HOST_OBJ=$(addprefix $(BUILD),$(HOST_SRC:.c=.lo)) $(filter-out $(BUILD)compat/ctime_r.lo, $(COMPAT_OBJ))
+UBANCHOR_SRC=smallapp/unbound-anchor.c
+UBANCHOR_OBJ=$(addprefix $(BUILD),$(UBANCHOR_SRC:.c=.lo)) $(filter-out $(BUILD)compat/ctime_r.lo, $(COMPAT_OBJ))
 TESTBOUND_SRC=testcode/testbound.c testcode/ldns-testpkts.c \
        daemon/worker.c daemon/acl_list.c daemon/daemon.c daemon/stats.c \
        testcode/replay.c testcode/fake_event.c $(filter-out util/netevent.c \
@@ -141,7 +143,7 @@ ALL_SRC=$(sort $(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
        $(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
        $(MEMSTATS_SRC) $(CHECKCONF_SRC) $(LIBUNBOUND_SRC) $(HOST_SRC) \
        $(ASYNCLOOK_SRC) $(STREAMTCP_SRC) $(PERF_SRC) $(DELAYER_SRC) \
-       $(HARVEST_SRC) $(CONTROL_SRC))
+       $(HARVEST_SRC) $(CONTROL_SRC) $(UBANCHOR_SRC))
 ALL_OBJ=$(addprefix $(BUILD),$(ALL_SRC:.c=.lo) \
        $(addprefix compat/,$(LIBOBJS:.o=.lo))) $(COMPAT_OBJ)
 
@@ -149,6 +151,7 @@ ifeq "$(UB_ON_WINDOWS)" "yes"
   DAEMON_SRC+=winrc/win_svc.c winrc/w_inst.c
   DAEMON_OBJ+=$(BUILD)winrc/rsrc_unbound.o $(BUILD)winrc/win_svc.lo
   HOST_OBJ+=$(BUILD)winrc/rsrc_unbound_host.o
+  UBANCHOR_OBJ+=$(BUILD)winrc/rsrc_unbound_anchor.o
   CONTROL_OBJ+=$(BUILD)winrc/rsrc_unbound_control.o
   CHECKCONF_OBJ+=$(BUILD)winrc/rsrc_unbound_checkconf.o
 
@@ -188,7 +191,7 @@ $(BUILD)%.lo:    $(srcdir)/%.c
        @-if test ! -d $(dir $@); then $(INSTALL) -d $(patsubst %/,%,$(dir $@)); fi
        $Q$(COMPILE) -o $@ -c $<
 
-all:   $(COMMON_OBJ) unbound$(EXEEXT) unbound-checkconf$(EXEEXT) lib unbound-host$(EXEEXT) unbound-control$(EXEEXT) unbound-control-setup $(WINAPPS)
+all:   $(COMMON_OBJ) unbound$(EXEEXT) unbound-checkconf$(EXEEXT) lib unbound-host$(EXEEXT) unbound-control$(EXEEXT) unbound-anchor$(EXEEXT) unbound-control-setup $(WINAPPS)
 
 TEST_BIN=$(addsuffix $(EXEEXT),asynclook delayer harvest lock-verify \
        memstats perf pktview signit streamtcp testbound unittest)
@@ -238,6 +241,10 @@ unbound-host$(EXEEXT):     $(HOST_OBJ) libunbound.la $(ldnslib)
        $(INFO) Link $@
        $Q$(LINK) -o $@ $(sort $(HOST_OBJ)) -L. -L.libs -lunbound $(LIBS)
 
+unbound-anchor$(EXEEXT):       $(UBANCHOR_OBJ) libunbound.la $(ldnslib)
+       $(INFO) Link $@
+       $Q$(LINK) -o $@ $(sort $(UBANCHOR_OBJ)) -L. -L.libs -lunbound -lexpat -lssl $(LIBS)
+
 unbound-service-install$(EXEEXT):      $(SVCINST_OBJ)
        $(INFO) Link $@
        $Q$(LINK) -o $@ $(sort $(SVCINST_OBJ)) $(LIBS)
@@ -343,7 +350,7 @@ util/configparser.c util/configparser.h:  $(srcdir)/util/configparser.y
 
 clean:
        rm -f *.o *.d *.lo *~ tags
-       rm -f unbound$(EXEEXT) unbound-checkconf$(EXEEXT) unbound-host$(EXEEXT) unbound-control$(EXEEXT) unbound-control-setup libunbound.la
+       rm -f unbound$(EXEEXT) unbound-checkconf$(EXEEXT) unbound-host$(EXEEXT) unbound-control$(EXEEXT) unbound-anchor$(EXEEXT) unbound-control-setup libunbound.la
        rm -rf autom4te.cache .libs build doc/html doc/xml
 
 realclean: clean
@@ -380,6 +387,7 @@ strip:
        $(STRIP) unbound-checkconf$(EXEEXT)
        $(STRIP) unbound-control$(EXEEXT)
        $(STRIP) unbound-host$(EXEEXT)
+       $(STRIP) unbound-anchor$(EXEEXT)
 
 install:       all
        $(INSTALL) -m 755 -d $(DESTDIR)$(sbindir)
@@ -394,6 +402,7 @@ install:    all
        $(LIBTOOL) --mode=install cp unbound-checkconf$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-checkconf$(EXEEXT)
        $(LIBTOOL) --mode=install cp unbound-control$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-control$(EXEEXT)
        $(LIBTOOL) --mode=install cp unbound-host$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-host$(EXEEXT)
+       $(LIBTOOL) --mode=install cp unbound-anchor$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-anchor$(EXEEXT)
 ifeq "$(WITH_PYTHONMODULE)" "yes"
        $(INSTALL) -m 755 -d $(DESTDIR)$(PYTHON_SITE_PKG)
        $(INSTALL) -c -m 644 pythonmod/unboundmodule.py $(DESTDIR)$(PYTHON_SITE_PKG)/unboundmodule.py
@@ -407,6 +416,7 @@ endif
        $(INSTALL) -c -m 644 doc/unbound.8 $(DESTDIR)$(mandir)/man8
        $(INSTALL) -c -m 644 doc/unbound-checkconf.8 $(DESTDIR)$(mandir)/man8
        $(INSTALL) -c -m 644 doc/unbound-control.8 $(DESTDIR)$(mandir)/man8
+       $(INSTALL) -c -m 644 doc/unbound-anchor.8 $(DESTDIR)$(mandir)/man8
        $(INSTALL) -c -m 644 doc/unbound.conf.5 $(DESTDIR)$(mandir)/man5
        $(INSTALL) -c -m 644 $(srcdir)/doc/unbound-host.1 $(DESTDIR)$(mandir)/man1
        $(INSTALL) -c -m 644 doc/libunbound.3 $(DESTDIR)$(mandir)/man3
@@ -417,8 +427,8 @@ endif
        $(LIBTOOL) --mode=finish $(DESTDIR)$(libdir)
 
 uninstall:
-       rm -f -- $(DESTDIR)$(sbindir)/unbound$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-checkconf$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-host$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-control$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-control-setup
-       rm -f -- $(DESTDIR)$(mandir)/man8/unbound.8 $(DESTDIR)$(mandir)/man8/unbound-checkconf.8 $(DESTDIR)$(mandir)/man5/unbound.conf.5 $(DESTDIR)$(mandir)/man8/unbound-control.8
+       rm -f -- $(DESTDIR)$(sbindir)/unbound$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-checkconf$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-host$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-control$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-anchor$(EXEEXT) $(DESTDIR)$(sbindir)/unbound-control-setup
+       rm -f -- $(DESTDIR)$(mandir)/man8/unbound.8 $(DESTDIR)$(mandir)/man8/unbound-checkconf.8 $(DESTDIR)$(mandir)/man5/unbound.conf.5 $(DESTDIR)$(mandir)/man8/unbound-control.8 $(DESTDIR)$(mandir)/man8/unbound-anchor.8
        rm -f -- $(DESTDIR)$(mandir)/man1/unbound-host.1 $(DESTDIR)$(mandir)/man3/libunbound.3
        rm -f -- $(DESTDIR)$(includedir)/unbound.h
        $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/libunbound.la
index 7c6e557c52d84b4320b8c6ea7379c3c55a8b6174..7eddf74a498c8de81bf42ce0938c2577843982ff 100644 (file)
@@ -84,6 +84,9 @@
 /* Define to 1 if you have the `ev_loop' function. */
 #undef HAVE_EV_LOOP
 
+/* Define to 1 if you have the <expat.h> header file. */
+#undef HAVE_EXPAT_H
+
 /* Define to 1 if you have the `fcntl' function. */
 #undef HAVE_FCNTL
 
index 493488fd2df9b8a25eaae3ff082dd448dfac9a77..b10d2d07535a11bf57606d7861e6287550c8634b 100755 (executable)
--- a/configure
+++ b/configure
@@ -12421,7 +12421,7 @@ CC="$lt_save_CC"
 
 
 # Checks for header files.
-for ac_header in stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h
+for ac_header in stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h expat.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
@@ -16542,7 +16542,7 @@ _ACEOF
 
 
 
-ac_config_files="$ac_config_files Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8"
+ac_config_files="$ac_config_files Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8"
 
 ac_config_headers="$ac_config_headers config.h"
 
@@ -17497,6 +17497,7 @@ do
     "doc/example.conf") CONFIG_FILES="$CONFIG_FILES doc/example.conf" ;;
     "doc/libunbound.3") CONFIG_FILES="$CONFIG_FILES doc/libunbound.3" ;;
     "doc/unbound.8") CONFIG_FILES="$CONFIG_FILES doc/unbound.8" ;;
+    "doc/unbound-anchor.8") CONFIG_FILES="$CONFIG_FILES doc/unbound-anchor.8" ;;
     "doc/unbound-checkconf.8") CONFIG_FILES="$CONFIG_FILES doc/unbound-checkconf.8" ;;
     "doc/unbound.conf.5") CONFIG_FILES="$CONFIG_FILES doc/unbound.conf.5" ;;
     "doc/unbound-control.8") CONFIG_FILES="$CONFIG_FILES doc/unbound-control.8" ;;
index 493feaa88727c2ae9c75e245a86574c21d848baa..dd3c4d9d1942ce29e9d56f42f526014a474a6496 100644 (file)
@@ -218,7 +218,7 @@ AC_CHECK_TOOL(STRIP, strip)
 ACX_LIBTOOL_C_ONLY
 
 # Checks for header files.
-AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h],,, [AC_INCLUDES_DEFAULT])
+AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h expat.h],,, [AC_INCLUDES_DEFAULT])
 
 # check for types.  
 # Using own tests for int64* because autoconf builtin only give 32bit.
@@ -816,6 +816,6 @@ void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
 #define UNBOUND_DNS_PORT 53
 ])
 
-AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8])
+AC_CONFIG_FILES([Makefile doc/example.conf doc/libunbound.3 doc/unbound.8 doc/unbound-anchor.8 doc/unbound-checkconf.8 doc/unbound.conf.5 doc/unbound-control.8])
 AC_CONFIG_HEADER([config.h])
 AC_OUTPUT
index eb42f476504b9c79f2a7a1cc95d4e4d0f2bef1d6..fb754462e27bf71b84dd3f349c947b9157ebc383 100644 (file)
@@ -1,3 +1,6 @@
+23 September 2010: Wouter
+       - unbound-anchor app, unbound requires libexpat (xml parser library).
+
 22 September 2010: Wouter
        - compliance with draft-ietf-dnsop-default-local-zones-14, removed
          reverse ipv6 orchid prefix from builtin list.
diff --git a/doc/unbound-anchor.8.in b/doc/unbound-anchor.8.in
new file mode 100644 (file)
index 0000000..269a617
--- /dev/null
@@ -0,0 +1,64 @@
+.TH "unbound-anchor" "8" "@date@" "NLnet Labs" "unbound @version@"
+.\"
+.\" unbound-control.8 -- unbound remote control manual
+.\"
+.\" Copyright (c) 2008, NLnet Labs. All rights reserved.
+.\"
+.\" See LICENSE for the license.
+.\"
+.\"
+.SH "NAME"
+.LP
+.B unbound\-anchor
+\- Unbound anchor utility.
+.SH "SYNOPSIS"
+.B unbound\-anchor
+.RB [ opts ]
+.SH "DESCRIPTION"
+.B Unbound\-anchor
+performs setup or update of the root trust anchor for DNSSEC validation.
+It can be run (as root) from the commandline, or run as part of startup
+scripts.  Before you start the \fIunbound\fR(8) DNS server.
+.P
+It provides builtin default contents for the root anchor and root update
+certificate files.
+.P
+It tests if the root anchor file works, and if not, and an update is possible,
+attempts to update the root anchor using the root update certificate.
+It performs a https fetch of root-anchors.xml and checks the results, if
+all checks are successful, it updates the root anchor file.  Otherwise
+the root anchor file is unchanged.  It performs RFC5011 tracking if the
+DNSSEC information available via the DNS makes that possible.
+.P
+If does not perform an update if the certificate is expired, if the network
+is down or other errors occur.
+.P
+The available options are:
+.TP
+.B \-a \fIfile
+The root anchor key file, that is read in and written out.
+Default is /usr/local/etc/unbound/root.key.
+.TP
+.B \-c \fIfile
+The root update certificate file, that is read in. It can be updated too.
+Default is /usr/local/etc/unbound/icannbundle.pem.
+.TP
+.B \-h
+Show the version and commandline option help.
+.TP
+.B \-v
+More verbose.  Prints output detailing what happens.
+.TP
+.B \-C \fIcfgfile
+Config file to read with debug settings.
+.SH "FILES"
+.TP
+.I /usr/local/etc/unbound/root.key
+The root anchor file, updated with 5011 tracking, and read and written to.
+.TP
+.I /usr/local/etc/unbound/icannbundle.pem
+The trusted self\-signed certificate that is used to verify the downloaded
+DNSSEC root trust anchor.
+.SH "SEE ALSO"
+\fIunbound.conf\fR(5), 
+\fIunbound\fR(8).
index 8d60e8b836c25308b95cbf02fd510a0c4c3b832c..c00475efc74bffaf3bf1a2b5672342a7b7b462dd 100755 (executable)
@@ -260,14 +260,15 @@ if [ "$DOWIN" = "yes" ]; then
     $strip anchor-update.exe
     $strip unbound-control.exe
     $strip unbound-host.exe
+    $strip unbound-anchor.exe
     $strip unbound-checkconf.exe
     $strip unbound-service-install.exe
     $strip unbound-service-remove.exe
     cd tmp.$$
     cp ../doc/example.conf example.conf
-    cp ../unbound.exe ../unbound-host.exe ../unbound-control.exe ../unbound-checkconf.exe ../unbound-service-install.exe ../unbound-service-remove.exe ../LICENSE ../winrc/unbound-website.url ../winrc/service.conf ../winrc/README.txt .
+    cp ../unbound.exe ../unbound-anchor.exe ../unbound-host.exe ../unbound-control.exe ../unbound-checkconf.exe ../unbound-service-install.exe ../unbound-service-remove.exe ../LICENSE ../winrc/unbound-website.url ../winrc/service.conf ../winrc/README.txt .
     # zipfile
-    zip ../$file LICENSE README.txt unbound.exe unbound-host.exe unbound-control.exe unbound-checkconf.exe unbound-service-install.exe unbound-service-remove.exe example.conf service.conf unbound-website.url
+    zip ../$file LICENSE README.txt unbound.exe unbound-anchor.exe unbound-host.exe unbound-control.exe unbound-checkconf.exe unbound-service-install.exe unbound-service-remove.exe example.conf service.conf unbound-website.url
     info "Testing $file"
     (cd .. ; zip -T $file )
     # installer
@@ -385,6 +386,7 @@ replace_all doc/unbound.8.in
 replace_all doc/unbound.conf.5.in
 replace_all doc/unbound-checkconf.8.in
 replace_all doc/unbound-control.8.in
+replace_all doc/unbound-anchor.8.in
 replace_all doc/unbound-host.1
 replace_all doc/libunbound.3.in
 
diff --git a/smallapp/unbound-anchor.c b/smallapp/unbound-anchor.c
new file mode 100644 (file)
index 0000000..48d01df
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * unbound-anchor.c - update the root anchor if necessary.
+ *
+ * Copyright (c) 2010, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file checks to see that the current 5011 keys work to prime the
+ * current root anchor.  If not a certificate is used to update the anchor.
+ */
+
+#include "config.h"
+#include "libunbound/unbound.h"
+#include <ldns/rr.h>
+#include <expat.h>
+#ifndef HAVE_EXPAT_H
+#error "need libexpat to parse root-anchors.xml file."
+#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+/* TODO configure defines with prefix */
+/** root key file, 5011 tracked */
+#define ROOT_ANCHOR_FILE "/usr/local/etc/unbound/root.key"
+/** root update cert file */
+#define ROOT_CERT_FILE "/usr/local/etc/unbound/icannbundle.pem"
+/** name of server in URL to fetch HTTPS from */
+#define URLNAME "data.iana.org"
+/** path on HTTPS server to xml file */
+#define XMLNAME "/root-anchors/root-anchors.xml"
+/** path on HTTPS server to p7s file */
+#define P7SNAME "/root-anchors/root-anchors.p7s"
+/** path on HTTPS server to pem file */
+#define PEMNAME "/root-anchors/icannbundle.pem"
+
+/** verbosity for this application */
+static int verb = 0;
+
+/** Give unbound-anchor usage, and exit (1). */
+static void
+usage()
+{
+       printf("Usage:  unbound-anchor [opts]\n");
+       printf("        Setup or update root anchor. "
+               "Most options have defaults.\n");
+       printf("        Run this program before you start the validator.\n");
+       printf("\n");
+       printf("        The anchor and cert are filled with default builtin\n");
+       printf("        values if the file does not exist or is empty.\n");
+       printf("\n");
+       printf("-a file         root key file, default %s\n", ROOT_ANCHOR_FILE);
+       printf("-c file         cert file, default %s\n", ROOT_CERT_FILE);
+       /* TODO
+       printf("-o file         output key file, if enabled new key written"
+               "               there and exit code 4 for manual change\n");
+       */
+       printf("-u name         server in https url, default %s\n", URLNAME);
+       printf("-x path         pathname to xml, default %s\n", XMLNAME);
+       printf("-s path         pathname to p7s, default %s\n", P7SNAME);
+       printf("-p path         pathname to pem, default %s\n", PEMNAME);
+       printf("-4              work using IPv4 only\n");
+       printf("-6              work using IPv6 only\n");
+       printf("-f resolv.conf  use given resolv.conf to resolve -u name\n");
+       printf("-r root.hints   use given root.hints to resolve -u name\n"
+               "               builtin root hints are used by default\n");
+       printf("-v              more verbose\n");
+       printf("-C conf         debug, read config\n");
+       printf("-F              debug, force update with cert\n");
+       printf("-h              show this usage help\n");
+       printf("Version %s\n", PACKAGE_VERSION);
+       printf("BSD licensed, see LICENSE in source package for details.\n");
+       printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
+       exit(1);
+}
+
+/** perform actual certupdate work */
+static int
+do_certupdate(char* root_anchor_file, char* root_cert_file,
+       char* urlname, char* xmlname, char* p7sname, char* pemname,
+       char* res_conf, char* root_hints, char* debugconf,
+       int ip4only, int ip6only, struct ub_result* dnskey)
+{
+       /* read pem file or provide builtin */
+
+       /* lookup A, AAAA for the urlname (or parse urlname if IP address) */
+
+       /* fetch the necessary files over HTTPS */
+
+       /* update the pem file (optional) */
+
+       /* verify and update the root anchor */
+               /* verify xml file */
+               /* see if xml file verifies the dnskey that was probed */
+               /* reinstate 5011 tracking */
+       if(verb) printf("success: the anchor has been updated "
+                       "using the cert\n");
+       ub_resolve_free(dnskey);
+       return 0;
+}
+
+/**
+ * Try to read the root RFC5011 autotrust anchor file,
+ * @param file: filename.
+ * @return:
+ *     0 if does not exist or empty
+ *     1 if trust-point-revoked-5011
+ *     2 if it is OK.
+ */
+static int
+try_read_anchor(char* file)
+{
+       int empty = 1;
+       char line[10240];
+       char* p;
+       FILE* in = fopen(file, "r");
+       if(!in) {
+               /* only if the file does not exist, can we fix it */
+               if(errno != ENOENT) {
+                       if(verb) printf("%s: %s\n", file, strerror(errno));
+                       if(verb) printf("error: cannot access the file\n");
+                       exit(0);
+               }
+               if(verb) printf("%s does not exist\n", file);
+               return 0;
+       }
+       while(fgets(line, (int)sizeof(line), in)) {
+               line[sizeof(line)-1] = 0;
+               if(strncmp(line, ";;REVOKED", 9) == 0) {
+                       fclose(in);
+                       if(verb) printf("%s : the trust point is revoked\n"
+                               "and the zone is considered unsigned.\n"
+                               "if you wish to re-enable, delete the file\n",
+                               file);
+                       return 1;
+               }
+               p=line;
+               while(*p == ' ' || *p == '\t')
+                       p++;
+               if(p[0]==0 || p[0]=='\n' || p[0]==';') continue;
+               /* this line is a line of content */
+               empty = 0;
+       }
+       fclose(in);
+       if(empty) {
+               if(verb) printf("%s is empty\n", file);
+               return 0;
+       }
+       if(verb) printf("%s has content\n", file);
+       return 2;
+}
+
+/** Write the builtin root anchor to a file */
+static void
+write_builtin_anchor(char* file)
+{
+       const char* builtin_root_anchor = ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n";
+       FILE* out = fopen(file, "w");
+       if(!out) {
+               if(verb) printf("%s: %s\n", file, strerror(errno));
+               if(verb) printf("  could not write builtin anchor\n");
+               return;
+       }
+       if(!fwrite(builtin_root_anchor, strlen(builtin_root_anchor), 1, out)) {
+               if(verb) printf("%s: %s\n", file, strerror(errno));
+               if(verb) printf("  could not complete write builtin anchor\n");
+       }
+       fclose(out);
+}
+
+/** 
+ * Check the root anchor file.
+ * If does not exist, provide builtin and write file.
+ * If empty, provide builtin and write file.
+ * If trust-point-revoked-5011 file: make the program exit.
+ */
+static int
+provide_builtin(char* root_anchor_file)
+{
+       /* try to read it */
+       switch(try_read_anchor(root_anchor_file))
+       {
+               case 0: /* no exist or empty */
+                       write_builtin_anchor(root_anchor_file);
+                       break;
+               case 1: /* revoked tp */
+                       return 0;       
+               case 2: /* it is fine */
+               default:
+                       break;
+       }
+       return 1;
+}
+
+/** print ub context creation error and exit */
+static void
+ub_ctx_error_exit(struct ub_ctx* ctx, const char* str, const char* str2)
+{
+       ub_ctx_delete(ctx);
+       if(str && str2 && verb) printf("%s: %s\n", str, str2);
+       if(verb) printf("error: could not create unbound resolver context\n");
+       exit(0);
+}
+
+/**
+ * Create a new unbound context with the commandline settings applied
+ */
+static struct ub_ctx* 
+create_unbound_context(char* res_conf, char* root_hints, char* debugconf,
+        int ip4only, int ip6only)
+{
+       int r;
+       struct ub_ctx* ctx = ub_ctx_create();
+       if(!ctx) {
+               if(verb) printf("out of memory\n");
+               exit(0);
+       }
+       /* do not waste time and network traffic to fetch extra nameservers */
+       r = ub_ctx_set_option(ctx, "target-fetch-policy:", "0 0 0 0 0");
+       if(r && verb) printf("ctx targetfetchpolicy: %s\n", ub_strerror(r));
+       /* read config file first, so its settings can be overridden */
+       if(debugconf) {
+               r = ub_ctx_config(ctx, debugconf);
+               if(r) ub_ctx_error_exit(ctx, debugconf, ub_strerror(r));
+       }
+       if(res_conf) {
+               r = ub_ctx_resolvconf(ctx, res_conf);
+               if(r) ub_ctx_error_exit(ctx, res_conf, ub_strerror(r));
+       }
+       if(root_hints) {
+               r = ub_ctx_set_option(ctx, "root-hints:", root_hints);
+               if(r) ub_ctx_error_exit(ctx, root_hints, ub_strerror(r));
+       }
+       if(ip4only) {
+               r = ub_ctx_set_option(ctx, "do-ip6:", "no");
+               if(r) ub_ctx_error_exit(ctx, "ip4only", ub_strerror(r));
+       }
+       if(ip6only) {
+               r = ub_ctx_set_option(ctx, "do-ip4:", "no");
+               if(r) ub_ctx_error_exit(ctx, "ip6only", ub_strerror(r));
+       }
+       return ctx;
+}
+
+/**
+ * add an autotrust anchor for the root to the context
+ */
+static void
+add_5011_probe_root(struct ub_ctx* ctx, char* root_anchor_file)
+{
+       int r;
+       r = ub_ctx_set_option(ctx, "auto-trust-anchor-file:", root_anchor_file);
+       if(r) {
+               if(verb) printf("add 5011 probe to ctx: %s\n", ub_strerror(r));
+               ub_ctx_delete(ctx);
+               exit(0);
+       }
+}
+
+/**
+ * Prime the root key and return the result.  Exit on error.
+ */
+static struct ub_result*
+prime_root_key(struct ub_ctx* ctx)
+{
+       struct ub_result* res = NULL;
+       int r;
+       r = ub_resolve(ctx, ".", LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, &res);
+       if(r) {
+               if(verb) printf("resolve DNSKEY: %s\n", ub_strerror(r));
+               ub_ctx_delete(ctx);
+               exit(0);
+       }
+       if(!res) {
+               if(verb) printf("out of memory\n");
+               ub_ctx_delete(ctx);
+               exit(0);
+       }
+       return res;
+}
+
+/** read last successful probe time from autotrust file (if possible) */
+static int32_t
+read_last_success_time(char* file)
+{
+       FILE* in = fopen(file, "r");
+       char line[1024];
+       if(!in) {
+               if(verb) printf("%s: %s\n", file, strerror(errno));
+               return 0;
+       }
+       while(fgets(line, (int)sizeof(line), in)) {
+               if(strncmp(line, ";;last_success: ", 16) == 0) {
+                       char* e;
+                       time_t x = (unsigned int)strtol(line+16, &e, 10);
+                       fclose(in);
+                       if(line+16 == e) {
+                               if(verb) printf("failed to parse "
+                                       "last_success probe time\n");
+                               return 0;
+                       }
+                       if(verb) printf("last successful probe: %s", ctime(&x));
+                       return (int32_t)x;
+               }
+       }
+       fclose(in);
+       if(verb) printf("no last_success probe time in anchor file\n");
+       return 0;
+}
+
+/**
+ * Get current time.
+ * @param debugconf: with override time for tests
+ */
+static int32_t
+get_time_now(char* debugconf)
+{
+       if(debugconf) {
+               FILE* in = fopen(debugconf, "r");
+               char line[1024];
+               if(!in) {
+                       if(verb) printf("%s: %s\n", debugconf, strerror(errno));
+                       return (int32_t)time(NULL);
+               }
+               /* must be ^val-override-date: 1234567$ formatted */
+               while(fgets(line, (int)sizeof(line), in)) {
+                       if(strncmp(line, "val-override-date: ", 19) == 0) {
+                               fclose(in);
+                               return (int32_t)atoi(line+19);
+                       }
+               }
+               fclose(in);
+       }
+       return (int32_t)time(NULL);
+}
+
+/**
+ * Read autotrust 5011 probe file and see if the date
+ * compared to the current date allows a certupdate.
+ * If the last successful probe was recent then 5011 cannot be behind,
+ * and the failure cannot be solved with a certupdate.
+ * The debugconf is to validation-override the date for testing.
+ * @return true if certupdate is ok.
+ */
+static int
+probe_date_allows_certupdate(char* root_anchor_file, char* debugconf)
+{
+       int32_t last_success = read_last_success_time(root_anchor_file);
+       int32_t now = get_time_now(debugconf);
+       int32_t leeway = 30 * 24 * 3600; /* 30 days leeway */
+       /* if the date is before 2010-07-15:00.00.00 then the root has not
+        * been signed yet, and thus we refuse to take action. */
+       if(now - 1279144800 < 0) {
+               if(verb) printf("the date is before the root was first signed,"
+                       " please correct the clock\n");
+               return 0;
+       }
+       if(now - last_success < 0) {
+               if(verb) printf("the last successful probe is in the future,"
+                       " clock was modified\n");
+               return 0;
+       }
+       if(now - last_success >= leeway) {
+               if(verb) printf("the last successful probe was more than 30 "
+                       "days ago\n");
+               return 1;
+       }
+       if(verb) printf("the last successful probe is recent\n");
+       return 0;
+}
+
+/** perform the unbound-anchor work */
+static int
+do_root_update_work(char* root_anchor_file, char* root_cert_file,
+       char* urlname, char* xmlname, char* p7sname, char* pemname,
+       char* res_conf, char* root_hints, char* debugconf,
+       int ip4only, int ip6only, int force)
+{
+       struct ub_ctx* ctx;
+       struct ub_result* dnskey;
+
+       /* see if builtin rootanchor needs to be provided, or if
+        * rootanchor is 'revoked-trust-point' */
+       if(!provide_builtin(root_anchor_file))
+               return 0;
+
+       /* make unbound context with 5011-probe for root anchor,
+        * and probe . DNSKEY */
+       ctx = create_unbound_context(res_conf, root_hints, debugconf,
+               ip4only, ip6only);
+       add_5011_probe_root(ctx, root_anchor_file);
+       dnskey = prime_root_key(ctx);
+       ub_ctx_delete(ctx);
+       
+       /* if secure: exit */
+       if(dnskey->secure && !force) {
+               if(verb) printf("success: the anchor is ok\n");
+               ub_resolve_free(dnskey);
+               return 0;
+       }
+       if(force && verb) printf("debug cert update forced\n");
+
+       /* if not (and NOERROR): check date and do certupdate */
+       if((dnskey->rcode == 0 && probe_date_allows_certupdate(root_anchor_file,
+               debugconf)) || force)
+               return do_certupdate(root_anchor_file, root_cert_file,
+                       urlname, xmlname, p7sname, pemname,
+                       res_conf, root_hints, debugconf, ip4only, ip6only,
+                       dnskey);
+       if(verb) printf("fail: the anchor is NOT ok and could not be fixed\n");
+       ub_resolve_free(dnskey);
+       return 0;
+}
+
+/** getopt global, in case header files fail to declare it. */
+extern int optind;
+/** getopt global, in case header files fail to declare it. */
+extern char* optarg;
+
+/** Main routine for checkconf */
+int main(int argc, char* argv[])
+{
+       int c;
+       char* root_anchor_file = ROOT_ANCHOR_FILE;
+       char* root_cert_file = ROOT_CERT_FILE;
+       char* urlname = URLNAME;
+       char* xmlname = XMLNAME;
+       char* p7sname = P7SNAME;
+       char* pemname = PEMNAME;
+       char* res_conf = NULL;
+       char* root_hints = NULL;
+       char* debugconf = NULL;
+       int ip4only=0, ip6only=0, force=0;
+       /* parse the options */
+       while( (c=getopt(argc, argv, "46C:Fa:c:f:hp:r:s:u:vx:")) != -1) {
+               switch(c) {
+               case '4':
+                       ip4only = 1;
+                       break;
+               case '6':
+                       ip6only = 1;
+                       break;
+               case 'a':
+                       root_anchor_file = optarg;
+                       break;
+               case 'c':
+                       root_cert_file = optarg;
+                       break;
+               case 'u':
+                       urlname = optarg;
+                       break;
+               case 'x':
+                       xmlname = optarg;
+                       break;
+               case 's':
+                       p7sname = optarg;
+                       break;
+               case 'p':
+                       pemname = optarg;
+                       break;
+               case 'f':
+                       res_conf = optarg;
+                       break;
+               case 'r':
+                       root_hints = optarg;
+                       break;
+               case 'C':
+                       debugconf = optarg;
+                       break;
+               case 'F':
+                       force = 1;
+                       break;
+               case 'v':
+                       verb++;
+                       break;
+               case '?':
+               case 'h':
+               default:
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       if(argc != 0)
+               usage();
+       return do_root_update_work(root_anchor_file, root_cert_file,
+               urlname, xmlname, p7sname, pemname,
+               res_conf, root_hints, debugconf, ip4only, ip6only, force);
+}
diff --git a/winrc/rsrc_unbound_anchor.rc b/winrc/rsrc_unbound_anchor.rc
new file mode 100644 (file)
index 0000000..76b96b7
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+  Unbound resource file for windows.  For use with windres
+*/
+#include "winver.h"
+#include "config.h"
+
+1 ICON "winrc/combined.ico"
+
+1 VERSIONINFO
+FILEVERSION    RSRC_PACKAGE_VERSION
+PRODUCTVERSION  RSRC_PACKAGE_VERSION
+FILEFLAGSMASK  0
+FILEFLAGS      0
+FILEOS         VOS__WINDOWS32
+FILETYPE       VFT_APP
+FILESUBTYPE    0
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904E4"
+    BEGIN
+      VALUE "CompanyName",     "NLnet Labs"
+      VALUE "FileDescription", "Unbound Anchor Utility"
+      VALUE "FileVersion",     PACKAGE_VERSION
+      VALUE "InternalName",    "unbound-anchor"
+      VALUE "OriginalFilename",        "unbound-anchor.exe"
+      VALUE "ProductName",     "unbound"
+      VALUE "ProductVersion",  PACKAGE_VERSION
+      VALUE "LegalCopyright",  "(C) 2010 NLnet Labs. Source is BSD licensed."
+    END
+  END
+  BLOCK "VarFileInfo"
+  BEGIN
+    /* English(409), windows ANSI codepage (1252) */
+    VALUE "Translation", 0x409, 0x1252
+  END
+END