iptables深入解析:filter應用篇

發表於2015-08-24

上一篇文章分析了iptables程式碼下發運作的流程細節,篇幅有限還有很多需要補充.關於netfilter的框架網上已經被講爛了,框架很簡單,但是實現卻不簡單.但不論什麼都要最終歸到實際應用上,才能體現其價值.

下面我們就以iptables1.4.21 ubuntu14 32位 核心版本 3.13.0為環境來開發一個最常規的擴充套件應用.

首先下載iptables原始碼:http://www.netfilter.org (這個網站有很多東西,可以好好看看)

關於linux kernel netfilter開啟的配置,這裡不多說,預設核心已經配置好了.(當然對於ubuntu14 系統預設把netfilter大部分都編譯成了核心模組,需要什麼自己手動安裝即可)

先說說編譯iptables,很簡單 看看裡面的說明文件即可,例INSTALL:
$./configure
$make
$make install

./configure 還可以支援一些選項引數 ,裡面都有說明。例子如下:
./configure –prefix=/home/iptables –host=arm-linux // host可以不指定,自動判定,預設就是x86
這裡還要補充點知識:動作的說明:

iptables動作———DROP、ACCEPT、REJECT

◆ACCEPT
一旦包滿足了指定的匹配條件,就會被ACCEPT,並且不會再去匹配當前鏈中的其他規則或同一個表內的其他規則,但它還要通過其他表中的鏈

◆DROP
如果包符合條件,這個target就會把它丟掉,也就是說包的生命到此結束,不會再向前走一步,效果就是包被阻塞了。在某些情況下,這個target會引起意外的結果,因為它不會向傳送者返回任何資訊,也不會向路由器返回資訊,這就可能會使連線的另一方的sockets因苦等迴音而亡:)

解決這個問題的較好的辦法是使用REJECT target,(注:因為它在丟棄包的同時還會向傳送者返回一個錯誤資訊,這樣另一方就能正常結束),尤其是在阻止埠掃描工具獲得更多的資訊時,可以隱蔽被過濾掉的埠等等(譯者注:因為掃描工具掃描一個埠時,如果沒有返回資訊,一般會認為埠未開啟或被防火牆等裝置過濾掉了)。還要注意如果包在子鏈中被DROP了,那麼它在主鏈裡也不會再繼續前進,不管是在當前的表還是在其他表裡。

◆REJECT
REJECT和DROP基本一樣,區別在於它除了阻塞包之外,還向傳送者返回錯誤資訊。現在,此target還只能用在INPUT、FORWARD、OUTPUT和它們的子鏈裡,而且包含 REJECT的鏈也只能被它們呼叫,否則不能發揮作用。它只有一個選項,是用來控制返回的錯誤資訊的種類的。

還有其他的動作:
LOG             用來記錄與資料包相關的資訊
MARK          設定mark值,這個值是一個無符號的整數
MASQUERADE             和SNAT的作用相同,區別在於它不需要指定–to-source
SNAT             源網路地址轉換
DNAT             目的網路地址轉換
REDIRECT             轉發資料包一另一個埠
REJECT             REJECT和DROP都會將資料包丟棄,區別在於REJECT除了丟棄資料包外,還向傳送者返回錯誤資訊
RETURN             使資料包返回上一層
TOS             用來設定IP頭部中的Type Of Service欄位
TTL             用於修改IP頭部中Time To Live欄位的值
ULOG             ULOG可以在使用者空間記錄被匹配的包的資訊,這些資訊和整個包都會通過netlink socket被多播
QUEUE             為使用者空間的程式或應用軟體管理包佇列
MIRROR             顛倒IP頭部中的源目地址,然後再轉發包

先一個實際的命令應用:
IPT -A INPUT -m pkttype –pkt-type broadcast -j REJECT
這裡我們自己註冊一個match 傳遞自己的引數並解析處理。
功能是禁止大於特定長度的ip報文通過 size由我們指定。

