十一长假第一天,清晨我放飞一群白鸽

范式

如果想实现哪个网口进来的流量从哪个网口返回这么一个需求,有一个范式,我先贴出来:

iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j ACCEPT
iptables -t mangle -A PREROUTING -i XXX .... -j MARK --set-mark YYY
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j CONNMARK --save-mark
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
ip rule add fwmark YYY table YYY
ip route add $net/$mask via $gw dev $device table YYY

问题

但是这里面有一个细节,对于本机流量而言,上述的OUTPUT链上的那条规则不一定能匹配成功,其实并不是没有匹配成功,而是说数据包在匹配这条规则之前就已经被丢弃了,根本就没有机会去匹配它!这是为什么呢?

  因为Netfilter的OUTPUT HOOK点是发生在标准IP路由之后的,如果在标准的路由查找(而不是策略路由查找)中没有成功找到路由,那么数据包在进入OUTPUT链之前就会被丢掉。

  也许你会问,为什么不直接查找策略路由表呢?

  很显然,这里发生了循环依赖,策略路由依赖fwmark,而要想把fwmark打给一个数据包,就必然要让数据包经过OUTPUT链,要想让数据包经过OUTPUT链,则必然要成功找到一条常规的路由。如果你的服务器没有配置这种恰好能被数据包使用的常规路由,那么上述的范式相当于就废掉了!不过值得注意的是,这条常规路由并不是真的给感兴趣数据包路由的,它存在的目的仅仅是为了让数据包有机会进入OUTPUT链去打mark。注意到这点,有助于我们设想出一个优雅的解决方案。

  那么我们怎么解决这个问题呢?

解法1:使用socket来设置mark

既然是本地流量,那么应用层一定会有一个服务来接纳这些流量并将本地始发流量注入协议栈,做这件事的无一例外就是socket,而socket可以通过下面的方式为协议栈的数据包提前打上mark:

int mark = 100;
setsockopt(client_socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));  

详情请看我的另一篇文章《Linux socket设置mark的必要性》
反正数据包上的mark就是为了策略路由,因此,协议栈里的数据包就不需要下面OUTPUT链上的规则了:

iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark

这是一个好的方案,但却并不一定可行,为什么呢?因为这要涉及到编程,超出了系统管理的范畴,而且服务程序代码不是说动就动的,即便是改一行代码,也要经过无穷尽的回归测试再测试…

  因此,我们来看看解法2。

解法2:使用dummy网卡

我觉得这是一个更加优雅的方案,不需要改代码,且不会造成流量泄漏!

  不是说在OUTPUT前必须找到一条路由吗?好吧,我给!然而这条路由真的就不是让你发包的,而只是一个Dummy路由!值得注意的是,Dummy路由并不是unreachable路由,也不是Linux上的blackhole路由,它是确确实实通过网卡发数据的路由,只是该网卡发数据的方式比较怪异,它只是默默丢弃数据包。

  很好,这并不会带来任何流量的泄漏。

  这一招依赖于你对Linux系统的足够熟悉,它依赖于一个特殊设备,叫做dummy网卡,你可以通过下面的命令加载它:

modprobe dummy
ifconfig dummy0 up

然后设置一条默认路由:

ip route add 0.0.0.0/0 dev dummy0

OK,就这样!

  如果你的系统配置中已经有了默认路由,就不必添加dummy默认路由了,因为彼种情况下数据包会被既有默认路由引导到OUTPUT链,待成功restore-mark后再重新路由。因此,为了不让默认路由冲突,可能需要封装一个脚本,添加基于fwmark的策略路由或者默认路由的时候,相互check一下,逻辑比较复杂,这里就不说了。

后记

其实这个问题早在几年前就遇到并思考过,近期有位朋友在工作中也遇到了同样的问题,所以就再次追忆了往事。

  当时第一次遇到这个问题的时候,我发誓一定要解决它,这并不是一个很难解决的问题,只需要把OUPUT移到路由前面即可,类似PREROUTING那样,但是这样又产生了循环依赖,比如OUTPUT链可以匹配-o这个match,如果OUTPUT在路由前,那么-o参数哪里来呢?…

  也难怪OUTPUT的特殊性了,虽然它和PREROUTING看上去差不多,但是方向却截然相反,只能作罢!后来,我想到了修改路由查找的代码,如果没有找到路由,就撸一遍OUPUT HOOK,然后重新路由,但依然太复杂了,不优雅…抑或说,在应用程序没有绑定网卡设备的时候再撸OUTPUT?…

  再往后,各种繁乱的工作任务交织,就把这事遗忘了。

  其实,iptables相关的还有别的问题,比如下面这个:
《关于Netfilter NF_HOOK宏的outdev参数bug》

