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.

1212 lines
33 KiB

  1. /*++
  2. Copyright(c) 1995 Microsoft Corporation
  3. MODULE NAME
  4. netmap.c
  5. ABSTRACT
  6. Network map routines
  7. AUTHOR
  8. Anthony Discolo (adiscolo) 21-May-1996
  9. REVISION HISTORY
  10. --*/
  11. #define UNICODE
  12. #define _UNICODE
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <stdlib.h>
  17. #include <windows.h>
  18. #include <tdi.h>
  19. #include <nb30.h>
  20. #include <nbtioctl.h>
  21. #include <stdio.h>
  22. #include <npapi.h>
  23. #include <ctype.h>
  24. #include <winsock.h>
  25. #include <acd.h>
  26. #include <ras.h>
  27. #include <raserror.h>
  28. #include <rasman.h>
  29. #include <debug.h>
  30. #include <ipexport.h>
  31. #include <icmpapi.h>
  32. #include "reg.h"
  33. #include "misc.h"
  34. #include "table.h"
  35. #include "access.h"
  36. #include "rasprocs.h"
  37. #include "imperson.h"
  38. extern DWORD g_dwCritSecFlags;
  39. //
  40. // We keep a map of network name to
  41. // address that groups related addresses
  42. // by network name. We use the network
  43. // name as a remote network identifier to
  44. // allow us to quickly determine whether
  45. // any address belongs to a network that
  46. // is connected or not.
  47. //
  48. typedef struct _NETWORK_MAP_ENTRY {
  49. BOOLEAN bUp; // network is connected
  50. DWORD dwConnectionTag; // unique index for connections
  51. PHASH_TABLE pTable; // table of addresses
  52. LIST_ENTRY listEntry; // addresses sorted by tag
  53. } NETWORK_MAP_ENTRY, *PNETWORK_MAP_ENTRY;
  54. //
  55. // The network map.
  56. //
  57. //
  58. typedef struct _NETWORK_MAP {
  59. CRITICAL_SECTION csLock;
  60. LPTSTR pszDnsAddresses; // DNS server list
  61. DWORD dwcConnections; // number of RAS connections
  62. DWORD dwcUpNetworks; // number of up networks
  63. DWORD dwConnectionTag; // unique index for connections for NULL network
  64. PHASH_TABLE pTable; // network table
  65. } NETWORK_MAP, PNETWORK_MAP;
  66. //
  67. // This structure is passed to an address
  68. // enumerator procedure to keep track of
  69. // any hosts that are accessible.
  70. //
  71. typedef struct _NETWORK_MAP_ACCESS {
  72. LPTSTR pszNbDevice; // Netbios device for find name requests
  73. BOOLEAN bUp; // network is up
  74. DWORD dwFailures; // number of host access failures
  75. } NETWORK_MAP_ACCESS, *PNETWORK_MAP_ACCESS;
  76. //
  77. // This structure is used to store the
  78. // network addresses sorted by tag.
  79. //
  80. typedef struct _TAGGED_ADDRESS {
  81. DWORD dwTag; // the tag
  82. LPTSTR pszAddress; // the address
  83. LIST_ENTRY listEntry; // sorted address list
  84. } TAGGED_ADDRESS, *PTAGGED_ADDRESS;
  85. //
  86. // Netbios device information passed
  87. // to AcsCheckNetworkThread
  88. //
  89. typedef struct _CHECK_NETWORK_INFO {
  90. LPTSTR *pszNbDevices; // array of Netbios device strings
  91. DWORD dwcNbDevices; // array size
  92. BOOLEAN fDns; // DNS server is up
  93. } CHECK_NETWORK_INFO, *PCHECK_NETWORK_INFO;
  94. //
  95. // Global variables
  96. //
  97. NETWORK_MAP NetworkMapG;
  98. LPTSTR
  99. GetPrimaryNetbiosDevice(VOID)
  100. {
  101. typedef struct _LANA_MAP {
  102. BOOLEAN fEnum;
  103. UCHAR bLana;
  104. } LANA_MAP, *PLANA_MAP;
  105. BOOLEAN fNetworkPresent = FALSE;
  106. HKEY hKey;
  107. PLANA_MAP pLanaMap = NULL, pLana;
  108. DWORD dwError, dwcbLanaMap;
  109. PWCHAR pwszLanas = NULL, pwszBuf;
  110. DWORD dwcBindings, dwcMaxLanas, i, dwcbLanas;
  111. LONG iLana;
  112. DWORD dwZero = 0;
  113. PWCHAR *paszLanas = NULL;
  114. SOCKET s;
  115. NTSTATUS status;
  116. UNICODE_STRING deviceName;
  117. OBJECT_ATTRIBUTES attributes;
  118. IO_STATUS_BLOCK iosb;
  119. HANDLE handle;
  120. PWCHAR pwszDevice = NULL;
  121. dwError = RegOpenKeyEx(
  122. HKEY_LOCAL_MACHINE,
  123. L"System\\CurrentControlSet\\Services\\Netbios\\Linkage",
  124. 0,
  125. KEY_READ,
  126. &hKey);
  127. if (dwError != ERROR_SUCCESS) {
  128. RASAUTO_TRACE1(
  129. "GetPrimaryNetbiosDevice: RegKeyOpenEx failed (dwError=%d)",
  130. GetLastError());
  131. return FALSE;
  132. }
  133. //
  134. // Read in the LanaMap.
  135. //
  136. if (!RegGetValue(hKey, L"LanaMap", &pLanaMap, &dwcbLanaMap, NULL)) {
  137. RASAUTO_TRACE("GetPrimaryNetbiosDevice: RegGetValue(LanaMap) failed");
  138. goto done;
  139. }
  140. dwcBindings = dwcbLanaMap / sizeof (LANA_MAP);
  141. //
  142. // Read in the bindings.
  143. //
  144. if (!RegGetValue(hKey, L"bind", &pwszLanas, &dwcbLanas, NULL)) {
  145. RASAUTO_TRACE("GetPrimaryNetbiosDevice: RegGetValue(bind) failed");
  146. goto done;
  147. }
  148. //
  149. // Allocate a buffer for the binding array.
  150. //
  151. paszLanas = LocalAlloc(LPTR, dwcBindings * sizeof (PWCHAR));
  152. if (paszLanas == NULL) {
  153. RASAUTO_TRACE("GetPrimaryNetbiosDevice: LocalAlloc failed");
  154. goto done;
  155. }
  156. //
  157. // Parse the bindings into an array of strings.
  158. //
  159. for (dwcMaxLanas = 0, pwszBuf = pwszLanas;
  160. (*pwszBuf) && (dwcMaxLanas < dwcBindings);
  161. pwszBuf++)
  162. {
  163. paszLanas[dwcMaxLanas++] = pwszBuf;
  164. while(*++pwszBuf);
  165. }
  166. for (iLana = 0, pLana = pLanaMap; dwcBindings--; iLana++, pLana++) {
  167. int iLanaMap = (int)pLana->bLana;
  168. if (pLana->fEnum && (DWORD)iLana < dwcMaxLanas) {
  169. int iError;
  170. WCHAR *pwsz, szDevice[MAX_DEVICE_NAME + 1];
  171. if (wcsstr(paszLanas[iLana], L"NwlnkNb") != NULL ||
  172. wcsstr(paszLanas[iLana], L"_NdisWan") != NULL)
  173. {
  174. RASAUTO_TRACE1(
  175. "GetPrimaryNetbiosDevice: ignoring %S",
  176. RASAUTO_TRACESTRW(paszLanas[iLana]));
  177. continue;
  178. }
  179. RtlInitUnicodeString(&deviceName, paszLanas[iLana]);
  180. InitializeObjectAttributes(
  181. &attributes,
  182. &deviceName,
  183. OBJ_CASE_INSENSITIVE,
  184. NULL,
  185. NULL);
  186. //
  187. // Open the lana device.
  188. //
  189. status = NtOpenFile(&handle, READ_CONTROL, &attributes, &iosb, 0, 0);
  190. NtClose(handle);
  191. if (!NT_SUCCESS(status)) {
  192. RASAUTO_TRACE2(
  193. "GetPrimaryNetbiosDevice: NtOpenFile(%S) failed (status=0x%x)",
  194. RASAUTO_TRACESTRW(paszLanas[iLana]),
  195. status);
  196. continue;
  197. }
  198. RASAUTO_TRACE1("GetPrimaryNetbiosDevice: opened %S", paszLanas[iLana]);
  199. //
  200. // If we succeed in opening the lana
  201. // device, we need to make sure the
  202. // underlying netcard device is loaded
  203. // as well, since transports create
  204. // device object for non-existent devices.
  205. //
  206. pwsz = wcsrchr(paszLanas[iLana], '_');
  207. if (pwsz == NULL) {
  208. RASAUTO_TRACE1(
  209. "GetPrimaryNetbiosDevice: couldn't parse %S",
  210. paszLanas[iLana]);
  211. continue;
  212. }
  213. wsprintf(szDevice, L"\\Device\\%s", pwsz + 1);
  214. //
  215. // Open the underlying netcard device.
  216. //
  217. RtlInitUnicodeString(&deviceName, szDevice);
  218. InitializeObjectAttributes(
  219. &attributes,
  220. &deviceName,
  221. OBJ_CASE_INSENSITIVE,
  222. NULL,
  223. NULL);
  224. status = NtOpenFile(&handle, READ_CONTROL, &attributes, &iosb, 0, 0);
  225. NtClose(handle);
  226. if (!NT_SUCCESS(status)) {
  227. RASAUTO_TRACE2(
  228. "GetPrimaryNetbiosDevice: NtOpenFile(%S) failed (status=0x%x)",
  229. RASAUTO_TRACESTRW(szDevice),
  230. status);
  231. continue;
  232. }
  233. //
  234. // We've succeeded. The netcard device must
  235. // be really loaded.
  236. //
  237. RASAUTO_TRACE3(
  238. "GetPrimaryNetbiosDevice: network (%S, %S, %d) is up",
  239. RASAUTO_TRACESTRW(paszLanas[iLana]),
  240. szDevice,
  241. iLana);
  242. pwszDevice = CopyString(paszLanas[iLana]);
  243. break;
  244. }
  245. }
  246. //
  247. // Free resources.
  248. //
  249. done:
  250. if (paszLanas != NULL)
  251. LocalFree(paszLanas);
  252. if (pwszLanas != NULL)
  253. LocalFree(pwszLanas);
  254. if (pLanaMap != NULL)
  255. LocalFree(pLanaMap);
  256. RegCloseKey(hKey);
  257. return pwszDevice;
  258. } // GetPrimaryNetbiosDevice
  259. LPTSTR
  260. DnsAddresses()
  261. /*++
  262. DESCRIPTION
  263. Return the list of DNS servers for this host.
  264. ARGUMENTS
  265. None.
  266. RETURN VALUE
  267. NULL if no DNS servers are configured; a list
  268. of IP addresses separated by a space otherwise.
  269. --*/
  270. {
  271. HKEY hkey;
  272. BOOLEAN fFound = FALSE;
  273. LPTSTR pszIpAddresses = NULL;
  274. LPTSTR pszIpAddress, pszIpAddressEnd;
  275. DWORD dwcbIpAddresses = 0;
  276. //
  277. // Look in various places in the registry
  278. // for one or more DNS addresses.
  279. //
  280. if (RegOpenKeyEx(
  281. HKEY_LOCAL_MACHINE,
  282. L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Transient",
  283. 0,
  284. KEY_QUERY_VALUE,
  285. &hkey) == ERROR_SUCCESS)
  286. {
  287. fFound = RegGetValue(
  288. hkey,
  289. L"NameServer",
  290. &pszIpAddresses,
  291. &dwcbIpAddresses,
  292. NULL);
  293. RegCloseKey(hkey);
  294. }
  295. if (fFound && dwcbIpAddresses > sizeof (TCHAR))
  296. goto found;
  297. if (pszIpAddresses != NULL) {
  298. LocalFree(pszIpAddresses);
  299. pszIpAddresses = NULL;
  300. }
  301. if (RegOpenKeyEx(
  302. HKEY_LOCAL_MACHINE,
  303. L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
  304. 0,
  305. KEY_QUERY_VALUE,
  306. &hkey) == ERROR_SUCCESS)
  307. {
  308. fFound = RegGetValue(
  309. hkey,
  310. L"NameServer",
  311. &pszIpAddresses,
  312. &dwcbIpAddresses,
  313. NULL);
  314. if (fFound && dwcbIpAddresses > sizeof (TCHAR)) {
  315. RegCloseKey(hkey);
  316. goto found;
  317. }
  318. if (pszIpAddresses != NULL) {
  319. LocalFree(pszIpAddresses);
  320. pszIpAddresses = NULL;
  321. }
  322. fFound = RegGetValue(
  323. hkey,
  324. L"DhcpNameServer",
  325. &pszIpAddresses,
  326. &dwcbIpAddresses,
  327. NULL);
  328. RegCloseKey(hkey);
  329. if (fFound && dwcbIpAddresses > sizeof (TCHAR))
  330. goto found;
  331. if (pszIpAddresses != NULL) {
  332. LocalFree(pszIpAddresses);
  333. pszIpAddresses = NULL;
  334. }
  335. }
  336. found:
  337. RASAUTO_TRACE1("DnsAddresses: pszIpAddresses=%S", RASAUTO_TRACESTRW(pszIpAddresses));
  338. return pszIpAddresses;
  339. } // DnsAddresses
  340. BOOLEAN
  341. PingAddressList(
  342. IN LPTSTR pszAddresses
  343. )
  344. {
  345. TCHAR szAddress[17];
  346. TCHAR *pSrc, *pDst;
  347. //
  348. // If the address list is NULL, we're done.
  349. //
  350. if (pszAddresses == NULL)
  351. return FALSE;
  352. //
  353. // Loop through the addresses and try to
  354. // ping each until one succeeds.
  355. //
  356. for (;;) {
  357. //
  358. // Copy the next address into szAddress.
  359. //
  360. for (pSrc = pszAddresses, pDst = szAddress;
  361. *pSrc != TEXT(' ') && *pSrc != TEXT(',') && *pSrc != TEXT('\0');
  362. *pSrc++, *pDst++)
  363. {
  364. *pDst = *pSrc;
  365. }
  366. *pDst = TEXT('\0');
  367. //
  368. // Ping it. If it succeeds, then
  369. // we're done.
  370. //
  371. if (PingIpAddress(szAddress))
  372. return TRUE;
  373. //
  374. // Skip to the next address.
  375. //
  376. if (*pSrc == TEXT('\0'))
  377. break;
  378. pSrc++;
  379. if (*pSrc == TEXT('\0'))
  380. break;
  381. pszAddresses = pSrc;
  382. }
  383. return FALSE;
  384. } // PingAddressList
  385. BOOLEAN
  386. InitializeNetworkMap(VOID)
  387. {
  388. DWORD dwError = NO_ERROR;
  389. RasInitializeCriticalSection(&NetworkMapG.csLock, &dwError);
  390. if(dwError != ERROR_SUCCESS)
  391. {
  392. return FALSE;
  393. }
  394. g_dwCritSecFlags |= RASAUTO_CRITSEC_NETMAP;
  395. NetworkMapG.pszDnsAddresses = NULL;
  396. NetworkMapG.dwcConnections = 0;
  397. NetworkMapG.dwcUpNetworks = 0;
  398. NetworkMapG.dwConnectionTag = 0;
  399. NetworkMapG.pTable = NewTable();
  400. if (NetworkMapG.pTable == NULL) {
  401. RASAUTO_TRACE("InitializeNetworkMap: NewTable failed");
  402. return FALSE;
  403. }
  404. return TRUE;
  405. } // InitializeNetworkMap
  406. VOID
  407. LockNetworkMap(VOID)
  408. {
  409. EnterCriticalSection(&NetworkMapG.csLock);
  410. } // LockNetworkMap
  411. VOID
  412. UnlockNetworkMap(VOID)
  413. {
  414. LeaveCriticalSection(&NetworkMapG.csLock);
  415. } // UnlockNetworkMap
  416. PNETWORK_MAP_ENTRY
  417. NewNetworkMapEntry(
  418. IN LPTSTR pszNetwork
  419. )
  420. {
  421. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  422. DWORD i;
  423. pNetworkMapEntry = LocalAlloc(LPTR, sizeof (NETWORK_MAP_ENTRY));
  424. if (pNetworkMapEntry == NULL) {
  425. RASAUTO_TRACE("NewNetworkMapEntry: LocalAlloc failed");
  426. return NULL;
  427. }
  428. pNetworkMapEntry->bUp = FALSE;
  429. pNetworkMapEntry->dwConnectionTag = 0;
  430. pNetworkMapEntry->pTable = NewTable();
  431. if (pNetworkMapEntry->pTable == NULL) {
  432. RASAUTO_TRACE("NewNetworkMapEntry: NewTable failed");
  433. LocalFree(pNetworkMapEntry);
  434. return NULL;
  435. }
  436. InitializeListHead(&pNetworkMapEntry->listEntry);
  437. if (!PutTableEntry(NetworkMapG.pTable, pszNetwork, pNetworkMapEntry)) {
  438. RASAUTO_TRACE("NewNetworkMapEntry: PutTableEntry failed");
  439. LocalFree(pNetworkMapEntry);
  440. return NULL;
  441. }
  442. return pNetworkMapEntry;
  443. } // NewNetworkMapEntry
  444. VOID
  445. FreeNetworkMapEntry(
  446. IN PNETWORK_MAP_ENTRY pNetworkMapEntry
  447. )
  448. {
  449. PLIST_ENTRY pEntry;
  450. PTAGGED_ADDRESS pTaggedAddress;
  451. /*
  452. //
  453. // Since the PTAGGED_ADDRESS structures are
  454. // in a hash table and a list, we need to
  455. // free the structures in a special way. The
  456. // table package automatically frees the
  457. // structures when a PutTableEntry(pTable, address, NULL)
  458. // is called.
  459. //
  460. for (pEntry = pNetworkMapEntry->listEntry.Flink;
  461. pEntry != &pNetworkMapEntry->listEntry;
  462. pEntry = pEntry->Flink)
  463. {
  464. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  465. LocalFree(pTaggedAddress->pszAddress);
  466. }
  467. */
  468. while (!IsListEmpty(&pNetworkMapEntry->listEntry)) {
  469. LPTSTR pszAddress;
  470. pEntry = RemoveHeadList(&pNetworkMapEntry->listEntry);
  471. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  472. pszAddress = pTaggedAddress->pszAddress;
  473. //
  474. // The following call frees the
  475. // pTaggedAddress structure, as
  476. // well as frees the table entry.
  477. //
  478. PutTableEntry(pNetworkMapEntry->pTable, pszAddress, NULL);
  479. LocalFree(pszAddress);
  480. }
  481. ClearTable(pNetworkMapEntry->pTable);
  482. } // FreeNetworkMapEntry
  483. ACD_ADDR_TYPE
  484. AddressToType(
  485. IN LPTSTR pszAddress
  486. )
  487. {
  488. LONG inaddr;
  489. CHAR szAddress[17];
  490. UnicodeStringToAnsiString(pszAddress, szAddress, sizeof (szAddress));
  491. inaddr = inet_addr(szAddress);
  492. if (inaddr != INADDR_NONE)
  493. return ACD_ADDR_IP;
  494. if (wcschr(pszAddress, ':') != NULL)
  495. return ACD_ADDR_IPX;
  496. if (wcschr(pszAddress, '.') != NULL)
  497. return ACD_ADDR_INET;
  498. return ACD_ADDR_NB;
  499. } // AddressToType
  500. PNETWORK_MAP_ENTRY
  501. GetNetworkMapEntry(
  502. IN LPTSTR pszNetwork
  503. )
  504. {
  505. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  506. if (GetTableEntry(
  507. NetworkMapG.pTable,
  508. pszNetwork,
  509. &pNetworkMapEntry))
  510. {
  511. return pNetworkMapEntry;
  512. }
  513. return NULL;
  514. } // GetNetworkMapEntry
  515. BOOLEAN
  516. AddNetworkAddress(
  517. IN LPTSTR pszNetwork,
  518. IN LPTSTR pszAddress,
  519. IN DWORD dwTag
  520. )
  521. {
  522. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  523. PTAGGED_ADDRESS pNewTaggedAddress, pTaggedAddress;
  524. PLIST_ENTRY pPrevEntry, pEntry;
  525. BOOLEAN bInserted = FALSE;
  526. BOOLEAN bCreateNew = TRUE;
  527. RASAUTO_TRACE3(
  528. "AddNetworkAddress(%S,%S,%d)",
  529. RASAUTO_TRACESTRW(pszNetwork),
  530. pszAddress,
  531. dwTag);
  532. //
  533. // Create the network map entry if necessary.
  534. //
  535. LockNetworkMap();
  536. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  537. if (pNetworkMapEntry == NULL) {
  538. pNetworkMapEntry = NewNetworkMapEntry(pszNetwork);
  539. if (pNetworkMapEntry == NULL) {
  540. UnlockNetworkMap();
  541. return FALSE;
  542. }
  543. }
  544. else {
  545. //
  546. // Check to see if the address already exists.
  547. //
  548. if (GetTableEntry(
  549. pNetworkMapEntry->pTable,
  550. pszAddress,
  551. &pNewTaggedAddress))
  552. {
  553. RASAUTO_TRACE2(
  554. "AddNetworkAddress: %S exists with dwTag=%d",
  555. pszAddress,
  556. pNewTaggedAddress->dwTag);
  557. //
  558. // If the address exists with a lower tag, then
  559. // we don't need to do anything.
  560. //
  561. if (pNewTaggedAddress->dwTag <= dwTag) {
  562. UnlockNetworkMap();
  563. return TRUE;
  564. }
  565. //
  566. // If the address exists with a higher tag, then
  567. // we need to remove the existing entry from
  568. // the list.
  569. //
  570. RemoveEntryList(&pNewTaggedAddress->listEntry);
  571. bCreateNew = FALSE;
  572. }
  573. }
  574. if (bCreateNew) {
  575. //
  576. // Create the new tagged address structure.
  577. //
  578. pNewTaggedAddress = LocalAlloc(LPTR, sizeof (TAGGED_ADDRESS));
  579. if (pNewTaggedAddress == NULL) {
  580. RASAUTO_TRACE("AddNetworkMap: LocalAlloc failed");
  581. UnlockNetworkMap();
  582. return FALSE;
  583. }
  584. pNewTaggedAddress->pszAddress = CopyString(pszAddress);
  585. if (pNewTaggedAddress->pszAddress == NULL) {
  586. RASAUTO_TRACE("AddNetworkMap: LocalAlloc failed");
  587. UnlockNetworkMap();
  588. LocalFree(pNewTaggedAddress);
  589. LocalFree(pNetworkMapEntry);
  590. return FALSE;
  591. }
  592. if (!PutTableEntry(
  593. pNetworkMapEntry->pTable,
  594. pszAddress,
  595. pNewTaggedAddress))
  596. {
  597. RASAUTO_TRACE("AddNetworkMap: PutTableEntry failed");
  598. UnlockNetworkMap();
  599. LocalFree(pNewTaggedAddress->pszAddress);
  600. LocalFree(pNewTaggedAddress);
  601. return FALSE;
  602. }
  603. }
  604. pNewTaggedAddress->dwTag = dwTag;
  605. //
  606. // Insert the new address into the list sorted by tag.
  607. //
  608. pPrevEntry = &pNetworkMapEntry->listEntry;
  609. for (pEntry = pNetworkMapEntry->listEntry.Flink;
  610. pEntry != &pNetworkMapEntry->listEntry;
  611. pEntry = pEntry->Flink)
  612. {
  613. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  614. if (pTaggedAddress->dwTag >= pNewTaggedAddress->dwTag) {
  615. InsertHeadList(pPrevEntry, &pNewTaggedAddress->listEntry);
  616. bInserted = TRUE;
  617. break;
  618. }
  619. pPrevEntry = pEntry;
  620. }
  621. if (!bInserted) {
  622. InsertTailList(
  623. &pNetworkMapEntry->listEntry,
  624. &pNewTaggedAddress->listEntry);
  625. }
  626. UnlockNetworkMap();
  627. return TRUE;
  628. } // AddNetworkAddress
  629. BOOLEAN
  630. ClearNetworkMapEntry(
  631. IN PVOID pArg,
  632. IN LPTSTR pszNetwork,
  633. IN PVOID pData
  634. )
  635. {
  636. PNETWORK_MAP_ENTRY pNetworkMapEntry = (PNETWORK_MAP_ENTRY)pData;
  637. FreeNetworkMapEntry(pNetworkMapEntry);
  638. return TRUE;
  639. } // ClearNetworkMapEntry
  640. VOID
  641. ClearNetworkMap(VOID)
  642. {
  643. LockNetworkMap();
  644. NetworkMapG.dwcConnections = 0;
  645. NetworkMapG.dwcUpNetworks = 0;
  646. NetworkMapG.dwConnectionTag = 0;
  647. EnumTable(NetworkMapG.pTable, ClearNetworkMapEntry, NULL);
  648. ClearTable(NetworkMapG.pTable);
  649. UnlockNetworkMap();
  650. } // ClearNetworkMap
  651. BOOLEAN
  652. IsAddressAccessible(
  653. IN LPTSTR *pszNbDevices,
  654. IN DWORD dwcNbDevices,
  655. IN BOOLEAN fDnsAvailable,
  656. IN LPTSTR pszAddress
  657. )
  658. {
  659. ACD_ADDR_TYPE fType;
  660. BOOLEAN bSuccess = FALSE;
  661. //
  662. // Get the type of the address.
  663. //
  664. fType = AddressToType(pszAddress);
  665. RASAUTO_TRACE2(
  666. "IsAddressAccessible: fType=%d, pszAddress=%S",
  667. fType,
  668. pszAddress);
  669. //
  670. // Call the address-specific accessibility routine.
  671. //
  672. switch (fType) {
  673. case ACD_ADDR_IP:
  674. bSuccess = PingIpAddress(pszAddress);
  675. break;
  676. case ACD_ADDR_IPX:
  677. RASAUTO_TRACE("IsAddressAccessible: IPX address!");
  678. break;
  679. case ACD_ADDR_NB:
  680. bSuccess = NetbiosFindName(pszNbDevices, dwcNbDevices, pszAddress);
  681. break;
  682. case ACD_ADDR_INET:
  683. if (fDnsAvailable) {
  684. struct hostent *hp;
  685. struct in_addr in;
  686. PCHAR pch;
  687. TCHAR szIpAddress[17];
  688. LPTSTR psz;
  689. psz = LocalAlloc(LPTR, (lstrlen(pszAddress) + 1) * sizeof(TCHAR));
  690. if(NULL == psz)
  691. {
  692. break;
  693. }
  694. lstrcpy(psz, pszAddress);
  695. UnlockNetworkMap();
  696. hp = InetAddressToHostent(psz);
  697. LocalFree(psz);
  698. LockNetworkMap();
  699. if (hp != NULL) {
  700. in.s_addr = *(PULONG)hp->h_addr;
  701. pch = inet_ntoa(in);
  702. if (pch != NULL) {
  703. AnsiStringToUnicodeString(
  704. pch,
  705. szIpAddress,
  706. sizeof (szIpAddress) / sizeof(TCHAR));
  707. bSuccess = PingIpAddress(szIpAddress);
  708. }
  709. }
  710. }
  711. break;
  712. default:
  713. RASAUTO_TRACE1("IsAddressAccessible: invalid type: %d", fType);
  714. break;
  715. }
  716. return bSuccess;
  717. } // IsAddressAccessible
  718. BOOLEAN
  719. CheckNetwork(
  720. IN PVOID pArg,
  721. IN LPTSTR pszNetwork,
  722. IN PVOID pData
  723. )
  724. {
  725. PCHECK_NETWORK_INFO pCheckNetworkInfo = (PCHECK_NETWORK_INFO)pArg;
  726. PNETWORK_MAP_ENTRY pNetworkMapEntry = (PNETWORK_MAP_ENTRY)pData;
  727. PLIST_ENTRY pEntry;
  728. DWORD dwFailures = 0;
  729. PTAGGED_ADDRESS pTaggedAddress;
  730. LockNetworkMap();
  731. //
  732. // Check the accessiblilty of up
  733. // to three addresses to
  734. // determine if the network is up.
  735. //
  736. if (!pNetworkMapEntry->bUp) {
  737. for (pEntry = pNetworkMapEntry->listEntry.Flink;
  738. pEntry != &pNetworkMapEntry->listEntry;
  739. pEntry = pEntry->Flink)
  740. {
  741. pTaggedAddress = CONTAINING_RECORD(pEntry, TAGGED_ADDRESS, listEntry);
  742. if (IsAddressAccessible(
  743. pCheckNetworkInfo->pszNbDevices,
  744. pCheckNetworkInfo->dwcNbDevices,
  745. pCheckNetworkInfo->fDns,
  746. pTaggedAddress->pszAddress))
  747. {
  748. pNetworkMapEntry->bUp = TRUE;
  749. NetworkMapG.dwcUpNetworks++;
  750. break;
  751. }
  752. //
  753. // Sanity check to see if the pEntry is
  754. // still valid - since IsAddressAccessible
  755. // releases the network map lock.
  756. //
  757. {
  758. PLIST_ENTRY pEntryT;
  759. for (pEntryT = pNetworkMapEntry->listEntry.Flink;
  760. pEntryT != &pNetworkMapEntry->listEntry;
  761. pEntryT = pEntryT->Flink)
  762. {
  763. if(pEntryT == pEntry)
  764. {
  765. RASAUTO_TRACE("CheckNetworkMap: Entry valid");
  766. break;
  767. }
  768. }
  769. if(pEntryT != pEntry)
  770. {
  771. RASAUTO_TRACE1("CheckNetworkMap: Entry %p is invalid!",
  772. pEntry);
  773. break;
  774. }
  775. }
  776. if (dwFailures++ > 2)
  777. break;
  778. }
  779. }
  780. RASAUTO_TRACE3(
  781. "CheckNetwork: %S is %s (NetworkMapG.dwcUpNetworks=%d",
  782. pszNetwork,
  783. pNetworkMapEntry->bUp ? "up" : "down",
  784. NetworkMapG.dwcUpNetworks);
  785. UnlockNetworkMap();
  786. return TRUE;
  787. } // CheckNetwork
  788. BOOLEAN
  789. MarkNetworkDown(
  790. IN PVOID pArg,
  791. IN LPTSTR pszNetwork,
  792. IN PVOID pData
  793. )
  794. {
  795. PNETWORK_MAP_ENTRY pNetworkMapEntry = (PNETWORK_MAP_ENTRY)pData;
  796. pNetworkMapEntry->bUp = FALSE;
  797. pNetworkMapEntry->dwConnectionTag = 0;
  798. return TRUE;
  799. } // MarkNetworkDown
  800. DWORD
  801. AcsCheckNetworkThread(
  802. LPVOID lpArg
  803. )
  804. {
  805. PCHECK_NETWORK_INFO pCheckNetworkInfo = (PCHECK_NETWORK_INFO)lpArg;
  806. RASAUTO_TRACE("AcsCheckNetworkThread");
  807. EnumTable(NetworkMapG.pTable, CheckNetwork, pCheckNetworkInfo);
  808. return 0;
  809. } // AcsCheckNetworkThread
  810. BOOLEAN
  811. UpdateNetworkMap(
  812. IN BOOLEAN bForce
  813. )
  814. {
  815. LPTSTR *pszNbDevices = NULL;
  816. DWORD i, dwcConnections, dwcNbDevices = 0;
  817. LPTSTR pszNetwork, *lpActiveEntries = NULL;
  818. LPTSTR pszDnsAddresses;
  819. HRASCONN *lphRasconns = NULL;
  820. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  821. CHECK_NETWORK_INFO checkNetworkInfo;
  822. HANDLE hThread;
  823. DWORD dwThreadId;
  824. BOOL fLockAcquired = FALSE;
  825. LockNetworkMap();
  826. fLockAcquired = TRUE;
  827. //
  828. // If the previous number of RAS connections
  829. // equals the current number of RAS connections,
  830. // then don't waste our time.
  831. //
  832. dwcConnections = ActiveConnections(TRUE, &lpActiveEntries, &lphRasconns);
  833. if (!bForce && dwcConnections == NetworkMapG.dwcConnections) {
  834. RASAUTO_TRACE1("UpdateNetworkMap: no change (%d connections)", dwcConnections);
  835. goto done;
  836. }
  837. //
  838. // Allocate the Netbios device array up front.
  839. //
  840. pszNbDevices = (LPTSTR *)LocalAlloc(
  841. LPTR,
  842. (dwcConnections + 1) *
  843. sizeof (LPTSTR));
  844. if (pszNbDevices == NULL) {
  845. RASAUTO_TRACE("UpdateNetworkMap: LocalAlloc failed");
  846. goto done;
  847. }
  848. pszNbDevices[0] = GetPrimaryNetbiosDevice();
  849. if (pszNbDevices[0] != NULL)
  850. dwcNbDevices++;
  851. //
  852. // Wait up to 3 seconds for the new
  853. // DNS servers to get set. Otherwise,
  854. // we may get inaccurate results from
  855. // subsequent Winsock getxbyy calls.
  856. //
  857. if (dwcConnections != NetworkMapG.dwcConnections) {
  858. for (i = 0; i < 3; i++) {
  859. BOOLEAN bChanged;
  860. pszDnsAddresses = DnsAddresses();
  861. RASAUTO_TRACE2(
  862. "UpdateNetworkMap: old DNS=%S, new DNS=%S",
  863. RASAUTO_TRACESTRW(NetworkMapG.pszDnsAddresses),
  864. RASAUTO_TRACESTRW(pszDnsAddresses));
  865. bChanged = (pszDnsAddresses != NULL && NetworkMapG.pszDnsAddresses != NULL) ?
  866. wcscmp(pszDnsAddresses, NetworkMapG.pszDnsAddresses) :
  867. (pszDnsAddresses != NULL || NetworkMapG.pszDnsAddresses != NULL);
  868. if (bChanged) {
  869. if (NetworkMapG.pszDnsAddresses != NULL)
  870. LocalFree(NetworkMapG.pszDnsAddresses);
  871. NetworkMapG.pszDnsAddresses = pszDnsAddresses;
  872. break;
  873. }
  874. LocalFree(pszDnsAddresses);
  875. Sleep(1000);
  876. }
  877. }
  878. else if (bForce && NetworkMapG.pszDnsAddresses == NULL)
  879. NetworkMapG.pszDnsAddresses = DnsAddresses();
  880. //
  881. //
  882. NetworkMapG.dwcConnections = dwcConnections;
  883. NetworkMapG.dwConnectionTag = 0;
  884. //
  885. // Mark all networks as down initially.
  886. //
  887. NetworkMapG.dwcUpNetworks = dwcNbDevices;
  888. EnumTable(NetworkMapG.pTable, MarkNetworkDown, NULL);
  889. //
  890. // Enumerate the connected phonebook entries
  891. // and automatically mark those networks as
  892. // connected.
  893. //
  894. for (i = 0; i < dwcConnections; i++) {
  895. pszNetwork = EntryToNetwork(lpActiveEntries[i]);
  896. RASAUTO_TRACE2(
  897. "UpdateNetworkMap: entry %S, network %S is connected",
  898. lpActiveEntries[i],
  899. RASAUTO_TRACESTRW(pszNetwork));
  900. //
  901. // Increment the number of up networks.
  902. //
  903. NetworkMapG.dwcUpNetworks++;
  904. if (pszNetwork != NULL) {
  905. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  906. if (pNetworkMapEntry != NULL) {
  907. pNetworkMapEntry->bUp = TRUE;
  908. RASAUTO_TRACE2(
  909. "UpdateNetworkMap: network %S is up (dwcUpNetworks=%d)",
  910. pszNetwork,
  911. NetworkMapG.dwcUpNetworks);
  912. }
  913. LocalFree(pszNetwork);
  914. }
  915. else {
  916. //
  917. // Add a Netbios device associated with
  918. // this phonebook entry to the list
  919. // of Netbios devices representing unknown
  920. // networks so we can do FIND NAME
  921. // requests on them below.
  922. //
  923. pszNbDevices[dwcNbDevices] = GetNetbiosDevice(lphRasconns[i]);
  924. if (pszNbDevices[dwcNbDevices] != NULL)
  925. dwcNbDevices++;
  926. }
  927. }
  928. UnlockNetworkMap();
  929. fLockAcquired = FALSE;
  930. //
  931. // Now go through all the networks that are
  932. // not associated with a connected phonebook
  933. // entry and see if they are connected (via
  934. // a netcard). We need to do this in a new
  935. // thread because only new Winsock threads
  936. // will get the new DNS server addresses.
  937. //
  938. checkNetworkInfo.pszNbDevices = pszNbDevices;
  939. checkNetworkInfo.dwcNbDevices = dwcNbDevices;
  940. checkNetworkInfo.fDns = PingAddressList(NetworkMapG.pszDnsAddresses);
  941. RASAUTO_TRACE1(
  942. "UpdateNetworkMap: DNS is %s",
  943. checkNetworkInfo.fDns ? "up" : "down");
  944. hThread = CreateThread(
  945. NULL,
  946. 10000L,
  947. (LPTHREAD_START_ROUTINE)AcsCheckNetworkThread,
  948. &checkNetworkInfo,
  949. 0,
  950. &dwThreadId);
  951. if (hThread == NULL) {
  952. RASAUTO_TRACE1(
  953. "UpdateNetworkMap: CreateThread failed (error=0x%x)",
  954. GetLastError());
  955. goto done;
  956. }
  957. //
  958. // Wait for the thread to terminate.
  959. //
  960. RASAUTO_TRACE("UpdateNetworkMap: waiting for AcsCheckNetworkThread to terminate...");
  961. WaitForSingleObject(hThread, INFINITE);
  962. RASAUTO_TRACE1(
  963. "UpdateNetworkMap: AcsCheckNetworkThread done (NetworkMapG.dwcUpNetworks=%d",
  964. NetworkMapG.dwcUpNetworks);
  965. CloseHandle(hThread);
  966. done:
  967. if(fLockAcquired)
  968. UnlockNetworkMap();
  969. if (lpActiveEntries != NULL)
  970. FreeStringArray(lpActiveEntries, dwcConnections);
  971. if (lphRasconns != NULL)
  972. LocalFree(lphRasconns);
  973. if (pszNbDevices != NULL)
  974. FreeStringArray(pszNbDevices, dwcNbDevices);
  975. return TRUE;
  976. } // UpdateNetworkMap
  977. BOOLEAN
  978. GetNetworkConnected(
  979. IN LPTSTR pszNetwork,
  980. OUT PBOOLEAN pbConnected
  981. )
  982. {
  983. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  984. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  985. if (pNetworkMapEntry == NULL)
  986. return FALSE;
  987. *pbConnected = pNetworkMapEntry->bUp;
  988. RASAUTO_TRACE2("GetNetworkConnected: %S is %d", pszNetwork, *pbConnected);
  989. return TRUE;
  990. } // GetNetworkConnected
  991. BOOLEAN
  992. SetNetworkConnected(
  993. IN LPTSTR pszNetwork,
  994. IN BOOLEAN bConnected
  995. )
  996. {
  997. PNETWORK_MAP_ENTRY pNetworkMapEntry;
  998. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  999. if (pNetworkMapEntry != NULL)
  1000. pNetworkMapEntry->bUp = bConnected;
  1001. if (bConnected)
  1002. NetworkMapG.dwcUpNetworks++;
  1003. else
  1004. NetworkMapG.dwcUpNetworks--;
  1005. RASAUTO_TRACE3(
  1006. "SetNetworkConnected: %S is %d (dwcUpNetworks=%d)",
  1007. RASAUTO_TRACESTRW(pszNetwork),
  1008. bConnected,
  1009. NetworkMapG.dwcUpNetworks);
  1010. return TRUE;
  1011. } // SetNetworkConnected
  1012. DWORD
  1013. GetNetworkConnectionTag(
  1014. IN LPTSTR pszNetwork,
  1015. IN BOOLEAN bIncrement
  1016. )
  1017. {
  1018. PNETWORK_MAP_ENTRY pNetworkMapEntry = NULL;
  1019. DWORD dwTag;
  1020. if (pszNetwork != NULL)
  1021. pNetworkMapEntry = GetNetworkMapEntry(pszNetwork);
  1022. if (bIncrement) {
  1023. dwTag = (pNetworkMapEntry == NULL) ?
  1024. NetworkMapG.dwConnectionTag++ :
  1025. pNetworkMapEntry->dwConnectionTag++;
  1026. }
  1027. else {
  1028. dwTag = (pNetworkMapEntry == NULL) ?
  1029. NetworkMapG.dwConnectionTag :
  1030. pNetworkMapEntry->dwConnectionTag;
  1031. }
  1032. RASAUTO_TRACE2(
  1033. "GetNetworkConnectionTag: network=%S, tag=%d",
  1034. RASAUTO_TRACESTRW(pszNetwork),
  1035. dwTag);
  1036. return dwTag;
  1037. } // GetNetworkConnectionTag
  1038. BOOLEAN
  1039. IsNetworkConnected(VOID)
  1040. {
  1041. BOOLEAN bConnected;
  1042. LockNetworkMap();
  1043. bConnected = (NetworkMapG.dwcUpNetworks > 0);
  1044. RASAUTO_TRACE1("IsNetworkConnected: dwcUpNetworks=%d", NetworkMapG.dwcUpNetworks);
  1045. UnlockNetworkMap();
  1046. return bConnected;
  1047. } // IsNetworkConnected
  1048. VOID
  1049. UninitializeNetworkMap(VOID)
  1050. {
  1051. if(g_dwCritSecFlags & RASAUTO_CRITSEC_NETMAP)
  1052. {
  1053. DeleteCriticalSection(&NetworkMapG.csLock);
  1054. g_dwCritSecFlags &= ~(RASAUTO_CRITSEC_NETMAP);
  1055. }
  1056. }