ip校验和及udp校验和的计算方法

一、ip校验和的计算: 
计算方法: 
1. ip包头(共20个字节)按照每16个bit作为一个值依次进行相加 
2. 将计算结果的进位加到低16位上 
3. 将结果取反 
ip包头的内存内容 
eg: 
45 00 00 20 0F B8 00 00 
80 11 00 00 C0 A8 0A 9F 
C0 A8 0A C7

将 0x4500 0x0020 0x0FB8 0x0000 0x8011 0x0000 0xC0A8 0x0A9F 0xC0A8 0x0AC7 依次相加 所得结果为0x26B9F 然后将 0x0002 + 0x6B9F = 0x6BA1 
然后将 0x6BA1 取反得 0x945E

要注意两点:

1 在给ip_header计算校验和之前   首先把ip_header的checksum字段置为0
2 计算得到checksum之后   赋值时要转换为网络字节序:
  ip_header.checksum = htons(checksum); 

struct ip_header  //小端模式__LITTLE_ENDIAN  
{   
    unsigned char ihl:4;       //ip   header   length      
    unsigned char version:4;   //version     
    u_char        tos;         //type   of   service     
    u_short       tot_len;     //total   length     
    u_short       id;          //identification     
    u_short       frag_off;    //fragment   offset     
    u_char        ttl;         //time   to   live     
    u_char        protocol;    //protocol   type     
    u_short       check;       //check   sum     
    u_int         saddr;       //source   address     
    u_int         daddr;       //destination   address     
};  