Linux策略路由和iptables OUTPUT链的一个细节相关推荐

  1. 快速入门linux系统的iptables防火墙 1 本机与外界的基本通信管理

    概述 iptables是一种运行在linux下的防火墙组件,下面的介绍可以快速的学习iptables的入门使用. 特点(重要) 它的工作逻辑分为 链.表.规则三层结构. 数据包通过的时候,在对应表中, ...

  2. Linux防火墙与iptables命令

    Linux防火墙与iptables命令 防火墙概念 一.Firewalld与iptables简介 1.1Firewalld 1.2Firewalld.iptables 二.iptables 2.1四表 ...

  3. iptables基础——链与表

    1.防火墙相关概念 此处先描述一些相关概念. 1)从逻辑上讲,防火墙可以大体分为主机防火墙和网络防火墙. 主机防火墙:针对于单个主机进行防护. 网络防火墙:往往处于网络入口或边缘,针对于网络入口进行防 ...

  4. Linux下防火墙iptables用法规则详及其防火墙配置

    原博主文章更美丽: http://www.cnblogs.com/yi-meng/p/3213925.html iptables规则 规则--顾名思义就是规矩和原则,和现实生活中的事情是一样的,国有国 ...

  5. linux下防火墙iptables原理及使用

    iptables简介 netfilter/iptables(简称为iptables)组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火 ...

  6. Linux命令:iptables网络防火墙

    Linux命令:iptables 网络防火墙 一.iptables的发展: iptables的前身叫ipfirewall (内核1.x时代),这是一个作者从freeBSD上移植过来的,能够工作在内核当 ...

  7. linux命令:iptables、modprobe装载模块、网络防火墙服务

    装载ip追踪模块ip_conntrack: [root@johntest ~]# modprobe ip_conntrack   #装载ip_conntrack模块 [root@johntest ~] ...

  8. Linux学习笔记 --iptables防火墙配置

    iptables防火墙配置 一.防火墙简介 1.功能: 1)通过源端口,源IP地址,源MAC地址,包中特定标记和目标端口,IP,MAC来确定数据包是否可以通过防火墙 2)分割内网和外网[附带的路由器的 ...

  9. Linux操作系统下IPTables配置方法详解(转载)

    为什么80%的码农都做不了架构师?>>>    配置一个filter表的防火墙 1.查看本机关于IPTABLES的设置情况 [root@tp ~]# iptables -L -n C ...

最新文章

  1. 毕业季:理想很丰满,现实也可以很丰满!
  2. 2014年年度工作总结--IT狂人实录
  3. js 倒计时 时间戳
  4. VUE项目中使用this.$forceUpdate();解决页面v-for中修改item属性值后页面v-if不改变的问题
  5. JAVA写出来的塔防能有多好玩?......真香!
  6. DockOne微信分享( 九十一):打造百亿级数据处理量的弹性调度容器平台
  7. Android解决依赖冲突
  8. jQuery中each的用法之退出循环和结束本次循环
  9. Python3.x:生成器简介
  10. Nginx日志和http模块相关变量
  11. 【动力学】基于matlab GUI汽车动力学分析系统【含Matlab源码 1050期】
  12. inav是什么意思?
  13. 中图杯获奖作品计算机组,地理奥赛网-首页
  14. bitvise一个非常好用的ssh软件
  15. 使用html语言编写收银系统,蓝色简洁样式html5店铺收银系统网页模板
  16. 通讯录系统图形化界面(C++,Qt5.12)(Visual Studio2019,QtCreator)(初学)
  17. 腾讯阿里面试题【图文详解】:25匹马5赛道选前三,最少要跑几次?赛几场?
  18. 话题 | 咨询师建议:如何关系断舍离
  19. matlab激光扩束总结,激光扩束系统设计(推荐).doc
  20. Linux应用开发: SQLite数据库交叉编译部署与运用

热门文章

  1. Navisworks 导入revit模型显示不全问题的解决方案(比如不显示体量模型)
  2. 磁共振成像过程_磁共振成像人工智能提高性能
  3. iview-admin 三级菜单路由
  4. 谷歌浏览器设置黑暗模式的背景(不需要插件)
  5. 怎样共享windows和linux之间的文件
  6. 中国电能质量治理行业需求规模及投资前景展望报告(2022-2027年)
  7. 如何实现光伏并网柜中电能质量在线监测?
  8. [office办公软件教程] Photoshop如何绘画烟雾?Photoshop绘画烟雾的方法
  9. USB接口定义;miniUSB接口定义
  10. DVD-R-01.我自己搜索收集的一些Delphi免杀远控软件源代码(永久免云杀变种)2013-12-14 11:53:19...