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
指定此次请求升级到 websocket
Sec-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.service
cat /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-lzjluzijie
systemctl 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