diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java
index fdbf449cf5..10c0065e54 100644
--- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java
+++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolver.java
@@ -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 rfc3492.
+ */
+ 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}.
diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverBuilder.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverBuilder.java
index dd6fed0e34..1b4561d904 100644
--- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverBuilder.java
+++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverBuilder.java
@@ -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 rfc3492.
+ *
+ * @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);
}
}
diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverContext.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverContext.java
index 41d7b72c63..5884513d84 100644
--- a/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverContext.java
+++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DnsNameResolverContext.java
@@ -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 {
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);
diff --git a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java
index b27c6aa36e..d5fd45d79c 100644
--- a/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java
+++ b/resolver-dns/src/test/java/io/netty/resolver/dns/DnsNameResolverTest.java
@@ -170,6 +170,20 @@ public class DnsNameResolverTest {
"blogspot.in",
"localhost")));
+ private static final Map DOMAINS_PUNYCODE = new HashMap();
+ 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 DOMAINS_ALL;
+ static {
+ Set all = new HashSet(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 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> 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)));
}
-
}