From 05b7b80891547c91813a189c2b29025e08c34910 Mon Sep 17 00:00:00 2001 From: ryanheffernan Date: Tue, 23 May 2017 14:58:11 -0700 Subject: [PATCH] Refactor Windows interface_addresses table to use win32 API and report accurate netmasks. (#3297) --- .../tables/networking/windows/interfaces.cpp | 123 ++++++++++++++---- osquery/tables/system/windows/services.cpp | 15 ++- specs/interface_addresses.table | 1 + 3 files changed, 109 insertions(+), 30 deletions(-) diff --git a/osquery/tables/networking/windows/interfaces.cpp b/osquery/tables/networking/windows/interfaces.cpp index da102d5c..284eacf1 100644 --- a/osquery/tables/networking/windows/interfaces.cpp +++ b/osquery/tables/networking/windows/interfaces.cpp @@ -10,6 +10,12 @@ #include +// clang-format off +#include +#include +#include +// clang-format on + #include #include @@ -21,6 +27,9 @@ namespace osquery { namespace tables { +auto kMaxBufferAllocRetries = 3; +auto kWorkingBufferSize = 15000; + QueryData genInterfaceDetails(QueryContext& context) { QueryData results_data; WmiRequest request("SELECT * FROM Win32_NetworkAdapter"); @@ -80,32 +89,98 @@ QueryData genInterfaceDetails(QueryContext& context) { } QueryData genInterfaceAddresses(QueryContext& context) { - QueryData results_data; - WmiRequest request( - "SELECT * FROM win32_networkadapterconfiguration where IPEnabled=TRUE"); - if (request.getStatus().ok()) { - std::vector& results = request.results(); - for (const auto& result : results) { - Row r; - long lPlaceHolder; - std::vector vPlaceHolderIps; - std::vector vPlaceHolderSubnets; + QueryData results; + DWORD buffSize = kWorkingBufferSize; + auto alloc_attempts = 0; + size_t alloc_result; + const auto addrFamily = AF_UNSPEC; + const auto addrFlags = + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST; + const auto freeMem = [](auto ptr) { free(ptr); }; + std::unique_ptr adapters(nullptr, + freeMem); - result.GetLong("InterfaceIndex", lPlaceHolder); - r["interface"] = SQL_TEXT(lPlaceHolder); - result.GetVectorOfStrings("IPAddress", vPlaceHolderIps); - result.GetVectorOfStrings("IPSubnet", vPlaceHolderSubnets); - for (size_t i = 0; i < vPlaceHolderIps.size(); i++) { - r["address"] = SQL_TEXT(vPlaceHolderIps.at(i)); - if (vPlaceHolderSubnets.size() > i) { - r["mask"] = SQL_TEXT(vPlaceHolderSubnets.at(i)); - } - results_data.push_back(r); - } + // Buffer size can change between the query and malloc (if adapters are + // added/removed), so shenanigans are required + do { + adapters.reset(static_cast(malloc(buffSize))); + if (adapters == nullptr) { + return results; } + alloc_result = GetAdaptersAddresses( + addrFamily, addrFlags, nullptr, adapters.get(), &buffSize); + alloc_attempts++; + } while (alloc_result == ERROR_BUFFER_OVERFLOW && + alloc_attempts < kMaxBufferAllocRetries); + if (alloc_result != NO_ERROR) { + return results; } - return results_data; + const IP_ADAPTER_ADDRESSES* currAdapter = adapters.get(); + while (currAdapter != nullptr) { + std::wstring wsAdapterName = std::wstring(currAdapter->FriendlyName); + std::string adapterName = + std::string(wsAdapterName.begin(), wsAdapterName.end()); + + const IP_ADAPTER_UNICAST_ADDRESS* ipaddr = currAdapter->FirstUnicastAddress; + while (ipaddr != nullptr) { + Row r; + r["interface"] = adapterName; + + switch (ipaddr->SuffixOrigin) { + case IpSuffixOriginManual: + r["type"] = "manual"; + break; + case IpSuffixOriginDhcp: + r["type"] = "dhcp"; + break; + case IpSuffixOriginLinkLayerAddress: + case IpSuffixOriginRandom: + r["type"] = "auto"; + break; + default: + r["type"] = "unknown"; + } + + if (ipaddr->Address.lpSockaddr->sa_family == AF_INET) { + ULONG mask; + ConvertLengthToIpv4Mask(ipaddr->OnLinkPrefixLength, &mask); + in_addr maskAddr; + maskAddr.s_addr = mask; + + char addrBuff[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, &maskAddr, addrBuff, INET_ADDRSTRLEN); + r["mask"] = addrBuff; + + inet_ntop(AF_INET, + &reinterpret_cast(ipaddr->Address.lpSockaddr) + ->sin_addr, + addrBuff, + INET_ADDRSTRLEN); + r["address"] = addrBuff; + } else if (ipaddr->Address.lpSockaddr->sa_family == AF_INET6) { + in6_addr netmask; + memset(&netmask, 0x0, sizeof(netmask)); + for (long i = ipaddr->OnLinkPrefixLength, j = 0; i > 0; i -= 8, ++j) + netmask.s6_addr[j] = i >= 8 ? 0xff : (ULONG)((0xffU << (8 - i))); + + char addrBuff[INET6_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET6, &netmask, addrBuff, INET6_ADDRSTRLEN); + r["mask"] = addrBuff; + + inet_ntop(AF_INET6, + &reinterpret_cast(ipaddr->Address.lpSockaddr) + ->sin6_addr, + addrBuff, + INET6_ADDRSTRLEN); + r["address"] = addrBuff; + } + results.emplace_back(r); + ipaddr = ipaddr->Next; + } + currAdapter = currAdapter->Next; + } + return results; } -} -} \ No newline at end of file +} // namespace tables +} // namespace osquery diff --git a/osquery/tables/system/windows/services.cpp b/osquery/tables/system/windows/services.cpp index d94b39ed..e10c8c78 100644 --- a/osquery/tables/system/windows/services.cpp +++ b/osquery/tables/system/windows/services.cpp @@ -45,15 +45,13 @@ const std::map kServiceType = { auto closeServiceHandle = [](SC_HANDLE sch) { CloseServiceHandle(sch); }; using svc_handle_t = std::unique_ptr; -auto freeMem = [](auto ptr) { free(ptr); }; -using svc_descr_t = std::unique_ptr; -using svc_query_t = std::unique_ptr; -using enum_svc_status_t = - std::unique_ptr; - static inline Status getService(const SC_HANDLE& scmHandle, const ENUM_SERVICE_STATUS_PROCESS& svc, QueryData& results) { + auto freeMem = [](auto ptr) { free(ptr); }; + using svc_descr_t = std::unique_ptr; + using svc_query_t = std::unique_ptr; + Row r; svc_handle_t svcHandle( OpenService(scmHandle, svc.lpServiceName, SERVICE_QUERY_CONFIG), @@ -139,6 +137,11 @@ static inline Status getService(const SC_HANDLE& scmHandle, } static inline Status getServices(QueryData& results) { + auto freeMem = [](auto ptr) { free(ptr); }; + using svc_descr_t = std::unique_ptr; + using enum_svc_status_t = + std::unique_ptr; + svc_handle_t scmHandle(OpenSCManager(nullptr, nullptr, GENERIC_READ), closeServiceHandle); if (scmHandle == nullptr) { diff --git a/specs/interface_addresses.table b/specs/interface_addresses.table index 4ba69d65..0598c88a 100644 --- a/specs/interface_addresses.table +++ b/specs/interface_addresses.table @@ -6,6 +6,7 @@ schema([ Column("mask", TEXT, "Interface netmask"), Column("broadcast", TEXT, "Broadcast address for the interface"), Column("point_to_point", TEXT, "PtP address for the interface"), + Column("type", TEXT, "Type of address. One of dhcp, manual, auto, other") ]) attributes(cacheable=True) implementation("interfaces@genInterfaceAddresses")