diff --git a/xds/src/main/java/io/grpc/xds/ClientXdsClient.java b/xds/src/main/java/io/grpc/xds/ClientXdsClient.java index ec817212d3..826c2cf52c 100644 --- a/xds/src/main/java/io/grpc/xds/ClientXdsClient.java +++ b/xds/src/main/java/io/grpc/xds/ClientXdsClient.java @@ -18,7 +18,7 @@ package io.grpc.xds; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static io.grpc.xds.EnvoyProtoData.TRANSPORT_SOCKET_NAME_TLS; +import static io.grpc.xds.EnvoyServerProtoData.TRANSPORT_SOCKET_NAME_TLS; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.CaseFormat; diff --git a/xds/src/main/java/io/grpc/xds/EnvoyProtoData.java b/xds/src/main/java/io/grpc/xds/EnvoyProtoData.java index 442e0629ee..3fa822d26c 100644 --- a/xds/src/main/java/io/grpc/xds/EnvoyProtoData.java +++ b/xds/src/main/java/io/grpc/xds/EnvoyProtoData.java @@ -47,7 +47,6 @@ import javax.annotation.Nullable; */ // TODO(chengyuanzhang): put data types into smaller categories. final class EnvoyProtoData { - static final String TRANSPORT_SOCKET_NAME_TLS = "envoy.transport_sockets.tls"; // Prevent instantiation. private EnvoyProtoData() { diff --git a/xds/src/main/java/io/grpc/xds/EnvoyServerProtoData.java b/xds/src/main/java/io/grpc/xds/EnvoyServerProtoData.java index 7eef74018f..1dab0db9fa 100644 --- a/xds/src/main/java/io/grpc/xds/EnvoyServerProtoData.java +++ b/xds/src/main/java/io/grpc/xds/EnvoyServerProtoData.java @@ -16,15 +16,16 @@ package io.grpc.xds; -import static io.grpc.xds.EnvoyProtoData.TRANSPORT_SOCKET_NAME_TLS; - import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; import com.google.protobuf.Any; import com.google.protobuf.InvalidProtocolBufferException; import io.envoyproxy.envoy.config.core.v3.Address; import io.envoyproxy.envoy.config.core.v3.SocketAddress; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext; import io.grpc.Internal; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -38,6 +39,8 @@ import javax.annotation.Nullable; @Internal public final class EnvoyServerProtoData { + static final String TRANSPORT_SOCKET_NAME_TLS = "envoy.transport_sockets.tls"; + // Prevent instantiation. private EnvoyServerProtoData() { } @@ -144,21 +147,25 @@ public final class EnvoyServerProtoData { } static final class CidrRange { - private final String addressPrefix; + private final InetAddress addressPrefix; private final int prefixLen; @VisibleForTesting - CidrRange(String addressPrefix, int prefixLen) { - this.addressPrefix = addressPrefix; + CidrRange(String addressPrefix, int prefixLen) throws InvalidProtocolBufferException { + try { + this.addressPrefix = InetAddress.getByName(addressPrefix); + } catch (UnknownHostException e) { + throw new InvalidProtocolBufferException(e.getMessage()); + } this.prefixLen = prefixLen; } static CidrRange fromEnvoyProtoCidrRange( - io.envoyproxy.envoy.config.core.v3.CidrRange proto) { + io.envoyproxy.envoy.config.core.v3.CidrRange proto) throws InvalidProtocolBufferException { return new CidrRange(proto.getAddressPrefix(), proto.getPrefixLen().getValue()); } - public String getAddressPrefix() { + public InetAddress getAddressPrefix() { return addressPrefix; } @@ -193,6 +200,17 @@ public final class EnvoyServerProtoData { } } + enum ConnectionSourceType { + // Any connection source matches. + ANY, + + // Match a connection originating from the same host. + SAME_IP_OR_LOOPBACK, + + // Match a connection originating from a different host. + EXTERNAL + } + /** * Corresponds to Envoy proto message * {@link io.envoyproxy.envoy.api.v2.listener.FilterChainMatch}. @@ -201,29 +219,62 @@ public final class EnvoyServerProtoData { private final int destinationPort; private final List prefixRanges; private final List applicationProtocols; + private final List sourcePrefixRanges; + private final ConnectionSourceType sourceType; + private final List sourcePorts; @VisibleForTesting - FilterChainMatch(int destinationPort, - List prefixRanges, List applicationProtocols) { + FilterChainMatch( + int destinationPort, + List prefixRanges, + List applicationProtocols, + List sourcePrefixRanges, + ConnectionSourceType sourceType, + List sourcePorts) { this.destinationPort = destinationPort; this.prefixRanges = Collections.unmodifiableList(prefixRanges); this.applicationProtocols = Collections.unmodifiableList(applicationProtocols); + this.sourcePrefixRanges = sourcePrefixRanges; + this.sourceType = sourceType; + this.sourcePorts = sourcePorts; } static FilterChainMatch fromEnvoyProtoFilterChainMatch( - io.envoyproxy.envoy.config.listener.v3.FilterChainMatch proto) { + io.envoyproxy.envoy.config.listener.v3.FilterChainMatch proto) + throws InvalidProtocolBufferException { List prefixRanges = new ArrayList<>(); for (io.envoyproxy.envoy.config.core.v3.CidrRange range : proto.getPrefixRangesList()) { prefixRanges.add(CidrRange.fromEnvoyProtoCidrRange(range)); } + List sourcePrefixRanges = new ArrayList<>(); + for (io.envoyproxy.envoy.config.core.v3.CidrRange range : proto.getSourcePrefixRangesList()) { + sourcePrefixRanges.add(CidrRange.fromEnvoyProtoCidrRange(range)); + } List applicationProtocols = new ArrayList<>(); - for (String appProtocol : proto.getApplicationProtocolsList()) { + for (String appProtocol : proto.getApplicationProtocolsList()) { applicationProtocols.add(appProtocol); } + ConnectionSourceType sourceType = null; + switch (proto.getSourceType()) { + case ANY: + sourceType = ConnectionSourceType.ANY; + break; + case EXTERNAL: + sourceType = ConnectionSourceType.EXTERNAL; + break; + case SAME_IP_OR_LOOPBACK: + sourceType = ConnectionSourceType.SAME_IP_OR_LOOPBACK; + break; + default: + throw new InvalidProtocolBufferException("Unknown source-type:" + proto.getSourceType()); + } return new FilterChainMatch( proto.getDestinationPort().getValue(), prefixRanges, - applicationProtocols); + applicationProtocols, + sourcePrefixRanges, + sourceType, + proto.getSourcePortsList()); } public int getDestinationPort() { @@ -238,6 +289,18 @@ public final class EnvoyServerProtoData { return applicationProtocols; } + public List getSourcePrefixRanges() { + return sourcePrefixRanges; + } + + public ConnectionSourceType getConnectionSourceType() { + return sourceType; + } + + public List getSourcePorts() { + return sourcePorts; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -248,22 +311,34 @@ public final class EnvoyServerProtoData { } FilterChainMatch that = (FilterChainMatch) o; return destinationPort == that.destinationPort - && java.util.Objects.equals(prefixRanges, that.prefixRanges) - && java.util.Objects.equals(applicationProtocols, that.applicationProtocols); + && Objects.equals(prefixRanges, that.prefixRanges) + && Objects.equals(applicationProtocols, that.applicationProtocols) + && Objects.equals(sourcePrefixRanges, that.sourcePrefixRanges) + && sourceType == that.sourceType + && Objects.equals(sourcePorts, that.sourcePorts); } @Override public int hashCode() { - return java.util.Objects.hash(destinationPort, prefixRanges, applicationProtocols); + return Objects.hash( + destinationPort, + prefixRanges, + applicationProtocols, + sourcePrefixRanges, + sourceType, + sourcePorts); } @Override public String toString() { - return "FilterChainMatch{" - + "destinationPort=" + destinationPort - + ", prefixRanges=" + prefixRanges - + ", applicationProtocols=" + applicationProtocols - + '}'; + return MoreObjects.toStringHelper(this) + .add("destinationPort", destinationPort) + .add("prefixRanges", prefixRanges) + .add("applicationProtocols", applicationProtocols) + .add("sourcePrefixRanges", sourcePrefixRanges) + .add("sourceType", sourceType) + .add("sourcePorts", sourcePorts) + .toString(); } } @@ -351,13 +426,15 @@ public final class EnvoyServerProtoData { @Nullable private final String address; private final List filterChains; + private final FilterChain defaultFilterChain; @VisibleForTesting Listener(String name, String address, - List filterChains) { + List filterChains, FilterChain defaultFilterChain) { this.name = name; this.address = address; this.filterChains = Collections.unmodifiableList(filterChains); + this.defaultFilterChain = defaultFilterChain; } private static String convertEnvoyAddressToString(Address proto) { @@ -381,12 +458,33 @@ public final class EnvoyServerProtoData { List filterChains = new ArrayList<>(proto.getFilterChainsCount()); for (io.envoyproxy.envoy.config.listener.v3.FilterChain filterChain : proto.getFilterChainsList()) { - filterChains.add(FilterChain.fromEnvoyProtoFilterChain(filterChain)); + if (isAcceptable(filterChain.getFilterChainMatch())) { + filterChains.add(FilterChain.fromEnvoyProtoFilterChain(filterChain)); + } } return new Listener( proto.getName(), convertEnvoyAddressToString(proto.getAddress()), - filterChains); + filterChains, FilterChain.fromEnvoyProtoFilterChain(proto.getDefaultFilterChain())); + } + + // check if a filter is acceptable for gRPC server side processing + private static boolean isAcceptable( + io.envoyproxy.envoy.config.listener.v3.FilterChainMatch filterChainMatch) { + // reject if filer-chain-match + // - has server_name + // - transport protocol is other than "raw_buffer" + // - application_protocols is non-empty (for now accept "managed-mtls") + if (!filterChainMatch.getServerNamesList().isEmpty()) { + return false; + } + String transportProtocol = filterChainMatch.getTransportProtocol(); + if (!transportProtocol.isEmpty() && !"raw_buffer".equals(transportProtocol)) { + return false; + } + List appProtocols = filterChainMatch.getApplicationProtocolsList(); + return appProtocols.isEmpty() + || appProtocols.contains("managed-mtls"); // TODO(sanjaypujare): remove once TD fixed } public String getName() { @@ -401,6 +499,10 @@ public final class EnvoyServerProtoData { return filterChains; } + public FilterChain getDefaultFilterChain() { + return defaultFilterChain; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -410,22 +512,30 @@ public final class EnvoyServerProtoData { return false; } Listener listener = (Listener) o; - return java.util.Objects.equals(name, listener.name) - && java.util.Objects.equals(address, listener.address) - && java.util.Objects.equals(filterChains, listener.filterChains); + return Objects.equals(name, listener.name) + && Objects.equals(address, listener.address) + && Objects.equals(filterChains, listener.filterChains) + && Objects.equals(defaultFilterChain, listener.defaultFilterChain); } @Override public int hashCode() { - return java.util.Objects.hash(name, address, filterChains); + return Objects.hash(name, address, filterChains, defaultFilterChain); } @Override public String toString() { return "Listener{" - + "name='" + name + '\'' - + ", address='" + address + '\'' - + ", filterChains=" + filterChains + + "name='" + + name + + '\'' + + ", address='" + + address + + '\'' + + ", filterChains=" + + filterChains + + ", defaultFilterChain=" + + defaultFilterChain + '}'; } } diff --git a/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java b/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java index 0cf349a6d0..135d0a17ef 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java +++ b/xds/src/main/java/io/grpc/xds/XdsClientWrapperForServerSds.java @@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkState; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; +import com.google.protobuf.UInt32Value; import io.grpc.Grpc; import io.grpc.Internal; import io.grpc.ManagedChannel; @@ -38,14 +39,16 @@ import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollEventLoopGroup; import io.netty.util.concurrent.DefaultThreadFactory; import java.io.IOException; +import java.math.BigInteger; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.net.UnknownHostException; -import java.util.Collections; +import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.PriorityQueue; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -170,31 +173,199 @@ public final class XdsClientWrapperForServerSds { public DownstreamTlsContext getDownstreamTlsContext(Channel channel) { if (curListener != null && channel != null) { SocketAddress localAddress = channel.localAddress(); - checkState( - localAddress instanceof InetSocketAddress, - "Channel localAddress is expected to be InetSocketAddress"); - InetSocketAddress localInetAddr = (InetSocketAddress) localAddress; - checkState( - port == localInetAddr.getPort(), - "Channel localAddress port does not match requested listener port"); - return getDownstreamTlsContext(localInetAddr); + SocketAddress remoteAddress = channel.remoteAddress(); + if (localAddress instanceof InetSocketAddress && remoteAddress instanceof InetSocketAddress) { + InetSocketAddress localInetAddr = (InetSocketAddress) localAddress; + InetSocketAddress remoteInetAddr = (InetSocketAddress) remoteAddress; + checkState( + port == localInetAddr.getPort(), + "Channel localAddress port does not match requested listener port"); + return getDownstreamTlsContext(localInetAddr, remoteInetAddr); + } } return null; } - private DownstreamTlsContext getDownstreamTlsContext(InetSocketAddress localInetAddr) { - checkNotNull(localInetAddr, "localInetAddr"); - if (curListener != null) { - List filterChains = curListener.getFilterChains(); - FilterChainComparator comparator = new FilterChainComparator(localInetAddr); - FilterChain bestMatch = - filterChains.isEmpty() ? null : Collections.max(filterChains, comparator); - if (bestMatch != null - && (newServerApi || comparator.isMatching(bestMatch.getFilterChainMatch()))) { - return bestMatch.getDownstreamTlsContext(); + /** + * Using the logic specified at + * https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/listener/listener_components.proto.html?highlight=filter%20chain#listener-filterchainmatch + * locate a matching filter and return the corresponding DownstreamTlsContext or else return one + * from default filter chain. + * + * @param localInetAddr dest address of the inbound connection + * @param remoteInetAddr source address of the inbound connection + */ + private DownstreamTlsContext getDownstreamTlsContext( + InetSocketAddress localInetAddr, InetSocketAddress remoteInetAddr) { + List filterChains = curListener.getFilterChains(); + + filterChains = filterOnDestinationPort(filterChains); + filterChains = filterOnIpAddress(filterChains, localInetAddr.getAddress(), true); + filterChains = + filterOnSourceType(filterChains, remoteInetAddr.getAddress(), localInetAddr.getAddress()); + 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) { + return filterChains.get(0).getDownstreamTlsContext(); + } + return curListener.getDefaultFilterChain().getDownstreamTlsContext(); + } + + // destination_port present => Always fail match + private static List filterOnDestinationPort(List filterChains) { + ArrayList filtered = new ArrayList<>(filterChains.size()); + for (FilterChain filterChain : filterChains) { + FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch(); + + if (filterChainMatch.getDestinationPort() == UInt32Value.getDefaultInstance().getValue()) { + filtered.add(filterChain); } } - return null; + return filtered; + } + + private static List filterOnSourcePort( + List filterChains, int sourcePort) { + ArrayList filteredOnMatch = new ArrayList<>(filterChains.size()); + ArrayList filteredOnEmpty = new ArrayList<>(filterChains.size()); + for (FilterChain filterChain : filterChains) { + FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch(); + + List sourcePortsToMatch = filterChainMatch.getSourcePorts(); + if (sourcePortsToMatch.isEmpty()) { + filteredOnEmpty.add(filterChain); + } else if (sourcePortsToMatch.contains(sourcePort)) { + filteredOnMatch.add(filterChain); + } + } + // match against source port is more specific than match against empty list + return filteredOnMatch.isEmpty() ? filteredOnEmpty : filteredOnMatch; + } + + private List filterOnSourceType( + List filterChains, InetAddress sourceAddress, InetAddress destAddress) { + ArrayList filtered = new ArrayList<>(filterChains.size()); + for (FilterChain filterChain : filterChains) { + FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch(); + EnvoyServerProtoData.ConnectionSourceType sourceType = + filterChainMatch.getConnectionSourceType(); + + boolean matching = false; + if (sourceType == EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK) { + matching = + sourceAddress.isLoopbackAddress() + || sourceAddress.isAnyLocalAddress() + || sourceAddress.equals(destAddress); + } else if (sourceType == EnvoyServerProtoData.ConnectionSourceType.EXTERNAL) { + matching = !sourceAddress.isLoopbackAddress() && !sourceAddress.isAnyLocalAddress(); + } else { // ANY or null + matching = true; + } + if (matching) { + filtered.add(filterChain); + } + } + return filtered; + } + + private static boolean isCidrMatching(byte[] cidrBytes, byte[] addressBytes, int prefixLen) { + BigInteger cidrInt = new BigInteger(cidrBytes); + BigInteger addrInt = new BigInteger(addressBytes); + + int shiftAmount = 8 * cidrBytes.length - prefixLen; + + cidrInt = cidrInt.shiftRight(shiftAmount); + addrInt = addrInt.shiftRight(shiftAmount); + return cidrInt.equals(addrInt); + } + + private static class QueueElement { + FilterChain filterChain; + int indexOfMatchingPrefixRange; + int matchingPrefixLength; + + public QueueElement(FilterChain filterChain, InetAddress address, boolean forDestination) { + this.filterChain = filterChain; + FilterChainMatch filterChainMatch = filterChain.getFilterChainMatch(); + byte[] addressBytes = address.getAddress(); + boolean isIPv6 = address instanceof Inet6Address; + List cidrRanges = + forDestination + ? filterChainMatch.getPrefixRanges() + : filterChainMatch.getSourcePrefixRanges(); + indexOfMatchingPrefixRange = -1; + if (cidrRanges.isEmpty()) { // if there is no CidrRange assume there is perfect match + matchingPrefixLength = isIPv6 ? 128 : 32; + } else { + matchingPrefixLength = 0; + int index = 0; + for (CidrRange cidrRange : cidrRanges) { + InetAddress cidrAddr = cidrRange.getAddressPrefix(); + boolean cidrIsIpv6 = cidrAddr instanceof Inet6Address; + if (isIPv6 == cidrIsIpv6) { + byte[] cidrBytes = cidrAddr.getAddress(); + int prefixLen = cidrRange.getPrefixLen(); + if (isCidrMatching(cidrBytes, addressBytes, prefixLen) + && prefixLen > matchingPrefixLength) { + matchingPrefixLength = prefixLen; + indexOfMatchingPrefixRange = index; + } + } + index++; + } + } + } + } + + private static final class QueueElementComparator implements Comparator { + + @Override + public int compare(QueueElement o1, QueueElement o2) { + // descending order for max heap + return o2.matchingPrefixLength - o1.matchingPrefixLength; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof QueueElementComparator; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + } + + // use prefix_ranges (CIDR) and get the most specific matches + private List filterOnIpAddress( + List filterChains, InetAddress address, boolean forDestination) { + PriorityQueue heap = new PriorityQueue<>(10, new QueueElementComparator()); + + for (FilterChain filterChain : filterChains) { + QueueElement element = new QueueElement(filterChain, address, forDestination); + + if (element.matchingPrefixLength > 0) { + heap.add(element); + } + } + // get the top ones + ArrayList topOnes = new ArrayList<>(heap.size()); + int topMatchingPrefixLen = -1; + while (!heap.isEmpty()) { + QueueElement element = heap.remove(); + if (topMatchingPrefixLen == -1) { + topMatchingPrefixLen = element.matchingPrefixLength; + } else { + if (element.matchingPrefixLength < topMatchingPrefixLen) { + break; + } + } + topOnes.add(element.filterChain); + } + return topOnes; } /** Adds a {@link ServerWatcher} to the list. */ @@ -204,7 +375,7 @@ public final class XdsClientWrapperForServerSds { serverWatchers.add(serverWatcher); } if (curListener != null) { - serverWatcher.onSuccess(getDownstreamTlsContext(new InetSocketAddress(port))); + serverWatcher.onSuccess(); } } @@ -229,10 +400,8 @@ public final class XdsClientWrapperForServerSds { } private void reportSuccess() { - DownstreamTlsContext downstreamTlsContext = - getDownstreamTlsContext(new InetSocketAddress(port)); for (ServerWatcher watcher : getServerWatchers()) { - watcher.onSuccess(downstreamTlsContext); + watcher.onSuccess(); } } @@ -249,97 +418,7 @@ public final class XdsClientWrapperForServerSds { void onError(Throwable throwable); /** Called to report successful receipt of server config. */ - void onSuccess(DownstreamTlsContext downstreamTlsContext); - } - - private static final class FilterChainComparator implements Comparator { - private final InetSocketAddress localAddress; - - private enum Match { - NO_MATCH, - EMPTY_PREFIX_RANGE_MATCH, - IPANY_MATCH, - EXACT_ADDRESS_MATCH - } - - private FilterChainComparator(InetSocketAddress localAddress) { - checkNotNull(localAddress, "localAddress cannot be null"); - this.localAddress = localAddress; - } - - @Override - public int compare(FilterChain first, FilterChain second) { - checkNotNull(first, "first arg cannot be null"); - checkNotNull(second, "second arg cannot be null"); - FilterChainMatch firstMatch = first.getFilterChainMatch(); - FilterChainMatch secondMatch = second.getFilterChainMatch(); - - if (firstMatch == null) { - return (secondMatch == null) ? 0 : (isMatching(secondMatch) ? -1 : 1); - } else { - return (secondMatch == null) - ? (isMatching(firstMatch) ? 1 : -1) - : compare(firstMatch, secondMatch); - } - } - - private int compare(FilterChainMatch first, FilterChainMatch second) { - int channelPort = localAddress.getPort(); - - if (first.getDestinationPort() == channelPort) { - return (second.getDestinationPort() == channelPort) - ? compare(first.getPrefixRanges(), second.getPrefixRanges()) - : (isInetAddressMatching(first.getPrefixRanges()) ? 1 : 0); - } else { - return (second.getDestinationPort() == channelPort) - ? (isInetAddressMatching(second.getPrefixRanges()) ? -1 : 0) - : 0; - } - } - - private int compare(List first, List second) { - return getInetAddressMatch(first).ordinal() - getInetAddressMatch(second).ordinal(); - } - - private boolean isInetAddressMatching(List prefixRanges) { - return getInetAddressMatch(prefixRanges).ordinal() > Match.NO_MATCH.ordinal(); - } - - private Match getInetAddressMatch(List prefixRanges) { - if (prefixRanges == null || prefixRanges.isEmpty()) { - return Match.EMPTY_PREFIX_RANGE_MATCH; - } - InetAddress localInetAddress = localAddress.getAddress(); - for (CidrRange cidrRange : prefixRanges) { - if (cidrRange.getPrefixLen() == 32) { - try { - InetAddress cidrAddr = InetAddress.getByName(cidrRange.getAddressPrefix()); - if (cidrAddr.isAnyLocalAddress()) { - return Match.IPANY_MATCH; - } - if (cidrAddr.equals(localInetAddress)) { - return Match.EXACT_ADDRESS_MATCH; - } - } catch (UnknownHostException e) { - logger.log(Level.WARNING, "cidrRange address parsing", e); - // continue - } - } - // TODO(sanjaypujare): implement prefix match logic as needed - } - return Match.NO_MATCH; - } - - private boolean isMatching(FilterChainMatch filterChainMatch) { - if (filterChainMatch == null) { - return true; - } - int destPort = filterChainMatch.getDestinationPort(); - if (destPort != localAddress.getPort()) { - return false; - } - return isInetAddressMatching(filterChainMatch.getPrefixRanges()); - } + void onSuccess(); } /** Shutdown this instance and release resources. */ diff --git a/xds/src/main/java/io/grpc/xds/internal/sds/ServerWrapperForXds.java b/xds/src/main/java/io/grpc/xds/internal/sds/ServerWrapperForXds.java index 5eb9379d56..cc75261f1e 100644 --- a/xds/src/main/java/io/grpc/xds/internal/sds/ServerWrapperForXds.java +++ b/xds/src/main/java/io/grpc/xds/internal/sds/ServerWrapperForXds.java @@ -92,8 +92,8 @@ public final class ServerWrapperForXds extends Server { } @Override - public void onSuccess(EnvoyServerProtoData.DownstreamTlsContext downstreamTlsContext) { - settableFuture.set(downstreamTlsContext); + public void onSuccess() { + settableFuture.set(null); } }; xdsClientWrapperForServerSds.addServerWatcher(serverWatcher); diff --git a/xds/src/test/java/io/grpc/xds/EnvoyServerProtoDataTest.java b/xds/src/test/java/io/grpc/xds/EnvoyServerProtoDataTest.java index 5a9761520f..0ee203c09c 100644 --- a/xds/src/test/java/io/grpc/xds/EnvoyServerProtoDataTest.java +++ b/xds/src/test/java/io/grpc/xds/EnvoyServerProtoDataTest.java @@ -57,6 +57,7 @@ public class EnvoyServerProtoDataTest { .setAddress(address) .addFilterChains(createOutFilter()) .addFilterChains(createInFilter()) + .setDefaultFilterChain(createDefaultFilterChain()) .build(); Listener xdsListener = Listener.fromEnvoyProtoListener(listener); @@ -81,8 +82,13 @@ public class EnvoyServerProtoDataTest { assertThat(inFilterChainMatch).isNotNull(); assertThat(inFilterChainMatch.getDestinationPort()).isEqualTo(8000); assertThat(inFilterChainMatch.getApplicationProtocols()).containsExactly("managed-mtls"); - assertThat(inFilterChainMatch.getPrefixRanges()).containsExactly( - new EnvoyServerProtoData.CidrRange("10.20.0.15", 32)); + assertThat(inFilterChainMatch.getPrefixRanges()) + .containsExactly(new EnvoyServerProtoData.CidrRange("10.20.0.15", 32)); + assertThat(inFilterChainMatch.getSourcePrefixRanges()) + .containsExactly(new EnvoyServerProtoData.CidrRange("10.30.3.0", 24)); + assertThat(inFilterChainMatch.getConnectionSourceType()) + .isEqualTo(EnvoyServerProtoData.ConnectionSourceType.EXTERNAL); + assertThat(inFilterChainMatch.getSourcePorts()).containsExactly(200, 300); DownstreamTlsContext inFilterTlsContext = inFilter.getDownstreamTlsContext(); assertThat(inFilterTlsContext.getCommonTlsContext()).isNotNull(); CommonTlsContext commonTlsContext = inFilterTlsContext.getCommonTlsContext(); @@ -90,6 +96,15 @@ public class EnvoyServerProtoDataTest { .getTlsCertificateSdsSecretConfigsList(); assertThat(tlsCertSdsConfigs).hasSize(1); assertThat(tlsCertSdsConfigs.get(0).getName()).isEqualTo("google-sds-config-default"); + + EnvoyServerProtoData.FilterChain defaultFilter = xdsListener.getDefaultFilterChain(); + assertThat(defaultFilter).isNotNull(); + EnvoyServerProtoData.FilterChainMatch defaultFilterChainMatch = + defaultFilter.getFilterChainMatch(); + assertThat(defaultFilterChainMatch).isNotNull(); + assertThat(defaultFilterChainMatch.getDestinationPort()).isEqualTo(8001); + assertThat(defaultFilterChainMatch.getPrefixRanges()) + .containsExactly(new EnvoyServerProtoData.CidrRange("10.20.0.16", 30)); } private static FilterChain createOutFilter() { @@ -116,7 +131,15 @@ public class EnvoyServerProtoDataTest { .setAddressPrefix("10.20.0.15") .setPrefixLen(UInt32Value.of(32)) .build()) + .addSourcePrefixRanges( + CidrRange.newBuilder() + .setAddressPrefix("10.30.3.0") + .setPrefixLen(UInt32Value.of(24)) + .build()) .addApplicationProtocols("managed-mtls") + .setSourceType(FilterChainMatch.ConnectionSourceType.EXTERNAL) + .addSourcePorts(200) + .addSourcePorts(300) .build()) .setTransportSocket(TransportSocket.newBuilder().setName("envoy.transport_sockets.tls") .setTypedConfig( @@ -133,4 +156,38 @@ public class EnvoyServerProtoDataTest { .build(); return filterChain; } + + private static FilterChain createDefaultFilterChain() { + FilterChain filterChain = + FilterChain.newBuilder() + .setFilterChainMatch( + FilterChainMatch.newBuilder() + .setDestinationPort(UInt32Value.of(8001)) + .addPrefixRanges( + CidrRange.newBuilder() + .setAddressPrefix("10.20.0.16") + .setPrefixLen(UInt32Value.of(30)) + .build()) + .build()) + .setTransportSocket( + TransportSocket.newBuilder() + .setName("envoy.transport_sockets.tls") + .setTypedConfig( + Any.pack( + CommonTlsContextTestsUtil.buildTestDownstreamTlsContext( + "google-sds-config-default", "ROOTCA"))) + .build()) + .addFilters( + Filter.newBuilder() + .setName("envoy.http_connection_manager") + .setTypedConfig( + Any.newBuilder() + .setTypeUrl( + "type.googleapis.com/" + + "envoy.config.filter.network.http_connection_manager" + + ".v2.HttpConnectionManager")) + .build()) + .build(); + return filterChain; + } } diff --git a/xds/src/test/java/io/grpc/xds/FilterChainMatchTest.java b/xds/src/test/java/io/grpc/xds/FilterChainMatchTest.java new file mode 100644 index 0000000000..80ee5b8d30 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/FilterChainMatchTest.java @@ -0,0 +1,652 @@ +/* + * Copyright 2021 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import com.google.protobuf.InvalidProtocolBufferException; +import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext; +import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil; +import io.netty.channel.Channel; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** Tests for {@link XdsClientWrapperForServerSds}. */ +@RunWith(JUnit4.class) +public class FilterChainMatchTest { + + private static final int PORT = 7000; + private static final String LOCAL_IP = "10.1.2.3"; // dest + private static final String REMOTE_IP = "10.4.2.3"; // source + + @Mock private XdsClient xdsClient; + @Mock private Channel channel; + + private XdsClientWrapperForServerSds xdsClientWrapperForServerSds; + private XdsClient.ListenerWatcher registeredWatcher; + + @Before + public void setUp() throws IOException { + MockitoAnnotations.initMocks(this); + xdsClientWrapperForServerSds = new XdsClientWrapperForServerSds(PORT); + registeredWatcher = + XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT); + } + + @After + public void tearDown() { + xdsClientWrapperForServerSds.shutdown(); + } + + @Test + public void singleFilterChainWithoutAlpn() throws UnknownHostException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + EnvoyServerProtoData.FilterChainMatch filterChainMatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + DownstreamTlsContext tlsContext = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChain filterChain = + new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener("listener1", LOCAL_IP, Arrays.asList(filterChain), null); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContext); + } + + @Test + public void singleFilterChainWithAlpn() throws UnknownHostException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + EnvoyServerProtoData.FilterChainMatch filterChainMatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList("managed-mtls"), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + DownstreamTlsContext tlsContext = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChain filterChain = + new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener("listener1", LOCAL_IP, Arrays.asList(filterChain), null); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContext); + } + + @Test + public void defaultFilterChain() throws UnknownHostException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContext = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChain filterChain = + new EnvoyServerProtoData.FilterChain(null, tlsContext); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", LOCAL_IP, Arrays.asList(), filterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContext); + } + + @Test + public void destPortFails_returnDefaultFilterChain() throws UnknownHostException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextWithDestPort = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchWithDestPort = + new EnvoyServerProtoData.FilterChainMatch( + PORT, + Arrays.asList(), + Arrays.asList("managed-mtls"), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainWithDestPort = + new EnvoyServerProtoData.FilterChain(filterChainMatchWithDestPort, tlsContextWithDestPort); + 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(filterChainWithDestPort), defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain); + } + + @Test + public void destPrefixRangeMatch() throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextMatch = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 24)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainWithMatch = + new EnvoyServerProtoData.FilterChain(filterChainMatchWithMatch, tlsContextMatch); + 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(filterChainWithMatch), defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextMatch); + } + + @Test + public void destPrefixRangeMismatch_returnDefaultFilterChain() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextMismatch = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + // 10.2.2.0/24 doesn't match LOCAL_IP + EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.2.2.0", 24)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainWithMismatch = + new EnvoyServerProtoData.FilterChain(filterChainMatchWithMismatch, tlsContextMismatch); + 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(filterChainWithMismatch), defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain); + } + + @Test + public void destPrefixRange_moreSpecificWins() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextLessSpecific = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 24)), + 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("10.1.2.2", 31)), + 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.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific); + } + + @Test + public void destPrefixRangeIpv6_moreSpecificWins() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel("FE80:0000:0000:0000:0202:B3FF:FE1E:8329", "2001:DB8::8:800:200C:417A", 15000); + DownstreamTlsContext tlsContextLessSpecific = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("FE80:0:0:0:0:0:0:0", 60)), + 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("FE80:0000:0000:0000:0202:0:0:0", 80)), + 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", + "FE80:0000:0000:0000:0202:B3FF:FE1E:8329", + Arrays.asList(filterChainLessSpecific, filterChainMoreSpecific), + defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific); + } + + @Test + public void destPrefixRange_moreSpecificWith2Wins() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextMoreSpecificWith2 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList( + new EnvoyServerProtoData.CidrRange("10.1.2.0", 24), + new EnvoyServerProtoData.CidrRange(LOCAL_IP, 32)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 = + new EnvoyServerProtoData.FilterChain( + filterChainMatchMoreSpecificWith2, tlsContextMoreSpecificWith2); + + DownstreamTlsContext tlsContextLessSpecific = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.2", 31)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainLessSpecific = + new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific); + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, null); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", + LOCAL_IP, + Arrays.asList(filterChainMoreSpecificWith2, filterChainLessSpecific), + defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecificWith2); + } + + @Test + public void sourceTypeMismatch_returnDefaultFilterChain() throws UnknownHostException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextMismatch = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainWithMismatch = + new EnvoyServerProtoData.FilterChain(filterChainMatchWithMismatch, tlsContextMismatch); + 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(filterChainWithMismatch), defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain); + } + + @Test + public void sourceTypeLocal() throws UnknownHostException { + setupChannel(LOCAL_IP, LOCAL_IP, 15000); + DownstreamTlsContext tlsContextMatch = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainWithMatch = + new EnvoyServerProtoData.FilterChain(filterChainMatchWithMatch, tlsContextMatch); + 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(filterChainWithMatch), defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextMatch); + } + + @Test + public void sourcePrefixRange_moreSpecificWith2Wins() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextMoreSpecificWith2 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList( + new EnvoyServerProtoData.CidrRange("10.4.2.0", 24), + new EnvoyServerProtoData.CidrRange(REMOTE_IP, 32)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 = + new EnvoyServerProtoData.FilterChain( + filterChainMatchMoreSpecificWith2, tlsContextMoreSpecificWith2); + + DownstreamTlsContext tlsContextLessSpecific = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.2.2", 31)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainLessSpecific = + new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific); + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, null); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", + LOCAL_IP, + Arrays.asList(filterChainMoreSpecificWith2, filterChainLessSpecific), + defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecificWith2); + } + + @Test + public void sourcePortMatch_exactMatchWinsOverEmptyList() + throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContextEmptySourcePorts = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchEmptySourcePorts = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList( + new EnvoyServerProtoData.CidrRange("10.4.2.0", 24), + new EnvoyServerProtoData.CidrRange("10.4.2.2", 31)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChainEmptySourcePorts = + new EnvoyServerProtoData.FilterChain( + filterChainMatchEmptySourcePorts, tlsContextEmptySourcePorts); + + DownstreamTlsContext tlsContextSourcePortMatch = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); + EnvoyServerProtoData.FilterChainMatch filterChainMatchSourcePortMatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.2.2", 31)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList(7000, 15000)); + EnvoyServerProtoData.FilterChain filterChainSourcePortMatch = + new EnvoyServerProtoData.FilterChain( + filterChainMatchSourcePortMatch, tlsContextSourcePortMatch); + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, null); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", + LOCAL_IP, + Arrays.asList(filterChainEmptySourcePorts, filterChainSourcePortMatch), + defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContext1 = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContext1).isSameInstanceAs(tlsContextSourcePortMatch); + } + + /** + * Create 6 filterChains: - 1st filter chain has dest port & specific prefix range but is + * eliminated due to dest port - 5 advance to next step: 1 is eliminated due to being less + * specific than the remaining 4. - 4 advance to 3rd step: source type external eliminates one + * with local source_type. - 3 advance to 4th step: more specific 2 get picked based on + * source-prefix range. - 5th step: out of 2 one with matching source port gets picked + */ + @Test + public void filterChain_5stepMatch() throws UnknownHostException, InvalidProtocolBufferException { + setupChannel(LOCAL_IP, REMOTE_IP, 15000); + DownstreamTlsContext tlsContext1 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); + DownstreamTlsContext tlsContext2 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); + DownstreamTlsContext tlsContext3 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT3", "VA3"); + DownstreamTlsContext tlsContext4 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT4", "VA4"); + DownstreamTlsContext tlsContext5 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT5", "VA5"); + DownstreamTlsContext tlsContext6 = + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT6", "VA6"); + + // has dest port and specific prefix ranges: gets eliminated in step 1 + EnvoyServerProtoData.FilterChainMatch filterChainMatch1 = + new EnvoyServerProtoData.FilterChainMatch( + PORT, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(new EnvoyServerProtoData.CidrRange(REMOTE_IP, 32)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChain1 = + new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext1); + + // next 5 use prefix range: 4 with prefixLen of 30 and last one with 29 + + // has single prefix range: and less specific source prefix range: gets eliminated in step 4 + EnvoyServerProtoData.FilterChainMatch filterChainMatch2 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)), + Arrays.asList(), + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.0.0", 16)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChain2 = + new EnvoyServerProtoData.FilterChain(filterChainMatch2, tlsContext2); + + // has prefix ranges with one not matching and source type local: gets eliminated in step 3 + EnvoyServerProtoData.FilterChainMatch filterChainMatch3 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList( + new EnvoyServerProtoData.CidrRange("192.168.2.0", 24), + new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.SAME_IP_OR_LOOPBACK, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChain3 = + new EnvoyServerProtoData.FilterChain(filterChainMatch3, tlsContext3); + + // has prefix ranges with both matching and source type external but non matching source port: + // gets eliminated in step 5 + EnvoyServerProtoData.FilterChainMatch filterChainMatch4 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList( + new EnvoyServerProtoData.CidrRange("10.1.0.0", 16), + new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)), + Arrays.asList(), + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.4.2.0", 24)), + EnvoyServerProtoData.ConnectionSourceType.EXTERNAL, + Arrays.asList(16000, 9000)); + EnvoyServerProtoData.FilterChain filterChain4 = + new EnvoyServerProtoData.FilterChain(filterChainMatch4, tlsContext4); + + // has prefix ranges with both matching and source type external and matching source port: this + // gets selected + EnvoyServerProtoData.FilterChainMatch filterChainMatch5 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList( + new EnvoyServerProtoData.CidrRange("10.1.0.0", 16), + new EnvoyServerProtoData.CidrRange("10.1.2.0", 30)), + Arrays.asList(), + Arrays.asList( + new EnvoyServerProtoData.CidrRange("10.4.2.0", 24), + new EnvoyServerProtoData.CidrRange("192.168.2.0", 24)), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList(15000, 8000)); + EnvoyServerProtoData.FilterChain filterChain5 = + new EnvoyServerProtoData.FilterChain(filterChainMatch5, tlsContext5); + + // has prefix range with prefixLen of 29: gets eliminated in step 2 + EnvoyServerProtoData.FilterChainMatch filterChainMatch6 = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(new EnvoyServerProtoData.CidrRange("10.1.2.0", 29)), + Arrays.asList(), + Arrays.asList(), + EnvoyServerProtoData.ConnectionSourceType.ANY, + Arrays.asList()); + EnvoyServerProtoData.FilterChain filterChain6 = + new EnvoyServerProtoData.FilterChain(filterChainMatch6, tlsContext6); + + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, null); + EnvoyServerProtoData.Listener listener = + new EnvoyServerProtoData.Listener( + "listener1", + LOCAL_IP, + Arrays.asList( + filterChain1, filterChain2, filterChain3, filterChain4, filterChain5, filterChain6), + defaultFilterChain); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + DownstreamTlsContext tlsContextPicked = + xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); + assertThat(tlsContextPicked).isSameInstanceAs(tlsContext5); + } + + private void setupChannel(String localIp, String remoteIp, int remotePort) + throws UnknownHostException { + when(channel.localAddress()) + .thenReturn(new InetSocketAddress(InetAddress.getByName(localIp), PORT)); + when(channel.remoteAddress()) + .thenReturn(new InetSocketAddress(InetAddress.getByName(remoteIp), remotePort)); + } +} diff --git a/xds/src/test/java/io/grpc/xds/ServerXdsClientNewServerApiTest.java b/xds/src/test/java/io/grpc/xds/ServerXdsClientNewServerApiTest.java index 7d8be1b215..50f788fefe 100644 --- a/xds/src/test/java/io/grpc/xds/ServerXdsClientNewServerApiTest.java +++ b/xds/src/test/java/io/grpc/xds/ServerXdsClientNewServerApiTest.java @@ -348,6 +348,88 @@ public class ServerXdsClientNewServerApiTest { assertThat(fakeClock.getPendingTasks(LISTENER_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty(); } + @Test + public void ldsResponseWith_defaultFilterChainListener() throws InvalidProtocolBufferException { + xdsClient.watchListenerData(PORT, listenerWatcher); + StreamObserver responseObserver = responseObservers.poll(); + StreamObserver requestObserver = requestObservers.poll(); + + verify(requestObserver) + .onNext( + eq( + XdsClientTestHelper.buildDiscoveryRequest( + NODE, + "", + ImmutableList.of("test/value?udpa.resource.listening_address=192.168.3.7:7000"), + ResourceType.LDS.typeUrl(), + ""))); + assertThat(fakeClock.getPendingTasks(LISTENER_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).hasSize(1); + + final FilterChain defaultFilterChain = + buildFilterChain( + buildFilterChainMatch("managed-mtls"), + CommonTlsContextTestsUtil.buildTestDownstreamTlsContext( + "google-sds-config-default", "ROOTCA"), + buildTestFilter("envoy.http_connection_manager")); + List listeners = + ImmutableList.of( + Any.pack( + buildListener( + "bar.googleapis.com", + Any.pack( + HttpConnectionManager.newBuilder() + .setRouteConfig( + buildRouteConfiguration( + "route-bar.googleapis.com", + ImmutableList.of( + buildVirtualHost( + ImmutableList.of("bar.googleapis.com"), + "cluster-bar.googleapis.com")))) + .build()))), + Any.pack( + buildListenerWithDefaultFilterChain( + "test/value?udpa.resource.listening_address=192.168.3.7:7000", + 7000, + "0.0.0.0", + defaultFilterChain))); + DiscoveryResponse response = + buildDiscoveryResponse("0", listeners, ResourceType.LDS.typeUrl(), "0000"); + responseObserver.onNext(response); + + // Client sends an ACK LDS request. + verify(requestObserver) + .onNext( + eq( + XdsClientTestHelper.buildDiscoveryRequest( + NODE, + "0", + ImmutableList.of("test/value?udpa.resource.listening_address=192.168.3.7:7000"), + ResourceType.LDS.typeUrl(), + "0000"))); + + ArgumentCaptor listenerUpdateCaptor = ArgumentCaptor.forClass(null); + verify(listenerWatcher, times(1)).onListenerChanged(listenerUpdateCaptor.capture()); + ListenerUpdate configUpdate = listenerUpdateCaptor.getValue(); + EnvoyServerProtoData.Listener listener = configUpdate.getListener(); + assertThat(listener.getName()) + .isEqualTo("test/value?udpa.resource.listening_address=192.168.3.7:7000"); + assertThat(listener.getAddress()).isEqualTo("0.0.0.0:7000"); + assertThat(listener.getFilterChains()).hasSize(0); + EnvoyServerProtoData.FilterChain filterChainInboundInListenerUpdate = + listener.getDefaultFilterChain(); + CommonTlsContext downstreamCommonTlsContext = + filterChainInboundInListenerUpdate.getDownstreamTlsContext().getCommonTlsContext(); + assertThat(downstreamCommonTlsContext.getTlsCertificateSdsSecretConfigs(0).getName()) + .isEqualTo("google-sds-config-default"); + assertThat( + downstreamCommonTlsContext + .getCombinedValidationContext() + .getValidationContextSdsSecretConfig() + .getName()) + .isEqualTo("ROOTCA"); + assertThat(fakeClock.getPendingTasks(LISTENER_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty(); + } + /** Client receives LDS responses for updating Listener previously received. */ @SuppressWarnings("unchecked") @Test @@ -622,6 +704,25 @@ public class ServerXdsClientNewServerApiTest { backoffPolicy2, requestObserver); } + static Listener buildListenerWithDefaultFilterChain(String name, int portValue, String address, + FilterChain defaultFilterChain) { + io.envoyproxy.envoy.config.core.v3.Address listenerAddress = + io.envoyproxy.envoy.config.core.v3.Address.newBuilder() + .setSocketAddress( + SocketAddress.newBuilder().setPortValue(portValue).setAddress(address)) + .build(); + if (defaultFilterChain == null) { + defaultFilterChain = FilterChain.getDefaultInstance(); + } + return + Listener.newBuilder() + .setName(name) + .setAddress(listenerAddress) + .setDefaultFilterChain(defaultFilterChain) + .setTrafficDirection(TrafficDirection.INBOUND) + .build(); + } + static Listener buildListenerWithFilterChain(String name, int portValue, String address, FilterChain... filterChains) { io.envoyproxy.envoy.config.core.v3.Address listenerAddress = @@ -633,6 +734,7 @@ public class ServerXdsClientNewServerApiTest { Listener.newBuilder() .setName(name) .setAddress(listenerAddress) + .setDefaultFilterChain(FilterChain.getDefaultInstance()) .addAllFilterChains(Arrays.asList(filterChains)) .setTrafficDirection(TrafficDirection.INBOUND) .build(); diff --git a/xds/src/test/java/io/grpc/xds/XdsClientWrapperForServerSdsTest.java b/xds/src/test/java/io/grpc/xds/XdsClientWrapperForServerSdsTest.java deleted file mode 100644 index 9237981b9a..0000000000 --- a/xds/src/test/java/io/grpc/xds/XdsClientWrapperForServerSdsTest.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright 2020 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext; -import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil; -import io.netty.channel.Channel; -import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.Arrays; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameter; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** Tests for {@link XdsClientWrapperForServerSds}. */ -@RunWith(Parameterized.class) -public class XdsClientWrapperForServerSdsTest { - - private static final int PORT = 7000; - - /** Iterable of various configurations to use for tests. */ - @Parameterized.Parameters(name = "{6}") - public static Iterable data() { - return Arrays.asList( - new Object[][] { - { - -1, // creates null filterChainMatch for filter1 - null, - null, - "192.168.10.1", - "192.168.10.2", - 1, - "null filter chain match, expect filter1" - }, - { - PORT + 1, - "192.168.10.1", - "192.168.10.2", - null, - null, - 2, - "only dest port match, expect filter2" - }, - { - PORT, // matches dest port - "168.20.20.2", - "10.1.2.3", // matches local address - "192.168.10.1", - "192.168.10.2", - 1, - "dest port & address match, expect filter1" - }, - { - -1, // creates null filterChainMatch for filter1 - null, - null, - null, // empty address range for filter2 - null, // empty address range for filter2 - 2, - "empty address range over empty filterChainMatch, expect filter2" - }, - { - PORT, - null, - null, - "192.168.1.4", - "0.0.0.0", // IPANY for filter2 - 2, - "IPANY over empty address match, expect filter2" - }, - { - PORT, - "192.168.1.4", - "0.0.0.0", // IPANY for filter1 - "168.154.4.7", - "10.1.2.3", // matches local address - 2, - "exact IP over IPANY match, expect filter2" - }, - { - PORT, // matches dest port but no address match - "168.20.20.2", - "10.1.2.4", - "192.168.10.1", - "192.168.10.2", - 0, - "dest port match but no address match, expect null" - } - }); - } - - @Parameter(0) - public int destPort1; - @Parameter(1) - public String addressPrefix11; - @Parameter(2) - public String addressPrefix12; - @Parameter(3) - public String addressPrefix21; - @Parameter(4) - public String addressPrefix22; - @Parameter(5) - public int expectedIndex; - @Parameter(6) - public String testName; - - @Mock private XdsClient xdsClient; - @Mock private Channel channel; - - private XdsClientWrapperForServerSds xdsClientWrapperForServerSds; - private final DownstreamTlsContext[] tlsContexts = new DownstreamTlsContext[3]; - - /** Creates XdsClientWrapperForServerSds: also used by other classes. */ - public static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds( - int port, DownstreamTlsContext downstreamTlsContext) { - XdsClient mockXdsClient = mock(XdsClient.class); - XdsClientWrapperForServerSds xdsClientWrapperForServerSds = - new XdsClientWrapperForServerSds(port); - xdsClientWrapperForServerSds.start(mockXdsClient); - generateListenerUpdateToWatcher( - port, downstreamTlsContext, xdsClientWrapperForServerSds.getListenerWatcher()); - return xdsClientWrapperForServerSds; - } - - static void generateListenerUpdateToWatcher( - int port, DownstreamTlsContext tlsContext, XdsClient.ListenerWatcher registeredWatcher) { - EnvoyServerProtoData.Listener listener = - XdsSdsClientServerTest.buildListener("listener1", "0.0.0.0", port, tlsContext); - XdsClient.ListenerUpdate listenerUpdate = - XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); - registeredWatcher.onListenerChanged(listenerUpdate); - } - - @Before - public void setUp() throws IOException { - MockitoAnnotations.initMocks(this); - xdsClientWrapperForServerSds = new XdsClientWrapperForServerSds(PORT); - xdsClientWrapperForServerSds.start(xdsClient); - tlsContexts[0] = null; - tlsContexts[1] = - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); - tlsContexts[2] = - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2"); - } - - @After - public void tearDown() { - xdsClientWrapperForServerSds.shutdown(); - } - - /** - * Common method called by most tests. Creates 2 filterChains each with 2 addresses. First - * filterChain's destPort is always PORT. - */ - @Test - public void commonFilterChainMatchTest() - throws UnknownHostException { - ArgumentCaptor listenerWatcherCaptor = ArgumentCaptor.forClass(null); - verify(xdsClient).watchListenerData(eq(PORT), listenerWatcherCaptor.capture()); - XdsClient.ListenerWatcher registeredWatcher = listenerWatcherCaptor.getValue(); - InetAddress ipLocalAddress = Inet4Address.getByName("10.1.2.3"); - InetSocketAddress localAddress = new InetSocketAddress(ipLocalAddress, PORT); - when(channel.localAddress()).thenReturn(localAddress); - EnvoyServerProtoData.Listener listener = - XdsServerTestHelper.buildTestListener( - "listener1", - "10.1.2.3", - destPort1, - PORT, - addressPrefix11, - addressPrefix12, - addressPrefix21, - addressPrefix22, - tlsContexts[1], - tlsContexts[2]); - XdsClient.ListenerUpdate listenerUpdate = - XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); - registeredWatcher.onListenerChanged(listenerUpdate); - DownstreamTlsContext downstreamTlsContext = - xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); - assertThat(downstreamTlsContext).isSameInstanceAs(tlsContexts[expectedIndex]); - } - -} diff --git a/xds/src/test/java/io/grpc/xds/XdsClientWrapperForServerSdsTestMisc.java b/xds/src/test/java/io/grpc/xds/XdsClientWrapperForServerSdsTestMisc.java index 9d02b6bc84..fc9b1eb4a0 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientWrapperForServerSdsTestMisc.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientWrapperForServerSdsTestMisc.java @@ -23,7 +23,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -79,28 +78,20 @@ public class XdsClientWrapperForServerSdsTestMisc { } @Test - public void nonInetSocketAddress_expectException() { + public void nonInetSocketAddress_expectNull() throws UnknownHostException { registeredWatcher = - XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT); - try { - DownstreamTlsContext unused = - sendListenerUpdate(new InProcessSocketAddress("test1"), null, null); - fail("exception expected"); - } catch (IllegalStateException expected) { - assertThat(expected) - .hasMessageThat() - .isEqualTo("Channel localAddress is expected to be InetSocketAddress"); - } + XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT); + assertThat(sendListenerUpdate(new InProcessSocketAddress("test1"), null)).isNull(); } @Test public void nonMatchingPort_expectException() throws UnknownHostException { registeredWatcher = - XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT); + XdsServerTestHelper.startAndGetWatcher(xdsClientWrapperForServerSds, xdsClient, PORT); try { InetAddress ipLocalAddress = InetAddress.getByName("10.1.2.3"); InetSocketAddress localAddress = new InetSocketAddress(ipLocalAddress, PORT + 1); - DownstreamTlsContext unused = sendListenerUpdate(localAddress, null, null); + DownstreamTlsContext unused = sendListenerUpdate(localAddress, null); fail("exception expected"); } catch (IllegalStateException expected) { assertThat(expected) @@ -121,7 +112,10 @@ public class XdsClientWrapperForServerSdsTestMisc { when(channel.localAddress()).thenReturn(localAddress); EnvoyServerProtoData.Listener listener = new EnvoyServerProtoData.Listener( - "listener1", "10.1.2.3", Collections.emptyList()); + "listener1", + "10.1.2.3", + Collections.emptyList(), + null); XdsClient.ListenerUpdate listenerUpdate = XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); registeredWatcher.onListenerChanged(listenerUpdate); @@ -141,10 +135,10 @@ public class XdsClientWrapperForServerSdsTestMisc { EnvoyServerProtoData.DownstreamTlsContext tlsContext = CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); verify(mockServerWatcher, never()) - .onSuccess(any(EnvoyServerProtoData.DownstreamTlsContext.class)); - DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext, null); + .onSuccess(); + DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext); assertThat(returnedTlsContext).isSameInstanceAs(tlsContext); - verify(mockServerWatcher).onSuccess(same(tlsContext)); + verify(mockServerWatcher).onSuccess(); xdsClientWrapperForServerSds.removeServerWatcher(mockServerWatcher); } @@ -156,12 +150,12 @@ public class XdsClientWrapperForServerSdsTestMisc { InetSocketAddress localAddress = new InetSocketAddress(ipLocalAddress, PORT); EnvoyServerProtoData.DownstreamTlsContext tlsContext = CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); - DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext, null); + DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext); assertThat(returnedTlsContext).isSameInstanceAs(tlsContext); XdsClientWrapperForServerSds.ServerWatcher mockServerWatcher = mock(XdsClientWrapperForServerSds.ServerWatcher.class); xdsClientWrapperForServerSds.addServerWatcher(mockServerWatcher); - verify(mockServerWatcher).onSuccess(same(tlsContext)); + verify(mockServerWatcher).onSuccess(); } @Test @@ -192,10 +186,10 @@ public class XdsClientWrapperForServerSdsTestMisc { EnvoyServerProtoData.DownstreamTlsContext tlsContext = CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"); verify(mockServerWatcher, never()) - .onSuccess(any(EnvoyServerProtoData.DownstreamTlsContext.class)); - DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext, null); + .onSuccess(); + DownstreamTlsContext returnedTlsContext = sendListenerUpdate(localAddress, tlsContext); assertThat(returnedTlsContext).isSameInstanceAs(tlsContext); - verify(mockServerWatcher).onSuccess(same(tlsContext)); + verify(mockServerWatcher).onSuccess(); } @Test @@ -215,12 +209,24 @@ public class XdsClientWrapperForServerSdsTestMisc { } private DownstreamTlsContext sendListenerUpdate( - SocketAddress localAddress, - DownstreamTlsContext tlsContext1, - DownstreamTlsContext tlsContext2) { + SocketAddress localAddress, DownstreamTlsContext tlsContext) throws UnknownHostException { when(channel.localAddress()).thenReturn(localAddress); - XdsServerTestHelper.generateListenerUpdate( - registeredWatcher, PORT, tlsContext1, tlsContext2); + InetAddress ipRemoteAddress = InetAddress.getByName("10.4.5.6"); + InetSocketAddress remoteAddress = new InetSocketAddress(ipRemoteAddress, 1234); + when(channel.remoteAddress()).thenReturn(remoteAddress); + XdsServerTestHelper.generateListenerUpdate(registeredWatcher, tlsContext); return xdsClientWrapperForServerSds.getDownstreamTlsContext(channel); } + + /** Creates XdsClientWrapperForServerSds: also used by other classes. */ + public static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds( + int port, DownstreamTlsContext downstreamTlsContext) { + XdsClient mockXdsClient = mock(XdsClient.class); + XdsClientWrapperForServerSds xdsClientWrapperForServerSds = + new XdsClientWrapperForServerSds(port); + xdsClientWrapperForServerSds.start(mockXdsClient); + XdsSdsClientServerTest.generateListenerUpdateToWatcher( + downstreamTlsContext, xdsClientWrapperForServerSds.getListenerWatcher()); + return xdsClientWrapperForServerSds; + } } diff --git a/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java b/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java index 65d02ee24a..2a91e2de96 100644 --- a/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java @@ -17,7 +17,6 @@ package io.grpc.xds; import static com.google.common.truth.Truth.assertThat; -import static io.grpc.xds.XdsServerTestHelper.buildFilterChainMatch; import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.BAD_CLIENT_KEY_FILE; import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.BAD_CLIENT_PEM_FILE; import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.BAD_SERVER_KEY_FILE; @@ -293,8 +292,7 @@ public class XdsSdsClientServerTest { DownstreamTlsContext downstreamTlsContext = CommonTlsContextTestsUtil.buildDownstreamTlsContextFromFilenames( BAD_SERVER_KEY_FILE, BAD_SERVER_PEM_FILE, CA_PEM_FILE); - XdsClientWrapperForServerSdsTest.generateListenerUpdateToWatcher( - port, downstreamTlsContext, listenerWatcher); + generateListenerUpdateToWatcher(downstreamTlsContext, listenerWatcher); try { SimpleServiceGrpc.SimpleServiceBlockingStub blockingStub = getBlockingStub(upstreamTlsContext, "foo.test.google.fr"); @@ -314,8 +312,7 @@ public class XdsSdsClientServerTest { SERVER_1_KEY_FILE, SERVER_1_PEM_FILE, CA_PEM_FILE); final XdsClientWrapperForServerSds xdsClientWrapperForServerSds = - XdsClientWrapperForServerSdsTest.createXdsClientWrapperForServerSds( - port, /* downstreamTlsContext= */ downstreamTlsContext); + createXdsClientWrapperForServerSds(port); buildServerWithFallbackServerCredentials( xdsClientWrapperForServerSds, InsecureServerCredentials.create(), downstreamTlsContext); @@ -353,6 +350,23 @@ public class XdsSdsClientServerTest { buildServer(port, xdsCredentials, xdsClientWrapperForServerSds, downstreamTlsContext); } + /** Creates XdsClientWrapperForServerSds. */ + private static XdsClientWrapperForServerSds createXdsClientWrapperForServerSds(int port) { + XdsClient mockXdsClient = mock(XdsClient.class); + XdsClientWrapperForServerSds xdsClientWrapperForServerSds = + new XdsClientWrapperForServerSds(port); + xdsClientWrapperForServerSds.start(mockXdsClient); + return xdsClientWrapperForServerSds; + } + + static void generateListenerUpdateToWatcher( + DownstreamTlsContext tlsContext, XdsClient.ListenerWatcher registeredWatcher) { + EnvoyServerProtoData.Listener listener = buildListener("listener1", "0.0.0.0", tlsContext); + XdsClient.ListenerUpdate listenerUpdate = + XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); + registeredWatcher.onListenerChanged(listenerUpdate); + } + private void buildServer( int port, ServerCredentials serverCredentials, @@ -362,20 +376,24 @@ public class XdsSdsClientServerTest { XdsServerBuilder builder = XdsServerBuilder.forPort(port, serverCredentials) .addService(new SimpleServiceImpl()); XdsServerTestHelper.generateListenerUpdate( - xdsClientWrapperForServerSds.getListenerWatcher(), - port, - downstreamTlsContext, - /* tlsContext2= */null); + xdsClientWrapperForServerSds.getListenerWatcher(), downstreamTlsContext); cleanupRule.register(builder.buildServer(xdsClientWrapperForServerSds)).start(); } static EnvoyServerProtoData.Listener buildListener( - String name, String address, int port, DownstreamTlsContext tlsContext) { - EnvoyServerProtoData.FilterChainMatch filterChainMatch = buildFilterChainMatch(port, address); - EnvoyServerProtoData.FilterChain filterChain1 = + String name, String address, DownstreamTlsContext tlsContext) { + EnvoyServerProtoData.FilterChainMatch filterChainMatch = + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(), + null, + Arrays.asList()); + EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext); EnvoyServerProtoData.Listener listener = - new EnvoyServerProtoData.Listener(name, address, Arrays.asList(filterChain1)); + new EnvoyServerProtoData.Listener(name, address, Arrays.asList(defaultFilterChain), null); return listener; } diff --git a/xds/src/test/java/io/grpc/xds/XdsServerBuilderTest.java b/xds/src/test/java/io/grpc/xds/XdsServerBuilderTest.java index 43eab4ea0d..e9f3beedec 100644 --- a/xds/src/test/java/io/grpc/xds/XdsServerBuilderTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsServerBuilderTest.java @@ -144,9 +144,8 @@ public class XdsServerBuilderTest { Future future = startServerAsync(); XdsServerTestHelper.generateListenerUpdate( listenerWatcher, - port, - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"), - null); + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1") + ); verifyServer(future, null, null); verifyShutdown(); } @@ -157,9 +156,8 @@ public class XdsServerBuilderTest { buildServer(null, true); XdsServerTestHelper.generateListenerUpdate( listenerWatcher, - port, - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"), - null); + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1") + ); xdsServer.start(); try { xdsServer.start(); @@ -180,9 +178,8 @@ public class XdsServerBuilderTest { Future future = startServerAsync(); XdsServerTestHelper.generateListenerUpdate( listenerWatcher, - port, - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"), - null); + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1") + ); verifyServer(future, mockXdsServingStatusListener, null); verifyShutdown(); } @@ -217,9 +214,8 @@ public class XdsServerBuilderTest { reset(mockXdsServingStatusListener); XdsServerTestHelper.generateListenerUpdate( listenerWatcher, - port, - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"), - null); + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1") + ); verifyServer(future, mockXdsServingStatusListener, null); verifyShutdown(); } @@ -235,9 +231,8 @@ public class XdsServerBuilderTest { ServerSocket serverSocket = new ServerSocket(port); XdsServerTestHelper.generateListenerUpdate( listenerWatcher, - port, - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"), - null); + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1") + ); Throwable exception = future.get(5, TimeUnit.SECONDS); assertThat(exception).isInstanceOf(IOException.class); assertThat(exception).hasMessageThat().contains("Failed to bind"); @@ -269,14 +264,12 @@ public class XdsServerBuilderTest { Future future = startServerAsync(); XdsServerTestHelper.generateListenerUpdate( listenerWatcher, - port, - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"), - null); + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1") + ); XdsServerTestHelper.generateListenerUpdate( listenerWatcher, - port, - CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"), - null); + CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1") + ); verify(mockXdsServingStatusListener, never()).onNotServing(any(Throwable.class)); verifyServer(future, mockXdsServingStatusListener, null); listenerWatcher.onError(Status.ABORTED); diff --git a/xds/src/test/java/io/grpc/xds/XdsServerTestHelper.java b/xds/src/test/java/io/grpc/xds/XdsServerTestHelper.java index b1ea2d589e..972340ecfc 100644 --- a/xds/src/test/java/io/grpc/xds/XdsServerTestHelper.java +++ b/xds/src/test/java/io/grpc/xds/XdsServerTestHelper.java @@ -19,12 +19,9 @@ package io.grpc.xds; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; -import com.google.common.base.Strings; import java.io.IOException; import java.net.ServerSocket; -import java.util.ArrayList; import java.util.Arrays; - import org.mockito.ArgumentCaptor; /** @@ -43,31 +40,17 @@ class XdsServerTestHelper { } /** - * Creates a {@link XdsClient.ListenerUpdate} with maximum of 2 - * {@link io.grpc.xds.EnvoyServerProtoData.FilterChain} each one with a destination port and an - * optional {@link EnvoyServerProtoData.DownstreamTlsContext}. - * @param registeredWatcher the watcher on which to generate the update - * @param destPort if > 0 to create both the {@link EnvoyServerProtoData.FilterChain} - * @param tlsContext1 if non-null, used to populate the 1st filterChain - * @param tlsContext2 if non-null, used to populate the 2nd filterChain + * Creates a {@link XdsClient.ListenerUpdate} with {@link + * io.grpc.xds.EnvoyServerProtoData.FilterChain} with a destination port and an optional {@link + * EnvoyServerProtoData.DownstreamTlsContext}. + * + * @param registeredWatcher the watcher on which to generate the update + * @param tlsContext if non-null, used to populate filterChain */ static void generateListenerUpdate( - XdsClient.ListenerWatcher registeredWatcher, - int destPort, - EnvoyServerProtoData.DownstreamTlsContext tlsContext1, - EnvoyServerProtoData.DownstreamTlsContext tlsContext2) { - EnvoyServerProtoData.Listener listener = - buildTestListener( - "listener1", - "10.1.2.3", - destPort, - destPort, - null, - null, - null, - null, - tlsContext1, - tlsContext2); + XdsClient.ListenerWatcher registeredWatcher, + EnvoyServerProtoData.DownstreamTlsContext tlsContext) { + EnvoyServerProtoData.Listener listener = buildTestListener("listener1", "10.1.2.3", tlsContext); XdsClient.ListenerUpdate listenerUpdate = XdsClient.ListenerUpdate.newBuilder().setListener(listener).build(); registeredWatcher.onListenerChanged(listenerUpdate); @@ -81,38 +64,22 @@ class XdsServerTestHelper { } static EnvoyServerProtoData.Listener buildTestListener( - String name, - String address, - int destPort1, - int destPort2, - String addressPrefix11, - String addressPrefix12, - String addressPrefix21, - String addressPrefix22, - EnvoyServerProtoData.DownstreamTlsContext tlsContext1, - EnvoyServerProtoData.DownstreamTlsContext tlsContext2) { + String name, String address, EnvoyServerProtoData.DownstreamTlsContext tlsContext) { EnvoyServerProtoData.FilterChainMatch filterChainMatch1 = - destPort1 > 0 ? buildFilterChainMatch(destPort1, addressPrefix11, addressPrefix12) : null; - EnvoyServerProtoData.FilterChainMatch filterChainMatch2 = - destPort2 > 0 ? buildFilterChainMatch(destPort2, addressPrefix21, addressPrefix22) : null; + new EnvoyServerProtoData.FilterChainMatch( + 0, + Arrays.asList(), + Arrays.asList(), + Arrays.asList(), + null, + Arrays.asList()); EnvoyServerProtoData.FilterChain filterChain1 = - new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext1); - EnvoyServerProtoData.FilterChain filterChain2 = - new EnvoyServerProtoData.FilterChain(filterChainMatch2, tlsContext2); + new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext); + EnvoyServerProtoData.FilterChain defaultFilterChain = + new EnvoyServerProtoData.FilterChain(null, null); EnvoyServerProtoData.Listener listener = - new EnvoyServerProtoData.Listener(name, address, Arrays.asList(filterChain1, filterChain2)); + new EnvoyServerProtoData.Listener( + name, address, Arrays.asList(filterChain1), defaultFilterChain); return listener; } - - static EnvoyServerProtoData.FilterChainMatch buildFilterChainMatch( - int destPort, String... addressPrefix) { - ArrayList prefixRanges = new ArrayList<>(); - for (String address : addressPrefix) { - if (!Strings.isNullOrEmpty(address)) { - prefixRanges.add(new EnvoyServerProtoData.CidrRange(address, 32)); - } - } - return new EnvoyServerProtoData.FilterChainMatch( - destPort, prefixRanges, Arrays.asList()); - } } diff --git a/xds/src/test/java/io/grpc/xds/internal/sds/SdsProtocolNegotiatorsTest.java b/xds/src/test/java/io/grpc/xds/internal/sds/SdsProtocolNegotiatorsTest.java index 4191b14970..6429415191 100644 --- a/xds/src/test/java/io/grpc/xds/internal/sds/SdsProtocolNegotiatorsTest.java +++ b/xds/src/test/java/io/grpc/xds/internal/sds/SdsProtocolNegotiatorsTest.java @@ -43,7 +43,7 @@ import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext; import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext; import io.grpc.xds.InternalXdsAttributes; import io.grpc.xds.XdsClientWrapperForServerSds; -import io.grpc.xds.XdsClientWrapperForServerSdsTest; +import io.grpc.xds.XdsClientWrapperForServerSdsTestMisc; import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsHandler; import io.grpc.xds.internal.sds.SdsProtocolNegotiators.ClientSdsProtocolNegotiator; import io.netty.channel.ChannelHandler; @@ -227,13 +227,18 @@ public class SdsProtocolNegotiatorsTest { 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(); DownstreamTlsContext downstreamTlsContext = buildDownstreamTlsContextFromFilenames(SERVER_1_KEY_FILE, SERVER_1_PEM_FILE, CA_PEM_FILE); XdsClientWrapperForServerSds xdsClientWrapperForServerSds = - XdsClientWrapperForServerSdsTest.createXdsClientWrapperForServerSds( + XdsClientWrapperForServerSdsTestMisc.createXdsClientWrapperForServerSds( 80, downstreamTlsContext); SdsProtocolNegotiators.HandlerPickerHandler handlerPickerHandler = new SdsProtocolNegotiators.HandlerPickerHandler(grpcHandler, xdsClientWrapperForServerSds, @@ -281,7 +286,7 @@ public class SdsProtocolNegotiatorsTest { .getDefaultInstance()); XdsClientWrapperForServerSds xdsClientWrapperForServerSds = - XdsClientWrapperForServerSdsTest.createXdsClientWrapperForServerSds( + XdsClientWrapperForServerSdsTestMisc.createXdsClientWrapperForServerSds( 80, downstreamTlsContext); SdsProtocolNegotiators.HandlerPickerHandler handlerPickerHandler = new SdsProtocolNegotiators.HandlerPickerHandler(