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.logging.InternalLogger;
22  import io.netty.util.internal.logging.InternalLoggerFactory;
23  
24  import java.lang.reflect.Method;
25  import java.net.Inet6Address;
26  import java.net.InetSocketAddress;
27  import java.util.ArrayList;
28  import java.util.Collections;
29  import java.util.List;
30  
31  import static io.netty.resolver.dns.DnsServerAddresses.sequential;
32  
33  /**
34   * A {@link DnsServerAddressStreamProvider} which will use predefined default DNS servers to use for DNS resolution.
35   * These defaults do not respect your host's machines defaults.
36   * <p>
37   * This may use the JDK's blocking DNS resolution to bootstrap the default DNS server addresses.
38   */
39  public final class DefaultDnsServerAddressStreamProvider implements DnsServerAddressStreamProvider {
40      private static final InternalLogger logger =
41              InternalLoggerFactory.getInstance(DefaultDnsServerAddressStreamProvider.class);
42      public static final DefaultDnsServerAddressStreamProvider INSTANCE = new DefaultDnsServerAddressStreamProvider();
43  
44      private static final List<InetSocketAddress> DEFAULT_NAME_SERVER_LIST;
45      private static final DnsServerAddresses DEFAULT_NAME_SERVERS;
46      static final int DNS_PORT = 53;
47  
48      static {
49          final List<InetSocketAddress> defaultNameServers = new ArrayList<InetSocketAddress>(2);
50          if (!PlatformDependent.isAndroid()) {
51              // Only try to use when not on Android as the classes not exists there:
52              // See https://github.com/netty/netty/issues/8654
53              DirContextUtils.addNameServers(defaultNameServers, DNS_PORT);
54          }
55  
56          // Only try when using Java8 and lower as otherwise it will produce:
57          // WARNING: Illegal reflective access by io.netty.resolver.dns.DefaultDnsServerAddressStreamProvider
58          if (PlatformDependent.javaVersion() < 9 && defaultNameServers.isEmpty()) {
59              try {
60                  Class<?> configClass = Class.forName("sun.net.dns.ResolverConfiguration");
61                  Method open = configClass.getMethod("open");
62                  Method nameservers = configClass.getMethod("nameservers");
63                  Object instance = open.invoke(null);
64  
65                  @SuppressWarnings("unchecked")
66                  final List<String> list = (List<String>) nameservers.invoke(instance);
67                  for (String a: list) {
68                      if (a != null) {
69                          defaultNameServers.add(new InetSocketAddress(SocketUtils.addressByName(a), DNS_PORT));
70                      }
71                  }
72              } catch (Exception ignore) {
73                  // Failed to get the system name server list via reflection.
74                  // Will add the default name servers afterwards.
75              }
76          }
77  
78          if (!defaultNameServers.isEmpty()) {
79              if (logger.isDebugEnabled()) {
80                  logger.debug(
81                          "Default DNS servers: {} (sun.net.dns.ResolverConfiguration)", defaultNameServers);
82              }
83          } else {
84              // Depending if IPv6 or IPv4 is used choose the correct DNS servers provided by google:
85              // https://developers.google.com/speed/public-dns/docs/using
86              // https://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html
87              if (NetUtil.isIpV6AddressesPreferred() ||
88                      (NetUtil.LOCALHOST instanceof Inet6Address && !NetUtil.isIpV4StackPreferred())) {
89                  Collections.addAll(
90                          defaultNameServers,
91                          SocketUtils.socketAddress("2001:4860:4860::8888", DNS_PORT),
92                          SocketUtils.socketAddress("2001:4860:4860::8844", DNS_PORT));
93              } else {
94                  Collections.addAll(
95                          defaultNameServers,
96                          SocketUtils.socketAddress("8.8.8.8", DNS_PORT),
97                          SocketUtils.socketAddress("8.8.4.4", DNS_PORT));
98              }
99  
100             if (logger.isWarnEnabled()) {
101                 logger.warn(
102                         "Default DNS servers: {} (Google Public DNS as a fallback)", defaultNameServers);
103             }
104         }
105 
106         DEFAULT_NAME_SERVER_LIST = Collections.unmodifiableList(defaultNameServers);
107         DEFAULT_NAME_SERVERS = sequential(DEFAULT_NAME_SERVER_LIST);
108     }
109 
110     private DefaultDnsServerAddressStreamProvider() {
111     }
112 
113     @Override
114     public DnsServerAddressStream nameServerAddressStream(String hostname) {
115         return DEFAULT_NAME_SERVERS.stream();
116     }
117 
118     /**
119      * Returns the list of the system DNS server addresses. If it failed to retrieve the list of the system DNS server
120      * addresses from the environment, it will return {@code "8.8.8.8"} and {@code "8.8.4.4"}, the addresses of the
121      * Google public DNS servers.
122      */
123     public static List<InetSocketAddress> defaultAddressList() {
124         return DEFAULT_NAME_SERVER_LIST;
125     }
126 
127     /**
128      * Returns the {@link DnsServerAddresses} that yields the system DNS server addresses sequentially. If it failed to
129      * retrieve the list of the system DNS server addresses from the environment, it will use {@code "8.8.8.8"} and
130      * {@code "8.8.4.4"}, the addresses of the Google public DNS servers.
131      * <p>
132      * This method has the same effect with the following code:
133      * <pre>
134      * DnsServerAddresses.sequential(DnsServerAddresses.defaultAddressList());
135      * </pre>
136      * </p>
137      */
138     public static DnsServerAddresses defaultAddresses() {
139         return DEFAULT_NAME_SERVERS;
140     }
141 }