Created
September 24, 2020 11:52
-
-
Save hazcod/1ab0f308e4a9bde057c686123e9dde7d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tls.netty; | |
import io.netty.channel.Channel; | |
import io.netty.channel.ChannelFutureListener; | |
import io.netty.channel.ChannelHandlerContext; | |
import io.netty.channel.ChannelInboundHandlerAdapter; | |
public class MTLSBackendHandler | |
extends ChannelInboundHandlerAdapter | |
{ | |
private final Channel inboundChannel; | |
public MTLSBackendHandler(Channel inboundChannel) { | |
this.inboundChannel = inboundChannel; | |
} | |
@Override | |
public void channelActive(ChannelHandlerContext ctx) { | |
ctx.read(); | |
} | |
@Override | |
public void channelRead(final ChannelHandlerContext ctx, Object msg) { | |
inboundChannel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> { | |
if (future.isSuccess()) { | |
System.out.println("backendhandler reading from inboundChannel"); | |
ctx.channel().read(); | |
} else { | |
System.err.println("could not read from inboundChannel on backend handler"); | |
future.channel().close(); | |
} | |
}); | |
} | |
@Override | |
public void channelInactive(ChannelHandlerContext ctx) { | |
MTLSFrontendHandler.closeOnFlush(inboundChannel); | |
} | |
@Override | |
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { | |
System.err.println(cause.toString()); | |
MTLSFrontendHandler.closeOnFlush(ctx.channel()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tls.netty; | |
import io.netty.channel.Channel; | |
import io.netty.channel.ChannelInitializer; | |
import io.netty.channel.socket.SocketChannel; | |
import io.netty.handler.ssl.ClientAuth; | |
import io.netty.handler.ssl.SslContext; | |
import io.netty.handler.ssl.SslContextBuilder; | |
import io.netty.handler.ssl.util.InsecureTrustManagerFactory; | |
import javax.net.ssl.KeyManager; | |
import javax.net.ssl.SSLException; | |
public class MTLSBackendInitializer | |
extends ChannelInitializer<SocketChannel> | |
{ | |
private final KeyManager[] sslContext; | |
private final Channel inboundChannel; | |
public MTLSBackendInitializer(Channel inboundChannel, KeyManager[] sslContext) { | |
this.inboundChannel = inboundChannel; | |
this.sslContext = sslContext; | |
} | |
@Override | |
public void initChannel(SocketChannel ch) | |
{ | |
try { | |
SslContext nettySSLContext = SslContextBuilder.forClient() | |
.clientAuth(ClientAuth.REQUIRE) | |
.trustManager(InsecureTrustManagerFactory.INSTANCE) | |
.keyManager(this.sslContext[0]) | |
.protocols("TLSv1.1", "TLSv1.2") | |
.build(); | |
ch.pipeline().addLast( | |
nettySSLContext.newHandler(ch.alloc()), | |
new MTLSBackendHandler(inboundChannel) | |
); | |
} catch (SSLException e) { | |
System.err.println(e); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tls.netty; | |
import io.netty.bootstrap.Bootstrap; | |
import io.netty.buffer.Unpooled; | |
import io.netty.channel.*; | |
import javax.net.ssl.KeyManager; | |
public class MTLSFrontendHandler | |
extends ChannelInboundHandlerAdapter | |
{ | |
private final String remoteHost; | |
private final int remotePort; | |
private KeyManager[] sslContext; | |
// As we use inboundChannel.eventLoop() when building the Bootstrap this does not need to be volatile as | |
// the outboundChannel will use the same EventLoop (and therefore Thread) as the inboundChannel. | |
private Channel outboundChannel; | |
public MTLSFrontendHandler(String remoteHost, int remotePort, KeyManager[] ctx) { | |
this.remoteHost = remoteHost; | |
this.remotePort = remotePort; | |
this.sslContext = ctx; | |
} | |
@Override | |
public void channelActive(ChannelHandlerContext ctx) { | |
final Channel inboundChannel = ctx.channel(); | |
// Start the connection attempt. | |
Bootstrap b = new Bootstrap(); | |
b.group(inboundChannel.eventLoop()) | |
.channel(ctx.channel().getClass()) | |
.handler(new MTLSBackendInitializer(inboundChannel, this.sslContext)) | |
.option(ChannelOption.AUTO_READ, true); | |
System.out.println("Connecting to " + remoteHost + ":" + remotePort); | |
ChannelFuture f = b.connect(remoteHost, remotePort); | |
outboundChannel = f.channel(); | |
f.addListener((ChannelFutureListener) future -> { | |
if (future.isSuccess()) { | |
// connection complete start to read first data | |
System.out.println("connected to " + remoteHost + ":" + remotePort); | |
inboundChannel.read(); | |
} | |
else { | |
// Close the connection if the connection attempt has failed. | |
System.err.println("connection attempt failed"); | |
inboundChannel.close(); | |
} | |
}); | |
} | |
@Override | |
public void channelRead(final ChannelHandlerContext ctx, Object msg) { | |
if (outboundChannel.isActive()) { | |
outboundChannel.writeAndFlush(msg).addListener((ChannelFutureListener) future -> { | |
if (future.isSuccess()) { | |
// was able to flush out data, start to read the next chunk | |
System.out.println("frontend handler reading from outboundChannel"); | |
ctx.channel().read(); | |
} | |
else { | |
System.err.println("frontend handler could not read from outboundChannel"); | |
future.channel().close(); | |
} | |
}); | |
} | |
} | |
@Override | |
public void channelInactive(ChannelHandlerContext ctx) { | |
if (outboundChannel != null) { | |
closeOnFlush(outboundChannel); | |
} | |
} | |
@Override | |
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { | |
System.err.println(cause.toString()); | |
closeOnFlush(ctx.channel()); | |
} | |
/** | |
* Closes the specified channel after all queued write requests are flushed. | |
*/ | |
static void closeOnFlush(Channel ch) { | |
if (ch.isActive()) { | |
ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tls.netty; | |
import io.netty.channel.ChannelInitializer; | |
import io.netty.channel.socket.SocketChannel; | |
import io.netty.handler.logging.LogLevel; | |
import io.netty.handler.logging.LoggingHandler; | |
import javax.net.ssl.KeyManager; | |
public class MTLSFrontendInitializer | |
extends ChannelInitializer<SocketChannel> { | |
private final String remoteHost; | |
private final int remotePort; | |
private KeyManager[] sslContext; | |
public MTLSFrontendInitializer(String remoteHost, int remotePort, KeyManager[] ctx) { | |
this.remoteHost = remoteHost; | |
this.remotePort = remotePort; | |
this.sslContext = ctx; | |
} | |
@Override | |
public void initChannel(SocketChannel ch) { | |
ch.pipeline().addLast( | |
new LoggingHandler(LogLevel.INFO), | |
new MTLSFrontendHandler(remoteHost, remotePort, sslContext)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package tls.netty; | |
import io.netty.bootstrap.ServerBootstrap; | |
import io.netty.channel.ChannelOption; | |
import io.netty.channel.EventLoopGroup; | |
import io.netty.channel.nio.NioEventLoopGroup; | |
import io.netty.channel.socket.nio.NioServerSocketChannel; | |
import javax.net.ssl.KeyManager; | |
public class MTLSInstance | |
implements Runnable | |
{ | |
private int listenPort; | |
private String host; | |
private int port; | |
private KeyManager[] sslContext; | |
public MTLSInstance(int p, String h, int rp, KeyManager[] sslContext) | |
{ | |
this.listenPort = p; | |
this.host = h; | |
this.port = rp; | |
this.sslContext = sslContext; | |
} | |
@Override | |
public void run() | |
{ | |
EventLoopGroup bossGroup = new NioEventLoopGroup(1); | |
EventLoopGroup workerGroup = new NioEventLoopGroup(); | |
try { | |
try { | |
System.out.println("starting mtls proxy listener on: " + this.listenPort); | |
ServerBootstrap b = new ServerBootstrap(); | |
b.group(bossGroup, workerGroup) | |
.channel(NioServerSocketChannel.class) | |
.childHandler(new MTLSFrontendInitializer(this.host, this.port, this.sslContext)) | |
.childOption(ChannelOption.AUTO_READ, false) | |
.bind(this.listenPort).sync().channel().closeFuture().sync(); | |
} finally { | |
System.out.println("closing mtls proxy"); | |
bossGroup.shutdownGracefully(); | |
workerGroup.shutdownGracefully(); | |
} | |
} catch (InterruptedException e) { | |
System.err.println(e.toString()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment