Chinaunix

标题: 为什么打了fwmark标记但却不起作用呢【已解决】 [打印本页]

作者: jiufei19    时间: 2014-08-20 13:39
标题: 为什么打了fwmark标记但却不起作用呢【已解决】
本帖最后由 jiufei19 于 2014-08-21 10:05 编辑

大家好,下面一个问题我一直没有找到错误出在哪里,请大家帮忙指正。

问题描述:

我希望某台linux主机允许来自任意客户端的ssh访问,而不是特定IP发来的ssh访问请求。换句话讲,ssh客户端的ip随时可能发生变化。下面是我的部分配置:

iptables -t mangle -A OUTPUT -p tcp --sport 22 -j MARK --set-mark 100

ip route add default via x.x.x.x table 300
ip rule add fwmark 100 table 300 pref 32759


该设置的思想是对凡是由该linux产生的对ssh客户端的应答都标记其fwmark为100,然后对此标记fwmark为100的数据设置策略路由为查路由表300,而路由表300中缺省路由为x.x.x.x。另外,之所以我要这样设计的原因是主路由表有其他设置,我不能使用主路由表的default来解决,于是必须使用策略,但是经过上述配置后,客户端将无法再访问linux了,说明路由出了问题,fwmark没有起到应有的作用。

请问大家,上面的配置哪里有问题?谢谢!



作者: q1208c    时间: 2014-08-20 15:02
tracert 一下看看 数据包是怎么走的.
作者: jiufei19    时间: 2014-08-20 15:30
本帖最后由 jiufei19 于 2014-08-20 16:11 编辑
q1208c 发表于 2014-08-20 15:02
tracert 一下看看 数据包是怎么走的.


请问q1208c,我没有反应过来如何使用tracert来看数据包如何走呢?

下面是我在linux上执行traceroute时的结果,其中192.168.0.145是ssh客户端的当前ip,可见ssh的应答先走192.168.23.2这个网关,然后再到192.168.0.145。但是我在策略路由中也设置了表300的网关为192.168.23.2,按理没有问题啊,但是实际结果不正确只能是说明fwmark没有起作用。

[admin@fedora8 ~]$ traceroute 192.168.0.145
traceroute to 192.168.0.145 (192.168.0.145), 30 hops max, 40 byte packets
1  192.168.23.2 (192.168.23.2)  0.487 ms  0.231 ms  0.262 ms
2  192.168.0.145 (192.168.0.145)  15.292 ms  14.306 ms  13.539 ms
作者: jiufei19    时间: 2014-08-20 15:47
本帖最后由 jiufei19 于 2014-08-20 16:14 编辑

我下面把设置后的策略和路由列出,便于大家帮我发现问题

[admin@fedora8 ~]$ ip rule list
0:                from all lookup local
32759:        from all fwmark 0x64 lookup 300
32766:        from all lookup main
32767:        from all lookup default
[admin@fedora8 ~]$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.168.23.0    *                   255.255.255.0   U        0      0        0   eth1
link-local            *                   255.255.0.0       U        0      0        0   eth1
default           192.168.23.2    0.0.0.0            UG        0      0        0   eth1
[admin@fedora8 ~]$ ip route show table 300
default via 192.168.23.2 dev eth1

此时,ssh客户端还可以访问linux,但是如果我将上面的红色字体的策略去掉,则将立刻无法再连接linux服务器了,因此显然是fwmark没有起作用,正是因为其没有起作用,所以之前红色字体的策略没有删除时,ssh请求的应答没有匹配策略32759,于是按主路由表进行操作,因此保证ssh客户端可以继续访问linux,而一旦去掉红色字体策略,而32759又不匹配,于是就出现了ssh客户端无法再访问linux的现象,为了进一步说明表300没有错误,我故意按如下策略进行了重复设置
[admin@fedora8 ~]$ ip rule list
0:        from all lookup local
32759:        from all fwmark 0x64 lookup 300
32766:        from all lookup 300
32767:        from all lookup default

此时ssh客户端仍然可以正常访问linux,这说明表300的设置是正确的,进一步说明了fwmark没有起作用。为什么会这样呢?一直对fwmark的使用不清晰。


作者: q1208c    时间: 2014-08-20 16:20
由于你指定了 端口22, 所以, 我建议你使用 tcp traceroute 看看会不会按你的路由来走.
作者: phanx    时间: 2014-08-20 16:27
本帖最后由 phanx 于 2014-08-20 23:52 编辑

