Winsock raw socket ping icmp recv

Résolu
4aBestWord Messages postés 4 Date d'inscription mardi 2 janvier 2007 Statut Membre Dernière intervention 13 février 2007 - 25 janv. 2007 à 17:43
4aBestWord Messages postés 4 Date d'inscription mardi 2 janvier 2007 Statut Membre Dernière intervention 13 février 2007 - 13 févr. 2007 à 14:30
bonjour,
j'ai repris un code source en c pour faire un un ping icmp en utilisant les raw sockets sous windows (XP). L'envoie du ping fontionne bien par contre je n'arrive pas à obtenir le retour. Le problème vient surement de l'utilisation de la fonction recv mais je ne vois pas le pb. Si quelqu'un veut bien m'éclairer

le code source compte 2 parties prog.c et packets .h :

prog.c :
/*
/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
/-  Nom : prog.exe                                           -/
/-  Auteur : 4aBestWorld                                     -/
/-  Date : 25/01/2007                                        -/ 
/-  Description :  essai ping                                -/
/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
*/

/*
Les Includes standards
*/
#include <stdio.h>
#include <winsock2.h>
/*
Les Includes de ce programme
*/
#include "packets.h"

/*
directives du PreProcesseur
*/
#pragma comment(lib, "ws2_32.lib")

/*
fonction checksum
*/
unsigned short in_cksum(u_short * addr, int len)
{
    register int nleft = len;
    register u_short *w = addr;
    register int sum = 0;
    u_short answer = 0;

    while (nleft > 1) {
    sum += *w++;
    nleft -= 2;
    }

    if (nleft == 1) {
    *(u_char *) (&answer) = *(u_char *) w;
    sum += answer;
    }

    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;

    return (answer);
}

/*
Fonction Main
*/

int main(int argc, char *argv[])
{
    WORD wVersionRequested;
    WSADATA WSAData;
    unsigned short packet_size, ip_version, ip_len;    /* Taille de notre paquet, ip version, longueur */
    int retour;
    int socket;            /* Notre Socket */
    int optval = 1;        /* Pour les options */
    struct sockaddr_in sin;    /* Notre structure sockaddr_in */
    struct iphdr *ip;        /* Notre structure ip */
    struct icmphdr *icmp;    /* Notre structure icmp */    char *ptr NULL, packet[32];    /* Notre paquet, 32 sizeof(struct icmphdr) + sizeof(struct iphdr) */
    char buffer[2];
   
    if (argc < 3) {
    //fprintf(stderr, "Usage: %s <source host> <destination host>\n",argv[0]);
    printf("Usage: %s <source host> <destination host>\n",argv[0]);
    exit(-5);
    }

    /* On initialise Winsock 2 */
    wVersionRequested = MAKEWORD(2, 2);
    if (WSAStartup(wVersionRequested, &WSAData) != 0) {
    perror("WSAStartup");
    exit(-2);
    }

    /* Création de notre Raw socket */
    socket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_RAW, NULL, 0, 0);
    if (socket == INVALID_SOCKET) {
    perror("WSASocket");
    WSACleanup();
    exit(-3);
    }

    /* On assigne les bonnes options à notre Raw socket */
    if (setsockopt(socket, IPPROTO_IP, 2, (char *) &optval, sizeof(optval))
    == SOCKET_ERROR) {
    perror("setsockopt");
    WSACleanup();
    exit(-4);
    }

    /* On initialise toutes les données nécéssaires pour la structure IP */

    /* Taille de notre paquet */
    packet_size = sizeof(struct iphdr) + sizeof(struct icmphdr);

    /* On alloue un espace mémoire pour notre structure IP */
    ip = (struct iphdr *) malloc(sizeof(struct iphdr));
    memset(ip, 0x0, sizeof(struct iphdr));

    /* Longueur de l'en tête IP */
    ip_len = sizeof(struct iphdr) / sizeof(unsigned long);

    /* IP Version */
    ip_version = 4;

    /* On remplie la structure IP */
    ip->ip_verlen = (ip_version << 4) | ip_len;
    ip->ip_tos = 0;
    ip->ip_tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr));
    ip->ip_id = 1;
    ip->ip_offset = 0;
    ip->ip_ttl = 255;
    ip->ip_protocol = IPPROTO_ICMP;
    ip->ip_saddr = inet_addr(argv[1]);
    ip->ip_daddr = inet_addr(argv[2]);
    ip->ip_checksum = 0;
    ip->ip_checksum = in_cksum((unsigned short *) ip, sizeof(struct iphdr));    /* Calcul du checksum avec la fonction
                                           déja connu */
    /* Maintenant passons à la structure ICMP */
    /* On alloue de la mémoire pour celle ci */
    icmp = (struct icmphdr *) malloc(sizeof(struct icmphdr));
    memset(icmp, 0x0, sizeof(struct icmphdr));

    /* On la remplie */
    icmp->icmp_type = 8;        /* Type ICMP ECHO REQUEST */
    icmp->icmp_code = 0;
    icmp->icmp_id = (USHORT) GetCurrentProcessId();
    icmp->icmp_seq = (USHORT) GetCurrentProcessId();
    icmp->icmp_checksum = 0;
    icmp->icmp_checksum = in_cksum((unsigned short *) icmp, sizeof(struct icmphdr));

    /* Maintenant on créé notre paquet */
    ZeroMemory(packet, sizeof(packet));
    ptr = packet;
    memcpy(ptr, ip, sizeof(struct iphdr));
    ptr += sizeof(struct iphdr);
    memcpy(ptr, icmp, sizeof(struct icmphdr));
    ptr += sizeof(struct icmphdr);

    /* On rempli notre structure sockaddr_in */
    sin.sin_family = AF_INET;
    sin.sin_addr.S_un.S_addr = inet_addr(argv[2]);

       
    /* Envoye du paquet à destination */
    if (sendto
    (socket, packet, sizeof(packet), 0x0, (struct sockaddr *) &sin,
     sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
    perror("sendto");
    }
    /* reception du paquet retour */
    else {
         retour = recv(socket,buffer,sizeof(buffer),0);
         if ( retour == SOCKET_ERROR){
         printf("recv : %d",WSAGetLastError());             
         }//finduif
    }//finduelse
   
    system("PAUSE");
   
    free(ip);
    free(icmp);
    WSACleanup();
       
  return 0;
}

