Расчет контрольной суммы TCP в C ++ - PullRequest
0 голосов
/ 08 марта 2020

Чтобы вычислить контрольную сумму tcp, мы делаем псевдозаголовок с единичной суммой + заголовок tcp (без контрольной суммы) + полезная нагрузка + заполнение (если полезная нагрузка нечетная, мы добавляем нули для создания чистых 16-битных фрагментов) и, наконец, дополняем единицами. результат.

struct pseudoheader{ // 96 Bits Pesudo, 3*32 Bits
    uint32_t arr[3];
};


void fill_pseudoheader(struct pseudoheader &p,uint32_t source, uint32_t destination, u_char reserved, u_char protocol, u_short tcp_length){
    p.arr[0] = source; //filling the pseudo-struct
    p.arr[1] = destination;
    uint32_t a = reserved;
    a = a << 8;
    a+=protocol;
    a = a << 16;
    a+=tcp_length;
    p.arr[2] = a;
}

 u_short calculateTCPChecksum(struct pseudoheader p,const u_short* tcp, int header_size, int payload_size){
    u_short checksum = 0;

    /* Adding 96 Bit Pseudo-Header in 16 bit fragments*/
    u_short* a = reinterpret_cast<u_short*>(p.arr);
    for(int i =0; i < 6;i++){
        if(checksum+*a>0xFFFF){
            checksum+=*a;
            checksum+=0x0001;
            a++;
        }else{
            checksum+=*a;
            a++;            
        }
    }
    /* Sum of TCP-Header + Payload in 16 bit fragments */
    int padding = (header_size+payload_size)*8%16; // Byte to Bits and modulo 16 Bits.
    for(int i = 0; i < ((header_size+payload_size)*8+padding)/16; i++){ // inclusive padding, how many 16 bit iterations
        if(i == 8){ // we skip checksum
            continue;
        }
        if(i==((header_size+payload_size)*8+padding)/16 - 1){ // the very last iteration. We know by padding which last bits are random.
            u_short mask = 0xFFFF;//mask off bits that are not part of payload with zeroes
            mask = mask << padding;
            checksum += *tcp & mask;
            break;      
        }
        if(checksum+*tcp>0xFFFF){
            checksum+=*tcp;
            checksum+=0x0001;
            tcp++;
        }else{
            checksum+=*tcp;
            tcp++;          
        }
    }

    return ~checksum; //ones complement the result
}

Я вызываю такие функции:

const u_short * tcp2 = reinterpret_cast<const u_short*>(packet+SIZE_ETHERNET + size_ip);
fill_pseudoheader(p, ip->ip_src.s_addr,ip->ip_dst.s_addr , 0, ip->ip_p, size_payload+size_tcp);
std::cout << "TCP MANUAL: " << std::bitset<16>(ntohs(calculateTCPChecksum(p,tcp2, size_tcp, size_payload))) << std::endl;

tcp2 - указатель на первый байт заголовка tcp. Применил его к указателю u_short, чтобы сделать 16-битные переходы. Аргументы должны быть понятны, когда вы смотрите на псевдо-заголовок, тогда как size_payload + size_tcp в байтах.

Мои результаты отличаются от Wireshark (последняя строка).

Packet number 3:
IP Header length : 20
       From: 127.0.0.1
         To: 127.0.0.1
   Protocol: TCP
Len : 101 CLen: 101
Seq: 3837327876
Ack: 2503991930
   Src port: 8080
   Dst port: 42316
   Payload (35 bytes):
00000   81 21 34 32 5b 22 6d 65  73 73 61 67 65 22 2c 7b    .!42["message",{
00016   22 67 72 65 65 74 69 6e  67 22 3a 22 70 69 6e 67    "greeting":"ping
00032   22 7d 5d                                            "}]
TCP Checksum:    1111111001001011 (wrong, because offloading identical with wiresharks warning)
TCP Checksum self-calculated: 0110010011111010 (my calculated checksum)
TCP Checksum Wireshark:       0010101111111101 (regarding to wireshark it should be)

I Я почти запутался, если Wireshark допустил ошибку.

...