aboutsummaryrefslogtreecommitdiff
path: root/src/org/xbill/DNS/ResolverConfig.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/xbill/DNS/ResolverConfig.java')
-rw-r--r--src/org/xbill/DNS/ResolverConfig.java509
1 files changed, 509 insertions, 0 deletions
diff --git a/src/org/xbill/DNS/ResolverConfig.java b/src/org/xbill/DNS/ResolverConfig.java
new file mode 100644
index 0000000..7b09daf
--- /dev/null
+++ b/src/org/xbill/DNS/ResolverConfig.java
@@ -0,0 +1,509 @@
+// 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() {
+ if (findProperty())
+ return;
+ if (findSunJVM())
+ return;
+ if (servers == null || searchlist == null) {
+ String OS = System.getProperty("os.name");
+ String vendor = System.getProperty("java.vendor");
+ if (OS.indexOf("Windows") != -1) {
+ if (OS.indexOf("95") != -1 ||
+ OS.indexOf("98") != -1 ||
+ OS.indexOf("ME") != -1)
+ find95();
+ else
+ findNT();
+ } else if (OS.indexOf("NetWare") != -1) {
+ findNetware();
+ } else if (vendor.indexOf("Android") != -1) {
+ findAndroid();
+ } else {
+ findUnix();
+ }
+ }
+}
+
+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 (servers == null && lserver.size() > 0)
+ servers = (String []) lserver.toArray(new String[0]);
+ if (searchlist == null && lsearch.size() > 0)
+ searchlist = (Name []) lsearch.toArray(new Name[0]);
+}
+
+private void
+configureNdots(int lndots) {
+ if (ndots < 0 && lndots > 0)
+ ndots = lndots;
+}
+
+/**
+ * Looks in the system properties to find servers and a search path.
+ * Servers are defined by dns.server=server1,server2...
+ * The search path is defined by dns.search=domain1,domain2...
+ */
+private boolean
+findProperty() {
+ String prop;
+ List lserver = new ArrayList(0);
+ List lsearch = new ArrayList(0);
+ StringTokenizer st;
+
+ prop = System.getProperty("dns.server");
+ if (prop != null) {
+ st = new StringTokenizer(prop, ",");
+ while (st.hasMoreTokens())
+ addServer(st.nextToken(), lserver);
+ }
+
+ prop = System.getProperty("dns.search");
+ if (prop != null) {
+ st = new StringTokenizer(prop, ",");
+ while (st.hasMoreTokens())
+ addSearch(st.nextToken(), lsearch);
+ }
+ configureFromLists(lserver, lsearch);
+ return (servers != null && searchlist != null);
+}
+
+/**
+ * Uses the undocumented Sun DNS implementation to determine the configuration.
+ * This doesn't work or even compile with all JVMs (gcj, for example).
+ */
+private boolean
+findSunJVM() {
+ List lserver = new ArrayList(0);
+ List lserver_tmp;
+ List lsearch = new ArrayList(0);
+ List lsearch_tmp;
+
+ try {
+ Class [] noClasses = new Class[0];
+ Object [] noObjects = new Object[0];
+ String resConfName = "sun.net.dns.ResolverConfiguration";
+ Class resConfClass = Class.forName(resConfName);
+ Object resConf;
+
+ // ResolverConfiguration resConf = ResolverConfiguration.open();
+ Method open = resConfClass.getDeclaredMethod("open", noClasses);
+ resConf = open.invoke(null, noObjects);
+
+ // lserver_tmp = resConf.nameservers();
+ Method nameservers = resConfClass.getMethod("nameservers",
+ noClasses);
+ lserver_tmp = (List) nameservers.invoke(resConf, noObjects);
+
+ // lsearch_tmp = resConf.searchlist();
+ Method searchlist = resConfClass.getMethod("searchlist",
+ noClasses);
+ lsearch_tmp = (List) searchlist.invoke(resConf, noObjects);
+ }
+ catch (Exception e) {
+ return false;
+ }
+
+ if (lserver_tmp.size() == 0)
+ return false;
+
+ if (lserver_tmp.size() > 0) {
+ Iterator it = lserver_tmp.iterator();
+ while (it.hasNext())
+ addServer((String) it.next(), lserver);
+ }
+
+ if (lsearch_tmp.size() > 0) {
+ Iterator it = lsearch_tmp.iterator();
+ while (it.hasNext())
+ addSearch((String) it.next(), lsearch);
+ }
+ configureFromLists(lserver, lsearch);
+ return true;
+}
+
+/**
+ * Looks in /etc/resolv.conf to find servers and a search path.
+ * "nameserver" lines specify servers. "domain" and "search" lines
+ * define the search path.
+ */
+private void
+findResolvConf(String file) {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ }
+ catch (FileNotFoundException e) {
+ return;
+ }
+ InputStreamReader isr = new InputStreamReader(in);
+ BufferedReader br = new BufferedReader(isr);
+ List lserver = new ArrayList(0);
+ List lsearch = new ArrayList(0);
+ int lndots = -1;
+ try {
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (line.startsWith("nameserver")) {
+ StringTokenizer st = new StringTokenizer(line);
+ st.nextToken(); /* skip nameserver */
+ addServer(st.nextToken(), lserver);
+ }
+ else if (line.startsWith("domain")) {
+ StringTokenizer st = new StringTokenizer(line);
+ st.nextToken(); /* skip domain */
+ if (!st.hasMoreTokens())
+ continue;
+ if (lsearch.isEmpty())
+ addSearch(st.nextToken(), lsearch);
+ }
+ else if (line.startsWith("search")) {
+ if (!lsearch.isEmpty())
+ lsearch.clear();
+ StringTokenizer st = new StringTokenizer(line);
+ st.nextToken(); /* skip search */
+ while (st.hasMoreTokens())
+ addSearch(st.nextToken(), lsearch);
+ }
+ else if(line.startsWith("options")) {
+ StringTokenizer st = new StringTokenizer(line);
+ st.nextToken(); /* skip options */
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+ if (token.startsWith("ndots:")) {
+ lndots = parseNdots(token);
+ }
+ }
+ }
+ }
+ br.close();
+ }
+ catch (IOException e) {
+ }
+
+ configureFromLists(lserver, lsearch);
+ configureNdots(lndots);
+}
+
+private void
+findUnix() {
+ findResolvConf("/etc/resolv.conf");
+}
+
+private void
+findNetware() {
+ findResolvConf("sys:/etc/resolv.cfg");
+}
+
+/**
+ * Parses the output of winipcfg or ipconfig.
+ */
+private void
+findWin(InputStream in, Locale locale) {
+ String packageName = ResolverConfig.class.getPackage().getName();
+ String resPackageName = packageName + ".windows.DNSServer";
+ ResourceBundle res;
+ if (locale != null)
+ res = ResourceBundle.getBundle(resPackageName, locale);
+ else
+ res = ResourceBundle.getBundle(resPackageName);
+
+ String host_name = res.getString("host_name");
+ String primary_dns_suffix = res.getString("primary_dns_suffix");
+ String dns_suffix = res.getString("dns_suffix");
+ String dns_servers = res.getString("dns_servers");
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ try {
+ List lserver = new ArrayList();
+ List lsearch = new ArrayList();
+ String line = null;
+ boolean readingServers = false;
+ boolean readingSearches = false;
+ while ((line = br.readLine()) != null) {
+ StringTokenizer st = new StringTokenizer(line);
+ if (!st.hasMoreTokens()) {
+ readingServers = false;
+ readingSearches = false;
+ continue;
+ }
+ String s = st.nextToken();
+ if (line.indexOf(":") != -1) {
+ readingServers = false;
+ readingSearches = false;
+ }
+
+ if (line.indexOf(host_name) != -1) {
+ while (st.hasMoreTokens())
+ s = st.nextToken();
+ Name name;
+ try {
+ name = Name.fromString(s, null);
+ }
+ catch (TextParseException e) {
+ continue;
+ }
+ if (name.labels() == 1)
+ continue;
+ addSearch(s, lsearch);
+ } else if (line.indexOf(primary_dns_suffix) != -1) {
+ while (st.hasMoreTokens())
+ s = st.nextToken();
+ if (s.equals(":"))
+ continue;
+ addSearch(s, lsearch);
+ readingSearches = true;
+ } else if (readingSearches ||
+ line.indexOf(dns_suffix) != -1)
+ {
+ while (st.hasMoreTokens())
+ s = st.nextToken();
+ if (s.equals(":"))
+ continue;
+ addSearch(s, lsearch);
+ readingSearches = true;
+ } else if (readingServers ||
+ line.indexOf(dns_servers) != -1)
+ {
+ while (st.hasMoreTokens())
+ s = st.nextToken();
+ if (s.equals(":"))
+ continue;
+ addServer(s, lserver);
+ readingServers = true;
+ }
+ }
+
+ configureFromLists(lserver, lsearch);
+ }
+ catch (IOException e) {
+ }
+ return;
+}
+
+private void
+findWin(InputStream in) {
+ String property = "org.xbill.DNS.windows.parse.buffer";
+ final int defaultBufSize = 8 * 1024;
+ int bufSize = Integer.getInteger(property, defaultBufSize).intValue();
+ BufferedInputStream b = new BufferedInputStream(in, bufSize);
+ b.mark(bufSize);
+ findWin(b, null);
+ if (servers == null) {
+ try {
+ b.reset();
+ }
+ catch (IOException e) {
+ return;
+ }
+ findWin(b, new Locale("", ""));
+ }
+}
+
+/**
+ * Calls winipcfg and parses the result to find servers and a search path.
+ */
+private void
+find95() {
+ String s = "winipcfg.out";
+ try {
+ Process p;
+ p = Runtime.getRuntime().exec("winipcfg /all /batch " + s);
+ p.waitFor();
+ File f = new File(s);
+ findWin(new FileInputStream(f));
+ new File(s).delete();
+ }
+ catch (Exception e) {
+ return;
+ }
+}
+
+/**
+ * Calls ipconfig and parses the result to find servers and a search path.
+ */
+private void
+findNT() {
+ try {
+ Process p;
+ p = Runtime.getRuntime().exec("ipconfig /all");
+ findWin(p.getInputStream());
+ p.destroy();
+ }
+ catch (Exception e) {
+ return;
+ }
+}
+
+/**
+ * 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;
+ }
+}
+
+}