Linux下路由配置的疑惑

80 views
Skip to first unread message

Yifan Gao

unread,
Jun 13, 2014, 11:00:04 AM6/13/14
to ustc...@googlegroups.com

刚才在Debian上配置openvpn客户端(以下称为A主机),发现连接LUG-vpn后,本地地址就无法从外网访问了。

因此,我将openvpn自动添加的0.0.0.0/1路由规则修改为了默认规则

ip route delete 0.0.0.0/1
route add default gw 10.7.0.1 tun0

此时发现,外网地址已经可以从公网访问,但却无法从vpn内部的网关访问。即:某主机B直接接入公网,可以连接A主机的公网地址;但若某主机C连接了vpn,则无法连接A主机的公网地址(当然,通过LUG-vpn的内网地址10.7.0.24是可以访问的)。

请问这是什么原因引起的呢?

附1 ip route:

default via 10.7.0.1 dev tun0
default via 222.195.93.254 dev eth0
10.7.0.0/16 dev tun0  proto kernel  scope link  src 10.7.0.24
128.0.0.0/1 via 10.7.0.1 dev tun0
192.168.13.0/24 dev eth1  proto kernel  scope link  src 192.168.13.3
202.141.176.99 via 222.195.93.254 dev eth0
222.195.92.0/23 dev eth0  proto kernel  scope link  src 222.195.92.141

附2 ifconfig tun0:

tun0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          inet addr:10.7.0.24  P-t-P:10.7.0.24  Mask:255.255.0.0
          inet6 addr: 2001:da8:d800:f001:176:99:1:16/64 Scope:Global
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:2571569 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1001570 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          RX bytes:2515353771 (2.3 GiB)  TX bytes:175492710 (167.3 MiB)

附3 uname -a:

Linux 1415-linux 3.2.0-4-amd64 #1 SMP Debian 3.2.57-3+deb7u2 x86_64 GNU/Linux

附4 openvpn --version:

OpenVPN 2.2.1 x86_64-linux-gnu [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] [MH] [PF_INET6] [IPv6 payload 20110424-2 (2.2RC2)] built on Jun 18 2013
Originally developed by James Yonan
Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sa...@openvpn.net>

  $ ./configure --build=x86_64-linux-gnu --prefix=/usr --includedir=${prefix}/include --mandir=${prefix}/share/man --infodir=${prefix}/share/info --sysconfdir=/etc --localstatedir=/var --libexecdir=${prefix}/lib/openvpn --disable-maintainer-mode --disable-dependency-tracking CFLAGS=-g -O2 -fPIE -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security CPPFLAGS=-D_FORTIFY_SOURCE=2 CXXFLAGS=-g -O2 -fPIE -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security FFLAGS=-g -O2 LDFLAGS=-fPIE -pie -Wl,-z,relro -Wl,-z,now --enable-password-save --host=x86_64-linux-gnu --build=x86_64-linux-gnu --prefix=/usr --mandir=${prefix}/share/man --with-ifconfig-path=/sbin/ifconfig --with-route-path=/sbin/route

Compile time defines:  ENABLE_CLIENT_SERVER ENABLE_DEBUG ENABLE_EUREPHIA ENABLE_FRAGMENT ENABLE_HTTP_PROXY ENABLE_MANAGEMENT ENABLE_MULTIHOME ENABLE_PASSWORD_SAVE ENABLE_PORT_SHARE ENABLE_SOCKS USE_CRYPTO USE_LIBDL USE_LZO USE_PF_INET6 USE_PKCS11 USE_SSL


-- 
Yifan Gao

Zhang Cheng

unread,
Jun 13, 2014, 11:09:17 AM6/13/14
to USTC LUG

参考boj的这篇文章:
https://boj.blog.ustc.edu.cn/index.php/2014/02/port-mapping-fallacies/

你拨了vpn之后相当于你链接了两个isp,配置路由需要借助fwmark来“修正”路由。

Cheng
(sent from a mobile device)

--
-- 来自USTC LUG
请使用gmail订阅,不要灌水。
更多信息more info:http://groups.google.com/group/ustc_lug?hl=en?hl=en

---
You received this message because you are subscribed to the Google Groups "USTC_LUG" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ustc_lug+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Yifan Gao

unread,
Jun 13, 2014, 12:41:59 PM6/13/14
to ustc...@googlegroups.com
请问有没有考虑ip层面的方法?如果考虑通用性,是否应该把tcp以外的协议都添加进nat表呢?

