Java DNS缓存查看器

Cha*_*tni 18 java dns networking

有没有办法查看/转储java.net api使用的DNS缓存?

Cha*_*tni 19

这是一个打印正负DNS地址缓存的脚本.

import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class DNSCache {
  public static void main(String[] args) throws Exception {
    InetAddress.getByName("stackoverflow.com");
    InetAddress.getByName("www.google.com");
    InetAddress.getByName("www.yahoo.com");
    InetAddress.getByName("www.example.com");
    try {
        InetAddress.getByName("nowhere.example.com");
    } catch (UnknownHostException e) {

    }

    String addressCache = "addressCache";
    System.out.println(addressCache);
    printDNSCache(addressCache);
    String negativeCache = "negativeCache";
    System.out.println(negativeCache);
    printDNSCache(negativeCache);
  }
  private static void printDNSCache(String cacheName) throws Exception {
    Class<InetAddress> klass = InetAddress.class;
    Field acf = klass.getDeclaredField(cacheName);
    acf.setAccessible(true);
    Object addressCache = acf.get(null);
    Class cacheKlass = addressCache.getClass();
    Field cf = cacheKlass.getDeclaredField("cache");
    cf.setAccessible(true);
    Map<String, Object> cache = (Map<String, Object>) cf.get(addressCache);
    for (Map.Entry<String, Object> hi : cache.entrySet()) {
        Object cacheEntry = hi.getValue();
        Class cacheEntryKlass = cacheEntry.getClass();
        Field expf = cacheEntryKlass.getDeclaredField("expiration");
        expf.setAccessible(true);
        long expires = (Long) expf.get(cacheEntry);

        Field af = cacheEntryKlass.getDeclaredField("address");
        af.setAccessible(true);
        InetAddress[] addresses = (InetAddress[]) af.get(cacheEntry);
        List<String> ads = new ArrayList<String>(addresses.length);
        for (InetAddress address : addresses) {
            ads.add(address.getHostAddress());
        }

        System.out.println(hi.getKey() + " "+new Date(expires) +" " +ads);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Pas*_*ent 17

java.net.InetAddress成功和不成功的主机名解析的用途缓存.

从它的javadoc:

InetAddress类具有用于存储成功和不成功主机名解析的缓存.

默认情况下,安装安全管理器时,为了防止DNS欺骗攻击,正主机名解析的结果将永久缓存.未安装安全管理器时,默认行为是缓存有限(依赖于实现)时间段的条目.主机名解析失败的结果会在非常短的时间(10秒)内缓存,以提高性能.

如果不需要默认行为,则可以将Java安全属性设置为正缓存的不同生存时间(TTL)值.同样,系统管理员可以在需要时配置不同的负缓存TTL值.

两个Java安全属性控制用于正面和负面主机名解析缓存的TTL值:

  • networkaddress.cache.ttl
    表示从名称服务成功进行名称查找的缓存策略.该值指定为整数,以指示缓存成功查找的秒数.默认设置是缓存特定于实现的时间段.

    值-1表示"永远缓存".

  • networkaddress.cache.negative.ttl(默认值:10)
    表示来自名称服务的未成功名称查找的缓存策略.该值指定为整数,以指示缓存未成功查找失败的秒数.

    值0表示"从不缓存".值-1表示"永远缓存".

如果你想到的是转储使用的缓存(类型java.net.InetAddress$Cache)java.net.InetAddress,它们是内部实现细节,因此private:

/*
 * Cached addresses - our own litle nis, not!
 */
private static Cache addressCache = new Cache(Cache.Type.Positive);

private static Cache negativeCache = new Cache(Cache.Type.Negative);
Run Code Online (Sandbox Code Playgroud)

所以我怀疑你会发现任何开箱即用的东西,并猜测你必须玩反射来实现你的目标.


小智 5

以上答案不再适用于 Java 8。这里稍作修改:

import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class DNSCache {
    public static void main(String[] args) throws Exception {
        InetAddress.getByName("stackoverflow.com");
        InetAddress.getByName("www.google.com");
        InetAddress.getByName("www.yahoo.com");
        InetAddress.getByName("www.example.com");
        try {
            InetAddress.getByName("nowhere.example.com");
        } catch (UnknownHostException e) {

        }

        String addressCache = "addressCache";
        System.out.println(addressCache);
        printDNSCache(addressCache);
        String negativeCache = "negativeCache";
        System.out.println(negativeCache);
        printDNSCache(negativeCache);
    }

    private static void printDNSCache(String cacheName) throws Exception {
        Class<InetAddress> klass = InetAddress.class;
        Field acf = klass.getDeclaredField(cacheName);
        acf.setAccessible(true);
        Object addressCache = acf.get(null);
        Class cacheKlass = addressCache.getClass();
        Field cf = cacheKlass.getDeclaredField("cache");
        cf.setAccessible(true);
        Map<String, Object> cache = (Map<String, Object>) cf.get(addressCache);
        for (Map.Entry<String, Object> hi : cache.entrySet()) {
            Object cacheEntry = hi.getValue();
            Class cacheEntryKlass = cacheEntry.getClass();
            Field expf = cacheEntryKlass.getDeclaredField("expiration");
            expf.setAccessible(true);
            long expires = (Long) expf.get(cacheEntry);

            Field af = cacheEntryKlass.getDeclaredField("addresses");
            af.setAccessible(true);
            InetAddress[] addresses = (InetAddress[]) af.get(cacheEntry);
            List<String> ads = new ArrayList<String>(addresses.length);
            for (InetAddress address : addresses) {
                ads.add(address.getHostAddress());
            }

            System.out.println(hi.getKey() + " expires in "
                    + Instant.now().until(Instant.ofEpochMilli(expires), ChronoUnit.SECONDS) + " seconds " + ads);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)