diff options
author | anonimal <anonimal@i2pmail.org> | 2017-06-28 21:07:24 +0000 |
---|---|---|
committer | anonimal <anonimal@i2pmail.org> | 2018-03-18 15:52:19 +0000 |
commit | 84c5a9ba481d7a33cc0fd0ca43867b61d127d907 (patch) | |
tree | f05d3d3f107da02005b4a61f0e5074c113a7165c /external/unbound/smallapp | |
parent | Merge pull request #3416 (diff) | |
download | monero-84c5a9ba481d7a33cc0fd0ca43867b61d127d907.tar.xz |
Unbound: remove unbound from in-tree source
We'll instead use a git submodule to pull from our unbound repo.
Diffstat (limited to 'external/unbound/smallapp')
-rw-r--r-- | external/unbound/smallapp/unbound-anchor.c | 2346 | ||||
-rw-r--r-- | external/unbound/smallapp/unbound-checkconf.c | 619 | ||||
-rw-r--r-- | external/unbound/smallapp/unbound-control-setup.sh.in | 160 | ||||
-rw-r--r-- | external/unbound/smallapp/unbound-control.c | 791 | ||||
-rw-r--r-- | external/unbound/smallapp/unbound-host.c | 497 | ||||
-rw-r--r-- | external/unbound/smallapp/worker_cb.c | 250 |
6 files changed, 0 insertions, 4663 deletions
diff --git a/external/unbound/smallapp/unbound-anchor.c b/external/unbound/smallapp/unbound-anchor.c deleted file mode 100644 index 2828088d9..000000000 --- a/external/unbound/smallapp/unbound-anchor.c +++ /dev/null @@ -1,2346 +0,0 @@ -/* - * 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 COPYRIGHT - * HOLDER 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, - * with RFC7958 https xml fetch. - * - * This is a concept solution for distribution of the DNSSEC root - * trust anchor. It is a small tool, called "unbound-anchor", that - * runs before the main validator starts. I.e. in the init script: - * unbound-anchor; unbound. Thus it is meant to run at system boot time. - * - * Management-Abstract: - * * first run: fill root.key file with hardcoded DS record. - * * mostly: use RFC5011 tracking, quick . DNSKEY UDP query. - * * failover: use RFC7958 builtin certificate, do https and update. - * Special considerations: - * * 30-days RFC5011 timer saves a lot of https traffic. - * * DNSKEY probe must be NOERROR, saves a lot of https traffic. - * * fail if clock before sign date of the root, if cert expired. - * * if the root goes back to unsigned, deals with it. - * - * It has hardcoded the root DS anchors and the ICANN CA root certificate. - * It allows with options to override those. It also takes root-hints (it - * has to do a DNS resolve), and also has hardcoded defaults for those. - * - * Once it starts, just before the validator starts, it quickly checks if - * the root anchor file needs to be updated. First it tries to use - * RFC5011-tracking of the root key. If that fails (and for 30-days since - * last successful probe), then it attempts to update using the - * certificate. So most of the time, the RFC5011 tracking will work fine, - * and within a couple milliseconds, the main daemon can start. It will - * have only probed the . DNSKEY, not done expensive https transfers on the - * root infrastructure. - * - * If there is no root key in the root.key file, it bootstraps the - * RFC5011-tracking with its builtin DS anchors; if that fails it - * bootstraps the RFC5011-tracking using the certificate. (again to avoid - * https, and it is also faster). - * - * It uses the XML file by converting it to DS records and writing that to the - * key file. Unbound can detect that the 'special comments' are gone, and - * the file contains a list of normal DNSKEY/DS records, and uses that to - * bootstrap 5011 (the KSK is made VALID). - * - * The certificate RFC7958 update is done by fetching root-anchors.xml and - * root-anchors.p7s via SSL. The HTTPS certificate can be logged but is - * not validated (https for channel security; the security comes from the - * certificate). The 'data.iana.org' domain name A and AAAA are resolved - * without DNSSEC. It tries a random IP until the transfer succeeds. It - * then checks the p7s signature. - * - * On any failure, it leaves the root key file untouched. The main - * validator has to cope with it, it cannot fix things (So a failure does - * not go 'without DNSSEC', no downgrade). If it used its builtin stuff or - * did the https, it exits with an exit code, so that this can trigger the - * init script to log the event and potentially alert the operator that can - * do a manual check. - * - * The date is also checked. Before 2010-07-15 is a failure (root not - * signed yet; avoids attacks on system clock). The - * last-successful-RFC5011-probe (if available) has to be more than 30 days - * in the past (otherwise, RFC5011 should have worked). This keeps - * unnecessary https traffic down. If the main certificate is expired, it - * fails. - * - * The dates on the keys in the xml are checked (uses the libexpat xml - * parser), only the valid ones are used to re-enstate RFC5011 tracking. - * If 0 keys are valid, the zone has gone to insecure (a special marker is - * written in the keyfile that tells the main validator daemon the zone is - * insecure). - * - * Only the root ICANN CA is shipped, not the intermediate ones. The - * intermediate CAs are included in the p7s file that was downloaded. (the - * root cert is valid to 2028 and the intermediate to 2014, today). - * - * Obviously, the tool also has options so the operator can provide a new - * keyfile, a new certificate and new URLs, and fresh root hints. By - * default it logs nothing on failure and success; it 'just works'. - * - */ - -#include "config.h" -#include "libunbound/unbound.h" -#include "sldns/rrdef.h" -#include "sldns/parseutil.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 -#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/x509v3.h> -#include <openssl/pem.h> - -/** 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" -/** name of the signer of the certificate */ -#define P7SIGNER "dnssec@iana.org" -/** port number for https access */ -#define HTTPS_PORT 443 - -#ifdef USE_WINSOCK -/* sneakily reuse the the wsa_strerror function, on windows */ -char* wsa_strerror(int err); -#endif - -/** verbosity for this application */ -static int verb = 0; - -/** list of IP addresses */ -struct ip_list { - /** next in list */ - struct ip_list* next; - /** length of addr */ - socklen_t len; - /** address ready to connect to */ - struct sockaddr_storage addr; - /** has the address been used */ - int used; -}; - -/** Give unbound-anchor usage, and exit (1). */ -static void -usage(void) -{ - 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 have default builtin content\n"); - printf(" 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(" The key is input and output for this tool.\n"); - printf("-c file cert file, default %s\n", ROOT_CERT_FILE); - printf("-l list builtin key and cert on stdout\n"); - printf("-u name server in https url, default %s\n", URLNAME); - printf("-x path pathname to xml in url, default %s\n", XMLNAME); - printf("-s path pathname to p7s in url, default %s\n", P7SNAME); - printf("-n name signer's subject emailAddress, default %s\n", P7SIGNER); - 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("-P port use port for https connect, default 443\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); -} - -/** return the built in root update certificate */ -static const char* -get_builtin_cert(void) -{ - return -/* The ICANN CA fetched at 24 Sep 2010. Valid to 2028 */ -"-----BEGIN CERTIFICATE-----\n" -"MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n" -"TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n" -"BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX\n" -"DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O\n" -"IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB\n" -"MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb\n" -"cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S\n" -"G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg\n" -"ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2\n" -"paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7\n" -"MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29\n" -"iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" -"Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3\n" -"DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH\n" -"6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD\n" -"2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h\n" -"15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n" -"0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n" -"j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n" -"-----END CERTIFICATE-----\n" - ; -} - -/** return the built in root DS trust anchor */ -static const char* -get_builtin_ds(void) -{ - return -/* anchor 19036 is from 2010 */ -/* anchor 20326 is from 2017 */ -". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n" -". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n"; -} - -/** print hex data */ -static void -print_data(const char* msg, const char* data, int len) -{ - int i; - printf("%s: ", msg); - for(i=0; i<len; i++) { - printf(" %2.2x", (unsigned char)data[i]); - } - printf("\n"); -} - -/** 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(const char* res_conf, const char* root_hints, - const 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; -} - -/** printout certificate in detail */ -static void -verb_cert(const char* msg, X509* x) -{ - if(verb == 0 || verb == 1) return; - if(verb == 2) { - if(msg) printf("%s\n", msg); - X509_print_ex_fp(stdout, x, 0, (unsigned long)-1 - ^(X509_FLAG_NO_SUBJECT - |X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY)); - return; - } - if(msg) printf("%s\n", msg); - X509_print_fp(stdout, x); -} - -/** printout certificates in detail */ -static void -verb_certs(const char* msg, STACK_OF(X509)* sk) -{ - int i, num = sk_X509_num(sk); - if(verb == 0 || verb == 1) return; - for(i=0; i<num; i++) { - printf("%s (%d/%d)\n", msg, i, num); - verb_cert(NULL, sk_X509_value(sk, i)); - } -} - -/** read certificates from a PEM bio */ -static STACK_OF(X509)* -read_cert_bio(BIO* bio) -{ - STACK_OF(X509) *sk = sk_X509_new_null(); - if(!sk) { - if(verb) printf("out of memory\n"); - exit(0); - } - 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"); - ERR_print_errors_fp(stdout); - } - continue; - } - if(!sk_X509_push(sk, x)) { - if(verb) printf("out of memory\n"); - exit(0); - } - } - return sk; -} - -/* read the certificate file */ -static STACK_OF(X509)* -read_cert_file(const char* file) -{ - STACK_OF(X509)* sk; - FILE* in; - int content = 0; - char buf[128]; - if(file == NULL || strcmp(file, "") == 0) { - return NULL; - } - sk = sk_X509_new_null(); - if(!sk) { - if(verb) printf("out of memory\n"); - exit(0); - } - in = fopen(file, "r"); - if(!in) { - if(verb) printf("%s: %s\n", file, strerror(errno)); -#ifndef S_SPLINT_S - sk_X509_pop_free(sk, X509_free); -#endif - return NULL; - } - while(!feof(in)) { - X509* x = PEM_read_X509(in, NULL, 0, NULL); - if(x == NULL) { - if(verb) { - printf("failed to read X509 file\n"); - ERR_print_errors_fp(stdout); - } - continue; - } - if(!sk_X509_push(sk, x)) { - if(verb) printf("out of memory\n"); - fclose(in); - exit(0); - } - content = 1; - /* read away newline after --END CERT-- */ - if(!fgets(buf, (int)sizeof(buf), in)) - break; - } - fclose(in); - if(!content) { - if(verb) printf("%s is empty\n", file); -#ifndef S_SPLINT_S - sk_X509_pop_free(sk, X509_free); -#endif - return NULL; - } - return sk; -} - -/** read certificates from the builtin certificate */ -static STACK_OF(X509)* -read_builtin_cert(void) -{ - const char* builtin_cert = get_builtin_cert(); - STACK_OF(X509)* sk; - BIO *bio; - char* d = strdup(builtin_cert); /* to avoid const warnings in the - changed prototype of BIO_new_mem_buf */ - if(!d) { - if(verb) printf("out of memory\n"); - exit(0); - } - bio = BIO_new_mem_buf(d, (int)strlen(d)); - if(!bio) { - if(verb) printf("out of memory\n"); - exit(0); - } - sk = read_cert_bio(bio); - if(!sk) { - if(verb) printf("internal error, out of memory\n"); - exit(0); - } - BIO_free(bio); - free(d); - return sk; -} - -/** read update cert file or use builtin */ -static STACK_OF(X509)* -read_cert_or_builtin(const char* file) -{ - STACK_OF(X509) *sk = read_cert_file(file); - if(!sk) { - if(verb) printf("using builtin certificate\n"); - sk = read_builtin_cert(); - } - if(verb) printf("have %d trusted certificates\n", sk_X509_num(sk)); - verb_certs("trusted certificates", sk); - return sk; -} - -static void -do_list_builtin(void) -{ - const char* builtin_cert = get_builtin_cert(); - const char* builtin_ds = get_builtin_ds(); - printf("%s\n", builtin_ds); - printf("%s\n", builtin_cert); - exit(0); -} - -/** printout IP address with message */ -static void -verb_addr(const char* msg, struct ip_list* ip) -{ - if(verb) { - char out[100]; - void* a = &((struct sockaddr_in*)&ip->addr)->sin_addr; - if(ip->len != (socklen_t)sizeof(struct sockaddr_in)) - a = &((struct sockaddr_in6*)&ip->addr)->sin6_addr; - - if(inet_ntop((int)((struct sockaddr_in*)&ip->addr)->sin_family, - a, out, (socklen_t)sizeof(out))==0) - printf("%s (inet_ntop error)\n", msg); - else printf("%s %s\n", msg, out); - } -} - -/** free ip_list */ -static void -ip_list_free(struct ip_list* p) -{ - struct ip_list* np; - while(p) { - np = p->next; - free(p); - p = np; - } -} - -/** create ip_list entry for a RR record */ -static struct ip_list* -RR_to_ip(int tp, char* data, int len, int port) -{ - struct ip_list* ip = (struct ip_list*)calloc(1, sizeof(*ip)); - uint16_t p = (uint16_t)port; - if(tp == LDNS_RR_TYPE_A) { - struct sockaddr_in* sa = (struct sockaddr_in*)&ip->addr; - ip->len = (socklen_t)sizeof(*sa); - sa->sin_family = AF_INET; - sa->sin_port = (in_port_t)htons(p); - if(len != (int)sizeof(sa->sin_addr)) { - if(verb) printf("skipped badly formatted A\n"); - free(ip); - return NULL; - } - memmove(&sa->sin_addr, data, sizeof(sa->sin_addr)); - - } else if(tp == LDNS_RR_TYPE_AAAA) { - struct sockaddr_in6* sa = (struct sockaddr_in6*)&ip->addr; - ip->len = (socklen_t)sizeof(*sa); - sa->sin6_family = AF_INET6; - sa->sin6_port = (in_port_t)htons(p); - if(len != (int)sizeof(sa->sin6_addr)) { - if(verb) printf("skipped badly formatted AAAA\n"); - free(ip); - return NULL; - } - memmove(&sa->sin6_addr, data, sizeof(sa->sin6_addr)); - } else { - if(verb) printf("internal error: bad type in RRtoip\n"); - free(ip); - return NULL; - } - verb_addr("resolved server address", ip); - return ip; -} - -/** Resolve name, type, class and add addresses to iplist */ -static void -resolve_host_ip(struct ub_ctx* ctx, const char* host, int port, int tp, int cl, - struct ip_list** head) -{ - struct ub_result* res = NULL; - int r; - int i; - - r = ub_resolve(ctx, host, tp, cl, &res); - if(r) { - if(verb) printf("error: resolve %s %s: %s\n", host, - (tp==LDNS_RR_TYPE_A)?"A":"AAAA", ub_strerror(r)); - return; - } - if(!res) { - if(verb) printf("out of memory\n"); - ub_ctx_delete(ctx); - exit(0); - } - if(!res->havedata || res->rcode || !res->data) { - if(verb) printf("resolve %s %s: no result\n", host, - (tp==LDNS_RR_TYPE_A)?"A":"AAAA"); - return; - } - for(i = 0; res->data[i]; i++) { - struct ip_list* ip = RR_to_ip(tp, res->data[i], res->len[i], - port); - if(!ip) continue; - ip->next = *head; - *head = ip; - } - ub_resolve_free(res); -} - -/** parse a text IP address into a sockaddr */ -static struct ip_list* -parse_ip_addr(const char* str, int port) -{ - socklen_t len = 0; - union { - struct sockaddr_in6 a6; - struct sockaddr_in a; - } addr; - struct ip_list* ip; - uint16_t p = (uint16_t)port; - memset(&addr, 0, sizeof(addr)); - - if(inet_pton(AF_INET6, str, &addr.a6.sin6_addr) > 0) { - /* it is an IPv6 */ - addr.a6.sin6_family = AF_INET6; - addr.a6.sin6_port = (in_port_t)htons(p); - len = (socklen_t)sizeof(addr.a6); - } - if(inet_pton(AF_INET, str, &addr.a.sin_addr) > 0) { - /* it is an IPv4 */ - addr.a.sin_family = AF_INET; - addr.a.sin_port = (in_port_t)htons(p); - len = (socklen_t)sizeof(struct sockaddr_in); - } - if(!len) return NULL; - ip = (struct ip_list*)calloc(1, sizeof(*ip)); - if(!ip) { - if(verb) printf("out of memory\n"); - exit(0); - } - ip->len = len; - memmove(&ip->addr, &addr, len); - if(verb) printf("server address is %s\n", str); - return ip; -} - -/** - * Resolve a domain name (even though the resolver is down and there is - * no trust anchor). Without DNSSEC validation. - * @param host: the name to resolve. - * If this name is an IP4 or IP6 address this address is returned. - * @param port: the port number used for the returned IP structs. - * @param res_conf: resolv.conf (if any). - * @param root_hints: root hints (if any). - * @param debugconf: unbound.conf for debugging options. - * @param ip4only: use only ip4 for resolve and only lookup A - * @param ip6only: use only ip6 for resolve and only lookup AAAA - * default is to lookup A and AAAA using ip4 and ip6. - * @return list of IP addresses. - */ -static struct ip_list* -resolve_name(const char* host, int port, const char* res_conf, - const char* root_hints, const char* debugconf, int ip4only, int ip6only) -{ - struct ub_ctx* ctx; - struct ip_list* list = NULL; - /* first see if name is an IP address itself */ - if( (list=parse_ip_addr(host, port)) ) { - return list; - } - - /* create resolver context */ - ctx = create_unbound_context(res_conf, root_hints, debugconf, - ip4only, ip6only); - - /* try resolution of A */ - if(!ip6only) { - resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_A, - LDNS_RR_CLASS_IN, &list); - } - - /* try resolution of AAAA */ - if(!ip4only) { - resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_AAAA, - LDNS_RR_CLASS_IN, &list); - } - - ub_ctx_delete(ctx); - if(!list) { - if(verb) printf("%s has no IP addresses I can use\n", host); - exit(0); - } - return list; -} - -/** clear used flags */ -static void -wipe_ip_usage(struct ip_list* p) -{ - while(p) { - p->used = 0; - p = p->next; - } -} - -/** cound unused IPs */ -static int -count_unused(struct ip_list* p) -{ - int num = 0; - while(p) { - if(!p->used) num++; - p = p->next; - } - return num; -} - -/** pick random unused element from IP list */ -static struct ip_list* -pick_random_ip(struct ip_list* list) -{ - struct ip_list* p = list; - int num = count_unused(list); - int sel; - if(num == 0) return NULL; - /* not perfect, but random enough */ - sel = (int)arc4random_uniform((uint32_t)num); - /* skip over unused elements that we did not select */ - while(sel > 0 && p) { - if(!p->used) sel--; - p = p->next; - } - /* find the next unused element */ - while(p && p->used) - p = p->next; - if(!p) return NULL; /* robustness */ - return p; -} - -/** close the fd */ -static void -fd_close(int fd) -{ -#ifndef USE_WINSOCK - close(fd); -#else - closesocket(fd); -#endif -} - -/** printout socket errno */ -static void -print_sock_err(const char* msg) -{ -#ifndef USE_WINSOCK - if(verb) printf("%s: %s\n", msg, strerror(errno)); -#else - if(verb) printf("%s: %s\n", msg, wsa_strerror(WSAGetLastError())); -#endif -} - -/** connect to IP address */ -static int -connect_to_ip(struct ip_list* ip) -{ - int fd; - verb_addr("connect to", ip); - fd = socket(ip->len==(socklen_t)sizeof(struct sockaddr_in)? - AF_INET:AF_INET6, SOCK_STREAM, 0); - if(fd == -1) { - print_sock_err("socket"); - return -1; - } - if(connect(fd, (struct sockaddr*)&ip->addr, ip->len) < 0) { - print_sock_err("connect"); - fd_close(fd); - return -1; - } - return fd; -} - -/** create SSL context */ -static SSL_CTX* -setup_sslctx(void) -{ - SSL_CTX* sslctx = SSL_CTX_new(SSLv23_client_method()); - if(!sslctx) { - if(verb) printf("SSL_CTX_new error\n"); - return NULL; - } - return sslctx; -} - -/** initiate TLS on a connection */ -static SSL* -TLS_initiate(SSL_CTX* sslctx, int fd) -{ - X509* x; - int r; - SSL* ssl = SSL_new(sslctx); - if(!ssl) { - if(verb) printf("SSL_new error\n"); - return NULL; - } - SSL_set_connect_state(ssl); - (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); - if(!SSL_set_fd(ssl, fd)) { - if(verb) printf("SSL_set_fd error\n"); - SSL_free(ssl); - return NULL; - } - while(1) { - ERR_clear_error(); - if( (r=SSL_do_handshake(ssl)) == 1) - break; - r = SSL_get_error(ssl, r); - if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) { - if(verb) printf("SSL handshake failed\n"); - SSL_free(ssl); - return NULL; - } - /* wants to be called again */ - } - x = SSL_get_peer_certificate(ssl); - if(!x) { - if(verb) printf("Server presented no peer certificate\n"); - SSL_free(ssl); - return NULL; - } - verb_cert("server SSL certificate", x); - X509_free(x); - return ssl; -} - -/** perform neat TLS shutdown */ -static void -TLS_shutdown(int fd, SSL* ssl, SSL_CTX* sslctx) -{ - /* shutdown the SSL connection nicely */ - if(SSL_shutdown(ssl) == 0) { - SSL_shutdown(ssl); - } - SSL_free(ssl); - SSL_CTX_free(sslctx); - fd_close(fd); -} - -/** write a line over SSL */ -static int -write_ssl_line(SSL* ssl, const char* str, const char* sec) -{ - char buf[1024]; - size_t l; - if(sec) { - snprintf(buf, sizeof(buf), str, sec); - } else { - snprintf(buf, sizeof(buf), "%s", str); - } - l = strlen(buf); - if(l+2 >= sizeof(buf)) { - if(verb) printf("line too long\n"); - return 0; - } - if(verb >= 2) printf("SSL_write: %s\n", buf); - buf[l] = '\r'; - buf[l+1] = '\n'; - buf[l+2] = 0; - /* add \r\n */ - if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) { - if(verb) printf("could not SSL_write %s", str); - return 0; - } - return 1; -} - -/** process header line, check rcode and keeping track of size */ -static int -process_one_header(char* buf, size_t* clen, int* chunked) -{ - if(verb>=2) printf("header: '%s'\n", buf); - if(strncasecmp(buf, "HTTP/1.1 ", 9) == 0) { - /* check returncode */ - if(buf[9] != '2') { - if(verb) printf("bad status %s\n", buf+9); - return 0; - } - } else if(strncasecmp(buf, "Content-Length: ", 16) == 0) { - if(!*chunked) - *clen = (size_t)atoi(buf+16); - } else if(strncasecmp(buf, "Transfer-Encoding: chunked", 19+7) == 0) { - *clen = 0; - *chunked = 1; - } - return 1; -} - -/** - * 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; -} - -/** read http headers and process them */ -static size_t -read_http_headers(SSL* ssl, size_t* clen) -{ - char buf[1024]; - int chunked = 0; - *clen = 0; - while(read_ssl_line(ssl, buf, sizeof(buf))) { - if(buf[0] == 0) - return 1; - if(!process_one_header(buf, clen, &chunked)) - return 0; - } - return 0; -} - -/** read a data chunk */ -static char* -read_data_chunk(SSL* ssl, size_t len) -{ - size_t got = 0; - int r; - char* data; - if(len >= 0xfffffff0) - return NULL; /* to protect against integer overflow in malloc*/ - data = malloc(len+1); - if(!data) { - if(verb) printf("out of memory\n"); - return NULL; - } - while(got < len) { - if((r = SSL_read(ssl, data+got, (int)(len-got))) <= 0) { - if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { - /* EOF */ - if(verb) printf("could not SSL_read: unexpected EOF\n"); - free(data); - return NULL; - } - if(verb) printf("could not SSL_read\n"); - free(data); - return NULL; - } - if(verb >= 2) printf("at %d/%d\n", (int)got, (int)len); - got += r; - } - if(verb>=2) printf("read %d data\n", (int)len); - data[len] = 0; - return data; -} - -/** parse chunk header */ -static int -parse_chunk_header(char* buf, size_t* result) -{ - char* e = NULL; - size_t v = (size_t)strtol(buf, &e, 16); - if(e == buf) - return 0; - *result = v; - return 1; -} - -/** read chunked data from connection */ -static BIO* -do_chunked_read(SSL* ssl) -{ - char buf[1024]; - size_t len; - char* body; - BIO* mem = BIO_new(BIO_s_mem()); - if(verb>=3) printf("do_chunked_read\n"); - if(!mem) { - if(verb) printf("out of memory\n"); - return NULL; - } - while(read_ssl_line(ssl, buf, sizeof(buf))) { - /* read the chunked start line */ - if(verb>=2) printf("chunk header: %s\n", buf); - if(!parse_chunk_header(buf, &len)) { - BIO_free(mem); - if(verb>=3) printf("could not parse chunk header\n"); - return NULL; - } - if(verb>=2) printf("chunk len: %d\n", (int)len); - /* are we done? */ - if(len == 0) { - char z = 0; - /* skip end-of-chunk-trailer lines, - * until the empty line after that */ - do { - if(!read_ssl_line(ssl, buf, sizeof(buf))) { - BIO_free(mem); - return NULL; - } - } while (strlen(buf) > 0); - /* end of chunks, zero terminate it */ - if(BIO_write(mem, &z, 1) <= 0) { - if(verb) printf("out of memory\n"); - BIO_free(mem); - return NULL; - } - return mem; - } - /* read the chunked body */ - body = read_data_chunk(ssl, len); - if(!body) { - BIO_free(mem); - return NULL; - } - if(BIO_write(mem, body, (int)len) <= 0) { - if(verb) printf("out of memory\n"); - free(body); - BIO_free(mem); - return NULL; - } - free(body); - /* skip empty line after data chunk */ - if(!read_ssl_line(ssl, buf, sizeof(buf))) { - BIO_free(mem); - return NULL; - } - } - BIO_free(mem); - return NULL; -} - -/** start HTTP1.1 transaction on SSL */ -static int -write_http_get(SSL* ssl, const char* pathname, const char* urlname) -{ - if(write_ssl_line(ssl, "GET /%s HTTP/1.1", pathname) && - write_ssl_line(ssl, "Host: %s", urlname) && - write_ssl_line(ssl, "User-Agent: unbound-anchor/%s", - PACKAGE_VERSION) && - /* We do not really do multiple queries per connection, - * but this header setting is also not needed. - * write_ssl_line(ssl, "Connection: close", NULL) &&*/ - write_ssl_line(ssl, "", NULL)) { - return 1; - } - return 0; -} - -/** read chunked data and zero terminate; len is without zero */ -static char* -read_chunked_zero_terminate(SSL* ssl, size_t* len) -{ - /* do the chunked version */ - BIO* tmp = do_chunked_read(ssl); - char* data, *d = NULL; - size_t l; - if(!tmp) { - if(verb) printf("could not read from https\n"); - return NULL; - } - 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"); - return NULL; - } - *len = l-1; - data = (char*)malloc(l); - if(data == NULL) { - if(verb) printf("out of memory\n"); - return NULL; - } - memcpy(data, d, l); - BIO_free(tmp); - return data; -} - -/** read HTTP result from SSL */ -static BIO* -read_http_result(SSL* ssl) -{ - size_t len = 0; - char* data; - BIO* m; - if(!read_http_headers(ssl, &len)) { - return NULL; - } - if(len == 0) { - data = read_chunked_zero_terminate(ssl, &len); - } else { - data = read_data_chunk(ssl, len); - } - if(!data) return NULL; - if(verb >= 4) print_data("read data", data, (int)len); - m = BIO_new_mem_buf(data, (int)len); - if(!m) { - if(verb) printf("out of memory\n"); - exit(0); - } - return m; -} - -/** https to an IP addr, return BIO with pathname or NULL */ -static BIO* -https_to_ip(struct ip_list* ip, const char* pathname, const char* urlname) -{ - int fd; - SSL* ssl; - BIO* bio; - SSL_CTX* sslctx = setup_sslctx(); - if(!sslctx) { - return NULL; - } - fd = connect_to_ip(ip); - if(fd == -1) { - SSL_CTX_free(sslctx); - return NULL; - } - ssl = TLS_initiate(sslctx, fd); - if(!ssl) { - SSL_CTX_free(sslctx); - fd_close(fd); - return NULL; - } - if(!write_http_get(ssl, pathname, urlname)) { - if(verb) printf("could not write to server\n"); - SSL_free(ssl); - SSL_CTX_free(sslctx); - fd_close(fd); - return NULL; - } - bio = read_http_result(ssl); - TLS_shutdown(fd, ssl, sslctx); - return bio; -} - -/** - * Do a HTTPS, HTTP1.1 over TLS, to fetch a file - * @param ip_list: list of IP addresses to use to fetch from. - * @param pathname: pathname of file on server to GET. - * @param urlname: name to pass as the virtual host for this request. - * @return a memory BIO with the file in it. - */ -static BIO* -https(struct ip_list* ip_list, const char* pathname, const char* urlname) -{ - struct ip_list* ip; - BIO* bio = NULL; - /* try random address first, and work through the list */ - wipe_ip_usage(ip_list); - while( (ip = pick_random_ip(ip_list)) ) { - ip->used = 1; - bio = https_to_ip(ip, pathname, urlname); - if(bio) break; - } - if(!bio) { - if(verb) printf("could not fetch %s\n", pathname); - exit(0); - } else { - if(verb) printf("fetched %s (%d bytes)\n", - pathname, (int)BIO_ctrl_pending(bio)); - } - return bio; -} - -/** free up a downloaded file BIO */ -static void -free_file_bio(BIO* bio) -{ - char* pp = NULL; - (void)BIO_reset(bio); - (void)BIO_get_mem_data(bio, &pp); - free(pp); - BIO_free(bio); -} - -/** XML parse private data during the parse */ -struct xml_data { - /** the parser, reference */ - XML_Parser parser; - /** the current tag; malloced; or NULL outside of tags */ - char* tag; - /** current date to use during the parse */ - time_t date; - /** number of keys usefully read in */ - int num_keys; - /** the compiled anchors as DS records */ - BIO* ds; - - /** do we want to use this anchor? */ - int use_key; - /** the current anchor: Zone */ - BIO* czone; - /** the current anchor: KeyTag */ - BIO* ctag; - /** the current anchor: Algorithm */ - BIO* calgo; - /** the current anchor: DigestType */ - BIO* cdigtype; - /** the current anchor: Digest*/ - BIO* cdigest; -}; - -/** The BIO for the tag */ -static BIO* -xml_selectbio(struct xml_data* data, const char* tag) -{ - BIO* b = NULL; - if(strcasecmp(tag, "KeyTag") == 0) - b = data->ctag; - else if(strcasecmp(tag, "Algorithm") == 0) - b = data->calgo; - else if(strcasecmp(tag, "DigestType") == 0) - b = data->cdigtype; - else if(strcasecmp(tag, "Digest") == 0) - b = data->cdigest; - return b; -} - -/** - * XML handle character data, the data inside an element. - * @param userData: xml_data structure - * @param s: the character data. May not all be in one callback. - * NOT zero terminated. - * @param len: length of this part of the data. - */ -static void -xml_charhandle(void *userData, const XML_Char *s, int len) -{ - struct xml_data* data = (struct xml_data*)userData; - BIO* b = NULL; - /* skip characters outside of elements */ - if(!data->tag) - return; - if(verb>=4) { - int i; - printf("%s%s charhandle: '", - data->use_key?"use ":"", - data->tag?data->tag:"none"); - for(i=0; i<len; i++) - printf("%c", s[i]); - printf("'\n"); - } - if(strcasecmp(data->tag, "Zone") == 0) { - if(BIO_write(data->czone, s, len) < 0) { - if(verb) printf("out of memory in BIO_write\n"); - exit(0); - } - return; - } - /* only store if key is used */ - if(!data->use_key) - return; - b = xml_selectbio(data, data->tag); - if(b) { - if(BIO_write(b, s, len) < 0) { - if(verb) printf("out of memory in BIO_write\n"); - exit(0); - } - } -} - -/** - * XML fetch value of particular attribute(by name) or NULL if not present. - * @param atts: attribute array (from xml_startelem). - * @param name: name of attribute to look for. - * @return the value or NULL. (ptr into atts). - */ -static const XML_Char* -find_att(const XML_Char **atts, const XML_Char* name) -{ - int i; - for(i=0; atts[i]; i+=2) { - if(strcasecmp(atts[i], name) == 0) - return atts[i+1]; - } - return NULL; -} - -/** - * XML convert DateTime element to time_t. - * [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] - * (with optional .ssssss fractional seconds) - * @param str: the string - * @return a time_t representation or 0 on failure. - */ -static time_t -xml_convertdate(const char* str) -{ - time_t t = 0; - struct tm tm; - const char* s; - /* for this application, ignore minus in front; - * only positive dates are expected */ - s = str; - if(s[0] == '-') s++; - memset(&tm, 0, sizeof(tm)); - /* parse initial content of the string (lots of whitespace allowed) */ - s = strptime(s, "%t%Y%t-%t%m%t-%t%d%tT%t%H%t:%t%M%t:%t%S%t", &tm); - if(!s) { - if(verb) printf("xml_convertdate parse failure %s\n", str); - return 0; - } - /* parse remainder of date string */ - if(*s == '.') { - /* optional '.' and fractional seconds */ - int frac = 0, n = 0; - if(sscanf(s+1, "%d%n", &frac, &n) < 1) { - if(verb) printf("xml_convertdate f failure %s\n", str); - return 0; - } - /* fraction is not used, time_t has second accuracy */ - s++; - s+=n; - } - if(*s == 'Z' || *s == 'z') { - /* nothing to do for this */ - s++; - } else if(*s == '+' || *s == '-') { - /* optional timezone spec: Z or +hh:mm or -hh:mm */ - int hr = 0, mn = 0, n = 0; - if(sscanf(s+1, "%d:%d%n", &hr, &mn, &n) < 2) { - if(verb) printf("xml_convertdate tz failure %s\n", str); - return 0; - } - if(*s == '+') { - tm.tm_hour += hr; - tm.tm_min += mn; - } else { - tm.tm_hour -= hr; - tm.tm_min -= mn; - } - s++; - s += n; - } - if(*s != 0) { - /* not ended properly */ - /* but ignore, (lenient) */ - } - - t = sldns_mktime_from_utc(&tm); - if(t == (time_t)-1) { - if(verb) printf("xml_convertdate mktime failure\n"); - return 0; - } - return t; -} - -/** - * XML handle the KeyDigest start tag, check validity periods. - */ -static void -handle_keydigest(struct xml_data* data, const XML_Char **atts) -{ - data->use_key = 0; - if(find_att(atts, "validFrom")) { - time_t from = xml_convertdate(find_att(atts, "validFrom")); - if(from == 0) { - if(verb) printf("error: xml cannot be parsed\n"); - exit(0); - } - if(data->date < from) - return; - } - if(find_att(atts, "validUntil")) { - time_t until = xml_convertdate(find_att(atts, "validUntil")); - if(until == 0) { - if(verb) printf("error: xml cannot be parsed\n"); - exit(0); - } - if(data->date > until) - return; - } - /* yes we want to use this key */ - data->use_key = 1; - (void)BIO_reset(data->ctag); - (void)BIO_reset(data->calgo); - (void)BIO_reset(data->cdigtype); - (void)BIO_reset(data->cdigest); -} - -/** See if XML element equals the zone name */ -static int -xml_is_zone_name(BIO* zone, const char* name) -{ - char buf[1024]; - char* z = NULL; - long zlen; - (void)BIO_seek(zone, 0); - zlen = BIO_get_mem_data(zone, &z); - if(!zlen || !z) return 0; - /* zero terminate */ - if(zlen >= (long)sizeof(buf)) return 0; - memmove(buf, z, (size_t)zlen); - buf[zlen] = 0; - /* compare */ - return (strncasecmp(buf, name, strlen(name)) == 0); -} - -/** - * XML start of element. This callback is called whenever an XML tag starts. - * XML_Char is UTF8. - * @param userData: the xml_data structure. - * @param name: the tag that starts. - * @param atts: array of strings, pairs of attr = value, ends with NULL. - * i.e. att[0]="att[1]" att[2]="att[3]" att[4]isNull - */ -static void -xml_startelem(void *userData, const XML_Char *name, const XML_Char **atts) -{ - struct xml_data* data = (struct xml_data*)userData; - BIO* b; - if(verb>=4) printf("xml tag start '%s'\n", name); - free(data->tag); - data->tag = strdup(name); - if(!data->tag) { - if(verb) printf("out of memory\n"); - exit(0); - } - if(verb>=4) { - int i; - for(i=0; atts[i]; i+=2) { - printf(" %s='%s'\n", atts[i], atts[i+1]); - } - } - /* handle attributes to particular types */ - if(strcasecmp(name, "KeyDigest") == 0) { - handle_keydigest(data, atts); - return; - } else if(strcasecmp(name, "Zone") == 0) { - (void)BIO_reset(data->czone); - return; - } - - /* for other types we prepare to pick up the data */ - if(!data->use_key) - return; - b = xml_selectbio(data, data->tag); - if(b) { - /* empty it */ - (void)BIO_reset(b); - } -} - -/** Append str to bio */ -static void -xml_append_str(BIO* b, const char* s) -{ - if(BIO_write(b, s, (int)strlen(s)) < 0) { - if(verb) printf("out of memory in BIO_write\n"); - exit(0); - } -} - -/** Append bio to bio */ -static void -xml_append_bio(BIO* b, BIO* a) -{ - char* z = NULL; - long i, len; - (void)BIO_seek(a, 0); - len = BIO_get_mem_data(a, &z); - if(!len || !z) { - if(verb) printf("out of memory in BIO_write\n"); - exit(0); - } - /* remove newlines in the data here */ - for(i=0; i<len; i++) { - if(z[i] == '\r' || z[i] == '\n') - z[i] = ' '; - } - /* write to BIO */ - if(BIO_write(b, z, len) < 0) { - if(verb) printf("out of memory in BIO_write\n"); - exit(0); - } -} - -/** write the parsed xml-DS to the DS list */ -static void -xml_append_ds(struct xml_data* data) -{ - /* write DS to accumulated DS */ - xml_append_str(data->ds, ". IN DS "); - xml_append_bio(data->ds, data->ctag); - xml_append_str(data->ds, " "); - xml_append_bio(data->ds, data->calgo); - xml_append_str(data->ds, " "); - xml_append_bio(data->ds, data->cdigtype); - xml_append_str(data->ds, " "); - xml_append_bio(data->ds, data->cdigest); - xml_append_str(data->ds, "\n"); - data->num_keys++; -} - -/** - * XML end of element. This callback is called whenever an XML tag ends. - * XML_Char is UTF8. - * @param userData: the xml_data structure - * @param name: the tag that ends. - */ -static void -xml_endelem(void *userData, const XML_Char *name) -{ - struct xml_data* data = (struct xml_data*)userData; - if(verb>=4) printf("xml tag end '%s'\n", name); - free(data->tag); - data->tag = NULL; - if(strcasecmp(name, "KeyDigest") == 0) { - if(data->use_key) - xml_append_ds(data); - data->use_key = 0; - } else if(strcasecmp(name, "Zone") == 0) { - if(!xml_is_zone_name(data->czone, ".")) { - if(verb) printf("xml not for the right zone\n"); - exit(0); - } - } -} - -/* Stop the parser when an entity declaration is encountered. For safety. */ -static void -xml_entitydeclhandler(void *userData, - const XML_Char *ATTR_UNUSED(entityName), - int ATTR_UNUSED(is_parameter_entity), - const XML_Char *ATTR_UNUSED(value), int ATTR_UNUSED(value_length), - const XML_Char *ATTR_UNUSED(base), - const XML_Char *ATTR_UNUSED(systemId), - const XML_Char *ATTR_UNUSED(publicId), - const XML_Char *ATTR_UNUSED(notationName)) -{ -#if HAVE_DECL_XML_STOPPARSER - (void)XML_StopParser((XML_Parser)userData, XML_FALSE); -#else - (void)userData; -#endif -} - -/** - * XML parser setup of the callbacks for the tags - */ -static void -xml_parse_setup(XML_Parser parser, struct xml_data* data, time_t now) -{ - char buf[1024]; - memset(data, 0, sizeof(*data)); - XML_SetUserData(parser, data); - data->parser = parser; - data->date = now; - data->ds = BIO_new(BIO_s_mem()); - data->ctag = BIO_new(BIO_s_mem()); - data->czone = BIO_new(BIO_s_mem()); - data->calgo = BIO_new(BIO_s_mem()); - data->cdigtype = BIO_new(BIO_s_mem()); - data->cdigest = BIO_new(BIO_s_mem()); - if(!data->ds || !data->ctag || !data->calgo || !data->czone || - !data->cdigtype || !data->cdigest) { - if(verb) printf("out of memory\n"); - exit(0); - } - snprintf(buf, sizeof(buf), "; created by unbound-anchor on %s", - ctime(&now)); - if(BIO_write(data->ds, buf, (int)strlen(buf)) < 0) { - if(verb) printf("out of memory\n"); - exit(0); - } - XML_SetEntityDeclHandler(parser, xml_entitydeclhandler); - XML_SetElementHandler(parser, xml_startelem, xml_endelem); - XML_SetCharacterDataHandler(parser, xml_charhandle); -} - -/** - * Perform XML parsing of the root-anchors file - * Its format description can be read here - * https://data.iana.org/root-anchors/draft-icann-dnssec-trust-anchor.txt - * It uses libexpat. - * @param xml: BIO with xml data. - * @param now: the current time for checking DS validity periods. - * @return memoryBIO with the DS data in zone format. - * or NULL if the zone is insecure. - * (It exit()s on error) - */ -static BIO* -xml_parse(BIO* xml, time_t now) -{ - char* pp; - int len; - XML_Parser parser; - struct xml_data data; - - parser = XML_ParserCreate(NULL); - if(!parser) { - if(verb) printf("could not XML_ParserCreate\n"); - exit(0); - } - - /* setup callbacks */ - xml_parse_setup(parser, &data, now); - - /* parse it */ - (void)BIO_reset(xml); - len = (int)BIO_get_mem_data(xml, &pp); - if(!len || !pp) { - if(verb) printf("out of memory\n"); - exit(0); - } - if(!XML_Parse(parser, pp, len, 1 /*isfinal*/ )) { - const char *e = XML_ErrorString(XML_GetErrorCode(parser)); - if(verb) printf("XML_Parse failure %s\n", e?e:""); - exit(0); - } - - /* parsed */ - if(verb) printf("XML was parsed successfully, %d keys\n", - data.num_keys); - free(data.tag); - XML_ParserFree(parser); - - if(verb >= 4) { - (void)BIO_seek(data.ds, 0); - len = BIO_get_mem_data(data.ds, &pp); - printf("got DS bio %d: '", len); - if(!fwrite(pp, (size_t)len, 1, stdout)) - /* compilers do not allow us to ignore fwrite .. */ - fprintf(stderr, "error writing to stdout\n"); - printf("'\n"); - } - BIO_free(data.czone); - BIO_free(data.ctag); - BIO_free(data.calgo); - BIO_free(data.cdigtype); - BIO_free(data.cdigest); - - if(data.num_keys == 0) { - /* the root zone seems to have gone insecure */ - BIO_free(data.ds); - return NULL; - } else { - return data.ds; - } -} - -/* get key usage out of its extension, returns 0 if no key_usage extension */ -static unsigned long -get_usage_of_ex(X509* cert) -{ - unsigned long val = 0; - ASN1_BIT_STRING* s; - if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) { - if(s->length > 0) { - val = s->data[0]; - if(s->length > 1) - val |= s->data[1] << 8; - } - ASN1_BIT_STRING_free(s); - } - return val; -} - -/** get valid signers from the list of signers in the signature */ -static STACK_OF(X509)* -get_valid_signers(PKCS7* p7, const char* p7signer) -{ - int i; - STACK_OF(X509)* validsigners = sk_X509_new_null(); - STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0); - unsigned long usage = 0; - if(!validsigners) { - if(verb) printf("out of memory\n"); - sk_X509_free(signers); - return NULL; - } - if(!signers) { - if(verb) printf("no signers in pkcs7 signature\n"); - sk_X509_free(validsigners); - return NULL; - } - for(i=0; i<sk_X509_num(signers); i++) { - X509_NAME* nm = X509_get_subject_name( - sk_X509_value(signers, i)); - char buf[1024]; - if(!nm) { - if(verb) printf("signer %d: cert has no subject name\n", i); - continue; - } - if(verb && nm) { - char* nmline = X509_NAME_oneline(nm, buf, - (int)sizeof(buf)); - printf("signer %d: Subject: %s\n", i, - nmline?nmline:"no subject"); - if(verb >= 3 && X509_NAME_get_text_by_NID(nm, - NID_commonName, buf, (int)sizeof(buf))) - printf("commonName: %s\n", buf); - if(verb >= 3 && X509_NAME_get_text_by_NID(nm, - NID_pkcs9_emailAddress, buf, (int)sizeof(buf))) - printf("emailAddress: %s\n", buf); - } - if(verb) { - int ku_loc = X509_get_ext_by_NID( - sk_X509_value(signers, i), NID_key_usage, -1); - if(verb >= 3 && ku_loc >= 0) { - X509_EXTENSION *ex = X509_get_ext( - sk_X509_value(signers, i), ku_loc); - if(ex) { - printf("keyUsage: "); - X509V3_EXT_print_fp(stdout, ex, 0, 0); - printf("\n"); - } - } - } - if(!p7signer || strcmp(p7signer, "")==0) { - /* there is no name to check, return all records */ - if(verb) printf("did not check commonName of signer\n"); - } else { - if(!X509_NAME_get_text_by_NID(nm, - NID_pkcs9_emailAddress, - buf, (int)sizeof(buf))) { - if(verb) printf("removed cert with no name\n"); - continue; /* no name, no use */ - } - if(strcmp(buf, p7signer) != 0) { - if(verb) printf("removed cert with wrong name\n"); - continue; /* wrong name, skip it */ - } - } - - /* check that the key usage allows digital signatures - * (the p7s) */ - usage = get_usage_of_ex(sk_X509_value(signers, i)); - if(!(usage & KU_DIGITAL_SIGNATURE)) { - if(verb) printf("removed cert with no key usage Digital Signature allowed\n"); - continue; - } - - /* we like this cert, add it to our list of valid - * signers certificates */ - sk_X509_push(validsigners, sk_X509_value(signers, i)); - } - sk_X509_free(signers); - return validsigners; -} - -/** verify a PKCS7 signature, false on failure */ -static int -verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust, const char* p7signer) -{ - PKCS7* p7; - X509_STORE *store = X509_STORE_new(); - STACK_OF(X509)* validsigners; - int secure = 0; - int i; -#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE - X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new(); - if(!param) { - if(verb) printf("out of memory\n"); - X509_STORE_free(store); - return 0; - } - /* do the selfcheck on the root certificate; it checks that the - * input is valid */ - X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CHECK_SS_SIGNATURE); - if(store) X509_STORE_set1_param(store, param); -#endif - if(!store) { - if(verb) printf("out of memory\n"); -#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE - X509_VERIFY_PARAM_free(param); -#endif - return 0; - } -#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE - X509_VERIFY_PARAM_free(param); -#endif - - (void)BIO_reset(p7s); - (void)BIO_reset(data); - - /* convert p7s to p7 (the signature) */ - p7 = d2i_PKCS7_bio(p7s, NULL); - if(!p7) { - if(verb) printf("could not parse p7s signature file\n"); - X509_STORE_free(store); - return 0; - } - if(verb >= 2) printf("parsed the PKCS7 signature\n"); - - /* convert trust to trusted certificate store */ - for(i=0; i<sk_X509_num(trust); i++) { - if(!X509_STORE_add_cert(store, sk_X509_value(trust, i))) { - if(verb) printf("failed X509_STORE_add_cert\n"); - X509_STORE_free(store); - PKCS7_free(p7); - return 0; - } - } - if(verb >= 2) printf("setup the X509_STORE\n"); - - /* check what is in the Subject name of the certificates, - * and build a stack that contains only the right certificates */ - validsigners = get_valid_signers(p7, p7signer); - if(!validsigners) { - X509_STORE_free(store); - PKCS7_free(p7); - return 0; - } - if(PKCS7_verify(p7, validsigners, store, data, NULL, PKCS7_NOINTERN) == 1) { - secure = 1; - if(verb) printf("the PKCS7 signature verified\n"); - } else { - if(verb) { - ERR_print_errors_fp(stdout); - } - } - - sk_X509_free(validsigners); - X509_STORE_free(store); - PKCS7_free(p7); - return secure; -} - -/** write unsigned root anchor file, a 5011 revoked tp */ -static void -write_unsigned_root(const char* root_anchor_file) -{ - FILE* out; - time_t now = time(NULL); - out = fopen(root_anchor_file, "w"); - if(!out) { - if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno)); - return; - } - if(fprintf(out, "; autotrust trust anchor file\n" - ";;REVOKED\n" - ";;id: . 1\n" - "; This file was written by unbound-anchor on %s" - "; It indicates that the root does not use DNSSEC\n" - "; to restart DNSSEC overwrite this file with a\n" - "; valid trustanchor or (empty-it and run unbound-anchor)\n" - , ctime(&now)) < 0) { - if(verb) printf("failed to write 'unsigned' to %s\n", - root_anchor_file); - if(verb && errno != 0) printf("%s\n", strerror(errno)); - } - fflush(out); -#ifdef HAVE_FSYNC - fsync(fileno(out)); -#else - FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); -#endif - fclose(out); -} - -/** write root anchor file */ -static void -write_root_anchor(const char* root_anchor_file, BIO* ds) -{ - char* pp = NULL; - int len; - FILE* out; - (void)BIO_seek(ds, 0); - len = BIO_get_mem_data(ds, &pp); - if(!len || !pp) { - if(verb) printf("out of memory\n"); - return; - } - out = fopen(root_anchor_file, "w"); - if(!out) { - if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno)); - return; - } - if(fwrite(pp, (size_t)len, 1, out) != 1) { - if(verb) printf("failed to write all data to %s\n", - root_anchor_file); - if(verb && errno != 0) printf("%s\n", strerror(errno)); - } - fflush(out); -#ifdef HAVE_FSYNC - fsync(fileno(out)); -#else - FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out))); -#endif - fclose(out); -} - -/** Perform the verification and update of the trustanchor file */ -static void -verify_and_update_anchor(const char* root_anchor_file, BIO* xml, BIO* p7s, - STACK_OF(X509)* cert, const char* p7signer) -{ - BIO* ds; - - /* verify xml file */ - if(!verify_p7sig(xml, p7s, cert, p7signer)) { - printf("the PKCS7 signature failed\n"); - exit(0); - } - - /* parse the xml file into DS records */ - ds = xml_parse(xml, time(NULL)); - if(!ds) { - /* the root zone is unsigned now */ - write_unsigned_root(root_anchor_file); - } else { - /* reinstate 5011 tracking */ - write_root_anchor(root_anchor_file, ds); - } - BIO_free(ds); -} - -#ifdef USE_WINSOCK -static void do_wsa_cleanup(void) { WSACleanup(); } -#endif - -/** perform actual certupdate work */ -static int -do_certupdate(const char* root_anchor_file, const char* root_cert_file, - const char* urlname, const char* xmlname, const char* p7sname, - const char* p7signer, const char* res_conf, const char* root_hints, - const char* debugconf, int ip4only, int ip6only, int port, - struct ub_result* dnskey) -{ - STACK_OF(X509)* cert; - BIO *xml, *p7s; - struct ip_list* ip_list = NULL; - - /* read pem file or provide builtin */ - cert = read_cert_or_builtin(root_cert_file); - - /* lookup A, AAAA for the urlname (or parse urlname if IP address) */ - ip_list = resolve_name(urlname, port, res_conf, root_hints, debugconf, - ip4only, ip6only); - -#ifdef USE_WINSOCK - if(1) { /* libunbound finished, startup WSA for the https connection */ - WSADATA wsa_data; - int r; - if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) { - if(verb) printf("WSAStartup failed: %s\n", - wsa_strerror(r)); - exit(0); - } - atexit(&do_wsa_cleanup); - } -#endif - - /* fetch the necessary files over HTTPS */ - xml = https(ip_list, xmlname, urlname); - p7s = https(ip_list, p7sname, urlname); - - /* verify and update the root anchor */ - verify_and_update_anchor(root_anchor_file, xml, p7s, cert, p7signer); - if(verb) printf("success: the anchor has been updated " - "using the cert\n"); - - free_file_bio(xml); - free_file_bio(p7s); -#ifndef S_SPLINT_S - sk_X509_pop_free(cert, X509_free); -#endif - ub_resolve_free(dnskey); - ip_list_free(ip_list); - return 1; -} - -/** - * 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(const 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(const char* file) -{ - const char* builtin_root_anchor = get_builtin_ds(); - 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. - * @param root_anchor_file: filename of the root anchor. - * @param used_builtin: set to 1 if the builtin is written. - * @return 0 if trustpoint is insecure, 1 on success. Exit on failure. - */ -static int -provide_builtin(const char* root_anchor_file, int* used_builtin) -{ - /* try to read it */ - switch(try_read_anchor(root_anchor_file)) - { - case 0: /* no exist or empty */ - write_builtin_anchor(root_anchor_file); - *used_builtin = 1; - break; - case 1: /* revoked tp */ - return 0; - case 2: /* it is fine */ - default: - break; - } - return 1; -} - -/** - * add an autotrust anchor for the root to the context - */ -static void -add_5011_probe_root(struct ub_ctx* ctx, const 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. - * @param ctx: the unbound context to perform the priming with. - * @return: the result of the prime, on error it exit()s. - */ -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; -} - -/** see if ADDPEND keys exist in autotrust file (if possible) */ -static int -read_if_pending_keys(const char* file) -{ - FILE* in = fopen(file, "r"); - char line[8192]; - if(!in) { - if(verb>=2) printf("%s: %s\n", file, strerror(errno)); - return 0; - } - while(fgets(line, (int)sizeof(line), in)) { - if(line[0]==';') continue; - if(strstr(line, "[ ADDPEND ]")) { - fclose(in); - if(verb) printf("RFC5011-state has ADDPEND keys\n"); - return 1; - } - } - fclose(in); - return 0; -} - -/** read last successful probe time from autotrust file (if possible) */ -static int32_t -read_last_success_time(const 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; -} - -/** - * 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. - * @param root_anchor_file: filename of root key - * @return true if certupdate is ok. - */ -static int -probe_date_allows_certupdate(const char* root_anchor_file) -{ - int has_pending_keys = read_if_pending_keys(root_anchor_file); - int32_t last_success = read_last_success_time(root_anchor_file); - int32_t now = (int32_t)time(NULL); - 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(time(NULL) < xml_convertdate("2010-07-15T00:00:00")) { - if(verb) printf("the date is before the root was first signed," - " please correct the clock\n"); - return 0; - } - if(last_success == 0) - return 1; /* no probe time */ - if(has_pending_keys) - return 1; /* key in ADDPEND state, a previous probe has - inserted that, and it was present in all recent probes, - but it has not become active. The 30 day timer may not have - expired, but we know(for sure) there is a rollover going on. - If we only managed to pickup the new key on its last day - of announcement (for example) this can happen. */ - 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(const char* root_anchor_file, const char* root_cert_file, - const char* urlname, const char* xmlname, const char* p7sname, - const char* p7signer, const char* res_conf, const char* root_hints, - const char* debugconf, int ip4only, int ip6only, int force, int port) -{ - struct ub_ctx* ctx; - struct ub_result* dnskey; - int used_builtin = 0; - - /* see if builtin rootanchor needs to be provided, or if - * rootanchor is 'revoked-trust-point' */ - if(!provide_builtin(root_anchor_file, &used_builtin)) - 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 used_builtin; - } - 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)) || force) { - if(do_certupdate(root_anchor_file, root_cert_file, urlname, - xmlname, p7sname, p7signer, res_conf, root_hints, - debugconf, ip4only, ip6only, port, dnskey)) - return 1; - return used_builtin; - } - if(verb) printf("fail: the anchor is NOT ok and could not be fixed\n"); - ub_resolve_free(dnskey); - return used_builtin; -} - -/** 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 unbound-anchor */ -int main(int argc, char* argv[]) -{ - int c; - const char* root_anchor_file = ROOT_ANCHOR_FILE; - const char* root_cert_file = ROOT_CERT_FILE; - const char* urlname = URLNAME; - const char* xmlname = XMLNAME; - const char* p7sname = P7SNAME; - const char* p7signer = P7SIGNER; - const char* res_conf = NULL; - const char* root_hints = NULL; - const char* debugconf = NULL; - int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT; - /* parse the options */ - while( (c=getopt(argc, argv, "46C:FP:a:c:f:hln:r:s:u:vx:")) != -1) { - switch(c) { - case 'l': - dolist = 1; - break; - 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 'n': - p7signer = 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 'P': - port = atoi(optarg); - break; - case 'v': - verb++; - break; - case '?': - case 'h': - default: - usage(); - } - } - argc -= optind; - argv += optind; - if(argc != 0) - usage(); - -#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS - ERR_load_crypto_strings(); -#endif - ERR_load_SSL_strings(); -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) - OpenSSL_add_all_algorithms(); -#else - OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS - | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); -#endif -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) - (void)SSL_library_init(); -#else - (void)OPENSSL_init_ssl(0, NULL); -#endif - - if(dolist) do_list_builtin(); - - return do_root_update_work(root_anchor_file, root_cert_file, urlname, - xmlname, p7sname, p7signer, res_conf, root_hints, debugconf, - ip4only, ip6only, force, port); -} diff --git a/external/unbound/smallapp/unbound-checkconf.c b/external/unbound/smallapp/unbound-checkconf.c deleted file mode 100644 index ddf8b3a75..000000000 --- a/external/unbound/smallapp/unbound-checkconf.c +++ /dev/null @@ -1,619 +0,0 @@ -/* - * checkconf/unbound-checkconf.c - config file checker for unbound.conf file. - * - * Copyright (c) 2007, 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 COPYRIGHT - * HOLDER 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 - * - * The config checker checks for syntax and other errors in the unbound.conf - * file, and can be used to check for errors before the server is started - * or sigHUPped. - * Exit status 1 means an error. - */ - -#include "config.h" -#include "util/log.h" -#include "util/config_file.h" -#include "util/module.h" -#include "util/net_help.h" -#include "util/regional.h" -#include "iterator/iterator.h" -#include "iterator/iter_fwd.h" -#include "iterator/iter_hints.h" -#include "validator/validator.h" -#include "services/localzone.h" -#include "services/view.h" -#include "respip/respip.h" -#include "sldns/sbuffer.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_GLOB_H -#include <glob.h> -#endif -#ifdef WITH_PYTHONMODULE -#include "pythonmod/pythonmod.h" -#endif - -/** Give checkconf usage, and exit (1). */ -static void -usage(void) -{ - printf("Usage: unbound-checkconf [file]\n"); - printf(" Checks unbound configuration file for errors.\n"); - printf("file if omitted %s is used.\n", CONFIGFILE); - printf("-o option print value of option to stdout.\n"); - printf("-f output full pathname with chroot applied, eg. with -o pidfile.\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); -} - -/** - * Print given option to stdout - * @param cfg: config - * @param opt: option name without trailing :. - * This is different from config_set_option. - * @param final: if final pathname with chroot applied has to be printed. - */ -static void -print_option(struct config_file* cfg, const char* opt, int final) -{ - if(strcmp(opt, "pidfile") == 0 && final) { - char *p = fname_after_chroot(cfg->pidfile, cfg, 1); - if(!p) fatal_exit("out of memory"); - printf("%s\n", p); - free(p); - return; - } - if(!config_get_option(cfg, opt, config_print_func, stdout)) - fatal_exit("cannot print option '%s'", opt); -} - -/** check if module works with config */ -static void -check_mod(struct config_file* cfg, struct module_func_block* fb) -{ - struct module_env env; - memset(&env, 0, sizeof(env)); - env.cfg = cfg; - env.scratch = regional_create(); - env.scratch_buffer = sldns_buffer_new(BUFSIZ); - if(!env.scratch || !env.scratch_buffer) - fatal_exit("out of memory"); - if(!edns_known_options_init(&env)) - fatal_exit("out of memory"); - if(!(*fb->init)(&env, 0)) { - fatal_exit("bad config for %s module", fb->name); - } - (*fb->deinit)(&env, 0); - sldns_buffer_free(env.scratch_buffer); - regional_destroy(env.scratch); - edns_known_options_delete(&env); -} - -/** check localzones */ -static void -localzonechecks(struct config_file* cfg) -{ - struct local_zones* zs; - if(!(zs = local_zones_create())) - fatal_exit("out of memory"); - if(!local_zones_apply_cfg(zs, cfg)) - fatal_exit("failed local-zone, local-data configuration"); - local_zones_delete(zs); -} - -/** check view and response-ip configuration */ -static void -view_and_respipchecks(struct config_file* cfg) -{ - struct views* views = NULL; - struct respip_set* respip = NULL; - int ignored = 0; - if(!(views = views_create())) - fatal_exit("Could not create views: out of memory"); - if(!(respip = respip_set_create())) - fatal_exit("Could not create respip set: out of memory"); - if(!views_apply_cfg(views, cfg)) - fatal_exit("Could not set up views"); - if(!respip_global_apply_cfg(respip, cfg)) - fatal_exit("Could not setup respip set"); - if(!respip_views_apply_cfg(views, cfg, &ignored)) - fatal_exit("Could not setup per-view respip sets"); - views_delete(views); - respip_set_delete(respip); -} - -/** emit warnings for IP in hosts */ -static void -warn_hosts(const char* typ, struct config_stub* list) -{ - struct sockaddr_storage a; - socklen_t alen; - struct config_stub* s; - struct config_strlist* h; - for(s=list; s; s=s->next) { - for(h=s->hosts; h; h=h->next) { - if(extstrtoaddr(h->str, &a, &alen)) { - fprintf(stderr, "unbound-checkconf: warning:" - " %s %s: \"%s\" is an IP%s address, " - "and when looked up as a host name " - "during use may not resolve.\n", - s->name, typ, h->str, - addr_is_ip6(&a, alen)?"6":"4"); - } - } - } -} - -/** check interface strings */ -static void -interfacechecks(struct config_file* cfg) -{ - int d; - struct sockaddr_storage a; - socklen_t alen; - int i, j; - for(i=0; i<cfg->num_ifs; i++) { - if(!extstrtoaddr(cfg->ifs[i], &a, &alen)) { - fatal_exit("cannot parse interface specified as '%s'", - cfg->ifs[i]); - } - for(j=0; j<cfg->num_ifs; j++) { - if(i!=j && strcmp(cfg->ifs[i], cfg->ifs[j])==0) - fatal_exit("interface: %s present twice, " - "cannot bind same ports twice.", - cfg->ifs[i]); - } - } - for(i=0; i<cfg->num_out_ifs; i++) { - if(!ipstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen) && - !netblockstrtoaddr(cfg->out_ifs[i], UNBOUND_DNS_PORT, &a, &alen, &d)) { - fatal_exit("cannot parse outgoing-interface " - "specified as '%s'", cfg->out_ifs[i]); - } - for(j=0; j<cfg->num_out_ifs; j++) { - if(i!=j && strcmp(cfg->out_ifs[i], cfg->out_ifs[j])==0) - fatal_exit("outgoing-interface: %s present " - "twice, cannot bind same ports twice.", - cfg->out_ifs[i]); - } - } -} - -/** check acl ips */ -static void -aclchecks(struct config_file* cfg) -{ - int d; - struct sockaddr_storage a; - socklen_t alen; - struct config_str2list* acl; - for(acl=cfg->acls; acl; acl = acl->next) { - if(!netblockstrtoaddr(acl->str, UNBOUND_DNS_PORT, &a, &alen, - &d)) { - fatal_exit("cannot parse access control address %s %s", - acl->str, acl->str2); - } - } -} - -/** true if fname is a file */ -static int -is_file(const char* fname) -{ - struct stat buf; - if(stat(fname, &buf) < 0) { - if(errno==EACCES) { - printf("warning: no search permission for one of the directories in path: %s\n", fname); - return 1; - } - perror(fname); - return 0; - } - if(S_ISDIR(buf.st_mode)) { - printf("%s is not a file\n", fname); - return 0; - } - return 1; -} - -/** true if fname is a directory */ -static int -is_dir(const char* fname) -{ - struct stat buf; - if(stat(fname, &buf) < 0) { - if(errno==EACCES) { - printf("warning: no search permission for one of the directories in path: %s\n", fname); - return 1; - } - perror(fname); - return 0; - } - if(!(S_ISDIR(buf.st_mode))) { - printf("%s is not a directory\n", fname); - return 0; - } - return 1; -} - -/** get base dir of a fname */ -static char* -basedir(char* fname) -{ - char* rev; - if(!fname) fatal_exit("out of memory"); - rev = strrchr(fname, '/'); - if(!rev) return NULL; - if(fname == rev) return NULL; - rev[0] = 0; - return fname; -} - -/** check chroot for a file string */ -static void -check_chroot_string(const char* desc, char** ss, - const char* chrootdir, struct config_file* cfg) -{ - char* str = *ss; - if(str && str[0]) { - *ss = fname_after_chroot(str, cfg, 1); - if(!*ss) fatal_exit("out of memory"); - if(!is_file(*ss)) { - if(chrootdir && chrootdir[0]) - fatal_exit("%s: \"%s\" does not exist in " - "chrootdir %s", desc, str, chrootdir); - else - fatal_exit("%s: \"%s\" does not exist", - desc, str); - } - /* put in a new full path for continued checking */ - free(str); - } -} - -/** check file list, every file must be inside the chroot location */ -static void -check_chroot_filelist(const char* desc, struct config_strlist* list, - const char* chrootdir, struct config_file* cfg) -{ - struct config_strlist* p; - for(p=list; p; p=p->next) { - check_chroot_string(desc, &p->str, chrootdir, cfg); - } -} - -/** check file list, with wildcard processing */ -static void -check_chroot_filelist_wild(const char* desc, struct config_strlist* list, - const char* chrootdir, struct config_file* cfg) -{ - struct config_strlist* p; - for(p=list; p; p=p->next) { -#ifdef HAVE_GLOB - if(strchr(p->str, '*') || strchr(p->str, '[') || - strchr(p->str, '?') || strchr(p->str, '{') || - strchr(p->str, '~')) { - char* s = p->str; - /* adjust whole pattern for chroot and check later */ - p->str = fname_after_chroot(p->str, cfg, 1); - free(s); - } else -#endif /* HAVE_GLOB */ - check_chroot_string(desc, &p->str, chrootdir, cfg); - } -} - -/** check configuration for errors */ -static void -morechecks(struct config_file* cfg, const char* fname) -{ - warn_hosts("stub-host", cfg->stubs); - warn_hosts("forward-host", cfg->forwards); - interfacechecks(cfg); - aclchecks(cfg); - - if(cfg->verbosity < 0) - fatal_exit("verbosity value < 0"); - if(cfg->num_threads <= 0 || cfg->num_threads > 10000) - fatal_exit("num_threads value weird"); - if(!cfg->do_ip4 && !cfg->do_ip6) - fatal_exit("ip4 and ip6 are both disabled, pointless"); - if(!cfg->do_ip6 && cfg->prefer_ip6) - fatal_exit("cannot prefer and disable ip6, pointless"); - if(!cfg->do_udp && !cfg->do_tcp) - fatal_exit("udp and tcp are both disabled, pointless"); - if(cfg->edns_buffer_size > cfg->msg_buffer_size) - fatal_exit("edns-buffer-size larger than msg-buffer-size, " - "answers will not fit in processing buffer"); -#ifdef UB_ON_WINDOWS - w_config_adjust_directory(cfg); -#endif - if(cfg->chrootdir && cfg->chrootdir[0] && - cfg->chrootdir[strlen(cfg->chrootdir)-1] == '/') - fatal_exit("chootdir %s has trailing slash '/' please remove.", - cfg->chrootdir); - if(cfg->chrootdir && cfg->chrootdir[0] && - !is_dir(cfg->chrootdir)) { - fatal_exit("bad chroot directory"); - } - if(cfg->chrootdir && cfg->chrootdir[0]) { - char buf[10240]; - buf[0] = 0; - if(fname[0] != '/') { - if(getcwd(buf, sizeof(buf)) == NULL) - fatal_exit("getcwd: %s", strerror(errno)); - (void)strlcat(buf, "/", sizeof(buf)); - } - (void)strlcat(buf, fname, sizeof(buf)); - if(strncmp(buf, cfg->chrootdir, strlen(cfg->chrootdir)) != 0) - fatal_exit("config file %s is not inside chroot %s", - buf, cfg->chrootdir); - } - if(cfg->directory && cfg->directory[0]) { - char* ad = fname_after_chroot(cfg->directory, cfg, 0); - if(!ad) fatal_exit("out of memory"); - if(!is_dir(ad)) fatal_exit("bad chdir directory"); - free(ad); - } - if( (cfg->chrootdir && cfg->chrootdir[0]) || - (cfg->directory && cfg->directory[0])) { - if(cfg->pidfile && cfg->pidfile[0]) { - char* ad = (cfg->pidfile[0]=='/')?strdup(cfg->pidfile): - fname_after_chroot(cfg->pidfile, cfg, 1); - char* bd = basedir(ad); - if(bd && !is_dir(bd)) - fatal_exit("pidfile directory does not exist"); - free(ad); - } - if(cfg->logfile && cfg->logfile[0]) { - char* ad = fname_after_chroot(cfg->logfile, cfg, 1); - char* bd = basedir(ad); - if(bd && !is_dir(bd)) - fatal_exit("logfile directory does not exist"); - free(ad); - } - } - - check_chroot_filelist("file with root-hints", - cfg->root_hints, cfg->chrootdir, cfg); - check_chroot_filelist("trust-anchor-file", - cfg->trust_anchor_file_list, cfg->chrootdir, cfg); - check_chroot_filelist("auto-trust-anchor-file", - cfg->auto_trust_anchor_file_list, cfg->chrootdir, cfg); - check_chroot_filelist_wild("trusted-keys-file", - cfg->trusted_keys_file_list, cfg->chrootdir, cfg); - check_chroot_string("dlv-anchor-file", &cfg->dlv_anchor_file, - cfg->chrootdir, cfg); - /* remove chroot setting so that modules are not stripping pathnames*/ - free(cfg->chrootdir); - cfg->chrootdir = NULL; - - /* There should be no reason for 'respip' module not to work with - * dns64, but it's not explicitly confirmed, so the combination is - * excluded below. It's simply unknown yet for the combination of - * respip and other modules. */ - if(strcmp(cfg->module_conf, "iterator") != 0 - && strcmp(cfg->module_conf, "validator iterator") != 0 - && strcmp(cfg->module_conf, "dns64 validator iterator") != 0 - && strcmp(cfg->module_conf, "dns64 iterator") != 0 - && strcmp(cfg->module_conf, "respip iterator") != 0 - && strcmp(cfg->module_conf, "respip validator iterator") != 0 -#ifdef WITH_PYTHONMODULE - && strcmp(cfg->module_conf, "python iterator") != 0 - && strcmp(cfg->module_conf, "python validator iterator") != 0 - && strcmp(cfg->module_conf, "validator python iterator") != 0 - && strcmp(cfg->module_conf, "dns64 python iterator") != 0 - && strcmp(cfg->module_conf, "dns64 python validator iterator") != 0 - && strcmp(cfg->module_conf, "dns64 validator python iterator") != 0 - && strcmp(cfg->module_conf, "python dns64 iterator") != 0 - && strcmp(cfg->module_conf, "python dns64 validator iterator") != 0 -#endif -#ifdef USE_CACHEDB - && strcmp(cfg->module_conf, "validator cachedb iterator") != 0 - && strcmp(cfg->module_conf, "cachedb iterator") != 0 - && strcmp(cfg->module_conf, "dns64 validator cachedb iterator") != 0 - && strcmp(cfg->module_conf, "dns64 cachedb iterator") != 0 -#endif -#if defined(WITH_PYTHONMODULE) && defined(USE_CACHEDB) - && strcmp(cfg->module_conf, "python dns64 cachedb iterator") != 0 - && strcmp(cfg->module_conf, "python dns64 validator cachedb iterator") != 0 - && strcmp(cfg->module_conf, "dns64 python cachedb iterator") != 0 - && strcmp(cfg->module_conf, "dns64 python validator cachedb iterator") != 0 - && strcmp(cfg->module_conf, "python cachedb iterator") != 0 - && strcmp(cfg->module_conf, "python validator cachedb iterator") != 0 - && strcmp(cfg->module_conf, "cachedb python iterator") != 0 - && strcmp(cfg->module_conf, "validator cachedb python iterator") != 0 - && strcmp(cfg->module_conf, "validator python cachedb iterator") != 0 -#endif -#ifdef CLIENT_SUBNET - && strcmp(cfg->module_conf, "subnetcache iterator") != 0 - && strcmp(cfg->module_conf, "subnetcache validator iterator") != 0 -#endif -#if defined(WITH_PYTHONMODULE) && defined(CLIENT_SUBNET) - && strcmp(cfg->module_conf, "python subnetcache iterator") != 0 - && strcmp(cfg->module_conf, "subnetcache python iterator") != 0 - && strcmp(cfg->module_conf, "subnetcache validator iterator") != 0 - && strcmp(cfg->module_conf, "python subnetcache validator iterator") != 0 - && strcmp(cfg->module_conf, "subnetcache python validator iterator") != 0 - && strcmp(cfg->module_conf, "subnetcache validator python iterator") != 0 -#endif - ) { - fatal_exit("module conf '%s' is not known to work", - cfg->module_conf); - } - -#ifdef HAVE_GETPWNAM - if(cfg->username && cfg->username[0]) { - if(getpwnam(cfg->username) == NULL) - fatal_exit("user '%s' does not exist.", cfg->username); -# ifdef HAVE_ENDPWENT - endpwent(); -# endif - } -#endif - if(cfg->remote_control_enable && cfg->remote_control_use_cert) { - check_chroot_string("server-key-file", &cfg->server_key_file, - cfg->chrootdir, cfg); - check_chroot_string("server-cert-file", &cfg->server_cert_file, - cfg->chrootdir, cfg); - if(!is_file(cfg->control_key_file)) - fatal_exit("control-key-file: \"%s\" does not exist", - cfg->control_key_file); - if(!is_file(cfg->control_cert_file)) - fatal_exit("control-cert-file: \"%s\" does not exist", - cfg->control_cert_file); - } - - localzonechecks(cfg); - view_and_respipchecks(cfg); -} - -/** check forwards */ -static void -check_fwd(struct config_file* cfg) -{ - struct iter_forwards* fwd = forwards_create(); - if(!fwd || !forwards_apply_cfg(fwd, cfg)) { - fatal_exit("Could not set forward zones"); - } - forwards_delete(fwd); -} - -/** check hints */ -static void -check_hints(struct config_file* cfg) -{ - struct iter_hints* hints = hints_create(); - if(!hints || !hints_apply_cfg(hints, cfg)) { - fatal_exit("Could not set root or stub hints"); - } - hints_delete(hints); -} - -/** check config file */ -static void -checkconf(const char* cfgfile, const char* opt, int final) -{ - char oldwd[4096]; - struct config_file* cfg = config_create(); - if(!cfg) - fatal_exit("out of memory"); - oldwd[0] = 0; - if(!getcwd(oldwd, sizeof(oldwd))) { - log_err("cannot getcwd: %s", strerror(errno)); - oldwd[0] = 0; - } - if(!config_read(cfg, cfgfile, NULL)) { - /* config_read prints messages to stderr */ - config_delete(cfg); - exit(1); - } - if(oldwd[0] && chdir(oldwd) == -1) - log_err("cannot chdir(%s): %s", oldwd, strerror(errno)); - if(opt) { - print_option(cfg, opt, final); - config_delete(cfg); - return; - } - morechecks(cfg, cfgfile); - check_mod(cfg, iter_get_funcblock()); - check_mod(cfg, val_get_funcblock()); -#ifdef WITH_PYTHONMODULE - if(strstr(cfg->module_conf, "python")) - check_mod(cfg, pythonmod_get_funcblock()); -#endif - check_fwd(cfg); - check_hints(cfg); - printf("unbound-checkconf: no errors in %s\n", cfgfile); - config_delete(cfg); -} - -/** 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; - int final = 0; - const char* f; - const char* opt = NULL; - const char* cfgfile = CONFIGFILE; - log_ident_set("unbound-checkconf"); - log_init(NULL, 0, NULL); - checklock_start(); -#ifdef USE_WINSOCK - /* use registry config file in preference to compiletime location */ - if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) - cfgfile = CONFIGFILE; -#endif /* USE_WINSOCK */ - /* parse the options */ - while( (c=getopt(argc, argv, "fho:")) != -1) { - switch(c) { - case 'f': - final = 1; - break; - case 'o': - opt = optarg; - break; - case '?': - case 'h': - default: - usage(); - } - } - argc -= optind; - argv += optind; - if(argc != 0 && argc != 1) - usage(); - if(argc == 1) - f = argv[0]; - else f = cfgfile; - checkconf(f, opt, final); - checklock_stop(); - return 0; -} diff --git a/external/unbound/smallapp/unbound-control-setup.sh.in b/external/unbound/smallapp/unbound-control-setup.sh.in deleted file mode 100644 index 0d759f441..000000000 --- a/external/unbound/smallapp/unbound-control-setup.sh.in +++ /dev/null @@ -1,160 +0,0 @@ -#!/bin/sh -# -# unbound-control-setup.sh - set up SSL certificates for unbound-control -# -# Copyright (c) 2008, 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 COPYRIGHT -# HOLDER 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. - -# settings: - -# directory for files -DESTDIR=@ub_conf_dir@ - -# issuer and subject name for certificates -SERVERNAME=unbound -CLIENTNAME=unbound-control - -# validity period for certificates -DAYS=7200 - -# size of keys in bits -BITS=3072 - -# hash algorithm -HASH=sha256 - -# base name for unbound server keys -SVR_BASE=unbound_server - -# base name for unbound-control keys -CTL_BASE=unbound_control - -# we want -rw-r----- access (say you run this as root: grp=yes (server), all=no). -umask 0027 - -# end of options - -# functions: -error ( ) { - echo "$0 fatal error: $1" - exit 1 -} - -# check arguments: -while test $# -ne 0; do - case $1 in - -d) - if test $# -eq 1; then error "need argument for -d"; fi - DESTDIR="$2" - shift - ;; - *) - echo "unbound-control-setup.sh - setup SSL keys for unbound-control" - echo " -d dir use directory to store keys and certificates." - echo " default: $DESTDIR" - echo "please run this command using the same user id that the " - echo "unbound daemon uses, it needs read privileges." - exit 1 - ;; - esac - shift -done - -# go!: -echo "setup in directory $DESTDIR" -cd "$DESTDIR" || error "could not cd to $DESTDIR" - -# create certificate keys; do not recreate if they already exist. -if test -f $SVR_BASE.key; then - echo "$SVR_BASE.key exists" -else - echo "generating $SVR_BASE.key" - openssl genrsa -out $SVR_BASE.key $BITS || error "could not genrsa" -fi -if test -f $CTL_BASE.key; then - echo "$CTL_BASE.key exists" -else - echo "generating $CTL_BASE.key" - openssl genrsa -out $CTL_BASE.key $BITS || error "could not genrsa" -fi - -# create self-signed cert for server -echo "[req]" > request.cfg -echo "default_bits=$BITS" >> request.cfg -echo "default_md=$HASH" >> request.cfg -echo "prompt=no" >> request.cfg -echo "distinguished_name=req_distinguished_name" >> request.cfg -echo "" >> request.cfg -echo "[req_distinguished_name]" >> request.cfg -echo "commonName=$SERVERNAME" >> request.cfg - -test -f request.cfg || error "could not create request.cfg" - -echo "create $SVR_BASE.pem (self signed certificate)" -openssl req -key $SVR_BASE.key -config request.cfg -new -x509 -days $DAYS -out $SVR_BASE.pem || error "could not create $SVR_BASE.pem" -# create trusted usage pem -openssl x509 -in $SVR_BASE.pem -addtrust serverAuth -out $SVR_BASE"_trust.pem" - -# create client request and sign it, piped -echo "[req]" > request.cfg -echo "default_bits=$BITS" >> request.cfg -echo "default_md=$HASH" >> request.cfg -echo "prompt=no" >> request.cfg -echo "distinguished_name=req_distinguished_name" >> request.cfg -echo "" >> request.cfg -echo "[req_distinguished_name]" >> request.cfg -echo "commonName=$CLIENTNAME" >> request.cfg - -test -f request.cfg || error "could not create request.cfg" - -echo "create $CTL_BASE.pem (signed client certificate)" -openssl req -key $CTL_BASE.key -config request.cfg -new | openssl x509 -req -days $DAYS -CA $SVR_BASE"_trust.pem" -CAkey $SVR_BASE.key -CAcreateserial -$HASH -out $CTL_BASE.pem -test -f $CTL_BASE.pem || error "could not create $CTL_BASE.pem" -# create trusted usage pem -# openssl x509 -in $CTL_BASE.pem -addtrust clientAuth -out $CTL_BASE"_trust.pem" - -# see details with openssl x509 -noout -text < $SVR_BASE.pem -# echo "create $CTL_BASE""_browser.pfx (web client certificate)" -# echo "create webbrowser PKCS#12 .PFX certificate file. In Firefox import in:" -# echo "preferences - advanced - encryption - view certificates - your certs" -# echo "empty password is used, simply click OK on the password dialog box." -# openssl pkcs12 -export -in $CTL_BASE"_trust.pem" -inkey $CTL_BASE.key -name "unbound remote control client cert" -out $CTL_BASE"_browser.pfx" -password "pass:" || error "could not create browser certificate" - -# remove unused permissions -chmod o-rw $SVR_BASE.pem $SVR_BASE.key $CTL_BASE.pem $CTL_BASE.key - -# remove crap -rm -f request.cfg -rm -f $CTL_BASE"_trust.pem" $SVR_BASE"_trust.pem" $SVR_BASE"_trust.srl" - -echo "Setup success. Certificates created. Enable in unbound.conf file to use" - -exit 0 diff --git a/external/unbound/smallapp/unbound-control.c b/external/unbound/smallapp/unbound-control.c deleted file mode 100644 index 6cd4e7086..000000000 --- a/external/unbound/smallapp/unbound-control.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * checkconf/unbound-control.c - remote control utility for unbound. - * - * Copyright (c) 2008, 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 COPYRIGHT - * HOLDER 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 - * - * The remote control utility contacts the unbound server over ssl and - * sends the command, receives the answer, and displays the result - * from the commandline. - */ - -#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 "util/log.h" -#include "util/config_file.h" -#include "util/locks.h" -#include "util/net_help.h" -#include "util/shm_side/shm_main.h" -#include "daemon/stats.h" -#include "sldns/wire2str.h" -#include "sldns/pkthdr.h" - -#ifdef HAVE_SYS_IPC_H -#include "sys/ipc.h" -#endif -#ifdef HAVE_SYS_SHM_H -#include "sys/shm.h" -#endif -#ifdef HAVE_SYS_UN_H -#include <sys/un.h> -#endif - -/** Give unbound-control usage, and exit (1). */ -static void -usage(void) -{ - printf("Usage: unbound-control [options] command\n"); - printf(" Remote control utility for unbound server.\n"); - printf("Options:\n"); - printf(" -c file config file, default is %s\n", CONFIGFILE); - printf(" -s ip[@port] server address, if omitted config is used.\n"); - printf(" -q quiet (don't print anything if it works ok).\n"); - printf(" -h show this usage help.\n"); - printf("Commands:\n"); - printf(" start start server; runs unbound(8)\n"); - printf(" stop stops the server\n"); - printf(" reload reloads the server\n"); - printf(" (this flushes data, stats, requestlist)\n"); - printf(" stats print statistics\n"); - printf(" stats_noreset peek at statistics\n"); -#ifdef HAVE_SHMGET - printf(" stats_shm print statistics using shm\n"); -#endif - printf(" status display status of server\n"); - printf(" verbosity <number> change logging detail\n"); - printf(" log_reopen close and open the logfile\n"); - printf(" local_zone <name> <type> add new local zone\n"); - printf(" local_zone_remove <name> remove local zone and its contents\n"); - printf(" local_data <RR data...> add local data, for example\n"); - printf(" local_data www.example.com A 192.0.2.1\n"); - printf(" local_data_remove <name> remove local RR data from name\n"); - printf(" local_zones, local_zones_remove, local_datas, local_datas_remove\n"); - printf(" same, but read list from stdin\n"); - printf(" (one entry per line).\n"); - printf(" dump_cache print cache to stdout\n"); - printf(" load_cache load cache from stdin\n"); - printf(" lookup <name> print nameservers for name\n"); - printf(" flush <name> flushes common types for name from cache\n"); - printf(" types: A, AAAA, MX, PTR, NS,\n"); - printf(" SOA, CNAME, DNAME, SRV, NAPTR\n"); - printf(" flush_type <name> <type> flush name, type from cache\n"); - printf(" flush_zone <name> flush everything at or under name\n"); - printf(" from rr and dnssec caches\n"); - printf(" flush_bogus flush all bogus data\n"); - printf(" flush_negative flush all negative data\n"); - printf(" flush_stats flush statistics, make zero\n"); - printf(" flush_requestlist drop queries that are worked on\n"); - printf(" dump_requestlist show what is worked on by first thread\n"); - printf(" flush_infra [all | ip] remove ping, edns for one IP or all\n"); - printf(" dump_infra show ping and edns entries\n"); - printf(" set_option opt: val set option to value, no reload\n"); - printf(" get_option opt get option value\n"); - printf(" list_stubs list stub-zones and root hints in use\n"); - printf(" list_forwards list forward-zones in use\n"); - printf(" list_insecure list domain-insecure zones\n"); - printf(" list_local_zones list local-zones in use\n"); - printf(" list_local_data list local-data RRs in use\n"); - printf(" insecure_add zone add domain-insecure zone\n"); - printf(" insecure_remove zone remove domain-insecure zone\n"); - printf(" forward_add [+i] zone addr.. add forward-zone with servers\n"); - printf(" forward_remove [+i] zone remove forward zone\n"); - printf(" stub_add [+ip] zone addr.. add stub-zone with servers\n"); - printf(" stub_remove [+i] zone remove stub zone\n"); - printf(" +i also do dnssec insecure point\n"); - printf(" +p set stub to use priming\n"); - printf(" forward [off | addr ...] without arg show forward setup\n"); - printf(" or off to turn off root forwarding\n"); - printf(" or give list of ip addresses\n"); - printf(" ratelimit_list [+a] list ratelimited domains\n"); - printf(" ip_ratelimit_list [+a] list ratelimited ip addresses\n"); - printf(" +a list all, also not ratelimited\n"); - printf(" view_list_local_zones view list local-zones in view\n"); - printf(" view_list_local_data view list local-data RRs in view\n"); - printf(" view_local_zone view name type add local-zone in view\n"); - printf(" view_local_zone_remove view name remove local-zone in view\n"); - printf(" view_local_data view RR... add local-data in view\n"); - printf(" view_local_data_remove view name remove local-data in view\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); -} - -#ifdef HAVE_SHMGET -/** what to put on statistics lines between var and value, ": " or "=" */ -#define SQ "=" -/** if true, inhibits a lot of =0 lines from the stats output */ -static const int inhibit_zero = 1; -/** divide sum of timers to get average */ -static void -timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d) -{ -#ifndef S_SPLINT_S - size_t leftover; - if(d == 0) { - avg->tv_sec = 0; - avg->tv_usec = 0; - return; - } - avg->tv_sec = sum->tv_sec / d; - avg->tv_usec = sum->tv_usec / d; - /* handle fraction from seconds divide */ - leftover = sum->tv_sec - avg->tv_sec*d; - avg->tv_usec += (leftover*1000000)/d; -#endif -} - -/** print unsigned long stats value */ -#define PR_UL_NM(str, var) printf("%s."str SQ"%lu\n", nm, (unsigned long)(var)); -#define PR_UL(str, var) printf(str SQ"%lu\n", (unsigned long)(var)); -#define PR_UL_SUB(str, nm, var) printf(str".%s"SQ"%lu\n", nm, (unsigned long)(var)); -#define PR_TIMEVAL(str, var) printf(str SQ ARG_LL "d.%6.6d\n", \ - (long long)var.tv_sec, (int)var.tv_usec); -#define PR_LL(str, var) printf(str SQ ARG_LL"d\n", (long long)(var)); - -/** print stat block */ -static void pr_stats(const char* nm, struct stats_info* s) -{ - struct timeval avg; - PR_UL_NM("num.queries", s->svr.num_queries); - PR_UL_NM("num.queries_ip_ratelimited", - s->svr.num_queries_ip_ratelimited); - PR_UL_NM("num.cachehits", - s->svr.num_queries - s->svr.num_queries_missed_cache); - PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache); - PR_UL_NM("num.prefetch", s->svr.num_queries_prefetch); - PR_UL_NM("num.zero_ttl", s->svr.zero_ttl_responses); - PR_UL_NM("num.recursivereplies", s->mesh_replies_sent); -#ifdef USE_DNSCRYPT - PR_UL_NM("num.dnscrypt.crypted", s->svr.num_query_dnscrypt_crypted); - PR_UL_NM("num.dnscrypt.cert", s->svr.num_query_dnscrypt_cert); - PR_UL_NM("num.dnscrypt.cleartext", s->svr.num_query_dnscrypt_cleartext); - PR_UL_NM("num.dnscrypt.malformed", - s->svr.num_query_dnscrypt_crypted_malformed); -#endif - printf("%s.requestlist.avg"SQ"%g\n", nm, - (s->svr.num_queries_missed_cache+s->svr.num_queries_prefetch)? - (double)s->svr.sum_query_list_size/ - (s->svr.num_queries_missed_cache+ - s->svr.num_queries_prefetch) : 0.0); - PR_UL_NM("requestlist.max", s->svr.max_query_list_size); - PR_UL_NM("requestlist.overwritten", s->mesh_jostled); - PR_UL_NM("requestlist.exceeded", s->mesh_dropped); - PR_UL_NM("requestlist.current.all", s->mesh_num_states); - PR_UL_NM("requestlist.current.user", s->mesh_num_reply_states); - timeval_divide(&avg, &s->mesh_replies_sum_wait, s->mesh_replies_sent); - printf("%s.", nm); - PR_TIMEVAL("recursion.time.avg", avg); - printf("%s.recursion.time.median"SQ"%g\n", nm, s->mesh_time_median); - PR_UL_NM("tcpusage", s->svr.tcp_accept_usage); -} - -/** print uptime */ -static void print_uptime(struct shm_stat_info* shm_stat) -{ - PR_TIMEVAL("time.now", shm_stat->time.now); - PR_TIMEVAL("time.up", shm_stat->time.up); - PR_TIMEVAL("time.elapsed", shm_stat->time.elapsed); -} - -/** print memory usage */ -static void print_mem(struct shm_stat_info* shm_stat) -{ - PR_LL("mem.cache.rrset", shm_stat->mem.rrset); - PR_LL("mem.cache.message", shm_stat->mem.msg); - PR_LL("mem.cache.iterator", shm_stat->mem.iter); - PR_LL("mem.cache.validator", shm_stat->mem.val); -#ifdef CLIENT_SUBNET - PR_LL("mem.cache.subnet", shm_stat->mem.subnet); -#endif -} - -/** print histogram */ -static void print_hist(struct stats_info* s) -{ - struct timehist* hist; - size_t i; - hist = timehist_setup(); - if(!hist) - fatal_exit("out of memory"); - timehist_import(hist, s->svr.hist, NUM_BUCKETS_HIST); - for(i=0; i<hist->num; i++) { - printf("histogram.%6.6d.%6.6d.to.%6.6d.%6.6d=%lu\n", - (int)hist->buckets[i].lower.tv_sec, - (int)hist->buckets[i].lower.tv_usec, - (int)hist->buckets[i].upper.tv_sec, - (int)hist->buckets[i].upper.tv_usec, - (unsigned long)hist->buckets[i].count); - } - timehist_delete(hist); -} - -/** print extended */ -static void print_extended(struct stats_info* s) -{ - int i; - char nm[16]; - - /* TYPE */ - for(i=0; i<STATS_QTYPE_NUM; i++) { - if(inhibit_zero && s->svr.qtype[i] == 0) - continue; - sldns_wire2str_type_buf((uint16_t)i, nm, sizeof(nm)); - PR_UL_SUB("num.query.type", nm, s->svr.qtype[i]); - } - if(!inhibit_zero || s->svr.qtype_big) { - PR_UL("num.query.type.other", s->svr.qtype_big); - } - - /* CLASS */ - for(i=0; i<STATS_QCLASS_NUM; i++) { - if(inhibit_zero && s->svr.qclass[i] == 0) - continue; - sldns_wire2str_class_buf((uint16_t)i, nm, sizeof(nm)); - PR_UL_SUB("num.query.class", nm, s->svr.qclass[i]); - } - if(!inhibit_zero || s->svr.qclass_big) { - PR_UL("num.query.class.other", s->svr.qclass_big); - } - - /* OPCODE */ - for(i=0; i<STATS_OPCODE_NUM; i++) { - if(inhibit_zero && s->svr.qopcode[i] == 0) - continue; - sldns_wire2str_opcode_buf(i, nm, sizeof(nm)); - PR_UL_SUB("num.query.opcode", nm, s->svr.qopcode[i]); - } - - /* transport */ - PR_UL("num.query.tcp", s->svr.qtcp); - PR_UL("num.query.tcpout", s->svr.qtcp_outgoing); - PR_UL("num.query.ipv6", s->svr.qipv6); - - /* flags */ - PR_UL("num.query.flags.QR", s->svr.qbit_QR); - PR_UL("num.query.flags.AA", s->svr.qbit_AA); - PR_UL("num.query.flags.TC", s->svr.qbit_TC); - PR_UL("num.query.flags.RD", s->svr.qbit_RD); - PR_UL("num.query.flags.RA", s->svr.qbit_RA); - PR_UL("num.query.flags.Z", s->svr.qbit_Z); - PR_UL("num.query.flags.AD", s->svr.qbit_AD); - PR_UL("num.query.flags.CD", s->svr.qbit_CD); - PR_UL("num.query.edns.present", s->svr.qEDNS); - PR_UL("num.query.edns.DO", s->svr.qEDNS_DO); - - /* RCODE */ - for(i=0; i<STATS_RCODE_NUM; i++) { - /* Always include RCODEs 0-5 */ - if(inhibit_zero && i > LDNS_RCODE_REFUSED && s->svr.ans_rcode[i] == 0) - continue; - sldns_wire2str_rcode_buf(i, nm, sizeof(nm)); - PR_UL_SUB("num.answer.rcode", nm, s->svr.ans_rcode[i]); - } - if(!inhibit_zero || s->svr.ans_rcode_nodata) { - PR_UL("num.answer.rcode.nodata", s->svr.ans_rcode_nodata); - } - /* validation */ - PR_UL("num.answer.secure", s->svr.ans_secure); - PR_UL("num.answer.bogus", s->svr.ans_bogus); - PR_UL("num.rrset.bogus", s->svr.rrset_bogus); - /* threat detection */ - PR_UL("unwanted.queries", s->svr.unwanted_queries); - PR_UL("unwanted.replies", s->svr.unwanted_replies); - /* cache counts */ - PR_UL("msg.cache.count", s->svr.msg_cache_count); - PR_UL("rrset.cache.count", s->svr.rrset_cache_count); - PR_UL("infra.cache.count", s->svr.infra_cache_count); - PR_UL("key.cache.count", s->svr.key_cache_count); -} - -/** print statistics out of memory structures */ -static void do_stats_shm(struct config_file* cfg, struct stats_info* stats, - struct shm_stat_info* shm_stat) -{ - int i; - char nm[16]; - for(i=0; i<cfg->num_threads; i++) { - snprintf(nm, sizeof(nm), "thread%d", i); - pr_stats(nm, &stats[i+1]); - } - pr_stats("total", &stats[0]); - print_uptime(shm_stat); - if(cfg->stat_extended) { - print_mem(shm_stat); - print_hist(stats); - print_extended(stats); - } -} -#endif /* HAVE_SHMGET */ - -/** print statistics from shm memory segment */ -static void print_stats_shm(const char* cfgfile) -{ -#ifdef HAVE_SHMGET - struct config_file* cfg; - struct stats_info* stats; - struct shm_stat_info* shm_stat; - int id_ctl, id_arr; - /* read config */ - if(!(cfg = config_create())) - fatal_exit("out of memory"); - if(!config_read(cfg, cfgfile, NULL)) - fatal_exit("could not read config file"); - /* get shm segments */ - id_ctl = shmget(cfg->shm_key, sizeof(int), SHM_R|SHM_W); - if(id_ctl == -1) { - fatal_exit("shmget(%d): %s", cfg->shm_key, strerror(errno)); - } - id_arr = shmget(cfg->shm_key+1, sizeof(int), SHM_R|SHM_W); - if(id_arr == -1) { - fatal_exit("shmget(%d): %s", cfg->shm_key+1, strerror(errno)); - } - shm_stat = (struct shm_stat_info*)shmat(id_ctl, NULL, 0); - if(shm_stat == (void*)-1) { - fatal_exit("shmat(%d): %s", id_ctl, strerror(errno)); - } - stats = (struct stats_info*)shmat(id_arr, NULL, 0); - if(stats == (void*)-1) { - fatal_exit("shmat(%d): %s", id_arr, strerror(errno)); - } - - /* print the stats */ - do_stats_shm(cfg, stats, shm_stat); - - /* shutdown */ - shmdt(shm_stat); - shmdt(stats); - config_delete(cfg); -#else - (void)cfgfile; -#endif /* HAVE_SHMGET */ -} - -/** exit with ssl error */ -static void ssl_err(const char* s) -{ - fprintf(stderr, "error: %s\n", s); - ERR_print_errors_fp(stderr); - exit(1); -} - -/** setup SSL context */ -static SSL_CTX* -setup_ctx(struct config_file* cfg) -{ - char* s_cert=NULL, *c_key=NULL, *c_cert=NULL; - SSL_CTX* ctx; - - if(cfg->remote_control_use_cert) { - s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1); - c_key = fname_after_chroot(cfg->control_key_file, cfg, 1); - c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1); - if(!s_cert || !c_key || !c_cert) - fatal_exit("out of memory"); - } - ctx = SSL_CTX_new(SSLv23_client_method()); - if(!ctx) - ssl_err("could not allocate SSL_CTX pointer"); - if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) - != SSL_OP_NO_SSLv2) - ssl_err("could not set SSL_OP_NO_SSLv2"); - if(cfg->remote_control_use_cert) { - if((SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3) - != SSL_OP_NO_SSLv3) - ssl_err("could not set SSL_OP_NO_SSLv3"); - if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert) || - !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) - || !SSL_CTX_check_private_key(ctx)) - ssl_err("Error setting up SSL_CTX client key and cert"); - if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1) - ssl_err("Error setting up SSL_CTX verify, server cert"); - SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); - - free(s_cert); - free(c_key); - free(c_cert); - } else { - /* Use ciphers that don't require authentication */ -#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL - SSL_CTX_set_security_level(ctx, 0); -#endif - if(!SSL_CTX_set_cipher_list(ctx, "aNULL, eNULL")) - ssl_err("Error setting NULL cipher!"); - } - return ctx; -} - -/** contact the server with TCP connect */ -static int -contact_server(const char* svr, struct config_file* cfg, int statuscmd) -{ - struct sockaddr_storage addr; - socklen_t addrlen; - int addrfamily = 0; - int fd; - /* use svr or the first config entry */ - if(!svr) { - if(cfg->control_ifs) { - svr = cfg->control_ifs->str; - } else if(cfg->do_ip4) { - svr = "127.0.0.1"; - } else { - svr = "::1"; - } - /* config 0 addr (everything), means ask localhost */ - if(strcmp(svr, "0.0.0.0") == 0) - svr = "127.0.0.1"; - else if(strcmp(svr, "::0") == 0 || - strcmp(svr, "0::0") == 0 || - strcmp(svr, "0::") == 0 || - strcmp(svr, "::") == 0) - svr = "::1"; - } - if(strchr(svr, '@')) { - if(!extstrtoaddr(svr, &addr, &addrlen)) - fatal_exit("could not parse IP@port: %s", svr); -#ifdef HAVE_SYS_UN_H - } else if(svr[0] == '/') { - struct sockaddr_un* usock = (struct sockaddr_un *) &addr; - usock->sun_family = AF_LOCAL; -#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN - usock->sun_len = (unsigned)sizeof(usock); -#endif - (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); - addrlen = (socklen_t)sizeof(struct sockaddr_un); - addrfamily = AF_LOCAL; -#endif - } else { - if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) - fatal_exit("could not parse IP: %s", svr); - } - - if(addrfamily == 0) - addrfamily = addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET; - fd = socket(addrfamily, SOCK_STREAM, 0); - if(fd == -1) { -#ifndef USE_WINSOCK - fatal_exit("socket: %s", strerror(errno)); -#else - fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); -#endif - } - if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { -#ifndef USE_WINSOCK - log_err_addr("connect", strerror(errno), &addr, addrlen); - if(errno == ECONNREFUSED && statuscmd) { - printf("unbound is stopped\n"); - exit(3); - } -#else - log_err_addr("connect", wsa_strerror(WSAGetLastError()), &addr, addrlen); - if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { - printf("unbound is stopped\n"); - exit(3); - } -#endif - exit(1); - } - return fd; -} - -/** setup SSL on the connection */ -static SSL* -setup_ssl(SSL_CTX* ctx, int fd, struct config_file* cfg) -{ - SSL* ssl; - X509* x; - int r; - - ssl = SSL_new(ctx); - if(!ssl) - ssl_err("could not SSL_new"); - SSL_set_connect_state(ssl); - (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); - if(!SSL_set_fd(ssl, fd)) - ssl_err("could not SSL_set_fd"); - while(1) { - ERR_clear_error(); - if( (r=SSL_do_handshake(ssl)) == 1) - break; - r = SSL_get_error(ssl, r); - if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) - ssl_err("SSL handshake failed"); - /* wants to be called again */ - } - - /* check authenticity of server */ - if(SSL_get_verify_result(ssl) != X509_V_OK) - ssl_err("SSL verification failed"); - if(cfg->remote_control_use_cert) { - x = SSL_get_peer_certificate(ssl); - if(!x) - ssl_err("Server presented no peer certificate"); - X509_free(x); - } - - return ssl; -} - -/** send stdin to server */ -static void -send_file(SSL* ssl, FILE* in, char* buf, size_t sz) -{ - while(fgets(buf, (int)sz, in)) { - if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) - ssl_err("could not SSL_write contents"); - } -} - -/** send end-of-file marker to server */ -static void -send_eof(SSL* ssl) -{ - char e[] = {0x04, 0x0a}; - if(SSL_write(ssl, e, (int)sizeof(e)) <= 0) - ssl_err("could not SSL_write end-of-file marker"); -} - -/** send command and display result */ -static int -go_cmd(SSL* ssl, int quiet, int argc, char* argv[]) -{ - char pre[10]; - const char* space=" "; - const char* newline="\n"; - int was_error = 0, first_line = 1; - int r, i; - char buf[1024]; - snprintf(pre, sizeof(pre), "UBCT%d ", UNBOUND_CONTROL_VERSION); - if(SSL_write(ssl, pre, (int)strlen(pre)) <= 0) - ssl_err("could not SSL_write"); - for(i=0; i<argc; i++) { - if(SSL_write(ssl, space, (int)strlen(space)) <= 0) - ssl_err("could not SSL_write"); - if(SSL_write(ssl, argv[i], (int)strlen(argv[i])) <= 0) - ssl_err("could not SSL_write"); - } - if(SSL_write(ssl, newline, (int)strlen(newline)) <= 0) - ssl_err("could not SSL_write"); - - if(argc == 1 && strcmp(argv[0], "load_cache") == 0) { - send_file(ssl, stdin, buf, sizeof(buf)); - } - else if(argc == 1 && (strcmp(argv[0], "local_zones") == 0 || - strcmp(argv[0], "local_zones_remove") == 0 || - strcmp(argv[0], "local_datas") == 0 || - strcmp(argv[0], "local_datas_remove") == 0)) { - send_file(ssl, stdin, buf, sizeof(buf)); - send_eof(ssl); - } - - while(1) { - ERR_clear_error(); - if((r = SSL_read(ssl, buf, (int)sizeof(buf)-1)) <= 0) { - if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { - /* EOF */ - break; - } - ssl_err("could not SSL_read"); - } - buf[r] = 0; - if(first_line && strncmp(buf, "error", 5) == 0) { - printf("%s", buf); - was_error = 1; - } else if (!quiet) - printf("%s", buf); - - first_line = 0; - } - return was_error; -} - -/** go ahead and read config, contact server and perform command and display */ -static int -go(const char* cfgfile, char* svr, int quiet, int argc, char* argv[]) -{ - struct config_file* cfg; - int fd, ret; - SSL_CTX* ctx; - SSL* ssl; - - /* read config */ - if(!(cfg = config_create())) - fatal_exit("out of memory"); - if(!config_read(cfg, cfgfile, NULL)) - fatal_exit("could not read config file"); - if(!cfg->remote_control_enable) - log_warn("control-enable is 'no' in the config file."); -#ifdef UB_ON_WINDOWS - w_config_adjust_directory(cfg); -#endif - ctx = setup_ctx(cfg); - - /* contact server */ - fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0); - ssl = setup_ssl(ctx, fd, cfg); - - /* send command */ - ret = go_cmd(ssl, quiet, argc, argv); - - SSL_free(ssl); -#ifndef USE_WINSOCK - close(fd); -#else - closesocket(fd); -#endif - SSL_CTX_free(ctx); - config_delete(cfg); - return ret; -} - -/** 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 unbound-control */ -int main(int argc, char* argv[]) -{ - int c, ret; - int quiet = 0; - const char* cfgfile = CONFIGFILE; - char* svr = NULL; -#ifdef USE_WINSOCK - int r; - WSADATA wsa_data; -#endif -#ifdef USE_THREAD_DEBUG - /* stop the file output from unbound-control, overwites the servers */ - extern int check_locking_order; - check_locking_order = 0; -#endif /* USE_THREAD_DEBUG */ - log_ident_set("unbound-control"); - log_init(NULL, 0, NULL); - checklock_start(); -#ifdef USE_WINSOCK - /* use registry config file in preference to compiletime location */ - if(!(cfgfile=w_lookup_reg_str("Software\\Unbound", "ConfigFile"))) - cfgfile = CONFIGFILE; -#endif - /* parse the options */ - while( (c=getopt(argc, argv, "c:s:qh")) != -1) { - switch(c) { - case 'c': - cfgfile = optarg; - break; - case 's': - svr = optarg; - break; - case 'q': - quiet = 1; - break; - case '?': - case 'h': - default: - usage(); - } - } - argc -= optind; - argv += optind; - if(argc == 0) - usage(); - if(argc >= 1 && strcmp(argv[0], "start")==0) { - if(execlp("unbound", "unbound", "-c", cfgfile, - (char*)NULL) < 0) { - fatal_exit("could not exec unbound: %s", - strerror(errno)); - } - } - if(argc >= 1 && strcmp(argv[0], "stats_shm")==0) { - print_stats_shm(cfgfile); - return 0; - } - -#ifdef USE_WINSOCK - if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) - fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); -#endif - -#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS - ERR_load_crypto_strings(); -#endif - ERR_load_SSL_strings(); -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) - OpenSSL_add_all_algorithms(); -#else - OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS - | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); -#endif -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) - (void)SSL_library_init(); -#else - (void)OPENSSL_init_ssl(0, NULL); -#endif - - if(!RAND_status()) { - /* try to seed it */ - unsigned char buf[256]; - unsigned int seed=(unsigned)time(NULL) ^ (unsigned)getpid(); - unsigned int v = seed; - size_t i; - for(i=0; i<256/sizeof(v); i++) { - memmove(buf+i*sizeof(v), &v, sizeof(v)); - v = v*seed + (unsigned int)i; - } - RAND_seed(buf, 256); - log_warn("no entropy, seeding openssl PRNG with time\n"); - } - - ret = go(cfgfile, svr, quiet, argc, argv); - -#ifdef USE_WINSOCK - WSACleanup(); -#endif - checklock_stop(); - return ret; -} diff --git a/external/unbound/smallapp/unbound-host.c b/external/unbound/smallapp/unbound-host.c deleted file mode 100644 index d7a36a231..000000000 --- a/external/unbound/smallapp/unbound-host.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * checkconf/unbound-host.c - replacement for host that supports validation. - * - * Copyright (c) 2007, 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 COPYRIGHT - * HOLDER 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 performs functionality like 'host', and also supports validation. - * It uses the libunbound library. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -/* remove alloc checks, not in this part of the code */ -#ifdef UNBOUND_ALLOC_STATS -#undef malloc -#undef calloc -#undef free -#undef realloc -#endif -#ifdef UNBOUND_ALLOC_LITE -#undef malloc -#undef calloc -#undef free -#undef realloc -#undef strdup -#define unbound_lite_wrapstr(s) s -#endif -#include "libunbound/unbound.h" -#include "sldns/rrdef.h" -#include "sldns/wire2str.h" -#ifdef HAVE_NSS -/* nss3 */ -#include "nss.h" -#endif - -/** verbosity for unbound-host app */ -static int verb = 0; - -/** Give unbound-host usage, and exit (1). */ -static void -usage(void) -{ - printf("Usage: unbound-host [-vdhr46] [-c class] [-t type] hostname\n"); - printf(" [-y key] [-f keyfile] [-F namedkeyfile]\n"); - printf(" [-C configfile]\n"); - printf(" Queries the DNS for information.\n"); - printf(" The hostname is looked up for IP4, IP6 and mail.\n"); - printf(" If an ip-address is given a reverse lookup is done.\n"); - printf(" Use the -v option to see DNSSEC security information.\n"); - printf(" -t type what type to look for.\n"); - printf(" -c class what class to look for, if not class IN.\n"); - printf(" -y 'keystring' specify trust anchor, DS or DNSKEY, like\n"); - printf(" -y 'example.com DS 31560 5 1 1CFED8478...'\n"); - printf(" -D DNSSEC enable with default root anchor\n"); - printf(" from %s\n", ROOT_ANCHOR_FILE); - printf(" -f keyfile read trust anchors from file, with lines as -y.\n"); - printf(" -F keyfile read named.conf-style trust anchors.\n"); - printf(" -C config use the specified unbound.conf (none read by default)\n"); - printf(" -r read forwarder information from /etc/resolv.conf\n"); - printf(" breaks validation if the forwarder does not do DNSSEC.\n"); - printf(" -v be more verbose, shows nodata and security.\n"); - printf(" -d debug, traces the action, -d -d shows more.\n"); - printf(" -4 use ipv4 network, avoid ipv6.\n"); - printf(" -6 use ipv6 network, avoid ipv4.\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); -} - -/** determine if str is ip4 and put into reverse lookup format */ -static int -isip4(const char* nm, char** res) -{ - struct in_addr addr; - /* ddd.ddd.ddd.ddd.in-addr.arpa. is less than 32 */ - char buf[32]; - if(inet_pton(AF_INET, nm, &addr) <= 0) { - return 0; - } - snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa", - (unsigned)((uint8_t*)&addr)[3], (unsigned)((uint8_t*)&addr)[2], - (unsigned)((uint8_t*)&addr)[1], (unsigned)((uint8_t*)&addr)[0]); - *res = strdup(buf); - return 1; -} - -/** determine if str is ip6 and put into reverse lookup format */ -static int -isip6(const char* nm, char** res) -{ - struct in6_addr addr; - /* [nibble.]{32}.ip6.arpa. is less than 128 */ - const char* hex = "0123456789abcdef"; - char buf[128]; - char *p; - int i; - if(inet_pton(AF_INET6, nm, &addr) <= 0) { - return 0; - } - p = buf; - for(i=15; i>=0; i--) { - uint8_t b = ((uint8_t*)&addr)[i]; - *p++ = hex[ (b&0x0f) ]; - *p++ = '.'; - *p++ = hex[ (b&0xf0) >> 4 ]; - *p++ = '.'; - } - snprintf(buf+16*4, sizeof(buf)-16*4, "ip6.arpa"); - *res = strdup(buf); - if(!*res) { - fprintf(stderr, "error: out of memory\n"); - exit(1); - } - return 1; -} - -/** massage input name */ -static char* -massage_qname(const char* nm, int* reverse) -{ - /* recognise IP4 and IP6, create reverse addresses if needed */ - char* res; - if(isip4(nm, &res)) { - *reverse = 1; - } else if(isip6(nm, &res)) { - *reverse = 1; - } else { - res = strdup(nm); - } - if(!res) { - fprintf(stderr, "error: out of memory\n"); - exit(1); - } - return res; -} - -/** massage input type */ -static int -massage_type(const char* t, int reverse, int* multi) -{ - if(t) { - int r = sldns_get_rr_type_by_name(t); - if(r == 0 && strcasecmp(t, "TYPE0") != 0 && - strcmp(t, "") != 0) { - fprintf(stderr, "error unknown type %s\n", t); - exit(1); - } - return r; - } - if(!t && reverse) - return LDNS_RR_TYPE_PTR; - *multi = 1; - return LDNS_RR_TYPE_A; -} - -/** massage input class */ -static int -massage_class(const char* c) -{ - if(c) { - int r = sldns_get_rr_class_by_name(c); - if(r == 0 && strcasecmp(c, "CLASS0") != 0 && - strcmp(c, "") != 0) { - fprintf(stderr, "error unknown class %s\n", c); - exit(1); - } - return r; - } - return LDNS_RR_CLASS_IN; -} - -/** nice security status string */ -static const char* -secure_str(struct ub_result* result) -{ - if(result->secure) return "(secure)"; - if(result->bogus) return "(BOGUS (security failure))"; - return "(insecure)"; -} - -/** nice string for type */ -static void -pretty_type(char* s, size_t len, int t) -{ - char d[16]; - sldns_wire2str_type_buf((uint16_t)t, d, sizeof(d)); - snprintf(s, len, "%s", d); -} - -/** nice string for class */ -static void -pretty_class(char* s, size_t len, int c) -{ - char d[16]; - sldns_wire2str_class_buf((uint16_t)c, d, sizeof(d)); - snprintf(s, len, "%s", d); -} - -/** nice string for rcode */ -static void -pretty_rcode(char* s, size_t len, int r) -{ - char d[16]; - sldns_wire2str_rcode_buf(r, d, sizeof(d)); - snprintf(s, len, "%s", d); -} - -/** convert and print rdata */ -static void -print_rd(int t, char* data, size_t len) -{ - char s[65535]; - sldns_wire2str_rdata_buf((uint8_t*)data, len, s, sizeof(s), (uint16_t)t); - printf(" %s", s); -} - -/** pretty line of RR data for results */ -static void -pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec, - char* data, size_t len) -{ - printf("%s", q); - if(strcmp(cstr, "IN") != 0) - printf(" in class %s", cstr); - if(t == LDNS_RR_TYPE_A) - printf(" has address"); - else if(t == LDNS_RR_TYPE_AAAA) - printf(" has IPv6 address"); - else if(t == LDNS_RR_TYPE_MX) - printf(" mail is handled by"); - else if(t == LDNS_RR_TYPE_PTR) - printf(" domain name pointer"); - else printf(" has %s record", tstr); - print_rd(t, data, len); - if(verb > 0) - printf(" %s", sec); - printf("\n"); -} - -/** pretty line of output for results */ -static void -pretty_output(char* q, int t, int c, struct ub_result* result, int docname) -{ - int i; - const char *secstatus = secure_str(result); - char tstr[16]; - char cstr[16]; - char rcodestr[16]; - pretty_type(tstr, 16, t); - pretty_class(cstr, 16, c); - pretty_rcode(rcodestr, 16, result->rcode); - - if(!result->havedata && result->rcode) { - printf("Host %s not found: %d(%s).", - q, result->rcode, rcodestr); - if(verb > 0) - printf(" %s", secstatus); - printf("\n"); - if(result->bogus && result->why_bogus) - printf("%s\n", result->why_bogus); - return; - } - if(docname && result->canonname && - result->canonname != result->qname) { - printf("%s is an alias for %s", result->qname, - result->canonname); - if(verb > 0) - printf(" %s", secstatus); - printf("\n"); - } - /* remove trailing . from long canonnames for nicer output */ - if(result->canonname && strlen(result->canonname) > 1 && - result->canonname[strlen(result->canonname)-1] == '.') - result->canonname[strlen(result->canonname)-1] = 0; - if(!result->havedata) { - if(verb > 0) { - printf("%s", result->canonname?result->canonname:q); - if(strcmp(cstr, "IN") != 0) - printf(" in class %s", cstr); - if(t == LDNS_RR_TYPE_A) - printf(" has no address"); - else if(t == LDNS_RR_TYPE_AAAA) - printf(" has no IPv6 address"); - else if(t == LDNS_RR_TYPE_PTR) - printf(" has no domain name ptr"); - else if(t == LDNS_RR_TYPE_MX) - printf(" has no mail handler record"); - else if(t == LDNS_RR_TYPE_ANY) { - char* s = sldns_wire2str_pkt( - result->answer_packet, - (size_t)result->answer_len); - if(!s) { - fprintf(stderr, "alloc failure\n"); - exit(1); - } - printf("%s\n", s); - } else printf(" has no %s record", tstr); - printf(" %s\n", secstatus); - } - /* else: emptiness to indicate no data */ - if(result->bogus && result->why_bogus) - printf("%s\n", result->why_bogus); - return; - } - i=0; - while(result->data[i]) - { - pretty_rdata( - result->canonname?result->canonname:q, - cstr, tstr, t, secstatus, result->data[i], - (size_t)result->len[i]); - i++; - } - if(result->bogus && result->why_bogus) - printf("%s\n", result->why_bogus); -} - -/** perform a lookup and printout return if domain existed */ -static int -dnslook(struct ub_ctx* ctx, char* q, int t, int c, int docname) -{ - int ret; - struct ub_result* result; - - ret = ub_resolve(ctx, q, t, c, &result); - if(ret != 0) { - fprintf(stderr, "resolve error: %s\n", ub_strerror(ret)); - exit(1); - } - pretty_output(q, t, c, result, docname); - ret = result->nxdomain; - ub_resolve_free(result); - return ret; -} - -/** perform host lookup */ -static void -lookup(struct ub_ctx* ctx, const char* nm, const char* qt, const char* qc) -{ - /* massage input into a query name, type and class */ - int multi = 0; /* no type, so do A, AAAA, MX */ - int reverse = 0; /* we are doing a reverse lookup */ - char* realq = massage_qname(nm, &reverse); - int t = massage_type(qt, reverse, &multi); - int c = massage_class(qc); - - /* perform the query */ - if(multi) { - if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c, 1)) { - /* domain exists, lookup more */ - (void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0); - (void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0); - } - } else { - (void)dnslook(ctx, realq, t, c, 1); - } - ub_ctx_delete(ctx); - free(realq); -} - -/** print error if any */ -static void -check_ub_res(int r) -{ - if(r != 0) { - fprintf(stderr, "error: %s\n", ub_strerror(r)); - exit(1); - } -} - -/** 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 unbound-host */ -int main(int argc, char* argv[]) -{ - int c; - char* qclass = NULL; - char* qtype = NULL; - struct ub_ctx* ctx = NULL; - int debuglevel = 0; - - ctx = ub_ctx_create(); - if(!ctx) { - fprintf(stderr, "error: out of memory\n"); - exit(1); - } - /* no need to fetch additional targets, we only do few lookups */ - check_ub_res(ub_ctx_set_option(ctx, "target-fetch-policy:", "0 0 0 0 0")); - - /* parse the options */ - while( (c=getopt(argc, argv, "46DF:c:df:hrt:vy:C:")) != -1) { - switch(c) { - case '4': - check_ub_res(ub_ctx_set_option(ctx, "do-ip6:", "no")); - break; - case '6': - check_ub_res(ub_ctx_set_option(ctx, "do-ip4:", "no")); - break; - case 'c': - qclass = optarg; - break; - case 'C': - check_ub_res(ub_ctx_config(ctx, optarg)); - break; - case 'D': - check_ub_res(ub_ctx_add_ta_file(ctx, ROOT_ANCHOR_FILE)); - break; - case 'd': - debuglevel++; - if(debuglevel < 2) - debuglevel = 2; /* at least VERB_DETAIL */ - break; - case 'r': - check_ub_res(ub_ctx_resolvconf(ctx, "/etc/resolv.conf")); - break; - case 't': - qtype = optarg; - break; - case 'v': - verb++; - break; - case 'y': - check_ub_res(ub_ctx_add_ta(ctx, optarg)); - break; - case 'f': - check_ub_res(ub_ctx_add_ta_file(ctx, optarg)); - break; - case 'F': - check_ub_res(ub_ctx_trustedkeys(ctx, optarg)); - break; - case '?': - case 'h': - default: - usage(); - } - } - if(debuglevel != 0) /* set after possible -C options */ - check_ub_res(ub_ctx_debuglevel(ctx, debuglevel)); - if(ub_ctx_get_option(ctx, "use-syslog", &optarg) == 0) { - if(strcmp(optarg, "yes") == 0) /* disable use-syslog */ - check_ub_res(ub_ctx_set_option(ctx, - "use-syslog:", "no")); - free(optarg); - } - argc -= optind; - argv += optind; - if(argc != 1) - usage(); - -#ifdef HAVE_NSS - if(NSS_NoDB_Init(".") != SECSuccess) { - fprintf(stderr, "could not init NSS\n"); - return 1; - } -#endif - lookup(ctx, argv[0], qtype, qclass); - return 0; -} diff --git a/external/unbound/smallapp/worker_cb.c b/external/unbound/smallapp/worker_cb.c deleted file mode 100644 index e88e8c8d7..000000000 --- a/external/unbound/smallapp/worker_cb.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * checkconf/worker_cb.c - fake callback routines to make fptr_wlist work - * - * Copyright (c) 2007, 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 COPYRIGHT - * HOLDER 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 contains fake callback functions, so that the symbols exist - * and the fptr_wlist continues to work even if the daemon/worker is not - * linked into the resulting program. - */ -#include "config.h" -#include "libunbound/context.h" -#include "libunbound/worker.h" -#include "util/fptr_wlist.h" -#include "util/log.h" -#include "services/mesh.h" - -void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), - uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), - int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -int worker_handle_request(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(repinfo)) -{ - log_assert(0); - return 0; -} - -int worker_handle_reply(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(reply_info)) -{ - log_assert(0); - return 0; -} - -int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(reply_info)) -{ - log_assert(0); - return 0; -} - -int remote_accept_callback(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(repinfo)) -{ - log_assert(0); - return 0; -} - -int remote_control_callback(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(repinfo)) -{ - log_assert(0); - return 0; -} - -void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -struct outbound_entry* worker_send_query( - struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), - int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), - socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), - size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream), - struct module_qstate* ATTR_UNUSED(q)) -{ - log_assert(0); - return 0; -} - -#ifdef UB_ON_WINDOWS -void -worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void* - ATTR_UNUSED(arg)) { - log_assert(0); -} - -void -wsvc_cron_cb(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} -#endif /* UB_ON_WINDOWS */ - -void -worker_alloc_cleanup(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -struct outbound_entry* libworker_send_query( - struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags), - int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec), - int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr), - socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone), - size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(ssl_upstream), - struct module_qstate* ATTR_UNUSED(q)) -{ - log_assert(0); - return 0; -} - -int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(reply_info)) -{ - log_assert(0); - return 0; -} - -int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(reply_info)) -{ - log_assert(0); - return 0; -} - -void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), - uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len), - int ATTR_UNUSED(error), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), - char* ATTR_UNUSED(why_bogus)) -{ - log_assert(0); -} - -void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), - char* ATTR_UNUSED(why_bogus)) -{ - log_assert(0); -} - -void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode), - struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s), - char* ATTR_UNUSED(why_bogus)) -{ - log_assert(0); -} - -int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - log_assert(0); - return 0; -} - -void worker_stat_timer_cb(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void worker_probe_timer_cb(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void worker_start_accept(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void worker_stop_accept(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -/** keep track of lock id in lock-verify application */ -struct order_id { - /** the thread id that created it */ - int thr; - /** the instance number of creation */ - int instance; -}; - -int order_lock_cmp(const void* e1, const void* e2) -{ - const struct order_id* o1 = e1; - const struct order_id* o2 = e2; - if(o1->thr < o2->thr) return -1; - if(o1->thr > o2->thr) return 1; - if(o1->instance < o2->instance) return -1; - if(o1->instance > o2->instance) return 1; - return 0; -} - -int -codeline_cmp(const void* a, const void* b) -{ - return strcmp(a, b); -} - -int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - log_assert(0); - return 0; -} - -void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} |