nftables相比iptables到底改变了什么

这不是一篇教你怎么可以配置nftables实现一个哪怕最简单防火墙的文章,我从来不写这种Howto,因为我觉得如果一项新技术,一个人连其本身的文档都懒得看,即便没有文档如果没有一点钻研精神将其搞懂,只靠看别人写好的Step by step的话,那真是太失败了。相反,这篇文章是一篇檄文,只为吹擂打鼓,目的是让你在无感于iptables的前提下爱上nftables。
---------------------------------
关于nftables,请参见以下几篇文字:
1.同样一篇檄文,翻译过来的,它是《Linux 首次引入 nftables,你可能会喜欢 nftables 的理由
2.nftables的文档,这个最具有权威性,它是《Nftables HOWTO 中文翻译》,我跟朋友说,这个文档就像当年的iptables文档一样好,我给出个中文链接,喜欢英文的请自行搜索。
3.详细剖析nftables语法以及内部结构的一篇文章,它是《What comes after 'iptables'? Its successor, of course: `nftables`》,很遗憾它没有中文翻译,不过看我的应该就够了。
4.我自己在2014年的时候写的一篇关于nftables的文章,它是《继iptables之后的新一代包过滤框架是nftables》,说实话,我确实自己又看了一遍这个。

如果你真的完整看过了以上4篇,我相信下面的文字是很轻松的。而且,你在读完下面文字的时候,应该会形成一种形而上的观点与我展开讨论,热烈欢迎!
---------------------------------
要站在历史的延长线上观看nftables,它是第X代Linux防火墙。它的前驱是iptables,再往前是ipchains,ipfirewall等等...如果你仔细观察它们的名字,就会发现,nftables中完全用nf前缀取代了ip前缀,这是不是意味着,之前类似iptables,ip6tables,arptables,ebtables等等“工具族”,完全被统一在nf-框架之上了呢?答案无疑是肯定的,nftables完全统一了所有这些,正如其名字所示,nf代表Netfilter,而不管是ipchains,iptables,ebtables,arptables,底层所依赖的机制完全就是Netfilter。nftables统一了所有这一切!伴随着这个事实,理所当然会有下面的疑问:




nftables的外部语法和内部架构该如何变化以适应这个大一统的名字呢?
        我们从名字开始,逐步开始向下挖。
---------------------------------
首先我们先从离我们最近的地方,即用户接口看起。这部分侧重表现在命令或者说语法方面。请注意,iptables的规则是没有语法的,它只是一系列命令行参数的组合,而nftables的语法也并不是完善的,起码现在还很弱,不过我们要向前看有所期待。
        有文章说nftables是借鉴了tcpdump的语法,将-a $a或者--abc $abc这种语法改成了类似a $a之类的语法,我不太认同nftables是借鉴了tcpdump,因为这是nftables自然而然的做法。
        如果是iptables时代,我们使用下面的规则:
iptables -A OUTPUT -p tcp --dport 80 -j DROP
到了nftables时代,同样的规则,会变成下面的样子:
nft add rule ip filter output tcp dport 80 drop
虽然长了些,但你会发现,所有的字词都完整地构成了一个个的句子构成元素,比如主语,谓语,宾语,状语,定语等,然后回看iptables的命令行参数,几乎全部都是限定性的,比如出现-p,就意味着后面将要出现的就是协议...在nftables中,没有这种限制了。映射到程序中,iptables可以用getopt这种方式处理“命令行参数”,请注意,iptables将所有的子命令都作为了命令行参数来看待,而nftables则完全不同,它处理子命令的过程完全是语法分析和词法分析的过程,所有你敲打进去的每一个单词都将构成一颗树上的节点,nftables是有“真正的语法”的,所以说,你配置nftables规则的过程,就是一个编程的过程。编程的过程是一个直观且简洁的过程,就像人们自然而然的写下一个句子一样。
        外部语法的升华背后,那是内部结构的调整。
