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.socks.SocksCmdRequest;
28 import io.netty.handler.codec.socks.SocksCmdResponse;
29 import io.netty.handler.codec.socks.SocksCmdStatus;
30 import io.netty.util.concurrent.Future;
31 import io.netty.util.concurrent.GenericFutureListener;
32 import io.netty.util.concurrent.Promise;
33
34 @ChannelHandler.Sharable
35 public final class SocksServerConnectHandler extends SimpleChannelInboundHandler<SocksCmdRequest> {
36
37 private final Bootstrap b = new Bootstrap();
38
39 @Override
40 public void channelRead0(final ChannelHandlerContext ctx, final SocksCmdRequest request) throws Exception {
41 Promise<Channel> promise = ctx.executor().newPromise();
42 promise.addListener(
43 new GenericFutureListener<Future<Channel>>() {
44 @Override
45 public void operationComplete(final Future<Channel> future) throws Exception {
46 final Channel outboundChannel = future.getNow();
47 if (future.isSuccess()) {
48 ctx.channel().writeAndFlush(new SocksCmdResponse(SocksCmdStatus.SUCCESS, request.addressType()))
49 .addListener(new ChannelFutureListener() {
50 @Override
51 public void operationComplete(ChannelFuture channelFuture) {
52 ctx.pipeline().remove(SocksServerConnectHandler.this);
53 outboundChannel.pipeline().addLast(new RelayHandler(ctx.channel()));
54 ctx.pipeline().addLast(new RelayHandler(outboundChannel));
55 }
56 });
57 } else {
58 ctx.channel().writeAndFlush(new SocksCmdResponse(SocksCmdStatus.FAILURE, request.addressType()));
59 SocksServerUtils.closeOnFlush(ctx.channel());
60 }
61 }
62 });
63
64 final Channel inboundChannel = ctx.channel();
65 b.group(inboundChannel.eventLoop())
66 .channel(NioSocketChannel.class)
67 .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
68 .option(ChannelOption.SO_KEEPALIVE, true)
69 .handler(new DirectClientHandler(promise));
70
71 b.connect(request.host(), request.port()).addListener(new ChannelFutureListener() {
72 @Override
73 public void operationComplete(ChannelFuture future) throws Exception {
74 if (future.isSuccess()) {
75
76 } else {
77
78 ctx.channel().writeAndFlush(
79 new SocksCmdResponse(SocksCmdStatus.FAILURE, request.addressType()));
80 SocksServerUtils.closeOnFlush(ctx.channel());
81 }
82 }
83 });
84 }
85
86 @Override
87 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
88 SocksServerUtils.closeOnFlush(ctx.channel());
89 }
90 }