]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Test for unbound-anchor.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 1 Oct 2010 11:31:35 +0000 (11:31 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 1 Oct 2010 11:31:35 +0000 (11:31 +0000)
git-svn-id: file:///svn/unbound/trunk@2268 be551aaa-1e26-0410-a405-d3ace91eadb9

Makefile.in
doc/Changelog
doc/unbound-anchor.8.in
smallapp/unbound-anchor.c
testcode/petal.c [new file with mode: 0644]
testdata/10-unbound-anchor.tpkg [new file with mode: 0644]

index 9c711687406b29615f4b993ddbed2dd36f375942..57d6a5c77b43ac105110ecafb53cfabc51ad4fdc 100644 (file)
@@ -119,6 +119,8 @@ TESTBOUND_SRC=testcode/testbound.c testcode/ldns-testpkts.c \
 TESTBOUND_OBJ=$(addprefix $(BUILD),$(TESTBOUND_SRC:.c=.lo)) $(COMPAT_OBJ)
 LOCKVERIFY_SRC=testcode/lock_verify.c smallapp/worker_cb.c $(COMMON_SRC)
 LOCKVERIFY_OBJ=$(addprefix $(BUILD),$(LOCKVERIFY_SRC:.c=.lo)) $(COMPAT_OBJ)
+PETAL_SRC=testcode/petal.c
+PETAL_OBJ=$(addprefix $(BUILD),$(PETAL_SRC:.c=.lo)) $(COMPAT_OBJ)
 PKTVIEW_SRC=testcode/pktview.c testcode/readhex.c smallapp/worker_cb.c \
        $(COMMON_SRC)
 PKTVIEW_OBJ=$(addprefix $(BUILD),$(PKTVIEW_SRC:.c=.lo)) $(COMPAT_OBJ)
@@ -143,7 +145,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) $(UBANCHOR_SRC))
+       $(HARVEST_SRC) $(CONTROL_SRC) $(UBANCHOR_SRC) $(PETAL_SRC))
 ALL_OBJ=$(addprefix $(BUILD),$(ALL_SRC:.c=.lo) \
        $(addprefix compat/,$(LIBOBJS:.o=.lo))) $(COMPAT_OBJ)
 
@@ -194,7 +196,7 @@ $(BUILD)%.lo:    $(srcdir)/%.c
 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)
+       memstats perf petal pktview signit streamtcp testbound unittest)
 tests: all $(TEST_BIN)
 
 check: test
@@ -269,6 +271,10 @@ lock-verify$(EXEEXT):      $(LOCKVERIFY_OBJ) $(ldnslib)
        $(INFO) Link $@
        $Q$(LINK) -o $@ $(sort $(LOCKVERIFY_OBJ)) $(LIBS)
 
+petal$(EXEEXT):        $(PETAL_OBJ)
+       $(INFO) Link $@
+       $Q$(LINK) -o $@ $(sort $(PETAL_OBJ)) -lssl $(LIBS)
+
 pktview$(EXEEXT):      $(PKTVIEW_OBJ) $(ldnslib)
        $(INFO) Link $@
        $Q$(LINK) -o $@ $(sort $(PKTVIEW_OBJ)) $(LIBS)
index ff08d5311eab7d013c3572fd0676b0e47bf991e5..39e257253e1227d1316eb37c8b7b9d71a6d53577 100644 (file)
@@ -1,3 +1,6 @@
+1 October 2010: Wouter
+       - test for unbound-anchor. fix for reading certs.
+
 28 September 2010: Wouter
        - unbound-anchor working, it creates or updates a root.key file.
          Use it before you start the validator (e.g. at system boot time).
index b333f49a036c8e6cfc2e51c7327eee813718a671..d98ccb4aa36830416ebbea8ee50645c7f9157b85 100644 (file)
@@ -1,6 +1,6 @@
 .TH "unbound-anchor" "8" "@date@" "NLnet Labs" "unbound @version@"
 .\"
