3

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?

axon
  • 688
  • 1
  • 7
  • 18

2 Answers2

1

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.

Bernd Elkemann
  • 23,242
  • 4
  • 37
  • 66
  • I'm just capturing bog-standard Ethernet frames, and that's all this program will have to do. I realize I could cast it to struct, and for me that would be the "EASY" way out (I'm sure that's the smart way to do it in C as well). I'm following the instructions at http://www.tcpdump.org/pcap.html, which includes that cast. I wanted to basically do a 1:1 port of the Python code, as it means I have to do more work in C. I'm using this as a way to really ingrain pointers and pointer arithmetic into my head. This has been something I've never been able to wrap my head around in the past. – axon Feb 15 '12 at 22:09
  • 1
    Wow that's some hard-core way of practicing – Bernd Elkemann Feb 15 '12 at 22:19
  • Would doing it the cast-to-struct way be the accepted way of doing complex memory access? Not just in this case, but most cases? – axon Feb 16 '12 at 03:27
  • It depends on how regular the data is, if every entry is the same number of bytes, e.g. x bytes, then casting to a uint_x-pointer is obviously easier. Also, with structs you always have to be careful that the compiler does not add padding-bytes for alignment. – Bernd Elkemann Feb 16 '12 at 06:56
1

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

Vyktor
  • 20,559
  • 6
  • 64
  • 96