1 /* 2 * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.net.dns; 27 28 import java.util.List; 29 import java.util.LinkedList; 30 import java.util.StringTokenizer; 31 import java.io.BufferedReader; 32 import java.io.FileReader; 33 import java.io.IOException; 34 35 /* 36 * An implementation of ResolverConfiguration for Solaris 37 * and Linux. 38 */ 39 40 public class ResolverConfigurationImpl 41 extends ResolverConfiguration 42 { 43 // Lock helds whilst loading configuration or checking 44 private static Object lock = new Object(); 45 46 // Time of last refresh. 47 private static long lastRefresh = -1; 48 49 // Cache timeout (300 seconds) - should be converted into property 50 // or configured as preference in the future. 51 private static final int TIMEOUT = 300000; 52 53 // Resolver options 54 private final Options opts; 55 56 // Parse /etc/resolv.conf to get the values for a particular 57 // keyword. 58 // 59 private LinkedList<String> resolvconf(String keyword, 60 int maxperkeyword, 61 int maxkeywords) 62 { 63 LinkedList<String> ll = new LinkedList<>(); 64 65 try { 66 BufferedReader in = 67 new BufferedReader(new FileReader("/etc/resolv.conf")); 68 String line; 69 while ((line = in.readLine()) != null) { 70 int maxvalues = maxperkeyword; 71 if (line.length() == 0) 72 continue; 73 if (line.charAt(0) == '#' || line.charAt(0) == ';') 74 continue; 75 if (!line.startsWith(keyword)) 76 continue; 77 String value = line.substring(keyword.length()); 78 if (value.length() == 0) 79 continue; 80 if (value.charAt(0) != ' ' && value.charAt(0) != '\t') 81 continue; 82 StringTokenizer st = new StringTokenizer(value, " \t"); 83 while (st.hasMoreTokens()) { 84 String val = st.nextToken(); 85 if (val.charAt(0) == '#' || val.charAt(0) == ';') { 86 break; 87 } 88 if ("nameserver".equals(keyword)) { 89 if (val.indexOf(':') >= 0 && 90 val.indexOf('.') < 0 && // skip for IPv4 literals with port 91 val.indexOf('[') < 0 && 92 val.indexOf(']') < 0 ) { 93 // IPv6 literal, in non-BSD-style. 94 val = "[" + val + "]"; 95 } 96 } 97 ll.add(val); 98 if (--maxvalues == 0) { 99 break; 100 } 101 } 102 if (--maxkeywords == 0) { 103 break; 104 } 105 } 106 in.close(); 107 } catch (IOException ioe) { 108 // problem reading value 109 } 110 111 return ll; 112 } 113 114 private LinkedList<String> searchlist; 115 private LinkedList<String> nameservers; 116 117 118 // Load DNS configuration from OS 119 120 private void loadConfig() { 121 assert Thread.holdsLock(lock); 122 123 // check if cached settings have expired. 124 if (lastRefresh >= 0) { 125 long currTime = System.currentTimeMillis(); 126 if ((currTime - lastRefresh) < TIMEOUT) { 127 return; 128 } 129 } 130 131 // get the name servers from /etc/resolv.conf 132 nameservers = 133 java.security.AccessController.doPrivileged( 134 new java.security.PrivilegedAction<LinkedList<String>>() { 135 public LinkedList<String> run() { 136 // typically MAXNS is 3 but we've picked 5 here 137 // to allow for additional servers if required. 138 return resolvconf("nameserver", 1, 5); 139 } /* run */ 140 }); 141 142 // get the search list (or domain) 143 searchlist = getSearchList(); 144 145 // update the timestamp on the configuration 146 lastRefresh = System.currentTimeMillis(); 147 } 148 149 150 // obtain search list or local domain 151 152 private LinkedList<String> getSearchList() { 153 154 LinkedList<String> sl; 155 156 // first try the search keyword in /etc/resolv.conf 157 158 sl = java.security.AccessController.doPrivileged( 159 new java.security.PrivilegedAction<LinkedList<String>>() { 160 public LinkedList<String> run() { 161 LinkedList<String> ll; 162 163 // first try search keyword (max 6 domains) 164 ll = resolvconf("search", 6, 1); 165 if (ll.size() > 0) { 166 return ll; 167 } 168 169 return null; 170 171 } /* run */ 172 173 }); 174 if (sl != null) { 175 return sl; 176 } 177 178 // No search keyword so use local domain 179 180 181 // LOCALDOMAIN has absolute priority on Solaris 182 183 String localDomain = localDomain0(); 184 if (localDomain != null && localDomain.length() > 0) { 185 sl = new LinkedList<String>(); 186 sl.add(localDomain); 187 return sl; 188 } 189 190 // try domain keyword in /etc/resolv.conf 191 192 sl = java.security.AccessController.doPrivileged( 193 new java.security.PrivilegedAction<LinkedList<String>>() { 194 public LinkedList<String> run() { 195 LinkedList<String> ll; 196 197 ll = resolvconf("domain", 1, 1); 198 if (ll.size() > 0) { 199 return ll; 200 } 201 return null; 202 203 } /* run */ 204 }); 205 if (sl != null) { 206 return sl; 207 } 208 209 // no local domain so try fallback (RPC) domain or 210 // hostName 211 212 sl = new LinkedList<>(); 213 String domain = fallbackDomain0(); 214 if (domain != null && domain.length() > 0) { 215 sl.add(domain); 216 } 217 218 return sl; 219 } 220 221 222 // ---- 223 224 ResolverConfigurationImpl() { 225 opts = new OptionsImpl(); 226 } 227 228 @SuppressWarnings("unchecked") 229 public List<String> searchlist() { 230 synchronized (lock) { 231 loadConfig(); 232 233 // List is mutable so return a shallow copy 234 return (List<String>)searchlist.clone(); 235 } 236 } 237 238 @SuppressWarnings("unchecked") 239 public List<String> nameservers() { 240 synchronized (lock) { 241 loadConfig(); 242 243 // List is mutable so return a shallow copy 244 245 return (List<String>)nameservers.clone(); 246 247 } 248 } 249 250 public Options options() { 251 return opts; 252 } 253 254 255 // --- Native methods -- 256 257 static native String localDomain0(); 258 259 static native String fallbackDomain0(); 260 261 static { 262 java.security.AccessController.doPrivileged( 263 new java.security.PrivilegedAction<Void>() { 264 public Void run() { 265 System.loadLibrary("net"); 266 return null; 267 } 268 }); 269 } 270 271 } 272 273 /** 274 * Implementation of {@link ResolverConfiguration.Options} 275 */ 276 class OptionsImpl extends ResolverConfiguration.Options { 277 }