Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用原始套接字ping localhost?_C_Linux_Sockets_Raw Sockets_Loopback - Fatal编程技术网

如何使用原始套接字ping localhost?

如何使用原始套接字ping localhost?,c,linux,sockets,raw-sockets,loopback,C,Linux,Sockets,Raw Sockets,Loopback,该程序从某个源获得杂项以太网通信,更改ip,并将其重定向到本地主机(例如,它应用于ssh连接),然后从本地主机发回应答。我使用了以下代码: int bind_if(int raw , char *device , int protocol) { struct sockaddr_ll sll; struct ifreq ifr; bzero(&sll , sizeof(sll)); bzero(&ifr , sizeof(i

该程序从某个源获得杂项以太网通信,更改ip,并将其重定向到本地主机(例如,它应用于ssh连接),然后从本地主机发回应答。我使用了以下代码:

    int bind_if(int raw , char *device , int protocol) { 
        struct sockaddr_ll sll;
        struct ifreq ifr; bzero(&sll , sizeof(sll));
        bzero(&ifr , sizeof(ifr)); 
        strncpy((char *)ifr.ifr_name ,device , IFNAMSIZ); 
        //copy device name to ifr 
        if((ioctl(raw , SIOCGIFINDEX , &ifr)) == -1)
        { 
            perror("Unable to find interface index");
            return -1; 
        }
        sll.sll_family = AF_PACKET; 
        sll.sll_ifindex = ifr.ifr_ifindex; 
        sll.sll_protocol = htons(protocol); 
        if((bind(raw , (struct sockaddr *)&sll , sizeof(sll))) ==-1)
        {
            perror("bind: ");
            return -1;
        }
        return 0;
    } 

    int _create_input_socket(int *s, char* interface)
    {
        struct packet_mreq mreq;
        struct ifreq if_idx;
        int sockopt;
        int ifnumber = 0;
        if ((*s = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
        {
                perror("cannot create socket");
                return -1;
        }
        memset(&if_idx, 0, sizeof(struct ifreq));
        strncpy(if_idx.ifr_name, interface, IFNAMSIZ-1);
        if (ioctl(*s, SIOCGIFINDEX, &if_idx) < 0)
        {
            perror("SIOCGIFINDEX for interface failed");
                close(*s);
            return -1;
        }
        ifnumber = if_idx.ifr_ifindex;

            /* Get the current flags that the device might have */
            if (ioctl(*s, SIOCGIFFLAGS, &if_idx) <0)
        {
            perror("SIOCGIFFLAGS failed");
                close(*s);
            return -1;
        }
        /* Set the old flags plus the IFF_PROMISC flag */
        if_idx.ifr_flags |= IFF_PROMISC;
        if (ioctl(*s, SIOCSIFFLAGS, &if_idx) == -1)
        {
            perror("SIOCSIFFLAGS while adding IFF_PROMISC failed");
                close(*s);
        }
        int flags = fcntl(*s, F_GETFL, 0);
        int ret = fcntl(*s, F_SETFL, flags | O_NONBLOCK);
        printf("ret = %d\n", ret);
        if(ret < 0)
        {
            perror("fcntl for O_NONBLOCK failed");
                close(*s);
                return -1;
        }

        if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) == -1) {
            perror("setsockopt SO_REUSEADDR failed");
            close(*s);
                    return -1;
        }
        if( bind_if(*s, interface, ETH_P_ALL) == -1 )
        {
            close(*s);
            return -1;
        }
        if (setsockopt(*s, SOL_SOCKET, SO_BINDTODEVICE, interface, IFNAMSIZ-1) == -1)   {
            perror("SO_BINDTODEVICE");
            close(*s);
            return -1;
        }

        memset(&mreq,0,sizeof(mreq));
        mreq.mr_ifindex = ifnumber;
        mreq.mr_type = PACKET_MR_PROMISC;
        mreq.mr_alen = 6;

        if (setsockopt(*s,SOL_PACKET,PACKET_ADD_MEMBERSHIP,
             (void*)&mreq,(socklen_t)sizeof(mreq)) < 0)
               perror("setsockopt(PACKET_ADD_MEMBERSHIP)");
        printf("create socket %d for iface %s(%d)\n", *s, interface, ifnumber);
        return ifnumber;
    }

    void SendTo(int sock, int ifindex, const unsigned char*buffer, int buffer_size)
    {
        struct sockaddr_ll socket_address;
        memset(&socket_address, 0, sizeof(socket_address));
        socket_address.sll_ifindex = ifindex;
        socket_address.sll_halen = ETH_ALEN;
        socket_address.sll_family = htons(PF_PACKET);
        socket_address.sll_protocol = htons(ETH_P_ALL);
        socket_address.sll_hatype = ARPHRD_ETHER;
        memcpy(socket_address.sll_addr, buffer, 6);
        if (sendto(sock, buffer, buffer_size, 0, (struct         sockaddr*)&socket_address, sizeof(socket_address)) < 0)
            printf("Send failed due error %d\n", errno);
    }
当我通过程序发送ping时,我在环回接口上使用tcpdump检查它的工作方式:

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 65535 bytes
00:10:24.269431 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 29046, seq 1, length 64
00:10:25.269125 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 29046, seq 2, length 64
当我从linux命令执行真正的ping时:

00:43:49.228192 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 1, length 64
00:43:49.228219 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 1, length 64
00:43:50.227183 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 2, length 64
00:43:50.227203 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 2, length 64

我检查了数据包-除了icmp序列号,它看起来是一样的。所有其他流量的情况也是如此:系统不回复我的程序生成的流量,而是回复其他来源生成的流量。我对环回接口上sendto的这种行为感到困惑。有人知道如何避免这种情况吗?

试着检查完整的数据包,包括以太网报头(-e到tcpdump),并确保它们是正确的

我认为
struct sockaddr\u ll.sll\u protocol
设置为ETH\u p\u ALL in
SendTo()
可能会弄乱您的数据包。使用错误的协议可以解释为什么没有将它们交付给相应的协议处理程序

尝试从
SendTo()
中删除除
struct sockaddr\u ll.sll\u系列和
struct sockaddr\u ll.sll\u iIndex
之外的所有内容。如果不起作用,请手动将.sll_协议设置为要发送的类型。手册页可以解释为当套接字为SOCK_RAW时,sll_协议没有影响,但我认为可能会

男7包:

发送数据包时,指定sll_族就足够了, sll_地址、sll_halen、sll_iIndex。其他字段应为0。 sll_hatype和sll_pkttype是为您的用户在收到的数据包上设置的 信息。对于bind,仅支持sll\U协议和sll\U ifindex 用过


您可以发布您正在使用的所有代码,但它已经相当长了。最好是编写一个很短的程序,该程序表现出相同的症状并发布。

我认为,使用原始套接字需要root权限。请尝试运行您的程序。谢谢您的回答,但我在目标计算机上使用了archlinux的根帐户,在这种情况下,权限应该不会有任何问题。如果我理解您的意思是正确的,您可以在数据包头中更改IP。如果是这样,您需要重新计算新数据包的校验和。若数据包的校验和不正确,目标机器可以直接丢弃它。谢谢你们的回答,但我知道。我重新计算校验和,它在tcpdump中显示为正确。此外,根据tcpdump,所有以太网和ip级别的报头(包括校验和)对于my和标准ping数据包都是相同的。所以我认为问题是关于sendto(),而不是外部流量内容。你知道问题出在哪里吗?
00:43:49.228192 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 1, length 64
00:43:49.228219 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 1, length 64
00:43:50.227183 IP localhost.localdomain > localhost.localdomain: ICMP echo request, id 535, seq 2, length 64
00:43:50.227203 IP localhost.localdomain > localhost.localdomain: ICMP echo reply, id 535, seq 2, length 64