Question

I have this code which should print the Destination and Source MAC address of each packet from a socket i am listening on:

sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
if(sock_raw < 0)
{
    printf("Socket Error\n");
    return 1;
}
while(1)
{
    saddr_size = sizeof saddr;
    //Receive a packet
    data_size = recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , (socklen_t*)&saddr_size);
    if(data_size <0 )
    {
        printf("Recvfrom error , failed to get packets\n");
        return 1;
    }
    //Now process the packet
    ProcessPacket(buffer , data_size);
}
close(sock_raw);

............

fprintf(logfile,"\n###########################################################");

struct ether_header *ethh;
ethh = (struct ether_header *)Buffer;

fprintf(logfile,"\n\n***********************ETHERNET Packet*************************\n");

fprintf(logfile,"\n");
fprintf(logfile,"Ethernet Header\n");
fprintf(logfile,"   |-Source Address      : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_dhost));
fprintf(logfile,"   |-Destination Address : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_shost));
fprintf(logfile,"\n");
fprintf(logfile,"\n###########################################################");

The problem is i expect to see the MAC of the PC i am listening on in the ether_dhost variable of my ether_addr struct when i run a ping or something. However the MAC that is printed from that variable is not mine. Further more the source MAC is not what i expect either.

Could someone please explain to me what is going on and possibly supply a fix to my code?

Thank you!

Was it helpful?

Solution

From the sock_raw man page, "Raw sockets allow new IPv4 protocols to be implemented in user space. A raw socket receives or sends the raw datagram not including link level headers.". So in your example, even though you are casting the buffer to an ethernet header structure, you are not actually getting ethernet headers.

To receive ethernet headers, you need to us an AF_PACKET socket. Here is a tweaked version of your code that should do what you want.

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <arpa/inet.h>

static FILE *logfile;

static void ProcessPacket(const void *Buffer, ssize_t data_size) {

    fprintf(logfile,"\n###########################################################");

    struct ether_header *ethh;
    ethh = (struct ether_header *)Buffer;

    fprintf(logfile,"\n\n***********************ETHERNET Packet*************************\n");

    fprintf(logfile,"\n");
    fprintf(logfile,"Ethernet Header\n");
    fprintf(logfile,"   |-Source Address      : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_dhost));;
    fprintf(logfile,"   |-Destination Address : %s\n", ether_ntoa((struct ether_addr *)&ethh->ether_shost));
    fprintf(logfile,"\n");
    fprintf(logfile,"\n###########################################################");
}

int main(int argc, char **argv) {
    logfile = stdout;

    int sock_raw = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    char buffer[65536];
    if(sock_raw < 0)
    {
        printf("Socket Error\n");
        return 1;
    }
    while(1)
    {
        //Receive a packet
        ssize_t data_size = recvfrom(sock_raw , buffer , sizeof(buffer) , 0 , NULL, NULL);
        if(data_size <0 )
        {
            printf("Recvfrom error , failed to get packets\n");
            break;
        }
        //Now process the packet
        ProcessPacket(buffer , data_size);
    }
    close(sock_raw);
    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top