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 :

[Socket Linux] Fonction Ping en C


Sujet :

Réseau C

  1. #1
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut [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 : 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
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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

  2. #2
    Membre éprouvé Avatar de psyphi
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    119
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Allemagne

    Informations professionnelles :
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2006
    Messages : 119
    Par défaut
    C'est ce que tu envoies qui est mal formé ou bien ce que tu reçois?

  3. #3
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut
    Citation Envoyé par psyphi
    C'est ce que tu envoies qui est mal formé ou bien ce que tu reçois?
    A priori je pense que c'est ce que j'envois qui est mal formé. Car Ethreal me dit que le type de message ICMP est mauvais alors que je lui donne le correct pour le Echo Request.

  4. #4
    Membre éprouvé Avatar de psyphi
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    119
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Allemagne

    Informations professionnelles :
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2006
    Messages : 119
    Par défaut
    Avec ethereal tu peux voir qui est le destinaire et la source. Si ce que tu envoies est mal formé c'est normal que tu ne recoives rien.

  5. #5
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut
    Citation Envoyé par psyphi
    Avec ethereal tu peux voir qui est le destinaire et la source. Si ce que tu envoies est mal formé c'est normal que tu ne recoives rien.
    Mon destinataire et source sont tous les deux corrects et le CRC aussi (d'apres ethereal) donc j'en conclu que mon paquet IP est correctement construit. Seul le datagramme ICMP me parait mauvais.

  6. #6
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut
    D'aprés les resultats que me donne Ethreal, je pense que je transmet mal mon paquet ICMP et donc que le PC que je ping ne comprend pas la requete. Et donc il ne peux pas répondre à ce que je lui demande.

    Mais je ne vois pas l'erreur dans ma fonction...

  7. #7
    Membre éprouvé Avatar de psyphi
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    119
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : Allemagne

    Informations professionnelles :
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2006
    Messages : 119
    Par défaut
    Vérifie les calculs du checksum, fait les à la main et compare avec les retours de tes fonctions. Regarde peut être au niveau de tes structures ICMP et IP.

    Pour l'header IP, n'aurait tu pas oublié de spécifier le protocol?
    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
     
     struct iphdr // structure IP Header
     {
     //Pour processeur de type little-endian
     unsigned char ihl:4; // IP header length
     unsigned char version:4;
     
     unsigned char tos; // Type of service
     unsigned short tot_len; // Total length
     unsigned short id; // Identification
     unsigned short frag_off; // Fragment Offset + Flags
     unsigned char ttl; // Time to life
     unsigned char protocol;
     unsigned short check; // Checksum
     unsigned int saddr; // Source address
     unsigned int daddr; // Destination address
     };
    Pour ICMP il faut spécifier le champs protocol à 1.

    Sinon des liens que je pense que tu as déjà lu mais qui peuvent être utile:

    http://abcdrfc.free.fr/rfc-vf/rfc792.html
    http://fr.wikipedia.org/wiki/Interne...ssage_Protocol

  8. #8
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    22
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 22
    Par défaut
    Bon voilà tout marche impec
    En faite, le soucis c'est que la fonction sendto elle-même créée et completer un structure de type IP. Donc moi je refaisais deux fois la meme chose. Donc avec le sendto j'ai juste à envoyer ma requete ICMP avec le socket RAW et voilà

    Merci de votre aide
    Romain

  9. #9
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Avril 2011
    Messages : 12
    Par défaut
    Citation Envoyé par ozyamdias Voir le message
    Bon voilà tout marche impec
    En faite, le soucis c'est que la fonction sendto elle-même créée et completer un structure de type IP. Donc moi je refaisais deux fois la meme chose. Donc avec le sendto j'ai juste à envoyer ma requete ICMP avec le socket RAW et voilà

    Merci de votre aide
    Romain

    s'il vous plait pouvez vous m'envoyer le code de ping.
    et Merci d'avance.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Programmation de socket linux sous windows
    Par neuro6 dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 16/10/2007, 18h35
  2. Réponses: 4
    Dernier message: 23/05/2007, 09h12
  3. Réponses: 2
    Dernier message: 24/01/2007, 13h47
  4. Réponses: 11
    Dernier message: 03/05/2006, 01h24
  5. [Debutant] Problème Socket Linux UDP
    Par AxldenieD dans le forum Réseau
    Réponses: 3
    Dernier message: 01/11/2005, 17h08

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