Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 12 sur 12
  1. #1
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    février 2007
    Messages
    520
    Détails du profil
    Informations personnelles :
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : février 2007
    Messages : 520
    Points : 653
    Points
    653

    Par défaut mapping de donnees "a plat" vers structure ipv6

    Bonjour a tous,

    J'ai besoin d'ecouter et de parser des trames IPv6 pour un besoin particulier. J'utilise la libpcap pour sniffer les paquets et pas de soucis de ce cote la. Mon probleme, c'est lorsque j'essaie de mapper le packet renvoye par pcap_next vers ma structure ipv6. Je n'arrive pas a mettre les bons entetes dans les bons champs de ma structure. C'est sans doute une erreur relativement simple ou une incomprehension de ma part. Voici les extraits de codes:

    ip6.h:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    #define ETHER_ADDR_LEN  6
    #define ETHER_HEADER_LEN  14
    #define IP6_ADDR_LEN  16
    #define IP6_HEADER_LEN  40
     
    typedef struct {
      unsigned char dst[ETHER_ADDR_LEN];
      unsigned char src[ETHER_ADDR_LEN];
      unsigned short type;
    } ether_header;
     
    typedef struct {
      unsigned char version:4;
      unsigned char cl;
      unsigned int label:20;
      unsigned short length;
      unsigned char next_header;
      unsigned char ttl;
      unsigned char src[IP6_ADDR_LEN];
      unsigned char dst[IP6_ADDR_LEN];
    } ip6_header;
    sniffer.c, packet est un pointeur vers u_char contenant les valeurs "a plat" du paquet:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    ether_header *ether;
    ip6_header *ip6;
    // If the datalink is standard ethernet
    if (datalink == DLT_EN10MB) {
        ether = (ether_header *)packet;
        printf("Ether_type: %x\n", ntohs(ether->type));
        // If IPv6, then map the remaining of the packet to our ipv6 structure
        if (ntohs(ether->type) == 0x86dd)
          ip6 = (ip6_header *)(packet + sizeof(ether_header));
    }
    printf("ip6 version: %x, class: %x, label: %x, len: %x, next-h: %x, ttl: %x\n", (ip6->version & 0xf0) >> 4, ip6->cl, (ip6->label & 0x000fffff), ip6->length, ip6->next_header, ip6->ttl);
    // Print source ip.
    for (int i = 0; i < IP6_ADDR_LEN; i++) {
        printf("%02x", ip6->src[i]);
    }
    Je ne comprends pas les resultats que j'obtiens, c'est peut etre du a mon incomprehension des bits fields, mais je vois pas comment specifier de maniere fine l'alignement des donnes. A l'execution:

    Code :
    1
    2
    3
    4
    5
     
    //IP version devrait etre 6. Cela marche si je modifie unsigned char version:4 en unsigned char version;
    ip6 version: 0, class: 0, label: a4000, len: 550, next-h: 10, ttl: 2
    //IP source devrait etre 50051002300450067008900ab00c2222, mais est decalee de 4 octets
    300450067008900ab00c222250051002
    Si je lance le tout dans gdb, je vois bien que les structures en memoire ne sont pas alignees de la meme maniere que ma structure:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    (gdb) print &ip6.version
    $4 = (unsigned char *) 0x100801020 "`"
    (gdb) print &ip6.cl     
    $5 = (unsigned char *) 0x100801021 ""
    (gdb) print &ip6.label
    $6 = (unsigned int *) 0x100801024
    (gdb) print &ip6.length
    $7 = (short unsigned int *) 0x100801028
    (gdb) print &ip6.next_header
    $8 = (unsigned char *) 0x10080102a
    entre ip6.version et ip6.cl, j'ai un octet, alors que j'utilise un bit field de 4 bits. entre ip6.cl et ip6.label, j'ai 3 octets, alors que j'utilise un unsigned short. Mes donnees se decalent donc, et mon addresse ipv6 source se retrouve decalee de 4 octets.
    Je pense que c'est du a l'alignement des donnees par le compilateur, mais je vois pas comment gerer ca.
    Mes questions:
    • Est-ce que je peux mapper une zone de memoire vers une structure, comme je le fait? Peut-on se reposer sur le fait que les donnes soient contigues?
    • Si oui, est-ce que le compilateur gere les offset supplementaires en memoire vers la structure a la compilation?
    • Si non, quelle est la methode utilisee dans ce genre de cas - donnees a plat vers donnes mises en forme?


    Merci a ceux qui ont lu jusque la.

  2. #2
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    octobre 2008
    Messages
    1 514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : octobre 2008
    Messages : 1 514
    Points : 2 483
    Points
    2 483

    Par défaut

    Ta structure ip6_header n'est pas bonne. Là tu définit "version" sur 4 bits, ce qui est bon, mais ensuite tu as les 4 autres bits du char qui ne sont pas utilisés. Donc tu lis ton "cl" 4 bits trop loin, et tout est décalé. Pareil pour "label", où tu laisses 12 bits non occupés.

  3. #3
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    février 2007
    Messages
    520
    Détails du profil
    Informations personnelles :
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : février 2007
    Messages : 520
    Points : 653
    Points
    653

    Par défaut

    Merci, effectivement ca marche beaucoup mieux.
    Pour ceux qui connaissent pas les bits fields, l'ensemble des bits doit etre contenu dans un champ type. La version correcte est:

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    typedef struct {
      unsigned int version:4;
      unsigned int class:8;
      unsigned int label:20;
      unsigned short length;
      unsigned char next_header;
      unsigned char ttl;
      unsigned char src[IP6_ADDR_LEN];
      unsigned char dst[IP6_ADDR_LEN];
    } ip6_header;
    J'ai des problemes d'indianness maintenant. Je comprends pas comment je peux avoir un probleme d'indianness au niveau octet d'ailleur...

    EDIT:
    Je crois que j'ai compris. J'ai lu ici que l'ordre des bits dans un bitfield n'est pas standard et depend de l'implementation.
    Je vois pas trop comment m'en sortir, a moins de considerer version, class et label sur un int et de parser a coup de decalage/masquage. Ca m'embete de parser de cette maniere, parce que je peux pas calquer ma structure directement sur la memoire et je dois ecrire un petit parseur.

    Y'a-t-il une solution plus elegante/interessante/utile a ce probleme?

  4. #4
    Membre chevronné

    Ingénieur développement matériel électronique
    Inscrit en
    juillet 2010
    Messages
    307
    Détails du profil
    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Industrie

    Informations forums :
    Inscription : juillet 2010
    Messages : 307
    Points : 606
    Points
    606

    Par défaut

    Salut!

    J'ai lu ici que l'ordre des bits dans un bitfield n'est pas standard et depend de l'implementation.
    Je vois pas trop comment m'en sortir, a moins de considerer version, class et label sur un int et de parser a coup de decalage/masquage. Ca m'embete de parser de cette maniere, parce que je peux pas calquer ma structure directement sur la memoire et je dois ecrire un petit parseur.

    Y'a-t-il une solution plus elegante/interessante/utile a ce probleme?
    C'est un problème au quel je suis souvent confronté. Pour le moment je n'est pas trouvé d'autre solution que de parser mes structures à la main...

    Je suis également preneur si quelqu'un connait une meilleur méthode!!

  5. #5
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    octobre 2008
    Messages
    1 514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : octobre 2008
    Messages : 1 514
    Points : 2 483
    Points
    2 483

    Par défaut

    Je n'ai pas de solution non plus...

    De toute façon, mapper des données sur une structure c'est fondamentalement non portable, même sans parler de bit fields. Rien ne dit que le compilo ne va pas ajouter du padding entre les champs.

  6. #6
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    février 2007
    Messages
    520
    Détails du profil
    Informations personnelles :
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : février 2007
    Messages : 520
    Points : 653
    Points
    653

    Par défaut

    Citation Envoyé par matafan Voir le message
    De toute façon, mapper des données sur une structure c'est fondamentalement non portable, même sans parler de bit fields. Rien ne dit que le compilo ne va pas ajouter du padding entre les champs.
    Je pense pas qu'il y ai de probleme dans ce cas la. Je suis sur que les donnees sont adjacentes en memoire, car le la libpcap ne fait que copier le contenu du paquet vers une adresse connue. Ce n'est pas une structure qui est ecrite en memoire, mais simplement le contenu d'un paquet qui est dumpe a un emplacement memoire.
    Je ne fait que mettre ces donnees en forme. D'ailleurs un parseur n'apporte rien de plus, car je dois avancer en offset fixes pour mapper mes champs. S'il y a padding (mais ce n'est pas possible), la structure sera incorrect de toute facon.

  7. #7
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    octobre 2008
    Messages
    1 514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : octobre 2008
    Messages : 1 514
    Points : 2 483
    Points
    2 483

    Par défaut

    Je sais que tes données sont adjacentes en mémoire. Mais par contre quand tu définit une structure le standard ne garantit pas que les champs sont adjacents en mémoire. Donc quand tu mappes ta structure sur tes données, le standard ne peut pas te garantir que ça va correspondre.

    Par exemple si tu fais :
    Code :
    1
    2
    3
    4
    struct mystruct {
        char a;
        int b;
    };
    alors typiquement tu auras 3 octets de padding entre a et b pour respecter l'alignement de ta plate-forme. Les compilos ont généralement un pragma qui permet de "packer" une structure, c'est à dire de ne pas insérer de padding, mais ces pragmas ne sont pas standardisés.

    Donc au final on fait généralement des trucs non standards qui dépendent du compilo et de la plate-forme, sinon on ne s'en sort pas.

  8. #8
    Membre chevronné
    Profil pro
    Ingénieur sécurité
    Inscrit en
    février 2007
    Messages
    520
    Détails du profil
    Informations personnelles :
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : février 2007
    Messages : 520
    Points : 653
    Points
    653

    Par défaut

    Ok, je comprends mieux ton explication. Je pensais (a tort) que le compilateur serait assez malin pour comprendre que lors du cast il doit mapper les donnees en tenant compte de l'alignement (vu qu'il le connait). Mais j'imagine que c'est trop complexe car il faut memoriser le padding pour chaque structure.

    Dans mon cas, ca doit marcher par chance, car l'en-tete ipv6 est aligne sur 32 bits. Je comprends mieux du coup l'existance et l'interet des __attribute__((__packed__)), pragma et consort.

    Pour info, j'ai finallement parse les donnees.

    Derniere question. Est-ce que je devrait creer mes propres types pour m'assurer que le champ length fait bien 2 octets par exemple? Dans mon cas, je me repose sur le fait que short fait 2 octets et int 4. J'imagine que c'est pour ca que la libpcap definit les types u_char et compagnie?

  9. #9
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    octobre 2008
    Messages
    1 514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : octobre 2008
    Messages : 1 514
    Points : 2 483
    Points
    2 483

    Par défaut

    Le C définit des types de taille fixe intX_t et uintX_t, par exemple int8_t ou uint32_t.

    Sinon les histoire de padding c'est surtout pour des raisons de performance, car il est plus rapide d'accéder à une donnée alignée qu'à une donnée non alignée.

  10. #10
    Modérateur
    Avatar de Bktero
    Profil pro
    Ingénieur systèmes embarqués
    Inscrit en
    juin 2009
    Messages
    2 739
    Détails du profil
    Informations personnelles :
    Âge : 27
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : juin 2009
    Messages : 2 739
    Points : 7 321
    Points
    7 321
    Billets dans le blog
    1

    Par défaut

    Voir même pour certains processeurs, il n'est pas possible d'accéder à des données non alignées.

    Ce qui me rappelle que j'ai un article en cours de rédaction là-dessus et qu'il faudrait que je termine
    Si Code::Blocks vous dit undefined reference to 'socket@12', cela signifie que vous avez un problème d'édition des liens. Allez dans Projects / Build Options / Linker Settings / Add et renseignez ici les .a qui vont bien. Exemple pour les sockets : C:\Program Files\CodeBlocks\MinGW\lib\libws2_32.a

    Pour les adeptes du langage SMS, allez ici et ramenez la traduction française ^^

    Pour vos problèmes d'embarqué, utilisez le forum dédié !

  11. #11
    Expert Confirmé Sénior

    Homme Profil pro Pierre
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    2 237
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 2 237
    Points : 5 198
    Points
    5 198

    Par défaut

    Citation Envoyé par matafan Voir le message
    Le C définit des types de taille fixe intX_t et uintX_t, par exemple int8_t ou uint32_t.
    Dans mes souvenirs, ces types sont "des entiers sur au moins X bits", mais ma mémoire peut me jouer des tours.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • La plus sotte des questions est celle qu'on ne pose pas.

    Pour faire des graphes, essayez yEd.

  12. #12
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    octobre 2008
    Messages
    1 514
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : octobre 2008
    Messages : 1 514
    Points : 2 483
    Points
    2 483

    Par défaut

    Non ce sont bien des longueur exactes. Pour les tailles minimales il y a les [u]int_leastX_t et [u]int_fastX_t.

+ Répondre à la discussion
Cette discussion est résolue.

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •