static isc_result_t probe_domain (struct probe_trans *trans) { isc_result_t result; size_t domainlen; isc_buffer_t b; char buf[4096]; /* XXX ad hoc constant, but should be enough */ char *cp; REQUIRE (trans != NULL); REQUIRE (trans->inuse == ISC_FALSE); REQUIRE (outstanding_probes < MAX_PROBES); /* Construct domain */ cp = fgets (buf, sizeof (buf), fp); if (cp == NULL) return (ISC_R_NOMORE); if ((cp = strchr (buf, '\n')) != NULL) /* zap NL if any */ *cp = '\0'; trans->domain = isc_mem_strdup (mctx, buf); if (trans->domain == NULL) { fprintf (stderr, "failed to allocate memory for domain: %s", cp); return (ISC_R_NOMEMORY); } /* Start getting NS for the domain */ domainlen = strlen (buf); isc_buffer_init (&b, buf, domainlen); isc_buffer_add (&b, domainlen); dns_fixedname_init (&trans->fixedname); trans->qname = dns_fixedname_name (&trans->fixedname); result = dns_name_fromtext (trans->qname, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto cleanup; result = dns_client_startresolve (client, trans->qname, dns_rdataclass_in, dns_rdatatype_ns, 0, probe_task, resolve_ns, trans, &trans->resid); if (result != ISC_R_SUCCESS) goto cleanup; trans->inuse = ISC_TRUE; outstanding_probes++; return (ISC_R_SUCCESS); cleanup: isc_mem_free (mctx, trans->domain); dns_fixedname_invalidate (&trans->fixedname); return (result); }
static void process_answer(isc_task_t *task, isc_event_t *event) { struct query_trans *trans = event->ev_arg; dns_clientresevent_t *rev = (dns_clientresevent_t *)event; dns_name_t *name; dns_rdataset_t *rdataset; isc_result_t result; REQUIRE(task == query_task); REQUIRE(trans->inuse == ISC_TRUE); REQUIRE(outstanding_queries > 0); printf("answer[%2d]\n", trans->id); if (rev->result != ISC_R_SUCCESS) printf(" failed: %d(%s)\n", rev->result, dns_result_totext(rev->result)); for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; name = ISC_LIST_NEXT(name, link)) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { (void)printdata(rdataset, name); } } dns_client_freeresanswer(client, &rev->answerlist); dns_client_destroyrestrans(&trans->xid); isc_event_free(&event); trans->inuse = ISC_FALSE; dns_fixedname_invalidate(&trans->fixedname); trans->qname = NULL; outstanding_queries--; result = dispatch_query(trans); #if 0 /* for cancel test */ if (result == ISC_R_SUCCESS) { static int count = 0; if ((++count) % 10 == 0) dns_client_cancelresolve(trans->xid); } #endif if (result == ISC_R_NOMORE && outstanding_queries == 0) isc_app_ctxshutdown(query_actx); }
static isc_result_t dispatch_query(struct query_trans *trans) { isc_result_t result; size_t namelen; isc_buffer_t b; char buf[4096]; /* XXX ad hoc constant, but should be enough */ char *cp; REQUIRE(trans != NULL); REQUIRE(trans->inuse == ISC_FALSE); REQUIRE(ISC_LIST_EMPTY(trans->answerlist)); REQUIRE(outstanding_queries < MAX_QUERIES); /* Construct qname */ cp = fgets(buf, sizeof(buf), fp); if (cp == NULL) return (ISC_R_NOMORE); /* zap NL if any */ if ((cp = strchr(buf, '\n')) != NULL) *cp = '\0'; namelen = strlen(buf); isc_buffer_init(&b, buf, namelen); isc_buffer_add(&b, namelen); dns_fixedname_init(&trans->fixedname); trans->qname = dns_fixedname_name(&trans->fixedname); result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL); if (result != ISC_R_SUCCESS) goto cleanup; /* Start resolution */ result = dns_client_startresolve(client, trans->qname, dns_rdataclass_in, trans->type, 0, query_task, process_answer, trans, &trans->xid); if (result != ISC_R_SUCCESS) goto cleanup; trans->inuse = ISC_TRUE; outstanding_queries++; return (ISC_R_SUCCESS); cleanup: dns_fixedname_invalidate(&trans->fixedname); return (result); }
static void reset_probe (struct probe_trans *trans) { struct probe_ns *pns; struct server *server; isc_result_t result; REQUIRE (trans->resid == NULL); REQUIRE (trans->reqid == NULL); update_stat (trans); dns_message_reset (trans->qmessage, DNS_MESSAGE_INTENTRENDER); dns_message_reset (trans->rmessage, DNS_MESSAGE_INTENTPARSE); trans->inuse = ISC_FALSE; if (trans->domain != NULL) isc_mem_free (mctx, trans->domain); trans->domain = NULL; if (trans->qname != NULL) dns_fixedname_invalidate (&trans->fixedname); trans->qname = NULL; trans->qlabel = qlabels; trans->qname_found = ISC_FALSE; trans->current_ns = NULL; while ((pns = ISC_LIST_HEAD (trans->nslist)) != NULL) { ISC_LIST_UNLINK (trans->nslist, pns, link); while ((server = ISC_LIST_HEAD (pns->servers)) != NULL) { ISC_LIST_UNLINK (pns->servers, server, link); isc_mem_put (mctx, server, sizeof (*server)); } isc_mem_put (mctx, pns, sizeof (*pns)); } outstanding_probes--; result = probe_domain (trans); if (result == ISC_R_NOMORE && outstanding_probes == 0) isc_app_ctxshutdown (actx); }
static void resolve_nsaddress(isc_task_t *task, isc_event_t *event) { struct probe_trans *trans = event->ev_arg; dns_clientresevent_t *rev = (dns_clientresevent_t *)event; dns_name_t *name; dns_rdataset_t *rdataset; dns_rdata_t rdata = DNS_RDATA_INIT; struct probe_ns *pns = trans->current_ns; isc_result_t result; REQUIRE(task == probe_task); REQUIRE(trans->inuse == ISC_TRUE); REQUIRE(pns != NULL); INSIST(outstanding_probes > 0); for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; name = ISC_LIST_NEXT(name, link)) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { (void)print_rdataset(rdataset, name); if (rdataset->type != dns_rdatatype_a) continue; for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { dns_rdata_in_a_t rdata_a; struct server *server; dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &rdata_a, NULL); if (result != ISC_R_SUCCESS) continue; server = isc_mem_get(mctx, sizeof(*server)); if (server == NULL) { fprintf(stderr, "resolve_nsaddress: " "mem_get failed"); result = ISC_R_NOMEMORY; POST(result); goto cleanup; } isc_sockaddr_fromin(&server->address, &rdata_a.in_addr, 53); ISC_LINK_INIT(server, link); server->result_a = none; server->result_aaaa = none; ISC_LIST_APPEND(pns->servers, server, link); } } } cleanup: dns_client_freeresanswer(client, &rev->answerlist); dns_client_destroyrestrans(&trans->resid); isc_event_free(&event); next_ns: trans->current_ns = ISC_LIST_NEXT(pns, link); if (trans->current_ns == NULL) { trans->current_ns = ISC_LIST_HEAD(trans->nslist); dns_fixedname_invalidate(&trans->fixedname); trans->qname = NULL; result = set_nextqname(trans); if (result == ISC_R_SUCCESS) result = probe_name(trans, dns_rdatatype_a); } else { result = fetch_nsaddress(trans); if (result != ISC_R_SUCCESS) goto next_ns; /* XXX: this is unlikely to succeed */ } if (result != ISC_R_SUCCESS) reset_probe(trans); }
static void request_done(isc_task_t *task, isc_event_t *event) { struct probe_trans *trans = event->ev_arg; dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event; dns_message_t *rmessage; struct probe_ns *pns; struct server *server; isc_result_t result; query_result_t *resultp; dns_name_t *name; dns_rdataset_t *rdataset; dns_rdatatype_t type; REQUIRE(task == probe_task); REQUIRE(trans != NULL && trans->inuse == ISC_TRUE); rmessage = rev->rmessage; REQUIRE(rmessage == trans->rmessage); INSIST(outstanding_probes > 0); server = trans->current_ns->current_server; INSIST(server != NULL); if (server->result_a == none) { type = dns_rdatatype_a; resultp = &server->result_a; } else { resultp = &server->result_aaaa; type = dns_rdatatype_aaaa; } if (rev->result == ISC_R_SUCCESS) { if ((rmessage->flags & DNS_MESSAGEFLAG_AA) == 0) *resultp = lame; else if (rmessage->rcode == dns_rcode_nxdomain) *resultp = nxdomain; else if (rmessage->rcode != dns_rcode_noerror) *resultp = othererr; else if (rmessage->counts[DNS_SECTION_ANSWER] == 0) { /* no error but empty answer */ *resultp = notype; } else { result = dns_message_firstname(rmessage, DNS_SECTION_ANSWER); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(rmessage, DNS_SECTION_ANSWER, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { (void)print_rdataset(rdataset, name); if (rdataset->type == dns_rdatatype_cname || rdataset->type == dns_rdatatype_dname) { /* Should chase the chain? */ *resultp = exist; goto found; } else if (rdataset->type == type) { *resultp = exist; goto found; } } result = dns_message_nextname(rmessage, DNS_SECTION_ANSWER); } /* * Something unexpected happened: the response * contained a non-empty authoritative answer, but we * could not find an expected result. */ *resultp = unexpected; } } else if (rev->result == DNS_R_RECOVERABLE || rev->result == DNS_R_BADLABELTYPE) { /* Broken response. Try identifying known cases. */ *resultp = brokenanswer; if (rmessage->counts[DNS_SECTION_ANSWER] > 0) { result = dns_message_firstname(rmessage, DNS_SECTION_ANSWER); while (result == ISC_R_SUCCESS) { /* * Check to see if the response has multiple * CNAME RRs. Update the result code if so. */ name = NULL; dns_message_currentname(rmessage, DNS_SECTION_ANSWER, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->type == dns_rdatatype_cname && dns_rdataset_count(rdataset) > 1) { *resultp = multiplecname; goto found; } } result = dns_message_nextname(rmessage, DNS_SECTION_ANSWER); } } if (rmessage->counts[DNS_SECTION_AUTHORITY] > 0) { result = dns_message_firstname(rmessage, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { /* * Check to see if the response has multiple * SOA RRs. Update the result code if so. */ name = NULL; dns_message_currentname(rmessage, DNS_SECTION_AUTHORITY, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->type == dns_rdatatype_soa && dns_rdataset_count(rdataset) > 1) { *resultp = multiplesoa; goto found; } } result = dns_message_nextname(rmessage, DNS_SECTION_AUTHORITY); } } } else if (rev->result == ISC_R_TIMEDOUT) *resultp = timedout; else { fprintf(stderr, "unexpected result: %d (domain=%s, server=", rev->result, trans->domain); print_address(stderr, &server->address); fputc('\n', stderr); *resultp = unexpected; } found: INSIST(*resultp != none); if (type == dns_rdatatype_a && *resultp == exist) trans->qname_found = ISC_TRUE; dns_client_destroyreqtrans(&trans->reqid); isc_event_free(&event); dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE); result = probe_name(trans, type); if (result == ISC_R_NOMORE) { /* We've tried all addresses of all servers. */ if (type == dns_rdatatype_a && trans->qname_found) { /* * If we've explored A RRs and found an existent * record, we can move to AAAA. */ trans->current_ns = ISC_LIST_HEAD(trans->nslist); probe_name(trans, dns_rdatatype_aaaa); result = ISC_R_SUCCESS; } else if (type == dns_rdatatype_a) { /* * No server provided an existent A RR of this name. * Try next label. */ dns_fixedname_invalidate(&trans->fixedname); trans->qname = NULL; result = set_nextqname(trans); if (result == ISC_R_SUCCESS) { trans->current_ns = ISC_LIST_HEAD(trans->nslist); for (pns = trans->current_ns; pns != NULL; pns = ISC_LIST_NEXT(pns, link)) { for (server = ISC_LIST_HEAD(pns->servers); server != NULL; server = ISC_LIST_NEXT(server, link)) { INSIST(server->result_aaaa == none); server->result_a = none; } } result = probe_name(trans, dns_rdatatype_a); } } if (result != ISC_R_SUCCESS) { /* * We've explored AAAA RRs or failed to find a valid * query label. Wrap up the result and move to the * next domain. */ reset_probe(trans); } } else if (result != ISC_R_SUCCESS) reset_probe(trans); /* XXX */ }