Linux下如何?狀態檢測

來源:互聯網
上載者:User
本文檔的Copyleft歸yfydz所有,使用GPL發布,可以自由拷貝、轉載,轉載時請保持文檔的完整性,嚴禁用於任何商業用途。
msn: yfydz_no1@hotmail.com來源:http://yfydz.cublog.cn 1. iptables規則中的state匹配 在2.4/2.6核心的Linux中的防火牆代碼netfilter中實現了狀態檢測(stateful inspection)檢測技術,在命令列介面的iptables命令是通過匹配“-m state”來實現,“-m state”匹配中定義了四種狀態:NEW,表示新串連;ESTABLISHED,表示已經建立的串連;RELATED,表示相關的子串連;INVALID,表示非法狀態。所以在制定iptables規則時,只需要定義單向的規則,再加上如下兩條規則,就可以保證串連回應包能正確通過防火牆而不必加反向規則:iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD -m state --state INVALID -j DROP
(如果是保護本機,將FORWARD改為INPUT) 2. 核心中的state匹配的實現 (以下的核心代碼基於2.4.26核心)
和匹配state對應的核心部分實現是ipt_state.c(net/ipv4/netfilter),匹配部分的代碼非常簡單,就是根據函數ip_conntrack_get()的傳回值來判斷資料包的狀態類型: if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
  statebit = IPT_STATE_INVALID;
 else
   statebit = IPT_STATE_BIT(ctinfo);3. skb與ip_conntrack的關聯 再跟蹤到ip_conntrack_get()函數(net/ipv4/netfilter_ipv4
/ip_conntrack_core.c),該函數有兩個參數,一個是指向sk_buff資料包的指標skb,另一個是枚舉類型enum
ip_conntrack_info的指標,實際上是一個返回參數,將返回資料包的狀態類型;該函數的傳回值是串連結構struct ip_conntrack的指標,表示該包屬於哪個串連,如果串連不存在,返回空,該包也將被認為是非法包: struct ip_conntrack *
ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
{
 if (skb->nfct)
  return __ip_conntrack_get(skb->nfct, ctinfo);
 return NULL;
} ip_conntrack_get()函數本身也很簡單,實際上是__ip_conntrack_get()函數(net/ipv4
/netfilter_ipv4/ip_conntrack_core.c)的包裹函數,判斷skb的nfct是否非空,非空則將其和枚舉指標
ctinfo傳給__ip_conntrack_get()函數,nfct是sk_buff中用於描述netfilter
conntrack資訊的struct nf_ct_info指標,在核心配置了CONFIG_NETFILTER後有效。struct
nf_ct_info結構在include/linux/sk_buff.h中定義:struct nf_conntrack {
 atomic_t use;
 void (*destroy)(struct nf_conntrack *);
}; struct nf_ct_info {
 struct nf_conntrack *master;
};在__ip_conntrack_get()函數中,通過nfct->master擷取串連指標ct,而nfct相對於ct成員infos的位移就是串連狀態: static inline struct ip_conntrack *
__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
{
 struct ip_conntrack *ct
  = (struct ip_conntrack *)nfct->master; /* ctinfo is the index of the nfct inside the conntrack */
 *ctinfo = nfct - ct->infos;
 IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
 return ct;
} 由此可見,netfilter的狀態檢測過程很簡潔,如果skb包中的nfct指標設定了的話,可以很快地確定該skb包屬於哪個串連,如果不屬於任何串連則是非法包。現在的焦點是skb中的nfct值是如何設定的?4. netfilter如何?中skb與ip_conntrack串連的關聯 nfct值是在resolve_normal_ct()函數(net/ipv4/netfilter/ip_conntrack_core.c)中定義的,該函數被ip_conntrack_in()函數(net/ipv4/netfilter/ip_conntrack_core.c)調用,在
ip_conntrack_local()函數(net/ipv4/netfilter/ip_conntrack_standalone.c)中調用了ip_conntrack_in()函數,而這兩個函數分別是PREROUTING鏈和OUTPUT鏈的起始函數,由下面兩個結構定義(net/ipv4/netfilter/ip_conntrack_standalone.c): static struct nf_hook_ops ip_conntrack_in_ops
= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING,
 NF_IP_PRI_CONNTRACK }; static struct nf_hook_ops ip_conntrack_local_out_ops
= { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT,
 NF_IP_PRI_CONNTRACK };這說明netfilter是在串連的第一個包時就建立串連了,這個串連可能是由外部發起的,也可能是由本機發起的,後續包尋找串連HASH表找到相應的串連,然後賦值給skb結構中的nfct,這就是resolve_normal_ct()函數的工作: /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
static inline struct ip_conntrack *
resolve_normal_ct(struct sk_buff *skb,  // 資料包
    struct ip_conntrack_protocol *proto, // 連線協定跟蹤,該結構對應協議特殊處理過程,如TCP的狀態轉換等
    int *set_reply, // 傳回值,表示該包是否是回應程式的包
    unsigned int hooknum,
    enum ip_conntrack_info *ctinfo)
{
 struct ip_conntrack_tuple tuple;
 struct ip_conntrack_tuple_hash *h; IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);// 確定該包對應的tuple,對TCP/UDP協議來說就是地址協議連接埠的5元組
 if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
  return NULL; /* look for tuple match */
// 根據tuple值尋找串連HASH
 h = ip_conntrack_find_get(&tuple, NULL);
 if (!h) {
// 在當前串連表中沒找到,說明是新串連的包,初始化新串連
  h = init_conntrack(&tuple, proto, skb);
  if (!h)
   return NULL;
// 該包非法返回NULL,其他錯誤會返回錯誤號碼的負值
  if (IS_ERR(h))
   return (void *)h;
 } /* It exists; we have (non-exclusive) reference. */
 if (DIRECTION(h) == IP_CT_DIR_REPLY) {
// 串連回應方向包
  *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
  /* Please set reply bit if this packet OK */
// 這個包是回應程式的包
  *set_reply = 1;
 } else {
// 串連原始方向的包
  /* Once we've had two way comms, always ESTABLISHED. */
  if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
   DEBUGP("ip_conntrack_in: normal packet for %p/n",
          h->ctrack);
// 如果不是第一個包,設定ESTABLISHED屬性,這個位標誌表示發現了回應程式發的包,
// 表示串連可以建立,該標誌在ip_conntrack_in()函數中設定
          *ctinfo = IP_CT_ESTABLISHED;
  } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
   DEBUGP("ip_conntrack_in: related packet for %p/n",
          h->ctrack);
// 該標誌表示是子串連的包,如FTP的資料連線
// 該標誌在init_conntrack()函數中設定
   *ctinfo = IP_CT_RELATED;
  } else {
   DEBUGP("ip_conntrack_in: new packet for %p/n",
          h->ctrack);
// 沒有任何標誌,是串連的第一個包,設定為NEW屬性
   *ctinfo = IP_CT_NEW;
  }
// 這個包是發起方的包
  *set_reply = 0;
 }
// infos是數量為IP_CT_NUMBER(=5)的數組,分別對應串連發起方向的
// NEW(2)/ESTABLISHED(0)/RELATED(1)
// 和串連回應程式向的ESTABLISHED(3)/RELATED(4)
// 每個skb包都會劃歸為其中一類, 也就是ctinfo的值
// 每個skb包根據其類型,將其nfct值設為相應infos項的地址
 skb->nfct = &h->ctrack->infos[*ctinfo];
 return h->ctrack;
} 在init_conntrack()函數中將串連的infos值初始化為:
...
 for (i=0; i < IP_CT_NUMBER; i++)
  conntrack->infos[i].master = &conntrack->ct_general;
