From a0fcb72e5d999cd1f260c0d6da078bb29ae69fc4 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Fri, 31 Mar 2017 08:05:46 +0200 Subject: [PATCH] Use jndi-dns to obtain default name servers Motivation: Using reflection to obtain the default name servers may fail in Java9 and also in previous Java versions if a SecurityManager is present. Modifications: Try using jndi-dns to obtain default name servers and only try using reflection if this fails. Result: Be able to detect default name servers in all cases. Fixes [#6347]. --- ...DefaultDnsServerAddressStreamProvider.java | 59 +++++++++++++++---- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/resolver-dns/src/main/java/io/netty/resolver/dns/DefaultDnsServerAddressStreamProvider.java b/resolver-dns/src/main/java/io/netty/resolver/dns/DefaultDnsServerAddressStreamProvider.java index 505ecfb4ae..b7c5bd719f 100644 --- a/resolver-dns/src/main/java/io/netty/resolver/dns/DefaultDnsServerAddressStreamProvider.java +++ b/resolver-dns/src/main/java/io/netty/resolver/dns/DefaultDnsServerAddressStreamProvider.java @@ -20,10 +20,17 @@ import io.netty.util.internal.UnstableApi; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; import java.lang.reflect.Method; import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; +import java.util.Hashtable; import java.util.List; import static io.netty.resolver.dns.DnsServerAddresses.sequential; @@ -47,22 +54,48 @@ public final class DefaultDnsServerAddressStreamProvider implements DnsServerAdd static { final List defaultNameServers = new ArrayList(2); - try { - Class configClass = Class.forName("sun.net.dns.ResolverConfiguration"); - Method open = configClass.getMethod("open"); - Method nameservers = configClass.getMethod("nameservers"); - Object instance = open.invoke(null); - @SuppressWarnings("unchecked") - final List list = (List) nameservers.invoke(instance); - for (String a: list) { - if (a != null) { - defaultNameServers.add(new InetSocketAddress(SocketUtils.addressByName(a), DNS_PORT)); + // Using jndi-dns to obtain the default name servers. + // + // See: + // - http://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-dns.html + // - http://mail.openjdk.java.net/pipermail/net-dev/2017-March/010695.html + Hashtable env = new Hashtable(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); + env.put("java.naming.provider.url", "dns://"); + try { + DirContext ctx = new InitialDirContext(env); + String dnsUrls = (String) ctx.getEnvironment().get("java.naming.provider.url"); + String[] servers = dnsUrls.split(" "); + for (String server : servers) { + try { + defaultNameServers.add(SocketUtils.socketAddress(new URI(server).getHost(), DNS_PORT)); + } catch (URISyntaxException e) { + logger.debug("Skipping a malformed nameserver URI: {}", server, e); } } - } catch (Exception ignore) { - // Failed to get the system name server list. - // Will add the default name servers afterwards. + } catch (NamingException ignore) { + // Will try reflection if this fails. + } + + if (defaultNameServers.isEmpty()) { + try { + Class configClass = Class.forName("sun.net.dns.ResolverConfiguration"); + Method open = configClass.getMethod("open"); + Method nameservers = configClass.getMethod("nameservers"); + Object instance = open.invoke(null); + + @SuppressWarnings("unchecked") + final List list = (List) nameservers.invoke(instance); + for (String a: list) { + if (a != null) { + defaultNameServers.add(new InetSocketAddress(SocketUtils.addressByName(a), DNS_PORT)); + } + } + } catch (Exception ignore) { + // Failed to get the system name server list via reflection. + // Will add the default name servers afterwards. + } } if (!defaultNameServers.isEmpty()) {