Leaked source code of windows server 2003
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

  1. // Copyright (c) 2001 Microsoft Corporation
  2. //
  3. // File: NetworkInterface.cpp
  4. //
  5. // Synopsis: Defines a NetworkInterface
  6. // This object has the knowledge of an
  7. // IP enabled network connection including
  8. // IP address, DHCP information, etc.
  9. //
  10. // History: 03/01/2001 JeffJon Created
  11. #include "pch.h"
  12. #include "NetworkInterface.h"
  13. #include <iphlpstk.h> // SetIpForwardEntryToStack
  14. #include <IPIfCons.h> // Adapter type info
  15. #include <raserror.h> // RAS error codes
  16. #define MPR50 1 // Needed in order to include routprot.h
  17. #include <routprot.h> // Router protocols
  18. #define CYS_WMIPROP_IPADDRESS L"IPAddress"
  19. #define CYS_WMIPROP_IPSUBNET L"IPSubnet"
  20. #define CYS_WMIPROP_DHCPENABLED L"DHCPEnabled"
  21. #define CYS_WMIPROP_DESCRIPTION L"Description"
  22. #define CYS_WMIPROP_DNSSERVERS L"DNSServerSearchOrder"
  23. #define CYS_WMIPROP_INDEX L"Index"
  24. // An array of strings to ease the logging of the adapter type
  25. static PCWSTR adapterTypes[] =
  26. {
  27. L"IF_TYPE_OTHER", // 1 None of the below
  28. L"IF_TYPE_REGULAR_1822", // 2
  29. L"IF_TYPE_HDH_1822", // 3
  30. L"IF_TYPE_DDN_X25", // 4
  31. L"IF_TYPE_RFC877_X25", // 5
  32. L"IF_TYPE_ETHERNET_CSMACD", // 6
  33. L"IF_TYPE_IS088023_CSMACD", // 7
  34. L"IF_TYPE_ISO88024_TOKENBUS", // 8
  35. L"IF_TYPE_ISO88025_TOKENRING", // 9
  36. L"IF_TYPE_ISO88026_MAN", // 10
  37. L"IF_TYPE_STARLAN", // 11
  38. L"IF_TYPE_PROTEON_10MBIT", // 12
  39. L"IF_TYPE_PROTEON_80MBIT", // 13
  40. L"IF_TYPE_HYPERCHANNEL", // 14
  41. L"IF_TYPE_FDDI", // 15
  42. L"IF_TYPE_LAP_B", // 16
  43. L"IF_TYPE_SDLC", // 17
  44. L"IF_TYPE_DS1", // 18 DS1-MIB
  45. L"IF_TYPE_E1", // 19 Obsolete; see DS1-MIB
  46. L"IF_TYPE_BASIC_ISDN", // 20
  47. L"IF_TYPE_PRIMARY_ISDN", // 21
  48. L"IF_TYPE_PROP_POINT2POINT_SERIAL", // 22 proprietary serial
  49. L"IF_TYPE_PPP", // 23
  50. L"IF_TYPE_SOFTWARE_LOOPBACK", // 24
  51. L"IF_TYPE_EON", // 25 CLNP over IP
  52. L"IF_TYPE_ETHERNET_3MBIT", // 26
  53. L"IF_TYPE_NSIP", // 27 XNS over IP
  54. L"IF_TYPE_SLIP", // 28 Generic Slip
  55. L"IF_TYPE_ULTRA", // 29 ULTRA Technologies
  56. L"IF_TYPE_DS3", // 30 DS3-MIB
  57. L"IF_TYPE_SIP", // 31 SMDS, coffee
  58. L"IF_TYPE_FRAMERELAY", // 32 DTE only
  59. L"IF_TYPE_RS232", // 33
  60. L"IF_TYPE_PARA", // 34 Parallel port
  61. L"IF_TYPE_ARCNET", // 35
  62. L"IF_TYPE_ARCNET_PLUS", // 36
  63. L"IF_TYPE_ATM", // 37 ATM cells
  64. L"IF_TYPE_MIO_X25", // 38
  65. L"IF_TYPE_SONET", // 39 SONET or SDH
  66. L"IF_TYPE_X25_PLE", // 40
  67. L"IF_TYPE_ISO88022_LLC", // 41
  68. L"IF_TYPE_LOCALTALK", // 42
  69. L"IF_TYPE_SMDS_DXI", // 43
  70. L"IF_TYPE_FRAMERELAY_SERVICE", // 44 FRNETSERV-MIB
  71. L"IF_TYPE_V35", // 45
  72. L"IF_TYPE_HSSI", // 46
  73. L"IF_TYPE_HIPPI", // 47
  74. L"IF_TYPE_MODEM", // 48 Generic Modem
  75. L"IF_TYPE_AAL5", // 49 AAL5 over ATM
  76. L"IF_TYPE_SONET_PATH", // 50
  77. L"IF_TYPE_SONET_VT", // 51
  78. L"IF_TYPE_SMDS_ICIP", // 52 SMDS InterCarrier Interface
  79. L"IF_TYPE_PROP_VIRTUAL", // 53 Proprietary virtual/internal
  80. L"IF_TYPE_PROP_MULTIPLEXOR", // 54 Proprietary multiplexing
  81. L"IF_TYPE_IEEE80212", // 55 100BaseVG
  82. L"IF_TYPE_FIBRECHANNEL", // 56
  83. L"IF_TYPE_HIPPIINTERFACE", // 57
  84. L"IF_TYPE_FRAMERELAY_INTERCONNECT", // 58 Obsolete, use 32 or 44
  85. L"IF_TYPE_AFLANE_8023", // 59 ATM Emulated LAN for 802.3
  86. L"IF_TYPE_AFLANE_8025", // 60 ATM Emulated LAN for 802.5
  87. L"IF_TYPE_CCTEMUL", // 61 ATM Emulated circuit
  88. L"IF_TYPE_FASTETHER", // 62 Fast Ethernet (100BaseT)
  89. L"IF_TYPE_ISDN", // 63 ISDN and X.25
  90. L"IF_TYPE_V11", // 64 CCITT V.11/X.21
  91. L"IF_TYPE_V36", // 65 CCITT V.36
  92. L"IF_TYPE_G703_64K", // 66 CCITT G703 at 64Kbps
  93. L"IF_TYPE_G703_2MB", // 67 Obsolete; see DS1-MIB
  94. L"IF_TYPE_QLLC", // 68 SNA QLLC
  95. L"IF_TYPE_FASTETHER_FX", // 69 Fast Ethernet (100BaseFX)
  96. L"IF_TYPE_CHANNEL", // 70
  97. L"IF_TYPE_IEEE80211", // 71 Radio spread spectrum
  98. L"IF_TYPE_IBM370PARCHAN", // 72 IBM System 360/370 OEMI Channel
  99. L"IF_TYPE_ESCON", // 73 IBM Enterprise Systems Connection
  100. L"IF_TYPE_DLSW", // 74 Data Link Switching
  101. L"IF_TYPE_ISDN_S", // 75 ISDN S/T interface
  102. L"IF_TYPE_ISDN_U", // 76 ISDN U interface
  103. L"IF_TYPE_LAP_D", // 77 Link Access Protocol D
  104. L"IF_TYPE_IPSWITCH", // 78 IP Switching Objects
  105. L"IF_TYPE_RSRB", // 79 Remote Source Route Bridging
  106. L"IF_TYPE_ATM_LOGICAL", // 80 ATM Logical Port
  107. L"IF_TYPE_DS0", // 81 Digital Signal Level 0
  108. L"IF_TYPE_DS0_BUNDLE", // 82 Group of ds0s on the same ds1
  109. L"IF_TYPE_BSC", // 83 Bisynchronous Protocol
  110. L"IF_TYPE_ASYNC", // 84 Asynchronous Protocol
  111. L"IF_TYPE_CNR", // 85 Combat Net Radio
  112. L"IF_TYPE_ISO88025R_DTR", // 86 ISO 802.5r DTR
  113. L"IF_TYPE_EPLRS", // 87 Ext Pos Loc Report Sys
  114. L"IF_TYPE_ARAP", // 88 Appletalk Remote Access Protocol
  115. L"IF_TYPE_PROP_CNLS", // 89 Proprietary Connectionless Proto
  116. L"IF_TYPE_HOSTPAD", // 90 CCITT-ITU X.29 PAD Protocol
  117. L"IF_TYPE_TERMPAD", // 91 CCITT-ITU X.3 PAD Facility
  118. L"IF_TYPE_FRAMERELAY_MPI", // 92 Multiproto Interconnect over FR
  119. L"IF_TYPE_X213", // 93 CCITT-ITU X213
  120. L"IF_TYPE_ADSL", // 94 Asymmetric Digital Subscrbr Loop
  121. L"IF_TYPE_RADSL", // 95 Rate-Adapt Digital Subscrbr Loop
  122. L"IF_TYPE_SDSL", // 96 Symmetric Digital Subscriber Loop
  123. L"IF_TYPE_VDSL", // 97 Very H-Speed Digital Subscrb Loop
  124. L"IF_TYPE_ISO88025_CRFPRINT", // 98 ISO 802.5 CRFP
  125. L"IF_TYPE_MYRINET", // 99 Myricom Myrinet
  126. L"IF_TYPE_VOICE_EM", // 100 Voice recEive and transMit
  127. L"IF_TYPE_VOICE_FXO", // 101 Voice Foreign Exchange Office
  128. L"IF_TYPE_VOICE_FXS", // 102 Voice Foreign Exchange Station
  129. L"IF_TYPE_VOICE_ENCAP", // 103 Voice encapsulation
  130. L"IF_TYPE_VOICE_OVERIP", // 104 Voice over IP encapsulation
  131. L"IF_TYPE_ATM_DXI", // 105 ATM DXI
  132. L"IF_TYPE_ATM_FUNI", // 106 ATM FUNI
  133. L"IF_TYPE_ATM_IMA", // 107 ATM IMA
  134. L"IF_TYPE_PPPMULTILINKBUNDLE", // 108 PPP Multilink Bundle
  135. L"IF_TYPE_IPOVER_CDLC", // 109 IBM ipOverCdlc
  136. L"IF_TYPE_IPOVER_CLAW", // 110 IBM Common Link Access to Workstn
  137. L"IF_TYPE_STACKTOSTACK", // 111 IBM stackToStack
  138. L"IF_TYPE_VIRTUALIPADDRESS", // 112 IBM VIPA
  139. L"IF_TYPE_MPC", // 113 IBM multi-proto channel support
  140. L"IF_TYPE_IPOVER_ATM", // 114 IBM ipOverAtm
  141. L"IF_TYPE_ISO88025_FIBER", // 115 ISO 802.5j Fiber Token Ring
  142. L"IF_TYPE_TDLC", // 116 IBM twinaxial data link control
  143. L"IF_TYPE_GIGABITETHERNET", // 117
  144. L"IF_TYPE_HDLC", // 118
  145. L"IF_TYPE_LAP_F", // 119
  146. L"IF_TYPE_V37", // 120
  147. L"IF_TYPE_X25_MLP", // 121 Multi-Link Protocol
  148. L"IF_TYPE_X25_HUNTGROUP", // 122 X.25 Hunt Group
  149. L"IF_TYPE_TRANSPHDLC", // 123
  150. L"IF_TYPE_INTERLEAVE", // 124 Interleave channel
  151. L"IF_TYPE_FAST", // 125 Fast channel
  152. L"IF_TYPE_IP", // 126 IP (for APPN HPR in IP networks)
  153. L"IF_TYPE_DOCSCABLE_MACLAYER", // 127 CATV Mac Layer
  154. L"IF_TYPE_DOCSCABLE_DOWNSTREAM", // 128 CATV Downstream interface
  155. L"IF_TYPE_DOCSCABLE_UPSTREAM", // 129 CATV Upstream interface
  156. L"IF_TYPE_A12MPPSWITCH", // 130 Avalon Parallel Processor
  157. L"IF_TYPE_TUNNEL", // 131 Encapsulation interface
  158. L"IF_TYPE_COFFEE", // 132 Coffee pot
  159. L"IF_TYPE_CES", // 133 Circuit Emulation Service
  160. L"IF_TYPE_ATM_SUBINTERFACE", // 134 ATM Sub Interface
  161. L"IF_TYPE_L2_VLAN", // 135 Layer 2 Virtual LAN using 802.1Q
  162. L"IF_TYPE_L3_IPVLAN", // 136 Layer 3 Virtual LAN using IP
  163. L"IF_TYPE_L3_IPXVLAN", // 137 Layer 3 Virtual LAN using IPX
  164. L"IF_TYPE_DIGITALPOWERLINE", // 138 IP over Power Lines
  165. L"IF_TYPE_MEDIAMAILOVERIP", // 139 Multimedia Mail over IP
  166. L"IF_TYPE_DTM", // 140 Dynamic syncronous Transfer Mode
  167. L"IF_TYPE_DCN", // 141 Data Communications Network
  168. L"IF_TYPE_IPFORWARD", // 142 IP Forwarding Interface
  169. L"IF_TYPE_MSDSL", // 143 Multi-rate Symmetric DSL
  170. L"IF_TYPE_IEEE1394", // 144 IEEE1394 High Perf Serial Bus
  171. L"IF_TYPE_RECEIVE_ONLY", // 145 TV adapter type
  172. };
  173. // macro that uses the string table above to log the adapter type
  174. #define LOG_ADAPTER_TYPE(type) \
  175. if (type >= 145 || type <= 0) \
  176. { \
  177. LOG(String::format(L"adapterType = %1", adapterTypes[0])); \
  178. } \
  179. else \
  180. { \
  181. LOG(String::format(L"adapterType = %1", adapterTypes[type-1])); \
  182. }
  183. NetworkInterface::NetworkInterface()
  184. : initialized(false),
  185. dhcpEnabled(false),
  186. dhcpServerAvailable(false),
  187. index(0)
  188. {
  189. LOG_CTOR(NetworkInterface);
  190. }
  191. NetworkInterface::~NetworkInterface()
  192. {
  193. LOG_DTOR(NetworkInterface);
  194. if (!ipaddresses.empty())
  195. {
  196. ipaddresses.clear();
  197. }
  198. if (!subnetMasks.empty())
  199. {
  200. subnetMasks.clear();
  201. }
  202. }
  203. NetworkInterface::NetworkInterface(const NetworkInterface &nic)
  204. {
  205. LOG_CTOR2(NetworkInterface, L"Copy constructor");
  206. if (this == &nic)
  207. {
  208. return;
  209. }
  210. name = nic.name;
  211. description = nic.description;
  212. initialized = nic.initialized;
  213. dhcpEnabled = nic.dhcpEnabled;
  214. index = nic.index;
  215. ipaddressStringList = nic.ipaddressStringList;
  216. subnetMaskStringList = nic.subnetMaskStringList;
  217. dnsServerSearchOrder = nic.dnsServerSearchOrder;
  218. // Make a copy of the ipaddress array
  219. ipaddresses = nic.ipaddresses;
  220. subnetMasks = nic.subnetMasks;
  221. }
  222. NetworkInterface&
  223. NetworkInterface::operator=(const NetworkInterface& rhs)
  224. {
  225. LOG_FUNCTION(NetworkInterface::operator=);
  226. if (this == &rhs)
  227. {
  228. return *this;
  229. }
  230. name = rhs.name;
  231. description = rhs.description;
  232. initialized = rhs.initialized;
  233. dhcpEnabled = rhs.dhcpEnabled;
  234. index = rhs.index;
  235. ipaddressStringList = rhs.ipaddressStringList;
  236. subnetMaskStringList = rhs.subnetMaskStringList;
  237. dnsServerSearchOrder = rhs.dnsServerSearchOrder;
  238. // Make a copy of the ipaddress array
  239. ipaddresses = rhs.ipaddresses;
  240. subnetMasks = rhs.subnetMasks;
  241. return *this;
  242. }
  243. HRESULT
  244. NetworkInterface::Initialize(const IP_ADAPTER_INFO& adapterInfo)
  245. {
  246. LOG_FUNCTION(NetworkInterface::Initialize);
  247. HRESULT hr = S_OK;
  248. do
  249. {
  250. if (initialized)
  251. {
  252. ASSERT(!initialized);
  253. hr = E_UNEXPECTED;
  254. }
  255. else
  256. {
  257. // Get the name
  258. name = adapterInfo.AdapterName;
  259. LOG(String::format(
  260. L"name = %1",
  261. name.c_str()));
  262. // the description
  263. description = adapterInfo.Description;
  264. LOG(String::format(
  265. L"description = %1",
  266. description.c_str()));
  267. // the type
  268. type = adapterInfo.Type;
  269. LOG_ADAPTER_TYPE(type);
  270. // the index
  271. index = adapterInfo.Index;
  272. LOG(String::format(
  273. L"index = %1!d!",
  274. index));
  275. // Is DHCP enabled?
  276. dhcpEnabled = (adapterInfo.DhcpEnabled != 0);
  277. LOG_BOOL(dhcpEnabled);
  278. hr = SetIPList(adapterInfo.IpAddressList);
  279. if (FAILED(hr))
  280. {
  281. LOG(String::format(
  282. L"Failed to set the IP and subnet mask: hr = 0x%1!x!",
  283. hr));
  284. break;
  285. }
  286. // Now retrieve the rest of the info from the registry
  287. // Note: this has to be done after getting the name from
  288. // the Adapter Info
  289. hr = RetrieveAdapterInfoFromRegistry();
  290. if (FAILED(hr))
  291. {
  292. LOG(String::format(
  293. L"Failed to retrieve adapter info from registry: hr = 0x%1!x!",
  294. hr));
  295. break;
  296. }
  297. }
  298. } while (false);
  299. // If we succeeded in retrieving the data we need,
  300. // mark the object initialized
  301. if (SUCCEEDED(hr))
  302. {
  303. initialized = true;
  304. }
  305. LOG_HRESULT(hr);
  306. return hr;
  307. }
  308. HRESULT
  309. NetworkInterface::RetrieveAdapterInfoFromRegistry()
  310. {
  311. LOG_FUNCTION(NetworkInterface::RetrieveAdapterInfoFromRegistry);
  312. HRESULT hr = S_OK;
  313. do
  314. {
  315. String keyName = CYS_NETWORK_INTERFACES_KEY;
  316. keyName += String(name);
  317. RegistryKey key;
  318. hr = key.Open(
  319. HKEY_LOCAL_MACHINE,
  320. keyName,
  321. KEY_READ);
  322. if (FAILED(hr))
  323. {
  324. LOG(String::format(
  325. L"Failed to read the interfaces regkey: hr = 0x%1!x!",
  326. hr));
  327. break;
  328. }
  329. // Read the NameServer key
  330. String nameServers;
  331. hr = key.GetValue(
  332. CYS_NETWORK_NAME_SERVERS,
  333. nameServers);
  334. if (SUCCEEDED(hr))
  335. {
  336. LOG(String::format(
  337. L"nameServers = %1",
  338. nameServers.c_str()));
  339. // Adds the name servers to the dnsServerSearchOrder member
  340. nameServers.tokenize(std::back_inserter(dnsServerSearchOrder));
  341. }
  342. else
  343. {
  344. LOG(String::format(
  345. L"Failed to read the NameServer regkey: hr = 0x%1!x!",
  346. hr));
  347. // This is not a breaking condition. We still can try the
  348. // DhcpNameServer key
  349. }
  350. // Read the DhcpNameServer key
  351. String dhcpNameServers;
  352. hr = key.GetValue(
  353. CYS_NETWORK_DHCP_NAME_SERVERS,
  354. dhcpNameServers);
  355. if (SUCCEEDED(hr))
  356. {
  357. LOG(String::format(
  358. L"dhcpNameServers = %1",
  359. dhcpNameServers.c_str()));
  360. // Adds the name servers to the dnsServerSearchOrder member
  361. dhcpNameServers.tokenize(std::back_inserter(dnsServerSearchOrder));
  362. }
  363. else
  364. {
  365. LOG(String::format(
  366. L"Failed to read the DhcpNameServer regkey: hr = 0x%1!x!",
  367. hr));
  368. }
  369. // It doesn't matter if we were not able to retrieve the name servers
  370. // These are just used as suggestions for DNS forwarding.
  371. hr = S_OK;
  372. } while (false);
  373. LOG_HRESULT(hr);
  374. return hr;
  375. }
  376. HRESULT
  377. NetworkInterface::SetIPList(
  378. const IP_ADDR_STRING& ipList)
  379. {
  380. LOG_FUNCTION(NetworkInterface::SetIPList);
  381. HRESULT hr = S_OK;
  382. // if the list already contains some entries, delete them and start over
  383. if (!ipaddresses.empty())
  384. {
  385. ipaddresses.erase(ipaddresses.begin());
  386. }
  387. if (!subnetMasks.empty())
  388. {
  389. subnetMasks.erase(subnetMasks.begin());
  390. }
  391. const IP_ADDR_STRING* current = &ipList;
  392. while (current)
  393. {
  394. // IP Address - convert and add
  395. String ipAddress(current->IpAddress.String);
  396. DWORD newAddress = StringToIPAddress(ipAddress);
  397. ASSERT(newAddress != INADDR_NONE);
  398. // StringToIPAddress returns an address of 1.2.3.4 as 04030201. The UI
  399. // controls return the same address as 01020304. So to make
  400. // things consistent convert to the UI way
  401. ipaddresses.push_back(ConvertIPAddressOrder(newAddress));
  402. // also add it to the string list
  403. ipaddressStringList.push_back(ipAddress);
  404. LOG(String::format(
  405. L"Adding address: %1",
  406. ipAddress.c_str()));
  407. // Subnet Mask - convert and add
  408. String subnetMask(current->IpMask.String);
  409. DWORD newMask = StringToIPAddress(subnetMask);
  410. // NTBUG#NTRAID-561163-2002/03/19-JeffJon
  411. // Do not assert the subnet mask is not INADDR_NONE because
  412. // if there is an RRAS connection then the subnet mask may be
  413. // 255.255.255.255 which is the same as INADDR_NONE. The appropriate
  414. // fix would be to use WSAStringToAddress inside StringToIPAddress
  415. // but that would require rearchitecting all of CYS since IP addresses
  416. // have a different structure for use to with that API
  417. // ASSERT(newMask != INADDR_NONE);
  418. // StringToIPAddress returns an address of 1.2.3.4 as 04030201. The UI
  419. // controls return the same address as 01020304. So to make
  420. // things consistent convert to the UI way
  421. subnetMasks.push_back(ConvertIPAddressOrder(newMask));
  422. // also add it to the string list
  423. subnetMaskStringList.push_back(subnetMask);
  424. LOG(String::format(
  425. L"Adding subnet: %1",
  426. subnetMask.c_str()));
  427. current = current->Next;
  428. }
  429. LOG_HRESULT(hr);
  430. return hr;
  431. }
  432. DWORD
  433. NetworkInterface::GetIPAddress(DWORD addressIndex) const
  434. {
  435. LOG_FUNCTION2(
  436. NetworkInterface::GetIPAddress,
  437. String::format(
  438. L"%1!d!",
  439. addressIndex));
  440. ASSERT(initialized);
  441. DWORD result = 0;
  442. if (addressIndex < ipaddresses.size())
  443. {
  444. result = ipaddresses[addressIndex];
  445. }
  446. LOG(IPAddressToString(result));
  447. return result;
  448. }
  449. String
  450. NetworkInterface::GetStringIPAddress(DWORD addressIndex) const
  451. {
  452. LOG_FUNCTION2(
  453. NetworkInterface::GetStringIPAddress,
  454. String::format(L"%1!d!", addressIndex));
  455. ASSERT(addressIndex < ipaddressStringList.size());
  456. String result;
  457. if (addressIndex < ipaddressStringList.size())
  458. {
  459. result = ipaddressStringList[addressIndex];
  460. }
  461. LOG(result);
  462. return result;
  463. }
  464. DWORD
  465. NetworkInterface::GetSubnetMask(DWORD addressIndex) const
  466. {
  467. LOG_FUNCTION2(
  468. NetworkInterface::GetSubnetMask,
  469. String::format(
  470. L"%1!d!",
  471. addressIndex));
  472. ASSERT(initialized);
  473. DWORD result = 0;
  474. if (addressIndex < subnetMasks.size())
  475. {
  476. result = subnetMasks[addressIndex];
  477. }
  478. LOG(IPAddressToString(result));
  479. return result;
  480. }
  481. String
  482. NetworkInterface::GetStringSubnetMask(DWORD addressIndex) const
  483. {
  484. LOG_FUNCTION2(
  485. NetworkInterface::GetStringSubnetMask,
  486. String::format(L"%1!d!", addressIndex));
  487. ASSERT(addressIndex < subnetMaskStringList.size());
  488. String result;
  489. if (addressIndex < subnetMaskStringList.size())
  490. {
  491. result = subnetMaskStringList[addressIndex];
  492. }
  493. LOG(result);
  494. return result;
  495. }
  496. String
  497. NetworkInterface::GetName() const
  498. {
  499. LOG_FUNCTION(NetworkInterface::GetName);
  500. ASSERT(initialized);
  501. LOG(name);
  502. return name;
  503. }
  504. String
  505. NetworkInterface::GetFriendlyName(
  506. const String defaultName) const
  507. {
  508. LOG_FUNCTION(NetworkInterface::GetFriendlyName);
  509. DWORD dwRet = 0;
  510. HANDLE hMprConfig = 0;
  511. static const unsigned friendlyNameLength = 128;
  512. wchar_t wszFriendlyName[friendlyNameLength];
  513. ZeroMemory(wszFriendlyName, sizeof(wchar_t) * friendlyNameLength);
  514. String result;
  515. String guidName = GetName();
  516. dwRet = MprConfigServerConnect(0, &hMprConfig);
  517. if (NO_ERROR == dwRet)
  518. {
  519. dwRet =
  520. MprConfigGetFriendlyName(
  521. hMprConfig,
  522. const_cast<wchar_t*>(guidName.c_str()),
  523. wszFriendlyName,
  524. sizeof(wchar_t) * friendlyNameLength);
  525. if (NO_ERROR != dwRet)
  526. {
  527. LOG(String::format(
  528. L"MprConfigGetFriendlyName() failed: error = %1!x!",
  529. dwRet));
  530. *wszFriendlyName = 0;
  531. }
  532. else
  533. {
  534. LOG(String::format(
  535. L"MprConfigGetFriendlyName() failed: error = 0x%1!x!",
  536. dwRet));
  537. }
  538. }
  539. else
  540. {
  541. LOG(String::format(
  542. L"MprConfigServerConnect() failed: error = 0x%1!x!",
  543. dwRet));
  544. }
  545. MprConfigServerDisconnect(hMprConfig);
  546. if (!*wszFriendlyName)
  547. {
  548. // we failed to get a friendly name, so use the default one
  549. result = defaultName;
  550. }
  551. else
  552. {
  553. result = wszFriendlyName;
  554. }
  555. LOG(result);
  556. return result;
  557. }
  558. HRESULT
  559. NetworkInterface::GetNameAsGUID(GUID& guid) const
  560. {
  561. LOG_FUNCTION(NetworkInterface::GetNameAsGUID);
  562. ASSERT(initialized);
  563. LPOLESTR oleString = 0;
  564. HRESULT hr = name.as_OLESTR(oleString);
  565. if (SUCCEEDED(hr))
  566. {
  567. hr = ::CLSIDFromString(
  568. oleString,
  569. &guid);
  570. ASSERT(SUCCEEDED(hr));
  571. ::CoTaskMemFree(oleString);
  572. }
  573. LOG_HRESULT(hr);
  574. return hr;
  575. }
  576. String
  577. NetworkInterface::GetDescription() const
  578. {
  579. LOG_FUNCTION(NetworkInterface::GetDescription);
  580. ASSERT(initialized);
  581. LOG(description);
  582. return description;
  583. }
  584. UINT
  585. NetworkInterface::GetType() const
  586. {
  587. LOG_FUNCTION(NetworkInterface::GetType);
  588. UINT result = type;
  589. LOG_ADAPTER_TYPE(result);
  590. return result;
  591. }
  592. DWORD
  593. NetworkInterface::GetIndex() const
  594. {
  595. LOG_FUNCTION(NetworkInterface::GetIndex);
  596. DWORD result = index;
  597. LOG(String::format(L"index = %1!d!", result));
  598. return result;
  599. }
  600. void
  601. NetworkInterface::SetIPAddress(DWORD address, String addressString)
  602. {
  603. LOG_FUNCTION2(
  604. NetworkInterface::SetIPAddress,
  605. addressString);
  606. DWORD newIPAddress = ConvertIPAddressOrder(address);
  607. LOG(IPAddressToString(newIPAddress));
  608. // Clear out the old values
  609. if (!ipaddresses.empty())
  610. {
  611. ipaddresses.clear();
  612. }
  613. if (!ipaddressStringList.empty())
  614. {
  615. ipaddressStringList.clear();
  616. }
  617. // Now add the new values
  618. ipaddresses.push_back(newIPAddress);
  619. ipaddressStringList.push_back(addressString);
  620. }
  621. void
  622. NetworkInterface::SetSubnetMask(DWORD address, String addressString)
  623. {
  624. LOG_FUNCTION2(
  625. NetworkInterface::SetSubnetMask,
  626. addressString);
  627. LOG(IPAddressToString(address));
  628. // Clear out the old values
  629. if (!subnetMasks.empty())
  630. {
  631. subnetMasks.clear();
  632. }
  633. if (!subnetMaskStringList.empty())
  634. {
  635. subnetMaskStringList.clear();
  636. }
  637. // Now add the new values
  638. subnetMasks.push_back(address);
  639. subnetMaskStringList.push_back(addressString);
  640. }
  641. String
  642. NetworkInterface::GetDNSServerString(DWORD index)
  643. {
  644. LOG_FUNCTION2(
  645. NetworkInterface::GetDNSServerString,
  646. String::format(
  647. L"%1!d!",
  648. index));
  649. String dnsServer;
  650. if (dnsServerSearchOrder.empty())
  651. {
  652. }
  653. if (index < dnsServerSearchOrder.size())
  654. {
  655. dnsServer = dnsServerSearchOrder[index];
  656. }
  657. else
  658. {
  659. LOG(String::format(
  660. L"Index to large for dnsServerSearchOrder vector: index = %1!d!, size = %2!d!",
  661. index,
  662. dnsServerSearchOrder.size()));
  663. }
  664. LOG(dnsServer);
  665. return dnsServer;
  666. }
  667. void
  668. NetworkInterface::GetDNSServers(IPAddressList& servers)
  669. {
  670. LOG_FUNCTION(NetworkInterface::GetDNSServers);
  671. // Note: this will read the values from WMI if they
  672. // haven't already been retrieved
  673. String server = GetDNSServerString(0);
  674. if (!dnsServerSearchOrder.empty())
  675. {
  676. for (StringVector::iterator itr = dnsServerSearchOrder.begin();
  677. itr != dnsServerSearchOrder.end();
  678. ++itr)
  679. {
  680. server = *itr;
  681. if (!server.empty())
  682. {
  683. DWORD newAddress = StringToIPAddress(server);
  684. if (newAddress != INADDR_NONE)
  685. {
  686. // Don't add the current IP address of this server
  687. DWORD newInorderAddress = ConvertIPAddressOrder(newAddress);
  688. if (newInorderAddress != GetIPAddress(0))
  689. {
  690. LOG(String::format(
  691. L"Adding server: %1",
  692. IPAddressToString(newInorderAddress).c_str()));
  693. servers.push_back(newInorderAddress);
  694. }
  695. }
  696. }
  697. }
  698. }
  699. }
  700. bool
  701. NetworkInterface::IsDHCPAvailable() const
  702. {
  703. LOG_FUNCTION(NetworkInterface::IsDHCPAvailable);
  704. LOG_BOOL(dhcpServerAvailable);
  705. return dhcpServerAvailable;
  706. }
  707. bool
  708. NetworkInterface::CanDetectDHCPServer()
  709. {
  710. LOG_FUNCTION(NetworkInterface::CanDetectDHCPServer);
  711. bool result = false;
  712. do
  713. {
  714. if (!IsConnected())
  715. {
  716. // Since the NIC isn't connected there
  717. // is no reason to make the check
  718. break;
  719. }
  720. ULONG serverIPAddress = 0;
  721. DWORD interfaceIPAddress =
  722. ConvertIPAddressOrder(GetIPAddress(0));
  723. // This will perform a DHCP_INFORM to try
  724. // to detect the DHCP server, if that fails
  725. // it will attemp a DHCP_DISCOVER to attempt
  726. // to detect the DHCP server.
  727. DWORD error =
  728. AnyDHCPServerRunning(
  729. interfaceIPAddress,
  730. &serverIPAddress);
  731. if (error == ERROR_SUCCESS)
  732. {
  733. // DHCP server found
  734. result = true;
  735. LOG(
  736. String::format(
  737. L"DHCP server found at the following IP: %1",
  738. IPAddressToString(
  739. ConvertIPAddressOrder(serverIPAddress)).c_str()));
  740. }
  741. else
  742. {
  743. LOG(
  744. String::format(
  745. L"DHCP server not found: error = 0x%1!x!",
  746. error));
  747. }
  748. } while (false);
  749. dhcpServerAvailable = result;
  750. LOG_BOOL(result);
  751. return result;
  752. }
  753. bool
  754. NetworkInterface::IsConnected() const
  755. {
  756. LOG_FUNCTION(NetworkInterface::IsConnected);
  757. bool result = true;
  758. do
  759. {
  760. // Convert the name to a GUID
  761. GUID guid;
  762. ZeroMemory(&guid, sizeof(GUID));
  763. HRESULT hr = GetNameAsGUID(guid);
  764. if (FAILED(hr))
  765. {
  766. LOG(String::format(
  767. L"Failed to get name as guid: hr = 0x%1!x!",
  768. hr));
  769. result = false;
  770. break;
  771. }
  772. // Different adapter types require different
  773. // ways of detecting connection state
  774. if (IsModem())
  775. {
  776. // We only know about modems if they are connected
  777. result = true;
  778. }
  779. else
  780. {
  781. result = IsStandardAdapterConnected(guid);
  782. }
  783. } while(false);
  784. LOG_BOOL(result);
  785. return result;
  786. }
  787. bool
  788. NetworkInterface::IsStandardAdapterConnected(const GUID& guid) const
  789. {
  790. LOG_FUNCTION(NetworkInterface::IsStandardAdapterConnected);
  791. bool result = true;
  792. do
  793. {
  794. // Now get the status using the GUID
  795. NETCON_STATUS status = NCS_CONNECTED;
  796. HRESULT hr = HrGetPnpDeviceStatus(&guid, &status);
  797. if (FAILED(hr))
  798. {
  799. LOG(String::format(
  800. L"Failed to get device status: hr = 0x%1!x!",
  801. hr));
  802. result = false;
  803. break;
  804. }
  805. // The status values are defined in netcon.h
  806. LOG(String::format(
  807. L"Device status = %1!d!",
  808. status));
  809. if (status == NCS_DISCONNECTED ||
  810. status == NCS_DISCONNECTING ||
  811. status == NCS_HARDWARE_NOT_PRESENT ||
  812. status == NCS_HARDWARE_DISABLED ||
  813. status == NCS_HARDWARE_MALFUNCTION ||
  814. status == NCS_MEDIA_DISCONNECTED)
  815. {
  816. result = false;
  817. }
  818. } while (false);
  819. LOG_BOOL(result);
  820. return result;
  821. }
  822. bool
  823. NetworkInterface::IsModem() const
  824. {
  825. LOG_FUNCTION(NetworkInterface::IsModem);
  826. bool isModem = false;
  827. switch (GetType())
  828. {
  829. case IF_TYPE_PPP:
  830. isModem = true;
  831. break;
  832. default:
  833. isModem = false;
  834. }
  835. LOG_BOOL(isModem);
  836. return isModem;
  837. }
  838. DWORD
  839. NetworkInterface::GetNextAvailableIPAddress(
  840. DWORD startAddress,
  841. DWORD subnetMask)
  842. {
  843. LOG_FUNCTION2(
  844. NetworkInterface::GetNextAvailableIPAddress,
  845. IPAddressToString(startAddress));
  846. DWORD result = startAddress;
  847. DWORD currentAddress = startAddress;
  848. bool isIPInUse = false;
  849. do
  850. {
  851. isIPInUse =
  852. IsIPAddressInUse(
  853. currentAddress,
  854. subnetMask);
  855. if (!isIPInUse)
  856. {
  857. break;
  858. }
  859. ++currentAddress;
  860. if ((currentAddress & subnetMask) != (startAddress & subnetMask))
  861. {
  862. // REVIEW_JEFFJON : what should the behavior be if there are
  863. // no available addresses? Is this likely to happen?
  864. // Since we couldn't find an available address in this subnet
  865. // use the start address
  866. currentAddress = startAddress;
  867. break;
  868. }
  869. } while (isIPInUse);
  870. result = currentAddress;
  871. LOG(IPAddressToString(result));
  872. return result;
  873. }
  874. bool
  875. NetworkInterface::IsIPAddressInUse(
  876. DWORD ipaddress,
  877. DWORD subnetMask)
  878. {
  879. LOG_FUNCTION2(
  880. NetworkInterface::IsIPAddressInUse,
  881. IPAddressToString(ipaddress));
  882. bool result = false;
  883. do
  884. {
  885. if (!IsConnected())
  886. {
  887. break;
  888. }
  889. // Before calling SendARP we have to set a route
  890. // on the interface for the subnet we are interested
  891. // in so that SendARP will work even if the interface
  892. // IP address is completely different than the IP
  893. // address we are looking for.
  894. SetRoute(
  895. ipaddress,
  896. subnetMask);
  897. // Use the interface IP address to tell TCP which interface
  898. // to send the ARP on
  899. DWORD interfaceIPAddress = GetIPAddress(0);
  900. if (interfaceIPAddress == ipaddress)
  901. {
  902. // If the IP address is in use by the NIC then
  903. // of course it is in use on the network
  904. result = true;
  905. break;
  906. }
  907. // MSDN doesn't mention whether or not the buffer needs to be
  908. // there but it appears that SendArp() is now failing if we
  909. // don't pass it a buffer even though we ignore the macAddress.
  910. // The size was taken from the example in MSDN.
  911. ULONG macAddress[2];
  912. ULONG macLength = sizeof(macAddress);
  913. memset(macAddress, 0xff, macLength);
  914. DWORD error =
  915. SendARP(
  916. ConvertIPAddressOrder(ipaddress),
  917. ConvertIPAddressOrder(interfaceIPAddress),
  918. macAddress,
  919. &macLength);
  920. LOG(
  921. String::format(
  922. L"SendARP returned: error = 0x%1!x!",
  923. error));
  924. if (error == NO_ERROR)
  925. {
  926. result = true;
  927. }
  928. // Now that we are done with the SendARP
  929. // remove the route so that the TCP stack
  930. // reverts to normal behavior
  931. RemoveRoute(
  932. ipaddress,
  933. subnetMask);
  934. } while (false);
  935. LOG_BOOL(result);
  936. return result;
  937. }
  938. void
  939. NetworkInterface::SetRoute(
  940. DWORD ipaddress,
  941. DWORD subnetMask)
  942. {
  943. LOG_FUNCTION2(
  944. NetworkInterface::SetRoute,
  945. IPAddressToString(ipaddress));
  946. LOG(
  947. String::format(
  948. L"subnetMask = %1",
  949. IPAddressToString(subnetMask).c_str()));
  950. MIB_IPFORWARDROW routerTableEntry;
  951. ZeroMemory(&routerTableEntry, sizeof(MIB_IPFORWARDROW));
  952. // Destination
  953. routerTableEntry.dwForwardDest =
  954. ConvertIPAddressOrder(ipaddress) & ConvertIPAddressOrder(subnetMask);
  955. LOG(
  956. String::format(
  957. L"dwForwardDest = %1",
  958. IPAddressToString(ipaddress & subnetMask).c_str()));
  959. // net mask
  960. routerTableEntry.dwForwardMask = ConvertIPAddressOrder(subnetMask);
  961. LOG(
  962. String::format(
  963. L"dwForwardMask = %1",
  964. IPAddressToString(subnetMask).c_str()));
  965. // Interface index
  966. routerTableEntry.dwForwardIfIndex = GetIndex();
  967. LOG(
  968. String::format(
  969. L"dwForwardIfIndex = %1!d!",
  970. GetIndex()));
  971. // Gateway
  972. routerTableEntry.dwForwardNextHop = ConvertIPAddressOrder(GetIPAddress(0));
  973. LOG(
  974. String::format(
  975. L"dwForwardNextHop = %1",
  976. IPAddressToString(GetIPAddress(0)).c_str()));
  977. // Protocol generator (must be PROTO_IP_NETMGMT according to MSDN)
  978. routerTableEntry.dwForwardProto = PROTO_IP_NETMGMT;
  979. // Taking these from %sdxroot%\net\rras\cm\customactions\cmroute\cmroute.cpp
  980. // since I can't get the API to succeed without them
  981. routerTableEntry.dwForwardType = 3;
  982. routerTableEntry.dwForwardAge = INFINITE;
  983. routerTableEntry.dwForwardMetric1 = 1;
  984. routerTableEntry.dwForwardMetric2 = 0xFFFFFFFF;
  985. routerTableEntry.dwForwardMetric3 = 0xFFFFFFFF;
  986. routerTableEntry.dwForwardMetric4 = 0xFFFFFFFF;
  987. routerTableEntry.dwForwardMetric5 = 0xFFFFFFFF;
  988. // Create the table entry
  989. // NTRAID#NTBUG9-667088-2002/09/25-JeffJon
  990. // Do not use CreateIpForwardEntry here because if
  991. // RRAS is running the call will become asynchronous
  992. // and the route may not be in the table by the time
  993. // we call SendARP()
  994. DWORD error =
  995. SetIpForwardEntryToStack(&routerTableEntry);
  996. if (error != NO_ERROR)
  997. {
  998. LOG(
  999. String::format(
  1000. L"SetIpForwardEntryToStack failed: error = 0x%1!x!",
  1001. error));
  1002. }
  1003. }
  1004. void
  1005. NetworkInterface::RemoveRoute(
  1006. DWORD ipaddress,
  1007. DWORD subnetMask)
  1008. {
  1009. LOG_FUNCTION2(
  1010. NetworkInterface::RemoveRoute,
  1011. IPAddressToString(ipaddress));
  1012. LOG(
  1013. String::format(
  1014. L"subnetMask = %1",
  1015. IPAddressToString(subnetMask).c_str()));
  1016. MIB_IPFORWARDROW routerTableEntry;
  1017. ZeroMemory(&routerTableEntry, sizeof(MIB_IPFORWARDROW));
  1018. // Destination
  1019. routerTableEntry.dwForwardDest =
  1020. ConvertIPAddressOrder(ipaddress) & ConvertIPAddressOrder(subnetMask);
  1021. LOG(
  1022. String::format(
  1023. L"dwForwardDest = %1",
  1024. IPAddressToString(ipaddress & subnetMask).c_str()));
  1025. // net mask
  1026. routerTableEntry.dwForwardMask = ConvertIPAddressOrder(subnetMask);
  1027. LOG(
  1028. String::format(
  1029. L"dwForwardMask = %1",
  1030. IPAddressToString(subnetMask).c_str()));
  1031. // Interface index
  1032. routerTableEntry.dwForwardIfIndex = GetIndex();
  1033. LOG(
  1034. String::format(
  1035. L"dwForwardIfIndex = %1!d!",
  1036. GetIndex()));
  1037. // Gateway
  1038. routerTableEntry.dwForwardNextHop = ConvertIPAddressOrder(GetIPAddress(0));
  1039. LOG(
  1040. String::format(
  1041. L"dwForwardNextHop = %1",
  1042. IPAddressToString(GetIPAddress(0)).c_str()));
  1043. // Delete the table entry
  1044. DWORD error =
  1045. DeleteIpForwardEntry(&routerTableEntry);
  1046. if (error != NO_ERROR)
  1047. {
  1048. LOG(
  1049. String::format(
  1050. L"DeleteIpForwardEntry failed: error = 0x%1!x!",
  1051. error));
  1052. }
  1053. }