-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
xds: listener type validation #11933
base: master
Are you sure you want to change the base?
Changes from 16 commits
4eb625a
ad90963
01927a6
8780c52
76270a4
da0d5ab
ba8af22
694c2f1
506bbe4
87aad6f
239f167
ca5bb14
cb41652
e07158f
9f79e8c
d8fb13a
6873d59
b3908f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,10 @@ | |
import com.google.common.annotations.VisibleForTesting; | ||
import com.google.common.collect.ImmutableList; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.net.HostAndPort; | ||
import com.google.common.net.InetAddresses; | ||
import com.google.common.util.concurrent.SettableFuture; | ||
import io.envoyproxy.envoy.config.core.v3.SocketAddress.Protocol; | ||
import io.grpc.Attributes; | ||
import io.grpc.InternalServerInterceptors; | ||
import io.grpc.Metadata; | ||
|
@@ -57,6 +60,7 @@ | |
import io.grpc.xds.client.XdsClient.ResourceWatcher; | ||
import io.grpc.xds.internal.security.SslContextProviderSupplier; | ||
import java.io.IOException; | ||
import java.net.InetAddress; | ||
import java.net.SocketAddress; | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
|
@@ -383,7 +387,21 @@ | |
return; | ||
} | ||
logger.log(Level.FINEST, "Received Lds update {0}", update); | ||
checkNotNull(update.listener(), "update"); | ||
if (update.listener() == null) { | ||
onResourceDoesNotExist("Non-API"); | ||
return; | ||
} | ||
|
||
String ldsAddress = update.listener().address(); | ||
ejona86 marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For my education: what would be the "best/most appropriate" behaviour if the String Currently, if Likewise, if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm. Good point. I couldn't find any mention about this case in gRFC A36. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In most NR/LB logic, exceptions cause the channel to go into panic mode. NR/LB should only throw in case of a bug. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Empty address is disallowed in the proto, but is not in our validation so we should add validation. The ip matching logic here should also be checking that it is a TCP listener, which is not being communicated through EnvoyServerData.Address. And the validation should probably be NACKing (throw There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do we check if it is a TCP listener?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This gRPC code is always TCP. So we need to not match when xDS tells us to use UDP. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The transport protocol doesn't seem to be about TCP vs UDP. That's We were talking about the address, and SocketAddress has a TCP vs UDP There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. You said we need not match addresses when it's UDP, so I assume we don't call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand. If you don't call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep. I was thinking right at first before editing the comment and then I messed up with thoughts. |
||
if (ldsAddress != null && update.listener().protocol() == Protocol.TCP | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From gRFC A36:
If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means that every place in our tests that calls |
||
&& !ipAddressesMatch(ldsAddress)) { | ||
handleConfigNotFoundOrMismatch( | ||
Status.UNKNOWN.withDescription( | ||
String.format( | ||
"Listener address mismatch: expected %s, but got %s.", | ||
listenerAddress, ldsAddress)).asException()); | ||
return; | ||
} | ||
if (!pendingRds.isEmpty()) { | ||
// filter chain state has not yet been applied to filterChainSelectorManager and there | ||
// are two sets of sslContextProviderSuppliers, so we release the old ones. | ||
|
@@ -432,6 +450,20 @@ | |
} | ||
} | ||
|
||
private boolean ipAddressesMatch(String ldsAddress) { | ||
HostAndPort ldsAddressHnP = HostAndPort.fromString(ldsAddress); | ||
HostAndPort listenerAddressHnP = HostAndPort.fromString(listenerAddress); | ||
|
||
InetAddress listenerIp = InetAddresses.forString(listenerAddressHnP.getHost()); | ||
InetAddress ldsIp = InetAddresses.forString(ldsAddressHnP.getHost()); | ||
if (!ldsAddressHnP.hasPort() || !listenerAddressHnP.hasPort() | ||
|| ldsAddressHnP.getPort() != listenerAddressHnP.getPort()) { | ||
return false; | ||
} | ||
|
||
return listenerIp.equals(ldsIp); | ||
} | ||
|
||
@Override | ||
public void onResourceDoesNotExist(final String resourceName) { | ||
if (stopped) { | ||
|
@@ -440,7 +472,7 @@ | |
StatusException statusException = Status.UNAVAILABLE.withDescription( | ||
String.format("Listener %s unavailable, xDS node ID: %s", resourceName, | ||
xdsClient.getBootstrapInfo().node().getId())).asException(); | ||
handleConfigNotFound(statusException); | ||
handleConfigNotFoundOrMismatch(statusException); | ||
} | ||
|
||
@Override | ||
|
@@ -673,7 +705,7 @@ | |
}; | ||
} | ||
|
||
private void handleConfigNotFound(StatusException exception) { | ||
private void handleConfigNotFoundOrMismatch(StatusException exception) { | ||
cleanUpRouteDiscoveryStates(); | ||
shutdownActiveFilters(); | ||
List<SslContextProviderSupplier> toRelease = getSuppliersInUse(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll uncomment this in the next commit.