MEDIUM: dns: Don't use the ANY query type
Basically, it's ill-defined and shouldn't really be used going forward.
We can't guarantee that resolvers will do the 'legwork' for us and
actually resolve CNAMES when we request the ANY query-type. Case in point
(obfuscated, clearly):
PRODUCTION! ahayworth@secret-hostname.com:~$
dig @10.11.12.53 ANY api.somestartup.io
; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @10.11.12.53 ANY api.somestartup.io
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62454
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 0
;; QUESTION SECTION:
;api.somestartup.io. IN ANY
;; ANSWER SECTION:
api.somestartup.io. 20 IN CNAME api-somestartup-production.ap-southeast-2.elb.amazonaws.com.
;; AUTHORITY SECTION:
somestartup.io. 166687 IN NS ns-1254.awsdns-28.org.
somestartup.io. 166687 IN NS ns-1884.awsdns-43.co.uk.
somestartup.io. 166687 IN NS ns-440.awsdns-55.com.
somestartup.io. 166687 IN NS ns-577.awsdns-08.net.
;; Query time: 1 msec
;; SERVER: 10.11.12.53#53(10.11.12.53)
;; WHEN: Mon Oct 19 22:02:29 2015
;; MSG SIZE rcvd: 242
HAProxy can't handle that response correctly.
Rather than try to build in support for resolving CNAMEs presented
without an A record in an answer section (which may be a valid
improvement further on), this change just skips ANY record types
altogether. A and AAAA are much more well-defined and predictable.
Notably, this commit preserves the implicit "Prefer IPV6 behavior."
Furthermore, ANY query type by default is a bad idea: (from Robin on
HAProxy's ML):
Using ANY queries for this kind of stuff is considered by most people
to be a bad practice since besides all the things you named it can
lead to incomplete responses. Basically a resolver is allowed to just
return whatever it has in cache when it receives an ANY query instead
of actually doing an ANY query at the authoritative nameserver. Thus
if it only received queries for an A record before you do an ANY query
you will not get an AAAA record even if it is actually available since
the resolver doesn't have it in its cache. Even worse if before it
only got MX queries, you won't get either A or AAAA
diff --git a/src/checks.c b/src/checks.c
index ade2428..997cf81 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -2214,11 +2214,15 @@
resolution->query_id = query_id;
resolution->qid.key = query_id;
resolution->step = RSLV_STEP_RUNNING;
- resolution->query_type = DNS_RTYPE_ANY;
+ resolution->resolver_family_priority = s->resolver_family_priority;
+ if (resolution->resolver_family_priority == AF_INET) {
+ resolution->query_type = DNS_RTYPE_A;
+ } else {
+ resolution->query_type = DNS_RTYPE_AAAA;
+ }
resolution->try = resolvers->resolve_retries;
resolution->try_cname = 0;
resolution->nb_responses = 0;
- resolution->resolver_family_priority = s->resolver_family_priority;
eb32_insert(&resolvers->query_ids, &resolution->qid);
dns_send_query(resolution);
diff --git a/src/dns.c b/src/dns.c
index 7f71ac7..53b65ab 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -102,7 +102,11 @@
resolution->qid.key = 0;
/* default values */
- resolution->query_type = DNS_RTYPE_ANY;
+ if (resolution->resolver_family_priority == AF_INET) {
+ resolution->query_type = DNS_RTYPE_A;
+ } else {
+ resolution->query_type = DNS_RTYPE_AAAA;
+ }
/* the second resolution in the queue becomes the first one */
LIST_DEL(&resolution->list);
diff --git a/src/server.c b/src/server.c
index 8ddff00..dcc5961 100644
--- a/src/server.c
+++ b/src/server.c
@@ -2668,7 +2668,7 @@
{
struct server *s;
struct dns_resolvers *resolvers;
- int qtype_any, res_preferred_afinet, res_preferred_afinet6;
+ int res_preferred_afinet, res_preferred_afinet6;
/* shortcut to the server whose name is being resolved */
s = (struct server *)resolution->requester;
@@ -2692,21 +2692,13 @@
case DNS_RESP_TRUNCATED:
case DNS_RESP_ERROR:
case DNS_RESP_NO_EXPECTED_RECORD:
- qtype_any = resolution->query_type == DNS_RTYPE_ANY;
res_preferred_afinet = resolution->resolver_family_priority == AF_INET && resolution->query_type == DNS_RTYPE_A;
res_preferred_afinet6 = resolution->resolver_family_priority == AF_INET6 && resolution->query_type == DNS_RTYPE_AAAA;
- if ((qtype_any || res_preferred_afinet || res_preferred_afinet6)
+ if ((res_preferred_afinet || res_preferred_afinet6)
|| (resolution->try > 0)) {
/* let's change the query type */
- if (qtype_any) {
- /* fallback from ANY to resolution preference */
- if (resolution->resolver_family_priority == AF_INET6)
- resolution->query_type = DNS_RTYPE_AAAA;
- else
- resolution->query_type = DNS_RTYPE_A;
- }
- else if (res_preferred_afinet6) {
+ if (res_preferred_afinet6) {
/* fallback from AAAA to A */
resolution->query_type = DNS_RTYPE_A;
}
@@ -2716,7 +2708,11 @@
}
else {
resolution->try -= 1;
- resolution->query_type = DNS_RTYPE_ANY;
+ if (resolution->resolver_family_priority == AF_INET) {
+ resolution->query_type = DNS_RTYPE_A;
+ } else {
+ resolution->query_type = DNS_RTYPE_AAAA;
+ }
}
dns_send_query(resolution);