DnsNameResolverContext#followCname only uses first name server
Motivation: When following a CNAME it is possible there are multiple name servers to query against. However DnsNameResolverContext#followCname explicitly only uses the first name server address when attempting the query. This may lead to resolution failures because we didn't try all the available name servers. Modifications: DnsNameResolverContext#followCname should not just try the first name server, but it should try all name servers Result: More complete CNAME resolution.
This commit is contained in:
parent
95b9b0af5c
commit
fe5c69bdd9
@ -755,7 +755,7 @@ abstract class DnsNameResolverContext<T> {
|
||||
|
||||
private void followCname(String cname, final DnsQueryLifecycleObserver queryLifecycleObserver, Promise<T> promise) {
|
||||
// Use the same server for both CNAME queries
|
||||
DnsServerAddressStream stream = DnsServerAddresses.singleton(getNameServers(cname).next()).stream();
|
||||
DnsServerAddressStream stream = getNameServers(cname);
|
||||
|
||||
DnsQuestion cnameQuestion = null;
|
||||
if (parent.supportsARecords()) {
|
||||
|
@ -49,6 +49,7 @@ import org.apache.directory.server.dns.messages.RecordClass;
|
||||
import org.apache.directory.server.dns.messages.RecordType;
|
||||
import org.apache.directory.server.dns.messages.ResourceRecord;
|
||||
import org.apache.directory.server.dns.messages.ResourceRecordModifier;
|
||||
import org.apache.directory.server.dns.messages.ResponseCode;
|
||||
import org.apache.directory.server.dns.store.DnsAttribute;
|
||||
import org.apache.directory.server.dns.store.RecordStore;
|
||||
import org.junit.AfterClass;
|
||||
@ -73,6 +74,7 @@ import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static io.netty.handler.codec.dns.DnsRecordType.A;
|
||||
import static io.netty.handler.codec.dns.DnsRecordType.AAAA;
|
||||
@ -817,6 +819,108 @@ public class DnsNameResolverTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCNAMERecursiveResolveMultipleNameServersIPv4() throws IOException {
|
||||
testCNAMERecursiveResolveMultipleNameServers(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCNAMERecursiveResolveMultipleNameServersIPv6() throws IOException {
|
||||
testCNAMERecursiveResolveMultipleNameServers(false);
|
||||
}
|
||||
|
||||
private static void testCNAMERecursiveResolveMultipleNameServers(boolean ipv4Preferred) throws IOException {
|
||||
final String firstName = "firstname.nettyfoo.com";
|
||||
final String lastName = "lastname.nettybar.com";
|
||||
final String ipv4Addr = "1.2.3.4";
|
||||
final String ipv6Addr = "::1";
|
||||
final AtomicBoolean hitServer2 = new AtomicBoolean();
|
||||
final TestDnsServer dnsServer2 = new TestDnsServer(new RecordStore() {
|
||||
@Override
|
||||
public Set<ResourceRecord> getRecords(QuestionRecord question) throws DnsException {
|
||||
hitServer2.set(true);
|
||||
if (question.getDomainName().equals(firstName)) {
|
||||
ResourceRecordModifier rm = new ResourceRecordModifier();
|
||||
rm.setDnsClass(RecordClass.IN);
|
||||
rm.setDnsName(question.getDomainName());
|
||||
rm.setDnsTtl(100);
|
||||
rm.setDnsType(RecordType.CNAME);
|
||||
rm.put(DnsAttribute.DOMAIN_NAME, lastName);
|
||||
return Collections.singleton(rm.getEntry());
|
||||
} else {
|
||||
throw new DnsException(ResponseCode.REFUSED);
|
||||
}
|
||||
}
|
||||
});
|
||||
final TestDnsServer dnsServer3 = new TestDnsServer(new RecordStore() {
|
||||
@Override
|
||||
public Set<ResourceRecord> getRecords(QuestionRecord question) throws DnsException {
|
||||
if (question.getDomainName().equals(lastName)) {
|
||||
ResourceRecordModifier rm = new ResourceRecordModifier();
|
||||
rm.setDnsClass(RecordClass.IN);
|
||||
rm.setDnsName(question.getDomainName());
|
||||
rm.setDnsTtl(100);
|
||||
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;
|
||||
}
|
||||
|
||||
return Collections.singleton(rm.getEntry());
|
||||
} else {
|
||||
throw new DnsException(ResponseCode.REFUSED);
|
||||
}
|
||||
}
|
||||
});
|
||||
dnsServer2.start();
|
||||
dnsServer3.start();
|
||||
DnsNameResolver resolver = null;
|
||||
try {
|
||||
DnsCache nsCache = new DefaultDnsCache();
|
||||
// What we want to test is the following:
|
||||
// 1. Do a DNS query.
|
||||
// 2. CNAME is returned, we want to lookup that CNAME on multiple DNS servers
|
||||
// 3. The first DNS server should fail
|
||||
// 4. The second DNS server should succeed
|
||||
// This verifies that we do in fact follow multiple DNS servers in the CNAME resolution.
|
||||
// The DnsCache is used for the name server cache, but doesn't provide a InetSocketAddress (only InetAddress
|
||||
// so no port), so we only specify the name server in the cache, and then specify both name servers in the
|
||||
// fallback name server provider.
|
||||
nsCache.cache("nettyfoo.com.", null, dnsServer2.localAddress().getAddress(), 10000, group.next());
|
||||
resolver = new DnsNameResolver(
|
||||
group.next(), new ReflectiveChannelFactory<DatagramChannel>(NioDatagramChannel.class),
|
||||
NoopDnsCache.INSTANCE, nsCache, NoopDnsQueryLifecycleObserverFactory.INSTANCE, 3000,
|
||||
ipv4Preferred ? ResolvedAddressTypes.IPV4_ONLY : ResolvedAddressTypes.IPV6_ONLY, true,
|
||||
10, true, 4096, false, HostsFileEntriesResolver.DEFAULT,
|
||||
new SequentialDnsServerAddressStreamProvider(dnsServer2.localAddress(), dnsServer3.localAddress()),
|
||||
DnsNameResolver.DEFAULT_SEARCH_DOMAINS, 0, true) {
|
||||
@Override
|
||||
int dnsRedirectPort(InetAddress server) {
|
||||
return hitServer2.get() ? dnsServer3.localAddress().getPort() : dnsServer2.localAddress().getPort();
|
||||
}
|
||||
};
|
||||
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();
|
||||
dnsServer3.stop();
|
||||
if (resolver != null) {
|
||||
resolver.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveAllNullIpv4() {
|
||||
testResolveAll0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, null);
|
||||
|
Loading…
Reference in New Issue
Block a user