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