linux2.6.30 核心netfilter部分IPV4發包流程分析

來源:互聯網
上載者:User

轉載請註明 作者: Alanx Email:zhangsuozhu@tom.com    QQ:8540426
                                                                     http://hi.baidu.com/alanx/



當核心準備好要發包時,將調用以下函數,其中最重要的結構是struct sk_buff請查相關資料
int ip_output(struct sk_buff *skb)
{
        struct net_device *dev = skb_dst(skb)->dev; 取發包裝置

        IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len); 此處應為snmp網網協議相關的操作

        skb->dev = dev; 設發發包的裝置
        skb->protocol = htons(ETH_P_IP); 指定IP協議

        return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb, NULL, dev,
                            ip_finish_output,
                            !(IPCB(skb)->flags & IPSKB_REROUTED));
}

最後一句是調用勾子,就是netfilter機制最著名的勾子函數。別急,我們像下看。
NF_HOOK_COND()是一個宏,定義如下:

#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond)                 /
({int __ret;                                                                   /
if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN, cond)) == 1)/
        __ret = (okfn)(skb);                                                   /
__ret;})

再像下看:
static inline int nf_hook_thresh(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 thresh,
                                 int cond)
{
        if (!cond)
                return 1;
#ifndef CONFIG_NETFILTER_DEBUG
        if (list_empty(&nf_hooks[pf][hook]))
                return 1;
#endif
        return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);
}
好像明白點什麼了,嗯。cond非0時或nf_hooks[pf][hook]鏈表為空白時,int nf_hook_thresh()返回1。接著NF_HOOK_COND()會調用(okfn)(skb)的指標函數。
根據傳過來的參數,我們得知,實際上就是調用:ip_finish_output(sk).最後我們再分析ip_finish_output(sk),先讓我們看看cond和nf_hooks[pf][hook]鏈表吧。
cond:
    根據我們傳來的參數得知就是!(IPCB(skb)->flags & IPSKB_REROUTED),具體沒細看,猜想可能是和路由重發有關吧。感興趣的朋友可以瞭解一下。

nf_hooks[pf][hook]:
    根據上層傳過來的參資料應為:nf_hooks[PF_INET][NF_INET_POST_ROUTING] 。
讓我們看看它的定義struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]
__read_mostly;
明白了吧。就是的一鏈表數組。我們這裡用的是其中的nf_hooks[PF_INET][NF_INET_POST_ROUTING]。解釋一下的話,應
為PF_INET協議時,路由發包的勾子函數鏈表。當我們用iptables或tc時。用netlink和核心通訊,在這個鏈表上掛上很多結點。
有什麼用呢?我們接著往下看:nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh)
我們看一下它的構成:

nt 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;
}

關鍵是這句 verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,
                             outdev, &elem, okfn, hook_thresh);
根據上面返回的值,決定這個包是否通過NF_ACCEPT 或 丟棄 NF_DROP 還是進行流控入排隊 NF_QUEUE.注意。這是個迴圈goto next_hook

接下來,我們看看關鍵的verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev, outdev, &elem, okfn, hook_thresh);
unsigned int nf_iterate(struct list_head *head,
                        struct sk_buff *skb,
                        unsigned int hook,
                        const struct net_device *indev,
                        const struct net_device *outdev,
                        struct list_head **i,
                        int (*okfn)(struct sk_buff *),
                        int hook_thresh)
{
        unsigned int verdict;

        /*
         * The caller must not block between calls to this
         * function because of risk of continuing from deleted element.
         */
        list_for_each_continue_rcu(*i, head) {
                struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;

                if (hook_thresh > elem->priority)
                        continue;

                /* Optimization: we don't need to hold module
                   reference here, since function can't sleep. --RR */
                verdict = elem->hook(hook, skb, indev, outdev, okfn);
                if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG
                        if (unlikely((verdict & NF_VERDICT_MASK)
                                                        > NF_MAX_VERDICT)) {
                                NFDEBUG("Evil return from %p(%u)./n",
                                        elem->hook, hook);
                                continue;
                        }
#endif
                        if (verdict != NF_REPEAT)
                                return verdict;
                        *i = (*i)->prev;
                }
        }
        return NF_ACCEPT;
}
其中
1、ist_for_each_continue_rcu(*i, head) 是迴圈遍曆head 既剛才所說的nf_hooks[PF_INET][NF_INET_POST_ROUTING]。

2、struct nf_hook_ops *elem = (struct nf_hook_ops *)*i; 取出上面鏈表的結點。

3、if (hook_thresh > elem->priority) 如果優先順序小。則下一個結點這裡 hook_thresh為INT_MIN
        continue;
         
4、verdict = elem->hook(hook, skb, indev, outdev, okfn);結於調到勾子了。萬歲。最激動人心的事。上面說了勾子是我們用iptables或tc通過與核心通訊的netlink,掛到nf_hooks上的。

讓我們看看。 nf_hooks上的結點的結構吧。

typedef unsigned int nf_hookfn(unsigned int hooknum,
                               struct sk_buff *skb,
                               const struct net_device *in,
                               const struct net_device *out,
                               int (*okfn)(struct sk_buff *));

struct nf_hook_ops
{                      
        struct list_head list;    鏈表
               
        /* User fills in from here down. */
        nf_hookfn *hook;    勾子函數,就是上面調用的
        struct module *owner; 模組
        u_int8_t pf;        如:PF_INT
        unsigned int hooknum;    如:NF_INET_POST_ROUTING
        /* Hooks are ordered in ascending priority. */
        int priority;        優先順序:如INT_MIN等  
};

               
等以上的都處理完,最後,要麼把包丟棄了。要最一開始的ip_finish_output處理髮包啦!先寫到此了!

相關文章

聯繫我們

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