View Javadoc
1   /*
2    * Copyright 2017 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.resolver.dns;
17  
18  import io.netty.util.NetUtil;
19  import io.netty.util.internal.PlatformDependent;
20  import io.netty.util.internal.SocketUtils;
21  import io.netty.util.internal.SystemPropertyUtil;
22  import io.netty.util.internal.logging.InternalLogger;
23  import io.netty.util.internal.logging.InternalLoggerFactory;
24  
25  import java.lang.reflect.Method;
26  import java.net.Inet6Address;
27  import java.net.InetSocketAddress;
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.List;
31  
32  import static io.netty.resolver.dns.DnsServerAddresses.sequential;
33  
34  /**
35   * A {@link DnsServerAddressStreamProvider} which will use predefined default DNS servers to use for DNS resolution.
36   * These defaults do not respect your host's machines defaults.
37   * <p>
38   * This may use the JDK's blocking DNS resolution to bootstrap the default DNS server addresses.
39   */
40  public final class DefaultDnsServerAddressStreamProvider implements DnsServerAddressStreamProvider {
41      private static final InternalLogger logger =
42              InternalLoggerFactory.getInstance(DefaultDnsServerAddressStreamProvider.class);
43      private static final String DEFAULT_FALLBACK_SERVER_PROPERTY = "io.netty.resolver.dns.defaultNameServerFallback";
44      public static final DefaultDnsServerAddressStreamProvider INSTANCE = new DefaultDnsServerAddressStreamProvider();
45  
46      private static final List<InetSocketAddress> DEFAULT_NAME_SERVER_LIST;
47      private static final DnsServerAddresses DEFAULT_NAME_SERVERS;
48      static final int DNS_PORT = 53;
49  
50      static {
51          final List<InetSocketAddress> defaultNameServers = new ArrayList<InetSocketAddress>(2);
52          if (!PlatformDependent.isAndroid()) {
53              // Skip this on Android; it has neither /etc/resolv.conf nor JNDI classes.
54              // See https://github.com/netty/netty/issues/8654
55              if (!PlatformDependent.isWindows()) {
56                  // Try reading /etc/resolv.conf. It's usually found on Linux or macOS, but can also be missing.
57                  try {
58                      defaultNameServers.addAll(ResolvConf.system().getNameservers());
59                  } catch (IllegalStateException e) {
60                      String fallbackMessage = "Failed to get name servers from /etc/resolv.conf; will fall back to JNDI";
61                      if (logger.isDebugEnabled()) {
62                          // Always log at INFO, but only include stack trace if DEBUG is enabled.
63                          logger.info(fallbackMessage, e);
64                      } else {
65                          logger.info(fallbackMessage);
66                      }
67                      DirContextUtils.addNameServers(defaultNameServers, DNS_PORT);
68                  }
69              } else {
70                  DirContextUtils.addNameServers(defaultNameServers, DNS_PORT);
71              }
72          }
73  
74          // Only try when using on Java8 and lower as otherwise it will produce:
75          // WARNING: Illegal reflective access by io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider
76          if (PlatformDependent.javaVersion() < 9 && defaultNameServers.isEmpty()) {
77              try {
78                  Class<?> configClass = Class.forName("sun.net.dns.ResolverConfiguration");
79                  Method open = configClass.getMethod("open");
80                  Method nameservers = configClass.getMethod("nameservers");
81                  Object instance = open.invoke(null);
82  
83                  @SuppressWarnings("unchecked")
84                  final List<String> list = (List<String>) nameservers.invoke(instance);
85                  for (String a: list) {
86                      if (a != null) {
87                          defaultNameServers.add(new InetSocketAddress(SocketUtils.addressByName(a), DNS_PORT));
88                      }
89                  }
90              } catch (Exception ignore) {
91                  // Failed to get the system name server list via reflection.
92                  // Will add the default name servers afterwards.
93              }
94          }
95  
96          if (!defaultNameServers.isEmpty()) {
97              if (logger.isDebugEnabled()) {
98                  logger.debug(
99                          "Default DNS servers: {} (sun.net.dns.ResolverConfiguration)", defaultNameServers);
100             }
101         } else {
102             String defaultNameserverString = SystemPropertyUtil.get(DEFAULT_FALLBACK_SERVER_PROPERTY, null);
103             if (defaultNameserverString != null) {
104                 for (String server : defaultNameserverString.split(",")) {
105                     String dns = server.trim();
106                     if (!NetUtil.isValidIpV4Address(dns) && !NetUtil.isValidIpV6Address(dns)) {
107                         throw new ExceptionInInitializerError(DEFAULT_FALLBACK_SERVER_PROPERTY + " doesn't" +
108                                 " contain a valid list of NameServers: " + defaultNameserverString);
109                     }
110                     defaultNameServers.add(SocketUtils.socketAddress(server.trim(), DNS_PORT));
111                 }
112                 if (defaultNameServers.isEmpty()) {
113                     throw new ExceptionInInitializerError(DEFAULT_FALLBACK_SERVER_PROPERTY + " doesn't" +
114                             " contain a valid list of NameServers: " + defaultNameserverString);
115                 }
116 
117                 if (logger.isWarnEnabled()) {
118                     logger.warn(
119                             "Default DNS servers: {} (Configured by {} system property)",
120                             defaultNameServers, DEFAULT_FALLBACK_SERVER_PROPERTY);
121                 }
122             } else {
123                 // Depending if IPv6 or IPv4 is used choose the correct DNS servers provided by google:
124                 // https://developers.google.com/speed/public-dns/docs/using
125                 // https://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html
126                 if (NetUtil.isIpV6AddressesPreferred() ||
127                         (NetUtil.LOCALHOST instanceof Inet6Address && !NetUtil.isIpV4StackPreferred())) {
128                     Collections.addAll(
129                             defaultNameServers,
130                             SocketUtils.socketAddress("2001:4860:4860::8888", DNS_PORT),
131                             SocketUtils.socketAddress("2001:4860:4860::8844", DNS_PORT));
132                 } else {
133                     Collections.addAll(
134                             defaultNameServers,
135                             SocketUtils.socketAddress("8.8.8.8", DNS_PORT),
136                             SocketUtils.socketAddress("8.8.4.4", DNS_PORT));
137                 }
138 
139                 if (logger.isWarnEnabled()) {
140                     logger.warn(
141                             "Default DNS servers: {} (Google Public DNS as a fallback)", defaultNameServers);
142                 }
143             }
144         }
145 
146         DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
147         DEFAULT_NAME_SERVERS = sequential(DEFAULT_NAME_SERVER_LIST);
148     }
149 
150     private DefaultDnsServerAddressStreamProvider() {
151     }
152 
153     @Override
154     public DnsServerAddressStream nameServerAddressStream(String hostname) {
155         return DEFAULT_NAME_SERVERS.stream();
156     }
157 
158     /**
159      * Returns the list of the system DNS server addresses. If it failed to retrieve the list of the system DNS server
160      * addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
161      * Google public DNS servers.
162      */
163     public static List<InetSocketAddress> defaultAddressList() {
164         return DEFAULT_NAME_SERVER_LIST;
165     }
166 
167     /**
168      * Returns the {@link DnsServerAddresses} that yields the system DNS server addresses sequentially. If it failed to
169      * retrieve the list of the system DNS server addresses from the environment, it will use {@code "8.8.8.8"} and
170      * {@code "8.8.4.4"}, the addresses of the Google public DNS servers.
171      * <p>
172      * This method has the same effect with the following code:
173      * <pre>
174      * DnsServerAddresses.sequential(DnsServerAddresses.defaultAddressList());
175      * </pre>
176      * </p>
177      */
178     public static DnsServerAddresses defaultAddresses() {
179         return DEFAULT_NAME_SERVERS;
180     }
181 }