libpcap 从 AF_LINK sockaddr_dl 获取 MAC (OSX)
我正在尝试使用 C 获取 OSX 上所有接口的 MAC 地址。获取它的常见方法 Linux 不适用于 BSD - 从我所看到的一切来看,您必须获取接口并查找类型的接口AF_LINK。我的问题是 LLADDR(sockaddr_dl) 给了我一大堆数据(包括我的 MAC),但我不知道数据是什么格式。以下代码将输出:
设备:en1 链接 sdl_alen: 101 mac: 31:f8:1e:df:d6:22:1d:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 :b0:06:10:00:01:00:00:00:c0:02:10:00:01:00:00:00:00:00:00:00:00:00:00:00:40 :03:10:00:01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:03:00:6c:6f :30:00:00:00:00:00:00:00:00:00:00:00:00:00:70:03:10:00:01:00:00:00:e0: 02:10:00:01:00:00:
我的 MAC 是粗体的。似乎一直都是这种格式,但如果我可以将 LLADDR(sockaddr_dl) 转换为某种东西,我会更舒服。在 net/if_dl.h 中,LLADDR 被定义为:
#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
据我所知,这表明结果的类型为 (void *) - 没有帮助。
其他帖子如:
在弄清楚如何使用 ioctl/SIOCGIFADDR/SIOCGIFCONF 在 Mac OS X 上获取以太网接口信息时遇到问题?
似乎认为他们已经解决了,但是如果你查看代码,你可以看到由于 sdl_alen 不是 6,它将无法工作。
int main() {
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *addr_buf[40];
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("no devs found\n");
return(-1);
}
for (d = alldevs; d != NULL; d = d->next) {
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
printf("link sdl_alen: %i\n", link->sdl_alen);
int i;
printf("mac: ");
for(i = 0; i<link->sdl_alen; i++){
printf("%02x:", (unsigned char)mac[i]);
}
printf("\n");
}
}
}
}
I am trying to obtain the MAC addresses of all of my interface on OSX using C. The common ways to obtain it Linux dont work on BSD - from everything I have seen, you must obtain the interfaces and look for the ones that are of type AF_LINK. My problem is that the LLADDR(sockaddr_dl) gives me a whole bunch of data (which includes my MAC) and I dont know what format the data is in. For example; the following code will output:
Device: en1
link sdl_alen: 101 mac:
31:f8:1e:df:d6:22:1d:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:b0:06:10:00:01:00:00:00:c0:02:10:00:01:00:00:00:00:00:00:00:00:00:00:00:40
:03:10:00:01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:03:00:6c:6f:30:00:00:00:00:00:00:00:00:00:00:00:00:00:70:03:10:00:01:00:00:00:e0:
02:10:00:01:00:00:
My MAC is bolded. It seems that this is the format all of the time, but I would be a lot more comfortable if I could cast LLADDR(sockaddr_dl) to something. In the net/if_dl.h, LLADDR is defied as:
#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
which, as far as I can tell, is saying that the results are of type (void *) - no help.
Other posts like:
seem to think they have it figured out, but if you look through the code, you can see it will not work due to sdl_alen not being 6.
int main() {
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *addr_buf[40];
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("no devs found\n");
return(-1);
}
for (d = alldevs; d != NULL; d = d->next) {
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
printf("link sdl_alen: %i\n", link->sdl_alen);
int i;
printf("mac: ");
for(i = 0; i<link->sdl_alen; i++){
printf("%02x:", (unsigned char)mac[i]);
}
printf("\n");
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题是您将 sockaddr->sa_data 转换为 sockaddr_dl,而不是将 sockaddr 本身转换为 sockaddr_dl。请记住,sockaddr_dl 是 OS X/BSD 的东西,因此 #ifdef 这部分是为了可移植性。
不做:
做:
然后您将获得正确的 sdl_alen 并且无需任何修改即可正常工作。如果您想真正轻松地获取可能是 AF_INET、AF_INET6 或 AF_LINK 的地址名称,请使用 getnameinfo():
The problem is that you are casting the sockaddr->sa_data to sockaddr_dl instead of casting the sockaddr itself to sockaddr_dl. Keep in mind that sockaddr_dl is an OS X/BSD thing, so #ifdef that part for portability.
Don't do:
Do:
Then you will get the correct sdl_alen and things will work with out any hacks. And if you want to really easily get the name of addresses that may be either AF_INET, AF_INET6, or AF_LINK use getnameinfo():
这是我最终所做的:
Here is what I ended up doing:
我试图查看 pcap_findalldevs 报告的所有设备,最后在这里寻找有关在 MAC 操作系统上解释 AF_LINK 地址的信息。
我习惯于看到 struct sockaddr 代表接口系列并立即转换为适当的类型,而不是编写代码来访问 *sa_data*。
对于我想要的,使用 link_ntoa 将地址转换为人类可读的形式就足够了。
在我的机器上运行时,我得到以下带有 AF_LINK 条目的设备。
2011-08-14 02:22:43.024 HomePlugToolHelper[12473:903] ntoa en0:0.16.cb.xx.x.xx
2011-08-14 02:22:43.027 HomePlugToolHelper[12473:903] ntoa fw0:0.16.cb.xx.xx.xx.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa en1:0.16.cb.x.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa lo0
I was trying to see all devices reported by pcap_findalldevs and ended up here looking for information on interpreting AF_LINK addresses on MAC OS.
I'm used to seeing the struct sockaddr standing in for a interface family and being immediately cast to the appropriate type and not writing code to access *sa_data*.
For what I wanted it was sufficient to use link_ntoa to convert the address to a human readable form.
Running on my machine I get the following devices with AF_LINK entries.
2011-08-14 02:22:43.024 HomePlugToolHelper[12473:903] ntoa en0:0.16.cb.xx.x.xx
2011-08-14 02:22:43.027 HomePlugToolHelper[12473:903] ntoa fw0:0.16.cb.xx.xx.xx.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa en1:0.16.cb.x.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa lo0