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