net.lightbody.bmp.proxy.dns.NativeCacheManipulatingResolver Maven / Gradle / Ivy
package net.lightbody.bmp.proxy.dns;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;
/**
* An {@link net.lightbody.bmp.proxy.dns.AdvancedHostResolver} that provides native JVM lookup using {@link net.lightbody.bmp.proxy.dns.NativeResolver}
* but also implements DNS cache manipulation functionality.
*
* Important note: The Oracle JVM does not provide any public facility to manipulate the JVM's DNS cache. This class uses reflection to forcibly
* manipulate the cache, which includes access to private class members that are not part of the published Java specification. As such, this
* implementation is brittle and may break in a future Java release, or may not work on non-Oracle JVMs. If this implementation cannot
* perform any of its operations due to a failure to find or set the relevant field using reflection, it will log a warning but will not
* throw an exception. You are using this class at your own risk! JVM cache manipulation does not work on Windows -- this class will behave exactly
* the same as {@link net.lightbody.bmp.proxy.dns.NativeResolver} on that platform.
*/
public class NativeCacheManipulatingResolver extends NativeResolver {
private static final Logger log = LoggerFactory.getLogger(NativeCacheManipulatingResolver.class);
@Override
public void clearDNSCache() {
// clear the DNS cache but replacing the LinkedHashMaps that contain the positive and negative caches on the
// private static InetAddress.Cache inner class with new, empty maps
try {
Field positiveCacheField = InetAddress.class.getDeclaredField("addressCache");
positiveCacheField.setAccessible(true);
Object positiveCacheInstance = positiveCacheField.get(null);
Field negativeCacheField = InetAddress.class.getDeclaredField("negativeCache");
negativeCacheField.setAccessible(true);
Object negativeCacheInstance = positiveCacheField.get(null);
Class> cacheClass = Class.forName("java.net.InetAddress$Cache");
Field cacheField = cacheClass.getDeclaredField("cache");
cacheField.setAccessible(true);
cacheField.set(positiveCacheInstance, new LinkedHashMap());
cacheField.set(negativeCacheInstance, new LinkedHashMap());
} catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) {
log.warn("Unable to clear native JVM DNS cache", e);
}
}
@Override
public void setPositiveDNSCacheTimeout(int timeout, TimeUnit timeUnit) {
try {
Class> inetAddressCachePolicyClass = Class.forName("sun.net.InetAddressCachePolicy");
Field positiveCacheTimeoutSeconds = inetAddressCachePolicyClass.getDeclaredField("cachePolicy");
positiveCacheTimeoutSeconds.setAccessible(true);
if (timeout < 0) {
positiveCacheTimeoutSeconds.setInt(null, -1);
java.security.Security.setProperty("networkaddress.cache.ttl", "-1");
} else {
positiveCacheTimeoutSeconds.setInt(null, (int) TimeUnit.SECONDS.convert(timeout, timeUnit));
java.security.Security.setProperty("networkaddress.cache.ttl", Long.toString(TimeUnit.SECONDS.convert(timeout, timeUnit)));
}
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
log.warn("Unable to modify native JVM DNS cache timeouts", e);
}
}
@Override
public void setNegativeDNSCacheTimeout(int timeout, TimeUnit timeUnit) {
try {
Class> inetAddressCachePolicyClass = Class.forName("sun.net.InetAddressCachePolicy");
Field negativeCacheTimeoutSeconds = inetAddressCachePolicyClass.getDeclaredField("negativeCachePolicy");
negativeCacheTimeoutSeconds.setAccessible(true);
if (timeout < 0) {
negativeCacheTimeoutSeconds.setInt(null, -1);
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "-1");
} else {
negativeCacheTimeoutSeconds.setInt(null, (int) TimeUnit.SECONDS.convert(timeout, timeUnit));
java.security.Security.setProperty("networkaddress.cache.negative.ttl", Long.toString(TimeUnit.SECONDS.convert(timeout, timeUnit)));
}
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
log.warn("Unable to modify native JVM DNS cache timeouts", e);
}
}
}