netfilter中對多連線協定跟蹤和NAT實現

來源:互聯網
上載者:User
本文檔的Copyleft歸yfydz所有,使用GPL發布,可以自由拷貝,轉載,轉載時請保持文檔的完整性,嚴禁用於任何商業用途。
msn: yfydz_no1@hotmail.com

來源:http://yfydz.cublog.cn1. 前言 對於多連線協定,netfilter需要對其進行特殊的跟蹤和NAT以提供動態對子串連的支援,詳見“防火牆為什麼要對多連線協定進行特殊處理”一文。netfilter對這些多連線協定的跟蹤和NAT和匹配、目標或IP層協議那樣進行模組化的跟蹤和NAT處理。 以下核心代碼說明都使用Linux-2.4.26版本的核心代碼。 2. 協議串連跟蹤 2.1 ip_conntrack_helper結構 netfilter中對每個要進行跟蹤的多連線協定定義了以下的串連輔助結構,每個多連線協定的串連跟蹤處理就是要填寫這樣一個結構: include/linux/netfilter_ipv4/ip_conntrack_helper.h
struct ip_conntrack_helper

 struct list_head list;   /* Internal use. */ const char *name;  /* name of the module */
 unsigned char flags;  /* Flags (see above) */
 struct module *me;  /* pointer to self */
 unsigned int max_expected; /* Maximum number of concurrent
      * expected connections */
 unsigned int timeout;  /* timeout for expecteds */ /* Mask of things we will help (compared against server response) */
 struct ip_conntrack_tuple tuple;
 struct ip_conntrack_tuple mask;
 
 /* Function to call when data passes; return verdict, or -1 to
           invalidate. */
 int (*help)(const struct iphdr *, size_t len,
      struct ip_conntrack *ct,
      enum ip_conntrack_info conntrackinfo);
}; 結構中包括以下參數: struct list_head list:將該結構掛接到多連線協定跟蹤鏈表helpers中, helpers鏈表在ip_conntrack_core.c檔案中定義:
static LIST_HEAD(helpers);
注意是static的,只在該檔案範圍有效; const char *name:協議名稱,字串常量 unsigned char flags:關於本串連跟蹤模組的一些標誌; struct module *me:指向模組本身,統計模組是否被使用 unsigned int
max_expected:子串連的數量,這隻是表示主串連在每個時刻所擁有的的子串連的數量,而不是主串連的整個生存期內總共產生的子串連的數量,如
FTP,不論傳多少個檔案,建立多少個子串連,每個時刻主串連最多隻有一個子串連,一個子串連結束前按協議是不能再派生出第二個子串連的,所以該值為1; unsigned int timeoout:逾時,指在多少時間範圍內子串連沒有建立的話子串連跟蹤失效 struct ip_conntrack_tuple tuple,
mask:這兩個參數用來描述子串連,判斷一個新來的串連是否是主串連期待的子串連,之所以要有mask參數,是因為子串連的某些參數不能確定,如被動模
式的FTP傳輸,只能得到子串連的目的連接埠而不能確定源連接埠,所以源連接埠部分要用mask來進行泛匹配; 結構中包括以下函數: (*help):串連跟蹤基本函數,解析主串連的通訊內容,提取出關於子串連的資訊,將子串連資訊填充到一個struct
ip_conntrack_expect結構中,然後將此結構通過調用函數ip_conntrack_expect_related()把子串連的資訊添
加到系統的期待子串連鏈表ip_conntrack_expect_list中。傳回值是NF_ACCEPT或NF_DROP,或-1表示協議資料非法。
該函數在ip_conntrack_in()函數中調用。2.2 期待的串連的結構 期待的串連結構用來描述所期待的串連,但該串連目前是不存在的,是一個虛構的串連,只是netfilter根據主串連的資訊解析出來的可能的子
串連的資訊,struct ip_conntrack_helper結構中的(*help)成員函數的目的就是建立一個struct
ip_conntrack_expect結構: struct ip_conntrack_expect
{
 /* Internal linked list (global expectation list) */
 struct list_head list; /* reference count */
 atomic_t use; /* expectation list for this master */
 struct list_head expected_list; /* The conntrack of the master connection */
 struct ip_conntrack *expectant; /* The conntrack of the sibling connection, set after
  * expectation arrived */
 struct ip_conntrack *sibling; /* Tuple saved for conntrack */
 struct ip_conntrack_tuple ct_tuple; /* Timer function; deletes the expectation. */
 struct timer_list timeout; /* Data filled out by the conntrack helpers follow: */ /* We expect this tuple, with the following mask */
 struct ip_conntrack_tuple tuple, mask; /* Function to call after setup and insertion */
 int (*expectfn)(struct ip_conntrack *new); /* At which sequence number did this expectation occur */
 u_int32_t seq;
 
 union ip_conntrack_expect_proto proto; union ip_conntrack_expect_help help;
}; 結構中包括以下參數: struct list_head list:將該結構掛接到期待串連鏈表 ip_conntrack_expect_list中; atomic_t use:該期待串連結構的使用次數; struct list_head expected_list:主串連的期待的子串連的鏈表; struct ip_conntrack *expectant:期待串連對應的主串連; struct ip_conntrack *sibling:期待串連對應的真實的子串連; struct ip_conntrack_tuple ct_tuple:串連的tuple值 struct timer_list timeout:定時器 struct ip_conntrack_tuple tuple, mask:期待串連相關的tuple和mask; u_int32_t seq:TCP協議時,主串連中描述子串連的資料起始處對應的序號值;
 