回复 4# jiufei19


    你应该在PREROUTING的时候做set-mark。
  1. iptables -t mangle -A PREROUTING -p tcp --sport 22 -j MARK --set-mark 100
复制代码


更正:对于本机发出的报文,PREROUTING没有效果。
作者: jiufei19    时间: 2014-08-20 16:28
q1208c 发表于 2014-08-20 16:20
由于你指定了 端口22, 所以, 我建议你使用 tcp traceroute 看看会不会按你的路由来走.


不好意思,我没有理解q1208c的说明呢,q1208c看了我上面两个说明了吗?

另外,当我按fwmark设置后,在linux主机上面直接执行traceroute 192.168.0.145时,将看到“Network is unreachable”的提示信息
作者: jiufei19    时间: 2014-08-20 16:32
phanx 发表于 2014-08-20 16:27
回复 4# jiufei19


为啥不能在OUTPUT这个chain做?我的本意就是要在linux的ssh服务发回应答的时候被标记为fwmark=100,以便后面路由处理。

此外,我也按phanx说的改在PREROUTING做了,可结果仍然不正确。
作者: q1208c    时间: 2014-08-20 17:34
回复 7# jiufei19

我看到你的说明了.

所以, 只有 tcp traceroute 才能触发你的 规则被mark上.

普通的traceroute使用的是 icmp协议, 你那规则用不上的.
   
作者: jiufei19    时间: 2014-08-20 22:22
回复 9# q1208c


    仔细看了下源码,发现主机的外出报文都是从ip_queue_xmit这个函数发出的,而这个函数中是首先进行路由,然后再调用NF_HOOK(NF_IP_LOCAL_OUT),也就是OUTPUT链,这样的话,之前我的策略配置就永远不会有效果了。所以,对于外出报文,可能fwmark的确无法起作用,而如果是转发报文,那么fwmark就可以起作用了。
作者: jiufei19    时间: 2014-08-20 22:24
本帖最后由 jiufei19 于 2014-08-20 22:24 编辑

回复 6# phanx


   也请phanx看看我自己找到的这个答案是否正确,谢谢!
作者: phanx    时间: 2014-08-20 23:47
本帖最后由 phanx 于 2014-08-20 23:56 编辑

回复 11# jiufei19


    是的,你是正确的。 我做了个TRACE

[root@testhost ~]# modprobe ipt_LOG
[root@testhost ~]# iptables -t raw -A PREROUTING --dst 10.0.0.222 -j TRACE
[root@testhost ~]# iptables -L -v -n -t raw
Chain PREROUTING (policy ACCEPT 6324 packets, 1112K bytes)
pkts bytes target     prot opt in     out     source               destination         
    0     0 TRACE      all  --  *      *       0.0.0.0/0                10.0.0.222        

Chain OUTPUT (policy ACCEPT 395 packets, 104K bytes)
pkts bytes target     prot opt in     out     source               destination         
   22  5026 TRACE      tcp  --  *      *       0.0.0.0/0            10.0.0.222        tcp spt:22

下面是TRACE结果

[root@testhost ~]#cat /var/log/message
testhost kernel: TRACE: raw:OUTPUT:rule:2 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0
testhost kernel: TRACE: raw:OUTPUT:policy:3 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0
testhost kernel: TRACE: mangle:OUTPUT:rule:1 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0
testhost kernel: output IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 WINDOW=14600 RES=0x00 ACK SYN URGP=0
testhost kernel: TRACE: mangle:OUTPUT:rule:3 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0
testhost kernel: TRACE: mangle:OUTPUT:rule:4 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0 MARK=0x64
testhost kernel: TRACE: mangle:OUTPUT:policy:5 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0 MARK=0x64
testhost kernel: TRACE: filter:OUTPUT:policy:1 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0 MARK=0x64
testhost kernel: TRACE: mangle: POSTROUTING:policy:1 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269519 ACK=1766750704 WINDOW=14600 RES=0x00 ACK SYN URGP=0 OPT (020405B40101040201030307) UID=0 GID=0 MARK=0x64
testhost kernel: TRACE: raw:OUTPUT:rule:2 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=35912 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269520 ACK=1766750755 WINDOW=115 RES=0x00 ACK URGP=0
testhost kernel: TRACE: raw:OUTPUT:policy:3 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=35912 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269520 ACK=1766750755 WINDOW=115 RES=0x00 ACK URGP=0
testhost kernel: TRACE: mangle:OUTPUT:rule:1 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=35912 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269520 ACK=1766750755 WINDOW=115 RES=0x00 ACK URGP=0
testhost kernel: output IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=35912 DF PROTO=TCP SPT=22 DPT=51680 WINDOW=115 RES=0x00 ACK URGP=0
testhost kernel: TRACE: mangle:OUTPUT:rule:3 IN= OUT=em1 SRC=192.168.1.111 DST=10.0.0.222 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=35912 DF PROTO=TCP SPT=22 DPT=51680 SEQ=669269520 ACK=1766750755 WINDOW=115 RES=0x00 ACK URGP=0