...也就是infos各項的值都是相同的,沒有發現在其他地方重新賦值,所以把所有項實際都是相同的,指向同一個串連。設計之初可能是考慮要區分,
但實現時還是只用到一個就行了,在其他地方基本只用到infos[0]進行處理,infos的用處目前只用來判斷狀態,也就是每一項相對於
infos[0]的位移值。 最後討論一下為什麼在__ip_conntrack_get()函數中nfct->master值就是串連的地址:
__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
{
 struct ip_conntrack *ct
  = (struct ip_conntrack *)nfct->master;
...skb的nfct值是infos數組中某一項的地址,而這些項中的master成員都初始化為串連中ct_general的地址,而ct_general參數是串連結構的第一項參數,所以其地址和串連結構的地址是相同,在Linux核心中,類似用法很多。 5. 結論 在每個skb資料包進入netfilter架構時,netfilter就會給其建立串連,通過簡單方法就能找到串連,能區分出發起方、回應程式以及第一個包還是後續包,並能識別子串連,從而實現狀態檢測。 串連結構中的infos數組就目前而言似乎不是很必要,單值就可以,然後增加一個串連狀態參數,而不是通過infos的位移來判斷。

 

發表於: 2006-01-19,修改於: 2006-02-23 08:59,已瀏覽3293次,有評論4條
推薦
投訴
網友:
本站網友
時間:2007-10-24 18:01:01 IP地址:221.221.155.★
分析的很對,多謝

網友:
本站網友
時間:2008-08-29 15:37:07 IP地址:218.247.216.★
在2.6.15核心已經改變很大了,比如:

 static inline struct ip_conntrack * ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)

{

         *ctinfo = skb->nfctinfo;

          return (struct ip_conntrack *)skb->nfct;

}

也就是已經沒有__ip_conntrack_get,更簡單了,同時在struct sk_buff中,有變數:

      __u8         local_df:1

                      cloned:1

                      ip_summed:2

                      nfctinfo:3

#ifdef CONFIG_NETFILTER

       __u32      nfmark;

       struct nf_conntrack *nfct;

網友:
本站網友
時間:2008-08-29 15:58:18 IP地址:218.247.216.★
新的 resolve_normal_ct,(linux2.6.15)

/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */

static inline struct ip_conntrack *

resolve_normal_ct(struct sk_buff *skb,

          struct ip_conntrack_protocol *proto,

          int *set_reply,

          unsigned int hooknum,

          enum ip_conntrack_info *ctinfo)

{

    struct ip_conntrack_tuple tuple;

    struct ip_conntrack_tuple_hash *h;

    struct ip_conntrack *ct;



    IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);



    if (!ip_ct_get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, 

                &tuple,proto))

        return NULL;



    /* look for tuple match */

    h = ip_conntrack_find_get(&tuple, NULL);

    if (!h) {

        h = init_conntrack(&tuple, proto, skb);

        if (!h)

            return NULL;

        if (IS_ERR(h))

            return (void *)h;

    }

    ct = tuplehash_to_ctrack(h);



    /* It exists; we have (non-exclusive) reference. */

    if (DIRECTION(h) == IP_CT_DIR_REPLY) {

        *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;

        /* Please set reply bit if this packet OK */

        *set_reply = 1;

    } else {

        /* Once we've had two way comms, always ESTABLISHED. */

        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {

            DEBUGP("ip_conntrack_in: normal packet for %p/n",

                   ct);

                *ctinfo = IP_CT_ESTABLISHED;

        } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {

            DEBUGP("ip_conntrack_in: related packet for %p/n",

                   ct);

            *ctinfo = IP_CT_RELATED;

        } else {

            DEBUGP("ip_conntrack_in: new packet for %p/n",

                   ct);

            *ctinfo = IP_CT_NEW;

        }

        *set_reply = 0;

    }

    skb->nfct = &ct->ct_general;

    skb->nfctinfo = *ctinfo;

    return ct;

}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.