Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Provide custom implementation for DNS lookup in java.net.URL class

Tags:

java

caching

dns

I was wondering if it's possible to provide a custom implementation for DNS lookups on java.net.URL - my hosting provider's DNS gets flaky at certain times of day and then DNS lookups fail for a few minutes, but if I manually configure the relevant domains in my hosts file, they work fine, so what I want to do is have some sort of DNS cache at a software level, if DNS lookup succeed, update the cache, if it fails, fall back to the cached IP address and open the URLConnection on that IP address.

This is my URL connection implementation:

    URL endpoint = new URL(null, url, new URLStreamHandler() {
        @Override
        protected URLConnection openConnection(URL url)
                throws IOException {
            URL target = new URL(url.toString());
            URLConnection connection = target.openConnection();
            // Connection settings
            connection.setConnectTimeout(connectionTimeout);
            connection.setReadTimeout(readTimeout);
            return (connection);
        }
    });

I was looking at proxies on Oracle, but can't see any immediate way to do custom DNS lookups at the software level.

Limitations:

1: It needs to work in Java6 (maybe Java7, but the client won't be switching to Java8 anytime soon)

2: Can't add JVM args

3: I don't own these endpoints, so substituting the hostname with an IP address is not a solution since load balancers will serve different content / APIs depending on whether you come from a hostname or an IP address. As an example: mail.google.com resolves to 216.58.223.37, going to that IP address will serve google.com content and not mail.google.com content, since both services are sitting behind the same load balancer using a single IP address.

4: I don't know how many URLs' DNS resolutions I'll need to cache, but I do know it won't be more than a 1000. Ideal solution would be to have the DNS resolutions in a static hashmap, if any DNS resolution succeed, update the hashmap, if it fails, use the DNS resolution in the hashmap.

5: If there's a native java solution, I'd prefer that over using JNI - Understanding host name resolution and DNS behavior in Java

like image 367
Jan Vladimir Mostert Avatar asked Feb 06 '15 08:02

Jan Vladimir Mostert


1 Answers

You could create a custom method to check whether the host resolves to an IP. Prior to opening the connection if the host does not resolve then do your lookup and use the IP directly to build the URL instead:

At class level:

private Map<String,InetAddress> cacheMap = new HashMap<String,InetAddress>();

....then a couple of methods to build your URL:

private URL buildUrl (String host) throws MalformedURLException {
    InetAddress ia = resolveHostToIp(host);
    URL url = null;

    if (ia != null) {
        url = new URL(ia.getHostAddress());
    } else {
        // Does not resolve and is not in cache....dunno
    }
    return url;
}


 private InetAddress resolveHostToIp(String host) {
    InetAddress ia = null;
    try {
        ia = InetAddress.getByName(host);
        // Update your cache
        cacheMap.put(host, ia);
    } catch (UnknownHostException uhe) {
        System.out.println("\"" + host + "\" does not resolve to an IP! Looking for it in the cacheMap....");
        // Head off to your cache and return the InetAddress from there.....
        ia = cacheMap.get(host);
    }
    return ia;
}
like image 80
Tom Mac Avatar answered Sep 25 '22 17:09

Tom Mac