packets.h :
typedef struct iphdr
{
    unsigned char  ip_verlen;
    unsigned char  ip_tos;          
    unsigned short ip_tot_len;      
    unsigned short ip_id;           
    unsigned short ip_offset;       
    unsigned char  ip_ttl;          
    unsigned char  ip_protocol;     
    unsigned short ip_checksum;     
    unsigned int   ip_saddr;        
    unsigned int   ip_daddr;    
} IPHDR;

typedef struct icmphdr
{
 unsigned char icmp_type;
 unsigned char icmp_code;
 unsigned short icmp_checksum;
 unsigned short icmp_id;
 unsigned short icmp_seq;
 unsigned long  timestamp;
} ICMPHDR;
   
typedef struct opt_packet
{
      char *saddr;
      char *daddr;
      unsigned int icmp_type;
      unsigned int icmp_code;
      unsigned int ttl;
      int nbpackets;
      unsigned int interval;
} OPT_PACKET;

Merci pour votre temps.
A voir également:

3 réponses

4aBestWord Messages postés 4 Date d'inscription mardi 2 janvier 2007 Statut Membre Dernière intervention 13 février 2007
13 févr. 2007 à 14:30
J'ai trouve sur ce site un code source déposé par Roswell117 en 2003 qui correspond exactement à  ce que je veux.
A+
3
xbabilone Messages postés 47 Date d'inscription vendredi 18 février 2005 Statut Membre Dernière intervention 7 janvier 2018 2
26 janv. 2007 à 17:18
Je suis pas un pro mais t'as configurer ton firewall pour laisser passer les paquets.
Si tu essaye ton code entre deux machines test desactive le firewall sur les deux machines.Car souvent les firewalls sont configurer pour ne pas repondre au ping.
Et sinon good luck .
0
4aBestWord Messages postés 4 Date d'inscription mardi 2 janvier 2007 Statut Membre Dernière intervention 13 février 2007
27 janv. 2007 à 10:24
J'y ai pensé aussi au début mais j'ai lancé une capture avec WireShark (ancien ethereal). Et en fait je reçois bien le reply.
Je pense que le pb vient du buffer du retour de la fonction recv() ou bien faut-il faire une synchro entre le sendto et le recv. On m'a parlé de la fonction select().

Voila je cherche toujours donc si quelqu'un a une explication ou une piste, il/elle est le/la bienvenue.
0
Rejoignez-nous