PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/xbill/DNS/ResolverConfig.java

https://bitbucket.org/Trugath/xabber
Java | 540 lines | 417 code | 45 blank | 78 comment | 106 complexity | 2a98e227a1e44fb4a2493c059ebc9125 MD5 | raw file
  1. // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
  2. package org.xbill.DNS;
  3. import java.io.*;
  4. import java.lang.reflect.*;
  5. import java.util.*;
  6. /**
  7. * A class that tries to locate name servers and the search path to
  8. * be appended to unqualified names.
  9. *
  10. * The following are attempted, in order, until one succeeds.
  11. * <UL>
  12. * <LI>The properties 'dns.server' and 'dns.search' (comma delimited lists)
  13. * are checked. The servers can either be IP addresses or hostnames
  14. * (which are resolved using Java's built in DNS support).
  15. * <LI>The sun.net.dns.ResolverConfiguration class is queried.
  16. * <LI>On Unix, /etc/resolv.conf is parsed.
  17. * <LI>On Windows, ipconfig/winipcfg is called and its output parsed. This
  18. * may fail for non-English versions on Windows.
  19. * <LI>"localhost" is used as the nameserver, and the search path is empty.
  20. * </UL>
  21. *
  22. * These routines will be called internally when creating Resolvers/Lookups
  23. * without explicitly specifying server names, and can also be called
  24. * directly if desired.
  25. *
  26. * @author Brian Wellington
  27. * @author <a href="mailto:yannick@meudal.net">Yannick Meudal</a>
  28. * @author <a href="mailto:arnt@gulbrandsen.priv.no">Arnt Gulbrandsen</a>
  29. */
  30. public class ResolverConfig {
  31. private String [] servers = null;
  32. private Name [] searchlist = null;
  33. private int ndots = -1;
  34. private static ResolverConfig currentConfig;
  35. static {
  36. refresh();
  37. }
  38. public
  39. ResolverConfig() {
  40. if (findProperty())
  41. return;
  42. if (findSunJVM())
  43. return;
  44. if (servers == null || searchlist == null) {
  45. String OS = System.getProperty("os.name");
  46. String vendor = System.getProperty("java.vendor");
  47. if (OS.indexOf("Windows") != -1) {
  48. if (OS.indexOf("95") != -1 ||
  49. OS.indexOf("98") != -1 ||
  50. OS.indexOf("ME") != -1)
  51. find95();
  52. else
  53. findNT();
  54. } else if (OS.indexOf("NetWare") != -1) {
  55. findNetware();
  56. } else if (vendor.indexOf("Android") != -1) {
  57. if (findAndroidProp())
  58. return;
  59. findAndroid();
  60. } else {
  61. findUnix();
  62. }
  63. }
  64. }
  65. private void
  66. addServer(String server, List list) {
  67. if (list.contains(server))
  68. return;
  69. if (Options.check("verbose"))
  70. System.out.println("adding server " + server);
  71. list.add(server);
  72. }
  73. private void
  74. addSearch(String search, List list) {
  75. Name name;
  76. if (Options.check("verbose"))
  77. System.out.println("adding search " + search);
  78. try {
  79. name = Name.fromString(search, Name.root);
  80. }
  81. catch (TextParseException e) {
  82. return;
  83. }
  84. if (list.contains(name))
  85. return;
  86. list.add(name);
  87. }
  88. private int
  89. parseNdots(String token) {
  90. token = token.substring(6);
  91. try {
  92. int ndots = Integer.parseInt(token);
  93. if (ndots >= 0) {
  94. if (Options.check("verbose"))
  95. System.out.println("setting ndots " + token);
  96. return ndots;
  97. }
  98. }
  99. catch (NumberFormatException e) {
  100. }
  101. return -1;
  102. }
  103. private void
  104. configureFromLists(List lserver, List lsearch) {
  105. if (servers == null && lserver.size() > 0)
  106. servers = (String []) lserver.toArray(new String[0]);
  107. if (searchlist == null && lsearch.size() > 0)
  108. searchlist = (Name []) lsearch.toArray(new Name[0]);
  109. }
  110. private void
  111. configureNdots(int lndots) {
  112. if (ndots < 0 && lndots > 0)
  113. ndots = lndots;
  114. }
  115. /**
  116. * Looks in the system properties to find servers and a search path.
  117. * Servers are defined by dns.server=server1,server2...
  118. * The search path is defined by dns.search=domain1,domain2...
  119. */
  120. private boolean
  121. findProperty() {
  122. String prop;
  123. List lserver = new ArrayList(0);
  124. List lsearch = new ArrayList(0);
  125. StringTokenizer st;
  126. prop = System.getProperty("dns.server");
  127. if (prop != null) {
  128. st = new StringTokenizer(prop, ",");
  129. while (st.hasMoreTokens())
  130. addServer(st.nextToken(), lserver);
  131. }
  132. prop = System.getProperty("dns.search");
  133. if (prop != null) {
  134. st = new StringTokenizer(prop, ",");
  135. while (st.hasMoreTokens())
  136. addSearch(st.nextToken(), lsearch);
  137. }
  138. configureFromLists(lserver, lsearch);
  139. return (servers != null && searchlist != null);
  140. }
  141. /**
  142. * Uses the undocumented Sun DNS implementation to determine the configuration.
  143. * This doesn't work or even compile with all JVMs (gcj, for example).
  144. */
  145. private boolean
  146. findSunJVM() {
  147. List lserver = new ArrayList(0);
  148. List lserver_tmp;
  149. List lsearch = new ArrayList(0);
  150. List lsearch_tmp;
  151. try {
  152. Class [] noClasses = new Class[0];
  153. Object [] noObjects = new Object[0];
  154. String resConfName = "sun.net.dns.ResolverConfiguration";
  155. Class resConfClass = Class.forName(resConfName);
  156. Object resConf;
  157. // ResolverConfiguration resConf = ResolverConfiguration.open();
  158. Method open = resConfClass.getDeclaredMethod("open", noClasses);
  159. resConf = open.invoke(null, noObjects);
  160. // lserver_tmp = resConf.nameservers();
  161. Method nameservers = resConfClass.getMethod("nameservers",
  162. noClasses);
  163. lserver_tmp = (List) nameservers.invoke(resConf, noObjects);
  164. // lsearch_tmp = resConf.searchlist();
  165. Method searchlist = resConfClass.getMethod("searchlist",
  166. noClasses);
  167. lsearch_tmp = (List) searchlist.invoke(resConf, noObjects);
  168. }
  169. catch (Exception e) {
  170. return false;
  171. }
  172. if (lserver_tmp.size() == 0)
  173. return false;
  174. if (lserver_tmp.size() > 0) {
  175. Iterator it = lserver_tmp.iterator();
  176. while (it.hasNext())
  177. addServer((String) it.next(), lserver);
  178. }
  179. if (lsearch_tmp.size() > 0) {
  180. Iterator it = lsearch_tmp.iterator();
  181. while (it.hasNext())
  182. addSearch((String) it.next(), lsearch);
  183. }
  184. configureFromLists(lserver, lsearch);
  185. return true;
  186. }
  187. /**
  188. * Looks in /etc/resolv.conf to find servers and a search path.
  189. * "nameserver" lines specify servers. "domain" and "search" lines
  190. * define the search path.
  191. */
  192. private void
  193. findResolvConf(String file) {
  194. InputStream in = null;
  195. try {
  196. in = new FileInputStream(file);
  197. }
  198. catch (FileNotFoundException e) {
  199. return;
  200. }
  201. InputStreamReader isr = new InputStreamReader(in);
  202. BufferedReader br = new BufferedReader(isr);
  203. List lserver = new ArrayList(0);
  204. List lsearch = new ArrayList(0);
  205. int lndots = -1;
  206. try {
  207. String line;
  208. while ((line = br.readLine()) != null) {
  209. if (line.startsWith("nameserver")) {
  210. StringTokenizer st = new StringTokenizer(line);
  211. st.nextToken(); /* skip nameserver */
  212. addServer(st.nextToken(), lserver);
  213. }
  214. else if (line.startsWith("domain")) {
  215. StringTokenizer st = new StringTokenizer(line);
  216. st.nextToken(); /* skip domain */
  217. if (!st.hasMoreTokens())
  218. continue;
  219. if (lsearch.isEmpty())
  220. addSearch(st.nextToken(), lsearch);
  221. }
  222. else if (line.startsWith("search")) {
  223. if (!lsearch.isEmpty())
  224. lsearch.clear();
  225. StringTokenizer st = new StringTokenizer(line);
  226. st.nextToken(); /* skip search */
  227. while (st.hasMoreTokens())
  228. addSearch(st.nextToken(), lsearch);
  229. }
  230. else if(line.startsWith("options")) {
  231. StringTokenizer st = new StringTokenizer(line);
  232. st.nextToken(); /* skip options */
  233. while (st.hasMoreTokens()) {
  234. String token = st.nextToken();
  235. if (token.startsWith("ndots:")) {
  236. lndots = parseNdots(token);
  237. }
  238. }
  239. }
  240. }
  241. br.close();
  242. }
  243. catch (IOException e) {
  244. }
  245. configureFromLists(lserver, lsearch);
  246. configureNdots(lndots);
  247. }
  248. private void
  249. findUnix() {
  250. findResolvConf("/etc/resolv.conf");
  251. }
  252. private void
  253. findNetware() {
  254. findResolvConf("sys:/etc/resolv.cfg");
  255. }
  256. /**
  257. * Parses the output of winipcfg or ipconfig.
  258. */
  259. private void
  260. findWin(InputStream in, Locale locale) {
  261. String packageName = ResolverConfig.class.getPackage().getName();
  262. String resPackageName = packageName + ".windows.DNSServer";
  263. ResourceBundle res;
  264. if (locale != null)
  265. res = ResourceBundle.getBundle(resPackageName, locale);
  266. else
  267. res = ResourceBundle.getBundle(resPackageName);
  268. String host_name = res.getString("host_name");
  269. String primary_dns_suffix = res.getString("primary_dns_suffix");
  270. String dns_suffix = res.getString("dns_suffix");
  271. String dns_servers = res.getString("dns_servers");
  272. BufferedReader br = new BufferedReader(new InputStreamReader(in));
  273. try {
  274. List lserver = new ArrayList();
  275. List lsearch = new ArrayList();
  276. String line = null;
  277. boolean readingServers = false;
  278. boolean readingSearches = false;
  279. while ((line = br.readLine()) != null) {
  280. StringTokenizer st = new StringTokenizer(line);
  281. if (!st.hasMoreTokens()) {
  282. readingServers = false;
  283. readingSearches = false;
  284. continue;
  285. }
  286. String s = st.nextToken();
  287. if (line.indexOf(":") != -1) {
  288. readingServers = false;
  289. readingSearches = false;
  290. }
  291. if (line.indexOf(host_name) != -1) {
  292. while (st.hasMoreTokens())
  293. s = st.nextToken();
  294. Name name;
  295. try {
  296. name = Name.fromString(s, null);
  297. }
  298. catch (TextParseException e) {
  299. continue;
  300. }
  301. if (name.labels() == 1)
  302. continue;
  303. addSearch(s, lsearch);
  304. } else if (line.indexOf(primary_dns_suffix) != -1) {
  305. while (st.hasMoreTokens())
  306. s = st.nextToken();
  307. if (s.equals(":"))
  308. continue;
  309. addSearch(s, lsearch);
  310. readingSearches = true;
  311. } else if (readingSearches ||
  312. line.indexOf(dns_suffix) != -1)
  313. {
  314. while (st.hasMoreTokens())
  315. s = st.nextToken();
  316. if (s.equals(":"))
  317. continue;
  318. addSearch(s, lsearch);
  319. readingSearches = true;
  320. } else if (readingServers ||
  321. line.indexOf(dns_servers) != -1)
  322. {
  323. while (st.hasMoreTokens())
  324. s = st.nextToken();
  325. if (s.equals(":"))
  326. continue;
  327. addServer(s, lserver);
  328. readingServers = true;
  329. }
  330. }
  331. configureFromLists(lserver, lsearch);
  332. }
  333. catch (IOException e) {
  334. }
  335. return;
  336. }
  337. private void
  338. findWin(InputStream in) {
  339. String property = "org.xbill.DNS.windows.parse.buffer";
  340. final int defaultBufSize = 8 * 1024;
  341. int bufSize = Integer.getInteger(property, defaultBufSize).intValue();
  342. BufferedInputStream b = new BufferedInputStream(in, bufSize);
  343. b.mark(bufSize);
  344. findWin(b, null);
  345. if (servers == null) {
  346. try {
  347. b.reset();
  348. }
  349. catch (IOException e) {
  350. return;
  351. }
  352. findWin(b, new Locale("", ""));
  353. }
  354. }
  355. /**
  356. * Calls winipcfg and parses the result to find servers and a search path.
  357. */
  358. private void
  359. find95() {
  360. String s = "winipcfg.out";
  361. try {
  362. Process p;
  363. p = Runtime.getRuntime().exec("winipcfg /all /batch " + s);
  364. p.waitFor();
  365. File f = new File(s);
  366. findWin(new FileInputStream(f));
  367. new File(s).delete();
  368. }
  369. catch (Exception e) {
  370. return;
  371. }
  372. }
  373. /**
  374. * Calls ipconfig and parses the result to find servers and a search path.
  375. */
  376. private void
  377. findNT() {
  378. try {
  379. Process p;
  380. p = Runtime.getRuntime().exec("ipconfig /all");
  381. findWin(p.getInputStream());
  382. p.destroy();
  383. }
  384. catch (Exception e) {
  385. return;
  386. }
  387. }
  388. /**
  389. * Directly access to the system properties using native functions in order
  390. * to avoid application freeze on system call. Related bug in Bionic was
  391. * fixed but still wasn't released in Android 4.0.4:
  392. * https://github.com/android/platform_bionic/commit/177ba8cb42ed6d232e7c8bcad5e6ee21fc51a0e8#libc/bionic
  393. */
  394. private boolean findAndroidProp() {
  395. try {
  396. Class<?> SystemProperties = Class
  397. .forName("android.os.SystemProperties");
  398. Method method = SystemProperties.getMethod("get",
  399. new Class[] { String.class });
  400. ArrayList lserver = new ArrayList();
  401. ArrayList lsearch = new ArrayList();
  402. for (String name : new String[] { "net.dns", "net.dns1",
  403. "net.dns2", "net.dns3", "net.dns4", }) {
  404. String value = (String) method.invoke(null, name);
  405. if (value == null || "".equals(value) || lserver.contains(value))
  406. continue;
  407. lserver.add(value);
  408. }
  409. configureFromLists(lserver, lsearch);
  410. } catch (Exception e) {
  411. e.printStackTrace();
  412. return false;
  413. }
  414. return true;
  415. }
  416. /**
  417. * Parses the output of getprop, which is the only way to get DNS
  418. * info on Android. getprop might disappear in future releases, so
  419. * this code comes with a use-by date.
  420. */
  421. private void
  422. findAndroid() {
  423. // This originally looked for all lines containing .dns; but
  424. // http://code.google.com/p/android/issues/detail?id=2207#c73
  425. // indicates that net.dns* should always be the active nameservers, so
  426. // we use those.
  427. String re1 = "^\\d+(\\.\\d+){3}$";
  428. String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$";
  429. try {
  430. ArrayList lserver = new ArrayList();
  431. ArrayList lsearch = new ArrayList();
  432. String line;
  433. Process p = Runtime.getRuntime().exec("getprop");
  434. InputStream in = p.getInputStream();
  435. InputStreamReader isr = new InputStreamReader(in);
  436. BufferedReader br = new BufferedReader(isr);
  437. while ((line = br.readLine()) != null ) {
  438. StringTokenizer t = new StringTokenizer(line, ":");
  439. String name = t.nextToken();
  440. if (name.indexOf( "net.dns" ) > -1) {
  441. String v = t.nextToken();
  442. v = v.replaceAll("[ \\[\\]]", "");
  443. if ((v.matches(re1) || v.matches(re2)) &&
  444. !lserver.contains(v))
  445. lserver.add(v);
  446. }
  447. }
  448. configureFromLists(lserver, lsearch);
  449. } catch ( Exception e ) {
  450. // ignore resolutely
  451. }
  452. }
  453. /** Returns all located servers */
  454. public String []
  455. servers() {
  456. return servers;
  457. }
  458. /** Returns the first located server */
  459. public String
  460. server() {
  461. if (servers == null)
  462. return null;
  463. return servers[0];
  464. }
  465. /** Returns all entries in the located search path */
  466. public Name []
  467. searchPath() {
  468. return searchlist;
  469. }
  470. /**
  471. * Returns the located ndots value, or the default (1) if not configured.
  472. * Note that ndots can only be configured in a resolv.conf file, and will only
  473. * take effect if ResolverConfig uses resolv.conf directly (that is, if the
  474. * JVM does not include the sun.net.dns.ResolverConfiguration class).
  475. */
  476. public int
  477. ndots() {
  478. if (ndots < 0)
  479. return 1;
  480. return ndots;
  481. }
  482. /** Gets the current configuration */
  483. public static synchronized ResolverConfig
  484. getCurrentConfig() {
  485. return currentConfig;
  486. }
  487. /** Gets the current configuration */
  488. public static void
  489. refresh() {
  490. ResolverConfig newConfig = new ResolverConfig();
  491. synchronized (ResolverConfig.class) {
  492. currentConfig = newConfig;
  493. }
  494. }
  495. }