union ip_conntrack_expect_proto proto:跟蹤各個多串連IP層協議相關的資料; union ip_conntrack_expect_help help:跟蹤各個多串連應用程式層協議相關的資料;結構中包括以下函數: int (*expectfn)(struct ip_conntrack *new):期待串連相關函數,在ip_conntrack_core.c檔案的init_conntrack()函數中調用:
...
 if (expected && expected->expectfn)
  expected->expectfn(conntrack);
... 2.3 多連線協定的串連跟蹤過程 2.3.1 過程簡述 新串連的資料包進入netfilter系統後先要建立對應串連,檢查是否是期待的串連,如果與某期待串連符合,說明該串連是子串連,將串連和主
串連建立相關的聯絡,並對串連設定相關標誌,表明是RELATED的串連;否則,說明是主串連,則尋找與這個串連對應的協議的串連輔助模組helper,
如果找到,執行helper中的(*help)函數檢查是否能提取出相關的子串連資訊,產生期待的串連資訊添加到期待串連鏈表中。2.3.2 串連helper尋找 在ip_conntrack_core.c檔案的init_conntrack()函數中先尋找期待串連是否存在,然後調用ip_ct_find_helper()函數來找到與該協議對應的helper函數,注意是用反向的tuple來尋找的:...
// 尋找是否期待串連
 expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
        struct ip_conntrack_expect *, tuple);...
// 尋找串連對應的helper
 if (!expected)
  conntrack->helper = ip_ct_find_helper(&repl_tuple);... 在尋找helper之前先檢查該串連是否存在對應的期待串連,如果是存在期待串連,說明是子串連,子串連就不再去找helper了,這就避免了
phrack63的那篇文章中描述的防火牆穿透方法。但這種限制也帶來一個問題,比如H.323協議,主串連是H.225協議,會派生出一個H.245的
串連,由H.245串連再派生出一個串連進行資料轉送,這種情況下H.245的helper就不能通過ip_ct_find_helper()函數來擷取
了,為解決這個問題,H.323跟蹤NAT模組的作者使用了一個很巧妙的方法,就是通到期待串連結構的(*expectfn)函數來解決,在該函數中直接
將H.245的helper直接賦值到該串連中。2.3.3 (*help)函數執行 (*help)函數對主串連的每個合法資料包都會進行檢查的,在ip_conntrack_core.c檔案的ip_conntrack_in()函數中調用: ...
 if (ret != NF_DROP && ct->helper) {
  ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len,
           ct, ctinfo);
  if (ret == -1) {
// 協議資料格式錯誤時help函數返回-1,清空該包對應的nfct,則該包在狀態檢測時將被視為非法包
   /* Invalid */
   nf_conntrack_put((*pskb)->nfct);
   (*pskb)->nfct = NULL;
   return NF_ACCEPT;
  }
 }
