很多本地代理都为Socks5或者HTTP代理，本篇将从理论与实践角度，解释二者原理。本篇是代理技术鉴赏的一篇分支，更加细致的介绍了Socks5和HTTP代理。Socks5代理于RFC 1928文档中定义，其是Socks4的升级版，在其基础上添加了认证机制、UDP代理和IPv6支持，Socks4已被Socks5完全替代。Socks5代理TCP时，分为认证、请求和通信3个阶段。1、Socks5代理TCP1.1 TCP认证首先，客户端会与Socks5代理建立TCP三次握手，之后发送认证请求，格式如下：VERNMETHODSMETHODS111 to 255VER：表示socks协议版本，值为0x05NMETHODS：表示支持多少种验证方式，也就是后面METHODS字段的长度METHODS：表示支持的验证方式，最多可提供255种，最少提供1种验证方式。0x00 无须验证 0x01 GSSAPI 0x02 用户名/密码 0x03~0x7F IANA分配 0x80~0xFE 自定义验证方式 0xFF 没有可验证的方式（这种情况下socks服务器必须关闭连接）流量示例：socks5服务端收到消息后，选择一种认证方式并发送给客户端，格式如下：VERMETHOD11流量示例：然后进入选定的认证方法认证阶段，这里以用户名/密码认证方式为例，给出流量示例：这里面用户名为bigbyto，密码为123456，然后服务端回复。1.2 TCP请求客户端认证后，就可以开始发送连接请求了，格式如下：VERCMDRSVATYPDST.ADDRDST.PORT110x001Variable2VER：表示socks协议版本，值为0x05CMD：请求命令类型，表示客户端希望代理执行的操作0x01 CONNECT（TCP连接请求） 0x02 BIND（绑定端口，用于服务器反向连接） 0x03 UDP ASSOCIATE（UDP中继，用于UDP转发）RSV：保留字段，必须填0x00。 ATYP：目标地址类型0x01 IPv4地址（4字节） 0x03 域名（第一个字节为域名长度） 0x04 IPv6地址（16字节）DST.ADDR：目标主机地址，格式取决于ATYPDST.PORT：目标主机端口大多数情况下，ATYP为域名，即客户端将域名直接传输给Socks5服务端，由服务端做DNS解析，由于Socks5服务端通常也在本地，故由后续的代理软件决定，如全局模式，就是在远端节点做DNS解析。这种情况下，客户端并不知道域名具体的IP，只知道已经通过代理转发给目的地址。流量示例：客户端请求访问a.baidu.com的80端口。socks5服务端收到访问请求后，回复客户端，格式如下：VERREPRSVATYPBND.ADDRBND.PORT110x001Variable2VER：协议版本，固定值为0x05。REP：回复字段，表示服务器执行请求的结果：0x00 成功 0x01 通用SOCKS服务器故障 0x02 连接不被规则集允许 0x03 网络不可达 0x04 主机不可达 0x05 连接被拒绝 0x06 TTL过期 0x07 不支持的命令 0x08 不支持的地址类型 0x09~0xFF 未分配RSV：保留字段，固定为0x00。ATYP：后续地址的类型：0x01 IPv4地址 0x03 域名 0x04 IPv6地址BND.ADDR：服务器绑定的地址。BND.PORT：服务器绑定的端口号。在最常见的CONNECT情况下，BND.ADDR和BND.PORT通常为0.0.0.0:0，只表示“连接成功”，具体绑定信息无意义。而BIND和UDP ASSOCIATE情况下，表示实际地址和端口，用于后续数据通道建立。流量示例：1.3 TCP通信连接建立后，客户端就可以和正常访问目标服务一样通信了，此时socks5代理仅会改变传输层以下的数据，而应用层的数据将原封不动的转发给目标服务器。也就是说，现在就可以把socks5代理服务器，当作目标服务器通信了。流量示例：2、Socks5代理UDP2.1 UDP认证Socks5代理UDP时，认证阶段与代理TCP时一样，且认证过程用的TCP连接。2.2 UDP请求认证通过后，客户端发送UDP代理请求，格式如下：VERCMDRSVATYPDST.ADDRDST.PORT110x001Variable2这个请求格式与Socks5代理TCP时相同，不过这里的CMD值是0x03，也就是UDP类型，说明本次请求是UDP请求，且目标地址和端口可以全0表示“尚不确定”。Socks5代理收到客户端发来的请求后，创建一个UDP监听端口，并将这个监听信息发回客户端，格式如下：VERREPRSVATYPBND.ADDRBND.PORT110x001Variable2这个回复格式依旧与Socks5代理TCP时相同，其中，BND.ADDR/BND.PORT的值为创建的UDP连接关联的地址和端口，客户端会直接将UDP数据发送到这个UDP连接中，所以上一个步骤接收的DST.ADDR/DST.PORT并没有太大意义。且在UDP通信阶段，请求阶段的TCP连接不能断开，否则UDP代理将结束。2.3 UDP通信客户端收来Socks5代理服务器发来的UDP端口后，就可以将本地的UDP数据发送到指定端口，格式如下：RSVFRAGATYPDST.ADDRDST.PORTDATA211Variable2VariableRSV：保留值，始终为 0x0000FRAG：分包序号，可能有以下值：​ 0x00 这是一个不需要分包的 UDP 报文0x01~0x7F 分包序号 0x80~0xFF 最高位是1，表示这个是最后一个分包ATYP：地址类型，可能有以下值：​ 0x01 IPV4 地址（占 4 字节）0x03 域名（第一字节为域名长度，后面为域名字符） 0x04 IPV6 地址（占 16 字节）DST.ADDR：目标地址DST.PORT：目标端口DATA：UDP数据相较于TCP代理，UDP代理在本地新开了一个UDP端口，但仍然与Socks5的TCP端口保持连接。但是，实际上很多Socks5代理工具并没有实现UDP代理功能[1]。目前代理UDP的方法还是启用TUN模式。3、HTTP代理HTTP分为正向代理和反向代理。正向代理为客户端服务，HTTP正向代理可以代理HTTP、HTTPS以及任何基于TCP的流量，而反向代理是针对服务端来说的，如Nginx的反向代理。HTTP正向代理：HTTP 1.1中，新增了CONNECT方法，使得HTTP能够正向代理任何基于TCP的流量，如可利用HTTP代理SSH流量，当客户端与代理服务端CONNECT协商后，这条通道就回退成了一条纯TCP通道，不再含有HTTP语义。HTTP反向代理：HTTP反向代理中，增加了WebSocket机制，使其能够基于HTTP语义升级WebSocket协议后代理任意TCP流量，不过客户端与Web服务器通信间还是会有WebSocket语义格式，而Web服务器反向代理时，会去除WebSocket语义，只留下Payload部分。科学上网工具常用WebSocket协议，因为Nginx等Web服务器的HTTP模块，可以实现即打开WebSocket反向代理，又启动Web服务，实现伪站防主动探测。另外，Nginx中虽然有stream模块，可以反向代理任意TCP流量，但其不能在同一端口打开Web服务，也就不抗主动探测攻击。HTTP代理在代理HTTP流量时，代理理解并转发HTTP请求内容，用GET/POST等普通方法。流量示例如下：HTTP在代理HTTPS、SSH等TCP流量时，会调用CONNECT方法，为客户端打开到目标主机的原始TCP连接并建立隧道。HTTP代理SSH流量示例如下：一些杂谈由于Socks5和HTTP的服务端都没有带加密功能，在互联网上明文传输数据，HTTP中的认证也仅是做了Base64编码，所以极其不安全，如今已经将二者的应用场景从远端移到了本地。浏览器能创建的UDP连接只有QUIC(HTTP 3.0)和WebRTC，其中WebRTC是正统的UDP。不过这两者都不会走浏览器或系统代理，只有在开启了TUN模式时，才可能会走，具体还要看代理节点对UDP的支持程度。WebRTC使用独立的网络栈，直接创建系统级UDP socket，不经过浏览器的代理模块，所以不会走浏览器或ZeroOmega设置的Socks5代理。WebRTC Control等防止WebRTC泄露IP的扩展工具，都是通过禁用STUN协议来的。DNS不算浏览器产生的，它是由浏览器调用系统API产生的。如果浏览器安装了代理插件，则会直接忽视系统代理，例如代理插件设置了直连，系统设置了代理，那么浏览器还是会走直连。References[1] https://www.txthinking.com/talks/articles/socks5-and-http-proxy.article