2015-01-11 08:39:16 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
2015-05-12 06:31:13 +00:00
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
2015-01-11 08:39:16 +00:00
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
#include <iomanip>
|
|
|
|
|
2015-05-08 23:03:43 +00:00
|
|
|
// Maintain the order of includes (ifaddrs after if).
|
2015-01-11 08:39:16 +00:00
|
|
|
#include <net/if.h>
|
2015-05-08 23:03:43 +00:00
|
|
|
#include <ifaddrs.h>
|
2015-01-11 08:39:16 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
#include <linux/if_link.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <osquery/core.h>
|
|
|
|
#include <osquery/logger.h>
|
|
|
|
#include <osquery/tables.h>
|
|
|
|
|
|
|
|
#include "osquery/tables/networking/utils.h"
|
|
|
|
|
|
|
|
namespace osquery {
|
|
|
|
namespace tables {
|
|
|
|
|
2015-10-21 20:56:58 +00:00
|
|
|
// Functions for safe sign-extension
|
|
|
|
std::basic_string<char> INTEGER_FROM_UCHAR(unsigned char x) {
|
|
|
|
return INTEGER(static_cast<uint16_t>(x));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::basic_string<char> BIGINT_FROM_UINT32(uint32_t x) {
|
|
|
|
return BIGINT(static_cast<uint64_t>(x));
|
|
|
|
}
|
2015-01-11 08:39:16 +00:00
|
|
|
|
|
|
|
void genAddressesFromAddr(const struct ifaddrs *addr, QueryData &results) {
|
|
|
|
std::string dest_address;
|
|
|
|
Row r;
|
|
|
|
r["interface"] = std::string(addr->ifa_name);
|
|
|
|
|
2015-04-17 00:40:19 +00:00
|
|
|
// Address and mask will appear every time.
|
2015-01-11 08:39:16 +00:00
|
|
|
if (addr->ifa_addr != nullptr) {
|
2015-10-21 20:56:58 +00:00
|
|
|
r["address"] = ipAsString(static_cast<struct sockaddr *>(addr->ifa_addr));
|
2015-01-11 08:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (addr->ifa_netmask != nullptr) {
|
2015-10-21 20:56:58 +00:00
|
|
|
r["mask"] = ipAsString(static_cast<struct sockaddr *>(addr->ifa_netmask));
|
2015-01-11 08:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The destination address is used for either a broadcast or PtP address.
|
|
|
|
if (addr->ifa_dstaddr != nullptr) {
|
2015-10-21 20:56:58 +00:00
|
|
|
dest_address = ipAsString(static_cast<struct sockaddr *>(addr->ifa_dstaddr));
|
2015-01-11 08:39:16 +00:00
|
|
|
if ((addr->ifa_flags & IFF_BROADCAST) == IFF_BROADCAST) {
|
|
|
|
r["broadcast"] = dest_address;
|
|
|
|
} else {
|
|
|
|
r["point_to_point"] = dest_address;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
results.push_back(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
void genDetailsFromAddr(const struct ifaddrs *addr, QueryData &results) {
|
|
|
|
Row r;
|
2015-07-09 05:37:35 +00:00
|
|
|
if (addr->ifa_name != nullptr) {
|
|
|
|
r["interface"] = std::string(addr->ifa_name);
|
|
|
|
} else {
|
|
|
|
r["interface"] = "";
|
|
|
|
}
|
2015-01-11 08:39:16 +00:00
|
|
|
r["mac"] = macAsString(addr);
|
|
|
|
|
2015-08-16 03:43:53 +00:00
|
|
|
if (addr->ifa_data != nullptr && addr->ifa_name != nullptr) {
|
2015-01-11 08:39:16 +00:00
|
|
|
#ifdef __linux__
|
|
|
|
// Linux/Netlink interface details parsing.
|
2015-10-21 20:56:58 +00:00
|
|
|
auto ifd = static_cast<struct rtnl_link_stats *>(addr->ifa_data);
|
2015-07-09 05:37:35 +00:00
|
|
|
r["mtu"] = "0";
|
|
|
|
r["metric"] = "0";
|
|
|
|
r["type"] = "0";
|
2015-01-11 08:39:16 +00:00
|
|
|
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.
|
2015-05-12 06:31:13 +00:00
|
|
|
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
2015-01-11 08:39:16 +00:00
|
|
|
if (fd >= 0) {
|
|
|
|
struct ifreq ifr;
|
2015-04-17 00:40:19 +00:00
|
|
|
memcpy(ifr.ifr_name, addr->ifa_name, IFNAMSIZ);
|
2015-01-11 08:39:16 +00:00
|
|
|
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) {
|
2015-05-12 06:31:13 +00:00
|
|
|
r["type"] = INTEGER_FROM_UCHAR(ifr.ifr_hwaddr.sa_family);
|
2015-01-11 08:39:16 +00:00
|
|
|
}
|
2015-10-12 16:59:09 +00:00
|
|
|
|
|
|
|
close(fd);
|
2015-01-11 08:39:16 +00:00
|
|
|
}
|
|
|
|
|
2015-07-09 05:37:35 +00:00
|
|
|
// Last change is not implemented in Linux.
|
2015-01-11 08:39:16 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
QueryData genInterfaceAddresses(QueryContext &context) {
|
|
|
|
QueryData results;
|
|
|
|
|
2015-10-21 20:56:58 +00:00
|
|
|
struct ifaddrs *if_addrs = nullptr;
|
|
|
|
struct ifaddrs *if_addr = nullptr;
|
2015-07-09 05:37:35 +00:00
|
|
|
if (getifaddrs(&if_addrs) != 0 || if_addrs == nullptr) {
|
2015-01-11 08:39:16 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2015-04-17 00:40:19 +00:00
|
|
|
for (if_addr = if_addrs; if_addr != nullptr; if_addr = if_addr->ifa_next) {
|
2015-10-15 22:47:15 +00:00
|
|
|
if (if_addr->ifa_addr == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
2015-05-07 04:58:23 +00:00
|
|
|
if (if_addr->ifa_addr->sa_family == AF_INET ||
|
|
|
|
if_addr->ifa_addr->sa_family == AF_INET6) {
|
2015-01-11 08:39:16 +00:00
|
|
|
genAddressesFromAddr(if_addr, results);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
freeifaddrs(if_addrs);
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
QueryData genInterfaceDetails(QueryContext &context) {
|
|
|
|
QueryData results;
|
|
|
|
|
2015-10-21 20:56:58 +00:00
|
|
|
struct ifaddrs *if_addrs = nullptr;
|
|
|
|
struct ifaddrs *if_addr = nullptr;
|
2015-07-09 05:37:35 +00:00
|
|
|
if (getifaddrs(&if_addrs) != 0 || if_addrs == nullptr) {
|
2015-01-11 08:39:16 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2015-04-17 00:40:19 +00:00
|
|
|
for (if_addr = if_addrs; if_addr != nullptr; if_addr = if_addr->ifa_next) {
|
2015-10-15 22:47:15 +00:00
|
|
|
if (if_addr->ifa_addr != nullptr &&
|
|
|
|
if_addr->ifa_addr->sa_family != AF_INTERFACE) {
|
2015-01-11 08:39:16 +00:00
|
|
|
// This interface entry does not describe the link details.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
genDetailsFromAddr(if_addr, results);
|
|
|
|
}
|
|
|
|
|
|
|
|
freeifaddrs(if_addrs);
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|