std::string macAsString(const struct ifaddrs *addr) { static std::string blank_mac = "00:00:00:00:00:00"; if (addr->ifa_addr == nullptr) { // No link or MAC exists. return blank_mac; } #if defined(__linux__) struct ifreq ifr; ifr.ifr_addr.sa_family = AF_INET; memcpy(ifr.ifr_name, addr->ifa_name, IFNAMSIZ); int socket_fd = socket(AF_INET, SOCK_DGRAM, 0); if (socket_fd < 0) { return blank_mac; } ioctl(socket_fd, SIOCGIFHWADDR, &ifr); close(socket_fd); return macAsString(ifr.ifr_hwaddr.sa_data); #else auto sdl = (struct sockaddr_dl *)addr->ifa_addr; if (sdl->sdl_alen != 6) { // Do not support MAC address that are not 6 bytes... return blank_mac; } return macAsString(&sdl->sdl_data[sdl->sdl_nlen]); #endif }
Status genArp(const struct rt_msghdr *route, const AddressMap &addr_map, Row &r) { if (addr_map[RTAX_DST]->sa_family != AF_INET) { return Status(1, "Not in ARP cache"); } // The cache will always know the address. r["address"] = ipAsString(addr_map[RTAX_DST]); auto sdl = (struct sockaddr_dl *)addr_map[RTA_DST]; if (sdl->sdl_alen > 0) { r["mac"] = macAsString(LLADDR(sdl)); } else { r["mac"] = "incomplete"; } // Note: also possible to detect published. if (route->rtm_rmx.rmx_expire == 0) { r["permanent"] = "1"; } else { r["permanent"] = "0"; } return Status(0, "OK"); }
void genDetailsFromAddr(const struct ifaddrs *addr, QueryData &results) { Row r; r["interface"] = std::string(addr->ifa_name); r["mac"] = macAsString(addr); if (addr->ifa_data != nullptr) { #ifdef __linux__ // Linux/Netlink interface details parsing. auto ifd = (struct rtnl_link_stats *)addr->ifa_data; r["ipackets"] = BIGINT_FROM_UINT32(ifd->rx_packets); r["opackets"] = BIGINT_FROM_UINT32(ifd->tx_packets); r["ibytes"] = BIGINT_FROM_UINT32(ifd->rx_bytes); r["obytes"] = BIGINT_FROM_UINT32(ifd->tx_bytes); r["ierrors"] = BIGINT_FROM_UINT32(ifd->rx_errors); r["oerrors"] = BIGINT_FROM_UINT32(ifd->tx_errors); // Get Linux physical properties for the AF_PACKET entry. int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd >= 0) { struct ifreq ifr; memcpy(ifr.ifr_name, addr->ifa_name, IFNAMSIZ); if (ioctl(fd, SIOCGIFMTU, &ifr) >= 0) { r["mtu"] = BIGINT_FROM_UINT32(ifr.ifr_mtu); } if (ioctl(fd, SIOCGIFMETRIC, &ifr) >= 0) { r["metric"] = BIGINT_FROM_UINT32(ifr.ifr_metric); } if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) { r["type"] = INTEGER_FROM_UCHAR(ifr.ifr_hwaddr.sa_family); } } r["last_change"] = "-1"; #else // Apple and FreeBSD interface details parsing. auto ifd = (struct if_data *)addr->ifa_data; r["type"] = INTEGER_FROM_UCHAR(ifd->ifi_type); r["mtu"] = BIGINT_FROM_UINT32(ifd->ifi_mtu); r["metric"] = BIGINT_FROM_UINT32(ifd->ifi_metric); r["ipackets"] = BIGINT_FROM_UINT32(ifd->ifi_ipackets); r["opackets"] = BIGINT_FROM_UINT32(ifd->ifi_opackets); r["ibytes"] = BIGINT_FROM_UINT32(ifd->ifi_ibytes); r["obytes"] = BIGINT_FROM_UINT32(ifd->ifi_obytes); r["ierrors"] = BIGINT_FROM_UINT32(ifd->ifi_ierrors); r["oerrors"] = BIGINT_FROM_UINT32(ifd->ifi_oerrors); r["last_change"] = BIGINT_FROM_UINT32(ifd->ifi_lastchange.tv_sec); #endif } results.push_back(r); }