一个关于 iptables 的问题

2019-09-16 05:19:44 +08:00
 KasuganoSoras

最近在研究用 OpenVPN + iptables 实现内网穿透,比传统 Frp 内网穿透有一个好处就是可以转发访客真实 IP,但是目前遇到一个问题,如何让 OpenVPN 客户端以非全局模式连接?目前内网穿透测试过已经没有问题,但是客户端的所有流量也会经过服务器,我的想法是让客户端只用于内网穿透,而不是代理上网。

环境信息

OpenVPN 服务器配置

port 1194
proto udp
dev tun
sndbuf 0
rcvbuf 0
ca ca.crt
cert server.crt
key server.key
dh dh.pem
auth SHA512
tls-auth ta.key 0
topology subnet
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 114.114.114.114"
push "dhcp-option DNS 223.5.5.5"
push "dhcp-option DNS 223.6.6.6"
keepalive 10 120
cipher AES-256-CBC
user openvpn
group openvpn
persist-key
persist-tun
status openvpn-status.log
log openvpn-tc.log
verb 3
crl-verify crl.pem
client-config-dir /etc/openvpn/server/clients/
script-security 2
down-pre
up /etc/openvpn/server/tc.sh
down /etc/openvpn/server/tc.sh
client-connect /etc/openvpn/server/tc.sh
client-disconnect /etc/openvpn/server/tc.sh

尝试过的操作

服务器上 iptables 配置:

iptables -t nat -A PREROUTING -d 123.123.123.123 -p tcp --dport 1:1023 -j DNAT --to-destination 10.8.0.181
iptables -t nat -A PREROUTING -d 123.123.123.123 -p udp --dport 1:1023 -j DNAT --to-destination 10.8.0.181

以上这个配置,内网穿透正常,可以转发真实 IP,但是客户端所有流量都会经过服务器。

然后经过我一晚上摸索,做了以下尝试:

注释掉 OpenVPN 服务器的这一行配置:

push "redirect-gateway def1 bypass-dhcp"

在服务器配置中增加一行:

push "route 10.0.0.0 255.0.0.0"

重新启动 OpenVPN 服务器和客户端,在客户端本地 curl 了一下 ip138,发现 IP 地址不再是服务器的 IP 了,也就说明此时是以非全局模式在运行的。

但是接着又遇到个问题,我发现内网穿透无法连接了,经过 tcpdump 抓包发现数据包已经到达了客户端主机,但是在返回的时候出不去,于是又照着网上教程在服务器上加了一个 iptables 规则:

iptables -t nat -A POSTROUTING -d 10.8.0.0/24 -j SNAT --to 10.8.0.1

加入这个规则后,内网穿透正常了,但是不能转发真实 IP,显示的访客 IP 都是来自 10.8.0.1 也就是 OpenVPN 的网关 IP。

有没有大佬知道如何解决这个问题?谢谢!

4966 次点击
所在节点    问与答
29 条回复
neroxps
2019-09-16 15:33:31 +08:00
@gowa #20 一般 OPENVPN 都是 Route 模式,不需要 nat,要 nat 是因为双方内网地址是一样的情况下才需要配置 NAT 做地址转换,防止干扰出口。
neroxps
2019-09-16 15:45:46 +08:00
楼主的问题感觉搞错方向,和 iptables 半毛钱关系都没有,楼主要的其实就是内网一台 openvpn 服务器提供 VPN 服务,然后让其访问内外的服务器而已。

如果 openvpn 不是在内网默认路由上做的,那么需要在内网网关上加一个路由条目,告诉内网的所有服务器 VPN 的网络地址的网关是谁。

例如 (这里假设 A 的内网地址是 192.168.2.x 网段,防止与 ovpn 环境内网冲突)外网 A 通过 openvpn 客户端访问 内网服务器 B,内外网关是 192.168.1.1,内网服务器是 192.168.1.2 内网 openvpn 服务器是 192.168.1.3 ovpn 地址池 10.10.10.0-254

那么流量是这样的,首先 A 的 openvpn 连接上,配置文件上写上 `route 192.168.1.0 255.255.255.0` ,此时 ovpn 客户端连接成功后,会自动在客户端系统上添加一条路由条目

**目的地址 192.168.1.0 网关是 ovpn 的服务器地址 10.10.10.1。**
A 客户端的接口也多了一个地址
**10.10.10.2 255.255.255.0**

本地默认网关不变,依然 A 的内网 DHCP 默认网关。

然后访问 192.168.1.2 内网服务器,发现网络不可达,因为数据包是先从 A ( 10.10.10.2 ) → ovpn ( 10.10.10.1 ) → B ( 192.168.1.2 ),B 是收到包了,但是他根本不知道 OVPN 10.10.10.x 段到底怎么去,所以他发给默认路由 192.168.1.1.但是 192.168.1.1 也不知道 10.10.10.x 的段到底怎么去,而且 10 开头也不是公网地址,所以网关把包丢弃了。

