如何计算UDP头的checksum

UDP报头只有4个字段,分别是:源端口号、目的端口号、报文长度和报头checksum,其中的报头checksum这个字段在IPv4中并不是强制的,但在IPv6中是强制的,本文介绍UDP报头中checksum的计算方法,并给出相应的源程序。

1. UDP报文结构

struct udphdr {
    __be16	source;
    __be16	dest;
    __be16	len;
    __sum16	check;
};

图1:UDP数据报结构

2. IP报头结构

图2:IP报头结构

3. UDP报头checksum的计算

图3:伪报头

  1. UDP报头中的check字段填充0;
  2. (伪报头+UDP报头+DATA)的长度应该为16-bit字的整数倍,如果不是,DATA的最后部分要填充1个字节0,以使其为16-bit字的整数倍;
  3. (伪报头+UDP报头+DATA)看作是很多个16-bit字,并逐一相加,结果仍为16-bit字,如果出现溢出,则结果+1,然后继续,直至完成;
  4. 结果求反即为所需的checksum;
#include 
#include 
#include 
#include 

#include 
#include 

// udp pseudo header structure
struct pseudohdr {
    uint32_t source_ip;
    uint32_t destination_ip;
    uint8_t zero;
    uint8_t protocol;
    uint16_t udp_len;
};
// udp packet structure for calculating checksum
struct udpcheckhdr {
    struct pseudohdr pseudo_hdr;
    struct udphdr udp_hdr;
    unsigned char data[16];
};
// initial pseudo header
void init_pseudohdr(struct udpcheckhdr *p) {
    p->pseudo_hdr.source_ip = inet_addr("152.1.51.27");         // 0X0198 0X1B33
    p->pseudo_hdr.destination_ip = inet_addr("152.14.94.75");   // 0X0E98 0X4B5E
    p->pseudo_hdr.zero = 0;                     // 0X00 - 0X1100
    p->pseudo_hdr.protocol = 17;                // 0X11
    p->pseudo_hdr.udp_len = 13;                 // 0X000D
}
// initial udp header
void init_udphdr(struct udpcheckhdr *p) {
    p->udp_hdr.source = 56020;                  // 0xDAD4
    p->udp_hdr.dest = 8000;                     // 0X1F40
    p->udp_hdr.len = 13;                        // 0X000D
    p->udp_hdr.check = 0;                       // 0X0000
}
// initial udp data
void init_udpdata(struct udpcheckhdr *p) {
    p->data[0] = 'h';                           // 0X68 - 0X6568
    p->data[1] = 'e';                           // 0X65
    p->data[2] = 'l';                           // 0X6C - 0X6C6C
    p->data[3] = 'l';                           // 0X6C
    p->data[4] = 'o';                           // 0X6F - 0X006F
    p->data[5] = 0;
}

uint16_t checksum1(uint16_t *p, int count) {
    register long sum = 0;
    unsigned short checksum;

    uint16_t temp;
    uint16_t i = 0;
    while (count > 1) {
        /*  This is the inner loop */
        temp = (unsigned short)*(unsigned short *)p++;
        printf("Step %02d: 0X%08lX + 0X%04X
", ++i, sum, temp);
        sum += temp;
        count -= 2;
    }

    /*  Add left-over byte, if any */
    if (count > 0) {
        temp = (unsigned short)*(unsigned short *)p;
        printf("Step %02d: 0X%08lX + 0X%04X
", ++i, sum, temp);
        sum += *(unsigned char *)p;
    }

    printf("Result before folding: 0X%08lX
", sum);
    /*  Fold 32-bit sum to 16 bits */
    while (sum >> 16)
        sum = (sum & 0xffff) + (sum >> 16);

    printf("Result after folding: 0X%08lX
", sum);

    checksum = ~(unsigned short)sum;
    printf("
Checksum = 0x%04X
", checksum);

    return checksum;
}

uint16_t checksum2(uint16_t *p, int count) {
    register long sum = 0;
    unsigned short checksum;

    uint16_t temp;
    uint16_t i = 0;
    while (count > 1) {
        /*  This is the inner loop */
        temp = (unsigned short)*(unsigned short *)p++;
        printf("Step %02d: 0X%08lX + 0X%04X(0X%04X)
", ++i, sum, (uint16_t)~temp, temp);
        sum += (uint16_t)~temp;
        count -= 2;
    }

    /*  Add left-over byte, if any */
    if (count > 0) {
        temp = (unsigned short)*(unsigned short *)p;
        printf("Step %02d: 0X%08lX + 0X%04X(0X%04X)
", ++i, sum, (uint16_t)~temp, temp);
        sum += (uint16_t)~temp;
    }

    printf("Result before folding: 0X%08lX
", sum);
    /*  Fold 32-bit sum to 16 bits */
    while (sum >> 16)
        sum = (sum & 0xffff) + (sum >> 16);

    printf("Result after folding: 0X%08lX
", sum);

    checksum = (unsigned short)sum;
    printf("
Checksum = 0x%04X
", checksum);
    return checksum;
}

int main(int argc, char **argv) {
    struct udpcheckhdr udp_packet;

    init_pseudohdr(&udp_packet);
    init_udphdr(&udp_packet);
    init_udpdata(&udp_packet);

    unsigned short *p = (unsigned short *)&udp_packet;
    int count = sizeof(struct pseudohdr) + udp_packet.udp_hdr.len;

    printf("
The one's complement code of 16-bit true code sum
");
    checksum1(p, count);
    printf("
The one's complement sum
");
    checksum2(p, count);

    return 0;
}

图4:程序运行截屏

4. UDP报头checksum的验证

  1. 加入伪报头;
  2. 将(伪报头+UDP头+DATA)按16-bit分成若干个16-bit字,如果最后一个字节无法组成一个16-bit字,要在DATA的最后补0;
  3. 将所有的16-bit字相加(包括checksum字段),其结果仍然是16-bit字,如果出现溢出则结果+1;
  4. 如果最后结果为全1,即:0XFFFF,则表示UDP报文正确,否则应该认为UDP报文有错误,应该丢弃。

欢迎访问我的博客:https:whowin.cn

展开阅读全文

页面更新:2024-03-12

标签:反码   报头   目的   报文   字段   算法   定义   协议   结构   地址

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top