Java DNS缓存查看器

时间:2009-12-02 20:03:15

标签: java networking dns

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

4 个答案:

答案 0 :(得分: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);
    }
  }
}

答案 1 :(得分:17)

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

来自其javadoc:

  

InetAddress类有一个缓存   商店成功以及   不成功的主机名解析。

     

默认情况下,安全管理器是   安装,以防止   DNS欺骗攻击的结果   积极的主机名称解析是   永远缓存。当一个安全   管理员未安装,默认   行为是缓存a的条目   有限的(依赖于实现)   一段的时间。的结果   主机名解析不成功   缓存很短的时间   (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);

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

答案 2 :(得分:3)

上面的答案在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);
        }
    }
}

答案 3 :(得分:0)

以上答案不适用于Java11。在Java 11中,可以使用'cache'实例变量来检索肯定和否定缓存条目。 这是新的改编:

import java.net.InetAddress;
import java.net.UnknownHostException;
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;
import java.util.concurrent.ConcurrentHashMap;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

public class DnsCacheFetcher {
static long startTimeinNano = System.nanoTime();

public static void main(String[] args) throws Exception {

    System.out.println("SecurityManager: " + System.getSecurityManager());

    InetAddress.getByName("stackoverflow.com");
    InetAddress.getByName("www.google.com");
    InetAddress.getByName("www.yahoo.com");
    InetAddress.getByName("www.ankit.com");

    try {
        InetAddress.getByName("nowhere.example.com");
    } catch (UnknownHostException e) {
        System.out.println("Unknown host: " + e);
    }

    String addressCache = "cache";
    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[] fields = klass.getDeclaredFields();

    /*
     * for (Field field : fields) { System.out.println(field.getName()); }
     */

    Field acf = klass.getDeclaredField(cacheName);
    acf.setAccessible(true);
    Object addressCache = acf.get(null);
    Class cacheKlass = addressCache.getClass();

    Map<String, Object> cache = (Map<String, Object>) acf.get(addressCache);
    for (Map.Entry<String, Object> hi : cache.entrySet()) {
        /* System.out.println("Fetching cache for: " + hi.getKey()); */
        Object cacheEntry = hi.getValue();
        Class cacheEntryKlass = cacheEntry.getClass();
        Field expf = cacheEntryKlass.getDeclaredField("expiryTime");
        expf.setAccessible(true);
        long expires = (Long) expf.get(cacheEntry);

        Field af = cacheEntryKlass.getDeclaredField("inetAddresses");
        af.setAccessible(true);
        InetAddress[] addresses = (InetAddress[]) af.get(cacheEntry);
        List<String> ads = null;
        if (addresses != null) {
            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. inetAddresses: " + ads);
         */

        /*
         * System.nanoTime() + 1000_000_000L * cachePolicy : this how java 11 set
         * expiryTime
         */
        System.out.println(hi.getKey() + " expires in approx " + (expires - startTimeinNano) / 1000_000_000L
                + " seconds. inetAddresses: " + ads);


    }
}

}