Пример #1
0
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);
}
Пример #2
0
static isc_result_t
probe_name(struct probe_trans *trans, dns_rdatatype_t type) {
	isc_result_t result;
	struct probe_ns *pns;
	struct server *server;

	REQUIRE(trans->reqid == NULL);
	REQUIRE(type == dns_rdatatype_a || type == dns_rdatatype_aaaa);

	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)) {
			if ((type == dns_rdatatype_a &&
			     server->result_a == none) ||
			    (type == dns_rdatatype_aaaa &&
			     server->result_aaaa == none)) {
				pns->current_server = server;
				goto found;
			}
		}
	}

 found:
	trans->current_ns = pns;
	if (pns == NULL)
		return (ISC_R_NOMORE);

	INSIST(pns->current_server != NULL);
	dns_message_reset(trans->qmessage, DNS_MESSAGE_INTENTRENDER);
	result = make_querymessage(trans->qmessage, trans->qname, type);
	if (result != ISC_R_SUCCESS)
		return (result);
	result = dns_client_startrequest(client, trans->qmessage,
					 trans->rmessage,
					 &pns->current_server->address,
					 0, DNS_MESSAGEPARSE_BESTEFFORT,
					 NULL, 120, 0, 4,
					 probe_task, request_done, trans,
					 &trans->reqid);

	return (result);
}
Пример #3
0
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 */
}