/*- * Copyright (C) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * * This file was distributed by Oracle as part of a version of Oracle Berkeley * DB Java Edition made available at: * * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html * * Please see the LICENSE file included in the top-level directory of the * appropriate version of Oracle Berkeley DB Java Edition for a copy of the * license and additional information. */ package com.sleepycat.je.rep.utilint; import java.lang.reflect.Field; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.logging.Logger; import sun.net.spi.nameservice.NameService; import sun.net.spi.nameservice.NameServiceDescriptor; import com.sleepycat.je.utilint.LoggerUtils; /** * Define a JDK name service provider that can be controlled by tests to * simulate DNS failures. The idea is to define dummy DNS names that translate * to the loopback address, and then undefine them as needed. * *
To use this class, you need to make a few modifications to the JVM that * wants to use it:
META-INF/services/sun.net.spi.nameservice.NameService
, which
* contains the fully qualified name of the {@link Descriptor} class. You can
* do that by create a file with that pathname relative to a component of the
* classpath.
*
* * -Dsun.net.spi.nameservice.provider.1=dns,default * -Dsun.net.spi.nameservice.provider.2=dns,localalias ** Note that these properties need to be set on the command line so they are * available at JVM startup time. * *
The cache policy values specify the time in milliseconds that the
* cache should remain valid, with 0 meaning don't cache and -1 meaning
* cache stays valid forever.
*
* @param positive the cache policy for successful lookups
* @param negative the cache policy for unsuccessful lookups
* @return an array of the previous cache policies, with the positive cache
* value appearing first
*/
public static int[] setDNSCachePolicy(int positive, int negative) {
try {
Class> cachePolicyClass
= Class.forName("sun.net.InetAddressCachePolicy");
Field positiveField =
cachePolicyClass.getDeclaredField("cachePolicy");
positiveField.setAccessible(true);
Field negativeField =
cachePolicyClass.getDeclaredField("negativeCachePolicy");
negativeField.setAccessible(true);
int[] result = new int[2];
synchronized (cachePolicyClass) {
result[0] = positiveField.getInt(null);
result[1] = negativeField.getInt(null);
positiveField.setInt(null, positive);
negativeField.setInt(null, negative);
}
return result;
} catch (Exception e) {
throw new RuntimeException(
"Unexpected exception when setting DNS cache: " + e, e);
}
}
/**
* This implementation returns the loopback address for hosts that match a
* current alias.
*/
@Override
public InetAddress[] lookupAllHostAddr(String host)
throws UnknownHostException {
if (!aliases.contains(host)) {
logger.info("LocalAliasNameService.lookupAllHostAddr:" +
" Unknown host: " + host);
throw new UnknownHostException("Unknown host: " + host);
}
final InetAddress lh = getLocalHost();
logger.info("LocalAliasNameService.lookupAllHostAddr:" + host +
" => " + lh);
return new InetAddress[] { lh };
}
/**
* Compute the local host if needed, avoiding circularities. The main name
* service provider should provide the local host when called from
* InetAddress.getLocalHost, so it should be OK to throw
* UnknownHostException if this method is called recursively.
*/
private static synchronized InetAddress getLocalHost()
throws UnknownHostException {
if (localHost == null) {
if (computingLocalHost) {
throw new UnknownHostException("Local host");
}
computingLocalHost = true;
try {
localHost = InetAddress.getLocalHost();
} finally {
computingLocalHost = false;
}
}
return localHost;
}
/**
* This implementation returns one of the current aliases if the argument
* matches the loopback address and there is at least one alias.
*/
@Override
public String getHostByAddr(byte[] addr)
throws UnknownHostException {
final InetAddress inetAddr = InetAddress.getByAddress(addr);
if (!getLocalHost().equals(inetAddr.getHostAddress())) {
logger.info("LocalAliasNameService.getHostByAddr:" +
" No mapping for address");
throw new UnknownHostException("No mapping for address");
}
synchronized (aliases) {
final Iterator