[Socket Linux] Fonction Ping en C
Bonjour à tous !
Voilà mon problème, dans une de mes applications j'ai besoin de savoir si un équipement en face est présent ou non sur le réseau.
Comme je ne peux pas utiliser l'appel systeme system(ping x.x.x.x) , j'ai refait la fonction ping en C (gestion de l'ICMP etc... etc...).
Voilà mon code (sous RTAI mais cela reste trés lisible) :
Code:
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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
int ping(char *AdresseAPinger)
{
char *Paquet; // Paquet que l'on enverra : le ping
char *Buffer; // Buffer de reception contenant la réponse
struct icmp *HeaderICMP; // Header contenant les paramètre IPs encapsulant l'header ICMP
struct ip *HeaderIP; // Header contenant les paramètres ICMP : ECHO_REQUEST etc...
struct sockaddr_in stMachineAPinger;
struct sockaddr_in stMachineQuiPing;
int Result = 0;
int Longueur = 0;
int Socket = 0;
int OptVal = 0;
// Allocation dynamique du paquet envoyé et du buffer de reception
Paquet = (char *)malloc(sizeof(struct icmp) + sizeof(struct ip));
Buffer = (char *)malloc(sizeof(struct icmp) + sizeof(struct ip));
// Association des headers dans le paquet que l'on enverra
HeaderIP = (struct ip *) Paquet;
HeaderICMP = (struct icmp *) (Paquet + sizeof(HeaderIP));
// Remplissage des structures qui gerent les machines : demandantes et répondantes
stMachineAPinger.sin_family = AF_INET;
stMachineAPinger.sin_addr.s_addr = inet_addr(AdresseAPinger);
stMachineQuiPing.sin_family = AF_INET;
stMachineQuiPing.sin_addr.s_addr = INADDR_ANY; // Adresse de la machine qui pingue
// Remplissage du header du protocole IP
rt_printk("Remplissage IP header...\n");
HeaderIP->ip_hl = 5; // Longueur de l'en-tête
HeaderIP->ip_v = 4; // IPv4
HeaderIP->ip_tos = 0; // Type de service
HeaderIP->ip_len = sizeof(HeaderIP) + sizeof(HeaderICMP);// Longueur total du paquet IP
HeaderIP->ip_id = htons(getuid()); // Identificateur
HeaderIP->ip_ttl = 255; // Temps de vie
HeaderIP->ip_src = stMachineQuiPing.sin_addr; // Adresse de la machine qui veut pinguer
HeaderIP->ip_dst = stMachineAPinger.sin_addr; // Adresse de la mahcine qui repondra... ou pas
// Ouverture du socket en mode RAW
rt_printk("Ouverture Socket...\n");
Socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(Socket == -1)
{
rt_printk("Ping : Erreur socket !!\n");
return -1;
}
// Changement des options du socket pour manipuler le datagramme IP
rt_printk("Changement options Socket...\n");
Result = setsockopt(Socket, IPPROTO_IP, IP_HDRINCL, &OptVal, sizeof(int));
if(Socket == -1)
{
rt_printk("Ping : Erreur setup socket !!\n");
return -1;
}
// Remplissage du header du protocole ICMP
rt_printk("Replissage ICMP header...\n");
HeaderICMP->icmp_type = ICMP_ECHO; // Type de message ICMP : Echo request
HeaderICMP->icmp_code = 0; // Code du message (0 pour nous)
HeaderICMP->icmp_cksum = 0;
// Calcul du checksum pour le datagramme ICMP
HeaderICMP->icmp_cksum = in_cksum((unsigned short *)HeaderICMP, sizeof(HeaderICMP));
// Calcul du checksum du datagramme IP précédent qui encapsule celui en ICMP
HeaderIP->ip_sum = in_cksum((unsigned short *)HeaderIP, sizeof(HeaderIP));
// Envois de la trame IP sur le reseau
rt_printk("Envois du ping...\n");
Result = sendto(Socket, Paquet, HeaderIP->ip_len, 0, (struct sockaddr*)&stMachineAPinger, sizeof(struct sockaddr));
if(Result != HeaderIP->ip_len)
{
rt_printk("Ping : Erreur envois -> longueur envoyee != longueur a envoyer");
return -1;
}
// Reception de la réponse... ou non
rt_printk("Reception du ping...");
Longueur = sizeof(struct sockaddr);
Result = recvfrom(Socket, Buffer, (sizeof(HeaderIP) + sizeof(HeaderICMP)), 0, (struct sockaddr*)&stMachineAPinger, &Longueur);
if(Result == HeaderIP->ip_len)
{
rt_printk("ok\n");
free(Paquet);
free(Buffer);
return 1; // Le ping c'est correctement passé, la machine distante à bien répondue
}
else
{
rt_printk("no\n");
free(Paquet);
free(Buffer);
return -1;
}
} |
Le soucis c'est que lorsque j'exécute mon programme, j'obtient ceci :
Code:
1 2 3 4 5 6 7 8
|
$ ./Ping
Remplissage IP header...
Ouverture Socket...
Changement options Socket...
Replissage ICMP hedaer...
Envois du ping...
Reception du ping... |
D'aprés ce résultat, on dirait que le blocage se fait au niveau du recvfrom.
Lorsque je scan ma connexion avec ethreal j'obtiens une entrée sur le protocole ICMP :
Code:
1 2 3 4 5 6
|
Internet Control Message Protocol :
Type : 69 (Obsolete or malformed)
Code : 0
CRC : Incorrect
... |
Auriez vous une idée d'où cela pourrait provenir ?
Merci de votre aide
Romain
edit : ortho