...3. 多連線協定NAT 3.1 ip_nat_helper結構 netfilter中對每個要進行NAT的多連線協定定義了以下結構,每個多連線協定的串連跟蹤處理就是要填寫這樣一個結構: struct ip_nat_helper
{
 struct list_head list;  /* Internal use */ const char *name;  /* name of the module */
 unsigned char flags;  /* Flags (see above) */
 struct module *me;  /* pointer to self */
 
 /* Mask of things we will help: vs. tuple from server */
 struct ip_conntrack_tuple tuple;
 struct ip_conntrack_tuple mask;
 
 /* Helper function: returns verdict */
 unsigned int (*help)(struct ip_conntrack *ct,
        struct ip_conntrack_expect *exp,
        struct ip_nat_info *info,
        enum ip_conntrack_info ctinfo,
        unsigned int hooknum,
        struct sk_buff **pskb); /* Returns verdict and sets up NAT for this connection */
 unsigned int (*expect)(struct sk_buff **pskb,
          unsigned int hooknum,
          struct ip_conntrack *ct,
          struct ip_nat_info *info);
};結構中包括以下參數: struct list_head list:將該結構掛接到多連線協定NAT鏈表helpers中,helpers鏈表在ip_nat_core.c檔案中定義:
LIST_HEAD(helpers);
注意該定義不是static的,而是全域有效,串連跟蹤的helpers則是static的,只在該檔案中起作用,而且屏蔽了ip_nat_core.c中的helpers,所以在此兩個檔案外的helpers是指nat的helpers; const char *name:協議名稱,字串常量 unsigned char flags:關於本串連跟蹤模組的一些標誌; struct module *me:指向模組本身,統計模組是否被使用 struct ip_conntrack_tuple tuple, mask:這兩個參數用來描述進行了NAT後的子串連,同樣因為子串連的某些參數不能確定,要用mask來進行泛匹配; 結構中包括以下函數: (*help):多協議串連NAT操作基本函數,由於作NAT後要修改IP地址以及連接埠,因此原來的主串連中描述子串連的資訊必須進行修改,
(*help)函數的功能就要要找到一個閒置tuple對應新的子串連,修改期待的子串連,然後修改主串連的通訊內容,修改關於IP地址和連接埠部分的描
述資訊為空白閑tuple的資訊,由於修改了應用程式層資料,資料的校正和必須重新計算,而且如果資料長度發生變化,會引起TCP序號的變化,在串連的協議相
關資料中會記錄這些變化,對後續的所有資料都要進行相應的調整;該函數在do_bindings()函數中調用; (*expect):該函數建立子串連對應的NAT相關資訊,主串連的NAT相關資訊是通過iptables的NAT規則建立的;該函數在ip_nat_statndalone.c的call_expect()函數中調用 在NAT的基本函數ip_nat_fn()中,先調用call_expect(),最後調用的do_bindings(),所以(*expect)函數先調用,(*help)函數後調用。 3.2 多連線協定的NAT過程 2.3.1 過程簡述 不論是SNAT還是DNAT,其對應的netfilter的nf_hook_ops節點都要執行ip_nat_fn(),此時與資料包對應的連
接已經建立,對於串連的後續包,只是把串連的NAT資訊綁定到該包(do_binding()函數);如果是新串連,如果是子串連,則調用協議相關
nat_helper的(*expect)函數建立子串連的相關資訊;否不論是SNAT還是DNAT都會調用ip_nat_setup_info()函數
建立與該串連對應的NAT資訊,所以在NAT規則中是不需要加狀態是NEW的匹配的,最後將串連的NAT資訊綁定到資料包。 在NAT資訊的綁定過程中,會檢查當前的資料包是否屬於期待的要進行NAT修改的包,具體是用exp_for_packet()函數進行檢查,
該函數中調用相應傳輸層協議的(*exp_matches_pkt)函數,該函數只在TCP的協議中定義,但UDP沒有,沒有定義此函數時
exp_for_packet()始終返回要求檢查;如果要修改,將調用相應nat_helper的(*help)函數來修改資料,修改期待的子串連。2.3.2 nat helper尋找 在ip_nat_core.c檔案的ip_nat_setup_info()函數中
...
 /* If there's a helper, assign it; based on new tuple. */
 if (!conntrack->master)
  info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
      &reply);
