c - ICMP 指针和校验和

标签 c pointers ping icmp raw-sockets

我重用了这个 site 中的原始套接字片段并删除了 TCP 部分并添加了我的 ICMP 部分以请求回显。我的两台机器都在同一个局域网上,运行 Ubuntu 32 位。 我给了校验和函数我的 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 header 结构的大小:

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

如您所见,ICMP 指针距离数据报和 IP 指针 20。为什么 10 人会完成这项工作?

提前谢谢你。

PS:代码如下:

**/*
    Raw TCP packets
    Silver Moon (m00n.silv3r@gmail.com)
*/
#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**

最佳答案

sizeof字节 为您提供大小,而不是一些任意的“单词”。这意味着您在第一个备选方案中添加了 20 16 字节字的偏移量。

您应该将 sizeof 的结果除以 unsigned short 的大小:

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

关于c - ICMP 指针和校验和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45376144/

相关文章:

windows - 在 Python 中获取网络位置的 DFS 路径

c - 释放内存时堆损坏 C

c - Linux进程堆栈被局部变量溢出(堆栈保护)

c - 地址上的二维 float 组

C++:取消引用指针

windows - 从 ping 获取主机名并将结果存储到文本

Bash:将 ping 对 SIGQUIT 的中间统计信息捕获到变量

c - 以十六进制打印负数是否有隐含的字长?

c - 我需要在 LLVM 中实现什么才能使 Clang 为自定义架构生成 IR?

c++ - 动态分配一个全局数组,该数组位于动态分配的结构数组中