¿Dónde está el problema? TCP checksum

Iniciado por Kaxperday, 13 Noviembre 2015, 20:23 PM

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

Kaxperday

He buscado funciones, he intentado hacerla paso a paso y no funciona, ¿alguien puede decirme como calcular el tcp checksum a partir de el array de bytes del paquete y otra variable con su tamaño?, estaría muy bien, mientras habrá que buscar.  :-* :-*

Código con el que traté de implementarlo por mi cuenta:

Código (cpp) [Seleccionar]
//http://www.arcesio.net/checksum/checksumTCP.html
u_char* tcp_checksum(u_char* datos, int tamaño)
{
u_char checksum[2];
uint16_t sumando = 0, sumanda = 0;
bitset<17> total;
for (int i = 26; i < 33; i++)//del 26 al 33 ip origen y destino se suman
{
sumanda = (uint16_t)((datos[i] << 8) + datos[i + 1]);
total = sumando + sumanda;
sumando += sumanda;
if (total[16] == 1)//al sumar sumanda a sumando acarrea bit.
sumando++;
i++;
}
sumanda = (uint16_t)(0x06);//sumamos el tipo paquete tcp
total = sumando + sumanda;
sumando += sumanda;
if (total[16] == 1)//al sumar sumanda a sumando acarrea bit.
sumando++;
sumanda = (uint16_t)(tamaño - 34);// ((datos[38] << 8) + datos[39]);//sumamos el tamaño del paquete.
//sumanda = (uint16_t)((datos[38] << 8) + datos[39]);//sumamos el tamaño del paquete.
total = sumando + sumanda;
sumando += sumanda;
if (total[16] == 1)//al sumar sumanda a sumando acarrea bit.
sumando++;
//YA TENEMOS CALCULADO EL PSEUDO HEADER.
for (int i = 34; i < 40; i++)//del 34 al 41, 3 campos tcp header.
{
sumanda = (uint16_t)((datos[i] << 8) + datos[i + 1]);
total = sumando + sumanda;
sumando += sumanda;
if (total[16] == 1)//al sumar sumanda a sumando acarrea bit.
sumando++;
i++;
}
for (int i = 42; i < tamaño; i++)//sumamos resto.
{
sumanda = (uint16_t)((datos[i] << 8) + datos[i + 1]);
total = sumando + sumanda;
sumando += sumanda;
if (total[16] == 1)//al sumar sumanda a sumando acarrea bit.
sumando++;
i++;
}
sumando = sumando & 0xFFFF;
sumando = ~sumando;
checksum[0] = (sumando >> 8) & 0x00FF;
checksum[1] = sumando & 0x00FF;
return checksum;
}


Lo saqué de aqui como hacerlo:

http://www.arcesio.net/checksum/checksumTCP.html

Pero no funciona, pues al comparar mis tcp checksums con los de wireshark no coinciden, ¿alguna ayuda?. ¿que tengo mal?.

Gracias.

He estado mirando y tengo mal en la linea que hago la suma del tamaño del paquete, ese no es su tamaño. Pero aun asi sigue fallando.

¿en la línea 20 que habría que poner?.

Edito: Haber sumo primero la ip origen y destino, el numero de protocolo 0x06 (pasandolo a u_short como todos los sumandos), y luego le sumo la linea en duda del tamaño del tcp header y sus datos.

Luego a eso le tengo que sumarla suma del campo tcp header de u_short en u_short e igual con el payload, ¿pero porque no funciona?.

Ejemplo salida:

Código (cpp) [Seleccionar]
if (pkt_data[23] == 0x06){
u_char origen[4];
u_char destino[4];
memcpy(origen, const_cast<u_char*>(pkt_data + 26), sizeof(u_char)* 4);
memcpy(destino, const_cast<u_char*>(pkt_data + 30), sizeof(u_char)* 4);

in_addr a;
in_addr b;
a.S_un.S_addr = inet_addr((char*)origen);
b.S_un.S_addr = inet_addr((char*)destino);
printf("%x%x==", pkt_data[50], pkt_data[51]);
printf("%x%x==", tcp_check(const_cast<u_char*>(pkt_data), header->caplen, inet_addr((char*)origen), inet_addr((char*)destino))[0],
tcp_check(const_cast<u_char*>(pkt_data), header->caplen, inet_addr((char*)origen), inet_addr((char*)destino))[1]);
printf("%x%x", tcp_checksum(const_cast<u_char*>(pkt_data), header->caplen)[0],
tcp_checksum(const_cast<u_char*>(pkt_data), header->caplen)[1]);
cout << endl;
}


Citarbee==d4f9==014
4eb4==d4f9==014
675a==d4f9==014

Me sale el checksum siempre 014 ???

Por cierto la otra funcion que pruebo, que no es mía tampoco funciona es:

Código (cpp) [Seleccionar]
u_char* tcp_check(u_char *buff, size_t len, u_long src_addr, u_long dest_addr)
{
uint16_t *buf = (uint16_t*)buff;
uint16_t ip_src = (uint16_t)src_addr, ip_dst = (uint16_t)dest_addr;
         uint32_t sum;
         size_t length = len;
         // Calculate the sum                                            //
         sum = 0;
         while (len > 1)
         {
                 sum += *buf++;
                 if (sum & 0x80000000)
                         sum = (sum & 0xFFFF) + (sum >> 16);
                len -= 2;
        }

        if (len & 1)
                // Add the padding if the packet lenght is odd          //
                 sum += *((uint8_t *)buf);

        // Add the pseudo-header                                        //
         sum += (ip_src++);
        sum += ip_src;
         sum += (ip_dst++);
         sum += ip_dst;
         sum += htons(IPPROTO_TCP);
        sum += htons(length);

         // Add the carries                                              //
         while (sum >> 16)
                 sum = (sum & 0xFFFF) + (sum >> 16);

u_char ret[2];
        // Return the one's complement of sum 
ret[0] = ((uint16_t)(~sum) >> 8) & 0x00FF;
ret[1] = (uint16_t)(~sum) & 0x00FF;//
        // return ((uint16_t)(~sum));
return ret;
}
//http://minirighi.sourceforge.net/html/tcp_8c-source.html
Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.

rub'n

#1
pufff y yo que ando con el CCNA. ya que toda la suite tcp/ip es código purito que no vemos  :xD


rubn0x52.com KNOWLEDGE  SHOULD BE FREE!!!
If you don't have time to read, you don't have the time (or the tools) to write, Simple as that. Stephen

Kaxperday

Buenas, a ver si puedo cerrar el tema por una vez:

http://www.tcpipguide.com/free/t_TCPChecksumCalculationandtheTCPPseudoHeader-2.htm

Lo que tengo que hacer para calcular primero el pseudoheader y sumar todos sus campos como de u_short en u_short (16 bits en 16 bits), ¿luego sumamos toda la cabecera TCP, y luego el payload?

¿Todo de 16 bits en 16 bits?, porque me daba todo unos luego ¿hacía algo mal, no tiene sentido o tenía algún error, o no se calcula así?.

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.

rub'n

una pregunta estas haciendo algún proyecto en especial ? o en realidad estas simulando comprobar el crc, del PDU, y luego pasarlo a la capa siguiente en tcp/ip?

todo practicamente manual ??  :huh:


rubn0x52.com KNOWLEDGE  SHOULD BE FREE!!!
If you don't have time to read, you don't have the time (or the tools) to write, Simple as that. Stephen

Kaxperday

#4
Si pertenece a un proyecto y es necesario para que pueda rodar en sí, pero no es lo que piensas, lo que trato de hacer es modificar paquetes TCP tanto de origen y destino, pero si el checksum no queda actualizado el paquete se descarta, el checksum ip si que lo conseguí calcular bien, pero este no.

Mí código que hice para calcularlo es sencillo, suma bien de 16 bits en 16 y controlando el acarreo de bit, el problema es más teórico. Necesito algo de ayuda.

Un saludo.

Os dejo el código que tengo, solo necesito calcular bien el tcp len para poder comprobar si funciona lo demás:

Código (cpp) [Seleccionar]

//http://www.arcesio.net/checksum/checksumTCP.html
u_char* tcp_checksum(u_char* datos, int tamaño)
{
u_char *checksum = new u_char[2]();
uint16_t sumando = 0;
bitset<17> total;

//sumo ip origen e ip destino
for (int i = 26; i < 33; i++){
total = sumando + (uint16_t)((datos[i] << 8) + datos[i + 1]);
sumando += (uint16_t)((datos[i] << 8) + datos[i + 1]);
if (total[16] == 1)
sumando++;
i++;
}

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

//aqui sumaría el tcp len no se calcular aún.
//[IP Total Length] - (([IP IHL] + [TCP Data offset]) * 4)
//Aquí sumaríamos el TCP len ¿cuanto es?.
/*total = sumando + (uint16_t)((datos[38] << 8) + datos[39]);
sumando += (uint16_t)((datos[38] << 8) + datos[39]);
if (total[16] == 1)
sumando++;*/

//sumo todo el campo de cabecera con el checksum a cero
for (int i = 34; i < 54; i++){
if (i != 50){
total = sumando + (uint16_t)((datos[i] << 8) + datos[i + 1]);
sumando += (uint16_t)((datos[i] << 8) + datos[i + 1]);
if (total[16] == 1)
sumando++;
}
i++;
}

//sumo todo el campo de datos a lo que teníamos.
for (int i = 55; i < tamaño - 1; i++){
total = sumando + (uint16_t)((datos[i] << 8) + datos[i + 1]);
sumando += (uint16_t)((datos[i] << 8) + datos[i + 1]);
if (total[16] == 1)
sumando++;
i++;
}

//invertimos y pasamos a dos bytes el resultado.
sumando = sumando & 0xFFFF;
sumando = ~sumando;
checksum[0] = (sumando >> 8) & 0x00FF;
checksum[1] = sumando & 0x00FF;
return checksum;
}


Edito:

Finalmente, para calcular el TCP checksum hay que tener crear un array de u_short formado por la concatenación del pseudoheader, cabecera tcp, y tcp payload (datos tcp).

Yo no formo el array paso directamente a sumar sus partes. Sumo primero las ips, luego sumo  el numero protocolo y el tcp len que son 96 bits.

Depués sigo sumando al resultado toda la cabecera casi siempre son 20 bytes, que sumamos de 16 bits en 16 bits cada par.

Después sumo los datos TCP de 16 bits en 16 bits como siempre.

Una vez está todo sumado, invierto el u_short y lo divido en 2 bytes (u_char).

¿Es el método correcto? ¿Por qué falla?.

El tcp len no es el único problema (ya que no lo sé calcular), pues con wireshark compruebo que hay paquetes que lo llevan a cero, y aún así no coinciden los checksums.

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