1*b7579f77SDag-Erling Smørgrav /* 2*b7579f77SDag-Erling Smørgrav * checkconf/unbound-host.c - replacement for host that supports validation. 3*b7579f77SDag-Erling Smørgrav * 4*b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, 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 performs functionality like 'host', and also supports validation. 40*b7579f77SDag-Erling Smørgrav * It uses the libunbound library. 41*b7579f77SDag-Erling Smørgrav */ 42*b7579f77SDag-Erling Smørgrav 43*b7579f77SDag-Erling Smørgrav #include "config.h" 44*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H 45*b7579f77SDag-Erling Smørgrav #include <getopt.h> 46*b7579f77SDag-Erling Smørgrav #endif 47*b7579f77SDag-Erling Smørgrav /* remove alloc checks, not in this part of the code */ 48*b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_ALLOC_STATS 49*b7579f77SDag-Erling Smørgrav #undef malloc 50*b7579f77SDag-Erling Smørgrav #undef calloc 51*b7579f77SDag-Erling Smørgrav #undef free 52*b7579f77SDag-Erling Smørgrav #undef realloc 53*b7579f77SDag-Erling Smørgrav #endif 54*b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_ALLOC_LITE 55*b7579f77SDag-Erling Smørgrav #undef malloc 56*b7579f77SDag-Erling Smørgrav #undef calloc 57*b7579f77SDag-Erling Smørgrav #undef free 58*b7579f77SDag-Erling Smørgrav #undef realloc 59*b7579f77SDag-Erling Smørgrav #undef strdup 60*b7579f77SDag-Erling Smørgrav #define unbound_lite_wrapstr(s) s 61*b7579f77SDag-Erling Smørgrav #endif 62*b7579f77SDag-Erling Smørgrav #include "libunbound/unbound.h" 63*b7579f77SDag-Erling Smørgrav #include <ldns/ldns.h> 64*b7579f77SDag-Erling Smørgrav 65*b7579f77SDag-Erling Smørgrav /** verbosity for unbound-host app */ 66*b7579f77SDag-Erling Smørgrav static int verb = 0; 67*b7579f77SDag-Erling Smørgrav 68*b7579f77SDag-Erling Smørgrav /** Give unbound-host usage, and exit (1). */ 69*b7579f77SDag-Erling Smørgrav static void 70*b7579f77SDag-Erling Smørgrav usage() 71*b7579f77SDag-Erling Smørgrav { 72*b7579f77SDag-Erling Smørgrav printf("Usage: unbound-host [-vdhr46] [-c class] [-t type] hostname\n"); 73*b7579f77SDag-Erling Smørgrav printf(" [-y key] [-f keyfile] [-F namedkeyfile]\n"); 74*b7579f77SDag-Erling Smørgrav printf(" [-C configfile]\n"); 75*b7579f77SDag-Erling Smørgrav printf(" Queries the DNS for information.\n"); 76*b7579f77SDag-Erling Smørgrav printf(" The hostname is looked up for IP4, IP6 and mail.\n"); 77*b7579f77SDag-Erling Smørgrav printf(" If an ip-address is given a reverse lookup is done.\n"); 78*b7579f77SDag-Erling Smørgrav printf(" Use the -v option to see DNSSEC security information.\n"); 79*b7579f77SDag-Erling Smørgrav printf(" -t type what type to look for.\n"); 80*b7579f77SDag-Erling Smørgrav printf(" -c class what class to look for, if not class IN.\n"); 81*b7579f77SDag-Erling Smørgrav printf(" -y 'keystring' specify trust anchor, DS or DNSKEY, like\n"); 82*b7579f77SDag-Erling Smørgrav printf(" -y 'example.com DS 31560 5 1 1CFED8478...'\n"); 83*b7579f77SDag-Erling Smørgrav printf(" -f keyfile read trust anchors from file, with lines as -y.\n"); 84*b7579f77SDag-Erling Smørgrav printf(" -F keyfile read named.conf-style trust anchors.\n"); 85*b7579f77SDag-Erling Smørgrav printf(" -C config use the specified unbound.conf (none read by default)\n"); 86*b7579f77SDag-Erling Smørgrav printf(" -r read forwarder information from /etc/resolv.conf\n"); 87*b7579f77SDag-Erling Smørgrav printf(" breaks validation if the fwder does not do DNSSEC.\n"); 88*b7579f77SDag-Erling Smørgrav printf(" -v be more verbose, shows nodata and security.\n"); 89*b7579f77SDag-Erling Smørgrav printf(" -d debug, traces the action, -d -d shows more.\n"); 90*b7579f77SDag-Erling Smørgrav printf(" -4 use ipv4 network, avoid ipv6.\n"); 91*b7579f77SDag-Erling Smørgrav printf(" -6 use ipv6 network, avoid ipv4.\n"); 92*b7579f77SDag-Erling Smørgrav printf(" -h show this usage help.\n"); 93*b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 94*b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 95*b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 96*b7579f77SDag-Erling Smørgrav exit(1); 97*b7579f77SDag-Erling Smørgrav } 98*b7579f77SDag-Erling Smørgrav 99*b7579f77SDag-Erling Smørgrav /** determine if str is ip4 and put into reverse lookup format */ 100*b7579f77SDag-Erling Smørgrav static int 101*b7579f77SDag-Erling Smørgrav isip4(const char* nm, char** res) 102*b7579f77SDag-Erling Smørgrav { 103*b7579f77SDag-Erling Smørgrav struct in_addr addr; 104*b7579f77SDag-Erling Smørgrav /* ddd.ddd.ddd.ddd.in-addr.arpa. is less than 32 */ 105*b7579f77SDag-Erling Smørgrav char buf[32]; 106*b7579f77SDag-Erling Smørgrav if(inet_pton(AF_INET, nm, &addr) <= 0) { 107*b7579f77SDag-Erling Smørgrav return 0; 108*b7579f77SDag-Erling Smørgrav } 109*b7579f77SDag-Erling Smørgrav snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa", 110*b7579f77SDag-Erling Smørgrav (unsigned)((uint8_t*)&addr)[3], (unsigned)((uint8_t*)&addr)[2], 111*b7579f77SDag-Erling Smørgrav (unsigned)((uint8_t*)&addr)[1], (unsigned)((uint8_t*)&addr)[0]); 112*b7579f77SDag-Erling Smørgrav *res = strdup(buf); 113*b7579f77SDag-Erling Smørgrav return 1; 114*b7579f77SDag-Erling Smørgrav } 115*b7579f77SDag-Erling Smørgrav 116*b7579f77SDag-Erling Smørgrav /** determine if str is ip6 and put into reverse lookup format */ 117*b7579f77SDag-Erling Smørgrav static int 118*b7579f77SDag-Erling Smørgrav isip6(const char* nm, char** res) 119*b7579f77SDag-Erling Smørgrav { 120*b7579f77SDag-Erling Smørgrav struct in6_addr addr; 121*b7579f77SDag-Erling Smørgrav /* [nibble.]{32}.ip6.arpa. is less than 128 */ 122*b7579f77SDag-Erling Smørgrav const char* hex = "0123456789abcdef"; 123*b7579f77SDag-Erling Smørgrav char buf[128]; 124*b7579f77SDag-Erling Smørgrav char *p; 125*b7579f77SDag-Erling Smørgrav int i; 126*b7579f77SDag-Erling Smørgrav if(inet_pton(AF_INET6, nm, &addr) <= 0) { 127*b7579f77SDag-Erling Smørgrav return 0; 128*b7579f77SDag-Erling Smørgrav } 129*b7579f77SDag-Erling Smørgrav p = buf; 130*b7579f77SDag-Erling Smørgrav for(i=15; i>=0; i--) { 131*b7579f77SDag-Erling Smørgrav uint8_t b = ((uint8_t*)&addr)[i]; 132*b7579f77SDag-Erling Smørgrav *p++ = hex[ (b&0x0f) ]; 133*b7579f77SDag-Erling Smørgrav *p++ = '.'; 134*b7579f77SDag-Erling Smørgrav *p++ = hex[ (b&0xf0) >> 4 ]; 135*b7579f77SDag-Erling Smørgrav *p++ = '.'; 136*b7579f77SDag-Erling Smørgrav } 137*b7579f77SDag-Erling Smørgrav snprintf(buf+16*4, sizeof(buf)-16*4, "ip6.arpa"); 138*b7579f77SDag-Erling Smørgrav *res = strdup(buf); 139*b7579f77SDag-Erling Smørgrav if(!*res) { 140*b7579f77SDag-Erling Smørgrav fprintf(stderr, "error: out of memory\n"); 141*b7579f77SDag-Erling Smørgrav exit(1); 142*b7579f77SDag-Erling Smørgrav } 143*b7579f77SDag-Erling Smørgrav return 1; 144*b7579f77SDag-Erling Smørgrav } 145*b7579f77SDag-Erling Smørgrav 146*b7579f77SDag-Erling Smørgrav /** massage input name */ 147*b7579f77SDag-Erling Smørgrav static char* 148*b7579f77SDag-Erling Smørgrav massage_qname(const char* nm, int* reverse) 149*b7579f77SDag-Erling Smørgrav { 150*b7579f77SDag-Erling Smørgrav /* recognise IP4 and IP6, create reverse addresses if needed */ 151*b7579f77SDag-Erling Smørgrav char* res; 152*b7579f77SDag-Erling Smørgrav if(isip4(nm, &res)) { 153*b7579f77SDag-Erling Smørgrav *reverse = 1; 154*b7579f77SDag-Erling Smørgrav } else if(isip6(nm, &res)) { 155*b7579f77SDag-Erling Smørgrav *reverse = 1; 156*b7579f77SDag-Erling Smørgrav } else { 157*b7579f77SDag-Erling Smørgrav res = strdup(nm); 158*b7579f77SDag-Erling Smørgrav } 159*b7579f77SDag-Erling Smørgrav if(!res) { 160*b7579f77SDag-Erling Smørgrav fprintf(stderr, "error: out of memory\n"); 161*b7579f77SDag-Erling Smørgrav exit(1); 162*b7579f77SDag-Erling Smørgrav } 163*b7579f77SDag-Erling Smørgrav return res; 164*b7579f77SDag-Erling Smørgrav } 165*b7579f77SDag-Erling Smørgrav 166*b7579f77SDag-Erling Smørgrav /** massage input type */ 167*b7579f77SDag-Erling Smørgrav static int 168*b7579f77SDag-Erling Smørgrav massage_type(const char* t, int reverse, int* multi) 169*b7579f77SDag-Erling Smørgrav { 170*b7579f77SDag-Erling Smørgrav if(t) { 171*b7579f77SDag-Erling Smørgrav int r = ldns_get_rr_type_by_name(t); 172*b7579f77SDag-Erling Smørgrav if(r == 0 && strcasecmp(t, "TYPE0") != 0 && 173*b7579f77SDag-Erling Smørgrav strcmp(t, "") != 0) { 174*b7579f77SDag-Erling Smørgrav fprintf(stderr, "error unknown type %s\n", t); 175*b7579f77SDag-Erling Smørgrav exit(1); 176*b7579f77SDag-Erling Smørgrav } 177*b7579f77SDag-Erling Smørgrav return r; 178*b7579f77SDag-Erling Smørgrav } 179*b7579f77SDag-Erling Smørgrav if(!t && reverse) 180*b7579f77SDag-Erling Smørgrav return LDNS_RR_TYPE_PTR; 181*b7579f77SDag-Erling Smørgrav *multi = 1; 182*b7579f77SDag-Erling Smørgrav return LDNS_RR_TYPE_A; 183*b7579f77SDag-Erling Smørgrav } 184*b7579f77SDag-Erling Smørgrav 185*b7579f77SDag-Erling Smørgrav /** massage input class */ 186*b7579f77SDag-Erling Smørgrav static int 187*b7579f77SDag-Erling Smørgrav massage_class(const char* c) 188*b7579f77SDag-Erling Smørgrav { 189*b7579f77SDag-Erling Smørgrav if(c) { 190*b7579f77SDag-Erling Smørgrav int r = ldns_get_rr_class_by_name(c); 191*b7579f77SDag-Erling Smørgrav if(r == 0 && strcasecmp(c, "CLASS0") != 0 && 192*b7579f77SDag-Erling Smørgrav strcmp(c, "") != 0) { 193*b7579f77SDag-Erling Smørgrav fprintf(stderr, "error unknown class %s\n", c); 194*b7579f77SDag-Erling Smørgrav exit(1); 195*b7579f77SDag-Erling Smørgrav } 196*b7579f77SDag-Erling Smørgrav return r; 197*b7579f77SDag-Erling Smørgrav } 198*b7579f77SDag-Erling Smørgrav return LDNS_RR_CLASS_IN; 199*b7579f77SDag-Erling Smørgrav } 200*b7579f77SDag-Erling Smørgrav 201*b7579f77SDag-Erling Smørgrav /** nice security status string */ 202*b7579f77SDag-Erling Smørgrav static const char* 203*b7579f77SDag-Erling Smørgrav secure_str(struct ub_result* result) 204*b7579f77SDag-Erling Smørgrav { 205*b7579f77SDag-Erling Smørgrav if(result->secure) return "(secure)"; 206*b7579f77SDag-Erling Smørgrav if(result->bogus) return "(BOGUS (security failure))"; 207*b7579f77SDag-Erling Smørgrav return "(insecure)"; 208*b7579f77SDag-Erling Smørgrav } 209*b7579f77SDag-Erling Smørgrav 210*b7579f77SDag-Erling Smørgrav /** nice string for type */ 211*b7579f77SDag-Erling Smørgrav static void 212*b7579f77SDag-Erling Smørgrav pretty_type(char* s, size_t len, int t) 213*b7579f77SDag-Erling Smørgrav { 214*b7579f77SDag-Erling Smørgrav char* d = ldns_rr_type2str(t); 215*b7579f77SDag-Erling Smørgrav snprintf(s, len, "%s", d); 216*b7579f77SDag-Erling Smørgrav free(d); 217*b7579f77SDag-Erling Smørgrav } 218*b7579f77SDag-Erling Smørgrav 219*b7579f77SDag-Erling Smørgrav /** nice string for class */ 220*b7579f77SDag-Erling Smørgrav static void 221*b7579f77SDag-Erling Smørgrav pretty_class(char* s, size_t len, int c) 222*b7579f77SDag-Erling Smørgrav { 223*b7579f77SDag-Erling Smørgrav char* d = ldns_rr_class2str(c); 224*b7579f77SDag-Erling Smørgrav snprintf(s, len, "%s", d); 225*b7579f77SDag-Erling Smørgrav free(d); 226*b7579f77SDag-Erling Smørgrav } 227*b7579f77SDag-Erling Smørgrav 228*b7579f77SDag-Erling Smørgrav /** nice string for rcode */ 229*b7579f77SDag-Erling Smørgrav static void 230*b7579f77SDag-Erling Smørgrav pretty_rcode(char* s, size_t len, int r) 231*b7579f77SDag-Erling Smørgrav { 232*b7579f77SDag-Erling Smørgrav ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes, r); 233*b7579f77SDag-Erling Smørgrav if(rcode) { 234*b7579f77SDag-Erling Smørgrav snprintf(s, len, "%s", rcode->name); 235*b7579f77SDag-Erling Smørgrav } else { 236*b7579f77SDag-Erling Smørgrav snprintf(s, len, "RCODE%d", r); 237*b7579f77SDag-Erling Smørgrav } 238*b7579f77SDag-Erling Smørgrav } 239*b7579f77SDag-Erling Smørgrav 240*b7579f77SDag-Erling Smørgrav /** convert and print rdata */ 241*b7579f77SDag-Erling Smørgrav static void 242*b7579f77SDag-Erling Smørgrav print_rd(int t, char* data, size_t len) 243*b7579f77SDag-Erling Smørgrav { 244*b7579f77SDag-Erling Smørgrav size_t i, pos = 0; 245*b7579f77SDag-Erling Smørgrav uint8_t* rd = (uint8_t*)malloc(len+2); 246*b7579f77SDag-Erling Smørgrav ldns_rr* rr = ldns_rr_new(); 247*b7579f77SDag-Erling Smørgrav ldns_status status; 248*b7579f77SDag-Erling Smørgrav if(!rd || !rr) { 249*b7579f77SDag-Erling Smørgrav fprintf(stderr, "out of memory"); 250*b7579f77SDag-Erling Smørgrav exit(1); 251*b7579f77SDag-Erling Smørgrav } 252*b7579f77SDag-Erling Smørgrav ldns_rr_set_type(rr, t); 253*b7579f77SDag-Erling Smørgrav ldns_write_uint16(rd, len); 254*b7579f77SDag-Erling Smørgrav memmove(rd+2, data, len); 255*b7579f77SDag-Erling Smørgrav ldns_rr_set_owner(rr, NULL); 256*b7579f77SDag-Erling Smørgrav status = ldns_wire2rdf(rr, rd, len+2, &pos); 257*b7579f77SDag-Erling Smørgrav if(status != LDNS_STATUS_OK) { 258*b7579f77SDag-Erling Smørgrav free(rd); 259*b7579f77SDag-Erling Smørgrav ldns_rr_free(rr); 260*b7579f77SDag-Erling Smørgrav printf("error_printing_data"); 261*b7579f77SDag-Erling Smørgrav return; 262*b7579f77SDag-Erling Smørgrav } 263*b7579f77SDag-Erling Smørgrav for(i=0; i<ldns_rr_rd_count(rr); i++) { 264*b7579f77SDag-Erling Smørgrav printf(" "); 265*b7579f77SDag-Erling Smørgrav ldns_rdf_print(stdout, ldns_rr_rdf(rr, i)); 266*b7579f77SDag-Erling Smørgrav } 267*b7579f77SDag-Erling Smørgrav ldns_rr_free(rr); 268*b7579f77SDag-Erling Smørgrav free(rd); 269*b7579f77SDag-Erling Smørgrav } 270*b7579f77SDag-Erling Smørgrav 271*b7579f77SDag-Erling Smørgrav /** pretty line of RR data for results */ 272*b7579f77SDag-Erling Smørgrav static void 273*b7579f77SDag-Erling Smørgrav pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec, 274*b7579f77SDag-Erling Smørgrav char* data, size_t len) 275*b7579f77SDag-Erling Smørgrav { 276*b7579f77SDag-Erling Smørgrav printf("%s", q); 277*b7579f77SDag-Erling Smørgrav if(strcmp(cstr, "IN") != 0) 278*b7579f77SDag-Erling Smørgrav printf(" in class %s", cstr); 279*b7579f77SDag-Erling Smørgrav if(t == LDNS_RR_TYPE_A) 280*b7579f77SDag-Erling Smørgrav printf(" has address"); 281*b7579f77SDag-Erling Smørgrav else if(t == LDNS_RR_TYPE_AAAA) 282*b7579f77SDag-Erling Smørgrav printf(" has IPv6 address"); 283*b7579f77SDag-Erling Smørgrav else if(t == LDNS_RR_TYPE_MX) 284*b7579f77SDag-Erling Smørgrav printf(" mail is handled by"); 285*b7579f77SDag-Erling Smørgrav else if(t == LDNS_RR_TYPE_PTR) 286*b7579f77SDag-Erling Smørgrav printf(" domain name pointer"); 287*b7579f77SDag-Erling Smørgrav else printf(" has %s record", tstr); 288*b7579f77SDag-Erling Smørgrav print_rd(t, data, len); 289*b7579f77SDag-Erling Smørgrav if(verb > 0) 290*b7579f77SDag-Erling Smørgrav printf(" %s", sec); 291*b7579f77SDag-Erling Smørgrav printf("\n"); 292*b7579f77SDag-Erling Smørgrav } 293*b7579f77SDag-Erling Smørgrav 294*b7579f77SDag-Erling Smørgrav /** pretty line of output for results */ 295*b7579f77SDag-Erling Smørgrav static void 296*b7579f77SDag-Erling Smørgrav pretty_output(char* q, int t, int c, struct ub_result* result, int docname) 297*b7579f77SDag-Erling Smørgrav { 298*b7579f77SDag-Erling Smørgrav int i; 299*b7579f77SDag-Erling Smørgrav const char *secstatus = secure_str(result); 300*b7579f77SDag-Erling Smørgrav char tstr[16]; 301*b7579f77SDag-Erling Smørgrav char cstr[16]; 302*b7579f77SDag-Erling Smørgrav char rcodestr[16]; 303*b7579f77SDag-Erling Smørgrav pretty_type(tstr, 16, t); 304*b7579f77SDag-Erling Smørgrav pretty_class(cstr, 16, c); 305*b7579f77SDag-Erling Smørgrav pretty_rcode(rcodestr, 16, result->rcode); 306*b7579f77SDag-Erling Smørgrav 307*b7579f77SDag-Erling Smørgrav if(!result->havedata && result->rcode) { 308*b7579f77SDag-Erling Smørgrav printf("Host %s not found: %d(%s).", 309*b7579f77SDag-Erling Smørgrav q, result->rcode, rcodestr); 310*b7579f77SDag-Erling Smørgrav if(verb > 0) 311*b7579f77SDag-Erling Smørgrav printf(" %s", secstatus); 312*b7579f77SDag-Erling Smørgrav printf("\n"); 313*b7579f77SDag-Erling Smørgrav if(result->bogus && result->why_bogus) 314*b7579f77SDag-Erling Smørgrav printf("%s\n", result->why_bogus); 315*b7579f77SDag-Erling Smørgrav return; 316*b7579f77SDag-Erling Smørgrav } 317*b7579f77SDag-Erling Smørgrav if(docname && result->canonname && 318*b7579f77SDag-Erling Smørgrav result->canonname != result->qname) { 319*b7579f77SDag-Erling Smørgrav printf("%s is an alias for %s", result->qname, 320*b7579f77SDag-Erling Smørgrav result->canonname); 321*b7579f77SDag-Erling Smørgrav if(verb > 0) 322*b7579f77SDag-Erling Smørgrav printf(" %s", secstatus); 323*b7579f77SDag-Erling Smørgrav printf("\n"); 324*b7579f77SDag-Erling Smørgrav } 325*b7579f77SDag-Erling Smørgrav /* remove trailing . from long canonnames for nicer output */ 326*b7579f77SDag-Erling Smørgrav if(result->canonname && strlen(result->canonname) > 1 && 327*b7579f77SDag-Erling Smørgrav result->canonname[strlen(result->canonname)-1] == '.') 328*b7579f77SDag-Erling Smørgrav result->canonname[strlen(result->canonname)-1] = 0; 329*b7579f77SDag-Erling Smørgrav if(!result->havedata) { 330*b7579f77SDag-Erling Smørgrav if(verb > 0) { 331*b7579f77SDag-Erling Smørgrav printf("%s", result->canonname?result->canonname:q); 332*b7579f77SDag-Erling Smørgrav if(strcmp(cstr, "IN") != 0) 333*b7579f77SDag-Erling Smørgrav printf(" in class %s", cstr); 334*b7579f77SDag-Erling Smørgrav if(t == LDNS_RR_TYPE_A) 335*b7579f77SDag-Erling Smørgrav printf(" has no address"); 336*b7579f77SDag-Erling Smørgrav else if(t == LDNS_RR_TYPE_AAAA) 337*b7579f77SDag-Erling Smørgrav printf(" has no IPv6 address"); 338*b7579f77SDag-Erling Smørgrav else if(t == LDNS_RR_TYPE_PTR) 339*b7579f77SDag-Erling Smørgrav printf(" has no domain name ptr"); 340*b7579f77SDag-Erling Smørgrav else if(t == LDNS_RR_TYPE_MX) 341*b7579f77SDag-Erling Smørgrav printf(" has no mail handler record"); 342*b7579f77SDag-Erling Smørgrav else if(t == LDNS_RR_TYPE_ANY) { 343*b7579f77SDag-Erling Smørgrav ldns_pkt* p = NULL; 344*b7579f77SDag-Erling Smørgrav if(ldns_wire2pkt(&p, result->answer_packet, 345*b7579f77SDag-Erling Smørgrav (size_t)result->answer_len)==LDNS_STATUS_OK){ 346*b7579f77SDag-Erling Smørgrav if(ldns_rr_list_rr_count( 347*b7579f77SDag-Erling Smørgrav ldns_pkt_answer(p)) == 0) 348*b7579f77SDag-Erling Smørgrav printf(" has no records\n"); 349*b7579f77SDag-Erling Smørgrav else { 350*b7579f77SDag-Erling Smørgrav printf(" ANY:\n"); 351*b7579f77SDag-Erling Smørgrav ldns_rr_list_print(stdout, 352*b7579f77SDag-Erling Smørgrav ldns_pkt_answer(p)); 353*b7579f77SDag-Erling Smørgrav } 354*b7579f77SDag-Erling Smørgrav } else { 355*b7579f77SDag-Erling Smørgrav fprintf(stderr, "could not parse " 356*b7579f77SDag-Erling Smørgrav "reply packet to ANY query\n"); 357*b7579f77SDag-Erling Smørgrav exit(1); 358*b7579f77SDag-Erling Smørgrav } 359*b7579f77SDag-Erling Smørgrav ldns_pkt_free(p); 360*b7579f77SDag-Erling Smørgrav 361*b7579f77SDag-Erling Smørgrav } else printf(" has no %s record", tstr); 362*b7579f77SDag-Erling Smørgrav printf(" %s\n", secstatus); 363*b7579f77SDag-Erling Smørgrav } 364*b7579f77SDag-Erling Smørgrav /* else: emptiness to indicate no data */ 365*b7579f77SDag-Erling Smørgrav if(result->bogus && result->why_bogus) 366*b7579f77SDag-Erling Smørgrav printf("%s\n", result->why_bogus); 367*b7579f77SDag-Erling Smørgrav return; 368*b7579f77SDag-Erling Smørgrav } 369*b7579f77SDag-Erling Smørgrav i=0; 370*b7579f77SDag-Erling Smørgrav while(result->data[i]) 371*b7579f77SDag-Erling Smørgrav { 372*b7579f77SDag-Erling Smørgrav pretty_rdata( 373*b7579f77SDag-Erling Smørgrav result->canonname?result->canonname:q, 374*b7579f77SDag-Erling Smørgrav cstr, tstr, t, secstatus, result->data[i], 375*b7579f77SDag-Erling Smørgrav (size_t)result->len[i]); 376*b7579f77SDag-Erling Smørgrav i++; 377*b7579f77SDag-Erling Smørgrav } 378*b7579f77SDag-Erling Smørgrav if(result->bogus && result->why_bogus) 379*b7579f77SDag-Erling Smørgrav printf("%s\n", result->why_bogus); 380*b7579f77SDag-Erling Smørgrav } 381*b7579f77SDag-Erling Smørgrav 382*b7579f77SDag-Erling Smørgrav /** perform a lookup and printout return if domain existed */ 383*b7579f77SDag-Erling Smørgrav static int 384*b7579f77SDag-Erling Smørgrav dnslook(struct ub_ctx* ctx, char* q, int t, int c, int docname) 385*b7579f77SDag-Erling Smørgrav { 386*b7579f77SDag-Erling Smørgrav int ret; 387*b7579f77SDag-Erling Smørgrav struct ub_result* result; 388*b7579f77SDag-Erling Smørgrav 389*b7579f77SDag-Erling Smørgrav ret = ub_resolve(ctx, q, t, c, &result); 390*b7579f77SDag-Erling Smørgrav if(ret != 0) { 391*b7579f77SDag-Erling Smørgrav fprintf(stderr, "resolve error: %s\n", ub_strerror(ret)); 392*b7579f77SDag-Erling Smørgrav exit(1); 393*b7579f77SDag-Erling Smørgrav } 394*b7579f77SDag-Erling Smørgrav pretty_output(q, t, c, result, docname); 395*b7579f77SDag-Erling Smørgrav ret = result->nxdomain; 396*b7579f77SDag-Erling Smørgrav ub_resolve_free(result); 397*b7579f77SDag-Erling Smørgrav return ret; 398*b7579f77SDag-Erling Smørgrav } 399*b7579f77SDag-Erling Smørgrav 400*b7579f77SDag-Erling Smørgrav /** perform host lookup */ 401*b7579f77SDag-Erling Smørgrav static void 402*b7579f77SDag-Erling Smørgrav lookup(struct ub_ctx* ctx, const char* nm, const char* qt, const char* qc) 403*b7579f77SDag-Erling Smørgrav { 404*b7579f77SDag-Erling Smørgrav /* massage input into a query name, type and class */ 405*b7579f77SDag-Erling Smørgrav int multi = 0; /* no type, so do A, AAAA, MX */ 406*b7579f77SDag-Erling Smørgrav int reverse = 0; /* we are doing a reverse lookup */ 407*b7579f77SDag-Erling Smørgrav char* realq = massage_qname(nm, &reverse); 408*b7579f77SDag-Erling Smørgrav int t = massage_type(qt, reverse, &multi); 409*b7579f77SDag-Erling Smørgrav int c = massage_class(qc); 410*b7579f77SDag-Erling Smørgrav 411*b7579f77SDag-Erling Smørgrav /* perform the query */ 412*b7579f77SDag-Erling Smørgrav if(multi) { 413*b7579f77SDag-Erling Smørgrav if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c, 1)) { 414*b7579f77SDag-Erling Smørgrav /* domain exists, lookup more */ 415*b7579f77SDag-Erling Smørgrav (void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0); 416*b7579f77SDag-Erling Smørgrav (void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0); 417*b7579f77SDag-Erling Smørgrav } 418*b7579f77SDag-Erling Smørgrav } else { 419*b7579f77SDag-Erling Smørgrav (void)dnslook(ctx, realq, t, c, 1); 420*b7579f77SDag-Erling Smørgrav } 421*b7579f77SDag-Erling Smørgrav ub_ctx_delete(ctx); 422*b7579f77SDag-Erling Smørgrav free(realq); 423*b7579f77SDag-Erling Smørgrav } 424*b7579f77SDag-Erling Smørgrav 425*b7579f77SDag-Erling Smørgrav /** print error if any */ 426*b7579f77SDag-Erling Smørgrav static void 427*b7579f77SDag-Erling Smørgrav check_ub_res(int r) 428*b7579f77SDag-Erling Smørgrav { 429*b7579f77SDag-Erling Smørgrav if(r != 0) { 430*b7579f77SDag-Erling Smørgrav fprintf(stderr, "error: %s\n", ub_strerror(r)); 431*b7579f77SDag-Erling Smørgrav exit(1); 432*b7579f77SDag-Erling Smørgrav } 433*b7579f77SDag-Erling Smørgrav } 434*b7579f77SDag-Erling Smørgrav 435*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 436*b7579f77SDag-Erling Smørgrav extern int optind; 437*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 438*b7579f77SDag-Erling Smørgrav extern char* optarg; 439*b7579f77SDag-Erling Smørgrav 440*b7579f77SDag-Erling Smørgrav /** Main routine for checkconf */ 441*b7579f77SDag-Erling Smørgrav int main(int argc, char* argv[]) 442*b7579f77SDag-Erling Smørgrav { 443*b7579f77SDag-Erling Smørgrav int c; 444*b7579f77SDag-Erling Smørgrav char* qclass = NULL; 445*b7579f77SDag-Erling Smørgrav char* qtype = NULL; 446*b7579f77SDag-Erling Smørgrav struct ub_ctx* ctx = NULL; 447*b7579f77SDag-Erling Smørgrav int debuglevel = 0; 448*b7579f77SDag-Erling Smørgrav 449*b7579f77SDag-Erling Smørgrav ctx = ub_ctx_create(); 450*b7579f77SDag-Erling Smørgrav if(!ctx) { 451*b7579f77SDag-Erling Smørgrav fprintf(stderr, "error: out of memory\n"); 452*b7579f77SDag-Erling Smørgrav exit(1); 453*b7579f77SDag-Erling Smørgrav } 454*b7579f77SDag-Erling Smørgrav 455*b7579f77SDag-Erling Smørgrav /* parse the options */ 456*b7579f77SDag-Erling Smørgrav while( (c=getopt(argc, argv, "46F:c:df:hrt:vy:C:")) != -1) { 457*b7579f77SDag-Erling Smørgrav switch(c) { 458*b7579f77SDag-Erling Smørgrav case '4': 459*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_set_option(ctx, "do-ip6:", "no")); 460*b7579f77SDag-Erling Smørgrav break; 461*b7579f77SDag-Erling Smørgrav case '6': 462*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_set_option(ctx, "do-ip4:", "no")); 463*b7579f77SDag-Erling Smørgrav break; 464*b7579f77SDag-Erling Smørgrav case 'c': 465*b7579f77SDag-Erling Smørgrav qclass = optarg; 466*b7579f77SDag-Erling Smørgrav break; 467*b7579f77SDag-Erling Smørgrav case 'C': 468*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_config(ctx, optarg)); 469*b7579f77SDag-Erling Smørgrav break; 470*b7579f77SDag-Erling Smørgrav case 'd': 471*b7579f77SDag-Erling Smørgrav debuglevel++; 472*b7579f77SDag-Erling Smørgrav if(debuglevel < 2) 473*b7579f77SDag-Erling Smørgrav debuglevel = 2; /* at least VERB_DETAIL */ 474*b7579f77SDag-Erling Smørgrav break; 475*b7579f77SDag-Erling Smørgrav case 'r': 476*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_resolvconf(ctx, "/etc/resolv.conf")); 477*b7579f77SDag-Erling Smørgrav break; 478*b7579f77SDag-Erling Smørgrav case 't': 479*b7579f77SDag-Erling Smørgrav qtype = optarg; 480*b7579f77SDag-Erling Smørgrav break; 481*b7579f77SDag-Erling Smørgrav case 'v': 482*b7579f77SDag-Erling Smørgrav verb++; 483*b7579f77SDag-Erling Smørgrav break; 484*b7579f77SDag-Erling Smørgrav case 'y': 485*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_add_ta(ctx, optarg)); 486*b7579f77SDag-Erling Smørgrav break; 487*b7579f77SDag-Erling Smørgrav case 'f': 488*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_add_ta_file(ctx, optarg)); 489*b7579f77SDag-Erling Smørgrav break; 490*b7579f77SDag-Erling Smørgrav case 'F': 491*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_trustedkeys(ctx, optarg)); 492*b7579f77SDag-Erling Smørgrav break; 493*b7579f77SDag-Erling Smørgrav case '?': 494*b7579f77SDag-Erling Smørgrav case 'h': 495*b7579f77SDag-Erling Smørgrav default: 496*b7579f77SDag-Erling Smørgrav usage(); 497*b7579f77SDag-Erling Smørgrav } 498*b7579f77SDag-Erling Smørgrav } 499*b7579f77SDag-Erling Smørgrav if(debuglevel != 0) /* set after possible -C options */ 500*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_debuglevel(ctx, debuglevel)); 501*b7579f77SDag-Erling Smørgrav if(ub_ctx_get_option(ctx, "use-syslog", &optarg) == 0) { 502*b7579f77SDag-Erling Smørgrav if(strcmp(optarg, "yes") == 0) /* disable use-syslog */ 503*b7579f77SDag-Erling Smørgrav check_ub_res(ub_ctx_set_option(ctx, 504*b7579f77SDag-Erling Smørgrav "use-syslog:", "no")); 505*b7579f77SDag-Erling Smørgrav free(optarg); 506*b7579f77SDag-Erling Smørgrav } 507*b7579f77SDag-Erling Smørgrav argc -= optind; 508*b7579f77SDag-Erling Smørgrav argv += optind; 509*b7579f77SDag-Erling Smørgrav if(argc != 1) 510*b7579f77SDag-Erling Smørgrav usage(); 511*b7579f77SDag-Erling Smørgrav 512*b7579f77SDag-Erling Smørgrav lookup(ctx, argv[0], qtype, qclass); 513*b7579f77SDag-Erling Smørgrav return 0; 514*b7579f77SDag-Erling Smørgrav } 515