2017-10-19 27 views
0

Je souhaite envoyer un message de requête ICMP avec des données à la fin. Je peux seulement envoyer une requête ICMP simple sans données pour le moment. Quand je veux ajouter des caractères à la fin de la structure icmp qui est dans le tampon, aucune demande ICMP n'est envoyée. Lorsque je supprime le caractère de fin ou change la taille de l'envoi de message dans la fonction sendto à sizeof (icmp), le message est envoyé normalement. Qu'est-ce qui ne va pas?Demande ICMP avec données

L'argument dans la fonction ping est correct.

void ping(struct sockaddr_in *addr) { 
    int sd; 
    const int val=255; 
    struct sockaddr_in r_addr; 
    sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); 
    if (sd < 0) { 
     perror("socket"); 
     return; 
    } 
    if (setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) 
     perror("Set TTL option"); 
    if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) 
     perror("Request nonblocking I/O"); 
    socklen_t len=sizeof(r_addr); 
    struct icmp *icmp_send, *icmp_recv; 
    icmp_send->icmp_type = ICMP_ECHO; 
    icmp_send->icmp_code = 0; 
    icmp_send->icmp_id = getpid(); 
    icmp_send->icmp_seq = 1; 
    icmp_send->icmp_cksum = 0; 
    icmp_send->icmp_cksum = checksum(icmp_send, sizeof(icmp_send)); 
    unsigned char buff[2000]; 
    unsigned char*p = buff; 
    memcpy(buff, icmp_send, sizeof(icmp)); 
    p += sizeof(icmp); 
    *p = 'A'; 
    if (sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1 , 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0) { 
       printf("Send err.\n"); 
    } 
} 
+3

C! = C++. Marquer uniquement avec la langue que vous utilisez, sauf si les deux sont réellement pertinents. – tambre

+2

Votre '* icmp_send' n'est pas initialisé. Et vous connaissez évidemment 'perror', pourquoi imprimez-vous" Send err. " au lieu? – rustyx

+0

Vous n'avez pas juste besoin de recalculer la somme de contrôle après avoir modifié le tampon et juste avant d'envoyer le paquet? Un bon exemple est donné ici: http://www.binarytides.com/icmp-ping-flood-code-sockets-c-linux/ –

Répondre

1

Vous devez recalculer la somme de contrôle dans l'en-tête ICMP avec les octets que vous ajoutez à l'en-tête.

La meilleure façon d'y parvenir est d'initialiser * icmp_send pour pointer vers la chaîne buff, puis de supprimer vos champs. Cela vous évitera memcpy de * icmp_send à buff. Voici un exemple.

unsigned char buff[2000]; 
unsigned char *p = buff; 
struct icmp *icmp_send; 

icmp_send = (struct icmp *)buff; 
icmp_send->icmp_type = ICMP_ECHO; 
icmp_send->icmp_code = 0; 
icmp_send->icmp_id = getpid(); 
icmp_send->icmp_cksum = 0; 
icmp_send->icmp_seq = htons(1); 
p += sizeof(icmp_send); 
*p = 'A'; 

icmp_send->icmp_cksum = checksum(buff, sizeof(icmp_send) + 1); 

if (sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1, 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0) { 
      printf("Send err.\n"); 
} 

Dans l'exemple ci-dessus, vous pouvez ajuster la taille de la charge utile pour le transport (sizeof(icmp_send) + 1) à toute valeur.

MISE À JOUR: Comme commenté par Matteo, jetant buff à un pointeur struct icmp pour accéder puis modifier les champs ICMP pourrait ne pas être sûr si votre plate-forme vous oblige à gérer l'accès aux champs dans des structures mal alignées correctement. Ecrire votre structure séparément, puis memcpy au buff avant de l'envoyer sur le réseau est la voie à suivre dans ce cas.

Retour à votre code, vous obtiendrez plus de détails dans l'exemple de code et compléter le code ci-après. L'idée ici est de calculer et de copier les valeurs entre pointeur car * icmp_send et buff ne sont pas liés.

Ce code envoie une requête d'écho ICMP avec des données, reçoit une réponse d'écho ICMP. Testé avec tcpdump pour valider que les paquets sont échangés entre les hôtes.

Code complet ci-dessous (OT: assurez-vous d'utiliser les fonctions de Hton lors de l'envoi des données sur le réseau, le cas échéant)

unsigned short checksum(void *b, int len) 
{ unsigned short *buf = b; 
    unsigned int sum=0; 
    unsigned short result; 

    for (sum = 0; len > 1; len -= 2) 
     sum += *buf++; 
    if (len == 1) 
     sum += *(unsigned char*)buf; 
    sum = (sum >> 16) + (sum & 0xFFFF); 
    sum += (sum >> 16); 
    result = ~sum; 
    return result; 
} 

void ping(struct sockaddr_in *addr) { 
    int sd; 
    const int val=255; 
    struct sockaddr_in r_addr; 
    sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); 
    if (sd < 0) { 
     perror("socket"); 
     return; 
    } 
    if (setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0) 
     perror("Set TTL option"); 
    if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) 
     perror("Request nonblocking I/O"); 
    socklen_t len=sizeof(r_addr); 
    struct icmp *icmp_send, *icmp_recv; 
    icmp_send->icmp_type = ICMP_ECHO; 
    icmp_send->icmp_code = 0; 
    icmp_send->icmp_id = getpid(); 
    icmp_send->icmp_seq = htons(1); 
    unsigned char buff[2000]; 
    unsigned char*p = buff; 
    p += sizeof(icmp_send); 
    *p = 'A'; 

    icmp_send->icmp_cksum = 0; 
    memcpy(buff, icmp_send, sizeof(icmp_send)) ; 

    icmp_send->icmp_cksum = checksum(buff, sizeof(icmp_send) + 1); 
    memcpy(buff, icmp_send, sizeof(icmp_send)) ; 

    if (sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1, 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0) { 
       printf("Send err.\n"); 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    if (argc != 2) { 
     printf("usage: %s destination_ip\n", argv[0]); 
     return 1; 
    } 

    struct sockaddr_in addr; 
    struct in_addr dst; 

    if (inet_aton(argv[1], &dst) == 0) { 

     perror("inet_aton"); 
     printf("%s isn't a valid IP address\n", argv[1]); 
     return 1; 
    } 


    memset(&addr, 0, sizeof addr); 
    addr.sin_family = AF_INET; 
    addr.sin_addr = dst; 

    ping(&addr); 
    return 0; 
} 

Hope this helps!

+1

"Le meilleur moyen d'y arriver est d'initialiser' * icmp_send' pour pointer vers le votre chaîne "buff", puis mangle vos champs là. " vous devez faire attention à ce genre de trucs si votre plate-forme n'est pas aussi indulgente que x86 à propos d'un accès mal aligné. Généralement, il est préférable de jouer en toute sécurité et «memcpy». –

+1

J'ai mis à jour ma réponse en fonction de votre remarque, merci Matteo. –

+0

Bonjour @stepanVich, pouvez-vous s'il vous plaît accepter la réponse? Ou si vous avez besoin de plus d'informations, s'il vous plaît laissez-moi savoir comment je peux vous aider. –