Linuxで状態検出はどうやって行いますか?


本文書のCopylityはyfydzの所有に帰属します.GPLを使って発表します.自由にコピー、転載できます.転載する時は文書の完全性を維持してください.商業用途に使用することは厳禁です.
msn:[email protected]
ソース: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
", 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
", h->ctrack); // , FTP // init_conntrack() *ctinfo = IP_CT_RELATED; } else { DEBUGP("ip_conntrack_in: new packet for %p
", 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 。