Where one library fails, but another works.
06 06 07 - 19:50 Create a packet in libnet. Inject it at layer 2 with a custom source MAC address. Inspection in Wireshark reveals that the packet has YOUR source mac address on it. What?Copy/paste the packet bytes, mangle them into a hex string with a bunch of terminal commands, modify the MAC address and send it out with libdnet. It works. Great.
So what's different?
eth-bsd.c from libdnet line 62
[blockquote>
#ifdef BIOCSHDRCMPLT
i = 1;
if (ioctl(e->fd, BIOCSHDRCMPLT, &i) < 0)
return (eth_close(e));
#endif
[/blockquote>
Alright. I wonder what BIOCSHDRCMPLT is for...
And what does libnet do at the same point?
libnet_link_bpf.c from libnet line 166
[blockquote>
#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
if (ioctl(l->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1)
{
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSHDRCMPLT: %s\n",
__func__, strerror(errno));
goto bad;
}
#endif
[/blockquote>
Ohh... but why is it not doing it on OS X?
For those of you that just go "What the hell", I'll fill you in. It's calling an ioctl, which stands for io control. This is a way of telling a dev node (a 'file' in /dev) to do something different, essentially.
The dev nodes we are playing with are bpf nodes. BPF stands for Berkeley Packet Filter, and is essentially a way of allowing userspace stuff (stuff that runs outside the kernel i.e. your apps and OS processes) to mess with layer 2 (raw frame) packets.
The flag we are setting from the ioctl (or not, because this code is set not to be used on a Mac OS X machine) is BIOCSHDRCMPLT. It stands for something involving source header completion. When it's off, and it is normally, it writes your MAC address into the "source" header of every frame you send. Regardless of if it is really your MAC in there already. Great for 'normal' usage, but suppose you wanted to send it with another MAC in there? In this case, we turn this flag on, and it tells the kernel that we want it not to write our MAC address into the packet. As a result, the packet is sent with the MAC address we want, and we (or at least I) am happy...
So, what to do? Easy. Comment out the #if line and recompile. Or get rid of the "!(__Apple__)". Easy.
I suspect this was because Mac OS 10.3 (the previous version for you non-Mac users) had the BIOCSHDRCMPLT flag defined, but didn't use it. There was a patch that was later submitted and included in 10.4's version of the kernel. And I guess the libnet developers got busy, and didn't look when Tiger came out. Oh well.
Trackback link: http://gm.stackunderflow.com/blog/pivot/tb.php?tb_id=93