故此,解决这个问题只需要在 B 服务器的网关路由上设置一个路由条目
**目标网络 10.10.10.0 掩码 255.255.255.0 下一跳地址 192.168.1.3**

这样网络就通了。
neroxps
2019-09-16 15:47:07 +08:00
楼主的 ovpn 服务器虚拟地址池不应该设成内网 ip 一样,因为 ovpn 本质上是新建了一个 bridge 二层不通。
KasuganoSoras
2019-09-16 18:11:14 +08:00
@neroxps #22 不是的,OpenVPN 服务端是搭建在一台拥有公网 IP 的服务器,然后客户端是运行在一个没有公网的家用电脑上,目的就是使用 VPN 将客户端电脑的某些端口映射到服务器端(也就和传统的端口映射一个原理,但是用的是 VPN 协议)。

如果删掉了 0.0.0.0/1 via 10.8.0.1 这条规则,客户端就不再是全局模式了,同时服务器和客户端也能正常通信,但是外部访问者的数据包路线就变成这样了:

(假设)访问者 11.22.33.44 》 OpenVPN 服务器的公网 IP ( 123.123.123.123 ) 》 通过 PREROUTING 转发给 OpenVPN 客户端 10.8.0.181 》 OpenVPN 客户端收到并处理请求 》 尝试返回数据包到源地址( 11.22.33.44 )》 缺失 0.0.0.0/1 路由规则(被删掉了)》 网络不可达(数据包只能接收无法返回)

而如果把 0.0.0.0/1 via 10.8.0.1 这条规则加回去,就会让客户端本机的所有数据包走 OpenVPN 转发,那么又会回到问题的起点。唯一解决这个死循环的办法就是在服务器上添加个 POSTROUTING 规则,但那样又会让访问者的 IP 全部被 SNAT 转换为网关的 IP。

除非有办法在客户端识别出某个数据包是来自哪个网卡设备的(比如 OpenVPN 的 tun0 ),然后在返回的时候让它走指定的网关再回去才可能实现,但是我谷歌找了很久也没有找到相关的内容……😓
neroxps
2019-09-16 18:18:32 +08:00
你意思是你公网搭建了一个 ovpn 服务器,然后两个没有公网 IP 的客户端都连上去,实现互通??

>>(假设)访问者 11.22.33.44 》 OpenVPN 服务器的公网 IP ( 123.123.123.123 ) 》 通过 PREROUTING 转发给 OpenVPN 客户端 10.8.0.181 》 OpenVPN 客户端收到并处理请求 》 尝试返回数据包到源地址( 11.22.33.44 )》 缺失 0.0.0.0/1 路由规则(被删掉了)》 网络不可达(数据包只能接收无法返回)

那么你这个 ovpn 服务器当你连接起来之后,就是由三个网络。
1. A 客户端本地网络 192.168.2.0 ovpn 地址池 IP 10.10.10.1
2. B 客户端本地网络 192.168.1.0 ovpn 地址池 IP 10.10.10.2
3. ovpn 服务器地址池网络 10.10.10.0

理论上 你 A 访问 B 只需要访问 10.10.10.2 即可。应该是通的啊。你不应该访问 B 的局域网地址。因为 B 的局域网地址是不可达的。
XiaoxiaoPu
2019-09-16 18:33:02 +08:00
huangya 的思路是对的,楼主可以把你尝试的配置具体发一下,看看是哪里有问题了
KasuganoSoras
2019-09-16 18:35:14 +08:00
@neroxps #25 不是互通,https://zerohosts.com/cart.php?gid=14 其实就是这个(

用 OpenVPN 实现内网穿透,把 A 客户端的 1000-1100 端口映射到服务器的 1001-1100,然后 B 客户端的 1101-1200 映射到服务器的 1101-1200,C 继续分配下 100 个端口,到大概就是这样一个操作。

客户端数量是不定的,随时可能会增加。而且有个问题,如果配置过于复杂,可能有些小白用户不会用……如果想让普通用户去配置什么路由规则,那样难度是 ++++

所以考虑众多因素后还是放弃了 x
KasuganoSoras
2019-09-16 18:38:57 +08:00
@XiaoxiaoPu #26 你这么一说我倒是发现了一个地方有问题,那就是复制
echo 1 openvpn-tun >>/etc/iproute2/rt_tables
这一行的时候好像 1 和 openvpn-tun 连一块了,变成了 1openvpn-tun,我感觉是这个问题。。。
我再去试一下
RodHamlet
313 天前
@KasuganoSoras 大佬,有搞定 openvpn 非全局连内网和内网能显示 VPN 客户端真实 IP 了吗?前者我是用 iptables 实现了,但是后者就犯难了!不改显示的全是 openvpn 服务器的 IP ,改了客户端又不能正常连内网其他 IP !

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/601016

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX