2 * Copyright (C) 2009-2014 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);
292 increment_entry(unsigned long *entryp) {
294 INSIST(*entryp != 0U); /* check overflow */
298 update_stat(struct probe_trans *trans) {
299 struct probe_ns *pns;
300 struct server *server;
301 struct lcl_stat local_stat;
302 unsigned int err_count = 0;
303 const char *stattype;
305 increment_entry(&number_of_domains);
306 memset(&local_stat, 0, sizeof(local_stat));
308 /* Update per sever statistics */
309 for (pns = ISC_LIST_HEAD(trans->nslist); pns != NULL;
310 pns = ISC_LIST_NEXT(pns, link)) {
311 for (server = ISC_LIST_HEAD(pns->servers); server != NULL;
312 server = ISC_LIST_NEXT(server, link)) {
313 increment_entry(&number_of_servers);
315 if (server->result_aaaa == exist ||
316 server->result_aaaa == notype) {
318 * Don't care about the result of A query if
319 * the answer to AAAA query was expected.
322 increment_entry(&server_stat.valid);
323 increment_entry(&local_stat.valid);
324 } else if (server->result_a == exist) {
325 switch (server->result_aaaa) {
329 increment_entry(&server_stat.valid);
330 increment_entry(&local_stat.valid);
334 increment_entry(&server_stat.ignore);
335 increment_entry(&local_stat.ignore);
338 stattype = "nxdomain";
339 increment_entry(&server_stat.nxdomain);
340 increment_entry(&local_stat.nxdomain);
343 stattype = "othererr";
344 increment_entry(&server_stat.othererr);
345 increment_entry(&local_stat.othererr);
348 stattype = "multiplesoa";
349 increment_entry(&server_stat.multiplesoa);
350 increment_entry(&local_stat.multiplesoa);
353 stattype = "multiplecname";
354 increment_entry(&server_stat.multiplecname);
355 increment_entry(&local_stat.multiplecname);
358 stattype = "brokenanswer";
359 increment_entry(&server_stat.brokenanswer);
360 increment_entry(&local_stat.brokenanswer);
364 increment_entry(&server_stat.lame);
365 increment_entry(&local_stat.lame);
368 stattype = "unknown";
369 increment_entry(&server_stat.unknown);
370 increment_entry(&local_stat.unknown);
374 stattype = "unknown";
375 increment_entry(&server_stat.unknown);
376 increment_entry(&local_stat.unknown);
379 if (verbose_level > 1 ||
380 (verbose_level == 1 &&
381 strcmp(stattype, "valid") != 0 &&
382 strcmp(stattype, "unknown") != 0)) {
383 print_name(pns->name);
385 print_address(stdout, &server->address);
386 printf(") for %s:%s\n", trans->domain,
392 /* Update per domain statistics */
393 if (local_stat.ignore > 0U) {
394 if (verbose_level > 0)
395 printf("%s:ignore\n", trans->domain);
396 increment_entry(&domain_stat.ignore);
399 if (local_stat.nxdomain > 0U) {
400 if (verbose_level > 0)
401 printf("%s:nxdomain\n", trans->domain);
402 increment_entry(&domain_stat.nxdomain);
405 if (local_stat.othererr > 0U) {
406 if (verbose_level > 0)
407 printf("%s:othererr\n", trans->domain);
408 increment_entry(&domain_stat.othererr);
411 if (local_stat.multiplesoa > 0U) {
412 if (verbose_level > 0)
413 printf("%s:multiplesoa\n", trans->domain);
414 increment_entry(&domain_stat.multiplesoa);
417 if (local_stat.multiplecname > 0U) {
418 if (verbose_level > 0)
419 printf("%s:multiplecname\n", trans->domain);
420 increment_entry(&domain_stat.multiplecname);
423 if (local_stat.brokenanswer > 0U) {
424 if (verbose_level > 0)
425 printf("%s:brokenanswer\n", trans->domain);
426 increment_entry(&domain_stat.brokenanswer);
429 if (local_stat.lame > 0U) {
430 if (verbose_level > 0)
431 printf("%s:lame\n", trans->domain);
432 increment_entry(&domain_stat.lame);
437 increment_entry(&multiple_error_domains);
440 * We regard the domain as valid if and only if no authoritative server
441 * has a problem and at least one server is known to be valid.
443 if (local_stat.valid > 0U && err_count == 0U) {
444 if (verbose_level > 1)
445 printf("%s:valid\n", trans->domain);
446 increment_entry(&domain_stat.valid);
450 * If the domain has no available server or all servers have the
451 * 'unknown' result, the domain's result is also regarded as unknown.
453 if (local_stat.valid == 0U && err_count == 0U) {
454 if (verbose_level > 1)
455 printf("%s:unknown\n", trans->domain);
456 increment_entry(&domain_stat.unknown);
461 * Search for an existent name with an A RR
465 set_nextqname(struct probe_trans *trans) {
469 char buf[4096]; /* XXX ad-hoc constant, but should be enough */
471 if (*trans->qlabel == NULL)
472 return (ISC_R_NOMORE);
474 result = isc_string_copy(buf, sizeof(buf), *trans->qlabel);
475 if (result != ISC_R_SUCCESS)
477 result = isc_string_append(buf, sizeof(buf), trans->domain);
478 if (result != ISC_R_SUCCESS)
481 domainlen = strlen(buf);
482 isc_buffer_init(&b, buf, domainlen);
483 isc_buffer_add(&b, domainlen);
484 dns_fixedname_init(&trans->fixedname);
485 trans->qname = dns_fixedname_name(&trans->fixedname);
486 result = dns_name_fromtext(trans->qname, &b, dns_rootname,
495 request_done(isc_task_t *task, isc_event_t *event) {
496 struct probe_trans *trans = event->ev_arg;
497 dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event;
498 dns_message_t *rmessage;
499 struct probe_ns *pns;
500 struct server *server;
502 query_result_t *resultp;
504 dns_rdataset_t *rdataset;
505 dns_rdatatype_t type;
507 REQUIRE(task == probe_task);
508 REQUIRE(trans != NULL && trans->inuse == ISC_TRUE);
509 rmessage = rev->rmessage;
510 REQUIRE(rmessage == trans->rmessage);
511 INSIST(outstanding_probes > 0);
513 server = trans->current_ns->current_server;
514 INSIST(server != NULL);
516 if (server->result_a == none) {
517 type = dns_rdatatype_a;
518 resultp = &server->result_a;
520 resultp = &server->result_aaaa;
521 type = dns_rdatatype_aaaa;
524 if (rev->result == ISC_R_SUCCESS) {
525 if ((rmessage->flags & DNS_MESSAGEFLAG_AA) == 0)
527 else if (rmessage->rcode == dns_rcode_nxdomain)
529 else if (rmessage->rcode != dns_rcode_noerror)
531 else if (rmessage->counts[DNS_SECTION_ANSWER] == 0) {
532 /* no error but empty answer */
535 result = dns_message_firstname(rmessage,
537 while (result == ISC_R_SUCCESS) {
539 dns_message_currentname(rmessage,
542 for (rdataset = ISC_LIST_HEAD(name->list);
544 rdataset = ISC_LIST_NEXT(rdataset,
546 (void)print_rdataset(rdataset, name);
548 if (rdataset->type ==
549 dns_rdatatype_cname ||
551 dns_rdatatype_dname) {
552 /* Should chase the chain? */
555 } else if (rdataset->type == type) {
560 result = dns_message_nextname(rmessage,
565 * Something unexpected happened: the response
566 * contained a non-empty authoritative answer, but we
567 * could not find an expected result.
569 *resultp = unexpected;
571 } else if (rev->result == DNS_R_RECOVERABLE ||
572 rev->result == DNS_R_BADLABELTYPE) {
573 /* Broken response. Try identifying known cases. */
574 *resultp = brokenanswer;
576 if (rmessage->counts[DNS_SECTION_ANSWER] > 0) {
577 result = dns_message_firstname(rmessage,
579 while (result == ISC_R_SUCCESS) {
581 * Check to see if the response has multiple
582 * CNAME RRs. Update the result code if so.
585 dns_message_currentname(rmessage,
588 for (rdataset = ISC_LIST_HEAD(name->list);
590 rdataset = ISC_LIST_NEXT(rdataset,
592 if (rdataset->type ==
593 dns_rdatatype_cname &&
594 dns_rdataset_count(rdataset) > 1) {
595 *resultp = multiplecname;
599 result = dns_message_nextname(rmessage,
604 if (rmessage->counts[DNS_SECTION_AUTHORITY] > 0) {
605 result = dns_message_firstname(rmessage,
606 DNS_SECTION_AUTHORITY);
607 while (result == ISC_R_SUCCESS) {
609 * Check to see if the response has multiple
610 * SOA RRs. Update the result code if so.
613 dns_message_currentname(rmessage,
614 DNS_SECTION_AUTHORITY,
616 for (rdataset = ISC_LIST_HEAD(name->list);
618 rdataset = ISC_LIST_NEXT(rdataset,
620 if (rdataset->type ==
622 dns_rdataset_count(rdataset) > 1) {
623 *resultp = multiplesoa;
627 result = dns_message_nextname(rmessage,
628 DNS_SECTION_AUTHORITY);
631 } else if (rev->result == ISC_R_TIMEDOUT)
634 fprintf(stderr, "unexpected result: %d (domain=%s, server=",
635 rev->result, trans->domain);
636 print_address(stderr, &server->address);
638 *resultp = unexpected;
642 INSIST(*resultp != none);
643 if (type == dns_rdatatype_a && *resultp == exist)
644 trans->qname_found = ISC_TRUE;
646 dns_client_destroyreqtrans(&trans->reqid);
647 isc_event_free(&event);
648 dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE);
650 result = probe_name(trans, type);
651 if (result == ISC_R_NOMORE) {
652 /* We've tried all addresses of all servers. */
653 if (type == dns_rdatatype_a && trans->qname_found) {
655 * If we've explored A RRs and found an existent
656 * record, we can move to AAAA.
658 trans->current_ns = ISC_LIST_HEAD(trans->nslist);
659 probe_name(trans, dns_rdatatype_aaaa);
660 result = ISC_R_SUCCESS;
661 } else if (type == dns_rdatatype_a) {
663 * No server provided an existent A RR of this name.
666 dns_fixedname_invalidate(&trans->fixedname);
668 result = set_nextqname(trans);
669 if (result == ISC_R_SUCCESS) {
671 ISC_LIST_HEAD(trans->nslist);
672 for (pns = trans->current_ns; pns != NULL;
673 pns = ISC_LIST_NEXT(pns, link)) {
674 for (server = ISC_LIST_HEAD(pns->servers);
676 server = ISC_LIST_NEXT(server,
678 INSIST(server->result_aaaa ==
680 server->result_a = none;
683 result = probe_name(trans, dns_rdatatype_a);
686 if (result != ISC_R_SUCCESS) {
688 * We've explored AAAA RRs or failed to find a valid
689 * query label. Wrap up the result and move to the
694 } else if (result != ISC_R_SUCCESS)
695 reset_probe(trans); /* XXX */
699 probe_name(struct probe_trans *trans, dns_rdatatype_t type) {
701 struct probe_ns *pns;
702 struct server *server;
704 REQUIRE(trans->reqid == NULL);
705 REQUIRE(type == dns_rdatatype_a || type == dns_rdatatype_aaaa);
707 for (pns = trans->current_ns; pns != NULL;
708 pns = ISC_LIST_NEXT(pns, link)) {
709 for (server = ISC_LIST_HEAD(pns->servers); server != NULL;
710 server = ISC_LIST_NEXT(server, link)) {
711 if ((type == dns_rdatatype_a &&
712 server->result_a == none) ||
713 (type == dns_rdatatype_aaaa &&
714 server->result_aaaa == none)) {
715 pns->current_server = server;
722 trans->current_ns = pns;
724 return (ISC_R_NOMORE);
726 INSIST(pns->current_server != NULL);
727 dns_message_reset(trans->qmessage, DNS_MESSAGE_INTENTRENDER);
728 result = make_querymessage(trans->qmessage, trans->qname, type);
729 if (result != ISC_R_SUCCESS)
731 result = dns_client_startrequest(client, trans->qmessage,
733 &pns->current_server->address,
734 0, DNS_MESSAGEPARSE_BESTEFFORT,
736 probe_task, request_done, trans,
743 * Get IP addresses of NSes
747 resolve_nsaddress(isc_task_t *task, isc_event_t *event) {
748 struct probe_trans *trans = event->ev_arg;
749 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
751 dns_rdataset_t *rdataset;
752 dns_rdata_t rdata = DNS_RDATA_INIT;
753 struct probe_ns *pns = trans->current_ns;
756 REQUIRE(task == probe_task);
757 REQUIRE(trans->inuse == ISC_TRUE);
758 REQUIRE(pns != NULL);
759 INSIST(outstanding_probes > 0);
761 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
762 name = ISC_LIST_NEXT(name, link)) {
763 for (rdataset = ISC_LIST_HEAD(name->list);
765 rdataset = ISC_LIST_NEXT(rdataset, link)) {
766 (void)print_rdataset(rdataset, name);
768 if (rdataset->type != dns_rdatatype_a)
771 for (result = dns_rdataset_first(rdataset);
772 result == ISC_R_SUCCESS;
773 result = dns_rdataset_next(rdataset)) {
774 dns_rdata_in_a_t rdata_a;
775 struct server *server;
777 dns_rdataset_current(rdataset, &rdata);
778 result = dns_rdata_tostruct(&rdata, &rdata_a,
780 if (result != ISC_R_SUCCESS)
783 server = isc_mem_get(mctx, sizeof(*server));
784 if (server == NULL) {
785 fprintf(stderr, "resolve_nsaddress: "
787 result = ISC_R_NOMEMORY;
791 isc_sockaddr_fromin(&server->address,
792 &rdata_a.in_addr, 53);
793 ISC_LINK_INIT(server, link);
794 server->result_a = none;
795 server->result_aaaa = none;
796 ISC_LIST_APPEND(pns->servers, server, link);
802 dns_client_freeresanswer(client, &rev->answerlist);
803 dns_client_destroyrestrans(&trans->resid);
804 isc_event_free(&event);
807 trans->current_ns = ISC_LIST_NEXT(pns, link);
808 if (trans->current_ns == NULL) {
809 trans->current_ns = ISC_LIST_HEAD(trans->nslist);
810 dns_fixedname_invalidate(&trans->fixedname);
812 result = set_nextqname(trans);
813 if (result == ISC_R_SUCCESS)
814 result = probe_name(trans, dns_rdatatype_a);
816 result = fetch_nsaddress(trans);
817 if (result != ISC_R_SUCCESS)
818 goto next_ns; /* XXX: this is unlikely to succeed */
821 if (result != ISC_R_SUCCESS)
826 fetch_nsaddress(struct probe_trans *trans) {
827 struct probe_ns *pns;
829 pns = trans->current_ns;
830 REQUIRE(pns != NULL);
832 return (dns_client_startresolve(client, pns->name, dns_rdataclass_in,
833 dns_rdatatype_a, 0, probe_task,
834 resolve_nsaddress, trans,
839 * Get NS RRset for a given domain
843 reset_probe(struct probe_trans *trans) {
844 struct probe_ns *pns;
845 struct server *server;
848 REQUIRE(trans->resid == NULL);
849 REQUIRE(trans->reqid == NULL);
853 dns_message_reset(trans->qmessage, DNS_MESSAGE_INTENTRENDER);
854 dns_message_reset(trans->rmessage, DNS_MESSAGE_INTENTPARSE);
856 trans->inuse = ISC_FALSE;
857 if (trans->domain != NULL)
858 isc_mem_free(mctx, trans->domain);
859 trans->domain = NULL;
860 if (trans->qname != NULL)
861 dns_fixedname_invalidate(&trans->fixedname);
863 trans->qlabel = qlabels;
864 trans->qname_found = ISC_FALSE;
865 trans->current_ns = NULL;
867 while ((pns = ISC_LIST_HEAD(trans->nslist)) != NULL) {
868 ISC_LIST_UNLINK(trans->nslist, pns, link);
869 while ((server = ISC_LIST_HEAD(pns->servers)) != NULL) {
870 ISC_LIST_UNLINK(pns->servers, server, link);
871 isc_mem_put(mctx, server, sizeof(*server));
873 isc_mem_put(mctx, pns, sizeof(*pns));
876 outstanding_probes--;
878 result = probe_domain(trans);
879 if (result == ISC_R_NOMORE && outstanding_probes == 0)
880 isc_app_ctxshutdown(actx);
884 resolve_ns(isc_task_t *task, isc_event_t *event) {
885 struct probe_trans *trans = event->ev_arg;
886 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
888 dns_rdataset_t *rdataset;
889 isc_result_t result = ISC_R_SUCCESS;
890 dns_rdata_t rdata = DNS_RDATA_INIT;
891 struct probe_ns *pns;
893 REQUIRE(task == probe_task);
894 REQUIRE(trans->inuse == ISC_TRUE);
895 INSIST(outstanding_probes > 0);
897 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
898 name = ISC_LIST_NEXT(name, link)) {
899 for (rdataset = ISC_LIST_HEAD(name->list);
901 rdataset = ISC_LIST_NEXT(rdataset, link)) {
902 (void)print_rdataset(rdataset, name);
904 if (rdataset->type != dns_rdatatype_ns)
907 for (result = dns_rdataset_first(rdataset);
908 result == ISC_R_SUCCESS;
909 result = dns_rdataset_next(rdataset)) {
912 dns_rdataset_current(rdataset, &rdata);
914 * Extract the name from the NS record.
916 result = dns_rdata_tostruct(&rdata, &ns, NULL);
917 if (result != ISC_R_SUCCESS)
920 pns = isc_mem_get(mctx, sizeof(*pns));
923 "resolve_ns: mem_get failed");
924 result = ISC_R_NOMEMORY;
927 * XXX: should we continue with the
928 * available servers anyway?
933 dns_fixedname_init(&pns->fixedname);
935 dns_fixedname_name(&pns->fixedname);
936 ISC_LINK_INIT(pns, link);
937 ISC_LIST_APPEND(trans->nslist, pns, link);
938 ISC_LIST_INIT(pns->servers);
940 dns_name_copy(&ns.name, pns->name, NULL);
941 dns_rdata_reset(&rdata);
942 dns_rdata_freestruct(&ns);
948 dns_client_freeresanswer(client, &rev->answerlist);
949 dns_client_destroyrestrans(&trans->resid);
950 isc_event_free(&event);
952 if (!ISC_LIST_EMPTY(trans->nslist)) {
953 /* Go get addresses of NSes */
954 trans->current_ns = ISC_LIST_HEAD(trans->nslist);
955 result = fetch_nsaddress(trans);
957 result = ISC_R_FAILURE;
959 if (result == ISC_R_SUCCESS)
966 probe_domain(struct probe_trans *trans) {
970 char buf[4096]; /* XXX ad hoc constant, but should be enough */
973 REQUIRE(trans != NULL);
974 REQUIRE(trans->inuse == ISC_FALSE);
975 REQUIRE(outstanding_probes < MAX_PROBES);
977 /* Construct domain */
978 cp = fgets(buf, sizeof(buf), fp);
980 return (ISC_R_NOMORE);
981 if ((cp = strchr(buf, '\n')) != NULL) /* zap NL if any */
983 trans->domain = isc_mem_strdup(mctx, buf);
984 if (trans->domain == NULL) {
986 "failed to allocate memory for domain: %s", cp);
987 return (ISC_R_NOMEMORY);
990 /* Start getting NS for the domain */
991 domainlen = strlen(buf);
992 isc_buffer_init(&b, buf, domainlen);
993 isc_buffer_add(&b, domainlen);
994 dns_fixedname_init(&trans->fixedname);
995 trans->qname = dns_fixedname_name(&trans->fixedname);
996 result = dns_name_fromtext(trans->qname, &b, dns_rootname, 0, NULL);
997 if (result != ISC_R_SUCCESS)
999 result = dns_client_startresolve(client, trans->qname,
1000 dns_rdataclass_in, dns_rdatatype_ns,
1001 0, probe_task, resolve_ns, trans,
1003 if (result != ISC_R_SUCCESS)
1006 trans->inuse = ISC_TRUE;
1007 outstanding_probes++;
1009 return (ISC_R_SUCCESS);
1012 isc_mem_free(mctx, trans->domain);
1013 dns_fixedname_invalidate(&trans->fixedname);
1018 ISC_PLATFORM_NORETURN_PRE static void
1019 usage(void) ISC_PLATFORM_NORETURN_POST;
1023 fprintf(stderr, "usage: nsprobe [-d] [-v [-v...]] [-c cache_address] "
1030 main(int argc, char *argv[]) {
1032 struct addrinfo hints, *res;
1033 isc_result_t result;
1035 isc_sockaddrlist_t servers;
1036 isc_taskmgr_t *taskmgr = NULL;
1037 isc_socketmgr_t *socketmgr = NULL;
1038 isc_timermgr_t *timermgr = NULL;
1040 while ((ch = getopt(argc, argv, "c:dhv")) != -1) {
1043 cacheserver = optarg;
1046 debug_mode = ISC_TRUE;
1065 result = dns_lib_init();
1066 if (result != ISC_R_SUCCESS) {
1067 fprintf(stderr, "dns_lib_init failed: %d\n", result);
1071 result = ctxs_init(&mctx, &actx, &taskmgr, &socketmgr,
1073 if (result != ISC_R_SUCCESS) {
1074 fprintf(stderr, "ctx create failed: %d\n", result);
1078 isc_app_ctxstart(actx);
1080 result = dns_client_createx(mctx, actx, taskmgr, socketmgr,
1081 timermgr, 0, &client);
1082 if (result != ISC_R_SUCCESS) {
1083 fprintf(stderr, "dns_client_createx failed: %d\n", result);
1087 /* Set local cache server */
1088 memset(&hints, 0, sizeof(hints));
1089 hints.ai_family = AF_UNSPEC;
1090 hints.ai_socktype = SOCK_DGRAM;
1091 error = getaddrinfo(cacheserver, "53", &hints, &res);
1093 fprintf(stderr, "failed to convert server name (%s): %s\n",
1094 cacheserver, gai_strerror(error));
1098 if (res->ai_addrlen > sizeof(sa.type)) {
1100 "assumption failure: addrlen is too long: %ld\n",
1101 (long)res->ai_addrlen);
1104 memmove(&sa.type.sa, res->ai_addr, res->ai_addrlen);
1105 sa.length = res->ai_addrlen;
1107 ISC_LINK_INIT(&sa, link);
1108 ISC_LIST_INIT(servers);
1109 ISC_LIST_APPEND(servers, &sa, link);
1110 result = dns_client_setservers(client, dns_rdataclass_in, NULL,
1112 if (result != ISC_R_SUCCESS) {
1113 fprintf(stderr, "failed to set server: %d\n", result);
1117 /* Create the main task */
1119 result = isc_task_create(taskmgr, 0, &probe_task);
1120 if (result != ISC_R_SUCCESS) {
1121 fprintf(stderr, "failed to create task: %d\n", result);
1125 /* Open input file */
1129 fp = fopen(argv[0], "r");
1131 fprintf(stderr, "failed to open input file: %s\n",
1137 /* Set up and start probe */
1138 for (i = 0; i < MAX_PROBES; i++) {
1139 probes[i].inuse = ISC_FALSE;
1140 probes[i].domain = NULL;
1141 dns_fixedname_init(&probes[i].fixedname);
1142 probes[i].qname = NULL;
1143 probes[i].qlabel = qlabels;
1144 probes[i].qname_found = ISC_FALSE;
1145 probes[i].resid = NULL;
1146 ISC_LIST_INIT(probes[i].nslist);
1147 probes[i].reqid = NULL;
1149 probes[i].qmessage = NULL;
1150 result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER,
1151 &probes[i].qmessage);
1152 if (result == ISC_R_SUCCESS) {
1153 result = dns_message_create(mctx,
1154 DNS_MESSAGE_INTENTPARSE,
1155 &probes[i].rmessage);
1157 if (result != ISC_R_SUCCESS) {
1158 fprintf(stderr, "initialization failure\n");
1162 for (i = 0; i < MAX_PROBES; i++) {
1163 result = probe_domain(&probes[i]);
1164 if (result == ISC_R_NOMORE)
1166 else if (result != ISC_R_SUCCESS) {
1167 fprintf(stderr, "failed to issue an initial probe\n");
1172 /* Start event loop */
1173 isc_app_ctxrun(actx);
1176 printf("Per domain results (out of %lu domains):\n",
1178 printf(" valid: %lu\n"
1182 " multiplesoa: %lu\n"
1183 " multiplecname: %lu\n"
1184 " brokenanswer: %lu\n"
1187 " multiple errors: %lu\n",
1188 domain_stat.valid, domain_stat.ignore, domain_stat.nxdomain,
1189 domain_stat.othererr, domain_stat.multiplesoa,
1190 domain_stat.multiplecname, domain_stat.brokenanswer,
1191 domain_stat.lame, domain_stat.unknown, multiple_error_domains);
1192 printf("Per server results (out of %lu servers):\n",
1194 printf(" valid: %lu\n"
1198 " multiplesoa: %lu\n"
1199 " multiplecname: %lu\n"
1200 " brokenanswer: %lu\n"
1203 server_stat.valid, server_stat.ignore, server_stat.nxdomain,
1204 server_stat.othererr, server_stat.multiplesoa,
1205 server_stat.multiplecname, server_stat.brokenanswer,
1206 server_stat.lame, server_stat.unknown);
1209 for (i = 0; i < MAX_PROBES; i++) {
1210 dns_message_destroy(&probes[i].qmessage);
1211 dns_message_destroy(&probes[i].rmessage);
1213 isc_task_detach(&probe_task);
1214 dns_client_destroy(&client);
1216 isc_app_ctxfinish(actx);
1217 ctxs_destroy(&mctx, &actx, &taskmgr, &socketmgr, &timermgr);