2017-07-28 202 views
1

我重用了這個site的原始套接字片斷,並刪除了TCP部分並添加了我的ICMP部分來請求回顯。我的兩臺機器都在同一個LAN上,運行Ubuntu 32位。 我給校驗功能我ICMP指針,但它無法計算正確的校驗:ICMP指針和校驗和

icmph->icmp_sum = csum((unsigned short *) datagram + sizeof(struct iphdr), sizeof(struct icmp_header)); 

然後我嘗試了一些原始數字作爲補償,直到它的工作:

icmph->icmp_sum = csum((unsigned short *) datagram + 10, sizeof(struct icmp_header)); 

我甚至查指針的位置和IP報頭,結構的大小:

Datagram-Pointer: 0xbff94680 
IP-Pointer: 0xbff94680 
ICMP-Pointer: 0xbff94694 

正如你可以看到,ICMP指針是20從Datagram-和IP-指針了。爲什麼要做10工作?

預先感謝您。

PS:這裏是代碼:

**/* 
    Raw TCP packets 
    Silver Moon ([email protected]) 
*/ 
#include<stdio.h> //for printf 
#include<string.h> //memset 
#include<sys/socket.h> //for socket ofcourse 
#include<stdlib.h> //for exit(0); 
#include<errno.h> //For errno - the error number 
#include<netinet/tcp.h> //Provides declarations for tcp header 
#include<netinet/ip.h> //Provides declarations for ip header 


//ICMP Header 
struct icmp_header 
{ 
    u_char icmp_type; 
    u_char icmp_code; 
    u_short icmp_sum; 
    u_short icmp_ident; 
    u_short icmp_seq; 
}; 

/* 
    Generic checksum calculation function 
*/ 
unsigned short csum(unsigned short *ptr,int nbytes) 
{ 
    register long sum; 
    unsigned short oddbyte; 
    register short answer; 

    sum=0; 
    while(nbytes>1) { 
     sum+=*ptr++; 
     nbytes-=2; 
    } 
    if(nbytes==1) { 
     oddbyte=0; 
     *((u_char*)&oddbyte)=*(u_char*)ptr; 
     sum+=oddbyte; 
    } 

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

    return(answer); 
} 

int main (void) 
{ 
    //Create a raw socket 
    int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); 

    if(s == -1) 
    { 
     //socket creation failed, may be because of non-root privileges 
     perror("Failed to create socket"); 
     exit(1); 
    } 

    //Datagram to represent the packet 
    char datagram[sizeof(struct iphdr) + sizeof(struct icmp_header)] , source_ip[32]; 

    //zero out the packet buffer 
    memset (datagram, 0, sizeof(struct iphdr) + sizeof(struct icmp_header)); 

    //IP header 
    struct iphdr *iph = (struct iphdr *) datagram; 

    //TCP header 
    struct icmp_header *icmph = (struct icmp_header *) (datagram + sizeof (struct iphdr)); 
    struct sockaddr_in sin; 


    //some address resolution 
    strcpy(source_ip , "10.0.2.5"); 
    sin.sin_family = AF_INET; 
    sin.sin_addr.s_addr = inet_addr ("10.0.2.4"); 

    //Fill in the IP Header 
    iph->ihl = 5; 
    iph->version = 4; 
    iph->tos = 0; 
    iph->tot_len = sizeof (struct iphdr) + sizeof (struct icmp_header); 
    iph->id = htonl (54321); //Id of this packet 
    iph->frag_off = 0; 
    iph->ttl = 255; 
    iph->protocol = 1; //Use ICMP afterwards 
    iph->check = 0;  //Set to 0 before calculating checksum 
    iph->saddr = inet_addr (source_ip); //Spoof the source ip address 
    iph->daddr = sin.sin_addr.s_addr; 

    //Ip checksum 
    iph->check = csum ((unsigned short *) datagram, iph->tot_len); 

    //Fill in the ICMP Header 
    icmph->icmp_type = 8; //Ping Request 
    icmph->icmp_code = 0; 
    icmph->icmp_sum = 0; //Set to 0 before calculating checksum 
    icmph->icmp_ident = 0x4142; //Just some Numbers 
    icmph->icmp_seq = 0x4142; //Just some Numbers 

    icmph->icmp_sum = csum((unsigned short *) datagram + 10, sizeof(struct icmp_header));//? Why 10 and not sizeof(struct iphdr)=20? 

    //For Debugging 
    printf("Datagram-Pointer: %p\n", (void*) datagram); 
    printf("IP-Pointer: %p\n", (void*) iph); 
    printf("ICMP-Pointer: %p\n\n", (void*) icmph); 
    printf("IP-Struct Size: %d\n", sizeof(struct iphdr)); 

    //IP_HDRINCL to tell the kernel that headers are included in the packet 
    int one = 1; 
    const int *val = &one; 
    if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) 
    { 
     perror("Error setting IP_HDRINCL"); 
     exit(0); 
    } 

    //Senden 
    if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) 
    { 
     perror("sendto failed"); 
    } 
    //Data send successfully 
    else 
    { 
     printf ("Packet Send. Length : %d \n" , iph->tot_len); 
    } 
    return 0; 
} 

//Complete** 

回答

2

sizeof讓你在字節,而不是一些亂 「字」 的大小。這意味着您在第一個選項中添加了一個20 16字節字的偏移量。

你應該的unsigned short大小劃分的sizeof結果:

icmph->icmp_sum = csum((unsigned short *) datagram + sizeof(struct iphdr)/sizeof(unsigned short), sizeof(struct icmp_header)); 
+1

或者,做'char'大小的單位加:'(無符號短*)((的char *)數據報+的sizeof (struct iphdr))'。 –

+0

謝謝@TobySpeight我喜歡這種方法。 – user3880174