一个关于 iptables 的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
KasuganoSoras
V2EX    问与答

一个关于 iptables 的问题

  •  
  •   KasuganoSoras 2019-09-16 05:19:44 +08:00 5442 次点击
    这是一个创建于 2268 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    环境信息

    • OpenVPN 网段:10.8.0.0/24
    • OpenVPN 客户端 IP:10.8.0.181
    • OpenVPN 网关:10.8.0.1
    • 服务器外网 IP: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。

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

    第 1 条附言    2019-09-16 06:00:51 +08:00

    补充:在 OpenVPN 客户端以全局模式启动的时候我看到它执行了一个这个:

    ip route add 0.0.0.0/1 via 10.8.0.1 

    此时内网穿透可以转发真实 IP,但是客户端所有流量都走服务器。

    于是我试了下在客户端删除掉这条规则:

    ip route del 0.0.0.0/1 

    此时就不再是全局模式了,但是内网穿透也连不上了。

    摸不着头脑.jpg

    第 2 条附言    2019-09-16 07:59:04 +08:00

    研究了一晚上,到现在还没睡,实在想不到其他方法了……

    img

    29 条回复    2023-12-30 19:30:21 +08:00
    hangvane
        1
    hangvane  
       2019-09-16 08:12:24 +08:00   1
    同一个世界,同一个问题,我也遇到过了最后选择 frp t/580901
    huangya
        2
    huangya  
       2019-09-16 08:23:42 +08:00 via iPhone
    请再详细描述一下你的内网穿透是什么意思。你最终的应用场景是什么
    KasuganoSoras
        3
    KasuganoSoras  
    OP
       2019-09-16 08:25:29 +08:00
    @hangvane #1 hhh 我就是做 Frp 的,因为苦于 Frp 不能转发访客真实 IP 所以想试试用 OpenVPN,结果又遇到了你遇到过的问题......
    KasuganoSoras
        4
    KasuganoSoras  
    OP
       2019-09-16 08:27:13 +08:00
    @huangya #2 就是和 Frp 一样的用法,只不过是想借助 VPN 协议可以转发访问者 IP 的特性(用 Frp 转发后的访问者 IP 全都是 127.0.0.1,目的就是解决这个问题),最终用途还是将内网的服务通过 VPN 暴露到公网。
    KasuganoSoras
        5
    KasuganoSoras  
    OP
       2019-09-16 08:29:05 +08:00
    目前遇到的技术难题就是,如何让 VPN 只作为内网穿透使用,而不是所有流量都经过服务器代理,同时还要能够转发访问者的真实 IP,这就是 1 楼之前遇到过的问题,没想到我又踩坑了。
    yibei
        6
    yibei  
       2019-09-16 08:41:45 +08:00 via iPhone
    @KasuganoSoras 这种只能对特定的端口进行转发才能实现吧
    paradislover
        7
    paradislover  
       2019-09-16 08:45:28 +08:00 via Android
    不推送网关,推送 route,客户端 iroute
    xduanx
        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"
    KasuganoSoras
        9
    KasuganoSoras  
    OP
       2019-09-16 09:04:19 +08:00
    @paradislover #7 能具体说一下如何操作吗?看了下谷歌找的文档,不太理解这个 iroute 怎么用
    KasuganoSoras
        10
    KasuganoSoras  
    OP
       2019-09-16 09:05:13 +08:00
    @xduanx #8 客户端 tcpdump 看到的是访问者的源 IP
    zbinlin
        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` 呀
    KasuganoSoras
        12
    KasuganoSoras  
    OP
       2019-09-16 09:17:10 +08:00
    @zbinlin #11 我试了一下,还是之前的问题,OpenVPN 传递到客户端的 IP 地址是访客的源 IP,客户端这边由于没有了 0.0.0.0/1 这条规则,就没办法将数据包再传回给 VPN 网关,也就是上面说的数据只能进不能出的问题。
    huangya
        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
    huangya
        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
    wwqgtxx
        15
    wwqgtxx  
       2019-09-16 09:23:06 +08:00
    提个尝试性建议,把你的 server 绑定在 tun 端口上,强制其在 tun 端口上收发数据,这样应该就能不受数据只进不出的影响(其实只是数据出的时候没走 OVN 而是直接从网卡出去了,所以被外层丢包)
    KasuganoSoras
        16
    KasuganoSoras  
    OP
       2019-09-16 09:27:39 +08:00
    @huangya #13 感谢感谢,我去测试一下

    @wwqgtxx #15 好的,可以尝试一下
    Meltdown
        17
    Meltdown  
       2019-09-16 09:31:34 +08:00 via Android
    用 docker 或者虚拟机跑服务,docker 或者虚拟机连 openvpn…
    KasuganoSoras
        18
    KasuganoSoras  
    OP
       2019-09-16 10:00:58 +08:00
    经过了 N 次尝试均以失败告终……甚至还两次把机器搞断网
    算了,还是老实用全局模式吧……感谢各位提供的帮助,谢谢!
    acess
        19
    acess  
       2019-09-16 12:06:54 +08:00
    这个就是路由表里默认网关的问题吧……
    gowa
        20
    gowa  
       2019-09-16 12:14:04 +08:00 via Android
    楼主我有个疑问。vpn 你确定你是用的 隧道形式 还是 nat 形式。在 nat 形式 是在网络层 转发 你怎么可能获取真实 ip。 只有在隧道形式 对原始报文进行包裹的才可以
    neroxps
        21
    neroxps  
       2019-09-16 15:33:31 +08:00
    @gowa #20 一般 OPENVPN 都是 Route 模式,不需要 nat,要 nat 是因为双方内网地址是一样的情况下才需要配置 NAT 做地址转换,防止干扰出口。
    neroxps
        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**

    这样网络就通了。
    neroxps
        23
    neroxps  
       2019-09-16 15:47:07 +08:00
    楼主的 ovpn 服务器虚拟地址池不应该设成内网 ip 一样,因为 ovpn 本质上是新建了一个 bridge 二层不通。
    KasuganoSoras
        24
    KasuganoSoras  
    OP
       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 ) 》 通过 REROUTING 转发给 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
        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 的局域网地址是不可达的。
    XiaoxiaoPu
        26
    XiaoxiaoPu  
       2019-09-16 18:33:02 +08:00
    huangya 的思路是对的,楼主可以把你尝试的配置具体发一下,看看是哪里有问题了
    KasuganoSoras
        27
    KasuganoSoras  
    OP
       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
        28
    KasuganoSoras  
    OP
       2019-09-16 18:38:57 +08:00
    @XiaoxiaoPu #26 你这么一说我倒是发现了一个地方有问题,那就是复制
    echo 1 openvpn-tun >>/etc/iproute2/rt_tables
    这一行的时候好像 1 和 openvpn-tun 连一块了,变成了 1openvpn-tun,我感觉是这个问题。。。
    我再去试一下
    RodHamlet
        29
    RodHamlet  
       2023-12-30 19:30:21 +08:00
    @KasuganoSoras 大佬,有搞定 openvpn 非全局连内网和内网能显示 VPN 客户端真实 IP 了吗?前者我是用 iptables 实现了,但是后者就犯难了!不改显示的全是 openvpn 服务器的 IP ,改了客户端又不能正常连内网其他 IP !
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5280 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 113ms UTC 07:11 PVG 15:11 LAX 23:11 JFK 02:11
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86