万字总结Linux内核过滤框架(Nftables)
夜已深然未央,準(zhǔn)備接著講述有關(guān)Netfilter的故事,行文有點(diǎn)松散,由于未打草稿,有點(diǎn)隨意識(shí)而流,一氣呵成不知是自夸還是自嘲,權(quán)當(dāng)小時(shí)候?qū)懙娜沼洶?#xff0c;自幼喜歡每天寫日記,中學(xué)時(shí)更是以退士為名折騰了幾箱子抄本,前幾年由于喝酒就改為周記了,現(xiàn)在意識(shí)到了生命短暫,時(shí)間甚是不夠用,不能在迷迷糊糊 中得過(guò)且過(guò),就準(zhǔn)備把自己知道的關(guān)于Linux網(wǎng)絡(luò)的東西一點(diǎn)一滴記錄下來(lái),本來(lái)想繼續(xù)行文于紙上,然而發(fā)現(xiàn)在個(gè)人電腦智能手機(jī)時(shí)代,很多字早就不會(huì)寫 了...上回沒(méi)有說(shuō)完關(guān)于iptables的故事,本文繼續(xù)...
一.nftables前傳-iptables之弊端
iptables幾乎是無(wú)人不知無(wú)人不曉,人們被卷入了框框也就覺(jué)得任何事情都是理所當(dāng)然,但我例外,和其他很多事情一樣,在這個(gè)領(lǐng)域,我依然做并且樂(lè)于做那個(gè)“被排除的人”。
iptables的諸多弊端已經(jīng)不能再視而不見(jiàn),然而只有很少的人看到了這些,大多數(shù)的人作為使用者,僅僅是使用罷了。在此我不會(huì)吐槽很多了。以下的弊端來(lái)自nftables的宣傳文檔,但是即使是在國(guó)外,也引發(fā)了超級(jí)多的爭(zhēng)論:
1.iptables框架在內(nèi)核態(tài)知道得太多,以至于產(chǎn)生了大量的代碼冗余。
這一點(diǎn)是顯而易見(jiàn)的,比如對(duì)于TCP和UDP而言,取sport,dport沒(méi)有什么不同,但是iptables卻使用了兩套代碼,這只是一個(gè)例子,類似的還有很多。
2.iptables的rule結(jié)構(gòu)設(shè)計(jì)不合理。
1.iptables的結(jié)構(gòu)
iptables由表,鏈,規(guī)則組成,其中規(guī)則又由match,target組成。如下面的結(jié)構(gòu)所示:
Table{Chain[Rule(match,match,match,...)->target,Rule(match,match,match,...)->target,...],Chain[...],... }2.iptables的規(guī)則匹配執(zhí)行流程
iptables的規(guī)則是按照配置順序順序匹配的,在每一張表的每一個(gè)鏈上依次匹配每一條規(guī)則,在每一條規(guī)則依次匹配每一個(gè)match,全部匹配的match執(zhí)行該規(guī)則的target,由target決定:
- a.繼續(xù)匹配下一條規(guī)則
- b.對(duì)數(shù)據(jù)包做一些修改
- c.跳轉(zhuǎn)到其它的鏈(即開始從該鏈依次匹配該鏈上的每一條規(guī)則)
- d.返回引發(fā)跳轉(zhuǎn)的鏈(即繼續(xù)匹配跳轉(zhuǎn)前的鏈的下一條規(guī)則)
- e.丟棄數(shù)據(jù)包
- f.接收數(shù)據(jù)包(即不再繼續(xù)往下匹配,直接返回)
- g.記錄日志
- h....
資料直通車:最新Linux內(nèi)核源碼資料文檔+視頻資料
學(xué)習(xí)直通車:Linux內(nèi)核源碼/內(nèi)存調(diào)優(yōu)/文件系統(tǒng)/進(jìn)程管理/設(shè)備驅(qū)動(dòng)/網(wǎng)絡(luò)協(xié)議棧
整個(gè)iptables框架執(zhí)行的流程如下:
循環(huán)1:static breakrule = 0;遍歷一個(gè)chain的每一條rule {nomatch = 0;循環(huán)2:遍歷一條rule的每一個(gè)match {result = rule->match[curr](skb, info);if(result != MATCH) {nomatch = 1;break;}}if (nomatch == 1) {continue該chain的下一條rule;}result = rule->target(skb, info);if (result == DROP) {break丟棄數(shù)據(jù)包 } else if (result == ACCEPT) {break接受數(shù)據(jù)包} else if (result == GOTO) {breakrule = rule;跳轉(zhuǎn)到相應(yīng)的chain,執(zhí)行循環(huán)1} else if (result == RETURN) {break返回調(diào)用chain,執(zhí)行其breakrule的下一條rule} ... }看了上述的代碼就基本知道了iptables的命令實(shí)現(xiàn),程序員能做的就是擴(kuò)展iptables的功能,具體的做法有兩個(gè):寫一個(gè)match以及寫一個(gè)target。除此之外,程序員就沒(méi)轍了,剩下的就看使用者的想象力了...
通過(guò)上面的流程,可以發(fā)現(xiàn),包過(guò)濾的流程最終要落實(shí)到規(guī)則匹配,而過(guò)濾的動(dòng)作最終落實(shí)到了該規(guī)則的target,前面的所有的match匹配返回結(jié)果就是0或者非0表示是否匹配,只有所有的match均匹配,才會(huì)執(zhí)行target。這就決定了下面幾件事:
a.如果你想實(shí)現(xiàn)多個(gè)target,就不得不寫多條規(guī)則
比如實(shí)現(xiàn)log和drop,那么就要寫兩條規(guī)則,或者擴(kuò)展一個(gè)LOG_and_DROP target,前者影響效率,后者需要編程。你很在乎性能,同時(shí)你又不是程序員不懂編程,你就抓狂了...
b.你可以寫一個(gè)match,在里面偷偷摸摸做一點(diǎn)事情,但是外部不知道
這一切太不正規(guī)了,你可以在一個(gè)match里面把一個(gè)數(shù)據(jù)包的校驗(yàn)碼改掉,也可以在里面做log,做NAT什么的,但是iptables的框架的本意雖不允許你這么做但是又沒(méi)有阻止你的行為。
我們可以在iptables執(zhí)行流的一個(gè)細(xì)節(jié)(上述的流程中未畫出)中看到另一個(gè)細(xì)節(jié),即iptables在match中僅僅確定“是否匹配”真的已經(jīng)很 不夠,就連代碼都設(shè)計(jì)得很勉強(qiáng)。如果你看ipt_do_table這個(gè)核心函數(shù),會(huì)發(fā)現(xiàn)一個(gè)控制變量名叫hotdrop,這個(gè)變量是干什么的呢?按照注釋 的意思是:
@hotdrop: drop packet if we had inspection problems這 個(gè)hotdrop作為傳出參數(shù)傳入每一個(gè)match回調(diào)函數(shù),用于在match內(nèi)部指示將一個(gè)數(shù)據(jù)包丟棄。這就暴露出了設(shè)計(jì)的不足,丟棄一個(gè)數(shù)據(jù)包不是 target要做的嗎?一個(gè)match的職責(zé)是選擇該數(shù)據(jù)包是否匹配,干嘛要指示丟棄它呢?這不是越級(jí)么?這只是一個(gè)細(xì)節(jié),你可以說(shuō)出一千個(gè)理由表明它是 合理的,但是它卻是丑陋的!
二.一點(diǎn)小歷史
弄清楚歷史總是能明白更多,這絕對(duì)是一句真話,但是恰恰是專業(yè)化阻止了大多數(shù)的程序員去讀歷史,哪怕是IT的歷史。最好的歷史資料就是原著,Netfilter的歷史不長(zhǎng),從Linux 2.3.15內(nèi)核版本被引入至今,不會(huì)像老子莊子那樣被篡改地體無(wú)完膚。
我們當(dāng)然要看iptables被引入的那段歷史。
iptables被引入旨在替掉ipchains,因?yàn)楫?dāng)時(shí)ipchains的維護(hù)者Rusty Russell認(rèn)識(shí)到它擁有諸多的弊端。總的說(shuō)來(lái),弊端有兩個(gè),其它的都是由這兩個(gè)而發(fā):
a.內(nèi)核的firewall框架僅僅設(shè)置了3個(gè)檢查點(diǎn),即input,forward,output,對(duì)于環(huán)回包以及indev,outdev的控制力很弱;
b.代碼寫死,匹配項(xiàng)固定,沒(méi)有可擴(kuò)展性。
問(wèn) 題就在這里的b。針對(duì)問(wèn)題a,Rusty Russell提出了Netfilter的設(shè)計(jì),精心設(shè)計(jì)了5個(gè)HOOK點(diǎn),解決了幾乎所有的控制點(diǎn)的問(wèn)題,特別是OUTPUT點(diǎn)的設(shè)計(jì)頂級(jí)絕妙,它被安 放在路由之后,原因在于Linux協(xié)議棧的路由操作之后才會(huì)給出完整的過(guò)濾匹配項(xiàng),比如源IP地址,出口設(shè)備等,路由之后的OUTPUT同時(shí)給了調(diào)用者再 次路由的權(quán)限。FORWARD和INPUT作為路由的二分,同時(shí)保持了無(wú)用功最少化,因?yàn)槿绻銢](méi)有打開ip_forward選項(xiàng),即便不是INPUT的 數(shù)據(jù)包也不會(huì)進(jìn)入FORWARD,如果根本就沒(méi)有找到路由,則既不會(huì)到達(dá)INPUT,也不會(huì)到達(dá)FORWARD。對(duì)于PREROUTING而言,它可以通 過(guò)conntrack區(qū)分本地環(huán)回流量和網(wǎng)卡進(jìn)入流量...不管怎么說(shuō),這是內(nèi)核的工作,這個(gè)Netfilter的設(shè)計(jì)十分完美,至今依然被使用。
對(duì)于問(wèn)題b,Rusty Russell提出了iptables,它是一個(gè)高度可擴(kuò)展的框架,也就是從此時(shí)起,iptables擁有了match/target配對(duì)的擴(kuò)展方式,每 當(dāng)需要擴(kuò)展的時(shí)候,每一個(gè)match/target除了有用戶態(tài)的lib之外,還有用內(nèi)核態(tài)的支持,它將ipchains時(shí)代的固定匹配模式變成了可以自 己編程擴(kuò)展的了。
針對(duì)ipchains的弊端,Rusty Russell可謂是給出了完美的解決方案,然而僅此而已!任何一個(gè)來(lái)自同一作者的新的框架幾乎均是為了解決上一個(gè)框架的弊端的,iptables作為一 個(gè)新秀,在獲得歡呼的時(shí)候,不會(huì)有人去考慮它的弊端,任何事情都是這樣,不是嗎?
iptables的弊端是被逐步發(fā)現(xiàn)的,Rusty Russell作為ipchains和iptables的共同作者,它對(duì)待后者取代前者的態(tài)度永遠(yuǎn)都是保守的,一個(gè)全新的框架需要另一個(gè)人或者團(tuán)隊(duì)來(lái)提 出,而不可能出現(xiàn)在Rusty Russell本人手里以及iptables團(tuán)隊(duì)的內(nèi)部。
針對(duì)Netfilter,Rusty寫了大量的文檔,均在Netfilter網(wǎng)站上可以找到:?http://people.netfilter.org/rusty/unreliable-guides/不可否認(rèn),這些都是珍貴的第一手資料,對(duì)于我們理解Netfilter,可能沒(méi)有比這些更好的了。任何人都可以從這些原著中找到“XX為何會(huì)這樣”這種問(wèn)題的蛛絲馬跡,同時(shí)它們也是指導(dǎo)你如何改進(jìn)現(xiàn)有框架的明燈。
三.nftables登場(chǎng)
鑒于iptables的諸多缺點(diǎn)(其實(shí)并不是缺點(diǎn),但是match/target配對(duì)的擴(kuò)展方式導(dǎo)致了開發(fā)者延伸了劣勢(shì),最終將其確定為缺點(diǎn)),nftables旨在一個(gè)個(gè)地改進(jìn)它們。
首先是兩個(gè)問(wèn)題:
a.如何使用一種統(tǒng)一的方式來(lái)解析數(shù)據(jù)包
在這個(gè)問(wèn)題的解決上,u32 match給了作者思路
b.如何執(zhí)行多個(gè)action
事 實(shí)上,是iptables的matches/target配對(duì)的方式限制了開發(fā)者的思路。為何非要區(qū)分match和target呢?iptables框架 的執(zhí)行流程限制了match的結(jié)果就是個(gè)布爾型,所有的動(dòng)作都在target中執(zhí)行,如果去掉了這個(gè)限制,將整個(gè)流程都開放給開發(fā)者,那就靈活多了。 nftables就在這樣的背景下登場(chǎng)了。事實(shí)證明,nftables做的比修正弊端更多,走的更遠(yuǎn)。
首先nftables采用了“虛擬機(jī)解釋字節(jié)碼”的方式,使一條rule真的成了“為一個(gè)數(shù)據(jù)包做一些事情”這樣靈活的命令,而去掉了“匹配所有的 match之后執(zhí)行一個(gè)target”這樣的限制。虛擬機(jī)執(zhí)行字節(jié)碼的方式早就被BPF采用了,我們熟知的tcpdump抓包程序就是利用的它來(lái)過(guò)濾的數(shù) 據(jù)包。我們來(lái)看一下nftables框架的執(zhí)行流程:
循環(huán)1:static breakrule = 0;遍歷一個(gè)chain的每一條rule {nomatch = 0;reg[MAX]循環(huán)2:遍歷一條rule的每一個(gè)expression {void rule->expression[curr]->operations->expr(skb, info, reg)if(reg[VERDICT] != CONTINUE) {break;}}if (reg[VERDICT] == CONTINUE) {continue該chain的下一條rule;} else if (reg[VERDICT] == DROP) {break丟棄數(shù)據(jù)包 } else if (reg[VERDICT] == ACCEPT) {break接受數(shù)據(jù)包} else if (reg[VERDICT] == GOTO) {breakrule = rule;跳轉(zhuǎn)到相應(yīng)的chain,執(zhí)行循環(huán)1} else if (reg[VERDICT] == RETURN) {break調(diào)用chain,執(zhí)行其breakrule的下一條rule} ... }光從這個(gè)流程上看,就已經(jīng)可以和iptables分出勝負(fù)了。可以看到,nftables沒(méi)有match和target,而是將一 條rule抽象成了若干條的表達(dá)式,即expression,所謂的表達(dá)式就是一個(gè)主語(yǔ)加謂詞的式子,它是“可執(zhí)行”的,它可以“做任何事情”,而不僅僅 是計(jì)算一個(gè)匹配結(jié)果。除此之外,nftables內(nèi)置了一組寄存器,其中之一是verdict寄存器,它指示了“下一步要怎么做”。
每一條 expression執(zhí)行完了之后,會(huì)取出該寄存器,由該寄存器的值來(lái)采取下一步的行動(dòng)。這個(gè)verdict寄存器替換了iptables中target 返回值,這就可以在一條rule中采取多個(gè)動(dòng)作,每條動(dòng)作可以解析成一個(gè)expression,每一個(gè)expression在執(zhí)行后將verdict寄存 器設(shè)置為CONTINUE即可!
除了執(zhí)行流程的顯著區(qū)別之外,nftables最大的意義在于它對(duì)expression進(jìn)行了抽象,nftables的內(nèi)核框架可以注冊(cè)很多種的 expression,每一種都有一個(gè)操作集,其中expr回調(diào)函數(shù)執(zhí)行具體的expression表達(dá)式。典型的expression有:
payload表達(dá)式:
將一個(gè)數(shù)據(jù)包的某一段數(shù)據(jù)拷貝到一個(gè)nftables寄存器指示的緩沖區(qū),除了出錯(cuò)之外verdict寄存器均為CONTINUE。
compare表達(dá)式:
將某段數(shù)據(jù)和nftables寄存器指示的緩沖區(qū)作比較,若不相等則設(shè)置verdict寄存器為BREAK。
counter表達(dá)式:
按照數(shù)據(jù)包的大小遞增字節(jié)計(jì)數(shù)器以及包計(jì)數(shù)器的值,保持verdict寄存器為CONTINUE。
log表達(dá)式:
對(duì)數(shù)據(jù)包記錄日志,保持verdict寄存器為CONTINUE。
nat表達(dá)式:
按照nftables寄存器的數(shù)值對(duì)數(shù)據(jù)包做NAT,verdict寄存器設(shè)置為NAT操作的結(jié)果,注意,NAT的參考數(shù)據(jù)均來(lái)自nftables寄存器。
compat表達(dá)式:
保 持對(duì)iptables的兼容性。細(xì)分為match寄存器以及target寄存器,其中match表達(dá)式調(diào)用iptables rule的match,若匹配設(shè)置verdict寄存器為CONTINUE,否則為BREAK;target表達(dá)式調(diào)用iptables rule的target,并根據(jù)target的結(jié)果設(shè)置verdict寄存器。
回到nftables的執(zhí)行流程,結(jié)合上述的表達(dá)式,看看這一切像什么?
這難道不就是一個(gè)解釋器嗎?類似高級(jí)語(yǔ)言比如Python的解釋器,將每一個(gè)表達(dá)式解釋執(zhí)行,我們可以將一條nftables rule分解為一系列的表達(dá)式,僅此而已,如下所示:
expr1: reg[verdict] = CONTINUE; reg[0] = skb[m...n]; expr2: info[0] = something from userspace; ret = compare(reg[0], info[0]);if (ret == true) ; then reg[verdict] = CONTINUE; else reg[verdict] = BREAK; break; fi expr3: log_packet(skb); expr4: ret = do_nat_packet(skb, reg[i]/*address to trans*/...); if (ret == true) ; then reg[verdict] = CONTINUE; else reg[verdict] = BREAK; break; fi ...看看吧,一條規(guī)則做了多少事情啊啊啊!解釋器按照expr1到expr4的順序執(zhí)行expression,每次執(zhí)行下一個(gè)expression之前要檢查verdict寄存器,那么誰(shuí)是解釋器,當(dāng)然就是上面的nftables的執(zhí)行流程啦!
nftables到底是什么玩意兒?實(shí)則一個(gè)虛擬機(jī)!那么這部虛擬機(jī)執(zhí)行的指令來(lái)自何方?來(lái)自用戶態(tài)的配置。用戶態(tài)怎么配置?當(dāng)然是使用nft命令。nft是什么命令?是類似iptables的命令。nft命令能否舉一個(gè)例子?能:
nft add rule ip filter input ip saddr 1.1.1.1 drop這 條命令怎么和諸多的表達(dá)式對(duì)應(yīng)?答案是nft命令行工具內(nèi)置了一個(gè)”編譯器“,將一條human readable命令編譯成了一個(gè)個(gè)的expression代碼。編譯的細(xì)節(jié)是什么?可以寫一本書,但是了解一下tcpdump的方式也就該能理解了。 tcpdump命令最終會(huì)將編譯好的指令注入到內(nèi)核的BPF系統(tǒng),以下是一條很常見(jiàn)的tcpdump命令:
tcpdump -i eth0 dst 1.1.1.1它會(huì)翻譯成什么代碼呢?后面跟上-dd參數(shù)就可以看出來(lái):
root@debian:/usr/local/etc/nftables# tcpdump -i eth0 dst 1.1.1.1 -dd { 0x28, 0, 0, 0x0000000c }, { 0x15, 0, 2, 0x00000800 }, { 0x20, 0, 0, 0x0000001e }, { 0x15, 4, 5, 0x01010101 }, { 0x15, 1, 0, 0x00000806 }, { 0x15, 0, 3, 0x00008035 }, { 0x20, 0, 0, 0x00000026 }, { 0x15, 0, 1, 0x01010101 }, { 0x6, 0, 0, 0x0000ffff }, { 0x6, 0, 0, 0x00000000 },具 體是什么意思請(qǐng)參考BPF的手冊(cè)。nftables設(shè)置的規(guī)則最終也會(huì)被”編譯“成類似的”指令“注入到內(nèi)核的nftables系統(tǒng),形成一個(gè)個(gè)的 expression。要注意,并不是所有的規(guī)則指令都是可以編譯的,比如iptables兼容指令就不能編譯,log指令也不能被編譯。
nftables就是這樣一個(gè)具有美感的包過(guò)濾框架,理解了它的運(yùn)行方式之后,你就可以擴(kuò)展它了,和iptables擴(kuò)展match/target不同, 對(duì)于nftables,你只需要擴(kuò)展expression即可,就是說(shuō)你要自己編寫expression,然后讓nftables虛擬機(jī)(即上面的執(zhí)行流 程)執(zhí)行它就可以了。最后,我們來(lái)看一下nftables框架的結(jié)構(gòu):
Table{Chain[Rule(expression,expression,expression,...)Rule(expression,expression,expression,...)...],Chain[...],... } expression := expression | datatype | operation | expression | datatype operation := + | - | * | / | memcpy | contain | ... datatype := u8 | u16 | u16 | ... | container | ... container := hash | map | tree | set | list | array | ...四.這一切到底怎么了
值得注意的是,雖然nftables在美學(xué)角度上完勝iptables,但是作為一個(gè)框架,它的性能并不十分高效。和nf-hipac相 比,iptables并不比nftables輸?shù)酶鼞K些。事實(shí)上,nftables和iptables一樣,對(duì)于一條chain上的所有rule,也是逐 條遍歷的,所不同的只是遍歷每條rule時(shí)執(zhí)行具體匹配的方式有所不同。那么和nf-hipac相比,nftables為何成功了?
其實(shí)nftables還遠(yuǎn)遠(yuǎn)沒(méi)有成功,它的阻力不是來(lái)自性能,而是來(lái)自iptables的陣營(yíng)!nftables作為一個(gè)優(yōu)美的框架,考慮的不僅僅是性 能,事實(shí)上性能只是其考慮的極小的一方面。作為一個(gè)框架,它首先要考慮的是擴(kuò)展性以及和iptables的兼容性。反對(duì)的聲音分分鐘響徹于 耳,iptables并沒(méi)有錯(cuò),match/target配對(duì)的方式并沒(méi)有錯(cuò),match就是要返回true or false,最終的結(jié)果就是要target來(lái)執(zhí)行,總之就是要區(qū)分match和target,并且各司其職!!
覺(jué)得iptables不能執(zhí)行多個(gè)動(dòng)作的為何不自己寫一個(gè)可以執(zhí)行多個(gè)動(dòng)作的target啊啊啊?!
覺(jué)得iptables逐條執(zhí)行且不能完成nf-hipac創(chuàng)舉的為何不將nf-hipac封裝成一個(gè)單獨(dú)的match啊啊啊?!
封裝成單獨(dú)match的nf-hipac看起來(lái)會(huì)是:
iptables -A INPUT -m hipac --match-hipac hipac_test -j NOTHING nf-hipac create hipac_test nf-hipac add hipac_test -s 1.1.1.1 -j DROP ...看到iptables的優(yōu)勢(shì)了吧,人家根本就不是來(lái)和nf-hipac拼性能的,人家是海納百川的,人家有容乃大!難道姓毛的椅子男要上戰(zhàn)場(chǎng)拚*** 嗎?NO!NO!NO!姑且不談nf-hipac,和上面類似的還有ipset,ipset不就是被封裝成一個(gè)match而和iptables聯(lián)動(dòng)的 嗎?iptables并不差,錯(cuò)在人們根本就不該直接將每一個(gè)簡(jiǎn)單功能擴(kuò)展成一套match/target聯(lián)合體,最終形成令人作嘔的代碼!是這樣嗎?
好吧!我承認(rèn)上面的YY都是對(duì)的!但是看看nftables,它是不是也可以這么玩并且玩得更high呢?!是啊!是吧!nftables內(nèi)部直接內(nèi)置了 諸多的容器類數(shù)據(jù)類型,比如rbtree,hash等,作為一種復(fù)合容器,你往里面放東西就是了,還用寫match嗎?我這么說(shuō)的意思是,寫過(guò) match/target的都知道,要例行多少公事啊,你要注冊(cè)match或者target,還要復(fù)制很多管理代碼,看過(guò)xtables-addons的 都知道其中之苦。
使用nftables的話,如果你想為iptables擴(kuò)展一個(gè)功能模塊,很多工作都可以在用戶態(tài)完成,換句話說(shuō),如果僅僅是基于 skb(即數(shù)據(jù)包)的內(nèi)容做過(guò)濾,那么nftables便是協(xié)議無(wú)關(guān)的,因?yàn)椴还苁裁磪f(xié)議,你都可以將過(guò)濾表達(dá)式用 payload,compare,bit等簡(jiǎn)單的expression開表示,協(xié)議解析的工作在用戶態(tài)編譯nftables指令的時(shí)候完成即可,到了內(nèi)核 態(tài),nftables虛擬機(jī)只執(zhí)行表達(dá)式,不管協(xié)議!
世界在向前走,我們要向前看!看看Linux的包過(guò)濾框架,從最初的移植BSD的實(shí)現(xiàn),到現(xiàn)在的nftables,中間經(jīng)歷了多少的坎坷曲折,每次有新東 西進(jìn)來(lái)總是會(huì)有復(fù)古者的謾罵!這下可好,這下可好,Linux內(nèi)核在主干上直接內(nèi)置了nftables的支持,正如當(dāng)初Netfilter進(jìn)入主干時(shí)的情 形一樣。
Just do it,劃時(shí)代的nftables,我并不是說(shuō)它有多么猛,而是說(shuō),它真的很干凈。
tables,chains,這名字叫得真不好,可是無(wú)論如何它也只是個(gè)名字而已。iptables要不是因?yàn)槊?#xff0c;我也不會(huì)為了理解它糾結(jié)那么久,現(xiàn)在 又來(lái)個(gè)nftables...Cisco管類似的東西叫做list,即ACL,也只是個(gè)名字,如果說(shuō)tables不好聽,list是不是顯得更低級(jí)呢?不 管低級(jí)不低級(jí),華為也延續(xù)了Cisco的叫法。因此下一代的包過(guò)濾框架也叫做tables,估計(jì)顯示文化上的認(rèn)同要比其實(shí)質(zhì)更加有用吧,特別是對(duì)待起名字 這件事上。iptables已經(jīng)深入人心,nftables這個(gè)名字會(huì)讓人更容易接受。當(dāng)初iptables替代ipchains,那是革命性的替換,而 這次,更多的顯示出來(lái)的是成熟Linux機(jī)制的一種自然而然的演變,或者說(shuō)進(jìn)化更合適些吧。
五.nftables用起來(lái)
我第一時(shí)間想的是在2.6.32上將nftables跑起來(lái),然而失敗了,根本就沒(méi)有辦法編譯。那么下面就是想辦法了,看了很多的宣傳文檔和HOWTO以及nftables的主站,花了好久clone了git映像,編譯通過(guò),終于跑起來(lái)了。
后來(lái)我干脆直接在http://kernel.org上下載3.17版本的內(nèi)核,在make config的時(shí)候?qū)ft相關(guān)的東西都給選上,然后編譯更新內(nèi)核。同時(shí)下載用戶態(tài)的nftables-0.3版本utils,編譯之,過(guò)程中缺什么補(bǔ)什 么,最終很順利。在make install之后,首先執(zhí)行:
nft -f /usr/local/etc/nftables/ipv4-filter這條命令是在內(nèi)核中載入了filter表,除了執(zhí)行預(yù)先配置好的文件,你也可以手工載入table。
在table,chain就緒之后,就是在自己希望的chain上添加rule了:
nft add rule ip filter output ip daddr 1.2.3.4 drop其它的用法請(qǐng)man nft,非常詳細(xì)但不詳盡的文檔,另外的好資料在?https://home.regit.org/netfilter-en/nftables-quick-howto以及?https://home.regit.org/2014/01/why-you-will-love-nftables!
我為何沒(méi)有將其移植到低版本的內(nèi)核上呢?因?yàn)槲矣X(jué)得這太簡(jiǎn)單了,為何出此狂言?因?yàn)閚ftables僅僅和Netfilter的 nf_register/unregister_hooks接口,其它的都是其框架內(nèi)部做的,其復(fù)雜性在于nft_expr_ops,而這個(gè)是非常獨(dú)立 的,和既有的內(nèi)核沒(méi)有任何關(guān)系。對(duì)于用戶態(tài)utils,本身就有一個(gè)nftables項(xiàng)目存在,就是一個(gè)編譯問(wèn)題,而這個(gè)編譯是本來(lái)就能通過(guò)編譯的。
六.配置防火墻變成了編程
本文的最后,我來(lái)從全局的角度看一下nftables和iptables的最終區(qū)別。
=我已經(jīng)從內(nèi)部原理的角度分析了nftables帶來(lái)的改變,那么這些給用戶到底能帶來(lái)多少實(shí)惠呢?如果沒(méi)有實(shí)惠,那么在用戶群中是不會(huì)有動(dòng)力切換到 nftables的。實(shí)惠不多,只有一個(gè),但是僅此就夠了,那就是:nftables讓用戶可以按照編程的思想來(lái)組織自己的配置邏輯。
=怎么說(shuō)呢?我們來(lái)看一個(gè)wiki上展示的例子吧:
nft add rule ip filter input ip protocol vmap { tcp : jump tcp-chain,udp : jump udp-chain , icmp : jump icmp-chain }這是什么?這是一條“編程語(yǔ)句”,它擁有一個(gè)簡(jiǎn)單的if-else if-else if邏輯,或者你把它當(dāng)成switch-case也可以。注意,這可是在一條規(guī)則中完成的!如果用iptables的話,你不得不獨(dú)立寫多條規(guī)則。以上的語(yǔ)句多么像是:
這是什么?這是一條“編程語(yǔ)句”,它擁有一個(gè)簡(jiǎn)單的if-else if-else if邏輯,或者你把它當(dāng)成switch-case也可以。注意,這可是在一條規(guī)則中完成的!如果用iptables的話,你不得不獨(dú)立寫多條規(guī)則。以上的語(yǔ)句多么像是:
proto = skb->net_hdr->proto; if (proto == tcp) {tcp_chain(skb); } else if (proto == udp) {udp_chain(skb); } else if (proto == icmp) {icmp_chain(skb); }nftables變成了真正的編程語(yǔ)言!既然成了編程語(yǔ)言,如果支持變量將會(huì)是多么靈活的一件事啊,幸運(yùn)的是,哦,不,不能說(shuō)幸運(yùn),而是nftables原生的性質(zhì),nftables支持“變量”!注意下面的命令:
nft add set filter blackhole { type ipv4_addr\;} nft add rule ip input ip saddr @blackhole drop nft add element filter blackhole { 192.168.1.4, 192.168.1.5 }雖然iptables的ipset match也可以這樣做,但是那畢竟只是一個(gè)match而已,nftables原生就支持這種語(yǔ)法!甚至,甚至還可以用字典映射策略的語(yǔ)法:
nft add map filter mydict { type ipv4_addr : verdict\; } nft add rule filter input ip saddr vmap @mydict nft add element filter mydict { 192.168.0.10 : drop, 192.168.0.11 : accept }這樣一來(lái),管理員將會(huì)像程序員一樣靈活組織自己的邏輯。
七.一個(gè)有點(diǎn)悲觀的事實(shí)
去 搜一下ipchain的文檔,幾乎沒(méi)有幾個(gè)能打開的,然后去搜iptables的,目前人氣還很旺,nftables的呢?能搜到結(jié)果,但是想用起來(lái)要費(fèi) 點(diǎn)勁。這就是前仆后繼的過(guò)程,可以設(shè)想將來(lái)的某天,nftables也會(huì)像ipchain一樣逐漸冷淡,淡出人們的視線...這難道就是Linux環(huán)境包 過(guò)濾框架的宿命嗎?
這并不是技術(shù)發(fā)展的必然,老牌的UNIX工具vi,Emacs直到現(xiàn)在依然是黑客們的利器,網(wǎng)絡(luò)工具netcat也是小巧便攜經(jīng)久不衰...而Linux 的包過(guò)濾框架短短的15年間更新?lián)Q代了多次。令人感到希望的是Netfilter這個(gè)底層的框架基本已經(jīng)穩(wěn)定,不管是iptables還是 nftables,都是基于Netfilter來(lái)開發(fā)的,而早期的ipfw則不是,那時(shí)的(Linux 2.3.15內(nèi)核之前的)底層包過(guò)濾框架及其簡(jiǎn)陋,因此Netfilter一出現(xiàn)就上位了。值得注意的是,這里面包含了太多的是開發(fā)者Rusty Russell的個(gè)人風(fēng)格,Netfilter是他完成的,ipchains也是他,這不禁讓人想起了破立有秩的Ingo Molnar,引入了O(1)調(diào)度器,然后卻用更好的CFS調(diào)度器替換了它...UNIX則非常不同,個(gè)人因素少之又少...
總結(jié)
以上是生活随笔為你收集整理的万字总结Linux内核过滤框架(Nftables)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java短信接口开发完整项目_java项
- 下一篇: linux aptana,如何设置内部浏