xds: Avoid NPE for no filter chain match on server-side

This commit is contained in:
Eric Anderson 2021-06-29 11:32:37 -05:00 committed by GitHub
parent 7644350ecb
commit 4814d975a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 6 deletions

View File

@ -313,7 +313,7 @@ public final class EnvoyServerProtoData {
/** /**
* Corresponds to Envoy proto message {@link io.envoyproxy.envoy.api.v2.listener.FilterChain}. * Corresponds to Envoy proto message {@link io.envoyproxy.envoy.api.v2.listener.FilterChain}.
*/ */
static final class FilterChain { public static final class FilterChain {
// Unique name for the FilterChain. // Unique name for the FilterChain.
private final String name; private final String name;
// TODO(sanjaypujare): flatten structure by moving FilterChainMatch class members here. // TODO(sanjaypujare): flatten structure by moving FilterChainMatch class members here.
@ -391,7 +391,7 @@ public final class EnvoyServerProtoData {
* Corresponds to Envoy proto message {@link io.envoyproxy.envoy.api.v2.Listener} & related * Corresponds to Envoy proto message {@link io.envoyproxy.envoy.api.v2.Listener} & related
* classes. * classes.
*/ */
static final class Listener { public static final class Listener {
private final String name; private final String name;
@Nullable @Nullable
private final String address; private final String address;
@ -399,7 +399,8 @@ public final class EnvoyServerProtoData {
@Nullable @Nullable
private final FilterChain defaultFilterChain; private final FilterChain defaultFilterChain;
Listener(String name, @Nullable String address, /** Construct a Listener. */
public Listener(String name, @Nullable String address,
List<FilterChain> filterChains, @Nullable FilterChain defaultFilterChain) { List<FilterChain> filterChains, @Nullable FilterChain defaultFilterChain) {
this.name = checkNotNull(name, "name"); this.name = checkNotNull(name, "name");
this.address = address; this.address = address;

View File

@ -238,6 +238,11 @@ public final class XdsClientWrapperForServerSds {
} else if (filterChains.size() == 1) { } else if (filterChains.size() == 1) {
return filterChains.get(0).getSslContextProviderSupplier(); return filterChains.get(0).getSslContextProviderSupplier();
} }
if (listener.getDefaultFilterChain() == null) {
// close the connection
throw new RuntimeException(
"no matching filter chain. local: " + localInetAddr + " remote: " + remoteInetAddr);
}
return listener.getDefaultFilterChain().getSslContextProviderSupplier(); return listener.getDefaultFilterChain().getSslContextProviderSupplier();
} }
@ -428,7 +433,7 @@ public final class XdsClientWrapperForServerSds {
} }
@VisibleForTesting @VisibleForTesting
XdsClient.LdsResourceWatcher getListenerWatcher() { public XdsClient.LdsResourceWatcher getListenerWatcher() {
return listenerWatcher; return listenerWatcher;
} }

View File

@ -37,7 +37,7 @@ import org.mockito.ArgumentCaptor;
/** /**
* Helper methods related to {@link XdsServerBuilder} and related classes. * Helper methods related to {@link XdsServerBuilder} and related classes.
*/ */
class XdsServerTestHelper { public class XdsServerTestHelper {
private static final String SERVER_URI = "trafficdirector.googleapis.com"; private static final String SERVER_URI = "trafficdirector.googleapis.com";
private static final String NODE_ID = private static final String NODE_ID =
@ -88,7 +88,8 @@ class XdsServerTestHelper {
} }
} }
static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds(int port, /** Create an XdsClientWrapperForServerSds with a mock XdsClient. */
public static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds(int port,
TlsContextManager tlsContextManager) { TlsContextManager tlsContextManager) {
FakeXdsClientPoolFactory fakeXdsClientPoolFactory = new FakeXdsClientPoolFactory( FakeXdsClientPoolFactory fakeXdsClientPoolFactory = new FakeXdsClientPoolFactory(
buildMockXdsClient(tlsContextManager)); buildMockXdsClient(tlsContextManager));
@ -139,6 +140,11 @@ class XdsServerTestHelper {
registeredWatcher.onChanged(listenerUpdate); registeredWatcher.onChanged(listenerUpdate);
} }
public static void generateListenerUpdate(
XdsClient.LdsResourceWatcher registeredWatcher, EnvoyServerProtoData.Listener listener) {
registeredWatcher.onChanged(LdsUpdate.forTcpListener(listener));
}
static int findFreePort() throws IOException { static int findFreePort() throws IOException {
try (ServerSocket socket = new ServerSocket(0)) { try (ServerSocket socket = new ServerSocket(0)) {
socket.setReuseAddress(true); socket.setReuseAddress(true);

View File

@ -44,12 +44,14 @@ import io.grpc.netty.InternalProtocolNegotiator.ProtocolNegotiator;
import io.grpc.netty.InternalProtocolNegotiators; import io.grpc.netty.InternalProtocolNegotiators;
import io.grpc.xds.Bootstrapper; import io.grpc.xds.Bootstrapper;
import io.grpc.xds.CommonBootstrapperTestUtils; import io.grpc.xds.CommonBootstrapperTestUtils;
import io.grpc.xds.EnvoyServerProtoData;
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext; import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext; import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
import io.grpc.xds.InternalXdsAttributes; import io.grpc.xds.InternalXdsAttributes;
import io.grpc.xds.TlsContextManager; import io.grpc.xds.TlsContextManager;
import io.grpc.xds.XdsClientWrapperForServerSds; import io.grpc.xds.XdsClientWrapperForServerSds;
import io.grpc.xds.XdsClientWrapperForServerSdsTestMisc; import io.grpc.xds.XdsClientWrapperForServerSdsTestMisc;
import io.grpc.xds.XdsServerTestHelper;
import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsHandler; import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsHandler;
import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsProtocolNegotiator; import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsProtocolNegotiator;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
@ -72,6 +74,7 @@ import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.security.cert.CertStoreException; import java.security.cert.CertStoreException;
import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -348,6 +351,54 @@ public class SdsProtocolNegotiatorsTest {
} }
} }
@Test
public void noMatchingFilterChain_expectException() {
// we need InetSocketAddress instead of EmbeddedSocketAddress as localAddress for this test
channel =
new EmbeddedChannel() {
@Override
public SocketAddress localAddress() {
return new InetSocketAddress("172.168.1.1", 80);
}
@Override
public SocketAddress remoteAddress() {
return new InetSocketAddress("172.168.2.2", 90);
}
};
pipeline = channel.pipeline();
Bootstrapper.BootstrapInfo bootstrapInfoForServer = CommonBootstrapperTestUtils
.buildBootstrapInfo("google_cloud_private_spiffe-server", SERVER_1_KEY_FILE,
SERVER_1_PEM_FILE, CA_PEM_FILE, null, null, null, null);
TlsContextManagerImpl tlsContextManager = new TlsContextManagerImpl(bootstrapInfoForServer);
XdsClientWrapperForServerSds xdsClientWrapperForServerSds =
XdsServerTestHelper.createXdsClientWrapperForServerSds(80, tlsContextManager);
xdsClientWrapperForServerSds.start();
EnvoyServerProtoData.Listener listener = new EnvoyServerProtoData.Listener(
"listener1", "0.0.0.0", Arrays.<EnvoyServerProtoData.FilterChain>asList(), null);
XdsServerTestHelper.generateListenerUpdate(
xdsClientWrapperForServerSds.getListenerWatcher(), listener);
SdsProtocolNegotiators.HandlerPickerHandler handlerPickerHandler =
new SdsProtocolNegotiators.HandlerPickerHandler(grpcHandler, xdsClientWrapperForServerSds,
InternalProtocolNegotiators.serverPlaintext());
pipeline.addLast(handlerPickerHandler);
channelHandlerCtx = pipeline.context(handlerPickerHandler);
assertThat(channelHandlerCtx).isNotNull(); // should find HandlerPickerHandler
// kick off protocol negotiation
pipeline.fireUserEventTriggered(InternalProtocolNegotiationEvent.getDefault());
channelHandlerCtx = pipeline.context(handlerPickerHandler);
assertThat(channelHandlerCtx).isNotNull(); // HandlerPickerHandler still there
try {
channel.checkException();
fail("exception expected!");
} catch (Exception e) {
assertThat(e).hasMessageThat().contains("no matching filter chain");
}
}
@Test @Test
public void clientSdsProtocolNegotiatorNewHandler_fireProtocolNegotiationEvent() public void clientSdsProtocolNegotiatorNewHandler_fireProtocolNegotiationEvent()
throws InterruptedException, TimeoutException, ExecutionException { throws InterruptedException, TimeoutException, ExecutionException {