DDoS攻防戰(三):ip黑白名單防火牆frdev的原理與實現

 

湯之盤銘曰 苟日新 日日新 又日新html

康誥曰 做新民前端

詩曰 周雖舊邦 其命維新git

是故 君子無所不用其極github

——禮記·大學shell

   

 

  在上一篇文章《DDoS攻防戰 (二) :CC攻擊工具實現與防護理論》中,筆者闡述了一個防護狀態機,它可用來抵禦來自應用層的DDoS攻擊,可是該狀態機依賴一個能應對大量條目快速增刪的ip黑白名單防火牆,咱們目前並無發現很好的開源實現以供咱們使用。api

 

·實現方案選擇:安全

  硬件實現或者軟件實現?服務器

  在面對諸如大量畸形包這樣的攻擊時,硬件實現將會是很是好的選擇,這是由於在進行此類型的封包過濾時,系統須要記憶的狀態不多(對於FPGA、ASIC諸多硬件實現方案來說,記憶元件的成本決不可忽視,寄存器與靜態RAM都很是昂貴,因此當須要記憶的信息不多時,純硬件方案的速度優點使得其完勝軟件方案)。網絡

  可是,當狀態機須要處理龐大的記憶信息時,咱們就須要選擇廉價的存儲器——動態隨機存儲器(如SDRAM中的DDR3)來做爲系統狀態機的存儲介質,以下降系統的成本和複雜度。這時,軟件實現更勝一籌。儘管純硬件實現的速度會比軟件的方式高出不少,但咱們也從第一篇文章《DDoS攻防戰 (一) : 概述》中lvs性能的測試結果中看到,軟件實現的、做爲服務器前端均衡調度器的lvs,性能理想而且能勝任實際生產環境中的、龐大的用戶請求處理,可見,若是設計合理,軟件實現的性能無需過多擔心。數據結構

  最終,咱們決定採用軟件的方法來實現所需的ip黑白名單模塊。

 

·最終系統鳥瞰:

  筆者花費大約二十天的時間,使用C語言實現了這一模塊,其中,內核空間的核心代碼約2300行,用戶空間管理工具的代碼總行數約爲700行。下爲系統的鳥瞰:

  ·用戶空間管理工具fripadm,經過ioctl與工做於內核態的frdev模塊進行通訊

  ·frdev維護兩個double_hash_table的實例,並提供了一個掛在NF_INET_PRE_ROUTING的鉤子函數,其經過操做這兩個double_hash_table的實例以分別實現ip黑名單、白名單的功能

  ·frdev經過內核中設備驅動的ioctl機制,向用戶空間提供這兩個double_hash_table實例的操做函數,而咱們的用戶空間管理工具fripadm正是基於此而實現的

  下面是內核態的主要數據結構與其對應的操做函數:

struct fr_ip_hash_array的功能:
  精確ip查詢;
  模糊ip查詢;
  自定義hash表的長度;
  自定義hash function,其輸入散列隨機數爲rnd;
  維護精確ip的哈希表;
  維護模糊ip的鏈表;
  維護精確ip與模糊ip的諸統計信息;

ip字符描述語法:
  /* ips_syntax : RE 
  digit  =: [0-9]
  num    =: (digit){1,3}
  atom   =: num | (num'-'num) | '*'
  ip     =: atom '.' atom '.' atom '.' atom 
  ips    =: (ip ' ')+
  */
  // ret 0 success,otherwise syntax error
  // "1-220.*.100.33 1-220.*.100.33 1-220.*.100.33"