Zhang Cheng <steph...@gmail.com>于2014年6月13日星期五写道:
--
Yifan Gao(高一凡)

Allan Lu

unread,
Jun 13, 2014, 12:46:43 PM6/13/14
to ustc...@googlegroups.com
问题描述不够详细,需要ABC的IP。

Soli Deo gloria.

Allan Lu
Email: al...@ream.at
梦.:如此短暂: http://d.ream.at

Zhang Cheng

unread,
Jun 13, 2014, 1:00:48 PM6/13/14
to USTC LUG
增加fwmark的语句中,可以不用"-p tcp -m tcp"这个筛选条件,这样所有iptables能够识别连接状态的数据包都可以处理。
tcp的状态很好理解,udp本身无状态,CONNTRACK模块根据通信四元组来判断是否一个连接。
对于非tcp/udp的协议,比如gre协议等,CONNTRACK也会尽量去判断连接,主要就是看通信的元组(尽最大的effort,有多少信息可用就用多少,虽然会有误判,但漏判比较少)。


On Sat, Jun 14, 2014 at 12:41 AM, Yifan Gao <ylgao...@gmail.com> wrote:



--
Cheng,
Best Regards

Bojie Li

unread,
Jun 13, 2014, 1:21:45 PM6/13/14
to USTC_LUG
解决这个问题有两种办法,一种是基于流的(例如 TCP 连接),一种是基于 socket 协议中源 IP 的。如果没有特殊需求,后者不需要保存连接状态,更轻量级一些。前一种方案 @Zhang Cheng 已经说了。后一种方案是 ip rule,也就是 mirrors 三条线路用的方案。

这是一台机器的样例配置,在 202.38.70.0/24 网段配置了三个固定 IP。只要把公网 IP 加到这里就行,作用是根据数据包的源 IP 选路由。Linux 做路由的时候,会从 ip rule 里 preference 最低的表开始查起,一般是 local 表,也就是哪些 IP 是本地地址;如果查到就退出,不然就查下一张表,直到 main 表就是我们平时用 ip route 看到的表,这里面一般有 default route,也就不会继续向下查了。

这种方法对监听 0.0.0.0 的 TCP socket 能够工作的原因是,socket accept 之后,协议栈就记住了这个 TCP 连接两头的 IP 和端口号,因此如果是到公网 IP 的请求,其回复的源 IP 也会被置为公网 IP。对监听 0.0.0.0 的 UDP socket,基于 ip rule 的方法是不工作的,需要用基于流的有状态路由来实现。当然,建议你的 UDP 应用分别监听每个本地 IP 的 53 端口,而不是 0.0.0.0:53,bind9 就是分别监听的。

$ ip rule
0:      from all lookup local
32763:  from 202.38.70.181 lookup 1000
32764:  from 202.38.70.99 lookup 1000
32765:  from 202.38.70.159 lookup 1000
32766:  from all lookup main
32767:  from all lookup default

$ ip route show table 1000
default via 202.38.70.254 dev eth0

$ ip route
202.141.160.99 via 202.38.70.254 dev eth0
202.38.70.0/24 dev eth0  proto kernel  scope link  src 202.38.70.159
10.8.0.0/16 dev tun0  proto kernel  scope link  src 10.8.0.23
0.0.0.0/1 via 10.8.0.1 dev tun0
128.0.0.0/1 via 10.8.0.1 dev tun0
default via 202.38.70.254 dev eth0



--

Yifan Gao

unread,
Jun 13, 2014, 1:53:05 PM6/13/14
to ustc...@googlegroups.com
我很好奇windows是用什么办法实现的?如果把A主机换成Windows系统(我测试的是Server 2012 R2),连接openvpn后,无需任何配置,从公网、VPN内网均可连接A主机的公网地址,并且不区分协议(目前TCP/UDP/ICMP测试都没问题)。
-- 
Yifan Gao

开启 2014年6月14日 at 上午1:21:44, Bojie Li (boj...@gmail.com) 写:

Yifan Gao

unread,
Jun 13, 2014, 2:24:06 PM6/13/14
to ustc...@googlegroups.com
A
eth0 global ip
tun0 openvpn ip
B
eth0 global ip
C
eth0 global ip
tun0 openvpn ip

B和C只是泛指
如果需要具体ip 也可以贴给你。
-- 
Yifan Gao

开启 2014年6月14日 at 上午12:46:42, Allan Lu (al...@ream.at) 写:

Zhang Cheng

