DnsResolver CNAME redirect bug

Motviation:
DnsNameResolverContext#followCname attempts to build a query to follow a CNAME, but puts the original hostname in the DnsQuery instead of the CNAME hostname. This will result in not following CNAME redirects correctly.

Result:
- DnsNameResolverContext#followCname should use the CNAME instead of the original hostname when building the DnsQuery

Result:
More correct handling of redirect queries.
This commit is contained in:
Scott Mitchell 2017-10-11 14:50:45 -07:00
parent dc98eae5a5
commit dcb828f02f
2 changed files with 78 additions and 3 deletions

View File

@ -735,7 +735,7 @@ abstract class DnsNameResolverContext<T> {
DnsQuestion cnameQuestion = null;
if (parent.supportsARecords()) {
try {
if ((cnameQuestion = newQuestion(hostname, DnsRecordType.A)) == null) {
if ((cnameQuestion = newQuestion(cname, DnsRecordType.A)) == null) {
return;
}
} catch (Throwable cause) {
@ -746,7 +746,7 @@ abstract class DnsNameResolverContext<T> {
}
if (parent.supportsAAAARecords()) {
try {
if ((cnameQuestion = newQuestion(hostname, DnsRecordType.AAAA)) == null) {
if ((cnameQuestion = newQuestion(cname, DnsRecordType.AAAA)) == null) {
return;
}
} catch (Throwable cause) {

View File

@ -425,7 +425,7 @@ public class DnsNameResolverTest {
}
@Test
public void testResolveA() throws Exception {
public void testResolveA() throws Exception {
DnsNameResolver resolver = newResolver(ResolvedAddressTypes.IPV4_ONLY)
// Cache for eternity
.ttl(Integer.MAX_VALUE, Integer.MAX_VALUE)
@ -741,6 +741,81 @@ public class DnsNameResolverTest {
testResolveAll0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, StringUtil.EMPTY_STRING);
}
@Test
public void testCNAMEResolveAllIpv4() throws IOException, InterruptedException {
testCNAMERecursiveResolve(true);
}
@Test
public void testCNAMEResolveAllIpv6() throws IOException, InterruptedException {
testCNAMERecursiveResolve(false);
}
private static void testCNAMERecursiveResolve(boolean ipv4Preferred) throws IOException, InterruptedException {
final String firstName = "firstname.com";
final String secondName = "secondname.com";
final String lastName = "lastname.com";
final String ipv4Addr = "1.2.3.4";
final String ipv6Addr = "::1";
TestDnsServer dnsServer2 = new TestDnsServer(new RecordStore() {
@Override
public Set<ResourceRecord> getRecords(QuestionRecord question) throws DnsException {
ResourceRecordModifier rm = new ResourceRecordModifier();
rm.setDnsClass(RecordClass.IN);
rm.setDnsName(question.getDomainName());
rm.setDnsTtl(100);
rm.setDnsType(RecordType.CNAME);
if (question.getDomainName().equals(firstName)) {
rm.put(DnsAttribute.DOMAIN_NAME, secondName);
} else if (question.getDomainName().equals(secondName)) {
rm.put(DnsAttribute.DOMAIN_NAME, lastName);
} else if (question.getDomainName().equals(lastName)) {
rm.setDnsType(question.getRecordType());
switch (question.getRecordType()) {
case A:
rm.put(DnsAttribute.IP_ADDRESS, ipv4Addr);
break;
case AAAA:
rm.put(DnsAttribute.IP_ADDRESS, ipv6Addr);
break;
default:
return null;
}
} else {
return null;
}
return Collections.singleton(rm.getEntry());
}
});
dnsServer2.start();
DnsNameResolver resolver = null;
try {
DnsNameResolverBuilder builder = newResolver()
.recursionDesired(true)
.maxQueriesPerResolve(16)
.nameServerProvider(new SingletonDnsServerAddressStreamProvider(dnsServer2.localAddress()));
if (ipv4Preferred) {
builder.resolvedAddressTypes(ResolvedAddressTypes.IPV4_PREFERRED);
} else {
builder.resolvedAddressTypes(ResolvedAddressTypes.IPV6_PREFERRED);
}
resolver = builder.build();
InetAddress resolvedAddress = resolver.resolve(firstName).syncUninterruptibly().getNow();
if (ipv4Preferred) {
assertEquals(ipv4Addr, resolvedAddress.getHostAddress());
} else {
assertEquals(ipv6Addr, NetUtil.toAddressString(resolvedAddress));
}
assertEquals(firstName, resolvedAddress.getHostName());
} finally {
dnsServer2.stop();
if (resolver != null) {
resolver.close();
}
}
}
@Test
public void testResolveAllNullIpv4() {
testResolveAll0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, null);