Чтобы вычислить контрольную сумму 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 допустил ошибку.