摘 要: 本文主要介紹在Linux內核中實現IP包過濾的基本流程,同時對IP偽裝和網絡地址轉換(NAT)的實現作簡要的介紹。 關鍵詞 包過濾 防火牆 網絡地址轉換(NAT) IP偽裝 隨著因特網的迅猛發展,信息安全、網絡安全已經成為人們日益關注的焦點。越來越多的企業和機關已經開始利用防火牆技術來保障網絡不受外部黑客的入侵。包過濾技術是防火牆技術的技術核心,更好的理解包過濾的機制有助於我們更深刻的理解和應用防火牆來保障網絡信息的安全。 一、 Linux網絡部分代碼分析 Linux網絡層采用統一的緩沖區結構skbuff,一個個單獨的skbuff被組織成雙向鏈表的形式。網卡接收到數據幀後,系統內核為接收到的數據幀分配一塊內存,然後將數據整理成skbuff的結構.在網絡協議處理的時候,數據均以skbuff的形式在各層之間傳遞、處理。 skbuff的強大功能在於它提供了眾多指針,可以快速的定位協議頭位置;它也同時保留了許多數據包信息(如使用的網絡設備等),以便協議層根據需要靈活應用. 在IP協議層有三個關鍵函數:ip_rcv( )、ip_forward( )、ip_output( ),分別處理IP層的接收、轉發和發送工作。防火牆的功能函數將在此三個函數中調用。 二、 包過濾. 包過濾主要工作於IP層。Linux在應用層利用ipchains( )來實現對包過濾的實現。可以用該函數實現過濾規則的添加、刪除、設置、更改,在對包過濾規則進行設置的同時,還可以指定對數據包進行IP偽裝。在Linux 內核中有三條內置的規則鏈(input chain, forward chain, output chain),分別對應接收檢測,轉發檢測和發送檢測(內置鏈不可刪除),每一條chain 包含一系列過濾規則及鏈的缺省策略.利用各規則鏈可以對輸入、轉發、和輸出的數據包進行過濾。 其實現過程如下: *在不同檢測點進入相應過濾鏈. *順序檢查每一條過濾規則,找出與之匹配的規則(ACCEPT, REJECT, DENY, MASQ,REDICT,RETURN). *當遇到第一條匹配的規則時采取以下行動: a. 將規則應用於此數據包; b. 每條規則都包含有packet和byte數的計數器,當匹配時,此計數器加 c. 如果設置記錄功能,則記錄. *當沒有規則匹配時,采用鏈的缺省策略. 具體流程結合代碼來說: 三種內置規則鏈分別作用於對應的三個函數ip_rcv( )、ip_forward( )和ip_output( )。 1、ip_rcv()是IP層的接收函數,由它來處理網卡接收到的數據包,它首先檢查: a.長度是否正確; b..版本號是否正確(是IPV4還是IPV6?); c.校驗和是否正確. 在確定這些信息無誤後,則調用包過濾檢測: fwres = call_in_firewall(PF_INET, dev, iph, &rport, &skb); call_in_firewall 會對輸入的數據包進行規則檢查,fwres返回的便是匹配出來的規則.如果對應的規則為不接受該數據包,則立即將此數據包丟棄: if (fwres < FW_ACCEPT && fwres != FW_REJECT) goto drop; 如果規則允許接受則查找路由表,對輸入的數據包進行路由: ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev) 此時路由信息已包括在了skbuff數據結構的dst 項中,緊接著調用 skb->dst->input(skb) 繼續處理 . 對發往本地高層協議的包,則調用ip_local_deliver(),進行處理。 對轉往其他主機的包,則實際調用ip_forward()處理。 值得注意的是,經偽裝的包在回來時,其目的IP是防火牆的IP,經路由後,也送入ip_local_deliver( )處理,在ip_local_deliver( )內部先解偽裝,然後再查一次路由,發往本地的直接送往高層,,否則依然調用ip_forward( )。 2、ip_forward( )用來處理發往其他主機的數據包,其函數流程為: 1)、因為ip_forward()接收的參數是一個skbuff,它首先利用skbuff的指針,把IP頭找出: iph = skb->nh.iph 2)、因為ip_forward()由ip_rcv()調用,而在ip_rcv()中已查過了路由,此處只需利用skbuff的指針定位路由信息即可: strUCt rtable *rt; /* Route we use */ rt = (struct rtable*)skb->dst; 3)、如果此IP包的生存時間(ttl)已到,則丟棄. if (iph->ttl is_strictroute && rt->rt_dst != rt->rt_gateway) goto sr_failed; 5)、如果指定的偽裝功能,且上層協議是ICMP,則在此處處理一部分,且跳過後面的包過濾處理 #ifdef CONFIG_IP_MASQUERADE if(!(IPCB(skb)->flags&IPSKB_MASQUERADED)) { if (iph->protocol == IPPROTO_ICMP) { ........ fw_res = ip_fw_masq_icmp(&skb, maddr); if (fw_res) /* ICMP matched - skip firewall */ goto skip_call_fw_firewall; ........ } } #endif 6)、如果上一步的前提不成立,則要經過一次包過濾. fw_res=call_fw_firewall(PF_INET, dev2, iph, NULL, &skb); 7)、在當前linux版本中,包過濾與偽裝功能在許多地方是緊密聯系在一起的,如采用同樣的配置工具ipchains,同樣的配置接口setsocketopt(),其中是否啟動偽裝的標志也在防火牆的chains中. 8)、因為偽裝可能改變了skbuff的一些信息,此時要重新定位一下IP頭及其選項: iph = skb->nh.iph; opt = &(IPCB(skb)->opt); 9)、因為轉發的數據總是要送出的,緊接著會調用call_out_firewall(),並把數據送出去. 3、在ip_local_deliver()中. 1).如果需要,首先重組IP包: if (sysctl_ip_always_defrag == 0 && (iph->frag_off & htons(IP_MFIP_OFFSET))) { skb = ip_defrag(skb); if (!skb) return 0; iph = skb->nh.iph; 2).然後調用ip_fw_demasquerade解開IP偽裝。 ret = ip_fw_demasquerade(&skb); 3)、再次調用路由查找,根據真正的IP來發送此包. ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev) 4).根據路由發往上層或是轉發(略). 在對數據包進行處理的全部過程中,分別調用了以下三個函數: call_in_firewall(), call_fw_firewall()和 call_out_firewall()。察看這三個函數的具體實現發現,其核心過程都在於ip_fw_check() 這個函數,它完成了數據包與規則的實際匹配. ip_fw_check()函數分析: 防火牆的規則鏈由ip_chain數據結構描述,其中包含了指向鏈中第一條規則的指針和鏈的缺省策略。規則鏈中的每條規則由ip_fwkernel數據結構描述。ip_fw_check()所做的就是將每一個ip包與規則鏈中的每一條規則(實際就是ip_fw數據結構所描述的內容)按照鏈表的組織順序一一比較,若匹配則並返回規則的行動項。 結束語 以上簡單的介紹了linux下實現包過濾的基本方法,希望對大家起到拋磚引玉的作用。