2009-12-02 85 views
18

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

+0

我的理解是,你必须有一个DNS服务器执行缓存 - 主机本身不缓存DNS请求。 – 2009-12-02 20:05:37

+2

没有主机缓存。事实上,JRE(与安全经理一起运行)和浏览器“钉住”DNS查找。 – 2009-12-02 20:23:58

+0

dns解析器库通常缓存dns结果,因此它们不必打扰服务器那么多,并且对调用提供更快的响应 – nos 2009-12-02 20:42:06

回答

18

这是一个脚本,用于打印正面和负面的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); 
    } 
    } 
} 
+0

反思? – Pacerier 2012-07-25 08:50:20

+0

不错的示例:-) – 2012-07-30 08:17:12

+0

如果有人想运行上面的代码使用安全管理器。 (或将其转换为在使用安全管理器运行的servlet引擎中运行),则策略文件中的条目将有助于:授予java.lang.RuntimePermission“accessClassInPackage.sun.net”的权限。 权限java.lang.RuntimePermission“accessDeclaredMembers”; permission java.lang.reflect.ReflectPermission“suppressAccessChecks”; 权限java.net.SocketPermission“*”,“接受,连接,解析”; – 2012-12-19 03:41:14

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使用(类型java.net.InetAddress$Cache)的缓存,它们内部的实现细节,因此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); 

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

1

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