Saturday, January 6, 2018

GoogleDNS for OkHttpClient

Sometimes, there are situations in life, when you have to truly rely on a DNS resolver. Your users' ISP might be doing some funny business with his DNS, so 8.8.8.8 to the rescue!

public class GoogleDns implements Dns {

    private ExtendedResolver resolver;

    private synchronized void init() throws UnknownHostException {
        if (resolver == null) {
            resolver = new ExtendedResolver(new String[]{"8.8.8.8", "8.8.4.4"});
            Lookup.setDefaultResolver(resolver);
        }
    }

    private Record[] lookupHostName(String hostname) throws UnknownHostException {
        try {
            Lookup lookup = new Lookup(hostname, Type.A);
            lookup.setResolver(resolver);
            Record[] a = lookup.run();
            Record[] aaaa;

            if(a == null) {
                if(lookup.getResult() == TYPE_NOT_FOUND) {
                    lookup = new Lookup(hostname, Type.AAAA);
                    lookup.setResolver(resolver);
                    aaaa = lookup.run();
                    if(aaaa != null) {
                        return aaaa;
                    }
                }

                throw new UnknownHostException("unknown host: " + hostname);
            } else {
                lookup = new Lookup(hostname, Type.AAAA);
                lookup.setResolver(resolver);
                aaaa = lookup.run();
                if(aaaa == null) {
                    return a;
                } else {
                    Record[] merged = new Record[a.length + aaaa.length];
                    System.arraycopy(a, 0, merged, 0, a.length);
                    System.arraycopy(aaaa, 0, merged, a.length, aaaa.length);
                    return merged;
                }
            }
        } catch (TextParseException e) {
            throw new UnknownHostException("invalid name");
        }
    }

    private InetAddress getAddressFromRecord(Record record) {
        if(record instanceof ARecord) {
            return ((ARecord)record).getAddress();
        } else {
            return ((AAAARecord)record).getAddress();
        }
    }

    @Override
    public List lookup(String hostname) throws UnknownHostException {
        if (hostname == null) throw new UnknownHostException("hostname == null");
        init(); //leverage OkHttp's calling of lookup on background thread

        Record[] records = lookupHostName(hostname);
        List out = new ArrayList<>(2);
        for (int i = 0; i < records.length; i++) {
            out.add(getAddressFromRecord(records[i]));
        }
        return out;
    }
}

And now use it like:


OkHttpClient client = new OkHttpClient.Builder()
            .dns(new GoogleDns())
            .build();

The code uses org.xbill.DNS library to resolve hostnames.

0 comments:

Post a Comment