1 /* 2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.jndi.dns; 27 28 29 import 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 42 class 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 */ Resolver(String[] servers, int timeout, int retries)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 close()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 */ query(DnsName fqdn, int rrclass, int rrtype, boolean recursion, boolean auth)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 */ queryZone(DnsName zone, int rrclass, boolean recursion)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 */ findZoneName(DnsName fqdn, int rrclass, boolean recursion)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 = rrs.authority.elementAt(i); 129 if (rr.getType() == ResourceRecord.TYPE_SOA) { 130 DnsName zone = rr.getName(); 131 if (fqdn.endsWith(zone)) { 132 return zone; 133 } 134 } 135 } 136 } 137 fqdn.remove(fqdn.size() - 1); // one step rootward 138 } 139 return fqdn; // no SOA found below root, so 140 // return root 141 } 142 143 /* 144 * Finds a zone's SOA record. Returns null if no SOA is found (in 145 * which case "zone" is not actually a zone). 146 * If recursion is true, recursion is requested on the query. 147 */ findSoa(DnsName zone, int rrclass, boolean recursion)148 ResourceRecord findSoa(DnsName zone, int rrclass, boolean recursion) 149 throws NamingException { 150 151 ResourceRecords rrs = query(zone, rrclass, ResourceRecord.TYPE_SOA, 152 recursion, false); 153 for (int i = 0; i < rrs.answer.size(); i++) { 154 ResourceRecord rr = rrs.answer.elementAt(i); 155 if (rr.getType() == ResourceRecord.TYPE_SOA) { 156 return rr; 157 } 158 } 159 return null; 160 } 161 162 /* 163 * Finds the name servers of a zone. <tt>zone</tt> is a fully-qualified 164 * domain name at the top of a zone. 165 * If recursion is true, recursion is requested on the query. 166 */ findNameServers(DnsName zone, boolean recursion)167 private String[] findNameServers(DnsName zone, boolean recursion) 168 throws NamingException { 169 170 // %%% As an optimization, could look in authority section of 171 // findZoneName() response first. 172 ResourceRecords rrs = 173 query(zone, ResourceRecord.CLASS_INTERNET, ResourceRecord.TYPE_NS, 174 recursion, false); 175 String[] ns = new String[rrs.answer.size()]; 176 for (int i = 0; i < ns.length; i++) { 177 ResourceRecord rr = rrs.answer.elementAt(i); 178 if (rr.getType() != ResourceRecord.TYPE_NS) { 179 throw new CommunicationException("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 } 191