import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.socks.SocksAuthResponse; import io.netty.handler.codec.socks.SocksCmdRequest; import io.netty.handler.codec.socks.SocksCmdRequestDecoder; import io.netty.handler.codec.socks.SocksCmdResponse; import io.netty.handler.codec.socks.SocksCmdStatus; import io.netty.handler.codec.socks.SocksInitRequestDecoder; import io.netty.handler.codec.socks.SocksInitResponse; import io.netty.handler.codec.socks.SocksMessageEncoder; import io.netty.handler.codec.socks.SocksRequest; import io.netty.handler.codec.socks.SocksServerHandler; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.handler.codec.socks.SocksAddressType; import io.netty.handler.codec.socks.SocksCmdType;

public class Socks5Server { private static ServerBootstrap serverBootstrap = new ServerBootstrap(); private static SocksInsideChannelInitializer channelInitializer = new SocksInsideChannelInitializer();

public static void main(String[] args) throws Exception {
    NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
    NioEventLoopGroup workerGroup = new NioEventLoopGroup();
    serverBootstrap.channel(NioServerSocketChannel.class);
    serverBootstrap.group(bossGroup, workerGroup);
    serverBootstrap.childHandler(channelInitializer);
    serverBootstrap.bind(52007).addListener(new GenericFutureListener<Future<? super Void>>() {
        @Override
        public void operationComplete(Future<? super Void> future) throws Exception {
            System.out.println('socks-inside-server started, listening port: ' + 52007);
        }
    });
}

private static class SocksInsideChannelInitializer extends ChannelInitializer<Channel> {
    private Socks5ProcessServerHandler socksProxyProcessHandler = new Socks5ProcessServerHandler();

    @Override
    protected void initChannel(Channel ch) throws Exception {
        ch.pipeline().addLast(new SocksInitRequestDecoder());
        ch.pipeline().addLast(new SocksMessageEncoder());
        ch.pipeline().addLast(socksProxyProcessHandler);
    }
}

@ChannelHandler.Sharable
private static class Socks5ProcessServerHandler extends SimpleChannelInboundHandler<SocksRequest> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, SocksRequest msg) throws Exception {

        switch (msg.requestType()) {
            case INIT:
                ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
                ctx.writeAndFlush(new SocksInitResponse(SocksAuthScheme.NO_AUTH));
                break;
            case AUTH:
                ctx.pipeline().addFirst(new SocksCmdRequestDecoder());
                ctx.writeAndFlush(new SocksAuthResponse(SocksAuthStatus.SUCCESS));
                break;
            case CMD:
                SocksCmdRequest req = (SocksCmdRequest) msg;
                if (req.cmdType() == SocksCmdType.CONNECT) {
                    ctx.pipeline().addLast(new SocksServerHandler());
                    ctx.pipeline().remove(this);
                    ctx.fireChannelRead(msg);
                } else {
                    ctx.close();
                }
                break;
            case UNKNOWN:
                ctx.close();
                break;
            default:
                ctx.close();
                break;
        }
    }
}

private static class SocksServerHandler extends SimpleChannelInboundHandler<SocksCmdRequest> {

    @Override
    protected void channelRead0(final ChannelHandlerContext browserCtx, final SocksCmdRequest msg) throws Exception {
        if (msg.host() == null || msg.host().isEmpty()) {
            browserCtx.close();
            return;
        }
        browserCtx.pipeline().remove(this);
        browserCtx.pipeline().addLast(new SocksHandler(browserCtx, msg));
        browserCtx.channel().writeAndFlush(new SocksCmdResponse(SocksCmdStatus.SUCCESS, SocksAddressType.IPv4));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (ctx.channel().isActive()) {
            ctx.channel().close();
        }
    }
}

private static class SocksHandler extends ChannelInboundHandlerAdapter {

    private ChannelHandlerContext browserCtx;
    private SocksCmdRequest req;

    public SocksHandler(ChannelHandlerContext browserCtx, SocksCmdRequest req) {
        this.browserCtx = browserCtx;
        this.req = req;
    }

    @Override
    public void channelRead(ChannelHandlerContext outsideProxyCtx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            if (request.decoderResult().isSuccess()) {
                String method = request.method().name();
                String uri = request.uri();
                String version = request.protocolVersion().text();
                System.out.println('HTTP Request: ' + method + ' ' + uri + ' ' + version);
                String response = 'Hello World!';
                FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                        HttpResponseStatus.OK, Unpooled.wrappedBuffer(response.getBytes()));
                httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, 'text/plain');
                httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
                outsideProxyCtx.writeAndFlush(httpResponse);
            } else {
                browserCtx.close();
            }
        }
    }
}

}

Netty 实现 Socks5 代理服务器:代码示例与优化

原文地址: https://www.cveoy.top/t/topic/oafL 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录