Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/src/main/java/io/netty/util/internal/Hidden.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public void applyTo(BlockHound.Builder builder) {
"parseEtcResolverOptions");

builder.allowBlockingCallsInside(
"io.netty.resolver.HostsFileParser",
"io.netty.resolver.HostsFileEntriesProvider$ParserImpl",
"parse");

builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import io.netty.handler.codec.dns.DnsResponse;
import io.netty.handler.codec.dns.TcpDnsQueryEncoder;
import io.netty.handler.codec.dns.TcpDnsResponseDecoder;
import io.netty.resolver.DefaultHostsFileEntriesResolver;
import io.netty.resolver.HostsFileEntries;
import io.netty.resolver.HostsFileEntriesResolver;
import io.netty.resolver.InetNameResolver;
Expand Down Expand Up @@ -693,20 +694,38 @@ protected EventLoop executor() {
private InetAddress resolveHostsFileEntry(String hostname) {
if (hostsFileEntriesResolver == null) {
return null;
}
InetAddress address = hostsFileEntriesResolver.address(hostname, resolvedAddressTypes);
return address == null && isLocalWindowsHost(hostname) ? LOCALHOST_ADDRESS : address;
}

private List<InetAddress> resolveHostsFileEntries(String hostname) {
if (hostsFileEntriesResolver == null) {
return null;
}
List<InetAddress> addresses;
if (hostsFileEntriesResolver instanceof DefaultHostsFileEntriesResolver) {
addresses = ((DefaultHostsFileEntriesResolver) hostsFileEntriesResolver)
.addresses(hostname, resolvedAddressTypes);
} else {
Comment thread
normanmaurer marked this conversation as resolved.
InetAddress address = hostsFileEntriesResolver.address(hostname, resolvedAddressTypes);
if (address == null && PlatformDependent.isWindows() &&
(LOCALHOST.equalsIgnoreCase(hostname) ||
(WINDOWS_HOST_NAME != null && WINDOWS_HOST_NAME.equalsIgnoreCase(hostname)))) {
// If we tried to resolve localhost we need workaround that windows removed localhost from its
// hostfile in later versions.
// See https://github.com/netty/netty/issues/5386
// Need a workaround for resolving the host (computer) name in case it cannot be resolved from hostfile
// See https://github.com/netty/netty/issues/11142
return LOCALHOST_ADDRESS;
}
return address;
addresses = address != null ? Collections.singletonList(address) : null;
}
return addresses == null && isLocalWindowsHost(hostname) ?
Collections.singletonList(LOCALHOST_ADDRESS) : addresses;
}

/**
* Checks whether the given hostname is the localhost/host (computer) name on Windows OS.
* Windows OS removed the localhost/host (computer) name information from the hosts file in the later versions
* and such hostname cannot be resolved from hosts file.
* See https://github.com/netty/netty/issues/5386
* See https://github.com/netty/netty/issues/11142
*/
private static boolean isLocalWindowsHost(String hostname) {
return PlatformDependent.isWindows() &&
(LOCALHOST.equalsIgnoreCase(hostname) ||
(WINDOWS_HOST_NAME != null && WINDOWS_HOST_NAME.equalsIgnoreCase(hostname)));
}

/**
Expand Down Expand Up @@ -840,24 +859,29 @@ private Future<List<DnsRecord>> resolveAll(DnsQuestion question, DnsRecord[] add
final String hostname = question.name();

if (type == DnsRecordType.A || type == DnsRecordType.AAAA) {
final InetAddress hostsFileEntry = resolveHostsFileEntry(hostname);
if (hostsFileEntry != null) {
ByteBuf content = null;
if (hostsFileEntry instanceof Inet4Address) {
if (type == DnsRecordType.A) {
content = Unpooled.wrappedBuffer(hostsFileEntry.getAddress());
final List<InetAddress> hostsFileEntries = resolveHostsFileEntries(hostname);
if (hostsFileEntries != null) {
List<DnsRecord> result = new ArrayList<DnsRecord>();
Comment thread
normanmaurer marked this conversation as resolved.
for (InetAddress hostsFileEntry : hostsFileEntries) {
ByteBuf content = null;
if (hostsFileEntry instanceof Inet4Address) {
if (type == DnsRecordType.A) {
content = Unpooled.wrappedBuffer(hostsFileEntry.getAddress());
}
} else if (hostsFileEntry instanceof Inet6Address) {
if (type == DnsRecordType.AAAA) {
content = Unpooled.wrappedBuffer(hostsFileEntry.getAddress());
}
}
} else if (hostsFileEntry instanceof Inet6Address) {
if (type == DnsRecordType.AAAA) {
content = Unpooled.wrappedBuffer(hostsFileEntry.getAddress());
if (content != null) {
// Our current implementation does not support reloading the hosts file,
// so use a fairly large TTL (1 day, i.e. 86400 seconds).
result.add(new DefaultDnsRawRecord(hostname, type, 86400, content));
}
}

if (content != null) {
// Our current implementation does not support reloading the hosts file,
// so use a fairly large TTL (1 day, i.e. 86400 seconds).
trySuccess(promise, Collections.<DnsRecord>singletonList(
new DefaultDnsRawRecord(hostname, type, 86400, content)));
if (!result.isEmpty()) {
trySuccess(promise, result);
return promise;
}
}
Expand Down Expand Up @@ -1033,9 +1057,9 @@ protected void doResolveAll(String inetHost,

final String hostname = hostname(inetHost);

InetAddress hostsFileEntry = resolveHostsFileEntry(hostname);
if (hostsFileEntry != null) {
promise.setSuccess(Collections.singletonList(hostsFileEntry));
List<InetAddress> hostsFileEntries = resolveHostsFileEntries(hostname);
if (hostsFileEntries != null) {
promise.setSuccess(hostsFileEntries);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
import io.netty.util.CharsetUtil;
import io.netty.util.internal.PlatformDependent;

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

Expand All @@ -30,33 +30,61 @@
*/
public final class DefaultHostsFileEntriesResolver implements HostsFileEntriesResolver {

private final Map<String, Inet4Address> inet4Entries;
private final Map<String, Inet6Address> inet6Entries;
private final Map<String, List<InetAddress>> inet4Entries;
private final Map<String, List<InetAddress>> inet6Entries;

public DefaultHostsFileEntriesResolver() {
this(parseEntries());
}

// for testing purpose only
DefaultHostsFileEntriesResolver(HostsFileEntries entries) {
inet4Entries = entries.inet4Entries();
inet6Entries = entries.inet6Entries();
DefaultHostsFileEntriesResolver(HostsFileEntriesProvider entries) {
inet4Entries = entries.ipv4Entries();
inet6Entries = entries.ipv6Entries();
}

@Override
public InetAddress address(String inetHost, ResolvedAddressTypes resolvedAddressTypes) {
String normalized = normalize(inetHost);
switch (resolvedAddressTypes) {
case IPV4_ONLY:
return firstAddress(inet4Entries.get(normalized));
case IPV6_ONLY:
return firstAddress(inet6Entries.get(normalized));
case IPV4_PREFERRED:
InetAddress inet4Address = firstAddress(inet4Entries.get(normalized));
return inet4Address != null ? inet4Address : firstAddress(inet6Entries.get(normalized));
case IPV6_PREFERRED:
InetAddress inet6Address = firstAddress(inet6Entries.get(normalized));
return inet6Address != null ? inet6Address : firstAddress(inet4Entries.get(normalized));
default:
throw new IllegalArgumentException("Unknown ResolvedAddressTypes " + resolvedAddressTypes);
}
}

/**
* Resolves all addresses of a hostname against the entries in a hosts file, depending on the specified
* {@link ResolvedAddressTypes}.
*
* @param inetHost the hostname to resolve
* @param resolvedAddressTypes the address types to resolve
* @return all matching addresses or {@code null} in case the hostname cannot be resolved
*/
public List<InetAddress> addresses(String inetHost, ResolvedAddressTypes resolvedAddressTypes) {
Comment thread
normanmaurer marked this conversation as resolved.
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);
List<InetAddress> allInet4Addresses = inet4Entries.get(normalized);
return allInet4Addresses != null ? allAddresses(allInet4Addresses, inet6Entries.get(normalized)) :
inet6Entries.get(normalized);
case IPV6_PREFERRED:
Inet6Address inet6Address = inet6Entries.get(normalized);
return inet6Address != null? inet6Address : inet4Entries.get(normalized);
List<InetAddress> allInet6Addresses = inet6Entries.get(normalized);
return allInet6Addresses != null ? allAddresses(allInet6Addresses, inet4Entries.get(normalized)) :
inet4Entries.get(normalized);
default:
throw new IllegalArgumentException("Unknown ResolvedAddressTypes " + resolvedAddressTypes);
}
Expand All @@ -67,13 +95,27 @@ String normalize(String inetHost) {
return inetHost.toLowerCase(Locale.ENGLISH);
}

private static HostsFileEntries parseEntries() {
private static List<InetAddress> allAddresses(List<InetAddress> a, List<InetAddress> b) {
List<InetAddress> result = new ArrayList<InetAddress>(a.size() + (b == null ? 0 : b.size()));
result.addAll(a);
if (b != null) {
result.addAll(b);
}
return result;
}

private static InetAddress firstAddress(List<InetAddress> addresses) {
return addresses != null && !addresses.isEmpty() ? addresses.get(0) : null;
}

private static HostsFileEntriesProvider parseEntries() {
if (PlatformDependent.isWindows()) {
// Ony windows there seems to be no standard for the encoding used for the hosts file, so let us
// try multiple until we either were able to parse it or there is none left and so we return an
// empty intstance.
return HostsFileParser.parseSilently(Charset.defaultCharset(), CharsetUtil.UTF_16, CharsetUtil.UTF_8);
// empty instance.
return HostsFileEntriesProvider.parser()
.parseSilently(Charset.defaultCharset(), CharsetUtil.UTF_16, CharsetUtil.UTF_8);
}
return HostsFileParser.parseSilently();
return HostsFileEntriesProvider.parser().parseSilently();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import java.util.Map;

/**
* A container of hosts file entries
* A container of hosts file entries.
* The mappings contain only the first entry per hostname.
* Consider using {@link HostsFileEntriesProvider} when mappings with all entries per hostname are needed.
*/
public final class HostsFileEntries {

Expand Down
Loading