// 计算ip数据包的checksum
// 将20个字节的ip数据包每16位组成一个字  依次相加  设所得结果为 0x34ACE
// 将 进位的3与 0x4ACE相加   得  0x4AD1
// 将 0x4AD1取反得到checksum
u_short get_ip_checksum(char* ip_hdr)
{
    char* ptr_data = ip_hdr; 
    u_long  tmp = 0; 
    u_long  sum = 0; 
    for (int i=0; i<20; i+=2)
    {
        tmp += (u_char)ptr_data[i] << 8; 
        tmp += (u_char)ptr_data[i+1]; 
        sum += tmp; 
        tmp = 0; 
    }
    u_short lWord = sum & 0x0000FFFF; 
    u_short hWord = sum >> 16; 
    u_short checksum = lWord + hWord; 
    checksum = ~checksum; 
    return checksum; 
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

二、udp校验和


// udp的checksum计算是用到的结构体
// udp中, 参与计算checksum的数据包括三部分: 亚头部 + UDP头部 + 数据部分
// 亚头部: 4 byte源ip地址 + 4 byte目的ip地址 + 0x00 + 1 byte协议 + UDP 长度(2byte)(udp包头长度+数据长度)
// UDP包头: 2 byte源端口 + 2 byte目的端口 + 2 byte UDP包长(此处是udp包头自带的值不用变) + 0x0000 (checksum)
// 数据部分
// 计算方法同get_ip_checksum一样
typedef struct udp_check_subhdr         // udp计算checksum时的 亚头部: 4 byte源ip地址 + 4 

byte目的ip地址 + 0x00 + 1 byte协议 + UDP 长度(2byte)
{
    u_long   src_ip; 
    u_long   dst_ip; 
    char     mbz;           // must be zero
    char     protocol; 
    u_short  len;           // 这里的长度是指  udp packet中  udp头部和数据部分的总长度
} udp_check_subhdr;


// pudp_pkt: udp的整个packet
// pkt_len: 整个packet的长度(以太网数据帧头 ip头 udp头)
u_short get_udp_checksum(char* pudp_pkt, int pkt_len) 
{
    ether_header *eth_hdr = (ether_header *)pudp_pkt; 
    ip_header    *ip_hdr  = (ip_header*)( pudp_pkt+sizeof(ether_header) ); 
    udphdr       *udp_hdr = (udphdr*)( (char*)ip_hdr+sizeof(ip_header) ); 

    u_short udp_part_len = pkt_len-sizeof(ether_header)-sizeof(ip_header);    // 亚包头中的len: =udp包头长度+数据长度(udp包总长度-ethernet包头长度-ip包头长度); 

    udp_check_subhdr udp_subhdr; 
    udp_subhdr.protocol = ip_hdr->protocol; 
    udp_subhdr.dst_ip = ip_hdr->daddr; 
    udp_subhdr.src_ip = ip_hdr->saddr; 
    udp_subhdr.mbz = 0x00; 
    udp_subhdr.len = htons(udp_part_len); 

    int subhdr_len = sizeof(udp_check_subhdr); 
    int buf_size = udp_part_len + subhdr_len;         // 亚包头 + udp包头 + 数据部分的总长度
    if (pkt_len < buf_size)
        return 0; 
    u_char* buffer = (u_char*)malloc(buf_size); 
    memset(buffer, 0x00, buf_size); 

    memcpy(buffer, (char*)&udp_subhdr, subhdr_len); 
    memcpy(buffer + subhdr_len, (char*)udp_hdr, udp_part_len); 


    unsigned char* ptr_data = buffer; 
    u_long  tmp = 0; 
    u_long  sum = 0; 
    for (int i=0; i<buf_size; i+=2)
    {
        tmp += (u_char)ptr_data[i] << 8; 
        tmp += (u_char)ptr_data[i+1]; 
        sum += tmp; 
        tmp = 0; 
    }
    u_short lWord = sum & 0x0000FFFF; 
    u_short hWord = sum >> 16; 
    u_short checksum = lWord + hWord; 
    checksum = ~checksum; 

    return checksum;  
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

最后: ip校验和还有udp校验和的查看是在接收端查看的,从源端查看是没有计算的值(ip校验和是0x00 udp校验和不清楚什么意义) 用pcap发送自定义数据包时 调用pcap_sendpacket时是直接发送定义好的数据包 就是将定义好的包直接通过网卡发送 不会经过电脑上的ip层和链路层 所以 校验和要自己计算

从两个网页处学到计算方法: 
http://www.360doc.com/content/12/0511/15/621500_210332306.shtml 
http://blog.csdn.net/maeom/article/details/6065203

*注: 仅作为笔记之用 如有错误或不妥之处还望指正。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IP、TCP和UDP校验和计算工具是计算机网络中用于检测数据传输错误的工具。 IP校验和是在IP协议中使用的一种检验机制,用于检测IP数据报在传输过程中是否发生错误。计算IP校验和的方法是将IP数据报中的每个16位字(包括头部和数据部分)相加,然后将结果取反。接收端在接收到IP数据报后也会计算校验和,若计算结果不一致,则说明数据传输中发生了错误。 TCP校验和是在TCP协议中使用的一种检验机制,用于检测TCP报文在传输过程中是否发生错误。计算TCP校验和的方法是将TCP报文中的每个16位字(包括头部和数据部分)相加,然后将结果取反。接收端在接收到TCP报文后也会计算校验和,若计算结果不一致,则说明数据传输中发生了错误。 UDP校验和是在UDP协议中使用的一种检验机制,用于检测UDP数据包在传输过程中是否发生错误。计算UDP校验和的方法是将UDP数据包中的每个16位字(包括头部和数据部分)相加,然后将结果取反。接收端在接收到UDP数据包后也会计算校验和,若计算结果不一致,则说明数据传输中发生了错误。 这些校验和计算工具的作用是保障数据在传输过程中的完整性,一旦检测到错误,就可以及时发现并进行错误处理,提高数据传输的可靠性和正确性。这在计算机网络中非常重要,尤其在数据的传输过程中经常存在着可能导致数据错误的噪声和干扰。通过使用IP、TCP和UDP校验和计算工具,可以有效降低数据传输错误带来的影响,保障数据的安全和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值