/* |
|
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
package com.sun.jndi.dns; |
|
import javax.naming.*; |
|
/** |
|
* The Resolver class performs DNS client operations in support of DnsContext. |
|
* |
|
* <p> Every DnsName instance passed to or returned from a method of |
|
* this class should be fully-qualified and contain a root label (an |
|
* empty component at position 0). |
|
* |
|
* @author Scott Seligman |
|
*/ |
|
class Resolver { |
|
private DnsClient dnsClient; |
|
private int timeout; // initial timeout on UDP queries in ms |
|
private int retries; // number of UDP retries |
|
/* |
|
* Constructs a new Resolver given its servers and timeout parameters. |
|
* Each server is of the form "server[:port]". |
|
* IPv6 literal host names include delimiting brackets. |
|
* There must be at least one server. |
|
* "timeout" is the initial timeout interval (in ms) for UDP queries, |
|
* and "retries" gives the number of retries per server. |
|
*/ |
|
Resolver(String[] servers, int timeout, int retries) |
|
throws NamingException { |
|
this.timeout = timeout; |
|
this.retries = retries; |
|
dnsClient = new DnsClient(servers, timeout, retries); |
|
} |
|
public void close() { |
|
dnsClient.close(); |
|
dnsClient = null; |
|
} |
|
/* |
|
* Queries resource records of a particular class and type for a |
|
* given domain name. |
|
* Useful values of rrclass are ResourceRecord.[Q]CLASS_xxx. |
|
* Useful values of rrtype are ResourceRecord.[Q]TYPE_xxx. |
|
* If recursion is true, recursion is requested on the query. |
|
* If auth is true, only authoritative responses are accepted. |
|
*/ |
|
ResourceRecords query(DnsName fqdn, int rrclass, int rrtype, |
|
boolean recursion, boolean auth) |
|
throws NamingException { |
|
return dnsClient.query(fqdn, rrclass, rrtype, recursion, auth); |
|
} |
|
/* |
|
* Queries all resource records of a zone given its domain name and class. |
|
* If recursion is true, recursion is requested on the query to find |
|
* the name server (and also on the zone transfer, but it won't matter). |
|
*/ |
|
ResourceRecords queryZone(DnsName zone, int rrclass, boolean recursion) |
|
throws NamingException { |
|
DnsClient cl = |
|
new DnsClient(findNameServers(zone, recursion), timeout, retries); |
|
try { |
|
return cl.queryZone(zone, rrclass, recursion); |
|
} finally { |
|
cl.close(); |
|
} |
|
} |
|
/* |
|
* Finds the zone of a given domain name. The method is to look |
|
* for the first SOA record on the path from the given domain to |
|
* the root. This search may be partially bypassed if the zone's |
|
* SOA record is received in the authority section of a response. |
|
* If recursion is true, recursion is requested on any queries. |
|
*/ |
|
DnsName findZoneName(DnsName fqdn, int rrclass, boolean recursion) |
|
throws NamingException { |
|
fqdn = (DnsName) fqdn.clone(); |
|
while (fqdn.size() > 1) { // while below root |
|
ResourceRecords rrs = null; |
|
try { |
|
rrs = query(fqdn, rrclass, ResourceRecord.TYPE_SOA, |
|
recursion, false); |
|
} catch (NameNotFoundException e) { |
|
throw e; |
|
} catch (NamingException e) { |
|
// Ignore error and keep searching up the tree. |
|
} |
|
if (rrs != null) { |
|
if (rrs.answer.size() > 0) { // found zone's SOA |
|
return fqdn; |
|
} |
|
// Look for an SOA record giving the zone's top node. |
|
for (int i = 0; i < rrs.authority.size(); i++) { |
|
ResourceRecord rr = rrs.authority.elementAt(i); |
|
if (rr.getType() == ResourceRecord.TYPE_SOA) { |
|
DnsName zone = rr.getName(); |
|
if (fqdn.endsWith(zone)) { |
|
return zone; |
|
} |
|
} |
|
} |
|
} |
|
fqdn.remove(fqdn.size() - 1); // one step rootward |
|
} |
|
return fqdn; // no SOA found below root, so |
|
// return root |
|
} |
|
/* |
|
* Finds a zone's SOA record. Returns null if no SOA is found (in |
|
* which case "zone" is not actually a zone). |
|
* If recursion is true, recursion is requested on the query. |
|
*/ |
|
ResourceRecord findSoa(DnsName zone, int rrclass, boolean recursion) |
|
throws NamingException { |
|
ResourceRecords rrs = query(zone, rrclass, ResourceRecord.TYPE_SOA, |
|
recursion, false); |
|
for (int i = 0; i < rrs.answer.size(); i++) { |
|
ResourceRecord rr = rrs.answer.elementAt(i); |
|
if (rr.getType() == ResourceRecord.TYPE_SOA) { |
|
return rr; |
|
} |
|
} |
|
return null; |
|
} |
|
/* |
|
* Finds the name servers of a zone. <tt>zone</tt> is a fully-qualified |
|
* domain name at the top of a zone. |
|
* If recursion is true, recursion is requested on the query. |
|
*/ |
|
private String[] findNameServers(DnsName zone, boolean recursion) |
|
throws NamingException { |
|
// %%% As an optimization, could look in authority section of |
|
// findZoneName() response first. |
|
ResourceRecords rrs = |
|
query(zone, ResourceRecord.CLASS_INTERNET, ResourceRecord.TYPE_NS, |
|
recursion, false); |
|
String[] ns = new String[rrs.answer.size()]; |
|
for (int i = 0; i < ns.length; i++) { |
|
ResourceRecord rr = rrs.answer.elementAt(i); |
|
if (rr.getType() != ResourceRecord.TYPE_NS) { |
|
throw new CommunicationException("Corrupted DNS message"); |
|
} |
|
ns[i] = (String) rr.getRdata(); |
|
// Server name will be passed to InetAddress.getByName(), which |
|
// may not be able to handle a trailing dot. |
|
// assert ns[i].endsWith("."); |
|
ns[i] = ns[i].substring(0, ns[i].length() - 1); |
|
} |
|
return ns; |
|
} |
|
} |