2013-05-17 159 views
1

我試圖改變在一個Netfilter POSTROUTING鉤的IP和TCP報頭中的某些字段,但是我似乎無法獲得內核TCP校驗功能正常工作事後修改它。計算TCP校驗和一個網絡過濾模塊

TCP握手過程中校驗和正常,但一旦數據包有任何有效載荷,校驗和就會出錯。

我把這個校驗和代碼從挖掘TCP源頭拉到一起。我相當確信tcplen是正確的,匹配預期的TCP報頭+有效負載大小。

static unsigned int posthook_fn(
    unsigned int hooknum, 
    struct sk_buff *skb, 
    const struct net_device *in, 
    const struct net_device *out, 
    int (*okfn)(struct sk_buff *)) 
{ 
    struct iphdr *iph; 
    struct tcphdr *tcph; 
    iph = ip_hdr(skb); 
    tcph = (struct tcphdr *)(skb->data + iph->ihl * 4); 

    tcph->source = port; 
    iph->saddr = addr; 

    tcplen = (skb->len - (ip_header->ihl << 2)); 
    tcph->check = 0; 
    tcph->check = tcp_v4_check(tcph, tcplen, 
     iph->saddr, 
     iph->daddr, 
     csum_partial((char *)tcph, tcplen, 0)); 
    skb->ip_summed = CHECKSUM_NONE; //stop offloading 

    ip_header->check = ip_fast_csum((u8 *)iph, iph->ihl);   

    return NF_ACCEPT; 
} 

上午我在想,tcp_v4_check改正計算僞報頭和csum_partial計算的有效載荷和tcp_header展開校驗?

我真的希望避免自己寫函數,因爲內核將會更快,因爲底層函數使用匯編進行計算。

有沒有其他方法可行?或者有什麼我錯過了嗎?

+0

我只是想感謝你的這篇文章。它幫助我解決了一些我使用netfilter代碼所遇到的問題。 – sparticvs

回答

3

無需額外調用skb_is_nonlinear(),因爲在include/linux/skbuff.h中:

ip_header->check = 0 

前:

static inline int skb_linearize(struct sk_buff *skb) 
{ 
     return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0; 
} 

此外,您有:

ip_header->check = ip_fast_csum((u8 *)iph, iph->ihl); 
1

它採取了一段時間才能得到在這裏,但這個問題似乎是套接字緩衝區不總是線性的,下面的代碼確保它是計算校驗和之前。

if (skb_is_nonlinear(skb)) { 
    if (skb_linearize(skb) != 0) { 
     return NF_DROP; 
    } 
    iph = ip_hdr(skb); 
    tcph = (void *)iph + (iph->ihl << 2); 
}