Java DNS 高速缓存查看器

2022-09-02 02:55:05

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


答案 1

下面是一个用于打印正负 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);
    }
  }
}

答案 2

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$Cachejava.net.InetAddressprivate

/*
 * 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);

所以我怀疑你会发现任何事情都是开箱即用的,并猜测你必须通过反思来实现你的目标。


推荐