blob: 755826364ec9d9e3df1e99ad7a61396e849fee6b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.jndi.dns;
27
28
29import javax.naming.*;
30
31
32/**
33 * The Resolver class performs DNS client operations in support of DnsContext.
34 *
35 * <p> Every DnsName instance passed to or returned from a method of
36 * this class should be fully-qualified and contain a root label (an
37 * empty component at position 0).
38 *
39 * @author Scott Seligman
40 */
41
42class Resolver {
43
44 private DnsClient dnsClient;
45 private int timeout; // initial timeout on UDP queries in ms
46 private int retries; // number of UDP retries
47
48
49 /*
50 * Constructs a new Resolver given its servers and timeout parameters.
51 * Each server is of the form "server[:port]".
52 * IPv6 literal host names include delimiting brackets.
53 * There must be at least one server.
54 * "timeout" is the initial timeout interval (in ms) for UDP queries,
55 * and "retries" gives the number of retries per server.
56 */
57 Resolver(String[] servers, int timeout, int retries)
58 throws NamingException {
59 this.timeout = timeout;
60 this.retries = retries;
61 dnsClient = new DnsClient(servers, timeout, retries);
62 }
63
64 public void close() {
65 dnsClient.close();
66 dnsClient = null;
67 }
68
69
70 /*
71 * Queries resource records of a particular class and type for a
72 * given domain name.
73 * Useful values of rrclass are ResourceRecord.[Q]CLASS_xxx.
74 * Useful values of rrtype are ResourceRecord.[Q]TYPE_xxx.
75 * If recursion is true, recursion is requested on the query.
76 * If auth is true, only authoritative responses are accepted.
77 */
78 ResourceRecords query(DnsName fqdn, int rrclass, int rrtype,
79 boolean recursion, boolean auth)
80 throws NamingException {
81 return dnsClient.query(fqdn, rrclass, rrtype, recursion, auth);
82 }
83
84 /*
85 * Queries all resource records of a zone given its domain name and class.
86 * If recursion is true, recursion is requested on the query to find
87 * the name server (and also on the zone transfer, but it won't matter).
88 */
89 ResourceRecords queryZone(DnsName zone, int rrclass, boolean recursion)
90 throws NamingException {
91
92 DnsClient cl =
93 new DnsClient(findNameServers(zone, recursion), timeout, retries);
94 try {
95 return cl.queryZone(zone, rrclass, recursion);
96 } finally {
97 cl.close();
98 }
99 }
100
101 /*
102 * Finds the zone of a given domain name. The method is to look
103 * for the first SOA record on the path from the given domain to
104 * the root. This search may be partially bypassed if the zone's
105 * SOA record is received in the authority section of a response.
106 * If recursion is true, recursion is requested on any queries.
107 */
108 DnsName findZoneName(DnsName fqdn, int rrclass, boolean recursion)
109 throws NamingException {
110
111 fqdn = (DnsName) fqdn.clone();
112 while (fqdn.size() > 1) { // while below root
113 ResourceRecords rrs = null;
114 try {
115 rrs = query(fqdn, rrclass, ResourceRecord.TYPE_SOA,
116 recursion, false);
117 } catch (NameNotFoundException e) {
118 throw e;
119 } catch (NamingException e) {
120 // Ignore error and keep searching up the tree.
121 }
122 if (rrs != null) {
123 if (rrs.answer.size() > 0) { // found zone's SOA
124 return fqdn;
125 }
126 // Look for an SOA record giving the zone's top node.
127 for (int i = 0; i < rrs.authority.size(); i++) {
128 ResourceRecord rr = (ResourceRecord)
129 rrs.authority.elementAt(i);
130 if (rr.getType() == ResourceRecord.TYPE_SOA) {
131 DnsName zone = rr.getName();
132 if (fqdn.endsWith(zone)) {
133 return zone;
134 }
135 }
136 }
137 }
138 fqdn.remove(fqdn.size() - 1); // one step rootward
139 }
140 return fqdn; // no SOA found below root, so
141 // return root
142 }
143
144 /*
145 * Finds a zone's SOA record. Returns null if no SOA is found (in
146 * which case "zone" is not actually a zone).
147 * If recursion is true, recursion is requested on the query.
148 */
149 ResourceRecord findSoa(DnsName zone, int rrclass, boolean recursion)
150 throws NamingException {
151
152 ResourceRecords rrs = query(zone, rrclass, ResourceRecord.TYPE_SOA,
153 recursion, false);
154 for (int i = 0; i < rrs.answer.size(); i++) {
155 ResourceRecord rr = (ResourceRecord) rrs.answer.elementAt(i);
156 if (rr.getType() == ResourceRecord.TYPE_SOA) {
157 return rr;
158 }
159 }
160 return null;
161 }
162
163 /*
164 * Finds the name servers of a zone. <tt>zone</tt> is a fully-qualified
165 * domain name at the top of a zone.
166 * If recursion is true, recursion is requested on the query.
167 */
168 private String[] findNameServers(DnsName zone, boolean recursion)
169 throws NamingException {
170
171 // %%% As an optimization, could look in authority section of
172 // findZoneName() response first.
173 ResourceRecords rrs =
174 query(zone, ResourceRecord.CLASS_INTERNET, ResourceRecord.TYPE_NS,
175 recursion, false);
176 String[] ns = new String[rrs.answer.size()];
177 for (int i = 0; i < ns.length; i++) {
178 ResourceRecord rr = (ResourceRecord)
179 rrs.answer.elementAt(i);
180 if (rr.getType() != ResourceRecord.TYPE_NS) {
181 throw new CommunicationException("Corrupted DNS message");
182 }
183 ns[i] = (String) rr.getRdata();
184
185 // Server name will be passed to InetAddress.getByName(), which
186 // may not be able to handle a trailing dot.
187 // assert ns[i].endsWith(".");
188 ns[i] = ns[i].substring(0, ns[i].length() - 1);
189 }
190 return ns;
191 }
192}