10
20
2013
5

通过 OpenVPN 让 TCP 使用 UDP 洞

上篇成功让 mosh 走 UDP 洞,连接上了在 NAT 后边的主机。然而,很多有用的协议都是走 TCP 的,比如能传文件的 ssh、访问我的 MediaWiki 的 HTTP。TCP 洞难打,于是在想,OpenVPN 可以使用 UDP 协议,那么把双方用 OpenVPN 连起来,不是可以想用什么传输层的协议都可以了吗!于是,有了新的脚本

与 mosh 相比,打洞部分主要的不同有:

  1. OpenVPN 的可配置性强,不需要 hack 即可让它绑定到需要的端口。
  2. OpenVPN 本身使用证书认证,因此把证书部分保存在客户端,余下的部分(包含双方使用的 IP 地址和端口号)可以通过打好的洞明文发送,不用怕被攻击。所以跑我这个脚本的话,当前工作目录要可写,以便保存双方即将使用的配置文件。
  3. OpenVPN 客户端会自动忽略对方发过来它不认识的配置信息,不用想办法避免。
  4. OpenVPN 需要 root 权限,因此脚本调用了 sudo,需要及时输入密码

在实验过程中也遇到了一些坑:

  1. Python 里没办法将已连接的 UDP socket「断开连接」,即将一个已经connect的 UDP socket 恢复到初始时可接收任意地址数据的状态。原本以为connect(('0.0.0.0', 0))可以的,结果客户端这边始终收不到服务端发送的 OpenVPN 配置信息。Wireshark 抓包看到内核收到数据后发了 ICMP Port Unreachable 错误之后才明白过来。
  2. MTU 的问题。默认值会导致刚开始传输正常,但随后收不到数据的情况。添加mssfix 1400配置解决。(其实这个 OpenVPN man 手册里有写。)
  3. 超时的问题。先是没注意到 OpenVPN 服务端说没有配置keepalive的警告,结果连接空闲几分钟之后,「洞」就失效了。加上keepalive 10 60解决。

配置中没有加默认路由,所以连接上之后唯一的效果就是,两个主机分别多出了同一网段的两个 IP 地址,相互间可以进行 TCP 通信了~~

对了,客户端连接时需要一个包含 OpenVPN 证书信息的文件,其格式为:

<ca>
# ca.crt 文件内容
</ca>

<cert>
# crt 文件内容(只需要 BEGIN 和 END 标记的那部分)
</cert>

<key>
# key 文件内容
</key>

PS: 有这个想法后不久,发现 None 已经做过类似的事情了。不过脚本有点多,是使用第三方服务器而不是像我这样手工交换地址的。

Category: 网络 | Tags: python 网络 openvpn UDP

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com