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