Fundamentals 16 min read

How to Dynamically Override Java DNS Resolution for Automated Tests

This article explains how to replace Java's default DNS resolver with a custom NameService, disable DNS caching, and manipulate DNS entries at runtime using reflection, enabling flexible, environment‑agnostic automated test cases without hard‑coding IP addresses.

Vipshop Quality Engineering
Vipshop Quality Engineering
Vipshop Quality Engineering
How to Dynamically Override Java DNS Resolution for Automated Tests

Preface

Hello everyone! Starting today I will explore automated testing techniques in a series called "Playing with Automated Testing". The series will continuously update, covering pain points and solutions from VIP.com’s automation practice, as well as the internally developed framework and platform such as AutoV, Vmock-Server, and Vmock-Agent, with detailed principles and implementation.

The main goal is to deepen understanding of the architecture, principles, and implementation of the frameworks, tools, and platforms used in daily work, thereby improving automation authoring efficiency and problem‑locating capability.

Note: Most of the automation practice and related frameworks, tools, and platforms at VIP.com are developed in Java, so all code examples are Java‑based.

Abstract

First, a quick warm‑up: we will discuss how to play with DNS resolution inside automated test cases using simple "black‑tech" tricks.

When writing automated test cases you often need to call interfaces, databases, message queues, external caches, or remote servers. Hard‑coding IP addresses is fragile because IPs change, especially in containerized environments, and tests may run across multiple environments (functional, integration, staging). Using domain names instead of fixed IPs reduces maintenance cost and eases troubleshooting.

Problem

Typical approaches for domain‑based access are:

Modifying the system hosts file, which fails when multiple test instances run on the same Jenkins slave due to conflicts.

Setting an HTTP proxy (e.g., via HttpClient RequestConfig), which is framework‑specific and does not work for non‑HTTP protocols.

For client‑side applications with automatic reconnection, simulating network disconnection via iptables is problematic because iptables is Linux‑only and DNS results are cached, so changes may not take effect immediately.

Fundamentals

1. java.net.InetAddress

InetAddress is a high‑level Java class representing IP addresses. It is used by most Java networking classes such as ServerSocket, Socket, URL, DatagramSocket, etc. It provides static factory methods and several useful methods (e.g., getByName, getAllByName).

2. NameService Interface

InetAddress[] lookupAllHostAddr(String host) // get all IPs for a host
String getHostByAddr(byte[] ip) // reverse lookup

NameService resides in sun.net.spi.nameservice and is an SPI that InetAddress can load via the Service Provider Interface mechanism.

3. InetAddress Source Code (DNS Part)

The DNS resolution code in InetAddress maintains a static list of NameService implementations. It first tries to load providers defined by the property sun.net.spi.nameservice.provider.. If none are found, a default provider is created.

static {
    // create the impl
    impl = InetAddressImplFactory.create();
    // get name service if provided and requested
    String provider = null;
    String propPrefix = "sun.net.spi.nameservice.provider.";
    int n = 1;
    nameServices = new ArrayList<NameService>();
    provider = AccessController.doPrivileged(new GetPropertyAction(propPrefix + n));
    while (provider != null) {
        NameService ns = createNSProvider(provider);
        if (ns != null) nameServices.add(ns);
        n++;
        provider = AccessController.doPrivileged(new GetPropertyAction(propPrefix + n));
    }
    if (nameServices.size() == 0) {
        NameService ns = createNSProvider("default");
        nameServices.add(ns);
    }
}

DNS results are cached inside InetAddress. The cache policy InetAddressCachePolicy.NEVER disables caching.

public CacheEntry get(String host) {
    int policy = getPolicy();
    // if policy is NEVER, return null (no cache)
    if (policy == InetAddressCachePolicy.NEVER) {
        return null;
    }
    CacheEntry entry = cache.get(host);
    if (entry != null && policy != InetAddressCachePolicy.FOREVER) {
        if (entry.expiration >= 0 && entry.expiration < System.currentTimeMillis()) {
            cache.remove(host);
            entry = null;
        }
    }
    return entry;
}

4. dnsjava Library

dnsjava is a third‑party Java DNS implementation that supports various record types and can act as a mini DNS server or specify custom name servers. The article only mentions it briefly because the solution sometimes uses dnsjava to set an external name server.

Implementation

1. Solution Overview

The solution consists of two steps:

Provide a custom NameService implementation to replace the system default.

Disable DNS caching.

2. Custom NameService (LocalManagedDnsProxy)

@Override
public InetAddress[] lookupAllHostAddr(String name) throws UnknownHostException {
    InetAddress ipAddresses = instance.get(name);
    if (ipAddresses == null) {
        // fallback to default DNS implementation
        return defaultDnsImpl.lookupAllHostAddr(name);
    }
    return new InetAddress[]{ipAddresses};
}

3. NameStore Cache

private final Map<String, InetAddress> globalNames = new ConcurrentHashMap<>();
public void put(String hostName, String ipAddress) {
    try {
        InetAddress ip = InetAddress.getByAddress(DnsUtils.textToNumericFormat(ipAddress));
        globalNames.put(hostName, ip);
    } catch (UnknownHostException ignored) {}
}
public InetAddress get(String hostName) {
    return globalNames.get(hostName);
}
public void remove(String hostName) {
    globalNames.remove(hostName);
}

4. Using dnsjava to Set an External Name Server

SimpleResolver resolver = new SimpleResolver(nameServer);
Lookup.setDefaultResolver(resolver);

5. Injecting the Custom DNS Service into InetAddress

protected void setNameServiceReflectively() {
    List<NameService> nameServices = (List<NameService>) ReflectionUtils.getStaticFieldValue(
        InetAddress.class, "nameServices");
    if (nameServices != null) {
        nameServices.add(0, new LocalManagedDnsProxy());
    }
}

6. Disabling DNS Cache

Two ways exist: setting networkaddress.cache.ttl=0 in java.security, or calling Security.setProperty("networkaddress.cache.ttl", "0") before the cache policy is initialized. The article uses reflection to modify the internal cache policy directly.

private void setCachePolicyReflectively() {
    try {
        ReflectionUtils.setStaticFieldValue(InetAddressCachePolicy.class, "cachePolicy", 0);
    } catch (Exception e) {
        logger.error("failed to set cachePolicy", e);
    }
}

Verification

A JUnit test demonstrates the effect:

@Test
public void testChangeDns() throws UnknownHostException {
    // add custom DNS entry
    NameStore.getInstance().put("www.baidu.com", "133.3.33.33");
    InetAddress inet = InetAddress.getByName("www.baidu.com");
    System.out.println("wrong address: " + inet);
    // remove custom entry
    NameStore.getInstance().remove("www.baidu.com");
    inet = InetAddress.getByName("www.baidu.com");
    System.out.println("original address: " + inet);
}

Console output shows the overridden address (133.3.33.33) and the original address after removal, confirming that dynamic DNS manipulation works.

Conclusion

The article demonstrates how to dynamically replace Java’s default DNS resolver and cache via reflection, enabling flexible DNS handling in automated test cases. With this approach, any test running in the same JVM can redirect domain requests to arbitrary IPs without hard‑coding, simplifying environment management and avoiding DNS conflicts in concurrent Jenkins jobs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaReflectionDNSautomation testingCustom NameService
Vipshop Quality Engineering
Written by

Vipshop Quality Engineering

Technology exchange and sharing for quality engineering

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.