探索iptables BPF模組的悲慘歷程

2021-09-06 10:27:13 字數 4817 閱讀 2614

接下來的事情就不能一筆帶過了,但是在詳述之前還是要帶幾筆,第3部是必要的,因為既然選擇了debian,就是喜歡它的工具集,否則隨便乙個發行版即可,第5步看似只是乙個水到渠成的結果,然後這個步驟是我花時間最多的。

debian自身有一套編譯kernel的工具,稱為kernel-package,它可以將最終生成的kernel映像,driver,initrd映像以及開發使用的headers打包成乙個deb包,可以直接安裝在debian發行版上,如果沒有這個套件,你毫無疑問就要花很多時間來編譯核心以及driver了,光是initrd就不一定能一次性做成功,即使你把這些都封裝進了shell,你也要時刻關注shell的執行,起碼不可能按下回車後去再看一段《勝者的迷思》了,由於使用了kernel-package,在編譯過程中,我竟然把《勝者的迷思》看完了!debian的工具是專門為debian上的開發者打造的,所以即使有問題,早就被其它人通告給了debian社群,早就改正了。構建這個工具套件很簡單:

apt-get install kernel-package

另外,為了能使用menuconfig配置kernel,還要安裝乙個東西:

apt-get install libncurses5-dev

必要的工具構建完畢,剩下的就是編譯核心了,這次折騰的直接目的是玩bpf模組,因此切記要在menuconfig配置核心的時候使能bpf配置,它在core netfilter configuration中的"bpf" match support,其它的就先別管了,直接使用debian 7的config檔案即可,然後就可以目睹kernel-package的風采了,注意上述的操作要分步驟完成:

第一步:cp /boot/config-3.2.0-4-amd64 /usr/src/linux-3.9.6/.config

第二步:make menuconfig

第三步:make-kpkg --initrd kernel-image && make-kpkg kernel-headers && find /usr/src/ -type deb -name *.deb|xargs -i dpkg -i {} &&reboot

第四步:找本書看,或者找個電影看,但是為了讓電腦全速編譯,還是換一台電腦心理上會得到安慰(note:心理上!);

以上就編譯完了新核心了,uname看一下,已經公升級到3.9.6了,kernel-header也在/usr/src下就位,/lib/modules/3.9.6/build也就位,剩下的工作就是編譯iptables了,這個十分簡單,也分為幾個步驟:

第一步:configure --enable-nfbpf-compiler;這個enable特別重要,其實這是我在寫iptables規則屢次不成功後返回來重新加上這個選項編譯的,一開始我是直接configure的,自以為耍小聰明可以過關,結果在編寫iptables測試的時候悲劇了!

第二步:make && make install

準備工作到此就做完了,此時的時間是上午8點半,吃完早飯因為要去買菜做午飯(由於今天老婆帶女兒上早教去了,我留守做飯,由於我做事比較分步有條理,所以就比較慢,做個簡單的午飯也要乙個步驟乙個步驟的從早晨八點開始...),iptables測試工作放在午後進行...

終於可以寫規則了,下意識的寫下以下的規則:

iptables -a input -m bpf --bytecode '傻眼了' -j drop

其實我的要求很簡單,就是想將bytecode設定為icmp,可是又不知道bpf的具體語法以及指令,原理是再明白不過了,可是到了實際操作,又懶得查手冊,既然不想查手冊,也就很難自己寫乙個翻譯程式出來,比如將tcp port 1234之類的翻譯成符合bpf語法的bytecode,於是想到從tcpdump裡面把**摳出來,然而那種行為有點巧奪天工了,一向不太在意**的我,如今被**折騰了。其實啊,像tcpdump這樣成熟的程式,一定有什麼引數可以將bpf的code列印出來的,這真的就是我的直覺,大多數玩過gnu**的都知道,作者在寫這段**的時候,肯定print過這些東西,最終發布時,就作為一種除錯資訊留下了,既然**都開源了,為何不讓用**的人更方便呢?事實也確實如是,man一下tcpdump,就會發現其d,dd,ddd選項,正是做這個的,以下就是這些東西,我還是以匹配icmp為例:

@首先看一下十進位制的code

root@zhaoya:/usr/src/linux-3.9.6/net/netfilter# tcpdump -i any icmp  -ddd

40 0 0 14

21 0 3 2048

48 0 0 25

21 0 1 1

6 0 0 65535

6 0 0 0

@雖然沒有意義,也看一下16進製制的code吧,起碼知道每行是個4元組

root@zhaoya:/usr/src/linux-3.9.6/net/netfilter# tcpdump -i any icmp  -dd,,

,,,,

@最後領略一下它的助記碼,類似彙編的指令

root@zhaoya:/usr/src/linux-3.9.6/net/netfilter# tcpdump -i any icmp  -d

(000) ldh      [14]

(001) jeq      #0x800           jt 2    jf 5  #ip協議

(002) ldb      [25]

(003) jeq      #0x1             jt 4    jf 5    #icmp協議

(004) ret      #65535

(005) ret      #0

既然有了這個,我當然喜出望外了,於是趕緊測試,google了一下bytecode的語法,還算簡單:

code=$(tcpdump -i any icmp  -ddd| tr '\n' ',')

即可,於是上述的「傻眼了」被code填充,拍下回車,ping閘道器,竟然是通的!dmesg也沒有任何報錯,於是我想得到,是bytecode有問題!然而到**去找正確的呢?失望之餘,真心有種自己寫乙個解析器的慾望了,廚房開啟抽油煙機穩定了一下情緒,還是google吧,別人做好的東西為何自己再做一遍呢!google發現iptables本來就有乙個叫做nfbpf-compiler的工具,在utils裡面,於是我就重新編譯了它,其實在iptables的bpf模組的help中就明確寫出了乙個格式,那就是:

--bytecode `nfbpf_compiler raw `

過於激動,文件都沒有看仔細,真是罪過!於是按照這個格式,將替換為'icmp',果真成功了,ping不通了,於是我想看看通過nfbpf_compiler生成的code和tcpdump生成的code有何不同,以下是工具生成的:

root@zhaoya:/usr/src/linux-3.9.6/net/netfilter# nfbpf_compile raw 'icmp'

7,48 0 0 0,84 0 0 240,21 0 3 64,48 0 0 9,21 0 1 1,6 0 0 65535,6 0 0 0

太大不同了啊,到底怎麼回事?我注意到了raw引數,我隱約記得raw是乙個linktype,當時研究tcpdump時好像注意過,因為有人問我en10mb是什麼型別,我當時也不知道,查資料時發現了它其實就是乙個鏈路層型別,和它並列的還是atm等(這些曾經網路層的協議在tcp/ip的天下都退化成了鏈路層),那麼raw是什麼,其實和socket的raw差不多,都是指裸ip,也就是說它沒有鏈路層或者說忽略鏈路層。到此,我終於明白,tcpdump的eth系列網絡卡翻譯過來的code明確就是en10mb,也就是乙太網協議,通過tcpdump -i eth0 -l看一下它都可以使用哪些linktype,令人失望!於是想用lo做實驗,可是lo也是和eth0一樣,lo怎麼會模擬乙太網卡啊啊啊啊!在mac上,lo0明確就是null,這才合理啊!具體參見 吧,反正即使看了也得不到什麼有用的,我們大多接觸到的都是en10mb!看一下nfbpf_compiler使用en10mb的結果:

root@zhaoya:/usr/src/linux-3.9.6/net/netfilter# nfbpf_compile en10mb 'icmp'

6,40 0 0 12,21 0 3 2048,48 0 0 23,21 0 1 1,6 0 0 65535,6 0 0 0

和tcpdump的結果及其類似!

反過來思考一下,bpf match為何不能使用ne10mb code呢?我看了xt_bpf patch的跟帖,作者的例子就是en10mb的啊!為何發布版不行了呢?難道是怕linktype太多,如果沒有處理就容易panic??看來沙漏細腰部位的ip**好寫啊!不管怎樣,事情總算是搞定了,總結一下有幾點教訓:

1.玩新東西之前一定要看文件,看手冊,現在不再一頭紮進**裡了,這是進步,但是在有了問題的時候也別指望僅僅看**就能解決。

2.編譯時的引數選項一定要注意,有時候並不是程式的bug,只是因為你在編譯的時候就自動放棄了那個你想要的功能。

3.還是那句話,別人已經做好的東西,自己就別再做了(bpf編譯程式寫了一半...),已經不是10年前那個把排序演算法寫一遍的青春期晚期了,現在要惜時如金,想練手就練別人沒人練過的!

最後,其實不像本文題目所說的那樣,這個歷程並不悲慘,這是因為大家普遍都喜歡悲劇罷了,一部悲劇看完以後,你會發現,可能它就是一部帶有黑色幽默的喜劇。當然,大半夜被女兒吵鬧的聲音吵醒看似挺悲慘的,但是有孩子的知道,真的悲慘嗎?可能也是一種幸福吧,沒孩子的,將來會懂得...

《勝者的迷思》,今日完結,明日早晨五點《條條大道通羅馬》!另,還有乙個好玩的,那就是debian上的ufw!

PHP核心探索 Apache模組介紹

apache概述 apache是目前世界上使用最為廣泛的一種web server,它以跨平台 高效和穩定而聞名。按照去年官方統計的資料,apache伺服器的裝機量占該市場60 以上的份額。尤其是在x unix linux 平台上,apache是最常見的選擇。其它的web server產品,比如iis...

linux 2 6 核心模組程式設計探索

乙個linux 核心模組程式設計的手記,未寫完不斷更新中 一 相關命令 0 檢視系統裝載了哪些 核心模組 lsmod modulename 1 載入核心模組 insmod modulename 2 解除安裝核心模組 rmmod modulename 3 建立裝置檔案 mknod filename d...

linux 2 6 核心模組程式設計探索

乙個linux 核心模組程式設計的手記,未寫完不斷更新中 一 相關命令 0 檢視系統裝載了哪些 核心模組 lsmod modulename 1 載入核心模組 insmod modulename 2 解除安裝核心模組 rmmod modulename 3 建立裝置檔案 mknod filename d...