void ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_zone *zone) { if (zone) { if (zone->soa) { if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { fprintf(out, ";; Zone: "); ldns_rdf_print(out, ldns_dnssec_name_name( zone->soa)); fprintf(out, "\n;\n"); } ldns_dnssec_rrsets_print_fmt(out, fmt, ldns_dnssec_name_find_rrset( zone->soa, LDNS_RR_TYPE_SOA), false); if ((fmt->flags & LDNS_COMMENT_LAYOUT)) fprintf(out, ";\n"); } if (zone->names) { ldns_dnssec_zone_names_print_fmt(out, fmt, zone->names, false); } } }
void drill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p) { ldns_rr_list *hostnames; if (verbosity < 5) { return; } hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0); fprintf(fd, ";; Received %d bytes from %s#%d(", (int) ldns_pkt_size(p), ldns_rdf2str(ldns_pkt_answerfrom(p)), (int) ldns_resolver_port(r)); /* if we can resolve this print it, other print the ip again */ if (hostnames) { ldns_rdf_print(fd, ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0)); ldns_rr_list_deep_free(hostnames); } else { fprintf(fd, "%s", ldns_rdf2str(ldns_pkt_answerfrom(p))); } fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p)); }
static void ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt, ldns_dnssec_name *name, bool show_soa) { if (name) { if(name->rrsets) { ldns_dnssec_rrsets_print_soa_fmt(out, fmt, name->rrsets, true, show_soa); } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { fprintf(out, ";; Empty nonterminal: "); ldns_rdf_print(out, name->name); fprintf(out, "\n"); } if(name->nsec) { ldns_rr_print_fmt(out, fmt, name->nsec); } if (name->nsec_signatures) { ldns_dnssec_rrs_print_fmt(out, fmt, name->nsec_signatures); } } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { fprintf(out, "; <void>\n"); } }
void read_in(ldns_rr_list* list, ldns_rdf** qname, FILE *in) { char* buf; while((buf=skip_comments_and_query(in, qname))) { /* add rr */ ldns_rr *rr=0; ldns_rdf *origin=0, *prev=0; ldns_status err; uint16_t ttl = 3600; if((err=ldns_rr_new_frm_str(&rr, buf, ttl, origin, &prev)) != LDNS_STATUS_OK) abort_ldns_error("read rr", err); ldns_rr_list_push_rr(list, rr); } printf("nsec3-covers: read %d rrs\n", (int)ldns_rr_list_rr_count(list)); if(!qname) { printf("Could not read question name\n"); exit(1); } printf("nsec3-covers: qname is "); ldns_rdf_print(stdout, *qname); printf("\n"); }
/** convert and print rdata */ static void print_rd(int t, char* data, size_t len) { size_t i, pos = 0; uint8_t* rd = (uint8_t*)malloc(len+2); ldns_rr* rr = ldns_rr_new(); ldns_status status; if(!rd || !rr) { fprintf(stderr, "out of memory"); exit(1); } ldns_rr_set_type(rr, t); ldns_write_uint16(rd, len); memmove(rd+2, data, len); ldns_rr_set_owner(rr, NULL); status = ldns_wire2rdf(rr, rd, len+2, &pos); if(status != LDNS_STATUS_OK) { free(rd); ldns_rr_free(rr); printf("error_printing_data"); return; } for(i=0; i<ldns_rr_rd_count(rr); i++) { printf(" "); ldns_rdf_print(stdout, ldns_rr_rdf(rr, i)); } ldns_rr_free(rr); free(rd); }
void drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p) { ldns_rr_list *new_nss; ldns_rr_list *hostnames; if (verbosity < 5) { return; } hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0); new_nss = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER); ldns_rr_list_print(fd, new_nss); /* new_nss can be empty.... */ fprintf(fd, ";; Received %d bytes from %s#%d(", (int) ldns_pkt_size(p), ldns_rdf2str(ldns_pkt_answerfrom(p)), (int) ldns_resolver_port(r)); /* if we can resolve this print it, other print the ip again */ if (hostnames) { ldns_rdf_print(fd, ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0)); ldns_rr_list_deep_free(hostnames); } else { fprintf(fd, "%s", ldns_rdf2str(ldns_pkt_answerfrom(p))); } fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p)); }
static int l_rdf_print(lua_State *L) { /* we always print to stdout */ ldns_rdf *toprint = (ldns_rdf*)lua_touserdata(L, 1); /* pop from the stack */ if (!toprint) { return 0; } ldns_rdf_print(stdout, toprint); return 0; }
/** process nsec3 params and perform hashing */ static void process_nsec3(int argc, char* argv[]) { char line[10240]; ldns_rdf* salt; ldns_rdf* in, *out; ldns_status status; status = ldns_str2rdf_nsec3_salt(&salt, argv[5]); if(status != LDNS_STATUS_OK) fatal_exit("Could not parse salt %s: %s", argv[5], ldns_get_errorstr_by_id(status)); log_assert(argc == 6); while(fgets(line, (int)sizeof(line), stdin)) { if(strlen(line) > 0) line[strlen(line)-1] = 0; /* remove trailing newline */ if(line[0]==0) continue; status = ldns_str2rdf_dname(&in, line); if(status != LDNS_STATUS_OK) fatal_exit("Could not parse name %s: %s", line, ldns_get_errorstr_by_id(status)); ldns_rdf_print(stdout, in); printf(" -> "); /* arg 3 is flags, unused */ out = ldns_nsec3_hash_name(in, (uint8_t)atoi(argv[2]), (uint16_t)atoi(argv[4]), ldns_rdf_data(salt)[0], ldns_rdf_data(salt)+1); if(!out) fatal_exit("Could not hash %s", line); ldns_rdf_print(stdout, out); printf("\n"); ldns_rdf_deep_free(in); ldns_rdf_deep_free(out); } ldns_rdf_deep_free(salt); }
void check_cover(ldns_rr_list *list, ldns_rdf *qname) { ldns_status status; size_t i; if(check_done(qname)) return; for(i=0; i<ldns_rr_list_rr_count(list); ++i) { ldns_rr* nsec3 = ldns_rr_list_rr(list, i); if(ldns_rr_get_type(nsec3) != LDNS_RR_TYPE_NSEC3) { /* skip non nsec3 */ continue; } ldns_rdf* hashed = ldns_nsec3_hash_name_frm_nsec3( nsec3, qname); status = ldns_dname_cat(hashed, ldns_dname_left_chop( ldns_rr_owner(nsec3))); if(status != LDNS_STATUS_OK) abort_ldns_error("ldns_dname_cat", status); if(ldns_dname_compare(hashed, ldns_rr_owner(nsec3)) == 0) { ldns_rdf_print(stdout, ldns_rr_owner(nsec3)); printf(" proves "); ldns_rdf_print(stdout, qname); printf(" exists.\n"); } else if(ldns_nsec_covers_name(nsec3, hashed)) { ldns_rdf_print(stdout, ldns_rr_owner(nsec3)); printf(" proves "); ldns_rdf_print(stdout, qname); printf(" does not exist.\n"); } ldns_rdf_free(hashed); } }
ldns_status do_chase(ldns_resolver *res, ldns_rdf *name, ldns_rr_type type, ldns_rr_class c, ldns_rr_list *trusted_keys, ldns_pkt *pkt_o, uint16_t qflags, ldns_rr_list *prev_key_list, int verbosity) { ldns_rr_list *rrset = NULL; ldns_status result; ldns_rr *orig_rr = NULL; /* ldns_rr_list *sigs; ldns_rr *cur_sig; uint16_t sig_i; ldns_rr_list *keys; */ ldns_pkt *pkt; ldns_status tree_result; ldns_dnssec_data_chain *chain; ldns_dnssec_trust_tree *tree; const ldns_rr_descriptor *descriptor; descriptor = ldns_rr_descript(type); ldns_dname2canonical(name); pkt = ldns_pkt_clone(pkt_o); if (!name) { ldns_pkt_free(pkt); return LDNS_STATUS_EMPTY_LABEL; } if (verbosity != -1) { printf(";; Chasing: "); ldns_rdf_print(stdout, name); if (descriptor && descriptor->_name) { printf(" %s\n", descriptor->_name); } else { printf(" type %d\n", type); } } if (!trusted_keys || ldns_rr_list_rr_count(trusted_keys) < 1) { } if (pkt) { rrset = ldns_pkt_rr_list_by_name_and_type(pkt, name, type, LDNS_SECTION_ANSWER ); if (!rrset) { /* nothing in answer, try authority */ rrset = ldns_pkt_rr_list_by_name_and_type(pkt, name, type, LDNS_SECTION_AUTHORITY ); } /* answer might be a cname, chase that first, then chase cname target? (TODO) */ if (!rrset) { rrset = ldns_pkt_rr_list_by_name_and_type(pkt, name, LDNS_RR_TYPE_CNAME, LDNS_SECTION_ANSWER ); if (!rrset) { /* nothing in answer, try authority */ rrset = ldns_pkt_rr_list_by_name_and_type(pkt, name, LDNS_RR_TYPE_CNAME, LDNS_SECTION_AUTHORITY ); } } } else { /* no packet? */ if (verbosity >= 0) { fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_MEM_ERR)); fprintf(stderr, "\n"); } return LDNS_STATUS_MEM_ERR; } if (!rrset) { /* not found in original packet, try again */ ldns_pkt_free(pkt); pkt = NULL; pkt = ldns_resolver_query(res, name, type, c, qflags); if (!pkt) { if (verbosity >= 0) { fprintf(stderr, "%s", ldns_get_errorstr_by_id(LDNS_STATUS_NETWORK_ERR)); fprintf(stderr, "\n"); } return LDNS_STATUS_NETWORK_ERR; } if (verbosity >= 5) { ldns_pkt_print(stdout, pkt); } rrset = ldns_pkt_rr_list_by_name_and_type(pkt, name, type, LDNS_SECTION_ANSWER ); } orig_rr = ldns_rr_new(); /* if the answer had no answer section, we need to construct our own rr (for instance if * the rr qe asked for doesn't exist. This rr will be destroyed when the chain is freed */ if (ldns_pkt_ancount(pkt) < 1) { ldns_rr_set_type(orig_rr, type); ldns_rr_set_owner(orig_rr, ldns_rdf_clone(name)); chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, ldns_rr_clone(orig_rr)); } else { /* chase the first answer */ chain = ldns_dnssec_build_data_chain(res, qflags, rrset, pkt, NULL); } if (verbosity >= 4) { printf("\n\nDNSSEC Data Chain:\n"); ldns_dnssec_data_chain_print(stdout, chain); } result = LDNS_STATUS_OK; tree = ldns_dnssec_derive_trust_tree(chain, NULL); if (verbosity >= 2) { printf("\n\nDNSSEC Trust tree:\n"); ldns_dnssec_trust_tree_print(stdout, tree, 0, true); } if (ldns_rr_list_rr_count(trusted_keys) > 0) { tree_result = ldns_dnssec_trust_tree_contains_keys(tree, trusted_keys); if (tree_result == LDNS_STATUS_DNSSEC_EXISTENCE_DENIED) { if (verbosity >= 1) { printf("Existence denied or verifiably insecure\n"); } result = LDNS_STATUS_OK; } else if (tree_result != LDNS_STATUS_OK) { if (verbosity >= 1) { printf("No trusted keys found in tree: first error was: %s\n", ldns_get_errorstr_by_id(tree_result)); } result = tree_result; } } else { result = -1; if (verbosity >= 0) { printf("You have not provided any trusted keys.\n"); } } ldns_rr_free(orig_rr); ldns_dnssec_trust_tree_free(tree); ldns_dnssec_data_chain_deep_free(chain); ldns_rr_list_deep_free(rrset); ldns_pkt_free(pkt); /* ldns_rr_free(orig_rr);*/ return result; }
/** * Main function of drill * parse the arguments and prepare a query */ int main(int argc, char *argv[]) { ldns_resolver *res = NULL; ldns_resolver *cmdline_res = NULL; /* only used to resolv @name names */ ldns_rr_list *cmdline_rr_list = NULL; ldns_rdf *cmdline_dname = NULL; ldns_rdf *qname, *qname_tmp; ldns_pkt *pkt; ldns_pkt *qpkt; char *serv; const char *name; char *name2; char *progname; char *query_file = NULL; char *answer_file = NULL; ldns_buffer *query_buffer = NULL; ldns_rdf *serv_rdf; ldns_rr_type type; ldns_rr_class clas; #if 0 ldns_pkt_opcode opcode = LDNS_PACKET_QUERY; #endif int i, c; int int_type; int int_clas; int PURPOSE; char *tsig_name = NULL; char *tsig_data = NULL; char *tsig_algorithm = NULL; size_t tsig_separator; size_t tsig_separator2; ldns_rr *axfr_rr; ldns_status status; char *type_str; /* list of keys used in dnssec operations */ ldns_rr_list *key_list = ldns_rr_list_new(); /* what key verify the current answer */ ldns_rr_list *key_verified; /* resolver options */ uint16_t qflags; uint16_t qbuf; uint16_t qport; uint8_t qfamily; bool qdnssec; bool qfallback; bool qds; bool qusevc; bool qrandom; char *resolv_conf_file = NULL; ldns_rdf *trace_start_name = NULL; int result = 0; #ifdef USE_WINSOCK int r; WSADATA wsa_data; #endif int_type = -1; serv = NULL; type = 0; int_clas = -1; name = NULL; clas = 0; qname = NULL; progname = strdup(argv[0]); #ifdef USE_WINSOCK r = WSAStartup(MAKEWORD(2,2), &wsa_data); if(r != 0) { printf("Failed WSAStartup: %d\n", r); result = EXIT_FAILURE; goto exit; } #endif /* USE_WINSOCK */ PURPOSE = DRILL_QUERY; qflags = LDNS_RD; qport = LDNS_PORT; verbosity = 2; qdnssec = false; qfamily = LDNS_RESOLV_INETANY; qfallback = false; qds = false; qbuf = 0; qusevc = false; qrandom = true; key_verified = NULL; ldns_init_random(NULL, 0); if (argc == 0) { usage(stdout, progname); result = EXIT_FAILURE; goto exit; } /* string from orig drill: "i:w:I46Sk:TNp:b:DsvhVcuaq:f:xr" */ /* global first, query opt next, option with parm's last * and sorted */ /* "46DITSVQf:i:w:q:achuvxzy:so:p:b:k:" */ while ((c = getopt(argc, argv, "46ab:c:d:Df:hi:Ik:o:p:q:Qr:sStTuvV:w:xy:z")) != -1) { switch(c) { /* global options */ case '4': qfamily = LDNS_RESOLV_INET; break; case '6': qfamily = LDNS_RESOLV_INET6; break; case 'D': qdnssec = true; break; case 'I': /* reserved for backward compatibility */ break; case 'T': if (PURPOSE == DRILL_CHASE) { fprintf(stderr, "-T and -S cannot be used at the same time.\n"); exit(EXIT_FAILURE); } PURPOSE = DRILL_TRACE; break; #ifdef HAVE_SSL case 'S': if (PURPOSE == DRILL_TRACE) { fprintf(stderr, "-T and -S cannot be used at the same time.\n"); exit(EXIT_FAILURE); } PURPOSE = DRILL_CHASE; break; #endif /* HAVE_SSL */ case 'V': if (strtok(optarg, "0123456789") != NULL) { fprintf(stderr, "-V expects an number as an argument.\n"); exit(EXIT_FAILURE); } verbosity = atoi(optarg); break; case 'Q': verbosity = -1; break; case 'f': query_file = optarg; break; case 'i': answer_file = optarg; PURPOSE = DRILL_AFROMFILE; break; case 'w': answer_file = optarg; break; case 'q': query_file = optarg; PURPOSE = DRILL_QTOFILE; break; case 'r': if (global_dns_root) { fprintf(stderr, "There was already a series of root servers set\n"); exit(EXIT_FAILURE); } global_dns_root = read_root_hints(optarg); if (!global_dns_root) { fprintf(stderr, "Unable to read root hints file %s, aborting\n", optarg); exit(EXIT_FAILURE); } break; /* query options */ case 'a': qfallback = true; break; case 'b': qbuf = (uint16_t)atoi(optarg); if (qbuf == 0) { error("%s", "<bufsize> could not be converted"); } break; case 'c': resolv_conf_file = optarg; break; case 't': qusevc = true; break; case 'k': status = read_key_file(optarg, key_list, false); if (status != LDNS_STATUS_OK) { error("Could not parse the key file %s: %s", optarg, ldns_get_errorstr_by_id(status)); } qdnssec = true; /* enable that too */ break; case 'o': /* only looks at the first hit: capital=ON, lowercase=OFF*/ if (strstr(optarg, "QR")) { DRILL_ON(qflags, LDNS_QR); } if (strstr(optarg, "qr")) { DRILL_OFF(qflags, LDNS_QR); } if (strstr(optarg, "AA")) { DRILL_ON(qflags, LDNS_AA); } if (strstr(optarg, "aa")) { DRILL_OFF(qflags, LDNS_AA); } if (strstr(optarg, "TC")) { DRILL_ON(qflags, LDNS_TC); } if (strstr(optarg, "tc")) { DRILL_OFF(qflags, LDNS_TC); } if (strstr(optarg, "RD")) { DRILL_ON(qflags, LDNS_RD); } if (strstr(optarg, "rd")) { DRILL_OFF(qflags, LDNS_RD); } if (strstr(optarg, "CD")) { DRILL_ON(qflags, LDNS_CD); } if (strstr(optarg, "cd")) { DRILL_OFF(qflags, LDNS_CD); } if (strstr(optarg, "RA")) { DRILL_ON(qflags, LDNS_RA); } if (strstr(optarg, "ra")) { DRILL_OFF(qflags, LDNS_RA); } if (strstr(optarg, "AD")) { DRILL_ON(qflags, LDNS_AD); } if (strstr(optarg, "ad")) { DRILL_OFF(qflags, LDNS_AD); } break; case 'p': qport = (uint16_t)atoi(optarg); if (qport == 0) { error("%s", "<port> could not be converted"); } break; case 's': qds = true; break; case 'u': qusevc = false; break; case 'v': version(stdout, progname); result = EXIT_SUCCESS; goto exit; case 'x': PURPOSE = DRILL_REVERSE; break; case 'y': #ifdef HAVE_SSL if (strchr(optarg, ':')) { tsig_separator = (size_t) (strchr(optarg, ':') - optarg); if (strchr(optarg + tsig_separator + 1, ':')) { tsig_separator2 = (size_t) (strchr(optarg + tsig_separator + 1, ':') - optarg); tsig_algorithm = xmalloc(strlen(optarg) - tsig_separator2); strncpy(tsig_algorithm, optarg + tsig_separator2 + 1, strlen(optarg) - tsig_separator2); tsig_algorithm[strlen(optarg) - tsig_separator2 - 1] = '\0'; } else { tsig_separator2 = strlen(optarg); tsig_algorithm = xmalloc(26); strncpy(tsig_algorithm, "hmac-md5.sig-alg.reg.int.", 25); tsig_algorithm[25] = '\0'; } tsig_name = xmalloc(tsig_separator + 1); tsig_data = xmalloc(tsig_separator2 - tsig_separator); strncpy(tsig_name, optarg, tsig_separator); strncpy(tsig_data, optarg + tsig_separator + 1, tsig_separator2 - tsig_separator - 1); /* strncpy does not append \0 if source is longer than n */ tsig_name[tsig_separator] = '\0'; tsig_data[ tsig_separator2 - tsig_separator - 1] = '\0'; } #else fprintf(stderr, "TSIG requested, but SSL is not supported\n"); result = EXIT_FAILURE; goto exit; #endif /* HAVE_SSL */ break; case 'z': qrandom = false; break; case 'd': trace_start_name = ldns_dname_new_frm_str(optarg); if (!trace_start_name) { fprintf(stderr, "Unable to parse argument for -%c\n", c); result = EXIT_FAILURE; goto exit; } break; case 'h': version(stdout, progname); usage(stdout, progname); result = EXIT_SUCCESS; goto exit; break; default: fprintf(stderr, "Unknown argument: -%c, use -h to see usage\n", c); result = EXIT_FAILURE; goto exit; } } argc -= optind; argv += optind; if ((PURPOSE == DRILL_CHASE || (PURPOSE == DRILL_TRACE && qdnssec)) && ldns_rr_list_rr_count(key_list) == 0) { (void) read_key_file(LDNS_TRUST_ANCHOR_FILE, key_list, true); } if (ldns_rr_list_rr_count(key_list) > 0) { printf(";; Number of trusted keys: %d\n", (int) ldns_rr_list_rr_count(key_list)); } /* do a secure trace when requested */ if (PURPOSE == DRILL_TRACE && qdnssec) { #ifdef HAVE_SSL if (ldns_rr_list_rr_count(key_list) == 0) { warning("%s", "No trusted keys were given. Will not be able to verify authenticity!"); } PURPOSE = DRILL_SECTRACE; #else fprintf(stderr, "ldns has not been compiled with OpenSSL support. Secure trace not available\n"); exit(1); #endif /* HAVE_SSL */ } /* parse the arguments, with multiple arguments, the last argument * found is used */ for(i = 0; i < argc; i++) { /* if ^@ then it's a server */ if (argv[i][0] == '@') { if (strlen(argv[i]) == 1) { warning("%s", "No nameserver given"); exit(EXIT_FAILURE); } serv = argv[i] + 1; continue; } /* if has a dot, it's a name */ if (strchr(argv[i], '.')) { name = argv[i]; continue; } /* if it matches a type, it's a type */ if (int_type == -1) { type = ldns_get_rr_type_by_name(argv[i]); if (type != 0) { int_type = 0; continue; } } /* if it matches a class, it's a class */ if (int_clas == -1) { clas = ldns_get_rr_class_by_name(argv[i]); if (clas != 0) { int_clas = 0; continue; } } /* it all fails assume it's a name */ name = argv[i]; } /* act like dig and use for . NS */ if (!name) { name = "."; int_type = 0; type = LDNS_RR_TYPE_NS; } /* defaults if not given */ if (int_clas == -1) { clas = LDNS_RR_CLASS_IN; } if (int_type == -1) { if (PURPOSE != DRILL_REVERSE) { type = LDNS_RR_TYPE_A; } else { type = LDNS_RR_TYPE_PTR; } } /* set the nameserver to use */ if (!serv) { /* no server given make a resolver from /etc/resolv.conf */ status = ldns_resolver_new_frm_file(&res, resolv_conf_file); if (status != LDNS_STATUS_OK) { warning("Could not create a resolver structure: %s (%s)\n" "Try drill @localhost if you have a resolver running on your machine.", ldns_get_errorstr_by_id(status), resolv_conf_file); result = EXIT_FAILURE; goto exit; } } else { res = ldns_resolver_new(); if (!res || strlen(serv) <= 0) { warning("Could not create a resolver structure"); result = EXIT_FAILURE; goto exit; } /* add the nameserver */ serv_rdf = ldns_rdf_new_addr_frm_str(serv); if (!serv_rdf) { /* try to resolv the name if possible */ status = ldns_resolver_new_frm_file(&cmdline_res, resolv_conf_file); if (status != LDNS_STATUS_OK) { error("%s", "@server ip could not be converted"); } ldns_resolver_set_dnssec(cmdline_res, qdnssec); ldns_resolver_set_ip6(cmdline_res, qfamily); ldns_resolver_set_fallback(cmdline_res, qfallback); ldns_resolver_set_usevc(cmdline_res, qusevc); cmdline_dname = ldns_dname_new_frm_str(serv); cmdline_rr_list = ldns_get_rr_list_addr_by_name( cmdline_res, cmdline_dname, LDNS_RR_CLASS_IN, qflags); ldns_rdf_deep_free(cmdline_dname); if (!cmdline_rr_list) { /* This error msg is not always accurate */ error("%s `%s\'", "could not find any address for the name:", serv); } else { if (ldns_resolver_push_nameserver_rr_list( res, cmdline_rr_list ) != LDNS_STATUS_OK) { error("%s", "pushing nameserver"); } } } else { if (ldns_resolver_push_nameserver(res, serv_rdf) != LDNS_STATUS_OK) { error("%s", "pushing nameserver"); } else { ldns_rdf_deep_free(serv_rdf); } } } /* set the resolver options */ ldns_resolver_set_port(res, qport); if (verbosity >= 5) { ldns_resolver_set_debug(res, true); } else { ldns_resolver_set_debug(res, false); } ldns_resolver_set_dnssec(res, qdnssec); /* ldns_resolver_set_dnssec_cd(res, qdnssec);*/ ldns_resolver_set_ip6(res, qfamily); ldns_resolver_set_fallback(res, qfallback); ldns_resolver_set_usevc(res, qusevc); ldns_resolver_set_random(res, qrandom); if (qbuf != 0) { ldns_resolver_set_edns_udp_size(res, qbuf); } if (!name && PURPOSE != DRILL_AFROMFILE && !query_file ) { usage(stdout, progname); result = EXIT_FAILURE; goto exit; } if (tsig_name && tsig_data) { ldns_resolver_set_tsig_keyname(res, tsig_name); ldns_resolver_set_tsig_keydata(res, tsig_data); ldns_resolver_set_tsig_algorithm(res, tsig_algorithm); } /* main switching part of drill */ switch(PURPOSE) { case DRILL_TRACE: /* do a trace from the root down */ if (!global_dns_root) { init_root(); } qname = ldns_dname_new_frm_str(name); if (!qname) { error("%s", "parsing query name"); } /* don't care about return packet */ (void)do_trace(res, qname, type, clas); clear_root(); break; case DRILL_SECTRACE: /* do a secure trace from the root down */ if (!global_dns_root) { init_root(); } qname = ldns_dname_new_frm_str(name); if (!qname) { error("%s", "making qname"); } /* don't care about return packet */ #ifdef HAVE_SSL result = do_secure_trace(res, qname, type, clas, key_list, trace_start_name); #endif /* HAVE_SSL */ clear_root(); break; case DRILL_CHASE: qname = ldns_dname_new_frm_str(name); if (!qname) { error("%s", "making qname"); } ldns_resolver_set_dnssec(res, true); ldns_resolver_set_dnssec_cd(res, true); /* set dnssec implies udp_size of 4096 */ ldns_resolver_set_edns_udp_size(res, 4096); pkt = ldns_resolver_query(res, qname, type, clas, qflags); if (!pkt) { error("%s", "error pkt sending"); result = EXIT_FAILURE; } else { if (verbosity >= 3) { ldns_pkt_print(stdout, pkt); } if (!ldns_pkt_answer(pkt)) { mesg("No answer in packet"); } else { #ifdef HAVE_SSL ldns_resolver_set_dnssec_anchors(res, ldns_rr_list_clone(key_list)); result = do_chase(res, qname, type, clas, key_list, pkt, qflags, NULL, verbosity); if (result == LDNS_STATUS_OK) { if (verbosity != -1) { mesg("Chase successful"); } result = 0; } else { if (verbosity != -1) { mesg("Chase failed."); } } #endif /* HAVE_SSL */ } ldns_pkt_free(pkt); } break; case DRILL_AFROMFILE: pkt = read_hex_pkt(answer_file); if (pkt) { if (verbosity != -1) { ldns_pkt_print(stdout, pkt); } ldns_pkt_free(pkt); } break; case DRILL_QTOFILE: qname = ldns_dname_new_frm_str(name); if (!qname) { error("%s", "making qname"); } status = ldns_resolver_prepare_query_pkt(&qpkt, res, qname, type, clas, qflags); if(status != LDNS_STATUS_OK) { error("%s", "making query: %s", ldns_get_errorstr_by_id(status)); } dump_hex(qpkt, query_file); ldns_pkt_free(qpkt); break; case DRILL_NSEC: break; case DRILL_REVERSE: /* ipv4 or ipv6 addr? */ if (strchr(name, ':')) { if (strchr(name, '.')) { error("Syntax error: both '.' and ':' seen in address\n"); } name2 = malloc(IP6_ARPA_MAX_LEN + 20); c = 0; for (i=0; i<(int)strlen(name); i++) { if (i >= IP6_ARPA_MAX_LEN) { error("%s", "reverse argument to long"); } if (name[i] == ':') { if (i < (int) strlen(name) && name[i + 1] == ':') { error("%s", ":: not supported (yet)"); } else { if (i + 2 == (int) strlen(name) || name[i + 2] == ':') { name2[c++] = '0'; name2[c++] = '.'; name2[c++] = '0'; name2[c++] = '.'; name2[c++] = '0'; name2[c++] = '.'; } else if (i + 3 == (int) strlen(name) || name[i + 3] == ':') { name2[c++] = '0'; name2[c++] = '.'; name2[c++] = '0'; name2[c++] = '.'; } else if (i + 4 == (int) strlen(name) || name[i + 4] == ':') { name2[c++] = '0'; name2[c++] = '.'; } } } else { name2[c++] = name[i]; name2[c++] = '.'; } } name2[c++] = '\0'; qname = ldns_dname_new_frm_str(name2); qname_tmp = ldns_dname_reverse(qname); ldns_rdf_deep_free(qname); qname = qname_tmp; qname_tmp = ldns_dname_new_frm_str("ip6.arpa."); status = ldns_dname_cat(qname, qname_tmp); if (status != LDNS_STATUS_OK) { error("%s", "could not create reverse address for ip6: %s\n", ldns_get_errorstr_by_id(status)); } ldns_rdf_deep_free(qname_tmp); free(name2); } else { qname = ldns_dname_new_frm_str(name); qname_tmp = ldns_dname_reverse(qname); ldns_rdf_deep_free(qname); qname = qname_tmp; qname_tmp = ldns_dname_new_frm_str("in-addr.arpa."); status = ldns_dname_cat(qname, qname_tmp); if (status != LDNS_STATUS_OK) { error("%s", "could not create reverse address for ip4: %s\n", ldns_get_errorstr_by_id(status)); } ldns_rdf_deep_free(qname_tmp); } if (!qname) { error("%s", "-x implies an ip address"); } /* create a packet and set the RD flag on it */ pkt = ldns_resolver_query(res, qname, type, clas, qflags); if (!pkt) { error("%s", "pkt sending"); result = EXIT_FAILURE; } else { if (verbosity != -1) { ldns_pkt_print(stdout, pkt); } ldns_pkt_free(pkt); } break; case DRILL_QUERY: default: if (query_file) { /* this old way, the query packet needed to be parseable, but we want to be able to send mangled packets, so we need to do it directly */ #if 0 qpkt = read_hex_pkt(query_file); if (qpkt) { status = ldns_resolver_send_pkt(&pkt, res, qpkt); if (status != LDNS_STATUS_OK) { printf("Error: %s\n", ldns_get_errorstr_by_id(status)); exit(1); } } else { /* qpkt was bogus, reset pkt */ pkt = NULL; } #endif query_buffer = read_hex_buffer(query_file); if (query_buffer) { status = ldns_send_buffer(&pkt, res, query_buffer, NULL); ldns_buffer_free(query_buffer); if (status != LDNS_STATUS_OK) { printf("Error: %s\n", ldns_get_errorstr_by_id(status)); exit(1); } } else { printf("NO BUFFER\n"); pkt = NULL; } } else { qname = ldns_dname_new_frm_str(name); if (!qname) { error("%s", "error in making qname"); } if (type == LDNS_RR_TYPE_AXFR) { status = ldns_axfr_start(res, qname, clas); if(status != LDNS_STATUS_OK) { error("Error starting axfr: %s", ldns_get_errorstr_by_id(status)); } axfr_rr = ldns_axfr_next(res); if(!axfr_rr) { fprintf(stderr, "AXFR failed.\n"); ldns_pkt_print(stdout, ldns_axfr_last_pkt(res)); goto exit; } while (axfr_rr) { if (verbosity != -1) { ldns_rr_print(stdout, axfr_rr); } ldns_rr_free(axfr_rr); axfr_rr = ldns_axfr_next(res); } goto exit; } else { /* create a packet and set the RD flag on it */ pkt = ldns_resolver_query(res, qname, type, clas, qflags); } } if (!pkt) { mesg("No packet received"); result = EXIT_FAILURE; } else { if (verbosity != -1) { ldns_pkt_print(stdout, pkt); if (ldns_pkt_tc(pkt)) { fprintf(stdout, "\n;; WARNING: The answer packet was truncated; you might want to\n"); fprintf(stdout, ";; query again with TCP (-t argument), or EDNS0 (-b for buffer size)\n"); } } if (qds) { if (verbosity != -1) { print_ds_of_keys(pkt); printf("\n"); } } if (ldns_rr_list_rr_count(key_list) > 0) { /* -k's were given on the cmd line */ ldns_rr_list *rrset_verified; uint16_t key_count; rrset_verified = ldns_pkt_rr_list_by_name_and_type( pkt, qname, type, LDNS_SECTION_ANY_NOQUESTION); if (type == LDNS_RR_TYPE_ANY) { /* don't verify this */ break; } if (verbosity != -1) { printf("; "); ldns_rr_list_print(stdout, rrset_verified); } /* verify */ #ifdef HAVE_SSL key_verified = ldns_rr_list_new(); result = ldns_pkt_verify(pkt, type, qname, key_list, NULL, key_verified); if (result == LDNS_STATUS_ERR) { /* is the existence denied then? */ result = ldns_verify_denial(pkt, qname, type, NULL, NULL); if (result == LDNS_STATUS_OK) { if (verbosity != -1) { printf("Existence denied for "); ldns_rdf_print(stdout, qname); type_str = ldns_rr_type2str(type); printf("\t%s\n", type_str); LDNS_FREE(type_str); } } else { if (verbosity != -1) { printf("Bad data; RR for name and " "type not found or failed to " "verify, and denial of " "existence failed.\n"); } } } else if (result == LDNS_STATUS_OK) { for(key_count = 0; key_count < ldns_rr_list_rr_count(key_verified); key_count++) { if (verbosity != -1) { printf("; VALIDATED by id = %u, owner = ", (unsigned int)ldns_calc_keytag( ldns_rr_list_rr(key_verified, key_count))); ldns_rdf_print(stdout, ldns_rr_owner( ldns_rr_list_rr(key_list, key_count))); printf("\n"); } } } else { for(key_count = 0; key_count < ldns_rr_list_rr_count(key_list); key_count++) { if (verbosity != -1) { printf("; %s for id = %u, owner = ", ldns_get_errorstr_by_id(result), (unsigned int)ldns_calc_keytag( ldns_rr_list_rr(key_list, key_count))); ldns_rdf_print(stdout, ldns_rr_owner( ldns_rr_list_rr(key_list, key_count))); printf("\n"); } } } ldns_rr_list_free(key_verified); #else (void) key_count; #endif /* HAVE_SSL */ } if (answer_file) { dump_hex(pkt, answer_file); } ldns_pkt_free(pkt); } break; } exit: ldns_rdf_deep_free(qname); ldns_resolver_deep_free(res); ldns_resolver_deep_free(cmdline_res); ldns_rr_list_deep_free(key_list); ldns_rr_list_deep_free(cmdline_rr_list); ldns_rdf_deep_free(trace_start_name); xfree(progname); xfree(tsig_name); xfree(tsig_data); xfree(tsig_algorithm); #ifdef HAVE_SSL ERR_remove_state(0); CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); EVP_cleanup(); #endif #ifdef USE_WINSOCK WSACleanup(); #endif return result; }
static ldns_rr_list * retrieve_dnskeys(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, ldns_rr_class c, ldns_rr_list *dns_root) { ldns_resolver *res; ldns_pkt *p; ldns_rr_list *new_nss_a; ldns_rr_list *new_nss_aaaa; ldns_rr_list *final_answer; ldns_rr_list *new_nss; ldns_rr_list *ns_addr; ldns_rr_list *ns_addr2; uint16_t loop_count; ldns_rdf *pop; ldns_status status; size_t i; size_t nss_i; ldns_rr_list *answer_list = NULL; ldns_rr_list *authority_list = NULL; size_t last_nameserver_count; ldns_rdf **last_nameservers; loop_count = 0; new_nss_a = NULL; new_nss_aaaa = NULL; new_nss = NULL; ns_addr = NULL; ns_addr2 = NULL; final_answer = NULL; p = ldns_pkt_new(); res = ldns_resolver_new(); if (!p || !res) { fprintf(stderr, "Memory allocation failed"); return NULL; } if (verbosity >= 2) { printf("Finding dnskey data for zone: "); ldns_rdf_print(stdout, name); printf("\n\n"); } /* transfer some properties of local_res to res, * because they were given on the commandline */ ldns_resolver_set_ip6(res, ldns_resolver_ip6(local_res)); ldns_resolver_set_port(res, ldns_resolver_port(local_res)); ldns_resolver_set_debug(res, ldns_resolver_debug(local_res)); ldns_resolver_set_dnssec(res, ldns_resolver_dnssec(local_res)); ldns_resolver_set_fail(res, ldns_resolver_fail(local_res)); ldns_resolver_set_usevc(res, ldns_resolver_usevc(local_res)); ldns_resolver_set_random(res, ldns_resolver_random(local_res)); ldns_resolver_set_recursive(res, false); /* setup the root nameserver in the new resolver */ status = ldns_resolver_push_nameserver_rr_list(res, dns_root); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error setting root nameservers in resolver: %s\n", ldns_get_errorstr_by_id(status)); return NULL; } ldns_pkt_free(p); status = ldns_resolver_send(&p, res, name, t, c, 0); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status)); return NULL; } if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) { printf("Error in packet:\n"); ldns_pkt_print(stdout, p); return NULL; } if (verbosity >= 4) { ldns_pkt_print(stdout, p); printf("\n\n"); } /* from now on, use TCP */ ldns_resolver_set_usevc(res, true); while(status == LDNS_STATUS_OK && ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) { if (verbosity >= 3) { printf("This is a delegation!\n\n"); } if (address_family == 0 || address_family == 1) { new_nss_a = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL); } else { new_nss_a = ldns_rr_list_new(); } if (address_family == 0 || address_family == 2) { new_nss_aaaa = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL); } else { new_nss_aaaa = ldns_rr_list_new(); } new_nss = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY); /* remove the old nameserver from the resolver */ while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); } /* also check for new_nss emptyness */ if (!new_nss_aaaa && !new_nss_a) { /* * no nameserver found!!! * try to resolve the names we do got */ if (verbosity >= 3) { printf("Did not get address record for nameserver, doing seperate query.\n"); } ns_addr = ldns_rr_list_new(); for(i = 0; (size_t) i < ldns_rr_list_rr_count(new_nss); i++) { /* get the name of the nameserver */ pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0); if (!pop) { break; } /* retrieve it's addresses */ ns_addr2 = ldns_get_rr_list_addr_by_name(local_res, pop, c, 0); if (!ldns_rr_list_cat(ns_addr, ns_addr2)) { fprintf(stderr, "Internal error adding nameserver address.\n"); exit(EXIT_FAILURE); } ldns_rr_list_free(ns_addr2); } if (ns_addr) { if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) != LDNS_STATUS_OK) { fprintf(stderr, "Error adding new nameservers"); ldns_pkt_free(p); return NULL; } ldns_rr_list_deep_free(ns_addr); } else { ldns_rr_list_print(stdout, ns_addr); fprintf(stderr, "Could not find the nameserver ip addr; abort"); ldns_pkt_free(p); return NULL; } } /* normally, the first working ns is used, but we need all now, so do it one by one * if the answer is null, take it from the next resolver * if the answer is not, compare it to that of the next resolver * error if different, continue if the same * if answer list null and no resolvers left die. */ ldns_rr_list_deep_free(answer_list); ldns_rr_list_deep_free(authority_list); answer_list = NULL; authority_list = NULL; for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_aaaa); nss_i++) { while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); } status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0)); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status)); } if (verbosity >= 1) { fprintf(stdout, "Querying nameserver: "); ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_aaaa, nss_i))); fprintf(stdout, " ("); ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0)); fprintf(stdout, ")\n"); } status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_aaaa, nss_i), 0)); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status)); } ldns_pkt_free(p); status = ldns_resolver_send(&p, res, name, t, c, 0); if (status == LDNS_STATUS_OK && p) { if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) { printf("Error in packet:\n"); ldns_pkt_print(stdout, p); return NULL; } if (verbosity >= 4) { ldns_pkt_print(stdout, p); printf("\n\n"); } if (answer_list) { if (verbosity >= 2) { printf("Comparing answer list of answer to previous\n\n"); } ldns_rr_list_sort(ldns_pkt_answer(p)); ldns_rr_list_sort(answer_list); if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) { fprintf(stderr, "ERROR: different answer answer from nameserver\n"); fprintf(stderr, "\nI had (from previous servers):\n"); ldns_rr_list_print(stderr, answer_list); fprintf(stderr, "\nI received (from nameserver at "); ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]); fprintf(stderr, "):\n"); ldns_rr_list_print(stderr, ldns_pkt_answer(p)); exit(EXIT_FAILURE); } } else { answer_list = ldns_rr_list_clone(ldns_pkt_answer(p)); ldns_rr_list_sort(answer_list); if (verbosity >= 2) { printf("First answer list for this set, nothing to compare with\n\n"); } } if (authority_list) { if (verbosity >= 2) { printf("Comparing authority list of answer to previous\n\n"); } ldns_rr_list_sort(ldns_pkt_authority(p)); ldns_rr_list_sort(authority_list); if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) { fprintf(stderr, "ERROR: different authority answer from nameserver\n"); fprintf(stderr, "\nI had (from previous servers):\n"); ldns_rr_list_print(stderr, authority_list); fprintf(stderr, "\nI received (from nameserver at "); ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]); fprintf(stderr, "):\n"); ldns_rr_list_print(stderr, ldns_pkt_authority(p)); exit(EXIT_FAILURE); } } else { authority_list = ldns_rr_list_clone(ldns_pkt_authority(p)); ldns_rr_list_sort(authority_list); if (verbosity >= 2) { printf("First authority list for this set, nothing to compare with\n\n"); } if (verbosity >= 3) { printf("NS RRset:\n"); ldns_rr_list_print(stdout, authority_list); printf("\n"); } } } } ldns_rr_list_deep_free(answer_list); ldns_rr_list_deep_free(authority_list); answer_list = NULL; authority_list = NULL; for (nss_i = 0; nss_i < ldns_rr_list_rr_count(new_nss_a); nss_i++) { while((pop = ldns_resolver_pop_nameserver(res))) {ldns_rdf_deep_free(pop); } if (verbosity >= 1) { fprintf(stdout, "Querying nameserver: "); ldns_rdf_print(stdout, ldns_rr_owner(ldns_rr_list_rr(new_nss_a, nss_i))); fprintf(stdout, " ("); ldns_rdf_print(stdout, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0)); fprintf(stdout, ")\n"); } status = ldns_resolver_push_nameserver(res, ldns_rr_rdf(ldns_rr_list_rr(new_nss_a, nss_i), 0)); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status)); } ldns_pkt_free(p); status = ldns_resolver_send(&p, res, name, t, c, 0); if (status == LDNS_STATUS_OK) { if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) { printf("Error in packet:\n"); ldns_pkt_print(stdout, p); return NULL; } if (verbosity >= 4) { ldns_pkt_print(stdout, p); printf("\n\n"); } if (answer_list) { if (verbosity >= 2) { printf("Comparing answer list of answer to previous\n\n"); } ldns_rr_list_sort(ldns_pkt_answer(p)); ldns_rr_list_sort(answer_list); if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) { fprintf(stderr, "ERROR: different answer answer from nameserver\n"); fprintf(stderr, "\nI had (from previous servers):\n"); ldns_rr_list_print(stderr, answer_list); fprintf(stderr, "\nI received (from nameserver at "); ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]); fprintf(stderr, "):\n"); ldns_rr_list_print(stderr, ldns_pkt_answer(p)); exit(EXIT_FAILURE); } } else { if (verbosity >= 2) { printf("First answer list for this set, nothing to compare with\n\n"); } answer_list = ldns_rr_list_clone(ldns_pkt_answer(p)); ldns_rr_list_sort(answer_list); } if (authority_list) { if (verbosity >= 2) { printf("Comparing authority list of answer to previous\n\n"); } ldns_rr_list_sort(ldns_pkt_authority(p)); ldns_rr_list_sort(authority_list); if (ldns_rr_list_compare(authority_list, ldns_pkt_authority(p)) != 0) { fprintf(stderr, "ERROR: different authority answer from nameserver\n"); fprintf(stderr, "\nI had (from previous servers):\n"); ldns_rr_list_print(stderr, authority_list); fprintf(stderr, "\nI received (from nameserver at "); ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]); fprintf(stderr, "):\n"); ldns_rr_list_print(stderr, ldns_pkt_authority(p)); exit(EXIT_FAILURE); } } else { if (verbosity >= 2) { printf("First authority list for this set, nothing to compare with\n\n"); } authority_list = ldns_rr_list_clone(ldns_pkt_authority(p)); ldns_rr_list_sort(authority_list); if (verbosity >= 3) { printf("NS RRset:\n"); ldns_rr_list_print(stdout, authority_list); printf("\n"); } } } } ldns_rr_list_deep_free(authority_list); authority_list = NULL; if (loop_count++ > 20) { /* unlikely that we are doing something usefull */ fprintf(stderr, "Looks like we are looping"); ldns_pkt_free(p); return NULL; } ldns_pkt_free(p); if (verbosity >= 3) { fprintf(stdout, "This level ok. Continuing to next.\n\n"); } status = ldns_resolver_send(&p, res, name, t, c, 0); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error querying root servers: %s\n", ldns_get_errorstr_by_id(status)); return NULL; } if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) { printf("Error in packet:\n"); ldns_pkt_print(stdout, p); return NULL; } if (verbosity >= 4) { ldns_pkt_print(stdout, p); printf("\n\n"); } ldns_rr_list_deep_free(new_nss_aaaa); ldns_rr_list_deep_free(new_nss_a); ldns_rr_list_deep_free(new_nss); new_nss_aaaa = NULL; new_nss_a = NULL; ns_addr = NULL; } ldns_rr_list_deep_free(answer_list); answer_list = NULL; /* clone the nameserver list, we are going to handle them one by one */ last_nameserver_count = 0; last_nameservers = LDNS_XMALLOC(ldns_rdf *, ldns_resolver_nameserver_count(res)); pop = NULL; while((pop = ldns_resolver_pop_nameserver(res))) { last_nameservers[last_nameserver_count] = pop; last_nameserver_count++; } for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) { /* remove previous nameserver */ while((pop = ldns_resolver_pop_nameserver(res))) { ldns_rdf_deep_free(pop); } if (verbosity >= 1) { printf("Querying nameserver: "); ldns_rdf_print(stdout, last_nameservers[nss_i]); printf("\n"); } status = ldns_resolver_push_nameserver(res, last_nameservers[nss_i]); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error adding nameserver to resolver: %s\n", ldns_get_errorstr_by_id(status)); } ldns_pkt_free(p); status = ldns_resolver_send(&p, res, name, t, c, 0); if (!p) { fprintf(stderr, "no packet received\n"); return NULL; } if (status == LDNS_STATUS_RES_NO_NS) { fprintf(stderr, "Error: nameserver at "); ldns_rdf_print(stderr, last_nameservers[nss_i]); fprintf(stderr, " not responding. Unable to check RRset here, aborting.\n"); return NULL; } if (ldns_pkt_get_rcode(p) != LDNS_RCODE_NOERROR) { printf("Error in packet:\n"); ldns_pkt_print(stdout, p); return NULL; } if (answer_list) { if (verbosity >= 2) { printf("1Comparing answer rr list of answer to previous\n"); } ldns_rr_list_sort(ldns_pkt_answer(p)); ldns_rr_list_sort(answer_list); if (ldns_rr_list_compare(answer_list, ldns_pkt_answer(p)) != 0) { printf("ERROR: different answer section in response from nameserver\n"); fprintf(stderr, "\nI had:\n"); ldns_rr_list_print(stderr, answer_list); fprintf(stderr, "\nI received (from nameserver at "); ldns_rdf_print(stderr, ldns_resolver_nameservers(res)[0]); fprintf(stderr, "):\n"); ldns_rr_list_print(stderr, ldns_pkt_answer(p)); exit(EXIT_FAILURE); } } else { if (verbosity >= 2) { printf("First answer rr list for this set, nothing to compare with\n"); } answer_list = ldns_rr_list_clone(ldns_pkt_answer(p)); if (verbosity >= 3) { printf("DNSKEY RRset:\n"); ldns_rr_list_print(stdout, answer_list); } } } for (nss_i = 0; nss_i < last_nameserver_count; nss_i++) { ldns_rdf_deep_free(last_nameservers[nss_i]); } LDNS_FREE(last_nameservers); ldns_resolver_deep_free(res); ldns_pkt_free(p); return answer_list; }
int main(int argc, char *argv[]) { ldns_rdf *dname, *hashed_dname; uint8_t nsec3_algorithm = 1; size_t nsec3_iterations_cmd = 1; uint16_t nsec3_iterations = 1; uint8_t nsec3_salt_length = 0; uint8_t *nsec3_salt = NULL; char *prog = strdup(argv[0]); int c; while ((c = getopt(argc, argv, "a:s:t:")) != -1) { switch (c) { case 'a': nsec3_algorithm = (uint8_t) atoi(optarg); break; case 's': if (strlen(optarg) % 2 != 0) { fprintf(stderr, "Salt value is not valid hex data, not a multiple of 2 characters\n"); exit(EXIT_FAILURE); } if (strlen(optarg) > 512) { fprintf(stderr, "Salt too long\n"); exit(EXIT_FAILURE); } nsec3_salt_length = (uint8_t) (strlen(optarg) / 2); nsec3_salt = LDNS_XMALLOC(uint8_t, nsec3_salt_length); for (c = 0; c < (int) strlen(optarg); c += 2) { if (isxdigit((int) optarg[c]) && isxdigit((int) optarg[c+1])) { nsec3_salt[c/2] = (uint8_t) ldns_hexdigit_to_int(optarg[c]) * 16 + ldns_hexdigit_to_int(optarg[c+1]); } else { fprintf(stderr, "Salt value is not valid hex data.\n"); exit(EXIT_FAILURE); } } break; case 't': nsec3_iterations_cmd = (size_t) atol(optarg); if (nsec3_iterations_cmd > LDNS_NSEC3_MAX_ITERATIONS) { fprintf(stderr, "Iterations count can not exceed %u, quitting\n", LDNS_NSEC3_MAX_ITERATIONS); exit(EXIT_FAILURE); } nsec3_iterations = (uint16_t) nsec3_iterations_cmd; break; default: usage(stderr, prog); exit(EXIT_SUCCESS); } } argc -= optind; argv += optind; if (argc < 1) { printf("Error: not enough arguments\n"); usage(stdout, prog); exit(EXIT_FAILURE); } else { dname = ldns_dname_new_frm_str(argv[0]); if (!dname) { fprintf(stderr, "Error: unable to parse domain name\n"); return EXIT_FAILURE; } hashed_dname = ldns_nsec3_hash_name(dname, nsec3_algorithm, nsec3_iterations, nsec3_salt_length, nsec3_salt); if (!hashed_dname) { fprintf(stderr, "Error creating NSEC3 hash\n"); return EXIT_FAILURE; } ldns_rdf_print(stdout, hashed_dname); printf("\n"); ldns_rdf_deep_free(dname); ldns_rdf_deep_free(hashed_dname); } if (nsec3_salt) { free(nsec3_salt); } free(prog); return EXIT_SUCCESS; }
/* same naive method as in drill0.9 * We resolver _ALL_ the names, which is ofcourse not needed * We _do_ use the local resolver to do that, so it still is * fast, but it can be made to run much faster */ ldns_pkt * do_trace(ldns_resolver *local_res, ldns_rdf *name, ldns_rr_type t, ldns_rr_class c) { ldns_resolver *res; ldns_pkt *p; ldns_rr_list *new_nss_a; ldns_rr_list *new_nss_aaaa; ldns_rr_list *final_answer; ldns_rr_list *new_nss; ldns_rr_list *ns_addr; uint16_t loop_count; ldns_rdf *pop; ldns_status status; size_t i; loop_count = 0; new_nss_a = NULL; new_nss_aaaa = NULL; new_nss = NULL; ns_addr = NULL; final_answer = NULL; p = ldns_pkt_new(); res = ldns_resolver_new(); if (!p) { if (res) { ldns_resolver_free(res); } error("Memory allocation failed"); return NULL; } if (!res) { ldns_pkt_free(p); error("Memory allocation failed"); return NULL; } /* transfer some properties of local_res to res, * because they were given on the commandline */ ldns_resolver_set_ip6(res, ldns_resolver_ip6(local_res)); ldns_resolver_set_port(res, ldns_resolver_port(local_res)); ldns_resolver_set_debug(res, ldns_resolver_debug(local_res)); ldns_resolver_set_dnssec(res, ldns_resolver_dnssec(local_res)); ldns_resolver_set_fail(res, ldns_resolver_fail(local_res)); ldns_resolver_set_usevc(res, ldns_resolver_usevc(local_res)); ldns_resolver_set_random(res, ldns_resolver_random(local_res)); ldns_resolver_set_recursive(res, false); /* setup the root nameserver in the new resolver */ status = ldns_resolver_push_nameserver_rr_list(res, global_dns_root); if (status != LDNS_STATUS_OK) { fprintf(stderr, "Error adding root servers to resolver: %s\n", ldns_get_errorstr_by_id(status)); ldns_rr_list_print(stdout, global_dns_root); ldns_resolver_free(res); ldns_pkt_free(p); return NULL; } /* this must be a real query to local_res */ status = ldns_resolver_send(&p, res, ldns_dname_new_frm_str("."), LDNS_RR_TYPE_NS, c, 0); /* p can still be NULL */ if (ldns_pkt_empty(p)) { warning("No root server information received"); } if (status == LDNS_STATUS_OK) { if (!ldns_pkt_empty(p)) { drill_pkt_print(stdout, local_res, p); } } else { error("cannot use local resolver"); return NULL; } status = ldns_resolver_send(&p, res, name, t, c, 0); while(status == LDNS_STATUS_OK && ldns_pkt_reply_type(p) == LDNS_PACKET_REFERRAL) { if (!p) { /* some error occurred, bail out */ return NULL; } new_nss_a = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_A, LDNS_SECTION_ADDITIONAL); new_nss_aaaa = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_AAAA, LDNS_SECTION_ADDITIONAL); new_nss = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS, LDNS_SECTION_AUTHORITY); if (verbosity != -1) { ldns_rr_list_print(stdout, new_nss); } /* checks itself for verbosity */ drill_pkt_print_footer(stdout, local_res, p); /* remove the old nameserver from the resolver */ while(ldns_resolver_pop_nameserver(res)) { /* do it */ } /* also check for new_nss emptyness */ if (!new_nss_aaaa && !new_nss_a) { /* * no nameserver found!!! * try to resolve the names we do got */ for(i = 0; i < ldns_rr_list_rr_count(new_nss); i++) { /* get the name of the nameserver */ pop = ldns_rr_rdf(ldns_rr_list_rr(new_nss, i), 0); if (!pop) { break; } ldns_rr_list_print(stdout, new_nss); ldns_rdf_print(stdout, pop); /* retrieve it's addresses */ ns_addr = ldns_rr_list_cat_clone(ns_addr, ldns_get_rr_list_addr_by_name(local_res, pop, c, 0)); } if (ns_addr) { if (ldns_resolver_push_nameserver_rr_list(res, ns_addr) != LDNS_STATUS_OK) { error("Error adding new nameservers"); ldns_pkt_free(p); return NULL; } ldns_rr_list_free(ns_addr); } else { ldns_rr_list_print(stdout, ns_addr); error("Could not find the nameserver ip addr; abort"); ldns_pkt_free(p); return NULL; } } /* add the new ones */ if (new_nss_aaaa) { if (ldns_resolver_push_nameserver_rr_list(res, new_nss_aaaa) != LDNS_STATUS_OK) { error("adding new nameservers"); ldns_pkt_free(p); return NULL; } } if (new_nss_a) { if (ldns_resolver_push_nameserver_rr_list(res, new_nss_a) != LDNS_STATUS_OK) { error("adding new nameservers"); ldns_pkt_free(p); return NULL; } } if (loop_count++ > 20) { /* unlikely that we are doing something usefull */ error("Looks like we are looping"); ldns_pkt_free(p); return NULL; } status = ldns_resolver_send(&p, res, name, t, c, 0); new_nss_aaaa = NULL; new_nss_a = NULL; ns_addr = NULL; } status = ldns_resolver_send(&p, res, name, t, c, 0); if (!p) { return NULL; } new_nss = ldns_pkt_authority(p); final_answer = ldns_pkt_answer(p); if (verbosity != -1) { ldns_rr_list_print(stdout, final_answer); ldns_rr_list_print(stdout, new_nss); } drill_pkt_print_footer(stdout, local_res, p); ldns_pkt_free(p); return NULL; }
/* this is NOT the hash, but the original name! */ ldns_rdf * ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) { /* remember parameters, they must match */ uint8_t algorithm; uint32_t iterations; uint8_t salt_length; uint8_t *salt; ldns_rdf *sname, *hashed_sname, *tmp; ldns_rr *ce; bool flag; bool exact_match_found; bool in_range_found; ldns_status status; ldns_rdf *zone_name; size_t nsec_i; ldns_rr *nsec; ldns_rdf *result = NULL; if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) { return NULL; } if (verbosity >= 4) { printf(";; finding closest encloser for type %d ", qtype); ldns_rdf_print(stdout, qname); printf("\n"); } nsec = ldns_rr_list_rr(nsec3s, 0); algorithm = ldns_nsec3_algorithm(nsec); salt_length = ldns_nsec3_salt_length(nsec); salt = ldns_nsec3_salt_data(nsec); iterations = ldns_nsec3_iterations(nsec); sname = ldns_rdf_clone(qname); ce = NULL; flag = false; zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec)); /* algorithm from nsec3-07 8.3 */ while (ldns_dname_label_count(sname) > 0) { exact_match_found = false; in_range_found = false; if (verbosity >= 3) { printf(";; "); ldns_rdf_print(stdout, sname); printf(" hashes to: "); } hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt); status = ldns_dname_cat(hashed_sname, zone_name); if (verbosity >= 3) { ldns_rdf_print(stdout, hashed_sname); printf("\n"); } for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) { nsec = ldns_rr_list_rr(nsec3s, nsec_i); /* check values of iterations etc! */ /* exact match? */ if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) { if (verbosity >= 4) { printf(";; exact match found\n"); } exact_match_found = true; } else if (ldns_nsec_covers_name(nsec, hashed_sname)) { if (verbosity >= 4) { printf(";; in range of an nsec\n"); } in_range_found = true; } } if (!exact_match_found && in_range_found) { flag = true; } else if (exact_match_found && flag) { result = ldns_rdf_clone(sname); } else if (exact_match_found && !flag) { // error! if (verbosity >= 4) { printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n"); } ldns_rdf_deep_free(hashed_sname); goto done; } else { flag = false; } ldns_rdf_deep_free(hashed_sname); tmp = sname; sname = ldns_dname_left_chop(sname); ldns_rdf_deep_free(tmp); } done: LDNS_FREE(salt); ldns_rdf_deep_free(zone_name); ldns_rdf_deep_free(sname); if (!result) { if (verbosity >= 4) { printf(";; no closest encloser found\n"); } } /* todo checks from end of 6.2. here or in caller? */ return result; }
/*return hash name match*/ ldns_rr * ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) { uint8_t algorithm; uint32_t iterations; uint8_t salt_length; uint8_t *salt; ldns_rdf *sname, *hashed_sname; size_t nsec_i; ldns_rr *nsec; ldns_rr *result = NULL; ldns_status status; const ldns_rr_descriptor *descriptor; ldns_rdf *zone_name; if (verbosity >= 4) { printf(";; finding exact match for "); descriptor = ldns_rr_descript(qtype); if (descriptor && descriptor->_name) { printf("%s ", descriptor->_name); } else { printf("TYPE%d ", qtype); } ldns_rdf_print(stdout, qname); printf("\n"); } if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) { if (verbosity >= 4) { printf("no qname, nsec3s or list empty\n"); } return NULL; } nsec = ldns_rr_list_rr(nsec3s, 0); algorithm = ldns_nsec3_algorithm(nsec); salt_length = ldns_nsec3_salt_length(nsec); salt = ldns_nsec3_salt_data(nsec); iterations = ldns_nsec3_iterations(nsec); sname = ldns_rdf_clone(qname); if (verbosity >= 4) { printf(";; owner name hashes to: "); } hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt); zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec)); status = ldns_dname_cat(hashed_sname, zone_name); if (verbosity >= 4) { ldns_rdf_print(stdout, hashed_sname); printf("\n"); } for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) { nsec = ldns_rr_list_rr(nsec3s, nsec_i); /* check values of iterations etc! */ /* exact match? */ if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) { result = nsec; goto done; } } done: ldns_rdf_deep_free(zone_name); ldns_rdf_deep_free(sname); ldns_rdf_deep_free(hashed_sname); LDNS_FREE(salt); if (verbosity >= 4) { if (result) { printf(";; Found.\n"); } else { printf(";; Not foud.\n"); } } return result; }