struct fr_ip_hash_array的方法:
  fr_ip_hash_array_malloc / fr_ip_hash_array_destroy
  fr_ip_hash_array_insert_ip  :增長一條精確ip記錄
  fr_ip_hash_array_insert_blurip_ptr  :增長一條模糊ip記錄(以指針引用的方式)
  fr_ip_hash_array_delete_ip
  fr_ip_hash_array_delete_blurip_ptr
  fr_ip_hash_array_delete_ip_randomly  :隨機地刪除指定數量的精確ip
  fr_ip_hash_array_insert_ip_bystrings  :經過字符串的表述方式,向fr_ip_hash_array增長精確ip或者模糊ip
  fr_ip_hash_array_delete_ip_bystrings
  fr_ip_hash_array_find_bool  :查找給定的ip是否在已存儲的模糊ip範圍以內或者精確ip的哈希表之中
  fr_ip_hash_array_find_ip_bool  :查找給定的ip是否在精確ip的哈希表之中
  fr_ip_hash_array_find_ip_bystrings_bool

 

·爲何使用雙哈希表緩衝?

  請考慮以下場景:

  狀況1:來自應用層的DDoS攻擊經常是瞬間涌入大量非法ip請求,例如數萬個非法ip,因此,對於防火牆黑白名單功能的要求至少有以下:能在很短的時間內更新大量數據項,且不能形成系統服務停頓。

  分析:若是隻使用一個全局的哈希表,當在短期內進行大量的數據項增刪時,例如,成千上萬個,此時,即便採用多把讀寫鎖分割哈希表的策略,對共享資源的競爭也依然將嚴重影響系統響應速度,嚴重時系統可能會停頓或者更糟,對於生產環境中的高負載服務器,這是沒法容忍的。

  解決:以空間換時間

 

  採用雙哈希表緩衝的策略,將系統共享資源的競爭熱點壓縮至兩個hash表指針主備切換的極短期內,此方法能顯著下降系統在大量數據項更新時共享資源的競爭。

  系統查詢將會直接訪問master指向的fr_ip_hash_array,而用戶的更新操做將直接針對mirror所指向的另外一個fr_ip_hash_array實例,直到switch_mirror_update操做的執行,master將被瞬間「更新」。這是其主要的工做特色。

  對於SMP與多隊列網卡的系統,可採用以下策略:多數cpu核心專門負責處理內核的softirq任務,剩下的少數cpu負責進行雙哈希表的更新、切換與重建等操做。這樣可提升系統對攻擊的快速防護響應。

  但此方案將使得系統須要維護兩個互爲鏡像的哈希表,這將加劇系統內存的讀寫負擔。

  具體實現細節以下:

struct fr_ip_double_hash的成員:
  struct fr_ip_hash_array * master_ptr;
  rwlock_t master_lock;  
  struct fr_ip_hash_array * mirror_ptr;
  rwlock_t mirror_lock;
struct fr_ip_double_hash的方法: fr_ip_double_hash_malloc / fr_ip_double_hash_destroy fr_ip_double_hash_mirror_insert_ip :只針對mirror的insert ip操做 fr_ip_double_hash_mirror_insert_blurip_ptr fr_ip_double_hash_mirror_insert_bystrings fr_ip_double_hash_mirror_delete_ip fr_ip_double_hash_mirror_delete_blurip_ptr fr_ip_double_hash_mirror_delete_bystrings fr_ip_double_hash_mirror_delete_ip_randomly fr_ip_double_hash_mirror_delete_all :刪除mirror中全部的ip記錄,即全部的精確ip和模糊ip記錄 fr_ip_double_hash_switch_mirror_update :將mirror與master互換,並更新master至mirror(此時的mirror即爲以前的master) fr_ip_double_hash_rebuild :將雙哈希表重建,可指定新的hash function、rnd以及hash表的長度,這將解決hash表查詢效率低下的問題,以防護外界針對hash表的攻擊。固然,在重建以後,原有的諸多ip條目不會丟失。 fr_ip_double_hash_find_bool fr_ip_double_hash_find_bystrings_bool

 

掛到協議棧上的鉤子函數:

  在模塊初始化函數fr_ip_dev_init的最後,即當兩個雙哈希表實例(分別用做黑名單與白名單)初始化成功、fedev設備註冊成功以後,其將會執行nf_register_hook,將指定的鉤子函數fr_nf_hook_sample掛到NF_INET_PRE_ROUTING之上。

  fr_nf_hook_sample的主要處理代碼以下:

   if(fr_ip_double_hash_find_bool(double_hash_white_ptr,sip)) 
   return NF_ACCEPT; else if(fr_ip_double_hash_find_bool(double_hash_ptr,sip))
   return NF_DROP; else
   return NF_ACCEPT;