看到的情况也跟你的得出的结论是一致的。
本机主动发出的包,只会从OUTPUT Chain出去。由于OUTPUT在路由之后,所以就算设置了MARK也不能再匹配路由规则了。如果是转发报文,那么在IN的时候可以在PREROUTING上set mark。这个时候应该就可以匹配到对应的路由规则了。

在default 路由表没有到10.0.0.222的路由,只有table 100 有到10.0.0.222的路由的时候,根本不会有任何输出,直接是路由不可达,证明了确实是先选路由。
作者: q1208c    时间: 2014-08-21 08:03
回复 10# jiufei19

看来, 你需要一个新的方式来处理你的问题了.
   
作者: jiufei19    时间: 2014-08-21 10:04
回复 12# phanx


    感谢phanx的热心答复
作者: jiufei19    时间: 2014-08-21 10:11
本帖最后由 jiufei19 于 2014-08-21 10:12 编辑

回复 13# q1208c


    谢谢q1208c,的确需要其他方法来处理我这里的特殊问题。不过现在很郁闷,因为default路由已经被用过了,不可能再来一个“特殊的default”应对我这里的情况,我本来寄托希望在fwmark上作文章,哪晓得fwmark在路由后。

    我好奇的是为啥linux内核不在本机发出数据的函数代码中直接增加一句NF_HOOK(PREROUTING),这样不就非常灵活了吗
作者: q1208c    时间: 2014-08-21 11:53
回复 15# jiufei19

我也不知道 kernel 为啥不这么做

或许 DNAT 能满足你的要求.

你把进来的 端口为 22 的包 DNAT 到另一个 IP, 然后就不用mark都会走新的路由了.
   
作者: jiufei19    时间: 2014-08-21 16:52
回复 16# q1208c


    但是没有其他ip了
作者: q1208c    时间: 2014-08-21 16:58
回复 17# jiufei19

在你本机上, 随便绑定一个IP就可以了. 反正DNAT之后, 你还需要一个 SNAT.
   
作者: jiufei19    时间: 2014-08-22 11:58
回复 18# q1208c


    我没有太明天你的意思呢,我现在的问题是外出报文如何使用策略路由的问题,即便绑定了另外一个ip,又怎么能做到外出报文在打了fwmark后可以再次路由?
作者: q1208c    时间: 2014-08-22 12:56
回复 19# jiufei19

因为有DNAT, 所以, 它必须经过INPUT, 而不是直接去到 OUTPUT.
   
作者: woxizishen    时间: 2015-04-29 08:49
本帖最后由 woxizishen 于 2015-04-29 16:40 编辑

回复 8# jiufei19


PREROUTING链你确定你的设定没问题,如果按照你开头设定。
作者: woxizishen    时间: 2015-04-29 16:39
回复 10# jiufei19

1.开发此款软体的作者一共设定了五个链,而这五个链outpt并不是在最后。outpt是处于数据从本机系统流出到路由前这个阶段,而POSTROUTING是处于最后的一个链,也就是路由后到本地网卡的阶段。你所理解的IP源码和作者开发此款防火墙软体可是2嘛事,千万别混淆,很多网上资料把这五个链顺序弄的乱七八糟。



2.你之所以把mangle 打上标记mark,在outpt链没成功,很正常啊,数据都已经从本机系统流出了,你打mark有何意义,你应该深入了解下iptables防火墙作者的开发思路后,
你会发现应该在PREROUTING阶段打上mark,但是为何PREROUTING打上MARK不起作用,嘿嘿,仔细检查下你会发现问题。   


帖子很久了,希望楼主看到,整理下思路



作者: lmtwl    时间: 2016-06-07 23:49
回复 22# woxizishen


精彩。吃透了

   




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2