相关的总结文档在:sock5 udp 透传总结
1:测试场景
测试使用的是双网卡的设备即有eth0和eth1,分别配置不同网段的IP地址,使用的代理软件为:dante-1.4.0。
其中
客服端的IP地址为:192.168.100.20 服务器端的IP地址为:10.10.98.2
客服端发送UDP数据包到服务端,proxy完成对UDP数据的转发。
2:测试结果
首先在proxy上面对eth0和eth1端口进行抓包。
eth0上面的抓包如下:Client端向server端发送的数据为:suiyaun2014,server端给client回的数据为:8888888888,其长度为:10。
有上面的抓包可以知道,proxy正确的转发了server和client端的数据通信。
现在来看看上面的的数据包:
开始的TCP数据包是client与proxy之间的TCP连接,proxy监听的端口是:1080,先看看dante-1.4.0的配置
# the server will log both via syslog, to stdout and to /var/log/sockd.log
#logoutput: syslog stdout /var/log/sockd.log
logoutput: stderr
# The server will bind to the address 10.1.1.1, port 1080 and will only
# accept connections going to that address.
#internal: 10.1.1.1 port = 1080
# Alternatively, the interface name can be used instead of the address.
internal: eth1 port = 1080
# all outgoing connections from the server will use the IP address
# 195.168.1.1
external: 10.10.98.25
# methods for socks-rules.
socksmethod: username none #rfc931
# The "client" rules. All our clients come from the net 10.0.0.0/8.
# Allow our clients, also provides an example of the port range command.
client pass {
from: 0.0.0.0/0 port 1-65535 to: 0.0.0.0/0
method: none # match all idented users that also are in passwordfile
}
# or you might want to allow it, for instance "active" ftp uses it.
# Note that a "bindreply" command must also be allowed, it
# should usually by from "0.0.0.0/0", i.e if a client of yours
# has permission to bind, it will also have permission to accept
# the reply from anywhere.
pass {
from: 10.0.0.0/8 to: 0.0.0.0/0
command: bind bindreply connect udpassociate udpreply
log: connect error
}
# some connections expect some sort of "reply", this might be
# the reply to a bind request or it may be the reply to a
# udppacket, since udp is packet based.
# Note that nothing is done to verify that it's a "genuine" reply,
# that is in general not possible anyway. The below will allow
# all "replies" in to your clients at the 10.0.0.0/8 net.
pass {
from: 0.0.0.0/0 to: 0.0.0.0/0
command: bind bindreply connect udpassociate udpreply
log: connect error
}
# everyone from our internal network, 10.0.0.0/8 is allowed to use
# tcp and udp for everything else.
pass {
from: 192.168.100.0/24 to: 0.0.0.0/0
protocol: tcp udp
}
上面的配置细节没有研究,如果配置不对,UDP server回复的数据可能不能到达UDPclient端。
具体到代码的实现上面。大致过程如下:此处没有进行认证操作,为无认证操作过程。
1:基于TCP的client与代理服务其之间的认证阶段。
认证过程可分为:使用和不使用户用户认证过程。其此过程不论sock5使用TCP还是UDP通信,认证过程是一样的。
A:client向proxy发送协商认证方式
连接代理服务器成功后,马上开始和代理协商,协商报文如下,询问服务器,版本5,是需要验证(0x02)还是不需要验证(0x00)
+------+-------------------+------------+
|VER | Number of METHODS |METHODS |
+------+-------------------+------------+
| 0x05 | 0x02 (有两个方法) | 0x00 | 0x02|
+------+-------------------+------------+
B:proxy响应client端的协议认证请求
The server selects from one of the methodsgiven in METHODS, andsends a METHOD selection message:
+----+--------+
|VER | METHOD |
+----+--------+
| 1 | 1 |
+----+--------+
If the selected METHOD is X'FF', none of themethods listed by the client are acceptable, and the client MUST close theconnection.
The values currently defined for METHOD are:
o X'00' NO AUTHENTICATION REQUIRED
o X'01'GSSAPI
o X'02'USERNAME/PASSWORD
o X'03' to X'7F' IANA ASSIGNED
o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
l X'FF' NOACCEPTABLE METHODS
完成上面的交换过程之后,client与prox进入认证阶段。是否继续进行认证操作由上面的proxy的放结果决定的,当返回值为:0x02是表示使用用户名和密码进行认证
2:基于UDP通过proxy中转的client和server数据交换过程。
这个阶段需要主要client与proxy之间通信地址的获取。其数据包格式如下:
A:UDP穿透请求
客户端会用通过认证的这个TCP连接发送UDP穿透请求,信令格式如下:
+----+-----+-------+------+----------+----------+
|VER| CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
|1 | 1 | X'00' | 1 | Variable | 2 |
+------+--------+-------+---------+-----------------+----------+
其中各项:
o VER 协议版本,对于SOCKS5都是 5。
o CMD 要请求的命令,UDP穿透填3。 其它的CONNECT是1,BIND是2。
o RSV 保留字段,填0。
o ATYP 地址类型,我们用IPV4,填1。域名的话填3,IPV6的话填4。
o DST.ADDR IP地址。对于UDP穿透来说,好像没有什么意义,填0(也就是127.0.0.1)。
o DST.PORT 这个很重要,要填client端想发送/接收UDP包的本地端口。后面在发送UDP包时代理服务器会检测收到的UDP包的源端口,只有和这里填入的端口号符合的包才会被处理。
B:UDP穿透应答
代理服务器会回应客户端的请求,消息格式如下:
+----+-----+-------+------+----------+----------+
|VER| REP | RSV | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
|1 | 1 | X'00'| 1 | Variable| 2 |
+----+-----+-------+------+----------+----------+
其中:
o VER 协议版本,对于SOCKS5都是 5。
o REP 代理服务器返回的结果,含义如下:
X'00'succeeded
X'01'general SOCKS server failure
X'02'connection not allowed by ruleset
X'03'Network unreachable
X'04'Host unreachable
X'05'Connection refused
X'06'TTL expired
X'07'Command not supported
X'08'Address type not supported
X'09'to X'FF' unassigned
o RSV 保留字段。
o ATYP 后面IP地址的格式,含义如下:
IP V4 address: X'01'
DOMAINNAME: X'03'
IP V6 address: X'04'
o BND.ADDR 此UDP穿透通道对应的代理服务器地址。
o BND.PORT 此UDP穿透通道对应的代理服务器端口。
至此,UDP穿透通道已经被建起来了,客户端只要按标准格式将UDP包发往上述地址端口,UDP包就会被代理服务器转发出去。
通过之上的交互之后client知道UDP发送的目的地址(proxy的地址及端口)。
C:client端数据的发送及接受
上面交互信令中都没有提到客户端想通过代理访问的远端服务器地址。UDP包的最终目的地是通过在原始UDP包数据前加一个包头来实现的。包头的格式如下:
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP |DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
|2 | 1 | 1 |Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
其中:
o RSV 保留字段,填0。
o FRAG 当前分片序号,我们没有分片,填0。
o ATYP 地址类型,和前面的几个一样。IPV4填 1 。
o DST.ADDR UDP包最终的目的地址。
o DST.PORT UDP包最终的目的端口。
o DATA 原始的UDP包的数据。
按照上面格式发出的UDP包中的DATA部分会被代理服务器转发到包头中填入的最终目的地址。
发送数据:
接受数据如下: