socks 专栏 —— 5. 认识代理和 socks5

·  阅读 78

5. 认识代理和 socks5

代理本质上是一个中间服务器。设客户端为 C,目标服务器为 S,代理服务器为 P,则他们的关系是:

5-1

可以看到,代理的主要工作就是转发数据。假设 C 和 S 之间存在某种障碍,导致他们之间无法直接进行通信,但是 C 和 P、P 和 S 之间可以自由通信,那么就可以利用 P 来进行 C 和 S 之间的通信。

本文接下来使用 client 指代 C,proxy server 指代 P,target server 指代 S。

socks5 是一个代理协议,位于应用层和传输层之间,也就是 HTTP 和 TCP 之间,所以 socks5 会用 TCP 来传输 HTTP 报文。

socks5 规定的具体通信过程如下(以最简单的不需要认证和 CONNECT CMD为例):

  1. client 发送一个 handshake:
                   +----+----------+----------+
                   |VER | NMETHODS | METHODS  |
                   +----+----------+----------+
                   | 1  |    1     | 1 to 255 |
                   +----+----------+----------+
复制代码

上图中,第二行的数字表示的含义不是值/取值范围,而是长度。比如 VER 下面的 1 代表 VER 这个数据的长度为 1 个字节。同理,NMETHODS 这个数据的长度为 1 个字节。而 METHODS 这个数据的长度为 1 至 255 个字节。

  • 第一个字节 VER 为版本号,socks5 统一为 0x05
  • 第二个字节 NMETHODS 为 client 支持的认证方式的数量。
  • 从第三个字节开始,每一个字节代表一种认证方式。

由于传递的是二进制数据,一个字节一个字节读取,信息是挨着的,没法区分界限,所以用特定的字节来表示某个数据的字节长度 n,用之后的 n 个字节来表示数据,这个方式非常常见。举个例子,127.0.0.14000 这13个字节,被读取的时候是没法知道哪部分是 ip,哪部分是 port。但是如果是09127.0.0.14000这 15 个字节,并且事先规定好前 2 个字节代表 ip 的长度,那么很轻松的就能分辨出,127.0.0.1是 ip,4000是端口。(一般情况下,长度会用无符号整数表示,上面的例子 09 实际上应该是 0x09

  1. proxy 发送一个 response:
​
                         +----+--------+
                         |VER | METHOD |
                         +----+--------+
                         | 1  |   1    |
                         +----+--------+
复制代码
  • 第一个字节 VER 同样为版本号,固定 0x05
  • 第二个字节 METHOD 为服务端从客户端发来的认证方式中,挑选出来的一种认证方式。其中0x00代表不需要认证。
  1. client 发送一个 request:
        +----+-----+-------+------+----------+----------+
        |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
复制代码

通过 handshake 建立连接后,client 就需要向 proxy 发请求。既然是代理协议,那么 client 至少需要告诉 proxy,我想访问的目标服务器的 ip 和 port,否则 proxy 根本不知道自己需要连接到哪里。

上述字段具体含义如下:

  • VER 不用多说

  • CMD 代表本次 socks 连接的命令

    • 0x01 表示 CONNECT
    • 0x02 表示 BIND
    • 0x03 表示 UDP 转发
  • RSV 为保留字段,一般保留字段都是 0x00

  • ATYP 为目标服务器地址的类型,DST.ADDR 为目标服务器的地址,DST.PORT 为目标服务器的端口

    • 0x01 表示 ipv4,此时 DST.ADDR 为 4 个字节。举个例子,ATYP + DST.ADDR + DST.PORT 为 01 c0 a8 01 01代表目标服务器的 ip 为 192.168.1.1
    • 0x02 表示域名。由于域名的长度不固定,DST.ADDR 的长度也不会固定。还记得针对这种变长的数据应该怎么传输吗,没错,length first。所以此时 DST.ADDR 会用第一个字节代表域名的长度 n ,后续 n 个字节代表域名。举个例子,ATYP + DST.ADDR + DST.PORT 为 03 09 62 61 69 64 75 2e 63 6f 6d 01 bb 代表目标服务器的域名是 baidu.com,端口为 443
    • 0x03 表示 ipv6,此时 DST.ADDR 为 16 个字节
  1. proxy 发送一个 response
        +----+-----+-------+------+----------+----------+
        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
复制代码
  • REP 代表本次的响应类型,0x00 代表成功
  • ATYPE 为 proxy 的地址类型
  • BND.ADDR 为 proxy 的地址,BND.PORT 为 proxy 的端口

这里的 BND.ADDR 是 proxy 自身的地址,BND.PORT 是 proxy 用来发起与 target server 连接的端口,而不是与 client 连接的端口。这两个值的作用查阅了部分文章,大致意思是:socks5 proxy server 可能是一个集群,不止一个 server,可能用于开始与 client 进行 socks5 交互的 server 和后续转发消息的 server 不是同一个。但是经过我的实验,BND.ADDR 和 BND.PORT 随便写了两个值,照样完成了转发。个人感觉这两个值实际上是用于 BIND CMD(忘记 BIND 是什么的,看上面 client 发送的 request,CMD 有三种类型)。总而言之,一般情况下,BND.ADDR 写0x00000000,BND.PORT 写 0X0000

  1. 开始实际上的数据转发

经过上面的 socks5 协议的部分之后,client 就会将真正需要转发的数据发给 proxy server,proxy server 需要转发给 target server。同理,target server 处理完来自 client 的数据后,也会发送自己的数据给 proxy server,proxy server 需要转发回给 client。这里的转发就是简单的 TCP socket 操作了,详见第三章。

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改