2017-07-28 191 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