标签 VPN 下的文章

正常的透明代理

  1. 工作在 L3 的 VPN
  2. tun2socks 
  3. Linux 内核的 TPROXY

曲折的透明代理

  1. 支持 UDP 的 SOCKS5 代理软件
  2. 用户空间的 WireGuard 服务端结合 SOCKS5 转发
  3. 安装了 WireGuard 模块的 OpenWRT 路由器

刚好也是三项,但这不是三个方案,是一个方案的三个组件。

听起来似乎完全没必要做这么复杂,但为了利用上唯一能刷 OpenWRT 的低配路由器、不干扰本就复杂的服务器路由,同时保障信道安全、可达,最终扭曲成了这样。

即使你没有这种特殊情况,或许也能用上某个组件就是了,例如在没有 root 的环境下提供 WireGuard 服务。

支持 UDP 的 SOCKS5 代理

这个相对好找,不过建议使用底层为 UDP 且保留了 UDP 不可靠传输特性的代理软件。否则发挥不了 UDP 的优势,性能上可能有负面影响。

用户空间的 WireGuard 服务端

服务端在一台单独的服务器上运行,建议配置成静态 IP。服务器可以通过 DMZ 或 VLAN 方式接入路由器 LAN 口,也可以接入上一层路由、通过 WAN 口通信。

我选择了开源的 Wiretap,好处是运行在用户空间不用动内核,坏处是性能会比原生网络栈差一些,但应该比虚拟机强。我对 Wiretap 进行了轻度的魔改以支持代理,但 ICMP 包的处理上还没完善。 https://github.com/l2dy/wiretap/tree/tproxy

别忘了在防火墙上放行对应的 UDP 端口,否则是连不上的(废话)。

OpenWRT 路由器

有条件的话买一个高配路由器安装上代理软件并配置 TPROXY 是最佳方案。

但如果你坚持使用低内存或闪存空间有限的低配路由器,WireGuard 是 OpenWRT 上最轻量的 VPN 方案之一了。由于 WireGuard 协议不具备混淆功能、特征过于明显,建议仅在本地使用。当然如果信道完全可信,也可以考虑 tun2socks 方案,省下加密的开销。

那么 DNS 怎么办呢?由于 LuCI 不支持给 WireGuard 接口配置 DNS,需要配置全局 DNS 并关闭从 DHCP 获取 DNS 的选项(设置 noresolv '1')。在 WireGuard 接口配置了 0.0.0.0/0 路由后,DNS 也会走 VPN。这个方案的前提是 SOCKS5 代理支持 UDP,但如果不支持的话也可以魔改服务端,把请求转发到本地的可信 DNS。

TCP 层由于 Wiretap 已经在用户空间 ACK 了相关的包,不会像远程 L3 VPN 那样出现 TCP meltdown。但为了 UDP 还是需要合理调整 MTU 值,否则底层可能会把 UDP 包拆分传输,也可能直接丢弃。

参考资料

首先由于 IPv6 VPN 服务器会转发 IPv6 包,需要用 sysctl 开启内核的 IPv6 转发。将以下内容配置到 /etc/sysctl.d 目录下一个 .conf 文件中,并用 sysctl -p xxx.conf 加载或重启服务器。

net.ipv6.conf.all.forwarding = 1

然后我们来安装 strongSwan。 dnf install epel-release 安装上 EPEL 源,然后 dnf install strongswan 就 OK 了。

strongSwan 现已支持 swanctl.conf 新格式的配置文件,文件路径在 /etc/strongswan/swanctl/swanctl.conf,密钥放在 /etc/strongswan/swanctl 对应目录下。下面给出一个示例配置,配置完成后可以通过 systemctl start strongswan.service 启动。

connections {
    ikev2-vpn {
        version=2
        remote_addrs=%any
        local_addrs=%any
        send_cert=always
        pools=pool-subnet-ipv6
        dpd_delay=300s
        children {
            ikev2-vpn {
                local_ts=::/0
                dpd_action=clear
            }

        }
        local-0 {
            certs = cert.pem
            id = @<domain>
        }
        remote-0 {
            auth = eap-mschapv2
            id = %any
        }
    }
}

pools {
    pool-subnet-ipv6 {
        addrs=xxx:8/125
        dns=2001:4860:4860::8888,2001:4860:4860::8844
    }
}

secrets {
    eap-user1 {
        id=user1
        secret="password"
    }
}

authorities {
}

P.S. 带有中间证书的证书文件需要拆分,strongSwan 只会读取证书文件里的第一个 PEM 证书。