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)
