libpcap получает MAC из AF_LINK sockaddr_dl (OSX) - PullRequest
3 голосов
/ 31 декабря 2010

Я пытаюсь получить MAC-адреса всех моих интерфейсов на OSX с использованием C. Обычные способы получить его Linux не работает на BSD - из всего, что я видел, вы должны получить интерфейсы и искать те, которые имеют тип AF_LINK. Моя проблема в том, что LLADDR (sockaddr_dl) дает мне целую кучу данных (включая мой MAC), и я не знаю, в каком формате эти данные. Например; следующий код выведет:

Устройство: en1 ссылка sdl_alen: 101 mac: 31: f8: 1e: ДФ: d 6: 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 *) - не поможет.

Другие сообщения, такие как:

Не можете понять, как получить информацию об интерфейсе Ethernet в Mac OS X с помощью ioctl / SIOCGIFADDR / SIOCGIFCONF?

, кажется, думают, что они это выяснили, но если вы посмотрите код, вы увидите, что он не будет работать из-за того, что 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");
            }
        }
    }
}

Ответы [ 3 ]

4 голосов
/ 13 декабря 2011

Проблема в том, что вы приводите sockaddr-> sa_data к sockaddr_dl вместо того, чтобы самому приводить sockaddr к sockaddr_dl.Помните, что sockaddr_dl - это OS X / BSD, так что #ifdef это часть для переносимости.

Не делайте:

link = (struct sockaddr_dl*)a->addr->sa_data;

Do:

link = (struct sockaddr_dl*)a->addr;

Тогда вы получите правильный sdl_alen, и все будет работать без каких-либо взломов.И если вы хотите действительно легко получить имена адресов, которые могут быть AF_INET, AF_INET6 или AF_LINK, используйте getnameinfo ():

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <net/if_dl.h>

int get_sock_len(struct sockaddr *sa)
{
    switch (sa->sa_family) {
    case AF_INET:
        return sizeof(struct sockaddr_in);
    case AF_INET6:
        return sizeof(struct sockaddr_in6);
    case AF_LINK:
        return sizeof(struct sockaddr_dl);
    default:
        return -1;
    }
}

int get_numeric_address(struct sockaddr *sa, char *outbuf, size_t buflen) {
    socklen_t len;
    if ((len = get_sock_len(sa)) < 0) {
        return -1;
    }
    if (getnameinfo(sa, len, outbuf, buflen, NULL, 0, NI_NUMERICHOST)) {
        return -1;
    }
    return 0;
}

...
char buf[NI_MAXHOST];
if (!get_numeric_address(sa, buf, sizeof(buf))) { /* For some struct sockaddr *sa */
    printf("address: %s\n", buf);
} else {
    printf("doh!\n");
} 
1 голос
/ 14 августа 2011

Я пытался увидеть все устройства, о которых сообщает pcap_findalldevs, и в итоге здесь искал информацию о интерпретации адресов AF_LINK в MAC OS.

Я привык видеть стоящее struct sockaddr для семейства интерфейсов, и его немедленно приводят к соответствующему типу, а не пишут код для доступа к * sa_data *.

Для того, что я хотел, было достаточно использовать link_ntoa для преобразования адреса в удобочитаемую форму.

#import <Foundation/Foundation.h>
#include <pcap.h>
#include <netinet/in.h>
#include <net/if_dl.h>
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    pcap_if_t* allDevs = NULL;
    char errbuff[PCAP_ERRBUF_SIZE];
    if (pcap_findalldevs(&allDevs, errbuff) <0) {
        NSLog(@"Failed with error '%s'", errbuff);
    }
    else {
        for (pcap_if_t* device = allDevs; device != NULL; device = device->next) {
            for (pcap_addr_t* address = device->addresses; address != NULL; address = address->next) {
                struct sockaddr* sa_addr = address->addr;
                if (sa_addr->sa_family == AF_LINK) {
                    struct sockaddr_dl* link_addr = (struct sockaddr_dl*) sa_addr;
                    char* linkAddress = link_ntoa(link_addr);
                    NSLog(@"ntoa %s", linkAddress);
                }
            }
        }
    }
    pcap_freealldevs(allDevs);

    [pool drain];
    return 0;
}

Работая на моем компьютере, я получаю следующие устройства с записями 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

1 голос
/ 16 марта 2011

Вот что я в итоге сделал:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <errno.h>
#include <net/if_dl.h>
#include <pcap.h>

#include "mac.h"

int main() {
    printf("en1: %s\n", lookupDeviceMac("vnic0"));
}

unsigned char *lookupDeviceMac(char *dev){
    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 *ret = malloc(6);

    if (pcap_findalldevs(&alldevs, eb) == -1) {
        printf("%s\n", eb);
        return(ret);
    }

    for (d = alldevs; d != NULL; d = d->next) {
        if(strcmp(d->name, dev) == 0){
            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);

                    if(link->sdl_alen == 6){
                        // Seen in some sample code
                        sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[0],
                                                                     (unsigned char)mac[1],
                                                                     (unsigned char)mac[2],
                                                                     (unsigned char)mac[3],
                                                                     (unsigned char)mac[4],
                                                                     (unsigned char)mac[5]);
                    } else if(link->sdl_alen > 6) {
                        // This is what happens in OSX 10.6.5
                        sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[1],
                                                                     (unsigned char)mac[2],
                                                                     (unsigned char)mac[3],
                                                                     (unsigned char)mac[4],
                                                                     (unsigned char)mac[5],
                                                                     (unsigned char)mac[6]);
                    }
                    return(ret);
                }
            }
        }
    }
}
...