From: Wouter Wijngaards Date: Thu, 23 Sep 2010 13:51:29 +0000 (+0000) Subject: unbound-anchor work X-Git-Tag: release-1.4.7rc1~83 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1c2a8d977c4f9e0751d5935b41fd09621d747e76;p=thirdparty%2Funbound.git unbound-anchor work git-svn-id: file:///svn/unbound/trunk@2242 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/Makefile.in b/Makefile.in index e9926fcb1..9c7116874 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/config.h.in b/config.h.in index 7c6e557c5..7eddf74a4 100644 --- a/config.h.in +++ b/config.h.in @@ -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 header file. */ +#undef HAVE_EXPAT_H + /* Define to 1 if you have the `fcntl' function. */ #undef HAVE_FCNTL diff --git a/configure b/configure index 493488fd2..b10d2d075 100755 --- 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" ;; diff --git a/configure.ac b/configure.ac index 493feaa88..dd3c4d9d1 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/doc/Changelog b/doc/Changelog index eb42f4765..fb754462e 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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 index 000000000..269a61729 --- /dev/null +++ b/doc/unbound-anchor.8.in @@ -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). diff --git a/makedist.sh b/makedist.sh index 8d60e8b83..c00475efc 100755 --- a/makedist.sh +++ b/makedist.sh @@ -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 index 000000000..48d01dff8 --- /dev/null +++ b/smallapp/unbound-anchor.c @@ -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 +#include +#ifndef HAVE_EXPAT_H +#error "need libexpat to parse root-anchors.xml file." +#endif +#ifdef HAVE_GETOPT_H +#include +#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 index 000000000..76b96b785 --- /dev/null +++ b/winrc/rsrc_unbound_anchor.rc @@ -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