pip3 install -U websocks
(会生成可执行文件websocks)
因为ws不是加密连接,所以运行上面的命令:
websocks client --policy PROXY --server-url ws://myusername:mypassword@vps-public-ip:2146 127.0.0.1 3278有可能翻墙失败。解决办法:使用nginx设置一个域名反向代理http://127.0.0.1:2146,并且替该域名申请和加上证书。具体就是在nginx的配置文件中加上一个server段如下:
https://github.com/abersheeran/websocks/issues/6
https://github.com/abersheeran/websocks/wiki
类似项目:https://briteming.blogspot.com/2018/04/haskellwstunnel-by-erebe.html
-----------------------------------------------------
使用WebSocket进行网络穿透
WebSocket
为什么要使用WebSocket
WebSocket 浅析
HTTP 握手
Connection: Upgrade 指定此次请求需要从 HTTP 协议升级Upgrade 指定此次请求升级到 websocketSec-WebSocket-Version 指定 WebSocket 的版本(一般都是 13)Sec-WebSocket-Key 是一个 16 byte 长度的随机字符串经过 base64 处理后的结果Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Accept 的值为客户端发送的 Sec-WebSocket-Key 拼接 "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 的字符串的 sha-1 值的 base64 编码结果base64encode(sha1(SecWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))WebSocket 报文结构

