/* * Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.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 = (ResourceRecord) 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 = (ResourceRecord) 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 = (ResourceRecord) 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; } }