diff options
| author | David Lönnhager <david.l@mullvad.net> | 2019-10-24 14:13:13 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2019-10-30 14:58:41 +0100 |
| commit | f3b73543cae5d14fbd2cd321d85e4d22d030e6fc (patch) | |
| tree | 1520f1801e5756ba3dc7f40980626643d645ed2d /windows/winnet | |
| parent | c8264165a9117eff7d03b48123762f38e1766adc (diff) | |
| download | mullvadvpn-f3b73543cae5d14fbd2cd321d85e4d22d030e6fc.tar.xz mullvadvpn-f3b73543cae5d14fbd2cd321d85e4d22d030e6fc.zip | |
Refactor NetMonitor
Diffstat (limited to 'windows/winnet')
| -rw-r--r-- | windows/winnet/src/winnet/netmonitor.cpp | 394 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/netmonitor.h | 65 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/networkadaptermonitor.cpp | 325 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/networkadaptermonitor.h | 126 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/offlinemonitor.cpp | 207 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/offlinemonitor.h | 35 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.cpp | 20 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.h | 5 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.vcxproj | 92 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.vcxproj.filters | 6 |
10 files changed, 797 insertions, 478 deletions
diff --git a/windows/winnet/src/winnet/netmonitor.cpp b/windows/winnet/src/winnet/netmonitor.cpp deleted file mode 100644 index bf6636fcd1..0000000000 --- a/windows/winnet/src/winnet/netmonitor.cpp +++ /dev/null @@ -1,394 +0,0 @@ -#include "stdafx.h" -#include "netmonitor.h" -#include <libcommon/error.h> -#include <libcommon/memory.h> -#include <libcommon/string.h> -#include <sstream> - -namespace -{ - -bool ValidInterfaceType(const MIB_IF_ROW2 &iface) -{ - switch (iface.InterfaceLuid.Info.IfType) - { - case IF_TYPE_SOFTWARE_LOOPBACK: - case IF_TYPE_TUNNEL: - { - return false; - } - } - - // - // (Windows 10, and possibly others.) - // The BT adapter is erronously not marked as representing hardware. - // By filtering on this we currently do not support BT tethering. - // - - if (FALSE == iface.InterfaceAndOperStatusFlags.HardwareInterface - || FALSE != iface.InterfaceAndOperStatusFlags.FilterInterface - || 0 == iface.PhysicalAddressLength - || FALSE != iface.InterfaceAndOperStatusFlags.EndPointInterface) - { - return false; - } - - return true; -} - -} // anonymous namespace - -NetMonitor::NetMonitor -( - std::shared_ptr<common::logging::ILogSink> logSink, - NetMonitor::Notifier notifier, - bool ¤tConnectivity -) - : m_logSink(logSink) - , m_notifier(notifier) - , m_connected(false) - , m_notificationHandle(nullptr) -{ - m_cache = CreateCache(); - updateConnectivity(); - - currentConnectivity = m_connected; - - const auto status = NotifyIpInterfaceChange(AF_UNSPEC, Callback, this, FALSE, &m_notificationHandle); - - THROW_UNLESS(NO_ERROR, status, "Register interface change notification"); - - if (false == m_connected) - { - LogOfflineState(m_logSink); - } -} - -NetMonitor::~NetMonitor() -{ - CancelMibChangeNotify2(m_notificationHandle); -} - -// static -bool NetMonitor::CheckConnectivity(std::shared_ptr<common::logging::ILogSink> logSink) -{ - static bool loggedOffline = false; - - const auto connected = CheckConnectivity(CreateCache()); - - if (connected) - { - loggedOffline = false; - } - else if (false == loggedOffline) - { - LogOfflineState(logSink); - loggedOffline = true; - } - - return connected; -} - -// static -NetMonitor::Cache NetMonitor::CreateCache() -{ - MIB_IF_TABLE2 *table; - - const auto status = GetIfTable2(&table); - - THROW_UNLESS(NO_ERROR, status, "Acquire network interface table"); - - common::memory::ScopeDestructor sd; - - sd += [table]() - { - FreeMibTable(table); - }; - - std::map<uint64_t, CacheEntry> cache; - - for (ULONG i = 0; i < table->NumEntries; ++i) - { - AddCacheEntry(cache, table->Table[i]); - } - - return cache; -} - -// static -void NetMonitor::AddCacheEntry(Cache &cache, const MIB_IF_ROW2 &iface) -{ - CacheEntry e; - - if (ValidInterfaceType(iface)) - { - e.luid = iface.InterfaceLuid.Value; - e.valid = true; - e.connected = - ( - NET_IF_ADMIN_STATUS_UP == iface.AdminStatus - && IfOperStatusUp == iface.OperStatus - && MediaConnectStateConnected == iface.MediaConnectState - ); - } - else - { - e.luid = iface.InterfaceLuid.Value; - e.valid = false; - e.connected = false; - } - - cache.insert(std::make_pair(e.luid, e)); -} - -// static -bool NetMonitor::CheckConnectivity(const Cache &cache) -{ - for (const auto cacheEntryIter : cache) - { - const auto entry = cacheEntryIter.second; - - if (entry.valid && entry.connected) - { - return true; - } - } - - return false; -} - -void NetMonitor::updateConnectivity() -{ - m_connected = NetMonitor::CheckConnectivity(m_cache); -} - -//static -void __stdcall NetMonitor::Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType) -{ - auto nm = reinterpret_cast<NetMonitor *>(context); - - try - { - nm->callback(hint, updateType); - } - catch (const std::exception &err) - { - nm->m_logSink->error(err.what()); - } - catch (...) - { - nm->m_logSink->error("Unspecified error in NetMonitor::Callback()"); - } -} - -void NetMonitor::callback(MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType) -{ - std::scoped_lock<std::mutex> processingLock(m_processingMutex); - - switch (updateType) - { - case MibAddInstance: - { - MIB_IF_ROW2 iface = { 0 }; - iface.InterfaceLuid = hint->InterfaceLuid; - - const auto status = GetIfEntry2(&iface); - - if (NO_ERROR != status) - { - std::stringstream ss; - - ss << "GetIfEntry2() failed for LUID 0x" << std::hex << iface.InterfaceLuid.Value - << " during processing of MibAddInstance, error: 0x" << status; - - throw std::runtime_error(ss.str()); - } - - // - // The reason for removing an existing entry is that enabling - // an interface on the adapter might change the overall properties in the - // "row" which is merely an abstraction over all interfaces. - // - - m_cache.erase(iface.InterfaceLuid.Value); - AddCacheEntry(m_cache, iface); - - break; - } - case MibDeleteInstance: - { - m_cache.erase(hint->InterfaceLuid.Value); - - MIB_IF_ROW2 iface = { 0 }; - iface.InterfaceLuid = hint->InterfaceLuid; - - const auto status = GetIfEntry2(&iface); - - if (NO_ERROR == status) - { - AddCacheEntry(m_cache, iface); - } - - break; - } - case MibParameterNotification: - { - MIB_IF_ROW2 iface = { 0 }; - iface.InterfaceLuid = hint->InterfaceLuid; - - const auto status = GetIfEntry2(&iface); - - if (NO_ERROR != status) - { - // - // Only update the cache if we can look up the interface details. - // This way, if the interface was connected and continues to be so, we don't - // mistakenly switch the status to "offline". - // - - std::stringstream ss; - - ss << "GetIfEntry2() failed for LUID 0x" << std::hex << iface.InterfaceLuid.Value - << " during processing of MibParameterNotification, error: 0x" << status; - - throw std::runtime_error(ss.str()); - } - - m_cache.erase(iface.InterfaceLuid.Value); - AddCacheEntry(m_cache, iface); - - break; - } - } - - const auto previousConnectivity = m_connected; - - updateConnectivity(); - - if (previousConnectivity != m_connected) - { - m_notifier(m_connected); - - if (false == m_connected) - { - LogOfflineState(m_logSink); - } - } -} - -//static -void NetMonitor::LogOfflineState(std::shared_ptr<common::logging::ILogSink> logSink) -{ - // - // There is a race condition here because logging is not done using the - // same data set that the online/offline logic processes. - // - // Not much of a problem really, this is temporary logging. - // - - logSink->info("Machine is offline"); - - MIB_IF_TABLE2 *table; - - const auto status = GetIfTable2(&table); - - if (NO_ERROR != status) - { - logSink->error("Failed to acquire list of network interfaces. Aborting detailed logging"); - return; - } - - common::memory::ScopeDestructor sd; - - sd += [table]() - { - FreeMibTable(table); - }; - - logSink->info("Begin detailed listing of network interfaces"); - - for (ULONG i = 0; i < table->NumEntries; ++i) - { - const auto &iface = table->Table[i]; - - // - // Don't flood the log with garbage. - // - const auto blacklist = std::vector<std::wstring> - { - L"WFP Native MAC Layer LightWeight Filter", - L"QoS Packet Scheduler", - L"WFP 802.3 MAC Layer LightWeight Filter", - L"Microsoft Kernel Debug Network Adapter", - L"Software Loopback Interface", - L"Microsoft Teredo Tunneling Adapter", - L"Microsoft IP-HTTPS Platform Adapter", - L"Microsoft 6to4 Adapter", - L"WAN Miniport", - L"WiFi Filter Driver", - L"Microsoft Wi-Fi Direct Virtual Adapter", - }; - - bool blacklisted = false; - - for (const auto &black : blacklist) - { - if (nullptr != wcsstr(iface.Description, black.c_str())) - { - blacklisted = true; - break; - } - } - - if (blacklisted) - { - continue; - } - - std::stringstream ss; - - ss << "Detailed interface logging" << std::endl; - ss << "Interface ordinal " << i << std::endl; - - { - const auto s = std::wstring(L" Alias: ").append(iface.Alias); - ss << common::string::ToAnsi(s) << std::endl; - } - - { - const auto s = std::wstring(L" Description: ").append(iface.Description); - ss << common::string::ToAnsi(s) << std::endl; - } - - ss << " PhysicalAddressLength: " << iface.PhysicalAddressLength << std::endl; - ss << " Type: " << iface.Type << std::endl; - ss << " MediaType: " << iface.MediaType << std::endl; - ss << " PhysicalMediumType: " << iface.PhysicalMediumType << std::endl; - ss << " AccessType: " << iface.AccessType << std::endl; - - // - // Bool cast prevents idiot stream from inserting literal 0/1. - // - - ss << " InterfaceAndOperStatusFlags.HardwareInterface: " << (bool)iface.InterfaceAndOperStatusFlags.HardwareInterface << std::endl; - ss << " InterfaceAndOperStatusFlags.FilterInterface: " << (bool)iface.InterfaceAndOperStatusFlags.FilterInterface << std::endl; - ss << " InterfaceAndOperStatusFlags.ConnectorPresent: " << (bool)iface.InterfaceAndOperStatusFlags.ConnectorPresent << std::endl; - ss << " InterfaceAndOperStatusFlags.NotAuthenticated: " << (bool)iface.InterfaceAndOperStatusFlags.NotAuthenticated << std::endl; - ss << " InterfaceAndOperStatusFlags.NotMediaConnected: " << (bool)iface.InterfaceAndOperStatusFlags.NotMediaConnected << std::endl; - ss << " InterfaceAndOperStatusFlags.Paused: " << (bool)iface.InterfaceAndOperStatusFlags.Paused << std::endl; - ss << " InterfaceAndOperStatusFlags.LowPower: " << (bool)iface.InterfaceAndOperStatusFlags.LowPower << std::endl; - ss << " InterfaceAndOperStatusFlags.EndPointInterface: " << (bool)iface.InterfaceAndOperStatusFlags.EndPointInterface << std::endl; - - ss << " OperStatus: " << iface.OperStatus << std::endl; - ss << " AdminStatus: " << iface.AdminStatus << std::endl; - ss << " MediaConnectState: " << iface.MediaConnectState << std::endl; - ss << " TransmitLinkSpeed: " << iface.TransmitLinkSpeed << std::endl; - - ss << " ReceiveLinkSpeed: " << iface.ReceiveLinkSpeed << std::endl; - ss << " InUcastPkts:" << iface.InUcastPkts; - - logSink->info(ss.str().c_str()); - } - - logSink->info("End detailed listing of network interfaces"); -} diff --git a/windows/winnet/src/winnet/netmonitor.h b/windows/winnet/src/winnet/netmonitor.h deleted file mode 100644 index a3e0a28281..0000000000 --- a/windows/winnet/src/winnet/netmonitor.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include <libcommon/logging/ilogsink.h> -#include <memory> -#include <map> -#include <string> -#include <cstdint> -#include <mutex> -#include <functional> -#include <winsock2.h> -#include <ws2ipdef.h> -#include <iphlpapi.h> -#include <windows.h> - -class NetMonitor -{ -public: - - // - // Connectivity changed. - // true = connected, false = disconnected. - // - using Notifier = std::function<void(bool)>; - - NetMonitor(std::shared_ptr<common::logging::ILogSink> logSink, Notifier notifier, bool ¤tConnectivity); - ~NetMonitor(); - - static bool CheckConnectivity(std::shared_ptr<common::logging::ILogSink> logSink); - -private: - - std::shared_ptr<common::logging::ILogSink> m_logSink; - Notifier m_notifier; - - struct CacheEntry - { - // Unique interface identifier. - uint64_t luid; - - // Whether this is a physical adapter or not. - bool valid; - - // Last known state. - bool connected; - }; - - using Cache = std::map<uint64_t, CacheEntry>; - - std::mutex m_processingMutex; - Cache m_cache; - bool m_connected; - - HANDLE m_notificationHandle; - - static Cache CreateCache(); - static void AddCacheEntry(Cache &cache, const MIB_IF_ROW2 &iface); - static bool CheckConnectivity(const Cache &cache); - - void updateConnectivity(); - - static void __stdcall Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType); - void callback(MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType); - - static void LogOfflineState(std::shared_ptr<common::logging::ILogSink> logSink); -}; diff --git a/windows/winnet/src/winnet/networkadaptermonitor.cpp b/windows/winnet/src/winnet/networkadaptermonitor.cpp new file mode 100644 index 0000000000..8a03012f4a --- /dev/null +++ b/windows/winnet/src/winnet/networkadaptermonitor.cpp @@ -0,0 +1,325 @@ +#include "stdafx.h" + +#include "networkadaptermonitor.h" +#include <libcommon/memory.h> +#include <sstream> +#include <cstring> + +using namespace std::placeholders; + + +NetworkAdapterMonitor::NetworkAdapterMonitor( + std::shared_ptr<common::logging::ILogSink> logSink, + UpdateSinkType updateSink, + FilterType filter, + std::shared_ptr<IDataProvider> dataProvider +) + : m_logSink(logSink) + , m_notificationHandle(nullptr) + , m_updateSink(updateSink) + , m_filter(filter) + , m_dataProvider(dataProvider) +{ + // + // Initialize adapters + // + + MIB_IF_TABLE2 *table; + + const auto status = m_dataProvider->getIfTable2(&table); + + THROW_UNLESS(NO_ERROR, status, "Acquire network interface table"); + + common::memory::ScopeDestructor sd; + + sd += [this, table]() + { + m_dataProvider->freeMibTable(table); + }; + + for (ULONG i = 0; i < table->NumEntries; ++i) + { + m_adapters[table->Table[i].InterfaceLuid.Value] = table->Table[i]; + + if (filter(table->Table[i])) + { + m_filteredAdapters.push_back(table->Table[i]); + } + } + + // + // Send initial notification + // + + if (!m_filteredAdapters.empty()) + { + m_updateSink(m_filteredAdapters, nullptr, UpdateType::Add); + } + + // + // Listen to adapter events + // + + const auto statusCb = m_dataProvider->notifyIpInterfaceChange( + AF_UNSPEC, + Callback, + this, + FALSE, + &m_notificationHandle + ); + + THROW_UNLESS(NO_ERROR, statusCb, "Register interface change notification"); +} + +NetworkAdapterMonitor::NetworkAdapterMonitor( + std::shared_ptr<common::logging::ILogSink> logSink + , UpdateSinkType updateSink + , FilterType filter +) : NetworkAdapterMonitor(logSink, updateSink, filter, std::make_shared<SystemDataProvider>()) +{ +} + +NetworkAdapterMonitor::~NetworkAdapterMonitor() +{ + if (nullptr != m_notificationHandle) + { + m_dataProvider->cancelMibChangeNotify2(m_notificationHandle); + m_notificationHandle = nullptr; + } +} + +bool NetworkAdapterMonitor::hasIPv4Interface(NET_LUID luid) const +{ + MIB_IPINTERFACE_ROW iprow = { 0 }; + iprow.InterfaceLuid = luid; + iprow.Family = AF_INET; + + const auto status = m_dataProvider->getIpInterfaceEntry(&iprow); + + if (NO_ERROR == status) + { + return true; + } + else if (ERROR_NOT_FOUND != status) + { + common::error::Throw("Resolve IPv4 interface", status); + } + return false; +} + +bool NetworkAdapterMonitor::hasIPv6Interface(NET_LUID luid) const +{ + MIB_IPINTERFACE_ROW iprow = { 0 }; + iprow.InterfaceLuid = luid; + iprow.Family = AF_INET6; + + const auto status = m_dataProvider->getIpInterfaceEntry(&iprow); + + if (NO_ERROR == status) + { + return true; + } + else if (ERROR_NOT_FOUND != status) + { + common::error::Throw("Resolve IPv6 interface", status); + } + return false; +} + +std::vector<MIB_IF_ROW2>::iterator NetworkAdapterMonitor::findFilteredAdapter(const MIB_IF_ROW2 &adapter) +{ + return std::find_if(m_filteredAdapters.begin(), m_filteredAdapters.end(), [&adapter](const MIB_IF_ROW2 &elem) + { + return elem.InterfaceLuid.Value == adapter.InterfaceLuid.Value; + }); +} + +MIB_IF_ROW2 NetworkAdapterMonitor::getAdapter(NET_LUID luid) const +{ + MIB_IF_ROW2 rowOut; + rowOut.InterfaceLuid = luid; + const auto status = m_dataProvider->getIfEntry2(&rowOut); + + if (NO_ERROR == status) + { + return rowOut; + } + + std::stringstream ss; + + ss << "GetIfEntry2() failed for LUID 0x" << std::hex << rowOut.InterfaceLuid.Value + << " in NetworkAdapterMonitor::getAdapter(), error: 0x" << status; + + throw std::runtime_error(ss.str()); +} + +void NetworkAdapterMonitor::callback(const MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE) +{ + MIB_IF_ROW2 iface = getAdapter(hint->InterfaceLuid); + + bool adapterEnabled = NET_IF_ADMIN_STATUS_UP == iface.AdminStatus + && (hasIPv4Interface(iface.InterfaceLuid) + || hasIPv6Interface(iface.InterfaceLuid)); + + const auto adapterIt = m_adapters.find(hint->InterfaceLuid.Value); + + if (adapterEnabled) + { + // + // Check if the adapter has been added or updated + // + + bool fieldsChanged; + + if (m_adapters.end() == adapterIt) + { + const auto pair = m_adapters.emplace( + iface.InterfaceLuid.Value, + iface + ); + fieldsChanged = true; + } + else + { + // + // Only send an Update event if the fields have changed + // + fieldsChanged = std::memcmp( + &adapterIt->second, + &iface, + sizeof(MIB_IF_ROW2) + ) != 0; + + // update stored adapter + adapterIt->second = iface; + } + + if (m_filter(iface)) + { + // + // Report Add event if this is new + // + if (m_filteredAdapters.end() == findFilteredAdapter(iface)) + { + m_filteredAdapters.push_back(iface); + m_updateSink(m_filteredAdapters, &iface, UpdateType::Add); + } + else if (fieldsChanged) + { + m_updateSink(m_filteredAdapters, &iface, UpdateType::Update); + } + } + else + { + // + // Synthesize a Delete event if we're no longer interested + // in this adapter + // + const auto filteredIt = findFilteredAdapter(iface); + + if (m_filteredAdapters.end() != filteredIt) + { + m_filteredAdapters.erase(filteredIt); + m_updateSink( + m_filteredAdapters, + &iface, + UpdateType::Delete + ); + } + } + } + else + { + if (m_adapters.end() == adapterIt) + { + return; + } + + // + // Remove the adapter + // + + m_adapters.erase(adapterIt); + + const auto filteredIt = findFilteredAdapter(iface); + + if (m_filteredAdapters.end() != filteredIt) + { + m_filteredAdapters.erase(filteredIt); + + if (m_filter(iface)) + { + m_updateSink( + m_filteredAdapters, + &iface, + UpdateType::Delete + ); + } + } + } +} + +//static +void __stdcall NetworkAdapterMonitor::Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType) +{ + auto inst = reinterpret_cast<NetworkAdapterMonitor *>(context); + + try + { + inst->callback(hint, updateType); + } + catch (const std::exception &err) + { + inst->m_logSink->error(err.what()); + } + catch (...) + { + inst->m_logSink->error("Unspecified error in NetworkAdapterMonitor::Callback()"); + } +} + +// +// SystemDataProvider +// + +DWORD NetworkAdapterMonitor::SystemDataProvider::notifyIpInterfaceChange( + ADDRESS_FAMILY Family, + PIPINTERFACE_CHANGE_CALLBACK Callback, + PVOID CallerContext, + BOOLEAN InitialNotification, + HANDLE *NotificationHandle +) +{ + return NotifyIpInterfaceChange( + Family, + Callback, + CallerContext, + InitialNotification, + NotificationHandle + ); +} + +DWORD NetworkAdapterMonitor::SystemDataProvider::cancelMibChangeNotify2(HANDLE NotificationHandle) +{ + return CancelMibChangeNotify2(NotificationHandle); +} + +DWORD NetworkAdapterMonitor::SystemDataProvider::getIfEntry2(PMIB_IF_ROW2 Row) +{ + return GetIfEntry2(Row); +} + +DWORD NetworkAdapterMonitor::SystemDataProvider::getIfTable2(PMIB_IF_TABLE2 *Table) +{ + return GetIfTable2(Table); +} + +DWORD NetworkAdapterMonitor::SystemDataProvider::getIpInterfaceEntry(PMIB_IPINTERFACE_ROW Row) +{ + return GetIpInterfaceEntry(Row); +} + +void NetworkAdapterMonitor::SystemDataProvider::freeMibTable(PVOID Memory) +{ + FreeMibTable(Memory); +} diff --git a/windows/winnet/src/winnet/networkadaptermonitor.h b/windows/winnet/src/winnet/networkadaptermonitor.h new file mode 100644 index 0000000000..fe78bb7e2d --- /dev/null +++ b/windows/winnet/src/winnet/networkadaptermonitor.h @@ -0,0 +1,126 @@ +#pragma once + +#include <libcommon/logging/ilogsink.h> +#include <libcommon/error.h> +#include <map> +#include <winsock2.h> +#include <ws2ipdef.h> +#include <iphlpapi.h> +#include <windows.h> +#include <functional> +#include <vector> + + +class NetworkAdapterMonitor +{ +public: + + enum class UpdateType + { + Add, + Delete, + Update + }; + + using FilterType = std::function<bool(const MIB_IF_ROW2 &adapter)>; + + // + // An event may apply to a specific adapter, or it may apply to all adapters. + // In the latter case, 'adapter' will be set to nullptr. + // + using UpdateSinkType = std::function<void(const std::vector<MIB_IF_ROW2> &adapters, const MIB_IF_ROW2 *adapter, UpdateType updateType)>; + + struct IDataProvider; + class SystemDataProvider; + + NetworkAdapterMonitor( + std::shared_ptr<common::logging::ILogSink> logSink + , UpdateSinkType updateSink + , FilterType filter + , std::shared_ptr<IDataProvider> dataProvider + ); + NetworkAdapterMonitor( + std::shared_ptr<common::logging::ILogSink> logSink + , UpdateSinkType updateSink + , FilterType filter + ); + ~NetworkAdapterMonitor(); + + NetworkAdapterMonitor(const NetworkAdapterMonitor &) = delete; + NetworkAdapterMonitor& operator=(const NetworkAdapterMonitor &) = delete; + NetworkAdapterMonitor(NetworkAdapterMonitor &&) = delete; + NetworkAdapterMonitor& operator=(NetworkAdapterMonitor &&) = delete; + +private: + + std::shared_ptr<common::logging::ILogSink> m_logSink; + UpdateSinkType m_updateSink; + FilterType m_filter; + + std::shared_ptr<IDataProvider> m_dataProvider; + + MIB_IF_ROW2 getAdapter(NET_LUID luid) const; + + bool hasIPv4Interface(NET_LUID luid) const; + bool hasIPv6Interface(NET_LUID luid) const; + + std::map<ULONG64, MIB_IF_ROW2> m_adapters; + std::vector<MIB_IF_ROW2> m_filteredAdapters; + + std::vector<MIB_IF_ROW2>::iterator findFilteredAdapter(const MIB_IF_ROW2 &adapter); + + HANDLE m_notificationHandle; + static void __stdcall Callback(void *context, MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType); + virtual void callback(const MIB_IPINTERFACE_ROW *hint, MIB_NOTIFICATION_TYPE updateType); +}; + + +struct NetworkAdapterMonitor::IDataProvider +{ + virtual ~IDataProvider() = 0 + { + } + + virtual DWORD notifyIpInterfaceChange( + ADDRESS_FAMILY Family, + PIPINTERFACE_CHANGE_CALLBACK Callback, + PVOID CallerContext, + BOOLEAN InitialNotification, + HANDLE *NotificationHandle + ) = 0; + virtual DWORD cancelMibChangeNotify2(HANDLE NotificationHandle) = 0; + + virtual DWORD getIfTable2(PMIB_IF_TABLE2 *Table) = 0; + virtual void freeMibTable(PVOID Memory) = 0; + + virtual DWORD getIfEntry2(PMIB_IF_ROW2 Row) = 0; + virtual DWORD getIpInterfaceEntry(PMIB_IPINTERFACE_ROW Row) = 0; +}; + +class NetworkAdapterMonitor::SystemDataProvider : public IDataProvider +{ +public: + + SystemDataProvider() = default; + virtual ~SystemDataProvider() = default; + + SystemDataProvider(const SystemDataProvider&) = delete; + SystemDataProvider(SystemDataProvider&&) = delete; + SystemDataProvider& operator=(const SystemDataProvider&) = delete; + SystemDataProvider& operator=(const SystemDataProvider&&) = delete; + + DWORD notifyIpInterfaceChange( + ADDRESS_FAMILY Family, + PIPINTERFACE_CHANGE_CALLBACK Callback, + PVOID CallerContext, + BOOLEAN InitialNotification, + HANDLE *NotificationHandle + ) override; + DWORD cancelMibChangeNotify2(HANDLE NotificationHandle) override; + + DWORD getIfTable2(PMIB_IF_TABLE2 *Table) override; + void freeMibTable(PVOID Memory) override; + + DWORD getIfEntry2(PMIB_IF_ROW2 Row) override; + DWORD getIpInterfaceEntry(PMIB_IPINTERFACE_ROW Row) override; +}; diff --git a/windows/winnet/src/winnet/offlinemonitor.cpp b/windows/winnet/src/winnet/offlinemonitor.cpp new file mode 100644 index 0000000000..4f93a01def --- /dev/null +++ b/windows/winnet/src/winnet/offlinemonitor.cpp @@ -0,0 +1,207 @@ +#include "stdafx.h" +#include "offlinemonitor.h" +#include <libcommon/error.h> +#include <libcommon/memory.h> +#include <libcommon/string.h> +#include <sstream> + + +using namespace std::placeholders; // for _1, _2 etc. + +namespace +{ + +bool IsConnectedAdapter(const MIB_IF_ROW2 &iface) +{ + switch (iface.InterfaceLuid.Info.IfType) + { + case IF_TYPE_SOFTWARE_LOOPBACK: + case IF_TYPE_TUNNEL: + { + return false; + } + } + + // + // (Windows 10, and possibly others.) + // The BT adapter is erronously not marked as representing hardware. + // By filtering on this we currently do not support BT tethering. + // + + if (FALSE == iface.InterfaceAndOperStatusFlags.HardwareInterface + || FALSE != iface.InterfaceAndOperStatusFlags.FilterInterface + || 0 == iface.PhysicalAddressLength + || FALSE != iface.InterfaceAndOperStatusFlags.EndPointInterface) + { + return false; + } + + bool connected = ( + IfOperStatusUp == iface.OperStatus + && MediaConnectStateConnected == iface.MediaConnectState + ); + return connected; +} + +} // anonymous namespace + + +OfflineMonitor::OfflineMonitor +( + std::shared_ptr<common::logging::ILogSink> logSink, + Notifier notifier, + std::shared_ptr<NetworkAdapterMonitor::IDataProvider> dataProvider +) + : m_logSink(logSink) + , m_notifier(notifier) + , m_connected(false) + , m_netAdapterMonitor( + m_logSink, + std::bind(&OfflineMonitor::callback, this, _1, _2, _3), + IsConnectedAdapter, + dataProvider + ) +{ +} + + +OfflineMonitor::OfflineMonitor +( + std::shared_ptr<common::logging::ILogSink> logSink, + Notifier notifier +) : OfflineMonitor(logSink, notifier, std::make_shared<NetworkAdapterMonitor::SystemDataProvider>()) +{ +} + + +void OfflineMonitor::callback(const std::vector<MIB_IF_ROW2> &adapters, const MIB_IF_ROW2 *, NetworkAdapterMonitor::UpdateType) +{ + const auto previousConnectivity = m_connected; + m_connected = !adapters.empty(); + + if (previousConnectivity != m_connected) + { + m_notifier(m_connected); + + if (false == m_connected) + { + LogOfflineState(); + } + } +} + +void OfflineMonitor::LogOfflineState() +{ + // + // There is a race condition here because logging is not done using the + // same data set that the online/offline logic processes. + // + // Not much of a problem really, this is temporary logging. + // + + m_logSink->info("Machine is offline"); + + MIB_IF_TABLE2 *table; + + const auto status = GetIfTable2(&table); + + if (NO_ERROR != status) + { + m_logSink->error("Failed to acquire list of network interfaces. Aborting detailed logging"); + return; + } + + common::memory::ScopeDestructor sd; + + sd += [table]() + { + FreeMibTable(table); + }; + + m_logSink->info("Begin detailed listing of network interfaces"); + + for (ULONG i = 0; i < table->NumEntries; ++i) + { + const auto &iface = table->Table[i]; + + // + // Don't flood the log with garbage. + // + const auto blacklist = std::vector<std::wstring> + { + L"WFP Native MAC Layer LightWeight Filter", + L"QoS Packet Scheduler", + L"WFP 802.3 MAC Layer LightWeight Filter", + L"Microsoft Kernel Debug Network Adapter", + L"Software Loopback Interface", + L"Microsoft Teredo Tunneling Adapter", + L"Microsoft IP-HTTPS Platform Adapter", + L"Microsoft 6to4 Adapter", + L"WAN Miniport", + L"WiFi Filter Driver", + L"Microsoft Wi-Fi Direct Virtual Adapter", + }; + + bool blacklisted = false; + + for (const auto &black : blacklist) + { + if (nullptr != wcsstr(iface.Description, black.c_str())) + { + blacklisted = true; + break; + } + } + + if (blacklisted) + { + continue; + } + + std::stringstream ss; + + ss << "Detailed interface logging" << std::endl; + ss << "Interface ordinal " << i << std::endl; + + { + const auto s = std::wstring(L" Alias: ").append(iface.Alias); + ss << common::string::ToAnsi(s) << std::endl; + } + + { + const auto s = std::wstring(L" Description: ").append(iface.Description); + ss << common::string::ToAnsi(s) << std::endl; + } + + ss << " PhysicalAddressLength: " << iface.PhysicalAddressLength << std::endl; + ss << " Type: " << iface.Type << std::endl; + ss << " MediaType: " << iface.MediaType << std::endl; + ss << " PhysicalMediumType: " << iface.PhysicalMediumType << std::endl; + ss << " AccessType: " << iface.AccessType << std::endl; + + // + // Bool cast prevents idiot stream from inserting literal 0/1. + // + + ss << " InterfaceAndOperStatusFlags.HardwareInterface: " << (bool)iface.InterfaceAndOperStatusFlags.HardwareInterface << std::endl; + ss << " InterfaceAndOperStatusFlags.FilterInterface: " << (bool)iface.InterfaceAndOperStatusFlags.FilterInterface << std::endl; + ss << " InterfaceAndOperStatusFlags.ConnectorPresent: " << (bool)iface.InterfaceAndOperStatusFlags.ConnectorPresent << std::endl; + ss << " InterfaceAndOperStatusFlags.NotAuthenticated: " << (bool)iface.InterfaceAndOperStatusFlags.NotAuthenticated << std::endl; + ss << " InterfaceAndOperStatusFlags.NotMediaConnected: " << (bool)iface.InterfaceAndOperStatusFlags.NotMediaConnected << std::endl; + ss << " InterfaceAndOperStatusFlags.Paused: " << (bool)iface.InterfaceAndOperStatusFlags.Paused << std::endl; + ss << " InterfaceAndOperStatusFlags.LowPower: " << (bool)iface.InterfaceAndOperStatusFlags.LowPower << std::endl; + ss << " InterfaceAndOperStatusFlags.EndPointInterface: " << (bool)iface.InterfaceAndOperStatusFlags.EndPointInterface << std::endl; + + ss << " OperStatus: " << iface.OperStatus << std::endl; + ss << " AdminStatus: " << iface.AdminStatus << std::endl; + ss << " MediaConnectState: " << iface.MediaConnectState << std::endl; + ss << " TransmitLinkSpeed: " << iface.TransmitLinkSpeed << std::endl; + + ss << " ReceiveLinkSpeed: " << iface.ReceiveLinkSpeed << std::endl; + ss << " InUcastPkts:" << iface.InUcastPkts; + + m_logSink->info(ss.str().c_str()); + } + + m_logSink->info("End detailed listing of network interfaces"); +} diff --git a/windows/winnet/src/winnet/offlinemonitor.h b/windows/winnet/src/winnet/offlinemonitor.h new file mode 100644 index 0000000000..230fef48d7 --- /dev/null +++ b/windows/winnet/src/winnet/offlinemonitor.h @@ -0,0 +1,35 @@ +#pragma once + +#include <libcommon/logging/ilogsink.h> +#include <mutex> +#include "networkadaptermonitor.h" + +class OfflineMonitor +{ +public: + + // + // Connectivity changed. + // true = connected, false = disconnected. + // + using Notifier = std::function<void(bool)>; + + OfflineMonitor( + std::shared_ptr<common::logging::ILogSink> logSink, + Notifier notifier, + std::shared_ptr<NetworkAdapterMonitor::IDataProvider> dataProvider + ); + OfflineMonitor(std::shared_ptr<common::logging::ILogSink> logSink, Notifier notifier); + +private: + + std::shared_ptr<common::logging::ILogSink> m_logSink; + Notifier m_notifier; + + bool m_connected; + NetworkAdapterMonitor m_netAdapterMonitor; + + void LogOfflineState(); + + void callback(const std::vector<MIB_IF_ROW2> &adapters, const MIB_IF_ROW2 *adapter, NetworkAdapterMonitor::UpdateType type); +}; diff --git a/windows/winnet/src/winnet/winnet.cpp b/windows/winnet/src/winnet/winnet.cpp index 329002d4f9..4b006964a6 100644 --- a/windows/winnet/src/winnet/winnet.cpp +++ b/windows/winnet/src/winnet/winnet.cpp @@ -2,7 +2,7 @@ #include "winnet.h"
#include "NetworkInterfaces.h"
#include "interfaceutils.h"
-#include "netmonitor.h"
+#include "offlinemonitor.h"
#include "../../shared/logsinkadapter.h"
#include <libcommon/error.h>
#include <cstdint>
@@ -12,7 +12,7 @@ namespace
{
-NetMonitor *g_NetMonitor = nullptr;
+OfflineMonitor *g_OfflineMonitor = nullptr;
void UnwindAndLog(MullvadLogSink logSink, void *logSinkContext, const std::exception &err)
{
@@ -152,14 +152,13 @@ WINNET_API WinNet_ActivateConnectivityMonitor(
WinNetConnectivityMonitorCallback callback,
void *callbackContext,
- bool *currentConnectivity,
MullvadLogSink logSink,
void *logSinkContext
)
{
try
{
- if (nullptr != g_NetMonitor)
+ if (nullptr != g_OfflineMonitor)
{
throw std::runtime_error("Cannot activate connectivity monitor twice");
}
@@ -169,16 +168,9 @@ WinNet_ActivateConnectivityMonitor( callback(connected, callbackContext);
};
- bool connected = false;
-
auto logger = std::make_shared<shared::LogSinkAdapter>(logSink, logSinkContext);
- g_NetMonitor = new NetMonitor(logger, forwarder, connected);
-
- if (nullptr != currentConnectivity)
- {
- *currentConnectivity = connected;
- }
+ g_OfflineMonitor = new OfflineMonitor(logger, forwarder);
return true;
}
@@ -202,8 +194,8 @@ WinNet_DeactivateConnectivityMonitor( {
try
{
- delete g_NetMonitor;
- g_NetMonitor = nullptr;
+ delete g_OfflineMonitor;
+ g_OfflineMonitor = nullptr;
}
catch (...)
{
diff --git a/windows/winnet/src/winnet/winnet.h b/windows/winnet/src/winnet/winnet.h index c56faad951..9b1af52e36 100644 --- a/windows/winnet/src/winnet/winnet.h +++ b/windows/winnet/src/winnet/winnet.h @@ -3,11 +3,15 @@ #include "../../shared/logsink.h" #include <stdbool.h> +#ifndef WINNET_STATIC #ifdef WINNET_EXPORTS #define WINNET_LINKAGE __declspec(dllexport) #else #define WINNET_LINKAGE __declspec(dllimport) #endif +#else +#define WINNET_LINKAGE +#endif #define WINNET_API __stdcall @@ -75,7 +79,6 @@ WINNET_API WinNet_ActivateConnectivityMonitor( WinNetConnectivityMonitorCallback callback, void *callbackContext, - bool *currentConnectivity, MullvadLogSink logSink, void *logSinkContext ); diff --git a/windows/winnet/src/winnet/winnet.vcxproj b/windows/winnet/src/winnet/winnet.vcxproj index fd10ec40fd..141c992c4e 100644 --- a/windows/winnet/src/winnet/winnet.vcxproj +++ b/windows/winnet/src/winnet/winnet.vcxproj @@ -1,6 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug Static|Win32"> + <Configuration>Debug Static</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug Static|x64"> + <Configuration>Debug Static</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> <ProjectConfiguration Include="Debug|Win32"> <Configuration>Debug</Configuration> <Platform>Win32</Platform> @@ -19,18 +27,20 @@ </ProjectConfiguration> </ItemGroup> <ItemGroup> + <ClCompile Include="networkadaptermonitor.cpp" /> <ClCompile Include="dllmain.cpp" /> <ClCompile Include="InterfacePair.cpp" /> <ClCompile Include="interfaceutils.cpp" /> - <ClCompile Include="netmonitor.cpp" /> + <ClCompile Include="offlinemonitor.cpp" /> <ClCompile Include="NetworkInterfaces.cpp" /> <ClCompile Include="stdafx.cpp" /> <ClCompile Include="winnet.cpp" /> </ItemGroup> <ItemGroup> + <ClInclude Include="networkadaptermonitor.h" /> <ClInclude Include="InterfacePair.h" /> <ClInclude Include="interfaceutils.h" /> - <ClInclude Include="netmonitor.h" /> + <ClInclude Include="offlinemonitor.h" /> <ClInclude Include="NetworkInterfaces.h" /> <ClInclude Include="stdafx.h" /> <ClInclude Include="targetver.h" /> @@ -56,6 +66,12 @@ <PlatformToolset>v141</PlatformToolset> <CharacterSet>Unicode</CharacterSet> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> @@ -69,6 +85,12 @@ <PlatformToolset>v141</PlatformToolset> <CharacterSet>Unicode</CharacterSet> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'" Label="Configuration"> + <ConfigurationType>StaticLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> @@ -84,12 +106,18 @@ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> @@ -99,11 +127,23 @@ <OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir> <IntDir>$(SolutionDir)\bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)\bin\$(Platform)-Debug\</OutDir> + <IntDir>$(SolutionDir)\bin\temp\$(Platform)-Debug\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-static</TargetName> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <LinkIncremental>true</LinkIncremental> <OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir> <IntDir>$(SolutionDir)\bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(SolutionDir)\bin\$(Platform)-Debug\</OutDir> + <IntDir>$(SolutionDir)\bin\temp\$(Platform)-Debug\$(ProjectName)\</IntDir> + <TargetName>$(ProjectName)-static</TargetName> + </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <LinkIncremental>false</LinkIncremental> <OutDir>$(SolutionDir)\bin\$(Platform)-$(Configuration)\</OutDir> @@ -134,6 +174,30 @@ <AdditionalDependencies>libcommon.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|Win32'"> + <ClCompile> + <PrecompiledHeader>Create</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WINNET_STATIC;WIN32;_DEBUG;WINNET_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + <AdditionalIncludeDirectories>$(ProjectDir)..\..\..\windows-libraries\src\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ModuleDefinitionFile>winnet.def</ModuleDefinitionFile> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <Lib> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-Debug</AdditionalLibraryDirectories> + <AdditionalDependencies>libcommon.lib;Iphlpapi.lib</AdditionalDependencies> + </Lib> + </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> <PrecompiledHeader>Create</PrecompiledHeader> @@ -154,6 +218,30 @@ <ModuleDefinitionFile>winnet.def</ModuleDefinitionFile> </Link> </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Static|x64'"> + <ClCompile> + <PrecompiledHeader>Create</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WINNET_STATIC;_DEBUG;WINNET_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <LanguageStandard>stdcpplatest</LanguageStandard> + <AdditionalIncludeDirectories>$(ProjectDir)..\..\..\windows-libraries\src\%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalDependencies>libcommon.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <ModuleDefinitionFile>winnet.def</ModuleDefinitionFile> + </Link> + <Lib> + <AdditionalDependencies>libcommon.lib;Iphlpapi.lib</AdditionalDependencies> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-Debug</AdditionalLibraryDirectories> + </Lib> + </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <PrecompiledHeader>Create</PrecompiledHeader> diff --git a/windows/winnet/src/winnet/winnet.vcxproj.filters b/windows/winnet/src/winnet/winnet.vcxproj.filters index 3ac5a14717..9a901d3203 100644 --- a/windows/winnet/src/winnet/winnet.vcxproj.filters +++ b/windows/winnet/src/winnet/winnet.vcxproj.filters @@ -7,7 +7,8 @@ <ClCompile Include="NetworkInterfaces.cpp" /> <ClCompile Include="InterfacePair.cpp" /> <ClCompile Include="interfaceutils.cpp" /> - <ClCompile Include="netmonitor.cpp" /> + <ClCompile Include="networkadaptermonitor.cpp" /> + <ClCompile Include="offlinemonitor.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="stdafx.h" /> @@ -16,7 +17,8 @@ <ClInclude Include="NetworkInterfaces.h" /> <ClInclude Include="InterfacePair.h" /> <ClInclude Include="interfaceutils.h" /> - <ClInclude Include="netmonitor.h" /> + <ClInclude Include="networkadaptermonitor.h" /> + <ClInclude Include="offlinemonitor.h" /> </ItemGroup> <ItemGroup> <None Include="winnet.def" /> |
