IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Réseau C Discussion :

mapping de donnees "a plat" vers structure ipv6


Sujet :

Réseau C

  1. #1
    Membre éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    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 éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 expérimenté

    Homme Profil pro
    Collégien
    Inscrit en
    Juillet 2010
    Messages
    545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Afghanistan

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Juillet 2010
    Messages : 545
    Points : 1 429
    Points
    1 429
    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 émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    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 éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    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 émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 éclairé
    Profil pro
    Ingénieur sécurité
    Inscrit en
    Février 2007
    Messages
    574
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Etats-Unis

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

    Informations forums :
    Inscription : Février 2007
    Messages : 574
    Points : 751
    Points
    751
    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 émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    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
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    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

  11. #11
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    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.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  12. #12
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    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.

Discussions similaires

  1. transferer les donnees d'une BD paradox vers access
    Par denza1 dans le forum Bases de données
    Réponses: 5
    Dernier message: 31/10/2004, 14h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo