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

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; }
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
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
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

D'abord la fontion de remplissage de l'en-tête ICMP
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));
}
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
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));
}
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
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;
}
j'apelle l'éxécutable avec

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
 
./sockraw2 @source @dest @passerelle
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.