unread,
Jun 13, 2014, 2:43:05 PM6/13/14
to ustc...@googlegroups.com
两种方案,如果是网关的机器,只能用第一种,因为from地址跟路由没有直接关系。此外,基于连接的方法还有一个额外的好处,例如科大的网络通,假设我先ssh到公网到一台机器,然后修改网络通出口,这个连接就会断掉,因为路由变了,但如果针对连接加fwmark然后路由,修改出口是不会影响已经建立的连接的,已经建立的连接也就不会断了。

我家里的网关就使用了这个配置方法,所以有时候从同一个网站下东西时可以用满我两个ISP 出口。例如我要从mirrors.ustc下载两个ISO,我可以先开始下载第一个,然后修改出口路由,再下第二个,我就可以同时用两个出口下东西了。


--

Bojie Li

unread,
Jun 13, 2014, 10:27:41 PM6/13/14
to USTC_LUG
2014-06-14 1:52 GMT+08:00 Yifan Gao <ylgao...@gmail.com>:
我很好奇windows是用什么办法实现的?如果把A主机换成Windows系统(我测试的是Server 2012 R2),连接openvpn后,无需任何配置,从公网、VPN内网均可连接A主机的公网地址,并且不区分协议(目前TCP/UDP/ICMP测试都没问题)。

Windows 正是用基于连接的第一种方案实现的,连接从哪个口进,回复的数据包就会从哪个口出。这种方案也是看起来最和谐的。Windows 没有策略路由更没有 iptables NAT,如果系统不内置,就凭一张基于目的 IP 的路由表,用户怎么实现这个功能?

如果你问 Linux 怎么不内置这样的功能,这就是两个系统设计哲学的区别了。如果我的 Linux 主机上并发的连接非常多,conntrack hold 不住,这种情况下可以关掉 conntrack,即不跟踪连接。但在 Windows 上,我不知道怎样关掉连接跟踪机制。

再举个例子,Windows 建 wifi 热点分享有线网络,只需要下面两条命令(或者在控制面板里新建无线自组织网络)建一个虚拟 AP,再在 Network Adapter Settings 里把一个网卡共享给另一个网卡(或者桥接有线网卡和虚拟 AP)。
netsh wlan set hostednetwork mode=allow ssid=<ssid> key=<password>
netsh wlan start hostednetwork
在 Linux 下,建虚拟 AP,单是 hostapd 就能绕晕一票人了吧,还得配置 DHCP 服务器。把一个网卡共享给另一个网卡,需要打开内核 IP 转发选项,并配置 iptables SNAT(桥接可能理解起来简单一些)。
但是,如果你想换一种密码认证协议,或者指定虚拟 AP 的频道,hostapd 可以轻松做到,Windows 却没有提供这个接口。

Ding ZhiGang

unread,
Jun 13, 2014, 11:44:49 PM6/13/14
to ustc...@googlegroups.com
boj怎么学的,太博学了。。。

---------
Ding ZhiGang
--

Bojie Li

unread,
Jun 14, 2014, 12:18:10 AM6/14/14
to USTC_LUG
2014-06-14 11:44 GMT+08:00 Ding ZhiGang <dingz...@gmail.com>:
boj怎么学的,太博学了。。。

我将来是要靠网络吃饭的啊,你要问我装系统或者 GNOME 挂了的问题,我可答不出来。

Zhuoyun Wei

unread,
Jun 14, 2014, 3:46:53 AM6/14/14
to ustc...@googlegroups.com
2014-06-14 10:27 GMT+08:00 Bojie Li <boj...@gmail.com>:
> 再举个例子,Windows 建 wifi 热点分享有线网络,只需要下面两条命令(或者在控制面板里新建无线自组织网络)建一个虚拟 AP,再在
> Network Adapter Settings 里把一个网卡共享给另一个网卡(或者桥接有线网卡和虚拟 AP)。
> netsh wlan set hostednetwork mode=allow ssid=<ssid> key=<password>
> netsh wlan start hostednetwork
> 在 Linux 下,建虚拟 AP,单是 hostapd 就能绕晕一票人了吧,还得配置 DHCP 服务器。把一个网卡共享给另一个网卡,需要打开内核 IP
> 转发选项,并配置 iptables SNAT(桥接可能理解起来简单一些)。
> 但是,如果你想换一种密码认证协议,或者指定虚拟 AP 的频道,hostapd 可以轻松做到,Windows 却没有提供这个接口。


而且 WHQL 驱动可以实现同一张无线网卡同时工作在 Station 和 Master
模式,因此可以很方便地去共享一个无线网络,特别适用于一些无线网络需要网页认证的环境。

