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",
|
||||
"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>>() {
|
||||
@Override
|
||||
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
|
||||
* <a href="
|
||||
* 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 etcResolverFiles List of files of the format defined in
|
||||
* <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
|
||||
* <a href="
|
||||
* 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 etcResolverDir Directory containing files of the format defined in
|
||||
* <a href="
|
||||
@ -379,7 +379,7 @@ public final class UnixResolverDnsServerAddressStreamProvider implements DnsServ
|
||||
} else if (line.startsWith(SEARCH_ROW_LABEL)) {
|
||||
int i = indexOfNonWhiteSpace(line, SEARCH_ROW_LABEL.length());
|
||||
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
|
||||
String[] domains = WHITESPACE_PATTERN.split(line.substring(i));
|
||||
Collections.addAll(searchDomains, domains);
|
||||
|
@ -26,6 +26,7 @@ import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
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.NioSocketChannel;
|
||||
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.util.InsecureTrustManagerFactory;
|
||||
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.util.HashedWheelTimer;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
@ -59,6 +60,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
@ -320,7 +322,30 @@ public class NettyBlockHoundIntegrationTest {
|
||||
}
|
||||
|
||||
@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 =
|
||||
new SingleThreadEventExecutor(null, new DefaultThreadFactory("test"), true) {
|
||||
@Override
|
||||
@ -335,11 +360,11 @@ public class NettyBlockHoundIntegrationTest {
|
||||
};
|
||||
try {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
List<DnsServerAddressStreamProvider> result = new ArrayList<>();
|
||||
List<Object> result = new ArrayList<>();
|
||||
List<Throwable> error = new ArrayList<>();
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
result.add(DnsServerAddressStreamProviders.unixDefault());
|
||||
result.add(callable.call());
|
||||
} catch (Throwable t) {
|
||||
error.add(t);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user