摘要
在通常情况下, 当我们访问公网时, 都会处于某种防火墙或代理之后。它们的目的是限制使用者只能使用某些特定类型的协议,并只能访问网络中的一部分内容。如今,使用最广泛的协议是HTTP协议, 且只能在被第三方设备允许的前提下正常使用。
Wstunnel是一款使用Rust语言编写的开源隧道程序, 稳定且强大。该工具使用与http兼容的websocket协议来绕过防火墙和代理。Wstunnel允许使用者在创建的隧道中传输任何流量, 并访问所需的任何资源或网站。
Wstunnel功能
Wstunnel功能特点包含以下几方面:
(1). 使用便捷, 具备良好的错误信息和调试信息。
(2). 支持静态正向和反向隧道, 包括: TCP、UDP、Unix套接字、Stdio。
(3). 支持动态隧道, 包括: TCP、UDP Socks5代理和透明代理。
(4). 支持HTTP代理及代理协议。
(5). 支持tls/https服务器, 并支持证书自动重新加载。(包括带有嵌入的自签名证书或自己的证书)
(6). 支持mTLS, 并支持证书自动重新加载。
(7). 支持IPv6。
(8). 支持Websocket和HTTP2传输协议。(Websocket性能更好)
(9). 具备独立的二进制程序文件, 只需复制到目标位置运行即可。
开源地址: https://github.com/erebe/wstunnel
Wstunnel安装
首先需要安装Rust环境: https://www.rust-lang.org/tools/install , 或者直接使用以下命令安装环境:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
接着clone项目到本地, 并在项目根目录下通过以下命令编译执行:
cargo build
target/debug/wstunnel ...
Wstunnel简单使用
完成后, 在远程主机上, 通过在终端输入以下命令来启动wstunnel服务器:
wstunnel server wss://[::]:8080
这将创建一个在8080端口监听的websocket服务器。在客户端,使用以下命令通过 websocket 隧道转发流量:
wstunnel client -L socks5://127.0.0.1:8888 --connection-min-idle 5 wss://myRemoteHost:8080
该命令将创建一个在本地 8888 端口上监听的 socks5 服务器,并将动态转发流量。connection-min-idle 10
将进行优化以创建一个连接到服务器的 10 个连接池,以加快新隧道的建立。
在浏览器中, 可以通过此隧道设置代理, 只需在网络首选项中设置127.0.0.1:8888并选择socks5代理。也可以使用以下命令达到同等效果:
curl -x socks5h://127.0.0.1:8888 http://google.com/
作为SSH代理命令使用
如果希望使用wstunnel作为ssh代理命令的一部分,可以在客户端指定源端口,命令如下:
ssh -o ProxyCommand="wstunnel client --log-lvl=off -L stdio://%h:%p ws://myRemoteHost:8080" my-server
绕过公司代理
当需要绕过公司的http代理时, 最可靠的方法是使用wstunnel, 以下命令启动wstunnel服务器并激活tls:
wstunnel server wss://[::]:443 --restrict-to 127.0.0.1:22
服务器将使用监听443(https)端口,并限制流量仅转发到 ssh 守护程序。
注意: 服务器将使用弱加密算法的自签名证书。这样做是为了兼容 TLS 的同时尽可能减少开销。不要依赖 wstunnel 来保护自己的隐私,而是只转发安全的流量(如:https 或 vpn 流量)
下面启动客户端:
wstunnel client -L tcp://9999:127.0.0.1:22 -p http://mycorporateproxy:8080 wss://myRemoteHost:443
它将在端口 9999 上启动一个 tcp 服务器,该服务器将联系公司代理,与远程主机协商 tls 连接,并将流量转发到远程主机上的 ssh 守护程序。现在便可以使用ssh 从本地计算机访问服务器:
ssh -p 9999 login@127.0.0.1
透明代理(仅限Linux)
透明代理可以轻松代理任何程序。使用以下命令启动 wstunnel:
sudo wstunnel client -L 'tproxy+tcp://1080' -L 'tproxy+udp://1080' wss://my.server.com:443
使用该项目无缝路由流量:https://github.com/NOBLES5E/cproxy , 它适用于任何程序:
cproxy --port 1080 --mode tproxy -- curl https://google.com
甚至可以启动一个新的 shell,所有命令都将被代理:
cproxy --port 1080 --mode tproxy -- bash
反向隧道
使用以下命令启动 wstunnel:
sudo wstunnel client -R 'tcp://[::]:8000:localhost:8000' wss://my.server.com:443
在另一个终端中,在本地机器上启动一个简单的网络服务器:
python3 -m http.server
现在可以从 my.server.com 机器/网络执行此操作:
curl http://localhost:8000
保护wstunnel 服务器的访问安全
假如生成了一个密钥:h3GywpDrP6gJEdZ6xbJbZZVFmvFZDCa4KcRd
现在使用以下命令启动服务器:
wstunnel server --restrict-http-upgrade-path-prefix h3GywpDrP6gJEdZ6xbJbZZVFmvFZDCa4KcRd wss://[::]:443
并开始使用:
wstunnel client --http-upgrade-path-prefix h3GywpDrP6gJEdZ6xbJbZZVFmvFZDCa4KcRd ... wss://myRemoteHost
现在,wstunnel 服务器只有在客户端在升级请求期间指定正确的路径前缀时才会接受连接。
如果需要更多自定义,可以使用配置文件来指定特定规则。限制规则示例如下:
# Restrictions are whitelist rules for the tunnels
# By default, all requests are denied and only if a restriction match, the request is allowed
restrictions:
- name: "Allow all"
description: "This restriction allows all requests"
# This restriction apply only and only if all matchers match/are evaluated to true
# It is a logical AND
match:
# This match apply only if it succeeds to match the path prefix with the given regex
# The regex does a match, so if you want to match exactly you need to bound the pattern with ^ $
# I.e: "tesotron" is going to match "XXXtesotronXXX", but "^tesotron$" is going to match only "tesotron"
- !PathPrefix "^.*$"
# The only other possible match type for now is !Any, that match everything/any request
# - !Any
# This is the list of tunnels your restriction is going to allow
# The list is checked in order, the first match is going to allow the request
allow:
# !Tunnel allows forward tunnels
- !Tunnel
# Protocol that are allowed. Empty list means all protocols are allowed
# Logical OR
protocol:
- Tcp
- Udp
# Port that are allowed. Can be a single port or an inclusive range (i.e. 80..90)
# Logical OR
port:
- 80
- 443
- 8080..8089
# if the tunnel wants to connect to a specific host, this regex must match
host: ^.*$
# if the tunnel wants to connect to a specific IP, it must be included in one of the network cidr
# Logical OR
cidr:
- 0.0.0.0/0
- ::/0
# !ReverseTunnel allows reverse tunnels
# Not specifying anything means all reverse tunnels are allowed
- !ReverseTunnel
protocol:
- Tcp
- Udp
- Socks5
- Unix
port:
- 1..65535
# Maps ports on the server side from X to Y (X:Y). For example with 10001:8080 configured and a client
# which connects using '-R tcp://10001:localhost:80' the server will listen on port 8080 instead of 10001.
# The originally requested ports (NOT the mapped ports) need to be allowed via the 'ports' directive.
port_mapping:
- 10001:8080
cidr:
- 0.0.0.0/0
- ::/0
---
# Examples
restrictions:
- name: "example 1"
description: "Only allow forward tunnels to port 443 and forbid reverse tunnels"
match:
- !PathPrefix "^.*$"
allow:
- !Tunnel
port:
- 443
---
restrictions:
- name: "example 2"
description: "Only allow forward tunnels to local ssh and forbid reverse tunnels"
match:
- !PathPrefix "^.*$"
allow:
- !Tunnel
protocol:
- Tcp
port:
- 22
host: ^localhost$
cidr:
- 127.0.0.1/32
---
restrictions:
- name: "example 3"
description: "Only allow socks5 reverse tunnels listening on port between 1080..1443 on lan network"
match:
- !PathPrefix "^.*$"
allow:
- !ReverseTunnel
protocol:
- Socks5
port:
- 1080..1443
cidr:
- 192.168.0.0/16
---
restrictions:
- name: "example 4"
description: "Allow everything for client using path prefix my-super-secret-path"
match:
- !PathPrefix "^my-super-secret-path$"
allow:
- !Tunnel
- !ReverseTunnel
---
restrictions:
- name: "example 5"
description: "Forbid everything ..."
match:
- !Any
allow: []
使用HTTP2 代替 websocket 作为传输协议
仅当防火墙/代理阻止 websocket 时才使用此选项。否则,它的性能不如 websocket。
像往常一样启动 wstunnel 服务器:
wstunnel server wss://[::]:8080
在客户端上,唯一的区别是指定 https:// 而不是 wss://
wstunnel client -L socks5://127.0.0.1:8888 https://myRemoteHost:8080
警告:
HTTP2 作为传输协议更难正常工作,因为:
如果使用(反向)代理/CDN,它们可能会缓冲整个请求,然后再将其转发到服务器。Cloudflare 就是这样做的,显然,这对于隧道流量不起作用
如果在反向代理后面有 wstunnel,那么大多数(即 nginx)都会将 http2 请求转换为 http1。这是行不通的,因为http1本身不支持流式传输
使其与 HTTP2兼容的唯一方法是将wstunnel服务器直接暴露在互联网上,而不需要在其前面使用任何反向代理。
此外,你可能还想使用请求标头(即内容长度和内容类型),使其看起来像正常流量,以绕过防火墙/代理。某些防火墙可能不喜欢看到未设置内容长度的请求,或将内容类型设置为 application/octet-stream
如何最大程度提高隐蔽性
使用已激活 TLS 的 wstunnel(wss://)并使用自己的证书
嵌入式证书是自签名的,对每个人都一样,因此可以轻松进行指纹识别/标记
使用有效证书(例如:使用 Let's Encrypt),自签名证书是可疑的
使用自定义 http 路径前缀(参见--http-upgrade-path-prefix
选项)
为了避免与其他 wstunnel 用户拥有相同的 URL
将tls-sni-override 更改为已知允许的域(即:google.com、baidu.com 等...)
如果wstunnel服务器位于反向代理后面(即:Nginx、Cloudflare、HAProxy 等),则此方法将不起作用。
点个在看你最好看
东 WHAT HAPPENED IN MAY 西