计算 ip udp tcp 效验和

下面叙述的是IPv4的 ip udp tcp 效验和的计算。
ip效验和计算相对简单,只需对ip协议头进行计算;
ip协议头长20字节;
udp协议头长8字节;
tcp协议头长20~60字节;
udp和tcp的校验和不仅要对整个ip协议负载(包括
udp/tcp协议头和udp/tcp协议负载)进行计算,
还要先对一个伪协议头进行计算。
在计算效验和前,协议头效验和字段要清0。

伪协议头结构如下:
  0     7 8      15 16     23 24  31
  +--------+--------+--------+--------+
  |           source address            |
  +--------+--------+--------+--------+
  |        destination address        |
  +--------+--------+--------+--------+
  | zero   |protocol| udp/tcp length |
  +--------+--------+--------+--------+

伪协议头中的字段同样都是网络字节序;


下面代码片段展现的是在GNU/Linux中具体的计算方式:

//=====================================================
#include <stdint.h>

#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ether.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>

struct pseudo_head {
    uint32_t saddr;
    uint32_t daddr;
    char zero;
    char proto;
    unsigned short len;
};

int cal_cksum(char *p)
{
    struct iphdr *ip = (struct iphdr *)
        (p + sizeof(struct ether_header));

    cal_ip_cksum(ip);

    struct tcphdr *tcp;
    struct udphdr *udp;
    char *f = (char *)ip + 20;

    switch(ip->protocol) {
    case IPPROTO_TCP:
        tcp = (struct tcphdr *)f;
        tcp->check = 0;
        tcp->check = cal_udptcp_cksum(
            (unsigned short *)f, ip);
        break;
    case IPPROTO_UDP:
        udp = (struct udphdr *)f;
        udp->check = 0;
        udp->check = cal_udptcp_cksum(
            (unsigned short *)f, ip);
        break;
    case IPPROTO_IP:
        break;
    default:
        return 1;
    }
    return 0;
}

inline static void cal_ip_cksum(struct iphdr *ip)
{
    ip->check = 0;
    ip->check = in_cksum((unsigned short *)ip,
            20, 0);
}

inline static unsigned short cal_udptcp_cksum(
        unsigned short *p, struct iphdr *ip)
{
    int len = ntohs(ip->tot_len) - 20;
    struct pseudo_head ph;

    ph.len = htons(len);
    ph.saddr = ip->saddr;
    ph.daddr = ip->daddr;
    ph.proto = ip->protocol;
    ph.zero = 0;

    int sum = cal_sum(
        (unsigned short *)&ph, sizeof(ph));

    return in_cksum(p, len, sum);
}

unsigned short in_cksum(unsigned short *p,
        int len, int sum)
{
    int n = len;

    while(n > 1) {
        sum += *p++;
        n -= 2;
    }
    if(n == 1)
        sum += *(unsigned char *)p;

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);

    unsigned short ret = ~sum;
    return ret;
}

inline static int cal_sum(unsigned short *p, int len)
{
    int sum = 0;
    while(len > 0) {
        sum += *p++;
        len -= 2;
    }
    return sum;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值