¿Por qué FUNCIONA TAN BIEN este TCP checksum? 4.0

Iniciado por Kaxperday, 4 Enero 2016, 09:23 AM

0 Miembros y 1 Visitante están viendo este tema.

Kaxperday

Lo que hace la función es recibir como argumentos los bytes de un paquete tcp y su tamaño, entonces recalcula su tcp checksum simplemente ESO.

Ayudandome con wireshark y estudiando los paquetes tcp, miro donde comienza cada campo, direcciónes ip origen y destino, los bytes donde se encuentran, y demás, y con la teoría aprendo a calcular las cosas.

Bien, se supone que para calcular un tcp checksum necesito:

http://www.roman10.net/how-to-calculate-iptcpudp-checksumpart-1-theory/

Citar

source address: 32 bits/4 bytes, taken from IP header
destination address: 32bits/4 bytes, taken from IP header
resevered: 8 bits/1 byte, all zeros
protocol: 8 bits/1 byte, taken from IP header. In case of TCP, this should always be 6, which is the assigned protocol number for TCP.
TCP Length: The length of the TCP segment, including TCP header and TCP data. Note that this field is not available in TCP header, therefore is computed on the fly.

Note that TCP pseudo header does not really exist, and it's not transmitted over the network. It's constructed on the fly to compute the checksum.

If a TCP segment contains an odd number of octets to be checksummed, the last octect is padded on the right with zeros to form a 16-bit word. But the padding is not part of the TCP segment and therefore not transmitted.

Lo que hago es eso, comienzo sumando ip de origen y destino, luego el numero de protocolo (con el byte de ceros a la izquierda que es indiferente y no lo pongo), luego sumo el tamaño del segmento tcp, tras mucho sudor lo conseguí pues coincide con el de wireshark y ahora los checksums me dan aproximados, y luego sumo los bytes de cabecera desde el byte que empieza hasta el final del mismo de 2 en 2 bytes, y luego con el payload tcp o campo de datos lo mismo hasta el final, y si es impar al ir sumando de 2 en 2 se queda sin pareja el ultimo byte, en ese caso hay que hacer un "padding a la derecha", que supongo que consiste en colocar un byte de ceros a la izquierda del ultimo byte para formar la ultima pareja del campo de datos o payload.

Código:

Código (cpp) [Seleccionar]

//http://www.arcesio.net/checksum/checksumTCP.html
u_char* tcp_checksum(const u_char* _datos, int _tamaño)
{
u_char *checksum = new u_char[2];
u_short sumando = 0, sumanda = 0;
bitset<17> controlador;

if (_tamaño < 54)
return nullptr;

//sumo ip origen e ip destino
for (int i = 26; i < 33; i++){
sumanda = (u_short)((_datos[i] << 8) + _datos[i + 1]);
controlador = sumando + sumanda;
sumando += sumanda;
if (controlador[16] == 1)
sumando++;
i++;
}

//sumo el byte de ceros y el numero de protocolo TCP
sumanda = (u_short)0x06;
controlador = sumando + sumanda;
sumando += sumanda;
if (controlador[16] == 1)
sumando++;

//sumamos el tcp segment len
sumanda = (u_short)((_datos[16] << 8) + _datos[17]) - ((u_short)((_datos[46] & 0xF0) >> 4) + (u_short)(_datos[14] & 0x0F)) * 4;
controlador = sumando + sumanda;
sumando += sumanda;
if (controlador[16] == 1)
sumando++;

//sumo todo el campo de cabecera con el checksum a cero
for (int i = 34; i < 53; i++){
if (i != 50){
sumanda = (u_short)((_datos[i] << 8) + _datos[i + 1]);
controlador = sumando + sumanda;
sumando += sumanda;
if (controlador[16] == 1)
sumando++;
}
i++;
}

//sumo todo el payload tcp
for (int i = 54; i < _tamaño - 1; i++){
sumanda = (u_short)((_datos[i] << 8) + _datos[i + 1]);
controlador = sumando + sumanda;
sumando += sumanda;
if (controlador[16] == 1)
sumando++;
i++;
}

if (_tamaño % 2){
sumanda = (u_short)_datos[_tamaño - 1];
controlador = sumando + sumanda;
sumando += sumanda;
if (controlador[16] == 1)
sumando++;
//if its odd the last octect is padded on the right with zeros to form a 16 - bit word
}

if (_tamaño % 2)cout << "Impar";

sumando = sumando & 0xFFFF;
sumando = ~sumando;
checksum[0] = (sumando >> 8) & 0x00FF;
checksum[1] = sumando & 0x00FF;
return checksum;
}


Ejemplo de salida:

7626==763a
8299==82ad
487b==488f
12dc==12f0
81d3==81e7
7a56==7a6a
289c==28b0
24c2==24d6
cfd6==cfea
2158==Impar2b62
1d25==1d39
82a4==Impar8cae
1651==1665
5d5d==Impar6767
abff==Imparb69
e6b6==e6ca
ca7e==ca92
b759==b76d
744f==7463
4f27==Impar8a0
b2bc==Imparbcc6
cfb6==Impard9c0
5a93==Impar649d
1b32==Impar253c
2c7==Imparcd1
5b40==Impar654a
f37a==Imparfd84
9f77==9f8b
40b9==Impar4ac3
17b==Imparb85
142e==Impar1e38
9acb==9adf
eab3==eac7
678d==Impar7197
3c56==Impar4660
16d==181


Como se puede observar en la salida, cuando es par hay una diferencia siempre constante entre el checksum original y el recalculado, sin embargo cuando es impar no encuentro la relación que difiere entre ellos.

¿que falla? ¿por qué no coinciden?, he sumado todos los campos que piden, tal y como piden.

PD: y no me seáis guiris que responden sin cerebro:

http://stackoverflow.com/questions/34582015/tcp-checksum-3-0-version

Saludos y gracias.

EDICION DELICATESSE MAAAXIMAAA: HOY ES EL DÍA, HOY ES EL DÍA que conseguí calcular el tcp checksum. Hoy es mí día, resulta que el padding cuando eran impares hay que añadir un byte de ceros en la última posición, no en la penúltima como hacía es decir, añader el cero a la derecha no a la izquierda, ahora si:


if (_tamaño % 2){
sumanda = (u_short)(_datos[_tamaño - 1] << 8) + 0;
controlador = sumando + sumanda;
sumando += sumanda;
if (controlador[16] == 1)
sumando++;
//if its odd the last octect is padded on the right with zeros to form a 16 - bit word
}
       sumando += 20;
if (_tamaño % 2)cout << "Impar";
sumando = sumando & 0xFFFF;
sumando = ~sumando;
checksum[0] = (sumando >> 8) & 0x00FF;
checksum[1] = sumando & 0x00FF;
return checksum;
}


Queríais tcp checksum, tomad tcp checksums:


504c==504c
e2fc==e2fc
4049==4049
3f42==Impar3f42
baa2==Imparbaa2
5d75==5d75
45bb==Impar45bb
3165==Impar3165
eb0==eb0
42f6==42f6
ce7==ce7
203d==Impar203d
6946==Impar6946
e57==Impare57
3229==Impar3229
ae92==Imparae92
6abd==Impar6abd
14d==Impar14d
c18e==Imparc18e
6372==Impar6372
6087==Impar6087
59fe==59fe
e086==Impare086
e475==Impare475
5f38==5f38


Eso sí, si me diriaís porque cohone estoy sumando 20 para que funcione ya sería lo maximo. Pero me es ya un poco indiferente porque.... FUNCIONAAAAA!!!!.

SOOLUCIONADO TAMBIEN:

Código (cpp) [Seleccionar]

sumanda = (u_short)((_datos[16] << 8) + _datos[17]) - (u_short)((_datos[46] & 0xF0) >> 4)  *4;// (u_short)(_datos[14] & 0x0F)) * 4;


https://www.youtube.com/watch?v=m5voqcN9zm4

Me abro el champan.

Os fije que caería esta semana, y no paso de primera hora.

Saludos.

Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.