2010-12-01 32 views
1

Je tente de créer un paquet uniquement en fonction du contenu de la charge utile. Par conséquent, je vais devoir créer des en-têtes IPv4 et UDP factices. J'ai un problème d'insertion de la valeur de contrôle IPv4 dans l'en-tête IP factice. La valeur de somme de contrôle est calculée à l'aide de l'algorithme utilisé par Wireshark. J'ai seulement légèrement modifié le code afin que je puisse insérer la valeur de somme de contrôle dans l'en-tête IP.Insertion de la somme de contrôle de l'en-tête IPv4 dans l'en-tête IP factice

Mon code est le suivant (en utilisant Microsoft Visual Studio .NET 2003):

/********************** main.c ***********************/ 
#include <stdio.h> 
#include <stdlib.h> 
#include <windows.h> 
#include <string.h> 
#include <tchar.h> 
#include <strsafe.h> 
#include "in_cksum.h" 

#define SIZE_IP_HDR 20 

unsigned char ip_header[] = {0x45, 0x00, 0x05, 0x30, 0x00, 0x00, 0x40, 0x00, 0x20, 0x11, 0x00, 0x00, 0x21, 0x4f, 0x02, 0x7b, 0xcc, 0x5c, 0x46, 0x00}; 

int main(int argc, char **argv) 
{ 
    ip_cal_checksum(ip_header, SIZE_IP_HDR); 
    ip_header[12] = 0x2d; 
    ip_cal_checksum(ip_header, SIZE_IP_HDR); 
    return 0; 
} 


/********************** in_cksum.h ***********************/ 
#ifndef IN_CKSUM_H 
#define IN_CKSUM_H 

typedef unsigned __int8 uint8_t; 
typedef unsigned __int16 uint16_t; 
typedef unsigned __int32 uint32_t; 

typedef struct 
{ 
    const uint8_t *ptr; 
    int len; 
} vec_t; 

int in_cksum(const vec_t *vec, int veclen); 
uint16_t calculate_cksum(const vec_t *vec, int veclen); 
void ip_cal_checksum(const uint8_t *ptr, int len); 

#endif /* IN_CKSUM_H */ 


/********************** in_cksum.c ***********************/ 
#include "in_cksum.h" 

#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) 
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} 

int in_cksum(const vec_t *vec, int veclen) 
{ 
    register const uint16_t *w; 
    register int sum = 0; 
    register int mlen = 0; 
    int byte_swapped = 0; 

    union { 
     uint8_t c[2]; 
     uint16_t s; 
    } s_util; 
    union { 
     uint16_t s[2]; 
     uint32_t l; 
    } l_util; 

    for (; veclen != 0; vec++, veclen--) { 
     if (vec->len == 0) 
      continue; 
     w = (const uint16_t *)vec->ptr; 
     if (mlen == -1) { 
      /* 
      * The first byte of this chunk is the continuation 
      * of a word spanning between this chunk and the 
      * last chunk. 
      * 
      * s_util.c[0] is already saved when scanning previous 
      * chunk. 
      */ 
      s_util.c[1] = *(const uint8_t *)w; 
      sum += s_util.s; 
      w = (const uint16_t *)((const uint8_t *)w + 1); 
      mlen = vec->len - 1; 
     } else 
      mlen = vec->len; 
     /* 
     * Force to even boundary. 
     */ 
     if ((1 & (unsigned long) w) && (mlen > 0)) { 
      REDUCE; 
      sum <<= 8; 
      s_util.c[0] = *(const uint8_t *)w; 
      w = (const uint16_t *)((const uint8_t *)w + 1); 
      mlen--; 
      byte_swapped = 1; 
     } 
     /* 
     * Unroll the loop to make overhead from 
     * branches &c small. 
     */ 
     while ((mlen -= 32) >= 0) { 
      sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 
      sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 
      sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 
      sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 
      w += 16; 
     } 
     mlen += 32; 
     while ((mlen -= 8) >= 0) { 
      sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 
      w += 4; 
     } 
     mlen += 8; 
     if (mlen == 0 && byte_swapped == 0) 
      continue; 
     REDUCE; 
     while ((mlen -= 2) >= 0) { 
      sum += *w++; 
     } 
     if (byte_swapped) { 
      REDUCE; 
      sum <<= 8; 
      byte_swapped = 0; 
      if (mlen == -1) { 
       s_util.c[1] = *(const uint8_t *)w; 
       sum += s_util.s; 
       mlen = 0; 
      } else 
       mlen = -1; 
     } else if (mlen == -1) 
      s_util.c[0] = *(const uint8_t *)w; 
    } 
    if (mlen == -1) { 
     /* The last mbuf has odd # of bytes. Follow the 
      standard (the odd byte may be shifted left by 8 bits 
      or not as determined by endian-ness of the machine) */ 
     s_util.c[1] = 0; 
     sum += s_util.s; 
    } 
    REDUCE; 
    return (~sum & 0xffff); 
} 

