001: // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS;
004:
005: import java.io.*;
006: import java.lang.reflect.*;
007: import java.util.*;
008:
009: /**
010: * A class that tries to locate name servers and the search path to
011: * be appended to unqualified names.
012: *
013: * The following are attempted, in order, until one succeeds.
014: * <UL>
015: * <LI>The properties 'dns.server' and 'dns.search' (comma delimited lists)
016: * are checked. The servers can either be IP addresses or hostnames
017: * (which are resolved using Java's built in DNS support).
018: * <LI>The sun.net.dns.ResolverConfiguration class is queried.
019: * <LI>On Unix, /etc/resolv.conf is parsed.
020: * <LI>On Windows, ipconfig/winipcfg is called and its output parsed. This
021: * may fail for non-English versions on Windows.
022: * <LI>"localhost" is used as the nameserver, and the search path is empty.
023: * </UL>
024: *
025: * These routines will be called internally when creating Resolvers/Lookups
026: * without explicitly specifying server names, and can also be called
027: * directly if desired.
028: *
029: * @author Brian Wellington
030: * @author <a href="mailto:yannick@meudal.net">Yannick Meudal</a>
031: */
032:
033: public class ResolverConfig {
034:
035: private static String[] servers = null;
036: private static Name[] searchlist = null;
037:
038: private static ResolverConfig currentConfig;
039:
040: static {
041: refresh();
042: }
043:
044: public ResolverConfig() {
045: if (findProperty())
046: return;
047: if (findSunJVM())
048: return;
049: if (servers == null || searchlist == null) {
050: String OS = System.getProperty("os.name");
051: if (OS.indexOf("Windows") != -1) {
052: if (OS.indexOf("95") != -1 || OS.indexOf("98") != -1
053: || OS.indexOf("ME") != -1)
054: find95();
055: else
056: findNT();
057: } else if (OS.indexOf("NetWare") != -1)
058: findNetware();
059: else
060: findUnix();
061: }
062: }
063:
064: private void addServer(String server, List list) {
065: if (list.contains(server))
066: return;
067: if (Options.check("verbose"))
068: System.out.println("adding server " + server);
069: list.add(server);
070: }
071:
072: private void addSearch(String search, List list) {
073: Name name;
074: if (Options.check("verbose"))
075: System.out.println("adding search " + search);
076: try {
077: name = Name.fromString(search, Name.root);
078: } catch (TextParseException e) {
079: return;
080: }
081: if (list.contains(name))
082: return;
083: list.add(name);
084: }
085:
086: private void configureFromLists(List lserver, List lsearch) {
087: if (servers == null && lserver.size() > 0)
088: servers = (String[]) lserver.toArray(new String[0]);
089: if (searchlist == null && lsearch.size() > 0)
090: searchlist = (Name[]) lsearch.toArray(new Name[0]);
091: }
092:
093: /**
094: * Looks in the system properties to find servers and a search path.
095: * Servers are defined by dns.server=server1,server2...
096: * The search path is defined by dns.search=domain1,domain2...
097: */
098: private boolean findProperty() {
099: String s, prop;
100: List lserver = new ArrayList(0);
101: List lsearch = new ArrayList(0);
102: StringTokenizer st;
103:
104: prop = System.getProperty("dns.server");
105: if (prop != null) {
106: st = new StringTokenizer(prop, ",");
107: while (st.hasMoreTokens())
108: addServer(st.nextToken(), lserver);
109: }
110:
111: prop = System.getProperty("dns.search");
112: if (prop != null) {
113: st = new StringTokenizer(prop, ",");
114: while (st.hasMoreTokens())
115: addSearch(st.nextToken(), lsearch);
116: }
117: configureFromLists(lserver, lsearch);
118: return (servers != null && searchlist != null);
119: }
120:
121: /**
122: * Uses the undocumented Sun DNS implementation to determine the configuration.
123: * This doesn't work or even compile with all JVMs (gcj, for example).
124: */
125: private boolean findSunJVM() {
126: List lserver = new ArrayList(0);
127: List lserver_tmp;
128: List lsearch = new ArrayList(0);
129: List lsearch_tmp;
130:
131: try {
132: Class[] noClasses = new Class[0];
133: Object[] noObjects = new Object[0];
134: String resConfName = "sun.net.dns.ResolverConfiguration";
135: Class resConfClass = Class.forName(resConfName);
136: Object resConf;
137:
138: // ResolverConfiguration resConf = ResolverConfiguration.open();
139: Method open = resConfClass.getDeclaredMethod("open",
140: noClasses);
141: resConf = open.invoke(null, noObjects);
142:
143: // lserver_tmp = resConf.nameservers();
144: Method nameservers = resConfClass.getMethod("nameservers",
145: noClasses);
146: lserver_tmp = (List) nameservers.invoke(resConf, noObjects);
147:
148: // lsearch_tmp = resConf.searchlist();
149: Method searchlist = resConfClass.getMethod("searchlist",
150: noClasses);
151: lsearch_tmp = (List) searchlist.invoke(resConf, noObjects);
152: } catch (Exception e) {
153: return false;
154: }
155:
156: if (lserver_tmp.size() > 0) {
157: Iterator it = lserver_tmp.iterator();
158: while (it.hasNext())
159: addServer((String) it.next(), lserver);
160: }
161:
162: if (lsearch_tmp.size() > 0) {
163: Iterator it = lsearch_tmp.iterator();
164: while (it.hasNext())
165: addSearch((String) it.next(), lsearch);
166: }
167: configureFromLists(lserver, lsearch);
168: return true;
169: }
170:
171: /**
172: * Looks in /etc/resolv.conf to find servers and a search path.
173: * "nameserver" lines specify servers. "domain" and "search" lines
174: * define the search path.
175: */
176: private void findResolvConf(String file) {
177: InputStream in = null;
178: try {
179: in = new FileInputStream(file);
180: } catch (FileNotFoundException e) {
181: return;
182: }
183: InputStreamReader isr = new InputStreamReader(in);
184: BufferedReader br = new BufferedReader(isr);
185: List lserver = new ArrayList(0);
186: List lsearch = new ArrayList(0);
187: try {
188: String line;
189: while ((line = br.readLine()) != null) {
190: if (line.startsWith("nameserver")) {
191: StringTokenizer st = new StringTokenizer(line);
192: st.nextToken(); /* skip nameserver */
193: addServer(st.nextToken(), lserver);
194: } else if (line.startsWith("domain")) {
195: StringTokenizer st = new StringTokenizer(line);
196: st.nextToken(); /* skip domain */
197: if (!st.hasMoreTokens())
198: continue;
199: if (lsearch.isEmpty())
200: addSearch(st.nextToken(), lsearch);
201: } else if (line.startsWith("search")) {
202: if (!lsearch.isEmpty())
203: lsearch.clear();
204: StringTokenizer st = new StringTokenizer(line);
205: st.nextToken(); /* skip search */
206: while (st.hasMoreTokens())
207: addSearch(st.nextToken(), lsearch);
208: }
209: }
210: br.close();
211: } catch (IOException e) {
212: }
213:
214: configureFromLists(lserver, lsearch);
215: }
216:
217: private void findUnix() {
218: findResolvConf("/etc/resolv.conf");
219: }
220:
221: private void findNetware() {
222: findResolvConf("sys:/etc/resolv.cfg");
223: }
224:
225: /**
226: * Parses the output of winipcfg or ipconfig.
227: */
228: private void findWin(InputStream in) {
229: String packageName = ResolverConfig.class.getPackage()
230: .getName();
231: String resPackageName = packageName + ".windows.DNSServer";
232: ResourceBundle res = ResourceBundle.getBundle(resPackageName);
233:
234: String host_name = res.getString("host_name");
235: String primary_dns_suffix = res.getString("primary_dns_suffix");
236: String dns_suffix = res.getString("dns_suffix");
237: String dns_servers = res.getString("dns_servers");
238:
239: BufferedReader br = new BufferedReader(
240: new InputStreamReader(in));
241: try {
242: List lserver = new ArrayList();
243: List lsearch = new ArrayList();
244: String line = null;
245: boolean readingServers = false;
246: boolean readingSearches = false;
247: while ((line = br.readLine()) != null) {
248: StringTokenizer st = new StringTokenizer(line);
249: if (!st.hasMoreTokens()) {
250: readingServers = false;
251: readingSearches = false;
252: continue;
253: }
254: String s = st.nextToken();
255: if (line.indexOf(":") != -1) {
256: readingServers = false;
257: readingSearches = false;
258: }
259:
260: if (line.indexOf(host_name) != -1) {
261: while (st.hasMoreTokens())
262: s = st.nextToken();
263: Name name;
264: try {
265: name = Name.fromString(s, null);
266: } catch (TextParseException e) {
267: continue;
268: }
269: if (name.labels() == 1)
270: continue;
271: addSearch(s, lsearch);
272: } else if (line.indexOf(primary_dns_suffix) != -1) {
273: while (st.hasMoreTokens())
274: s = st.nextToken();
275: if (s.equals(":"))
276: continue;
277: addSearch(s, lsearch);
278: readingSearches = true;
279: } else if (readingSearches
280: || line.indexOf(dns_suffix) != -1) {
281: while (st.hasMoreTokens())
282: s = st.nextToken();
283: if (s.equals(":"))
284: continue;
285: addSearch(s, lsearch);
286: readingSearches = true;
287: } else if (readingServers
288: || line.indexOf(dns_servers) != -1) {
289: while (st.hasMoreTokens())
290: s = st.nextToken();
291: if (s.equals(":"))
292: continue;
293: addServer(s, lserver);
294: readingServers = true;
295: }
296: }
297:
298: configureFromLists(lserver, lsearch);
299: } catch (IOException e) {
300: } finally {
301: try {
302: br.close();
303: } catch (IOException e) {
304: }
305: }
306: return;
307: }
308:
309: /**
310: * Calls winipcfg and parses the result to find servers and a search path.
311: */
312: private void find95() {
313: String s = "winipcfg.out";
314: try {
315: Process p;
316: p = Runtime.getRuntime().exec("winipcfg /all /batch " + s);
317: p.waitFor();
318: File f = new File(s);
319: findWin(new FileInputStream(f));
320: new File(s).delete();
321: } catch (Exception e) {
322: return;
323: }
324: }
325:
326: /**
327: * Calls ipconfig and parses the result to find servers and a search path.
328: */
329: private void findNT() {
330: try {
331: Process p;
332: p = Runtime.getRuntime().exec("ipconfig /all");
333: findWin(p.getInputStream());
334: p.destroy();
335: } catch (Exception e) {
336: return;
337: }
338: }
339:
340: /** Returns all located servers */
341: public String[] servers() {
342: return servers;
343: }
344:
345: /** Returns the first located server */
346: public String server() {
347: if (servers == null)
348: return null;
349: return servers[0];
350: }
351:
352: /** Returns all entries in the located search path */
353: public Name[] searchPath() {
354: return searchlist;
355: }
356:
357: /** Gets the current configuration */
358: public static synchronized ResolverConfig getCurrentConfig() {
359: return currentConfig;
360: }
361:
362: /** Gets the current configuration */
363: public static synchronized void refresh() {
364: currentConfig = new ResolverConfig();
365: }
366:
367: }
|