简体   繁体   English

数据链路套接字读取传出数据包?

[英]data link socket read outgoing packets?

I wrote a simple program using raw data link socket to read packets going through my local ethernet interface, say, eth0. 我使用原始数据链接套接字编写了一个简单程序,以读取通过本地以太网接口(例如eth0)的数据包。 Here is the loop structure of my program. 这是我程序的循环结构。 The complete source code is attached at the end of this post. 完整的源代码附在本文的结尾。 The program is based on C Language Examples of IPv4 and IPv6 Raw Sockets for Linux . 该程序基于Linux的C语言示例IPv4和IPv6原始套接字 I compiled the source code on CentOS 7. 我在CentOS 7上编译了源代码。

while(1)
{

    if ((bytes = recvfrom(recvsd, recv_ether_frame, IP_MAXPACKET, 0, (struct sockaddr *)&from, &fromlen)) < 0) {
        perror ("recvfrom() failed ");
    }

    if ( (0==memcmp(recv_ether_frame, dst_mac, 6)) && (0==memcmp(recv_ether_frame+6, src_mac, 6)))
    {
        printf("Outgoing >>>>>>>>>>>>>>>>>>>>\n");

        dumpMemory(recv_ether_frame, bytes, 16);
    }

    if ((0==memcmp(recv_ether_frame, src_mac, 6)) && (0==memcmp(recv_ether_frame+6, dst_mac, 6)) )
    {

        printf("Incoming >>>>>>>>>>>>>>>>>>>>\n");

        dumpMemory(recv_ether_frame, bytes, 16);
    }
}

In the above code, recvsd is a data link socket (PF_PACKET) created with socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL)) . 在上面的代码中, recvsd是使用socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))创建的数据链接套接字(PF_PACKET socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL)) I though the statement recvfrom(recvsd, recv_ether_frame, IP_MAXPACKET, 0, (struct sockaddr *)&from, &fromlen)) only reads the data incoming to my local machine, like a L3 socket (PF_NET) does. 尽管语句recvfrom(recvsd, recv_ether_frame, IP_MAXPACKET, 0, (struct sockaddr *)&from, &fromlen))只能读取传入本地计算机的数据,就像L3套接字(PF_NET)一样。 But to my surprise, it also reads data originating from my local machine and outgoing to other hosts. 但是令我惊讶的是,它还读取了来自本地计算机并传给其他主机的数据。 I though this is a behavior of promisc mode, but I got the same result after I make sure the interface eth0 is not in promisc mode. 尽管这是混杂模式的行为,但是在确保接口eth0不在混杂模式下后,我得到了相同的结果。

Is this a well-defined behavior of data link sockets? 这是数据链接套接字的明确定义的行为吗?

The complete source code: 完整的源代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <errno.h>




// Define some constants.
#define ETH_HDRLEN 14  // Ethernet header length
#define IP4_HDRLEN 20  // IPv4 header length
#define ICMP_HDRLEN 8  // ICMP header length for echo request, excludes data

using namespace std;


void dumpMemory(void* data, size_t len, int bytes_per_row)
{
    size_t i;
    for (i=0; i<len; i++) {
        printf("%02X ", ((unsigned char*)data)[i] );
        if (0==(i+1)%bytes_per_row) {
            printf("\n");
        }
    }
    printf("\n");
}


