tcpdump mailing list archives
Re: Obtaining MAC on OSX using AF_LINK
From: Guy Harris <guy () alum mit edu>
Date: Sun, 2 Jan 2011 14:33:35 -0800
On Dec 30, 2010, at 5:00 PM, Mathew Rowley wrote:
I am trying to understand how to get the MAC address when a pcap_addr family is of type AF_LINK.
...on OS X, which is relevant here. AF_LINK is a BSDism, and only OSes that inherit AF_LINK from whatever flavor of BSD introduced it support it - i.e., you can only do that on *BSD and OS X. Forget about it on other OSes.
It seems that the pacap_addr.sa_data should be of type (struct sockaddr_dl*)
Yes. A sockaddr_dl is defined in OS X 10.6 as struct sockaddr_dl { u_char sdl_len; /* Total length of sockaddr */ u_char sdl_family; /* AF_LINK */ u_short sdl_index; /* if != 0, system given index for interface */ u_char sdl_type; /* interface type */ u_char sdl_nlen; /* interface name length, no trailing 0 reqd. */ u_char sdl_alen; /* link level address length */ u_char sdl_slen; /* link layer selector length */ char sdl_data[12]; /* minimum work area, can be larger; contains both if name and ll address */ #ifndef __APPLE__ /* For TokenRing */ u_short sdl_rcf; /* source routing control */ u_short sdl_route[16]; /* source routing information */ #endif };
but then the sockaddr_dl sdl_alen is of variable size (I was expecting),
You were expecting a fixed-length structure? As the above indicates, there's no reason to expect it to be fixed-length; as it says, sdl_data "contains both if name and ll address", with no guarantee that the interface name is fixed-length. Furthermore, there is no guarantee that the link-layer address is a 6-octet MAC address - a PPP interface would not have any link-layer address, and a FireWire interface would have an 8-octet link-layer address, not a 6-octet one.
and LLADDR doesnt help much. Any insight? Here is the sample code and output: OUTPUT: link sdl_alen: 101 mac : 64:ffffffb9:ffffffe8:ffffffb7:ffffffb8:06
OK, that's 64:b9:e8:b7:b8:06. "char" in "char sdl_data[12]" really means "byte", and, for the link-layer address, "byte" generally means "unsigned byte", and "char" is not an unsigned byte on most platforms - it's a *signed* byte on most platforms (and you're not using a Gould/SEL minicomputer, so you're on a platform where it's signed; maybe there are others where char is signed, but no modern UN*X platform has char as an unsigned type). I would treat the bytes pointed to by LLADDR(link) as "unsigned char".
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
a->addr->sa_data will never be null - sa_data is an array member of "struct sockaddr", not a pointer, and the address of that array member can never be null.
// MAC ADDRESS //struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data; link = (struct sockaddr_dl*)a->addr->sa_data;
No, you want to do link = (struct sockaddr_dl *)(a->addr); a->addr points to a sockaddr structure of some sort. All sockaddr structures begin with the same fields, including the address family, with the same sizes; what follows it is address-family-dependent data. "struct sockaddr" is a template for all sockaddr structures; sa_family is the address family, and sa_data is the data. Other sockaddr structures overlay the *entire* structure; they also contain an address family field, followed by data.
char mac[link->sdl_alen]; memcpy(mac, LLADDR(link), link->sdl_alen); printf("link sdl_alen: %i\n", link->sdl_alen); printf("mac : %02x:%02x:%02x:%02x:%02x:%02x\n", mac[1], mac[2], mac[3], mac[4], mac[5], mac[6]);
That will print garbage for a PPP interface, as sdl_alen is 0 for PPP interfaces, and will print only the first 6 octets of the address for a FireWire interface. Also, C arrays are zero-index, so that will not print the first octet of the address - and will print garbage as the last octet, *even for an 802.x MAC address*. You want to do if (link->sdl_alen != 0) { unsigned char *octetp; unsigned int i; char sep; printf("mac: "); sep = '\0'; octetp = (unsigned char *)LLADDR(link); for (i = 0; i < link->sdl_alen; i++) { if (sep != '\0') putchar(sep); printf("%02x", octetp[i]); sep = ':'; } putchar('\n'); } so that: 1) you don't print anything if the address is zero-length; 2) you print the exact number of octets there are in the address, even if it's less than or greater than 6; 3) you print the first octet.- This is the tcpdump-workers list. Visit https://cod.sandelman.ca/ to unsubscribe.
Current thread:
- Re: Obtaining MAC on OSX using AF_LINK Guy Harris (Jan 02)
- Re: Obtaining MAC on OSX using AF_LINK Guy Harris (Jan 02)