最近在做的项目,需要自己搭建一个socks代理。netty4.0附带了一个socks代理的样例,但是3.x就没有这个东西了,碰巧使用的又是3.7,就只能自己摸索并实现一遍,也算是对netty和socks协议的一个熟悉。 socks代理涉及到协议解析、server、client等功能,是一个比较复杂的网络程序,对于学习netty的使用也是非常好的例子。

socks是在传输层之上的一层协议,主要功能是提供代理认证等功能。socks协议虽然是应用层协议(在TCP/IP4层协议栈里),本身可以理解为一个信道,可以传输任何TCP/UDP内容。例如著名的科学上网软件就是基于socks协议,对通信内容进行加密实现的。

TCP/IP协议栈的结构中,下层协议总会在上层协议内容之前加上自己的头。而socks协议稍微不同,其实它对比TCP协议,仅仅是多了验证部分,验证之后,完全是使用TCP来进行传输,而没有socks报文头。socks协议的具体内容可以参考rfc1928。这一点来说,其实将socks理解成与其他应用层协议平级也没什么问题。

一个最基本的socks连接流程是这样的:

那么我们开始netty之旅吧。

首先我们需要建立一个server:

如你所见,主要的处理逻辑以SocksProxyPipelineFactory的形式提供。SocksProxyPipelineFactory的代码包括几部分:

这里要详细解释一下几个handler的作用:

ChannelUpstreamHandler用于接收之后的处理,而ChannelDownstreamHandler则相反,用于写入数据之后的处理。这两个都可以附加到ChannelPipeline中。偷个懒,直接附上netty的ChannelPipeline中的一段很有爱的javadoc:

SocksInitRequestDecoder用于对socks的请求进行解码。你可能会说,为什么没有SocksCmdRequest的解码?别急,netty的handler是可以动态添加的,这里我们先解码一个初始化的请求。SocksInitRequestDecoder是一个ChannelUpstreamHandler,即接收流的处理器。

SocksMessageEncoder是一个ChannelDownstreamHandler,即输出时的编码器,有了它,我们可以很开心的在channel.write()里直接传入一个对象,而无需自己去写buffer了。

SocksServerHandler是处理的重头。这里会根据请求的不同类型,做不同的处理。

前面两种INIT和AUTH就不做赘述了,后面当CMD为Connect时,添加一个处理连接的SocksServerConnectHandler,它会起到client与外部server的桥梁作用。

这里我们先实现一个纯转发的handler-OutboundHandler:

它会把收到的内容,写入到inboundChannel中,其他转发的作用。最后就是我们的SocksServerConnectHandler了:

好了,完工!输入curl --socks5 127.0.0.1:1080 http://www.oschina.net/测试一下吧?但是测试时发现,怎么老是无法接收到响应?

使用wiredshark抓包之后,发现对外请求完全正常,但是对客户端的响应,则完全没有http响应部分?

一步步debug下去,才发现SocksMessageEncoder出了问题!

这里只有SocksMessage才会被处理,其他的message全部被丢掉了!于是我们加上一行:

至此,一个代理完成!点这里查看代码:https://github.com/code4craft/netty-learning/tree/master/learning-src/socksproxy

查看原文 >>
相关文章