Search code examples
clinuxnetworkingchecksumraw-sockets

Unable to verify TCP checksum


I have been using raw sockets to create custom TCP packets in C. To verify, I sent them to the loopback interface, and when I checked the received packets using TCPDUMP, the checksum did not match for the TCP packet. Here are the fields in the TCP header :

        tcp->th_sport = temp_port;      // The TCP structure. The source port, spoofed, we accept through the command line
        tcp->th_dport = atoi(argv[2]);  // The destination port, we accept through command line
        tcp->th_seq = htonl(random_id()%1000);
        tcp->th_ack = htonl(random_id()%1000);
        tcp->th_off = 5;
        tcp->th_flags = TH_SYN;
        tcp->th_win = 10000;
        tcp->th_sum = 0;
        tcp->th_urp = 0;
        
        //pseudo header for TCP checksum calculation
        p_hdr->source = t1->s_addr;
        p_hdr->dest = t2->s_addr;
        p_hdr->reserved = 0;
        p_hdr->protocol = IPPROTO_TCP;  //TCP
        p_hdr->tcp_size = sizeof(struct tcphdr);
        memcpy(buffer2 + sizeof(struct pseudo_tcp_header) , tcp , sizeof(struct tcphdr) );
        tcp->th_sum = htons(csum((unsigned short *) (buffer2 ), sizeof(struct tcphdr) + sizeof(struct pseudo_tcp_header)));

This is the random_id function :

int random_id()
{
    int lower = 1, upper = 65535,number;
    number = (rand() % (upper - lower + 1)) + lower;
    return number;
}

And the checksum is computed by the function,

unsigned short csum(unsigned short *buf, int len)
{
    unsigned long sum;
    for(sum=0; len>0; len--)
        sum += *buf++;
    sum = (sum >> 16) + (sum &0xffff);
    sum += (sum >> 16);
    return (unsigned short)(~sum);
}

Is there a default function to compute the tcpchecksum in C ?


Solution

  • I understand that there is no default function for calculating the ip/tcp checksum. It can be found by the following code :

    unsigned short csum(unsigned short *buf, int len)
    {
        unsigned long sum;
        for(sum=0; len>0; len--)
            sum += *buf++;
        while (sum>>16)
            sum = (sum >> 16) + (sum &0xffff);
        return (unsigned short)(~sum);
    }
    

    Where the input, buf if the data with the pseudo header.

    This calculation is only required if the data packet only traverses through the localhost. If it passes the network card to an external network, leave the sum field blank. The network card will automatically compute the header value.