1238106Sdes/* 2238106Sdes * checkconf/unbound-host.c - replacement for host that supports validation. 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33238106Sdes * POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file performs functionality like 'host', and also supports validation. 40238106Sdes * It uses the libunbound library. 41238106Sdes */ 42238106Sdes 43238106Sdes#include "config.h" 44238106Sdes#ifdef HAVE_GETOPT_H 45238106Sdes#include <getopt.h> 46238106Sdes#endif 47238106Sdes/* remove alloc checks, not in this part of the code */ 48238106Sdes#ifdef UNBOUND_ALLOC_STATS 49238106Sdes#undef malloc 50238106Sdes#undef calloc 51238106Sdes#undef free 52238106Sdes#undef realloc 53238106Sdes#endif 54238106Sdes#ifdef UNBOUND_ALLOC_LITE 55238106Sdes#undef malloc 56238106Sdes#undef calloc 57238106Sdes#undef free 58238106Sdes#undef realloc 59238106Sdes#undef strdup 60238106Sdes#define unbound_lite_wrapstr(s) s 61238106Sdes#endif 62238106Sdes#include "libunbound/unbound.h" 63238106Sdes#include <ldns/ldns.h> 64249141Sdes#ifdef HAVE_NSS 65249141Sdes/* nss3 */ 66249141Sdes#include "nss.h" 67249141Sdes#endif 68238106Sdes 69238106Sdes/** verbosity for unbound-host app */ 70238106Sdesstatic int verb = 0; 71238106Sdes 72238106Sdes/** Give unbound-host usage, and exit (1). */ 73238106Sdesstatic void 74238106Sdesusage() 75238106Sdes{ 76238106Sdes printf("Usage: unbound-host [-vdhr46] [-c class] [-t type] hostname\n"); 77238106Sdes printf(" [-y key] [-f keyfile] [-F namedkeyfile]\n"); 78238106Sdes printf(" [-C configfile]\n"); 79238106Sdes printf(" Queries the DNS for information.\n"); 80238106Sdes printf(" The hostname is looked up for IP4, IP6 and mail.\n"); 81238106Sdes printf(" If an ip-address is given a reverse lookup is done.\n"); 82238106Sdes printf(" Use the -v option to see DNSSEC security information.\n"); 83238106Sdes printf(" -t type what type to look for.\n"); 84238106Sdes printf(" -c class what class to look for, if not class IN.\n"); 85238106Sdes printf(" -y 'keystring' specify trust anchor, DS or DNSKEY, like\n"); 86238106Sdes printf(" -y 'example.com DS 31560 5 1 1CFED8478...'\n"); 87238106Sdes printf(" -f keyfile read trust anchors from file, with lines as -y.\n"); 88238106Sdes printf(" -F keyfile read named.conf-style trust anchors.\n"); 89238106Sdes printf(" -C config use the specified unbound.conf (none read by default)\n"); 90238106Sdes printf(" -r read forwarder information from /etc/resolv.conf\n"); 91238106Sdes printf(" breaks validation if the fwder does not do DNSSEC.\n"); 92238106Sdes printf(" -v be more verbose, shows nodata and security.\n"); 93238106Sdes printf(" -d debug, traces the action, -d -d shows more.\n"); 94238106Sdes printf(" -4 use ipv4 network, avoid ipv6.\n"); 95238106Sdes printf(" -6 use ipv6 network, avoid ipv4.\n"); 96238106Sdes printf(" -h show this usage help.\n"); 97238106Sdes printf("Version %s\n", PACKAGE_VERSION); 98238106Sdes printf("BSD licensed, see LICENSE in source package for details.\n"); 99238106Sdes printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 100238106Sdes exit(1); 101238106Sdes} 102238106Sdes 103238106Sdes/** determine if str is ip4 and put into reverse lookup format */ 104238106Sdesstatic int 105238106Sdesisip4(const char* nm, char** res) 106238106Sdes{ 107238106Sdes struct in_addr addr; 108238106Sdes /* ddd.ddd.ddd.ddd.in-addr.arpa. is less than 32 */ 109238106Sdes char buf[32]; 110238106Sdes if(inet_pton(AF_INET, nm, &addr) <= 0) { 111238106Sdes return 0; 112238106Sdes } 113238106Sdes snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa", 114238106Sdes (unsigned)((uint8_t*)&addr)[3], (unsigned)((uint8_t*)&addr)[2], 115238106Sdes (unsigned)((uint8_t*)&addr)[1], (unsigned)((uint8_t*)&addr)[0]); 116238106Sdes *res = strdup(buf); 117238106Sdes return 1; 118238106Sdes} 119238106Sdes 120238106Sdes/** determine if str is ip6 and put into reverse lookup format */ 121238106Sdesstatic int 122238106Sdesisip6(const char* nm, char** res) 123238106Sdes{ 124238106Sdes struct in6_addr addr; 125238106Sdes /* [nibble.]{32}.ip6.arpa. is less than 128 */ 126238106Sdes const char* hex = "0123456789abcdef"; 127238106Sdes char buf[128]; 128238106Sdes char *p; 129238106Sdes int i; 130238106Sdes if(inet_pton(AF_INET6, nm, &addr) <= 0) { 131238106Sdes return 0; 132238106Sdes } 133238106Sdes p = buf; 134238106Sdes for(i=15; i>=0; i--) { 135238106Sdes uint8_t b = ((uint8_t*)&addr)[i]; 136238106Sdes *p++ = hex[ (b&0x0f) ]; 137238106Sdes *p++ = '.'; 138238106Sdes *p++ = hex[ (b&0xf0) >> 4 ]; 139238106Sdes *p++ = '.'; 140238106Sdes } 141238106Sdes snprintf(buf+16*4, sizeof(buf)-16*4, "ip6.arpa"); 142238106Sdes *res = strdup(buf); 143238106Sdes if(!*res) { 144238106Sdes fprintf(stderr, "error: out of memory\n"); 145238106Sdes exit(1); 146238106Sdes } 147238106Sdes return 1; 148238106Sdes} 149238106Sdes 150238106Sdes/** massage input name */ 151238106Sdesstatic char* 152238106Sdesmassage_qname(const char* nm, int* reverse) 153238106Sdes{ 154238106Sdes /* recognise IP4 and IP6, create reverse addresses if needed */ 155238106Sdes char* res; 156238106Sdes if(isip4(nm, &res)) { 157238106Sdes *reverse = 1; 158238106Sdes } else if(isip6(nm, &res)) { 159238106Sdes *reverse = 1; 160238106Sdes } else { 161238106Sdes res = strdup(nm); 162238106Sdes } 163238106Sdes if(!res) { 164238106Sdes fprintf(stderr, "error: out of memory\n"); 165238106Sdes exit(1); 166238106Sdes } 167238106Sdes return res; 168238106Sdes} 169238106Sdes 170238106Sdes/** massage input type */ 171238106Sdesstatic int 172238106Sdesmassage_type(const char* t, int reverse, int* multi) 173238106Sdes{ 174238106Sdes if(t) { 175238106Sdes int r = ldns_get_rr_type_by_name(t); 176238106Sdes if(r == 0 && strcasecmp(t, "TYPE0") != 0 && 177238106Sdes strcmp(t, "") != 0) { 178238106Sdes fprintf(stderr, "error unknown type %s\n", t); 179238106Sdes exit(1); 180238106Sdes } 181238106Sdes return r; 182238106Sdes } 183238106Sdes if(!t && reverse) 184238106Sdes return LDNS_RR_TYPE_PTR; 185238106Sdes *multi = 1; 186238106Sdes return LDNS_RR_TYPE_A; 187238106Sdes} 188238106Sdes 189238106Sdes/** massage input class */ 190238106Sdesstatic int 191238106Sdesmassage_class(const char* c) 192238106Sdes{ 193238106Sdes if(c) { 194238106Sdes int r = ldns_get_rr_class_by_name(c); 195238106Sdes if(r == 0 && strcasecmp(c, "CLASS0") != 0 && 196238106Sdes strcmp(c, "") != 0) { 197238106Sdes fprintf(stderr, "error unknown class %s\n", c); 198238106Sdes exit(1); 199238106Sdes } 200238106Sdes return r; 201238106Sdes } 202238106Sdes return LDNS_RR_CLASS_IN; 203238106Sdes} 204238106Sdes 205238106Sdes/** nice security status string */ 206238106Sdesstatic const char* 207238106Sdessecure_str(struct ub_result* result) 208238106Sdes{ 209238106Sdes if(result->secure) return "(secure)"; 210238106Sdes if(result->bogus) return "(BOGUS (security failure))"; 211238106Sdes return "(insecure)"; 212238106Sdes} 213238106Sdes 214238106Sdes/** nice string for type */ 215238106Sdesstatic void 216238106Sdespretty_type(char* s, size_t len, int t) 217238106Sdes{ 218238106Sdes char* d = ldns_rr_type2str(t); 219238106Sdes snprintf(s, len, "%s", d); 220238106Sdes free(d); 221238106Sdes} 222238106Sdes 223238106Sdes/** nice string for class */ 224238106Sdesstatic void 225238106Sdespretty_class(char* s, size_t len, int c) 226238106Sdes{ 227238106Sdes char* d = ldns_rr_class2str(c); 228238106Sdes snprintf(s, len, "%s", d); 229238106Sdes free(d); 230238106Sdes} 231238106Sdes 232238106Sdes/** nice string for rcode */ 233238106Sdesstatic void 234238106Sdespretty_rcode(char* s, size_t len, int r) 235238106Sdes{ 236238106Sdes ldns_lookup_table *rcode = ldns_lookup_by_id(ldns_rcodes, r); 237238106Sdes if(rcode) { 238238106Sdes snprintf(s, len, "%s", rcode->name); 239238106Sdes } else { 240238106Sdes snprintf(s, len, "RCODE%d", r); 241238106Sdes } 242238106Sdes} 243238106Sdes 244238106Sdes/** convert and print rdata */ 245238106Sdesstatic void 246238106Sdesprint_rd(int t, char* data, size_t len) 247238106Sdes{ 248238106Sdes size_t i, pos = 0; 249238106Sdes uint8_t* rd = (uint8_t*)malloc(len+2); 250238106Sdes ldns_rr* rr = ldns_rr_new(); 251238106Sdes ldns_status status; 252238106Sdes if(!rd || !rr) { 253238106Sdes fprintf(stderr, "out of memory"); 254238106Sdes exit(1); 255238106Sdes } 256238106Sdes ldns_rr_set_type(rr, t); 257238106Sdes ldns_write_uint16(rd, len); 258238106Sdes memmove(rd+2, data, len); 259238106Sdes ldns_rr_set_owner(rr, NULL); 260238106Sdes status = ldns_wire2rdf(rr, rd, len+2, &pos); 261238106Sdes if(status != LDNS_STATUS_OK) { 262238106Sdes free(rd); 263238106Sdes ldns_rr_free(rr); 264238106Sdes printf("error_printing_data"); 265238106Sdes return; 266238106Sdes } 267238106Sdes for(i=0; i<ldns_rr_rd_count(rr); i++) { 268238106Sdes printf(" "); 269238106Sdes ldns_rdf_print(stdout, ldns_rr_rdf(rr, i)); 270238106Sdes } 271238106Sdes ldns_rr_free(rr); 272238106Sdes free(rd); 273238106Sdes} 274238106Sdes 275238106Sdes/** pretty line of RR data for results */ 276238106Sdesstatic void 277238106Sdespretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec, 278238106Sdes char* data, size_t len) 279238106Sdes{ 280238106Sdes printf("%s", q); 281238106Sdes if(strcmp(cstr, "IN") != 0) 282238106Sdes printf(" in class %s", cstr); 283238106Sdes if(t == LDNS_RR_TYPE_A) 284238106Sdes printf(" has address"); 285238106Sdes else if(t == LDNS_RR_TYPE_AAAA) 286238106Sdes printf(" has IPv6 address"); 287238106Sdes else if(t == LDNS_RR_TYPE_MX) 288238106Sdes printf(" mail is handled by"); 289238106Sdes else if(t == LDNS_RR_TYPE_PTR) 290238106Sdes printf(" domain name pointer"); 291238106Sdes else printf(" has %s record", tstr); 292238106Sdes print_rd(t, data, len); 293238106Sdes if(verb > 0) 294238106Sdes printf(" %s", sec); 295238106Sdes printf("\n"); 296238106Sdes} 297238106Sdes 298238106Sdes/** pretty line of output for results */ 299238106Sdesstatic void 300238106Sdespretty_output(char* q, int t, int c, struct ub_result* result, int docname) 301238106Sdes{ 302238106Sdes int i; 303238106Sdes const char *secstatus = secure_str(result); 304238106Sdes char tstr[16]; 305238106Sdes char cstr[16]; 306238106Sdes char rcodestr[16]; 307238106Sdes pretty_type(tstr, 16, t); 308238106Sdes pretty_class(cstr, 16, c); 309238106Sdes pretty_rcode(rcodestr, 16, result->rcode); 310238106Sdes 311238106Sdes if(!result->havedata && result->rcode) { 312238106Sdes printf("Host %s not found: %d(%s).", 313238106Sdes q, result->rcode, rcodestr); 314238106Sdes if(verb > 0) 315238106Sdes printf(" %s", secstatus); 316238106Sdes printf("\n"); 317238106Sdes if(result->bogus && result->why_bogus) 318238106Sdes printf("%s\n", result->why_bogus); 319238106Sdes return; 320238106Sdes } 321238106Sdes if(docname && result->canonname && 322238106Sdes result->canonname != result->qname) { 323238106Sdes printf("%s is an alias for %s", result->qname, 324238106Sdes result->canonname); 325238106Sdes if(verb > 0) 326238106Sdes printf(" %s", secstatus); 327238106Sdes printf("\n"); 328238106Sdes } 329238106Sdes /* remove trailing . from long canonnames for nicer output */ 330238106Sdes if(result->canonname && strlen(result->canonname) > 1 && 331238106Sdes result->canonname[strlen(result->canonname)-1] == '.') 332238106Sdes result->canonname[strlen(result->canonname)-1] = 0; 333238106Sdes if(!result->havedata) { 334238106Sdes if(verb > 0) { 335238106Sdes printf("%s", result->canonname?result->canonname:q); 336238106Sdes if(strcmp(cstr, "IN") != 0) 337238106Sdes printf(" in class %s", cstr); 338238106Sdes if(t == LDNS_RR_TYPE_A) 339238106Sdes printf(" has no address"); 340238106Sdes else if(t == LDNS_RR_TYPE_AAAA) 341238106Sdes printf(" has no IPv6 address"); 342238106Sdes else if(t == LDNS_RR_TYPE_PTR) 343238106Sdes printf(" has no domain name ptr"); 344238106Sdes else if(t == LDNS_RR_TYPE_MX) 345238106Sdes printf(" has no mail handler record"); 346238106Sdes else if(t == LDNS_RR_TYPE_ANY) { 347238106Sdes ldns_pkt* p = NULL; 348238106Sdes if(ldns_wire2pkt(&p, result->answer_packet, 349238106Sdes (size_t)result->answer_len)==LDNS_STATUS_OK){ 350238106Sdes if(ldns_rr_list_rr_count( 351238106Sdes ldns_pkt_answer(p)) == 0) 352238106Sdes printf(" has no records\n"); 353238106Sdes else { 354238106Sdes printf(" ANY:\n"); 355238106Sdes ldns_rr_list_print(stdout, 356238106Sdes ldns_pkt_answer(p)); 357238106Sdes } 358238106Sdes } else { 359238106Sdes fprintf(stderr, "could not parse " 360238106Sdes "reply packet to ANY query\n"); 361238106Sdes exit(1); 362238106Sdes } 363238106Sdes ldns_pkt_free(p); 364238106Sdes 365238106Sdes } else printf(" has no %s record", tstr); 366238106Sdes printf(" %s\n", secstatus); 367238106Sdes } 368238106Sdes /* else: emptiness to indicate no data */ 369238106Sdes if(result->bogus && result->why_bogus) 370238106Sdes printf("%s\n", result->why_bogus); 371238106Sdes return; 372238106Sdes } 373238106Sdes i=0; 374238106Sdes while(result->data[i]) 375238106Sdes { 376238106Sdes pretty_rdata( 377238106Sdes result->canonname?result->canonname:q, 378238106Sdes cstr, tstr, t, secstatus, result->data[i], 379238106Sdes (size_t)result->len[i]); 380238106Sdes i++; 381238106Sdes } 382238106Sdes if(result->bogus && result->why_bogus) 383238106Sdes printf("%s\n", result->why_bogus); 384238106Sdes} 385238106Sdes 386238106Sdes/** perform a lookup and printout return if domain existed */ 387238106Sdesstatic int 388238106Sdesdnslook(struct ub_ctx* ctx, char* q, int t, int c, int docname) 389238106Sdes{ 390238106Sdes int ret; 391238106Sdes struct ub_result* result; 392238106Sdes 393238106Sdes ret = ub_resolve(ctx, q, t, c, &result); 394238106Sdes if(ret != 0) { 395238106Sdes fprintf(stderr, "resolve error: %s\n", ub_strerror(ret)); 396238106Sdes exit(1); 397238106Sdes } 398238106Sdes pretty_output(q, t, c, result, docname); 399238106Sdes ret = result->nxdomain; 400238106Sdes ub_resolve_free(result); 401238106Sdes return ret; 402238106Sdes} 403238106Sdes 404238106Sdes/** perform host lookup */ 405238106Sdesstatic void 406238106Sdeslookup(struct ub_ctx* ctx, const char* nm, const char* qt, const char* qc) 407238106Sdes{ 408238106Sdes /* massage input into a query name, type and class */ 409238106Sdes int multi = 0; /* no type, so do A, AAAA, MX */ 410238106Sdes int reverse = 0; /* we are doing a reverse lookup */ 411238106Sdes char* realq = massage_qname(nm, &reverse); 412238106Sdes int t = massage_type(qt, reverse, &multi); 413238106Sdes int c = massage_class(qc); 414238106Sdes 415238106Sdes /* perform the query */ 416238106Sdes if(multi) { 417238106Sdes if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c, 1)) { 418238106Sdes /* domain exists, lookup more */ 419238106Sdes (void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0); 420238106Sdes (void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0); 421238106Sdes } 422238106Sdes } else { 423238106Sdes (void)dnslook(ctx, realq, t, c, 1); 424238106Sdes } 425238106Sdes ub_ctx_delete(ctx); 426238106Sdes free(realq); 427238106Sdes} 428238106Sdes 429238106Sdes/** print error if any */ 430238106Sdesstatic void 431238106Sdescheck_ub_res(int r) 432238106Sdes{ 433238106Sdes if(r != 0) { 434238106Sdes fprintf(stderr, "error: %s\n", ub_strerror(r)); 435238106Sdes exit(1); 436238106Sdes } 437238106Sdes} 438238106Sdes 439238106Sdes/** getopt global, in case header files fail to declare it. */ 440238106Sdesextern int optind; 441238106Sdes/** getopt global, in case header files fail to declare it. */ 442238106Sdesextern char* optarg; 443238106Sdes 444238106Sdes/** Main routine for checkconf */ 445238106Sdesint main(int argc, char* argv[]) 446238106Sdes{ 447238106Sdes int c; 448238106Sdes char* qclass = NULL; 449238106Sdes char* qtype = NULL; 450238106Sdes struct ub_ctx* ctx = NULL; 451238106Sdes int debuglevel = 0; 452238106Sdes 453238106Sdes ctx = ub_ctx_create(); 454238106Sdes if(!ctx) { 455238106Sdes fprintf(stderr, "error: out of memory\n"); 456238106Sdes exit(1); 457238106Sdes } 458238106Sdes 459238106Sdes /* parse the options */ 460238106Sdes while( (c=getopt(argc, argv, "46F:c:df:hrt:vy:C:")) != -1) { 461238106Sdes switch(c) { 462238106Sdes case '4': 463238106Sdes check_ub_res(ub_ctx_set_option(ctx, "do-ip6:", "no")); 464238106Sdes break; 465238106Sdes case '6': 466238106Sdes check_ub_res(ub_ctx_set_option(ctx, "do-ip4:", "no")); 467238106Sdes break; 468238106Sdes case 'c': 469238106Sdes qclass = optarg; 470238106Sdes break; 471238106Sdes case 'C': 472238106Sdes check_ub_res(ub_ctx_config(ctx, optarg)); 473238106Sdes break; 474238106Sdes case 'd': 475238106Sdes debuglevel++; 476238106Sdes if(debuglevel < 2) 477238106Sdes debuglevel = 2; /* at least VERB_DETAIL */ 478238106Sdes break; 479238106Sdes case 'r': 480238106Sdes check_ub_res(ub_ctx_resolvconf(ctx, "/etc/resolv.conf")); 481238106Sdes break; 482238106Sdes case 't': 483238106Sdes qtype = optarg; 484238106Sdes break; 485238106Sdes case 'v': 486238106Sdes verb++; 487238106Sdes break; 488238106Sdes case 'y': 489238106Sdes check_ub_res(ub_ctx_add_ta(ctx, optarg)); 490238106Sdes break; 491238106Sdes case 'f': 492238106Sdes check_ub_res(ub_ctx_add_ta_file(ctx, optarg)); 493238106Sdes break; 494238106Sdes case 'F': 495238106Sdes check_ub_res(ub_ctx_trustedkeys(ctx, optarg)); 496238106Sdes break; 497238106Sdes case '?': 498238106Sdes case 'h': 499238106Sdes default: 500238106Sdes usage(); 501238106Sdes } 502238106Sdes } 503238106Sdes if(debuglevel != 0) /* set after possible -C options */ 504238106Sdes check_ub_res(ub_ctx_debuglevel(ctx, debuglevel)); 505238106Sdes if(ub_ctx_get_option(ctx, "use-syslog", &optarg) == 0) { 506238106Sdes if(strcmp(optarg, "yes") == 0) /* disable use-syslog */ 507238106Sdes check_ub_res(ub_ctx_set_option(ctx, 508238106Sdes "use-syslog:", "no")); 509238106Sdes free(optarg); 510238106Sdes } 511238106Sdes argc -= optind; 512238106Sdes argv += optind; 513238106Sdes if(argc != 1) 514238106Sdes usage(); 515238106Sdes 516249141Sdes#ifdef HAVE_NSS 517249141Sdes if(NSS_NoDB_Init(".") != SECSuccess) { 518249141Sdes fprintf(stderr, "could not init NSS\n"); 519249141Sdes return 1; 520249141Sdes } 521249141Sdes#endif 522238106Sdes lookup(ctx, argv[0], qtype, qclass); 523238106Sdes return 0; 524238106Sdes} 525