Allow blocking calls when parsing etcResolver/hosts files (#11009)
Motivation: When etcResolver/hosts files are parsed, FileInputStream.read(...) is internally called by - UnixResolverDnsServerAddressStreamProvider#parseEtcResolverSearchDomains - UnixResolverDnsServerAddressStreamProvider#parseEtcResolverOptions - HostsFileParser#parse This will cause the error below when BlockHound is enabled reactor.blockhound.BlockingOperationError: Blocking call! java.io.FileInputStream#readBytes at java.io.FileInputStream.readBytes(FileInputStream.java) at java.io.FileInputStream.read(FileInputStream.java:255) Modifications: - Add whitelist entries to BlockHound configuration - Fix typos in UnixResolverDnsServerAddressStreamProvider - Add tests Result: Fixes #11004
This commit is contained in:
parent
bb9370f2a2
commit
6808d7582a
@ -119,6 +119,18 @@ class Hidden {
|
|||||||
"io.netty.resolver.dns.UnixResolverDnsServerAddressStreamProvider",
|
"io.netty.resolver.dns.UnixResolverDnsServerAddressStreamProvider",
|
||||||
"parse");
|
"parse");
|
||||||
|
|
||||||
|
builder.allowBlockingCallsInside(
|
||||||
|
"io.netty.resolver.dns.UnixResolverDnsServerAddressStreamProvider",
|
||||||
|
"parseEtcResolverSearchDomains");
|
||||||
|
|
||||||
|
builder.allowBlockingCallsInside(
|
||||||
|
"io.netty.resolver.dns.UnixResolverDnsServerAddressStreamProvider",
|
||||||
|
"parseEtcResolverOptions");
|
||||||
|
|
||||||
|
builder.allowBlockingCallsInside(
|
||||||
|
"io.netty.resolver.HostsFileParser",
|
||||||
|
"parse");
|
||||||
|
|
||||||
builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
|
builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
|
||||||
@Override
|
@Override
|
||||||
public Predicate<Thread> apply(final Predicate<Thread> p) {
|
public Predicate<Thread> apply(final Predicate<Thread> p) {
|
||||||
|
@ -86,7 +86,7 @@ public final class UnixResolverDnsServerAddressStreamProvider implements DnsServ
|
|||||||
* the default DNS server to use, and also overrides for individual domains. Also parse list of files of the format
|
* the default DNS server to use, and also overrides for individual domains. Also parse list of files of the format
|
||||||
* <a href="
|
* <a href="
|
||||||
* https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/resolver.5.html">
|
* https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/resolver.5.html">
|
||||||
* /etc/resolver</a> which may contain multiple files to override the name servers used for multimple domains.
|
* /etc/resolver</a> which may contain multiple files to override the name servers used for multiple domains.
|
||||||
* @param etcResolvConf <a href="https://linux.die.net/man/5/resolver">/etc/resolv.conf</a>.
|
* @param etcResolvConf <a href="https://linux.die.net/man/5/resolver">/etc/resolv.conf</a>.
|
||||||
* @param etcResolverFiles List of files of the format defined in
|
* @param etcResolverFiles List of files of the format defined in
|
||||||
* <a href="
|
* <a href="
|
||||||
@ -121,7 +121,7 @@ public final class UnixResolverDnsServerAddressStreamProvider implements DnsServ
|
|||||||
* the default DNS server to use, and also overrides for individual domains. Also parse a directory of the format
|
* the default DNS server to use, and also overrides for individual domains. Also parse a directory of the format
|
||||||
* <a href="
|
* <a href="
|
||||||
* https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/resolver.5.html">
|
* https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man5/resolver.5.html">
|
||||||
* /etc/resolver</a> which may contain multiple files to override the name servers used for multimple domains.
|
* /etc/resolver</a> which may contain multiple files to override the name servers used for multiple domains.
|
||||||
* @param etcResolvConf <a href="https://linux.die.net/man/5/resolver">/etc/resolv.conf</a>.
|
* @param etcResolvConf <a href="https://linux.die.net/man/5/resolver">/etc/resolv.conf</a>.
|
||||||
* @param etcResolverDir Directory containing files of the format defined in
|
* @param etcResolverDir Directory containing files of the format defined in
|
||||||
* <a href="
|
* <a href="
|
||||||
@ -379,7 +379,7 @@ public final class UnixResolverDnsServerAddressStreamProvider implements DnsServ
|
|||||||
} else if (line.startsWith(SEARCH_ROW_LABEL)) {
|
} else if (line.startsWith(SEARCH_ROW_LABEL)) {
|
||||||
int i = indexOfNonWhiteSpace(line, SEARCH_ROW_LABEL.length());
|
int i = indexOfNonWhiteSpace(line, SEARCH_ROW_LABEL.length());
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
// May contain more then one entry, either seperated by whitespace or tab.
|
// May contain more then one entry, either separated by whitespace or tab.
|
||||||
// See https://linux.die.net/man/5/resolver
|
// See https://linux.die.net/man/5/resolver
|
||||||
String[] domains = WHITESPACE_PATTERN.split(line.substring(i));
|
String[] domains = WHITESPACE_PATTERN.split(line.substring(i));
|
||||||
Collections.addAll(searchDomains, domains);
|
Collections.addAll(searchDomains, domains);
|
||||||
|
@ -26,6 +26,7 @@ import io.netty.channel.ChannelInboundHandlerAdapter;
|
|||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.nio.NioDatagramChannel;
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
@ -35,7 +36,7 @@ import io.netty.handler.ssl.SslHandshakeCompletionEvent;
|
|||||||
import io.netty.handler.ssl.SslProvider;
|
import io.netty.handler.ssl.SslProvider;
|
||||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||||
import io.netty.resolver.dns.DnsServerAddressStreamProvider;
|
import io.netty.resolver.dns.DnsNameResolverBuilder;
|
||||||
import io.netty.resolver.dns.DnsServerAddressStreamProviders;
|
import io.netty.resolver.dns.DnsServerAddressStreamProviders;
|
||||||
import io.netty.util.HashedWheelTimer;
|
import io.netty.util.HashedWheelTimer;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
import io.netty.util.ReferenceCountUtil;
|
||||||
@ -59,6 +60,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@ -320,7 +322,30 @@ public class NettyBlockHoundIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout = 5000L)
|
@Test(timeout = 5000L)
|
||||||
public void testParseEtcResolverFilesAllowsBlockingCalls() throws InterruptedException {
|
public void testUnixResolverDnsServerAddressStreamProvider_Parse() throws InterruptedException {
|
||||||
|
doTestParseResolverFilesAllowsBlockingCalls(DnsServerAddressStreamProviders::unixDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 5000L)
|
||||||
|
public void testHostsFileParser_Parse() throws InterruptedException {
|
||||||
|
doTestParseResolverFilesAllowsBlockingCalls(DnsNameResolverBuilder::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 5000L)
|
||||||
|
public void testUnixResolverDnsServerAddressStreamProvider_ParseEtcResolverSearchDomainsAndOptions()
|
||||||
|
throws InterruptedException {
|
||||||
|
NioEventLoopGroup group = new NioEventLoopGroup();
|
||||||
|
try {
|
||||||
|
DnsNameResolverBuilder builder = new DnsNameResolverBuilder(group.next())
|
||||||
|
.channelFactory(NioDatagramChannel::new);
|
||||||
|
doTestParseResolverFilesAllowsBlockingCalls(builder::build);
|
||||||
|
} finally {
|
||||||
|
group.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doTestParseResolverFilesAllowsBlockingCalls(Callable<Object> callable)
|
||||||
|
throws InterruptedException {
|
||||||
SingleThreadEventExecutor executor =
|
SingleThreadEventExecutor executor =
|
||||||
new SingleThreadEventExecutor(null, new DefaultThreadFactory("test"), true) {
|
new SingleThreadEventExecutor(null, new DefaultThreadFactory("test"), true) {
|
||||||
@Override
|
@Override
|
||||||
@ -335,11 +360,11 @@ public class NettyBlockHoundIntegrationTest {
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
List<DnsServerAddressStreamProvider> result = new ArrayList<>();
|
List<Object> result = new ArrayList<>();
|
||||||
List<Throwable> error = new ArrayList<>();
|
List<Throwable> error = new ArrayList<>();
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
result.add(DnsServerAddressStreamProviders.unixDefault());
|
result.add(callable.call());
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
error.add(t);
|
error.add(t);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user