2012-04-28 144 views
1

我正在開發一個netfilter的內核模塊中,我需要重新計算IP校驗和。我用這個功能來計算IP校驗(發現它的地方,互聯網上):如何重新計算netfilter中的IP校驗和?

unsigned short ComputeIPChecksum(unsigned char *data, int len) 
{ 
     long sum = 0; /* assume 32 bit long, 16 bit short */ 
    unsigned short *temp = (unsigned short *)data; 

     while(len > 1){ 
      sum += *temp++; 
      if(sum & 0x80000000) /* if high order bit set, fold */ 
       sum = (sum & 0xFFFF) + (sum >> 16); 
      len -= 2; 
     } 

     if(len)  /* take care of left over byte */ 
      sum += (unsigned short) *((unsigned char *)temp); 

     while(sum>>16) 
      sum = (sum & 0xFFFF) + (sum >> 16); 

     return ~sum; 
} 

通過查看Wireshark的我可以看到,接收的數據包成功,但傳出的數據包Wireshark的顯示不正確的IP校驗和接收。 這是我的鉤子函數:

static unsigned int hook_func(unsigned int hooknum, 
         struct sk_buff *skb, 
           const struct net_device *in, 
           const struct net_device *out, 
           int (*okfn)(struct sk_buff *)) 
{ 
    sock_buff = skb; 

    if (sock_buff) 
    { 
      ip_header = (struct iphdr *)skb_network_header(sock_buff); 
      if (ip_header && ip_header->protocol == TCP) 
      { 
       ip_header->check = ComputeIPChecksum((unsigned char *)ip_header, ip_header->ihl*4); 
      } 
    } 
    return NF_ACCEPT; 
} 

這裏是主要的,我特地綁定同一鉤子函數PRE_ROUTING和POST_ROUTING

static int __init init_main(void) 
{ 
    nfho.hook  = hook_func; 
    nfho.hooknum = 0; 
    nfho.pf  = PF_INET; 
    nfho.priority = NF_IP_PRI_FIRST; 

    nfho1.hook  = hook_func; 
    nfho1.hooknum = 4; 
    nfho1.pf  = PF_INET; 
    nfho1.priority = NF_IP_PRI_FIRST; 

    nf_register_hook(&nfho); 
    nf_register_hook(&nfho1); 

    return 0; 
} 

爲什麼IP校驗遭到損壞時,傳出的數據包? ?

在Wireshark中所示的錯誤:

Header checksum: 0x0000 [incorrect, should be 0x85de (maybe caused by "IP checksum offload"?)] 
+1

你實現C++中的Linux內核模塊? – 2012-04-28 20:18:50

+0

您在Linux內核模塊中使用的代碼是「您在互聯網上找到的」?你明白什麼是版權意味着什麼?你是否理解「簽名」意味着你發誓你寫了所有的代碼,或者擁有代碼版權的人已經在GPLv2下授權了它? – 2012-04-28 20:21:11

+0

定義「損壞的IP標頭」。這是否意味着「不正確的校驗和」或實際上「損壞的IP頭」?如果是後者,那麼你可能搞亂了別的東西。 – mfontanini 2012-04-28 20:48:16

回答

1

你在哪裏捕獲數據包?

IP校驗和(以及TCP/UDP校驗和)可以由網絡卡本身來計算。如果你的卡上有這種情況(這是一個非常常見的功能),並且你正在捕獲你的機器,我希望看到0個校驗和。

0

如果定義IP報頭是這樣的:

struct iphdr *iph; 

然後

iph = (struct iphdr *) skb_header_pointer(skb, 0, 0, NULL); 

,那麼你可以重新計算校驗和,就像下面。

/* Calculation of IP header checksum */ 
iph->check = 0; 
ip_send_check (iph); 

你可以看看我的問題:How to append data on a packet from kernel space? 在那裏,你可以在底部給出答案由我自己找到詳細的代碼。在那裏,我不得不 重新計算IP和UDP標頭校驗和。