java通过netty实现代理服务器

来源: libraryhu 发布时间:2018-11-21 15:52:32 阅读量:1030

思路

netty有内置的http编解码器,那就可以轻易做到不只是转发原始数据,而是可以修改响应内容,当然仅限http代理,因为https代理的话私钥都存在客户端和目标服务器上,代理服务器只能捕获到双方的公钥,无法解密成明文,除非代理服务器制作证书,并实现SSL/TLS握手。

image.png

实现

EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup(2);try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100).option(ChannelOption.TCP_NODELAY, true).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<Channel>() {@Overrideprotected void initChannel(Channel ch) throws Exception {ch.pipeline().addLast("httpCodec",new HttpServerCodec());ch.pipeline().addLast("httpObject",new HttpObjectAggregator(65536));ch.pipeline().addLast("serverHandle",new HttpProxyServerHandle());}});ChannelFuture f = b.bind(port).sync();f.channel().closeFuture().sync();} catch (Exception e) {e.printStackTrace();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}

public class HttpProxyServerHandle extends ChannelInboundHandlerAdapter {private ChannelFuture cf;private String host;private int port;@Overridepublic void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {if (msg instanceof FullHttpRequest) {FullHttpRequest request = (FullHttpRequest) msg;String host = request.headers().get("host");String[] temp = host.split(":");int port = 80;if (temp.length > 1) {port = Integer.parseInt(temp[1]);} else {if (request.uri().indexOf("https") == 0) {port = 443;}}this.host = temp[0];this.port = port;if ("CONNECT".equalsIgnoreCase(request.method().name())) {//HTTPS建立代理握手HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, NettyHttpProxyServer.SUCCESS);ctx.writeAndFlush(response);ctx.pipeline().remove("httpCodec");ctx.pipeline().remove("httpObject");return;}//连接至目标服务器Bootstrap bootstrap = new Bootstrap();bootstrap.group(ctx.channel().eventLoop()) // 注册线程池.channel(ctx.channel().getClass()) // 使用NioSocketChannel来作为连接用的channel类.handler(new HttpProxyInitializer(ctx.channel()));ChannelFuture cf = bootstrap.connect(temp[0], port);cf.addListener(new ChannelFutureListener() {public void operationComplete(ChannelFuture future) throws Exception {if (future.isSuccess()) {future.channel().writeAndFlush(msg);} else {ctx.channel().close();}}});//            ChannelFuture cf = bootstrap.connect(temp[0], port).sync();//            cf.channel().writeAndFlush(request);} else { // https 只转发数据,不做处理if (cf == null) {//连接至目标服务器Bootstrap bootstrap = new Bootstrap();bootstrap.group(ctx.channel().eventLoop()) // 复用客户端连接线程池.channel(ctx.channel().getClass()) // 使用NioSocketChannel来作为连接用的channel类.handler(new ChannelInitializer() {@Overrideprotected void initChannel(Channel ch) throws Exception {ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelRead(ChannelHandlerContext ctx0, Object msg) throws Exception {ctx.channel().writeAndFlush(msg);}});}});cf = bootstrap.connect(host, port);cf.addListener(new ChannelFutureListener() {public void operationComplete(ChannelFuture future) throws Exception {if (future.isSuccess()) {future.channel().writeAndFlush(msg);} else {ctx.channel().close();}}});} else {cf.channel().writeAndFlush(msg);}}}}
public class HttpProxyInitializer extends ChannelInitializer{private Channel clientChannel;public HttpProxyInitializer(Channel clientChannel) {this.clientChannel = clientChannel;}@Overrideprotected void initChannel(Channel ch) throws Exception {ch.pipeline().addLast(new HttpClientCodec());ch.pipeline().addLast(new HttpObjectAggregator(6553600));ch.pipeline().addLast(new HttpProxyClientHandle(clientChannel));}}

public class HttpProxyClientHandle extends ChannelInboundHandlerAdapter {private Channel clientChannel;public HttpProxyClientHandle(Channel clientChannel) {this.clientChannel = clientChannel;}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {FullHttpResponse response = (FullHttpResponse) msg;//修改http响应体返回至客户端response.headers().add("test","from proxy");clientChannel.writeAndFlush(msg);}}


    标签: 服务器搭建
    分享:
    评论:
    你还没有登录,请先