diff options
author | Dave Barach <dave@barachs.net> | 2018-01-10 18:18:59 -0500 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2018-01-11 16:41:14 +0000 |
commit | c6372ebfc9914ea2b43279dd593da47fd00f0af4 (patch) | |
tree | 8ff3c1e18ca75a63766e8bb8f7cf9da4eb2737a3 /src/vnet/dns | |
parent | c3644a86e816eec63e2334038950bca9aa876802 (diff) |
Handle a mix of CNAME, A/AAAA records
Poster-child: 8.8.8.8 resolving mag.ncep.noaa.gov
Change-Id: I600cd0274b9017e9c91817511d3d3366f0bd02b9
Signed-off-by: Dave Barach <dave@barachs.net>
Diffstat (limited to 'src/vnet/dns')
-rw-r--r-- | src/vnet/dns/dns.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/src/vnet/dns/dns.c b/src/vnet/dns/dns.c index 7e6465b4eea..24cd5969aa7 100644 --- a/src/vnet/dns/dns.c +++ b/src/vnet/dns/dns.c @@ -941,9 +941,11 @@ vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply) dns_rr_t *rr; u8 *curpos; u8 *pos, *pos2; + u8 *cname_pos = 0; int len, i; u8 *cname = 0; u8 *request = 0; + u8 *name_copy; u32 qp_offset; u16 flags; u16 rcode; @@ -999,25 +1001,36 @@ vnet_dns_cname_indirection_nolock (dns_main_t * dm, u32 ep_index, u8 * reply) case DNS_TYPE_A: case DNS_TYPE_AAAA: return 0; - /* Chase a CNAME pointer? */ + /* + * Maybe chase a CNAME pointer? + * It's not unheard-of for name-servers to return + * both CNAME and A/AAAA records... + */ case DNS_TYPE_CNAME: - goto chase_chain; + cname_pos = pos; + break; /* Some other junk, e.g. a nameserver... */ default: break; } pos += sizeof (*rr) + clib_net_to_host_u16 (rr->rdlength); + /* Skip name... */ + if ((pos2[0] & 0xc0) == 0xc0) + pos += 2; } /* Neither a CNAME nor a real address. Try another server */ - flags &= ~DNS_RCODE_MASK; - flags |= DNS_RCODE_NAME_ERROR; - h->flags = clib_host_to_net_u16 (flags); - return -1; + if (cname_pos == 0) + { + flags &= ~DNS_RCODE_MASK; + flags |= DNS_RCODE_NAME_ERROR; + h->flags = clib_host_to_net_u16 (flags); + return -1; + } -chase_chain: /* This is a CNAME record, chase the name chain. */ + pos = cname_pos; /* The last request is no longer pending.. */ for (i = 0; i < vec_len (dm->unresolved_entries); i++) @@ -1068,15 +1081,22 @@ found_last_request: #undef _ request = name_to_labels (cname); + name_copy = vec_dup (request); qp_offset = vec_len (request); /* Add space for the query header */ - vec_validate (request, qp_offset + sizeof (dns_query_t) - 1); + vec_validate (request, 2 * qp_offset + 2 * sizeof (dns_query_t) - 1); qp = (dns_query_t *) (request + qp_offset); - qp->type = clib_host_to_net_u16 (DNS_TYPE_ALL); + qp->type = clib_host_to_net_u16 (DNS_TYPE_A); + qp->class = clib_host_to_net_u16 (DNS_CLASS_IN); + clib_memcpy (qp, name_copy, vec_len (name_copy)); + qp = (dns_query_t *) (((u8 *) qp) + vec_len (name_copy)); + vec_free (name_copy); + + qp->type = clib_host_to_net_u16 (DNS_TYPE_AAAA); qp->class = clib_host_to_net_u16 (DNS_CLASS_IN); /* Punch in space for the dns_header_t */ @@ -1089,7 +1109,7 @@ found_last_request: /* Ask for a recursive lookup */ h->flags = clib_host_to_net_u16 (DNS_RD | DNS_OPCODE_QUERY); - h->qdcount = clib_host_to_net_u16 (1); + h->qdcount = clib_host_to_net_u16 (2); h->nscount = 0; h->arcount = 0; |