Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C pointers and memory (PCAP & Packet handling)

This is my first C app, so please excuse some ignorance. I'm working on porting a Python-based libpcap application over to C for speed reasons. I'm having issues understanding how to extract information from the packet. It comes to my handler function as a u_char, and you can munge it from there. In python, I would just slice the "string" and extract my information that way, but I don't know how to proceed.

For example, how to I extract the destination and source MAC addresses from an ethernet frame (bytes 0-6 and 7-11 respectively). Right now I have:

void handle_sniffed(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
    u_char *mac_dst = malloc(6*sizeof(u_char));
    u_char *mac_src = malloc(6*sizeof(u_char));
    memcpy(mac_dst, packet, 6);
    memcpy(mac_src, packet+6, 6);
}

Am I doing this correctly, and now how do I display the MAC address, for example using printf?

like image 559
axon Avatar asked Dec 31 '25 00:12

axon


2 Answers

I think you're doing it just fine, memcpy() attributes are just fine, malloc() is correct. You could use inline function like this to allocate memory safe/check allocation (you should check each allocation):

inline void* s_malloc(size_t size){
    void *ptr = malloc( size);
    if( !ptr){
         printf( "Allocation failed");
         exit(1);
    }
    return ptr;
}

You may also write macro for that but you won't be able to use it as function probably. If you guys have a better way of doing this I'll be glad to extend/edit.

Anyway, to answer your question. How to output MAC address. Here's a manual for prinf(), take a look at x resp. X format. It output's decimal number.

It works great until you want to print one character long number. So let's tell printf() to print number with precision 2 numbers .2. And we also need to tell it that it should be "left" pad instead of "decimal fraction digits on right side", that's - (check everything in manual). So complete string for printing one byte of MAC is: %-.2X. Complete example would be:

#include <stdio.h>

int main(){
    unsigned char data[6] = {0x00, 0xab, 0x03, 0xff, 0xba, 0x10};
    printf( "%-.2X:%-.2X:%-.2X:%-.2X:%-.2X:%-.2X\n", data[0], data[1], data[2],
           data[3], data[4], data[5]);

    return 0;
}

And the result:

[vyktor@grepfruit tmp]$ gcc -Wall src.cpp && ./a.out 
00:AB:03:FF:BA:10

To speed things up you may build function like this:

void print_mac( const unsigned char *data){
    printf( "%-.2X:%-.2X:%-.2X:%-.2X:%-.2X:%-.2X\n", data[0], data[1], data[2],
           data[3], data[4], data[5]);
}

// Usage example:
printf( "SrcMAC: ");
print_mac(packet+6);
printf( "DstMAC: ");
print_mac(packet);

There of course may be better way to do this. I tried to make this clear and educational, if you don't understand anything, please feel free to ask in the comment

like image 141
Vyktor Avatar answered Jan 02 '26 13:01

Vyktor


A packet sniffer as a first C-program? Impressive.

In C the proper way would be to create a struct which contains the layout of a single packet, you can then cast the packet-pointer you are given to that struct and de-reference e.g. the long long that holds the MAC-address.

Can you tell us where to find the specifications for the packets you are receiving, we can then help you create a matching struct.

like image 28
Bernd Elkemann Avatar answered Jan 02 '26 13:01

Bernd Elkemann