DnsClient now throws UnknownHostException if there is no DNS resolution.
Added a default timeout for DNS queries/etc + method with the timeout as a parameter
This commit is contained in:
parent
542092a7b3
commit
6d7ccb322e
@ -27,6 +27,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@ -72,19 +73,23 @@ import io.netty.util.internal.PlatformDependent;
|
|||||||
public
|
public
|
||||||
class DnsClient extends EndPoint {
|
class DnsClient extends EndPoint {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
http://bugs.java.com/view_bug.do?bug_id=8176361
|
* TODO: verify ResolverConfiguration works as expected!
|
||||||
Previous JDK releases documented how to configure `java.net.InetAddress` to use the JNDI DNS service provider as the name service. This mechanism, and the system properties to configure it, have been removed in JDK 9
|
* http://bugs.java.com/view_bug.do?bug_id=8176361
|
||||||
|
* Previous JDK releases documented how to configure `java.net.InetAddress` to use the JNDI DNS service provider as the name service.
|
||||||
A new mechanism to configure the use of a hosts file has been introduced.
|
* This mechanism, and the system properties to configure it, have been removed in JDK 9
|
||||||
|
*
|
||||||
A new system property `jdk.net.hosts.file` has been defined. When this system property is set, the name and address resolution calls of `InetAddress`, i.e `getByXXX`, retrieve the relevant mapping from the specified file. The structure of this file is equivalent to that of the `/etc/hosts` file.
|
* A new mechanism to configure the use of a hosts file has been introduced.
|
||||||
|
*
|
||||||
When the system property `jdk.net.hosts.file` is set, and the specified file doesn't exist, the name or address lookup will result in an UnknownHostException. Thus, a non existent hosts file is handled as if the file is empty.
|
* A new system property `jdk.net.hosts.file` has been defined. When this system property is set, the name and address resolution calls
|
||||||
|
* of `InetAddress`, i.e `getByXXX`, retrieve the relevant mapping from the specified file. The structure of this file is equivalent to
|
||||||
|
* that of the `/etc/hosts` file.
|
||||||
UP UNTIL java 1.8, one can use org/xbill/DNS/spi, ie: sun.net.dns.ResolverConfiguration
|
*
|
||||||
*/
|
* When the system property `jdk.net.hosts.file` is set, and the specified file doesn't exist, the name or address lookup will result in
|
||||||
|
* an UnknownHostException. Thus, a non existent hosts file is handled as if the file is empty.
|
||||||
|
*
|
||||||
|
* UP UNTIL java 1.8, one can use org/xbill/DNS/spi, ie: sun.net.dns.ResolverConfiguration
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,7 +113,6 @@ UP UNTIL java 1.8, one can use org/xbill/DNS/spi, ie: sun.net.dns.ResolverConfig
|
|||||||
*/
|
*/
|
||||||
public final static List<InetSocketAddress> DEFAULT_DNS_SERVER_LIST = DefaultDnsServerAddressStreamProvider.defaultAddressList();
|
public final static List<InetSocketAddress> DEFAULT_DNS_SERVER_LIST = DefaultDnsServerAddressStreamProvider.defaultAddressList();
|
||||||
|
|
||||||
private static final String ptrSuffix = ".in-addr.arpa";
|
|
||||||
public static final InetAddress[] INET_ADDRESSES = new InetAddress[0];
|
public static final InetAddress[] INET_ADDRESSES = new InetAddress[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -602,41 +606,87 @@ UP UNTIL java 1.8, one can use org/xbill/DNS/spi, ie: sun.net.dns.ResolverConfig
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a specific hostname A/AAAA record.
|
* Resolves a specific hostname A/AAAA record with the default timeout of 5 seconds
|
||||||
*
|
*
|
||||||
* @param hostname the hostname, ie: google.com, that you want to resolve
|
* @param hostname the hostname, ie: google.com, that you want to resolve
|
||||||
* @return the list of resolved InetAddress or null
|
*
|
||||||
|
* @return the list of resolved InetAddress or throws an exception if the hostname cannot be resolved
|
||||||
* @throws UnknownHostException if the hostname cannot be resolved
|
* @throws UnknownHostException if the hostname cannot be resolved
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
List<InetAddress> resolve(String hostname) throws UnknownHostException {
|
List<InetAddress> resolve(String hostname) throws UnknownHostException {
|
||||||
|
return resolve(hostname, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a specific hostname A/AAAA record.
|
||||||
|
*
|
||||||
|
* @param hostname the hostname, ie: google.com, that you want to resolve
|
||||||
|
* @param queryTimeoutSeconds the number of seconds to wait for host resolution
|
||||||
|
*
|
||||||
|
* @return the list of resolved InetAddress or throws an exception if the hostname cannot be resolved
|
||||||
|
* @throws UnknownHostException if the hostname cannot be resolved
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
List<InetAddress> resolve(String hostname, int queryTimeoutSeconds) throws UnknownHostException {
|
||||||
|
if (hostname == null) {
|
||||||
|
throw new UnknownHostException("Cannot submit query for an unknown host");
|
||||||
|
}
|
||||||
|
|
||||||
if (resolver == null) {
|
if (resolver == null) {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// use "resolve", since it handles A/AAAA records + redirects correctly
|
// use "resolve", since it handles A/AAAA records + redirects correctly
|
||||||
final Future<List<InetAddress>> resolve = resolver.resolveAll(hostname);
|
final Future<List<InetAddress>> resolve = resolver.resolveAll(hostname);
|
||||||
final Future<List<InetAddress>> result = resolve.awaitUninterruptibly();
|
|
||||||
|
boolean finished = resolve.awaitUninterruptibly(queryTimeoutSeconds, TimeUnit.SECONDS);
|
||||||
|
|
||||||
// now return whatever value we had
|
// now return whatever value we had
|
||||||
if (result.isSuccess() && result.isDone()) {
|
if (finished && resolve.isSuccess() && resolve.isDone()) {
|
||||||
try {
|
try {
|
||||||
List<InetAddress> now = result.getNow();
|
List<InetAddress> now = resolve.getNow();
|
||||||
return now;
|
return now;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Could not ask question to DNS server", e);
|
String msg = "Could not ask question to DNS server";
|
||||||
return null;
|
logger.error(msg, e);
|
||||||
|
throw new UnknownHostException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.error("Could not ask question to DNS server for A/AAAA record: {}", hostname);
|
String msg = "Could not ask question to DNS server for A/AAAA record: {}";
|
||||||
|
logger.error(msg, hostname);
|
||||||
|
|
||||||
UnknownHostException cause = (UnknownHostException) result.cause();
|
UnknownHostException cause = (UnknownHostException) resolve.cause();
|
||||||
if (cause != null) {
|
if (cause != null) {
|
||||||
throw cause;
|
throw cause;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
throw new UnknownHostException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a specific hostname record, of the specified type (PTR, MX, TXT, etc) with the default timeout of 5 seconds
|
||||||
|
* <p/>
|
||||||
|
* <p/>
|
||||||
|
* Note: PTR queries absolutely MUST end in '.in-addr.arpa' in order for the DNS server to understand it.
|
||||||
|
* -- because of this, we will automatically fix this in case that clients are unaware of this requirement
|
||||||
|
* <p/>
|
||||||
|
* <p/>
|
||||||
|
* Note: A/AAAA queries absolutely MUST end in a '.' -- because of this we will automatically fix this in case that clients are
|
||||||
|
* unaware of this requirement
|
||||||
|
*
|
||||||
|
* @param hostname the hostname, ie: google.com, that you want to resolve
|
||||||
|
* @param type the DnsRecordType you want to resolve (PTR, MX, TXT, etc)
|
||||||
|
*
|
||||||
|
* @return the DnsRecords or throws an exception if the hostname cannot be resolved
|
||||||
|
*
|
||||||
|
* @throws @throws UnknownHostException if the hostname cannot be resolved
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unchecked", "Duplicates"})
|
||||||
|
public
|
||||||
|
DnsRecord[] query(String hostname, final int type) throws UnknownHostException {
|
||||||
|
return query(hostname, type, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -652,32 +702,32 @@ UP UNTIL java 1.8, one can use org/xbill/DNS/spi, ie: sun.net.dns.ResolverConfig
|
|||||||
*
|
*
|
||||||
* @param hostname the hostname, ie: google.com, that you want to resolve
|
* @param hostname the hostname, ie: google.com, that you want to resolve
|
||||||
* @param type the DnsRecordType you want to resolve (PTR, MX, TXT, etc)
|
* @param type the DnsRecordType you want to resolve (PTR, MX, TXT, etc)
|
||||||
* @return the DnsRecords or null if there was an error resolving the hostname
|
* @param queryTimeoutSeconds the number of seconds to wait for host resolution
|
||||||
|
*
|
||||||
|
* @return the DnsRecords or throws an exception if the hostname cannot be resolved
|
||||||
*
|
*
|
||||||
* @throws @throws UnknownHostException if the hostname cannot be resolved
|
* @throws @throws UnknownHostException if the hostname cannot be resolved
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "Duplicates"})
|
@SuppressWarnings({"unchecked", "Duplicates"})
|
||||||
public
|
public
|
||||||
DnsRecord[] query(String hostname, final int type) throws UnknownHostException {
|
DnsRecord[] query(String hostname, final int type, int queryTimeoutSeconds) throws UnknownHostException {
|
||||||
if (resolver == null) {
|
if (hostname == null) {
|
||||||
start();
|
throw new UnknownHostException("Cannot submit query for an unknown host");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == DnsRecordType.PTR && !hostname.endsWith(ptrSuffix)) {
|
if (resolver == null) {
|
||||||
// PTR absolutely MUST end in '.in-addr.arpa' in order for the DNS server to understand it.
|
start();
|
||||||
// in this case, hostname is an ip address
|
|
||||||
hostname += ptrSuffix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use our own resolvers
|
// we use our own resolvers
|
||||||
DnsQuestion dnsMessage = DnsQuestion.newQuery(hostname, type, recursionDesired);
|
DnsQuestion dnsMessage = DnsQuestion.newQuery(hostname, type, recursionDesired);
|
||||||
|
|
||||||
final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query = resolver.query(dnsMessage);
|
final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query = resolver.query(dnsMessage);
|
||||||
final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> result = query.awaitUninterruptibly();
|
boolean finished = query.awaitUninterruptibly(queryTimeoutSeconds, TimeUnit.SECONDS);
|
||||||
|
|
||||||
// now return whatever value we had
|
// now return whatever value we had
|
||||||
if (result.isSuccess() && result.isDone()) {
|
if (finished && query.isSuccess() && query.isDone()) {
|
||||||
AddressedEnvelope<DnsResponse, InetSocketAddress> envelope = result.getNow();
|
AddressedEnvelope<DnsResponse, InetSocketAddress> envelope = query.getNow();
|
||||||
DnsResponse response = envelope.content();
|
DnsResponse response = envelope.content();
|
||||||
try {
|
try {
|
||||||
final int code = response.getHeader().getRcode();
|
final int code = response.getHeader().getRcode();
|
||||||
@ -685,24 +735,24 @@ UP UNTIL java 1.8, one can use org/xbill/DNS/spi, ie: sun.net.dns.ResolverConfig
|
|||||||
return response.getSectionArray(DnsSection.ANSWER);
|
return response.getSectionArray(DnsSection.ANSWER);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.error("Could not ask question to DNS server: Error code {} for type: {} - {}",
|
String msg = "Could not ask question to DNS server: Error code " + code + " for type: " + type + " - " + DnsRecordType.string(type);
|
||||||
code, type, DnsRecordType.string(type));
|
logger.error(msg);
|
||||||
|
|
||||||
logger.error("Could not ask question to DNS server: Error code {}", code);
|
throw new UnknownHostException(msg);
|
||||||
return null;
|
|
||||||
} finally {
|
} finally {
|
||||||
response.release();
|
response.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.error("Could not ask question to DNS server for type: {}", DnsRecordType.string(type));
|
String msg = "Could not ask question to DNS server for type: " + DnsRecordType.string(type);
|
||||||
|
logger.error(msg);
|
||||||
|
|
||||||
UnknownHostException cause = (UnknownHostException) result.cause();
|
UnknownHostException cause = (UnknownHostException) query.cause();
|
||||||
if (cause != null) {
|
if (cause != null) {
|
||||||
throw cause;
|
throw cause;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
throw new UnknownHostException(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user