Java DNS 缓存查看器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1835421/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java DNS cache viewer
提问by Chandra Patni
Is there a way to view/dump DNS cached used by java.net api?
有没有办法查看/转储 java.net api 使用的 DNS 缓存?
采纳答案by Chandra Patni
Here is a script to print the positive and negative DNS address cache.
这是一个打印正负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);
}
}
}
回答by Pascal Thivent
The java.net.InetAddressuses caching of successful and unsuccessful host name resolutions.
在java.net.InetAddress使用缓存成功和不成功的主机名解析的。
From its javadoc:
从它的javadoc:
The InetAddress class has a cache to store successful as well as unsuccessful host name resolutions.
By default, when a security manager is installed, in order to protect against DNS spoofing attacks, the result of positive host name resolutions are cached forever. When a security manager is not installed, the default behavior is to cache entries for a finite (implementation dependent) period of time. The result of unsuccessful host name resolution is cached for a very short period of time (10 seconds) to improve performance.
If the default behavior is not desired, then a Java security property can be set to a different Time-to-live (TTL) value for positive caching. Likewise, a system admin can configure a different negative caching TTL value when needed.
Two Java security properties control the TTL values used for positive and negative host name resolution caching:
networkaddress.cache.ttl
Indicates the caching policy for successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the successful lookup. The default setting is to cache for an implementation specific period of time.A value of -1 indicates "cache forever".
networkaddress.cache.negative.ttl(default: 10)
Indicates the caching policy for un-successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the failure for un-successful lookups.A value of 0 indicates "never cache". A value of -1 indicates "cache forever".
InetAddress 类有一个缓存来存储成功和不成功的主机名解析。
默认情况下,当安装了安全管理器时,为了防止 DNS 欺骗攻击,主机名解析的结果会被永久缓存。当未安装安全管理器时,默认行为是在有限的(依赖于实现的)时间段内缓存条目。主机名解析失败的结果会缓存很短的时间(10 秒)以提高性能。
如果不需要默认行为,则可以将 Java 安全属性设置为不同的生存时间 (TTL) 值以进行正缓存。同样,系统管理员可以在需要时配置不同的负缓存 TTL 值。
两个 Java 安全属性控制用于正负主机名解析缓存的 TTL 值:
networkaddress.cache.ttl
指示从名称服务成功进行名称查找的缓存策略。该值指定为整数以指示缓存成功查找的秒数。默认设置是缓存一段特定于实现的时间。值 -1 表示“永远缓存”。
networkaddress.cache.negative.ttl(默认值:10)
指示名称服务不成功的名称查找的缓存策略。该值指定为整数,以指示为不成功的查找缓存失败的秒数。值 0 表示“从不缓存”。值 -1 表示“永远缓存”。
If what you have in mind is dumping the caches (of type java.net.InetAddress$Cache) used by java.net.InetAddress, they are internal implementation details and thus private:
如果您想到的是转储 使用的缓存(类型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);
So I doubt you'll find anything doing this out of the box and guess that you'll have to play with reflection to achieve your goal.
所以我怀疑你会发现任何开箱即用的方法,并猜测你必须通过反思来实现你的目标。
回答by Simon Flandergan
Above answer does not work in Java 8 anymore. Here a slight adaption:
以上答案不再适用于 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);
}
}
}