---------------------------------
nftables的内部结构与iptables相比,有哪些变化呢?
        首先,我们先看下规则的布局。
        我们知道,iptables规则的布局是基于连续的大块内存的,我之前曾经称之为数组式布局,写到这里,我想你应该知道我想说什么了,既然iptables规则是数组式布局,那么nftables规则会不会是链表式布局呢?答案无疑是肯定的。那么iptables规则的布局和nftables规则的布局之间的区别,其实就是数组和链表的区别了。
        举个最简单的例子,数组的元素要是被删除了,保证顺序不变的前提下,后面所有的元素都要往前移动,试想10000个元素的数组删除array[1]的情况,链表就不存在这个问题,只需要修改一个或者几个指针即可。当然,数组还是有好处的,内存紧凑,cache命中率高,可以索引定位什么的...
        当然,我并不晓得iptables当初为什么要采用这种数组式的布局,这很值得深挖一下,但却不是本文的主题。离开这个话题前,我必须要说的是,对于我个人来说,在快速实现一个可以测试的功能的编程过程中,如果需要容器,我首选的就是数组,因为在实验阶段它更直接,且不会遇到O(n)问题...最后等真的遇到问题且有替换数组为链表的十足理由了,我才会去重构成链表式的实现,否则它就在那里了。
        看完了规则的布局差异,我们继续往下看。
        如果你熟悉iptables的内核机制(如果不知道,请Stop,本文不是介绍这方面的Howto),你就会知道它实际上是一个非常规则且简单的“机械装置”,这套装置明令要求所有的规则必须由若干的matches和一个target组成,我们经常在肯德基或者老式工厂(比如老式机床厂)的车间见到类似的这种装置。这类装置的特点是“工序是固定的”!我以煎蛋为例,如果我想煎三个鸡蛋,并且我有一把足够大的平底锅,我会一次性把三个鸡蛋全部打在刷了足够植物油的锅底,这也是一种自然而然的做法,然而如果用类似iptables内核机制那样的煎锅,不管锅有多大,每次只能煎一个鸡蛋,如果你想煎三个鸡蛋,很简单,重复三次且只能重复三次。这种装置是“不可编程的”!
        我们生活的世界不是这样子的!试想你去一趟超市只能买一样东西,并且不能再去别的地方,现在需要你买来做午饭的所有食材,鉴于超市的蔬菜可能不太新鲜,你要去路对面的蔬菜店单独购买蔬菜,怎么办?使用iptables装置是“可以实现的”,但也仅仅是可以实现而已,除非我们是机器人,否则这种世界是不令人舒适的!我们更容易适应的世界应该是这样子:大早上起床先去海鲜市场买条鱼,然后拎着鱼去蔬菜店买蔬菜,然后拎着鱼和蔬菜寄存在超市,进入超市购买各种肉类,酒水饮料以及家里需要的日用品,结完帐取出寄存的鱼和蔬菜,拎回家或者一起放入汽车的后备箱。
        幸运的是,这就是nftables的方式!
        nftables不再固定“机械装置的行为”,行为完全由你自己来确定,它只是实现了几个足够独立的动作,组合这些动作你几乎可以实现任何操作,事实上,这种新的装置解构了行为,将行为分解成了更加基础的动作,你让它执行什么动作它就执行什么动作,怎么组合这些动作以及最终完成什么样的行为,全在你。这装置是什么?这好像跟电脑很像。其实跟我们人本身更像!稍微术语一点,这就是一部虚拟机。nftables竟然在Linux内核协议栈里实现了一个虚拟机!其实不止一个,而是5个!Netfilter的5个HOOK点上均有一部这样的虚拟机。
        和以往固定的机械装置不同,你灌输给虚拟机的不光是数据,还有程序,而固定的机械装置只能灌输给其数据,因为程序是固定的。
        回过头来我们再来看一下nftables的语法特点,一条规则其实就是一个程序,一个简单的程序就是一个描述性的祈使句,谁,在什么地点,什么时候,用什么,做什么事:
