Automatically decode DNS domain name to unicode
Motivation: DnsNameResolver will return the domain / host name as ascii code using punycode (https://tools.ietf.org/html/rfc3492). This is different to what the JDK does which always convert it to unicode. We should do the same by default but allow to also not do it. Modifications: - Add new builder method on DnsNameResolverBuilder which allow to disable / enable converting. Default is to convert just like the JDK does. - Add unit tests for it. Result: DnsNameResolver and JDK impl behave the same way.
This commit is contained in:
parent
ead9938980
commit
0d5b665fba
@ -155,6 +155,7 @@ public class DnsNameResolver extends InetNameResolver {
|
||||
private final boolean cnameFollowAAAARecords;
|
||||
private final InternetProtocolFamily preferredAddressType;
|
||||
private final DnsRecordType[] resolveRecordTypes;
|
||||
private final boolean decodeIdn;
|
||||
|
||||
/**
|
||||
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
|
||||
@ -175,7 +176,11 @@ public class DnsNameResolver extends InetNameResolver {
|
||||
* @param hostsFileEntriesResolver the {@link HostsFileEntriesResolver} used to check for local aliases
|
||||
* @param searchDomains the list of search domain
|
||||
* @param ndots the ndots value
|
||||
* @deprecated use {@link #DnsNameResolver(EventLoop, ChannelFactory, DnsServerAddresses, DnsCache, long,
|
||||
* InternetProtocolFamily[], boolean, int, boolean, int,
|
||||
* boolean, HostsFileEntriesResolver, String[], int, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
public DnsNameResolver(
|
||||
EventLoop eventLoop,
|
||||
ChannelFactory<? extends DatagramChannel> channelFactory,
|
||||
@ -191,6 +196,49 @@ public class DnsNameResolver extends InetNameResolver {
|
||||
HostsFileEntriesResolver hostsFileEntriesResolver,
|
||||
String[] searchDomains,
|
||||
int ndots) {
|
||||
this(eventLoop, channelFactory, nameServerAddresses, resolveCache, queryTimeoutMillis, resolvedAddressTypes,
|
||||
recursionDesired, maxQueriesPerResolve, traceEnabled, maxPayloadSize, optResourceEnabled,
|
||||
hostsFileEntriesResolver, searchDomains, ndots, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
|
||||
*
|
||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
||||
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
||||
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new stream is created from
|
||||
* this to determine which DNS server should be contacted for the next retry in case
|
||||
* of failure.
|
||||
* @param resolveCache the DNS resolved entries cache
|
||||
* @param queryTimeoutMillis timeout of each DNS query in millis
|
||||
* @param resolvedAddressTypes list of the protocol families
|
||||
* @param recursionDesired if recursion desired flag must be set
|
||||
* @param maxQueriesPerResolve the maximum allowed number of DNS queries for a given name resolution
|
||||
* @param traceEnabled if trace is enabled
|
||||
* @param maxPayloadSize the capacity of the datagram packet buffer
|
||||
* @param optResourceEnabled if automatic inclusion of a optional records is enabled
|
||||
* @param hostsFileEntriesResolver the {@link HostsFileEntriesResolver} used to check for local aliases
|
||||
* @param searchDomains the list of search domain
|
||||
* @param ndots the ndots value
|
||||
* @param decodeIdn {@code true} if domain / host names should be decoded to unicode when received.
|
||||
* See <a href="https://tools.ietf.org/html/rfc3492">rfc3492</a>.
|
||||
*/
|
||||
public DnsNameResolver(
|
||||
EventLoop eventLoop,
|
||||
ChannelFactory<? extends DatagramChannel> channelFactory,
|
||||
DnsServerAddresses nameServerAddresses,
|
||||
final DnsCache resolveCache,
|
||||
long queryTimeoutMillis,
|
||||
InternetProtocolFamily[] resolvedAddressTypes,
|
||||
boolean recursionDesired,
|
||||
int maxQueriesPerResolve,
|
||||
boolean traceEnabled,
|
||||
int maxPayloadSize,
|
||||
boolean optResourceEnabled,
|
||||
HostsFileEntriesResolver hostsFileEntriesResolver,
|
||||
String[] searchDomains,
|
||||
int ndots,
|
||||
boolean decodeIdn) {
|
||||
|
||||
super(eventLoop);
|
||||
checkNotNull(channelFactory, "channelFactory");
|
||||
@ -206,6 +254,7 @@ public class DnsNameResolver extends InetNameResolver {
|
||||
this.resolveCache = checkNotNull(resolveCache, "resolveCache");
|
||||
this.searchDomains = checkNotNull(searchDomains, "searchDomains").clone();
|
||||
this.ndots = checkPositiveOrZero(ndots, "ndots");
|
||||
this.decodeIdn = decodeIdn;
|
||||
|
||||
boolean cnameFollowARecords = false;
|
||||
boolean cnameFollowAAAARecords = false;
|
||||
@ -309,6 +358,10 @@ public class DnsNameResolver extends InetNameResolver {
|
||||
return resolveRecordTypes;
|
||||
}
|
||||
|
||||
final boolean isDecodeIdn() {
|
||||
return decodeIdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if this resolver sends a DNS query with the RD (recursion desired) flag set.
|
||||
* The default value is {@code true}.
|
||||
|
@ -53,6 +53,7 @@ public final class DnsNameResolverBuilder {
|
||||
private HostsFileEntriesResolver hostsFileEntriesResolver = HostsFileEntriesResolver.DEFAULT;
|
||||
private String[] searchDomains = DnsNameResolver.DEFAULT_SEACH_DOMAINS;
|
||||
private int ndots = 1;
|
||||
private boolean decodeIdn = true;
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
@ -330,6 +331,18 @@ public final class DnsNameResolverBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if domain / host names should be decoded to unicode when received.
|
||||
* See <a href="https://tools.ietf.org/html/rfc3492">rfc3492</a>.
|
||||
*
|
||||
* @param decodeIdn if should get decoded
|
||||
* @return {@code this}
|
||||
*/
|
||||
public DnsNameResolverBuilder decodeIdn(boolean decodeIdn) {
|
||||
this.decodeIdn = decodeIdn;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link DnsNameResolver} instance.
|
||||
*
|
||||
@ -358,6 +371,7 @@ public final class DnsNameResolverBuilder {
|
||||
optResourceEnabled,
|
||||
hostsFileEntriesResolver,
|
||||
searchDomains,
|
||||
ndots);
|
||||
ndots,
|
||||
decodeIdn);
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import io.netty.util.concurrent.FutureListener;
|
||||
import io.netty.util.concurrent.Promise;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.net.IDN;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
@ -272,7 +273,8 @@ abstract class DnsNameResolverContext<T> {
|
||||
|
||||
final InetAddress resolved;
|
||||
try {
|
||||
resolved = InetAddress.getByAddress(hostname, addrBytes);
|
||||
resolved = InetAddress.getByAddress(
|
||||
parent.isDecodeIdn() ? IDN.toUnicode(hostname) : hostname, addrBytes);
|
||||
} catch (UnknownHostException e) {
|
||||
// Should never reach here.
|
||||
throw new Error(e);
|
||||
|
@ -170,6 +170,20 @@ public class DnsNameResolverTest {
|
||||
"blogspot.in",
|
||||
"localhost")));
|
||||
|
||||
private static final Map<String, String> DOMAINS_PUNYCODE = new HashMap<String, String>();
|
||||
static {
|
||||
DOMAINS_PUNYCODE.put("büchner.de", "xn--bchner-3ya.de");
|
||||
DOMAINS_PUNYCODE.put("müller.de", "xn--mller-kva.de");
|
||||
}
|
||||
|
||||
private static final Set<String> DOMAINS_ALL;
|
||||
static {
|
||||
Set<String> all = new HashSet<String>(DOMAINS.size() + DOMAINS_PUNYCODE.size());
|
||||
all.addAll(DOMAINS);
|
||||
all.addAll(DOMAINS_PUNYCODE.values());
|
||||
DOMAINS_ALL = Collections.unmodifiableSet(all);
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of the domain names to exclude from {@link #testResolveAorAAAA()}.
|
||||
*/
|
||||
@ -238,17 +252,22 @@ public class DnsNameResolverTest {
|
||||
StringUtil.EMPTY_STRING);
|
||||
}
|
||||
|
||||
private static final TestDnsServer dnsServer = new TestDnsServer(DOMAINS);
|
||||
private static final TestDnsServer dnsServer = new TestDnsServer(DOMAINS_ALL);
|
||||
private static final EventLoopGroup group = new NioEventLoopGroup(1);
|
||||
|
||||
private static DnsNameResolverBuilder newResolver() {
|
||||
private static DnsNameResolverBuilder newResolver(boolean decodeToUnicode) {
|
||||
return new DnsNameResolverBuilder(group.next())
|
||||
.channelType(NioDatagramChannel.class)
|
||||
.nameServerAddresses(DnsServerAddresses.singleton(dnsServer.localAddress()))
|
||||
.maxQueriesPerResolve(1)
|
||||
.decodeIdn(decodeToUnicode)
|
||||
.optResourceEnabled(false);
|
||||
}
|
||||
|
||||
private static DnsNameResolverBuilder newResolver() {
|
||||
return newResolver(true);
|
||||
}
|
||||
|
||||
private static DnsNameResolverBuilder newResolver(InternetProtocolFamily... resolvedAddressTypes) {
|
||||
return newResolver()
|
||||
.resolvedAddressTypes(resolvedAddressTypes);
|
||||
@ -558,6 +577,28 @@ public class DnsNameResolverTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveDecodeUnicode() {
|
||||
testResolveUnicode(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveNotDecodeUnicode() {
|
||||
testResolveUnicode(false);
|
||||
}
|
||||
|
||||
private static void testResolveUnicode(boolean decode) {
|
||||
DnsNameResolver resolver = newResolver(decode).build();
|
||||
try {
|
||||
for (Entry<String, String> entries : DOMAINS_PUNYCODE.entrySet()) {
|
||||
InetAddress address = resolver.resolve(entries.getKey()).syncUninterruptibly().getNow();
|
||||
assertEquals(decode ? entries.getKey() : entries.getValue(), address.getHostName());
|
||||
}
|
||||
} finally {
|
||||
resolver.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolve(DnsNameResolver resolver, Map<String, Future<InetAddress>> futures, String hostname) {
|
||||
futures.put(hostname, resolver.resolve(hostname));
|
||||
}
|
||||
@ -568,5 +609,4 @@ public class DnsNameResolverTest {
|
||||
String hostname) throws Exception {
|
||||
futures.put(hostname, resolver.query(new DefaultDnsQuestion(hostname, DnsRecordType.MX)));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user