问题:

问题:

我正在尝试在我的家庭服务器上设置策略路由。我的网络如下所示:

Host routed          VPN gateway          Internet link
through VPN

192.168.0.35/24 ---> 192.168.0.5/24   ---> 192.168.0.1 DSL router
                     10.200.2.235/22  ....             .... 10.200.0.1  VPN server

来自 192.168.0.32/27 的流量应该通过 VPN 路由。我想定义一些路由策略,以便将来自 192.168.0.5 的一些流量也通过 VPN 路由 - 首先 - 来自 uid 为 2000 的用户。策略路由是使用 iptables mark target 和 ip rule fwmark 完成的。

问题:

当使用来自 192.168.0.5 的用户 2000 进行连接时,tcpdump 显示传出的数据包,但没有返回任何内容。来自 192.168.0.35 的流量工作正常(这里我没有使用 fwmark,而是使用 src 策略)。

这是我的 VPN 网关设置:

# uname -a
Linux placebo 3.2.0-34-generic #53-Ubuntu SMP Thu Nov 15 10:49:02 UTC 2012 i686 i686 i386 GNU/Linux
# iptables -V
iptables v1.4.12
# ip -V
ip utility, iproute2-ss111117

IPtables 规则(表过滤器中的所有策略都为 ACCEPT)

# iptables -t mangle -nvL
Chain PREROUTING (policy ACCEPT 770K packets, 314M bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain INPUT (policy ACCEPT 767K packets, 312M bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 5520 packets, 1920K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 782K packets, 901M bytes)
 pkts bytes target     prot opt in     out     source               destination         
   74  4707 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 2000 MARK set 0x3

Chain POSTROUTING (policy ACCEPT 788K packets, 903M bytes)
 pkts bytes target     prot opt in     out     source               destination         


# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 996 packets, 51172 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain INPUT (policy ACCEPT 7 packets, 432 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 1364 packets, 112K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 2302 packets, 160K bytes)
 pkts bytes target     prot opt in     out     source               destination         
  119  7588 MASQUERADE  all  --  *      vpn  0.0.0.0/0            0.0.0.0/0           

路由:

# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master lan state UNKNOWN qlen 1000
    link/ether 00:40:63:f9:c3:8f brd ff:ff:ff:ff:ff:ff
       valid_lft forever preferred_lft forever
3: lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether 00:40:63:f9:c3:8f brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.5/24 brd 192.168.0.255 scope global lan
    inet6 fe80::240:63ff:fef9:c38f/64 scope link 
       valid_lft forever preferred_lft forever
4: vpn: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 100
    link/none 
    inet 10.200.2.235/22 brd 10.200.3.255 scope global vpn

# ip rule show
0:  from all lookup local 
32764:  from all fwmark 0x3 lookup VPN 
32765:  from 192.168.0.32/27 lookup VPN 
32766:  from all lookup main 
32767:  from all lookup default 

# ip route show table VPN
default via 10.200.0.1 dev vpn 
10.200.0.0/22 dev vpn  proto kernel  scope link  src 10.200.2.235 
192.168.0.0/24 dev lan  proto kernel  scope link  src 192.168.0.5

# ip route show
default via 192.168.0.1 dev lan  metric 100 
10.200.0.0/22 dev vpn  proto kernel  scope link  src 10.200.2.235 
192.168.0.0/24 dev lan  proto kernel  scope link  src 192.168.0.5 

TCP 转储显示从 192.168.0.5 用户 2000 建立连接时没有返回流量

# tcpdump -i vpn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vpn, link-type RAW (Raw IP), capture size 65535 bytes
### Traffic from user 2000 on 192.168.0.5 ###
10:19:05.629985 IP 10.200.2.235.37291 > 10.100-78-194.akamai.com.http: Flags [S], seq 2868799562, win 14600, options [mss 1460,sackOK,TS val 6887764 ecr 0,nop,wscale 4], length 0
10:19:21.678001 IP 10.200.2.235.37291 > 10.100-78-194.akamai.com.http: Flags [S], seq 2868799562, win 14600, options [mss 1460,sackOK,TS val 6891776 ecr 0,nop,wscale 4], length 0
### Traffic from 192.168.0.35 ###
10:23:12.066174 IP 10.200.2.235.49247 > 10.100-78-194.akamai.com.http: Flags [S], seq 2294159276, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 557451322 ecr 0,sackOK,eol], length 0
10:23:12.265640 IP 10.100-78-194.akamai.com.http > 10.200.2.235.49247: Flags [S.], seq 2521908813, ack 2294159277, win 14480, options [mss 1367,sackOK,TS val 388565772 ecr 557451322,nop,wscale 1], length 0
10:23:12.276573 IP 10.200.2.235.49247 > 10.100-78-194.akamai.com.http: Flags [.], ack 1, win 8214, options [nop,nop,TS val 557451534 ecr 388565772], length 0
10:23:12.293030 IP 10.200.2.235.49247 > 10.100-78-194.akamai.com.http: Flags [P.], seq 1:480, ack 1, win 8214, options [nop,nop,TS val 557451552 ecr 388565772], length 479
10:23:12.574773 IP 10.100-78-194.akamai.com.http > 10.200.2.235.49247: Flags [.], ack 480, win 7776, options [nop,nop,TS val 388566081 ecr 557451552], length 0

