假设你的防火墙管理员允许透明 TCP 连接到某台服务器机器的某个端口(无论是标准的 SSH 端口 22,还是备用目标端口,如 HTTP 端口 80 或其他端口),或者你设法将防火墙一侧的某个端口重定向到另一侧的端口(使用 httptunnel、mailtunnel、通过 telnet 的某些隧道,或其他方式)。
然后,你可以在服务器端端口上运行 sshd,并在客户端端口上使用 ssh 连接到它。在 ssh 连接的两端,你运行 IP 模拟器(pppd),这样你就拥有了 VPN,即虚拟公共网络,它可以绕过愚蠢的防火墙限制,并额外提供加密以保护隐私(注意:防火墙管理员仍然知道隧道的另一端,以及你在运行 ssh 之前可能发送的任何身份验证信息)。
相同的技术可以用于构建 VPN,即虚拟专用网络,从而将物理站点安全地连接到一个逻辑网络中,而不会牺牲站点之间传输网络的安全。
以下是一个示例脚本,供你根据自己的需求进行调整。它使用了 zsh 的数组功能,但你可以轻松地将其调整为你喜欢的 shell。使用 ssh 的 -p 选项来尝试端口 22 以外的其他端口(但请务必在同一端口上运行 sshd)。
请注意,该脚本假定 ssh 可以登录,而无需你交互式地键入密码(实际上,它的控制 tty 将连接到 pppd,因此如果它要求输入密码,你将失败)。这可以通过你的˜/.ssh/authorized_keys中的 ssh 密钥来完成,这些密钥要么不需要密码,要么你可以使用 ssh-agent 或 ssh-askpass 解锁。请参阅你的 SSH 文档。实际上,你也可以使用 chat 脚本输入密码,但这绝对不是正确的方法。
如果你不是服务器端的 root 用户,或者只是想屏蔽客户端网络的出站连接,你可以使用 slirp 而不是 pppd 作为服务器的 PPP 模拟器。只需取消注释相关行即可。
#!/bin/zsh -f SERVER_ACCOUNT=root@server.fqdn.tld SERVER_PPPD="pppd ipcp-accept-local ipcp-accept-remote" #SERVER_PPPD="pppd" ### This usually suffices if it's in /usr/sbin/ #SERVER_PPPD="/home/joekluser/bin/slirp ppp" CLIENT_PPPD=( pppd silent 10.0.2.15:10.0.2.2 ### For debugging purposes, you may uncomment the following: # updetach debug ### Another potentially useful option (see section on Routing): # defaultroute ) $CLIENT_PPPD pty "ssh -t $SERVER_ACCOUNT $SERVER_PPPD" |
请注意,来自你的/etc/ppp/options或˜/.slirprc的默认选项可能会破坏此脚本,因此请从中删除任何不需要的选项。
另请注意,10.0.2.2是 slirp 的默认设置,可能适合也可能不适合你的特定设置。在任何情况下,你都应该最有可能使用 RFC 1918 为私有网络保留的范围内的某个地址10.0.0.0/8, 172.16.0.0/12或192.168.0.0/16。受防火墙保护的 LAN 可能已经在使用其中的一些地址,避免冲突是你的责任。有关更多自定义设置,请阅读相应的文档。
如果你的客户端 pppd 较旧或非 Linux(例如 BSD)且没有 pty 选项,请使用
cotty -d -- $CLIENT_PPPD -- ssh -t $SERVER_ACCOUNT $SERVER_PPPD |
自动重新连接留给读者作为练习(提示:pppd 的 nodetach 选项可能对此有所帮助)。