package com.lightsocks.socks5.handler; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import java.net.InetAddress; import java.util.Random; import com.lightsocks.socks5.Server; import com.lightsocks.socks5.bean.DstServer; import com.lightsocks.socks5.crpt.Icrptor; import com.lightsocks.socks5.crpt.IcrptorImp; import com.lightsocks.socks5.crpt.KeyUtil; public class SLeftHandler extends ChannelHandlerAdapter implements ForwardAdapter { private Icrptor decrpt; private Icrptor encrptor; private ChannelHandlerContext ctx; private ForwardAdapter forwardWriter; private volatile boolean isInitEncrptor = false; private volatile boolean close = false; private volatile boolean isForwardRead = false; private DstServer dst; public SLeftHandler(Icrptor decrpt, DstServer dst) { this.decrpt = decrpt; this.dst = dst; } @Override public void handlerAdded(ChannelHandlerContext ctx) { this.ctx = ctx; // ctx.fireChannelActive(); try { RemoteConnector proxy = new RemoteConnector(dst.getIP(), dst.getPt(), Server.getWorkerGroup2(), this); proxy.run(); if (!isInitEncrptor) { initEncrptor(); byte[] iv = encrptor.getIv(); write(iv, iv.length); isInitEncrptor = true; } } catch (Exception ex) { ex.printStackTrace(); ctx.close(); } } public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf m = (ByteBuf) msg; if (m.readableBytes() > 0) { if (isForwardRead) { int validate = m.readInt(); // read the validate length int length = m.readInt(); // read the content length byte[] content = new byte[length]; m.readBytes(content); m.release(); ByteBuf buf = ctx.alloc().buffer(validate); buf.writeBytes(decrpt.update(content), 0, validate); forwardWriter.forward(buf); } } } public void forward(ByteBuf m) throws Exception { if (!isInitEncrptor) { initEncrptor(); byte[] iv = encrptor.getIv(); write(iv, iv.length); isInitEncrptor = true; } int total = m.readableBytes(); int left = total % Server.AppConfig.getCrptorParam().getKeyLen(); int first = total - left; if (first != 0) { byte[] firstBulk = new byte[first]; m.readBytes(firstBulk); byte[] dst = encrptor.update(firstBulk); if (dst != null) { write(dst, first); } } if (left != 0) { byte[] LeftBulk = new byte[left]; m.readBytes(LeftBulk); byte[] end = new byte[Server.AppConfig.getCrptorParam().getKeyLen()]; for (int i = 0; i < left; i++) { end[i] = LeftBulk[i]; } byte[] dst = encrptor.update(end); if (dst != null) { write(dst, left); } } m.release(); } public void channelInactive(ChannelHandlerContext ctx) throws Exception { // ctx.fireChannelInactive(); close = true; if (forwardWriter != null) { forwardWriter.closeNotify(); } } public void closeNotify() { if (!close) { close = true; this.ctx.close(); } } public void attach(ForwardAdapter target) { this.forwardWriter = target; } public void forwardReadyNotify() { isForwardRead = true; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } private void initEncrptor() throws Exception { byte[] iv = new byte[Server.AppConfig.getCrptorParam().getIvLen()]; Random random1 = new Random(256); random1.nextBytes(iv); encrptor = new IcrptorImp(KeyUtil.evpBytesToKey(Server.AppConfig .getPassword(), Server.AppConfig.getCrptorParam().getKeyLen()), iv, Server.AppConfig.getCrptorParam().getMode(), Server.AppConfig.getCrptorParam().getType(), 0); encrptor.init(); } private void write(byte[] data, int validate) { ByteBuf len = ctx.alloc().buffer(8); len.writeInt(validate); len.writeInt(data.length); ctx.writeAndFlush(len); ByteBuf buf = Unpooled.wrappedBuffer(data); ctx.writeAndFlush(buf); } private final static class RemoteConnector { private final InetAddress host; private final int port; // private EventLoopGroup group; private ForwardAdapter forwardWrite; private EventLoopGroup workerGroup; public RemoteConnector(InetAddress host, int port, EventLoopGroup group, ForwardAdapter forwardWrite) { this.host = host; this.port = port; this.workerGroup = group; this.forwardWrite = forwardWrite; } public void run() throws Exception { // Configure the client. // EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( // new LoggingHandler(LogLevel.INFO), new SRightHandler(forwardWrite)); } }); // Start the client. System.out.println(host.toString() + ":" + port); ChannelFuture f = b.connect(host, port).sync(); // Wait until the connection is closed. // f.channel().closeFuture().sync(); } finally { // Shut down the event loop to terminate all threads. // group.shutdownGracefully(); } } } }