uint16_t calculate_cksum(const vec_t *vec, int veclen) 
{ 
    register const uint16_t *w; 
    register int sum = 0; 
    register int mlen = 0; 
    int byte_swapped = 0; 

    union { 
     uint8_t c[2]; 
     uint16_t s; 
    } s_util; 
    union { 
     uint16_t s[2]; 
     uint32_t l; 
    } l_util; 

    for (; veclen != 0; vec++, veclen--) { 
     if (vec->len == 0) 
      continue; 
     w = (const uint16_t *)vec->ptr; 
     if (mlen == -1) { 
      /* 
      * The first byte of this chunk is the continuation 
      * of a word spanning between this chunk and the 
      * last chunk. 
      * 
      * s_util.c[0] is already saved when scanning previous 
      * chunk. 
      */ 
      s_util.c[1] = *(const uint8_t *)w; 
      sum += s_util.s; 
      w = (const uint16_t *)((const uint8_t *)w + 1); 
      mlen = vec->len - 1; 
     } else 
      mlen = vec->len; 
     /* 
     * Force to even boundary. 
     */ 
     if ((1 & (unsigned long) w) && (mlen > 0)) { 
      REDUCE; 
      sum <<= 8; 
      s_util.c[0] = *(const uint8_t *)w; 
      w = (const uint16_t *)((const uint8_t *)w + 1); 
      mlen--; 
      byte_swapped = 1; 
     } 
     /* 
     * Unroll the loop to make overhead from 
     * branches &c small. 
     */ 
     while ((mlen -= 32) >= 0) { 
      sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 
      sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; 
      sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; 
      sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; 
      w += 16; 
     } 
     mlen += 32; 
     while ((mlen -= 8) >= 0) { 
      sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; 
      w += 4; 
     } 
     mlen += 8; 
     if (mlen == 0 && byte_swapped == 0) 
      continue; 
     REDUCE; 
     while ((mlen -= 2) >= 0) { 
      sum += *w++; 
     } 
     if (byte_swapped) { 
      REDUCE; 
      sum <<= 8; 
      byte_swapped = 0; 
      if (mlen == -1) { 
       s_util.c[1] = *(const uint8_t *)w; 
       sum += s_util.s; 
       mlen = 0; 
      } else 
       mlen = -1; 
     } else if (mlen == -1) 
      s_util.c[0] = *(const uint8_t *)w; 
    } 
    if (mlen == -1) { 
     /* The last mbuf has odd # of bytes. Follow the 
      standard (the odd byte may be shifted left by 8 bits 
      or not as determined by endian-ness of the machine) */ 
     s_util.c[1] = 0; 
     sum += s_util.s; 
    } 
    REDUCE; 
    return (~sum & 0xffff); 
} 

void ip_cal_checksum(const uint8_t *ptr, int len) 
{ 
    vec_t cksum_vec[1]; 
    uint16_t ip_checksum = 0; 

    cksum_vec[0].ptr = ptr; 
    cksum_vec[0].len = len; 
    ip_checksum = calculate_cksum(&cksum_vec[0], 1); 
    printf("%x\n", ip_checksum); 
    memcpy((void *)&ptr[10], &ip_checksum, 2); // copy checksum value to IP header 
} 

Le code ci-dessus est une version simplifiée. Dans le code actuel, j'ai créé le paquet avec les en-têtes et le contenu et les ai écrits dans un fichier pcap. En utilisant Wireshark, je vérifie ensuite si la somme de contrôle IP est correcte, c'est-à-dire la même valeur que celle calculée par Wireshark elle-même. Mon problème est que sans la ligne memcpy dans ip_cal_checksum(), j'obtiens les valeurs de checksum correctes pour tous les paquets créés. Cependant, avec la ligne memcpy, seule la première somme de contrôle est correcte et la plupart sinon toutes les autres valeurs de total de contrôle sont erronées.

Par exemple, en utilisant le code ci-dessus, la première valeur de total de contrôle calculée est 0x971f indépendamment de la présence de la ligne memcpy. Toutefois, la deuxième valeur de total de contrôle calculée est 0x9713 SANS la ligne memcpy et 0xfff3 avec la memcpy.

Pourquoi la valeur de la somme de contrôle varie-t-elle selon que la ligne memcpy est présente et comment puis-je la résoudre?

Merci.

Regards, Rayne

Répondre

2

La ligne de memcpy modifie l'en-tête (en réglant la somme de contrôle à l'intérieur), et en ce que en-tête modifié est l'entrée à la seconde somme de contrôle.

Vous devez définir le champ de somme de contrôle sur 0 avant de calculer une somme de contrôle, pour obtenir le résultat correct.