-1

ICMP要求を受信して​​表示できるCプログラムがありますが、Wiresharkを使用して見たものからICMP要求自体を送信しません。

必要なライブラリをインクルードし、IPヘッダーファイルと省略されたICMPヘッダーファイルを使用しています。

どんな助けでもいただければ幸いです。ランダムなPrintfステートメントは無視してください。

ありがとう

****

***IP.h*****

#ifndef __IP_H__
#define __IP_H__

struct iphdr {

   uint8_t   hdrlen:4;    
   uint8_t   version:4;
   uint8_t   ecn:2;       
   uint8_t   dscp:6;     
   uint16_t  length;
   uint16_t  ident;
   uint16_t  fragoff:13;
   uint16_t  flags:3;
   uint8_t   ttl;
   uint8_t   protocol;
   uint16_t  checksum;
   uint32_t  srcip;
   uint32_t  dstip;
   uint32_t  options[ ];  
} __attribute__((__packed__));

#endif // __IP_H__

****ICMP.H****

#ifndef __ICMP_H__
#define __ICMP_H__

struct icmphdr {
   uint8_t   type;         
   uint8_t   code;          
   uint16_t  checksum;      
   uint16_t  id;          
   uint16_t  seqNum;       
   uint32_t  data[ ];       
} __attribute__((__packed__));


char * messages[ ] = {
   "Echo reply",
   "Type 1",
   "Type 2",
   "Destination unreachable",
   "Source quench",
   "Redirect",
   "Type 6",
   "Type 7",
   "Echo request",
   "Router advertisement",
   "Router discovery",
   "Time exceeded",
   "Parameter problem",
   "Timestamp request",
   "Timestamp reply",
   "Information request (obsol.)",
   "Information reply (obsol.)",
   "Address mask request",
   "Address mask reply"
};

#endif // __ICMP_H__


****Main C File ****

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/time.h>

    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>

    #include "ip.h"
    #include "icmp.h"

    struct timeval timeout;
    struct timeval end;


    #define BUF_SIZE   1024
    #define ICMP       1
    #define ECHO_REQ   8
    #define ECHO_REPL  0
    #define HOSTADDR   "8.8.8.8"

    char *
    iptos (uint32_t ipaddr) {
       static char ips[16];

       sprintf(ips, "%d.%d.%d.%d",
          (ipaddr >> 24),
          (ipaddr >> 16) & 0xff,
          (ipaddr >>  8) & 0xff,
          (ipaddr      ) & 0xff );
       return ips;
    }

    uint16_t
    sum (uint16_t initial, void * buffer, int bytes) {
       uint32_t   total;
       uint16_t * ptr;
       int        words;

       total = initial;
       ptr   = (uint16_t *) buffer;
       words = (bytes + 1) / 2; // +1 & truncation on / handles any odd byte at end

       while (words--) total += *ptr++;
       while (total & 0xffff0000) total = (total >> 16) + (total & 0xffff);

       return (uint16_t) total;
    }




    void
    some_function ( ) {

       struct sockaddr_storage peer_addr;
       socklen_t               peer_addrlen;

       struct sockaddr_in      addr;
       struct sockaddr_in      dstaddr;
       struct iphdr   *        ip;
       struct icmphdr *        icmp;
       struct timeval *        sent;
       int skt;
       int sequence;
       long int length;
       fd_set rdfds;
       int ready;
       int rtt;

       char buff [BUF_SIZE];



       skt = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
       if (skt < 0) {
          perror ("socket()");
          exit (1);
       }

       addr.sin_family      = AF_INET;
       addr.sin_port        = 0;
       addr.sin_addr.s_addr = INADDR_ANY;

       if (bind (skt, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
          perror ("Can't bind socket");
          exit (1);
       }
    printf("aaa");
       ip = (struct iphdr *)buff;
       peer_addrlen = (socklen_t) sizeof (struct sockaddr_storage);

       memset (&dstaddr, 0, sizeof(struct sockaddr_in));
       dstaddr.sin_addr.s_addr = inet_addr(HOSTADDR);
       dstaddr.sin_family = AF_INET;

       memset (buff, 0, sizeof(buff));
       icmp = (struct icmphdr *) buff;
       icmp->type   = ECHO_REQ;
       icmp->id     = htons(getpid( ) & 0xffff);
       icmp->seqNum = htons(sequence++);

    printf("aabba");


       if (gettimeofday ((struct timeval *)icmp->data, NULL)) {
          perror ("Can't establish send time");
          exit (1);
       }

       length = sizeof(struct icmphdr) + sizeof(struct timeval);
       icmp->checksum = ~htons(sum (0, buff, length));


    printf("aaa");

       if (sendto (skt, buff, length, 0,
             (struct sockaddr *) &dstaddr, sizeof(struct sockaddr_in)) <= 0) {
          perror ("sendto()");
          exit (1);


    }
    printf("aaa");
     timeout.tv_sec  = 1;
       timeout.tv_usec = 0;
       FD_ZERO(&rdfds);
       FD_SET (skt, &rdfds);

       ready = select (skt + 1, &rdfds, NULL, NULL, &timeout);
       if (ready < 0) {
          perror ("Select()");
          exit (1);
       }

     memset (buff, 0, sizeof(buff));
       if (recvfrom (skt, buff, sizeof(buff), 0,
            (struct sockaddr *) &peer_addr, &peer_addrlen) <= 0) exit (1);

       if (gettimeofday (&end, NULL)) {   // Timestamp reception
          perror ("Can't establish time of receipt");
          exit (1);
       }

       if (ip->version != 4 ||
           sum (0, buff, sizeof(struct iphdr)) != 0xffff ||
           ip->protocol != ICMP)
          exit(1);

       length = ntohs(ip->length) - ip->hdrlen * 4;       // Length of IP payload
       icmp = (struct icmphdr *)((uint32_t *)ip + ip->hdrlen);   // Find ICMP hdr

       if (icmp->type != ECHO_REPL || sum (0, icmp, length) != 0xffff) {
          fprintf (stderr, "Received %s\n", messages[icmp->type]);
          exit (1);
       }


       sent = (struct timeval *)icmp->data;
       if ((rtt = (end.tv_usec - sent->tv_usec) / 100) < 0)
          rtt += 10000;  // We've cycled to a new second
       rtt += (end.tv_sec - sent->tv_sec) * 10000;  // Add any seconds

       printf ("%ld bytes from %s: icmp_req=%d ttl=%d time=%0.1f ms\n",
          length,
          iptos(ntohl(ip->srcip)),
          ntohs(icmp->seqNum),
          ip->ttl,
          ((float)rtt) / 10);

    }
    int main(){
    printf("aaa");
    some_function();
    return(0);

    }
4

1 に答える 1

2

問題はチェックサムが間違っていることです。

この行を変更します

icmp->checksum = htons(sum (0, buff, length));

icmp->checksum = ~(sum (0, buff, length));

合計関数はすでにバイト順序を考慮しているので、次のように再度変換する必要はありません。htons

于 2013-02-01T13:24:15.600 に答える