* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: resolver.c,v 1.409 2009/11/04 02:15:29 marka Exp $ */
+/* $Id: resolver.c,v 1.410 2009/11/17 02:23:15 each Exp $ */
/*! \file */
unsigned int findfail;
unsigned int valfail;
isc_boolean_t timeout;
+ dns_adbaddrinfo_t *addrinfo;
+ isc_sockaddr_t *client;
};
#define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
else
ISC_LIST_APPEND(fctx->events, event, ev_link);
fctx->references++;
+ fctx->client = client;
fetch->magic = DNS_FETCH_MAGIC;
fetch->private = fctx;
fctx->rand_buf = 0;
fctx->rand_bits = 0;
fctx->timeout = ISC_FALSE;
+ fctx->addrinfo = NULL;
+ fctx->client = NULL;
dns_name_init(&fctx->nsname, NULL);
fctx->nsfetch = NULL;
namebuf, domainbuf, addrbuf);
}
+static inline void
+log_formerr(fetchctx_t *fctx, const char *format, ...) {
+ char nsbuf[ISC_SOCKADDR_FORMATSIZE];
+ char clbuf[ISC_SOCKADDR_FORMATSIZE];
+ const char *clmsg = "";
+ char msgbuf[2048];
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf(msgbuf, sizeof(msgbuf), format, args);
+ va_end(args);
+
+ isc_sockaddr_format(&fctx->addrinfo->sockaddr, nsbuf, sizeof(nsbuf));
+
+ if (fctx->client != NULL) {
+ clmsg = " for client ";
+ isc_sockaddr_format(fctx->client, clbuf, sizeof(clbuf));
+ } else {
+ clbuf[0] = '\0';
+ }
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+ DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE,
+ "DNS format error from %s resolving %s%s%s: %s",
+ nsbuf, fctx->info, clmsg, clbuf, msgbuf);
+}
+
static inline isc_result_t
same_question(fetchctx_t *fctx) {
isc_result_t result;
/*
* XXXRTH Currently we support only one question.
*/
- if (message->counts[DNS_SECTION_QUESTION] != 1)
+ if (message->counts[DNS_SECTION_QUESTION] != 1) {
+ log_formerr(fctx, "too many questions");
return (DNS_R_FORMERR);
+ }
result = dns_message_firstname(message, DNS_SECTION_QUESTION);
if (result != ISC_R_SUCCESS)
rdataset = ISC_LIST_HEAD(name->list);
INSIST(rdataset != NULL);
INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
+
if (fctx->type != rdataset->type ||
fctx->res->rdclass != rdataset->rdclass ||
- !dns_name_equal(&fctx->name, name))
+ !dns_name_equal(&fctx->name, name)) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ char class[DNS_RDATACLASS_FORMATSIZE];
+ char type[DNS_RDATATYPE_FORMATSIZE];
+
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_rdataclass_format(rdataset->rdclass, class, sizeof(class));
+ dns_rdatatype_format(rdataset->type, type, sizeof(type));
+ log_formerr(fctx, "question section mismatch: got %s/%s/%s",
+ namebuf, class, type);
return (DNS_R_FORMERR);
+ }
return (ISC_R_SUCCESS);
}
}
static inline isc_result_t
-dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, dns_name_t *oname,
- dns_fixedname_t *fixeddname)
+dname_target(fetchctx_t *fctx, dns_rdataset_t *rdataset, dns_name_t *qname,
+ dns_name_t *oname, dns_fixedname_t *fixeddname)
{
isc_result_t result;
dns_rdata_t rdata = DNS_RDATA_INIT;
/*
* Get the target name of the DNAME.
*/
-
result = dns_rdataset_first(rdataset);
if (result != ISC_R_SUCCESS)
return (result);
*/
namereln = dns_name_fullcompare(qname, oname, &order, &nlabels);
if (namereln != dns_namereln_subdomain) {
+ char qbuf[DNS_NAME_FORMATSIZE];
+ char obuf[DNS_NAME_FORMATSIZE];
+
dns_rdata_freestruct(&dname);
+ dns_name_format(qname, qbuf, sizeof(qbuf));
+ dns_name_format(oname, obuf, sizeof(obuf));
+ log_formerr(fctx, "unrelated DNAME in answer: "
+ "%s is not in %s", qbuf, obuf);
return (DNS_R_FORMERR);
}
dns_fixedname_init(&prefix);
type = rdataset->covers;
if (((type == dns_rdatatype_ns ||
type == dns_rdatatype_soa) &&
- !dns_name_issubdomain(qname, name)))
+ !dns_name_issubdomain(qname, name))) {
+ char qbuf[DNS_NAME_FORMATSIZE];
+ char nbuf[DNS_NAME_FORMATSIZE];
+ char tbuf[DNS_RDATATYPE_FORMATSIZE];
+ dns_rdatatype_format(fctx->type, tbuf,
+ sizeof(tbuf));
+ dns_name_format(name, nbuf,
+ sizeof(nbuf));
+ dns_name_format(qname, qbuf,
+ sizeof(qbuf));
+ log_formerr(fctx,
+ "unrelated %s %s in "
+ "%s authority section",
+ tbuf, qbuf, nbuf);
return (DNS_R_FORMERR);
+ }
if (type == dns_rdatatype_ns) {
/*
* NS or RRSIG NS.
if (rdataset->type ==
dns_rdatatype_ns) {
if (ns_name != NULL &&
- name != ns_name)
+ name != ns_name) {
+ log_formerr(fctx,
+ "multiple NS "
+ "RRsets in "
+ "authority "
+ "section");
return (DNS_R_FORMERR);
+ }
ns_name = name;
ns_rdataset = rdataset;
}
if (rdataset->type ==
dns_rdatatype_soa) {
if (soa_name != NULL &&
- name != soa_name)
+ name != soa_name) {
+ log_formerr(fctx,
+ "multiple SOA "
+ "RRs in "
+ "authority "
+ "section");
return (DNS_R_FORMERR);
+ }
soa_name = name;
}
name->attributes |=
* this is a referral, and there
* should only be one DS RRset.
*/
- if (ns_name == NULL)
+ if (ns_name == NULL) {
+ log_formerr(fctx,
+ "DS with no "
+ "referral");
return (DNS_R_FORMERR);
+ }
if (rdataset->type ==
dns_rdatatype_ds) {
if (ds_name != NULL &&
- name != ds_name)
+ name != ds_name) {
+ log_formerr(fctx,
+ "DS doesn't "
+ "match "
+ "referral "
+ "(NS)");
return (DNS_R_FORMERR);
+ }
ds_name = name;
}
name->attributes |=
/*
* The responder is insane.
*/
+ log_formerr(fctx, "invalid response");
return (DNS_R_FORMERR);
}
}
/*
* If we found both NS and SOA, they should be the same name.
*/
- if (ns_name != NULL && soa_name != NULL && ns_name != soa_name)
+ if (ns_name != NULL && soa_name != NULL && ns_name != soa_name) {
+ log_formerr(fctx, "NS/SOA mismatch");
return (DNS_R_FORMERR);
+ }
/*
* Do we have a referral? (We only want to follow a referral if
* progress. We return DNS_R_FORMERR so that we'll keep
* trying other servers.
*/
- if (dns_name_equal(ns_name, &fctx->domain))
+ if (dns_name_equal(ns_name, &fctx->domain)) {
+ log_formerr(fctx, "sideways referral");
return (DNS_R_FORMERR);
+ }
/*
* If the referral name is not a parent of the query
* name, consider the responder insane.
*/
if (! dns_name_issubdomain(&fctx->name, ns_name)) {
+ /* Logged twice */
+ log_formerr(fctx, "referral to non-parent");
FCTXTRACE("referral to non-parent");
return (DNS_R_FORMERR);
}
* NSEC3 records are not allowed to
* appear in the answer section.
*/
+ log_formerr(fctx, "NSEC3 in answer");
return (DNS_R_FORMERR);
}
*/
if (type == dns_rdatatype_rrsig ||
type == dns_rdatatype_dnskey ||
- type == dns_rdatatype_nsec)
+ type == dns_rdatatype_nsec ||
+ type == dns_rdatatype_nsec3) {
+ char buf[DNS_RDATATYPE_FORMATSIZE];
+ dns_rdatatype_format(fctx->type,
+ buf, sizeof(buf));
+ log_formerr(fctx,
+ "CNAME response "
+ "for %s RR", buf);
return (DNS_R_FORMERR);
+ }
found = ISC_TRUE;
found_cname = ISC_TRUE;
want_chaining = ISC_TRUE;
* If we're not chaining, then the
* DNAME should not be external.
*/
- if (!chaining && external)
+ if (!chaining && external) {
+ log_formerr(fctx,
+ "external DNAME");
return (DNS_R_FORMERR);
+ }
found = ISC_TRUE;
want_chaining = ISC_TRUE;
aflag = DNS_RDATASETATTR_ANSWER;
- result = dname_target(rdataset,
+ result = dname_target(fctx, rdataset,
qname, name,
&dname);
if (result == ISC_R_NOSPACE) {
/*
* We should have found an answer.
*/
- if (!have_answer)
+ if (!have_answer) {
+ log_formerr(fctx, "reply has no answer");
return (DNS_R_FORMERR);
+ }
/*
* This response is now potentially cacheable.
* We didn't end with an incomplete chain, so the rcode should be
* "no error".
*/
- if (message->rcode != dns_rcode_noerror)
+ if (message->rcode != dns_rcode_noerror) {
+ log_formerr(fctx, "CNAME/DNAME chain complete, but RCODE "
+ "indicates error");
return (DNS_R_FORMERR);
+ }
/*
* Examine the authority section (if there is one).
fctx->timeouts = 0;
fctx->timeout = ISC_FALSE;
+ fctx->addrinfo = query->addrinfo;
/*
* XXXRTH We should really get the current time just once. We
* cannot make any more progress with this
* fetch.
*/
+ log_formerr(fctx, "server sent FORMERR");
result = DNS_R_FORMERR;
}
} else if (message->rcode == dns_rcode_yxdomain) {