diff --git a/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java b/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java index 17ba379a9c..24d6f21e5e 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java +++ b/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java @@ -216,9 +216,10 @@ public final class XdsClientWrapperForServerSds { filterChains = filterOnIpAddress(filterChains, remoteInetAddr.getAddress(), false); filterChains = filterOnSourcePort(filterChains, remoteInetAddr.getPort()); - // if we get more than 1, we ignore filterChains and use the defaultFilerChain - // although spec not clear for that case - if (filterChains.size() == 1) { + if (filterChains.size() > 1) { + // close the connection + throw new IllegalStateException("Found 2 matching filter-chains"); + } else if (filterChains.size() == 1) { return filterChains.get(0).getDownstreamTlsContext(); } return curListener.getDefaultFilterChain().getDownstreamTlsContext(); @@ -307,10 +308,10 @@ public final class XdsClientWrapperForServerSds { ? filterChainMatch.getPrefixRanges() : filterChainMatch.getSourcePrefixRanges(); indexOfMatchingPrefixRange = -1; - if (cidrRanges.isEmpty()) { // if there is no CidrRange assume there is perfect match - matchingPrefixLength = isIPv6 ? 128 : 32; - } else { + if (cidrRanges.isEmpty()) { // if there is no CidrRange assume 0-length match matchingPrefixLength = 0; + } else { + matchingPrefixLength = -1; int index = 0; for (CidrRange cidrRange : cidrRanges) { InetAddress cidrAddr = cidrRange.getAddressPrefix(); @@ -357,7 +358,7 @@ public final class XdsClientWrapperForServerSds { for (FilterChain filterChain : filterChains) { QueueElement element = new QueueElement(filterChain, address, forDestination); - if (element.matchingPrefixLength > 0) { + if (element.matchingPrefixLength >= 0) { heap.add(element); } } diff --git a/xds/src/test/java/io/grpc/xds/FilterChainMatchTest.java b/xds/src/test/java/io/grpc/xds/FilterChainMatchTest.java index b92b1b8ccd..e13064cd9f 100644 --- a/xds/src/test/java/io/grpc/xds/FilterChainMatchTest.java +++ b/xds/src/test/java/io/grpc/xds/FilterChainMatchTest.java @@ -17,6 +17,7 @@ package io.grpc.xds; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; import static org.mockito.Mockito.when; import com.google.protobuf.InvalidProtocolBufferException; @@ -217,6 +218,37 @@ public class FilterChainMatchTest { assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain); } + @Test + public void dest0LengthPrefixRange() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContext0Length = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + // 10.2.2.0/24 doesn't match LOCAL_IP + EnvoyServerProtoData.FilterChainMatch filterChainMatch0Length = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.2.2.0", 0)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChain0Length = + new EnvoyServerProtoData.FilterChain(filterChainMatch0Length, tlsContext0Length); + DownstreamTlsContext tlsContextForDefaultFilterChain = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", LOCAL_IP, Arrays.asList(filterChain0Length), defaultFilterChain); + XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener); + registeredWatcher.onChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContext0Length); + } + @Test public void destPrefixRange_moreSpecificWins() throws UnknownHostException, InvalidProtocolBufferException { @@ -261,6 +293,50 @@ public class FilterChainMatchTest { assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific); } + @Test + public void destPrefixRange_emptyListLessSpecific() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextLessSpecific = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainLessSpecific = + new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific); + + DownstreamTlsContext tlsContextMoreSpecific = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("8.0.0.0", 5)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainMoreSpecific = + new EnvoyServerProtoData.FilterChain(filterChainMatchMoreSpecific, tlsContextMoreSpecific); + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, null); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", + LOCAL_IP, + Arrays.asList(filterChainLessSpecific, filterChainMoreSpecific), + defaultFilterChain); + XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener); + registeredWatcher.onChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific); + } + @Test public void destPrefixRangeIpv6_moreSpecificWins() throws UnknownHostException, InvalidProtocolBufferException { @@ -457,6 +533,52 @@ public class FilterChainMatchTest { assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecificWith2); } + @Test + public void sourcePrefixRange_2Matchers_expectException() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContext1 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatch1 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList( + new EnvoyServerProtoData.CidrRange("10.4.2.0", 24), + new EnvoyServerProtoData.CidrRange("192.168.10.2", 32)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChain1 = + new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext1); + + DownstreamTlsContext tlsContext2 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); + EnvoyServerProtoData.FilterChainMatch filterChainMatch2 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.2.0", 24)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChain2 = + new EnvoyServerProtoData.FilterChain(filterChainMatch2, tlsContext2); + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, null); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", LOCAL_IP, Arrays.asList(filterChain1, filterChain2), defaultFilterChain); + XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener); + registeredWatcher.onChanged(listenerUpdate); + try { + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + fail("expect exception!"); + } catch (IllegalStateException ise) { + assertThat(ise).hasMessageThat().isEqualTo("Found 2 matching filter-chains"); + } + } + @Test public void sourcePortMatch_exactMatchWinsOverEmptyList() throws UnknownHostException, InvalidProtocolBufferException {