最近在研究用 OpenVPN + iptables 实现内网穿透,比传统 Frp 内网穿透有一个好处就是可以转发访客真实 IP,但是目前遇到一个问题,如何让 OpenVPN 客户端以非全局模式连接?目前内网穿透测试过已经没有问题,但是客户端的所有流量也会经过服务器,我的想法是让客户端只用于内网穿透,而不是代理上网。
10.8.0.0/24
10.8.0.181
10.8.0.1
123.123.123.123
(假设)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。
有没有大佬知道如何解决这个问题?谢谢!
补充:在 OpenVPN 客户端以全局模式启动的时候我看到它执行了一个这个:
ip route add 0.0.0.0/1 via 10.8.0.1
此时内网穿透可以转发真实 IP,但是客户端所有流量都走服务器。
于是我试了下在客户端删除掉这条规则:
ip route del 0.0.0.0/1
此时就不再是全局模式了,但是内网穿透也连不上了。
摸不着头脑.jpg
研究了一晚上,到现在还没睡,实在想不到其他方法了……
1
hangvane 2019-09-16 08:12:24 +08:00 1
同一个世界,同一个问题,我也遇到过了最后选择 frp https://www.v2ex.com/t/580901
|
2
huangya 2019-09-16 08:23:42 +08:00 via iPhone
请再详细描述一下你的内网穿透是什么意思。你最终的应用场景是什么
|
3
KasuganoSoras OP @hangvane #1 hhh 我就是做 Frp 的,因为苦于 Frp 不能转发访客真实 IP 所以想试试用 OpenVPN,结果又遇到了你遇到过的问题......
|
4
KasuganoSoras OP @huangya #2 就是和 Frp 一样的用法,只不过是想借助 VPN 协议可以转发访问者 IP 的特性(用 Frp 转发后的访问者 IP 全都是 127.0.0.1,目的就是解决这个问题),最终用途还是将内网的服务通过 VPN 暴露到公网。
|
5
KasuganoSoras OP 目前遇到的技术难题就是,如何让 VPN 只作为内网穿透使用,而不是所有流量都经过服务器代理,同时还要能够转发访问者的真实 IP,这就是 1 楼之前遇到过的问题,没想到我又踩坑了。
|
6
yibei 2019-09-16 08:41:45 +08:00 via iPhone
@KasuganoSoras 这种只能对特定的端口进行转发才能实现吧
|
7
paradislover 2019-09-16 08:45:28 +08:00 via Android
不推送网关,推送 route,客户端 iroute
|
8
xduanx 2019-09-16 08:55:18 +08:00
客户端 tcpdump 的时候看到的源 IP 是什么
如果不在 10.0.0.0 255.0.0.0 这里面(比如 192.168.0.0/16 或者 172.16.0.0/12 ),那就 push "route XXXX XXXX" |
9
KasuganoSoras OP @paradislover #7 能具体说一下如何操作吗?看了下谷歌找的文档,不太理解这个 iroute 怎么用
|
10
KasuganoSoras OP @xduanx #8 客户端 tcpdump 看到的是访问者的源 IP
|
11
zbinlin 2019-09-16 09:08:00 +08:00
这是路由问题,你删除了 `ip route add 0.0.0.0/1 via 10.8.0.1` 就要加上 `ip route add 10.8.0.0/24 via 10.8.0.1` 呀
|
12
KasuganoSoras OP @zbinlin #11 我试了一下,还是之前的问题,OpenVPN 传递到客户端的 IP 地址是访客的源 IP,客户端这边由于没有了 0.0.0.0/1 这条规则,就没办法将数据包再传回给 VPN 网关,也就是上面说的数据只能进不能出的问题。
|
13
huangya 2019-09-16 09:21:03 +08:00
@KasuganoSoras 有看了下你的问题,基本弄清楚了需求。
>但是接着又遇到个问题,我发现内网穿透无法连接了,经过 tcpdump 抓包发现数据包已经到达了客户端主机,但是在返回的时候出不去,于是又照着网上教程在服务器上加了一个 iptables 规则: 前面步骤保留,在这里不要在服务器上添加 iptables 规则,建议在客户端上用策略路由。我写了一些没有验证过的命令,你可以在客户端试试看(用 root 权限执行),有什么问题可以后续交流。 iptables -t mangle -A OUTPUT -p udp -m udp --sport 1:1023 -j MARK --set-xmark 0x1/0xffffffff iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 1:1023 -j MARK --set-xmark 0x1/0xffffffff echo 1 openvpn-tun >>/etc/iproute2/rt_tables ip route add default via 192.168.5.1 dev tun0 table openvpn-tun ip rule add from all fwmark 0x1 lookup openvpn-tun |
14
huangya 2019-09-16 09:22:50 +08:00
@huangya
不好意思,有个命令 ip 写错了 ip route add default via 192.168.5.1 dev tun0 table openvpn-tun 改为 ip route add default via 10.8.0.1 dev tun0 table openvpn-tun |
15
wwqgtxx 2019-09-16 09:23:06 +08:00
提个尝试性建议,把你的 server 绑定在 tun 端口上,强制其在 tun 端口上收发数据,这样应该就能不受数据只进不出的影响(其实只是数据出的时候没走 OVN 而是直接从网卡出去了,所以被外层丢包)
|
16
KasuganoSoras OP |
17
Meltdown 2019-09-16 09:31:34 +08:00 via Android
用 docker 或者虚拟机跑服务,docker 或者虚拟机连 openvpn…
|
18
KasuganoSoras OP 经过了 N 次尝试均以失败告终……甚至还两次把机器搞断网 😓
算了,还是老实用全局模式吧……感谢各位提供的帮助,谢谢! |
19
acess 2019-09-16 12:06:54 +08:00
这个就是路由表里默认网关的问题吧……
|
20
gowa 2019-09-16 12:14:04 +08:00 via Android
楼主我有个疑问。vpn 你确定你是用的 隧道形式 还是 nat 形式。在 nat 形式 是在网络层 转发 你怎么可能获取真实 ip。 只有在隧道形式 对原始报文进行包裹的才可以
|
21
neroxps 2019-09-16 15:33:31 +08:00
@gowa #20 一般 OPENVPN 都是 Route 模式,不需要 nat,要 nat 是因为双方内网地址是一样的情况下才需要配置 NAT 做地址转换,防止干扰出口。
|
22
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** 这样网络就通了。 |
23
neroxps 2019-09-16 15:47:07 +08:00
楼主的 ovpn 服务器虚拟地址池不应该设成内网 ip 一样,因为 ovpn 本质上是新建了一个 bridge 二层不通。
|
24
KasuganoSoras OP @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 ),然后在返回的时候让它走指定的网关再回去才可能实现,但是我谷歌找了很久也没有找到相关的内容……😓 |
25
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 的局域网地址是不可达的。 |
26
XiaoxiaoPu 2019-09-16 18:33:02 +08:00
huangya 的思路是对的,楼主可以把你尝试的配置具体发一下,看看是哪里有问题了
|
27
KasuganoSoras OP @neroxps #25 不是互通,https://zerohosts.com/cart.php?gid=14 其实就是这个(
用 OpenVPN 实现内网穿透,把 A 客户端的 1000-1100 端口映射到服务器的 1001-1100,然后 B 客户端的 1101-1200 映射到服务器的 1101-1200,C 继续分配下 100 个端口,到大概就是这样一个操作。 客户端数量是不定的,随时可能会增加。而且有个问题,如果配置过于复杂,可能有些小白用户不会用……如果想让普通用户去配置什么路由规则,那样难度是 ++++ 所以考虑众多因素后还是放弃了 x |
28
KasuganoSoras OP @XiaoxiaoPu #26 你这么一说我倒是发现了一个地方有问题,那就是复制
echo 1 openvpn-tun >>/etc/iproute2/rt_tables 这一行的时候好像 1 和 openvpn-tun 连一块了,变成了 1openvpn-tun,我感觉是这个问题。。。 我再去试一下 |
29
RodHamlet 337 天前
@KasuganoSoras 大佬,有搞定 openvpn 非全局连内网和内网能显示 VPN 客户端真实 IP 了吗?前者我是用 iptables 实现了,但是后者就犯难了!不改显示的全是 openvpn 服务器的 IP ,改了客户端又不能正常连内网其他 IP !
|