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.