int
main (int argc, char **argv)
{
    int i, status, datalen, send_frame_length, tmpsd, recvsd, bytes, timeout, trycount, trylim, done;
    char *interface, *src_ip, *dst_ip, *rec_ip;
    struct iphdr *send_iphdr, *recv_iphdr;
    struct icmp send_icmphdr, *recv_icmphdr;
    unsigned char *src_mac, *dst_mac, *recv_ether_frame;
    struct sockaddr_ll device;
    struct ifreq ifr;
    struct sockaddr from;
    socklen_t fromlen;


    if (argc != 6) {
        printf("Example usage: ./a.out <dev_name>  <src_mac> <src_ip> <dst_mac> <dst_ip>\n");
        return -1;
    }

    // Allocate memory for various arrays.
    src_mac = (unsigned char*)malloc (6);
    dst_mac = (unsigned char*)malloc (6);
    recv_ether_frame = (unsigned char*)malloc (IP_MAXPACKET);
    interface = (char*)malloc (40);


    strcpy (interface, argv[1]);
    sscanf(argv[2], "%x:%x:%x:%x:%x:%x", &src_mac[0], &src_mac[1], &src_mac[2], &src_mac[3], &src_mac[4], &src_mac[5]);
    src_ip = argv[3];
    struct in_addr src_in_addr;
    if (inet_pton(PF_INET, src_ip, &src_in_addr) <=0 ) {
        perror("inet_pton failed ");
        exit (1);
    }

    sscanf(argv[4], "%x:%x:%x:%x:%x:%x", &dst_mac[0], &dst_mac[1], &dst_mac[2], &dst_mac[3], &dst_mac[4], &dst_mac[5]);
    struct in_addr dst_in_addr;
    dst_ip = argv[5];
    if (inet_pton(PF_INET, dst_ip, &dst_in_addr) <=0 ) {
        perror("inet_pton failed ");
        exit (1);
    }

    // Submit request for a socket descriptor to look up interface.
    // We'll use it to send packets as well, so we leave it open.
    if ((tmpsd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
        perror ("socket() failed to get socket descriptor for using ioctl() ");
        exit (EXIT_FAILURE);
    }

    // Use ioctl() to look up interface name and get its MAC address.
    // memset (&ifr, 0, sizeof (ifr));
    // snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
    // if (ioctl (tmpsd, SIOCGIFHWADDR, &ifr) < 0) {
    //   perror ("ioctl() failed to get source MAC address ");
    //   return (EXIT_FAILURE);
    // }

    // Copy source MAC address.
    //memcpy (src_mac, ifr.ifr_hwaddr.sa_data, 6);

    snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
    if ((ifr.ifr_ifindex = if_nametoindex (interface)) == 0) {
        perror ("if_nametoindex() failed to obtain interface index ");
        exit (EXIT_FAILURE);
    }

    /* Get the current flags that the device might have */
    if (ioctl (tmpsd, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror ("Error: Could not retrive the flags from the device.\n");
        exit (1);
    }

    /* Set the old flags plus the IFF_PROMISC flag */
//    ifr.ifr_flags |= IFF_PROMISC;
//    if (ioctl (tmpsd, SIOCSIFFLAGS, &ifr) == -1)
//    {
//        perror ("Error: Could not set flag IFF_PROMISC");
//        exit (1);
//    }
//    printf ("Entering promiscuous mode\n");
    close(tmpsd);

    if ((recvsd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
        perror ("socket() failed to obtain a receive socket descriptor ");
        exit (EXIT_FAILURE);
    }

    if (setsockopt (recvsd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) < 0) {
        printf("setsockopt(...SOL_SOCKET, SO_BINDTODEVICE,...) failed: %s\n", strerror(errno));
    }

    while(1)
    {
        memset (recv_ether_frame, 0, IP_MAXPACKET * sizeof (uint8_t));
        memset (&from, 0, sizeof (from));
        fromlen = sizeof (from);

        if ((bytes = recvfrom(recvsd, recv_ether_frame, IP_MAXPACKET, 0, (struct sockaddr *)&from, &fromlen)) < 0) {
            perror ("recvfrom() failed ");
        }

        if ( (0==memcmp(recv_ether_frame, dst_mac, 6)) && (0==memcmp(recv_ether_frame+6, src_mac, 6)))
        {
            printf("Outgoing >>>>>>>>>>>>>>>>>>>>\n");

            dumpMemory(recv_ether_frame, bytes, 16);
        }

        if ((0==memcmp(recv_ether_frame, src_mac, 6)) && (0==memcmp(recv_ether_frame+6, dst_mac, 6)) )
        {

            printf("Incoming >>>>>>>>>>>>>>>>>>>>\n");

            dumpMemory(recv_ether_frame, bytes, 16);
        }
    }

    // Close socket descriptors.
    close (recvsd);


    // Free allocated memory.
    free (src_mac);
    free (dst_mac);
    free (recv_ether_frame);
    free (interface);

    return (EXIT_SUCCESS);
}

A short answer is - yes. 一个简单的答案是-是的。 But why are you surprised? 但是你为什么感到惊讶?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM