HostsFileParser should allow both IPv4 and IPv6 for a given host
Motivation: HostsFileParser only retains the first address for each given hostname. This is wrong, and it’s allowed to have both an IPv4 and an IPv6. Modifications: * Have `HostsFileParser` now return a `HostsFileEntries` that contains IPv4 entries and IPv6 entries * Introduce `ResolvedAddressTypes` to describe resolved address types preferences * Add a new `ResolvedAddressTypes` parameter to `HostsFileEntriesResolver::address` to account for address types preferences * Change `DnsNameResolver` constructor to take a `ResolvedAddressTypes`, allowing for a null value that would use default * Change `DnsNameResolverBuilder::resolvedAddressTypes` to take a `ResolvedAddressTypes` * Make `DnsNameResolver::resolvedAddressTypes` return a `ResolvedAddressTypes` * Add a static `DnsNameResolverBuilder::computeResolvedAddressTypes` to ease converting from `InternetProtocolFamily` Result: We now support hosts files that contains IPv4 and IPv6 pairs for a same hostname.
This commit is contained in:
parent
64abef5f5b
commit
81f9de423c
@ -39,6 +39,7 @@ import io.netty.handler.codec.dns.DnsRecordType;
|
|||||||
import io.netty.handler.codec.dns.DnsResponse;
|
import io.netty.handler.codec.dns.DnsResponse;
|
||||||
import io.netty.resolver.HostsFileEntriesResolver;
|
import io.netty.resolver.HostsFileEntriesResolver;
|
||||||
import io.netty.resolver.InetNameResolver;
|
import io.netty.resolver.InetNameResolver;
|
||||||
|
import io.netty.resolver.ResolvedAddressTypes;
|
||||||
import io.netty.util.NetUtil;
|
import io.netty.util.NetUtil;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
import io.netty.util.concurrent.FastThreadLocal;
|
import io.netty.util.concurrent.FastThreadLocal;
|
||||||
@ -56,13 +57,10 @@ import java.net.IDN;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
|
import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
|
||||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
@ -78,24 +76,37 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsNameResolver.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DnsNameResolver.class);
|
||||||
private static final String LOCALHOST = "localhost";
|
private static final String LOCALHOST = "localhost";
|
||||||
private static final InetAddress LOCALHOST_ADDRESS;
|
private static final InetAddress LOCALHOST_ADDRESS;
|
||||||
private static final DnsRecord[] EMTPY_ADDITIONALS = new DnsRecord[0];
|
private static final DnsRecord[] EMPTY_ADDITIONALS = new DnsRecord[0];
|
||||||
|
private static final DnsRecordType[] IPV4_ONLY_RESOLVED_RECORD_TYPES =
|
||||||
|
new DnsRecordType[] {DnsRecordType.A};
|
||||||
|
private static final InternetProtocolFamily[] IPV4_ONLY_RESOLVED_PROTOCOL_FAMILIES =
|
||||||
|
new InternetProtocolFamily[] {InternetProtocolFamily.IPv4};
|
||||||
|
private static final DnsRecordType[] IPV4_PREFERRED_RESOLVED_RECORD_TYPES =
|
||||||
|
new DnsRecordType[] {DnsRecordType.A, DnsRecordType.AAAA};
|
||||||
|
private static final InternetProtocolFamily[] IPV4_PREFERRED_RESOLVED_PROTOCOL_FAMILIES =
|
||||||
|
new InternetProtocolFamily[] {InternetProtocolFamily.IPv4, InternetProtocolFamily.IPv6};
|
||||||
|
private static final DnsRecordType[] IPV6_ONLY_RESOLVED_RECORD_TYPES =
|
||||||
|
new DnsRecordType[] {DnsRecordType.AAAA};
|
||||||
|
private static final InternetProtocolFamily[] IPV6_ONLY_RESOLVED_PROTOCOL_FAMILIES =
|
||||||
|
new InternetProtocolFamily[] {InternetProtocolFamily.IPv6};
|
||||||
|
private static final DnsRecordType[] IPV6_PREFERRED_RESOLVED_RECORD_TYPES =
|
||||||
|
new DnsRecordType[] {DnsRecordType.AAAA, DnsRecordType.A};
|
||||||
|
private static final InternetProtocolFamily[] IPV6_PREFERRED_RESOLVED_PROTOCOL_FAMILIES =
|
||||||
|
new InternetProtocolFamily[] {InternetProtocolFamily.IPv6, InternetProtocolFamily.IPv4};
|
||||||
|
|
||||||
static final InternetProtocolFamily[] DEFAULT_RESOLVE_ADDRESS_TYPES;
|
static final ResolvedAddressTypes DEFAULT_RESOLVE_ADDRESS_TYPES;
|
||||||
static final String[] DEFAULT_SEACH_DOMAINS;
|
static final String[] DEFAULT_SEARCH_DOMAINS;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
if (NetUtil.isIpV4StackPreferred()) {
|
if (NetUtil.isIpV4StackPreferred()) {
|
||||||
DEFAULT_RESOLVE_ADDRESS_TYPES = new InternetProtocolFamily[] { InternetProtocolFamily.IPv4 };
|
DEFAULT_RESOLVE_ADDRESS_TYPES = ResolvedAddressTypes.IPV4_ONLY;
|
||||||
LOCALHOST_ADDRESS = NetUtil.LOCALHOST4;
|
LOCALHOST_ADDRESS = NetUtil.LOCALHOST4;
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_RESOLVE_ADDRESS_TYPES = new InternetProtocolFamily[2];
|
|
||||||
if (NetUtil.isIpV6AddressesPreferred()) {
|
if (NetUtil.isIpV6AddressesPreferred()) {
|
||||||
DEFAULT_RESOLVE_ADDRESS_TYPES[0] = InternetProtocolFamily.IPv6;
|
DEFAULT_RESOLVE_ADDRESS_TYPES = ResolvedAddressTypes.IPV6_PREFERRED;
|
||||||
DEFAULT_RESOLVE_ADDRESS_TYPES[1] = InternetProtocolFamily.IPv4;
|
|
||||||
LOCALHOST_ADDRESS = NetUtil.LOCALHOST6;
|
LOCALHOST_ADDRESS = NetUtil.LOCALHOST6;
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_RESOLVE_ADDRESS_TYPES[0] = InternetProtocolFamily.IPv4;
|
DEFAULT_RESOLVE_ADDRESS_TYPES = ResolvedAddressTypes.IPV4_PREFERRED;
|
||||||
DEFAULT_RESOLVE_ADDRESS_TYPES[1] = InternetProtocolFamily.IPv6;
|
|
||||||
LOCALHOST_ADDRESS = NetUtil.LOCALHOST4;
|
LOCALHOST_ADDRESS = NetUtil.LOCALHOST4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +127,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
// Failed to get the system name search domain list.
|
// Failed to get the system name search domain list.
|
||||||
searchDomains = EmptyArrays.EMPTY_STRINGS;
|
searchDomains = EmptyArrays.EMPTY_STRINGS;
|
||||||
}
|
}
|
||||||
DEFAULT_SEACH_DOMAINS = searchDomains;
|
DEFAULT_SEARCH_DOMAINS = searchDomains;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final DatagramDnsResponseDecoder DECODER = new DatagramDnsResponseDecoder();
|
private static final DatagramDnsResponseDecoder DECODER = new DatagramDnsResponseDecoder();
|
||||||
@ -148,7 +159,8 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
private final long queryTimeoutMillis;
|
private final long queryTimeoutMillis;
|
||||||
private final int maxQueriesPerResolve;
|
private final int maxQueriesPerResolve;
|
||||||
private final boolean traceEnabled;
|
private final boolean traceEnabled;
|
||||||
private final InternetProtocolFamily[] resolvedAddressTypes;
|
private final ResolvedAddressTypes resolvedAddressTypes;
|
||||||
|
private final InternetProtocolFamily[] resolvedInternetProtocolFamilies;
|
||||||
private final boolean recursionDesired;
|
private final boolean recursionDesired;
|
||||||
private final int maxPayloadSize;
|
private final int maxPayloadSize;
|
||||||
private final boolean optResourceEnabled;
|
private final boolean optResourceEnabled;
|
||||||
@ -161,49 +173,6 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
private final DnsRecordType[] resolveRecordTypes;
|
private final DnsRecordType[] resolveRecordTypes;
|
||||||
private final boolean decodeIdn;
|
private final boolean decodeIdn;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
|
|
||||||
*
|
|
||||||
* @param eventLoop the {@link EventLoop} which will perform the communication with the DNS servers
|
|
||||||
* @param channelFactory the {@link ChannelFactory} that will create a {@link DatagramChannel}
|
|
||||||
* @param nameServerAddresses the addresses of the DNS server. For each DNS query, a new stream is created from
|
|
||||||
* this to determine which DNS server should be contacted for the next retry in case
|
|
||||||
* of failure.
|
|
||||||
* @param resolveCache the DNS resolved entries cache
|
|
||||||
* @param queryTimeoutMillis timeout of each DNS query in millis
|
|
||||||
* @param resolvedAddressTypes list of the protocol families
|
|
||||||
* @param recursionDesired if recursion desired flag must be set
|
|
||||||
* @param maxQueriesPerResolve the maximum allowed number of DNS queries for a given name resolution
|
|
||||||
* @param traceEnabled if trace is enabled
|
|
||||||
* @param maxPayloadSize the capacity of the datagram packet buffer
|
|
||||||
* @param optResourceEnabled if automatic inclusion of a optional records is enabled
|
|
||||||
* @param hostsFileEntriesResolver the {@link HostsFileEntriesResolver} used to check for local aliases
|
|
||||||
* @param searchDomains the list of search domain
|
|
||||||
* @param ndots the ndots value
|
|
||||||
* @deprecated use {@link DnsNameResolver#DnsNameResolver(EventLoop, ChannelFactory, DnsServerAddresses, DnsCache,
|
|
||||||
* DnsCache, long, InternetProtocolFamily[], boolean, int, boolean, int, boolean,
|
|
||||||
* HostsFileEntriesResolver, String[], int, boolean)}
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public DnsNameResolver(
|
|
||||||
EventLoop eventLoop,
|
|
||||||
ChannelFactory<? extends DatagramChannel> channelFactory,
|
|
||||||
DnsServerAddresses nameServerAddresses,
|
|
||||||
final DnsCache resolveCache,
|
|
||||||
long queryTimeoutMillis,
|
|
||||||
InternetProtocolFamily[] resolvedAddressTypes,
|
|
||||||
boolean recursionDesired,
|
|
||||||
int maxQueriesPerResolve,
|
|
||||||
boolean traceEnabled,
|
|
||||||
int maxPayloadSize,
|
|
||||||
boolean optResourceEnabled,
|
|
||||||
HostsFileEntriesResolver hostsFileEntriesResolver,
|
|
||||||
String[] searchDomains,
|
|
||||||
int ndots) {
|
|
||||||
this(eventLoop, channelFactory, nameServerAddresses, resolveCache, NoopDnsCache.INSTANCE, queryTimeoutMillis,
|
|
||||||
resolvedAddressTypes, recursionDesired, maxQueriesPerResolve, traceEnabled, maxPayloadSize,
|
|
||||||
optResourceEnabled, hostsFileEntriesResolver, searchDomains, ndots, true);
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
|
* Creates a new DNS-based name resolver that communicates with the specified list of DNS servers.
|
||||||
*
|
*
|
||||||
@ -215,7 +184,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
* @param resolveCache the DNS resolved entries cache
|
* @param resolveCache the DNS resolved entries cache
|
||||||
* @param authoritativeDnsServerCache the cache used to find the authoritative DNS server for a domain
|
* @param authoritativeDnsServerCache the cache used to find the authoritative DNS server for a domain
|
||||||
* @param queryTimeoutMillis timeout of each DNS query in millis
|
* @param queryTimeoutMillis timeout of each DNS query in millis
|
||||||
* @param resolvedAddressTypes list of the protocol families
|
* @param resolvedAddressTypes the preferred address types
|
||||||
* @param recursionDesired if recursion desired flag must be set
|
* @param recursionDesired if recursion desired flag must be set
|
||||||
* @param maxQueriesPerResolve the maximum allowed number of DNS queries for a given name resolution
|
* @param maxQueriesPerResolve the maximum allowed number of DNS queries for a given name resolution
|
||||||
* @param traceEnabled if trace is enabled
|
* @param traceEnabled if trace is enabled
|
||||||
@ -234,7 +203,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
final DnsCache resolveCache,
|
final DnsCache resolveCache,
|
||||||
DnsCache authoritativeDnsServerCache,
|
DnsCache authoritativeDnsServerCache,
|
||||||
long queryTimeoutMillis,
|
long queryTimeoutMillis,
|
||||||
InternetProtocolFamily[] resolvedAddressTypes,
|
ResolvedAddressTypes resolvedAddressTypes,
|
||||||
boolean recursionDesired,
|
boolean recursionDesired,
|
||||||
int maxQueriesPerResolve,
|
int maxQueriesPerResolve,
|
||||||
boolean traceEnabled,
|
boolean traceEnabled,
|
||||||
@ -248,7 +217,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
checkNotNull(channelFactory, "channelFactory");
|
checkNotNull(channelFactory, "channelFactory");
|
||||||
this.nameServerAddresses = checkNotNull(nameServerAddresses, "nameServerAddresses");
|
this.nameServerAddresses = checkNotNull(nameServerAddresses, "nameServerAddresses");
|
||||||
this.queryTimeoutMillis = checkPositive(queryTimeoutMillis, "queryTimeoutMillis");
|
this.queryTimeoutMillis = checkPositive(queryTimeoutMillis, "queryTimeoutMillis");
|
||||||
this.resolvedAddressTypes = checkNonEmpty(resolvedAddressTypes, "resolvedAddressTypes");
|
this.resolvedAddressTypes = resolvedAddressTypes != null ? resolvedAddressTypes : DEFAULT_RESOLVE_ADDRESS_TYPES;
|
||||||
this.recursionDesired = recursionDesired;
|
this.recursionDesired = recursionDesired;
|
||||||
this.maxQueriesPerResolve = checkPositive(maxQueriesPerResolve, "maxQueriesPerResolve");
|
this.maxQueriesPerResolve = checkPositive(maxQueriesPerResolve, "maxQueriesPerResolve");
|
||||||
this.traceEnabled = traceEnabled;
|
this.traceEnabled = traceEnabled;
|
||||||
@ -261,31 +230,38 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
this.ndots = checkPositiveOrZero(ndots, "ndots");
|
this.ndots = checkPositiveOrZero(ndots, "ndots");
|
||||||
this.decodeIdn = decodeIdn;
|
this.decodeIdn = decodeIdn;
|
||||||
|
|
||||||
boolean supportsARecords = false;
|
switch (this.resolvedAddressTypes) {
|
||||||
boolean supportsAAAARecords = false;
|
case IPV4_ONLY:
|
||||||
// Use LinkedHashSet to maintain correct ordering.
|
supportsAAAARecords = false;
|
||||||
Set<DnsRecordType> recordTypes = new LinkedHashSet<DnsRecordType>(resolvedAddressTypes.length);
|
|
||||||
for (InternetProtocolFamily family: resolvedAddressTypes) {
|
|
||||||
switch (family) {
|
|
||||||
case IPv4:
|
|
||||||
supportsARecords = true;
|
supportsARecords = true;
|
||||||
recordTypes.add(DnsRecordType.A);
|
resolveRecordTypes = IPV4_ONLY_RESOLVED_RECORD_TYPES;
|
||||||
|
resolvedInternetProtocolFamilies = IPV4_ONLY_RESOLVED_PROTOCOL_FAMILIES;
|
||||||
|
preferredAddressType = InternetProtocolFamily.IPv4;
|
||||||
break;
|
break;
|
||||||
case IPv6:
|
case IPV4_PREFERRED:
|
||||||
supportsAAAARecords = true;
|
supportsAAAARecords = true;
|
||||||
recordTypes.add(DnsRecordType.AAAA);
|
supportsARecords = true;
|
||||||
|
resolveRecordTypes = IPV4_PREFERRED_RESOLVED_RECORD_TYPES;
|
||||||
|
resolvedInternetProtocolFamilies = IPV4_PREFERRED_RESOLVED_PROTOCOL_FAMILIES;
|
||||||
|
preferredAddressType = InternetProtocolFamily.IPv4;
|
||||||
|
break;
|
||||||
|
case IPV6_ONLY:
|
||||||
|
supportsAAAARecords = true;
|
||||||
|
supportsARecords = false;
|
||||||
|
resolveRecordTypes = IPV6_ONLY_RESOLVED_RECORD_TYPES;
|
||||||
|
resolvedInternetProtocolFamilies = IPV6_ONLY_RESOLVED_PROTOCOL_FAMILIES;
|
||||||
|
preferredAddressType = InternetProtocolFamily.IPv6;
|
||||||
|
break;
|
||||||
|
case IPV6_PREFERRED:
|
||||||
|
supportsAAAARecords = true;
|
||||||
|
supportsARecords = true;
|
||||||
|
resolveRecordTypes = IPV6_PREFERRED_RESOLVED_RECORD_TYPES;
|
||||||
|
resolvedInternetProtocolFamilies = IPV6_PREFERRED_RESOLVED_PROTOCOL_FAMILIES;
|
||||||
|
preferredAddressType = InternetProtocolFamily.IPv6;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error();
|
throw new IllegalArgumentException("Unknown ResolvedAddressTypes " + resolvedAddressTypes);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// One of both must be always true.
|
|
||||||
assert supportsARecords || supportsAAAARecords;
|
|
||||||
this.supportsAAAARecords = supportsAAAARecords;
|
|
||||||
this.supportsARecords = supportsARecords;
|
|
||||||
resolveRecordTypes = recordTypes.toArray(new DnsRecordType[recordTypes.size()]);
|
|
||||||
preferredAddressType = resolvedAddressTypes[0];
|
|
||||||
|
|
||||||
Bootstrap b = new Bootstrap();
|
Bootstrap b = new Bootstrap();
|
||||||
b.group(executor());
|
b.group(executor());
|
||||||
@ -339,16 +315,15 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of the protocol families of the address resolved by {@link #resolve(String)}
|
* Returns the {@link ResolvedAddressTypes} resolved by {@link #resolve(String)}.
|
||||||
* in the order of preference.
|
|
||||||
* The default value depends on the value of the system property {@code "java.net.preferIPv6Addresses"}.
|
* The default value depends on the value of the system property {@code "java.net.preferIPv6Addresses"}.
|
||||||
*/
|
*/
|
||||||
public List<InternetProtocolFamily> resolvedAddressTypes() {
|
public ResolvedAddressTypes resolvedAddressTypes() {
|
||||||
return Arrays.asList(resolvedAddressTypes);
|
return resolvedAddressTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
InternetProtocolFamily[] resolveAddressTypesUnsafe() {
|
InternetProtocolFamily[] resolvedInternetProtocolFamiliesUnsafe() {
|
||||||
return resolvedAddressTypes;
|
return resolvedInternetProtocolFamilies;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String[] searchDomains() {
|
final String[] searchDomains() {
|
||||||
@ -447,7 +422,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
if (hostsFileEntriesResolver == null) {
|
if (hostsFileEntriesResolver == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
InetAddress address = hostsFileEntriesResolver.address(hostname);
|
InetAddress address = hostsFileEntriesResolver.address(hostname, resolvedAddressTypes);
|
||||||
if (address == null && PlatformDependent.isWindows() && LOCALHOST.equalsIgnoreCase(hostname)) {
|
if (address == null && PlatformDependent.isWindows() && LOCALHOST.equalsIgnoreCase(hostname)) {
|
||||||
// If we tried to resolve localhost we need workaround that windows removed localhost from its
|
// If we tried to resolve localhost we need workaround that windows removed localhost from its
|
||||||
// hostfile in later versions.
|
// hostfile in later versions.
|
||||||
@ -526,7 +501,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doResolve(String inetHost, Promise<InetAddress> promise) throws Exception {
|
protected void doResolve(String inetHost, Promise<InetAddress> promise) throws Exception {
|
||||||
doResolve(inetHost, EMTPY_ADDITIONALS, promise, resolveCache);
|
doResolve(inetHost, EMPTY_ADDITIONALS, promise, resolveCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DnsRecord[] toArray(Iterable<DnsRecord> additionals, boolean validateType) {
|
private static DnsRecord[] toArray(Iterable<DnsRecord> additionals, boolean validateType) {
|
||||||
@ -541,7 +516,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
|
|
||||||
Iterator<DnsRecord> additionalsIt = additionals.iterator();
|
Iterator<DnsRecord> additionalsIt = additionals.iterator();
|
||||||
if (!additionalsIt.hasNext()) {
|
if (!additionalsIt.hasNext()) {
|
||||||
return EMTPY_ADDITIONALS;
|
return EMPTY_ADDITIONALS;
|
||||||
}
|
}
|
||||||
List<DnsRecord> records = new ArrayList<DnsRecord>();
|
List<DnsRecord> records = new ArrayList<DnsRecord>();
|
||||||
do {
|
do {
|
||||||
@ -617,7 +592,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
cause = cachedEntries.get(0).cause();
|
cause = cachedEntries.get(0).cause();
|
||||||
} else {
|
} else {
|
||||||
// Find the first entry with the preferred address type.
|
// Find the first entry with the preferred address type.
|
||||||
for (InternetProtocolFamily f : resolvedAddressTypes) {
|
for (InternetProtocolFamily f : resolvedInternetProtocolFamilies) {
|
||||||
for (int i = 0; i < numEntries; i++) {
|
for (int i = 0; i < numEntries; i++) {
|
||||||
final DnsCacheEntry e = cachedEntries.get(i);
|
final DnsCacheEntry e = cachedEntries.get(i);
|
||||||
if (f.addressType().isInstance(e.address())) {
|
if (f.addressType().isInstance(e.address())) {
|
||||||
@ -692,7 +667,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doResolveAll(String inetHost, Promise<List<InetAddress>> promise) throws Exception {
|
protected void doResolveAll(String inetHost, Promise<List<InetAddress>> promise) throws Exception {
|
||||||
doResolveAll(inetHost, EMTPY_ADDITIONALS, promise, resolveCache);
|
doResolveAll(inetHost, EMPTY_ADDITIONALS, promise, resolveCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -746,7 +721,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
if (cachedEntries.get(0).cause() != null) {
|
if (cachedEntries.get(0).cause() != null) {
|
||||||
cause = cachedEntries.get(0).cause();
|
cause = cachedEntries.get(0).cause();
|
||||||
} else {
|
} else {
|
||||||
for (InternetProtocolFamily f : resolvedAddressTypes) {
|
for (InternetProtocolFamily f : resolvedInternetProtocolFamilies) {
|
||||||
for (int i = 0; i < numEntries; i++) {
|
for (int i = 0; i < numEntries; i++) {
|
||||||
final DnsCacheEntry e = cachedEntries.get(i);
|
final DnsCacheEntry e = cachedEntries.get(i);
|
||||||
if (f.addressType().isInstance(e.address())) {
|
if (f.addressType().isInstance(e.address())) {
|
||||||
@ -859,7 +834,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
public Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query(
|
public Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query(
|
||||||
InetSocketAddress nameServerAddr, DnsQuestion question) {
|
InetSocketAddress nameServerAddr, DnsQuestion question) {
|
||||||
|
|
||||||
return query0(nameServerAddr, question, EMTPY_ADDITIONALS,
|
return query0(nameServerAddr, question, EMPTY_ADDITIONALS,
|
||||||
ch.eventLoop().<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>>newPromise());
|
ch.eventLoop().<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>>newPromise());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -880,7 +855,7 @@ public class DnsNameResolver extends InetNameResolver {
|
|||||||
InetSocketAddress nameServerAddr, DnsQuestion question,
|
InetSocketAddress nameServerAddr, DnsQuestion question,
|
||||||
Promise<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>> promise) {
|
Promise<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>> promise) {
|
||||||
|
|
||||||
return query0(nameServerAddr, question, EMTPY_ADDITIONALS, promise);
|
return query0(nameServerAddr, question, EMPTY_ADDITIONALS, promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,6 +23,7 @@ import io.netty.channel.ReflectiveChannelFactory;
|
|||||||
import io.netty.channel.socket.DatagramChannel;
|
import io.netty.channel.socket.DatagramChannel;
|
||||||
import io.netty.channel.socket.InternetProtocolFamily;
|
import io.netty.channel.socket.InternetProtocolFamily;
|
||||||
import io.netty.resolver.HostsFileEntriesResolver;
|
import io.netty.resolver.HostsFileEntriesResolver;
|
||||||
|
import io.netty.resolver.ResolvedAddressTypes;
|
||||||
import io.netty.util.internal.UnstableApi;
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -45,14 +46,14 @@ public final class DnsNameResolverBuilder {
|
|||||||
private Integer maxTtl;
|
private Integer maxTtl;
|
||||||
private Integer negativeTtl;
|
private Integer negativeTtl;
|
||||||
private long queryTimeoutMillis = 5000;
|
private long queryTimeoutMillis = 5000;
|
||||||
private InternetProtocolFamily[] resolvedAddressTypes = DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
|
private ResolvedAddressTypes resolvedAddressTypes = DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
|
||||||
private boolean recursionDesired = true;
|
private boolean recursionDesired = true;
|
||||||
private int maxQueriesPerResolve = 16;
|
private int maxQueriesPerResolve = 16;
|
||||||
private boolean traceEnabled;
|
private boolean traceEnabled;
|
||||||
private int maxPayloadSize = 4096;
|
private int maxPayloadSize = 4096;
|
||||||
private boolean optResourceEnabled = true;
|
private boolean optResourceEnabled = true;
|
||||||
private HostsFileEntriesResolver hostsFileEntriesResolver = HostsFileEntriesResolver.DEFAULT;
|
private HostsFileEntriesResolver hostsFileEntriesResolver = HostsFileEntriesResolver.DEFAULT;
|
||||||
private String[] searchDomains = DnsNameResolver.DEFAULT_SEACH_DOMAINS;
|
private String[] searchDomains = DnsNameResolver.DEFAULT_SEARCH_DOMAINS;
|
||||||
private int ndots = 1;
|
private int ndots = 1;
|
||||||
private boolean decodeIdn = true;
|
private boolean decodeIdn = true;
|
||||||
|
|
||||||
@ -162,76 +163,45 @@ public final class DnsNameResolverBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the list of the protocol families of the address resolved.
|
* Compute a {@link ResolvedAddressTypes} from some {@link InternetProtocolFamily}s.
|
||||||
* Usually, both {@link InternetProtocolFamily#IPv4} and {@link InternetProtocolFamily#IPv6} are specified in
|
* An empty input will return the default value, based on "java.net" System properties.
|
||||||
* the order of preference. To enforce the resolve to retrieve the address of a specific protocol family,
|
* Valid inputs are (), (IPv4), (IPv6), (Ipv4, IPv6) and (IPv6, IPv4).
|
||||||
* specify only a single {@link InternetProtocolFamily}.
|
* @param internetProtocolFamilies a valid sequence of {@link InternetProtocolFamily}s
|
||||||
*
|
* @return a {@link ResolvedAddressTypes}
|
||||||
* @param resolvedAddressTypes the address types
|
|
||||||
* @return {@code this}
|
|
||||||
*/
|
*/
|
||||||
public DnsNameResolverBuilder resolvedAddressTypes(InternetProtocolFamily... resolvedAddressTypes) {
|
public static ResolvedAddressTypes computeResolvedAddressTypes(InternetProtocolFamily... internetProtocolFamilies) {
|
||||||
checkNotNull(resolvedAddressTypes, "resolvedAddressTypes");
|
if (internetProtocolFamilies == null || internetProtocolFamilies.length == 0) {
|
||||||
|
return DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
|
||||||
final List<InternetProtocolFamily> list = new ArrayList<InternetProtocolFamily>(
|
}
|
||||||
InternetProtocolFamily.values().length);
|
if (internetProtocolFamilies.length > 2) {
|
||||||
|
throw new IllegalArgumentException("No more than 2 InternetProtocolFamilies");
|
||||||
for (InternetProtocolFamily f : resolvedAddressTypes) {
|
|
||||||
if (f == null) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid duplicate entries.
|
switch(internetProtocolFamilies[0]) {
|
||||||
if (list.contains(f)) {
|
case IPv4:
|
||||||
continue;
|
return (internetProtocolFamilies.length >= 2
|
||||||
|
&& internetProtocolFamilies[1] == InternetProtocolFamily.IPv6) ?
|
||||||
|
ResolvedAddressTypes.IPV4_PREFERRED: ResolvedAddressTypes.IPV4_ONLY;
|
||||||
|
case IPv6:
|
||||||
|
return (internetProtocolFamilies.length >= 2
|
||||||
|
&& internetProtocolFamilies[1] == InternetProtocolFamily.IPv4) ?
|
||||||
|
ResolvedAddressTypes.IPV6_PREFERRED: ResolvedAddressTypes.IPV6_ONLY;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Couldn't resolve ResolvedAddressTypes from InternetProtocolFamily array");
|
||||||
}
|
}
|
||||||
|
|
||||||
list.add(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("no protocol family specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.resolvedAddressTypes = list.toArray(new InternetProtocolFamily[list.size()]);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the list of the protocol families of the address resolved.
|
* Sets the list of the protocol families of the address resolved.
|
||||||
* Usually, both {@link InternetProtocolFamily#IPv4} and {@link InternetProtocolFamily#IPv6} are specified in
|
* You can use {@link DnsNameResolverBuilder#computeResolvedAddressTypes(InternetProtocolFamily...)}
|
||||||
* the order of preference. To enforce the resolve to retrieve the address of a specific protocol family,
|
* to get a {@link ResolvedAddressTypes} out of some {@link InternetProtocolFamily}s.
|
||||||
* specify only a single {@link InternetProtocolFamily}.
|
|
||||||
*
|
*
|
||||||
* @param resolvedAddressTypes the address types
|
* @param resolvedAddressTypes the address types
|
||||||
* @return {@code this}
|
* @return {@code this}
|
||||||
*/
|
*/
|
||||||
public DnsNameResolverBuilder resolvedAddressTypes(Iterable<InternetProtocolFamily> resolvedAddressTypes) {
|
public DnsNameResolverBuilder resolvedAddressTypes(ResolvedAddressTypes resolvedAddressTypes) {
|
||||||
checkNotNull(resolvedAddressTypes, "resolveAddressTypes");
|
this.resolvedAddressTypes = resolvedAddressTypes;
|
||||||
|
|
||||||
final List<InternetProtocolFamily> list = new ArrayList<InternetProtocolFamily>(
|
|
||||||
InternetProtocolFamily.values().length);
|
|
||||||
|
|
||||||
for (InternetProtocolFamily f : resolvedAddressTypes) {
|
|
||||||
if (f == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid duplicate entries.
|
|
||||||
if (list.contains(f)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.add(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("no protocol family specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.resolvedAddressTypes = list.toArray(new InternetProtocolFamily[list.size()]);
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
private final DnsCache resolveCache;
|
private final DnsCache resolveCache;
|
||||||
private final boolean traceEnabled;
|
private final boolean traceEnabled;
|
||||||
private final int maxAllowedQueries;
|
private final int maxAllowedQueries;
|
||||||
private final InternetProtocolFamily[] resolveAddressTypes;
|
private final InternetProtocolFamily[] resolvedInternetProtocolFamilies;
|
||||||
private final DnsRecord[] additionals;
|
private final DnsRecord[] additionals;
|
||||||
|
|
||||||
private final Set<Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>> queriesInProgress =
|
private final Set<Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>> queriesInProgress =
|
||||||
@ -97,7 +97,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
|
|
||||||
nameServerAddrs = parent.nameServerAddresses.stream();
|
nameServerAddrs = parent.nameServerAddresses.stream();
|
||||||
maxAllowedQueries = parent.maxQueriesPerResolve();
|
maxAllowedQueries = parent.maxQueriesPerResolve();
|
||||||
resolveAddressTypes = parent.resolveAddressTypesUnsafe();
|
resolvedInternetProtocolFamilies = parent.resolvedInternetProtocolFamiliesUnsafe();
|
||||||
traceEnabled = parent.isTraceEnabled();
|
traceEnabled = parent.isTraceEnabled();
|
||||||
allowedQueries = maxAllowedQueries;
|
allowedQueries = maxAllowedQueries;
|
||||||
}
|
}
|
||||||
@ -611,7 +611,7 @@ abstract class DnsNameResolverContext<T> {
|
|||||||
|
|
||||||
if (resolvedEntries != null) {
|
if (resolvedEntries != null) {
|
||||||
// Found at least one resolved address.
|
// Found at least one resolved address.
|
||||||
for (InternetProtocolFamily f: resolveAddressTypes) {
|
for (InternetProtocolFamily f: resolvedInternetProtocolFamilies) {
|
||||||
if (finishResolve(f.addressType(), resolvedEntries, promise)) {
|
if (finishResolve(f.addressType(), resolvedEntries, promise)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import io.netty.handler.codec.dns.DnsRecordType;
|
|||||||
import io.netty.handler.codec.dns.DnsResponse;
|
import io.netty.handler.codec.dns.DnsResponse;
|
||||||
import io.netty.handler.codec.dns.DnsResponseCode;
|
import io.netty.handler.codec.dns.DnsResponseCode;
|
||||||
import io.netty.handler.codec.dns.DnsSection;
|
import io.netty.handler.codec.dns.DnsSection;
|
||||||
|
import io.netty.resolver.ResolvedAddressTypes;
|
||||||
import io.netty.util.NetUtil;
|
import io.netty.util.NetUtil;
|
||||||
import io.netty.resolver.HostsFileEntriesResolver;
|
import io.netty.resolver.HostsFileEntriesResolver;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
@ -65,7 +66,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.hasToString;
|
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@ -283,12 +283,12 @@ public class DnsNameResolverTest {
|
|||||||
return newResolver(true);
|
return newResolver(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DnsNameResolverBuilder newResolver(InternetProtocolFamily... resolvedAddressTypes) {
|
private static DnsNameResolverBuilder newResolver(ResolvedAddressTypes resolvedAddressTypes) {
|
||||||
return newResolver()
|
return newResolver()
|
||||||
.resolvedAddressTypes(resolvedAddressTypes);
|
.resolvedAddressTypes(resolvedAddressTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DnsNameResolverBuilder newNonCachedResolver(InternetProtocolFamily... resolvedAddressTypes) {
|
private static DnsNameResolverBuilder newNonCachedResolver(ResolvedAddressTypes resolvedAddressTypes) {
|
||||||
return newResolver()
|
return newResolver()
|
||||||
.resolveCache(NoopDnsCache.INSTANCE)
|
.resolveCache(NoopDnsCache.INSTANCE)
|
||||||
.resolvedAddressTypes(resolvedAddressTypes);
|
.resolvedAddressTypes(resolvedAddressTypes);
|
||||||
@ -306,7 +306,7 @@ public class DnsNameResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveAorAAAA() throws Exception {
|
public void testResolveAorAAAA() throws Exception {
|
||||||
DnsNameResolver resolver = newResolver(InternetProtocolFamily.IPv4, InternetProtocolFamily.IPv6).build();
|
DnsNameResolver resolver = newResolver(ResolvedAddressTypes.IPV4_PREFERRED).build();
|
||||||
try {
|
try {
|
||||||
testResolve0(resolver, EXCLUSIONS_RESOLVE_A);
|
testResolve0(resolver, EXCLUSIONS_RESOLVE_A);
|
||||||
} finally {
|
} finally {
|
||||||
@ -316,7 +316,7 @@ public class DnsNameResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveAAAAorA() throws Exception {
|
public void testResolveAAAAorA() throws Exception {
|
||||||
DnsNameResolver resolver = newResolver(InternetProtocolFamily.IPv6, InternetProtocolFamily.IPv4).build();
|
DnsNameResolver resolver = newResolver(ResolvedAddressTypes.IPV6_PREFERRED).build();
|
||||||
try {
|
try {
|
||||||
testResolve0(resolver, EXCLUSIONS_RESOLVE_A);
|
testResolve0(resolver, EXCLUSIONS_RESOLVE_A);
|
||||||
} finally {
|
} finally {
|
||||||
@ -326,7 +326,7 @@ public class DnsNameResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveA() throws Exception {
|
public void testResolveA() throws Exception {
|
||||||
DnsNameResolver resolver = newResolver(InternetProtocolFamily.IPv4)
|
DnsNameResolver resolver = newResolver(ResolvedAddressTypes.IPV4_ONLY)
|
||||||
// Cache for eternity
|
// Cache for eternity
|
||||||
.ttl(Integer.MAX_VALUE, Integer.MAX_VALUE)
|
.ttl(Integer.MAX_VALUE, Integer.MAX_VALUE)
|
||||||
.build();
|
.build();
|
||||||
@ -357,7 +357,7 @@ public class DnsNameResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveAAAA() throws Exception {
|
public void testResolveAAAA() throws Exception {
|
||||||
DnsNameResolver resolver = newResolver(InternetProtocolFamily.IPv6).build();
|
DnsNameResolver resolver = newResolver(ResolvedAddressTypes.IPV6_ONLY).build();
|
||||||
try {
|
try {
|
||||||
testResolve0(resolver, EXCLUSIONS_RESOLVE_AAAA);
|
testResolve0(resolver, EXCLUSIONS_RESOLVE_AAAA);
|
||||||
} finally {
|
} finally {
|
||||||
@ -367,7 +367,7 @@ public class DnsNameResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNonCachedResolve() throws Exception {
|
public void testNonCachedResolve() throws Exception {
|
||||||
DnsNameResolver resolver = newNonCachedResolver(InternetProtocolFamily.IPv4).build();
|
DnsNameResolver resolver = newNonCachedResolver(ResolvedAddressTypes.IPV4_ONLY).build();
|
||||||
try {
|
try {
|
||||||
testResolve0(resolver, EXCLUSIONS_RESOLVE_A);
|
testResolve0(resolver, EXCLUSIONS_RESOLVE_A);
|
||||||
} finally {
|
} finally {
|
||||||
@ -442,7 +442,7 @@ public class DnsNameResolverTest {
|
|||||||
assertThat(resolved.getHostName(), is(unresolved));
|
assertThat(resolved.getHostName(), is(unresolved));
|
||||||
|
|
||||||
boolean typeMatches = false;
|
boolean typeMatches = false;
|
||||||
for (InternetProtocolFamily f: resolver.resolvedAddressTypes()) {
|
for (InternetProtocolFamily f: resolver.resolvedInternetProtocolFamiliesUnsafe()) {
|
||||||
Class<?> resolvedType = resolved.getClass();
|
Class<?> resolvedType = resolved.getClass();
|
||||||
if (f.addressType().isAssignableFrom(resolvedType)) {
|
if (f.addressType().isAssignableFrom(resolvedType)) {
|
||||||
typeMatches = true;
|
typeMatches = true;
|
||||||
@ -574,26 +574,26 @@ public class DnsNameResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveEmptyIpv4() {
|
public void testResolveEmptyIpv4() {
|
||||||
testResolve0(InternetProtocolFamily.IPv4, NetUtil.LOCALHOST4, StringUtil.EMPTY_STRING);
|
testResolve0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, StringUtil.EMPTY_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveEmptyIpv6() {
|
public void testResolveEmptyIpv6() {
|
||||||
testResolve0(InternetProtocolFamily.IPv6, NetUtil.LOCALHOST6, StringUtil.EMPTY_STRING);
|
testResolve0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, StringUtil.EMPTY_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveNullIpv4() {
|
public void testResolveNullIpv4() {
|
||||||
testResolve0(InternetProtocolFamily.IPv4, NetUtil.LOCALHOST4, null);
|
testResolve0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveNullIpv6() {
|
public void testResolveNullIpv6() {
|
||||||
testResolve0(InternetProtocolFamily.IPv6, NetUtil.LOCALHOST6, null);
|
testResolve0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testResolve0(InternetProtocolFamily family, InetAddress expectedAddr, String name) {
|
private static void testResolve0(ResolvedAddressTypes addressTypes, InetAddress expectedAddr, String name) {
|
||||||
DnsNameResolver resolver = newResolver(family).build();
|
DnsNameResolver resolver = newResolver(addressTypes).build();
|
||||||
try {
|
try {
|
||||||
InetAddress address = resolver.resolve(name).syncUninterruptibly().getNow();
|
InetAddress address = resolver.resolve(name).syncUninterruptibly().getNow();
|
||||||
assertEquals(expectedAddr, address);
|
assertEquals(expectedAddr, address);
|
||||||
@ -604,26 +604,26 @@ public class DnsNameResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveAllEmptyIpv4() {
|
public void testResolveAllEmptyIpv4() {
|
||||||
testResolveAll0(InternetProtocolFamily.IPv4, NetUtil.LOCALHOST4, StringUtil.EMPTY_STRING);
|
testResolveAll0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, StringUtil.EMPTY_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveAllEmptyIpv6() {
|
public void testResolveAllEmptyIpv6() {
|
||||||
testResolveAll0(InternetProtocolFamily.IPv6, NetUtil.LOCALHOST6, StringUtil.EMPTY_STRING);
|
testResolveAll0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, StringUtil.EMPTY_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveAllNullIpv4() {
|
public void testResolveAllNullIpv4() {
|
||||||
testResolveAll0(InternetProtocolFamily.IPv4, NetUtil.LOCALHOST4, null);
|
testResolveAll0(ResolvedAddressTypes.IPV4_ONLY, NetUtil.LOCALHOST4, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResolveAllNullIpv6() {
|
public void testResolveAllNullIpv6() {
|
||||||
testResolveAll0(InternetProtocolFamily.IPv6, NetUtil.LOCALHOST6, null);
|
testResolveAll0(ResolvedAddressTypes.IPV6_ONLY, NetUtil.LOCALHOST6, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testResolveAll0(InternetProtocolFamily family, InetAddress expectedAddr, String name) {
|
private static void testResolveAll0(ResolvedAddressTypes addressTypes, InetAddress expectedAddr, String name) {
|
||||||
DnsNameResolver resolver = newResolver(family).build();
|
DnsNameResolver resolver = newResolver(addressTypes).build();
|
||||||
try {
|
try {
|
||||||
List<InetAddress> addresses = resolver.resolveAll(name).syncUninterruptibly().getNow();
|
List<InetAddress> addresses = resolver.resolveAll(name).syncUninterruptibly().getNow();
|
||||||
assertEquals(1, addresses.size());
|
assertEquals(1, addresses.size());
|
||||||
@ -682,9 +682,9 @@ public class DnsNameResolverTest {
|
|||||||
DnsNameResolver resolver = new DnsNameResolver(
|
DnsNameResolver resolver = new DnsNameResolver(
|
||||||
group.next(), new ReflectiveChannelFactory<DatagramChannel>(NioDatagramChannel.class),
|
group.next(), new ReflectiveChannelFactory<DatagramChannel>(NioDatagramChannel.class),
|
||||||
DnsServerAddresses.singleton(dnsServer.localAddress()), NoopDnsCache.INSTANCE, nsCache,
|
DnsServerAddresses.singleton(dnsServer.localAddress()), NoopDnsCache.INSTANCE, nsCache,
|
||||||
3000, new InternetProtocolFamily[] { InternetProtocolFamily.IPv4 }, true, 10,
|
3000, ResolvedAddressTypes.IPV4_ONLY, true, 10,
|
||||||
true, 4096, false, HostsFileEntriesResolver.DEFAULT,
|
true, 4096, false, HostsFileEntriesResolver.DEFAULT,
|
||||||
DnsNameResolver.DEFAULT_SEACH_DOMAINS, 0, true) {
|
DnsNameResolver.DEFAULT_SEARCH_DOMAINS, 0, true) {
|
||||||
@Override
|
@Override
|
||||||
int dnsRedirectPort(InetAddress server) {
|
int dnsRedirectPort(InetAddress server) {
|
||||||
return server.equals(dnsServerAuthority.localAddress().getAddress()) ?
|
return server.equals(dnsServerAuthority.localAddress().getAddress()) ?
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.resolver;
|
package io.netty.resolver;
|
||||||
|
|
||||||
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -22,13 +26,39 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Default {@link HostsFileEntriesResolver} that resolves hosts file entries only once.
|
* Default {@link HostsFileEntriesResolver} that resolves hosts file entries only once.
|
||||||
*/
|
*/
|
||||||
|
@UnstableApi
|
||||||
public final class DefaultHostsFileEntriesResolver implements HostsFileEntriesResolver {
|
public final class DefaultHostsFileEntriesResolver implements HostsFileEntriesResolver {
|
||||||
|
|
||||||
private final Map<String, InetAddress> entries = HostsFileParser.parseSilently();
|
private final Map<String, Inet4Address> inet4Entries;
|
||||||
|
private final Map<String, Inet6Address> inet6Entries;
|
||||||
|
|
||||||
|
public DefaultHostsFileEntriesResolver() {
|
||||||
|
this(HostsFileParser.parseSilently());
|
||||||
|
}
|
||||||
|
|
||||||
|
// for testing purpose only
|
||||||
|
DefaultHostsFileEntriesResolver(HostsFileEntries entries) {
|
||||||
|
inet4Entries = entries.inet4Entries();
|
||||||
|
inet6Entries = entries.inet6Entries();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetAddress address(String inetHost) {
|
public InetAddress address(String inetHost, ResolvedAddressTypes resolvedAddressTypes) {
|
||||||
return entries.get(normalize(inetHost));
|
String normalized = normalize(inetHost);
|
||||||
|
switch (resolvedAddressTypes) {
|
||||||
|
case IPV4_ONLY:
|
||||||
|
return inet4Entries.get(normalized);
|
||||||
|
case IPV6_ONLY:
|
||||||
|
return inet6Entries.get(normalized);
|
||||||
|
case IPV4_PREFERRED:
|
||||||
|
Inet4Address inet4Address = inet4Entries.get(normalized);
|
||||||
|
return inet4Address != null? inet4Address : inet6Entries.get(normalized);
|
||||||
|
case IPV6_PREFERRED:
|
||||||
|
Inet6Address inet6Address = inet6Entries.get(normalized);
|
||||||
|
return inet6Address != null? inet6Address : inet4Entries.get(normalized);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown ResolvedAddressTypes " + resolvedAddressTypes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// package-private for testing purposes
|
// package-private for testing purposes
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.resolver;
|
||||||
|
|
||||||
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A container of hosts file entries
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
public final class HostsFileEntries {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty entries
|
||||||
|
*/
|
||||||
|
static final HostsFileEntries EMPTY =
|
||||||
|
new HostsFileEntries(
|
||||||
|
Collections.<String, Inet4Address>emptyMap(),
|
||||||
|
Collections.<String, Inet6Address>emptyMap());
|
||||||
|
|
||||||
|
private final Map<String, Inet4Address> inet4Entries;
|
||||||
|
private final Map<String, Inet6Address> inet6Entries;
|
||||||
|
|
||||||
|
public HostsFileEntries(Map<String, Inet4Address> inet4Entries, Map<String, Inet6Address> inet6Entries) {
|
||||||
|
this.inet4Entries = Collections.unmodifiableMap(new HashMap<String, Inet4Address>(inet4Entries));
|
||||||
|
this.inet6Entries = Collections.unmodifiableMap(new HashMap<String, Inet6Address>(inet6Entries));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IPv4 entries
|
||||||
|
* @return the IPv4 entries
|
||||||
|
*/
|
||||||
|
public Map<String, Inet4Address> inet4Entries() {
|
||||||
|
return inet4Entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IPv6 entries
|
||||||
|
* @return the IPv6 entries
|
||||||
|
*/
|
||||||
|
public Map<String, Inet6Address> inet6Entries() {
|
||||||
|
return inet6Entries;
|
||||||
|
}
|
||||||
|
}
|
@ -15,11 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.resolver;
|
package io.netty.resolver;
|
||||||
|
|
||||||
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a hostname against the hosts file entries.
|
* Resolves a hostname against the hosts file entries.
|
||||||
*/
|
*/
|
||||||
|
@UnstableApi
|
||||||
public interface HostsFileEntriesResolver {
|
public interface HostsFileEntriesResolver {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,5 +30,11 @@ public interface HostsFileEntriesResolver {
|
|||||||
*/
|
*/
|
||||||
HostsFileEntriesResolver DEFAULT = new DefaultHostsFileEntriesResolver();
|
HostsFileEntriesResolver DEFAULT = new DefaultHostsFileEntriesResolver();
|
||||||
|
|
||||||
InetAddress address(String inetHost);
|
/**
|
||||||
|
* Resolve the address of a hostname against the entries in a hosts file, depending on some address types.
|
||||||
|
* @param inetHost the hostname to resolve
|
||||||
|
* @param resolvedAddressTypes the address types to resolve
|
||||||
|
* @return the first matching address
|
||||||
|
*/
|
||||||
|
InetAddress address(String inetHost, ResolvedAddressTypes resolvedAddressTypes);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package io.netty.resolver;
|
|||||||
|
|
||||||
import io.netty.util.NetUtil;
|
import io.netty.util.NetUtil;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
import io.netty.util.internal.UnstableApi;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
@ -25,9 +26,10 @@ import java.io.File;
|
|||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -39,6 +41,7 @@ import static io.netty.util.internal.ObjectUtil.*;
|
|||||||
/**
|
/**
|
||||||
* A parser for hosts files.
|
* A parser for hosts files.
|
||||||
*/
|
*/
|
||||||
|
@UnstableApi
|
||||||
public final class HostsFileParser {
|
public final class HostsFileParser {
|
||||||
|
|
||||||
private static final String WINDOWS_DEFAULT_SYSTEM_ROOT = "C:\\Windows";
|
private static final String WINDOWS_DEFAULT_SYSTEM_ROOT = "C:\\Windows";
|
||||||
@ -65,25 +68,25 @@ public final class HostsFileParser {
|
|||||||
/**
|
/**
|
||||||
* Parse hosts file at standard OS location.
|
* Parse hosts file at standard OS location.
|
||||||
*
|
*
|
||||||
* @return a map of hostname or alias to {@link InetAddress}
|
* @return a {@link HostsFileEntries}
|
||||||
*/
|
*/
|
||||||
public static Map<String, InetAddress> parseSilently() {
|
public static HostsFileEntries parseSilently() {
|
||||||
File hostsFile = locateHostsFile();
|
File hostsFile = locateHostsFile();
|
||||||
try {
|
try {
|
||||||
return parse(hostsFile);
|
return parse(hostsFile);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("Failed to load and parse hosts file at " + hostsFile.getPath(), e);
|
logger.warn("Failed to load and parse hosts file at " + hostsFile.getPath(), e);
|
||||||
return Collections.emptyMap();
|
return HostsFileEntries.EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse hosts file at standard OS location.
|
* Parse hosts file at standard OS location.
|
||||||
*
|
*
|
||||||
* @return a map of hostname or alias to {@link InetAddress}
|
* @return a {@link HostsFileEntries}
|
||||||
* @throws IOException file could not be read
|
* @throws IOException file could not be read
|
||||||
*/
|
*/
|
||||||
public static Map<String, InetAddress> parse() throws IOException {
|
public static HostsFileEntries parse() throws IOException {
|
||||||
return parse(locateHostsFile());
|
return parse(locateHostsFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,15 +94,15 @@ public final class HostsFileParser {
|
|||||||
* Parse a hosts file.
|
* Parse a hosts file.
|
||||||
*
|
*
|
||||||
* @param file the file to be parsed
|
* @param file the file to be parsed
|
||||||
* @return a map of hostname or alias to {@link InetAddress}
|
* @return a {@link HostsFileEntries}
|
||||||
* @throws IOException file could not be read
|
* @throws IOException file could not be read
|
||||||
*/
|
*/
|
||||||
public static Map<String, InetAddress> parse(File file) throws IOException {
|
public static HostsFileEntries parse(File file) throws IOException {
|
||||||
checkNotNull(file, "file");
|
checkNotNull(file, "file");
|
||||||
if (file.exists() && file.isFile()) {
|
if (file.exists() && file.isFile()) {
|
||||||
return parse(new BufferedReader(new FileReader(file)));
|
return parse(new BufferedReader(new FileReader(file)));
|
||||||
} else {
|
} else {
|
||||||
return Collections.emptyMap();
|
return HostsFileEntries.EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,14 +110,15 @@ public final class HostsFileParser {
|
|||||||
* Parse a reader of hosts file format.
|
* Parse a reader of hosts file format.
|
||||||
*
|
*
|
||||||
* @param reader the file to be parsed
|
* @param reader the file to be parsed
|
||||||
* @return a map of hostname or alias to {@link InetAddress}
|
* @return a {@link HostsFileEntries}
|
||||||
* @throws IOException file could not be read
|
* @throws IOException file could not be read
|
||||||
*/
|
*/
|
||||||
public static Map<String, InetAddress> parse(Reader reader) throws IOException {
|
public static HostsFileEntries parse(Reader reader) throws IOException {
|
||||||
checkNotNull(reader, "reader");
|
checkNotNull(reader, "reader");
|
||||||
BufferedReader buff = new BufferedReader(reader);
|
BufferedReader buff = new BufferedReader(reader);
|
||||||
try {
|
try {
|
||||||
Map<String, InetAddress> entries = new HashMap<String, InetAddress>();
|
Map<String, Inet4Address> ipv4Entries = new HashMap<String, Inet4Address>();
|
||||||
|
Map<String, Inet6Address> ipv6Entries = new HashMap<String, Inet6Address>();
|
||||||
String line;
|
String line;
|
||||||
while ((line = buff.readLine()) != null) {
|
while ((line = buff.readLine()) != null) {
|
||||||
// remove comment
|
// remove comment
|
||||||
@ -153,14 +157,25 @@ public final class HostsFileParser {
|
|||||||
for (int i = 1; i < lineParts.size(); i ++) {
|
for (int i = 1; i < lineParts.size(); i ++) {
|
||||||
String hostname = lineParts.get(i);
|
String hostname = lineParts.get(i);
|
||||||
String hostnameLower = hostname.toLowerCase(Locale.ENGLISH);
|
String hostnameLower = hostname.toLowerCase(Locale.ENGLISH);
|
||||||
if (!entries.containsKey(hostnameLower)) {
|
InetAddress address = InetAddress.getByAddress(hostname, ipBytes);
|
||||||
// trying to map a host to multiple IPs is wrong
|
if (address instanceof Inet4Address) {
|
||||||
// only the first entry is honored
|
Inet4Address previous = ipv4Entries.put(hostnameLower, (Inet4Address) address);
|
||||||
entries.put(hostnameLower, InetAddress.getByAddress(hostname, ipBytes));
|
if (previous != null) {
|
||||||
|
// restore, we want to keep the first entry
|
||||||
|
ipv4Entries.put(hostnameLower, previous);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Inet6Address previous = ipv6Entries.put(hostnameLower, (Inet6Address) address);
|
||||||
|
if (previous != null) {
|
||||||
|
// restore, we want to keep the first entry
|
||||||
|
ipv6Entries.put(hostnameLower, previous);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entries;
|
}
|
||||||
|
return ipv4Entries.isEmpty() && ipv6Entries.isEmpty() ?
|
||||||
|
HostsFileEntries.EMPTY :
|
||||||
|
new HostsFileEntries(ipv4Entries, ipv6Entries);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
buff.close();
|
buff.close();
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.resolver;
|
||||||
|
|
||||||
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defined resolved address types.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
public enum ResolvedAddressTypes {
|
||||||
|
/**
|
||||||
|
* Only resolve IPv4 addresses
|
||||||
|
*/
|
||||||
|
IPV4_ONLY,
|
||||||
|
/**
|
||||||
|
* Only resolve IPv6 addresses
|
||||||
|
*/
|
||||||
|
IPV6_ONLY,
|
||||||
|
/**
|
||||||
|
* Prefer IPv4 addresses over IPv6 ones
|
||||||
|
*/
|
||||||
|
IPV4_PREFERRED,
|
||||||
|
/**
|
||||||
|
* Prefer IPv6 addresses over IPv4 ones
|
||||||
|
*/
|
||||||
|
IPV6_PREFERRED
|
||||||
|
}
|
@ -13,21 +13,72 @@
|
|||||||
* License for the specific language governing permissions and limitations
|
* License for the specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
/**
|
|
||||||
* show issue https://github.com/netty/netty/issues/5182
|
|
||||||
* HostsFileParser tries to resolve hostnames as case-sensitive
|
|
||||||
*/
|
|
||||||
package io.netty.resolver;
|
package io.netty.resolver;
|
||||||
|
|
||||||
|
import io.netty.util.NetUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class DefaultHostsFileEntriesResolverTest {
|
public class DefaultHostsFileEntriesResolverTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show issue https://github.com/netty/netty/issues/5182
|
||||||
|
* HostsFileParser tries to resolve hostnames as case-sensitive
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCaseInsensitivity() throws Exception {
|
public void testCaseInsensitivity() throws Exception {
|
||||||
DefaultHostsFileEntriesResolver resolver = new DefaultHostsFileEntriesResolver();
|
DefaultHostsFileEntriesResolver resolver = new DefaultHostsFileEntriesResolver();
|
||||||
//normalized somehow
|
//normalized somehow
|
||||||
Assert.assertEquals(resolver.normalize("localhost"), resolver.normalize("LOCALHOST"));
|
Assert.assertEquals(resolver.normalize("localhost"), resolver.normalize("LOCALHOST"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldntFindWhenAddressTypeDoesntMatch() {
|
||||||
|
Map<String, Inet4Address> inet4Entries = new HashMap<String, Inet4Address>();
|
||||||
|
Map<String, Inet6Address> inet6Entries = new HashMap<String, Inet6Address>();
|
||||||
|
|
||||||
|
inet4Entries.put("localhost", NetUtil.LOCALHOST4);
|
||||||
|
|
||||||
|
DefaultHostsFileEntriesResolver resolver =
|
||||||
|
new DefaultHostsFileEntriesResolver(new HostsFileEntries(inet4Entries, inet6Entries));
|
||||||
|
|
||||||
|
InetAddress address = resolver.address("localhost", ResolvedAddressTypes.IPV6_ONLY);
|
||||||
|
Assert.assertNull("Should pick an IPv6 address", address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPickIpv4WhenBothAreDefinedButIpv4IsPreferred() {
|
||||||
|
Map<String, Inet4Address> inet4Entries = new HashMap<String, Inet4Address>();
|
||||||
|
Map<String, Inet6Address> inet6Entries = new HashMap<String, Inet6Address>();
|
||||||
|
|
||||||
|
inet4Entries.put("localhost", NetUtil.LOCALHOST4);
|
||||||
|
inet6Entries.put("localhost", NetUtil.LOCALHOST6);
|
||||||
|
|
||||||
|
DefaultHostsFileEntriesResolver resolver =
|
||||||
|
new DefaultHostsFileEntriesResolver(new HostsFileEntries(inet4Entries, inet6Entries));
|
||||||
|
|
||||||
|
InetAddress address = resolver.address("localhost", ResolvedAddressTypes.IPV4_PREFERRED);
|
||||||
|
Assert.assertTrue("Should pick an IPv4 address", address instanceof Inet4Address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPickIpv6WhenBothAreDefinedButIpv6IsPreferred() {
|
||||||
|
Map<String, Inet4Address> inet4Entries = new HashMap<String, Inet4Address>();
|
||||||
|
Map<String, Inet6Address> inet6Entries = new HashMap<String, Inet6Address>();
|
||||||
|
|
||||||
|
inet4Entries.put("localhost", NetUtil.LOCALHOST4);
|
||||||
|
inet6Entries.put("localhost", NetUtil.LOCALHOST6);
|
||||||
|
|
||||||
|
DefaultHostsFileEntriesResolver resolver =
|
||||||
|
new DefaultHostsFileEntriesResolver(new HostsFileEntries(inet4Entries, inet6Entries));
|
||||||
|
|
||||||
|
InetAddress address = resolver.address("localhost", ResolvedAddressTypes.IPV6_PREFERRED);
|
||||||
|
Assert.assertTrue("Should pick an IPv6 address", address instanceof Inet6Address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,8 @@ import org.junit.Test;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.net.InetAddress;
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
@ -31,6 +32,7 @@ public class HostsFileParserTest {
|
|||||||
public void testParse() throws IOException {
|
public void testParse() throws IOException {
|
||||||
String hostsString = new StringBuilder()
|
String hostsString = new StringBuilder()
|
||||||
.append("127.0.0.1 host1").append("\n") // single hostname, separated with blanks
|
.append("127.0.0.1 host1").append("\n") // single hostname, separated with blanks
|
||||||
|
.append("::1 host1").append("\n") // same as above, but IPv6
|
||||||
.append("\n") // empty line
|
.append("\n") // empty line
|
||||||
.append("192.168.0.1\thost2").append("\n") // single hostname, separated with tabs
|
.append("192.168.0.1\thost2").append("\n") // single hostname, separated with tabs
|
||||||
.append("#comment").append("\n") // comment at the beginning of the line
|
.append("#comment").append("\n") // comment at the beginning of the line
|
||||||
@ -42,16 +44,20 @@ public class HostsFileParserTest {
|
|||||||
.append("192.168.0.6 host7").append("\n") // should be ignored since we have the uppercase host already
|
.append("192.168.0.6 host7").append("\n") // should be ignored since we have the uppercase host already
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
Map<String, InetAddress> entries = HostsFileParser.parse(new BufferedReader(new StringReader(hostsString)));
|
HostsFileEntries entries = HostsFileParser.parse(new BufferedReader(new StringReader(hostsString)));
|
||||||
|
Map<String, Inet4Address> inet4Entries = entries.inet4Entries();
|
||||||
|
Map<String, Inet6Address> inet6Entries = entries.inet6Entries();
|
||||||
|
|
||||||
assertEquals("Expected 7 entries", 7, entries.size());
|
assertEquals("Expected 7 IPv4 entries", 7, inet4Entries.size());
|
||||||
assertEquals("127.0.0.1", entries.get("host1").getHostAddress());
|
assertEquals("Expected 1 IPv6 entries", 1, inet6Entries.size());
|
||||||
assertEquals("192.168.0.1", entries.get("host2").getHostAddress());
|
assertEquals("127.0.0.1", inet4Entries.get("host1").getHostAddress());
|
||||||
assertEquals("192.168.0.2", entries.get("host3").getHostAddress());
|
assertEquals("192.168.0.1", inet4Entries.get("host2").getHostAddress());
|
||||||
assertEquals("192.168.0.3", entries.get("host4").getHostAddress());
|
assertEquals("192.168.0.2", inet4Entries.get("host3").getHostAddress());
|
||||||
assertEquals("192.168.0.3", entries.get("host5").getHostAddress());
|
assertEquals("192.168.0.3", inet4Entries.get("host4").getHostAddress());
|
||||||
assertEquals("192.168.0.3", entries.get("host6").getHostAddress());
|
assertEquals("192.168.0.3", inet4Entries.get("host5").getHostAddress());
|
||||||
assertNotNull("uppercase host doesn't resolve", entries.get("host7"));
|
assertEquals("192.168.0.3", inet4Entries.get("host6").getHostAddress());
|
||||||
assertEquals("192.168.0.5", entries.get("host7").getHostAddress());
|
assertNotNull("uppercase host doesn't resolve", inet4Entries.get("host7"));
|
||||||
|
assertEquals("192.168.0.5", inet4Entries.get("host7").getHostAddress());
|
||||||
|
assertEquals("0:0:0:0:0:0:0:1", inet6Entries.get("host1").getHostAddress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user