diff --git a/osquery/tables/CMakeLists.txt b/osquery/tables/CMakeLists.txt index 85d80d1b..5a7106a0 100644 --- a/osquery/tables/CMakeLists.txt +++ b/osquery/tables/CMakeLists.txt @@ -6,9 +6,11 @@ FILE(GLOB table_sources ADD_LIBRARY(osquery_tables registry.cpp ${table_sources} + networking/utils.cpp networking/etc_hosts.cpp networking/listening_ports.cpp networking/routes.cpp + networking/interfaces.cpp system/kextstat.cpp system/processes.cpp system/nvram.cpp diff --git a/osquery/tables/networking/interfaces.cpp b/osquery/tables/networking/interfaces.cpp new file mode 100644 index 00000000..299352f7 --- /dev/null +++ b/osquery/tables/networking/interfaces.cpp @@ -0,0 +1,113 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include + +#include +#include + +#include + +#include + +#include "osquery/core.h" +#include "osquery/database.h" +#include "utils.h" + +using namespace osquery::core; +using namespace osquery::db; + +namespace osquery { +namespace tables { + +// Macros for safe sign-extension +#define STRING_FROM_UCHAR(x) boost::lexical_cast((uint16_t)x); +#define STRING_FROM_UINT32(x) boost::lexical_cast((uint64_t)x); + +void genAddressesFromAddr(const struct ifaddrs *addr, QueryData &results) { + std::string dest_address; + Row r; + r["interface"] = std::string(addr->ifa_name); + + // Address and mask will appear everytime. + r["address"] = canonical_ip_address((struct sockaddr *)addr->ifa_addr); + r["mask"] = canonical_ip_address((struct sockaddr *)addr->ifa_netmask); + + // The destination address is used for either a broadcast or PtP address. + if (addr->ifa_dstaddr != NULL) { + dest_address = canonical_ip_address((struct sockaddr *)addr->ifa_dstaddr); + 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) { + struct if_data *ifd; + + Row r; + r["interface"] = std::string(addr->ifa_name); + r["mac"] = canonical_mac_address(addr); + + ifd = (struct if_data *)addr->ifa_data; + r["type"] = STRING_FROM_UCHAR(ifd->ifi_type); + r["mtu"] = STRING_FROM_UINT32(ifd->ifi_mtu); + r["metric"] = STRING_FROM_UINT32(ifd->ifi_metric); + r["ipackets"] = STRING_FROM_UINT32(ifd->ifi_ipackets); + r["opackets"] = STRING_FROM_UINT32(ifd->ifi_opackets); + r["ibytes"] = STRING_FROM_UINT32(ifd->ifi_ibytes); + r["obytes"] = STRING_FROM_UINT32(ifd->ifi_obytes); + r["ierrors"] = STRING_FROM_UINT32(ifd->ifi_ierrors); + r["oerrors"] = STRING_FROM_UINT32(ifd->ifi_oerrors); + r["last_change"] = STRING_FROM_UINT32(ifd->ifi_lastchange.tv_sec); + results.push_back(r); +} + +QueryData genInterfaceAddresses() { + QueryData results; + + struct ifaddrs *if_addrs, *if_addr; + + if (getifaddrs(&if_addrs) != 0) { + return {}; + } + + for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next) { + if (if_addr->ifa_addr->sa_family == AF_LINK) { + continue; + } + + genAddressesFromAddr(if_addr, results); + } + + freeifaddrs(if_addrs); + return results; +} + +QueryData genInterfaceDetails() { + QueryData results; + + struct ifaddrs *if_addrs, *if_addr; + + if (getifaddrs(&if_addrs) != 0) { + return {}; + } + + for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next) { + if (if_addr->ifa_addr->sa_family != AF_LINK) { + // This interface entry does not describe the link details. + continue; + } + + genDetailsFromAddr(if_addr, results); + } + + freeifaddrs(if_addrs); + return results; +} +} +} diff --git a/osquery/tables/networking/utils.cpp b/osquery/tables/networking/utils.cpp new file mode 100644 index 00000000..d982f858 --- /dev/null +++ b/osquery/tables/networking/utils.cpp @@ -0,0 +1,53 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include + +#include + +#include + +#include "utils.h" + +std::string canonical_ip_address(const struct sockaddr *in) { + char dst[INET6_ADDRSTRLEN]; + memset(dst, 0, sizeof(dst)); + void *in_addr; + + if (in->sa_family == AF_INET) { + in_addr = (void *)&(((struct sockaddr_in *)in)->sin_addr); + } else if (in->sa_family == AF_INET6) { + in_addr = (void *)&(((struct sockaddr_in6 *)in)->sin6_addr); + } else { + return ""; + } + + inet_ntop(in->sa_family, in_addr, dst, sizeof(dst)); + std::string address(dst); + boost::trim(address); + + return address; +} + +std::string canonical_mac_address(const struct ifaddrs *addr) { + std::stringstream mac; + struct sockaddr_dl* sdl; + + if (addr->ifa_addr == NULL) { + // No link or MAC exists. + return ""; + } + + sdl = (struct sockaddr_dl *)addr->ifa_addr; + if (sdl->sdl_alen != 6) { + // Do not support MAC address that are not 6 bytes... + return ""; + } + + for (size_t i = 0; i < sdl->sdl_alen; i++) { + mac << std::hex << std::setfill('0') << std::setw(2); + // Prevent char sign extension. + mac << (int)((uint8_t)sdl->sdl_data[i + sdl->sdl_nlen]) << ":"; + } + return mac.str(); +} diff --git a/osquery/tables/networking/utils.h b/osquery/tables/networking/utils.h new file mode 100644 index 00000000..72b06559 --- /dev/null +++ b/osquery/tables/networking/utils.h @@ -0,0 +1,15 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#ifndef OSQUERY_TABLES_NETWORKING_H +#define OSQUERY_TABLES_NETWORKING_H + +#include + +#include +#include + +// Return a string representation for an IPv4/IPv6 struct. +std::string canonical_ip_address(const struct sockaddr*); +std::string canonical_mac_address(const struct ifaddrs *addr); + +#endif /* OSQUERY_TABLES_NETWORKING_H */ diff --git a/osquery/tables/specs/darwin/interface_addresses.table b/osquery/tables/specs/darwin/interface_addresses.table new file mode 100644 index 00000000..596f9a62 --- /dev/null +++ b/osquery/tables/specs/darwin/interface_addresses.table @@ -0,0 +1,9 @@ +table_name("interface_addresses") +schema([ + Column(name="interface", type="std::string"), + Column(name="address", type="std::string"), + Column(name="mask", type="std::string"), + Column(name="broadcast", type="std::string"), + Column(name="point_to_point", type="std::string"), +]) +implementation("osquery/tables/networking/interfaces@genInterfaceAddresses") diff --git a/osquery/tables/specs/darwin/interface_details.table b/osquery/tables/specs/darwin/interface_details.table new file mode 100644 index 00000000..b1363c2f --- /dev/null +++ b/osquery/tables/specs/darwin/interface_details.table @@ -0,0 +1,16 @@ +table_name("interface_details") +schema([ + Column(name="interface", type="std::string"), + Column(name="mac", type="std::string"), + Column(name="type", type="int"), + Column(name="mtu", type="std::string"), + Column(name="metric", type="std::string"), + Column(name="ipackets", type="std::string"), + Column(name="opackets", type="std::string"), + Column(name="ibytes", type="std::string"), + Column(name="obytes", type="std::string"), + Column(name="ierrors", type="std::string"), + Column(name="oerrors", type="std::string"), + Column(name="last_change", type="std::string"), +]) +implementation("osquery/tables/networking/interfaces@genInterfaceDetails")