Search code examples
csocketsethernetwifi

Raw socket packet receiver in C, strange output


I wrote a simple packet receiver using raw sockets and I get strange outputs, 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

When I'm browsing the internet, the packets are bigger, but the host name and address stays the same or almost the same.

Could someone help me identify the problem?

Here's the code:

#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] = '\0';
        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;
}

Solution

  • Since you are receiving raw packet recvfrom() can not return IP address because data in general may not be an internet packet. For example it may be simply an arbitrary Ethernet packet, that was sent from some device that has no TCP/IP stack at all. Probably recvfrom() treats passed sockaddr pointer as struct sockaddr_ll * and returns physical layer address.

    You can try to obtain correct IP address via parsing of received packet. If it is really IP packet - it will contain all headers, with source and destination addresses.