Faire un don ! | | style | statistiques | contactez-nous | plan | lettre d'information

Programmation.c : Probleme de calcul du Checksum TCP

Posté par Julien Vehent (Jabber id, page perso, ) le 24 juillet 2007
Bonjour a tous,



je fabrique mes propres paquets TCP et j'ai du mal a calculer le checksum



je cree le pseudo header comme ca :



struct pseudo_header

{

unsigned long saddr, daddr; /*! src/dst IP addresses */

char mbz;

unsigned char ptcl; /*! protocol (tcp = 6, udp = 17) */

unsigned short tcpl; /*! length (tcp header + payload)*/

};





ma fonction checksum est la suivante



int checksum (unsigned short *buf, int nwords)

{

unsigned long sum;

for (sum = 0; nwords > 0; nwords--)

sum += *buf++;

sum = (sum >> 16) + (sum & 0xffff);

sum += (sum >> 16);

return ~sum;

}





et le tout est appele de la facon suivante





/*! *******************

* compute TCP checksum

* ********************

*/

int PSEUDO_SIZE = /*! 12 = size of the pseudoheader */

PAYLOAD_SIZE + (replay_tcp->doff*4) + 12;



char pseudo_tcp[ PSEUDO_SIZE ];



/*! fill up the pseudo header

*/

struct pseudo_header *ph;



ph->saddr = iph->saddr;

ph->daddr = iph->daddr;

ph->mbz = 0;

ph->ptcl = 6;

ph->tcpl = htons(PSEUDO_SIZE - 12);



replay_tcp->check = 0;



memcpy(pseudo_tcp, (char *) ph, 12);

memcpy(pseudo_tcp + 12, (char *) replay_tcp, PSEUDO_SIZE - 12);



/*! compute the checksum and store it in the TCP structure

*/

replay_tcp->check = checksum((unsigned short*) pseudo_tcp, PSEUDO_SIZE );

replay_tcp->check = checksum((unsigned short*) pseudo_tcp, PSEUDO_SIZE );



g_print("%x\n", ntohs(checksum((unsigned short*) pseudo_tcp, PSEUDO_SIZE )));





PAYLOAD_SIZE a la bonne valeur (je bosse sur des caracteres ascii pour le moment)

replay_tcp est bien parse, je le vois dans ethereal



Par contre ethereal me dit toujours que mes checksums sont faux, et effectivement la machine de destination n'accepte pas la connection lorsquelle recoit un SYN



J'ai relu plusieurs fois la RFC et le pseudo header correspond a ce qui est requis. Du coup, je pense que j'ai un probleme avec ma fonction checksum mais comme elle ne viens pas de moi et que je suis pas super a l'aise avec les complements a 1, j'y ai pas retouche......



si quelqu'un a une idee.... :)

> Lire le message (3 commentaires, moyenne: 1).  

Vous avez demandé le commentaire #853719.

2 idées et 1 remarque

Posté par jcs (page perso, ) le 25/07/2007 à 08:13. (lien). Évalué à 1.

1 - La RFC 793 dit

The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit words in the header and text.
. Cependant tu calcules la somme des mots de 16 bits sans prendre le complément à 1.

2 - Tu risques des problèmes d'endianness en castant ta struct en unsigned short (surtout si tu es sur une little endian comme les x86) : problème des retenues dans la somme.

Remarque : Le unsigned short ne fait pas forcément 16 bits. Mieux vaut utiliser les types définis dans inttypes.h (Single Unix) intXX_t et uintXX_t.

--
Hurd will be out in a year (or two, or next month, who knows)
-- Linus Benedict Torvalds, 1991
  • [^]Re: 2 idées et 1 remarque

    Posté par Julien Vehent (Jabber id, page perso, ) le 25/07/2007 à 17:57. (lien). Évalué à 1.

    J'utilise une autre fonction de calcul de checksum qui vient d'un article de phrack maintenant


    int checksum (unsigned short *buf, int nwords)
    {
    /*! Compute Internet Checksum for "count" bytes
    * beginning at location "addr".
    */
    register long sum = 0;

    while( nwords > 1 ) {
    /*! This is the inner loop */
    sum += *buf++;
    nwords -= 2;
    }

    /*! Add left-over byte, if any */
    if( nwords == 1 )
    {
    u_short oddbyte = 0;
    *((u_char *) &oddbyte) = *(u_char *)buf;
    sum += oddbyte;
    }

    /*! Fold 32-bit sum to 16 bits */
    sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
    sum += (sum >> 16); /* add carry */
    return(~sum);
    }


    de fait, le code de creation devient


    /*! *******************
    * compute TCP checksum
    * ********************
    */
    int PSEUDO_SIZE = /*! 12 = size of the pseudoheader */
    PAYLOAD_SIZE + (replay_tcp->doff*4) + 12;

    char pseudo_tcp[ PSEUDO_SIZE ];

    /*! fill up the pseudo header
    */
    struct pseudo_header *ph = (struct pseudo_header *) pseudo_tcp;

    ph->saddr = iph->saddr;
    ph->daddr = iph->daddr;
    ph->mbz = 0;
    ph->ptcl = 6;
    ph->tcpl = htons(PSEUDO_SIZE - 12);

    /*! fill check field to 0 for checksum computation
    */
    replay_tcp->check = 0;

    /*! add tcp header + payload to the pseudo packet
    */
    memcpy((char *)&ph->tcp, (char *)&replay_tcp, PSEUDO_SIZE - 12);

    /*! compute the checksum and store it in the TCP structure
    */
    replay_tcp->check = checksum((unsigned short *) pseudo_tcp, PSEUDO_SIZE );

    g_print("check = %x, size = %u \n", ntohs(replay_tcp->check), PSEUDO_SIZE);


    mais ca marche toujours pas :'(

    --
    www.linuxwall.info