如何重新计算netfilter中的IP校验和?

问题描述:

我正在开发一个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

你在哪里捕获数据包?

IP校验和(以及TCP/UDP校验和)可以由网络卡本身来计算。如果你的卡上有这种情况(这是一个非常常见的功能),并且你正在捕获你的机器,我希望看到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标头校验和。