nft add rule ip filter output tcp dport 80 drop
如果想看个究竟,那么加上 --debug=netlink,我们看下其输出:
ip filter output
  [ payload load 1b @ network header + 9 => reg 1 ]
  [ cmp eq reg 1 0x00000006 ]
  [ payload load 2b @ transport header + 2 => reg 1 ]
  [ cmp eq reg 1 0x00005000 ]
  [ immediate reg 0 drop ]

非常明确的一个程序,简直就是另一个Arch上的汇编程序代码,用人话描述这个程序,就是:
从数据包IP头开始算,取出数据包的第10个字节开始的1字节并把它放入reg 1,比较reg 1的值是不是0x06,如果是的话,以数据包TCP头开始算,取出第3个字节开始的2个字节放入reg 1,看看它是不是80,如果是,就指示这个数据包应该丢掉。
关于这个论点,我觉得再继续说下去就有点拖沓了,用一下nftables便知,如果不知,看下其内核代码,比iptables的要简单。
        现在,说点关于人的。
---------------------------------
程序员一般都不懂怎么配iptables规则,甚至都不懂网络,而会配iptables规则的或者会配网络的人一般也不会编程,他们可能是运维管理员,我一直都徘徊在两个阵营之间,最终我自己就死皮赖脸刀枪不入了。我就是个墙头草,跟程序员在一起的时候,说那帮运维只懂搬机器,只会键盘上敲命令,根本就无力修改命令的行为,而编程才是最高贵的随心所欲。然而跟运维在一起的时候,我会说,编程者只会写代码,以为网络就是Socket,充其量就是TCP,根本就不懂IP路由协议,更别提硬件特征比如网卡指示灯,电源了,出了问题他们根本就无力定位,只会撸代码。....虽然说这种自嘲其实是一种自我吹捧,以显得自己什么都会,但如果大家都用nftables的话,我便无力吐槽了。
        nftables的运维者成了编程者。
        因为nftables规则的编写过程就是一个编程的过程,你可以对不服者如下呐喊:
汇编语言和C语言写的程序喂的是CPU这个虚拟机;
Java写的程序喂的是JVM这个Java虚拟机;
nftables编写的规则喂的是Netfilter钩子点上内置的虚拟机。

只要想象一下就兴奋,Netfilter钩子点竟然可以内置虚拟机了,那么如此一来,所有的完成特定功能的Netfilter内核模块都可以扔掉了,在用户态写nftables规则即可。这个特性
可以吸引iptables使用者去使用nftables,因为后者可以“随心所有编程”了!我个人也是比较期待nftables在BSD的Netgraph上有所为的。
        但是如此的想法后只能呵呵,其实nftables还远远没有进化到如此地步。不过基本思想在,我们可以期待nftables的进化。
        以前,你是拿着原材料到传统的代工厂生产了一条规则,如今你是用自家的家伙自己“烹饪”了一条规则。
        nftables引入了运算符,变量和数据结构,这意味着nftables规则的设置者从此成了“编程者”,内核仅仅执行nftables管理员编制的程序,不再做任何假定。
        接近尾声,关于性能相关的话题,我再辩护几句。