而 hostapd 想要做到类似的功能,就非常麻烦。我折腾了好久都没成功。当然有可能是当时 b43 驱动的问题……

--
wzyboy
Link: https://wzyboy.im/
Twitter: @wzyboy

Bojie Li

unread,
Jun 14, 2014, 4:05:01 AM6/14/14
to USTC_LUG
这有可能是驱动问题。消费领域 Linux 版的驱动经常缺少一些高级功能,企业级市场就刚好反过来了,Windows 版的驱动经常缺少一些高级功能。设备厂商可能认为不值得为小众操作系统付出那么多开发成本。

Zhuoyun Wei <wzyb...@gmail.com>编写:

Bojie Li

unread,
Jun 14, 2014, 1:16:52 PM6/14/14
to USTC_LUG
2014-06-14 10:27 GMT+08:00 Bojie Li <boj...@gmail.com>:
2014-06-14 1:52 GMT+08:00 Yifan Gao <ylgao...@gmail.com>:

我很好奇windows是用什么办法实现的?如果把A主机换成Windows系统(我测试的是Server 2012 R2),连接openvpn后,无需任何配置,从公网、VPN内网均可连接A主机的公网地址,并且不区分协议(目前TCP/UDP/ICMP测试都没问题)。

Windows 正是用基于连接的第一种方案实现的,连接从哪个口进,回复的数据包就会从哪个口出。这种方案也是看起来最和谐的。Windows 没有策略路由更没有 iptables NAT,如果系统不内置,就凭一张基于目的 IP 的路由表,用户怎么实现这个功能?

非常抱歉,我弄错了,之前的一次错误的观察导致了我错误的推断,然后我一直保持着这个错误的观念。刚刚在 Windows 里测试,外面发起的连接的响应包是按照路由表发出去的,如果路由表配错了就会发到错误的网卡。也就是系统没有采用基于连接的路由机制,由于没有策略路由,我不知道如何实现从不同网卡(interface)都能访问的功能。
Windows 里的路由表跟 Linux 的路由表基本上是一样的,都是根据目的 IP 前缀查询,找到最长的前缀,按照 metric 比较,然后选定下一跳(nexthop)的 IP 和网卡(interface)。

@Yifan Gao 如果你在 Server 2012 挂上 openvpn 后,公网地址仍然可以连接,请检查 openvpn 是否让你机器的所有流量都走了 VPN,也就是 route /print 是否包括 0.0.0.0/1128.0.0.0/1 两条规则,如果不包括则说明默认路由还是原来的公网出口;如果包括,而且你在服务器上访问 ip138.com 看到的是 LUG VPN 的 IP,则说明默认路由变成了 openvpn 虚拟网卡,这时如果公网地址能从 LUG VPN 和服务器所在局域网以外的机器连接,就很奇怪了。公网地址能从 LUG VPN 访问是自然的,因为 openvpn 会插入一条 202.141.160.99/176.99 via 物理网卡的路由规则,使得 VPN 封装后的数据包从物理网卡出去;公网地址能从服务器所在局域网访问也是自然的,因为局域网路由规则的优先级(前缀长度)比 openvpn 插入的默认路由规则更高。

Yifan Gao

unread,
Jun 14, 2014, 1:41:08 PM6/14/14
to ustc...@googlegroups.com
我弄错了,这是一个乌龙。Server2012上安装的ovpn版本不对,导致ovpn修改路由表失败,路由表中没有 0.0.0.0/1 128.0.0.0/1 规则。
正确配置ovpn后,公网ip既无法从外部访问,也无法从ovpn内部访问。
-- 
Yifan Gao

开启 2014年6月15日 at 上午1:16:51, Bojie Li (boj...@gmail.com) 写:

Bojie Li

unread,
Jun 14, 2014, 1:48:05 PM6/14/14
to USTC_LUG
server 2012 是中文系统吗?用了没解决网卡编码问题的 openvpn?

Yifan Gao <ylgao...@gmail.com>编写:

Yifan Gao

unread,
Jun 14, 2014, 1:50:22 PM6/14/14
to ustc...@googlegroups.com
好像不是由于网卡名编码问题造成的(网卡名是英文)。由于是公共主机,openvpn是其他人安装的,不太清楚具体情况
-- 
Yifan Gao

开启 2014年6月15日 at 上午1:48:04, Bojie Li (boj...@gmail.com) 写:

Reply all
Reply to author
Forward
0 new messages