ICMP报文没有被发送Ç [英] ICMP packets are not being sent C

查看:243
本文介绍了ICMP报文没有被发送Ç的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建C中的ICMP Ping测试计划,但时遇到的成功发送数据包的困难。在 SENDTO 函数返回字节,一切的#但没有数据包实际发送。我已经使用Wireshark在目标计算机上验证了这一点。主机上的常平工作正常,虽然在Wireshark中显示出来。

I'm trying to create an ICMP ping test program in C but am having difficulties with successfully sending the packets. The sendto function returns the # of bytes and everything but no packets are actually sent. I've verified this with WireShark on the destination computer. A regular ping on the host works fine and shows up in WireShark though.

下面是我的code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>

unsigned short cksum(unsigned short *addr, int len);

int main(int argc, char *argv[])
{
    int sock;
    char send_buf[400], recv_buf[400], src_name[256], src_ip[15], dst_ip[15];
    struct ip *ip = (struct ip *)send_buf;
    struct icmp *icmp = (struct icmp *)(ip + 1);
    struct hostent *src_hp, *dst_hp;
    struct sockaddr_in src, dst;
    struct timeval t;
    int on;
    int num = 10;
    int failed_count = 0;
    int bytes_sent, bytes_recv;
    int dst_addr_len;
    int result;
    fd_set socks;

    /* Initialize variables */
    on = 1;
    memset(send_buf, 0, sizeof(send_buf));

    /* Check for valid args */
    if(argc < 2)
    {
        printf("\nUsage: %s <dst_server>\n", argv[0]);
        printf("- dst_server is the target\n");
        exit(EXIT_FAILURE);
    }

    /* Check for root access */
    if (getuid() != 0)
    {
        fprintf(stderr, "%s: This program requires root privileges!\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    /* Get source IP address */
    if(gethostname(src_name, sizeof(src_name)) < 0)
    {
        perror("gethostname() error");
        exit(EXIT_FAILURE);
    }
    else
    {
        if((src_hp = gethostbyname(src_name)) == NULL)
        {
            fprintf(stderr, "%s: Can't resolve, unknown source.\n", src_name);
            exit(EXIT_FAILURE);
        }
        else
            ip->ip_src = (*(struct in_addr *)src_hp->h_addr);
    }

    /* Get destination IP address */
    if((dst_hp = gethostbyname(argv[1])) == NULL)
    {
        if((ip->ip_dst.s_addr = inet_addr(argv[1])) == -1)
        {
            fprintf(stderr, "%s: Can't resolve, unknown destination.\n", argv[1]);
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        ip->ip_dst = (*(struct in_addr *)dst_hp->h_addr);
        dst.sin_addr = (*(struct in_addr *)dst_hp->h_addr);
    }

    sprintf(src_ip, "%s", inet_ntoa(ip->ip_src));
    sprintf(dst_ip, "%s", inet_ntoa(ip->ip_dst));
    printf("Source IP: '%s' -- Destination IP: '%s'\n", src_ip, dst_ip);

    /* Create RAW socket */
    if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
    {
        perror("socket() error");

        /* If something wrong, just exit */
        exit(EXIT_FAILURE);
    }

    /* Socket options, tell the kernel we provide the IP structure */
    if(setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)
    {
        perror("setsockopt() for IP_HDRINCL error");
        exit(EXIT_FAILURE);
    }

    /* IP structure, check the ip.h */
    ip->ip_v = 4;
    ip->ip_hl = 5;
    ip->ip_tos = 0;
    ip->ip_len = htons(sizeof(send_buf));
    ip->ip_id = htons(321);
    ip->ip_off = htons(0);
    ip->ip_ttl = 255;
    ip->ip_p = IPPROTO_ICMP;
    ip->ip_sum = 0;

    /* ICMP structure, check ip_icmp.h */
    icmp->icmp_type = ICMP_ECHO;
    icmp->icmp_code = 0;
    icmp->icmp_id = 123;
    icmp->icmp_seq = 0;

    /* Set up destination address family */
    dst.sin_family = AF_INET;

    /* Loop based on the packet number */
    for(int i = 1; i <= num; i++)
    {
        /* Header checksums */
        icmp->icmp_cksum = 0;
        ip->ip_sum = cksum((unsigned short *)send_buf, ip->ip_hl);
        icmp->icmp_cksum = cksum((unsigned short *)icmp, sizeof(send_buf) - sizeof(struct icmp));

        /* Get destination address length */
        dst_addr_len = sizeof(dst);

        /* Set listening timeout */
        t.tv_sec = 5;
        t.tv_usec = 0;

        /* Set socket listening descriptors */
        FD_ZERO(&socks);
        FD_SET(sock, &socks);

        /* Send packet */
        if((bytes_sent = sendto(sock, send_buf, sizeof(send_buf), 0, (struct sockaddr *)&dst, dst_addr_len)) < 0)
        {
            perror("sendto() error");
            failed_count++;
            printf("Failed to send packet.\n");
            fflush(stdout);
        }
        else
        {
            printf("Sent %d byte packet... ", bytes_sent);

            fflush(stdout);

            /* Listen for the response or timeout */
            if((result = select(sock + 1, &socks, NULL, NULL, &t)) < 0)
            {
                perror("select() error");
                failed_count++;
                printf("Error receiving packet!\n");
            }
            else if (result > 0)
            {
                printf("Waiting for packet... ");
                fflush(stdout);

                if((bytes_recv = recvfrom(sock, recv_buf, sizeof(ip) + sizeof(icmp) + sizeof(recv_buf), 0, (struct sockaddr *)&dst, (socklen_t *)&dst_addr_len)) < 0)
                {
                    perror("recvfrom() error");
                    failed_count++;
                    fflush(stdout);
                }
                else
                    printf("Received %d byte packet!\n", bytes_recv);
            }
            else
            {
                printf("Failed to receive packet!\n");
                failed_count++;
            }

            fflush(stdout);

            icmp->icmp_seq++;
        }
    }

    /* Display success rate */
    printf("Ping test completed with %d%% success rate.\n", (((num - failed_count) / num) * 100));

    /* close socket */
    close(sock);

    return 0;
}

/* One's Complement checksum algorithm */
unsigned short cksum(unsigned short *addr, int len)
{
    int nleft = len;
    int sum = 0;
    unsigned short *w = addr;
    unsigned short answer = 0;

    while (nleft > 1)
    {
      sum += *w++;
      nleft -= 2;
    }

    if (nleft == 1)
    {
      *(unsigned char *)(&answer) = *(unsigned char *)w;
      sum += answer;
    }

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

    return (answer);
}

在我做错了什么有什么想法?此外,在校验好吗?难道罚款只使用0为?

Any thoughts at what I'm doing wrong? Also, are the checksums alright? Is it fine to just use 0 for both?

编辑:确定,所以我已经成功地获取发送正确由于下面的乡亲包!和目标计算机会发回的回显应答。但是,现在,我的程序不拿起答复。在选择()函数总是超时。我已经更新了我上面的code。

OK, so I've managed to get the packets sent properly thanks to the folks below! And the destination computer will send back an echo reply. However, now, my program doesn't pick up the reply. The select() function always times out. I've updated my code above.

编辑2:好吧,我得到它的工作!我需要的套接字协议设置为 IPPROTO_ICMP 而不是 IPPROTO_RAW 和它的工作太棒了!再次感谢你们的评论!确实帮助了!貌似我只能标记一个答案正确的,但是你都在解决这个帮助。 :)

EDIT 2: Alright, I've got it working! I needed to set the socket protocol to IPPROTO_ICMP instead of IPPROTO_RAW and it worked great! Thanks again you guys that commented! Really helped out! Looks like I can only mark one answer correct, but you all aided in fixing this. :)

推荐答案

一件事,我已经注意到了...

Just one thing that I've noticed...

您已经有了这样的:

 struct ip *ip = (struct ip *)send_buf;

然后,你要分配目标字段:

Then, you are assigning destination field:

ip->ip_dst = (*(struct in_addr *)dst_hp->h_addr)

和则您与memset的擦除它(因为send_buff指向同一件事):<​​/ p>

And then you are erasing it with memset (since send_buff points to the same thing):

memset(send_buf, 0, sizeof(send_buf));

所以,当你试图让ip_dst这里:

So, when you are trying to get ip_dst here:

dst.sin_addr = ip->ip_dst;

你得到0,而不是你先前设置。

you are getting 0 instead of what you set earlier.

这篇关于ICMP报文没有被发送Ç的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