需要兩個部分的工作
1.使用者空間match的註冊
2.核心空間match的註冊
根據程式碼裡pkttype的實際例子作為參考,很快我們就能幹一票了.

需要修改的檔案:

使用者空間
Xt_pktsize.c // 路徑extensions下
Xt_pktsize.h // 路徑 include/linux/netfilter/
核心:這裡編譯為模組的方式
Xt_pktsize.c
Xt_pktsize.h

註冊match當然首先要初始化它各個節點的元素
使用者空間程式碼如下:
xt_pktsize.h

xt_pktsize.c

通過程式碼我們看到主要工作就是初始化struct xtables_match,然後註冊而已. 它的核心函式是x6_parse/parse

或者

例子中為 pktsize_parse函式,之前我們已經分析過如何呼叫到某一個match的parse函式.主要解析ipt_entry_match裡data(其實就是解析命令引數賦值給它)
除了parse函式還有options,即解析–XXX的引數需要用到的東西,也需要我們去填寫。

下面看看核心部分:
xt_pktsize.h

xt_pktsize.c

這裡我們計算ip報文的有效載荷的長度即ip包的總長度-ip頭的長度
size=ntohs(iph->tot_len) – (iph->ihl*4);
同樣或許我們還需要判斷協議型別 protocal字等,簡單說幾個常用:
Decimal  Keyword          Protocol                                 References
——-  —————  —————————————  ——————
1        ICMP             Internet Control Message                 [RFC792]
6        TCP              Transmission Control                     [RFC793]
17       UDP              User Datagram                            [RFC768][JBP]

ip報文格式如下:

版本:佔4位(bit),指IP協議的版本號。目前的主要版本為IPV4,即第4版本號,也有一些教育網和科研機構在使用IPV6。在進行通訊時,通訊雙方的IP協議版本號必須一致,否則無法直接通訊。
首部長度:佔4位(bit),指IP報文頭的長度。最大的長度(即4個bit都為1時)為15個長度單位,每個長度單位為4位元組(TCP/IP標準,DoubleWord),所以IP協議報文頭的最大長度為60個位元組,最短為上圖所示的20個位元組。
服務型別:佔8位(bit),用來獲得更好的服務。其中的前3位表示報文的優先順序,後面的幾位分別表示要求更低時延、更高的吞吐量、更高的可靠性、更低的路由代價等。對應位為1即有相應要求,為0則不要求。
總長度:16位(bit),指報文的總長度。注意這裡的單位為位元組,而不是4位元組,所以一個IP報文的的最大長度為65535個位元組。
標識(identification):該欄位標記當前分片為第幾個分片,在資料包重組時很有用。
標誌(flag):該欄位用於標記該報文是否為分片(有一些可能不需要分片,或不希望分片),後面是否還有分片(是否是最後一個分片)。
片偏移:指當前分片在原資料包(分片前的資料包)中相對於使用者資料欄位的偏移量,即在原資料包中的相對位置。
生存時間:TTL(Time to Live)。該欄位表明當前報文還能生存多久。每經過1ms或者一個閘道器,TTL的值自動減1,當生存時間為0時,報文將被認為目的主機不可到達而丟棄。使用過Ping命令的使用者應該有印象,在windows中輸入ping命令,在返回的結果中即有TTL的數值。
協議:該欄位指出在上層(網路7層結構或TCP/IP的傳輸層)使用的協議,可能的協議有UDP、TCP、ICMP、IGMP、IGP等。
首部校驗和:用於檢驗IP報文頭部在傳播的過程中是否出錯,主要校驗報文頭中是否有某一個或幾個bit被汙染或修改了。
源IP地址:32位(bit),4個位元組,每一個位元組為0~255之間的整數,及我們日常見到的IP地址格式。
目的IP地址:32位(bit),4個位元組,每一個位元組為0~255之間的整數,及我們日常見到的IP地址格式。

當然對ip理解的越深刻越好了,那麼這樣就完成了一個簡單的match擴充套件的例子,僅僅作為拋磚引玉,一個小小的開始.

相關文章