...static inline int
helper_cmp(const struct ip_nat_helper *helper,
    const struct ip_conntrack_tuple *tuple)
{
 return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
} 3.3.3 (*expect)函數執行 在ip_nat_standalone.c檔案的ip_nat_fn()函數中調用call_expect()函數,在call_expect()函數中調用(*expect)函數: static inline int call_expect(struct ip_conntrack *master,
         struct sk_buff **pskb,
         unsigned int hooknum,
         struct ip_conntrack *ct,
         struct ip_nat_info *info)
{
 return master->nat.info.helper->expect(pskb, hooknum, ct, info);
} static unsigned int
ip_nat_fn(unsigned int hooknum,
   struct sk_buff **pskb,
   const struct net_device *in,
   const struct net_device *out,
   int (*okfn)(struct sk_buff *))
{
...
 case IP_CT_NEW:
...
   if (ct->master
       && master_ct(ct)->nat.info.helper
       && master_ct(ct)->nat.info.helper->expect) {
    ret = call_expect(master_ct(ct), pskb,
        hooknum, ct, info);
   } else {
#ifdef CONFIG_IP_NF_NAT_LOCAL
    /* LOCAL_IN hook doesn't have a chain!  */
    if (hooknum == NF_IP_LOCAL_IN)
     ret = alloc_null_binding(ct, info,
         hooknum);
    else
#endif
    ret = ip_nat_rule_find(pskb, hooknum, in, out,
             ct, info);
   }... 3.3.3 (*help)函數執行 在ip_nat_core.c檔案的do_binding()函數中: ...
// 判斷是否是期待的修改點
   if (exp_for_packet(exp, pskb)) {
    /* FIXME: May be true multiple times in the
     * case of UDP!! */
// 因為UDP沒有序號,沒辦法指示修改點,不象TCP可以用序號表示,所以所有UDP包
// 都會執行help
    DEBUGP("calling nat helper (exp=%p) for packet/n", exp);
// 修改資料參數
    ret = helper->help(ct, exp, info, ctinfo,
         hooknum, pskb);
    if (ret != NF_ACCEPT) {
     READ_UNLOCK(&ip_conntrack_lock);
     return ret;
    }
    helper_called = 1;
   }  }
  /* Helper might want to manip the packet even when there is no
   * matching expectation for this packet */
  if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
   DEBUGP("calling nat helper for packet without expectation/n");
   ret = helper->help(ct, NULL, info, ctinfo,
        hooknum, pskb);
   if (ret != NF_ACCEPT) {
    READ_UNLOCK(&ip_conntrack_lock);
    return ret;
   }
  }
... 有兩處地方調用了(*help)函數,第一處(*help)執行了後面的(*help)就不會執行,但即使前面的(*help)沒有執行,由於很多helper的flags都設定為0,所以後面那次(*help)基本都不會執行。 4. 結論 netfilter對多連線協定跟蹤和NAT處理很好地實現了模組化,只要按固定的格式編寫跟蹤和NAT程式就能支援新的多連線協定,現在
netfilter已經可以支援很多多連線協定,如FTP、TFTP、IRC、TALK、H.323、SIP、MMS、QUAKE3等。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.