Skip to content

Commit 1fdcf48

Browse files
SenseBinSenseBin
authored andcommitted
feat: add support for udp
1 parent fa8959d commit 1fdcf48

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

src/main/java/sense/test/socks5/constant/ChannelAttrKey.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ import io.netty.util.AttributeKey
88
*/
99
interface ChannelAttrKey {
1010
AttributeKey<Bootstrap> BOOTSTRAP = new AttributeKey('bootstrap')
11+
AttributeKey<Bootstrap> BOOTSTRAP_UDP = new AttributeKey('bootstrap_udp')
1112
}

src/main/java/sense/test/socks5/handler/CmdHandler.groovy

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ class CmdHandler extends ChannelDuplexHandler {
4242
case SocksCmdType.CONNECT:
4343
connect(ctx, request)
4444
break
45+
case SocksCmdType.UDP:
46+
udp(ctx, request)
47+
break
4548
default:
4649
ctx.close()
4750
}
@@ -81,4 +84,39 @@ class CmdHandler extends ChannelDuplexHandler {
8184
}
8285
})
8386
}
87+
88+
protected void udp(final ChannelHandlerContext ctx, final SocksCmdRequest request) {
89+
InetSocketAddress clientAddress = ctx.channel().remoteAddress() as InetSocketAddress
90+
logger.debug('以udp模式进行代理,[{}:{} -> {}:{}]',
91+
clientAddress.hostString, clientAddress.port, request.host(), request.port())
92+
93+
ctx.channel().attr(ChannelAttrKey.BOOTSTRAP_UDP).get().connect(request.host(), request.port()).addListener(new ChannelFutureListener() {
94+
@Override
95+
void operationComplete(ChannelFuture future) throws Exception {
96+
Channel channel = null
97+
try {
98+
channel = future.sync().channel()
99+
InetSocketAddress socketAddress = channel.remoteAddress() as InetSocketAddress
100+
boolean ipv4 = socketAddress.address instanceof Inet4Address
101+
SocksAddressType addressType = ipv4 ? SocksAddressType.IPv4 : SocksAddressType.IPv6
102+
SocksCmdResponse cmdResponse = new SocksCmdResponse(SocksCmdStatus.SUCCESS, addressType, socketAddress.address.getHostAddress(), socketAddress.port)
103+
104+
ctx.pipeline().addFirst(new ConnectHandler(channel))
105+
channel.pipeline().addLast(new ChildConnectHandler(ctx.channel()))
106+
ctx.writeAndFlush(cmdResponse)
107+
ctx.pipeline().remove(CmdHandler.this)
108+
} catch (Exception e) {
109+
logger.warn('代理udp请求失败', e)
110+
try {
111+
channel?.close()
112+
} catch (ignore) {
113+
}
114+
try {
115+
ctx.writeAndFlush(new SocksCmdResponse(SocksCmdStatus.FAILURE, SocksAddressType.UNKNOWN)).channel().close()
116+
} catch (ignore) {
117+
}
118+
}
119+
}
120+
})
121+
}
84122
}

src/main/java/sense/test/socks5/strap/ServerStrap.groovy

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import io.netty.channel.ChannelOption
77
import io.netty.channel.EventLoopGroup
88
import io.netty.channel.nio.NioEventLoopGroup
99
import io.netty.channel.socket.SocketChannel
10+
import io.netty.channel.socket.nio.NioDatagramChannel
1011
import io.netty.channel.socket.nio.NioServerSocketChannel
1112
import io.netty.channel.socket.nio.NioSocketChannel
1213
import io.netty.handler.codec.socks.SocksCmdRequestDecoder
@@ -39,16 +40,23 @@ class ServerStrap {
3940
return new Thread(r, "childGroup-" + atomicLong.getAndIncrement())
4041
}
4142
})
42-
private Bootstrap childConnectBootstrap = new Bootstrap().with {
43-
EventLoopGroup group = new NioEventLoopGroup(0, new ThreadFactory() {
44-
private AtomicLong atomicLong = new AtomicLong()
43+
private EventLoopGroup childConnectGroup = new NioEventLoopGroup(0, new ThreadFactory() {
44+
private AtomicLong atomicLong = new AtomicLong()
4545

46+
@Override
47+
Thread newThread(Runnable r) {
48+
return new Thread(r, "childConnectGroup-" + atomicLong.getAndIncrement())
49+
}
50+
})
51+
private Bootstrap childConnectBootstrap = new Bootstrap().with {
52+
it.group(childConnectGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
4653
@Override
47-
Thread newThread(Runnable r) {
48-
return new Thread(r, "childConnectGroup-" + atomicLong.getAndIncrement())
54+
protected void initChannel(SocketChannel socketChannel) throws Exception {
4955
}
50-
})
51-
it.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
56+
}).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
57+
}
58+
private Bootstrap childUdpConnectBootstrap = new Bootstrap().with {
59+
it.group(childConnectGroup).channel(NioDatagramChannel.class).handler(new ChannelInitializer<SocketChannel>() {
5260
@Override
5361
protected void initChannel(SocketChannel socketChannel) throws Exception {
5462
}
@@ -62,14 +70,15 @@ class ServerStrap {
6270
serverBootstrapTemplate.childHandler(new ChannelInitializer<SocketChannel>() {
6371
@Override
6472
protected void initChannel(SocketChannel ch) throws Exception {
65-
ch.pipeline()
73+
def channel = ch.pipeline()
6674
.addLast(new SocksMessageEncoder())
6775
.addLast(new SocksInitRequestDecoder())
6876
.addLast(new InitHandler())
6977
.addLast(new SocksCmdRequestDecoder())
7078
.addLast(new CmdHandler())
7179
.channel()
72-
.attr(ChannelAttrKey.BOOTSTRAP).set(childConnectBootstrap)
80+
channel.attr(ChannelAttrKey.BOOTSTRAP).set(childConnectBootstrap)
81+
channel.attr(ChannelAttrKey.BOOTSTRAP_UDP).set(childUdpConnectBootstrap)
7382
}
7483
})
7584
serverBootstrapTemplate.bind(port).sync().channel().closeFuture().await()

0 commit comments

Comments
 (0)