---------------------------------
iptables曾经饱受诟病,iptables和Netfilter只能为此承担了责任。因为iptables和其依赖的Netfilter内核模块为用户做的太多了!我们来看看这是为什么。
        iptables规则集由N条规则组成,这些规则和Netfilter的5和HOOK点相关联,在每一个HOOK点上,进入的IP数据报文要遍历所有关联与此点的规则,直到某条规则明确返回ACCEPT或者DROP之类。如果有10000条规则,那就要最多去匹配10000次。除此之外,进入内部,我刚才说过,iptables的内核设施明令规定了规则的结构以及执行过程,写规则的“运维人员”根本就无力像“程序员”那般去修改其行为以便优化,一切都是固定的,如果一个iptables内核模块实现的不好,比如数据结构组织的不好,那么iptables规则的编写者只能兴叹。
        正是因为这种无力,除非必须要用,人们一提起Netfilter/iptables就想到它会影响性能,这其实不是Netfilter的问题,这是iptables的问题,nf-HiPAC也是基于Netfilter的,但为什么就不影响性能呢?
        nftables作为iptables的后继者,摆脱了本不该自己承担的责任。
        从此以后随着nftables版本的进化,它的行为和性能只与“nftables编程者”有关,你再也不能抱怨nftables的效率低下了,如果它的性能低下,那只能怪你编程编的不好。nftables作为拥有自己独立语法的“一种编程语言”,和C语言是类似的,如果你的C语言代码性能很低,你会怪C语言本身吗?不光如此,你不能怪C语言,你也不能怪CPU,所以你不能怪nftables,也不能怪Netfilter。
        包分类这个性能攸关的话题一直以来真的是性能攸关,一般情况下,人们不敢用iptables来搞包分类,这也是事实。后来出现了nf-HiPAC,这玩意儿性能非常高,但是其背后却是复杂的内核代码,伴随着nf-HiPAC作者被招安以及其作品的商业化,你能看到的那个性能比iptables高很多的nf-HiPAC版本其实只是个低级版本。使用nftables的话,你甚至可以“烹饪”出一条基于多维树匹配的规则来,在iptables中,你无力放弃线性的逐条matches匹配,但是在nftables中,你却有能力将其由线性匹配优化成一颗多维匹配树。
---------------------------------
如果你能看到这里,那么下面的内容也就不重要了。但是虽不重要有可能还是比较有用的。最后来点Howto。
        和xtables-addons一样,安装nftables需要先安装以下的包:libmnl-1.0.4.tar.bz2,libnftnl-1.0.6.tar.bz2,readline-6.3.tar.gz,gmp-6.1.2.tar.bz2。这些都很容易找到,我就不给链接了。然后就可以编译nftables了。内核方面的升级并没有难度,我在CentOS 6.7(内核版本为2.6.32)上成功编译了4.9版本内核(将关于nftables的编译选项全部打开)并安装,随后成功安装了nftable并顺利运行,难度并不大。

后记
昨天带着小小参加公司组织的新年健步行,小家伙足足走了7公里,一步都没有让抱,她太猛了。
        今早3点起来写这篇文章,那是我心里有话说。头还有点微微晕,因为昨晚喝多了,我自己竟然喝多了!虽然不胜斗酒诗百篇,我觉得我这篇文章写的还是相当有代入感的(我指前面,而不是这段)。
        自从跟公司同事大规模聚餐喝酒惹事(不是打架斗殴之类的小事,而是关乎前程的大事)之后,我已经快4年不参加同事之间超过3个人的聚众喝酒了。期间真的有几次是真的家里有事需要请假,包括昨天的年会。但每次我也与大家同庆,我自己在家喝的也并不少...我记得那是2014年的年会,那是我的主场,我还抒发了一下比较失败的感言,庆祝项目成功,照例,随后的饭局酒局,我肯定会大醉而归,然而我请假走了,回家跟我老丈人俩人喝了一瓶半白酒,我稍微喝的多点,年会都结束了,我俩还没结束...那时我已经发誓不再超过3人喝酒了...
        然而在去年,我们没有超过3人,我们正好3人,一起去喝了酒,我自觉7,8两的量还可以,结果竟然断片了...然后就发生了让我决定从上海来到深圳的大事...快到11月份启程的日子,我破例一次4人聚餐喝酒...唉,知者自知,不知者也不必知了。
        这很容易让人产生误解,让人觉得清高,让人觉得得瑟,其实这是误解,每个人都有自己的生活,自己的爱好,自己的圈子,自己的面子,像我老丈人说的,人活着就是为了一张嘴,像我表姐天天朋友圈晒的饭局酒场,这些我并不赞同,但我尊重他们,我不喜欢在公司待太久,但我也不喜欢回家,至于那段时间我做什么,那是个人的世界,我本来想再写点的,但这个平台不太合适,就此为止吧。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页