Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure hostname resolution to use a custom DNS server in Java?

java.net.InetAddress resolves hostnames using the local machine's default host-name resolver by default:

Host name-to-IP address resolution is accomplished through the use of a combination of local machine configuration information and network naming services such as the Domain Name System (DNS) and Network Information Service(NIS). The particular naming services(s) being used is by default the local machine configured one. For any host name, its corresponding IP address is returned. [source]

How can we configure this behavior without modifying the local machine's default hostname resolver?

For example, is there anyway to configure java.net.InetAddress such that it resolves host names through OpenDNS (208.67.222.222, 208.67.220.220) or Google Public DNS (2001:4860:4860::8888, 2001:4860:4860::8844)?

Or is the only solution to explicitly create DNS packet requests, send them to the servers through either java.net.DatagramSocket or java.net.Socket, and parse the responses?

like image 585
Pacerier Avatar asked Jul 25 '12 10:07

Pacerier


2 Answers

Java 9 removed this capability. You will need to use a third party DNS client library.

If you are using Java 8 or older you can do:

You can set the system property sun.net.spi.nameservice.nameservers as documented by this site.

like image 192
Pace Avatar answered Sep 30 '22 20:09

Pace


with the following Interface and allowing access to java.net.* it is possible to use own DNS provider with JDK8 and JDK9. The new Provider is installed via "INameService.install(new MyNameService());"

public interface INameService extends InvocationHandler {
    public static void install(final INameService dns) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException, ClassNotFoundException {
        final Class<?> inetAddressClass = InetAddress.class;
        Object neu;
        Field nameServiceField;
        try {
            final Class<?> iface = Class.forName("java.net.InetAddress$NameService");
            nameServiceField = inetAddressClass.getDeclaredField("nameService");
            neu = Proxy.newProxyInstance(iface.getClassLoader(), new Class<?>[] { iface }, dns);
        } catch(final ClassNotFoundException|NoSuchFieldException e) {
            nameServiceField = inetAddressClass.getDeclaredField("nameServices");
            final Class<?> iface = Class.forName("sun.net.spi.nameservice.NameService");
            neu = Arrays.asList(Proxy.newProxyInstance(iface.getClassLoader(), new Class<?>[] { iface }, dns));
        }
        nameServiceField.setAccessible(true);
        nameServiceField.set(inetAddressClass, neu);
    }

    /**
     * Lookup a host mapping by name. Retrieve the IP addresses associated with a host
     *
     * @param host the specified hostname
     * @return array of IP addresses for the requested host
     * @throws UnknownHostException  if no IP address for the {@code host} could be found
     */
    InetAddress[] lookupAllHostAddr(final String host) throws UnknownHostException;

    /**
     * Lookup the host corresponding to the IP address provided
     *
     * @param addr byte array representing an IP address
     * @return {@code String} representing the host name mapping
     * @throws UnknownHostException
     *             if no host found for the specified IP address
     */
    String getHostByAddr(final byte[] addr) throws UnknownHostException;

    @Override default public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        switch(method.getName()) {
        case "lookupAllHostAddr": return lookupAllHostAddr((String)args[0]);
        case "getHostByAddr"    : return getHostByAddr    ((byte[])args[0]);
        default                 :
            final StringBuilder o = new StringBuilder();
            o.append(method.getReturnType().getCanonicalName()+" "+method.getName()+"(");
            final Class<?>[] ps = method.getParameterTypes();
            for(int i=0;i<ps.length;++i) {
                if(i>0) o.append(", ");
                o.append(ps[i].getCanonicalName()).append(" p").append(i);
            }
            o.append(")");
            throw new UnsupportedOperationException(o.toString());
        }
    }
}
like image 42
SkateScout Avatar answered Sep 30 '22 19:09

SkateScout