jdk/src/jdk.naming.dns/share/classes/sun/net/spi/nameservice/dns/DNSNameService.java
changeset 36967 d041d2e80712
parent 36966 4209c9e19c45
child 36968 4ddff5909b4f
--- a/jdk/src/jdk.naming.dns/share/classes/sun/net/spi/nameservice/dns/DNSNameService.java	Sat Apr 09 20:12:13 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,501 +0,0 @@
-/*
- * 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 sun.net.spi.nameservice.dns;
-
-import java.lang.ref.SoftReference;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import javax.naming.*;
-import javax.naming.directory.*;
-import javax.naming.spi.NamingManager;
-import java.util.*;
-import sun.net.util.IPAddressUtil;
-import sun.net.dns.ResolverConfiguration;
-import sun.net.spi.nameservice.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-/*
- * A name service provider based on JNDI-DNS.
- */
-
-public final class DNSNameService implements NameService {
-
-    // List of domains specified by property
-    private LinkedList<String> domainList = null;
-
-    // JNDI-DNS URL for name servers specified via property
-    private String nameProviderUrl = null;
-
-    // Per-thread soft cache of the last temporary context
-    private static ThreadLocal<SoftReference<ThreadContext>> contextRef =
-            new ThreadLocal<>();
-
-    // Simple class to encapsulate the temporary context
-    private static class ThreadContext {
-        private DirContext dirCtxt;
-        private List<String> nsList;
-
-        public ThreadContext(DirContext dirCtxt, List<String> nsList) {
-            this.dirCtxt = dirCtxt;
-            this.nsList = nsList;
-        }
-
-        public DirContext dirContext() {
-            return dirCtxt;
-        }
-
-        public List<String> nameservers() {
-            return nsList;
-        }
-    }
-
-    // Returns a per-thread DirContext
-    private DirContext getTemporaryContext() throws NamingException {
-        SoftReference<ThreadContext> ref = contextRef.get();
-        ThreadContext thrCtxt = null;
-        List<String> nsList = null;
-
-        // if no property specified we need to obtain the list of servers
-        //
-        if (nameProviderUrl == null)
-            nsList = ResolverConfiguration.open().nameservers();
-
-        // if soft reference hasn't been gc'ed no property has been
-        // specified then we need to check if the DNS configuration
-        // has changed.
-        //
-        if ((ref != null) && ((thrCtxt = ref.get()) != null)) {
-            if (nameProviderUrl == null) {
-                if (!thrCtxt.nameservers().equals(nsList)) {
-                    // DNS configuration has changed
-                    thrCtxt = null;
-                }
-            }
-        }
-
-        // new thread context needs to be created
-        if (thrCtxt == null) {
-            final Hashtable<String,Object> env = new Hashtable<>();
-            env.put("java.naming.factory.initial",
-                    "com.sun.jndi.dns.DnsContextFactory");
-
-            // If no nameservers property specified we create provider URL
-            // based on system configured name servers
-            //
-            String provUrl = nameProviderUrl;
-            if (provUrl == null) {
-                provUrl = createProviderURL(nsList);
-                if (provUrl.length() == 0) {
-                    throw new RuntimeException("bad nameserver configuration");
-                }
-            }
-            env.put("java.naming.provider.url", provUrl);
-
-            // Need to create directory context in privileged block
-            // as JNDI-DNS needs to resolve the name servers.
-            //
-            DirContext dirCtxt;
-            try {
-                dirCtxt = java.security.AccessController.doPrivileged(
-                        new java.security.PrivilegedExceptionAction<DirContext>() {
-                            public DirContext run() throws NamingException {
-                                // Create the DNS context using NamingManager rather than using
-                                // the initial context constructor. This avoids having the initial
-                                // context constructor call itself.
-                                Context ctx = NamingManager.getInitialContext(env);
-                                if (!(ctx instanceof DirContext)) {
-                                    return null; // cannot create a DNS context
-                                }
-                                return (DirContext)ctx;
-                            }
-                    });
-            } catch (java.security.PrivilegedActionException pae) {
-                throw (NamingException)pae.getException();
-            }
-
-            // create new soft reference to our thread context
-            //
-            thrCtxt = new ThreadContext(dirCtxt, nsList);
-            contextRef.set(new SoftReference<ThreadContext>(thrCtxt));
-        }
-
-        return thrCtxt.dirContext();
-    }
-
-    /**
-     * Resolves the specified entry in DNS.
-     *
-     * Canonical name records are recursively resolved (to a maximum
-     * of 5 to avoid performance hit and potential CNAME loops).
-     *
-     * @param   ctx     JNDI directory context
-     * @param   name    name to resolve
-     * @param   ids     record types to search
-     * @param   depth   call depth - pass as 0.
-     *
-     * @return  array list with results (will have at least on entry)
-     *
-     * @throws  UnknownHostException if lookup fails or other error.
-     */
-    private ArrayList<String> resolve(final DirContext ctx, final String name,
-                                      final String[] ids, int depth)
-            throws UnknownHostException
-    {
-        ArrayList<String> results = new ArrayList<>();
-        Attributes attrs;
-
-        // do the query
-        try {
-            attrs = java.security.AccessController.doPrivileged(
-                    new java.security.PrivilegedExceptionAction<Attributes>() {
-                        public Attributes run() throws NamingException {
-                            return ctx.getAttributes(name, ids);
-                        }
-                });
-        } catch (java.security.PrivilegedActionException pae) {
-            throw new UnknownHostException(pae.getException().getMessage());
-        }
-
-        // non-requested type returned so enumeration is empty
-        NamingEnumeration<? extends Attribute> ne = attrs.getAll();
-        if (!ne.hasMoreElements()) {
-            throw new UnknownHostException("DNS record not found");
-        }
-
-        // iterate through the returned attributes
-        UnknownHostException uhe = null;
-        try {
-            while (ne.hasMoreElements()) {
-                Attribute attr = ne.next();
-                String attrID = attr.getID();
-
-                for (NamingEnumeration<?> e = attr.getAll(); e.hasMoreElements();) {
-                    String addr = (String)e.next();
-
-                    // for canoncical name records do recursive lookup
-                    // - also check for CNAME loops to avoid stack overflow
-
-                    if (attrID.equals("CNAME")) {
-                        if (depth > 4) {
-                            throw new UnknownHostException(name + ": possible CNAME loop");
-                        }
-                        try {
-                            results.addAll(resolve(ctx, addr, ids, depth+1));
-                        } catch (UnknownHostException x) {
-                            // canonical name can't be resolved.
-                            if (uhe == null)
-                                uhe = x;
-                        }
-                    } else {
-                        results.add(addr);
-                    }
-                }
-            }
-        } catch (NamingException nx) {
-            throw new UnknownHostException(nx.getMessage());
-        }
-
-        // pending exception as canonical name could not be resolved.
-        if (results.isEmpty() && uhe != null) {
-            throw uhe;
-        }
-
-        return results;
-    }
-
-    public DNSNameService() throws Exception {
-
-        // default domain
-        String domain = AccessController.doPrivileged(
-            (PrivilegedAction<String>) () -> System.getProperty("sun.net.spi.nameservice.domain"));
-        if (domain != null && domain.length() > 0) {
-            domainList = new LinkedList<String>();
-            domainList.add(domain);
-        }
-
-        // name servers
-        String nameservers = AccessController.doPrivileged(
-            (PrivilegedAction<String>) () -> System.getProperty("sun.net.spi.nameservice.nameservers"));
-        if (nameservers != null && nameservers.length() > 0) {
-            nameProviderUrl = createProviderURL(nameservers);
-            if (nameProviderUrl.length() == 0) {
-                throw new RuntimeException("malformed nameservers property");
-            }
-
-        } else {
-
-            // no property specified so check host DNS resolver configured
-            // with at least one nameserver in dotted notation.
-            //
-            List<String> nsList = ResolverConfiguration.open().nameservers();
-            if (nsList.isEmpty()) {
-                throw new RuntimeException("no nameservers provided");
-            }
-            boolean found = false;
-            for (String addr: nsList) {
-                if (IPAddressUtil.isIPv4LiteralAddress(addr) ||
-                    IPAddressUtil.isIPv6LiteralAddress(addr)) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                throw new RuntimeException("bad nameserver configuration");
-            }
-        }
-    }
-
-    public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException {
-
-        // DNS records that we search for
-        String[] ids = {"A", "AAAA", "CNAME"};
-
-        // first get directory context
-        DirContext ctx;
-        try {
-            ctx = getTemporaryContext();
-        } catch (NamingException nx) {
-            throw new Error(nx);
-        }
-
-        ArrayList<String> results = null;
-        UnknownHostException uhe = null;
-
-        // If host already contains a domain name then just look it up
-        if (host.indexOf('.') >= 0) {
-            try {
-                results = resolve(ctx, host, ids, 0);
-            } catch (UnknownHostException x) {
-                uhe = x;
-            }
-        }
-
-        // Here we try to resolve the host using the domain suffix or
-        // the domain suffix search list. If the host cannot be resolved
-        // using the domain suffix then we attempt devolution of
-        // the suffix - eg: if we are searching for "foo" and our
-        // domain suffix is "eng.sun.com" we will try to resolve
-        // "foo.eng.sun.com" and "foo.sun.com".
-        // It's not normal to attempt devolation with domains on the
-        // domain suffix search list - however as ResolverConfiguration
-        // doesn't distinguish domain or search list in the list it
-        // returns we approximate by doing devolution on the domain
-        // suffix if the list has one entry.
-
-        if (results == null) {
-            List<String> searchList = null;
-            Iterator<String> i;
-            boolean usingSearchList = false;
-
-            if (domainList != null) {
-                i = domainList.iterator();
-            } else {
-                searchList = ResolverConfiguration.open().searchlist();
-                if (searchList.size() > 1) {
-                    usingSearchList = true;
-                }
-                i = searchList.iterator();
-            }
-
-            // iterator through each domain suffix
-            while (i.hasNext()) {
-                String parentDomain = i.next();
-                int start = 0;
-                while ((start = parentDomain.indexOf('.')) != -1
-                       && start < parentDomain.length() -1) {
-                    try {
-                        results = resolve(ctx, host+"."+parentDomain, ids, 0);
-                        break;
-                    } catch (UnknownHostException x) {
-                        uhe = x;
-                        if (usingSearchList) {
-                            break;
-                        }
-
-                        // devolve
-                        parentDomain = parentDomain.substring(start+1);
-                    }
-                }
-                if (results != null) {
-                    break;
-                }
-            }
-        }
-
-        // finally try the host if it doesn't have a domain name
-        if (results == null && (host.indexOf('.') < 0)) {
-            results = resolve(ctx, host, ids, 0);
-        }
-
-        // if not found then throw the (last) exception thrown.
-        if (results == null) {
-            assert uhe != null;
-            throw uhe;
-        }
-
-        /**
-         * Convert the array list into a byte aray list - this
-         * filters out any invalid IPv4/IPv6 addresses.
-         */
-        assert results.size() > 0;
-        InetAddress[] addrs = new InetAddress[results.size()];
-        int count = 0;
-        for (int i=0; i<results.size(); i++) {
-            String addrString = results.get(i);
-            byte addr[] = IPAddressUtil.textToNumericFormatV4(addrString);
-            if (addr == null) {
-                addr = IPAddressUtil.textToNumericFormatV6(addrString);
-            }
-            if (addr != null) {
-                addrs[count++] = InetAddress.getByAddress(host, addr);
-            }
-        }
-
-        /**
-         * If addresses are filtered then we need to resize the
-         * array. Additionally if all addresses are filtered then
-         * we throw an exception.
-         */
-        if (count == 0) {
-            throw new UnknownHostException(host + ": no valid DNS records");
-        }
-        if (count < results.size()) {
-            InetAddress[] tmp = new InetAddress[count];
-            for (int i=0; i<count; i++) {
-                tmp[i] = addrs[i];
-            }
-            addrs = tmp;
-        }
-
-        return addrs;
-    }
-
-    /**
-     * Reverse lookup code. I.E: find a host name from an IP address.
-     * IPv4 addresses are mapped in the IN-ADDR.ARPA. top domain, while
-     * IPv6 addresses can be in IP6.ARPA or IP6.INT.
-     * In both cases the address has to be converted into a dotted form.
-     */
-    public String getHostByAddr(byte[] addr) throws UnknownHostException {
-        String host = null;
-        try {
-            String literalip = "";
-            String[] ids = { "PTR" };
-            DirContext ctx;
-            ArrayList<String> results = null;
-            try {
-                ctx = getTemporaryContext();
-            } catch (NamingException nx) {
-                throw new Error(nx);
-            }
-            if (addr.length == 4) { // IPv4 Address
-                for (int i = addr.length-1; i >= 0; i--) {
-                    literalip += (addr[i] & 0xff) +".";
-                }
-                literalip += "IN-ADDR.ARPA.";
-
-                results = resolve(ctx, literalip, ids, 0);
-                host = results.get(0);
-            } else if (addr.length == 16) { // IPv6 Address
-                /**
-                 * Because RFC 3152 changed the root domain name for reverse
-                 * lookups from IP6.INT. to IP6.ARPA., we need to check
-                 * both. I.E. first the new one, IP6.ARPA, then if it fails
-                 * the older one, IP6.INT
-                 */
-
-                for (int i = addr.length-1; i >= 0; i--) {
-                    literalip += Integer.toHexString((addr[i] & 0x0f)) +"."
-                        +Integer.toHexString((addr[i] & 0xf0) >> 4) +".";
-                }
-                String ip6lit = literalip + "IP6.ARPA.";
-
-                try {
-                    results = resolve(ctx, ip6lit, ids, 0);
-                    host = results.get(0);
-                } catch (UnknownHostException e) {
-                    host = null;
-                }
-                if (host == null) {
-                    // IP6.ARPA lookup failed, let's try the older IP6.INT
-                    ip6lit = literalip + "IP6.INT.";
-                    results = resolve(ctx, ip6lit, ids, 0);
-                    host = results.get(0);
-                }
-            }
-        } catch (Exception e) {
-            throw new UnknownHostException(e.getMessage());
-        }
-        // Either we couldn't find it or the address was neither IPv4 or IPv6
-        if (host == null)
-            throw new UnknownHostException();
-        // remove trailing dot
-        if (host.endsWith(".")) {
-            host = host.substring(0, host.length() - 1);
-        }
-        return host;
-    }
-
-
-    // ---------
-
-    private static void appendIfLiteralAddress(String addr, StringBuilder sb) {
-        if (IPAddressUtil.isIPv4LiteralAddress(addr)) {
-            sb.append("dns://").append(addr).append(' ');
-        } else {
-            if (IPAddressUtil.isIPv6LiteralAddress(addr)) {
-                sb.append("dns://[").append(addr).append("] ");
-            }
-        }
-    }
-
-    /*
-     * @return String containing the JNDI-DNS provider URL
-     *         corresponding to the supplied List of nameservers.
-     */
-    private static String createProviderURL(List<String> nsList) {
-        StringBuilder sb = new StringBuilder();
-        for (String s: nsList) {
-            appendIfLiteralAddress(s, sb);
-        }
-        return sb.toString();
-    }
-
-    /*
-     * @return String containing the JNDI-DNS provider URL
-     *         corresponding to the list of nameservers
-     *         contained in the provided str.
-     */
-    private static String createProviderURL(String str) {
-        StringBuilder sb = new StringBuilder();
-        StringTokenizer st = new StringTokenizer(str, ",");
-        while (st.hasMoreTokens()) {
-            appendIfLiteralAddress(st.nextToken(), sb);
-        }
-        return sb.toString();
-    }
-}