- Fin
: 1bit, 用于标记当前数据帧是不是最后一个数据帧, 单条消息可能会分成多个数据帧来传递。 如果只需要一个数据帧( , 第一个数据帧也就是最后一个) - RSV1
, RSV2, RSV3: 各自1bit, 用于扩展用途, 一般全部置0即可。 - Opcode
: 4bit, 操作码, 用于描述此数据帧的类型: - 0x0
: 标示当前数据帧为分片的数据帧, 也就是当一个消息需要分成多个数据帧来传送的时候, 需要将opcode设置位0x0。 - 0x1
: 标示当前数据帧传递的内容是文本, 编码为UTF-8。 - 0x2
: 标示当前数据帧传递的内容是二进制数据。 - 0x8
: 标示请求关闭连接。 - 0x9
: 标示此数据帧为ping帧。 - 0xA
: 标示此数据帧为pong帧, 仅在接收ping帧后发送pong。 - 0x3~0x7以及0xB~0xF
: 留作其他用途。
- 0x0
- MASK
: 1bit, 标示数据有没有使用掩码。 在RFC中规定, 服务端发送给客户端的数据帧不能使用掩码, 客户端发送给服务端的数据帧必须使用掩码。 - Payload length
: 7bit的无符号整数, 用于标识Payload data的长度。
值在0-125之间时, 这就是Payload data的长度。
值为126时, 使用后续2个bytes也就是16 bit的无符号整数来标识Payload data的长度。
值为127时, 使用后续8个bytes也就是64 bit的无符号整数用于标识Payload data的长度。 - Masking-key
: 数据掩码。 如果Mask位为0, 则该部分可以省略; 如果Mask位为1, 则为32 bit (4 byte)的掩码。
自定义协议
身份验证
Authorization 头发送到服务器请求代理
客户端请求
{ "VERSION": 1, "CMD": "TCP" | "UDP", "ADDR": "目标的地址", "PORT": "目标的端口" }
- VERSION: 协议版本号
, 此处为'01' - CMD: 指定代理方式
- "TCP"
- "UDP"
- ADDR: 目标的地址
- PORT: 目标的端口(number类型)
服务端响应
当服务端对此次请求处理完毕后
{ "VERSION": 1, "STATUS": "SUCCESS" }
- STATUS: 为
SUCCESS时, 客户端可进行下一步。 否则, 客户端认为服务器无法做到此次请求的要求, 立刻关闭连接。
数据传输
TCP
UDP
+------+----------+----------+----------+
| ATYP | DST.ADDR | DST.PORT | DATA |
+------+----------+----------+----------+
| 1 | Variable | 2 | Variable |
+------+----------+----------+----------+
- ATYP: 指定DST.ADDR的类型
- IPV4: X'01'
- 域名: X'03'
- IPV6: X'04'
- DST.ADDR: 该数据包渴望到达的目标地址
- DST.PORT: 该数据包渴望到达的目标端口
- DATA: 实际要传输的数据
题外话
代码实现在websocks
使用WebSocket进行网络穿透(续)
协商
Authorization 头发送到服务器转发
请求连接
{ "HOST": "example.com", "PORT": 443 }
{ "ALLOW": true/false }
转发
结束连接
{ "STATUS": "CLOSED" }
websocks-by-lzjluzijie优点
- 使用WS+TLS,十分安全且不易被检测,和普通HTTPS网站一样.
- 可以搭配使用cloudflare这类cdn,完全不怕被墙!
服务端命令:
./websocks server -l 0.0.0.0:2333 -p /xyz此服务端命令是运行在前台的,我们可以利用systemd来把该命令运行为service:nano /etc/systemd/system/websocks-by-lzjluzijie.servicecat /etc/systemd/system/websocks-by-lzjluzijie.service[Unit]
After=network.target
[Service]
ExecStart=/root/websocks_Linux_x86_64/websocks server -l 0.0.0.0:2333 -p /xyz
Restart=always
[Install]
WantedBy=multi-user.target然后,运行:systemctl start websocks-by-lzjluzijiesystemctl enable websocks-by-lzjluzijie caddy webserver的Caddyfile:
https://mydomain.com:1443 {
proxy /xyz localhost:2333 {
websocket
}
}橘红色文字的意思是用caddy webserver做反向代理,代理websocks的服务器端地址localhost:2333当然,也可用nginx做反向代理,代理websocks的服务器端地址localhost:2333 ,具体的server
段内容如下:服务端搭建完成。
from https://github.com/lzjluzijie/websocks https://github.com/lzjluzijie/websocks/releases (编译失败,于是下载作者提供的可执行文件来使用。) 服务器端程序 https://github.com/lzjluzijie/websocks/releases/download/v0.15.1/websocks_Linux_x86_64.tar.gz 客户端程序 https://github.com/lzjluzijie/websocks/releases/download/v0.15.1/websocks_Darwin_x86_64.tar.gz
客户端命令:
./websocks client -l :2081 -s wss://mydomain.com:1443/xyz 不要关闭此终端,设置浏览器的socks5 proxy的地址为127.0.0.1 ,端口为2081,浏览器即可翻墙。 ------------
Websocks开发记录
作为一个 App
一开始软件结构是仿照 LightSocks 的,分为了 server 和 local 两部分。这样做缺点很明显——麻烦,不仅写代码麻烦,编译也麻烦,运行更麻烦。
于是,我把这两部分利用 cli 合到了一起。这样可以一个软件同时担任 client 和 server 的角色,还可以加入其它功能,比如生成证书,打开官网之类的~
伪装混淆
众所周知,TLS 是个十分安全的协议,可以保护数据不被 ISP 或者 GFW 获取到,这是选择 HTTPS 作为底层协议的原因。但是 TLS 在 Client Hello 阶段是明文的,server name 会作为明文发给服务端,这样就会暴露要访问的域名。但我们也可以利用这个特性达到伪装的目的。
来抓包对比一下。首先可以看到在伪装前,即使是启用了 TLS,访问的主机名依然可以被检测到:
而通过设置 TlsConfig.ServerName 可以达到伪装的目的:
WebSocket
一开始用的 WebSocket 包是官方包,虽然简单方便,但是总有些问题,比如套上 CF 就用不了(其实可能是别的原因)。
后来看了很多其它 go 写的代理工具比如v2ray与gost,基本上用的都是用的第三方库,甚至 go 官方推荐用它,我也选择换成了github.com/gorilla/websocket这个库:
from https://halu.lu/%E7%AC%94%E8%AE%B0/websocks-%E5%BC%80%E5%8F%91%E8%AE%B0%E5%BD%95/
No comments:
Post a Comment