You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1339 lines
36 KiB
1339 lines
36 KiB
// Copyright (c) 2001 Microsoft Corporation
|
|
//
|
|
// File: NetworkInterface.cpp
|
|
//
|
|
// Synopsis: Defines a NetworkInterface
|
|
// This object has the knowledge of an
|
|
// IP enabled network connection including
|
|
// IP address, DHCP information, etc.
|
|
//
|
|
// History: 03/01/2001 JeffJon Created
|
|
|
|
#include "pch.h"
|
|
|
|
#include "NetworkInterface.h"
|
|
|
|
#include <iphlpstk.h> // SetIpForwardEntryToStack
|
|
#include <IPIfCons.h> // Adapter type info
|
|
#include <raserror.h> // RAS error codes
|
|
|
|
#define MPR50 1 // Needed in order to include routprot.h
|
|
#include <routprot.h> // Router protocols
|
|
|
|
#define CYS_WMIPROP_IPADDRESS L"IPAddress"
|
|
#define CYS_WMIPROP_IPSUBNET L"IPSubnet"
|
|
#define CYS_WMIPROP_DHCPENABLED L"DHCPEnabled"
|
|
#define CYS_WMIPROP_DESCRIPTION L"Description"
|
|
#define CYS_WMIPROP_DNSSERVERS L"DNSServerSearchOrder"
|
|
#define CYS_WMIPROP_INDEX L"Index"
|
|
|
|
// An array of strings to ease the logging of the adapter type
|
|
|
|
static PCWSTR adapterTypes[] =
|
|
{
|
|
L"IF_TYPE_OTHER", // 1 None of the below
|
|
L"IF_TYPE_REGULAR_1822", // 2
|
|
L"IF_TYPE_HDH_1822", // 3
|
|
L"IF_TYPE_DDN_X25", // 4
|
|
L"IF_TYPE_RFC877_X25", // 5
|
|
L"IF_TYPE_ETHERNET_CSMACD", // 6
|
|
L"IF_TYPE_IS088023_CSMACD", // 7
|
|
L"IF_TYPE_ISO88024_TOKENBUS", // 8
|
|
L"IF_TYPE_ISO88025_TOKENRING", // 9
|
|
L"IF_TYPE_ISO88026_MAN", // 10
|
|
L"IF_TYPE_STARLAN", // 11
|
|
L"IF_TYPE_PROTEON_10MBIT", // 12
|
|
L"IF_TYPE_PROTEON_80MBIT", // 13
|
|
L"IF_TYPE_HYPERCHANNEL", // 14
|
|
L"IF_TYPE_FDDI", // 15
|
|
L"IF_TYPE_LAP_B", // 16
|
|
L"IF_TYPE_SDLC", // 17
|
|
L"IF_TYPE_DS1", // 18 DS1-MIB
|
|
L"IF_TYPE_E1", // 19 Obsolete; see DS1-MIB
|
|
L"IF_TYPE_BASIC_ISDN", // 20
|
|
L"IF_TYPE_PRIMARY_ISDN", // 21
|
|
L"IF_TYPE_PROP_POINT2POINT_SERIAL", // 22 proprietary serial
|
|
L"IF_TYPE_PPP", // 23
|
|
L"IF_TYPE_SOFTWARE_LOOPBACK", // 24
|
|
L"IF_TYPE_EON", // 25 CLNP over IP
|
|
L"IF_TYPE_ETHERNET_3MBIT", // 26
|
|
L"IF_TYPE_NSIP", // 27 XNS over IP
|
|
L"IF_TYPE_SLIP", // 28 Generic Slip
|
|
L"IF_TYPE_ULTRA", // 29 ULTRA Technologies
|
|
L"IF_TYPE_DS3", // 30 DS3-MIB
|
|
L"IF_TYPE_SIP", // 31 SMDS, coffee
|
|
L"IF_TYPE_FRAMERELAY", // 32 DTE only
|
|
L"IF_TYPE_RS232", // 33
|
|
L"IF_TYPE_PARA", // 34 Parallel port
|
|
L"IF_TYPE_ARCNET", // 35
|
|
L"IF_TYPE_ARCNET_PLUS", // 36
|
|
L"IF_TYPE_ATM", // 37 ATM cells
|
|
L"IF_TYPE_MIO_X25", // 38
|
|
L"IF_TYPE_SONET", // 39 SONET or SDH
|
|
L"IF_TYPE_X25_PLE", // 40
|
|
L"IF_TYPE_ISO88022_LLC", // 41
|
|
L"IF_TYPE_LOCALTALK", // 42
|
|
L"IF_TYPE_SMDS_DXI", // 43
|
|
L"IF_TYPE_FRAMERELAY_SERVICE", // 44 FRNETSERV-MIB
|
|
L"IF_TYPE_V35", // 45
|
|
L"IF_TYPE_HSSI", // 46
|
|
L"IF_TYPE_HIPPI", // 47
|
|
L"IF_TYPE_MODEM", // 48 Generic Modem
|
|
L"IF_TYPE_AAL5", // 49 AAL5 over ATM
|
|
L"IF_TYPE_SONET_PATH", // 50
|
|
L"IF_TYPE_SONET_VT", // 51
|
|
L"IF_TYPE_SMDS_ICIP", // 52 SMDS InterCarrier Interface
|
|
L"IF_TYPE_PROP_VIRTUAL", // 53 Proprietary virtual/internal
|
|
L"IF_TYPE_PROP_MULTIPLEXOR", // 54 Proprietary multiplexing
|
|
L"IF_TYPE_IEEE80212", // 55 100BaseVG
|
|
L"IF_TYPE_FIBRECHANNEL", // 56
|
|
L"IF_TYPE_HIPPIINTERFACE", // 57
|
|
L"IF_TYPE_FRAMERELAY_INTERCONNECT", // 58 Obsolete, use 32 or 44
|
|
L"IF_TYPE_AFLANE_8023", // 59 ATM Emulated LAN for 802.3
|
|
L"IF_TYPE_AFLANE_8025", // 60 ATM Emulated LAN for 802.5
|
|
L"IF_TYPE_CCTEMUL", // 61 ATM Emulated circuit
|
|
L"IF_TYPE_FASTETHER", // 62 Fast Ethernet (100BaseT)
|
|
L"IF_TYPE_ISDN", // 63 ISDN and X.25
|
|
L"IF_TYPE_V11", // 64 CCITT V.11/X.21
|
|
L"IF_TYPE_V36", // 65 CCITT V.36
|
|
L"IF_TYPE_G703_64K", // 66 CCITT G703 at 64Kbps
|
|
L"IF_TYPE_G703_2MB", // 67 Obsolete; see DS1-MIB
|
|
L"IF_TYPE_QLLC", // 68 SNA QLLC
|
|
L"IF_TYPE_FASTETHER_FX", // 69 Fast Ethernet (100BaseFX)
|
|
L"IF_TYPE_CHANNEL", // 70
|
|
L"IF_TYPE_IEEE80211", // 71 Radio spread spectrum
|
|
L"IF_TYPE_IBM370PARCHAN", // 72 IBM System 360/370 OEMI Channel
|
|
L"IF_TYPE_ESCON", // 73 IBM Enterprise Systems Connection
|
|
L"IF_TYPE_DLSW", // 74 Data Link Switching
|
|
L"IF_TYPE_ISDN_S", // 75 ISDN S/T interface
|
|
L"IF_TYPE_ISDN_U", // 76 ISDN U interface
|
|
L"IF_TYPE_LAP_D", // 77 Link Access Protocol D
|
|
L"IF_TYPE_IPSWITCH", // 78 IP Switching Objects
|
|
L"IF_TYPE_RSRB", // 79 Remote Source Route Bridging
|
|
L"IF_TYPE_ATM_LOGICAL", // 80 ATM Logical Port
|
|
L"IF_TYPE_DS0", // 81 Digital Signal Level 0
|
|
L"IF_TYPE_DS0_BUNDLE", // 82 Group of ds0s on the same ds1
|
|
L"IF_TYPE_BSC", // 83 Bisynchronous Protocol
|
|
L"IF_TYPE_ASYNC", // 84 Asynchronous Protocol
|
|
L"IF_TYPE_CNR", // 85 Combat Net Radio
|
|
L"IF_TYPE_ISO88025R_DTR", // 86 ISO 802.5r DTR
|
|
L"IF_TYPE_EPLRS", // 87 Ext Pos Loc Report Sys
|
|
L"IF_TYPE_ARAP", // 88 Appletalk Remote Access Protocol
|
|
L"IF_TYPE_PROP_CNLS", // 89 Proprietary Connectionless Proto
|
|
L"IF_TYPE_HOSTPAD", // 90 CCITT-ITU X.29 PAD Protocol
|
|
L"IF_TYPE_TERMPAD", // 91 CCITT-ITU X.3 PAD Facility
|
|
L"IF_TYPE_FRAMERELAY_MPI", // 92 Multiproto Interconnect over FR
|
|
L"IF_TYPE_X213", // 93 CCITT-ITU X213
|
|
L"IF_TYPE_ADSL", // 94 Asymmetric Digital Subscrbr Loop
|
|
L"IF_TYPE_RADSL", // 95 Rate-Adapt Digital Subscrbr Loop
|
|
L"IF_TYPE_SDSL", // 96 Symmetric Digital Subscriber Loop
|
|
L"IF_TYPE_VDSL", // 97 Very H-Speed Digital Subscrb Loop
|
|
L"IF_TYPE_ISO88025_CRFPRINT", // 98 ISO 802.5 CRFP
|
|
L"IF_TYPE_MYRINET", // 99 Myricom Myrinet
|
|
L"IF_TYPE_VOICE_EM", // 100 Voice recEive and transMit
|
|
L"IF_TYPE_VOICE_FXO", // 101 Voice Foreign Exchange Office
|
|
L"IF_TYPE_VOICE_FXS", // 102 Voice Foreign Exchange Station
|
|
L"IF_TYPE_VOICE_ENCAP", // 103 Voice encapsulation
|
|
L"IF_TYPE_VOICE_OVERIP", // 104 Voice over IP encapsulation
|
|
L"IF_TYPE_ATM_DXI", // 105 ATM DXI
|
|
L"IF_TYPE_ATM_FUNI", // 106 ATM FUNI
|
|
L"IF_TYPE_ATM_IMA", // 107 ATM IMA
|
|
L"IF_TYPE_PPPMULTILINKBUNDLE", // 108 PPP Multilink Bundle
|
|
L"IF_TYPE_IPOVER_CDLC", // 109 IBM ipOverCdlc
|
|
L"IF_TYPE_IPOVER_CLAW", // 110 IBM Common Link Access to Workstn
|
|
L"IF_TYPE_STACKTOSTACK", // 111 IBM stackToStack
|
|
L"IF_TYPE_VIRTUALIPADDRESS", // 112 IBM VIPA
|
|
L"IF_TYPE_MPC", // 113 IBM multi-proto channel support
|
|
L"IF_TYPE_IPOVER_ATM", // 114 IBM ipOverAtm
|
|
L"IF_TYPE_ISO88025_FIBER", // 115 ISO 802.5j Fiber Token Ring
|
|
L"IF_TYPE_TDLC", // 116 IBM twinaxial data link control
|
|
L"IF_TYPE_GIGABITETHERNET", // 117
|
|
L"IF_TYPE_HDLC", // 118
|
|
L"IF_TYPE_LAP_F", // 119
|
|
L"IF_TYPE_V37", // 120
|
|
L"IF_TYPE_X25_MLP", // 121 Multi-Link Protocol
|
|
L"IF_TYPE_X25_HUNTGROUP", // 122 X.25 Hunt Group
|
|
L"IF_TYPE_TRANSPHDLC", // 123
|
|
L"IF_TYPE_INTERLEAVE", // 124 Interleave channel
|
|
L"IF_TYPE_FAST", // 125 Fast channel
|
|
L"IF_TYPE_IP", // 126 IP (for APPN HPR in IP networks)
|
|
L"IF_TYPE_DOCSCABLE_MACLAYER", // 127 CATV Mac Layer
|
|
L"IF_TYPE_DOCSCABLE_DOWNSTREAM", // 128 CATV Downstream interface
|
|
L"IF_TYPE_DOCSCABLE_UPSTREAM", // 129 CATV Upstream interface
|
|
L"IF_TYPE_A12MPPSWITCH", // 130 Avalon Parallel Processor
|
|
L"IF_TYPE_TUNNEL", // 131 Encapsulation interface
|
|
L"IF_TYPE_COFFEE", // 132 Coffee pot
|
|
L"IF_TYPE_CES", // 133 Circuit Emulation Service
|
|
L"IF_TYPE_ATM_SUBINTERFACE", // 134 ATM Sub Interface
|
|
L"IF_TYPE_L2_VLAN", // 135 Layer 2 Virtual LAN using 802.1Q
|
|
L"IF_TYPE_L3_IPVLAN", // 136 Layer 3 Virtual LAN using IP
|
|
L"IF_TYPE_L3_IPXVLAN", // 137 Layer 3 Virtual LAN using IPX
|
|
L"IF_TYPE_DIGITALPOWERLINE", // 138 IP over Power Lines
|
|
L"IF_TYPE_MEDIAMAILOVERIP", // 139 Multimedia Mail over IP
|
|
L"IF_TYPE_DTM", // 140 Dynamic syncronous Transfer Mode
|
|
L"IF_TYPE_DCN", // 141 Data Communications Network
|
|
L"IF_TYPE_IPFORWARD", // 142 IP Forwarding Interface
|
|
L"IF_TYPE_MSDSL", // 143 Multi-rate Symmetric DSL
|
|
L"IF_TYPE_IEEE1394", // 144 IEEE1394 High Perf Serial Bus
|
|
L"IF_TYPE_RECEIVE_ONLY", // 145 TV adapter type
|
|
};
|
|
|
|
// macro that uses the string table above to log the adapter type
|
|
|
|
#define LOG_ADAPTER_TYPE(type) \
|
|
if (type >= 145 || type <= 0) \
|
|
{ \
|
|
LOG(String::format(L"adapterType = %1", adapterTypes[0])); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LOG(String::format(L"adapterType = %1", adapterTypes[type-1])); \
|
|
}
|
|
|
|
|
|
|
|
NetworkInterface::NetworkInterface()
|
|
: initialized(false),
|
|
dhcpEnabled(false),
|
|
dhcpServerAvailable(false),
|
|
index(0)
|
|
{
|
|
LOG_CTOR(NetworkInterface);
|
|
|
|
}
|
|
|
|
|
|
NetworkInterface::~NetworkInterface()
|
|
{
|
|
LOG_DTOR(NetworkInterface);
|
|
|
|
if (!ipaddresses.empty())
|
|
{
|
|
ipaddresses.clear();
|
|
}
|
|
|
|
if (!subnetMasks.empty())
|
|
{
|
|
subnetMasks.clear();
|
|
}
|
|
}
|
|
|
|
NetworkInterface::NetworkInterface(const NetworkInterface &nic)
|
|
{
|
|
LOG_CTOR2(NetworkInterface, L"Copy constructor");
|
|
|
|
if (this == &nic)
|
|
{
|
|
return;
|
|
}
|
|
|
|
name = nic.name;
|
|
description = nic.description;
|
|
initialized = nic.initialized;
|
|
dhcpEnabled = nic.dhcpEnabled;
|
|
index = nic.index;
|
|
|
|
ipaddressStringList = nic.ipaddressStringList;
|
|
subnetMaskStringList = nic.subnetMaskStringList;
|
|
dnsServerSearchOrder = nic.dnsServerSearchOrder;
|
|
|
|
// Make a copy of the ipaddress array
|
|
|
|
ipaddresses = nic.ipaddresses;
|
|
subnetMasks = nic.subnetMasks;
|
|
}
|
|
|
|
NetworkInterface&
|
|
NetworkInterface::operator=(const NetworkInterface& rhs)
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::operator=);
|
|
|
|
if (this == &rhs)
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
name = rhs.name;
|
|
description = rhs.description;
|
|
initialized = rhs.initialized;
|
|
dhcpEnabled = rhs.dhcpEnabled;
|
|
index = rhs.index;
|
|
|
|
ipaddressStringList = rhs.ipaddressStringList;
|
|
subnetMaskStringList = rhs.subnetMaskStringList;
|
|
dnsServerSearchOrder = rhs.dnsServerSearchOrder;
|
|
|
|
// Make a copy of the ipaddress array
|
|
|
|
ipaddresses = rhs.ipaddresses;
|
|
subnetMasks = rhs.subnetMasks;
|
|
|
|
return *this;
|
|
}
|
|
|
|
HRESULT
|
|
NetworkInterface::Initialize(const IP_ADAPTER_INFO& adapterInfo)
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::Initialize);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
if (initialized)
|
|
{
|
|
ASSERT(!initialized);
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
// Get the name
|
|
|
|
name = adapterInfo.AdapterName;
|
|
LOG(String::format(
|
|
L"name = %1",
|
|
name.c_str()));
|
|
|
|
// the description
|
|
|
|
description = adapterInfo.Description;
|
|
LOG(String::format(
|
|
L"description = %1",
|
|
description.c_str()));
|
|
|
|
|
|
// the type
|
|
|
|
type = adapterInfo.Type;
|
|
LOG_ADAPTER_TYPE(type);
|
|
|
|
// the index
|
|
|
|
index = adapterInfo.Index;
|
|
LOG(String::format(
|
|
L"index = %1!d!",
|
|
index));
|
|
|
|
// Is DHCP enabled?
|
|
|
|
dhcpEnabled = (adapterInfo.DhcpEnabled != 0);
|
|
LOG_BOOL(dhcpEnabled);
|
|
|
|
hr = SetIPList(adapterInfo.IpAddressList);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG(String::format(
|
|
L"Failed to set the IP and subnet mask: hr = 0x%1!x!",
|
|
hr));
|
|
break;
|
|
}
|
|
|
|
// Now retrieve the rest of the info from the registry
|
|
// Note: this has to be done after getting the name from
|
|
// the Adapter Info
|
|
|
|
hr = RetrieveAdapterInfoFromRegistry();
|
|
if (FAILED(hr))
|
|
{
|
|
LOG(String::format(
|
|
L"Failed to retrieve adapter info from registry: hr = 0x%1!x!",
|
|
hr));
|
|
break;
|
|
}
|
|
}
|
|
} while (false);
|
|
|
|
// If we succeeded in retrieving the data we need,
|
|
// mark the object initialized
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
initialized = true;
|
|
}
|
|
|
|
LOG_HRESULT(hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
NetworkInterface::RetrieveAdapterInfoFromRegistry()
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::RetrieveAdapterInfoFromRegistry);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
do
|
|
{
|
|
String keyName = CYS_NETWORK_INTERFACES_KEY;
|
|
keyName += String(name);
|
|
|
|
RegistryKey key;
|
|
hr = key.Open(
|
|
HKEY_LOCAL_MACHINE,
|
|
keyName,
|
|
KEY_READ);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG(String::format(
|
|
L"Failed to read the interfaces regkey: hr = 0x%1!x!",
|
|
hr));
|
|
break;
|
|
}
|
|
|
|
// Read the NameServer key
|
|
|
|
String nameServers;
|
|
|
|
hr = key.GetValue(
|
|
CYS_NETWORK_NAME_SERVERS,
|
|
nameServers);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG(String::format(
|
|
L"nameServers = %1",
|
|
nameServers.c_str()));
|
|
|
|
// Adds the name servers to the dnsServerSearchOrder member
|
|
|
|
nameServers.tokenize(std::back_inserter(dnsServerSearchOrder));
|
|
}
|
|
else
|
|
{
|
|
LOG(String::format(
|
|
L"Failed to read the NameServer regkey: hr = 0x%1!x!",
|
|
hr));
|
|
|
|
// This is not a breaking condition. We still can try the
|
|
// DhcpNameServer key
|
|
}
|
|
|
|
// Read the DhcpNameServer key
|
|
|
|
String dhcpNameServers;
|
|
|
|
hr = key.GetValue(
|
|
CYS_NETWORK_DHCP_NAME_SERVERS,
|
|
dhcpNameServers);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG(String::format(
|
|
L"dhcpNameServers = %1",
|
|
dhcpNameServers.c_str()));
|
|
|
|
// Adds the name servers to the dnsServerSearchOrder member
|
|
|
|
dhcpNameServers.tokenize(std::back_inserter(dnsServerSearchOrder));
|
|
}
|
|
else
|
|
{
|
|
LOG(String::format(
|
|
L"Failed to read the DhcpNameServer regkey: hr = 0x%1!x!",
|
|
hr));
|
|
}
|
|
|
|
// It doesn't matter if we were not able to retrieve the name servers
|
|
// These are just used as suggestions for DNS forwarding.
|
|
|
|
hr = S_OK;
|
|
} while (false);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
NetworkInterface::SetIPList(
|
|
const IP_ADDR_STRING& ipList)
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::SetIPList);
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// if the list already contains some entries, delete them and start over
|
|
|
|
if (!ipaddresses.empty())
|
|
{
|
|
ipaddresses.erase(ipaddresses.begin());
|
|
}
|
|
|
|
if (!subnetMasks.empty())
|
|
{
|
|
subnetMasks.erase(subnetMasks.begin());
|
|
}
|
|
|
|
const IP_ADDR_STRING* current = &ipList;
|
|
while (current)
|
|
{
|
|
// IP Address - convert and add
|
|
|
|
String ipAddress(current->IpAddress.String);
|
|
|
|
DWORD newAddress = StringToIPAddress(ipAddress);
|
|
ASSERT(newAddress != INADDR_NONE);
|
|
|
|
// StringToIPAddress returns an address of 1.2.3.4 as 04030201. The UI
|
|
// controls return the same address as 01020304. So to make
|
|
// things consistent convert to the UI way
|
|
|
|
ipaddresses.push_back(ConvertIPAddressOrder(newAddress));
|
|
|
|
// also add it to the string list
|
|
|
|
ipaddressStringList.push_back(ipAddress);
|
|
|
|
LOG(String::format(
|
|
L"Adding address: %1",
|
|
ipAddress.c_str()));
|
|
|
|
|
|
// Subnet Mask - convert and add
|
|
|
|
String subnetMask(current->IpMask.String);
|
|
|
|
DWORD newMask = StringToIPAddress(subnetMask);
|
|
|
|
// NTBUG#NTRAID-561163-2002/03/19-JeffJon
|
|
// Do not assert the subnet mask is not INADDR_NONE because
|
|
// if there is an RRAS connection then the subnet mask may be
|
|
// 255.255.255.255 which is the same as INADDR_NONE. The appropriate
|
|
// fix would be to use WSAStringToAddress inside StringToIPAddress
|
|
// but that would require rearchitecting all of CYS since IP addresses
|
|
// have a different structure for use to with that API
|
|
// ASSERT(newMask != INADDR_NONE);
|
|
|
|
// StringToIPAddress returns an address of 1.2.3.4 as 04030201. The UI
|
|
// controls return the same address as 01020304. So to make
|
|
// things consistent convert to the UI way
|
|
|
|
subnetMasks.push_back(ConvertIPAddressOrder(newMask));
|
|
|
|
// also add it to the string list
|
|
|
|
subnetMaskStringList.push_back(subnetMask);
|
|
|
|
LOG(String::format(
|
|
L"Adding subnet: %1",
|
|
subnetMask.c_str()));
|
|
|
|
|
|
current = current->Next;
|
|
}
|
|
|
|
LOG_HRESULT(hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DWORD
|
|
NetworkInterface::GetIPAddress(DWORD addressIndex) const
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::GetIPAddress,
|
|
String::format(
|
|
L"%1!d!",
|
|
addressIndex));
|
|
|
|
ASSERT(initialized);
|
|
|
|
DWORD result = 0;
|
|
if (addressIndex < ipaddresses.size())
|
|
{
|
|
result = ipaddresses[addressIndex];
|
|
}
|
|
|
|
LOG(IPAddressToString(result));
|
|
return result;
|
|
}
|
|
|
|
String
|
|
NetworkInterface::GetStringIPAddress(DWORD addressIndex) const
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::GetStringIPAddress,
|
|
String::format(L"%1!d!", addressIndex));
|
|
|
|
ASSERT(addressIndex < ipaddressStringList.size());
|
|
|
|
String result;
|
|
|
|
if (addressIndex < ipaddressStringList.size())
|
|
{
|
|
result = ipaddressStringList[addressIndex];
|
|
}
|
|
|
|
LOG(result);
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
NetworkInterface::GetSubnetMask(DWORD addressIndex) const
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::GetSubnetMask,
|
|
String::format(
|
|
L"%1!d!",
|
|
addressIndex));
|
|
|
|
ASSERT(initialized);
|
|
|
|
DWORD result = 0;
|
|
if (addressIndex < subnetMasks.size())
|
|
{
|
|
result = subnetMasks[addressIndex];
|
|
}
|
|
|
|
LOG(IPAddressToString(result));
|
|
return result;
|
|
}
|
|
|
|
String
|
|
NetworkInterface::GetStringSubnetMask(DWORD addressIndex) const
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::GetStringSubnetMask,
|
|
String::format(L"%1!d!", addressIndex));
|
|
|
|
ASSERT(addressIndex < subnetMaskStringList.size());
|
|
|
|
String result;
|
|
if (addressIndex < subnetMaskStringList.size())
|
|
{
|
|
result = subnetMaskStringList[addressIndex];
|
|
}
|
|
|
|
LOG(result);
|
|
return result;
|
|
}
|
|
|
|
String
|
|
NetworkInterface::GetName() const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::GetName);
|
|
|
|
ASSERT(initialized);
|
|
|
|
LOG(name);
|
|
return name;
|
|
}
|
|
|
|
String
|
|
NetworkInterface::GetFriendlyName(
|
|
const String defaultName) const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::GetFriendlyName);
|
|
|
|
DWORD dwRet = 0;
|
|
HANDLE hMprConfig = 0;
|
|
|
|
static const unsigned friendlyNameLength = 128;
|
|
wchar_t wszFriendlyName[friendlyNameLength];
|
|
ZeroMemory(wszFriendlyName, sizeof(wchar_t) * friendlyNameLength);
|
|
|
|
String result;
|
|
|
|
String guidName = GetName();
|
|
|
|
dwRet = MprConfigServerConnect(0, &hMprConfig);
|
|
if (NO_ERROR == dwRet)
|
|
{
|
|
dwRet =
|
|
MprConfigGetFriendlyName(
|
|
hMprConfig,
|
|
const_cast<wchar_t*>(guidName.c_str()),
|
|
wszFriendlyName,
|
|
sizeof(wchar_t) * friendlyNameLength);
|
|
if (NO_ERROR != dwRet)
|
|
{
|
|
LOG(String::format(
|
|
L"MprConfigGetFriendlyName() failed: error = %1!x!",
|
|
dwRet));
|
|
*wszFriendlyName = 0;
|
|
}
|
|
else
|
|
{
|
|
LOG(String::format(
|
|
L"MprConfigGetFriendlyName() failed: error = 0x%1!x!",
|
|
dwRet));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG(String::format(
|
|
L"MprConfigServerConnect() failed: error = 0x%1!x!",
|
|
dwRet));
|
|
}
|
|
|
|
MprConfigServerDisconnect(hMprConfig);
|
|
|
|
if (!*wszFriendlyName)
|
|
{
|
|
// we failed to get a friendly name, so use the default one
|
|
|
|
result = defaultName;
|
|
}
|
|
else
|
|
{
|
|
result = wszFriendlyName;
|
|
}
|
|
|
|
LOG(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
HRESULT
|
|
NetworkInterface::GetNameAsGUID(GUID& guid) const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::GetNameAsGUID);
|
|
|
|
ASSERT(initialized);
|
|
|
|
LPOLESTR oleString = 0;
|
|
HRESULT hr = name.as_OLESTR(oleString);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ::CLSIDFromString(
|
|
oleString,
|
|
&guid);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
::CoTaskMemFree(oleString);
|
|
}
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
String
|
|
NetworkInterface::GetDescription() const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::GetDescription);
|
|
|
|
ASSERT(initialized);
|
|
|
|
LOG(description);
|
|
return description;
|
|
}
|
|
|
|
UINT
|
|
NetworkInterface::GetType() const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::GetType);
|
|
|
|
UINT result = type;
|
|
LOG_ADAPTER_TYPE(result);
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
NetworkInterface::GetIndex() const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::GetIndex);
|
|
|
|
DWORD result = index;
|
|
LOG(String::format(L"index = %1!d!", result));
|
|
return result;
|
|
}
|
|
|
|
|
|
void
|
|
NetworkInterface::SetIPAddress(DWORD address, String addressString)
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::SetIPAddress,
|
|
addressString);
|
|
|
|
DWORD newIPAddress = ConvertIPAddressOrder(address);
|
|
|
|
LOG(IPAddressToString(newIPAddress));
|
|
|
|
// Clear out the old values
|
|
|
|
if (!ipaddresses.empty())
|
|
{
|
|
ipaddresses.clear();
|
|
}
|
|
|
|
if (!ipaddressStringList.empty())
|
|
{
|
|
ipaddressStringList.clear();
|
|
}
|
|
|
|
// Now add the new values
|
|
|
|
ipaddresses.push_back(newIPAddress);
|
|
ipaddressStringList.push_back(addressString);
|
|
}
|
|
|
|
void
|
|
NetworkInterface::SetSubnetMask(DWORD address, String addressString)
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::SetSubnetMask,
|
|
addressString);
|
|
|
|
LOG(IPAddressToString(address));
|
|
|
|
// Clear out the old values
|
|
|
|
if (!subnetMasks.empty())
|
|
{
|
|
subnetMasks.clear();
|
|
}
|
|
|
|
if (!subnetMaskStringList.empty())
|
|
{
|
|
subnetMaskStringList.clear();
|
|
}
|
|
|
|
// Now add the new values
|
|
|
|
subnetMasks.push_back(address);
|
|
subnetMaskStringList.push_back(addressString);
|
|
}
|
|
|
|
|
|
String
|
|
NetworkInterface::GetDNSServerString(DWORD index)
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::GetDNSServerString,
|
|
String::format(
|
|
L"%1!d!",
|
|
index));
|
|
|
|
String dnsServer;
|
|
|
|
if (dnsServerSearchOrder.empty())
|
|
{
|
|
}
|
|
|
|
if (index < dnsServerSearchOrder.size())
|
|
{
|
|
dnsServer = dnsServerSearchOrder[index];
|
|
}
|
|
else
|
|
{
|
|
LOG(String::format(
|
|
L"Index to large for dnsServerSearchOrder vector: index = %1!d!, size = %2!d!",
|
|
index,
|
|
dnsServerSearchOrder.size()));
|
|
}
|
|
|
|
LOG(dnsServer);
|
|
return dnsServer;
|
|
}
|
|
|
|
void
|
|
NetworkInterface::GetDNSServers(IPAddressList& servers)
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::GetDNSServers);
|
|
|
|
// Note: this will read the values from WMI if they
|
|
// haven't already been retrieved
|
|
|
|
String server = GetDNSServerString(0);
|
|
|
|
if (!dnsServerSearchOrder.empty())
|
|
{
|
|
for (StringVector::iterator itr = dnsServerSearchOrder.begin();
|
|
itr != dnsServerSearchOrder.end();
|
|
++itr)
|
|
{
|
|
server = *itr;
|
|
|
|
if (!server.empty())
|
|
{
|
|
DWORD newAddress = StringToIPAddress(server);
|
|
|
|
if (newAddress != INADDR_NONE)
|
|
{
|
|
// Don't add the current IP address of this server
|
|
|
|
DWORD newInorderAddress = ConvertIPAddressOrder(newAddress);
|
|
if (newInorderAddress != GetIPAddress(0))
|
|
{
|
|
LOG(String::format(
|
|
L"Adding server: %1",
|
|
IPAddressToString(newInorderAddress).c_str()));
|
|
|
|
servers.push_back(newInorderAddress);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
NetworkInterface::IsDHCPAvailable() const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::IsDHCPAvailable);
|
|
|
|
LOG_BOOL(dhcpServerAvailable);
|
|
return dhcpServerAvailable;
|
|
}
|
|
|
|
bool
|
|
NetworkInterface::CanDetectDHCPServer()
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::CanDetectDHCPServer);
|
|
|
|
bool result = false;
|
|
|
|
do
|
|
{
|
|
if (!IsConnected())
|
|
{
|
|
// Since the NIC isn't connected there
|
|
// is no reason to make the check
|
|
|
|
break;
|
|
}
|
|
|
|
ULONG serverIPAddress = 0;
|
|
|
|
DWORD interfaceIPAddress =
|
|
ConvertIPAddressOrder(GetIPAddress(0));
|
|
|
|
// This will perform a DHCP_INFORM to try
|
|
// to detect the DHCP server, if that fails
|
|
// it will attemp a DHCP_DISCOVER to attempt
|
|
// to detect the DHCP server.
|
|
|
|
DWORD error =
|
|
AnyDHCPServerRunning(
|
|
interfaceIPAddress,
|
|
&serverIPAddress);
|
|
|
|
if (error == ERROR_SUCCESS)
|
|
{
|
|
// DHCP server found
|
|
|
|
result = true;
|
|
|
|
LOG(
|
|
String::format(
|
|
L"DHCP server found at the following IP: %1",
|
|
IPAddressToString(
|
|
ConvertIPAddressOrder(serverIPAddress)).c_str()));
|
|
}
|
|
else
|
|
{
|
|
LOG(
|
|
String::format(
|
|
L"DHCP server not found: error = 0x%1!x!",
|
|
error));
|
|
}
|
|
} while (false);
|
|
|
|
dhcpServerAvailable = result;
|
|
LOG_BOOL(result);
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
NetworkInterface::IsConnected() const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::IsConnected);
|
|
|
|
bool result = true;
|
|
|
|
do
|
|
{
|
|
// Convert the name to a GUID
|
|
|
|
GUID guid;
|
|
ZeroMemory(&guid, sizeof(GUID));
|
|
|
|
HRESULT hr = GetNameAsGUID(guid);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG(String::format(
|
|
L"Failed to get name as guid: hr = 0x%1!x!",
|
|
hr));
|
|
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
// Different adapter types require different
|
|
// ways of detecting connection state
|
|
|
|
if (IsModem())
|
|
{
|
|
// We only know about modems if they are connected
|
|
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
result = IsStandardAdapterConnected(guid);
|
|
}
|
|
|
|
} while(false);
|
|
|
|
LOG_BOOL(result);
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
NetworkInterface::IsStandardAdapterConnected(const GUID& guid) const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::IsStandardAdapterConnected);
|
|
|
|
bool result = true;
|
|
|
|
do
|
|
{
|
|
// Now get the status using the GUID
|
|
|
|
NETCON_STATUS status = NCS_CONNECTED;
|
|
HRESULT hr = HrGetPnpDeviceStatus(&guid, &status);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG(String::format(
|
|
L"Failed to get device status: hr = 0x%1!x!",
|
|
hr));
|
|
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
// The status values are defined in netcon.h
|
|
|
|
LOG(String::format(
|
|
L"Device status = %1!d!",
|
|
status));
|
|
|
|
if (status == NCS_DISCONNECTED ||
|
|
status == NCS_DISCONNECTING ||
|
|
status == NCS_HARDWARE_NOT_PRESENT ||
|
|
status == NCS_HARDWARE_DISABLED ||
|
|
status == NCS_HARDWARE_MALFUNCTION ||
|
|
status == NCS_MEDIA_DISCONNECTED)
|
|
{
|
|
result = false;
|
|
}
|
|
} while (false);
|
|
|
|
LOG_BOOL(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool
|
|
NetworkInterface::IsModem() const
|
|
{
|
|
LOG_FUNCTION(NetworkInterface::IsModem);
|
|
|
|
bool isModem = false;
|
|
|
|
switch (GetType())
|
|
{
|
|
case IF_TYPE_PPP:
|
|
isModem = true;
|
|
break;
|
|
|
|
default:
|
|
isModem = false;
|
|
}
|
|
|
|
LOG_BOOL(isModem);
|
|
|
|
return isModem;
|
|
}
|
|
|
|
|
|
DWORD
|
|
NetworkInterface::GetNextAvailableIPAddress(
|
|
DWORD startAddress,
|
|
DWORD subnetMask)
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::GetNextAvailableIPAddress,
|
|
IPAddressToString(startAddress));
|
|
|
|
DWORD result = startAddress;
|
|
DWORD currentAddress = startAddress;
|
|
|
|
bool isIPInUse = false;
|
|
|
|
do
|
|
{
|
|
isIPInUse =
|
|
IsIPAddressInUse(
|
|
currentAddress,
|
|
subnetMask);
|
|
|
|
if (!isIPInUse)
|
|
{
|
|
break;
|
|
}
|
|
|
|
++currentAddress;
|
|
|
|
if ((currentAddress & subnetMask) != (startAddress & subnetMask))
|
|
{
|
|
// REVIEW_JEFFJON : what should the behavior be if there are
|
|
// no available addresses? Is this likely to happen?
|
|
|
|
// Since we couldn't find an available address in this subnet
|
|
// use the start address
|
|
|
|
currentAddress = startAddress;
|
|
break;
|
|
}
|
|
} while (isIPInUse);
|
|
|
|
result = currentAddress;
|
|
|
|
LOG(IPAddressToString(result));
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
bool
|
|
NetworkInterface::IsIPAddressInUse(
|
|
DWORD ipaddress,
|
|
DWORD subnetMask)
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::IsIPAddressInUse,
|
|
IPAddressToString(ipaddress));
|
|
|
|
bool result = false;
|
|
|
|
do
|
|
{
|
|
if (!IsConnected())
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Before calling SendARP we have to set a route
|
|
// on the interface for the subnet we are interested
|
|
// in so that SendARP will work even if the interface
|
|
// IP address is completely different than the IP
|
|
// address we are looking for.
|
|
|
|
SetRoute(
|
|
ipaddress,
|
|
subnetMask);
|
|
|
|
// Use the interface IP address to tell TCP which interface
|
|
// to send the ARP on
|
|
|
|
DWORD interfaceIPAddress = GetIPAddress(0);
|
|
|
|
if (interfaceIPAddress == ipaddress)
|
|
{
|
|
// If the IP address is in use by the NIC then
|
|
// of course it is in use on the network
|
|
|
|
result = true;
|
|
|
|
break;
|
|
}
|
|
|
|
// MSDN doesn't mention whether or not the buffer needs to be
|
|
// there but it appears that SendArp() is now failing if we
|
|
// don't pass it a buffer even though we ignore the macAddress.
|
|
// The size was taken from the example in MSDN.
|
|
|
|
ULONG macAddress[2];
|
|
ULONG macLength = sizeof(macAddress);
|
|
|
|
memset(macAddress, 0xff, macLength);
|
|
|
|
DWORD error =
|
|
SendARP(
|
|
ConvertIPAddressOrder(ipaddress),
|
|
ConvertIPAddressOrder(interfaceIPAddress),
|
|
macAddress,
|
|
&macLength);
|
|
|
|
LOG(
|
|
String::format(
|
|
L"SendARP returned: error = 0x%1!x!",
|
|
error));
|
|
|
|
if (error == NO_ERROR)
|
|
{
|
|
result = true;
|
|
}
|
|
|
|
// Now that we are done with the SendARP
|
|
// remove the route so that the TCP stack
|
|
// reverts to normal behavior
|
|
|
|
RemoveRoute(
|
|
ipaddress,
|
|
subnetMask);
|
|
|
|
} while (false);
|
|
|
|
LOG_BOOL(result);
|
|
|
|
return result;
|
|
}
|
|
|
|
void
|
|
NetworkInterface::SetRoute(
|
|
DWORD ipaddress,
|
|
DWORD subnetMask)
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::SetRoute,
|
|
IPAddressToString(ipaddress));
|
|
|
|
LOG(
|
|
String::format(
|
|
L"subnetMask = %1",
|
|
IPAddressToString(subnetMask).c_str()));
|
|
|
|
MIB_IPFORWARDROW routerTableEntry;
|
|
ZeroMemory(&routerTableEntry, sizeof(MIB_IPFORWARDROW));
|
|
|
|
// Destination
|
|
|
|
routerTableEntry.dwForwardDest =
|
|
ConvertIPAddressOrder(ipaddress) & ConvertIPAddressOrder(subnetMask);
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardDest = %1",
|
|
IPAddressToString(ipaddress & subnetMask).c_str()));
|
|
|
|
// net mask
|
|
|
|
routerTableEntry.dwForwardMask = ConvertIPAddressOrder(subnetMask);
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardMask = %1",
|
|
IPAddressToString(subnetMask).c_str()));
|
|
|
|
// Interface index
|
|
|
|
routerTableEntry.dwForwardIfIndex = GetIndex();
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardIfIndex = %1!d!",
|
|
GetIndex()));
|
|
|
|
// Gateway
|
|
|
|
routerTableEntry.dwForwardNextHop = ConvertIPAddressOrder(GetIPAddress(0));
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardNextHop = %1",
|
|
IPAddressToString(GetIPAddress(0)).c_str()));
|
|
|
|
// Protocol generator (must be PROTO_IP_NETMGMT according to MSDN)
|
|
|
|
routerTableEntry.dwForwardProto = PROTO_IP_NETMGMT;
|
|
|
|
// Taking these from %sdxroot%\net\rras\cm\customactions\cmroute\cmroute.cpp
|
|
// since I can't get the API to succeed without them
|
|
|
|
routerTableEntry.dwForwardType = 3;
|
|
routerTableEntry.dwForwardAge = INFINITE;
|
|
routerTableEntry.dwForwardMetric1 = 1;
|
|
routerTableEntry.dwForwardMetric2 = 0xFFFFFFFF;
|
|
routerTableEntry.dwForwardMetric3 = 0xFFFFFFFF;
|
|
routerTableEntry.dwForwardMetric4 = 0xFFFFFFFF;
|
|
routerTableEntry.dwForwardMetric5 = 0xFFFFFFFF;
|
|
|
|
// Create the table entry
|
|
// NTRAID#NTBUG9-667088-2002/09/25-JeffJon
|
|
// Do not use CreateIpForwardEntry here because if
|
|
// RRAS is running the call will become asynchronous
|
|
// and the route may not be in the table by the time
|
|
// we call SendARP()
|
|
|
|
DWORD error =
|
|
SetIpForwardEntryToStack(&routerTableEntry);
|
|
|
|
if (error != NO_ERROR)
|
|
{
|
|
LOG(
|
|
String::format(
|
|
L"SetIpForwardEntryToStack failed: error = 0x%1!x!",
|
|
error));
|
|
}
|
|
}
|
|
|
|
void
|
|
NetworkInterface::RemoveRoute(
|
|
DWORD ipaddress,
|
|
DWORD subnetMask)
|
|
{
|
|
LOG_FUNCTION2(
|
|
NetworkInterface::RemoveRoute,
|
|
IPAddressToString(ipaddress));
|
|
|
|
LOG(
|
|
String::format(
|
|
L"subnetMask = %1",
|
|
IPAddressToString(subnetMask).c_str()));
|
|
|
|
MIB_IPFORWARDROW routerTableEntry;
|
|
ZeroMemory(&routerTableEntry, sizeof(MIB_IPFORWARDROW));
|
|
|
|
// Destination
|
|
|
|
routerTableEntry.dwForwardDest =
|
|
ConvertIPAddressOrder(ipaddress) & ConvertIPAddressOrder(subnetMask);
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardDest = %1",
|
|
IPAddressToString(ipaddress & subnetMask).c_str()));
|
|
|
|
// net mask
|
|
|
|
routerTableEntry.dwForwardMask = ConvertIPAddressOrder(subnetMask);
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardMask = %1",
|
|
IPAddressToString(subnetMask).c_str()));
|
|
|
|
// Interface index
|
|
|
|
routerTableEntry.dwForwardIfIndex = GetIndex();
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardIfIndex = %1!d!",
|
|
GetIndex()));
|
|
|
|
// Gateway
|
|
|
|
routerTableEntry.dwForwardNextHop = ConvertIPAddressOrder(GetIPAddress(0));
|
|
|
|
LOG(
|
|
String::format(
|
|
L"dwForwardNextHop = %1",
|
|
IPAddressToString(GetIPAddress(0)).c_str()));
|
|
|
|
// Delete the table entry
|
|
|
|
DWORD error =
|
|
DeleteIpForwardEntry(&routerTableEntry);
|
|
|
|
if (error != NO_ERROR)
|
|
{
|
|
LOG(
|
|
String::format(
|
|
L"DeleteIpForwardEntry failed: error = 0x%1!x!",
|
|
error));
|
|
}
|
|
|
|
}
|