其中,double_hash_white_ptr指向白名單fr_ip_double_hash實例,double_hash_ptr則指向黑名單fr_ip_double_hash實例,因爲支持模糊ip匹配,故,上述代碼使得對源ip過濾的「通」、「堵」策略皆可以使用。

 

內核空間frdev的ioctl處理函數:

  目前,ioctl支持來自用戶空間的以下操做:

//黑名單操做
/* in-black ip */
#define FR_IP_IOCTL_TYPE_FIND    1
#define FR_IP_IOCTL_TYPE_FIND_BYSTRINGS        2    // *   輸入ip字符查找
#define FR_IP_IOCTL_TYPE_MIRROR_INSERT_IP    3    
#define FR_IP_IOCTL_TYPE_MIRROR_INSERT_BYSTRINGS    4    // * 
#define FR_IP_IOCTL_TYPE_MIRROR_DELETE_IP    5        // *  
#define FR_IP_IOCTL_TYPE_MIRROR_DELETE_IP_RANDOMLY        6 //*  
#define FR_IP_IOCTL_TYPE_MIRROR_DELETE_BYSTRINGS    7    // * 
#define FR_IP_IOCTL_TYPE_MIRROR_DELETE_ALL        8    //*  
#define FR_IP_IOCTL_TYPE_SWITCH_MIRROR_UPDATE    9    // *  
#define FR_IP_IOCTL_TYPE_REBUILD    10    // *    
#define FR_IP_IOCTL_TYPE_COPY_HASH_STRUCT     11    // *
#define FR_IP_IOCTL_TYPE_DUMP    12    //*    輸出雙哈希表的分佈狀況與統計信息
#define FR_IP_IOCTL_TYPE_MIRROR_INSERT_IP_BINS    13    //*   一次增長大量精確ip,以二進制的方式輸入
#define FR_IP_IOCTL_TYPE_MIRROR_DELETE_IP_BINS    14    //*  

//白名單操做
/* in-white ip */
#define FR_IP_IOCTL_TYPE_WHITE_FIND    101
#define FR_IP_IOCTL_TYPE_WHITE_FIND_BYSTRINGS        102  // * 
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_INSERT_IP        103
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_INSERT_BYSTRINGS    104  // * 
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_DELETE_IP        105
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_DELETE_IP_RANDOMLY        106  // * 
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_DELETE_BYSTRINGS    107    // * 
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_DELETE_ALL        108    //*  
#define FR_IP_IOCTL_TYPE_WHITE_SWITCH_MIRROR_UPDATE    109    // *  
#define FR_IP_IOCTL_TYPE_WHITE_REBUILD    110    // *    
#define FR_IP_IOCTL_TYPE_WHITE_COPY_HASH_STRUCT     111    // *
#define FR_IP_IOCTL_TYPE_WHITE_DUMP    112    //*  
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_INSERT_IP_BINS    113    //*  
#define FR_IP_IOCTL_TYPE_WHITE_MIRROR_DELETE_IP_BINS    114    //*  

  上述各功能的具體實現請閱讀frdev源碼中的fr_ip_dev_ioctl_routine函數。

 

用戶空間管理工具:fripadm

  第一步,實現fripadm_black_in_exe與fripadm_white_in_exe,是分別管理黑白名單的工具,不過,較爲簡陋,第二步,使用shell腳本對其進行二次封裝獲得fripadm_black_in.sh與fripadm_white_in.sh這兩個較用戶友好的工具。

  fripadm爲用戶空間的C語言開發者們提供了以下API:

//針對ip黑名單的操做
double_hash_find_bystrings(int fd,char * str, unsigned int size) //其中fd爲frdev的fd——文件描述符
double_hash_mirror_insert_bystrings(int fd,char * str, unsigned int size)
double_hash_mirror_insert_bins(int fd,char * str, unsigned int size)
double_hash_mirror_delete_bystrings(int fd,char * str, unsigned int size)
double_hash_mirror_delete_bins(int fd,char * str, unsigned int size)
double_hash_mirror_delete_ip_randomly(int fd,unsigned int size)
double_hash_mirror_delete_all(int fd)
double_hash_switch_mirror_update(int fd)
double_hash_rebuild(int fd,unsigned int modular, unsigned int rnd)
double_hash_dump(int fd)
//針對ip白名單的操做
double_hash_white_find_bystrings(int fd,char * str, unsigned int size) //其中fd爲frdev的fd——文件描述符
double_hash_white_mirror_insert_bystrings(int fd,char * str, unsigned int size)
double_hash_white_mirror_insert_bins(int fd,char * str, unsigned int size)
double_hash_white_mirror_delete_bystrings(int fd,char * str, unsigned int size)
double_hash_white_mirror_delete_bins(int fd,char * str, unsigned int size)
double_hash_white_mirror_delete_ip_randomly(int fd,unsigned int size)
double_hash_white_mirror_delete_all(int fd)
double_hash_white_switch_mirror_update(int fd)
double_hash_white_rebuild(int fd,unsigned int modular, unsigned int rnd)
double_hash_white_dump(int fd)

  fripadm_black_in_exe、fripadm_white_in_exe、fripadm_black_in.sh與 fripadm_white_in.sh的具體實現請參看frdev源碼。

 

最終系統測試:

  按照README所述的過程,編譯、安裝完畢frdev設備後,即可進行以下測試:

  本來被black所DROP的數據包,在更新了white的ip條目後,被white所ACCEPT,上圖紅線標出了數據包被截斷的icmp_seq的區間。  

  關於frdev的陳述到此爲止。

 

  最近筆者在閱讀《白帽子講Web安全》這本書時,發現了雅虎公司用於防禦應用層DDoS攻擊的系統Yahoo Detecting System Abuse,yahoo爲此係統申請了專利保護。下面是關於這個系統的描述: 

 (Patent N0.: US 7,533,414 B1 資料來源 http://patentimages.storage.googleapis.com/pdfs/US7533414.pdf)

   A system continually monitors service requests and detects service abuses.

  First, a screening list is created to identify potential abuse events. A screening list includes event IDs and associated count values. A pointer cyclically selects entries in the table,advancing as events are received. 

  An incoming event ID is compared with the event IDs in the table. If the incoming event ID matches an event ID in the Screening list,the associated count is incremented. Otherwise, the count of a selected table entry is decremented. If the count value of the selected entry falls to Zero, it is replaced With the incoming event. 

  Event IDs can be based on properties of service users,such as user identifications, or of service request contents,such as a search term or message content. The screening list is analyzed to determine whether actual abuse is occurring.

  大概思路以下:

  此係統經過維護一個篩選表來獲得用戶的請求頻率,以判斷其是否存在service abuse,然採起相關措施,例如BLOCK。

  這種防護思想,與咱們以前所提出的防護狀態機有着殊途同歸之妙。筆者認爲這是必然的。

  前面的文章已經提過,DDoS攻擊存在的主要緣由之一是網絡服務的開放性,咱們不可能從下層來解決這樣的問題(由於服務的可用性是第一要求),只能從上層分析解決.

  而應用層已經處於協議棧的最高層,因此,要防護應用層DDoS攻擊,只能從應用層以上來尋找解法,故,在這種狀況下,除了藉助數據統計分析,難道還會有更好的方法麼?

 

  在實現frdev的過程當中,藉助互聯網解決了不少問題,因此,若是您須要frdev的源碼,請在下方留下郵箱 :)

  這是frdev在github上的地址,https://github.com/hnes/frdev若是有小夥伴想要一塊兒來加強frdev的功能,熱烈歡迎 :)

  通信郵箱:at Gmail named yunthanatos 

相關文章
相關標籤/搜索