2 * Copyright (C) 2009-2012 Internet Systems Consortium, Inc. ("ISC")
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
21 #include <sys/types.h>
22 #include <sys/socket.h>
31 #include <isc/buffer.h>
34 #include <isc/socket.h>
35 #include <isc/sockaddr.h>
36 #include <isc/string.h>
38 #include <isc/timer.h>
41 #include <dns/client.h>
42 #include <dns/fixedname.h>
44 #include <dns/message.h>
46 #include <dns/rdata.h>
47 #include <dns/rdataset.h>
48 #include <dns/rdatastruct.h>
49 #include <dns/rdatatype.h>
50 #include <dns/result.h>
52 #define MAX_PROBES 1000
54 static dns_client_t *client = NULL;
55 static isc_task_t *probe_task = NULL;
56 static isc_appctx_t *actx = NULL;
57 static isc_mem_t *mctx = NULL;
58 static unsigned int outstanding_probes = 0;
59 const char *cacheserver = "127.0.0.1";
77 ISC_LINK(struct server) link;
79 isc_sockaddr_t address;
80 query_result_t result_a;
81 query_result_t result_aaaa;
85 ISC_LINK(struct probe_ns) link;
87 dns_fixedname_t fixedname;
89 struct server *current_server;
90 ISC_LIST(struct server) servers;
96 dns_fixedname_t fixedname;
99 isc_boolean_t qname_found;
100 dns_clientrestrans_t *resid;
101 dns_message_t *qmessage;
102 dns_message_t *rmessage;
103 dns_clientreqtrans_t *reqid;
106 struct probe_ns *current_ns;
107 ISC_LIST(struct probe_ns) nslist;
112 unsigned long ignore;
113 unsigned long nxdomain;
114 unsigned long othererr;
115 unsigned long multiplesoa;
116 unsigned long multiplecname;
117 unsigned long brokenanswer;
119 unsigned long unknown;
120 } server_stat, domain_stat;
122 static unsigned long number_of_domains = 0;
123 static unsigned long number_of_servers = 0;
124 static unsigned long multiple_error_domains = 0;
125 static isc_boolean_t debug_mode = ISC_FALSE;
126 static int verbose_level = 0;
127 static const char *qlabels[] = {"www.", "ftp.", NULL};
128 static struct probe_trans probes[MAX_PROBES];
130 static isc_result_t probe_domain(struct probe_trans *trans);
131 static void reset_probe(struct probe_trans *trans);
132 static isc_result_t fetch_nsaddress(struct probe_trans *trans);
133 static isc_result_t probe_name(struct probe_trans *trans,
134 dns_rdatatype_t type);
136 /* Dump an rdataset for debug */
138 print_rdataset(dns_rdataset_t *rdataset, dns_name_t *owner) {
145 return (ISC_R_SUCCESS);
147 isc_buffer_init(&target, t, sizeof(t));
149 if (!dns_rdataset_isassociated(rdataset))
150 return (ISC_R_SUCCESS);
151 result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE,
153 if (result != ISC_R_SUCCESS)
155 isc_buffer_usedregion(&target, &r);
156 printf("%.*s", (int)r.length, (char *)r.base);
158 return (ISC_R_SUCCESS);
162 print_name(dns_name_t *name) {
168 isc_buffer_init(&target, t, sizeof(t));
169 result = dns_name_totext(name, ISC_TRUE, &target);
170 if (result == ISC_R_SUCCESS) {
171 isc_buffer_usedregion(&target, &r);
172 printf("%.*s", (int)r.length, (char *)r.base);
174 printf("(invalid name)");
180 print_address(FILE *fp, isc_sockaddr_t *addr) {
181 char buf[NI_MAXHOST];
183 if (getnameinfo(&addr->type.sa, addr->length, buf, sizeof(buf),
184 NULL, 0, NI_NUMERICHOST) == 0) {
185 fprintf(fp, "%s", buf);
187 fprintf(fp, "(invalid address)");
190 return (ISC_R_SUCCESS);
194 ctxs_destroy(isc_mem_t **mctxp, isc_appctx_t **actxp,
195 isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
196 isc_timermgr_t **timermgrp)
198 if (*taskmgrp != NULL)
199 isc_taskmgr_destroy(taskmgrp);
201 if (*timermgrp != NULL)
202 isc_timermgr_destroy(timermgrp);
204 if (*socketmgrp != NULL)
205 isc_socketmgr_destroy(socketmgrp);
208 isc_appctx_destroy(actxp);
211 isc_mem_destroy(mctxp);
215 ctxs_init(isc_mem_t **mctxp, isc_appctx_t **actxp,
216 isc_taskmgr_t **taskmgrp, isc_socketmgr_t **socketmgrp,
217 isc_timermgr_t **timermgrp)
221 result = isc_mem_create(0, 0, mctxp);
222 if (result != ISC_R_SUCCESS)
225 result = isc_appctx_create(*mctxp, actxp);
226 if (result != ISC_R_SUCCESS)
229 result = isc_taskmgr_createinctx(*mctxp, *actxp, 1, 0, taskmgrp);
230 if (result != ISC_R_SUCCESS)
233 result = isc_socketmgr_createinctx(*mctxp, *actxp, socketmgrp);
234 if (result != ISC_R_SUCCESS)
237 result = isc_timermgr_createinctx(*mctxp, *actxp, timermgrp);
238 if (result != ISC_R_SUCCESS)
241 return (ISC_R_SUCCESS);
244 ctxs_destroy(mctxp, actxp, taskmgrp, socketmgrp, timermgrp);
250 * Common routine to make query data
253 make_querymessage(dns_message_t *message, dns_name_t *qname0,
254 dns_rdatatype_t rdtype)
256 dns_name_t *qname = NULL;
257 dns_rdataset_t *qrdataset = NULL;
260 message->opcode = dns_opcode_query;
261 message->rdclass = dns_rdataclass_in;
263 result = dns_message_gettempname(message, &qname);
264 if (result != ISC_R_SUCCESS)
267 result = dns_message_gettemprdataset(message, &qrdataset);
268 if (result != ISC_R_SUCCESS)
271 dns_name_init(qname, NULL);
272 dns_name_clone(qname0, qname);
273 dns_rdataset_init(qrdataset);
274 dns_rdataset_makequestion(qrdataset, message->rdclass, rdtype);
275 ISC_LIST_APPEND(qname->list, qrdataset, link);
276 dns_message_addname(message, qname, DNS_SECTION_QUESTION);
278 return (ISC_R_SUCCESS);
282 dns_message_puttempname(message, &qname);
283 if (qrdataset != NULL)
284 dns_message_puttemprdataset(message, &qrdataset);
286 dns_message_destroy(&message);
294 increment_entry(unsigned long *entryp) {
296 INSIST(*entryp != 0); /* check overflow */
300 update_stat(struct probe_trans *trans) {
301 struct probe_ns *pns;
302 struct server *server;
303 struct lcl_stat local_stat;
304 unsigned int err_count = 0;
305 const char *stattype;
307 increment_entry(&number_of_domains);
308 memset(&local_stat, 0, sizeof(local_stat));
310 /* Update per sever statistics */
311 for (pns = ISC_LIST_HEAD(trans->nslist); pns != NULL;
312 pns = ISC_LIST_NEXT(pns, link)) {
313 for (server = ISC_LIST_HEAD(pns->servers); server != NULL;
314 server = ISC_LIST_NEXT(server, link)) {
315 increment_entry(&number_of_servers);
317 if (server->result_aaaa == exist ||
318 server->result_aaaa == notype) {
320 * Don't care about the result of A query if
321 * the answer to AAAA query was expected.
324 increment_entry(&server_stat.valid);
325 increment_entry(&local_stat.valid);
326 } else if (server->result_a == exist) {
327 switch (server->result_aaaa) {
331 increment_entry(&server_stat.valid);
332 increment_entry(&local_stat.valid);
336 increment_entry(&server_stat.ignore);
337 increment_entry(&local_stat.ignore);
340 stattype = "nxdomain";
341 increment_entry(&server_stat.nxdomain);
342 increment_entry(&local_stat.nxdomain);
345 stattype = "othererr";
346 increment_entry(&server_stat.othererr);
347 increment_entry(&local_stat.othererr);
350 stattype = "multiplesoa";
351 increment_entry(&server_stat.multiplesoa);
352 increment_entry(&local_stat.multiplesoa);
355 stattype = "multiplecname";
356 increment_entry(&server_stat.multiplecname);
357 increment_entry(&local_stat.multiplecname);
360 stattype = "brokenanswer";
361 increment_entry(&server_stat.brokenanswer);
362 increment_entry(&local_stat.brokenanswer);
366 increment_entry(&server_stat.lame);
367 increment_entry(&local_stat.lame);
370 stattype = "unknown";
371 increment_entry(&server_stat.unknown);
372 increment_entry(&local_stat.unknown);
376 stattype = "unknown";
377 increment_entry(&server_stat.unknown);
378 increment_entry(&local_stat.unknown);
381 if (verbose_level > 1 ||
382 (verbose_level == 1 &&
383 strcmp(stattype, "valid") != 0 &&
384 strcmp(stattype, "unknown") != 0)) {
385 print_name(pns->name);
387 print_address(stdout, &server->address);
388 printf(") for %s:%s\n", trans->domain,
394 /* Update per domain statistics */
395 if (local_stat.ignore > 0) {
396 if (verbose_level > 0)
397 printf("%s:ignore\n", trans->domain);
398 increment_entry(&domain_stat.ignore);
401 if (local_stat.nxdomain > 0) {
402 if (verbose_level > 0)
403 printf("%s:nxdomain\n", trans->domain);
404 increment_entry(&domain_stat.nxdomain);
407 if (local_stat.othererr > 0) {
408 if (verbose_level > 0)
409 printf("%s:othererr\n", trans->domain);
410 increment_entry(&domain_stat.othererr);
413 if (local_stat.multiplesoa > 0) {
414 if (verbose_level > 0)
415 printf("%s:multiplesoa\n", trans->domain);
416 increment_entry(&domain_stat.multiplesoa);
419 if (local_stat.multiplecname > 0) {
420 if (verbose_level > 0)
421 printf("%s:multiplecname\n", trans->domain);
422 increment_entry(&domain_stat.multiplecname);
425 if (local_stat.brokenanswer > 0) {
426 if (verbose_level > 0)
427 printf("%s:brokenanswer\n", trans->domain);
428 increment_entry(&domain_stat.brokenanswer);
431 if (local_stat.lame > 0) {
432 if (verbose_level > 0)
433 printf("%s:lame\n", trans->domain);
434 increment_entry(&domain_stat.lame);
439 increment_entry(&multiple_error_domains);
442 * We regard the domain as valid if and only if no authoritative server
443 * has a problem and at least one server is known to be valid.
445 if (local_stat.valid > 0 && err_count == 0) {
446 if (verbose_level > 1)
447 printf("%s:valid\n", trans->domain);
448 increment_entry(&domain_stat.valid);
452 * If the domain has no available server or all servers have the
453 * 'unknown' result, the domain's result is also regarded as unknown.
455 if (local_stat.valid == 0 && err_count == 0) {
456 if (verbose_level > 1)
457 printf("%s:unknown\n", trans->domain);
458 increment_entry(&domain_stat.unknown);
463 * Search for an existent name with an A RR
467 set_nextqname(struct probe_trans *trans) {
471 char buf[4096]; /* XXX ad-hoc constant, but should be enough */
473 if (*trans->qlabel == NULL)
474 return (ISC_R_NOMORE);
476 result = isc_string_copy(buf, sizeof(buf), *trans->qlabel);
477 if (result != ISC_R_SUCCESS)
479 result = isc_string_append(buf, sizeof(buf), trans->domain);
480 if (result != ISC_R_SUCCESS)
483 domainlen = strlen(buf);
484 isc_buffer_init(&b, buf, domainlen);
485 isc_buffer_add(&b, domainlen);
486 dns_fixedname_init(&trans->fixedname);
487 trans->qname = dns_fixedname_name(&trans->fixedname);
488 result = dns_name_fromtext(trans->qname, &b, dns_rootname,
497 request_done(isc_task_t *task, isc_event_t *event) {
498 struct probe_trans *trans = event->ev_arg;
499 dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event;
500 dns_message_t *rmessage;
501 struct probe_ns *pns;
502 struct server *server;
504 query_result_t *resultp;
506 dns_rdataset_t *rdataset;
507 dns_rdatatype_t type;
509 REQUIRE(task == probe_task);
510 REQUIRE(trans != NULL && trans->inuse == ISC_TRUE);
511 rmessage = rev->rmessage;
512 REQUIRE(rmessage == trans->rmessage);
513 INSIST(outstanding_probes > 0);
515 server = trans->current_ns->current_server;
516 INSIST(server != NULL);
518 if (server->result_a == none) {
519 type = dns_rdatatype_a;
520 resultp = &server->result_a;
522 resultp = &server->result_aaaa;
523 type = dns_rdatatype_aaaa;
526 if (rev->result == ISC_R_SUCCESS) {
527 if ((rmessage->flags & DNS_MESSAGEFLAG_AA) == 0)
529 else if (rmessage->rcode == dns_rcode_nxdomain)
531 else if (rmessage->rcode != dns_rcode_noerror)
533 else if (rmessage->counts[DNS_SECTION_ANSWER] == 0) {
534 /* no error but empty answer */
537 result = dns_message_firstname(rmessage,
539 while (result == ISC_R_SUCCESS) {
541 dns_message_currentname(rmessage,
544 for (rdataset = ISC_LIST_HEAD(name->list);
546 rdataset = ISC_LIST_NEXT(rdataset,
548 (void)print_rdataset(rdataset, name);
550 if (rdataset->type ==
551 dns_rdatatype_cname ||
553 dns_rdatatype_dname) {
554 /* Should chase the chain? */
557 } else if (rdataset->type == type) {
562 result = dns_message_nextname(rmessage,
567 * Something unexpected happened: the response
568 * contained a non-empty authoritative answer, but we
569 * could not find an expected result.
571 *resultp = unexpected;
573 } else if (rev->result == DNS_R_RECOVERABLE ||
574 rev->result == DNS_R_BADLABELTYPE) {
575 /* Broken response. Try identifying known cases. */
576 *resultp = brokenanswer;
578 if (rmessage->counts[DNS_SECTION_ANSWER] > 0) {
579 result = dns_message_firstname(rmessage,
581 while (result == ISC_R_SUCCESS) {
583 * Check to see if the response has multiple
584 * CNAME RRs. Update the result code if so.
587 dns_message_currentname(rmessage,
590 for (rdataset = ISC_LIST_HEAD(name->list);
592 rdataset = ISC_LIST_NEXT(rdataset,
594 if (rdataset->type ==
595 dns_rdatatype_cname &&
596 dns_rdataset_count(rdataset) > 1) {
597 *resultp = multiplecname;
601 result = dns_message_nextname(rmessage,
606 if (rmessage->counts[DNS_SECTION_AUTHORITY] > 0) {
607 result = dns_message_firstname(rmessage,
608 DNS_SECTION_AUTHORITY);
609 while (result == ISC_R_SUCCESS) {
611 * Check to see if the response has multiple
612 * SOA RRs. Update the result code if so.
615 dns_message_currentname(rmessage,
616 DNS_SECTION_AUTHORITY,
618 for (rdataset = ISC_LIST_HEAD(name->list);
620 rdataset = ISC_LIST_NEXT(rdataset,
622 if (rdataset->type ==
624 dns_rdataset_count(rdataset) > 1) {
625 *resultp = multiplesoa;
629 result = dns_message_nextname(rmessage,
630 DNS_SECTION_AUTHORITY);
633 } else if (rev->result == ISC_R_TIMEDOUT)
636 fprintf(stderr, "unexpected result: %d (domain=%s, server=",
637 rev->result, trans->domain);
638 print_address(stderr, &server->address);
640 *resultp = unexpected;
644 INSIST(*resultp != none);
645 if (type == dns_rdatatype_a && *resultp == exist)
646 trans->qname_found = ISC_TRUE;
648 dns_client_destroyreqtrans(&trans->reqid);
649 isc_event_free(&event);
650 dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE);
652 result = probe_name(trans, type);
653 if (result == ISC_R_NOMORE) {
654 /* We've tried all addresses of all servers. */
655 if (type == dns_rdatatype_a && trans->qname_found) {
657 * If we've explored A RRs and found an existent
658 * record, we can move to AAAA.
660 trans->current_ns = ISC_LIST_HEAD(trans->nslist);
661 probe_name(trans, dns_rdatatype_aaaa);
662 result = ISC_R_SUCCESS;
663 } else if (type == dns_rdatatype_a) {
665 * No server provided an existent A RR of this name.
668 dns_fixedname_invalidate(&trans->fixedname);
670 result = set_nextqname(trans);
671 if (result == ISC_R_SUCCESS) {
673 ISC_LIST_HEAD(trans->nslist);
674 for (pns = trans->current_ns; pns != NULL;
675 pns = ISC_LIST_NEXT(pns, link)) {
676 for (server = ISC_LIST_HEAD(pns->servers);
678 server = ISC_LIST_NEXT(server,
680 INSIST(server->result_aaaa ==
682 server->result_a = none;
685 result = probe_name(trans, dns_rdatatype_a);
688 if (result != ISC_R_SUCCESS) {
690 * We've explored AAAA RRs or failed to find a valid
691 * query label. Wrap up the result and move to the
696 } else if (result != ISC_R_SUCCESS)
697 reset_probe(trans); /* XXX */
701 probe_name(struct probe_trans *trans, dns_rdatatype_t type) {
703 struct probe_ns *pns;
704 struct server *server;
706 REQUIRE(trans->reqid == NULL);
707 REQUIRE(type == dns_rdatatype_a || type == dns_rdatatype_aaaa);
709 for (pns = trans->current_ns; pns != NULL;
710 pns = ISC_LIST_NEXT(pns, link)) {
711 for (server = ISC_LIST_HEAD(pns->servers); server != NULL;
712 server = ISC_LIST_NEXT(server, link)) {
713 if ((type == dns_rdatatype_a &&
714 server->result_a == none) ||
715 (type == dns_rdatatype_aaaa &&
716 server->result_aaaa == none)) {
717 pns->current_server = server;
724 trans->current_ns = pns;
726 return (ISC_R_NOMORE);
728 INSIST(pns->current_server != NULL);
729 dns_message_reset(trans->qmessage, DNS_MESSAGE_INTENTRENDER);
730 result = make_querymessage(trans->qmessage, trans->qname, type);
731 if (result != ISC_R_SUCCESS)
733 result = dns_client_startrequest(client, trans->qmessage,
735 &pns->current_server->address,
736 0, DNS_MESSAGEPARSE_BESTEFFORT,
738 probe_task, request_done, trans,
745 * Get IP addresses of NSes
749 resolve_nsaddress(isc_task_t *task, isc_event_t *event) {
750 struct probe_trans *trans = event->ev_arg;
751 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
753 dns_rdataset_t *rdataset;
754 dns_rdata_t rdata = DNS_RDATA_INIT;
755 struct probe_ns *pns = trans->current_ns;
758 REQUIRE(task == probe_task);
759 REQUIRE(trans->inuse == ISC_TRUE);
760 REQUIRE(pns != NULL);
761 INSIST(outstanding_probes > 0);
763 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
764 name = ISC_LIST_NEXT(name, link)) {
765 for (rdataset = ISC_LIST_HEAD(name->list);
767 rdataset = ISC_LIST_NEXT(rdataset, link)) {
768 (void)print_rdataset(rdataset, name);
770 if (rdataset->type != dns_rdatatype_a)
773 for (result = dns_rdataset_first(rdataset);
774 result == ISC_R_SUCCESS;
775 result = dns_rdataset_next(rdataset)) {
776 dns_rdata_in_a_t rdata_a;
777 struct server *server;
779 dns_rdataset_current(rdataset, &rdata);
780 result = dns_rdata_tostruct(&rdata, &rdata_a,
782 if (result != ISC_R_SUCCESS)
785 server = isc_mem_get(mctx, sizeof(*server));
786 if (server == NULL) {
787 fprintf(stderr, "resolve_nsaddress: "
789 result = ISC_R_NOMEMORY;
793 isc_sockaddr_fromin(&server->address,
794 &rdata_a.in_addr, 53);
795 ISC_LINK_INIT(server, link);
796 server->result_a = none;
797 server->result_aaaa = none;
798 ISC_LIST_APPEND(pns->servers, server, link);
804 dns_client_freeresanswer(client, &rev->answerlist);
805 dns_client_destroyrestrans(&trans->resid);
806 isc_event_free(&event);
809 trans->current_ns = ISC_LIST_NEXT(pns, link);
810 if (trans->current_ns == NULL) {
811 trans->current_ns = ISC_LIST_HEAD(trans->nslist);
812 dns_fixedname_invalidate(&trans->fixedname);
814 result = set_nextqname(trans);
815 if (result == ISC_R_SUCCESS)
816 result = probe_name(trans, dns_rdatatype_a);
818 result = fetch_nsaddress(trans);
819 if (result != ISC_R_SUCCESS)
820 goto next_ns; /* XXX: this is unlikely to succeed */
823 if (result != ISC_R_SUCCESS)
828 fetch_nsaddress(struct probe_trans *trans) {
829 struct probe_ns *pns;
831 pns = trans->current_ns;
832 REQUIRE(pns != NULL);
834 return (dns_client_startresolve(client, pns->name, dns_rdataclass_in,
835 dns_rdatatype_a, 0, probe_task,
836 resolve_nsaddress, trans,
841 * Get NS RRset for a given domain
845 reset_probe(struct probe_trans *trans) {
846 struct probe_ns *pns;
847 struct server *server;
850 REQUIRE(trans->resid == NULL);
851 REQUIRE(trans->reqid == NULL);
855 dns_message_reset(trans->qmessage, DNS_MESSAGE_INTENTRENDER);
856 dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE);
858 trans->inuse = ISC_FALSE;
859 if (trans->domain != NULL)
860 isc_mem_free(mctx, trans->domain);
861 trans->domain = NULL;
862 if (trans->qname != NULL)
863 dns_fixedname_invalidate(&trans->fixedname);
865 trans->qlabel = qlabels;
866 trans->qname_found = ISC_FALSE;
867 trans->current_ns = NULL;
869 while ((pns = ISC_LIST_HEAD(trans->nslist)) != NULL) {
870 ISC_LIST_UNLINK(trans->nslist, pns, link);
871 while ((server = ISC_LIST_HEAD(pns->servers)) != NULL) {
872 ISC_LIST_UNLINK(pns->servers, server, link);
873 isc_mem_put(mctx, server, sizeof(*server));
875 isc_mem_put(mctx, pns, sizeof(*pns));
878 outstanding_probes--;
880 result = probe_domain(trans);
881 if (result == ISC_R_NOMORE && outstanding_probes == 0)
882 isc_app_ctxshutdown(actx);
886 resolve_ns(isc_task_t *task, isc_event_t *event) {
887 struct probe_trans *trans = event->ev_arg;
888 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
890 dns_rdataset_t *rdataset;
891 isc_result_t result = ISC_R_SUCCESS;
892 dns_rdata_t rdata = DNS_RDATA_INIT;
893 struct probe_ns *pns;
895 REQUIRE(task == probe_task);
896 REQUIRE(trans->inuse == ISC_TRUE);
897 INSIST(outstanding_probes > 0);
899 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
900 name = ISC_LIST_NEXT(name, link)) {
901 for (rdataset = ISC_LIST_HEAD(name->list);
903 rdataset = ISC_LIST_NEXT(rdataset, link)) {
904 (void)print_rdataset(rdataset, name);
906 if (rdataset->type != dns_rdatatype_ns)
909 for (result = dns_rdataset_first(rdataset);
910 result == ISC_R_SUCCESS;
911 result = dns_rdataset_next(rdataset)) {
914 dns_rdataset_current(rdataset, &rdata);
916 * Extract the name from the NS record.
918 result = dns_rdata_tostruct(&rdata, &ns, NULL);
919 if (result != ISC_R_SUCCESS)
922 pns = isc_mem_get(mctx, sizeof(*pns));
925 "resolve_ns: mem_get failed");
926 result = ISC_R_NOMEMORY;
929 * XXX: should we continue with the
930 * available servers anyway?
935 dns_fixedname_init(&pns->fixedname);
937 dns_fixedname_name(&pns->fixedname);
938 ISC_LINK_INIT(pns, link);
939 ISC_LIST_APPEND(trans->nslist, pns, link);
940 ISC_LIST_INIT(pns->servers);
942 dns_name_copy(&ns.name, pns->name, NULL);
943 dns_rdata_reset(&rdata);
944 dns_rdata_freestruct(&ns);
950 dns_client_freeresanswer(client, &rev->answerlist);
951 dns_client_destroyrestrans(&trans->resid);
952 isc_event_free(&event);
954 if (!ISC_LIST_EMPTY(trans->nslist)) {
955 /* Go get addresses of NSes */
956 trans->current_ns = ISC_LIST_HEAD(trans->nslist);
957 result = fetch_nsaddress(trans);
959 result = ISC_R_FAILURE;
961 if (result == ISC_R_SUCCESS)
968 probe_domain(struct probe_trans *trans) {
972 char buf[4096]; /* XXX ad hoc constant, but should be enough */
975 REQUIRE(trans != NULL);
976 REQUIRE(trans->inuse == ISC_FALSE);
977 REQUIRE(outstanding_probes < MAX_PROBES);
979 /* Construct domain */
980 cp = fgets(buf, sizeof(buf), fp);
982 return (ISC_R_NOMORE);
983 if ((cp = strchr(buf, '\n')) != NULL) /* zap NL if any */
985 trans->domain = isc_mem_strdup(mctx, buf);
986 if (trans->domain == NULL) {
988 "failed to allocate memory for domain: %s", cp);
989 return (ISC_R_NOMEMORY);
992 /* Start getting NS for the domain */
993 domainlen = strlen(buf);
994 isc_buffer_init(&b, buf, domainlen);
995 isc_buffer_add(&b, domainlen);
996 dns_fixedname_init(&trans->fixedname);
997 trans->qname = dns_fixedname_name(&trans->fixedname);
998 result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL);
999 if (result != ISC_R_SUCCESS)
1001 result = dns_client_startresolve(client, trans->qname,
1002 dns_rdataclass_in, dns_rdatatype_ns,
1003 0, probe_task, resolve_ns, trans,
1005 if (result != ISC_R_SUCCESS)
1008 trans->inuse = ISC_TRUE;
1009 outstanding_probes++;
1011 return (ISC_R_SUCCESS);
1014 isc_mem_free(mctx, trans->domain);
1015 dns_fixedname_invalidate(&trans->fixedname);
1020 ISC_PLATFORM_NORETURN_PRE static void
1021 usage(void) ISC_PLATFORM_NORETURN_POST;
1025 fprintf(stderr, "usage: nsprobe [-d] [-v [-v...]] [-c cache_address] "
1032 main(int argc, char *argv[]) {
1034 struct addrinfo hints, *res;
1035 isc_result_t result;
1037 isc_sockaddrlist_t servers;
1038 isc_taskmgr_t *taskmgr = NULL;
1039 isc_socketmgr_t *socketmgr = NULL;
1040 isc_timermgr_t *timermgr = NULL;
1042 while ((ch = getopt(argc, argv, "c:dhv")) != -1) {
1045 cacheserver = optarg;
1048 debug_mode = ISC_TRUE;
1067 result = dns_lib_init();
1068 if (result != ISC_R_SUCCESS) {
1069 fprintf(stderr, "dns_lib_init failed: %d\n", result);
1073 result = ctxs_init(&mctx, &actx, &taskmgr, &socketmgr,
1075 if (result != ISC_R_SUCCESS) {
1076 fprintf(stderr, "ctx create failed: %d\n", result);
1080 isc_app_ctxstart(actx);
1082 result = dns_client_createx(mctx, actx, taskmgr, socketmgr,
1083 timermgr, 0, &client);
1084 if (result != ISC_R_SUCCESS) {
1085 fprintf(stderr, "dns_client_createx failed: %d\n", result);
1089 /* Set local cache server */
1090 memset(&hints, 0, sizeof(hints));
1091 hints.ai_family = AF_UNSPEC;
1092 hints.ai_socktype = SOCK_DGRAM;
1093 error = getaddrinfo(cacheserver, "53", &hints, &res);
1095 fprintf(stderr, "failed to convert server name (%s): %s\n",
1096 cacheserver, gai_strerror(error));
1100 if (res->ai_addrlen > sizeof(sa.type)) {
1102 "assumption failure: addrlen is too long: %ld\n",
1103 (long)res->ai_addrlen);
1106 memcpy(&sa.type.sa, res->ai_addr, res->ai_addrlen);
1107 sa.length = res->ai_addrlen;
1109 ISC_LINK_INIT(&sa, link);
1110 ISC_LIST_INIT(servers);
1111 ISC_LIST_APPEND(servers, &sa, link);
1112 result = dns_client_setservers(client, dns_rdataclass_in, NULL,
1114 if (result != ISC_R_SUCCESS) {
1115 fprintf(stderr, "failed to set server: %d\n", result);
1119 /* Create the main task */
1121 result = isc_task_create(taskmgr, 0, &probe_task);
1122 if (result != ISC_R_SUCCESS) {
1123 fprintf(stderr, "failed to create task: %d\n", result);
1127 /* Open input file */
1131 fp = fopen(argv[0], "r");
1133 fprintf(stderr, "failed to open input file: %s\n",
1139 /* Set up and start probe */
1140 for (i = 0; i < MAX_PROBES; i++) {
1141 probes[i].inuse = ISC_FALSE;
1142 probes[i].domain = NULL;
1143 dns_fixedname_init(&probes[i].fixedname);
1144 probes[i].qname = NULL;
1145 probes[i].qlabel = qlabels;
1146 probes[i].qname_found = ISC_FALSE;
1147 probes[i].resid = NULL;
1148 ISC_LIST_INIT(probes[i].nslist);
1149 probes[i].reqid = NULL;
1151 probes[i].qmessage = NULL;
1152 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
1153 &probes[i].qmessage);
1154 if (result == ISC_R_SUCCESS) {
1155 result = dns_message_create(mctx,
1156 DNS_MESSAGE_INTENTPARSE,
1157 &probes[i].rmessage);
1159 if (result != ISC_R_SUCCESS) {
1160 fprintf(stderr, "initialization failure\n");
1164 for (i = 0; i < MAX_PROBES; i++) {
1165 result = probe_domain(&probes[i]);
1166 if (result == ISC_R_NOMORE)
1168 else if (result != ISC_R_SUCCESS) {
1169 fprintf(stderr, "failed to issue an initial probe\n");
1174 /* Start event loop */
1175 isc_app_ctxrun(actx);
1178 printf("Per domain results (out of %lu domains):\n",
1180 printf(" valid: %lu\n"
1184 " multiplesoa: %lu\n"
1185 " multiplecname: %lu\n"
1186 " brokenanswer: %lu\n"
1189 " multiple errors: %lu\n",
1190 domain_stat.valid, domain_stat.ignore, domain_stat.nxdomain,
1191 domain_stat.othererr, domain_stat.multiplesoa,
1192 domain_stat.multiplecname, domain_stat.brokenanswer,
1193 domain_stat.lame, domain_stat.unknown, multiple_error_domains);
1194 printf("Per server results (out of %lu servers):\n",
1196 printf(" valid: %lu\n"
1200 " multiplesoa: %lu\n"
1201 " multiplecname: %lu\n"
1202 " brokenanswer: %lu\n"
1205 server_stat.valid, server_stat.ignore, server_stat.nxdomain,
1206 server_stat.othererr, server_stat.multiplesoa,
1207 server_stat.multiplecname, server_stat.brokenanswer,
1208 server_stat.lame, server_stat.unknown);
1211 for (i = 0; i < MAX_PROBES; i++) {
1212 dns_message_destroy(&probes[i].qmessage);
1213 dns_message_destroy(&probes[i].rmessage);
1215 isc_task_detach(&probe_task);
1216 dns_client_destroy(&client);
1218 isc_app_ctxfinish(actx);
1219 ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);