网络[七]:NetFilter(2)

NetFilter调用

        在报文在内核协议栈传递时,会调用NetFilter模块对报文进行特定的进滤,这样的过滤在代码中随处可见。
        以上一篇讲过的网桥为例,对于要进行网桥处理的报文,handle_bridge()->br_handle_frame(),如果端口处理于LEARNING或FORWARDING状态,且报文目的地址正确,则会调用br_handle_frame()进行后续处理,而这个函数调用就是:
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish);
NF_HOOK()->NF_HOOK_THRESH()->nf_hook_thresh()->nf_hook_slow():

 

int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,            struct net_device *indev,            struct net_device *outdev,            int (*okfn)(struct sk_buff *),            int hook_thresh)   {       struct list_head *elem;       unsigned int verdict;       int ret = 0;             /* We may already have this, but read-locks nest anyway */       rcu_read_lock();             elem = &nf_hooks[pf][hook];   next_hook:       verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,                    outdev, &elem, okfn, hook_thresh);       if (verdict == NF_ACCEPT || verdict == NF_STOP) {           ret = 1;       } else if (verdict == NF_DROP) {           kfree_skb(skb);           ret = -EPERM;       } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {           if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn,                     verdict >> NF_VERDICT_BITS))               goto next_hook;       }       rcu_read_unlock();       return ret;   }  

        nf_hook_slow()从nf_hooks中找出到执行的勾子队列,依次执行,然后根据返回值决定是否继续(由nf_iterate()完成)。参数中的pf和hook代表了注册勾子函数时给的参数PF和HOOKNUM,它们共同决定勾子函数要插入的nf_hook的哪个队列中。 
        作为过滤报文的勾子函数的返回值是值得注意的地方,可取值如下:

 

#define NF_DROP 0    #define NF_ACCEPT 1    #define NF_STOLEN 2    #define NF_QUEUE 3    #define NF_REPEAT 4    #define NF_STOP 5  

        先以nf_iterate()函数为例,elem->hook()表示执行勾子函数,执行结构为verdict;

 

unsigned int nf_iterate(……)   {       unsigned int verdict;             list_for_each_continue_rcu(*i, head) {           struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;           if (hook_thresh > elem->priority)               continue;           verdict = elem->hook(hook, skb, indev, outdev, okfn);           if (verdict != NF_ACCEPT) {               if (verdict != NF_REPEAT)                   return verdict;               *i = (*i)->prev;           }       }       return NF_ACCEPT;   }  

        根据nf_iterate()返回,会有以下情况:
              1.如果结果为NF_ACCEPT,表示勾子函数允许报文继续向下处理,此时应该继续执行队列上的下一个勾子函数,因为这些勾子函数都是对同一类报文在相同位置的过滤,前一个通后,并不能返回,而要所有函数都执行完,结果仍为NF_ACCEPT时,则可返回它;
              2.如果结果为NF_REPEAT,表示要重复执行勾子函数一次;所以勾子函数要编写得当,否则报文会一直执行一个返回NF_REPEAET的勾子函数,当返回值为NF_REPEAT时,不会返回;
              3.如果为其它结果,则不必再执行队列上的其它函数,直接返回它;如NF_STOP表示停止执行队列上的勾子函数,直接返回;NF_DROP表示丢弃掉报文;NF_STOLEN表示报文不再往上传递,与NF_DROP不同的是,它没有调用kfree_skb()释放掉skb;NF_QUEUE检查给定协议(pf)是否有队列处理函数,有则进行处理,否则丢掉。       

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wypjxx.html