0

I spent some time trying to calculate the UDP checksum, but every time I observe the packets in Wireshark, it says that the checksum is incorrect. Here's the code:

uint16_t compute_udp_checksum(IP *ip, UDP *u, 
               void *data, int data_len)
{
    uint32_t sum = 0;
    uint16_t *arr = NULL;
    void *buffer = NULL;
    int size = 0;
    PSEUDO_HDR *ps = NULL;

    size = PS_SIZE + UDP_SIZE + data_len;

    if (size % 2)
            size += 1;

    buffer = malloc(size);
    if (!buffer)
     {
            perror("malloc");
            return 0;
     }

    ps = create_pseudo_hdr(ip, u);
    if (!ps)
     {
            free(buffer);
            perror("malloc");
            return 0;
     }

    memset(buffer, 0, size);
    memcpy(buffer, ps, PS_SIZE);
    memcpy(buffer + PS_SIZE, u, UDP_SIZE);
    memcpy(buffer + PS_SIZE + UDP_SIZE, data, data_len);

    arr = (uint16_t *) buffer;

    int i = size;
    while (i > 1)
     {
            sum += *arr++;
            i -= 2;
     }

    sum = (sum & 0xFFFF) + (sum >> 16);
    return ~sum;

}

As I said, when I sent the packet into the network, Wireshark reports (on the receiving end) that the checksum is incorrect. Any help would be appreciated.

Thank you.

Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
  • 1
    1) you are not treating your shorts in 1's complement. you need to use htons possibly. 2) you are potentially missing the last byte sum in your while loop, also your sum is assuming that it's going to end up being 16 bits after one pass. not sure how you are adding the IP address info (no idea what your UDP * looks like) also you are not adding the data length into the sum (which has to be in 1s complement) so yeah. – Ahmed Masud Apr 16 '18 at 09:49
  • "Wireshark reports (on the receiving end) that the checksum is incorrect." Posting the report and your code's result and the expected result would be useful than simply describing the error. – chux - Reinstate Monica Apr 16 '18 at 16:00

1 Answers1

0

Since I don't really know what you are doing up there with all your structs I will give you a reference checksum implementation, hopefully it will help you figure out your thing:

#include <stdint.h>
#include <netinet/in.h>

struct udp {
      uint16_t u_sport; /* source port */
      uint16_t u_dport; /* dest port */
      uint16_t u_len; /* length */
      uint16_t u_chksum; /* checksum */
} __attribute__((packed));

uint16_t udp_checksum(const void *buffer, size_t length, in_addr_t src_addr, in_addr_t dest_addr)
{
    const uint16_t *buf = buffer; /* treat input as bunch of uint16_t's */
    uint16_t *src_ip = (void *) &src_addr; 
    uint16_t *dest_ip = (void *)&dest_addr;
    uint32_t sum;
    size_t len = length;

    sum = 0; 

    /* fold the carry bits for the buffer */
    while (length > 1) {
        sum += *buf++;
        if (sum & 0x80000000)
            sum = (sum & 0xFFFF) + (sum >> 16); /* fold  carries */
        length -= 2;
    }

    if(length & 1)
        sum += *((uint8_t *)buf); // add the padding if packet length is odd */

    /* inject checksum of the pseudo-header */
    sum += *(src_ip++);
    sum += *(src_ip);

    sum += *(dest_ip++);
    sum += *(dest_ip);

    sum += htons(IPPROTO_UDP); /* protocol info */
    sum += htons(len); /* original length! */

    /* fold any carry bits created by adding header sums */
    while(sum >> 16)
        sum = (sum & 0xFFFF) + (sum >> 16);

    return (uint16_t)(~sum);
}
Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
  • Does it handle final the byte correctly both on big-endian and little-endian platforms? – Vi. Sep 14 '18 at 21:24