1238104Sdes/* 2238104Sdes * drill.c 3238104Sdes * the main file of drill 4238104Sdes * (c) 2005-2008 NLnet Labs 5238104Sdes * 6238104Sdes * See the file LICENSE for the license 7238104Sdes * 8238104Sdes */ 9238104Sdes 10238104Sdes#include "drill.h" 11238104Sdes#include <ldns/ldns.h> 12238104Sdes 13238104Sdes#ifdef HAVE_SSL 14238104Sdes#include <openssl/err.h> 15238104Sdes#endif 16238104Sdes 17238104Sdes#define IP6_ARPA_MAX_LEN 65 18238104Sdes 19238104Sdes/* query debug, 2 hex dumps */ 20238104Sdesint verbosity; 21238104Sdes 22238104Sdesstatic void 23238104Sdesusage(FILE *stream, const char *progname) 24238104Sdes{ 25238104Sdes fprintf(stream, " Usage: %s name [@server] [type] [class]\n", progname); 26238104Sdes fprintf(stream, "\t<name> can be a domain name or an IP address (-x lookups)\n"); 27238104Sdes fprintf(stream, "\t<type> defaults to A\n"); 28238104Sdes fprintf(stream, "\t<class> defaults to IN\n"); 29238104Sdes fprintf(stream, "\n\targuments may be placed in random order\n"); 30238104Sdes fprintf(stream, "\n Options:\n"); 31238104Sdes fprintf(stream, "\t-D\t\tenable DNSSEC (DO bit)\n"); 32238104Sdes#ifdef HAVE_SSL 33238104Sdes fprintf(stream, "\t-T\t\ttrace from the root down to <name>\n"); 34238104Sdes fprintf(stream, "\t-S\t\tchase signature(s) from <name> to a know key [*]\n"); 35238104Sdes#endif /*HAVE_SSL*/ 36269257Sdes fprintf(stream, "\t-I <address>\tsource address to query from\n"); 37238104Sdes fprintf(stream, "\t-V <number>\tverbosity (0-5)\n"); 38238104Sdes fprintf(stream, "\t-Q\t\tquiet mode (overrules -V)\n"); 39238104Sdes fprintf(stream, "\n"); 40238104Sdes fprintf(stream, "\t-f file\t\tread packet from file and send it\n"); 41238104Sdes fprintf(stream, "\t-i file\t\tread packet from file and print it\n"); 42238104Sdes fprintf(stream, "\t-w file\t\twrite answer packet to file\n"); 43238104Sdes fprintf(stream, "\t-q file\t\twrite query packet to file\n"); 44238104Sdes fprintf(stream, "\t-h\t\tshow this help\n"); 45238104Sdes fprintf(stream, "\t-v\t\tshow version\n"); 46238104Sdes fprintf(stream, "\n Query options:\n"); 47238104Sdes fprintf(stream, "\t-4\t\tstay on ip4\n"); 48238104Sdes fprintf(stream, "\t-6\t\tstay on ip6\n"); 49238104Sdes fprintf(stream, "\t-a\t\tfallback to EDNS0 and TCP if the answer is truncated\n"); 50238104Sdes fprintf(stream, "\t-b <bufsize>\tuse <bufsize> as the buffer size (defaults to 512 b)\n"); 51246854Sdes fprintf(stream, "\t-c <file>\tuse file for rescursive nameserver configuration" 52246854Sdes "\n\t\t\t(/etc/resolv.conf)\n"); 53246854Sdes fprintf(stream, "\t-k <file>\tspecify a file that contains a trusted DNSSEC key [**]\n"); 54246854Sdes fprintf(stream, "\t\t\tUsed to verify any signatures in the current answer.\n"); 55246854Sdes fprintf(stream, "\t\t\tWhen DNSSEC enabled tracing (-TD) or signature\n" 56246854Sdes "\t\t\tchasing (-S) and no key files are given, keys are read\n" 57246854Sdes "\t\t\tfrom: %s\n", 58246854Sdes LDNS_TRUST_ANCHOR_FILE); 59246854Sdes fprintf(stream, "\t-o <mnemonic>\tset flags to:" 60246854Sdes "\n\t\t\t[QR|qr][AA|aa][TC|tc][RD|rd][CD|cd][RA|ra][AD|ad]\n"); 61238104Sdes fprintf(stream, "\t\t\tlowercase: unset bit, uppercase: set bit\n"); 62238104Sdes fprintf(stream, "\t-p <port>\tuse <port> as remote port number\n"); 63238104Sdes fprintf(stream, "\t-s\t\tshow the DS RR for each key in a packet\n"); 64238104Sdes fprintf(stream, "\t-u\t\tsend the query with udp (the default)\n"); 65238104Sdes fprintf(stream, "\t-x\t\tdo a reverse lookup\n"); 66238104Sdes fprintf(stream, "\twhen doing a secure trace:\n"); 67246854Sdes fprintf(stream, "\t-r <file>\tuse file as root servers hint file\n"); 68238104Sdes fprintf(stream, "\t-t\t\tsend the query with tcp (connected)\n"); 69246854Sdes fprintf(stream, "\t-d <domain>\tuse domain as the start point for the trace\n"); 70238104Sdes fprintf(stream, "\t-y <name:key[:algo]>\tspecify named base64 tsig key, and optional an\n\t\t\talgorithm (defaults to hmac-md5.sig-alg.reg.int)\n"); 71238104Sdes fprintf(stream, "\t-z\t\tdon't randomize the nameservers before use\n"); 72238104Sdes fprintf(stream, "\n [*] = enables/implies DNSSEC\n"); 73238104Sdes fprintf(stream, " [**] = can be given more than once\n"); 74238104Sdes fprintf(stream, "\n ldns-team@nlnetlabs.nl | http://www.nlnetlabs.nl/ldns/\n"); 75238104Sdes} 76238104Sdes 77238104Sdes/** 78238104Sdes * Prints the drill version to stderr 79238104Sdes */ 80238104Sdesstatic void 81238104Sdesversion(FILE *stream, const char *progname) 82238104Sdes{ 83238104Sdes fprintf(stream, "%s version %s (ldns version %s)\n", progname, DRILL_VERSION, ldns_version()); 84238104Sdes fprintf(stream, "Written by NLnet Labs.\n"); 85238104Sdes fprintf(stream, "\nCopyright (c) 2004-2008 NLnet Labs.\n"); 86238104Sdes fprintf(stream, "Licensed under the revised BSD license.\n"); 87238104Sdes fprintf(stream, "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"); 88238104Sdes fprintf(stream, "FOR A PARTICULAR PURPOSE.\n"); 89238104Sdes} 90238104Sdes 91238104Sdes 92238104Sdes/** 93238104Sdes * Main function of drill 94238104Sdes * parse the arguments and prepare a query 95238104Sdes */ 96238104Sdesint 97238104Sdesmain(int argc, char *argv[]) 98238104Sdes{ 99238104Sdes ldns_resolver *res = NULL; 100238104Sdes ldns_resolver *cmdline_res = NULL; /* only used to resolv @name names */ 101238104Sdes ldns_rr_list *cmdline_rr_list = NULL; 102238104Sdes ldns_rdf *cmdline_dname = NULL; 103238104Sdes ldns_rdf *qname, *qname_tmp; 104238104Sdes ldns_pkt *pkt; 105238104Sdes ldns_pkt *qpkt; 106238104Sdes char *serv; 107269257Sdes char *src = NULL; 108238104Sdes const char *name; 109238104Sdes char *name2; 110238104Sdes char *progname; 111238104Sdes char *query_file = NULL; 112238104Sdes char *answer_file = NULL; 113238104Sdes ldns_buffer *query_buffer = NULL; 114238104Sdes ldns_rdf *serv_rdf; 115269257Sdes ldns_rdf *src_rdf = NULL; 116238104Sdes ldns_rr_type type; 117238104Sdes ldns_rr_class clas; 118238104Sdes#if 0 119238104Sdes ldns_pkt_opcode opcode = LDNS_PACKET_QUERY; 120238104Sdes#endif 121238104Sdes int i, c; 122238104Sdes int int_type; 123238104Sdes int int_clas; 124238104Sdes int PURPOSE; 125238104Sdes char *tsig_name = NULL; 126238104Sdes char *tsig_data = NULL; 127238104Sdes char *tsig_algorithm = NULL; 128238104Sdes size_t tsig_separator; 129238104Sdes size_t tsig_separator2; 130238104Sdes ldns_rr *axfr_rr; 131238104Sdes ldns_status status; 132238104Sdes char *type_str; 133238104Sdes 134238104Sdes /* list of keys used in dnssec operations */ 135238104Sdes ldns_rr_list *key_list = ldns_rr_list_new(); 136238104Sdes /* what key verify the current answer */ 137238104Sdes ldns_rr_list *key_verified; 138238104Sdes 139238104Sdes /* resolver options */ 140238104Sdes uint16_t qflags; 141238104Sdes uint16_t qbuf; 142238104Sdes uint16_t qport; 143238104Sdes uint8_t qfamily; 144238104Sdes bool qdnssec; 145238104Sdes bool qfallback; 146238104Sdes bool qds; 147238104Sdes bool qusevc; 148238104Sdes bool qrandom; 149238104Sdes 150238104Sdes char *resolv_conf_file = NULL; 151238104Sdes 152238104Sdes ldns_rdf *trace_start_name = NULL; 153238104Sdes 154238104Sdes int result = 0; 155238104Sdes 156238104Sdes#ifdef USE_WINSOCK 157238104Sdes int r; 158238104Sdes WSADATA wsa_data; 159238104Sdes#endif 160238104Sdes 161238104Sdes int_type = -1; serv = NULL; type = 0; 162238104Sdes int_clas = -1; name = NULL; clas = 0; 163269257Sdes qname = NULL; src = NULL; 164238104Sdes progname = strdup(argv[0]); 165238104Sdes 166238104Sdes#ifdef USE_WINSOCK 167238104Sdes r = WSAStartup(MAKEWORD(2,2), &wsa_data); 168238104Sdes if(r != 0) { 169238104Sdes printf("Failed WSAStartup: %d\n", r); 170238104Sdes result = EXIT_FAILURE; 171238104Sdes goto exit; 172238104Sdes } 173238104Sdes#endif /* USE_WINSOCK */ 174238104Sdes 175238104Sdes 176238104Sdes PURPOSE = DRILL_QUERY; 177238104Sdes qflags = LDNS_RD; 178238104Sdes qport = LDNS_PORT; 179238104Sdes verbosity = 2; 180238104Sdes qdnssec = false; 181238104Sdes qfamily = LDNS_RESOLV_INETANY; 182238104Sdes qfallback = false; 183238104Sdes qds = false; 184238104Sdes qbuf = 0; 185238104Sdes qusevc = false; 186238104Sdes qrandom = true; 187238104Sdes key_verified = NULL; 188238104Sdes 189238104Sdes ldns_init_random(NULL, 0); 190238104Sdes 191238104Sdes if (argc == 0) { 192238104Sdes usage(stdout, progname); 193238104Sdes result = EXIT_FAILURE; 194238104Sdes goto exit; 195238104Sdes } 196238104Sdes 197238104Sdes /* string from orig drill: "i:w:I46Sk:TNp:b:DsvhVcuaq:f:xr" */ 198238104Sdes /* global first, query opt next, option with parm's last 199238104Sdes * and sorted */ /* "46DITSVQf:i:w:q:achuvxzy:so:p:b:k:" */ 200238104Sdes 201269257Sdes while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:I:k:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) { 202238104Sdes switch(c) { 203238104Sdes /* global options */ 204238104Sdes case '4': 205238104Sdes qfamily = LDNS_RESOLV_INET; 206238104Sdes break; 207238104Sdes case '6': 208238104Sdes qfamily = LDNS_RESOLV_INET6; 209238104Sdes break; 210238104Sdes case 'D': 211238104Sdes qdnssec = true; 212238104Sdes break; 213238104Sdes case 'I': 214269257Sdes src = optarg; 215238104Sdes break; 216238104Sdes case 'T': 217238104Sdes if (PURPOSE == DRILL_CHASE) { 218238104Sdes fprintf(stderr, "-T and -S cannot be used at the same time.\n"); 219238104Sdes exit(EXIT_FAILURE); 220238104Sdes } 221238104Sdes PURPOSE = DRILL_TRACE; 222238104Sdes break; 223238104Sdes#ifdef HAVE_SSL 224238104Sdes case 'S': 225238104Sdes if (PURPOSE == DRILL_TRACE) { 226238104Sdes fprintf(stderr, "-T and -S cannot be used at the same time.\n"); 227238104Sdes exit(EXIT_FAILURE); 228238104Sdes } 229238104Sdes PURPOSE = DRILL_CHASE; 230238104Sdes break; 231238104Sdes#endif /* HAVE_SSL */ 232238104Sdes case 'V': 233238104Sdes if (strtok(optarg, "0123456789") != NULL) { 234238104Sdes fprintf(stderr, "-V expects an number as an argument.\n"); 235238104Sdes exit(EXIT_FAILURE); 236238104Sdes } 237238104Sdes verbosity = atoi(optarg); 238238104Sdes break; 239238104Sdes case 'Q': 240238104Sdes verbosity = -1; 241238104Sdes break; 242238104Sdes case 'f': 243238104Sdes query_file = optarg; 244238104Sdes break; 245238104Sdes case 'i': 246238104Sdes answer_file = optarg; 247238104Sdes PURPOSE = DRILL_AFROMFILE; 248238104Sdes break; 249238104Sdes case 'w': 250238104Sdes answer_file = optarg; 251238104Sdes break; 252238104Sdes case 'q': 253238104Sdes query_file = optarg; 254238104Sdes PURPOSE = DRILL_QTOFILE; 255238104Sdes break; 256238104Sdes case 'r': 257238104Sdes if (global_dns_root) { 258238104Sdes fprintf(stderr, "There was already a series of root servers set\n"); 259238104Sdes exit(EXIT_FAILURE); 260238104Sdes } 261238104Sdes global_dns_root = read_root_hints(optarg); 262238104Sdes if (!global_dns_root) { 263238104Sdes fprintf(stderr, "Unable to read root hints file %s, aborting\n", optarg); 264238104Sdes exit(EXIT_FAILURE); 265238104Sdes } 266238104Sdes break; 267238104Sdes /* query options */ 268238104Sdes case 'a': 269238104Sdes qfallback = true; 270238104Sdes break; 271238104Sdes case 'b': 272238104Sdes qbuf = (uint16_t)atoi(optarg); 273238104Sdes if (qbuf == 0) { 274238104Sdes error("%s", "<bufsize> could not be converted"); 275238104Sdes } 276238104Sdes break; 277238104Sdes case 'c': 278238104Sdes resolv_conf_file = optarg; 279238104Sdes break; 280238104Sdes case 't': 281238104Sdes qusevc = true; 282238104Sdes break; 283238104Sdes case 'k': 284246854Sdes status = read_key_file(optarg, 285246854Sdes key_list, false); 286238104Sdes if (status != LDNS_STATUS_OK) { 287238104Sdes error("Could not parse the key file %s: %s", optarg, ldns_get_errorstr_by_id(status)); 288238104Sdes } 289238104Sdes qdnssec = true; /* enable that too */ 290238104Sdes break; 291238104Sdes case 'o': 292238104Sdes /* only looks at the first hit: capital=ON, lowercase=OFF*/ 293238104Sdes if (strstr(optarg, "QR")) { 294238104Sdes DRILL_ON(qflags, LDNS_QR); 295238104Sdes } 296238104Sdes if (strstr(optarg, "qr")) { 297238104Sdes DRILL_OFF(qflags, LDNS_QR); 298238104Sdes } 299238104Sdes if (strstr(optarg, "AA")) { 300238104Sdes DRILL_ON(qflags, LDNS_AA); 301238104Sdes } 302238104Sdes if (strstr(optarg, "aa")) { 303238104Sdes DRILL_OFF(qflags, LDNS_AA); 304238104Sdes } 305238104Sdes if (strstr(optarg, "TC")) { 306238104Sdes DRILL_ON(qflags, LDNS_TC); 307238104Sdes } 308238104Sdes if (strstr(optarg, "tc")) { 309238104Sdes DRILL_OFF(qflags, LDNS_TC); 310238104Sdes } 311238104Sdes if (strstr(optarg, "RD")) { 312238104Sdes DRILL_ON(qflags, LDNS_RD); 313238104Sdes } 314238104Sdes if (strstr(optarg, "rd")) { 315238104Sdes DRILL_OFF(qflags, LDNS_RD); 316238104Sdes } 317238104Sdes if (strstr(optarg, "CD")) { 318238104Sdes DRILL_ON(qflags, LDNS_CD); 319238104Sdes } 320238104Sdes if (strstr(optarg, "cd")) { 321238104Sdes DRILL_OFF(qflags, LDNS_CD); 322238104Sdes } 323238104Sdes if (strstr(optarg, "RA")) { 324238104Sdes DRILL_ON(qflags, LDNS_RA); 325238104Sdes } 326238104Sdes if (strstr(optarg, "ra")) { 327238104Sdes DRILL_OFF(qflags, LDNS_RA); 328238104Sdes } 329238104Sdes if (strstr(optarg, "AD")) { 330238104Sdes DRILL_ON(qflags, LDNS_AD); 331238104Sdes } 332238104Sdes if (strstr(optarg, "ad")) { 333238104Sdes DRILL_OFF(qflags, LDNS_AD); 334238104Sdes } 335238104Sdes break; 336238104Sdes case 'p': 337238104Sdes qport = (uint16_t)atoi(optarg); 338238104Sdes if (qport == 0) { 339238104Sdes error("%s", "<port> could not be converted"); 340238104Sdes } 341238104Sdes break; 342238104Sdes case 's': 343238104Sdes qds = true; 344238104Sdes break; 345238104Sdes case 'u': 346238104Sdes qusevc = false; 347238104Sdes break; 348238104Sdes case 'v': 349238104Sdes version(stdout, progname); 350238104Sdes result = EXIT_SUCCESS; 351238104Sdes goto exit; 352238104Sdes case 'x': 353238104Sdes PURPOSE = DRILL_REVERSE; 354238104Sdes break; 355238104Sdes case 'y': 356238104Sdes#ifdef HAVE_SSL 357238104Sdes if (strchr(optarg, ':')) { 358238104Sdes tsig_separator = (size_t) (strchr(optarg, ':') - optarg); 359238104Sdes if (strchr(optarg + tsig_separator + 1, ':')) { 360238104Sdes tsig_separator2 = (size_t) (strchr(optarg + tsig_separator + 1, ':') - optarg); 361238104Sdes tsig_algorithm = xmalloc(strlen(optarg) - tsig_separator2); 362238104Sdes strncpy(tsig_algorithm, optarg + tsig_separator2 + 1, strlen(optarg) - tsig_separator2); 363238104Sdes tsig_algorithm[strlen(optarg) - tsig_separator2 - 1] = '\0'; 364238104Sdes } else { 365238104Sdes tsig_separator2 = strlen(optarg); 366238104Sdes tsig_algorithm = xmalloc(26); 367238104Sdes strncpy(tsig_algorithm, "hmac-md5.sig-alg.reg.int.", 25); 368238104Sdes tsig_algorithm[25] = '\0'; 369238104Sdes } 370238104Sdes tsig_name = xmalloc(tsig_separator + 1); 371238104Sdes tsig_data = xmalloc(tsig_separator2 - tsig_separator); 372238104Sdes strncpy(tsig_name, optarg, tsig_separator); 373238104Sdes strncpy(tsig_data, optarg + tsig_separator + 1, tsig_separator2 - tsig_separator - 1); 374238104Sdes /* strncpy does not append \0 if source is longer than n */ 375238104Sdes tsig_name[tsig_separator] = '\0'; 376238104Sdes tsig_data[ tsig_separator2 - tsig_separator - 1] = '\0'; 377238104Sdes } 378238104Sdes#else 379238104Sdes fprintf(stderr, "TSIG requested, but SSL is not supported\n"); 380238104Sdes result = EXIT_FAILURE; 381238104Sdes goto exit; 382238104Sdes#endif /* HAVE_SSL */ 383238104Sdes break; 384238104Sdes case 'z': 385238104Sdes qrandom = false; 386238104Sdes break; 387238104Sdes case 'd': 388238104Sdes trace_start_name = ldns_dname_new_frm_str(optarg); 389238104Sdes if (!trace_start_name) { 390238104Sdes fprintf(stderr, "Unable to parse argument for -%c\n", c); 391238104Sdes result = EXIT_FAILURE; 392238104Sdes goto exit; 393238104Sdes } 394238104Sdes break; 395238104Sdes case 'h': 396238104Sdes version(stdout, progname); 397238104Sdes usage(stdout, progname); 398238104Sdes result = EXIT_SUCCESS; 399238104Sdes goto exit; 400238104Sdes break; 401238104Sdes default: 402238104Sdes fprintf(stderr, "Unknown argument: -%c, use -h to see usage\n", c); 403238104Sdes result = EXIT_FAILURE; 404238104Sdes goto exit; 405238104Sdes } 406238104Sdes } 407238104Sdes argc -= optind; 408238104Sdes argv += optind; 409238104Sdes 410246854Sdes if ((PURPOSE == DRILL_CHASE || (PURPOSE == DRILL_TRACE && qdnssec)) && 411246854Sdes ldns_rr_list_rr_count(key_list) == 0) { 412246854Sdes 413246854Sdes (void) read_key_file(LDNS_TRUST_ANCHOR_FILE, key_list, true); 414246854Sdes } 415246854Sdes if (ldns_rr_list_rr_count(key_list) > 0) { 416246854Sdes printf(";; Number of trusted keys: %d\n", 417246854Sdes (int) ldns_rr_list_rr_count(key_list)); 418246854Sdes } 419238104Sdes /* do a secure trace when requested */ 420238104Sdes if (PURPOSE == DRILL_TRACE && qdnssec) { 421238104Sdes#ifdef HAVE_SSL 422238104Sdes if (ldns_rr_list_rr_count(key_list) == 0) { 423238104Sdes warning("%s", "No trusted keys were given. Will not be able to verify authenticity!"); 424238104Sdes } 425238104Sdes PURPOSE = DRILL_SECTRACE; 426238104Sdes#else 427238104Sdes fprintf(stderr, "ldns has not been compiled with OpenSSL support. Secure trace not available\n"); 428238104Sdes exit(1); 429238104Sdes#endif /* HAVE_SSL */ 430238104Sdes } 431238104Sdes 432238104Sdes /* parse the arguments, with multiple arguments, the last argument 433238104Sdes * found is used */ 434238104Sdes for(i = 0; i < argc; i++) { 435238104Sdes 436238104Sdes /* if ^@ then it's a server */ 437238104Sdes if (argv[i][0] == '@') { 438238104Sdes if (strlen(argv[i]) == 1) { 439238104Sdes warning("%s", "No nameserver given"); 440238104Sdes exit(EXIT_FAILURE); 441238104Sdes } 442238104Sdes serv = argv[i] + 1; 443238104Sdes continue; 444238104Sdes } 445238104Sdes /* if has a dot, it's a name */ 446238104Sdes if (strchr(argv[i], '.')) { 447238104Sdes name = argv[i]; 448238104Sdes continue; 449238104Sdes } 450238104Sdes /* if it matches a type, it's a type */ 451238104Sdes if (int_type == -1) { 452238104Sdes type = ldns_get_rr_type_by_name(argv[i]); 453238104Sdes if (type != 0) { 454238104Sdes int_type = 0; 455238104Sdes continue; 456238104Sdes } 457238104Sdes } 458238104Sdes /* if it matches a class, it's a class */ 459238104Sdes if (int_clas == -1) { 460238104Sdes clas = ldns_get_rr_class_by_name(argv[i]); 461238104Sdes if (clas != 0) { 462238104Sdes int_clas = 0; 463238104Sdes continue; 464238104Sdes } 465238104Sdes } 466238104Sdes /* it all fails assume it's a name */ 467238104Sdes name = argv[i]; 468238104Sdes } 469238104Sdes /* act like dig and use for . NS */ 470238104Sdes if (!name) { 471238104Sdes name = "."; 472238104Sdes int_type = 0; 473238104Sdes type = LDNS_RR_TYPE_NS; 474238104Sdes } 475238104Sdes 476238104Sdes /* defaults if not given */ 477238104Sdes if (int_clas == -1) { 478238104Sdes clas = LDNS_RR_CLASS_IN; 479238104Sdes } 480238104Sdes if (int_type == -1) { 481238104Sdes if (PURPOSE != DRILL_REVERSE) { 482238104Sdes type = LDNS_RR_TYPE_A; 483238104Sdes } else { 484238104Sdes type = LDNS_RR_TYPE_PTR; 485238104Sdes } 486238104Sdes } 487238104Sdes 488269257Sdes if (src) { 489269257Sdes src_rdf = ldns_rdf_new_addr_frm_str(src); 490269257Sdes if(!src_rdf) { 491269257Sdes fprintf(stderr, "-I must be (or resolve) to a valid IP[v6] address.\n"); 492269257Sdes exit(EXIT_FAILURE); 493269257Sdes } 494269257Sdes } 495269257Sdes 496238104Sdes /* set the nameserver to use */ 497238104Sdes if (!serv) { 498238104Sdes /* no server given make a resolver from /etc/resolv.conf */ 499238104Sdes status = ldns_resolver_new_frm_file(&res, resolv_conf_file); 500238104Sdes if (status != LDNS_STATUS_OK) { 501238104Sdes warning("Could not create a resolver structure: %s (%s)\n" 502238104Sdes "Try drill @localhost if you have a resolver running on your machine.", 503238104Sdes ldns_get_errorstr_by_id(status), resolv_conf_file); 504238104Sdes result = EXIT_FAILURE; 505238104Sdes goto exit; 506238104Sdes } 507238104Sdes } else { 508238104Sdes res = ldns_resolver_new(); 509238104Sdes if (!res || strlen(serv) <= 0) { 510238104Sdes warning("Could not create a resolver structure"); 511238104Sdes result = EXIT_FAILURE; 512238104Sdes goto exit; 513238104Sdes } 514238104Sdes /* add the nameserver */ 515238104Sdes serv_rdf = ldns_rdf_new_addr_frm_str(serv); 516238104Sdes if (!serv_rdf) { 517238104Sdes /* try to resolv the name if possible */ 518238104Sdes status = ldns_resolver_new_frm_file(&cmdline_res, resolv_conf_file); 519238104Sdes 520238104Sdes if (status != LDNS_STATUS_OK) { 521238104Sdes error("%s", "@server ip could not be converted"); 522238104Sdes } 523238104Sdes ldns_resolver_set_dnssec(cmdline_res, qdnssec); 524238104Sdes ldns_resolver_set_ip6(cmdline_res, qfamily); 525238104Sdes ldns_resolver_set_fallback(cmdline_res, qfallback); 526238104Sdes ldns_resolver_set_usevc(cmdline_res, qusevc); 527269257Sdes ldns_resolver_set_source(cmdline_res, src_rdf); 528238104Sdes 529238104Sdes cmdline_dname = ldns_dname_new_frm_str(serv); 530238104Sdes 531238104Sdes cmdline_rr_list = ldns_get_rr_list_addr_by_name( 532238104Sdes cmdline_res, 533238104Sdes cmdline_dname, 534238104Sdes LDNS_RR_CLASS_IN, 535238104Sdes qflags); 536238104Sdes ldns_rdf_deep_free(cmdline_dname); 537238104Sdes if (!cmdline_rr_list) { 538238104Sdes /* This error msg is not always accurate */ 539238104Sdes error("%s `%s\'", "could not find any address for the name:", serv); 540238104Sdes } else { 541238104Sdes if (ldns_resolver_push_nameserver_rr_list( 542238104Sdes res, 543238104Sdes cmdline_rr_list 544238104Sdes ) != LDNS_STATUS_OK) { 545238104Sdes error("%s", "pushing nameserver"); 546238104Sdes } 547238104Sdes } 548238104Sdes } else { 549238104Sdes if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) { 550238104Sdes error("%s", "pushing nameserver"); 551238104Sdes } else { 552238104Sdes ldns_rdf_deep_free(serv_rdf); 553238104Sdes } 554238104Sdes } 555238104Sdes } 556238104Sdes /* set the resolver options */ 557238104Sdes ldns_resolver_set_port(res, qport); 558269257Sdes ldns_resolver_set_source(res, src_rdf); 559238104Sdes if (verbosity >= 5) { 560238104Sdes ldns_resolver_set_debug(res, true); 561238104Sdes } else { 562238104Sdes ldns_resolver_set_debug(res, false); 563238104Sdes } 564238104Sdes ldns_resolver_set_dnssec(res, qdnssec); 565238104Sdes/* ldns_resolver_set_dnssec_cd(res, qdnssec);*/ 566238104Sdes ldns_resolver_set_ip6(res, qfamily); 567238104Sdes ldns_resolver_set_fallback(res, qfallback); 568238104Sdes ldns_resolver_set_usevc(res, qusevc); 569238104Sdes ldns_resolver_set_random(res, qrandom); 570238104Sdes if (qbuf != 0) { 571238104Sdes ldns_resolver_set_edns_udp_size(res, qbuf); 572238104Sdes } 573238104Sdes 574238104Sdes if (!name && 575238104Sdes PURPOSE != DRILL_AFROMFILE && 576238104Sdes !query_file 577238104Sdes ) { 578238104Sdes usage(stdout, progname); 579238104Sdes result = EXIT_FAILURE; 580238104Sdes goto exit; 581238104Sdes } 582238104Sdes 583238104Sdes if (tsig_name && tsig_data) { 584238104Sdes ldns_resolver_set_tsig_keyname(res, tsig_name); 585238104Sdes ldns_resolver_set_tsig_keydata(res, tsig_data); 586238104Sdes ldns_resolver_set_tsig_algorithm(res, tsig_algorithm); 587238104Sdes } 588238104Sdes 589238104Sdes /* main switching part of drill */ 590238104Sdes switch(PURPOSE) { 591238104Sdes case DRILL_TRACE: 592238104Sdes /* do a trace from the root down */ 593238104Sdes if (!global_dns_root) { 594238104Sdes init_root(); 595238104Sdes } 596238104Sdes qname = ldns_dname_new_frm_str(name); 597238104Sdes if (!qname) { 598238104Sdes error("%s", "parsing query name"); 599238104Sdes } 600238104Sdes /* don't care about return packet */ 601238104Sdes (void)do_trace(res, qname, type, clas); 602238104Sdes clear_root(); 603238104Sdes break; 604238104Sdes case DRILL_SECTRACE: 605238104Sdes /* do a secure trace from the root down */ 606238104Sdes if (!global_dns_root) { 607238104Sdes init_root(); 608238104Sdes } 609238104Sdes qname = ldns_dname_new_frm_str(name); 610238104Sdes if (!qname) { 611238104Sdes error("%s", "making qname"); 612238104Sdes } 613238104Sdes /* don't care about return packet */ 614238104Sdes#ifdef HAVE_SSL 615238104Sdes result = do_secure_trace(res, qname, type, clas, key_list, trace_start_name); 616238104Sdes#endif /* HAVE_SSL */ 617238104Sdes clear_root(); 618238104Sdes break; 619238104Sdes case DRILL_CHASE: 620238104Sdes qname = ldns_dname_new_frm_str(name); 621238104Sdes if (!qname) { 622238104Sdes error("%s", "making qname"); 623238104Sdes } 624238104Sdes 625238104Sdes ldns_resolver_set_dnssec(res, true); 626238104Sdes ldns_resolver_set_dnssec_cd(res, true); 627238104Sdes /* set dnssec implies udp_size of 4096 */ 628238104Sdes ldns_resolver_set_edns_udp_size(res, 4096); 629269257Sdes pkt = NULL; 630269257Sdes status = ldns_resolver_query_status( 631269257Sdes &pkt, res, qname, type, clas, qflags); 632269257Sdes if (status != LDNS_STATUS_OK) { 633269257Sdes error("error sending query: %s", 634269257Sdes ldns_get_errorstr_by_id(status)); 635269257Sdes } 636238104Sdes if (!pkt) { 637269257Sdes if (status == LDNS_STATUS_OK) { 638269257Sdes error("%s", "error pkt sending"); 639269257Sdes } 640238104Sdes result = EXIT_FAILURE; 641238104Sdes } else { 642238104Sdes if (verbosity >= 3) { 643238104Sdes ldns_pkt_print(stdout, pkt); 644238104Sdes } 645238104Sdes 646238104Sdes if (!ldns_pkt_answer(pkt)) { 647238104Sdes mesg("No answer in packet"); 648238104Sdes } else { 649238104Sdes#ifdef HAVE_SSL 650238104Sdes ldns_resolver_set_dnssec_anchors(res, ldns_rr_list_clone(key_list)); 651238104Sdes result = do_chase(res, qname, type, 652238104Sdes clas, key_list, 653238104Sdes pkt, qflags, NULL, 654238104Sdes verbosity); 655238104Sdes if (result == LDNS_STATUS_OK) { 656238104Sdes if (verbosity != -1) { 657238104Sdes mesg("Chase successful"); 658238104Sdes } 659238104Sdes result = 0; 660238104Sdes } else { 661238104Sdes if (verbosity != -1) { 662238104Sdes mesg("Chase failed."); 663238104Sdes } 664238104Sdes } 665238104Sdes#endif /* HAVE_SSL */ 666238104Sdes } 667238104Sdes ldns_pkt_free(pkt); 668238104Sdes } 669238104Sdes break; 670238104Sdes case DRILL_AFROMFILE: 671238104Sdes pkt = read_hex_pkt(answer_file); 672238104Sdes if (pkt) { 673238104Sdes if (verbosity != -1) { 674238104Sdes ldns_pkt_print(stdout, pkt); 675238104Sdes } 676238104Sdes ldns_pkt_free(pkt); 677238104Sdes } 678238104Sdes 679238104Sdes break; 680238104Sdes case DRILL_QTOFILE: 681238104Sdes qname = ldns_dname_new_frm_str(name); 682238104Sdes if (!qname) { 683238104Sdes error("%s", "making qname"); 684238104Sdes } 685238104Sdes 686238104Sdes status = ldns_resolver_prepare_query_pkt(&qpkt, res, qname, type, clas, qflags); 687238104Sdes if(status != LDNS_STATUS_OK) { 688238104Sdes error("%s", "making query: %s", 689238104Sdes ldns_get_errorstr_by_id(status)); 690238104Sdes } 691238104Sdes dump_hex(qpkt, query_file); 692238104Sdes ldns_pkt_free(qpkt); 693238104Sdes break; 694238104Sdes case DRILL_NSEC: 695238104Sdes break; 696238104Sdes case DRILL_REVERSE: 697238104Sdes /* ipv4 or ipv6 addr? */ 698238104Sdes if (strchr(name, ':')) { 699238104Sdes if (strchr(name, '.')) { 700238104Sdes error("Syntax error: both '.' and ':' seen in address\n"); 701238104Sdes } 702238104Sdes name2 = malloc(IP6_ARPA_MAX_LEN + 20); 703238104Sdes c = 0; 704238104Sdes for (i=0; i<(int)strlen(name); i++) { 705238104Sdes if (i >= IP6_ARPA_MAX_LEN) { 706238104Sdes error("%s", "reverse argument to long"); 707238104Sdes } 708238104Sdes if (name[i] == ':') { 709238104Sdes if (i < (int) strlen(name) && name[i + 1] == ':') { 710238104Sdes error("%s", ":: not supported (yet)"); 711238104Sdes } else { 712238104Sdes if (i + 2 == (int) strlen(name) || name[i + 2] == ':') { 713238104Sdes name2[c++] = '0'; 714238104Sdes name2[c++] = '.'; 715238104Sdes name2[c++] = '0'; 716238104Sdes name2[c++] = '.'; 717238104Sdes name2[c++] = '0'; 718238104Sdes name2[c++] = '.'; 719238104Sdes } else if (i + 3 == (int) strlen(name) || name[i + 3] == ':') { 720238104Sdes name2[c++] = '0'; 721238104Sdes name2[c++] = '.'; 722238104Sdes name2[c++] = '0'; 723238104Sdes name2[c++] = '.'; 724238104Sdes } else if (i + 4 == (int) strlen(name) || name[i + 4] == ':') { 725238104Sdes name2[c++] = '0'; 726238104Sdes name2[c++] = '.'; 727238104Sdes } 728238104Sdes } 729238104Sdes } else { 730238104Sdes name2[c++] = name[i]; 731238104Sdes name2[c++] = '.'; 732238104Sdes } 733238104Sdes } 734238104Sdes name2[c++] = '\0'; 735238104Sdes 736238104Sdes qname = ldns_dname_new_frm_str(name2); 737238104Sdes qname_tmp = ldns_dname_reverse(qname); 738238104Sdes ldns_rdf_deep_free(qname); 739238104Sdes qname = qname_tmp; 740238104Sdes qname_tmp = ldns_dname_new_frm_str("ip6.arpa."); 741238104Sdes status = ldns_dname_cat(qname, qname_tmp); 742238104Sdes if (status != LDNS_STATUS_OK) { 743238104Sdes error("%s", "could not create reverse address for ip6: %s\n", ldns_get_errorstr_by_id(status)); 744238104Sdes } 745238104Sdes ldns_rdf_deep_free(qname_tmp); 746238104Sdes 747238104Sdes free(name2); 748238104Sdes } else { 749238104Sdes qname = ldns_dname_new_frm_str(name); 750238104Sdes qname_tmp = ldns_dname_reverse(qname); 751238104Sdes ldns_rdf_deep_free(qname); 752238104Sdes qname = qname_tmp; 753238104Sdes qname_tmp = ldns_dname_new_frm_str("in-addr.arpa."); 754238104Sdes status = ldns_dname_cat(qname, qname_tmp); 755238104Sdes if (status != LDNS_STATUS_OK) { 756238104Sdes error("%s", "could not create reverse address for ip4: %s\n", ldns_get_errorstr_by_id(status)); 757238104Sdes } 758238104Sdes ldns_rdf_deep_free(qname_tmp); 759238104Sdes } 760238104Sdes if (!qname) { 761238104Sdes error("%s", "-x implies an ip address"); 762238104Sdes } 763238104Sdes 764238104Sdes /* create a packet and set the RD flag on it */ 765269257Sdes pkt = NULL; 766269257Sdes status = ldns_resolver_query_status( 767269257Sdes &pkt, res, qname, type, clas, qflags); 768269257Sdes if (status != LDNS_STATUS_OK) { 769269257Sdes error("error sending query: %s", 770269257Sdes ldns_get_errorstr_by_id(status)); 771269257Sdes } 772238104Sdes if (!pkt) { 773269257Sdes if (status == LDNS_STATUS_OK) { 774269257Sdes error("%s", "pkt sending"); 775269257Sdes } 776238104Sdes result = EXIT_FAILURE; 777238104Sdes } else { 778238104Sdes if (verbosity != -1) { 779238104Sdes ldns_pkt_print(stdout, pkt); 780238104Sdes } 781238104Sdes ldns_pkt_free(pkt); 782238104Sdes } 783238104Sdes break; 784238104Sdes case DRILL_QUERY: 785238104Sdes default: 786238104Sdes if (query_file) { 787238104Sdes /* this old way, the query packet needed 788238104Sdes to be parseable, but we want to be able 789238104Sdes to send mangled packets, so we need 790238104Sdes to do it directly */ 791238104Sdes #if 0 792238104Sdes qpkt = read_hex_pkt(query_file); 793238104Sdes if (qpkt) { 794238104Sdes status = ldns_resolver_send_pkt(&pkt, res, qpkt); 795238104Sdes if (status != LDNS_STATUS_OK) { 796238104Sdes printf("Error: %s\n", ldns_get_errorstr_by_id(status)); 797238104Sdes exit(1); 798238104Sdes } 799238104Sdes } else { 800238104Sdes /* qpkt was bogus, reset pkt */ 801238104Sdes pkt = NULL; 802238104Sdes } 803238104Sdes #endif 804238104Sdes query_buffer = read_hex_buffer(query_file); 805238104Sdes if (query_buffer) { 806238104Sdes status = ldns_send_buffer(&pkt, res, query_buffer, NULL); 807238104Sdes ldns_buffer_free(query_buffer); 808238104Sdes if (status != LDNS_STATUS_OK) { 809238104Sdes printf("Error: %s\n", ldns_get_errorstr_by_id(status)); 810238104Sdes exit(1); 811238104Sdes } 812238104Sdes } else { 813238104Sdes printf("NO BUFFER\n"); 814238104Sdes pkt = NULL; 815238104Sdes } 816238104Sdes } else { 817238104Sdes qname = ldns_dname_new_frm_str(name); 818238104Sdes if (!qname) { 819238104Sdes error("%s", "error in making qname"); 820238104Sdes } 821238104Sdes 822238104Sdes if (type == LDNS_RR_TYPE_AXFR) { 823238104Sdes status = ldns_axfr_start(res, qname, clas); 824238104Sdes if(status != LDNS_STATUS_OK) { 825238104Sdes error("Error starting axfr: %s", 826238104Sdes ldns_get_errorstr_by_id(status)); 827238104Sdes } 828238104Sdes axfr_rr = ldns_axfr_next(res); 829238104Sdes if(!axfr_rr) { 830238104Sdes fprintf(stderr, "AXFR failed.\n"); 831238104Sdes ldns_pkt_print(stdout, 832238104Sdes ldns_axfr_last_pkt(res)); 833238104Sdes goto exit; 834238104Sdes } 835238104Sdes while (axfr_rr) { 836238104Sdes if (verbosity != -1) { 837238104Sdes ldns_rr_print(stdout, axfr_rr); 838238104Sdes } 839238104Sdes ldns_rr_free(axfr_rr); 840238104Sdes axfr_rr = ldns_axfr_next(res); 841238104Sdes } 842238104Sdes 843238104Sdes goto exit; 844238104Sdes } else { 845238104Sdes /* create a packet and set the RD flag on it */ 846269257Sdes pkt = NULL; 847269257Sdes status = ldns_resolver_query_status( 848269257Sdes &pkt, res, qname, 849269257Sdes type, clas, qflags); 850269257Sdes if (status != LDNS_STATUS_OK) { 851269257Sdes error("error sending query: %s" 852269257Sdes , ldns_get_errorstr_by_id( 853269257Sdes status)); 854269257Sdes } 855238104Sdes } 856238104Sdes } 857238104Sdes 858238104Sdes if (!pkt) { 859238104Sdes mesg("No packet received"); 860238104Sdes result = EXIT_FAILURE; 861238104Sdes } else { 862238104Sdes if (verbosity != -1) { 863238104Sdes ldns_pkt_print(stdout, pkt); 864238104Sdes if (ldns_pkt_tc(pkt)) { 865238104Sdes fprintf(stdout, 866238104Sdes "\n;; WARNING: The answer packet was truncated; you might want to\n"); 867238104Sdes fprintf(stdout, 868238104Sdes ";; query again with TCP (-t argument), or EDNS0 (-b for buffer size)\n"); 869238104Sdes } 870238104Sdes } 871238104Sdes if (qds) { 872238104Sdes if (verbosity != -1) { 873238104Sdes print_ds_of_keys(pkt); 874238104Sdes printf("\n"); 875238104Sdes } 876238104Sdes } 877238104Sdes 878238104Sdes if (ldns_rr_list_rr_count(key_list) > 0) { 879238104Sdes /* -k's were given on the cmd line */ 880238104Sdes ldns_rr_list *rrset_verified; 881238104Sdes uint16_t key_count; 882238104Sdes 883238104Sdes rrset_verified = ldns_pkt_rr_list_by_name_and_type( 884238104Sdes pkt, qname, type, 885238104Sdes LDNS_SECTION_ANY_NOQUESTION); 886238104Sdes 887238104Sdes if (type == LDNS_RR_TYPE_ANY) { 888238104Sdes /* don't verify this */ 889238104Sdes break; 890238104Sdes } 891238104Sdes 892238104Sdes if (verbosity != -1) { 893238104Sdes printf("; "); 894238104Sdes ldns_rr_list_print(stdout, rrset_verified); 895238104Sdes } 896238104Sdes 897238104Sdes /* verify */ 898238104Sdes#ifdef HAVE_SSL 899238104Sdes key_verified = ldns_rr_list_new(); 900238104Sdes result = ldns_pkt_verify(pkt, type, qname, key_list, NULL, key_verified); 901238104Sdes 902238104Sdes if (result == LDNS_STATUS_ERR) { 903238104Sdes /* is the existence denied then? */ 904238104Sdes result = ldns_verify_denial(pkt, qname, type, NULL, NULL); 905238104Sdes if (result == LDNS_STATUS_OK) { 906238104Sdes if (verbosity != -1) { 907238104Sdes printf("Existence denied for "); 908238104Sdes ldns_rdf_print(stdout, qname); 909238104Sdes type_str = ldns_rr_type2str(type); 910238104Sdes printf("\t%s\n", type_str); 911238104Sdes LDNS_FREE(type_str); 912238104Sdes } 913238104Sdes } else { 914238104Sdes if (verbosity != -1) { 915238104Sdes printf("Bad data; RR for name and " 916238104Sdes "type not found or failed to " 917238104Sdes "verify, and denial of " 918238104Sdes "existence failed.\n"); 919238104Sdes } 920238104Sdes } 921238104Sdes } else if (result == LDNS_STATUS_OK) { 922238104Sdes for(key_count = 0; key_count < ldns_rr_list_rr_count(key_verified); 923238104Sdes key_count++) { 924238104Sdes if (verbosity != -1) { 925238104Sdes printf("; VALIDATED by id = %u, owner = ", 926238104Sdes (unsigned int)ldns_calc_keytag( 927238104Sdes ldns_rr_list_rr(key_verified, key_count))); 928238104Sdes ldns_rdf_print(stdout, ldns_rr_owner( 929238104Sdes ldns_rr_list_rr(key_list, key_count))); 930238104Sdes printf("\n"); 931238104Sdes } 932238104Sdes } 933238104Sdes } else { 934238104Sdes for(key_count = 0; key_count < ldns_rr_list_rr_count(key_list); 935238104Sdes key_count++) { 936238104Sdes if (verbosity != -1) { 937238104Sdes printf("; %s for id = %u, owner = ", 938238104Sdes ldns_get_errorstr_by_id(result), 939238104Sdes (unsigned int)ldns_calc_keytag( 940238104Sdes ldns_rr_list_rr(key_list, key_count))); 941238104Sdes ldns_rdf_print(stdout, ldns_rr_owner( 942238104Sdes 943238104Sdes ldns_rr_list_rr(key_list, 944238104Sdes key_count))); 945238104Sdes printf("\n"); 946238104Sdes } 947238104Sdes } 948238104Sdes } 949238104Sdes ldns_rr_list_free(key_verified); 950238104Sdes#else 951238104Sdes (void) key_count; 952238104Sdes#endif /* HAVE_SSL */ 953238104Sdes } 954238104Sdes if (answer_file) { 955238104Sdes dump_hex(pkt, answer_file); 956238104Sdes } 957238104Sdes ldns_pkt_free(pkt); 958238104Sdes } 959238104Sdes 960238104Sdes break; 961238104Sdes } 962238104Sdes 963238104Sdes exit: 964238104Sdes ldns_rdf_deep_free(qname); 965269257Sdes ldns_rdf_deep_free(src_rdf); 966238104Sdes ldns_resolver_deep_free(res); 967238104Sdes ldns_resolver_deep_free(cmdline_res); 968238104Sdes ldns_rr_list_deep_free(key_list); 969238104Sdes ldns_rr_list_deep_free(cmdline_rr_list); 970238104Sdes ldns_rdf_deep_free(trace_start_name); 971238104Sdes xfree(progname); 972238104Sdes xfree(tsig_name); 973238104Sdes xfree(tsig_data); 974238104Sdes xfree(tsig_algorithm); 975238104Sdes 976238104Sdes#ifdef HAVE_SSL 977238104Sdes ERR_remove_state(0); 978238104Sdes CRYPTO_cleanup_all_ex_data(); 979238104Sdes ERR_free_strings(); 980238104Sdes EVP_cleanup(); 981238104Sdes#endif 982238104Sdes#ifdef USE_WINSOCK 983238104Sdes WSACleanup(); 984238104Sdes#endif 985238104Sdes 986238104Sdes return result; 987238104Sdes} 988