1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * unbound-anchor.c - update the root anchor if necessary. 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2010, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24b7579f77SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25b7579f77SDag-Erling Smørgrav * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26b7579f77SDag-Erling Smørgrav * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27b7579f77SDag-Erling Smørgrav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28b7579f77SDag-Erling Smørgrav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29b7579f77SDag-Erling Smørgrav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30b7579f77SDag-Erling Smørgrav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31b7579f77SDag-Erling Smørgrav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32b7579f77SDag-Erling Smørgrav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33b7579f77SDag-Erling Smørgrav * POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * This file checks to see that the current 5011 keys work to prime the 40b7579f77SDag-Erling Smørgrav * current root anchor. If not a certificate is used to update the anchor. 41b7579f77SDag-Erling Smørgrav * 42b7579f77SDag-Erling Smørgrav * This is a concept solution for distribution of the DNSSEC root 43b7579f77SDag-Erling Smørgrav * trust anchor. It is a small tool, called "unbound-anchor", that 44b7579f77SDag-Erling Smørgrav * runs before the main validator starts. I.e. in the init script: 45b7579f77SDag-Erling Smørgrav * unbound-anchor; unbound. Thus it is meant to run at system boot time. 46b7579f77SDag-Erling Smørgrav * 47b7579f77SDag-Erling Smørgrav * Management-Abstract: 48b7579f77SDag-Erling Smørgrav * * first run: fill root.key file with hardcoded DS record. 49b7579f77SDag-Erling Smørgrav * * mostly: use RFC5011 tracking, quick . DNSKEY UDP query. 50b7579f77SDag-Erling Smørgrav * * failover: use builtin certificate, do https and update. 51b7579f77SDag-Erling Smørgrav * Special considerations: 52b7579f77SDag-Erling Smørgrav * * 30-days RFC5011 timer saves a lot of https traffic. 53b7579f77SDag-Erling Smørgrav * * DNSKEY probe must be NOERROR, saves a lot of https traffic. 54b7579f77SDag-Erling Smørgrav * * fail if clock before sign date of the root, if cert expired. 55b7579f77SDag-Erling Smørgrav * * if the root goes back to unsigned, deals with it. 56b7579f77SDag-Erling Smørgrav * 57b7579f77SDag-Erling Smørgrav * It has hardcoded the root DS anchors and the ICANN CA root certificate. 58b7579f77SDag-Erling Smørgrav * It allows with options to override those. It also takes root-hints (it 59b7579f77SDag-Erling Smørgrav * has to do a DNS resolve), and also has hardcoded defaults for those. 60b7579f77SDag-Erling Smørgrav * 61b7579f77SDag-Erling Smørgrav * Once it starts, just before the validator starts, it quickly checks if 62b7579f77SDag-Erling Smørgrav * the root anchor file needs to be updated. First it tries to use 63b7579f77SDag-Erling Smørgrav * RFC5011-tracking of the root key. If that fails (and for 30-days since 64b7579f77SDag-Erling Smørgrav * last successful probe), then it attempts to update using the 65b7579f77SDag-Erling Smørgrav * certificate. So most of the time, the RFC5011 tracking will work fine, 66b7579f77SDag-Erling Smørgrav * and within a couple milliseconds, the main daemon can start. It will 67b7579f77SDag-Erling Smørgrav * have only probed the . DNSKEY, not done expensive https transfers on the 68b7579f77SDag-Erling Smørgrav * root infrastructure. 69b7579f77SDag-Erling Smørgrav * 70b7579f77SDag-Erling Smørgrav * If there is no root key in the root.key file, it bootstraps the 71b7579f77SDag-Erling Smørgrav * RFC5011-tracking with its builtin DS anchors; if that fails it 72b7579f77SDag-Erling Smørgrav * bootstraps the RFC5011-tracking using the certificate. (again to avoid 73b7579f77SDag-Erling Smørgrav * https, and it is also faster). 74b7579f77SDag-Erling Smørgrav * 75b7579f77SDag-Erling Smørgrav * It uses the XML file by converting it to DS records and writing that to the 76b7579f77SDag-Erling Smørgrav * key file. Unbound can detect that the 'special comments' are gone, and 77b7579f77SDag-Erling Smørgrav * the file contains a list of normal DNSKEY/DS records, and uses that to 78b7579f77SDag-Erling Smørgrav * bootstrap 5011 (the KSK is made VALID). 79b7579f77SDag-Erling Smørgrav * 80b7579f77SDag-Erling Smørgrav * The certificate update is done by fetching root-anchors.xml and 81b7579f77SDag-Erling Smørgrav * root-anchors.p7s via SSL. The HTTPS certificate can be logged but is 82b7579f77SDag-Erling Smørgrav * not validated (https for channel security; the security comes from the 83b7579f77SDag-Erling Smørgrav * certificate). The 'data.iana.org' domain name A and AAAA are resolved 84b7579f77SDag-Erling Smørgrav * without DNSSEC. It tries a random IP until the transfer succeeds. It 85b7579f77SDag-Erling Smørgrav * then checks the p7s signature. 86b7579f77SDag-Erling Smørgrav * 87b7579f77SDag-Erling Smørgrav * On any failure, it leaves the root key file untouched. The main 88b7579f77SDag-Erling Smørgrav * validator has to cope with it, it cannot fix things (So a failure does 89b7579f77SDag-Erling Smørgrav * not go 'without DNSSEC', no downgrade). If it used its builtin stuff or 90b7579f77SDag-Erling Smørgrav * did the https, it exits with an exit code, so that this can trigger the 91b7579f77SDag-Erling Smørgrav * init script to log the event and potentially alert the operator that can 92b7579f77SDag-Erling Smørgrav * do a manual check. 93b7579f77SDag-Erling Smørgrav * 94b7579f77SDag-Erling Smørgrav * The date is also checked. Before 2010-07-15 is a failure (root not 95b7579f77SDag-Erling Smørgrav * signed yet; avoids attacks on system clock). The 96b7579f77SDag-Erling Smørgrav * last-successful-RFC5011-probe (if available) has to be more than 30 days 97b7579f77SDag-Erling Smørgrav * in the past (otherwise, RFC5011 should have worked). This keeps 98b7579f77SDag-Erling Smørgrav * unneccesary https traffic down. If the main certificate is expired, it 99b7579f77SDag-Erling Smørgrav * fails. 100b7579f77SDag-Erling Smørgrav * 101b7579f77SDag-Erling Smørgrav * The dates on the keys in the xml are checked (uses the libexpat xml 102b7579f77SDag-Erling Smørgrav * parser), only the valid ones are used to re-enstate RFC5011 tracking. 103b7579f77SDag-Erling Smørgrav * If 0 keys are valid, the zone has gone to insecure (a special marker is 104b7579f77SDag-Erling Smørgrav * written in the keyfile that tells the main validator daemon the zone is 105b7579f77SDag-Erling Smørgrav * insecure). 106b7579f77SDag-Erling Smørgrav * 107b7579f77SDag-Erling Smørgrav * Only the root ICANN CA is shipped, not the intermediate ones. The 108b7579f77SDag-Erling Smørgrav * intermediate CAs are included in the p7s file that was downloaded. (the 109b7579f77SDag-Erling Smørgrav * root cert is valid to 2028 and the intermediate to 2014, today). 110b7579f77SDag-Erling Smørgrav * 111b7579f77SDag-Erling Smørgrav * Obviously, the tool also has options so the operator can provide a new 112b7579f77SDag-Erling Smørgrav * keyfile, a new certificate and new URLs, and fresh root hints. By 113b7579f77SDag-Erling Smørgrav * default it logs nothing on failure and success; it 'just works'. 114b7579f77SDag-Erling Smørgrav * 115b7579f77SDag-Erling Smørgrav */ 116b7579f77SDag-Erling Smørgrav 117b7579f77SDag-Erling Smørgrav #include "config.h" 118b7579f77SDag-Erling Smørgrav #include "libunbound/unbound.h" 119b7579f77SDag-Erling Smørgrav #include <ldns/rr.h> 120b7579f77SDag-Erling Smørgrav #include <expat.h> 121b7579f77SDag-Erling Smørgrav #ifndef HAVE_EXPAT_H 122b7579f77SDag-Erling Smørgrav #error "need libexpat to parse root-anchors.xml file." 123b7579f77SDag-Erling Smørgrav #endif 124b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H 125b7579f77SDag-Erling Smørgrav #include <getopt.h> 126b7579f77SDag-Erling Smørgrav #endif 127b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H 128b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h> 129b7579f77SDag-Erling Smørgrav #endif 130b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H 131b7579f77SDag-Erling Smørgrav #include <openssl/err.h> 132b7579f77SDag-Erling Smørgrav #endif 133b7579f77SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_RAND_H 134b7579f77SDag-Erling Smørgrav #include <openssl/rand.h> 135b7579f77SDag-Erling Smørgrav #endif 136b7579f77SDag-Erling Smørgrav #include <openssl/x509.h> 1378ed2b524SDag-Erling Smørgrav #include <openssl/x509v3.h> 138b7579f77SDag-Erling Smørgrav #include <openssl/pem.h> 139b7579f77SDag-Erling Smørgrav 140b7579f77SDag-Erling Smørgrav /** name of server in URL to fetch HTTPS from */ 141b7579f77SDag-Erling Smørgrav #define URLNAME "data.iana.org" 142b7579f77SDag-Erling Smørgrav /** path on HTTPS server to xml file */ 143b7579f77SDag-Erling Smørgrav #define XMLNAME "root-anchors/root-anchors.xml" 144b7579f77SDag-Erling Smørgrav /** path on HTTPS server to p7s file */ 145b7579f77SDag-Erling Smørgrav #define P7SNAME "root-anchors/root-anchors.p7s" 1468ed2b524SDag-Erling Smørgrav /** name of the signer of the certificate */ 1478ed2b524SDag-Erling Smørgrav #define P7SIGNER "dnssec@iana.org" 148b7579f77SDag-Erling Smørgrav /** port number for https access */ 149b7579f77SDag-Erling Smørgrav #define HTTPS_PORT 443 150b7579f77SDag-Erling Smørgrav 151b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 152b7579f77SDag-Erling Smørgrav /* sneakily reuse the the wsa_strerror function, on windows */ 153b7579f77SDag-Erling Smørgrav char* wsa_strerror(int err); 154b7579f77SDag-Erling Smørgrav #endif 155b7579f77SDag-Erling Smørgrav 156b7579f77SDag-Erling Smørgrav /** verbosity for this application */ 157b7579f77SDag-Erling Smørgrav static int verb = 0; 158b7579f77SDag-Erling Smørgrav 159b7579f77SDag-Erling Smørgrav /** list of IP addresses */ 160b7579f77SDag-Erling Smørgrav struct ip_list { 161b7579f77SDag-Erling Smørgrav /** next in list */ 162b7579f77SDag-Erling Smørgrav struct ip_list* next; 163b7579f77SDag-Erling Smørgrav /** length of addr */ 164b7579f77SDag-Erling Smørgrav socklen_t len; 165b7579f77SDag-Erling Smørgrav /** address ready to connect to */ 166b7579f77SDag-Erling Smørgrav struct sockaddr_storage addr; 167b7579f77SDag-Erling Smørgrav /** has the address been used */ 168b7579f77SDag-Erling Smørgrav int used; 169b7579f77SDag-Erling Smørgrav }; 170b7579f77SDag-Erling Smørgrav 171b7579f77SDag-Erling Smørgrav /** Give unbound-anchor usage, and exit (1). */ 172b7579f77SDag-Erling Smørgrav static void 173b7579f77SDag-Erling Smørgrav usage() 174b7579f77SDag-Erling Smørgrav { 175b7579f77SDag-Erling Smørgrav printf("Usage: unbound-anchor [opts]\n"); 176b7579f77SDag-Erling Smørgrav printf(" Setup or update root anchor. " 177b7579f77SDag-Erling Smørgrav "Most options have defaults.\n"); 178b7579f77SDag-Erling Smørgrav printf(" Run this program before you start the validator.\n"); 179b7579f77SDag-Erling Smørgrav printf("\n"); 180b7579f77SDag-Erling Smørgrav printf(" The anchor and cert have default builtin content\n"); 181b7579f77SDag-Erling Smørgrav printf(" if the file does not exist or is empty.\n"); 182b7579f77SDag-Erling Smørgrav printf("\n"); 183b7579f77SDag-Erling Smørgrav printf("-a file root key file, default %s\n", ROOT_ANCHOR_FILE); 184b7579f77SDag-Erling Smørgrav printf(" The key is input and output for this tool.\n"); 185b7579f77SDag-Erling Smørgrav printf("-c file cert file, default %s\n", ROOT_CERT_FILE); 186b7579f77SDag-Erling Smørgrav printf("-l list builtin key and cert on stdout\n"); 187b7579f77SDag-Erling Smørgrav printf("-u name server in https url, default %s\n", URLNAME); 188b7579f77SDag-Erling Smørgrav printf("-x path pathname to xml in url, default %s\n", XMLNAME); 189b7579f77SDag-Erling Smørgrav printf("-s path pathname to p7s in url, default %s\n", P7SNAME); 1908ed2b524SDag-Erling Smørgrav printf("-n name signer's subject emailAddress, default %s\n", P7SIGNER); 191b7579f77SDag-Erling Smørgrav printf("-4 work using IPv4 only\n"); 192b7579f77SDag-Erling Smørgrav printf("-6 work using IPv6 only\n"); 193b7579f77SDag-Erling Smørgrav printf("-f resolv.conf use given resolv.conf to resolve -u name\n"); 194b7579f77SDag-Erling Smørgrav printf("-r root.hints use given root.hints to resolve -u name\n" 195b7579f77SDag-Erling Smørgrav " builtin root hints are used by default\n"); 196b7579f77SDag-Erling Smørgrav printf("-v more verbose\n"); 197b7579f77SDag-Erling Smørgrav printf("-C conf debug, read config\n"); 198b7579f77SDag-Erling Smørgrav printf("-P port use port for https connect, default 443\n"); 199b7579f77SDag-Erling Smørgrav printf("-F debug, force update with cert\n"); 200b7579f77SDag-Erling Smørgrav printf("-h show this usage help\n"); 201b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 202b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 203b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 204b7579f77SDag-Erling Smørgrav exit(1); 205b7579f77SDag-Erling Smørgrav } 206b7579f77SDag-Erling Smørgrav 207b7579f77SDag-Erling Smørgrav /** return the built in root update certificate */ 208b7579f77SDag-Erling Smørgrav static const char* 209b7579f77SDag-Erling Smørgrav get_builtin_cert(void) 210b7579f77SDag-Erling Smørgrav { 211b7579f77SDag-Erling Smørgrav return 212b7579f77SDag-Erling Smørgrav /* The ICANN CA fetched at 24 Sep 2010. Valid to 2028 */ 213b7579f77SDag-Erling Smørgrav "-----BEGIN CERTIFICATE-----\n" 214b7579f77SDag-Erling Smørgrav "MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n" 215b7579f77SDag-Erling Smørgrav "TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n" 216b7579f77SDag-Erling Smørgrav "BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX\n" 217b7579f77SDag-Erling Smørgrav "DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O\n" 218b7579f77SDag-Erling Smørgrav "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB\n" 219b7579f77SDag-Erling Smørgrav "MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb\n" 220b7579f77SDag-Erling Smørgrav "cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S\n" 221b7579f77SDag-Erling Smørgrav "G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg\n" 222b7579f77SDag-Erling Smørgrav "ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2\n" 223b7579f77SDag-Erling Smørgrav "paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7\n" 224b7579f77SDag-Erling Smørgrav "MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29\n" 225b7579f77SDag-Erling Smørgrav "iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n" 226b7579f77SDag-Erling Smørgrav "Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3\n" 227b7579f77SDag-Erling Smørgrav "DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH\n" 228b7579f77SDag-Erling Smørgrav "6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD\n" 229b7579f77SDag-Erling Smørgrav "2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h\n" 230b7579f77SDag-Erling Smørgrav "15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n" 231b7579f77SDag-Erling Smørgrav "0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n" 232b7579f77SDag-Erling Smørgrav "j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n" 233b7579f77SDag-Erling Smørgrav "-----END CERTIFICATE-----\n" 234b7579f77SDag-Erling Smørgrav ; 235b7579f77SDag-Erling Smørgrav } 236b7579f77SDag-Erling Smørgrav 237b7579f77SDag-Erling Smørgrav /** return the built in root DS trust anchor */ 238b7579f77SDag-Erling Smørgrav static const char* 239b7579f77SDag-Erling Smørgrav get_builtin_ds(void) 240b7579f77SDag-Erling Smørgrav { 241b7579f77SDag-Erling Smørgrav return 242b7579f77SDag-Erling Smørgrav ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n"; 243b7579f77SDag-Erling Smørgrav } 244b7579f77SDag-Erling Smørgrav 245b7579f77SDag-Erling Smørgrav /** print hex data */ 246b7579f77SDag-Erling Smørgrav static void 247*ebc5657fSDag-Erling Smørgrav print_data(const char* msg, const char* data, int len) 248b7579f77SDag-Erling Smørgrav { 249b7579f77SDag-Erling Smørgrav int i; 250b7579f77SDag-Erling Smørgrav printf("%s: ", msg); 251b7579f77SDag-Erling Smørgrav for(i=0; i<len; i++) { 252b7579f77SDag-Erling Smørgrav printf(" %2.2x", (unsigned char)data[i]); 253b7579f77SDag-Erling Smørgrav } 254b7579f77SDag-Erling Smørgrav printf("\n"); 255b7579f77SDag-Erling Smørgrav } 256b7579f77SDag-Erling Smørgrav 257b7579f77SDag-Erling Smørgrav /** print ub context creation error and exit */ 258b7579f77SDag-Erling Smørgrav static void 259b7579f77SDag-Erling Smørgrav ub_ctx_error_exit(struct ub_ctx* ctx, const char* str, const char* str2) 260b7579f77SDag-Erling Smørgrav { 261b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 262b7579f77SDag-Erling Smørgrav if(str && str2 && verb) printf("%s: %s\n", str, str2); 263b7579f77SDag-Erling Smørgrav if(verb) printf("error: could not create unbound resolver context\n"); 264b7579f77SDag-Erling Smørgrav exit(0); 265b7579f77SDag-Erling Smørgrav } 266b7579f77SDag-Erling Smørgrav 267b7579f77SDag-Erling Smørgrav /** 268b7579f77SDag-Erling Smørgrav * Create a new unbound context with the commandline settings applied 269b7579f77SDag-Erling Smørgrav */ 270b7579f77SDag-Erling Smørgrav static struct ub_ctx* 271*ebc5657fSDag-Erling Smørgrav create_unbound_context(const char* res_conf, const char* root_hints, 272*ebc5657fSDag-Erling Smørgrav const char* debugconf, int ip4only, int ip6only) 273b7579f77SDag-Erling Smørgrav { 274b7579f77SDag-Erling Smørgrav int r; 275b7579f77SDag-Erling Smørgrav struct ub_ctx* ctx = ub_ctx_create(); 276b7579f77SDag-Erling Smørgrav if(!ctx) { 277b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 278b7579f77SDag-Erling Smørgrav exit(0); 279b7579f77SDag-Erling Smørgrav } 280b7579f77SDag-Erling Smørgrav /* do not waste time and network traffic to fetch extra nameservers */ 281b7579f77SDag-Erling Smørgrav r = ub_ctx_set_option(ctx, "target-fetch-policy:", "0 0 0 0 0"); 282b7579f77SDag-Erling Smørgrav if(r && verb) printf("ctx targetfetchpolicy: %s\n", ub_strerror(r)); 283b7579f77SDag-Erling Smørgrav /* read config file first, so its settings can be overridden */ 284b7579f77SDag-Erling Smørgrav if(debugconf) { 285b7579f77SDag-Erling Smørgrav r = ub_ctx_config(ctx, debugconf); 286b7579f77SDag-Erling Smørgrav if(r) ub_ctx_error_exit(ctx, debugconf, ub_strerror(r)); 287b7579f77SDag-Erling Smørgrav } 288b7579f77SDag-Erling Smørgrav if(res_conf) { 289b7579f77SDag-Erling Smørgrav r = ub_ctx_resolvconf(ctx, res_conf); 290b7579f77SDag-Erling Smørgrav if(r) ub_ctx_error_exit(ctx, res_conf, ub_strerror(r)); 291b7579f77SDag-Erling Smørgrav } 292b7579f77SDag-Erling Smørgrav if(root_hints) { 293b7579f77SDag-Erling Smørgrav r = ub_ctx_set_option(ctx, "root-hints:", root_hints); 294b7579f77SDag-Erling Smørgrav if(r) ub_ctx_error_exit(ctx, root_hints, ub_strerror(r)); 295b7579f77SDag-Erling Smørgrav } 296b7579f77SDag-Erling Smørgrav if(ip4only) { 297b7579f77SDag-Erling Smørgrav r = ub_ctx_set_option(ctx, "do-ip6:", "no"); 298b7579f77SDag-Erling Smørgrav if(r) ub_ctx_error_exit(ctx, "ip4only", ub_strerror(r)); 299b7579f77SDag-Erling Smørgrav } 300b7579f77SDag-Erling Smørgrav if(ip6only) { 301b7579f77SDag-Erling Smørgrav r = ub_ctx_set_option(ctx, "do-ip4:", "no"); 302b7579f77SDag-Erling Smørgrav if(r) ub_ctx_error_exit(ctx, "ip6only", ub_strerror(r)); 303b7579f77SDag-Erling Smørgrav } 304b7579f77SDag-Erling Smørgrav return ctx; 305b7579f77SDag-Erling Smørgrav } 306b7579f77SDag-Erling Smørgrav 307b7579f77SDag-Erling Smørgrav /** printout certificate in detail */ 308b7579f77SDag-Erling Smørgrav static void 309*ebc5657fSDag-Erling Smørgrav verb_cert(const char* msg, X509* x) 310b7579f77SDag-Erling Smørgrav { 311b7579f77SDag-Erling Smørgrav if(verb == 0 || verb == 1) return; 312b7579f77SDag-Erling Smørgrav if(verb == 2) { 313b7579f77SDag-Erling Smørgrav if(msg) printf("%s\n", msg); 314b7579f77SDag-Erling Smørgrav X509_print_ex_fp(stdout, x, 0, (unsigned long)-1 315b7579f77SDag-Erling Smørgrav ^(X509_FLAG_NO_SUBJECT 316b7579f77SDag-Erling Smørgrav |X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY)); 317b7579f77SDag-Erling Smørgrav return; 318b7579f77SDag-Erling Smørgrav } 319b7579f77SDag-Erling Smørgrav if(msg) printf("%s\n", msg); 320b7579f77SDag-Erling Smørgrav X509_print_fp(stdout, x); 321b7579f77SDag-Erling Smørgrav } 322b7579f77SDag-Erling Smørgrav 323b7579f77SDag-Erling Smørgrav /** printout certificates in detail */ 324b7579f77SDag-Erling Smørgrav static void 325*ebc5657fSDag-Erling Smørgrav verb_certs(const char* msg, STACK_OF(X509)* sk) 326b7579f77SDag-Erling Smørgrav { 327b7579f77SDag-Erling Smørgrav int i, num = sk_X509_num(sk); 328b7579f77SDag-Erling Smørgrav if(verb == 0 || verb == 1) return; 329b7579f77SDag-Erling Smørgrav for(i=0; i<num; i++) { 330b7579f77SDag-Erling Smørgrav printf("%s (%d/%d)\n", msg, i, num); 331b7579f77SDag-Erling Smørgrav verb_cert(NULL, sk_X509_value(sk, i)); 332b7579f77SDag-Erling Smørgrav } 333b7579f77SDag-Erling Smørgrav } 334b7579f77SDag-Erling Smørgrav 335b7579f77SDag-Erling Smørgrav /** read certificates from a PEM bio */ 336b7579f77SDag-Erling Smørgrav static STACK_OF(X509)* 337b7579f77SDag-Erling Smørgrav read_cert_bio(BIO* bio) 338b7579f77SDag-Erling Smørgrav { 339b7579f77SDag-Erling Smørgrav STACK_OF(X509) *sk = sk_X509_new_null(); 340b7579f77SDag-Erling Smørgrav if(!sk) { 341b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 342b7579f77SDag-Erling Smørgrav exit(0); 343b7579f77SDag-Erling Smørgrav } 344b7579f77SDag-Erling Smørgrav while(!BIO_eof(bio)) { 345b7579f77SDag-Erling Smørgrav X509* x = PEM_read_bio_X509(bio, NULL, 0, NULL); 346b7579f77SDag-Erling Smørgrav if(x == NULL) { 347b7579f77SDag-Erling Smørgrav if(verb) { 348b7579f77SDag-Erling Smørgrav printf("failed to read X509\n"); 349b7579f77SDag-Erling Smørgrav ERR_print_errors_fp(stdout); 350b7579f77SDag-Erling Smørgrav } 351b7579f77SDag-Erling Smørgrav continue; 352b7579f77SDag-Erling Smørgrav } 353b7579f77SDag-Erling Smørgrav if(!sk_X509_push(sk, x)) { 354b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 355b7579f77SDag-Erling Smørgrav exit(0); 356b7579f77SDag-Erling Smørgrav } 357b7579f77SDag-Erling Smørgrav } 358b7579f77SDag-Erling Smørgrav return sk; 359b7579f77SDag-Erling Smørgrav } 360b7579f77SDag-Erling Smørgrav 361b7579f77SDag-Erling Smørgrav /* read the certificate file */ 362b7579f77SDag-Erling Smørgrav static STACK_OF(X509)* 363*ebc5657fSDag-Erling Smørgrav read_cert_file(const char* file) 364b7579f77SDag-Erling Smørgrav { 365b7579f77SDag-Erling Smørgrav STACK_OF(X509)* sk; 366b7579f77SDag-Erling Smørgrav FILE* in; 367b7579f77SDag-Erling Smørgrav int content = 0; 368b7579f77SDag-Erling Smørgrav char buf[128]; 369b7579f77SDag-Erling Smørgrav if(file == NULL || strcmp(file, "") == 0) { 370b7579f77SDag-Erling Smørgrav return NULL; 371b7579f77SDag-Erling Smørgrav } 372b7579f77SDag-Erling Smørgrav sk = sk_X509_new_null(); 373b7579f77SDag-Erling Smørgrav if(!sk) { 374b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 375b7579f77SDag-Erling Smørgrav exit(0); 376b7579f77SDag-Erling Smørgrav } 377b7579f77SDag-Erling Smørgrav in = fopen(file, "r"); 378b7579f77SDag-Erling Smørgrav if(!in) { 379b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", file, strerror(errno)); 380b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 381b7579f77SDag-Erling Smørgrav sk_X509_pop_free(sk, X509_free); 382b7579f77SDag-Erling Smørgrav #endif 383b7579f77SDag-Erling Smørgrav return NULL; 384b7579f77SDag-Erling Smørgrav } 385b7579f77SDag-Erling Smørgrav while(!feof(in)) { 386b7579f77SDag-Erling Smørgrav X509* x = PEM_read_X509(in, NULL, 0, NULL); 387b7579f77SDag-Erling Smørgrav if(x == NULL) { 388b7579f77SDag-Erling Smørgrav if(verb) { 389b7579f77SDag-Erling Smørgrav printf("failed to read X509 file\n"); 390b7579f77SDag-Erling Smørgrav ERR_print_errors_fp(stdout); 391b7579f77SDag-Erling Smørgrav } 392b7579f77SDag-Erling Smørgrav continue; 393b7579f77SDag-Erling Smørgrav } 394b7579f77SDag-Erling Smørgrav if(!sk_X509_push(sk, x)) { 395b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 396b7579f77SDag-Erling Smørgrav fclose(in); 397b7579f77SDag-Erling Smørgrav exit(0); 398b7579f77SDag-Erling Smørgrav } 399b7579f77SDag-Erling Smørgrav content = 1; 400b7579f77SDag-Erling Smørgrav /* read away newline after --END CERT-- */ 401b7579f77SDag-Erling Smørgrav if(!fgets(buf, (int)sizeof(buf), in)) 402b7579f77SDag-Erling Smørgrav break; 403b7579f77SDag-Erling Smørgrav } 404b7579f77SDag-Erling Smørgrav fclose(in); 405b7579f77SDag-Erling Smørgrav if(!content) { 406b7579f77SDag-Erling Smørgrav if(verb) printf("%s is empty\n", file); 407b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 408b7579f77SDag-Erling Smørgrav sk_X509_pop_free(sk, X509_free); 409b7579f77SDag-Erling Smørgrav #endif 410b7579f77SDag-Erling Smørgrav return NULL; 411b7579f77SDag-Erling Smørgrav } 412b7579f77SDag-Erling Smørgrav return sk; 413b7579f77SDag-Erling Smørgrav } 414b7579f77SDag-Erling Smørgrav 415b7579f77SDag-Erling Smørgrav /** read certificates from the builtin certificate */ 416b7579f77SDag-Erling Smørgrav static STACK_OF(X509)* 417b7579f77SDag-Erling Smørgrav read_builtin_cert(void) 418b7579f77SDag-Erling Smørgrav { 419b7579f77SDag-Erling Smørgrav const char* builtin_cert = get_builtin_cert(); 420b7579f77SDag-Erling Smørgrav STACK_OF(X509)* sk; 421b7579f77SDag-Erling Smørgrav BIO *bio = BIO_new_mem_buf((void*)builtin_cert, 422b7579f77SDag-Erling Smørgrav (int)strlen(builtin_cert)); 423b7579f77SDag-Erling Smørgrav if(!bio) { 424b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 425b7579f77SDag-Erling Smørgrav exit(0); 426b7579f77SDag-Erling Smørgrav } 427b7579f77SDag-Erling Smørgrav sk = read_cert_bio(bio); 428b7579f77SDag-Erling Smørgrav if(!sk) { 429b7579f77SDag-Erling Smørgrav if(verb) printf("internal error, out of memory\n"); 430b7579f77SDag-Erling Smørgrav exit(0); 431b7579f77SDag-Erling Smørgrav } 432b7579f77SDag-Erling Smørgrav BIO_free(bio); 433b7579f77SDag-Erling Smørgrav return sk; 434b7579f77SDag-Erling Smørgrav } 435b7579f77SDag-Erling Smørgrav 436b7579f77SDag-Erling Smørgrav /** read update cert file or use builtin */ 437b7579f77SDag-Erling Smørgrav static STACK_OF(X509)* 438*ebc5657fSDag-Erling Smørgrav read_cert_or_builtin(const char* file) 439b7579f77SDag-Erling Smørgrav { 440b7579f77SDag-Erling Smørgrav STACK_OF(X509) *sk = read_cert_file(file); 441b7579f77SDag-Erling Smørgrav if(!sk) { 442b7579f77SDag-Erling Smørgrav if(verb) printf("using builtin certificate\n"); 443b7579f77SDag-Erling Smørgrav sk = read_builtin_cert(); 444b7579f77SDag-Erling Smørgrav } 445b7579f77SDag-Erling Smørgrav if(verb) printf("have %d trusted certificates\n", sk_X509_num(sk)); 446b7579f77SDag-Erling Smørgrav verb_certs("trusted certificates", sk); 447b7579f77SDag-Erling Smørgrav return sk; 448b7579f77SDag-Erling Smørgrav } 449b7579f77SDag-Erling Smørgrav 450b7579f77SDag-Erling Smørgrav static void 451b7579f77SDag-Erling Smørgrav do_list_builtin(void) 452b7579f77SDag-Erling Smørgrav { 453b7579f77SDag-Erling Smørgrav const char* builtin_cert = get_builtin_cert(); 454b7579f77SDag-Erling Smørgrav const char* builtin_ds = get_builtin_ds(); 455b7579f77SDag-Erling Smørgrav printf("%s\n", builtin_ds); 456b7579f77SDag-Erling Smørgrav printf("%s\n", builtin_cert); 457b7579f77SDag-Erling Smørgrav exit(0); 458b7579f77SDag-Erling Smørgrav } 459b7579f77SDag-Erling Smørgrav 460b7579f77SDag-Erling Smørgrav /** printout IP address with message */ 461b7579f77SDag-Erling Smørgrav static void 462*ebc5657fSDag-Erling Smørgrav verb_addr(const char* msg, struct ip_list* ip) 463b7579f77SDag-Erling Smørgrav { 464b7579f77SDag-Erling Smørgrav if(verb) { 465b7579f77SDag-Erling Smørgrav char out[100]; 466b7579f77SDag-Erling Smørgrav void* a = &((struct sockaddr_in*)&ip->addr)->sin_addr; 467b7579f77SDag-Erling Smørgrav if(ip->len != (socklen_t)sizeof(struct sockaddr_in)) 468b7579f77SDag-Erling Smørgrav a = &((struct sockaddr_in6*)&ip->addr)->sin6_addr; 469b7579f77SDag-Erling Smørgrav 470b7579f77SDag-Erling Smørgrav if(inet_ntop((int)((struct sockaddr_in*)&ip->addr)->sin_family, 471b7579f77SDag-Erling Smørgrav a, out, (socklen_t)sizeof(out))==0) 472b7579f77SDag-Erling Smørgrav printf("%s (inet_ntop error)\n", msg); 473b7579f77SDag-Erling Smørgrav else printf("%s %s\n", msg, out); 474b7579f77SDag-Erling Smørgrav } 475b7579f77SDag-Erling Smørgrav } 476b7579f77SDag-Erling Smørgrav 477b7579f77SDag-Erling Smørgrav /** free ip_list */ 478b7579f77SDag-Erling Smørgrav static void 479b7579f77SDag-Erling Smørgrav ip_list_free(struct ip_list* p) 480b7579f77SDag-Erling Smørgrav { 481b7579f77SDag-Erling Smørgrav struct ip_list* np; 482b7579f77SDag-Erling Smørgrav while(p) { 483b7579f77SDag-Erling Smørgrav np = p->next; 484b7579f77SDag-Erling Smørgrav free(p); 485b7579f77SDag-Erling Smørgrav p = np; 486b7579f77SDag-Erling Smørgrav } 487b7579f77SDag-Erling Smørgrav } 488b7579f77SDag-Erling Smørgrav 489b7579f77SDag-Erling Smørgrav /** create ip_list entry for a RR record */ 490b7579f77SDag-Erling Smørgrav static struct ip_list* 491b7579f77SDag-Erling Smørgrav RR_to_ip(int tp, char* data, int len, int port) 492b7579f77SDag-Erling Smørgrav { 493b7579f77SDag-Erling Smørgrav struct ip_list* ip = (struct ip_list*)calloc(1, sizeof(*ip)); 494b7579f77SDag-Erling Smørgrav uint16_t p = (uint16_t)port; 495b7579f77SDag-Erling Smørgrav if(tp == LDNS_RR_TYPE_A) { 496b7579f77SDag-Erling Smørgrav struct sockaddr_in* sa = (struct sockaddr_in*)&ip->addr; 497b7579f77SDag-Erling Smørgrav ip->len = (socklen_t)sizeof(*sa); 498b7579f77SDag-Erling Smørgrav sa->sin_family = AF_INET; 499b7579f77SDag-Erling Smørgrav sa->sin_port = (in_port_t)htons(p); 500b7579f77SDag-Erling Smørgrav if(len != (int)sizeof(sa->sin_addr)) { 501b7579f77SDag-Erling Smørgrav if(verb) printf("skipped badly formatted A\n"); 502b7579f77SDag-Erling Smørgrav free(ip); 503b7579f77SDag-Erling Smørgrav return NULL; 504b7579f77SDag-Erling Smørgrav } 505b7579f77SDag-Erling Smørgrav memmove(&sa->sin_addr, data, sizeof(sa->sin_addr)); 506b7579f77SDag-Erling Smørgrav 507b7579f77SDag-Erling Smørgrav } else if(tp == LDNS_RR_TYPE_AAAA) { 508b7579f77SDag-Erling Smørgrav struct sockaddr_in6* sa = (struct sockaddr_in6*)&ip->addr; 509b7579f77SDag-Erling Smørgrav ip->len = (socklen_t)sizeof(*sa); 510b7579f77SDag-Erling Smørgrav sa->sin6_family = AF_INET6; 511b7579f77SDag-Erling Smørgrav sa->sin6_port = (in_port_t)htons(p); 512b7579f77SDag-Erling Smørgrav if(len != (int)sizeof(sa->sin6_addr)) { 513b7579f77SDag-Erling Smørgrav if(verb) printf("skipped badly formatted AAAA\n"); 514b7579f77SDag-Erling Smørgrav free(ip); 515b7579f77SDag-Erling Smørgrav return NULL; 516b7579f77SDag-Erling Smørgrav } 517b7579f77SDag-Erling Smørgrav memmove(&sa->sin6_addr, data, sizeof(sa->sin6_addr)); 518b7579f77SDag-Erling Smørgrav } else { 519b7579f77SDag-Erling Smørgrav if(verb) printf("internal error: bad type in RRtoip\n"); 520b7579f77SDag-Erling Smørgrav free(ip); 521b7579f77SDag-Erling Smørgrav return NULL; 522b7579f77SDag-Erling Smørgrav } 523b7579f77SDag-Erling Smørgrav verb_addr("resolved server address", ip); 524b7579f77SDag-Erling Smørgrav return ip; 525b7579f77SDag-Erling Smørgrav } 526b7579f77SDag-Erling Smørgrav 527b7579f77SDag-Erling Smørgrav /** Resolve name, type, class and add addresses to iplist */ 528b7579f77SDag-Erling Smørgrav static void 529*ebc5657fSDag-Erling Smørgrav resolve_host_ip(struct ub_ctx* ctx, const char* host, int port, int tp, int cl, 530b7579f77SDag-Erling Smørgrav struct ip_list** head) 531b7579f77SDag-Erling Smørgrav { 532b7579f77SDag-Erling Smørgrav struct ub_result* res = NULL; 533b7579f77SDag-Erling Smørgrav int r; 534b7579f77SDag-Erling Smørgrav int i; 535b7579f77SDag-Erling Smørgrav 536b7579f77SDag-Erling Smørgrav r = ub_resolve(ctx, host, tp, cl, &res); 537b7579f77SDag-Erling Smørgrav if(r) { 538b7579f77SDag-Erling Smørgrav if(verb) printf("error: resolve %s %s: %s\n", host, 539b7579f77SDag-Erling Smørgrav (tp==LDNS_RR_TYPE_A)?"A":"AAAA", ub_strerror(r)); 540b7579f77SDag-Erling Smørgrav return; 541b7579f77SDag-Erling Smørgrav } 542b7579f77SDag-Erling Smørgrav if(!res) { 543b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 544b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 545b7579f77SDag-Erling Smørgrav exit(0); 546b7579f77SDag-Erling Smørgrav } 5478ed2b524SDag-Erling Smørgrav if(!res->havedata || res->rcode || !res->data) { 5488ed2b524SDag-Erling Smørgrav if(verb) printf("resolve %s %s: no result\n", host, 5498ed2b524SDag-Erling Smørgrav (tp==LDNS_RR_TYPE_A)?"A":"AAAA"); 5508ed2b524SDag-Erling Smørgrav return; 5518ed2b524SDag-Erling Smørgrav } 552b7579f77SDag-Erling Smørgrav for(i = 0; res->data[i]; i++) { 553b7579f77SDag-Erling Smørgrav struct ip_list* ip = RR_to_ip(tp, res->data[i], res->len[i], 554b7579f77SDag-Erling Smørgrav port); 555b7579f77SDag-Erling Smørgrav if(!ip) continue; 556b7579f77SDag-Erling Smørgrav ip->next = *head; 557b7579f77SDag-Erling Smørgrav *head = ip; 558b7579f77SDag-Erling Smørgrav } 559b7579f77SDag-Erling Smørgrav ub_resolve_free(res); 560b7579f77SDag-Erling Smørgrav } 561b7579f77SDag-Erling Smørgrav 562b7579f77SDag-Erling Smørgrav /** parse a text IP address into a sockaddr */ 563b7579f77SDag-Erling Smørgrav static struct ip_list* 564*ebc5657fSDag-Erling Smørgrav parse_ip_addr(const char* str, int port) 565b7579f77SDag-Erling Smørgrav { 566b7579f77SDag-Erling Smørgrav socklen_t len = 0; 567*ebc5657fSDag-Erling Smørgrav union { 568b7579f77SDag-Erling Smørgrav struct sockaddr_in6 a6; 569b7579f77SDag-Erling Smørgrav struct sockaddr_in a; 570*ebc5657fSDag-Erling Smørgrav } addr; 571b7579f77SDag-Erling Smørgrav struct ip_list* ip; 572b7579f77SDag-Erling Smørgrav uint16_t p = (uint16_t)port; 573*ebc5657fSDag-Erling Smørgrav memset(&addr, 0, sizeof(addr)); 574b7579f77SDag-Erling Smørgrav 575*ebc5657fSDag-Erling Smørgrav if(inet_pton(AF_INET6, str, &addr.a6.sin6_addr) > 0) { 576b7579f77SDag-Erling Smørgrav /* it is an IPv6 */ 577*ebc5657fSDag-Erling Smørgrav addr.a6.sin6_family = AF_INET6; 578*ebc5657fSDag-Erling Smørgrav addr.a6.sin6_port = (in_port_t)htons(p); 579*ebc5657fSDag-Erling Smørgrav len = (socklen_t)sizeof(addr.a6); 580b7579f77SDag-Erling Smørgrav } 581*ebc5657fSDag-Erling Smørgrav if(inet_pton(AF_INET, str, &addr.a.sin_addr) > 0) { 582b7579f77SDag-Erling Smørgrav /* it is an IPv4 */ 583*ebc5657fSDag-Erling Smørgrav addr.a.sin_family = AF_INET; 584*ebc5657fSDag-Erling Smørgrav addr.a.sin_port = (in_port_t)htons(p); 585b7579f77SDag-Erling Smørgrav len = (socklen_t)sizeof(struct sockaddr_in); 586b7579f77SDag-Erling Smørgrav } 587b7579f77SDag-Erling Smørgrav if(!len) return NULL; 588b7579f77SDag-Erling Smørgrav ip = (struct ip_list*)calloc(1, sizeof(*ip)); 589b7579f77SDag-Erling Smørgrav if(!ip) { 590b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 591b7579f77SDag-Erling Smørgrav exit(0); 592b7579f77SDag-Erling Smørgrav } 593b7579f77SDag-Erling Smørgrav ip->len = len; 594*ebc5657fSDag-Erling Smørgrav memmove(&ip->addr, &addr, len); 595b7579f77SDag-Erling Smørgrav if(verb) printf("server address is %s\n", str); 596b7579f77SDag-Erling Smørgrav return ip; 597b7579f77SDag-Erling Smørgrav } 598b7579f77SDag-Erling Smørgrav 599b7579f77SDag-Erling Smørgrav /** 600b7579f77SDag-Erling Smørgrav * Resolve a domain name (even though the resolver is down and there is 601b7579f77SDag-Erling Smørgrav * no trust anchor). Without DNSSEC validation. 602b7579f77SDag-Erling Smørgrav * @param host: the name to resolve. 603b7579f77SDag-Erling Smørgrav * If this name is an IP4 or IP6 address this address is returned. 604b7579f77SDag-Erling Smørgrav * @param port: the port number used for the returned IP structs. 605b7579f77SDag-Erling Smørgrav * @param res_conf: resolv.conf (if any). 606b7579f77SDag-Erling Smørgrav * @param root_hints: root hints (if any). 607b7579f77SDag-Erling Smørgrav * @param debugconf: unbound.conf for debugging options. 608b7579f77SDag-Erling Smørgrav * @param ip4only: use only ip4 for resolve and only lookup A 609b7579f77SDag-Erling Smørgrav * @param ip6only: use only ip6 for resolve and only lookup AAAA 610b7579f77SDag-Erling Smørgrav * default is to lookup A and AAAA using ip4 and ip6. 611b7579f77SDag-Erling Smørgrav * @return list of IP addresses. 612b7579f77SDag-Erling Smørgrav */ 613b7579f77SDag-Erling Smørgrav static struct ip_list* 614*ebc5657fSDag-Erling Smørgrav resolve_name(const char* host, int port, const char* res_conf, 615*ebc5657fSDag-Erling Smørgrav const char* root_hints, const char* debugconf, int ip4only, int ip6only) 616b7579f77SDag-Erling Smørgrav { 617b7579f77SDag-Erling Smørgrav struct ub_ctx* ctx; 618b7579f77SDag-Erling Smørgrav struct ip_list* list = NULL; 619b7579f77SDag-Erling Smørgrav /* first see if name is an IP address itself */ 620b7579f77SDag-Erling Smørgrav if( (list=parse_ip_addr(host, port)) ) { 621b7579f77SDag-Erling Smørgrav return list; 622b7579f77SDag-Erling Smørgrav } 623b7579f77SDag-Erling Smørgrav 624b7579f77SDag-Erling Smørgrav /* create resolver context */ 625b7579f77SDag-Erling Smørgrav ctx = create_unbound_context(res_conf, root_hints, debugconf, 626b7579f77SDag-Erling Smørgrav ip4only, ip6only); 627b7579f77SDag-Erling Smørgrav 628b7579f77SDag-Erling Smørgrav /* try resolution of A */ 629b7579f77SDag-Erling Smørgrav if(!ip6only) { 630b7579f77SDag-Erling Smørgrav resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_A, 631b7579f77SDag-Erling Smørgrav LDNS_RR_CLASS_IN, &list); 632b7579f77SDag-Erling Smørgrav } 633b7579f77SDag-Erling Smørgrav 634b7579f77SDag-Erling Smørgrav /* try resolution of AAAA */ 635b7579f77SDag-Erling Smørgrav if(!ip4only) { 636b7579f77SDag-Erling Smørgrav resolve_host_ip(ctx, host, port, LDNS_RR_TYPE_AAAA, 637b7579f77SDag-Erling Smørgrav LDNS_RR_CLASS_IN, &list); 638b7579f77SDag-Erling Smørgrav } 639b7579f77SDag-Erling Smørgrav 640b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 641b7579f77SDag-Erling Smørgrav if(!list) { 642b7579f77SDag-Erling Smørgrav if(verb) printf("%s has no IP addresses I can use\n", host); 643b7579f77SDag-Erling Smørgrav exit(0); 644b7579f77SDag-Erling Smørgrav } 645b7579f77SDag-Erling Smørgrav return list; 646b7579f77SDag-Erling Smørgrav } 647b7579f77SDag-Erling Smørgrav 648b7579f77SDag-Erling Smørgrav /** clear used flags */ 649b7579f77SDag-Erling Smørgrav static void 650b7579f77SDag-Erling Smørgrav wipe_ip_usage(struct ip_list* p) 651b7579f77SDag-Erling Smørgrav { 652b7579f77SDag-Erling Smørgrav while(p) { 653b7579f77SDag-Erling Smørgrav p->used = 0; 654b7579f77SDag-Erling Smørgrav p = p->next; 655b7579f77SDag-Erling Smørgrav } 656b7579f77SDag-Erling Smørgrav } 657b7579f77SDag-Erling Smørgrav 658b7579f77SDag-Erling Smørgrav /** cound unused IPs */ 659b7579f77SDag-Erling Smørgrav static int 660b7579f77SDag-Erling Smørgrav count_unused(struct ip_list* p) 661b7579f77SDag-Erling Smørgrav { 662b7579f77SDag-Erling Smørgrav int num = 0; 663b7579f77SDag-Erling Smørgrav while(p) { 664b7579f77SDag-Erling Smørgrav if(!p->used) num++; 665b7579f77SDag-Erling Smørgrav p = p->next; 666b7579f77SDag-Erling Smørgrav } 667b7579f77SDag-Erling Smørgrav return num; 668b7579f77SDag-Erling Smørgrav } 669b7579f77SDag-Erling Smørgrav 670b7579f77SDag-Erling Smørgrav /** pick random unused element from IP list */ 671b7579f77SDag-Erling Smørgrav static struct ip_list* 672b7579f77SDag-Erling Smørgrav pick_random_ip(struct ip_list* list) 673b7579f77SDag-Erling Smørgrav { 674b7579f77SDag-Erling Smørgrav struct ip_list* p = list; 675b7579f77SDag-Erling Smørgrav int num = count_unused(list); 676b7579f77SDag-Erling Smørgrav int sel; 677b7579f77SDag-Erling Smørgrav if(num == 0) return NULL; 678b7579f77SDag-Erling Smørgrav /* not perfect, but random enough */ 679b7579f77SDag-Erling Smørgrav sel = (int)ldns_get_random() % num; 680b7579f77SDag-Erling Smørgrav /* skip over unused elements that we did not select */ 681b7579f77SDag-Erling Smørgrav while(sel > 0 && p) { 682b7579f77SDag-Erling Smørgrav if(!p->used) sel--; 683b7579f77SDag-Erling Smørgrav p = p->next; 684b7579f77SDag-Erling Smørgrav } 685b7579f77SDag-Erling Smørgrav /* find the next unused element */ 686b7579f77SDag-Erling Smørgrav while(p && p->used) 687b7579f77SDag-Erling Smørgrav p = p->next; 688b7579f77SDag-Erling Smørgrav if(!p) return NULL; /* robustness */ 689b7579f77SDag-Erling Smørgrav return p; 690b7579f77SDag-Erling Smørgrav } 691b7579f77SDag-Erling Smørgrav 692b7579f77SDag-Erling Smørgrav /** close the fd */ 693b7579f77SDag-Erling Smørgrav static void 694b7579f77SDag-Erling Smørgrav fd_close(int fd) 695b7579f77SDag-Erling Smørgrav { 696b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 697b7579f77SDag-Erling Smørgrav close(fd); 698b7579f77SDag-Erling Smørgrav #else 699b7579f77SDag-Erling Smørgrav closesocket(fd); 700b7579f77SDag-Erling Smørgrav #endif 701b7579f77SDag-Erling Smørgrav } 702b7579f77SDag-Erling Smørgrav 703b7579f77SDag-Erling Smørgrav /** printout socket errno */ 704b7579f77SDag-Erling Smørgrav static void 705b7579f77SDag-Erling Smørgrav print_sock_err(const char* msg) 706b7579f77SDag-Erling Smørgrav { 707b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 708b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", msg, strerror(errno)); 709b7579f77SDag-Erling Smørgrav #else 710b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", msg, wsa_strerror(WSAGetLastError())); 711b7579f77SDag-Erling Smørgrav #endif 712b7579f77SDag-Erling Smørgrav } 713b7579f77SDag-Erling Smørgrav 714b7579f77SDag-Erling Smørgrav /** connect to IP address */ 715b7579f77SDag-Erling Smørgrav static int 716b7579f77SDag-Erling Smørgrav connect_to_ip(struct ip_list* ip) 717b7579f77SDag-Erling Smørgrav { 718b7579f77SDag-Erling Smørgrav int fd; 719b7579f77SDag-Erling Smørgrav verb_addr("connect to", ip); 720b7579f77SDag-Erling Smørgrav fd = socket(ip->len==(socklen_t)sizeof(struct sockaddr_in)? 721b7579f77SDag-Erling Smørgrav AF_INET:AF_INET6, SOCK_STREAM, 0); 722b7579f77SDag-Erling Smørgrav if(fd == -1) { 723b7579f77SDag-Erling Smørgrav print_sock_err("socket"); 724b7579f77SDag-Erling Smørgrav return -1; 725b7579f77SDag-Erling Smørgrav } 726b7579f77SDag-Erling Smørgrav if(connect(fd, (struct sockaddr*)&ip->addr, ip->len) < 0) { 727b7579f77SDag-Erling Smørgrav print_sock_err("connect"); 728b7579f77SDag-Erling Smørgrav fd_close(fd); 729b7579f77SDag-Erling Smørgrav return -1; 730b7579f77SDag-Erling Smørgrav } 731b7579f77SDag-Erling Smørgrav return fd; 732b7579f77SDag-Erling Smørgrav } 733b7579f77SDag-Erling Smørgrav 734b7579f77SDag-Erling Smørgrav /** create SSL context */ 735b7579f77SDag-Erling Smørgrav static SSL_CTX* 736b7579f77SDag-Erling Smørgrav setup_sslctx(void) 737b7579f77SDag-Erling Smørgrav { 738b7579f77SDag-Erling Smørgrav SSL_CTX* sslctx = SSL_CTX_new(SSLv23_client_method()); 739b7579f77SDag-Erling Smørgrav if(!sslctx) { 740b7579f77SDag-Erling Smørgrav if(verb) printf("SSL_CTX_new error\n"); 741b7579f77SDag-Erling Smørgrav return NULL; 742b7579f77SDag-Erling Smørgrav } 743b7579f77SDag-Erling Smørgrav return sslctx; 744b7579f77SDag-Erling Smørgrav } 745b7579f77SDag-Erling Smørgrav 746b7579f77SDag-Erling Smørgrav /** initiate TLS on a connection */ 747b7579f77SDag-Erling Smørgrav static SSL* 748b7579f77SDag-Erling Smørgrav TLS_initiate(SSL_CTX* sslctx, int fd) 749b7579f77SDag-Erling Smørgrav { 750b7579f77SDag-Erling Smørgrav X509* x; 751b7579f77SDag-Erling Smørgrav int r; 752b7579f77SDag-Erling Smørgrav SSL* ssl = SSL_new(sslctx); 753b7579f77SDag-Erling Smørgrav if(!ssl) { 754b7579f77SDag-Erling Smørgrav if(verb) printf("SSL_new error\n"); 755b7579f77SDag-Erling Smørgrav return NULL; 756b7579f77SDag-Erling Smørgrav } 757b7579f77SDag-Erling Smørgrav SSL_set_connect_state(ssl); 758b7579f77SDag-Erling Smørgrav (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); 759b7579f77SDag-Erling Smørgrav if(!SSL_set_fd(ssl, fd)) { 760b7579f77SDag-Erling Smørgrav if(verb) printf("SSL_set_fd error\n"); 761b7579f77SDag-Erling Smørgrav SSL_free(ssl); 762b7579f77SDag-Erling Smørgrav return NULL; 763b7579f77SDag-Erling Smørgrav } 764b7579f77SDag-Erling Smørgrav while(1) { 765b7579f77SDag-Erling Smørgrav ERR_clear_error(); 766b7579f77SDag-Erling Smørgrav if( (r=SSL_do_handshake(ssl)) == 1) 767b7579f77SDag-Erling Smørgrav break; 768b7579f77SDag-Erling Smørgrav r = SSL_get_error(ssl, r); 769b7579f77SDag-Erling Smørgrav if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) { 770b7579f77SDag-Erling Smørgrav if(verb) printf("SSL handshake failed\n"); 771b7579f77SDag-Erling Smørgrav SSL_free(ssl); 772b7579f77SDag-Erling Smørgrav return NULL; 773b7579f77SDag-Erling Smørgrav } 774b7579f77SDag-Erling Smørgrav /* wants to be called again */ 775b7579f77SDag-Erling Smørgrav } 776b7579f77SDag-Erling Smørgrav x = SSL_get_peer_certificate(ssl); 777b7579f77SDag-Erling Smørgrav if(!x) { 778b7579f77SDag-Erling Smørgrav if(verb) printf("Server presented no peer certificate\n"); 779b7579f77SDag-Erling Smørgrav SSL_free(ssl); 780b7579f77SDag-Erling Smørgrav return NULL; 781b7579f77SDag-Erling Smørgrav } 782b7579f77SDag-Erling Smørgrav verb_cert("server SSL certificate", x); 783b7579f77SDag-Erling Smørgrav X509_free(x); 784b7579f77SDag-Erling Smørgrav return ssl; 785b7579f77SDag-Erling Smørgrav } 786b7579f77SDag-Erling Smørgrav 787b7579f77SDag-Erling Smørgrav /** perform neat TLS shutdown */ 788b7579f77SDag-Erling Smørgrav static void 789b7579f77SDag-Erling Smørgrav TLS_shutdown(int fd, SSL* ssl, SSL_CTX* sslctx) 790b7579f77SDag-Erling Smørgrav { 791b7579f77SDag-Erling Smørgrav /* shutdown the SSL connection nicely */ 792b7579f77SDag-Erling Smørgrav if(SSL_shutdown(ssl) == 0) { 793b7579f77SDag-Erling Smørgrav SSL_shutdown(ssl); 794b7579f77SDag-Erling Smørgrav } 795b7579f77SDag-Erling Smørgrav SSL_free(ssl); 796b7579f77SDag-Erling Smørgrav SSL_CTX_free(sslctx); 797b7579f77SDag-Erling Smørgrav fd_close(fd); 798b7579f77SDag-Erling Smørgrav } 799b7579f77SDag-Erling Smørgrav 800b7579f77SDag-Erling Smørgrav /** write a line over SSL */ 801b7579f77SDag-Erling Smørgrav static int 802*ebc5657fSDag-Erling Smørgrav write_ssl_line(SSL* ssl, const char* str, const char* sec) 803b7579f77SDag-Erling Smørgrav { 804b7579f77SDag-Erling Smørgrav char buf[1024]; 805b7579f77SDag-Erling Smørgrav size_t l; 806b7579f77SDag-Erling Smørgrav if(sec) { 807b7579f77SDag-Erling Smørgrav snprintf(buf, sizeof(buf), str, sec); 808b7579f77SDag-Erling Smørgrav } else { 809b7579f77SDag-Erling Smørgrav snprintf(buf, sizeof(buf), "%s", str); 810b7579f77SDag-Erling Smørgrav } 811b7579f77SDag-Erling Smørgrav l = strlen(buf); 812b7579f77SDag-Erling Smørgrav if(l+2 >= sizeof(buf)) { 813b7579f77SDag-Erling Smørgrav if(verb) printf("line too long\n"); 814b7579f77SDag-Erling Smørgrav return 0; 815b7579f77SDag-Erling Smørgrav } 816b7579f77SDag-Erling Smørgrav if(verb >= 2) printf("SSL_write: %s\n", buf); 817b7579f77SDag-Erling Smørgrav buf[l] = '\r'; 818b7579f77SDag-Erling Smørgrav buf[l+1] = '\n'; 819b7579f77SDag-Erling Smørgrav buf[l+2] = 0; 820b7579f77SDag-Erling Smørgrav /* add \r\n */ 821b7579f77SDag-Erling Smørgrav if(SSL_write(ssl, buf, (int)strlen(buf)) <= 0) { 822b7579f77SDag-Erling Smørgrav if(verb) printf("could not SSL_write %s", str); 823b7579f77SDag-Erling Smørgrav return 0; 824b7579f77SDag-Erling Smørgrav } 825b7579f77SDag-Erling Smørgrav return 1; 826b7579f77SDag-Erling Smørgrav } 827b7579f77SDag-Erling Smørgrav 828b7579f77SDag-Erling Smørgrav /** process header line, check rcode and keeping track of size */ 829b7579f77SDag-Erling Smørgrav static int 830b7579f77SDag-Erling Smørgrav process_one_header(char* buf, size_t* clen, int* chunked) 831b7579f77SDag-Erling Smørgrav { 832b7579f77SDag-Erling Smørgrav if(verb>=2) printf("header: '%s'\n", buf); 833b7579f77SDag-Erling Smørgrav if(strncasecmp(buf, "HTTP/1.1 ", 9) == 0) { 834b7579f77SDag-Erling Smørgrav /* check returncode */ 835b7579f77SDag-Erling Smørgrav if(buf[9] != '2') { 836b7579f77SDag-Erling Smørgrav if(verb) printf("bad status %s\n", buf+9); 837b7579f77SDag-Erling Smørgrav return 0; 838b7579f77SDag-Erling Smørgrav } 839b7579f77SDag-Erling Smørgrav } else if(strncasecmp(buf, "Content-Length: ", 16) == 0) { 840b7579f77SDag-Erling Smørgrav if(!*chunked) 841b7579f77SDag-Erling Smørgrav *clen = (size_t)atoi(buf+16); 842b7579f77SDag-Erling Smørgrav } else if(strncasecmp(buf, "Transfer-Encoding: chunked", 19+7) == 0) { 843b7579f77SDag-Erling Smørgrav *clen = 0; 844b7579f77SDag-Erling Smørgrav *chunked = 1; 845b7579f77SDag-Erling Smørgrav } 846b7579f77SDag-Erling Smørgrav return 1; 847b7579f77SDag-Erling Smørgrav } 848b7579f77SDag-Erling Smørgrav 849b7579f77SDag-Erling Smørgrav /** 850b7579f77SDag-Erling Smørgrav * Read one line from SSL 851b7579f77SDag-Erling Smørgrav * zero terminates. 852b7579f77SDag-Erling Smørgrav * skips "\r\n" (but not copied to buf). 853b7579f77SDag-Erling Smørgrav * @param ssl: the SSL connection to read from (blocking). 854b7579f77SDag-Erling Smørgrav * @param buf: buffer to return line in. 855b7579f77SDag-Erling Smørgrav * @param len: size of the buffer. 856b7579f77SDag-Erling Smørgrav * @return 0 on error, 1 on success. 857b7579f77SDag-Erling Smørgrav */ 858b7579f77SDag-Erling Smørgrav static int 859b7579f77SDag-Erling Smørgrav read_ssl_line(SSL* ssl, char* buf, size_t len) 860b7579f77SDag-Erling Smørgrav { 861b7579f77SDag-Erling Smørgrav size_t n = 0; 862b7579f77SDag-Erling Smørgrav int r; 863b7579f77SDag-Erling Smørgrav int endnl = 0; 864b7579f77SDag-Erling Smørgrav while(1) { 865b7579f77SDag-Erling Smørgrav if(n >= len) { 866b7579f77SDag-Erling Smørgrav if(verb) printf("line too long\n"); 867b7579f77SDag-Erling Smørgrav return 0; 868b7579f77SDag-Erling Smørgrav } 869b7579f77SDag-Erling Smørgrav if((r = SSL_read(ssl, buf+n, 1)) <= 0) { 870b7579f77SDag-Erling Smørgrav if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 871b7579f77SDag-Erling Smørgrav /* EOF */ 872b7579f77SDag-Erling Smørgrav break; 873b7579f77SDag-Erling Smørgrav } 874b7579f77SDag-Erling Smørgrav if(verb) printf("could not SSL_read\n"); 875b7579f77SDag-Erling Smørgrav return 0; 876b7579f77SDag-Erling Smørgrav } 877b7579f77SDag-Erling Smørgrav if(endnl && buf[n] == '\n') { 878b7579f77SDag-Erling Smørgrav break; 879b7579f77SDag-Erling Smørgrav } else if(endnl) { 880b7579f77SDag-Erling Smørgrav /* bad data */ 881b7579f77SDag-Erling Smørgrav if(verb) printf("error: stray linefeeds\n"); 882b7579f77SDag-Erling Smørgrav return 0; 883b7579f77SDag-Erling Smørgrav } else if(buf[n] == '\r') { 884b7579f77SDag-Erling Smørgrav /* skip \r, and also \n on the wire */ 885b7579f77SDag-Erling Smørgrav endnl = 1; 886b7579f77SDag-Erling Smørgrav continue; 887b7579f77SDag-Erling Smørgrav } else if(buf[n] == '\n') { 888b7579f77SDag-Erling Smørgrav /* skip the \n, we are done */ 889b7579f77SDag-Erling Smørgrav break; 890b7579f77SDag-Erling Smørgrav } else n++; 891b7579f77SDag-Erling Smørgrav } 892b7579f77SDag-Erling Smørgrav buf[n] = 0; 893b7579f77SDag-Erling Smørgrav return 1; 894b7579f77SDag-Erling Smørgrav } 895b7579f77SDag-Erling Smørgrav 896b7579f77SDag-Erling Smørgrav /** read http headers and process them */ 897b7579f77SDag-Erling Smørgrav static size_t 898b7579f77SDag-Erling Smørgrav read_http_headers(SSL* ssl, size_t* clen) 899b7579f77SDag-Erling Smørgrav { 900b7579f77SDag-Erling Smørgrav char buf[1024]; 901b7579f77SDag-Erling Smørgrav int chunked = 0; 902b7579f77SDag-Erling Smørgrav *clen = 0; 903b7579f77SDag-Erling Smørgrav while(read_ssl_line(ssl, buf, sizeof(buf))) { 904b7579f77SDag-Erling Smørgrav if(buf[0] == 0) 905b7579f77SDag-Erling Smørgrav return 1; 906b7579f77SDag-Erling Smørgrav if(!process_one_header(buf, clen, &chunked)) 907b7579f77SDag-Erling Smørgrav return 0; 908b7579f77SDag-Erling Smørgrav } 909b7579f77SDag-Erling Smørgrav return 0; 910b7579f77SDag-Erling Smørgrav } 911b7579f77SDag-Erling Smørgrav 912b7579f77SDag-Erling Smørgrav /** read a data chunk */ 913b7579f77SDag-Erling Smørgrav static char* 914b7579f77SDag-Erling Smørgrav read_data_chunk(SSL* ssl, size_t len) 915b7579f77SDag-Erling Smørgrav { 916b7579f77SDag-Erling Smørgrav size_t got = 0; 917b7579f77SDag-Erling Smørgrav int r; 918b7579f77SDag-Erling Smørgrav char* data = malloc(len+1); 919b7579f77SDag-Erling Smørgrav if(!data) { 920b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 921b7579f77SDag-Erling Smørgrav return NULL; 922b7579f77SDag-Erling Smørgrav } 923b7579f77SDag-Erling Smørgrav while(got < len) { 924b7579f77SDag-Erling Smørgrav if((r = SSL_read(ssl, data+got, (int)(len-got))) <= 0) { 925b7579f77SDag-Erling Smørgrav if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { 926b7579f77SDag-Erling Smørgrav /* EOF */ 927b7579f77SDag-Erling Smørgrav if(verb) printf("could not SSL_read: unexpected EOF\n"); 928b7579f77SDag-Erling Smørgrav free(data); 929b7579f77SDag-Erling Smørgrav return NULL; 930b7579f77SDag-Erling Smørgrav } 931b7579f77SDag-Erling Smørgrav if(verb) printf("could not SSL_read\n"); 932b7579f77SDag-Erling Smørgrav free(data); 933b7579f77SDag-Erling Smørgrav return NULL; 934b7579f77SDag-Erling Smørgrav } 935b7579f77SDag-Erling Smørgrav if(verb >= 2) printf("at %d/%d\n", (int)got, (int)len); 936b7579f77SDag-Erling Smørgrav got += r; 937b7579f77SDag-Erling Smørgrav } 938b7579f77SDag-Erling Smørgrav if(verb>=2) printf("read %d data\n", (int)len); 939b7579f77SDag-Erling Smørgrav data[len] = 0; 940b7579f77SDag-Erling Smørgrav return data; 941b7579f77SDag-Erling Smørgrav } 942b7579f77SDag-Erling Smørgrav 943b7579f77SDag-Erling Smørgrav /** parse chunk header */ 944b7579f77SDag-Erling Smørgrav static int 945b7579f77SDag-Erling Smørgrav parse_chunk_header(char* buf, size_t* result) 946b7579f77SDag-Erling Smørgrav { 947b7579f77SDag-Erling Smørgrav char* e = NULL; 948b7579f77SDag-Erling Smørgrav size_t v = (size_t)strtol(buf, &e, 16); 949b7579f77SDag-Erling Smørgrav if(e == buf) 950b7579f77SDag-Erling Smørgrav return 0; 951b7579f77SDag-Erling Smørgrav *result = v; 952b7579f77SDag-Erling Smørgrav return 1; 953b7579f77SDag-Erling Smørgrav } 954b7579f77SDag-Erling Smørgrav 955b7579f77SDag-Erling Smørgrav /** read chunked data from connection */ 956b7579f77SDag-Erling Smørgrav static BIO* 957b7579f77SDag-Erling Smørgrav do_chunked_read(SSL* ssl) 958b7579f77SDag-Erling Smørgrav { 959b7579f77SDag-Erling Smørgrav char buf[1024]; 960b7579f77SDag-Erling Smørgrav size_t len; 961b7579f77SDag-Erling Smørgrav char* body; 962b7579f77SDag-Erling Smørgrav BIO* mem = BIO_new(BIO_s_mem()); 963b7579f77SDag-Erling Smørgrav if(verb>=3) printf("do_chunked_read\n"); 964b7579f77SDag-Erling Smørgrav if(!mem) { 965b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 966b7579f77SDag-Erling Smørgrav return NULL; 967b7579f77SDag-Erling Smørgrav } 968b7579f77SDag-Erling Smørgrav while(read_ssl_line(ssl, buf, sizeof(buf))) { 969b7579f77SDag-Erling Smørgrav /* read the chunked start line */ 970b7579f77SDag-Erling Smørgrav if(verb>=2) printf("chunk header: %s\n", buf); 971b7579f77SDag-Erling Smørgrav if(!parse_chunk_header(buf, &len)) { 972b7579f77SDag-Erling Smørgrav BIO_free(mem); 973b7579f77SDag-Erling Smørgrav if(verb>=3) printf("could not parse chunk header\n"); 974b7579f77SDag-Erling Smørgrav return NULL; 975b7579f77SDag-Erling Smørgrav } 976b7579f77SDag-Erling Smørgrav if(verb>=2) printf("chunk len: %d\n", (int)len); 977b7579f77SDag-Erling Smørgrav /* are we done? */ 978b7579f77SDag-Erling Smørgrav if(len == 0) { 979b7579f77SDag-Erling Smørgrav char z = 0; 980b7579f77SDag-Erling Smørgrav /* skip end-of-chunk-trailer lines, 981b7579f77SDag-Erling Smørgrav * until the empty line after that */ 982b7579f77SDag-Erling Smørgrav do { 983b7579f77SDag-Erling Smørgrav if(!read_ssl_line(ssl, buf, sizeof(buf))) { 984b7579f77SDag-Erling Smørgrav BIO_free(mem); 985b7579f77SDag-Erling Smørgrav return NULL; 986b7579f77SDag-Erling Smørgrav } 987b7579f77SDag-Erling Smørgrav } while (strlen(buf) > 0); 988b7579f77SDag-Erling Smørgrav /* end of chunks, zero terminate it */ 989b7579f77SDag-Erling Smørgrav if(BIO_write(mem, &z, 1) <= 0) { 990b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 991b7579f77SDag-Erling Smørgrav BIO_free(mem); 992b7579f77SDag-Erling Smørgrav return NULL; 993b7579f77SDag-Erling Smørgrav } 994b7579f77SDag-Erling Smørgrav return mem; 995b7579f77SDag-Erling Smørgrav } 996b7579f77SDag-Erling Smørgrav /* read the chunked body */ 997b7579f77SDag-Erling Smørgrav body = read_data_chunk(ssl, len); 998b7579f77SDag-Erling Smørgrav if(!body) { 999b7579f77SDag-Erling Smørgrav BIO_free(mem); 1000b7579f77SDag-Erling Smørgrav return NULL; 1001b7579f77SDag-Erling Smørgrav } 1002b7579f77SDag-Erling Smørgrav if(BIO_write(mem, body, (int)len) <= 0) { 1003b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1004b7579f77SDag-Erling Smørgrav free(body); 1005b7579f77SDag-Erling Smørgrav BIO_free(mem); 1006b7579f77SDag-Erling Smørgrav return NULL; 1007b7579f77SDag-Erling Smørgrav } 1008b7579f77SDag-Erling Smørgrav free(body); 1009b7579f77SDag-Erling Smørgrav /* skip empty line after data chunk */ 1010b7579f77SDag-Erling Smørgrav if(!read_ssl_line(ssl, buf, sizeof(buf))) { 1011b7579f77SDag-Erling Smørgrav BIO_free(mem); 1012b7579f77SDag-Erling Smørgrav return NULL; 1013b7579f77SDag-Erling Smørgrav } 1014b7579f77SDag-Erling Smørgrav } 1015b7579f77SDag-Erling Smørgrav BIO_free(mem); 1016b7579f77SDag-Erling Smørgrav return NULL; 1017b7579f77SDag-Erling Smørgrav } 1018b7579f77SDag-Erling Smørgrav 1019b7579f77SDag-Erling Smørgrav /** start HTTP1.1 transaction on SSL */ 1020b7579f77SDag-Erling Smørgrav static int 1021*ebc5657fSDag-Erling Smørgrav write_http_get(SSL* ssl, const char* pathname, const char* urlname) 1022b7579f77SDag-Erling Smørgrav { 1023b7579f77SDag-Erling Smørgrav if(write_ssl_line(ssl, "GET /%s HTTP/1.1", pathname) && 1024b7579f77SDag-Erling Smørgrav write_ssl_line(ssl, "Host: %s", urlname) && 1025b7579f77SDag-Erling Smørgrav write_ssl_line(ssl, "User-Agent: unbound-anchor/%s", 1026b7579f77SDag-Erling Smørgrav PACKAGE_VERSION) && 1027b7579f77SDag-Erling Smørgrav /* We do not really do multiple queries per connection, 1028b7579f77SDag-Erling Smørgrav * but this header setting is also not needed. 1029b7579f77SDag-Erling Smørgrav * write_ssl_line(ssl, "Connection: close", NULL) &&*/ 1030b7579f77SDag-Erling Smørgrav write_ssl_line(ssl, "", NULL)) { 1031b7579f77SDag-Erling Smørgrav return 1; 1032b7579f77SDag-Erling Smørgrav } 1033b7579f77SDag-Erling Smørgrav return 0; 1034b7579f77SDag-Erling Smørgrav } 1035b7579f77SDag-Erling Smørgrav 1036b7579f77SDag-Erling Smørgrav /** read chunked data and zero terminate; len is without zero */ 1037b7579f77SDag-Erling Smørgrav static char* 1038b7579f77SDag-Erling Smørgrav read_chunked_zero_terminate(SSL* ssl, size_t* len) 1039b7579f77SDag-Erling Smørgrav { 1040b7579f77SDag-Erling Smørgrav /* do the chunked version */ 1041b7579f77SDag-Erling Smørgrav BIO* tmp = do_chunked_read(ssl); 1042b7579f77SDag-Erling Smørgrav char* data, *d = NULL; 1043b7579f77SDag-Erling Smørgrav size_t l; 1044b7579f77SDag-Erling Smørgrav if(!tmp) { 1045b7579f77SDag-Erling Smørgrav if(verb) printf("could not read from https\n"); 1046b7579f77SDag-Erling Smørgrav return NULL; 1047b7579f77SDag-Erling Smørgrav } 1048b7579f77SDag-Erling Smørgrav l = (size_t)BIO_get_mem_data(tmp, &d); 1049b7579f77SDag-Erling Smørgrav if(verb>=2) printf("chunked data is %d\n", (int)l); 1050b7579f77SDag-Erling Smørgrav if(l == 0 || d == NULL) { 1051b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1052b7579f77SDag-Erling Smørgrav return NULL; 1053b7579f77SDag-Erling Smørgrav } 1054b7579f77SDag-Erling Smørgrav *len = l-1; 1055b7579f77SDag-Erling Smørgrav data = (char*)malloc(l); 1056b7579f77SDag-Erling Smørgrav if(data == NULL) { 1057b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1058b7579f77SDag-Erling Smørgrav return NULL; 1059b7579f77SDag-Erling Smørgrav } 1060b7579f77SDag-Erling Smørgrav memcpy(data, d, l); 1061b7579f77SDag-Erling Smørgrav BIO_free(tmp); 1062b7579f77SDag-Erling Smørgrav return data; 1063b7579f77SDag-Erling Smørgrav } 1064b7579f77SDag-Erling Smørgrav 1065b7579f77SDag-Erling Smørgrav /** read HTTP result from SSL */ 1066b7579f77SDag-Erling Smørgrav static BIO* 1067b7579f77SDag-Erling Smørgrav read_http_result(SSL* ssl) 1068b7579f77SDag-Erling Smørgrav { 1069b7579f77SDag-Erling Smørgrav size_t len = 0; 1070b7579f77SDag-Erling Smørgrav char* data; 1071b7579f77SDag-Erling Smørgrav BIO* m; 1072b7579f77SDag-Erling Smørgrav if(!read_http_headers(ssl, &len)) { 1073b7579f77SDag-Erling Smørgrav return NULL; 1074b7579f77SDag-Erling Smørgrav } 1075b7579f77SDag-Erling Smørgrav if(len == 0) { 1076b7579f77SDag-Erling Smørgrav data = read_chunked_zero_terminate(ssl, &len); 1077b7579f77SDag-Erling Smørgrav } else { 1078b7579f77SDag-Erling Smørgrav data = read_data_chunk(ssl, len); 1079b7579f77SDag-Erling Smørgrav } 1080b7579f77SDag-Erling Smørgrav if(!data) return NULL; 1081b7579f77SDag-Erling Smørgrav if(verb >= 4) print_data("read data", data, (int)len); 1082b7579f77SDag-Erling Smørgrav m = BIO_new_mem_buf(data, (int)len); 1083b7579f77SDag-Erling Smørgrav if(!m) { 1084b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1085b7579f77SDag-Erling Smørgrav exit(0); 1086b7579f77SDag-Erling Smørgrav } 1087b7579f77SDag-Erling Smørgrav return m; 1088b7579f77SDag-Erling Smørgrav } 1089b7579f77SDag-Erling Smørgrav 1090b7579f77SDag-Erling Smørgrav /** https to an IP addr, return BIO with pathname or NULL */ 1091b7579f77SDag-Erling Smørgrav static BIO* 1092*ebc5657fSDag-Erling Smørgrav https_to_ip(struct ip_list* ip, const char* pathname, const char* urlname) 1093b7579f77SDag-Erling Smørgrav { 1094b7579f77SDag-Erling Smørgrav int fd; 1095b7579f77SDag-Erling Smørgrav SSL* ssl; 1096b7579f77SDag-Erling Smørgrav BIO* bio; 1097b7579f77SDag-Erling Smørgrav SSL_CTX* sslctx = setup_sslctx(); 1098b7579f77SDag-Erling Smørgrav if(!sslctx) { 1099b7579f77SDag-Erling Smørgrav return NULL; 1100b7579f77SDag-Erling Smørgrav } 1101b7579f77SDag-Erling Smørgrav fd = connect_to_ip(ip); 1102b7579f77SDag-Erling Smørgrav if(fd == -1) { 1103b7579f77SDag-Erling Smørgrav SSL_CTX_free(sslctx); 1104b7579f77SDag-Erling Smørgrav return NULL; 1105b7579f77SDag-Erling Smørgrav } 1106b7579f77SDag-Erling Smørgrav ssl = TLS_initiate(sslctx, fd); 1107b7579f77SDag-Erling Smørgrav if(!ssl) { 1108b7579f77SDag-Erling Smørgrav SSL_CTX_free(sslctx); 1109b7579f77SDag-Erling Smørgrav fd_close(fd); 1110b7579f77SDag-Erling Smørgrav return NULL; 1111b7579f77SDag-Erling Smørgrav } 1112b7579f77SDag-Erling Smørgrav if(!write_http_get(ssl, pathname, urlname)) { 1113b7579f77SDag-Erling Smørgrav if(verb) printf("could not write to server\n"); 1114b7579f77SDag-Erling Smørgrav SSL_free(ssl); 1115b7579f77SDag-Erling Smørgrav SSL_CTX_free(sslctx); 1116b7579f77SDag-Erling Smørgrav fd_close(fd); 1117b7579f77SDag-Erling Smørgrav return NULL; 1118b7579f77SDag-Erling Smørgrav } 1119b7579f77SDag-Erling Smørgrav bio = read_http_result(ssl); 1120b7579f77SDag-Erling Smørgrav TLS_shutdown(fd, ssl, sslctx); 1121b7579f77SDag-Erling Smørgrav return bio; 1122b7579f77SDag-Erling Smørgrav } 1123b7579f77SDag-Erling Smørgrav 1124b7579f77SDag-Erling Smørgrav /** 1125b7579f77SDag-Erling Smørgrav * Do a HTTPS, HTTP1.1 over TLS, to fetch a file 1126b7579f77SDag-Erling Smørgrav * @param ip_list: list of IP addresses to use to fetch from. 1127b7579f77SDag-Erling Smørgrav * @param pathname: pathname of file on server to GET. 1128b7579f77SDag-Erling Smørgrav * @param urlname: name to pass as the virtual host for this request. 1129b7579f77SDag-Erling Smørgrav * @return a memory BIO with the file in it. 1130b7579f77SDag-Erling Smørgrav */ 1131b7579f77SDag-Erling Smørgrav static BIO* 1132*ebc5657fSDag-Erling Smørgrav https(struct ip_list* ip_list, const char* pathname, const char* urlname) 1133b7579f77SDag-Erling Smørgrav { 1134b7579f77SDag-Erling Smørgrav struct ip_list* ip; 1135b7579f77SDag-Erling Smørgrav BIO* bio = NULL; 1136b7579f77SDag-Erling Smørgrav /* try random address first, and work through the list */ 1137b7579f77SDag-Erling Smørgrav wipe_ip_usage(ip_list); 1138b7579f77SDag-Erling Smørgrav while( (ip = pick_random_ip(ip_list)) ) { 1139b7579f77SDag-Erling Smørgrav ip->used = 1; 1140b7579f77SDag-Erling Smørgrav bio = https_to_ip(ip, pathname, urlname); 1141b7579f77SDag-Erling Smørgrav if(bio) break; 1142b7579f77SDag-Erling Smørgrav } 1143b7579f77SDag-Erling Smørgrav if(!bio) { 1144b7579f77SDag-Erling Smørgrav if(verb) printf("could not fetch %s\n", pathname); 1145b7579f77SDag-Erling Smørgrav exit(0); 1146b7579f77SDag-Erling Smørgrav } else { 1147b7579f77SDag-Erling Smørgrav if(verb) printf("fetched %s (%d bytes)\n", 1148b7579f77SDag-Erling Smørgrav pathname, (int)BIO_ctrl_pending(bio)); 1149b7579f77SDag-Erling Smørgrav } 1150b7579f77SDag-Erling Smørgrav return bio; 1151b7579f77SDag-Erling Smørgrav } 1152b7579f77SDag-Erling Smørgrav 1153b7579f77SDag-Erling Smørgrav /** free up a downloaded file BIO */ 1154b7579f77SDag-Erling Smørgrav static void 1155b7579f77SDag-Erling Smørgrav free_file_bio(BIO* bio) 1156b7579f77SDag-Erling Smørgrav { 1157b7579f77SDag-Erling Smørgrav char* pp = NULL; 1158b7579f77SDag-Erling Smørgrav (void)BIO_reset(bio); 1159b7579f77SDag-Erling Smørgrav (void)BIO_get_mem_data(bio, &pp); 1160b7579f77SDag-Erling Smørgrav free(pp); 1161b7579f77SDag-Erling Smørgrav BIO_free(bio); 1162b7579f77SDag-Erling Smørgrav } 1163b7579f77SDag-Erling Smørgrav 1164b7579f77SDag-Erling Smørgrav /** XML parse private data during the parse */ 1165b7579f77SDag-Erling Smørgrav struct xml_data { 1166b7579f77SDag-Erling Smørgrav /** the parser, reference */ 1167b7579f77SDag-Erling Smørgrav XML_Parser parser; 1168b7579f77SDag-Erling Smørgrav /** the current tag; malloced; or NULL outside of tags */ 1169b7579f77SDag-Erling Smørgrav char* tag; 1170b7579f77SDag-Erling Smørgrav /** current date to use during the parse */ 1171b7579f77SDag-Erling Smørgrav time_t date; 1172b7579f77SDag-Erling Smørgrav /** number of keys usefully read in */ 1173b7579f77SDag-Erling Smørgrav int num_keys; 1174b7579f77SDag-Erling Smørgrav /** the compiled anchors as DS records */ 1175b7579f77SDag-Erling Smørgrav BIO* ds; 1176b7579f77SDag-Erling Smørgrav 1177b7579f77SDag-Erling Smørgrav /** do we want to use this anchor? */ 1178b7579f77SDag-Erling Smørgrav int use_key; 1179b7579f77SDag-Erling Smørgrav /** the current anchor: Zone */ 1180b7579f77SDag-Erling Smørgrav BIO* czone; 1181b7579f77SDag-Erling Smørgrav /** the current anchor: KeyTag */ 1182b7579f77SDag-Erling Smørgrav BIO* ctag; 1183b7579f77SDag-Erling Smørgrav /** the current anchor: Algorithm */ 1184b7579f77SDag-Erling Smørgrav BIO* calgo; 1185b7579f77SDag-Erling Smørgrav /** the current anchor: DigestType */ 1186b7579f77SDag-Erling Smørgrav BIO* cdigtype; 1187b7579f77SDag-Erling Smørgrav /** the current anchor: Digest*/ 1188b7579f77SDag-Erling Smørgrav BIO* cdigest; 1189b7579f77SDag-Erling Smørgrav }; 1190b7579f77SDag-Erling Smørgrav 1191b7579f77SDag-Erling Smørgrav /** The BIO for the tag */ 1192b7579f77SDag-Erling Smørgrav static BIO* 1193b7579f77SDag-Erling Smørgrav xml_selectbio(struct xml_data* data, const char* tag) 1194b7579f77SDag-Erling Smørgrav { 1195b7579f77SDag-Erling Smørgrav BIO* b = NULL; 1196b7579f77SDag-Erling Smørgrav if(strcasecmp(tag, "KeyTag") == 0) 1197b7579f77SDag-Erling Smørgrav b = data->ctag; 1198b7579f77SDag-Erling Smørgrav else if(strcasecmp(tag, "Algorithm") == 0) 1199b7579f77SDag-Erling Smørgrav b = data->calgo; 1200b7579f77SDag-Erling Smørgrav else if(strcasecmp(tag, "DigestType") == 0) 1201b7579f77SDag-Erling Smørgrav b = data->cdigtype; 1202b7579f77SDag-Erling Smørgrav else if(strcasecmp(tag, "Digest") == 0) 1203b7579f77SDag-Erling Smørgrav b = data->cdigest; 1204b7579f77SDag-Erling Smørgrav return b; 1205b7579f77SDag-Erling Smørgrav } 1206b7579f77SDag-Erling Smørgrav 1207b7579f77SDag-Erling Smørgrav /** 1208b7579f77SDag-Erling Smørgrav * XML handle character data, the data inside an element. 1209b7579f77SDag-Erling Smørgrav * @param userData: xml_data structure 1210b7579f77SDag-Erling Smørgrav * @param s: the character data. May not all be in one callback. 1211b7579f77SDag-Erling Smørgrav * NOT zero terminated. 1212b7579f77SDag-Erling Smørgrav * @param len: length of this part of the data. 1213b7579f77SDag-Erling Smørgrav */ 1214*ebc5657fSDag-Erling Smørgrav static void 1215b7579f77SDag-Erling Smørgrav xml_charhandle(void *userData, const XML_Char *s, int len) 1216b7579f77SDag-Erling Smørgrav { 1217b7579f77SDag-Erling Smørgrav struct xml_data* data = (struct xml_data*)userData; 1218b7579f77SDag-Erling Smørgrav BIO* b = NULL; 1219b7579f77SDag-Erling Smørgrav /* skip characters outside of elements */ 1220b7579f77SDag-Erling Smørgrav if(!data->tag) 1221b7579f77SDag-Erling Smørgrav return; 1222b7579f77SDag-Erling Smørgrav if(verb>=4) { 1223b7579f77SDag-Erling Smørgrav int i; 1224b7579f77SDag-Erling Smørgrav printf("%s%s charhandle: '", 1225b7579f77SDag-Erling Smørgrav data->use_key?"use ":"", 1226b7579f77SDag-Erling Smørgrav data->tag?data->tag:"none"); 1227b7579f77SDag-Erling Smørgrav for(i=0; i<len; i++) 1228b7579f77SDag-Erling Smørgrav printf("%c", s[i]); 1229b7579f77SDag-Erling Smørgrav printf("'\n"); 1230b7579f77SDag-Erling Smørgrav } 1231b7579f77SDag-Erling Smørgrav if(strcasecmp(data->tag, "Zone") == 0) { 1232b7579f77SDag-Erling Smørgrav if(BIO_write(data->czone, s, len) <= 0) { 1233b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory in BIO_write\n"); 1234b7579f77SDag-Erling Smørgrav exit(0); 1235b7579f77SDag-Erling Smørgrav } 1236b7579f77SDag-Erling Smørgrav return; 1237b7579f77SDag-Erling Smørgrav } 1238b7579f77SDag-Erling Smørgrav /* only store if key is used */ 1239b7579f77SDag-Erling Smørgrav if(!data->use_key) 1240b7579f77SDag-Erling Smørgrav return; 1241b7579f77SDag-Erling Smørgrav b = xml_selectbio(data, data->tag); 1242b7579f77SDag-Erling Smørgrav if(b) { 1243b7579f77SDag-Erling Smørgrav if(BIO_write(b, s, len) <= 0) { 1244b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory in BIO_write\n"); 1245b7579f77SDag-Erling Smørgrav exit(0); 1246b7579f77SDag-Erling Smørgrav } 1247b7579f77SDag-Erling Smørgrav } 1248b7579f77SDag-Erling Smørgrav } 1249b7579f77SDag-Erling Smørgrav 1250b7579f77SDag-Erling Smørgrav /** 1251b7579f77SDag-Erling Smørgrav * XML fetch value of particular attribute(by name) or NULL if not present. 1252b7579f77SDag-Erling Smørgrav * @param atts: attribute array (from xml_startelem). 1253b7579f77SDag-Erling Smørgrav * @param name: name of attribute to look for. 1254b7579f77SDag-Erling Smørgrav * @return the value or NULL. (ptr into atts). 1255b7579f77SDag-Erling Smørgrav */ 1256b7579f77SDag-Erling Smørgrav static const XML_Char* 1257*ebc5657fSDag-Erling Smørgrav find_att(const XML_Char **atts, const XML_Char* name) 1258b7579f77SDag-Erling Smørgrav { 1259b7579f77SDag-Erling Smørgrav int i; 1260b7579f77SDag-Erling Smørgrav for(i=0; atts[i]; i+=2) { 1261b7579f77SDag-Erling Smørgrav if(strcasecmp(atts[i], name) == 0) 1262b7579f77SDag-Erling Smørgrav return atts[i+1]; 1263b7579f77SDag-Erling Smørgrav } 1264b7579f77SDag-Erling Smørgrav return NULL; 1265b7579f77SDag-Erling Smørgrav } 1266b7579f77SDag-Erling Smørgrav 1267b7579f77SDag-Erling Smørgrav /** 1268b7579f77SDag-Erling Smørgrav * XML convert DateTime element to time_t. 1269b7579f77SDag-Erling Smørgrav * [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] 1270b7579f77SDag-Erling Smørgrav * (with optional .ssssss fractional seconds) 1271b7579f77SDag-Erling Smørgrav * @param str: the string 1272b7579f77SDag-Erling Smørgrav * @return a time_t representation or 0 on failure. 1273b7579f77SDag-Erling Smørgrav */ 1274b7579f77SDag-Erling Smørgrav static time_t 1275b7579f77SDag-Erling Smørgrav xml_convertdate(const char* str) 1276b7579f77SDag-Erling Smørgrav { 1277b7579f77SDag-Erling Smørgrav time_t t = 0; 1278b7579f77SDag-Erling Smørgrav struct tm tm; 1279b7579f77SDag-Erling Smørgrav const char* s; 1280b7579f77SDag-Erling Smørgrav /* for this application, ignore minus in front; 1281b7579f77SDag-Erling Smørgrav * only positive dates are expected */ 1282b7579f77SDag-Erling Smørgrav s = str; 1283b7579f77SDag-Erling Smørgrav if(s[0] == '-') s++; 1284b7579f77SDag-Erling Smørgrav memset(&tm, 0, sizeof(tm)); 1285b7579f77SDag-Erling Smørgrav /* parse initial content of the string (lots of whitespace allowed) */ 1286b7579f77SDag-Erling Smørgrav s = strptime(s, "%t%Y%t-%t%m%t-%t%d%tT%t%H%t:%t%M%t:%t%S%t", &tm); 1287b7579f77SDag-Erling Smørgrav if(!s) { 1288b7579f77SDag-Erling Smørgrav if(verb) printf("xml_convertdate parse failure %s\n", str); 1289b7579f77SDag-Erling Smørgrav return 0; 1290b7579f77SDag-Erling Smørgrav } 1291b7579f77SDag-Erling Smørgrav /* parse remainder of date string */ 1292b7579f77SDag-Erling Smørgrav if(*s == '.') { 1293b7579f77SDag-Erling Smørgrav /* optional '.' and fractional seconds */ 1294b7579f77SDag-Erling Smørgrav int frac = 0, n = 0; 1295b7579f77SDag-Erling Smørgrav if(sscanf(s+1, "%d%n", &frac, &n) < 1) { 1296b7579f77SDag-Erling Smørgrav if(verb) printf("xml_convertdate f failure %s\n", str); 1297b7579f77SDag-Erling Smørgrav return 0; 1298b7579f77SDag-Erling Smørgrav } 1299b7579f77SDag-Erling Smørgrav /* fraction is not used, time_t has second accuracy */ 1300b7579f77SDag-Erling Smørgrav s++; 1301b7579f77SDag-Erling Smørgrav s+=n; 1302b7579f77SDag-Erling Smørgrav } 1303b7579f77SDag-Erling Smørgrav if(*s == 'Z' || *s == 'z') { 1304b7579f77SDag-Erling Smørgrav /* nothing to do for this */ 1305b7579f77SDag-Erling Smørgrav s++; 1306b7579f77SDag-Erling Smørgrav } else if(*s == '+' || *s == '-') { 1307b7579f77SDag-Erling Smørgrav /* optional timezone spec: Z or +hh:mm or -hh:mm */ 1308b7579f77SDag-Erling Smørgrav int hr = 0, mn = 0, n = 0; 1309b7579f77SDag-Erling Smørgrav if(sscanf(s+1, "%d:%d%n", &hr, &mn, &n) < 2) { 1310b7579f77SDag-Erling Smørgrav if(verb) printf("xml_convertdate tz failure %s\n", str); 1311b7579f77SDag-Erling Smørgrav return 0; 1312b7579f77SDag-Erling Smørgrav } 1313b7579f77SDag-Erling Smørgrav if(*s == '+') { 1314b7579f77SDag-Erling Smørgrav tm.tm_hour += hr; 1315b7579f77SDag-Erling Smørgrav tm.tm_min += mn; 1316b7579f77SDag-Erling Smørgrav } else { 1317b7579f77SDag-Erling Smørgrav tm.tm_hour -= hr; 1318b7579f77SDag-Erling Smørgrav tm.tm_min -= mn; 1319b7579f77SDag-Erling Smørgrav } 1320b7579f77SDag-Erling Smørgrav s++; 1321b7579f77SDag-Erling Smørgrav s += n; 1322b7579f77SDag-Erling Smørgrav } 1323b7579f77SDag-Erling Smørgrav if(*s != 0) { 1324b7579f77SDag-Erling Smørgrav /* not ended properly */ 1325b7579f77SDag-Erling Smørgrav /* but ignore, (lenient) */ 1326b7579f77SDag-Erling Smørgrav } 1327b7579f77SDag-Erling Smørgrav 1328b7579f77SDag-Erling Smørgrav t = mktime(&tm); 1329b7579f77SDag-Erling Smørgrav if(t == (time_t)-1) { 1330b7579f77SDag-Erling Smørgrav if(verb) printf("xml_convertdate mktime failure\n"); 1331b7579f77SDag-Erling Smørgrav return 0; 1332b7579f77SDag-Erling Smørgrav } 1333b7579f77SDag-Erling Smørgrav return t; 1334b7579f77SDag-Erling Smørgrav } 1335b7579f77SDag-Erling Smørgrav 1336b7579f77SDag-Erling Smørgrav /** 1337b7579f77SDag-Erling Smørgrav * XML handle the KeyDigest start tag, check validity periods. 1338b7579f77SDag-Erling Smørgrav */ 1339b7579f77SDag-Erling Smørgrav static void 1340b7579f77SDag-Erling Smørgrav handle_keydigest(struct xml_data* data, const XML_Char **atts) 1341b7579f77SDag-Erling Smørgrav { 1342b7579f77SDag-Erling Smørgrav data->use_key = 0; 1343b7579f77SDag-Erling Smørgrav if(find_att(atts, "validFrom")) { 1344b7579f77SDag-Erling Smørgrav time_t from = xml_convertdate(find_att(atts, "validFrom")); 1345b7579f77SDag-Erling Smørgrav if(from == 0) { 1346b7579f77SDag-Erling Smørgrav if(verb) printf("error: xml cannot be parsed\n"); 1347b7579f77SDag-Erling Smørgrav exit(0); 1348b7579f77SDag-Erling Smørgrav } 1349b7579f77SDag-Erling Smørgrav if(data->date < from) 1350b7579f77SDag-Erling Smørgrav return; 1351b7579f77SDag-Erling Smørgrav } 1352b7579f77SDag-Erling Smørgrav if(find_att(atts, "validUntil")) { 1353b7579f77SDag-Erling Smørgrav time_t until = xml_convertdate(find_att(atts, "validUntil")); 1354b7579f77SDag-Erling Smørgrav if(until == 0) { 1355b7579f77SDag-Erling Smørgrav if(verb) printf("error: xml cannot be parsed\n"); 1356b7579f77SDag-Erling Smørgrav exit(0); 1357b7579f77SDag-Erling Smørgrav } 1358b7579f77SDag-Erling Smørgrav if(data->date > until) 1359b7579f77SDag-Erling Smørgrav return; 1360b7579f77SDag-Erling Smørgrav } 1361b7579f77SDag-Erling Smørgrav /* yes we want to use this key */ 1362b7579f77SDag-Erling Smørgrav data->use_key = 1; 1363b7579f77SDag-Erling Smørgrav (void)BIO_reset(data->ctag); 1364b7579f77SDag-Erling Smørgrav (void)BIO_reset(data->calgo); 1365b7579f77SDag-Erling Smørgrav (void)BIO_reset(data->cdigtype); 1366b7579f77SDag-Erling Smørgrav (void)BIO_reset(data->cdigest); 1367b7579f77SDag-Erling Smørgrav } 1368b7579f77SDag-Erling Smørgrav 1369b7579f77SDag-Erling Smørgrav /** See if XML element equals the zone name */ 1370b7579f77SDag-Erling Smørgrav static int 1371*ebc5657fSDag-Erling Smørgrav xml_is_zone_name(BIO* zone, const char* name) 1372b7579f77SDag-Erling Smørgrav { 1373b7579f77SDag-Erling Smørgrav char buf[1024]; 1374b7579f77SDag-Erling Smørgrav char* z = NULL; 1375b7579f77SDag-Erling Smørgrav long zlen; 1376b7579f77SDag-Erling Smørgrav (void)BIO_seek(zone, 0); 1377b7579f77SDag-Erling Smørgrav zlen = BIO_get_mem_data(zone, &z); 1378b7579f77SDag-Erling Smørgrav if(!zlen || !z) return 0; 1379b7579f77SDag-Erling Smørgrav /* zero terminate */ 1380b7579f77SDag-Erling Smørgrav if(zlen >= (long)sizeof(buf)) return 0; 1381b7579f77SDag-Erling Smørgrav memmove(buf, z, (size_t)zlen); 1382b7579f77SDag-Erling Smørgrav buf[zlen] = 0; 1383b7579f77SDag-Erling Smørgrav /* compare */ 1384b7579f77SDag-Erling Smørgrav return (strncasecmp(buf, name, strlen(name)) == 0); 1385b7579f77SDag-Erling Smørgrav } 1386b7579f77SDag-Erling Smørgrav 1387b7579f77SDag-Erling Smørgrav /** 1388b7579f77SDag-Erling Smørgrav * XML start of element. This callback is called whenever an XML tag starts. 1389b7579f77SDag-Erling Smørgrav * XML_Char is UTF8. 1390b7579f77SDag-Erling Smørgrav * @param userData: the xml_data structure. 1391b7579f77SDag-Erling Smørgrav * @param name: the tag that starts. 1392b7579f77SDag-Erling Smørgrav * @param atts: array of strings, pairs of attr = value, ends with NULL. 1393b7579f77SDag-Erling Smørgrav * i.e. att[0]="att[1]" att[2]="att[3]" att[4]isNull 1394b7579f77SDag-Erling Smørgrav */ 1395b7579f77SDag-Erling Smørgrav static void 1396b7579f77SDag-Erling Smørgrav xml_startelem(void *userData, const XML_Char *name, const XML_Char **atts) 1397b7579f77SDag-Erling Smørgrav { 1398b7579f77SDag-Erling Smørgrav struct xml_data* data = (struct xml_data*)userData; 1399b7579f77SDag-Erling Smørgrav BIO* b; 1400b7579f77SDag-Erling Smørgrav if(verb>=4) printf("xml tag start '%s'\n", name); 1401b7579f77SDag-Erling Smørgrav free(data->tag); 1402b7579f77SDag-Erling Smørgrav data->tag = strdup(name); 1403b7579f77SDag-Erling Smørgrav if(!data->tag) { 1404b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1405b7579f77SDag-Erling Smørgrav exit(0); 1406b7579f77SDag-Erling Smørgrav } 1407b7579f77SDag-Erling Smørgrav if(verb>=4) { 1408b7579f77SDag-Erling Smørgrav int i; 1409b7579f77SDag-Erling Smørgrav for(i=0; atts[i]; i+=2) { 1410b7579f77SDag-Erling Smørgrav printf(" %s='%s'\n", atts[i], atts[i+1]); 1411b7579f77SDag-Erling Smørgrav } 1412b7579f77SDag-Erling Smørgrav } 1413b7579f77SDag-Erling Smørgrav /* handle attributes to particular types */ 1414b7579f77SDag-Erling Smørgrav if(strcasecmp(name, "KeyDigest") == 0) { 1415b7579f77SDag-Erling Smørgrav handle_keydigest(data, atts); 1416b7579f77SDag-Erling Smørgrav return; 1417b7579f77SDag-Erling Smørgrav } else if(strcasecmp(name, "Zone") == 0) { 1418b7579f77SDag-Erling Smørgrav (void)BIO_reset(data->czone); 1419b7579f77SDag-Erling Smørgrav return; 1420b7579f77SDag-Erling Smørgrav } 1421b7579f77SDag-Erling Smørgrav 1422b7579f77SDag-Erling Smørgrav /* for other types we prepare to pick up the data */ 1423b7579f77SDag-Erling Smørgrav if(!data->use_key) 1424b7579f77SDag-Erling Smørgrav return; 1425b7579f77SDag-Erling Smørgrav b = xml_selectbio(data, data->tag); 1426b7579f77SDag-Erling Smørgrav if(b) { 1427b7579f77SDag-Erling Smørgrav /* empty it */ 1428b7579f77SDag-Erling Smørgrav (void)BIO_reset(b); 1429b7579f77SDag-Erling Smørgrav } 1430b7579f77SDag-Erling Smørgrav } 1431b7579f77SDag-Erling Smørgrav 1432b7579f77SDag-Erling Smørgrav /** Append str to bio */ 1433b7579f77SDag-Erling Smørgrav static void 1434b7579f77SDag-Erling Smørgrav xml_append_str(BIO* b, const char* s) 1435b7579f77SDag-Erling Smørgrav { 1436b7579f77SDag-Erling Smørgrav if(BIO_write(b, s, (int)strlen(s)) <= 0) { 1437b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory in BIO_write\n"); 1438b7579f77SDag-Erling Smørgrav exit(0); 1439b7579f77SDag-Erling Smørgrav } 1440b7579f77SDag-Erling Smørgrav } 1441b7579f77SDag-Erling Smørgrav 1442b7579f77SDag-Erling Smørgrav /** Append bio to bio */ 1443b7579f77SDag-Erling Smørgrav static void 1444b7579f77SDag-Erling Smørgrav xml_append_bio(BIO* b, BIO* a) 1445b7579f77SDag-Erling Smørgrav { 1446b7579f77SDag-Erling Smørgrav char* z = NULL; 1447b7579f77SDag-Erling Smørgrav long i, len; 1448b7579f77SDag-Erling Smørgrav (void)BIO_seek(a, 0); 1449b7579f77SDag-Erling Smørgrav len = BIO_get_mem_data(a, &z); 1450b7579f77SDag-Erling Smørgrav if(!len || !z) { 1451b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory in BIO_write\n"); 1452b7579f77SDag-Erling Smørgrav exit(0); 1453b7579f77SDag-Erling Smørgrav } 1454b7579f77SDag-Erling Smørgrav /* remove newlines in the data here */ 1455b7579f77SDag-Erling Smørgrav for(i=0; i<len; i++) { 1456b7579f77SDag-Erling Smørgrav if(z[i] == '\r' || z[i] == '\n') 1457b7579f77SDag-Erling Smørgrav z[i] = ' '; 1458b7579f77SDag-Erling Smørgrav } 1459b7579f77SDag-Erling Smørgrav /* write to BIO */ 1460b7579f77SDag-Erling Smørgrav if(BIO_write(b, z, len) <= 0) { 1461b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory in BIO_write\n"); 1462b7579f77SDag-Erling Smørgrav exit(0); 1463b7579f77SDag-Erling Smørgrav } 1464b7579f77SDag-Erling Smørgrav } 1465b7579f77SDag-Erling Smørgrav 1466b7579f77SDag-Erling Smørgrav /** write the parsed xml-DS to the DS list */ 1467b7579f77SDag-Erling Smørgrav static void 1468b7579f77SDag-Erling Smørgrav xml_append_ds(struct xml_data* data) 1469b7579f77SDag-Erling Smørgrav { 1470b7579f77SDag-Erling Smørgrav /* write DS to accumulated DS */ 1471b7579f77SDag-Erling Smørgrav xml_append_str(data->ds, ". IN DS "); 1472b7579f77SDag-Erling Smørgrav xml_append_bio(data->ds, data->ctag); 1473b7579f77SDag-Erling Smørgrav xml_append_str(data->ds, " "); 1474b7579f77SDag-Erling Smørgrav xml_append_bio(data->ds, data->calgo); 1475b7579f77SDag-Erling Smørgrav xml_append_str(data->ds, " "); 1476b7579f77SDag-Erling Smørgrav xml_append_bio(data->ds, data->cdigtype); 1477b7579f77SDag-Erling Smørgrav xml_append_str(data->ds, " "); 1478b7579f77SDag-Erling Smørgrav xml_append_bio(data->ds, data->cdigest); 1479b7579f77SDag-Erling Smørgrav xml_append_str(data->ds, "\n"); 1480b7579f77SDag-Erling Smørgrav data->num_keys++; 1481b7579f77SDag-Erling Smørgrav } 1482b7579f77SDag-Erling Smørgrav 1483b7579f77SDag-Erling Smørgrav /** 1484b7579f77SDag-Erling Smørgrav * XML end of element. This callback is called whenever an XML tag ends. 1485b7579f77SDag-Erling Smørgrav * XML_Char is UTF8. 1486b7579f77SDag-Erling Smørgrav * @param userData: the xml_data structure 1487b7579f77SDag-Erling Smørgrav * @param name: the tag that ends. 1488b7579f77SDag-Erling Smørgrav */ 1489b7579f77SDag-Erling Smørgrav static void 1490b7579f77SDag-Erling Smørgrav xml_endelem(void *userData, const XML_Char *name) 1491b7579f77SDag-Erling Smørgrav { 1492b7579f77SDag-Erling Smørgrav struct xml_data* data = (struct xml_data*)userData; 1493b7579f77SDag-Erling Smørgrav if(verb>=4) printf("xml tag end '%s'\n", name); 1494b7579f77SDag-Erling Smørgrav free(data->tag); 1495b7579f77SDag-Erling Smørgrav data->tag = NULL; 1496b7579f77SDag-Erling Smørgrav if(strcasecmp(name, "KeyDigest") == 0) { 1497b7579f77SDag-Erling Smørgrav if(data->use_key) 1498b7579f77SDag-Erling Smørgrav xml_append_ds(data); 1499b7579f77SDag-Erling Smørgrav data->use_key = 0; 1500b7579f77SDag-Erling Smørgrav } else if(strcasecmp(name, "Zone") == 0) { 1501b7579f77SDag-Erling Smørgrav if(!xml_is_zone_name(data->czone, ".")) { 1502b7579f77SDag-Erling Smørgrav if(verb) printf("xml not for the right zone\n"); 1503b7579f77SDag-Erling Smørgrav exit(0); 1504b7579f77SDag-Erling Smørgrav } 1505b7579f77SDag-Erling Smørgrav } 1506b7579f77SDag-Erling Smørgrav } 1507b7579f77SDag-Erling Smørgrav 15088ed2b524SDag-Erling Smørgrav /* Stop the parser when an entity declaration is encountered. For safety. */ 15098ed2b524SDag-Erling Smørgrav static void 15108ed2b524SDag-Erling Smørgrav xml_entitydeclhandler(void *userData, 15118ed2b524SDag-Erling Smørgrav const XML_Char *ATTR_UNUSED(entityName), 15128ed2b524SDag-Erling Smørgrav int ATTR_UNUSED(is_parameter_entity), 15138ed2b524SDag-Erling Smørgrav const XML_Char *ATTR_UNUSED(value), int ATTR_UNUSED(value_length), 15148ed2b524SDag-Erling Smørgrav const XML_Char *ATTR_UNUSED(base), 15158ed2b524SDag-Erling Smørgrav const XML_Char *ATTR_UNUSED(systemId), 15168ed2b524SDag-Erling Smørgrav const XML_Char *ATTR_UNUSED(publicId), 15178ed2b524SDag-Erling Smørgrav const XML_Char *ATTR_UNUSED(notationName)) 15188ed2b524SDag-Erling Smørgrav { 15198ed2b524SDag-Erling Smørgrav (void)XML_StopParser((XML_Parser)userData, XML_FALSE); 15208ed2b524SDag-Erling Smørgrav } 15218ed2b524SDag-Erling Smørgrav 1522b7579f77SDag-Erling Smørgrav /** 1523b7579f77SDag-Erling Smørgrav * XML parser setup of the callbacks for the tags 1524b7579f77SDag-Erling Smørgrav */ 1525b7579f77SDag-Erling Smørgrav static void 1526b7579f77SDag-Erling Smørgrav xml_parse_setup(XML_Parser parser, struct xml_data* data, time_t now) 1527b7579f77SDag-Erling Smørgrav { 1528b7579f77SDag-Erling Smørgrav char buf[1024]; 1529b7579f77SDag-Erling Smørgrav memset(data, 0, sizeof(*data)); 1530b7579f77SDag-Erling Smørgrav XML_SetUserData(parser, data); 1531b7579f77SDag-Erling Smørgrav data->parser = parser; 1532b7579f77SDag-Erling Smørgrav data->date = now; 1533b7579f77SDag-Erling Smørgrav data->ds = BIO_new(BIO_s_mem()); 1534b7579f77SDag-Erling Smørgrav data->ctag = BIO_new(BIO_s_mem()); 1535b7579f77SDag-Erling Smørgrav data->czone = BIO_new(BIO_s_mem()); 1536b7579f77SDag-Erling Smørgrav data->calgo = BIO_new(BIO_s_mem()); 1537b7579f77SDag-Erling Smørgrav data->cdigtype = BIO_new(BIO_s_mem()); 1538b7579f77SDag-Erling Smørgrav data->cdigest = BIO_new(BIO_s_mem()); 1539b7579f77SDag-Erling Smørgrav if(!data->ds || !data->ctag || !data->calgo || !data->czone || 1540b7579f77SDag-Erling Smørgrav !data->cdigtype || !data->cdigest) { 1541b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1542b7579f77SDag-Erling Smørgrav exit(0); 1543b7579f77SDag-Erling Smørgrav } 1544b7579f77SDag-Erling Smørgrav snprintf(buf, sizeof(buf), "; created by unbound-anchor on %s", 1545b7579f77SDag-Erling Smørgrav ctime(&now)); 1546b7579f77SDag-Erling Smørgrav if(BIO_write(data->ds, buf, (int)strlen(buf)) <= 0) { 1547b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1548b7579f77SDag-Erling Smørgrav exit(0); 1549b7579f77SDag-Erling Smørgrav } 15508ed2b524SDag-Erling Smørgrav XML_SetEntityDeclHandler(parser, xml_entitydeclhandler); 1551b7579f77SDag-Erling Smørgrav XML_SetElementHandler(parser, xml_startelem, xml_endelem); 1552b7579f77SDag-Erling Smørgrav XML_SetCharacterDataHandler(parser, xml_charhandle); 1553b7579f77SDag-Erling Smørgrav } 1554b7579f77SDag-Erling Smørgrav 1555b7579f77SDag-Erling Smørgrav /** 1556b7579f77SDag-Erling Smørgrav * Perform XML parsing of the root-anchors file 1557b7579f77SDag-Erling Smørgrav * Its format description can be read here 1558b7579f77SDag-Erling Smørgrav * https://data.iana.org/root-anchors/draft-icann-dnssec-trust-anchor.txt 1559b7579f77SDag-Erling Smørgrav * It uses libexpat. 1560b7579f77SDag-Erling Smørgrav * @param xml: BIO with xml data. 1561b7579f77SDag-Erling Smørgrav * @param now: the current time for checking DS validity periods. 1562b7579f77SDag-Erling Smørgrav * @return memoryBIO with the DS data in zone format. 1563b7579f77SDag-Erling Smørgrav * or NULL if the zone is insecure. 1564b7579f77SDag-Erling Smørgrav * (It exit()s on error) 1565b7579f77SDag-Erling Smørgrav */ 1566b7579f77SDag-Erling Smørgrav static BIO* 1567b7579f77SDag-Erling Smørgrav xml_parse(BIO* xml, time_t now) 1568b7579f77SDag-Erling Smørgrav { 1569b7579f77SDag-Erling Smørgrav char* pp; 1570b7579f77SDag-Erling Smørgrav int len; 1571b7579f77SDag-Erling Smørgrav XML_Parser parser; 1572b7579f77SDag-Erling Smørgrav struct xml_data data; 1573b7579f77SDag-Erling Smørgrav 1574b7579f77SDag-Erling Smørgrav parser = XML_ParserCreate(NULL); 1575b7579f77SDag-Erling Smørgrav if(!parser) { 1576b7579f77SDag-Erling Smørgrav if(verb) printf("could not XML_ParserCreate\n"); 1577b7579f77SDag-Erling Smørgrav exit(0); 1578b7579f77SDag-Erling Smørgrav } 1579b7579f77SDag-Erling Smørgrav 1580b7579f77SDag-Erling Smørgrav /* setup callbacks */ 1581b7579f77SDag-Erling Smørgrav xml_parse_setup(parser, &data, now); 1582b7579f77SDag-Erling Smørgrav 1583b7579f77SDag-Erling Smørgrav /* parse it */ 1584b7579f77SDag-Erling Smørgrav (void)BIO_reset(xml); 1585b7579f77SDag-Erling Smørgrav len = (int)BIO_get_mem_data(xml, &pp); 1586b7579f77SDag-Erling Smørgrav if(!len || !pp) { 1587b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1588b7579f77SDag-Erling Smørgrav exit(0); 1589b7579f77SDag-Erling Smørgrav } 1590b7579f77SDag-Erling Smørgrav if(!XML_Parse(parser, pp, len, 1 /*isfinal*/ )) { 1591b7579f77SDag-Erling Smørgrav const char *e = XML_ErrorString(XML_GetErrorCode(parser)); 1592b7579f77SDag-Erling Smørgrav if(verb) printf("XML_Parse failure %s\n", e?e:""); 1593b7579f77SDag-Erling Smørgrav exit(0); 1594b7579f77SDag-Erling Smørgrav } 1595b7579f77SDag-Erling Smørgrav 1596b7579f77SDag-Erling Smørgrav /* parsed */ 1597b7579f77SDag-Erling Smørgrav if(verb) printf("XML was parsed successfully, %d keys\n", 1598b7579f77SDag-Erling Smørgrav data.num_keys); 1599b7579f77SDag-Erling Smørgrav free(data.tag); 1600b7579f77SDag-Erling Smørgrav XML_ParserFree(parser); 1601b7579f77SDag-Erling Smørgrav 1602b7579f77SDag-Erling Smørgrav if(verb >= 4) { 1603b7579f77SDag-Erling Smørgrav (void)BIO_seek(data.ds, 0); 1604b7579f77SDag-Erling Smørgrav len = BIO_get_mem_data(data.ds, &pp); 1605b7579f77SDag-Erling Smørgrav printf("got DS bio %d: '", len); 1606b7579f77SDag-Erling Smørgrav if(!fwrite(pp, (size_t)len, 1, stdout)) 1607b7579f77SDag-Erling Smørgrav /* compilers do not allow us to ignore fwrite .. */ 1608b7579f77SDag-Erling Smørgrav fprintf(stderr, "error writing to stdout\n"); 1609b7579f77SDag-Erling Smørgrav printf("'\n"); 1610b7579f77SDag-Erling Smørgrav } 1611b7579f77SDag-Erling Smørgrav BIO_free(data.czone); 1612b7579f77SDag-Erling Smørgrav BIO_free(data.ctag); 1613b7579f77SDag-Erling Smørgrav BIO_free(data.calgo); 1614b7579f77SDag-Erling Smørgrav BIO_free(data.cdigtype); 1615b7579f77SDag-Erling Smørgrav BIO_free(data.cdigest); 1616b7579f77SDag-Erling Smørgrav 1617b7579f77SDag-Erling Smørgrav if(data.num_keys == 0) { 1618b7579f77SDag-Erling Smørgrav /* the root zone seems to have gone insecure */ 1619b7579f77SDag-Erling Smørgrav BIO_free(data.ds); 1620b7579f77SDag-Erling Smørgrav return NULL; 1621b7579f77SDag-Erling Smørgrav } else { 1622b7579f77SDag-Erling Smørgrav return data.ds; 1623b7579f77SDag-Erling Smørgrav } 1624b7579f77SDag-Erling Smørgrav } 1625b7579f77SDag-Erling Smørgrav 16268ed2b524SDag-Erling Smørgrav /* get key usage out of its extension, returns 0 if no key_usage extension */ 16278ed2b524SDag-Erling Smørgrav static unsigned long 16288ed2b524SDag-Erling Smørgrav get_usage_of_ex(X509* cert) 16298ed2b524SDag-Erling Smørgrav { 16308ed2b524SDag-Erling Smørgrav unsigned long val = 0; 16318ed2b524SDag-Erling Smørgrav ASN1_BIT_STRING* s; 16328ed2b524SDag-Erling Smørgrav if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) { 16338ed2b524SDag-Erling Smørgrav if(s->length > 0) { 16348ed2b524SDag-Erling Smørgrav val = s->data[0]; 16358ed2b524SDag-Erling Smørgrav if(s->length > 1) 16368ed2b524SDag-Erling Smørgrav val |= s->data[1] << 8; 16378ed2b524SDag-Erling Smørgrav } 16388ed2b524SDag-Erling Smørgrav ASN1_BIT_STRING_free(s); 16398ed2b524SDag-Erling Smørgrav } 16408ed2b524SDag-Erling Smørgrav return val; 16418ed2b524SDag-Erling Smørgrav } 16428ed2b524SDag-Erling Smørgrav 16438ed2b524SDag-Erling Smørgrav /** get valid signers from the list of signers in the signature */ 16448ed2b524SDag-Erling Smørgrav static STACK_OF(X509)* 1645*ebc5657fSDag-Erling Smørgrav get_valid_signers(PKCS7* p7, const char* p7signer) 16468ed2b524SDag-Erling Smørgrav { 16478ed2b524SDag-Erling Smørgrav int i; 16488ed2b524SDag-Erling Smørgrav STACK_OF(X509)* validsigners = sk_X509_new_null(); 16498ed2b524SDag-Erling Smørgrav STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0); 16508ed2b524SDag-Erling Smørgrav unsigned long usage = 0; 16518ed2b524SDag-Erling Smørgrav if(!validsigners) { 16528ed2b524SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 16538ed2b524SDag-Erling Smørgrav sk_X509_free(signers); 16548ed2b524SDag-Erling Smørgrav return NULL; 16558ed2b524SDag-Erling Smørgrav } 16568ed2b524SDag-Erling Smørgrav if(!signers) { 16578ed2b524SDag-Erling Smørgrav if(verb) printf("no signers in pkcs7 signature\n"); 16588ed2b524SDag-Erling Smørgrav sk_X509_free(validsigners); 16598ed2b524SDag-Erling Smørgrav return NULL; 16608ed2b524SDag-Erling Smørgrav } 16618ed2b524SDag-Erling Smørgrav for(i=0; i<sk_X509_num(signers); i++) { 16628ed2b524SDag-Erling Smørgrav X509_NAME* nm = X509_get_subject_name( 16638ed2b524SDag-Erling Smørgrav sk_X509_value(signers, i)); 16648ed2b524SDag-Erling Smørgrav char buf[1024]; 16658ed2b524SDag-Erling Smørgrav if(!nm) { 16668ed2b524SDag-Erling Smørgrav if(verb) printf("signer %d: cert has no subject name\n", i); 16678ed2b524SDag-Erling Smørgrav continue; 16688ed2b524SDag-Erling Smørgrav } 16698ed2b524SDag-Erling Smørgrav if(verb && nm) { 16708ed2b524SDag-Erling Smørgrav char* nmline = X509_NAME_oneline(nm, buf, 16718ed2b524SDag-Erling Smørgrav (int)sizeof(buf)); 16728ed2b524SDag-Erling Smørgrav printf("signer %d: Subject: %s\n", i, 16738ed2b524SDag-Erling Smørgrav nmline?nmline:"no subject"); 16748ed2b524SDag-Erling Smørgrav if(verb >= 3 && X509_NAME_get_text_by_NID(nm, 16758ed2b524SDag-Erling Smørgrav NID_commonName, buf, (int)sizeof(buf))) 16768ed2b524SDag-Erling Smørgrav printf("commonName: %s\n", buf); 16778ed2b524SDag-Erling Smørgrav if(verb >= 3 && X509_NAME_get_text_by_NID(nm, 16788ed2b524SDag-Erling Smørgrav NID_pkcs9_emailAddress, buf, (int)sizeof(buf))) 16798ed2b524SDag-Erling Smørgrav printf("emailAddress: %s\n", buf); 16808ed2b524SDag-Erling Smørgrav } 16818ed2b524SDag-Erling Smørgrav if(verb) { 16828ed2b524SDag-Erling Smørgrav int ku_loc = X509_get_ext_by_NID( 16838ed2b524SDag-Erling Smørgrav sk_X509_value(signers, i), NID_key_usage, -1); 16848ed2b524SDag-Erling Smørgrav if(verb >= 3 && ku_loc >= 0) { 16858ed2b524SDag-Erling Smørgrav X509_EXTENSION *ex = X509_get_ext( 16868ed2b524SDag-Erling Smørgrav sk_X509_value(signers, i), ku_loc); 16878ed2b524SDag-Erling Smørgrav if(ex) { 16888ed2b524SDag-Erling Smørgrav printf("keyUsage: "); 16898ed2b524SDag-Erling Smørgrav X509V3_EXT_print_fp(stdout, ex, 0, 0); 16908ed2b524SDag-Erling Smørgrav printf("\n"); 16918ed2b524SDag-Erling Smørgrav } 16928ed2b524SDag-Erling Smørgrav } 16938ed2b524SDag-Erling Smørgrav } 16948ed2b524SDag-Erling Smørgrav if(!p7signer || strcmp(p7signer, "")==0) { 16958ed2b524SDag-Erling Smørgrav /* there is no name to check, return all records */ 16968ed2b524SDag-Erling Smørgrav if(verb) printf("did not check commonName of signer\n"); 16978ed2b524SDag-Erling Smørgrav } else { 16988ed2b524SDag-Erling Smørgrav if(!X509_NAME_get_text_by_NID(nm, 16998ed2b524SDag-Erling Smørgrav NID_pkcs9_emailAddress, 17008ed2b524SDag-Erling Smørgrav buf, (int)sizeof(buf))) { 17018ed2b524SDag-Erling Smørgrav if(verb) printf("removed cert with no name\n"); 17028ed2b524SDag-Erling Smørgrav continue; /* no name, no use */ 17038ed2b524SDag-Erling Smørgrav } 17048ed2b524SDag-Erling Smørgrav if(strcmp(buf, p7signer) != 0) { 17058ed2b524SDag-Erling Smørgrav if(verb) printf("removed cert with wrong name\n"); 17068ed2b524SDag-Erling Smørgrav continue; /* wrong name, skip it */ 17078ed2b524SDag-Erling Smørgrav } 17088ed2b524SDag-Erling Smørgrav } 17098ed2b524SDag-Erling Smørgrav 17108ed2b524SDag-Erling Smørgrav /* check that the key usage allows digital signatures 17118ed2b524SDag-Erling Smørgrav * (the p7s) */ 17128ed2b524SDag-Erling Smørgrav usage = get_usage_of_ex(sk_X509_value(signers, i)); 17138ed2b524SDag-Erling Smørgrav if(!(usage & KU_DIGITAL_SIGNATURE)) { 17148ed2b524SDag-Erling Smørgrav if(verb) printf("removed cert with no key usage Digital Signature allowed\n"); 17158ed2b524SDag-Erling Smørgrav continue; 17168ed2b524SDag-Erling Smørgrav } 17178ed2b524SDag-Erling Smørgrav 17188ed2b524SDag-Erling Smørgrav /* we like this cert, add it to our list of valid 17198ed2b524SDag-Erling Smørgrav * signers certificates */ 17208ed2b524SDag-Erling Smørgrav sk_X509_push(validsigners, sk_X509_value(signers, i)); 17218ed2b524SDag-Erling Smørgrav } 17228ed2b524SDag-Erling Smørgrav sk_X509_free(signers); 17238ed2b524SDag-Erling Smørgrav return validsigners; 17248ed2b524SDag-Erling Smørgrav } 17258ed2b524SDag-Erling Smørgrav 1726b7579f77SDag-Erling Smørgrav /** verify a PKCS7 signature, false on failure */ 1727b7579f77SDag-Erling Smørgrav static int 1728*ebc5657fSDag-Erling Smørgrav verify_p7sig(BIO* data, BIO* p7s, STACK_OF(X509)* trust, const char* p7signer) 1729b7579f77SDag-Erling Smørgrav { 1730b7579f77SDag-Erling Smørgrav PKCS7* p7; 1731b7579f77SDag-Erling Smørgrav X509_STORE *store = X509_STORE_new(); 17328ed2b524SDag-Erling Smørgrav STACK_OF(X509)* validsigners; 1733b7579f77SDag-Erling Smørgrav int secure = 0; 1734b7579f77SDag-Erling Smørgrav int i; 1735b7579f77SDag-Erling Smørgrav #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE 1736b7579f77SDag-Erling Smørgrav X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new(); 1737b7579f77SDag-Erling Smørgrav if(!param) { 1738b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1739b7579f77SDag-Erling Smørgrav X509_STORE_free(store); 1740b7579f77SDag-Erling Smørgrav return 0; 1741b7579f77SDag-Erling Smørgrav } 1742b7579f77SDag-Erling Smørgrav /* do the selfcheck on the root certificate; it checks that the 1743b7579f77SDag-Erling Smørgrav * input is valid */ 1744b7579f77SDag-Erling Smørgrav X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CHECK_SS_SIGNATURE); 1745b7579f77SDag-Erling Smørgrav if(store) X509_STORE_set1_param(store, param); 1746b7579f77SDag-Erling Smørgrav #endif 1747b7579f77SDag-Erling Smørgrav if(!store) { 1748b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1749b7579f77SDag-Erling Smørgrav #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE 1750b7579f77SDag-Erling Smørgrav X509_VERIFY_PARAM_free(param); 1751b7579f77SDag-Erling Smørgrav #endif 1752b7579f77SDag-Erling Smørgrav return 0; 1753b7579f77SDag-Erling Smørgrav } 17548ed2b524SDag-Erling Smørgrav #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE 17558ed2b524SDag-Erling Smørgrav X509_VERIFY_PARAM_free(param); 17568ed2b524SDag-Erling Smørgrav #endif 1757b7579f77SDag-Erling Smørgrav 1758b7579f77SDag-Erling Smørgrav (void)BIO_reset(p7s); 1759b7579f77SDag-Erling Smørgrav (void)BIO_reset(data); 1760b7579f77SDag-Erling Smørgrav 1761b7579f77SDag-Erling Smørgrav /* convert p7s to p7 (the signature) */ 1762b7579f77SDag-Erling Smørgrav p7 = d2i_PKCS7_bio(p7s, NULL); 1763b7579f77SDag-Erling Smørgrav if(!p7) { 1764b7579f77SDag-Erling Smørgrav if(verb) printf("could not parse p7s signature file\n"); 1765b7579f77SDag-Erling Smørgrav X509_STORE_free(store); 1766b7579f77SDag-Erling Smørgrav return 0; 1767b7579f77SDag-Erling Smørgrav } 1768b7579f77SDag-Erling Smørgrav if(verb >= 2) printf("parsed the PKCS7 signature\n"); 1769b7579f77SDag-Erling Smørgrav 1770b7579f77SDag-Erling Smørgrav /* convert trust to trusted certificate store */ 1771b7579f77SDag-Erling Smørgrav for(i=0; i<sk_X509_num(trust); i++) { 1772b7579f77SDag-Erling Smørgrav if(!X509_STORE_add_cert(store, sk_X509_value(trust, i))) { 1773b7579f77SDag-Erling Smørgrav if(verb) printf("failed X509_STORE_add_cert\n"); 1774b7579f77SDag-Erling Smørgrav X509_STORE_free(store); 1775b7579f77SDag-Erling Smørgrav PKCS7_free(p7); 1776b7579f77SDag-Erling Smørgrav return 0; 1777b7579f77SDag-Erling Smørgrav } 1778b7579f77SDag-Erling Smørgrav } 1779b7579f77SDag-Erling Smørgrav if(verb >= 2) printf("setup the X509_STORE\n"); 1780b7579f77SDag-Erling Smørgrav 17818ed2b524SDag-Erling Smørgrav /* check what is in the Subject name of the certificates, 17828ed2b524SDag-Erling Smørgrav * and build a stack that contains only the right certificates */ 17838ed2b524SDag-Erling Smørgrav validsigners = get_valid_signers(p7, p7signer); 17848ed2b524SDag-Erling Smørgrav if(!validsigners) { 17858ed2b524SDag-Erling Smørgrav X509_STORE_free(store); 17868ed2b524SDag-Erling Smørgrav PKCS7_free(p7); 17878ed2b524SDag-Erling Smørgrav return 0; 17888ed2b524SDag-Erling Smørgrav } 17898ed2b524SDag-Erling Smørgrav if(PKCS7_verify(p7, validsigners, store, data, NULL, PKCS7_NOINTERN) == 1) { 1790b7579f77SDag-Erling Smørgrav secure = 1; 1791b7579f77SDag-Erling Smørgrav if(verb) printf("the PKCS7 signature verified\n"); 1792b7579f77SDag-Erling Smørgrav } else { 1793b7579f77SDag-Erling Smørgrav if(verb) { 1794b7579f77SDag-Erling Smørgrav ERR_print_errors_fp(stdout); 1795b7579f77SDag-Erling Smørgrav } 1796b7579f77SDag-Erling Smørgrav } 1797b7579f77SDag-Erling Smørgrav 17988ed2b524SDag-Erling Smørgrav sk_X509_free(validsigners); 1799b7579f77SDag-Erling Smørgrav X509_STORE_free(store); 1800b7579f77SDag-Erling Smørgrav PKCS7_free(p7); 1801b7579f77SDag-Erling Smørgrav return secure; 1802b7579f77SDag-Erling Smørgrav } 1803b7579f77SDag-Erling Smørgrav 1804b7579f77SDag-Erling Smørgrav /** write unsigned root anchor file, a 5011 revoked tp */ 1805b7579f77SDag-Erling Smørgrav static void 1806*ebc5657fSDag-Erling Smørgrav write_unsigned_root(const char* root_anchor_file) 1807b7579f77SDag-Erling Smørgrav { 1808b7579f77SDag-Erling Smørgrav FILE* out; 1809b7579f77SDag-Erling Smørgrav time_t now = time(NULL); 1810b7579f77SDag-Erling Smørgrav out = fopen(root_anchor_file, "w"); 1811b7579f77SDag-Erling Smørgrav if(!out) { 1812b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno)); 1813b7579f77SDag-Erling Smørgrav return; 1814b7579f77SDag-Erling Smørgrav } 1815b7579f77SDag-Erling Smørgrav if(fprintf(out, "; autotrust trust anchor file\n" 1816b7579f77SDag-Erling Smørgrav ";;REVOKED\n" 1817b7579f77SDag-Erling Smørgrav ";;id: . 1\n" 1818b7579f77SDag-Erling Smørgrav "; This file was written by unbound-anchor on %s" 1819b7579f77SDag-Erling Smørgrav "; It indicates that the root does not use DNSSEC\n" 1820b7579f77SDag-Erling Smørgrav "; to restart DNSSEC overwrite this file with a\n" 1821b7579f77SDag-Erling Smørgrav "; valid trustanchor or (empty-it and run unbound-anchor)\n" 1822b7579f77SDag-Erling Smørgrav , ctime(&now)) < 0) { 1823b7579f77SDag-Erling Smørgrav if(verb) printf("failed to write 'unsigned' to %s\n", 1824b7579f77SDag-Erling Smørgrav root_anchor_file); 1825b7579f77SDag-Erling Smørgrav if(verb && errno != 0) printf("%s\n", strerror(errno)); 1826b7579f77SDag-Erling Smørgrav } 1827b7579f77SDag-Erling Smørgrav fclose(out); 1828b7579f77SDag-Erling Smørgrav } 1829b7579f77SDag-Erling Smørgrav 1830b7579f77SDag-Erling Smørgrav /** write root anchor file */ 1831b7579f77SDag-Erling Smørgrav static void 1832*ebc5657fSDag-Erling Smørgrav write_root_anchor(const char* root_anchor_file, BIO* ds) 1833b7579f77SDag-Erling Smørgrav { 1834b7579f77SDag-Erling Smørgrav char* pp = NULL; 1835b7579f77SDag-Erling Smørgrav int len; 1836b7579f77SDag-Erling Smørgrav FILE* out; 1837b7579f77SDag-Erling Smørgrav (void)BIO_seek(ds, 0); 1838b7579f77SDag-Erling Smørgrav len = BIO_get_mem_data(ds, &pp); 1839b7579f77SDag-Erling Smørgrav if(!len || !pp) { 1840b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 1841b7579f77SDag-Erling Smørgrav return; 1842b7579f77SDag-Erling Smørgrav } 1843b7579f77SDag-Erling Smørgrav out = fopen(root_anchor_file, "w"); 1844b7579f77SDag-Erling Smørgrav if(!out) { 1845b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", root_anchor_file, strerror(errno)); 1846b7579f77SDag-Erling Smørgrav return; 1847b7579f77SDag-Erling Smørgrav } 1848b7579f77SDag-Erling Smørgrav if(fwrite(pp, (size_t)len, 1, out) != 1) { 1849b7579f77SDag-Erling Smørgrav if(verb) printf("failed to write all data to %s\n", 1850b7579f77SDag-Erling Smørgrav root_anchor_file); 1851b7579f77SDag-Erling Smørgrav if(verb && errno != 0) printf("%s\n", strerror(errno)); 1852b7579f77SDag-Erling Smørgrav } 1853b7579f77SDag-Erling Smørgrav fclose(out); 1854b7579f77SDag-Erling Smørgrav } 1855b7579f77SDag-Erling Smørgrav 1856b7579f77SDag-Erling Smørgrav /** Perform the verification and update of the trustanchor file */ 1857b7579f77SDag-Erling Smørgrav static void 1858*ebc5657fSDag-Erling Smørgrav verify_and_update_anchor(const char* root_anchor_file, BIO* xml, BIO* p7s, 1859*ebc5657fSDag-Erling Smørgrav STACK_OF(X509)* cert, const char* p7signer) 1860b7579f77SDag-Erling Smørgrav { 1861b7579f77SDag-Erling Smørgrav BIO* ds; 1862b7579f77SDag-Erling Smørgrav 1863b7579f77SDag-Erling Smørgrav /* verify xml file */ 18648ed2b524SDag-Erling Smørgrav if(!verify_p7sig(xml, p7s, cert, p7signer)) { 1865b7579f77SDag-Erling Smørgrav printf("the PKCS7 signature failed\n"); 1866b7579f77SDag-Erling Smørgrav exit(0); 1867b7579f77SDag-Erling Smørgrav } 1868b7579f77SDag-Erling Smørgrav 1869b7579f77SDag-Erling Smørgrav /* parse the xml file into DS records */ 1870b7579f77SDag-Erling Smørgrav ds = xml_parse(xml, time(NULL)); 1871b7579f77SDag-Erling Smørgrav if(!ds) { 1872b7579f77SDag-Erling Smørgrav /* the root zone is unsigned now */ 1873b7579f77SDag-Erling Smørgrav write_unsigned_root(root_anchor_file); 1874b7579f77SDag-Erling Smørgrav } else { 1875b7579f77SDag-Erling Smørgrav /* reinstate 5011 tracking */ 1876b7579f77SDag-Erling Smørgrav write_root_anchor(root_anchor_file, ds); 1877b7579f77SDag-Erling Smørgrav } 1878b7579f77SDag-Erling Smørgrav BIO_free(ds); 1879b7579f77SDag-Erling Smørgrav } 1880b7579f77SDag-Erling Smørgrav 1881b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 1882b7579f77SDag-Erling Smørgrav static void do_wsa_cleanup(void) { WSACleanup(); } 1883b7579f77SDag-Erling Smørgrav #endif 1884b7579f77SDag-Erling Smørgrav 1885b7579f77SDag-Erling Smørgrav /** perform actual certupdate work */ 1886b7579f77SDag-Erling Smørgrav static int 1887*ebc5657fSDag-Erling Smørgrav do_certupdate(const char* root_anchor_file, const char* root_cert_file, 1888*ebc5657fSDag-Erling Smørgrav const char* urlname, const char* xmlname, const char* p7sname, 1889*ebc5657fSDag-Erling Smørgrav const char* p7signer, const char* res_conf, const char* root_hints, 1890*ebc5657fSDag-Erling Smørgrav const char* debugconf, int ip4only, int ip6only, int port, 1891*ebc5657fSDag-Erling Smørgrav struct ub_result* dnskey) 1892b7579f77SDag-Erling Smørgrav { 1893b7579f77SDag-Erling Smørgrav STACK_OF(X509)* cert; 1894b7579f77SDag-Erling Smørgrav BIO *xml, *p7s; 1895b7579f77SDag-Erling Smørgrav struct ip_list* ip_list = NULL; 1896b7579f77SDag-Erling Smørgrav 1897b7579f77SDag-Erling Smørgrav /* read pem file or provide builtin */ 1898b7579f77SDag-Erling Smørgrav cert = read_cert_or_builtin(root_cert_file); 1899b7579f77SDag-Erling Smørgrav 1900b7579f77SDag-Erling Smørgrav /* lookup A, AAAA for the urlname (or parse urlname if IP address) */ 1901b7579f77SDag-Erling Smørgrav ip_list = resolve_name(urlname, port, res_conf, root_hints, debugconf, 1902b7579f77SDag-Erling Smørgrav ip4only, ip6only); 1903b7579f77SDag-Erling Smørgrav 1904b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 1905b7579f77SDag-Erling Smørgrav if(1) { /* libunbound finished, startup WSA for the https connection */ 1906b7579f77SDag-Erling Smørgrav WSADATA wsa_data; 1907b7579f77SDag-Erling Smørgrav int r; 1908b7579f77SDag-Erling Smørgrav if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) { 1909b7579f77SDag-Erling Smørgrav if(verb) printf("WSAStartup failed: %s\n", 1910b7579f77SDag-Erling Smørgrav wsa_strerror(r)); 1911b7579f77SDag-Erling Smørgrav exit(0); 1912b7579f77SDag-Erling Smørgrav } 1913b7579f77SDag-Erling Smørgrav atexit(&do_wsa_cleanup); 1914b7579f77SDag-Erling Smørgrav } 1915b7579f77SDag-Erling Smørgrav #endif 1916b7579f77SDag-Erling Smørgrav 1917b7579f77SDag-Erling Smørgrav /* fetch the necessary files over HTTPS */ 1918b7579f77SDag-Erling Smørgrav xml = https(ip_list, xmlname, urlname); 1919b7579f77SDag-Erling Smørgrav p7s = https(ip_list, p7sname, urlname); 1920b7579f77SDag-Erling Smørgrav 1921b7579f77SDag-Erling Smørgrav /* verify and update the root anchor */ 19228ed2b524SDag-Erling Smørgrav verify_and_update_anchor(root_anchor_file, xml, p7s, cert, p7signer); 1923b7579f77SDag-Erling Smørgrav if(verb) printf("success: the anchor has been updated " 1924b7579f77SDag-Erling Smørgrav "using the cert\n"); 1925b7579f77SDag-Erling Smørgrav 1926b7579f77SDag-Erling Smørgrav free_file_bio(xml); 1927b7579f77SDag-Erling Smørgrav free_file_bio(p7s); 1928b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 1929b7579f77SDag-Erling Smørgrav sk_X509_pop_free(cert, X509_free); 1930b7579f77SDag-Erling Smørgrav #endif 1931b7579f77SDag-Erling Smørgrav ub_resolve_free(dnskey); 1932b7579f77SDag-Erling Smørgrav ip_list_free(ip_list); 1933b7579f77SDag-Erling Smørgrav return 1; 1934b7579f77SDag-Erling Smørgrav } 1935b7579f77SDag-Erling Smørgrav 1936b7579f77SDag-Erling Smørgrav /** 1937b7579f77SDag-Erling Smørgrav * Try to read the root RFC5011 autotrust anchor file, 1938b7579f77SDag-Erling Smørgrav * @param file: filename. 1939b7579f77SDag-Erling Smørgrav * @return: 1940b7579f77SDag-Erling Smørgrav * 0 if does not exist or empty 1941b7579f77SDag-Erling Smørgrav * 1 if trust-point-revoked-5011 1942b7579f77SDag-Erling Smørgrav * 2 if it is OK. 1943b7579f77SDag-Erling Smørgrav */ 1944b7579f77SDag-Erling Smørgrav static int 1945*ebc5657fSDag-Erling Smørgrav try_read_anchor(const char* file) 1946b7579f77SDag-Erling Smørgrav { 1947b7579f77SDag-Erling Smørgrav int empty = 1; 1948b7579f77SDag-Erling Smørgrav char line[10240]; 1949b7579f77SDag-Erling Smørgrav char* p; 1950b7579f77SDag-Erling Smørgrav FILE* in = fopen(file, "r"); 1951b7579f77SDag-Erling Smørgrav if(!in) { 1952b7579f77SDag-Erling Smørgrav /* only if the file does not exist, can we fix it */ 1953b7579f77SDag-Erling Smørgrav if(errno != ENOENT) { 1954b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", file, strerror(errno)); 1955b7579f77SDag-Erling Smørgrav if(verb) printf("error: cannot access the file\n"); 1956b7579f77SDag-Erling Smørgrav exit(0); 1957b7579f77SDag-Erling Smørgrav } 1958b7579f77SDag-Erling Smørgrav if(verb) printf("%s does not exist\n", file); 1959b7579f77SDag-Erling Smørgrav return 0; 1960b7579f77SDag-Erling Smørgrav } 1961b7579f77SDag-Erling Smørgrav while(fgets(line, (int)sizeof(line), in)) { 1962b7579f77SDag-Erling Smørgrav line[sizeof(line)-1] = 0; 1963b7579f77SDag-Erling Smørgrav if(strncmp(line, ";;REVOKED", 9) == 0) { 1964b7579f77SDag-Erling Smørgrav fclose(in); 1965b7579f77SDag-Erling Smørgrav if(verb) printf("%s : the trust point is revoked\n" 1966b7579f77SDag-Erling Smørgrav "and the zone is considered unsigned.\n" 1967b7579f77SDag-Erling Smørgrav "if you wish to re-enable, delete the file\n", 1968b7579f77SDag-Erling Smørgrav file); 1969b7579f77SDag-Erling Smørgrav return 1; 1970b7579f77SDag-Erling Smørgrav } 1971b7579f77SDag-Erling Smørgrav p=line; 1972b7579f77SDag-Erling Smørgrav while(*p == ' ' || *p == '\t') 1973b7579f77SDag-Erling Smørgrav p++; 1974b7579f77SDag-Erling Smørgrav if(p[0]==0 || p[0]=='\n' || p[0]==';') continue; 1975b7579f77SDag-Erling Smørgrav /* this line is a line of content */ 1976b7579f77SDag-Erling Smørgrav empty = 0; 1977b7579f77SDag-Erling Smørgrav } 1978b7579f77SDag-Erling Smørgrav fclose(in); 1979b7579f77SDag-Erling Smørgrav if(empty) { 1980b7579f77SDag-Erling Smørgrav if(verb) printf("%s is empty\n", file); 1981b7579f77SDag-Erling Smørgrav return 0; 1982b7579f77SDag-Erling Smørgrav } 1983b7579f77SDag-Erling Smørgrav if(verb) printf("%s has content\n", file); 1984b7579f77SDag-Erling Smørgrav return 2; 1985b7579f77SDag-Erling Smørgrav } 1986b7579f77SDag-Erling Smørgrav 1987b7579f77SDag-Erling Smørgrav /** Write the builtin root anchor to a file */ 1988b7579f77SDag-Erling Smørgrav static void 1989*ebc5657fSDag-Erling Smørgrav write_builtin_anchor(const char* file) 1990b7579f77SDag-Erling Smørgrav { 1991b7579f77SDag-Erling Smørgrav const char* builtin_root_anchor = get_builtin_ds(); 1992b7579f77SDag-Erling Smørgrav FILE* out = fopen(file, "w"); 1993b7579f77SDag-Erling Smørgrav if(!out) { 1994b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", file, strerror(errno)); 1995b7579f77SDag-Erling Smørgrav if(verb) printf(" could not write builtin anchor\n"); 1996b7579f77SDag-Erling Smørgrav return; 1997b7579f77SDag-Erling Smørgrav } 1998b7579f77SDag-Erling Smørgrav if(!fwrite(builtin_root_anchor, strlen(builtin_root_anchor), 1, out)) { 1999b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", file, strerror(errno)); 2000b7579f77SDag-Erling Smørgrav if(verb) printf(" could not complete write builtin anchor\n"); 2001b7579f77SDag-Erling Smørgrav } 2002b7579f77SDag-Erling Smørgrav fclose(out); 2003b7579f77SDag-Erling Smørgrav } 2004b7579f77SDag-Erling Smørgrav 2005b7579f77SDag-Erling Smørgrav /** 2006b7579f77SDag-Erling Smørgrav * Check the root anchor file. 2007b7579f77SDag-Erling Smørgrav * If does not exist, provide builtin and write file. 2008b7579f77SDag-Erling Smørgrav * If empty, provide builtin and write file. 2009b7579f77SDag-Erling Smørgrav * If trust-point-revoked-5011 file: make the program exit. 2010b7579f77SDag-Erling Smørgrav * @param root_anchor_file: filename of the root anchor. 2011b7579f77SDag-Erling Smørgrav * @param used_builtin: set to 1 if the builtin is written. 2012b7579f77SDag-Erling Smørgrav * @return 0 if trustpoint is insecure, 1 on success. Exit on failure. 2013b7579f77SDag-Erling Smørgrav */ 2014b7579f77SDag-Erling Smørgrav static int 2015*ebc5657fSDag-Erling Smørgrav provide_builtin(const char* root_anchor_file, int* used_builtin) 2016b7579f77SDag-Erling Smørgrav { 2017b7579f77SDag-Erling Smørgrav /* try to read it */ 2018b7579f77SDag-Erling Smørgrav switch(try_read_anchor(root_anchor_file)) 2019b7579f77SDag-Erling Smørgrav { 2020b7579f77SDag-Erling Smørgrav case 0: /* no exist or empty */ 2021b7579f77SDag-Erling Smørgrav write_builtin_anchor(root_anchor_file); 2022b7579f77SDag-Erling Smørgrav *used_builtin = 1; 2023b7579f77SDag-Erling Smørgrav break; 2024b7579f77SDag-Erling Smørgrav case 1: /* revoked tp */ 2025b7579f77SDag-Erling Smørgrav return 0; 2026b7579f77SDag-Erling Smørgrav case 2: /* it is fine */ 2027b7579f77SDag-Erling Smørgrav default: 2028b7579f77SDag-Erling Smørgrav break; 2029b7579f77SDag-Erling Smørgrav } 2030b7579f77SDag-Erling Smørgrav return 1; 2031b7579f77SDag-Erling Smørgrav } 2032b7579f77SDag-Erling Smørgrav 2033b7579f77SDag-Erling Smørgrav /** 2034b7579f77SDag-Erling Smørgrav * add an autotrust anchor for the root to the context 2035b7579f77SDag-Erling Smørgrav */ 2036b7579f77SDag-Erling Smørgrav static void 2037*ebc5657fSDag-Erling Smørgrav add_5011_probe_root(struct ub_ctx* ctx, const char* root_anchor_file) 2038b7579f77SDag-Erling Smørgrav { 2039b7579f77SDag-Erling Smørgrav int r; 2040b7579f77SDag-Erling Smørgrav r = ub_ctx_set_option(ctx, "auto-trust-anchor-file:", root_anchor_file); 2041b7579f77SDag-Erling Smørgrav if(r) { 2042b7579f77SDag-Erling Smørgrav if(verb) printf("add 5011 probe to ctx: %s\n", ub_strerror(r)); 2043b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 2044b7579f77SDag-Erling Smørgrav exit(0); 2045b7579f77SDag-Erling Smørgrav } 2046b7579f77SDag-Erling Smørgrav } 2047b7579f77SDag-Erling Smørgrav 2048b7579f77SDag-Erling Smørgrav /** 2049b7579f77SDag-Erling Smørgrav * Prime the root key and return the result. Exit on error. 2050b7579f77SDag-Erling Smørgrav * @param ctx: the unbound context to perform the priming with. 2051b7579f77SDag-Erling Smørgrav * @return: the result of the prime, on error it exit()s. 2052b7579f77SDag-Erling Smørgrav */ 2053b7579f77SDag-Erling Smørgrav static struct ub_result* 2054b7579f77SDag-Erling Smørgrav prime_root_key(struct ub_ctx* ctx) 2055b7579f77SDag-Erling Smørgrav { 2056b7579f77SDag-Erling Smørgrav struct ub_result* res = NULL; 2057b7579f77SDag-Erling Smørgrav int r; 2058b7579f77SDag-Erling Smørgrav r = ub_resolve(ctx, ".", LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN, &res); 2059b7579f77SDag-Erling Smørgrav if(r) { 2060b7579f77SDag-Erling Smørgrav if(verb) printf("resolve DNSKEY: %s\n", ub_strerror(r)); 2061b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 2062b7579f77SDag-Erling Smørgrav exit(0); 2063b7579f77SDag-Erling Smørgrav } 2064b7579f77SDag-Erling Smørgrav if(!res) { 2065b7579f77SDag-Erling Smørgrav if(verb) printf("out of memory\n"); 2066b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 2067b7579f77SDag-Erling Smørgrav exit(0); 2068b7579f77SDag-Erling Smørgrav } 2069b7579f77SDag-Erling Smørgrav return res; 2070b7579f77SDag-Erling Smørgrav } 2071b7579f77SDag-Erling Smørgrav 2072b7579f77SDag-Erling Smørgrav /** see if ADDPEND keys exist in autotrust file (if possible) */ 2073b7579f77SDag-Erling Smørgrav static int 2074*ebc5657fSDag-Erling Smørgrav read_if_pending_keys(const char* file) 2075b7579f77SDag-Erling Smørgrav { 2076b7579f77SDag-Erling Smørgrav FILE* in = fopen(file, "r"); 2077b7579f77SDag-Erling Smørgrav char line[8192]; 2078b7579f77SDag-Erling Smørgrav if(!in) { 2079b7579f77SDag-Erling Smørgrav if(verb>=2) printf("%s: %s\n", file, strerror(errno)); 2080b7579f77SDag-Erling Smørgrav return 0; 2081b7579f77SDag-Erling Smørgrav } 2082b7579f77SDag-Erling Smørgrav while(fgets(line, (int)sizeof(line), in)) { 2083b7579f77SDag-Erling Smørgrav if(line[0]==';') continue; 2084b7579f77SDag-Erling Smørgrav if(strstr(line, "[ ADDPEND ]")) { 2085b7579f77SDag-Erling Smørgrav fclose(in); 2086b7579f77SDag-Erling Smørgrav if(verb) printf("RFC5011-state has ADDPEND keys\n"); 2087b7579f77SDag-Erling Smørgrav return 1; 2088b7579f77SDag-Erling Smørgrav } 2089b7579f77SDag-Erling Smørgrav } 2090b7579f77SDag-Erling Smørgrav fclose(in); 2091b7579f77SDag-Erling Smørgrav return 0; 2092b7579f77SDag-Erling Smørgrav } 2093b7579f77SDag-Erling Smørgrav 2094b7579f77SDag-Erling Smørgrav /** read last successful probe time from autotrust file (if possible) */ 2095b7579f77SDag-Erling Smørgrav static int32_t 2096*ebc5657fSDag-Erling Smørgrav read_last_success_time(const char* file) 2097b7579f77SDag-Erling Smørgrav { 2098b7579f77SDag-Erling Smørgrav FILE* in = fopen(file, "r"); 2099b7579f77SDag-Erling Smørgrav char line[1024]; 2100b7579f77SDag-Erling Smørgrav if(!in) { 2101b7579f77SDag-Erling Smørgrav if(verb) printf("%s: %s\n", file, strerror(errno)); 2102b7579f77SDag-Erling Smørgrav return 0; 2103b7579f77SDag-Erling Smørgrav } 2104b7579f77SDag-Erling Smørgrav while(fgets(line, (int)sizeof(line), in)) { 2105b7579f77SDag-Erling Smørgrav if(strncmp(line, ";;last_success: ", 16) == 0) { 2106b7579f77SDag-Erling Smørgrav char* e; 2107b7579f77SDag-Erling Smørgrav time_t x = (unsigned int)strtol(line+16, &e, 10); 2108b7579f77SDag-Erling Smørgrav fclose(in); 2109b7579f77SDag-Erling Smørgrav if(line+16 == e) { 2110b7579f77SDag-Erling Smørgrav if(verb) printf("failed to parse " 2111b7579f77SDag-Erling Smørgrav "last_success probe time\n"); 2112b7579f77SDag-Erling Smørgrav return 0; 2113b7579f77SDag-Erling Smørgrav } 2114b7579f77SDag-Erling Smørgrav if(verb) printf("last successful probe: %s", ctime(&x)); 2115b7579f77SDag-Erling Smørgrav return (int32_t)x; 2116b7579f77SDag-Erling Smørgrav } 2117b7579f77SDag-Erling Smørgrav } 2118b7579f77SDag-Erling Smørgrav fclose(in); 2119b7579f77SDag-Erling Smørgrav if(verb) printf("no last_success probe time in anchor file\n"); 2120b7579f77SDag-Erling Smørgrav return 0; 2121b7579f77SDag-Erling Smørgrav } 2122b7579f77SDag-Erling Smørgrav 2123b7579f77SDag-Erling Smørgrav /** 2124b7579f77SDag-Erling Smørgrav * Read autotrust 5011 probe file and see if the date 2125b7579f77SDag-Erling Smørgrav * compared to the current date allows a certupdate. 2126b7579f77SDag-Erling Smørgrav * If the last successful probe was recent then 5011 cannot be behind, 2127b7579f77SDag-Erling Smørgrav * and the failure cannot be solved with a certupdate. 2128b7579f77SDag-Erling Smørgrav * The debugconf is to validation-override the date for testing. 2129b7579f77SDag-Erling Smørgrav * @param root_anchor_file: filename of root key 2130b7579f77SDag-Erling Smørgrav * @return true if certupdate is ok. 2131b7579f77SDag-Erling Smørgrav */ 2132b7579f77SDag-Erling Smørgrav static int 2133*ebc5657fSDag-Erling Smørgrav probe_date_allows_certupdate(const char* root_anchor_file) 2134b7579f77SDag-Erling Smørgrav { 2135b7579f77SDag-Erling Smørgrav int has_pending_keys = read_if_pending_keys(root_anchor_file); 2136b7579f77SDag-Erling Smørgrav int32_t last_success = read_last_success_time(root_anchor_file); 2137b7579f77SDag-Erling Smørgrav int32_t now = (int32_t)time(NULL); 2138b7579f77SDag-Erling Smørgrav int32_t leeway = 30 * 24 * 3600; /* 30 days leeway */ 2139b7579f77SDag-Erling Smørgrav /* if the date is before 2010-07-15:00.00.00 then the root has not 2140b7579f77SDag-Erling Smørgrav * been signed yet, and thus we refuse to take action. */ 2141b7579f77SDag-Erling Smørgrav if(time(NULL) < xml_convertdate("2010-07-15T00:00:00")) { 2142b7579f77SDag-Erling Smørgrav if(verb) printf("the date is before the root was first signed," 2143b7579f77SDag-Erling Smørgrav " please correct the clock\n"); 2144b7579f77SDag-Erling Smørgrav return 0; 2145b7579f77SDag-Erling Smørgrav } 2146b7579f77SDag-Erling Smørgrav if(last_success == 0) 2147b7579f77SDag-Erling Smørgrav return 1; /* no probe time */ 2148b7579f77SDag-Erling Smørgrav if(has_pending_keys) 2149b7579f77SDag-Erling Smørgrav return 1; /* key in ADDPEND state, a previous probe has 2150b7579f77SDag-Erling Smørgrav inserted that, and it was present in all recent probes, 2151b7579f77SDag-Erling Smørgrav but it has not become active. The 30 day timer may not have 2152b7579f77SDag-Erling Smørgrav expired, but we know(for sure) there is a rollover going on. 2153b7579f77SDag-Erling Smørgrav If we only managed to pickup the new key on its last day 2154b7579f77SDag-Erling Smørgrav of announcement (for example) this can happen. */ 2155b7579f77SDag-Erling Smørgrav if(now - last_success < 0) { 2156b7579f77SDag-Erling Smørgrav if(verb) printf("the last successful probe is in the future," 2157b7579f77SDag-Erling Smørgrav " clock was modified\n"); 2158b7579f77SDag-Erling Smørgrav return 0; 2159b7579f77SDag-Erling Smørgrav } 2160b7579f77SDag-Erling Smørgrav if(now - last_success >= leeway) { 2161b7579f77SDag-Erling Smørgrav if(verb) printf("the last successful probe was more than 30 " 2162b7579f77SDag-Erling Smørgrav "days ago\n"); 2163b7579f77SDag-Erling Smørgrav return 1; 2164b7579f77SDag-Erling Smørgrav } 2165b7579f77SDag-Erling Smørgrav if(verb) printf("the last successful probe is recent\n"); 2166b7579f77SDag-Erling Smørgrav return 0; 2167b7579f77SDag-Erling Smørgrav } 2168b7579f77SDag-Erling Smørgrav 2169b7579f77SDag-Erling Smørgrav /** perform the unbound-anchor work */ 2170b7579f77SDag-Erling Smørgrav static int 2171*ebc5657fSDag-Erling Smørgrav do_root_update_work(const char* root_anchor_file, const char* root_cert_file, 2172*ebc5657fSDag-Erling Smørgrav const char* urlname, const char* xmlname, const char* p7sname, 2173*ebc5657fSDag-Erling Smørgrav const char* p7signer, const char* res_conf, const char* root_hints, 2174*ebc5657fSDag-Erling Smørgrav const char* debugconf, int ip4only, int ip6only, int force, int port) 2175b7579f77SDag-Erling Smørgrav { 2176b7579f77SDag-Erling Smørgrav struct ub_ctx* ctx; 2177b7579f77SDag-Erling Smørgrav struct ub_result* dnskey; 2178b7579f77SDag-Erling Smørgrav int used_builtin = 0; 2179b7579f77SDag-Erling Smørgrav 2180b7579f77SDag-Erling Smørgrav /* see if builtin rootanchor needs to be provided, or if 2181b7579f77SDag-Erling Smørgrav * rootanchor is 'revoked-trust-point' */ 2182b7579f77SDag-Erling Smørgrav if(!provide_builtin(root_anchor_file, &used_builtin)) 2183b7579f77SDag-Erling Smørgrav return 0; 2184b7579f77SDag-Erling Smørgrav 2185b7579f77SDag-Erling Smørgrav /* make unbound context with 5011-probe for root anchor, 2186b7579f77SDag-Erling Smørgrav * and probe . DNSKEY */ 2187b7579f77SDag-Erling Smørgrav ctx = create_unbound_context(res_conf, root_hints, debugconf, 2188b7579f77SDag-Erling Smørgrav ip4only, ip6only); 2189b7579f77SDag-Erling Smørgrav add_5011_probe_root(ctx, root_anchor_file); 2190b7579f77SDag-Erling Smørgrav dnskey = prime_root_key(ctx); 2191b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 2192b7579f77SDag-Erling Smørgrav 2193b7579f77SDag-Erling Smørgrav /* if secure: exit */ 2194b7579f77SDag-Erling Smørgrav if(dnskey->secure && !force) { 2195b7579f77SDag-Erling Smørgrav if(verb) printf("success: the anchor is ok\n"); 2196b7579f77SDag-Erling Smørgrav ub_resolve_free(dnskey); 2197b7579f77SDag-Erling Smørgrav return used_builtin; 2198b7579f77SDag-Erling Smørgrav } 2199b7579f77SDag-Erling Smørgrav if(force && verb) printf("debug cert update forced\n"); 2200b7579f77SDag-Erling Smørgrav 2201b7579f77SDag-Erling Smørgrav /* if not (and NOERROR): check date and do certupdate */ 2202b7579f77SDag-Erling Smørgrav if((dnskey->rcode == 0 && 2203b7579f77SDag-Erling Smørgrav probe_date_allows_certupdate(root_anchor_file)) || force) { 2204b7579f77SDag-Erling Smørgrav if(do_certupdate(root_anchor_file, root_cert_file, urlname, 22058ed2b524SDag-Erling Smørgrav xmlname, p7sname, p7signer, res_conf, root_hints, 22068ed2b524SDag-Erling Smørgrav debugconf, ip4only, ip6only, port, dnskey)) 2207b7579f77SDag-Erling Smørgrav return 1; 2208b7579f77SDag-Erling Smørgrav return used_builtin; 2209b7579f77SDag-Erling Smørgrav } 2210b7579f77SDag-Erling Smørgrav if(verb) printf("fail: the anchor is NOT ok and could not be fixed\n"); 2211b7579f77SDag-Erling Smørgrav ub_resolve_free(dnskey); 2212b7579f77SDag-Erling Smørgrav return used_builtin; 2213b7579f77SDag-Erling Smørgrav } 2214b7579f77SDag-Erling Smørgrav 2215b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 2216b7579f77SDag-Erling Smørgrav extern int optind; 2217b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 2218b7579f77SDag-Erling Smørgrav extern char* optarg; 2219b7579f77SDag-Erling Smørgrav 2220b7579f77SDag-Erling Smørgrav /** Main routine for unbound-anchor */ 2221b7579f77SDag-Erling Smørgrav int main(int argc, char* argv[]) 2222b7579f77SDag-Erling Smørgrav { 2223b7579f77SDag-Erling Smørgrav int c; 2224*ebc5657fSDag-Erling Smørgrav const char* root_anchor_file = ROOT_ANCHOR_FILE; 2225*ebc5657fSDag-Erling Smørgrav const char* root_cert_file = ROOT_CERT_FILE; 2226*ebc5657fSDag-Erling Smørgrav const char* urlname = URLNAME; 2227*ebc5657fSDag-Erling Smørgrav const char* xmlname = XMLNAME; 2228*ebc5657fSDag-Erling Smørgrav const char* p7sname = P7SNAME; 2229*ebc5657fSDag-Erling Smørgrav const char* p7signer = P7SIGNER; 2230*ebc5657fSDag-Erling Smørgrav const char* res_conf = NULL; 2231*ebc5657fSDag-Erling Smørgrav const char* root_hints = NULL; 2232*ebc5657fSDag-Erling Smørgrav const char* debugconf = NULL; 2233b7579f77SDag-Erling Smørgrav int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT; 2234b7579f77SDag-Erling Smørgrav /* parse the options */ 22358ed2b524SDag-Erling Smørgrav while( (c=getopt(argc, argv, "46C:FP:a:c:f:hln:r:s:u:vx:")) != -1) { 2236b7579f77SDag-Erling Smørgrav switch(c) { 2237b7579f77SDag-Erling Smørgrav case 'l': 2238b7579f77SDag-Erling Smørgrav dolist = 1; 2239b7579f77SDag-Erling Smørgrav break; 2240b7579f77SDag-Erling Smørgrav case '4': 2241b7579f77SDag-Erling Smørgrav ip4only = 1; 2242b7579f77SDag-Erling Smørgrav break; 2243b7579f77SDag-Erling Smørgrav case '6': 2244b7579f77SDag-Erling Smørgrav ip6only = 1; 2245b7579f77SDag-Erling Smørgrav break; 2246b7579f77SDag-Erling Smørgrav case 'a': 2247b7579f77SDag-Erling Smørgrav root_anchor_file = optarg; 2248b7579f77SDag-Erling Smørgrav break; 2249b7579f77SDag-Erling Smørgrav case 'c': 2250b7579f77SDag-Erling Smørgrav root_cert_file = optarg; 2251b7579f77SDag-Erling Smørgrav break; 2252b7579f77SDag-Erling Smørgrav case 'u': 2253b7579f77SDag-Erling Smørgrav urlname = optarg; 2254b7579f77SDag-Erling Smørgrav break; 2255b7579f77SDag-Erling Smørgrav case 'x': 2256b7579f77SDag-Erling Smørgrav xmlname = optarg; 2257b7579f77SDag-Erling Smørgrav break; 2258b7579f77SDag-Erling Smørgrav case 's': 2259b7579f77SDag-Erling Smørgrav p7sname = optarg; 2260b7579f77SDag-Erling Smørgrav break; 22618ed2b524SDag-Erling Smørgrav case 'n': 22628ed2b524SDag-Erling Smørgrav p7signer = optarg; 22638ed2b524SDag-Erling Smørgrav break; 2264b7579f77SDag-Erling Smørgrav case 'f': 2265b7579f77SDag-Erling Smørgrav res_conf = optarg; 2266b7579f77SDag-Erling Smørgrav break; 2267b7579f77SDag-Erling Smørgrav case 'r': 2268b7579f77SDag-Erling Smørgrav root_hints = optarg; 2269b7579f77SDag-Erling Smørgrav break; 2270b7579f77SDag-Erling Smørgrav case 'C': 2271b7579f77SDag-Erling Smørgrav debugconf = optarg; 2272b7579f77SDag-Erling Smørgrav break; 2273b7579f77SDag-Erling Smørgrav case 'F': 2274b7579f77SDag-Erling Smørgrav force = 1; 2275b7579f77SDag-Erling Smørgrav break; 2276b7579f77SDag-Erling Smørgrav case 'P': 2277b7579f77SDag-Erling Smørgrav port = atoi(optarg); 2278b7579f77SDag-Erling Smørgrav break; 2279b7579f77SDag-Erling Smørgrav case 'v': 2280b7579f77SDag-Erling Smørgrav verb++; 2281b7579f77SDag-Erling Smørgrav break; 2282b7579f77SDag-Erling Smørgrav case '?': 2283b7579f77SDag-Erling Smørgrav case 'h': 2284b7579f77SDag-Erling Smørgrav default: 2285b7579f77SDag-Erling Smørgrav usage(); 2286b7579f77SDag-Erling Smørgrav } 2287b7579f77SDag-Erling Smørgrav } 2288b7579f77SDag-Erling Smørgrav argc -= optind; 2289b7579f77SDag-Erling Smørgrav argv += optind; 2290b7579f77SDag-Erling Smørgrav if(argc != 0) 2291b7579f77SDag-Erling Smørgrav usage(); 2292b7579f77SDag-Erling Smørgrav 2293b7579f77SDag-Erling Smørgrav ERR_load_crypto_strings(); 2294b7579f77SDag-Erling Smørgrav ERR_load_SSL_strings(); 2295b7579f77SDag-Erling Smørgrav OpenSSL_add_all_algorithms(); 2296b7579f77SDag-Erling Smørgrav (void)SSL_library_init(); 2297b7579f77SDag-Erling Smørgrav 2298b7579f77SDag-Erling Smørgrav if(dolist) do_list_builtin(); 2299b7579f77SDag-Erling Smørgrav 2300b7579f77SDag-Erling Smørgrav return do_root_update_work(root_anchor_file, root_cert_file, urlname, 23018ed2b524SDag-Erling Smørgrav xmlname, p7sname, p7signer, res_conf, root_hints, debugconf, 23028ed2b524SDag-Erling Smørgrav ip4only, ip6only, force, port); 2303b7579f77SDag-Erling Smørgrav } 2304