-.\" unbound-control.8 -- unbound remote control manual
+.\" unbound-anchor.8 -- unbound anchor maintenance utility manual
 .\"
 .\" Copyright (c) 2008, NLnet Labs. All rights reserved.
 .\"
index 7464386183b95127af2ab98deaffbbf145c03d14..9013535248d2c8321ac91c9aaf60e68730890065 100644 (file)
@@ -322,7 +322,10 @@ read_cert_bio(BIO* bio)
        while(!BIO_eof(bio)) {
                X509* x = PEM_read_bio_X509(bio, NULL, 0, NULL);
                if(x == NULL) {
-                       if(verb) printf("failed to read X509\n");
+                       if(verb) {
+                               printf("failed to read X509\n");
+                               ERR_print_errors_fp(stdout);
+                       }
                        continue;
                }
                if(!sk_X509_push(sk, x)) {
@@ -340,6 +343,7 @@ read_cert_file(char* file)
        STACK_OF(X509)* sk;
        FILE* in;
        int content = 0;
+       char buf[128];
        if(file == NULL || strcmp(file, "") == 0) {
                return NULL;
        }
@@ -359,7 +363,10 @@ read_cert_file(char* file)
        while(!feof(in)) {
                X509* x = PEM_read_X509(in, NULL, 0, NULL);
                if(x == NULL) {
-                       if(verb) printf("failed to read X509\n");
+                       if(verb) {
+                               printf("failed to read X509 file\n");
+                               ERR_print_errors_fp(stdout);
+                       }
                        continue;
                }
                if(!sk_X509_push(sk, x)) {
@@ -367,6 +374,8 @@ read_cert_file(char* file)
                        fclose(in);
                        exit(0);
                }
+               /* read away newline after --END CERT-- */
+               (void)fgets(buf, (int)sizeof(buf), in);
                content = 1;
        }
        fclose(in);
@@ -1008,8 +1017,8 @@ read_http_result(SSL* ssl)
                /* do the chunked version */
                BIO* tmp = do_chunked_read(ssl);
                char* d = NULL;
-               long l;
-               l = BIO_get_mem_data(tmp, &d);
+               size_t l;
+               l = (size_t)BIO_get_mem_data(tmp, &d);
                if(verb>=2) printf("chunked data is %d\n", (int)l);
                if(l == 0 || d == NULL) {
                        if(verb) printf("out of memory\n");
@@ -1017,7 +1026,7 @@ read_http_result(SSL* ssl)
                }
                /* the result is zero terminated for robustness, but we 
                 * do not include that in the BIO len (for binary data) */
-               len = (size_t)l-1;
+               len = l-1;
                data = (char*)malloc(l);
                if(data == NULL) {
                        if(verb) printf("out of memory\n");
diff --git a/testcode/petal.c b/testcode/petal.c
new file mode 100644 (file)
index 0000000..2e6f1c5
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * petal.c - https daemon that is small and beautiful.
+ *
+ * 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
+ *
+ * HTTP1.1/SSL server.
+ */
+
+#include "config.h"
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
+#ifdef HAVE_OPENSSL_RAND_H
+#include <openssl/rand.h>
+#endif
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <ctype.h>
+#include <signal.h>
+
+/** verbosity for this application */
+static int verb = 0;
+
+/** Give petal usage, and exit (1). */
+static void
+usage()
+{
+       printf("Usage:  petal [opts]\n");
+       printf("        https daemon serves files from ./'host'/filename\n");
+       printf("        (no hostname: from the 'default' directory)\n");
+       printf("-a addr         bind to this address, 127.0.0.1\n");
+       printf("-p port         port number, default 443\n");
+       printf("-k keyfile      SSL private key file (PEM), petal.key\n");
+       printf("-c certfile     SSL certificate file (PEM), petal.pem\n");
+       printf("-v              more verbose\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);
+}
+
+/** fatal exit */
+static void print_exit(const char* str) {printf("error %s\n", str); exit(1);}
+/** print errno */
+static void log_errno(const char* str)
+{printf("error %s: %s\n", str, strerror(errno));}
+
+/** parse a text IP address into a sockaddr */
+static int
+parse_ip_addr(char* str, int port, struct sockaddr_storage* ret, socklen_t* l)
+{
+       socklen_t len = 0;
+       struct sockaddr_storage* addr = NULL;
+       struct sockaddr_in6 a6;
+       struct sockaddr_in a;
+       uint16_t p = (uint16_t)port;
+       int fam = 0;
+       memset(&a6, 0, sizeof(a6));
+       memset(&a, 0, sizeof(a));
+
+       if(inet_pton(AF_INET6, str, &a6.sin6_addr) > 0) {
+               /* it is an IPv6 */
+               fam = AF_INET6;
+               a6.sin6_family = AF_INET6;
+               a6.sin6_port = (in_port_t)htons(p);
+               addr = (struct sockaddr_storage*)&a6;
+               len = (socklen_t)sizeof(struct sockaddr_in6);
+       }
+       if(inet_pton(AF_INET, str, &a.sin_addr) > 0) {
+               /* it is an IPv4 */
+               fam = AF_INET;
+               a.sin_family = AF_INET;
+               a.sin_port = (in_port_t)htons(p);
+               addr = (struct sockaddr_storage*)&a;
+               len = (socklen_t)sizeof(struct sockaddr_in);
+       }
+       if(!len) print_exit("cannot parse addr");
+       *l = len;
+       memmove(ret, addr, len);
+       return fam;
+}
+
+/** close the fd */
+static void
+fd_close(int fd)
+{
+#ifndef USE_WINSOCK
+       close(fd);
+#else
+       closesocket(fd);
+#endif
+}
+
+/** 
+ * Read one line from SSL
+ * zero terminates.
+ * skips "\r\n" (but not copied to buf).
+ * @param ssl: the SSL connection to read from (blocking).
+ * @param buf: buffer to return line in.
+ * @param len: size of the buffer.
+ * @return 0 on error, 1 on success.
+ */
+static int
+read_ssl_line(SSL* ssl, char* buf, size_t len)
+{
+       size_t n = 0;
+       int r;
+       int endnl = 0;
+       while(1) {
+               if(n >= len) {
+                       if(verb) printf("line too long\n");
+                       return 0;
+               }
+               if((r = SSL_read(ssl, buf+n, 1)) <= 0) {
+                       if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
+                               /* EOF */
+                               break;
+                       }
+                       if(verb) printf("could not SSL_read\n");
+                       return 0;
+               }
+               if(endnl && buf[n] == '\n') {
+                       break;
+               } else if(endnl) {
+                       /* bad data */
+                       if(verb) printf("error: stray linefeeds\n");
+                       return 0;
+               } else if(buf[n] == '\r') {
+                       /* skip \r, and also \n on the wire */
+                       endnl = 1;
+                       continue;
+               } else if(buf[n] == '\n') {
+                       /* skip the \n, we are done */
+                       break;
+               } else n++;
+       }
+       buf[n] = 0;
+       return 1;
+}
+
+/** process one http header */
+static int
+process_one_header(char* buf, char* file, size_t flen, char* host, size_t hlen,
+       int* vs)
+{
+       if(strncasecmp(buf, "GET ", 4) == 0) {
+               char* e = strstr(buf, " HTTP/1.1");
+               if(!e) e = strstr(buf, " http/1.1");
+               if(!e) {
+                       e = strstr(buf, " HTTP/1.0");
+                       if(!e) e = strstr(buf, " http/1.0");
+                       if(!e) e = strrchr(buf, ' ');
+                       if(!e) e = strrchr(buf, '\t');
+                       if(e) *vs = 10;
+               }
+               if(e) *e = 0;
+               if(strlen(buf) < 4) return 0;
+               (void)strlcpy(file, buf+4, flen);
+       } else if(strncasecmp(buf, "Host: ", 6) == 0) {
+               (void)strlcpy(host, buf+6, hlen);
+       }
+       return 1;
+}
+
+/** read http headers and process them */
+static int
+read_http_headers(SSL* ssl, char* file, size_t flen, char* host, size_t hlen,
+       int* vs)
+{
+       char buf[1024];
+       file[0] = 0;
+       host[0] = 0;
+       while(read_ssl_line(ssl, buf, sizeof(buf))) {
+               if(verb>=2) printf("read: %s\n", buf);
+               if(buf[0] == 0)
+                       return 1;
+               if(!process_one_header(buf, file, flen, host, hlen, vs))
+                       return 0;
+       }
+       return 0;
+}
+
+/** setup SSL context */
+static SSL_CTX*
+setup_ctx(char* key, char* cert)
+{
+       SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
+       if(!ctx) print_exit("out of memory");
+       (void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+       if(!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM))
+               print_exit("cannot read cert");
+       if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM))
+               print_exit("cannot read key");
+       if(!SSL_CTX_check_private_key(ctx))
+               print_exit("private key is not correct");
+       if(!SSL_CTX_load_verify_locations(ctx, cert, NULL))
+               print_exit("cannot load cert verify locations");
+       return ctx;
+}
+
+/** setup listening TCP */
+static int
+setup_fd(char* addr, int port)
+{
+       struct sockaddr_storage ad;
+       socklen_t len;
+       int fd;
+       int c = 1;
+       int fam = parse_ip_addr(addr, port, &ad, &len);
+       fd = socket(fam, SOCK_STREAM, 0);
+       if(fd == -1) {
+               log_errno("socket");
+               return -1;
+       }
+       if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+               (void*)&c, (socklen_t) sizeof(int)) < 0) {
+               log_errno("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+       }
+       if(bind(fd, (struct sockaddr*)&ad, len) == -1) {
+               log_errno("bind");
+               fd_close(fd);
+               return -1;
+       }
+       if(listen(fd, 5) == -1) {
+               log_errno("listen");
+               fd_close(fd);
+               return -1;
+       }
+       return fd;
+}
+
+/** setup SSL connection to the client */
+static SSL*
+setup_ssl(int s, SSL_CTX* ctx)
+{
+       SSL* ssl = SSL_new(ctx);
+       if(!ssl) return NULL;
+       SSL_set_accept_state(ssl);
+       (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+       if(!SSL_set_fd(ssl, s)) {
+               SSL_free(ssl);
+               return NULL;
+       }
+       return ssl;
+}
+
+/** check a file name for safety */
+static int
+file_name_is_safe(char* s)
+{
+       size_t l = strlen(s);
+       if(s[0] != '/')
+               return 0; /* must start with / */
+       if(strstr(s, "/../"))
+               return 0; /* no updirs in URL */
+       if(l>=3 && s[l-1]=='.' && s[l-2]=='.' && s[l-3]=='/')
+               return 0; /* ends with /.. */
+       return 1;
+}
+
+/** adjust host and filename */
+static void
+adjust_host_file(char* host, char* file)
+{
+       size_t i, len;
+       /* remove a port number if present */
+       if(strrchr(host, ':'))
+               *strrchr(host, ':') = 0;
+       /* lowercase */
+       len = strlen(host);
+       for(i=0; i<len; i++)
+               host[i] = tolower((unsigned char)host[i]);
+       len = strlen(file);
+       for(i=0; i<len; i++)
+               file[i] = tolower((unsigned char)file[i]);
+}
+
+/** check a host name for safety */
+static int
+host_name_is_safe(char* s)
+{
+       if(strchr(s, '/'))
+               return 0;
+       if(strcmp(s, "..") == 0)
+               return 0;
+       if(strcmp(s, ".") == 0)
+               return 0;
+       return 1;
+}
+
+/** provide file in whole transfer */
+static void
+provide_file_10(SSL* ssl, char* fname)
+{
+       char* buf, *at;
+       size_t len, avail, header_reserve=1024;
+       FILE* in = fopen(fname, "r");
+       int r;
+       const char* rcode = "200 OK";
+       if(!in) {
+               char hdr[1024];
+               rcode = "404 File not found";
+               r = snprintf(hdr, sizeof(hdr), "HTTP/1.1 %s\r\n\r\n", rcode);
+               if(SSL_write(ssl, hdr, r) <= 0) {
+                       /* write failure */
+               }
+               return;
+       }
+       fseek(in, 0, SEEK_END);
+       len = (size_t)ftell(in);
+       fseek(in, 0, SEEK_SET);
+       /* plus some space for the header */
+       buf = (char*)malloc(len+header_reserve);
+       if(!buf) {
+               fclose(in);
+               return;
+       }
+       avail = len+header_reserve;
+       at = buf;
+       r = snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode);
+       at += r;
+       avail -= r;
+       r = snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION);
+       at += r;
+       avail -= r;
+       r = snprintf(at, avail, "Content-Length: %u\r\n", (unsigned)len);
+       at += r;
+       avail -= r;
+       r = snprintf(at, avail, "\r\n");
+       at += r;
+       avail -= r;
+       if(avail < len) { /* robust */
+               free(buf);
+               fclose(in);
+               return;
+       }
+       if(fread(at, 1, len, in) != len) {
+               free(buf);
+               fclose(in);
+               return;
+       }
+       fclose(in);
+       at += len;
+       avail -= len;
+       if(SSL_write(ssl, buf, at-buf) <= 0) {
+               /* write failure */
+       }
+       free(buf);
+}
+
+/** provide file over SSL, chunked encoding */
+static void
+provide_file_chunked(SSL* ssl, char* fname)
+{
+       char buf[16384];
+       char* at = buf;
+       size_t avail = sizeof(buf);
+       int r;
+       FILE* in = fopen(fname, "r");
+       const char* rcode = "200 OK";
+       if(!in) {
+               rcode = "404 File not found";
+       }
+
+       /* print headers */
+       r = snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode);
+       at += r;
+       avail -= r;
+       r = snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION);
+       at += r;
+       avail -= r;
+       r = snprintf(at, avail, "Transfer-Encoding: chunked\r\n");
+       at += r;
+       avail -= r;
+       r = snprintf(at, avail, "Connection: close\r\n");
+       at += r;
+       avail -= r;
+       r = snprintf(at, avail, "\r\n");
+       at += r;
+       avail -= r;
+       if(avail < 16) { /* robust */
+               if(in) fclose(in);
+               return;
+       }
+
+       do {
+               char tmpbuf[sizeof(buf)];
+               /* read chunk; space-16 for xxxxCRLF..CRLF0CRLFCRLF (3 spare)*/
+               size_t red = in?fread(tmpbuf, 1, avail-16, in):0;
+               /* prepare chunk */
+               r = snprintf(at, avail, "%x\r\n", (unsigned)red);
+               at += r;
+               avail -= r;
+               if(red != 0) {
+                       if(red > avail) break; /* robust */
+                       memmove(at, tmpbuf, red);
+                       at += red;
+                       avail -= red;
+                       r = snprintf(at, avail, "\r\n");
+                       at += r;
+                       avail -= r;
+               }
+               if(in && feof(in) && red != 0) {
+                       r = snprintf(at, avail, "0\r\n");
+                       at += r;
+                       avail -= r;
+               }
+               if(!in || feof(in)) {
+                       r = snprintf(at, avail, "\r\n");
+                       at += r;
+                       avail -= r;
+               }
+               /* send chunk */
+               if(SSL_write(ssl, buf, at-buf) <= 0) {
+                       /* SSL error */
+                       break;
+               }
+
+               /* setup for next chunk */
+               at = buf;
+               avail = sizeof(buf);
+       } while(in && !feof(in) && !ferror(in));
+
+       if(in) fclose(in);
+}
+
+/** provide service to the ssl descriptor */
+static void
+service_ssl(SSL* ssl, struct sockaddr_storage* from, socklen_t falen)
+{
+       char file[1024];
+       char host[1024];
+       char combined[2048];
+       int vs = 11;
+       if(!read_http_headers(ssl, file, sizeof(file), host, sizeof(host),
+               &vs))
+               return;
+       adjust_host_file(host, file);
+       if(host[0] == 0 || !host_name_is_safe(host))
+               (void)strlcpy(host, "default", sizeof(host));
+       if(!file_name_is_safe(file)) {
+               return;
+       }
+       snprintf(combined, sizeof(combined), "%s%s", host, file);
+       if(verb) {
+               char out[100];
+               void* a = &((struct sockaddr_in*)from)->sin_addr;
+               if(falen != (socklen_t)sizeof(struct sockaddr_in))
+                       a = &((struct sockaddr_in6*)from)->sin6_addr;
+               out[0]=0;
+               (void)inet_ntop((int)((struct sockaddr_in*)from)->sin_family,
+                       a, out, (socklen_t)sizeof(out));
+               printf("%s requests %s\n", out, combined);
+       }
+       if(vs == 10)
+               provide_file_10(ssl, combined);
+       else    provide_file_chunked(ssl, combined);
+}
+
+/** provide ssl service */
+static void
+do_service(char* addr, int port, char* key, char* cert)
+{
+       SSL_CTX* sslctx = setup_ctx(key, cert);
+       int fd = setup_fd(addr, port);
+       int go = 1;
+       if(fd == -1) print_exit("could not setup sockets");
+       if(verb) {printf("petal start\n"); fflush(stdout);}
+       while(go) {
+               struct sockaddr_storage from;
+               socklen_t flen = (socklen_t)sizeof(from);
+               int s = accept(fd, (struct sockaddr*)&from, &flen);
+               if(s != -1) {
+                       SSL* ssl = setup_ssl(s, sslctx);
+                       if(ssl) {
+                               service_ssl(ssl, &from, flen);
+                               SSL_shutdown(ssl);
+                               SSL_free(ssl);
+                       }
+                       fd_close(s);
+               } else if (verb >=2) log_errno("accept");
+       }
+       /* if we get a kill signal, the process dies and the OS reaps us */
+       if(verb) printf("petal end\n");
+       fd_close(fd);
+       SSL_CTX_free(sslctx);
+}
+
+/** 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 petal */
+int main(int argc, char* argv[])
+{
+       int c;
+       int port = 443;
+       char* addr = "127.0.0.1", *key = "petal.key", *cert = "petal.pem";
+       /* parse the options */
+       while( (c=getopt(argc, argv, "a:c:k:hp:v")) != -1) {
+               switch(c) {
+               case 'a':
+                       addr = optarg;
+                       break;
+               case 'c':
+                       cert = optarg;
+                       break;
+               case 'k':
+                       key = optarg;
+                       break;
+               case 'p':
+                       port = atoi(optarg);
+                       break;
+               case 'v':
+                       verb++;
+                       break;
+               case '?':
+               case 'h':
+               default:
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       if(argc != 0)
+               usage();
+
+       (void)signal(SIGPIPE, SIG_IGN);
+       ERR_load_crypto_strings();
+       ERR_load_SSL_strings();
+       OpenSSL_add_all_algorithms();
+       (void)SSL_library_init();
+
+       do_service(addr, port, key, cert);
+
+       CRYPTO_cleanup_all_ex_data();
+       ERR_remove_state(0);
+       ERR_free_strings();
+       RAND_cleanup();
+       return 0;
+}
diff --git a/testdata/10-unbound-anchor.tpkg b/testdata/10-unbound-anchor.tpkg
new file mode 100644 (file)
index 0000000..0049021
Binary files /dev/null and b/testdata/10-unbound-anchor.tpkg differ