C中的原始套接字数据包接收器,奇怪的输出

Raw socket packet receiver in C, strange output

我使用原始套接字编写了一个简单的数据包接收器,但我得到了奇怪的输出,f.e.:

Received packet: size: 124, type: PACKET_HOST (0)
Sender info: Name: n003-000-000-000.static.ge.com, IP: 3.0.0.0
Data:
74 2f 68 3c d1 9f 00 37 b7 d1 5a a7 08 00 45 00 00 6e 00 00 40
00 40 11 b6 e9 c0 a8 01 01 c0 a8 01 44 00 35 94 08 00 5a 3b aa 
e1 78 81 80 00 01 00 01 00 00 00 00 01 30 01 30 01 30 01 33 07
69 6e 2d 61 64 64 72 04 61 72 70 61 00 00 0c 00 01 c0 0c 00 0c
00 01 00 00 65 95 00 20 10 6e 30 30 33 2d 30 30 30 2d 30 30 30
2d 30 30 30 06 73 74 61 74 69 63 02 67 65 03 63 6f 6d 00

当我浏览互联网时,数据包变大了,但主机名和地址保持不变或几乎相同。

谁能帮我找出问题所在?

代码如下:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/if_ether.h>
#include <netdb.h>
#include <linux/if_packet.h>
#include <netinet/ether.h>

#define PACKET_SIZE 1 << 16

void usage();
void packetTypeToStr(int type, char *str);

int main(int argc, char **argv) {
    const char *iface_name;
    if (argc == 2) {
        iface_name = argv[1];
    } else if (argc > 2) {
        usage();
        return 1;
    } else {
        iface_name = "wlan0";
    }

    // Opening socket in raw mode
    int socketFileDesc = 0;
    if ((socketFileDesc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
        perror("socket");
        return errno;
    }
    printf("Opened raw socket\n");

    // Acquiring the index of the interface
    struct ifreq iface;
    memset(&iface, 0, sizeof(struct ifreq));
    strncpy(iface.ifr_name, iface_name, strlen(iface_name) + 1);
    if (ioctl(socketFileDesc, SIOCGIFINDEX, &iface) < 0) {
        perror("SIOCGIFINDEX");
        usage();
        close(socketFileDesc);
        return errno;
    }
    int index = iface.ifr_ifindex;
    printf("Index of the interface %s: %d\n", iface_name, index);

    // Acquiring the mac address of the interface
    struct ifreq iface_mac;
    memset(&iface_mac, 0, sizeof(struct ifreq));
    strncpy(iface_mac.ifr_name, iface_name, strlen(iface_name) + 1);
    if (ioctl(socketFileDesc, SIOCGIFHWADDR, &iface_mac) < 0) {
        perror("SIOCGIFHWADDR");
        usage();
        close(socketFileDesc);
        return errno;
    }
    printf("MAC address of the interface %s: %s\n", iface_name, ether_ntoa((struct ether_addr*)iface_mac.ifr_hwaddr.sa_data));


    // Setting interface in promiscuous mode
    struct ifreq iface_options;
    memset(&iface_options, 0, sizeof(struct ifreq));
    strncpy(iface_options.ifr_name, iface_name, strlen(iface_name) + 1);
    if (ioctl(socketFileDesc, SIOCGIFFLAGS, &iface_options) < 0) {
        perror("SIOCGIFFLAGS");
        close(socketFileDesc);
        return errno;
    }
    iface_options.ifr_flags |= IFF_PROMISC;
    if (ioctl(socketFileDesc, SIOCSIFFLAGS, &iface_options) < 0) {
        perror("SIOCGIFFLAGS");
        close(socketFileDesc);
        return errno;
    }
    printf("Interface %s set in promiscuous mode\n", iface_name);

    // Binding socket to the interface
    struct sockaddr_ll socketAddress;
    memset(&socketAddress, 0, sizeof(socketAddress));
    socketAddress.sll_family = AF_PACKET;
    socketAddress.sll_protocol = htons(ETH_P_ALL);
    socketAddress.sll_ifindex = index;
    if (bind(socketFileDesc, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0) {
        perror("bind");
        close(socketFileDesc);
        return errno;
    }
    printf("Socket bound to the interface: %s\nWaiting for packets...\n", iface_name);

    // Receiving packets in a loop
    while (1) {
        ssize_t n = 0;
        uint8_t packet[PACKET_SIZE];
        bzero(packet, sizeof(packet));
        struct sockaddr_in address;
        socklen_t length = sizeof(address);

        if ((n = recvfrom(socketFileDesc, packet, sizeof(packet), 0, (struct sockaddr *) &address, &length)) < 0) {
            perror("recvfrom");
            close(socketFileDesc);
            return errno;
        }
        // Null-terminated data
        if (n > 0)
            packet[n - 1] = '[=11=]';
        else
            continue;

        // IP address
        char ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(address.sin_addr), ip, length);

        // Host name
        struct hostent *host = gethostbyaddr(&(address.sin_addr), length, AF_INET);
        if (host == NULL) {
            herror("gethostbyaddr");
            return h_errno;
        }
        const char *hostName = host->h_name;

        // Packet type
        char packetType[BUFSIZ];
        int type = ((struct sockaddr_ll *) &address)->sll_pkttype;
        packetTypeToStr(type, packetType);

        // Printing info and data
        printf("\n\nReceived packet: size: %li, type: %s\n"
                       "Sender info: Name: %s, IP: %s\n",
               n, packetType, hostName, ip);
        printf("Data:\n");
        int i = 0;
        for (; i < n; ++i)
            printf("%02x ", packet[i]);
    }
    return 0;
}

由于您正在接收原始数据包 recvfrom() 不能 return IP 地址,因为数据通常可能不是互联网数据包。例如,它可能只是一个任意的以太网数据包,它是从一些根本没有 TCP/IP 堆栈的设备发送的。可能 recvfrom() 将传递的 sockaddr 指针视为 struct sockaddr_ll * 和 return 的物理层地址。

您可以尝试通过解析接收到的数据包来获取正确的IP地址。如果它真的是 IP 数据包 - 它将包含所有 headers,以及源地址和目标地址。