Question

I have been working on a packet sniffer just for fun/education and it's been going quite well. The problem that I'm having is that the only packets appearing in recvfrom() are SENT packets i.e. packets with my IP as their source IP and not my WAN IP but my LAN IP (if that makes sense). I tried fixing it and spent hours reading everything I could find but to me there seems no solution. I am 100% positive that the code I've written does not detect all packets because wireshark detects way more (ingoing and outgoing) and it's obvious that there is not only outgoing traffic from my PC.

packetsize = recvfrom(sniffer , Buffer , 65536 , 0 , (SOCKADDR *)&SenderAddr , &SenderAddrSize); 
for (int x = 12; x < 16; x++) 
{
    printf("%c ",Buffer[x]); 
}
std::cout << "\n";

iphdr = (IPV4_HDR *)Buffer;

memset(&source, 0, sizeof(source));
source.sin_addr.s_addr = iphdr->ip_srcaddr;
std::cout << inet_ntoa(source.sin_addr) << "\n\n";

That's the point where it all goes down (there is way more code but not important), the structures are all properly defined so there is no errors there (else I couldn't be getting the same IP adress over and over in every single packet). Also there is another, non-existent IP from my network showing up as source IP and very occasionally the source IP is 0.0.0.0 which I both find very weird.

Buffer is declared as

char *Buffer = (char *)malloc(65536);

so it's signed char and I have no idea how I could manually "extract" the separate parts of the header from these values.

I hope anyone can explain to me that recvfrom is actually not losing packets and that I'm doing something wrong. Also I'd like to know how to interpret the output from recvfrom, i.e. converting signed to unsigned or maybe some other way?

I hope I made my problem clear, thanks in advance.

EDIT. Bigger chunk of my code

int main()
{
    SOCKET sniffer;
    struct in_addr addr;
    int in;

    char hostname[100];
    struct hostent *local;
    WSADATA wsa;


    // Initialise Winsock

    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2), &wsa) != 0)
    {
        printf("WSAStartup() failed.\n");
        getchar();
        return 1;
    }
    printf("Initialised");

    // Create a RAW Socket
    printf("\nCreating RAW Socket....");
    sniffer = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
    if (sniffer == INVALID_SOCKET)
    {
        printf("Failed to create raw socket.\n");
        printf("WSA throws error code %d\n",WSAGetLastError());
        printf("Run as admin to fix\n");
        getchar();
        return 1;
    }
    printf("Created.");

    // Retrieve the local hostname
    if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR)
    {
        printf("WSA throws error code %d\n",WSAGetLastError());
        getchar();
        return 1;
    }
    printf("\nHost name : %s \n",hostname);

    bool retry = true;
    signed int maxnumber = -1;

    do
    {
        // Retrieve the available IPs of the local host
        local = gethostbyname(hostname);
        printf("\nAvailable Network Interfaces  \n");
        if (local == NULL)
        {
            printf("WSA throws error code %d.\n",WSAGetLastError());
            getchar();
            return 1;
        }

        // Available interfaces
        for (i = 0; local->h_addr_list[i] != 0; i++) // h_addr_list is null terminated
        {
            // local is hostent struct in which information about the host is stored
            // in_addr represents an IPv4 internet address. inet_ntoa: in_addr to string (ip adress)
            memmove(&addr, local->h_addr_list[i], sizeof(struct in_addr));
            //memmove(destination, source, number of bytes to copy)
            printf("Interface Number : %d Address : %s\n", i, inet_ntoa(addr));
            maxnumber = i;
            printf("\n");
        }

        // Choose interface
        if (maxnumber > 0)
        {
            printf("Enter the interface number you would like to sniff : ");
            scanf("%d",&in);
            printf(" in: %d | maxnumber: %d \n", in, maxnumber);
            if (in <= maxnumber)
            {
                retry = false;
            } else {
                printf("Interface number %d with adress %d does not exist \n\n", in, local->h_addr_list[in]);
            }
        }
        else
        {
            printf("Only one interface available");
            in = 0;
            retry = false;
        }
    } while (retry);

    self = addr;
    CreateFolder(self);

    memset(&dest, 0, sizeof(dest));
    memcpy(&dest.sin_addr.s_addr,local->h_addr_list[in],sizeof(dest.sin_addr.s_addr));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(source.sin_port);//=0;

    printf("\nBinding socket to local system and port 0 ...");
    if (bind(sniffer,(struct sockaddr *)&dest,sizeof(dest)) == SOCKET_ERROR)
    {
        printf("bind(%s) failed.\n", inet_ntoa(addr));
        getchar();
        return 1;
    }
    printf("Binding successful");

    j=1;
    unsigned long nbytesret;
    printf("\nSetting socket to sniff...");
    if (WSAIoctl(sniffer, SIO_RCVALL, &j, sizeof(j), 0, 0, &nbytesret , 0 , 0) == SOCKET_ERROR)
    {
        printf("WSAIoctl() failed.\n");
        getchar();
        return 1;
    }
    printf("Socket set\n");
    printf("Press enter to start\n");
    getchar();

    printf("Packet Capture Statistics...\n");
    StartSniffing(sniffer); 

    printf("Ending sniffer, press enter to exit \n");
    getchar();
    closesocket(sniffer);
    WSACleanup();

    return 0;
}

void StartSniffing(SOCKET sniffer)
{
    char *Buffer = (char *)malloc(65536);
    int packetsize;

    if (Buffer == NULL)
    {
        printf("malloc() failed.\n");
    getchar();
    return;
    }

    do
    {
        packetsize = recvfrom(sniffer , Buffer , 65536 , 0 , (SOCKADDR *)&SenderAddr , &SenderAddrSize); 

        if(packetsize > 0)
        {
            ProcessPacket(Buffer, packetsize);
        }
        else
        {
            printf( "recvfrom() failed.\n");
            getchar();
        }

    }
    while (packetsize > 0);

    free(Buffer);
}
Was it helpful?

Solution

To read from the buffer as unsigned, use reinterpret_cast like so to get an unsigned pointer:

unsigned char *uBuffer = reinterpret_cast<unsigned char *>(Buffer);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top