001: /*
002: * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.jndi.dns;
027:
028: import javax.naming.*;
029:
030: /**
031: * The Resolver class performs DNS client operations in support of DnsContext.
032: *
033: * <p> Every DnsName instance passed to or returned from a method of
034: * this class should be fully-qualified and contain a root label (an
035: * empty component at position 0).
036: *
037: * @author Scott Seligman
038: * @version 1.23 07/05/05
039: */
040:
041: class Resolver {
042:
043: private DnsClient dnsClient;
044: private int timeout; // initial timeout on UDP queries in ms
045: private int retries; // number of UDP retries
046:
047: /*
048: * Constructs a new Resolver given its servers and timeout parameters.
049: * Each server is of the form "server[:port]".
050: * IPv6 literal host names include delimiting brackets.
051: * There must be at least one server.
052: * "timeout" is the initial timeout interval (in ms) for UDP queries,
053: * and "retries" gives the number of retries per server.
054: */
055: Resolver(String[] servers, int timeout, int retries)
056: throws NamingException {
057: this .timeout = timeout;
058: this .retries = retries;
059: dnsClient = new DnsClient(servers, timeout, retries);
060: }
061:
062: public void close() {
063: dnsClient.close();
064: dnsClient = null;
065: }
066:
067: /*
068: * Queries resource records of a particular class and type for a
069: * given domain name.
070: * Useful values of rrclass are ResourceRecord.[Q]CLASS_xxx.
071: * Useful values of rrtype are ResourceRecord.[Q]TYPE_xxx.
072: * If recursion is true, recursion is requested on the query.
073: * If auth is true, only authoritative responses are accepted.
074: */
075: ResourceRecords query(DnsName fqdn, int rrclass, int rrtype,
076: boolean recursion, boolean auth) throws NamingException {
077: return dnsClient.query(fqdn, rrclass, rrtype, recursion, auth);
078: }
079:
080: /*
081: * Queries all resource records of a zone given its domain name and class.
082: * If recursion is true, recursion is requested on the query to find
083: * the name server (and also on the zone transfer, but it won't matter).
084: */
085: ResourceRecords queryZone(DnsName zone, int rrclass,
086: boolean recursion) throws NamingException {
087:
088: DnsClient cl = new DnsClient(findNameServers(zone, recursion),
089: timeout, retries);
090: try {
091: return cl.queryZone(zone, rrclass, recursion);
092: } finally {
093: cl.close();
094: }
095: }
096:
097: /*
098: * Finds the zone of a given domain name. The method is to look
099: * for the first SOA record on the path from the given domain to
100: * the root. This search may be partially bypassed if the zone's
101: * SOA record is received in the authority section of a response.
102: * If recursion is true, recursion is requested on any queries.
103: */
104: DnsName findZoneName(DnsName fqdn, int rrclass, boolean recursion)
105: throws NamingException {
106:
107: fqdn = (DnsName) fqdn.clone();
108: while (fqdn.size() > 1) { // while below root
109: ResourceRecords rrs = null;
110: try {
111: rrs = query(fqdn, rrclass, ResourceRecord.TYPE_SOA,
112: recursion, false);
113: } catch (NameNotFoundException e) {
114: throw e;
115: } catch (NamingException e) {
116: // Ignore error and keep searching up the tree.
117: }
118: if (rrs != null) {
119: if (rrs.answer.size() > 0) { // found zone's SOA
120: return fqdn;
121: }
122: // Look for an SOA record giving the zone's top node.
123: for (int i = 0; i < rrs.authority.size(); i++) {
124: ResourceRecord rr = (ResourceRecord) rrs.authority
125: .elementAt(i);
126: if (rr.getType() == ResourceRecord.TYPE_SOA) {
127: DnsName zone = rr.getName();
128: if (fqdn.endsWith(zone)) {
129: return zone;
130: }
131: }
132: }
133: }
134: fqdn.remove(fqdn.size() - 1); // one step rootward
135: }
136: return fqdn; // no SOA found below root, so
137: // return root
138: }
139:
140: /*
141: * Finds a zone's SOA record. Returns null if no SOA is found (in
142: * which case "zone" is not actually a zone).
143: * If recursion is true, recursion is requested on the query.
144: */
145: ResourceRecord findSoa(DnsName zone, int rrclass, boolean recursion)
146: throws NamingException {
147:
148: ResourceRecords rrs = query(zone, rrclass,
149: ResourceRecord.TYPE_SOA, recursion, false);
150: for (int i = 0; i < rrs.answer.size(); i++) {
151: ResourceRecord rr = (ResourceRecord) rrs.answer
152: .elementAt(i);
153: if (rr.getType() == ResourceRecord.TYPE_SOA) {
154: return rr;
155: }
156: }
157: return null;
158: }
159:
160: /*
161: * Finds the name servers of a zone. <tt>zone</tt> is a fully-qualified
162: * domain name at the top of a zone.
163: * If recursion is true, recursion is requested on the query.
164: */
165: private String[] findNameServers(DnsName zone, boolean recursion)
166: throws NamingException {
167:
168: // %%% As an optimization, could look in authority section of
169: // findZoneName() response first.
170: ResourceRecords rrs = query(zone,
171: ResourceRecord.CLASS_INTERNET, ResourceRecord.TYPE_NS,
172: recursion, false);
173: String[] ns = new String[rrs.answer.size()];
174: for (int i = 0; i < ns.length; i++) {
175: ResourceRecord rr = (ResourceRecord) rrs.answer
176: .elementAt(i);
177: if (rr.getType() != ResourceRecord.TYPE_NS) {
178: throw new CommunicationException(
179: "Corrupted DNS message");
180: }
181: ns[i] = (String) rr.getRdata();
182:
183: // Server name will be passed to InetAddress.getByName(), which
184: // may not be able to handle a trailing dot.
185: // assert ns[i].endsWith(".");
186: ns[i] = ns[i].substring(0, ns[i].length() - 1);
187: }
188: return ns;
189: }
190: }
|