View Javadoc
1   /*
2    * Copyright 2024 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.internal.BoundedInputStream;
19  
20  import java.io.BufferedReader;
21  import java.io.FileInputStream;
22  import java.io.IOException;
23  import java.io.InputStreamReader;
24  import java.net.InetSocketAddress;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.List;
28  
29  /**
30   * Looks up the {@code nameserver}s from the {@code /etc/resolv.conf} file, intended for Linux and macOS.
31   */
32  final class ResolvConf {
33      private final List<InetSocketAddress> nameservers;
34  
35      /**
36       * Reads from the given reader and extracts the {@code nameserver}s using the syntax of the
37       * {@code /etc/resolv.conf} file, see {@code man resolv.conf}.
38       *
39       * @param reader contents of {@code resolv.conf} are read from this {@link BufferedReader},
40       *              up to the caller to close it
41       */
42      static ResolvConf fromReader(BufferedReader reader) throws IOException {
43          return new ResolvConf(reader);
44      }
45  
46      /**
47       * Reads the given file and extracts the {@code nameserver}s using the syntax of the
48       * {@code /etc/resolv.conf} file, see {@code man resolv.conf}.
49       */
50      static ResolvConf fromFile(String file) throws IOException {
51          BufferedReader reader = new BufferedReader(new InputStreamReader(
52                  // Use 1 MB to be a bit conservative
53                  new BoundedInputStream(new FileInputStream(file), 1024 * 1024)));
54          try {
55              return fromReader(reader);
56          } finally {
57              reader.close();
58          }
59      }
60  
61      /**
62       * Returns the {@code nameserver}s from the {@code /etc/resolv.conf} file. The file is only read once
63       * during the lifetime of this class.
64       */
65      static ResolvConf system() {
66          ResolvConf resolvConv = ResolvConfLazy.machineResolvConf;
67          if (resolvConv != null) {
68              return resolvConv;
69          }
70          throw new IllegalStateException("/etc/resolv.conf could not be read");
71      }
72  
73      private ResolvConf(BufferedReader reader) throws IOException {
74          List<InetSocketAddress> nameservers = new ArrayList<InetSocketAddress>();
75          String ln;
76          while ((ln = reader.readLine()) != null) {
77              ln = ln.trim();
78              if (ln.isEmpty()) {
79                  continue;
80              }
81  
82              if (ln.startsWith("nameserver")) {
83                  ln = ln.substring("nameserver".length()).trim();
84                  nameservers.add(new InetSocketAddress(ln, 53));
85              }
86          }
87          this.nameservers = Collections.unmodifiableList(nameservers);
88      }
89  
90      List<InetSocketAddress> getNameservers() {
91          return nameservers;
92      }
93  
94      private static final class ResolvConfLazy {
95          static final ResolvConf machineResolvConf;
96  
97          static {
98              ResolvConf resolvConf;
99              try {
100                 resolvConf = ResolvConf.fromFile("/etc/resolv.conf");
101             } catch (IOException e) {
102                 resolvConf = null;
103             } catch (SecurityException ignore) {
104                 resolvConf = null;
105             }
106             machineResolvConf = resolvConf;
107         }
108     }
109 }