更新:

我按照@BatchyX 的建议做了:

# iptables -t mangle -nvL
Chain PREROUTING (policy ACCEPT 3 packets, 179 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  173 15993 CONNMARK   all  --  *      *       0.0.0.0/0            0.0.0.0/0            CONNMARK restore

Chain INPUT (policy ACCEPT 3 packets, 179 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 1 packets, 67 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 1 packets, 60 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   83  5247 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 2000 MARK set 0x3
  166 16053 CONNMARK   all  --  *      *       0.0.0.0/0            0.0.0.0/0            CONNMARK save

Chain POSTROUTING (policy ACCEPT 2 packets, 127 bytes)
 pkts bytes target     prot opt in     out     source               destination        

另外,我已禁用 vpn 的 rp_filter

# echo 0 > /proc/sys/net/ipv4/conf/vpn/rp_filter

现在情况好多了 - 我收到了 SYN、ACK 数据包,但握手似乎没有完成。此外,传出数据包的校验和似乎有误...

仅作为线索 - 这是一个双重 NAT 场景 - 我正在对进入 VPN 的数据包进行 NAT,并且我的 VPN 提供商在将它们转发到世界各地之前对它们进行 NAT。

# tcpdump -vvi vpn
tcpdump: listening on vpn, link-type RAW (Raw IP), capture size 65535 bytes
16:27:56.308479 IP (tos 0x10, ttl 64, id 49013, offset 0, flags [DF], proto TCP (6), length 60)
    10.200.2.235.58020 > wi-in-f104.1e100.net.http: Flags [S], cksum 0xff0b (incorrect -> 0x9790), seq 3580181028, win 14600, options [mss 1460,sackOK,TS val 12420433 ecr 0,nop,wscale 4], length 0
16:27:56.488691 IP (tos 0x0, ttl 46, id 44196, offset 0, flags [none], proto TCP (6), length 60)
    wi-in-f104.1e100.net.http > 10.200.2.235.58020: Flags [S.], cksum 0x12a2 (correct), seq 3226424033, ack 3580181029, win 14180, options [mss 1367,sackOK,TS val 1968045661 ecr 12420433,nop,wscale 6], length 0
16:27:56.799066 IP (tos 0x0, ttl 46, id 44197, offset 0, flags [none], proto TCP (6), length 60)
    wi-in-f104.1e100.net.http > 10.200.2.235.58020: Flags [S.], cksum 0x116c (correct), seq 3226424033, ack 3580181029, win 14180, options [mss 1367,sackOK,TS val 1968045971 ecr 12420433,nop,wscale 6], length 0

更新 2:

如前所述,我现在收到了 SYN、ACK,但无法通过 ACK 数据包完成握手。因此,如果我从路由用户的帐户进行 telnet,我会得到:

routed@placebo ~ # telnet 85.214.204.92 80
Trying 85.214.204.92...
telnet: Unable to connect to remote host: Connection timed out

以及相应的 tcpdump:

# tcpdump -vvi vpn
tcpdump: listening on vpn, link-type RAW (Raw IP), capture size 65535 bytes
20:33:51.940151 IP (tos 0x10, ttl 64, id 65041, offset 0, flags [DF], proto TCP (6), length 60)
    10.200.2.235.60547 > korn.vibfolks.eu.http: Flags [S], cksum 0x3014 (incorrect -> 0xe817), seq 151728396, win 14600, options [mss 1460,sackOK,TS val 16109341 ecr 0,nop,wscale 4], length 0
20:33:52.142823 IP (tos 0x0, ttl 50, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    korn.vibfolks.eu.http > 10.200.2.235.60547: Flags [S.], cksum 0xf897 (correct), seq 986246473, ack 151728397, win 14480, options [mss 1367,sackOK,TS val 62899312 ecr 16109341,nop,wscale 6], length 0
20:33:52.937974 IP (tos 0x10, ttl 64, id 65042, offset 0, flags [DF], proto TCP (6), length 60)
    10.200.2.235.60547 > korn.vibfolks.eu.http: Flags [S], cksum 0x3014 (incorrect -> 0xe71d), seq 151728396, win 14600, options [mss 1460,sackOK,TS val 16109591 ecr 0,nop,wscale 4], length 0
20:33:53.140728 IP (tos 0x0, ttl 50, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    korn.vibfolks.eu.http > 10.200.2.235.60547: Flags [S.], cksum 0xf79e (correct), seq 986246473, ack 151728397, win 14480, options [mss 1367,sackOK,TS val 62899561 ecr 16109341,nop,wscale 6], length 0
20:33:53.341764 IP (tos 0x0, ttl 50, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    korn.vibfolks.eu.http > 10.200.2.235.60547: Flags [S.], cksum 0xf76b (correct), seq 986246473, ack 151728397, win 14480, options [mss 1367,sackOK,TS val 62899612 ecr 16109341,nop,wscale 6], length 0

但非路由用户连接没有问题:

nonrouted@placebo ~ $ telnet 85.214.204.92 80
Trying 85.214.204.92...
Connected to 85.214.204.92.
Escape character is '^]'.
^]

telnet> quit
Connection closed.

更新 3

我已经将日志规则添加到 mangle 和 nat 表中,以找出数据包丢失的位置。

我在标记之前和之后登录 mangle(基于 uid),在 nat 后路由中登录(基于 iface),在 mangle 预路由中登录(基于 iface),在 mangle 输入和转发中登录(基于恢复的标记)

Dec  9 01:00:55 placebo kernel: [80760.497780] [VPN mangle OUTPUT pre] IN= OUT=lan SRC=192.168.0.5 DST=85.214.204.137 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=30041 DF PROTO=TCP SPT=48700 DPT=80 SEQ=3158481901 ACK=0 WINDOW=14600 RES=0x00 SYN URGP=0 OPT (020405B40402080A0132EEB40000000001030304) 
Dec  9 01:00:55 placebo kernel: [80760.497819] [VPN mangle OUTPUT post] IN= OUT=lan SRC=192.168.0.5 DST=85.214.204.137 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=30041 DF PROTO=TCP SPT=48700 DPT=80 SEQ=3158481901 ACK=0 WINDOW=14600 RES=0x00 SYN URGP=0 OPT (020405B40402080A0132EEB40000000001030304) MARK=0x3 
Dec  9 01:00:55 placebo kernel: [80760.497875] [VPN nat POSTROUTING] IN= OUT=vpn SRC=192.168.0.5 DST=85.214.204.137 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=30041 DF PROTO=TCP SPT=48700 DPT=80 SEQ=3158481901 ACK=0 WINDOW=14600 RES=0x00 SYN URGP=0 OPT (020405B40402080A0132EEB40000000001030304) MARK=0x3 
Dec  9 01:00:55 placebo kernel: [80760.695265] [VPN mangle PREROUTING pre] IN=vpn OUT= MAC= SRC=85.214.204.137 DST=10.200.2.235 LEN=60 TOS=0x00 PREC=0x00 TTL=50 ID=0 DF PROTO=TCP SPT=80 DPT=48700 SEQ=3597895441 ACK=3158481902 WINDOW=14480 RES=0x00 ACK SYN URGP=0 OPT (020405570402080A03FCE5720132EEB401030306) 
Dec  9 01:00:55 placebo kernel: [80760.695305] [VPN mangle PREROUTING post] IN=vpn OUT= MAC= SRC=85.214.204.137 DST=10.200.2.235 LEN=60 TOS=0x00 PREC=0x00 TTL=50 ID=0 DF PROTO=TCP SPT=80 DPT=48700 SEQ=3597895441 ACK=3158481902 WINDOW=14480 RES=0x00 ACK SYN URGP=0 OPT (020405570402080A03FCE5720132EEB401030306) MARK=0x3

Conntrack显示:

# conntrack -L --output extended | grep 85.214.204.137 | grep tcp
ipv4     2 tcp      6 59 SYN_RECV src=192.168.0.5 dst=85.214.204.137 sport=48724 dport=80 src=85.214.204.137 dst=10.200.2.235 sport=80 dport=48724 mark=3 use=1

结论 - 数据包永远无法到达 INPUT...为什么?路由不好?

答案1

确保您的路由是对称的,或者禁用反向路径过滤(仅当您知道自己在做什么时,因为修复您的路由始终是更好的选择)。

我们来做个测试,流量来自192.168.0.33:

192.168.0.33 -> 192.178.100.10 如果 eth0

反向路径过滤在 ubuntu 中默认启用。它会反转源地址和目标地址,并尝试选择一条路由,就好像它有一个带有这些源地址和目标地址的数据包一样。如果接口与接收数据包的接口不匹配,则认为该数据包是伪造的。

因此内核尝试将 192.178.100.10 路由到 192.168.0.33 ...它查找主表...通过 eth0 找到条目 192.168.0.0/24,这也是接收数据包的接口,因此不会丢弃数据包。

因此,您对其进行 NAT 并在 VPN 接口上发送 10.200.2.235 -> 192.178.100.10。VPN 程序会将其封装并将其作为 192.168.0.5 -> remotevpn 发送。现在,您会从同一接口收到来自 VPN 的答复。反向路径过滤显然会在这里通过。VPN 解封装结果(192.178.100.10 -> 10.200.2.235),然后 NAT 将发生,破坏数据包以恢复原始目标地址。然后,您将对生成的数据包进行反向路径过滤:

192.178.100.10 -> 192.168.0.33 当且仅当 VPN

让我们尝试将 192.168.0.33 路由到 192.178.100.10 ...查找表 VPN ...默认通过 dev vpn 上的 10.200.0.1:PASS。

现在您想从主机执行操作,作为 192.168.0.5 或 10.200.2.235(带标记 3)。您将其发送到您的 VPN,VPN 将其从 192.168.0.5 发送到 VPN 远程。您以相同的方式获得答案,然后 VPN 将解封装(192.178.100.10 -> 192.168.0.5(或 10.200.2.235)),然后进行反向路径过滤。

192.168.0.5 或 10.200.2.235 -> 192.178.100.10 ... 不查找 VPN 表(它没有标记,也不来自 192.168.0.32/27),因此它最终进入主表,该表告诉它使用接口 eth0。反向路径过滤失败,因此该数据包被丢弃,作为 IP 源欺骗尝试。因此您看不到结果。

至于为什么 tcpdump 没有显示这些数据包...也许 VPN 端点上也存在路由问题。

至于解决方案,在您的情况下,我将使用 conntrack 的连接标记,并将传入数据包的标记设置为 conntrack 连接的标记:

# keep that rule
OUTPUT -m owner .... -j MARK 0x3
# add this one after the previous one: it saves the current mark into connmark
OUTPUT -j CONNMARK --save-mark

# and add this one (in mangle), which sets the mark to the connmark
# if conntrack determines that it is from the same connection.
PREROUTING -j CONNMARK --restore-mark

编辑:

您不必禁用反向路径过滤即可使此 iptables 解决方案发挥作用。不必要地禁用 rp_filter 并不是解决问题的好方法,它只会隐藏问题。

现在来谈谈随机想法:

  • 我一直在猜测你的程序使用了哪个 IP 地址。找到一个可以打印出它正在使用的源 IP 地址的程序。或者告诉 telnet 绑定到 192.168.0.35 或 10.200.2.235。tcpdump 只会在传出数据包被 NAT 后显示它,并且只会在传入数据包被取消 NAT 之前显示它,所以它不会告诉你实际使用了哪一个。作为专家解决方案,你也可以尝试将 nflog 放入链中,并使用 tcpdump 检查链中的内容。

  • 不要伪装所有发往 vpn 的信息,只伪装那些不是来自 的vpnIP 或子网的信息。将您自己的流量伪装成您自己的流量似乎毫无意义。也许 conntrack 对此感到困惑。

答案2

好的,它开始工作了...我仍然不知道我之前做错了什么。无论如何,为了让它工作,我使用了:

iptables -t mangle -A OUTPUT -m owner --uid-owner 2000 -j MARK --set-mark 3
iptables -t nat -A POSTROUTING -o vpn -j MASQUERADE

ip rule add fwmark 3 lookup VPN
ip route add default via x.x.x.x table VPN

sysctl -w net.ipv4.conf.vpn.rp_filter=2

希望它也能帮助其他人。

答案3

我认为需要明确的是:
参见 Gheorghe 的“设计和实施 Linux 防火墙和 QoS……”第 116 页)

nat 的 INPUT 链:(Fedora 18 的手册页中从未提及)

mangle 的 INPUT 链:(根据 iptables 手册页,用于进入盒子本身的数据包)

他们和过滤表输入

以及
mangle 的 FORWARD 链和 filter 的 FORWARD 链。
这两个 FORWARD 链之间有什么区别?
(好的,我找到了答案,但其他人可以审查一下吗: http://www.linuxhomenetworking.com/wiki/index.php/Quick_HOWTO_:第 14 章:_Linux_防火墙_使用_iptables#.UMUF0HTqOIU

相关内容