Fix DN resolution when ndots is greater than 1
Motivation: DN resolution does not fall back to the "original name" lookup after search list is checked. This results in a failure to resolve any name (outside of search list) that has number of dots less than resolv.conf's ndots value (which, for example, is often the case in the context of Kubernetes where kubelet passes on resolv.conf containing "options ndots:5"). It also does not go through the search list in a situation described in resolv.conf man: "The default for n[dots] is 1, meaning that if there are any dots in a name, the name will be tried first as an absolute name before any search list elements are appended to it." Modifications: DnsNameResolverContext::resolve was updated to match Go's https://github.com/golang/go/blob/release-branch.go1.9/src/net/dnsclient_unix.go#L338 logic. Result: DnsNameResolverContext::resolve will now try to resolve "original name" if search list yields no results when number of dots in the original name is less than resolv.conf's ndots value. It will also go through the search list in case "origin name" resolution fails and number of dots is equal or larger than resolv.conf's ndots value.
This commit is contained in:
parent
a8bb9dc180
commit
844d804aba
@ -125,33 +125,43 @@ abstract class DnsNameResolverContext<T> {
|
||||
}
|
||||
|
||||
void resolve(final Promise<T> promise) {
|
||||
if (parent.searchDomains().length == 0 || parent.ndots() == 0 || StringUtil.endsWith(hostname, '.')) {
|
||||
final String[] searchDomains = parent.searchDomains();
|
||||
if (searchDomains.length == 0 || parent.ndots() == 0 || StringUtil.endsWith(hostname, '.')) {
|
||||
internalResolve(promise);
|
||||
} else {
|
||||
int dots = 0;
|
||||
for (int idx = hostname.length() - 1; idx >= 0; idx--) {
|
||||
if (hostname.charAt(idx) == '.' && ++dots >= parent.ndots()) {
|
||||
internalResolve(promise);
|
||||
return;
|
||||
}
|
||||
}
|
||||
final boolean startWithoutSearchDomain = hasNDots();
|
||||
final String initialHostname = startWithoutSearchDomain ? hostname : hostname + '.' + searchDomains[0];
|
||||
final int initialSearchDomainIdx = startWithoutSearchDomain ? 0 : 1;
|
||||
|
||||
doSearchDomainQuery(0, new FutureListener<T>() {
|
||||
private int count = 1;
|
||||
doSearchDomainQuery(initialHostname, new FutureListener<T>() {
|
||||
private int searchDomainIdx = initialSearchDomainIdx;
|
||||
@Override
|
||||
public void operationComplete(Future<T> future) throws Exception {
|
||||
if (future.isSuccess()) {
|
||||
promise.trySuccess(future.getNow());
|
||||
} else if (count < parent.searchDomains().length) {
|
||||
doSearchDomainQuery(count++, this);
|
||||
} else if (searchDomainIdx < searchDomains.length) {
|
||||
doSearchDomainQuery(hostname + '.' + searchDomains[searchDomainIdx++], this);
|
||||
} else {
|
||||
promise.tryFailure(new SearchDomainUnknownHostException(future.cause(), hostname));
|
||||
if (!startWithoutSearchDomain) {
|
||||
internalResolve(promise);
|
||||
} else {
|
||||
promise.tryFailure(new SearchDomainUnknownHostException(future.cause(), hostname));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasNDots() {
|
||||
for (int idx = hostname.length() - 1, dots = 0; idx >= 0; idx--) {
|
||||
if (hostname.charAt(idx) == '.' && ++dots >= parent.ndots()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final class SearchDomainUnknownHostException extends UnknownHostException {
|
||||
private static final long serialVersionUID = -8573510133644997085L;
|
||||
|
||||
@ -166,12 +176,9 @@ abstract class DnsNameResolverContext<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private void doSearchDomainQuery(int count, FutureListener<T> listener) {
|
||||
DnsNameResolverContext<T> nextContext = newResolverContext(parent,
|
||||
hostname + '.' + parent.searchDomains()[count],
|
||||
additionals,
|
||||
resolveCache,
|
||||
nameServerAddrs);
|
||||
private void doSearchDomainQuery(String hostname, FutureListener<T> listener) {
|
||||
DnsNameResolverContext<T> nextContext = newResolverContext(parent, hostname, additionals, resolveCache,
|
||||
nameServerAddrs);
|
||||
Promise<T> nextPromise = parent.executor().newPromise();
|
||||
nextContext.internalResolve(nextPromise);
|
||||
nextPromise.addListener(listener);
|
||||
|
@ -104,8 +104,10 @@ public class SearchDomainTest {
|
||||
// "host2" not resolved
|
||||
assertNotResolve(resolver, "host2");
|
||||
|
||||
// "host3" does not contain a dot or is not absolute
|
||||
assertNotResolve(resolver, "host3");
|
||||
// "host3" does not contain a dot nor it's absolute but it should still be resolved after search list have
|
||||
// been checked
|
||||
resolved = assertResolve(resolver, "host3");
|
||||
assertEquals(store.getAddress("host3"), resolved);
|
||||
|
||||
// "host3." does not contain a dot but is absolute
|
||||
resolved = assertResolve(resolver, "host3.");
|
||||
@ -152,8 +154,10 @@ public class SearchDomainTest {
|
||||
// "host2" not resolved
|
||||
assertNotResolveAll(resolver, "host2");
|
||||
|
||||
// "host3" does not contain a dot or is not absolute
|
||||
assertNotResolveAll(resolver, "host3");
|
||||
// "host3" does not contain a dot nor it's absolute but it should still be resolved after search list have
|
||||
// been checked
|
||||
resolved = assertResolveAll(resolver, "host3");
|
||||
assertEquals(store.getAddresses("host3"), resolved);
|
||||
|
||||
// "host3." does not contain a dot but is absolute
|
||||
resolved = assertResolveAll(resolver, "host3.");
|
||||
@ -281,7 +285,7 @@ public class SearchDomainTest {
|
||||
dnsServer = new TestDnsServer(store);
|
||||
dnsServer.start();
|
||||
|
||||
resolver = newResolver().searchDomains(Collections.singletonList("foo.com")).ndots(2).build();
|
||||
resolver = newResolver().searchDomains(Collections.singletonList("foo.com")).ndots(1).build();
|
||||
|
||||
Future<InetAddress> fut = resolver.resolve("unknown.hostname");
|
||||
assertTrue(fut.await(10, TimeUnit.SECONDS));
|
||||
@ -293,12 +297,12 @@ public class SearchDomainTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionMsgDoesNotContainSearchDomainIfNdotsNotHighEnough() throws Exception {
|
||||
public void testExceptionMsgDoesNotContainSearchDomainIfNdotsIsNotReached() throws Exception {
|
||||
TestDnsServer.MapRecordStoreA store = new TestDnsServer.MapRecordStoreA(Collections.<String>emptySet());
|
||||
dnsServer = new TestDnsServer(store);
|
||||
dnsServer.start();
|
||||
|
||||
resolver = newResolver().searchDomains(Collections.singletonList("foo.com")).ndots(1).build();
|
||||
resolver = newResolver().searchDomains(Collections.singletonList("foo.com")).ndots(2).build();
|
||||
|
||||
Future<InetAddress> fut = resolver.resolve("unknown.hostname");
|
||||
assertTrue(fut.await(10, TimeUnit.SECONDS));
|
||||
|
Loading…
Reference in New Issue
Block a user