带有 getifaddrs 的 MAC 地址

Posted

技术标签:

【中文标题】带有 getifaddrs 的 MAC 地址【英文标题】:MAC address with getifaddrs 【发布时间】:2011-10-09 10:01:54 【问题描述】:

有没有办法通过getifaddrs()获取接口的MAC地址?

我已经有了这个来获取 IP 地址,但我有点错过了MAC。我试图在getifaddrs() 中查找信息,但没有关于MAC 地址的信息

struct ifaddrs *iflist, *iface;

  if (getifaddrs(&iflist) < 0) 
  
      perror("getifaddrs");
  

  char addrp[INET6_ADDRSTRLEN];
  char macp[INET6_ADDRSTRLEN];
  int i=0;

  for (iface = iflist; iface; iface = iface->ifa_next) 
  
    int af = iface->ifa_addr->sa_family;
    const void *addr;
    const void *mac;

      switch (af) 
      
        case AF_INET:
          addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
          break;
      //get mac address somehow?
        default:
          addr = NULL;
      

      if (addr) 
      
        if (inet_ntop(af, addr, addrp, sizeof addrp) == NULL)
        
           perror("inet_ntop");
           continue;
        
    if (inet_ntop(af, mac, macp, sizeof macp) == NULL) // this is already for MAC add
        
           perror("inet_ntop");
           continue;
        
    if (strcmp(addrp, "127.0.0.1") != 0) 
    
       strcat(tableO[i].IPaddr, addrp);
       strcat(tableO[i].MACaddr, macp);
       i++;
    
      

谢谢

【问题讨论】:

【参考方案1】:

结合几个答案,这适用于 Linux 和 Mac/ios/BSD

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#ifdef __linux__
    #include <arpa/inet.h>
    #include <netpacket/packet.h>
    #include <net/ethernet.h>
#else
    #include <net/if_dl.h>
#endif

int listmacaddrs(void) 
    struct ifaddrs *ifap, *ifaptr;
    unsigned char *ptr;

    if (getifaddrs(&ifap) == 0) 
        for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) 
            #ifdef __linux__
                char macp[INET6_ADDRSTRLEN];
                if (((ifaptr)->ifa_addr)->sa_family == AF_PACKET) 
                    struct sockaddr_ll *s = (struct sockaddr_ll*)(ifaptr->ifa_addr);
                    int i;
                    int len = 0;
                    for (i = 0; i < 6; i++) 
                        len += sprintf(macp+len, "%02X%s", s->sll_addr[i], i < 5 ? ":":"");
                    
                    printf("%s: %s\n", (ifaptr)->ifa_name, macp);
                
            #else
            if (((ifaptr)->ifa_addr)->sa_family == AF_LINK) 
                ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)(ifaptr)->ifa_addr);
                printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",
                                    (ifaptr)->ifa_name,
                                    *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
            
            #endif
        
        freeifaddrs(ifap);
        return 1;
     else 
        return 0;
       


