1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.example.socksproxy;
17
18 import io.netty.bootstrap.Bootstrap;
19 import io.netty.channel.Channel;
20 import io.netty.channel.ChannelFuture;
21 import io.netty.channel.ChannelHandler;
22 import io.netty.channel.ChannelHandlerContext;
23 import io.netty.channel.ChannelOption;
24 import io.netty.channel.SimpleChannelInboundHandler;
25 import io.netty.channel.socket.nio.NioSocketChannel;
26 import io.netty.handler.codec.socksx.SocksMessage;
27 import io.netty.handler.codec.socksx.v4.DefaultSocks4CommandResponse;
28 import io.netty.handler.codec.socksx.v4.Socks4CommandRequest;
29 import io.netty.handler.codec.socksx.v4.Socks4CommandStatus;
30 import io.netty.handler.codec.socksx.v5.DefaultSocks5CommandResponse;
31 import io.netty.handler.codec.socksx.v5.Socks5CommandRequest;
32 import io.netty.handler.codec.socksx.v5.Socks5CommandStatus;
33 import io.netty.util.concurrent.FutureListener;
34 import io.netty.util.concurrent.Promise;
35
36 @ChannelHandler.Sharable
37 public final class SocksServerConnectHandler extends SimpleChannelInboundHandler<SocksMessage> {
38
39 private final Bootstrap b = new Bootstrap();
40
41 @Override
42 public void channelRead0(final ChannelHandlerContext ctx, final SocksMessage message) throws Exception {
43 if (message instanceof Socks4CommandRequest) {
44 final Socks4CommandRequest request = (Socks4CommandRequest) message;
45 Promise<Channel> promise = ctx.executor().newPromise();
46 promise.addListener(
47 (FutureListener<Channel>) future -> {
48 final Channel outboundChannel = future.getNow();
49 if (future.isSuccess()) {
50 ChannelFuture responseFuture = ctx.channel().writeAndFlush(
51 new DefaultSocks4CommandResponse(Socks4CommandStatus.SUCCESS));
52
53 responseFuture.addListener(channelFuture -> {
54 ctx.pipeline().remove(SocksServerConnectHandler.this);
55 outboundChannel.pipeline().addLast(new RelayHandler(ctx.channel()));
56 ctx.pipeline().addLast(new RelayHandler(outboundChannel));
57 });
58 } else {
59 ctx.channel().writeAndFlush(
60 new DefaultSocks4CommandResponse(Socks4CommandStatus.REJECTED_OR_FAILED));
61 SocksServerUtils.closeOnFlush(ctx.channel());
62 }
63 });
64
65 final Channel inboundChannel = ctx.channel();
66 b.group(inboundChannel.eventLoop())
67 .channel(NioSocketChannel.class)
68 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
69 .option(ChannelOption.SO_KEEPALIVE, true)
70 .handler(new DirectClientHandler(promise));
71
72 b.connect(request.dstAddr(), request.dstPort()).addListener(future -> {
73 if (future.isSuccess()) {
74
75 } else {
76
77 ctx.channel().writeAndFlush(
78 new DefaultSocks4CommandResponse(Socks4CommandStatus.REJECTED_OR_FAILED)
79 );
80 SocksServerUtils.closeOnFlush(ctx.channel());
81 }
82 });
83 } else if (message instanceof Socks5CommandRequest) {
84 final Socks5CommandRequest request = (Socks5CommandRequest) message;
85 Promise<Channel> promise = ctx.executor().newPromise();
86 promise.addListener(
87 (FutureListener<Channel>) future -> {
88 final Channel outboundChannel = future.getNow();
89 if (future.isSuccess()) {
90 ChannelFuture responseFuture =
91 ctx.channel().writeAndFlush(new DefaultSocks5CommandResponse(
92 Socks5CommandStatus.SUCCESS,
93 request.dstAddrType(),
94 request.dstAddr(),
95 request.dstPort()));
96
97 responseFuture.addListener(f -> {
98 ctx.pipeline().remove(SocksServerConnectHandler.this);
99 outboundChannel.pipeline().addLast(new RelayHandler(ctx.channel()));
100 ctx.pipeline().addLast(new RelayHandler(outboundChannel));
101 });
102 } else {
103 ctx.channel().writeAndFlush(new DefaultSocks5CommandResponse(
104 Socks5CommandStatus.FAILURE, request.dstAddrType()));
105 SocksServerUtils.closeOnFlush(ctx.channel());
106 }
107 });
108
109 final Channel inboundChannel = ctx.channel();
110 b.group(inboundChannel.eventLoop())
111 .channel(NioSocketChannel.class)
112 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
113 .option(ChannelOption.SO_KEEPALIVE, true)
114 .handler(new DirectClientHandler(promise));
115
116 b.connect(request.dstAddr(), request.dstPort()).addListener(future -> {
117 if (future.isSuccess()) {
118
119 } else {
120
121 ctx.channel().writeAndFlush(
122 new DefaultSocks5CommandResponse(Socks5CommandStatus.FAILURE, request.dstAddrType()));
123 SocksServerUtils.closeOnFlush(ctx.channel());
124 }
125 });
126 } else {
127 ctx.close();
128 }
129 }
130
131 @Override
132 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
133 SocksServerUtils.closeOnFlush(ctx.channel());
134 }
135 }