我已经运行 SOHO 域多年,包括用于内部客户端的基于 Linux 的防火墙/网关和 SNAT,并在 WAN 上提供各种服务,其中包括端口转发 (DNAT)。防火墙具有用于 LAN (eth0) 和 WAN (eth1) 的以太网网卡。效果很好。
我想修改此设置,以通过 OpenVPN 隧道透明地将所有源自 LAN 的传出连接发送到充当 Internet 网关的 OpenVPN 服务器。 LAN 的内部 DNS 和 DHCP 服务器、文件服务器等应保持可供 LAN 客户端访问。网关在其静态 WAN IP 上提供的 WAN 服务应像以前一样保持可用。根据我迄今为止的研究,这种情况建议在防火墙上使用分割隧道 VPN,最好通过连接标记和策略路由来实现。网关将是一个 OpenVPN 客户端。
堆栈交换问题通过 OpenVPN 路由无线 LAN类似,但没有答案。针对这个特定问题的其他资源很少。
到目前为止,我还没有成功通过隧道从 LAN 客户端进行往返连接。到目前为止,我的最佳尝试(如下所述)显示了一些走出隧道的连接,以及返回的响应,但这些响应似乎没有路由到原始客户端。我尝试禁用反欺骗,但这并没有改变结果。
在我的研究中,我发现了关于 Linux 下的分割隧道 VPN 的精彩概述:https://www.htpcguides.com/force-torrent-traffic-vpn-split-tunnel-debian-8-ubuntu-16-04/,但其策略路由基于用户 ID,并且不涵盖 LAN 网关所需的附加功能。对于实施策略路由的细节,存在许多资源;包括这个在内的套装非常棒:http://security.maruhn.com/iptables-tutorial/x9125.html一个有价值的 iproute2“备忘单”是http://baturin.org/docs/iproute2。
现有设置
我现有的设置有一个简单的主路由表,如下所示(我的 ISP 在 /30 子网上提供静态 IP,网关的内部 IP 是 LAN 192.168.0.0/24 上的 192.168.0.1):
# ip route list all
default via <isp_gw_ip> dev eth1
<isp_subnet>/30 dev eth1 proto kernel scope link src <ext_ip>
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.1
本地表有 10 条本地和广播路由,此处未显示(这些路由很重要吗?)。
防火墙使用以下方式实现 SNAT:
iptables -t nat -A POSTROUTING -o eth1 \! -d 192.168.0.0/24 -s 192.168.0.0/24 -j SNAT —to-source <ext_ip>
所以这就是最简单的事情了。
计划
我认为需要做的是:
标记稍后将进行 SNAT 的连接的所有数据包。将它们标记
PREROUTING
为转发连接和OUTPUT
网关发起的连接通过以下方式路由标记的数据包
tun0
:- 使用
tunnel
表使用ip rule add fwmark ... table tunnel
- 使用
设置网关和默认路由以
tun0
使用从 VPN 服务器接收的参数- 使用
ip route add ... table tunnel
- 该表的结构应与主表类似,但不需要 LAN 路由
- 使用
- 添加 SNAT
tun0
作为输出设备,并将tun0
的 IP 地址作为新的源 IP
这是正确的更改吗?
我已经走了多远
当我启动 OpenVPN 客户端时,连接已成功启动,并且客户端(网关)tun0
使用以下系统日志条目创建设备:
/sbin/ip addr add dev tun0 local 10.95.3.110 peer 10.95.3.109
tun0
设置后,OpenVPN 客户端将运行以下脚本(shell 变量$ifconfig_remote
包含 /30 隧道子网上的网关设备 IP 地址,$ifconfig_local
是 的 IP 地址tun0
,以及$dev
设备名称tun0
):
# Set packet mark on to-be-SNATed packet (first one only)
iptables -t nat -A PREROUTING -i eth0 \! --dst 192.168.0.0/24 --source 192.168.0.0/24 -j MARK --set-mark 99
# Save packet mark to connection on first packet
iptables -t nat -A PREROUTING -j CONNMARK --save-mark
# Restore connection mark to packets
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
# Same for locally-generated packets
iptables -t nat -A OUTPUT \! --dst 192.168.0.0/24 -j MARK --set-mark 99
iptables -t nat -A OUTPUT -j CONNMARK --save-mark
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
# SNAT for tun0
iptables -t nat -A POSTROUTING -o $dev \! -d 192.168.0.0/24 -s 192.168.0.0/24 -j SNAT --to-source $ifconfig_local
# Set default route for all marked packets to go out the VPN, governed by custom routing table
#
# First derive the network CIDR
network=`ipcalc $ifconfig_local/30 | grep ^Network: | awk ‘{print $2}’`
# Flush it first
ip route flush table tunnel
# Rule and routes
ip rule add fwmark 99 table tunnel
ip route add $network dev $dev table tunnel
ip route add default via $ifconfig_remote dev $dev table tunnel
# Flush route cache (unnecessary in recent kernels?)
ip route flush cache
OpenVPN 客户端报告初始化序列已完成,没有警告或错误。
结果
ifconfig
显示少量数据包通过 tun0(Tx 和 Rx)传输。 traceroute 4.2.2.2
来自网关的信息显示数据包仍然通过 eth1 从正常的 ISP 路径发出,因此基于OUTPUT
链的标记的策略路由可能不起作用。但ping 4.2.2.2
似乎表明只有第一个数据包返回;后续数据包不会返回。 LAN客户端根本无法连接外部;对外部 IP 地址执行 ping 操作会导致超时。
tcpdump -i tun0 -vvv
显示某些流量正在通过隧道,例如:
11:05:48.610910 IP (tos 0x0, ttl 63, id 14981, offset 0, flags [DF], proto ICMP (1), length 84)
10.95.3.110 > b.resolvers.Level3.net: ICMP echo request, id 13207, seq 29, length 64
11:05:48.623063 IP (tos 0x0, ttl 57, id 9307, offset 0, flags [none], proto ICMP (1), length 84)
b.resolvers.Level3.net > 10.95.3.110: ICMP echo reply, id 13207, seq 29, length 64
这意味着 ping 或跟踪路由似乎已成功通过隧道路由。但它可能不会返回到原始客户端?我还看到类似的 DNS 流量以及其他一些流量。
附加诊断信息
ip route list main
显示一条附加路由,涉及tun0
,已由 VPN 启动添加到main
表中,这样可以吗?
default via <isp_gw_ip> dev eth1
10.95.3.109 dev tun0 proto kernel scope link src 10.95.3.110
<isp_subnet>/30 dev eth1 proto kernel scope link src <ext_ip>
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.1
iptables -L -t mangle
节目
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
CONNMARK all -- anywhere anywhere CONNMARK restore
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
CONNMARK all -- anywhere anywhere CONNMARK restore
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
iptables -L -t nat
节目
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
NAT_PREROUTING_CHAIN all -- anywhere anywhere
POST_NAT_PREROUTING_CHAIN all -- anywhere anywhere
MARK all -- 192.168.0.0/24 !192.168.0.0/24 MARK set 0x63
CONNMARK all -- anywhere anywhere CONNMARK save
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
MARK all -- anywhere !192.168.0.0 MARK set 0x63
CONNMARK all -- anywhere anywhere CONNMARK save
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
TCPMSS tcp -- anywhere anywhere tcp flags:SYN,RST/SYN TCPMSS clamp to PMTU
NAT_POSTROUTING_CHAIN all -- anywhere anywhere
SNAT all -- 192.168.0.0/24 !192.168.0.0/24 to:<ext_ip>
POST_NAT_POSTROUTING_CHAIN all -- anywhere anywhere
SNAT all -- 192.168.0.0/24 !192.168.0.0/24 to:10.95.3.110
Chain NAT_POSTROUTING_CHAIN (1 references)
target prot opt source destination
Chain NAT_PREROUTING_CHAIN (1 references)
target prot opt source destination
Chain POST_NAT_POSTROUTING_CHAIN (1 references)
target prot opt source destination
Chain POST_NAT_PREROUTING_CHAIN (1 references)
target prot opt source destination
route-noexec
我正在禁用 OpenVPN 服务器在 OpenVPN 配置文件中使用的推送到网关的默认路由。