DEV Community

Cover image for How to configure host name resolution to use a universal host name resolver in Java
JJBRT
JJBRT

Posted on • Updated on

How to configure host name resolution to use a universal host name resolver in Java

In the JDK 8 the java.net.InetAddress resolves host names 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]

In the JDK 19 the java.net.InetAddress works the same way but there is also the option to use a custom configuration:

The built-in InetAddress resolver implementation does host name-to-IP address resolution and vice versa through the use of a combination of local machine configuration information and network naming services such as the Domain Name System (DNS) and the Lightweight Directory Access Protocol (LDAP). The particular naming services that the built-in resolver uses by default depends on the configuration of the local machine. InetAddress has a service provider mechanism for InetAddress resolvers that allows a custom InetAddress resolver to be used instead of the built-in implementation. [source]

So how can we configure this behavior without modifying the local machine's default host name resolver in a universal way that works for Java 8 and later?

In this situation Burningwave Tools comes to our aid by providing us with the HostResolutionRequestInterceptor that allows us:

  • to use a custom resolver instead the default one
  • to prepend a custom resolver to the default one
  • to postpone a custom resolver to the default one

To include Burningwave Tools in our project we need to add the following dependency to our pom.xml:

And to install the HostResolutionRequestInterceptor component we must proceed as follows:

Map<String, String> hostAliases = new LinkedHashMap<>();
hostAliases.put("my.hostname.one", "123.123.123.123");

//Installing the host resolvers
HostResolutionRequestInterceptor.INSTANCE.install(
    new MappedHostResolver(hostAliases),
    //This is the system default resolving wrapper
    DefaultHostResolver.INSTANCE
);

InetAddress inetAddress = InetAddress.getByName("my.hostname.one");
Enter fullscreen mode Exit fullscreen mode

Burningwave Tools provides also a DNS server connection based host resolver:

HostResolutionRequestInterceptor.INSTANCE.install(
    new DNSClientHostResolver("208.67.222.222"), //Open DNS server
    new DNSClientHostResolver("208.67.222.220"), //Open DNS server
    new DNSClientHostResolver("8.8.8.8"), //Google DNS server
    new DNSClientHostResolver("8.8.4.4"), //Google DNS server
    DefaultHostResolver.INSTANCE
);
InetAddress inetAddress = InetAddress.getByName("github.com");
Enter fullscreen mode Exit fullscreen mode

But you can also define a new custom resolver by implementing the HostResolver interface that create DNS packet requests, send them to the servers through the java.net.DatagramSocket and parse the responses:

HostResolutionRequestInterceptor.INSTANCE.install(
    new HostResolver() {

        @Override
        public Collection<InetAddress> getAllAddressesForHostName(Map<String, Object> argumentMap) {
            String hostName = (String)super.getMethodArguments(argumentMap)[0]
            //Do the stuff...
        }

        @Override
        public Collection<String> getAllHostNamesForHostAddress(Map<String, Object> argumentMap) {
            byte[] iPAddressAsByteArray = (byte[])super.getMethodArguments(argumentMap)[0];
            String iPAddress = IPAddressUtil.INSTANCE.numericToTextFormat(iPAddressAsByteArray);
            //Do the stuff...
        }

    },
    DefaultHostResolver.INSTANCE
);
Enter fullscreen mode Exit fullscreen mode

If we add the Jackson framework to our project we can add the configuration via yaml file support with a few lines of code by using the PathHelper component:

public static void installHostResolutionRequestInterceptor() throws UnknownHostException {
    Map<String, Object> configuration = loadConfiguration("config.yml");
    List<HostResolver> resolvers = new ArrayList<>();
    resolvers.add(
        new MappedHostResolver(() -> (List<Map<String, Object>>)configuration.get("hostAliases"))
    );
    resolvers.addAll(
        DNSClientHostResolver.newInstances(() -> 
            (List<Map<String, Object>>)((Map<String, Object>)configuration.get("dns")).get("servers")
        )
    );
    resolvers.add(DefaultHostResolver.INSTANCE);
    HostResolutionRequestInterceptor.INSTANCE.install(
        resolvers.toArray(new HostResolver[resolvers.size()])
    );
    InetAddress.getByName("google.com");
}

public static Map<String, Object> loadConfiguration(String fileNameRelativePathFromClasspath) {
    ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
    try (InputStream inputStream = ComponentContainer.getInstance().getPathHelper().getResourceAsStream(fileRelativePathFromClasspath)) {
        return mapper.readValue(inputStream, Map.class);
    } catch (IOException exc) {
        return Driver.throwException(exc);
    }
}
Enter fullscreen mode Exit fullscreen mode
hostAliases:
  - ip: 123.123.123.123
    hostnames:
      - my.hostname.one
      - my.hostname.two
  - ip: 12.21.34.43
    hostnames:
      - my.hostname.three
      - my.hostname.four
dns:
  servers:
    - ip: 208.67.222.222
      port: 53
      ipTypeToSearchFor:
        - IPV4
        - IPV6
    - ip: 208.67.222.220
      port: 53
      ipTypeToSearchFor:
        - IPV4
        - IPV6
Enter fullscreen mode Exit fullscreen mode

From here you can download/clone the tutorial shared on GitHub.

Top comments (0)