Voici mon problème:
Je voudrais envoyer un paquet IP de type ICMP-EHO (un ping quoi) par le biais d'une socket raw qui me permettra de spécifier
l'en-tête IP à utiliser (Je ne voudrais pas que le protoole IP me génère une en-tête IP). Pour cela j'ai lu dans le man SOCK_RAW qu'il faut actier l'option IP_HDRINCL pour povoir soi-même spécifier son en-tête IP et que cette option est directementactivée lorsqu'on utilise le protocole IPPROTO_RAW dans la fontion soket (sous linux). Je crée donc ma socket
j'ai des structures IP_HDR et ICMP_HDR_ECHO déclarées ainsi
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 // Création de la soket sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if(sock == -1) { printf("Erreur de création de la socket\n%s\n", strerror(errno)); return -1; }
Ma méthode consiste don à créer un tampon d'envoi dont la taille est la somme de la taille de l'en-tête IP et ICMP, je rempli ce tampon, je l'envoi par sendto et j'attends la réponse du destinataire. voici mon ode
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
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 #ifndef __STRUCTURES_H__ #define __STRUCTURES_H__ typedef unsigned char u_char; typedef signed char s_char; typedef unsigned short u_short; typedef signed short s_short; typedef signed int s_int; typedef unsigned int u_int; typedef unsigned long u_long; // En-tête IP typedef struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) u_int ihl:4; // Longueur d'en-tête u_int version:4; // version #else u_char version:4; // version u_int ihl:4; // longueur d'en-tête #endif u_char tos:8; // Type de service u_short tot_len:16; // Longueur totale du datagramme u_short id:16; // Identificateur du datagramme u_short frag_off:16; // Offset du fragment u_char ttl:8; // Temps de vie u_char protocol:8; // Protocol Internet utilisé u_short check:16; // Champ de contrôle (checksum) u_int saddr:32; // Adresse source u_int daddr:32; // Adresse destination /*The options start here. */ } IP_HDR; // Structure de l'en-tête ICMP typedef struct icmphdr_echo { u_char type:8; // Type de message ICMP u_char code:8; // Code du message ICMP u_short checksum:16; // Checksum u_short id:16; // Identificateur u_short sequence:16; // Numéro de séquence u_long timestamp; } ICMP_HDR_ECHO; #endif
D'abord la fontion de remplissage de l'en-tête ICMP
Ensuite celle de remplissge du tampon de IP
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 void MakeICMPECHO(char* sendbuf, int paquetId){ ICMP_HDR_ECHO* icmp = (ICMP_HDR_ECHO*)sendbuf; // Remplissage icmphdr_echo memset(sendbuf, 0, sizeof(ICMP_HDR_ECHO)); icmp->type = 8; // Requête ICMP de type echo icmp->code = 0; icmp->checksum = 0; icmp->id = 0; icmp->sequence = 0; icmp->timestamp = 100000; // Mise en place des Checksum icmp->checksum = CheckSum((unsigned short *)sendbuf, sizeof(ICMP_HDR_ECHO)); }
enfin le programme principal
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 void MakeIPICMP(char* sendbuf, int paquetId, char* s, char* d){ IP_HDR* ip = (IP_HDR*)sendbuf; // Remplissage ip memset(sendbuf, 0, sizeof(IP_HDR)); ip->ihl = sizeof(IP_HDR); ip->version = 4; ip->tos = 0; ip->tot_len = sizeof(IP_HDR) + sizeof(ICMP_HDR_ECHO); ip->id = paquetId; ip->frag_off = (u_short)(ip + ip->ihl); ip->check = 0; ip->protocol = 1; ip->saddr = htonl(inet_addr(s)); ip->daddr = htonl(inet_ntoa(d)); // Mise en place des Checksum ip->check = CheckSum((unsigned short *)sendbuf, sizeof(IP_HDR)); }
j'apelle l'éxécutable avec
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
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 int main(int argc, char* argv[]){ // Déclaration des variables utiles int sock; // La raw socket int send, recieve; // statut d'envoi et de reception char sendbuficmp[sizeof(ICMP_HDR_ECHO)]; // Buffer icmp char sendbufip[sizeof(IP_HDR)]; // Buffer IP char sendbuf[sizeof(IP_HDR) + sizeof(ICMP_HDR_ECHO)]; char* ptr; // Utilisé pour la copie des en-tête dans le tampon d'enoi sendbuf char recvbuf[MAX_PACKET]; // Buffer de reception struct icmphdr_echo* icmp; // En-tête icmp de type echo struct iphdr* ip; // En-tête ip struct icmphdr_echo* ricmp; // En-tête icmp de retour struct iphdr* rip; // En-tête ip de retour char* csource = argv[1]; // @ source char* cdest = argv[2]; // @ destination du datagramme char* cproxy = argv[3]; // du proxy struct sockaddr_in dest, from; // Adresse du destinataire fd_set fdsr; // Ensemle surveillé struct timeval tv_timeout; // Délai de sureillance int surv, fromlen = sizeof(from); // Création de la soket sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if(sock == -1) { printf("Erreur de création de la socket\n%s\n", strerror(errno)); return -1; } // Préparation du paquet ICMP MakeICMPECHO(sendbuficmp, getpid()); MakeIPICMP(sendbufip, getpid(), csource, cdest); // Initialisation du tampon d'envoi à 0 memset(sendbuf, 0, sizeof(IP_HDR) + sizeof(ICMP_HDR_ECHO)); // ptr pointe sur sendbuf ptr = sendbuf; // Copie de l'en-tête IP dans ce tampon memcpy(ptr, sendbufip, sizeof(IP_HDR)); // On va en fin d'en-tête IP ptr += sizeof(IP_HDR); // Copie de l'en-tête ICMP la suite dans le tampon (en partie données du datagramme IP) memcpy(ptr, sendbuficmp, sizeof(ICMP_HDR_ECHO)); // Paramétrage de l'adresse d'envoi direct dest.sin_family = AF_INET; dest.sin_addr.s_addr = inet_addr(cproxy); // Envoi du message send = sendto(sock, sendbuf, sizeof(IP_HDR) + sizeof(ICMP_HDR_ECHO), 0, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); if(send == -1) { printf("Erreur d'envoi\n%s\n", strerror(errno)); return -1; } // Paramétrage de l'ensemble surveillé FD_ZERO(&fdsr); FD_SET(sock, &fdsr); tv_timeout.tv_sec = 5; tv_timeout.tv_usec = 0; // Appel de la fontion de surveillane surv = select(sock + 1, &fdsr, NULL, NULL, &tv_timeout); if(surv > 0 ){ if (FD_ISSET(sock, &fdsr)){ printf("Données en entrées sur la socket\n"); recieve = recvfrom(sock, recvbuf, MAX_PACKET, 0, (struct sockaddr *)&from, &fromlen); decode_recv(recvbuf); } } else{ printf("Aucune Données en entrées sur la socket\n"); } return 0; }
mais malheureusement le destinataire ne répond pas et je sais pas pourquoi. Je me demande si mes en-tête sont bonnes ou si je rempli correctement les en-têtes ou encore si le message arrive à bon port.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 ./sockraw2 @source @dest @passerelle
Partager