Forum Programmation.c Probleme de calcul du Checksum TCP

Posté par  (site web personnel) .
Étiquettes : aucune
0
24
juil.
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.... :)
  • # 2 idées et 1 remarque

    Posté par  (site web personnel) . É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.
    • [^] # Re: 2 idées et 1 remarque

      Posté par  (site web personnel) . É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 :'(
  • # malloc ?

    Posté par  . Évalué à 1.

    Il ne manquerait pas un appel à malloc() avant l'initialisation des membres de ph ?
    /*! fill up the pseudo header
    */
    struct pseudo_header *ph;
    
    ph = malloc(sizeof(struct pseudo_header));
    
    ph->saddr = iph->saddr;
    ph->daddr = iph->daddr;
    ph->mbz = 0;
    ph->ptcl = 6;
    ph->tcpl = htons(PSEUDO_SIZE - 12);

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.