int macaddr(char *ifname, char *macaddrstr) 
    struct ifaddrs *ifap, *ifaptr;
    unsigned char *ptr;

    if (getifaddrs(&ifap) == 0) 
        for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) 
            #ifdef __linux__
                if (!strcmp((ifaptr)->ifa_name, ifname) && (((ifaptr)->ifa_addr)->sa_family == AF_PACKET)) 
                    struct sockaddr_ll *s = (struct sockaddr_ll*)(ifaptr->ifa_addr);
                    int i;
                    int len = 0;
                    for (i = 0; i < 6; i++) 
                        len += sprintf(macaddrstr+len, "%02X%s", s->sll_addr[i], i < 5 ? ":":"");
                    
                    break;
                
            #else
            if (!strcmp((ifaptr)->ifa_name, ifname) && (((ifaptr)->ifa_addr)->sa_family == AF_LINK)) 
                ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)(ifaptr)->ifa_addr);
                sprintf(macaddrstr, "%02x:%02x:%02x:%02x:%02x:%02x",
                                    *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
                break;
            
            #endif
        
        freeifaddrs(ifap);
        return ifaptr != NULL;
     else 
        return 0;
    


extern int
main(int argc, char* argv[]) 

    char macaddrstr[18], *ifname;

    if (argc == 2) 
        ifname = argv[1];
        if (!strcmp(ifname,"-l")) 
            return listmacaddrs();
         else 
            if (macaddr(ifname, macaddrstr)) 
                printf("%s: %s\n", ifname, macaddrstr);
                return 0;
             else 
                printf("%s: not found\n", ifname);
                return 1;
            
        
     else 
        printf("list all interfaces: %s -l\n", argv[0]);
        printf("single interface: %s interface_name\n", argv[0]);
        return 2;
    

【讨论】:

【参考方案2】:

my experiments 有不同的方法来列出接口

/* Copyright Yadro (C) 2016
 * Author: ed@ngslab.ru
 *
 * For those who have pissed off awking output of ip(8)...
 *
 * [root@opt-03 ~]# ./lsif
 *  1: lo              : 127.0.0.1      : LOOPBACK -
 *  2: eno1            : 172.17.32.102  : ETHER 6c:ae:8b:2c:eb:18
 *  3: br-ctlplane     : 192.0.2.1      : ETHER 6c:ae:8b:2c:eb:19
 *  4: br-ctlplane     : 192.0.2.3      : ETHER 6c:ae:8b:2c:eb:19
 *  5: br-ctlplane     : 192.0.2.2      : ETHER 6c:ae:8b:2c:eb:19
 *
 * See netdevice(7) for
 * - SIOCGIFADDR
 * - SIOCGIFBRDADDR
 * - SIOCGIFCONF (here)
 * - SIOCGIFDSTADDR
 * - SIOCGIFFLAGS
 * - SIOCGIFHWADDR (here)
 * - SIOCGIFINDEX
 * - SIOCGIFMAP
 * - SIOCGIFMETRIC
 * - SIOCGIFMTU
 * - SIOCGIFNAME
 * - SIOCGIFNETMASK
 * - SIOCGIFPFLAGS
 * - SIOCGIFTXQLEN
 */
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <linux/if_link.h>
#include <linux/types.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <arpa/inet.h>
#include <netpacket/packet.h>

/* legacy mode decls */
extern int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;

/* bool type is not a default feature in C */
typedef enum  false = 0, true = 1  bool;

static struct 
    int mode;
    bool ifname_set;
    char ifname[IFNAMSIZ+1];
    bool show_ip;
    bool show_mac;
    bool flags_set;
    short flags;
    bool verbose;
 global = ;

int run_ioctl(int opcode, void *arg, const struct sockaddr *sa)

    int af = sa ? sa->sa_family : AF_INET;
    int rc, sock = socket(af, SOCK_DGRAM, 0);

    if (sock < 0) 
        if (global.verbose) perror("socket");
        return sock;
    

    if (sa) 
        int sa_len = sizeof(struct sockaddr);

        switch (af) 
        case AF_INET: sa_len = sizeof(struct sockaddr_in); break;
        case AF_INET6: sa_len = sizeof(struct sockaddr_in6); break;
        case AF_PACKET: sa_len = sizeof(struct sockaddr_ll); break;
        

        if (bind(sock, sa, sa_len)) 
            // if (global.verbose) perror("bind");
            close(sock);
            return rc;
        
    

    rc = ioctl(sock, opcode, arg);
    if (rc) 
        // if (global.verbose) perror("ioctl");
        close(sock);
        return rc;
    

    close(sock);
    return 0;


int query_response_size(void)

    struct ifconf ifc = ;
    int rc = run_ioctl(SIOCGIFCONF, &ifc, NULL);

    if (rc) 
        if (global.verbose) perror("query_response_size");
        return rc;
    

    return ifc.ifc_len;


int query_if_hwaddr(struct ifreq *req)

    int rc = run_ioctl(SIOCGIFHWADDR, req, NULL);

    if (rc) 
        if (global.verbose) perror("query_if_hwaddr:ioctl");
        return rc;
    

    return 0;


int query_ip_addr(struct ifreq *req)

    int rc;

    req->ifr_addr.sa_family = AF_INET;
    rc = run_ioctl(SIOCGIFADDR, req, NULL);

    if (rc) 
        if (global.verbose) perror("query_ip_addr:ioctl");
        return rc;
    

    return 0;


int query_if_flags(struct ifreq *req)

    int rc = run_ioctl(SIOCGIFHWADDR, req, NULL);

    if (rc) 
        if (global.verbose) perror("query_if_flags:ioctl");
        return rc;
    

    return 0;


double query_if_last_pkt(const struct sockaddr *sa)

    struct timeval t;
    double res;
    int rc = run_ioctl(SIOCGSTAMP, &t, sa);

    if (rc) 
        if (global.verbose) perror("query_if_last_pkt:ioctl");
        return -1.0;
    

    res = (double) t.tv_sec;
    res += ((double) t.tv_usec) / 1000000.0;

    return res;


enum addr_fmt 
    ADDR_FMT_LONG,
    ADDR_FMT_SHORT,
;

static const char iff_flag_delimiter[] = ",";
#define _STR(x) ""#x
#define IFF_FLAG2STR(flag, value, string, descr)            \
    do                                 \
        if ((value) & (IFF_##flag))                \
            if ((string)[0])                \
                strcat((string), iff_flag_delimiter);   \
            strcat((string), _STR(flag));           \
                                   \
     while (0)

static inline char *if_flags(short flags, enum addr_fmt fmt)

    static char sflags[128];

    memset(sflags, 0, sizeof(sflags));
    /* sprintf(sflags, "0x%0*x", (int)sizeof(flags) * 2, flags); */
    IFF_FLAG2STR(UP, flags, sflags, "Interface is up");
    IFF_FLAG2STR(BROADCAST, flags, sflags, "Broadcast address valid");
    IFF_FLAG2STR(DEBUG, flags, sflags, "Turn on debugging");
    IFF_FLAG2STR(LOOPBACK, flags, sflags, "Is a loopback net");
    IFF_FLAG2STR(POINTOPOINT, flags, sflags, "Interface is point-to-point link");
    IFF_FLAG2STR(NOTRAILERS, flags, sflags, "Avoid use of trailers");
    IFF_FLAG2STR(RUNNING, flags, sflags, "Resources allocated");
    IFF_FLAG2STR(NOARP, flags, sflags, "No address resolution protocol");
    IFF_FLAG2STR(PROMISC, flags, sflags, "Receive all packets");
    IFF_FLAG2STR(ALLMULTI, flags, sflags, "Receive all multicast packets");
    IFF_FLAG2STR(MASTER, flags, sflags, "Master of a load balancer");
    IFF_FLAG2STR(SLAVE, flags, sflags, "Slave of a load balancer");
    IFF_FLAG2STR(MULTICAST, flags, sflags, "Supports multicast");
    IFF_FLAG2STR(PORTSEL, flags, sflags, "Can set media type");
    IFF_FLAG2STR(AUTOMEDIA, flags, sflags, "Auto media select active");
    IFF_FLAG2STR(DYNAMIC, flags, sflags, "Dialup device with changing addresses");

    return sflags;


static const char *_families[] = 
    [AF_UNSPEC] = "UNSPEC",
    [AF_LOCAL] = "LOCAL", /* == [AF_UNIX] == [AF_FILE] */
    [AF_INET] = "INET",
    [AF_AX25] = "AX25",
    [AF_IPX] = "IPX",
    [AF_APPLETALK] = "APPLETALK",
    [AF_NETROM] = "NETROM",
    [AF_BRIDGE] = "BRIDGE",
    [AF_ATMPVC] = "ATMPVC",
    [AF_X25] = "X25",
    [AF_INET6] = "INET6",
    [AF_ROSE] = "ROSE",
    [AF_DECnet] = "DECnet",
    [AF_NETBEUI] = "NETBEUI",
    [AF_SECURITY] = "SECURITY",
    [AF_KEY] = "KEY",
    [AF_NETLINK] = "NETLINK",
    [AF_ROUTE] = "ROUTE",
    [AF_PACKET] = "PACKET",
    [AF_ASH] = "ASH",
    [AF_ECONET] = "ECONET",
    [AF_ATMSVC] = "ATMSVC",
    [AF_RDS] = "RDS",
    [AF_SNA] = "SNA",
    [AF_IRDA] = "IRDA",
    [AF_PPPOX] = "PPPOX",
    [AF_WANPIPE] = "WANPIPE",
    [AF_LLC] = "LLC",
    [AF_IB] = "IB",
    [AF_MPLS] = "MPLS",
    [AF_CAN] = "CAN",
    [AF_TIPC] = "TIPC",
    [AF_BLUETOOTH] = "BLUETOOTH",
    [AF_IUCV] = "IUCV",
    [AF_RXRPC] = "RXRPC",
    [AF_ISDN] = "ISDN",
    [AF_PHONET] = "PHONET",
    [AF_IEEE802154] = "IEEE802154",
    [AF_CAIF] = "CAIF",
    [AF_ALG] = "ALG",
    [AF_NFC] = "NFC",
    [AF_VSOCK] = "VSOCK",
;

static inline const char *af_name(int af)

    if (af >= 0 && af < AF_MAX)
        return _families[af];
    return NULL;


static inline char *add_af_name(char *s, int af, enum addr_fmt fmt)

    static int af_name_len_max;

    if (!af_name_len_max) 
        int i;

        for (i = 0; i < AF_MAX; i++) 
            int l = strlen(af_name(i));

            if (l > af_name_len_max)
                af_name_len_max = l;
        
        af_name_len_max++; /* add a space */
    

    switch (fmt) 
    case ADDR_FMT_LONG:
        sprintf(s, "%-*.*s", af_name_len_max, af_name_len_max, af_name(af));
        break;
    case ADDR_FMT_SHORT:
        strcpy(s, af_name(af));
        strcat(s, " ");
        break;
    
    s += strlen(s);
    return s;


#define min(x,y) (((x) > (y)) ? (y) : (x))

#define left_in(space) (sizeof(space) - strlen(space))

static inline void rpad4fmt(char *s, int s_size, int pad_size, enum addr_fmt fmt)

    while (fmt == ADDR_FMT_LONG && strlen(s) < min(s_size, pad_size))
        strncat(s, " ", s_size);


static inline int fetch_address(const struct sockaddr *sa, char *s, int size)

    int inf_size = -1;

    switch (sa->sa_family) 
    case AF_INET:  inf_size = sizeof(struct sockaddr_in); break;
    case AF_INET6: inf_size = sizeof(struct sockaddr_in6); break;
    

    return getnameinfo(sa, inf_size, s, size, NULL, 0, NI_NUMERICHOST);


static inline void hex_colon_bytes(char *s, const void *data, int d_sz)

    int i;
    const uint8_t *d = data;
    char *p;

    for (i = 0, p = s + strlen(s); i < d_sz; i++)
        sprintf(p + i * 3, "%02x%s", d[i], (i < d_sz - 1) ? ":" : "");


static inline void decode_packet(char *s, int size, const struct sockaddr *sa, enum addr_fmt fmt)

    const struct sockaddr_ll *ll = (struct sockaddr_ll *)sa;
    uint8_t *data = (uint8_t *) &ll->sll_addr[0];
    const int af = ll->sll_hatype;
    char *p;

    switch (af) 
    case ARPHRD_LOOPBACK:
        switch (fmt) 
        case ADDR_FMT_LONG: p = "LOOPBACK -"; break;
        case ADDR_FMT_SHORT:    p = "-"; break;
        
        strncpy(s, p, size);
        break;
    case ARPHRD_ETHER:
        switch (fmt) 
        case ADDR_FMT_LONG: p = "ETHER %02x:%02x:%02x:%02x:%02x:%02x"; break;
        case ADDR_FMT_SHORT:    p = "%02x:%02x:%02x:%02x:%02x:%02x"; break;
        
        snprintf(s, size, p, data[0], data[1], data[2], data[3], data[4], data[5]);
        break;
    default:
        switch (fmt) 
        case ADDR_FMT_LONG:
            snprintf(s, size, "<%d> <", af);
            break;
        case ADDR_FMT_SHORT:
            snprintf(s, size, "<%d/", af);
            break;
        
        hex_colon_bytes(s, data, ll->sll_halen);
        strncat(s, ">", size);
        break;
    


static inline char *ip_addr(const struct sockaddr *sa, enum addr_fmt fmt)

    const int af = sa->sa_family;
    static char addr[64];
    char *fmx, *p;
    int i, rc, pad_size;

    addr[0] = '\0';
    p = (fmt == ADDR_FMT_LONG) ? add_af_name(addr, af, fmt) : addr;

    switch (af) 
    case AF_INET:  pad_size = strlen(addr) + 15; break;
    case AF_INET6: pad_size = strlen(addr) + 40; break;
    default: pad_size = 0; break;
    

    switch (af) 
    case AF_INET:
    case AF_INET6:
        rc = fetch_address(sa, p, min(left_in(addr), NI_MAXHOST));
        if (rc) 
            strcat(addr, "<error:");
            strncat(addr, gai_strerror(rc), sizeof(addr));
            strncat(addr, ">", sizeof(addr));
            return addr;
        
        rpad4fmt(addr, sizeof(addr), pad_size, fmt);
        break;
    case AF_PACKET: /* no real IP here, of course */
        decode_packet(p, left_in(addr), sa, fmt);
        break;
    default:
        snprintf(p, left_in(addr), "<%d/", af);
        hex_colon_bytes(addr, sa->sa_data, sizeof(sa->sa_data));
        strncat(addr, ">", left_in(addr));
        break;
    
    return addr;


static inline char *hw_addr(const struct sockaddr *sa, enum addr_fmt fmt)

    const int af = sa->sa_family;
    uint8_t *data = (uint8_t *) &sa->sa_data[0];
    const size_t data_size = sizeof(sa->sa_data);
    static char mac[64]; /* ETHER aa:bb:cc:dd:ee:ff */
    char *p, *fmx;
    int i;

    switch (af) 
    case ARPHRD_LOOPBACK:
        switch (fmt) 
        case ADDR_FMT_LONG: fmx = "LOOPBACK -"; break;
        case ADDR_FMT_SHORT:    fmx = "-"; break;
        
        strcpy(mac, fmx);
        break;
    case ARPHRD_ETHER:
        switch (fmt) 
        case ADDR_FMT_LONG: fmx = "ETHER %02x:%02x:%02x:%02x:%02x:%02x"; break;
        case ADDR_FMT_SHORT:    fmx = "%02x:%02x:%02x:%02x:%02x:%02x"; break;
        
        sprintf(mac, fmx, data[0], data[1], data[2], data[3], data[4], data[5]);
        break;
    default:
        switch (fmt) 
        case ADDR_FMT_LONG:
            sprintf(mac, "<%d> <", af);
            break;
        case ADDR_FMT_SHORT:
            strcpy(mac, "<");
            break;
        
        for (i = 0, p = mac + strlen(mac); i < data_size; i++)
            sprintf(p + i * 3, "%02x%s", data[i],
                (i < data_size - 1) ? ":" : ">");
        break;
    

    return mac;


static inline void add_ip_addr(void *ifx, const char *errmsg, enum addr_fmt fmt)

    struct sockaddr *sa;
    struct ifreq *ifr = ifx;
    struct ifaddrs *ifa = ifx;

    switch (global.mode) 
    case 1: /* already fetched */ sa = &ifr->ifr_addr; break;
    case 2: sa = query_ip_addr(ifr) ? NULL : &ifr->ifr_addr; break;
    case 3: /* already fetched */ sa = ifa->ifa_addr; break;
    

    fputs(sa ? ip_addr(sa, fmt) : errmsg, stdout);


static inline void add_hw_addr(struct ifreq *ifr, const char *errmsg, enum addr_fmt fmt)

    fputs(query_if_hwaddr(ifr) ? errmsg : hw_addr(&ifr->ifr_addr, fmt), stdout);


static inline void add_flags(void *ifx, const char *errmsg, enum addr_fmt fmt)

    struct ifreq *ifr = ifx;
    struct ifaddrs *ifa = ifx;
    int flags = -1;

    switch (global.mode) 
    case 1:
    case 2: flags = query_if_flags(ifr) ? -1 : ifr->ifr_flags; break;
    case 3: /* already fetched */ flags = ifa->ifa_flags; break;
    

    fputs((flags == -1) ? errmsg : if_flags(flags, fmt), stdout);


static inline void add_if_name(void *ifx, enum addr_fmt fmt)

    struct ifreq *ifr = ifx;
    struct ifaddrs *ifa = ifx;
    char *name;

    switch (global.mode) 
    case 1:
    case 2: name = ifr->ifr_name; break;
    case 3: name = ifa->ifa_name; break;
    

    switch (fmt) 
    case ADDR_FMT_LONG:
        printf("%-*.*s", IFNAMSIZ, IFNAMSIZ, name);
        break;
    case ADDR_FMT_SHORT:
        fputs(name, stdout);
        break;
    


static void print_interface(struct ifreq *ifr)

    if (global.ifname_set) 
        if (strncmp(ifr->ifr_name, global.ifname, IFNAMSIZ))
            return;
        if (global.show_ip || !global.show_mac) 
            add_ip_addr(ifr, NULL, ADDR_FMT_SHORT);
            fputs(global.show_ip ? "" : "\t", stdout);
        
        if (global.show_mac || !global.show_ip)
            add_hw_addr(ifr, "<no-hw-addr>", ADDR_FMT_SHORT);
        putchar('\n');
        return;
    

    add_if_name(ifr, ADDR_FMT_LONG);
    printf(" : ");
    add_ip_addr(ifr, "<error> -", ADDR_FMT_LONG);
    printf(" : ");
    add_hw_addr(ifr, "<error> <no-hw-addr>", ADDR_FMT_LONG);

    if (global.flags_set) 
        printf(" : ");
        add_flags(ifr, "<error-no-flags>", ADDR_FMT_LONG);
    

    putchar('\n');


static void print_address(struct ifaddrs *ifa)

    if (global.ifname_set) 
        if (strncmp(ifa->ifa_name, global.ifname, IFNAMSIZ))
            return;
     else 
        add_if_name(ifa, ADDR_FMT_LONG);
        printf(" : ");
    
    if (ifa->ifa_addr == NULL) 
        printf("<no-address>\n");
        return;
    
    add_ip_addr(ifa, "<error> -", ADDR_FMT_LONG);
    if (global.flags_set) 
        printf(" : ");
        add_flags(ifa, "<error-no-flags>", ADDR_FMT_LONG);
    
    putchar('\n');
    return;


static void __dispose_req(struct ifreq **req)

    if (req && *req) 
        free(*req);
        *req = 0;
    


static int __1__query_if_list(void)

    struct ifreq *req __attribute__((cleanup(__dispose_req))) = NULL;
    struct ifconf ifc = ;
    int rc, i, j, size = query_response_size();

    if (size <= 0) return -1;

    req = calloc(size, 1);
    if (!req) 
        if (global.verbose) perror("query_if_list:cmalloc");
        return -1;
    

    ifc.ifc_len = size;
    ifc.ifc_req = req;

    rc = run_ioctl(SIOCGIFCONF, &ifc, NULL);
    if (rc) 
        if (global.verbose) perror("query_if_list:ioctl");
        return rc;
    

    for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++) 
        struct ifreq *ifr = &ifc.ifc_req[i];

        if (global.ifname_set) 
            if (strncmp(ifr->ifr_name, global.ifname, IFNAMSIZ))
                continue;
         else
            printf("%2d: ", i + 1);
        print_interface(ifr);
    

    return 0;


static void __dispose_if_list_2(struct if_nameindex **if_list)

    if (if_list && *if_list) 
        if_freenameindex(*if_list);
        *if_list = 0;
    


static int __2__query_if_list(void)

    struct if_nameindex *i;
    struct if_nameindex *if_list
        __attribute__((cleanup(__dispose_if_list_2)))
        = if_nameindex();

    if (!if_list) 
        if (global.verbose) perror("if_nameindex");
        return -1;
    
    for (i = if_list; ! (i->if_index == 0 && i->if_name == NULL); i++) 
        struct ifreq ifr;

        // printf("%u: %s\n", i->if_index, i->if_name);
        strncpy(ifr.ifr_name, i->if_name, sizeof(ifr.ifr_name));
        print_interface(&ifr);
    

    return 0;


static void __dispose_if_list_3(struct ifaddrs **if_list)

    if (if_list && *if_list) 
        freeifaddrs(*if_list);
        *if_list = 0;
    


static int __3__query_if_list(void)

    struct ifaddrs *ifa;
    struct ifaddrs *if_list __attribute__((cleanup(__dispose_if_list_3))) = NULL;

    if (getifaddrs(&if_list) == -1) 
        if (global.verbose) perror("getifaddrs");
        return -1;
    

    for (ifa = if_list; ifa != NULL; ifa = ifa->ifa_next) 
//      if (!ifa->ifa_addr)
//          continue;
        print_address(ifa);
    


int query_if_list(void)

    switch (global.mode) 
    case 1: return __1__query_if_list();
    case 2: return __2__query_if_list();
    case 3: return __3__query_if_list();
    


static char HELP[] = "%s [-f] [-i <interface> [-a | -m]]\n\n"
    "Options:\n"
    " -h -- this help\n"
    " -1, -2, -3 -- use different query schemes:\n"
    "   SIOCGIFCONF, if_nameindex, getifaddrs\n"
    " -i <interface> -- set <interface> name to query for\n"
    " -a -- list IP addresses\n"
    " -m -- list MAC addresses (you may want to use 'sort -u') here\n"
    " -f -- add flags to the output\n"
    " -v -- verbose\n"
    "\n";

static int parse_args(int argc, char * const argv[])

    const static char optspec[] = "hvi:amf123";

    global.mode = 1; /* default */

    while (true) 
        int opt = getopt(argc, argv, optspec);

        if (opt == -1)
            break;

        switch (opt) 
        case 'h':
            printf(HELP, argv[0]);
            exit(EXIT_SUCCESS);

        case '1': global.mode = 1; break;
        case '2': global.mode = 2; break;
        case '3': global.mode = 3; break;
        case '4': global.mode = 4; break;
        case '5': global.mode = 5; break;
        case '6': global.mode = 6; break;
        case '7': global.mode = 7; break;
        case '8': global.mode = 8; break;
        case '9': global.mode = 9; break;

        case 'i':
            global.ifname_set = true;
            strncpy(global.ifname, optarg, IFNAMSIZ);
            continue;
        case 'a':
            global.show_ip = true;
            continue;
        case 'm':
            global.show_mac = true;
            continue;
        case 'f':
            global.flags_set = true;
            continue;
        case 'v':
            global.verbose = true;
            continue;
        default:
            return -1;
        
    

    /* argv[optind] may be parsed here */

    if (optind < argc) 
        fprintf(stderr, "%s: trailing extra args\n", argv[0]);
        return -1;
    

    if ((global.show_ip || global.show_mac) && !global.ifname_set) 
        fprintf(stderr, "%s: -a and -m require -i <interface>.\n", argv[0]);
        return -1;
    

    if (global.show_ip && global.show_mac) 
        /* just turn'em off */
        global.show_ip = false;
        global.show_mac = false;
        /*
        fprintf(stderr, "%s: -a and -m are mutually exclusive.\n", argv[0]);
        return -1;
        */
    

    return 0;


int main(int argc, char * const argv[])

    if (parse_args(argc, argv))
        return EXIT_FAILURE;

    if (query_if_list())
        return EXIT_FAILURE;

    return EXIT_SUCCESS;

【讨论】:

【参考方案3】:

getifaddrs() 已经提供了与每个接口关联的 MAC 地址。在 Linux 上,当你遇到一个家庭时 == AF_PACKET 就是 MAC 地址。在 OSX / BSD 上也是如此,但在这种情况下,家庭将是 AF_LINK。

【讨论】:

【参考方案4】:

在 BSD 系统上,您可以直接使用 getifaddrs 来检索 MAC。 以下是完整的 macaddr.c 工具示例:

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

int listmacaddrs(void) 
    struct ifaddrs *ifap, *ifaptr;
    unsigned char *ptr;

    if (getifaddrs(&ifap) == 0) 
        for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) 
            if (((ifaptr)->ifa_addr)->sa_family == AF_LINK) 
                ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)(ifaptr)->ifa_addr);
                printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n",
                                    (ifaptr)->ifa_name,
                                    *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
            
        
        freeifaddrs(ifap);
        return 1;
     else 
        return 0;
       


int macaddr(char *ifname, char *macaddrstr) 
    struct ifaddrs *ifap, *ifaptr;
    unsigned char *ptr;

    if (getifaddrs(&ifap) == 0) 
        for(ifaptr = ifap; ifaptr != NULL; ifaptr = (ifaptr)->ifa_next) 
            if (!strcmp((ifaptr)->ifa_name, ifname) && (((ifaptr)->ifa_addr)->sa_family == AF_LINK)) 
                ptr = (unsigned char *)LLADDR((struct sockaddr_dl *)(ifaptr)->ifa_addr);
                sprintf(macaddrstr, "%02x:%02x:%02x:%02x:%02x:%02x",
                                    *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
                break;
            
        
        freeifaddrs(ifap);
        return ifaptr != NULL;
     else 
        return 0;
    


extern int
main(int argc, char* argv[]) 

    char macaddrstr[18], *ifname;

    if (argc == 2) 
        ifname = argv[1];
        if (!strcmp(ifname,"-l")) 
            return listmacaddrs();
         else 
            if (macaddr(ifname, macaddrstr)) 
                printf("%s: %s\n", ifname, macaddrstr);
                return 0;
             else 
                printf("%s: not found\n", ifname);
                return 1;
            
        
     else 
        printf("list all interfaces: %s -l\n", argv[0]);
        printf("single interface: %s interface_name\n", argv[0]);
        return 2;
    

【讨论】:

此解决方案已在 FreeBSD、OS X 和 iOS 上进行了测试。【参考方案5】:

这是获取IP和MAC地址的代码

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>

int main(void)

  char buf[8192] = 0;
  struct ifconf ifc = 0;
  struct ifreq *ifr = NULL;
  int sck = 0;
  int nInterfaces = 0;
  int i = 0;
  char ip[INET6_ADDRSTRLEN] = 0;
  char macp[19];
  struct ifreq *item;
  struct sockaddr *addr;

  /* Get a socket handle. */
  sck = socket(PF_INET, SOCK_DGRAM, 0);
  if(sck < 0) 
  
    perror("socket");
    return 1;
  

  /* Query available interfaces. */
  ifc.ifc_len = sizeof(buf);
  ifc.ifc_buf = buf;
  if(ioctl(sck, SIOCGIFCONF, &ifc) < 0) 
  
    perror("ioctl(SIOCGIFCONF)");
    return 1;
  

  /* Iterate through the list of interfaces. */
  ifr = ifc.ifc_req;
  nInterfaces = ifc.ifc_len / sizeof(struct ifreq);

  for(i = 0; i < nInterfaces; i++) 
  
    item = &ifr[i];

    addr = &(item->ifr_addr);

    /* Get the IP address*/
    if(ioctl(sck, SIOCGIFADDR, item) < 0) 
    
      perror("ioctl(OSIOCGIFADDR)");
    

    if (inet_ntop(AF_INET, &(((struct sockaddr_in *)addr)->sin_addr), ip, sizeof ip) == NULL) //vracia adresu interf
        
           perror("inet_ntop");
           continue;
        

    /* Get the MAC address */
    if(ioctl(sck, SIOCGIFHWADDR, item) < 0) 
      perror("ioctl(SIOCGIFHWADDR)");
      return 1;
    

    /* display result */

    sprintf(macp, " %02x:%02x:%02x:%02x:%02x:%02x", 
    (unsigned char)item->ifr_hwaddr.sa_data[0],
    (unsigned char)item->ifr_hwaddr.sa_data[1],
    (unsigned char)item->ifr_hwaddr.sa_data[2],
    (unsigned char)item->ifr_hwaddr.sa_data[3],
    (unsigned char)item->ifr_hwaddr.sa_data[4],
    (unsigned char)item->ifr_hwaddr.sa_data[5]);

    printf("%s %s ", ip, macp);

  

  return 0;

【讨论】:

与此问题无关。他在问如何使用 getifaddrs 获取 MAC 地址,而不是其他方式。【参考方案6】:

在 Linux 上,你会做这样的事情

 case AF_PACKET:  
            struct sockaddr_ll *s = (struct sockaddr_ll*)iface->ifa_addr;
            int i;
            int len = 0;
            for(i = 0; i < 6; i++)
                len+=sprintf(macp+len,"%02X%s",s->sll_addr[i],i < 5 ? ":":"");

        

不过,您可能想要检查更多的 struct sockaddr_ll 成员,请参阅 here 了解说明。

【讨论】:

嘿,看起来不错,但我在s-&gt;sll_addr[i] 上找到了dereferencing pointer to incomplete type,不知道为什么。你能帮忙吗? 您添加了所有必要的包含吗?按照包含的链接。 已修复。谢谢!但是我总是得到相同的 MAC 地址,虽然在接口上,它是不一样的。你知道为什么吗? @shaggy 好吧,你在循环之外有 macp 缓冲区,所以我不知道你是如何查看 MAC 地址的。当您增加 i 时,您还将 addr 与 127.0.0.1 进行比较,这似乎没有什么意义。完整示例请参见pastebin.com/C71fA6UG 为了让这段代码更健壮,你真的应该测试一下sll_hatype==ARPHRD_ETHER。 (#include &lt;net/if_arp.h&gt; 获取该定义,否则其值仅为 1)。这是因为,至少在理论上,您可能有一个使用非以太网物理地址的非以太网/非 WiFi(严格来说,非 IEEE 802)网络设备,在这种情况下,该地址可能不是 MAC 地址,但其他内容,其长度可能多于或少于 6 个字节,并且可能具有不同的标准打印格式。【参考方案7】:

如果您使用的是 Unix,您正在寻找 ioctl SIOCGIFHWADDR

SIOCGIFHWADDR、SIOCGIFHWADDR

使用 ifr_hwaddr 获取或设置设备的硬件地址。这 硬件地址在 struct sockaddr 中指定。 sa_family 包含 ARPHRD_* 设备类型,sa_data L2 硬件地址起始 从字节 0 开始。设置硬件地址是一项特权操作。

man netdevice

【讨论】:

谢谢,但问题是,如果有什么方法可以通过 getifaddrs() 得到这个

以上是关于带有 getifaddrs 的 MAC 地址的主要内容,如果未能解决你的问题,请参考以下文章

PHP获取MAC地址的函数代码

交换机的三种安全模式

获取本机IP地址

获取和设置接口地址

如何快速获取IP地址

Erlang:读取ip地址