2013-01-31 26 views
-1

我有一個C程序能夠接收ICMP請求並顯示它們,但是不會從我見過的Wireshark發出任何ICMP請求本身。需要幫助修復這個C Socket 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); 

    } 
+0

謝謝你的建議 –

+2

@ H2CO3再翻譯一下:代碼審查僅適用於工作代碼(根據常見問題解答)。 – palacsint

+0

@ H2CO3請不要閱讀常見問題,不要將用戶重定向到Codereview。 – Yuushi

回答

2

的問題是錯誤校驗和。

改變這一行

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

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

總和功能已經關心字節順序,無需與htons

+0

非常感謝,它現在似乎在工作! –

+0

你願意接受答案嗎? ^^ –

+0

哈哈,沒有注意到,我之前試圖把它投票,但它不會讓我。 –