// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package org.xbill.DNS;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
/**
* A class that tries to locate name servers and the search path to
* be appended to unqualified names.
*
* The following are attempted, in order, until one succeeds.
* <UL>
* <LI>The properties 'dns.server' and 'dns.search' (comma delimited lists)
* are checked. The servers can either be IP addresses or hostnames
* (which are resolved using Java's built in DNS support).
* <LI>The sun.net.dns.ResolverConfiguration class is queried.
* <LI>On Unix, /etc/resolv.conf is parsed.
* <LI>On Windows, ipconfig/winipcfg is called and its output parsed. This
* may fail for non-English versions on Windows.
* <LI>"localhost" is used as the nameserver, and the search path is empty.
* </UL>
*
* These routines will be called internally when creating Resolvers/Lookups
* without explicitly specifying server names, and can also be called
* directly if desired.
*
* @author Brian Wellington
* @author <a href="mailto:yannick@meudal.net">Yannick Meudal</a>
* @author <a href="mailto:arnt@gulbrandsen.priv.no">Arnt Gulbrandsen</a>
*/
public class ResolverConfig {
private String [] servers = null;
private Name [] searchlist = null;
private int ndots = -1;
private static ResolverConfig currentConfig;
static {
refresh();
}
public
ResolverConfig() {
findAndroid();
}
private void
addServer(String server, List list) {
if (list.contains(server))
return;
if (Options.check("verbose"))
System.out.println("adding server " + server);
list.add(server);
}
private void
addSearch(String search, List list) {
Name name;
if (Options.check("verbose"))
System.out.println("adding search " + search);
try {
name = Name.fromString(search, Name.root);
}
catch (TextParseException e) {
return;
}
if (list.contains(name))
return;
list.add(name);
}
private int
parseNdots(String token) {
token = token.substring(6);
try {
int ndots = Integer.parseInt(token);
if (ndots >= 0) {
if (Options.check("verbose"))
System.out.println("setting ndots " + token);
return ndots;
}
}
catch (NumberFormatException e) {
}
return -1;
}
private void
configureFromLists(List lserver, List lsearch) {
if (lserver.size() > 0)
servers = (String []) lserver.toArray(new String[0]);
if (lsearch.size() > 0)
searchlist = (Name []) lsearch.toArray(new Name[0]);
}
private void
configureNdots(int lndots) {
if (ndots < 0 && lndots > 0)
ndots = lndots;
}
/**
* Parses the output of getprop, which is the only way to get DNS
* info on Android. getprop might disappear in future releases, so
* this code comes with a use-by date.
*/
private void
findAndroid() {
// This originally looked for all lines containing .dns; but
// http://code.google.com/p/android/issues/detail?id=2207#c73
// indicates that net.dns* should always be the active nameservers, so
// we use those.
String re1 = "^\\d+(\\.\\d+){3}$";
String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$";
try {
ArrayList lserver = new ArrayList();
ArrayList lsearch = new ArrayList();
String line;
Process p = Runtime.getRuntime().exec("getprop");
InputStream in = p.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null ) {
StringTokenizer t = new StringTokenizer(line, ":");
String name = t.nextToken();
if (name.indexOf( "net.dns" ) > -1) {
String v = t.nextToken();
v = v.replaceAll("[ \\[\\]]", "");
if ((v.matches(re1) || v.matches(re2)) &&
!lserver.contains(v))
lserver.add(v);
}
}
configureFromLists(lserver, lsearch);
} catch ( Exception e ) {
// ignore resolutely
}
}
/** Returns all located servers */
public String []
servers() {
return servers;
}
/** Returns the first located server */
public String
server() {
if (servers == null)
return null;
return servers[0];
}
/** Returns all entries in the located search path */
public Name []
searchPath() {
return searchlist;
}
/**
* Returns the located ndots value, or the default (1) if not configured.
* Note that ndots can only be configured in a resolv.conf file, and will only
* take effect if ResolverConfig uses resolv.conf directly (that is, if the
* JVM does not include the sun.net.dns.ResolverConfiguration class).
*/
public int
ndots() {
if (ndots < 0)
return 1;
return ndots;
}
/** Gets the current configuration */
public static synchronized ResolverConfig
getCurrentConfig() {
return currentConfig;
}
/** Gets the current configuration */
public static void
refresh() {
ResolverConfig newConfig = new ResolverConfig();
synchronized (ResolverConfig.class) {
currentConfig = newConfig;
}
}
}