use of com.netflix.netty.common.ssl.SslHandshakeInfo in project zuul by Netflix.
the class ClientRequestReceiver method buildZuulHttpRequest.
// Build a ZuulMessage from the netty request.
private HttpRequestMessage buildZuulHttpRequest(final HttpRequest nativeRequest, final ChannelHandlerContext clientCtx) {
PerfMark.attachTag("path", nativeRequest, HttpRequest::uri);
// Setup the context for this request.
final SessionContext context;
if (decorator != null) {
// Optionally decorate the context.
SessionContext tempContext = new SessionContext();
// Store the netty channel in SessionContext.
tempContext.set(CommonContextKeys.NETTY_SERVER_CHANNEL_HANDLER_CONTEXT, clientCtx);
context = decorator.decorate(tempContext);
// We expect the UUID is present after decoration
PerfMark.attachTag("uuid", context, SessionContext::getUUID);
} else {
context = new SessionContext();
}
// Get the client IP (ignore XFF headers at this point, as that can be app specific).
final Channel channel = clientCtx.channel();
final String clientIp = channel.attr(SourceAddressChannelHandler.ATTR_SOURCE_ADDRESS).get();
// This is the only way I found to get the port of the request with netty...
final int port = channel.attr(SourceAddressChannelHandler.ATTR_SERVER_LOCAL_PORT).get();
final String serverName = channel.attr(SourceAddressChannelHandler.ATTR_SERVER_LOCAL_ADDRESS).get();
final SocketAddress clientDestinationAddress = channel.attr(SourceAddressChannelHandler.ATTR_LOCAL_ADDR).get();
final InetSocketAddress proxyProtocolDestinationAddress = channel.attr(SourceAddressChannelHandler.ATTR_PROXY_PROTOCOL_DESTINATION_ADDRESS).get();
if (proxyProtocolDestinationAddress != null) {
context.set(CommonContextKeys.PROXY_PROTOCOL_DESTINATION_ADDRESS, proxyProtocolDestinationAddress);
}
// Store info about the SSL handshake if applicable, and choose the http scheme.
String scheme = SCHEME_HTTP;
final SslHandshakeInfo sslHandshakeInfo = channel.attr(SslHandshakeInfoHandler.ATTR_SSL_INFO).get();
if (sslHandshakeInfo != null) {
context.set(CommonContextKeys.SSL_HANDSHAKE_INFO, sslHandshakeInfo);
scheme = SCHEME_HTTPS;
}
// Decide if this is HTTP/1 or HTTP/2.
String protocol = channel.attr(PROTOCOL_NAME).get();
if (protocol == null) {
protocol = nativeRequest.protocolVersion().text();
}
// Strip off the query from the path.
String path = parsePath(nativeRequest.uri());
// Setup the req/resp message objects.
final HttpRequestMessage request = new HttpRequestMessageImpl(context, protocol, nativeRequest.method().asciiName().toString().toLowerCase(), path, copyQueryParams(nativeRequest), copyHeaders(nativeRequest), clientIp, scheme, port, serverName, clientDestinationAddress, false);
// a LastHttpContent without any prior HttpContent's.
if (HttpUtils.hasChunkedTransferEncodingHeader(request) || HttpUtils.hasNonZeroContentLengthHeader(request)) {
request.setHasBody(true);
}
// Store this original request info for future reference (ie. for metrics and access logging purposes).
request.storeInboundRequest();
// Store the netty request for use later.
context.set(CommonContextKeys.NETTY_HTTP_REQUEST, nativeRequest);
// Store zuul request on netty channel for later use.
channel.attr(ATTR_ZUUL_REQ).set(request);
if (nativeRequest instanceof DefaultFullHttpRequest) {
final ByteBuf chunk = ((DefaultFullHttpRequest) nativeRequest).content();
request.bufferBodyContents(new DefaultLastHttpContent(chunk));
}
return request;
}
use of com.netflix.netty.common.ssl.SslHandshakeInfo in project zuul by Netflix.
the class SslHandshakeInfoHandler method userEventTriggered.
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof SslHandshakeCompletionEvent) {
try {
SslHandshakeCompletionEvent sslEvent = (SslHandshakeCompletionEvent) evt;
if (sslEvent.isSuccess()) {
CurrentPassport.fromChannel(ctx.channel()).add(PassportState.SERVER_CH_SSL_HANDSHAKE_COMPLETE);
SslHandler sslhandler = ctx.channel().pipeline().get(SslHandler.class);
SSLSession session = sslhandler.engine().getSession();
ClientAuth clientAuth = whichClientAuthEnum(sslhandler);
Certificate serverCert = null;
X509Certificate peerCert = null;
if ((clientAuth == ClientAuth.REQUIRE || clientAuth == ClientAuth.OPTIONAL) && session.getPeerCertificates() != null && session.getPeerCertificates().length > 0) {
peerCert = (X509Certificate) session.getPeerCertificates()[0];
}
if (session.getLocalCertificates() != null && session.getLocalCertificates().length > 0) {
serverCert = session.getLocalCertificates()[0];
}
SslHandshakeInfo info = new SslHandshakeInfo(isSSlFromIntermediary, session.getProtocol(), session.getCipherSuite(), clientAuth, serverCert, peerCert);
ctx.channel().attr(ATTR_SSL_INFO).set(info);
// Metrics.
incrementCounters(sslEvent, info);
logger.debug("Successful SSL Handshake: {}", info);
} else {
String clientIP = ctx.channel().attr(SourceAddressChannelHandler.ATTR_SOURCE_ADDRESS).get();
Throwable cause = sslEvent.cause();
PassportState passportState = CurrentPassport.fromChannel(ctx.channel()).getState();
if (cause instanceof ClosedChannelException && (PassportState.SERVER_CH_INACTIVE.equals(passportState) || PassportState.SERVER_CH_IDLE_TIMEOUT.equals(passportState))) {
// Either client closed the connection without/before having completed a handshake, or
// the connection idle timed-out before handshake.
// NOTE: we were seeing a lot of these in prod and can repro by just telnetting to port and then closing terminal
// without sending anything.
// So don't treat these as SSL handshake failures.
logger.debug("Client closed connection or it idle timed-out without doing an ssl handshake. " + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()));
} else if (cause instanceof SSLException && cause.getMessage().contains("handshake timed out")) {
logger.debug("Client timed-out doing the ssl handshake. " + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()));
} else if (cause instanceof SSLException && cause.getMessage().contains("failure when writing TLS control frames")) {
// This can happen if the ClientHello is sent followed by a RST packet, before we can respond.
logger.debug("Client terminated handshake early." + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()));
} else {
String msg = "Unsuccessful SSL Handshake: " + sslEvent + ", client_ip = " + clientIP + ", channel_info = " + ChannelUtils.channelInfoForLogging(ctx.channel()) + ", error = " + cause;
if (cause instanceof ClosedChannelException) {
logger.debug(msg);
} else {
logger.debug(msg, cause);
}
incrementCounters(sslEvent, null);
}
}
} catch (Throwable e) {
logger.warn("Error getting the SSL handshake info.", e);
} finally {
// Now remove this handler from the pipeline as no longer needed once the ssl handshake has completed.
ctx.pipeline().remove(this);
}
} else if (evt instanceof SslCloseCompletionEvent) {
// TODO - increment a separate metric for this event?
} else if (evt instanceof SniCompletionEvent) {
logger.debug("SNI Parsing Complete: {}", evt);
SniCompletionEvent sniCompletionEvent = (SniCompletionEvent) evt;
if (sniCompletionEvent.isSuccess()) {
spectatorRegistry.counter("zuul.sni.parse.success").increment();
} else {
Throwable cause = sniCompletionEvent.cause();
spectatorRegistry.counter("zuul.sni.parse.failure", "cause", cause != null ? cause.getMessage() : "UNKNOWN").increment();
}
}
super.userEventTriggered(ctx, evt);
}
use of com.netflix.netty.common.ssl.SslHandshakeInfo in project zuul by Netflix.
the class StripUntrustedProxyHeadersHandler method connectionIsUsingMutualSSLWithAuthEnforced.
@VisibleForTesting
boolean connectionIsUsingMutualSSLWithAuthEnforced(Channel ch) {
boolean is = false;
SslHandshakeInfo sslHandshakeInfo = ch.attr(SslHandshakeInfoHandler.ATTR_SSL_INFO).get();
if (sslHandshakeInfo != null) {
if (sslHandshakeInfo.getClientAuthRequirement() == ClientAuth.REQUIRE) {
is = true;
}
}
return is;
}
Aggregations