2011-07-20 43 views
7

Có cách nào để nhận địa chỉ MAC của giao diện qua số getifaddrs() không?Địa chỉ MAC với getifaddrs

Tôi đã có, để nhận địa chỉ IP, nhưng tôi đã bỏ lỡ MAC. Ive đã cố gắng để tìm kiếm thông tin trong getifaddrs(), nhưng không có gì về MAC địa chỉ

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++; 
    } 
     } 

Cảm ơn

Trả lời

1

Đây là đoạn mã để nhận IP và địa chỉ 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; 
} 
+0

không có liên quan đến câu hỏi này.Hãy hỏi làm thế nào anh ta có thể nhận được địa chỉ mac bằng cách sử dụng getifaddrs, không phải cách thay thế. – gurpinars

3

Nếu bạn đang ở trên Unix, bạn đang tìm kiếm ioctlSIOCGIFHWADDR là:

SIOCGIFHWADDR, SIOCSIFHWADDR

Nhận hoặc đặt địa chỉ phần cứng của thiết bị bằng ifr_hwaddr. Địa chỉ phần cứng được chỉ định trong cấu trúc sockaddr. sa_family chứa loại thiết bị ARPHRD_ *, sa_data địa chỉ phần cứng L2 bắt đầu từ từ byte 0. Đặt địa chỉ phần cứng là một hoạt động đặc quyền.

Xem man netdevice.

+1

cảm ơn, nhưng câu hỏi là, nếu có bất kỳ cách nào làm thế nào để có được điều này thông qua getifaddrs() – shaggy

8

Trên Linux, bạn muốn làm điều gì đó như

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 ? ":":""); 

     } 

Mặc dù này, có thể có nhiều thành viên của struct sockaddr_ll bạn muốn kiểm tra, xem here cho một mô tả.

+0

hey, có vẻ tốt đẹp, nhưng ive got a 'dereferencing trỏ tới kiểu không đầy đủ' trên 's-> sll_addr [i]' và dunno tại sao. bạn có thể giúp? – shaggy

+0

Bạn đã thêm tất cả các gói cần thiết chưa? Thực hiện theo các liên kết cho các bao gồm. – Ioan

+0

Đã sửa lỗi. Cảm ơn! Nhưng tôi luôn có cùng một địa chỉ MAC, mặc dù trên các giao diện, nó không giống nhau. Bạn có ý tưởng tại sao không? – shaggy

10

Trên các hệ thống BSD bạn có thể sử dụng getifaddrs trực tiếp để lấy máy Mac. Dưới đây là ví dụ về các công cụ hoàn chỉnh của 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; 
    } 
} 
+0

Giải pháp này đã được thử nghiệm trên FreeBSD, OS X và iOS. – royaltm

9

getifaddrs() đã cung cấp địa chỉ MAC được liên kết với mỗi giao diện. Trên Linux, khi bạn truy cập vào một gia đình == AF_PACKET thì là địa chỉ MAC. Điều tương tự trên OSX/BSD nhưng trong trường hợp đó gia đình sẽ là AF_LINK.

0

my experiments với cách tiếp cận khác nhau để liệt kê các giao diện

/* Copyright Yadro (C) 2016 
* Author: [email protected] 
* 
* For those who have pissed off awking output of ip(8)... 
* 
* [[email protected] ~]# ./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; 
} 
Các vấn đề liên quan