Source code of Windows XP (NT5)
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.

3439 lines
83 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. natconn.c
  5. Abstract:
  6. This module contains code for the NAT's RAS connection management.
  7. This includes
  8. * code to support 'shared-access', in which a RAS client-connection
  9. serves as the NAT public network.
  10. * code to support 'on-demand dialing', in which a routing-failure
  11. results in our attempting to establish a dialup connection
  12. with the help of the autodial service.
  13. Author:
  14. Abolade Gbadegesin (aboladeg) 2-May-1998
  15. Revision History:
  16. Jonathan Burstein (jonburs) 6-July-2000
  17. Updated to new config APIs
  18. --*/
  19. #include "precomp.h"
  20. #pragma hdrstop
  21. #include <ras.h>
  22. #include <rasuip.h>
  23. #include <raserror.h>
  24. #include <dnsapi.h>
  25. #include "beacon.h"
  26. //
  27. // EXTERNAL DECLARATIONS
  28. //
  29. extern "C"
  30. ULONG APIENTRY
  31. RasGetEntryHrasconnW(
  32. LPCWSTR Phonebook,
  33. LPCWSTR EntryName,
  34. LPHRASCONN Hrasconn
  35. );
  36. extern "C"
  37. ULONG
  38. SetIpForwardEntryToStack(
  39. PMIB_IPFORWARDROW IpForwardRow
  40. );
  41. extern "C"
  42. ULONG
  43. NhpAllocateAndGetInterfaceInfoFromStack(
  44. IP_INTERFACE_NAME_INFO** Table,
  45. PULONG Count,
  46. BOOL SortOutput,
  47. HANDLE AllocationHeap,
  48. ULONG AllocationFlags
  49. );
  50. //
  51. // Notifications
  52. //
  53. HANDLE NatConfigurationChangedEvent = NULL;
  54. HANDLE NatpConfigurationChangedWaitHandle = NULL;
  55. HANDLE NatConnectionNotifyEvent = NULL;
  56. HANDLE NatpConnectionNotifyWaitHandle = NULL;
  57. HANDLE NatpEnableRouterEvent = NULL;
  58. OVERLAPPED NatpEnableRouterOverlapped;
  59. HANDLE NatpEnableRouterWaitHandle = NULL;
  60. IO_STATUS_BLOCK NatpRoutingFailureIoStatus;
  61. IP_NAT_ROUTING_FAILURE_NOTIFICATION NatpRoutingFailureNotification;
  62. //
  63. // Connection information
  64. //
  65. LIST_ENTRY NatpConnectionList = {NULL, NULL};
  66. ULONG NatpFirewallConnectionCount = 0;
  67. BOOLEAN NatpSharedConnectionPresent = FALSE;
  68. PCHAR NatpSharedConnectionDomainName = NULL;
  69. LONG NatpNextInterfaceIndex = 1;
  70. #define INADDR_LOOPBACK_NO 0x0100007f // 127.0.0.1 in network order
  71. //
  72. // FORWARD DECLARATIONS
  73. //
  74. HRESULT
  75. NatpAddConnectionEntry(
  76. IUnknown *pUnk
  77. );
  78. ULONG
  79. NatpBindConnection(
  80. PNAT_CONNECTION_ENTRY pConEntry,
  81. HRASCONN Hrasconn,
  82. ULONG AdapterIndex OPTIONAL,
  83. PIP_ADAPTER_BINDING_INFO BindingInfo OPTIONAL
  84. );
  85. HRESULT
  86. NatpBuildPortMappingList(
  87. PNAT_CONNECTION_ENTRY pConEntry,
  88. PIP_ADAPTER_BINDING_INFO pBindingInfo
  89. );
  90. VOID NTAPI
  91. NatpConfigurationChangedCallbackRoutine(
  92. PVOID Context,
  93. BOOLEAN TimedOut
  94. );
  95. VOID NTAPI
  96. NatpConnectionNotifyCallbackRoutine(
  97. PVOID Context,
  98. BOOLEAN TimedOut
  99. );
  100. VOID NTAPI
  101. NatpEnableRouterCallbackRoutine(
  102. PVOID Context,
  103. BOOLEAN TimedOut
  104. );
  105. VOID
  106. NatpFreeConnectionEntry(
  107. PNAT_CONNECTION_ENTRY pConEntry
  108. );
  109. VOID
  110. NatpFreePortMappingList(
  111. PNAT_CONNECTION_ENTRY pConEntry
  112. );
  113. PNAT_INTERFACE
  114. NatpLookupInterface(
  115. ULONG Index,
  116. OUT PLIST_ENTRY* InsertionPoint OPTIONAL
  117. );
  118. ULONG
  119. NatpQueryConnectionAdapter(
  120. ULONG Index
  121. );
  122. PIP_NAT_INTERFACE_INFO
  123. NatpQueryConnectionInformation(
  124. PNAT_CONNECTION_ENTRY pConEntry,
  125. PIP_ADAPTER_BINDING_INFO BindingInfo
  126. );
  127. VOID
  128. NatpProcessConfigurationChanged(
  129. VOID
  130. );
  131. VOID
  132. NatpProcessConnectionNotify(
  133. VOID
  134. );
  135. VOID NTAPI
  136. NatpRoutingFailureCallbackRoutine(
  137. PVOID Context,
  138. PIO_STATUS_BLOCK IoStatus,
  139. ULONG Reserved
  140. );
  141. VOID NTAPI
  142. NatpRoutingFailureWorkerRoutine(
  143. PVOID Context
  144. );
  145. ULONG
  146. NatpStartSharedConnectionManagement(
  147. VOID
  148. );
  149. ULONG
  150. NatpStopSharedConnectionManagement(
  151. VOID
  152. );
  153. VOID
  154. NatpUpdateSharedConnectionDomainName(
  155. ULONG AdapterIndex
  156. );
  157. BOOLEAN
  158. NatpUnbindConnection(
  159. PNAT_CONNECTION_ENTRY pConEntry
  160. );
  161. PNAT_CONNECTION_ENTRY
  162. NatFindConnectionEntry(
  163. GUID *pGuid
  164. )
  165. /*++
  166. Routine Description:
  167. Locates a connection entry by guid
  168. Arguments:
  169. pGuid - identifies the connection to locate
  170. Return Value:
  171. PNAT_CONNECTION_ENTRY - a pointer to the connection, or NULL
  172. if not found
  173. Environment:
  174. Invoked with 'NatInterfaceLock' held by the caller.
  175. --*/
  176. {
  177. PNAT_CONNECTION_ENTRY pConnection;
  178. PLIST_ENTRY pLink;
  179. for (pLink = NatpConnectionList.Flink;
  180. pLink != &NatpConnectionList;
  181. pLink = pLink->Flink)
  182. {
  183. pConnection = CONTAINING_RECORD(pLink, NAT_CONNECTION_ENTRY, Link);
  184. if (IsEqualGUID(pConnection->Guid, *pGuid))
  185. {
  186. return pConnection;
  187. }
  188. }
  189. return NULL;
  190. } // NatFindConnectionEntry
  191. PNAT_PORT_MAPPING_ENTRY
  192. NatFindPortMappingEntry(
  193. PNAT_CONNECTION_ENTRY pConnection,
  194. GUID *pGuid
  195. )
  196. /*++
  197. Routine Description:
  198. Locates a port mapping entry for a connection
  199. Arguments:
  200. pConnection - the connection to search
  201. pGuid - identifies the port mapping entry to locate
  202. Return Value:
  203. PNAT_PORT_MAPPING_ENTRY - a pointer to the port mapping, or NULL
  204. if not found
  205. Environment:
  206. Invoked with 'NatInterfaceLock' held by the caller.
  207. --*/
  208. {
  209. PNAT_PORT_MAPPING_ENTRY pMapping;
  210. PLIST_ENTRY pLink;
  211. for (pLink = pConnection->PortMappingList.Flink;
  212. pLink != &pConnection->PortMappingList;
  213. pLink = pLink->Flink)
  214. {
  215. pMapping = CONTAINING_RECORD(pLink, NAT_PORT_MAPPING_ENTRY, Link);
  216. if (IsEqualGUID(*pMapping->pProtocolGuid, *pGuid))
  217. {
  218. return pMapping;
  219. }
  220. }
  221. return NULL;
  222. } // NatFindPortMappingEntry
  223. VOID
  224. NatFreePortMappingEntry(
  225. PNAT_PORT_MAPPING_ENTRY pEntry
  226. )
  227. /*++
  228. Routine Description:
  229. Frees all resources associated with a port mapping entry. This
  230. entry must have already been removed from the containing port
  231. mapping list and destroyed at the kernel / UDP broadcast mapper
  232. level.
  233. Arguments:
  234. pEntry - the entry to free
  235. Return Value:
  236. none.
  237. --*/
  238. {
  239. ASSERT(NULL != pEntry);
  240. if (NULL != pEntry->pProtocolGuid)
  241. {
  242. CoTaskMemFree(pEntry->pProtocolGuid);
  243. }
  244. if (NULL != pEntry->pProtocol)
  245. {
  246. pEntry->pProtocol->Release();
  247. }
  248. if (NULL != pEntry->pBinding)
  249. {
  250. pEntry->pBinding->Release();
  251. }
  252. NH_FREE(pEntry);
  253. } // NatFreePortMappingEntry
  254. HRESULT
  255. NatpAddConnectionEntry(
  256. IUnknown *pUnk
  257. )
  258. /*++
  259. Routine Description:
  260. Creates a NAT_CONNECTION_ENTRY for a firewalled or Ics public connection.
  261. Arguments:
  262. pUnk - pointer to an IHNetFirewalledConnection or IHNetIcsPublicConnection.
  263. This need not be the canonical IUnknown (i.e., it's fine to pass in a
  264. pointer of either of the above interfaces).
  265. Return Value:
  266. Standard HRESULT
  267. Environment:
  268. Invoked with 'NatInterfaceLock' held by the caller.
  269. --*/
  270. {
  271. HRESULT hr = S_OK;
  272. PNAT_CONNECTION_ENTRY pNewEntry = NULL;
  273. IHNetConnection *pNetCon = NULL;
  274. //
  275. // Allocate new entry stucture
  276. //
  277. pNewEntry = reinterpret_cast<PNAT_CONNECTION_ENTRY>(
  278. NH_ALLOCATE(sizeof(*pNewEntry))
  279. );
  280. if (NULL != pNewEntry)
  281. {
  282. RtlZeroMemory(pNewEntry, sizeof(*pNewEntry));
  283. InitializeListHead(&pNewEntry->Link);
  284. InitializeListHead(&pNewEntry->PortMappingList);
  285. }
  286. else
  287. {
  288. hr = E_OUTOFMEMORY;
  289. }
  290. //
  291. // Get IHNetConnection interface
  292. //
  293. if (S_OK == hr)
  294. {
  295. hr = pUnk->QueryInterface(IID_PPV_ARG(IHNetConnection, &pNetCon));
  296. if (SUCCEEDED(hr))
  297. {
  298. pNewEntry->pHNetConnection = pNetCon;
  299. pNewEntry->pHNetConnection->AddRef();
  300. HNET_CONN_PROPERTIES *pProps;
  301. //
  302. // Get the properties for the connection
  303. //
  304. hr = pNetCon->GetProperties(&pProps);
  305. if (SUCCEEDED(hr))
  306. {
  307. //
  308. // Copy properties into entry
  309. //
  310. RtlCopyMemory(
  311. &pNewEntry->HNetProperties,
  312. pProps,
  313. sizeof(*pProps)
  314. );
  315. CoTaskMemFree(pProps);
  316. }
  317. }
  318. if (SUCCEEDED(hr))
  319. {
  320. GUID *pGuid;
  321. //
  322. // Get the guid of the connectoin
  323. //
  324. hr = pNetCon->GetGuid(&pGuid);
  325. if (SUCCEEDED(hr))
  326. {
  327. RtlCopyMemory(&pNewEntry->Guid, pGuid, sizeof(GUID));
  328. CoTaskMemFree(pGuid);
  329. }
  330. }
  331. if (SUCCEEDED(hr) && !pNewEntry->HNetProperties.fLanConnection)
  332. {
  333. //
  334. // Get the RAS phonebook path. We don't cache the
  335. // name since that can change over time.
  336. //
  337. hr = pNetCon->GetRasPhonebookPath(
  338. &pNewEntry->wszPhonebookPath
  339. );
  340. }
  341. }
  342. if (SUCCEEDED(hr) && pNewEntry->HNetProperties.fFirewalled)
  343. {
  344. //
  345. // Get the firewall control interface
  346. //
  347. hr = pNetCon->GetControlInterface(
  348. IID_PPV_ARG(IHNetFirewalledConnection, &pNewEntry->pHNetFwConnection)
  349. );
  350. if (SUCCEEDED(hr))
  351. {
  352. NatpFirewallConnectionCount += 1;
  353. }
  354. }
  355. if (SUCCEEDED(hr) && pNewEntry->HNetProperties.fIcsPublic)
  356. {
  357. //
  358. // Get the ICS public control interface
  359. //
  360. hr = pNetCon->GetControlInterface(
  361. IID_PPV_ARG(IHNetIcsPublicConnection, &pNewEntry->pHNetIcsPublicConnection)
  362. );
  363. if (SUCCEEDED(hr))
  364. {
  365. //
  366. // Remember that we now have a shared connection
  367. //
  368. NatpSharedConnectionPresent = TRUE;
  369. }
  370. }
  371. if (NULL != pNetCon)
  372. {
  373. pNetCon->Release();
  374. }
  375. if (SUCCEEDED(hr))
  376. {
  377. //
  378. // Add the new entry to the connection list. Ordering doesn't matter.
  379. //
  380. InsertTailList(&NatpConnectionList, &pNewEntry->Link);
  381. }
  382. else if (NULL != pNewEntry)
  383. {
  384. //
  385. // Cleanup the partially constructed entry
  386. //
  387. NatpFreeConnectionEntry(pNewEntry);
  388. }
  389. return hr;
  390. }
  391. ULONG
  392. NatpBindConnection(
  393. PNAT_CONNECTION_ENTRY pConEntry,
  394. HRASCONN Hrasconn,
  395. ULONG AdapterIndex,
  396. PIP_ADAPTER_BINDING_INFO BindingInfo
  397. )
  398. /*++
  399. Routine Description:
  400. This routine is responsible for binding the shared-connection.
  401. Arguments:
  402. pConEntry - the entry to bind
  403. Hrasconn - if the connection is a dialup connection,
  404. contains the handle for the active RAS connection.
  405. AdapterIndex - if the connection is a LAN connection,
  406. contains the adapter index for the active LAN connection.
  407. BindingInfo - if the connection is a LAN connection,
  408. contains the binding information for the active LAN interface.
  409. Return Value:
  410. ULONG - Win32 error.
  411. Environment:
  412. Invoked with 'NatInterfaceLock' held by the caller.
  413. --*/
  414. {
  415. ULONG Error;
  416. MIB_IPFORWARDROW IpForwardRow;
  417. GUID Guid;
  418. RASPPPIPA RasPppIp;
  419. ULONG Size;
  420. PLIST_ENTRY InsertionPoint;
  421. PLIST_ENTRY Link;
  422. PNAT_PORT_MAPPING_ENTRY PortMapping;
  423. HRESULT hr;
  424. if (NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  425. return NO_ERROR;
  426. }
  427. //
  428. // LAN public interfaces are handled differently than RAS public interfaces.
  429. // With a LAN interface, the binding information is passed in from
  430. // 'NatpProcessConnectionNotify'.
  431. // With a RAS inteface, though, we retrieve the projection-information
  432. // for the active connection, and map the address to an adapter index.
  433. //
  434. if (!pConEntry->HNetProperties.fLanConnection) {
  435. //
  436. // Allocate space for the binding info, if this has not yet
  437. // occured. (This memory will be freed in NatpFreeConnectionEntry.)
  438. //
  439. if (NULL == pConEntry->pBindingInfo) {
  440. pConEntry->pBindingInfo =
  441. reinterpret_cast<PIP_ADAPTER_BINDING_INFO>(
  442. NH_ALLOCATE(
  443. FIELD_OFFSET(IP_ADAPTER_BINDING_INFO, Address)
  444. + sizeof(IP_LOCAL_BINDING)
  445. )
  446. );
  447. if (NULL == pConEntry->pBindingInfo) {
  448. NhTrace(
  449. TRACE_FLAG_NAT,
  450. "NatpBindConnection: Unable to allocate binding info"
  451. );
  452. return ERROR_NOT_ENOUGH_MEMORY;
  453. }
  454. }
  455. //
  456. // Retrieve the PPP projection information for the interface.
  457. //
  458. ZeroMemory(&RasPppIp, sizeof(RasPppIp));
  459. Size = RasPppIp.dwSize = sizeof(RasPppIp);
  460. Error =
  461. RasGetProjectionInfoA(
  462. Hrasconn,
  463. RASP_PppIp,
  464. &RasPppIp,
  465. &Size
  466. );
  467. if (Error) {
  468. NhTrace(
  469. TRACE_FLAG_NAT,
  470. "NatpBindConnection: RasGetProjectionInfoA=%d",
  471. Error
  472. );
  473. return Error;
  474. }
  475. //
  476. // Convert the projection information to our format
  477. //
  478. BindingInfo = pConEntry->pBindingInfo;
  479. BindingInfo->AddressCount = 1;
  480. BindingInfo->RemoteAddress = 0;
  481. BindingInfo->Address[0].Address = inet_addr(RasPppIp.szIpAddress);
  482. BindingInfo->Address[0].Mask = 0xffffffff;
  483. //
  484. // Attempt to find the TCP/IP adapter index for the connection
  485. //
  486. AdapterIndex = NhMapAddressToAdapter(BindingInfo->Address[0].Address);
  487. if (AdapterIndex == (ULONG)-1) {
  488. NhTrace(
  489. TRACE_FLAG_NAT,
  490. "NatpBindConnection: MapAddressToAdapter failed"
  491. );
  492. return ERROR_NO_SUCH_INTERFACE;
  493. }
  494. //
  495. // Install a default route through the interface, if this is
  496. // the shared connection. (We don't want to do this for a
  497. // firewall-only connection.)
  498. //
  499. if (pConEntry->HNetProperties.fIcsPublic) {
  500. ZeroMemory(&IpForwardRow, sizeof(IpForwardRow));
  501. IpForwardRow.dwForwardNextHop =
  502. BindingInfo->Address[0].Address;
  503. IpForwardRow.dwForwardIfIndex = AdapterIndex;
  504. IpForwardRow.dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
  505. IpForwardRow.dwForwardProto = PROTO_IP_NAT;
  506. IpForwardRow.dwForwardMetric1 = 1;
  507. Error = SetIpForwardEntryToStack(&IpForwardRow);
  508. if (Error) {
  509. NhTrace(
  510. TRACE_FLAG_NAT,
  511. "NatpBindConnection: SetIpForwardEntryToStack=%d",
  512. Error
  513. );
  514. return Error;
  515. }
  516. }
  517. }
  518. pConEntry->AdapterIndex = AdapterIndex;
  519. //
  520. // Make sure the interface type is correct.
  521. //
  522. pConEntry->Interface.Type = ROUTER_IF_TYPE_INTERNAL;
  523. //
  524. // Set the interface index value. This can be anything except 0
  525. // (as 0 is reserved for the private connection).
  526. //
  527. do
  528. {
  529. pConEntry->Interface.Index =
  530. static_cast<ULONG>(InterlockedIncrement(&NatpNextInterfaceIndex));
  531. } while (0 == pConEntry->Interface.Index);
  532. //
  533. // Build the port mapping list for this connection
  534. //
  535. hr = NatpBuildPortMappingList(pConEntry, BindingInfo);
  536. if (FAILED(hr))
  537. {
  538. NhTrace(
  539. TRACE_FLAG_NAT,
  540. "NatpBindConnection: NatpBuildPortMappingList=0x%08x",
  541. hr
  542. );
  543. return ERROR_CAN_NOT_COMPLETE;
  544. }
  545. //
  546. // Bind the interface, building its configuration to include
  547. // any port-mappings configured as part of shared access settings.
  548. //
  549. pConEntry->Interface.Info =
  550. NatpQueryConnectionInformation(pConEntry, BindingInfo);
  551. if (NULL == pConEntry->Interface.Info) {
  552. NhTrace(
  553. TRACE_FLAG_NAT,
  554. "NatpBindConnection[%i]: NatpQueryConnectionInformation failed",
  555. pConEntry->Interface.Index
  556. );
  557. //
  558. // Free the port mapping list
  559. //
  560. NatpFreePortMappingList(pConEntry);
  561. return ERROR_CAN_NOT_COMPLETE;
  562. }
  563. Error =
  564. NatBindInterface(
  565. pConEntry->Interface.Index,
  566. &pConEntry->Interface,
  567. BindingInfo,
  568. AdapterIndex
  569. );
  570. if (Error) {
  571. NhTrace(
  572. TRACE_FLAG_NAT,
  573. "NatpBindConnection[%i]: NatBindInterface=%d",
  574. pConEntry->Interface.Index,
  575. Error
  576. );
  577. //
  578. // Free the port mapping list
  579. //
  580. NatpFreePortMappingList(pConEntry);
  581. return Error;
  582. }
  583. //
  584. // At this point NAT_INTERFACE_FLAG_BOUND has been set on the
  585. // interface, so we don't need to clean up the port mapping
  586. // list on error, as the list will be cleaned up in
  587. // NatpUnbindConnection.
  588. //
  589. //
  590. // Create UDP broadcast mappings if this is the ICS
  591. // public connection.
  592. //
  593. if (pConEntry->HNetProperties.fIcsPublic
  594. && 0 != pConEntry->UdpBroadcastPortMappingCount)
  595. {
  596. DWORD dwAddress;
  597. DWORD dwMask;
  598. DWORD dwBroadcastAddress;
  599. ASSERT(NULL != NhpUdpBroadcastMapper);
  600. ASSERT(!IsListEmpty(&pConEntry->PortMappingList));
  601. if (NhQueryScopeInformation(&dwAddress, &dwMask))
  602. {
  603. dwBroadcastAddress = (dwAddress & dwMask) | ~dwMask;
  604. for (Link = pConEntry->PortMappingList.Flink;
  605. Link != &pConEntry->PortMappingList;
  606. Link = Link->Flink)
  607. {
  608. PortMapping =
  609. CONTAINING_RECORD(Link, NAT_PORT_MAPPING_ENTRY, Link);
  610. if (!PortMapping->fUdpBroadcastMapping) { continue; }
  611. hr = NhpUdpBroadcastMapper->CreateUdpBroadcastMapping(
  612. PortMapping->usPublicPort,
  613. AdapterIndex,
  614. dwBroadcastAddress,
  615. &PortMapping->pvBroadcastCookie
  616. );
  617. if (FAILED(hr))
  618. {
  619. //
  620. // We'll continue if an error occurs here.
  621. //
  622. NhTrace(
  623. TRACE_FLAG_INIT,
  624. "NatpBindConnection: CreateUdpBroadcastMapping=0x%08x",
  625. hr
  626. );
  627. }
  628. }
  629. }
  630. }
  631. //
  632. // Make sure that the interface is on the global list (so that the
  633. // FTP, ALG, and H.323 proxies will be able to find its configuration).
  634. //
  635. if (!NatpLookupInterface(
  636. pConEntry->Interface.Index,
  637. &InsertionPoint
  638. )) {
  639. InsertTailList(InsertionPoint, &pConEntry->Interface.Link);
  640. }
  641. #ifndef NO_FTP_PROXY
  642. //
  643. // Add the interface the the FTP proxy, if this has not yet
  644. // happened.
  645. //
  646. if (!NAT_INTERFACE_ADDED_FTP(&pConEntry->Interface)) {
  647. Error =
  648. FtpRmAddInterface(
  649. NULL,
  650. pConEntry->Interface.Index,
  651. PERMANENT,
  652. IF_TYPE_OTHER,
  653. IF_ACCESS_BROADCAST,
  654. IF_CONNECTION_DEDICATED,
  655. NULL,
  656. IP_NAT_VERSION,
  657. 0,
  658. 0
  659. );
  660. if (Error) {
  661. NhTrace(
  662. TRACE_FLAG_INIT,
  663. "NatpBindConnection: FtpRmAddInterface=%d",
  664. Error
  665. );
  666. return Error;
  667. }
  668. pConEntry->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_FTP;
  669. }
  670. //
  671. // Bind and enable the interface for FTP
  672. //
  673. Error = FtpRmBindInterface(pConEntry->Interface.Index, BindingInfo);
  674. if (Error) {
  675. NhTrace(
  676. TRACE_FLAG_INIT,
  677. "NatpBindConnection: FtpRmBindInterface=%d",
  678. Error
  679. );
  680. return Error;
  681. }
  682. Error = FtpRmEnableInterface(pConEntry->Interface.Index);
  683. if (Error) {
  684. NhTrace(
  685. TRACE_FLAG_INIT,
  686. "NatpBindConnection: FtpRmEnableInterface=%d",
  687. Error
  688. );
  689. return Error;
  690. }
  691. #endif
  692. //
  693. // Add the interface the the ALG proxy, if this has not yet
  694. // happened.
  695. //
  696. if (!NAT_INTERFACE_ADDED_ALG(&pConEntry->Interface)) {
  697. Error =
  698. AlgRmAddInterface(
  699. NULL,
  700. pConEntry->Interface.Index,
  701. PERMANENT,
  702. IF_TYPE_OTHER,
  703. IF_ACCESS_BROADCAST,
  704. IF_CONNECTION_DEDICATED,
  705. NULL,
  706. IP_NAT_VERSION,
  707. 0,
  708. 0
  709. );
  710. if (Error) {
  711. NhTrace(
  712. TRACE_FLAG_INIT,
  713. "NatpBindConnection: AlgRmAddInterface=%d",
  714. Error
  715. );
  716. return Error;
  717. }
  718. pConEntry->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_ALG;
  719. }
  720. //
  721. // Bind and enable the interface for ALG
  722. //
  723. Error = AlgRmBindInterface(pConEntry->Interface.Index, BindingInfo);
  724. if (Error) {
  725. NhTrace(
  726. TRACE_FLAG_INIT,
  727. "NatpBindConnection: AlgRmBindInterface=%d",
  728. Error
  729. );
  730. return Error;
  731. }
  732. Error = AlgRmEnableInterface(pConEntry->Interface.Index);
  733. if (Error) {
  734. NhTrace(
  735. TRACE_FLAG_INIT,
  736. "NatpBindConnection: AlgRmEnableInterface=%d",
  737. Error
  738. );
  739. return Error;
  740. }
  741. //
  742. // Add the interface the the H.323 proxy, if this has not yet
  743. // happened.
  744. //
  745. if (!NAT_INTERFACE_ADDED_H323(&pConEntry->Interface)) {
  746. Error =
  747. H323RmAddInterface(
  748. NULL,
  749. pConEntry->Interface.Index,
  750. PERMANENT,
  751. IF_TYPE_OTHER,
  752. IF_ACCESS_BROADCAST,
  753. IF_CONNECTION_DEDICATED,
  754. NULL,
  755. IP_NAT_VERSION,
  756. 0,
  757. 0
  758. );
  759. if (Error) {
  760. NhTrace(
  761. TRACE_FLAG_INIT,
  762. "NatpBindConnection: H323RmAddInterface=%d",
  763. Error
  764. );
  765. return Error;
  766. }
  767. pConEntry->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_H323;
  768. }
  769. //
  770. // Bind and enable the interface for H323
  771. //
  772. Error = H323RmBindInterface(pConEntry->Interface.Index, BindingInfo);
  773. if (Error) {
  774. NhTrace(
  775. TRACE_FLAG_INIT,
  776. "NatpBindConnection: H323RmBindInterface=%d",
  777. Error
  778. );
  779. return Error;
  780. }
  781. Error = H323RmEnableInterface(pConEntry->Interface.Index);
  782. if (Error) {
  783. NhTrace(
  784. TRACE_FLAG_INIT,
  785. "NatpBindConnection: H323RmEnableInterface=%d",
  786. Error
  787. );
  788. return Error;
  789. }
  790. if (pConEntry->HNetProperties.fIcsPublic) {
  791. //
  792. // Finally, update the DNS domain name cached for the shared connection.
  793. //
  794. NatpUpdateSharedConnectionDomainName(AdapterIndex);
  795. }
  796. return NO_ERROR;
  797. } // NatpBindConnection
  798. HRESULT
  799. NatpBuildPortMappingList(
  800. PNAT_CONNECTION_ENTRY pConEntry,
  801. PIP_ADAPTER_BINDING_INFO pBindingInfo
  802. )
  803. /*++
  804. Routine Description:
  805. Builds the list of port mappings for a connection entry
  806. Arguments:
  807. pConEntry - the entry to build the list for
  808. pBindingInfo - the binding info for that entry
  809. Return Value:
  810. Standard HRESULT.
  811. Environment:
  812. NatInterfaceLock must be held by the caller.
  813. --*/
  814. {
  815. HRESULT hr;
  816. IHNetPortMappingBinding *pBinding;
  817. PNAT_PORT_MAPPING_ENTRY pEntry;
  818. IEnumHNetPortMappingBindings *pEnum;
  819. PLIST_ENTRY pLink;
  820. IHNetPortMappingProtocol *pProtocol;
  821. ULONG ulCount;
  822. PROFILE("NatpBuildPortMappingList");
  823. hr = pConEntry->pHNetConnection->EnumPortMappings(TRUE, &pEnum);
  824. if (FAILED(hr))
  825. {
  826. NhTrace(
  827. TRACE_FLAG_NAT,
  828. "NatpBuildPortMappingList: EnumPortMappings 0x%08x",
  829. hr
  830. );
  831. return hr;
  832. }
  833. //
  834. // Process enumeration, creating the port mapping entries.
  835. //
  836. do
  837. {
  838. hr = pEnum->Next(1, &pBinding, &ulCount);
  839. if (SUCCEEDED(hr) && 1 == ulCount)
  840. {
  841. pEntry =
  842. reinterpret_cast<PNAT_PORT_MAPPING_ENTRY>(
  843. NH_ALLOCATE(sizeof(*pEntry))
  844. );
  845. if (NULL != pEntry)
  846. {
  847. ZeroMemory(pEntry, sizeof(*pEntry));
  848. //
  849. // Get the protocol for the binding
  850. //
  851. hr = pBinding->GetProtocol(&pProtocol);
  852. }
  853. else
  854. {
  855. hr = E_OUTOFMEMORY;
  856. }
  857. if (SUCCEEDED(hr))
  858. {
  859. //
  860. // Fill out the entry
  861. //
  862. hr = pProtocol->GetGuid(&pEntry->pProtocolGuid);
  863. if (SUCCEEDED(hr))
  864. {
  865. hr = pProtocol->GetIPProtocol(&pEntry->ucProtocol);
  866. }
  867. if (SUCCEEDED(hr))
  868. {
  869. hr = pProtocol->GetPort(&pEntry->usPublicPort);
  870. }
  871. if (SUCCEEDED(hr))
  872. {
  873. hr = pBinding->GetTargetPort(&pEntry->usPrivatePort);
  874. }
  875. if (SUCCEEDED(hr))
  876. {
  877. //
  878. // We need to know if the name is active in order to
  879. // avoid rebuilding the DHCP reservation list more
  880. // than necessary.
  881. //
  882. hr = pBinding->GetCurrentMethod(&pEntry->fNameActive);
  883. }
  884. if (SUCCEEDED(hr))
  885. {
  886. //
  887. // If this is a FW-only connection, use the address from
  888. // our binding info instead of the protocol binding.
  889. //
  890. if (!pConEntry->HNetProperties.fIcsPublic)
  891. {
  892. pEntry->ulPrivateAddress =
  893. pBindingInfo->Address[0].Address;
  894. }
  895. else
  896. {
  897. hr = pBinding->GetTargetComputerAddress(
  898. &pEntry->ulPrivateAddress
  899. );
  900. if (SUCCEEDED(hr)
  901. && INADDR_LOOPBACK_NO == pEntry->ulPrivateAddress)
  902. {
  903. //
  904. // If the port mapping targets the loopback address
  905. // we want to use the address from the binding
  906. // info instead.
  907. //
  908. pEntry->ulPrivateAddress =
  909. pBindingInfo->Address[0].Address;
  910. }
  911. }
  912. }
  913. if (SUCCEEDED(hr))
  914. {
  915. pEntry->pBinding = pBinding;
  916. pEntry->pBinding->AddRef();
  917. pEntry->pProtocol = pProtocol;
  918. pEntry->pProtocol->AddRef();
  919. //
  920. // Check to see if this mapping is:
  921. // 1) targeted at the broadcast address, and
  922. // 2) is UDP.
  923. //
  924. if (NAT_PROTOCOL_UDP == pEntry->ucProtocol
  925. && 0xffffffff == pEntry->ulPrivateAddress)
  926. {
  927. pEntry->fUdpBroadcastMapping = TRUE;
  928. pConEntry->UdpBroadcastPortMappingCount += 1;
  929. }
  930. else
  931. {
  932. pConEntry->PortMappingCount += 1;
  933. }
  934. InsertTailList(&pConEntry->PortMappingList, &pEntry->Link);
  935. }
  936. else
  937. {
  938. NatFreePortMappingEntry(pEntry);
  939. }
  940. pProtocol->Release();
  941. }
  942. //
  943. // If anything failed above we still want to continue operation --
  944. // it's preferable to have the firewall running w/ some port
  945. // mapping entries missing instead of not having the firewall
  946. // run at all.
  947. //
  948. hr = S_OK;
  949. pBinding->Release();
  950. }
  951. } while (SUCCEEDED(hr) && 1 == ulCount);
  952. pEnum->Release();
  953. if (FAILED(hr))
  954. {
  955. //
  956. // Free the port mapping list
  957. //
  958. NatpFreePortMappingList(pConEntry);
  959. }
  960. return hr;
  961. }// NatpBuildPortMappingList
  962. VOID NTAPI
  963. NatpConfigurationChangedCallbackRoutine(
  964. PVOID Context,
  965. BOOLEAN TimedOut
  966. )
  967. /*++
  968. Routine Description:
  969. This routine is invoked upon a change in the NAT/Firewall
  970. configuration.
  971. It may also be invoked when cleanup is in progress.
  972. Arguments:
  973. Context - unused
  974. TimedOut - unused
  975. Return Value:
  976. none.
  977. Environment:
  978. The routine runs in the context of an Rtl wait-thread.
  979. (See 'RtlRegisterWait'.)
  980. A reference to the component will have been made on our behalf
  981. when 'RtlRegisterWait' was called. The reference is released
  982. and re-acquired here.
  983. --*/
  984. {
  985. BOOLEAN ComInitialized = TRUE;
  986. HRESULT hr;
  987. PROFILE("NatpConfigurationChangedCallbackRoutine");
  988. //
  989. // See whether cleanup has occurred
  990. //
  991. EnterCriticalSection(&NatInterfaceLock);
  992. if (!NatConfigurationChangedEvent) {
  993. LeaveCriticalSection(&NatInterfaceLock);
  994. DEREFERENCE_NAT();
  995. return;
  996. }
  997. LeaveCriticalSection(&NatInterfaceLock);
  998. //
  999. // Acquire a new reference to the component (and release
  1000. // our original reference on failure).
  1001. //
  1002. if (!REFERENCE_NAT()) { DEREFERENCE_NAT(); return; }
  1003. //
  1004. // Make sure the thread is COM-initialized
  1005. //
  1006. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
  1007. if (FAILED(hr))
  1008. {
  1009. ComInitialized = FALSE;
  1010. if (RPC_E_CHANGED_MODE == hr)
  1011. {
  1012. ASSERT(FALSE);
  1013. hr = S_OK;
  1014. NhTrace(
  1015. TRACE_FLAG_NAT,
  1016. "NatpConfigurationChangedCallbackRoutine: Unexpectedly in STA."
  1017. );
  1018. }
  1019. }
  1020. //
  1021. // Process connection notifications
  1022. //
  1023. if (SUCCEEDED(hr))
  1024. {
  1025. NatpProcessConfigurationChanged();
  1026. }
  1027. //
  1028. // Uninitialize COM, if necessary
  1029. //
  1030. if (TRUE == ComInitialized)
  1031. {
  1032. CoUninitialize();
  1033. }
  1034. //
  1035. // Release our original reference to the component.
  1036. //
  1037. DEREFERENCE_NAT();
  1038. } // NatpConfigurationChangedCallbackRoutine
  1039. VOID NTAPI
  1040. NatpConnectionNotifyCallbackRoutine(
  1041. PVOID Context,
  1042. BOOLEAN TimedOut
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. This routine is invoked upon connection or disconnection
  1047. of a RAS phonebook entry.
  1048. It may also be invoked when cleanup is in progress.
  1049. Arguments:
  1050. Context - unused
  1051. TimedOut - unused
  1052. Return Value:
  1053. none.
  1054. Environment:
  1055. The routine runs in the context of an Rtl wait-thread.
  1056. (See 'RtlRegisterWait'.)
  1057. A reference to the component will have been made on our behalf
  1058. when 'RtlRegisterWait' was called. The reference is released
  1059. and re-acquired here.
  1060. --*/
  1061. {
  1062. BOOLEAN ComInitialized = TRUE;
  1063. HRESULT hr;
  1064. PROFILE("NatpConnectionNotifyCallbackRoutine");
  1065. //
  1066. // See whether cleanup has occurred
  1067. //
  1068. EnterCriticalSection(&NatInterfaceLock);
  1069. if (!NatConnectionNotifyEvent) {
  1070. LeaveCriticalSection(&NatInterfaceLock);
  1071. DEREFERENCE_NAT();
  1072. return;
  1073. }
  1074. LeaveCriticalSection(&NatInterfaceLock);
  1075. //
  1076. // Acquire a new reference to the component (and release
  1077. // our original reference on failure).
  1078. //
  1079. if (!REFERENCE_NAT()) { DEREFERENCE_NAT(); return; }
  1080. //
  1081. // Make sure the thread is COM-initialized
  1082. //
  1083. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
  1084. if (FAILED(hr))
  1085. {
  1086. ComInitialized = FALSE;
  1087. if (RPC_E_CHANGED_MODE == hr)
  1088. {
  1089. ASSERT(FALSE);
  1090. hr = S_OK;
  1091. NhTrace(
  1092. TRACE_FLAG_NAT,
  1093. "NatpConnectionNotifyCallbackRoutine: Unexpectedly in STA."
  1094. );
  1095. }
  1096. }
  1097. //
  1098. // Process connection notifications
  1099. //
  1100. if (SUCCEEDED(hr))
  1101. {
  1102. NatpProcessConnectionNotify();
  1103. }
  1104. //
  1105. // Uninitialize COM, if necessary
  1106. //
  1107. if (TRUE == ComInitialized)
  1108. {
  1109. CoUninitialize();
  1110. }
  1111. //
  1112. // Release our original reference to the component.
  1113. //
  1114. DEREFERENCE_NAT();
  1115. } // NatpConnectionNotifyCallbackRoutine
  1116. VOID NTAPI
  1117. NatpEnableRouterCallbackRoutine(
  1118. PVOID Context,
  1119. BOOLEAN TimedOut
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. This routine is invoked upon completion or cancellation of an outstanding
  1124. request to enable IP forwarding. It determines whether the module is still
  1125. running and, if so, re-enables forwarding. Otherwise, it cancels any
  1126. existing request and returns control immediately.
  1127. Arguments:
  1128. none used.
  1129. Return Value:
  1130. none.
  1131. Environment:
  1132. The routine runs in the context of an Rtl wait-thread.
  1133. (See 'RtlRegisterWait'.)
  1134. A reference to the component will have been made on our behalf
  1135. when 'RtlRegisterWait' was called. The reference is released
  1136. and re-acquired here.
  1137. --*/
  1138. {
  1139. ULONG Error;
  1140. HANDLE UnusedHandle;
  1141. PROFILE("NatpEnableRouterCallbackRoutine");
  1142. //
  1143. // See whether cleanup has occurred and, if so, restore forwarding
  1144. // to its original setting. Otherwise, acquire a new reference to the
  1145. // component, and release the original reference.
  1146. //
  1147. EnterCriticalSection(&NatInterfaceLock);
  1148. if (!NatpEnableRouterEvent || !REFERENCE_NAT()) {
  1149. UnenableRouter(&NatpEnableRouterOverlapped, NULL);
  1150. LeaveCriticalSection(&NatInterfaceLock);
  1151. DEREFERENCE_NAT();
  1152. return;
  1153. }
  1154. DEREFERENCE_NAT();
  1155. //
  1156. // Re-enable forwarding
  1157. //
  1158. ZeroMemory(&NatpEnableRouterOverlapped, sizeof(OVERLAPPED));
  1159. NatpEnableRouterOverlapped.hEvent = NatpEnableRouterEvent;
  1160. Error = EnableRouter(&UnusedHandle, &NatpEnableRouterOverlapped);
  1161. if (Error != ERROR_IO_PENDING) {
  1162. NhTrace(
  1163. TRACE_FLAG_NAT,
  1164. "NatpEnableRouterCallbackRoutine: EnableRouter=%d", Error
  1165. );
  1166. }
  1167. LeaveCriticalSection(&NatInterfaceLock);
  1168. } // NatpEnableRouterCallbackRoutine
  1169. VOID
  1170. NatpFreeConnectionEntry(
  1171. PNAT_CONNECTION_ENTRY pConEntry
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. Frees all resources associated with a connection entry. This entry
  1176. must have already been removed from the connection list.
  1177. Arguments:
  1178. pConEntry - the entry to free
  1179. Return Value:
  1180. none.
  1181. --*/
  1182. {
  1183. PROFILE("NatpFreeConnectionEntry");
  1184. if (NULL != pConEntry->pInterfaceInfo)
  1185. {
  1186. NH_FREE(pConEntry->pInterfaceInfo);
  1187. }
  1188. if (NULL != pConEntry->pBindingInfo)
  1189. {
  1190. NH_FREE(pConEntry->pBindingInfo);
  1191. }
  1192. if (NULL != pConEntry->pHNetConnection)
  1193. {
  1194. pConEntry->pHNetConnection->Release();
  1195. }
  1196. if (NULL != pConEntry->pHNetFwConnection)
  1197. {
  1198. pConEntry->pHNetFwConnection->Release();
  1199. }
  1200. if (NULL != pConEntry->pHNetIcsPublicConnection)
  1201. {
  1202. pConEntry->pHNetIcsPublicConnection->Release();
  1203. }
  1204. if (NULL != pConEntry->wszPhonebookPath)
  1205. {
  1206. CoTaskMemFree(pConEntry->wszPhonebookPath);
  1207. }
  1208. NatpFreePortMappingList(pConEntry);
  1209. NH_FREE(pConEntry);
  1210. } // NatpFreeConnectionEntry
  1211. VOID
  1212. NatpFreePortMappingList(
  1213. PNAT_CONNECTION_ENTRY pConEntry
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. Frees the port mapping list for a connection entry. This
  1218. includes cancelling any active UDP broadcast mappings.
  1219. Arguments:
  1220. pConEntry - the entry to free
  1221. Return Value:
  1222. none.
  1223. Environment:
  1224. Invoked w/ NatInterfaceLock held by the caller
  1225. --*/
  1226. {
  1227. PLIST_ENTRY pLink;
  1228. PNAT_PORT_MAPPING_ENTRY pMapping;
  1229. while (!IsListEmpty(&pConEntry->PortMappingList))
  1230. {
  1231. pLink = RemoveHeadList(&pConEntry->PortMappingList);
  1232. pMapping = CONTAINING_RECORD(pLink, NAT_PORT_MAPPING_ENTRY, Link);
  1233. if (pMapping->fUdpBroadcastMapping &&
  1234. NULL != pMapping->pvBroadcastCookie)
  1235. {
  1236. ASSERT(NULL != NhpUdpBroadcastMapper);
  1237. NhpUdpBroadcastMapper->CancelUdpBroadcastMapping(
  1238. pMapping->pvBroadcastCookie
  1239. );
  1240. }
  1241. NatFreePortMappingEntry(pMapping);
  1242. }
  1243. pConEntry->PortMappingCount = 0;
  1244. pConEntry->UdpBroadcastPortMappingCount = 0;
  1245. } // NatpFreePortMappingList
  1246. VOID
  1247. NatpProcessConfigurationChanged(
  1248. VOID
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. This routine is invoked to see when the NAT/Firewall configuration
  1253. changes. It unbinds the old interfaces, and binds the new ones.
  1254. It is also responsible for making sure that the autodial service
  1255. is running.
  1256. Arguments:
  1257. none.
  1258. Return Value:
  1259. none.
  1260. --*/
  1261. {
  1262. PLIST_ENTRY Link;
  1263. PNAT_CONNECTION_ENTRY pConEntry;
  1264. HRESULT hr;
  1265. IHNetCfgMgr *pCfgMgr = NULL;
  1266. IHNetFirewallSettings *pFwSettings;
  1267. IHNetIcsSettings *pIcsSettings;
  1268. IEnumHNetFirewalledConnections *pFwEnum;
  1269. IHNetFirewalledConnection *pFwConn;
  1270. IEnumHNetIcsPublicConnections *pIcsEnum;
  1271. IHNetIcsPublicConnection *pIcsConn;
  1272. ULONG ulCount;
  1273. UNICODE_STRING UnicodeString;
  1274. PROFILE("NatpProcessConfigurationChanged");
  1275. EnterCriticalSection(&NatInterfaceLock);
  1276. //
  1277. // Start by deleting all of our current connections
  1278. //
  1279. while (!IsListEmpty(&NatpConnectionList))
  1280. {
  1281. Link = RemoveHeadList(&NatpConnectionList);
  1282. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  1283. NatpUnbindConnection(pConEntry);
  1284. NatpFreeConnectionEntry(pConEntry);
  1285. }
  1286. //
  1287. // Reset other items to initial state
  1288. //
  1289. NatpFirewallConnectionCount = 0;
  1290. NatpSharedConnectionPresent = FALSE;
  1291. if (NULL != NatpSharedConnectionDomainName)
  1292. {
  1293. NH_FREE(NatpSharedConnectionDomainName);
  1294. NatpSharedConnectionDomainName = NULL;
  1295. }
  1296. //
  1297. // Get the configuration manager
  1298. //
  1299. hr = NhGetHNetCfgMgr(&pCfgMgr);
  1300. if (NhPolicyAllowsFirewall)
  1301. {
  1302. if (SUCCEEDED(hr))
  1303. {
  1304. //
  1305. // Get the firewall settings interface
  1306. //
  1307. hr = pCfgMgr->QueryInterface(
  1308. IID_PPV_ARG(IHNetFirewallSettings, &pFwSettings)
  1309. );
  1310. }
  1311. if (SUCCEEDED(hr))
  1312. {
  1313. //
  1314. // Get the enumeration of firewalled connections
  1315. //
  1316. hr = pFwSettings->EnumFirewalledConnections(&pFwEnum);
  1317. pFwSettings->Release();
  1318. }
  1319. if (SUCCEEDED(hr))
  1320. {
  1321. //
  1322. // Process the enumeration
  1323. //
  1324. do
  1325. {
  1326. hr = pFwEnum->Next(1, &pFwConn, &ulCount);
  1327. if (SUCCEEDED(hr) && 1 == ulCount)
  1328. {
  1329. //
  1330. // We don't check the return code for NatpAddConnectionEntry.
  1331. // NatpAddConnectionEntry will clean up gracefully if an
  1332. // error occurs and will leave the system in a consistent
  1333. // state, so an error will not prevent us from processing
  1334. // the rest of the connections.
  1335. //
  1336. NatpAddConnectionEntry(pFwConn);
  1337. pFwConn->Release();
  1338. }
  1339. }
  1340. while (SUCCEEDED(hr) && 1 == ulCount);
  1341. pFwEnum->Release();
  1342. }
  1343. }
  1344. //
  1345. // If we don't yet have a shared connection (i.e., none of the
  1346. // firewalled connections were also IcsPublic), retrieve that
  1347. // enumeration now.
  1348. //
  1349. if (FALSE == NatpSharedConnectionPresent
  1350. && NULL != pCfgMgr
  1351. && NhPolicyAllowsSharing)
  1352. {
  1353. //
  1354. // Get the IcsSettings interface
  1355. //
  1356. hr = pCfgMgr->QueryInterface(
  1357. IID_PPV_ARG(IHNetIcsSettings, &pIcsSettings)
  1358. );
  1359. if (SUCCEEDED(hr))
  1360. {
  1361. //
  1362. // Get the enumeration of ICS public connections
  1363. //
  1364. hr = pIcsSettings->EnumIcsPublicConnections(&pIcsEnum);
  1365. pIcsSettings->Release();
  1366. }
  1367. if (SUCCEEDED(hr))
  1368. {
  1369. //
  1370. // See if we can get a connection out of the enum
  1371. //
  1372. hr = pIcsEnum->Next(1, &pIcsConn, &ulCount);
  1373. if (SUCCEEDED(hr) && 1 == ulCount)
  1374. {
  1375. //
  1376. // We don't check the return code for NatpAddConnectionEntry.
  1377. // NatpAddConnectionEntry will clean up gracefully if an
  1378. // error occurs and will leave the system in a consistent
  1379. // state, so an error will not prevent us from processing
  1380. // the rest of the connections.
  1381. //
  1382. NatpAddConnectionEntry(pIcsConn);
  1383. pIcsConn->Release();
  1384. }
  1385. pIcsEnum->Release();
  1386. }
  1387. }
  1388. if (TRUE == NatpSharedConnectionPresent && NhPolicyAllowsSharing)
  1389. {
  1390. //
  1391. // Make sure shared connection management is started
  1392. //
  1393. NatpStartSharedConnectionManagement();
  1394. }
  1395. else
  1396. {
  1397. //
  1398. // Stop shared connection management
  1399. //
  1400. NatpStopSharedConnectionManagement();
  1401. }
  1402. //
  1403. // Notify the firewall subsystem as to whether it needs to
  1404. // start or stop logging. (These calls are effectively no-ops if
  1405. // the logger is already in the correct state.)
  1406. //
  1407. if (NatpFirewallConnectionCount > 0 && NhPolicyAllowsFirewall)
  1408. {
  1409. FwStartLogging();
  1410. }
  1411. else
  1412. {
  1413. FwStopLogging();
  1414. }
  1415. //
  1416. // Bind connections
  1417. //
  1418. NatpProcessConnectionNotify();
  1419. if (NULL != pCfgMgr)
  1420. {
  1421. pCfgMgr->Release();
  1422. }
  1423. LeaveCriticalSection(&NatInterfaceLock);
  1424. } // NatpProcessConfigurationChanged
  1425. VOID
  1426. NatpProcessConnectionNotify(
  1427. VOID
  1428. )
  1429. /*++
  1430. Routine Description:
  1431. This routine is invoked to see if the shared or firewall connections,
  1432. if any, have been connected or disconnected since its last invocation.
  1433. Arguments:
  1434. none.
  1435. Return Value:
  1436. none.
  1437. --*/
  1438. {
  1439. PLIST_ENTRY Link;
  1440. PNAT_CONNECTION_ENTRY pConEntry;
  1441. BOOLEAN Active;
  1442. ULONG i;
  1443. ULONG AdapterIndex;
  1444. PIP_ADAPTER_BINDING_INFO BindingInfo = NULL;
  1445. ULONG Error;
  1446. HRASCONN Hrasconn;
  1447. GUID Guid;
  1448. UNICODE_STRING UnicodeString;
  1449. NTSTATUS Status;
  1450. BOOLEAN bUPnPEventAlreadyFired = FALSE;
  1451. PROFILE("NatpProcessConnectionNotify");
  1452. EnterCriticalSection(&NatInterfaceLock);
  1453. //
  1454. // Walk through the connection list
  1455. //
  1456. for (Link = NatpConnectionList.Flink;
  1457. Link != &NatpConnectionList;
  1458. Link = Link->Flink)
  1459. {
  1460. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  1461. //
  1462. // If the connection is a LAN connection,
  1463. // it is always active.
  1464. //
  1465. // If the connection is a dialup connection,
  1466. // find out whether the connection is active.
  1467. //
  1468. if (pConEntry->HNetProperties.fLanConnection) {
  1469. Hrasconn = NULL;
  1470. Active = TRUE;
  1471. //
  1472. // The connection is a LAN connection, so we need to detect
  1473. // any changes to its IP address if it is already bound.
  1474. // To do so we retrieve the current binding information
  1475. // and compare it to the active binding information.
  1476. // If the two are different, we unbind the interface and rebind.
  1477. //
  1478. Status =
  1479. RtlStringFromGUID(pConEntry->Guid, &UnicodeString);
  1480. if (NT_SUCCESS(Status)) {
  1481. AdapterIndex = NhMapGuidToAdapter(UnicodeString.Buffer);
  1482. RtlFreeUnicodeString(&UnicodeString);
  1483. } else {
  1484. AdapterIndex = (ULONG)-1;
  1485. NhTrace(
  1486. TRACE_FLAG_NAT,
  1487. "NatpProcessConnectionNotify: RtlStringFromGUID failed\n"
  1488. );
  1489. }
  1490. if (AdapterIndex == (ULONG)-1) {
  1491. NhTrace(
  1492. TRACE_FLAG_NAT,
  1493. "NatpProcessConnectionNotify: MapGuidToAdapter failed\n"
  1494. );
  1495. Active = FALSE;
  1496. } else {
  1497. BindingInfo = NhQueryBindingInformation(AdapterIndex);
  1498. if (!BindingInfo) {
  1499. NhTrace(
  1500. TRACE_FLAG_NAT,
  1501. "NatpProcessConnectionNotify: QueryBinding failed\n"
  1502. );
  1503. Active = FALSE;
  1504. } else if (NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  1505. //
  1506. // The interface is already bound;
  1507. // compare the retrieved binding to the active binding,
  1508. // and unbind the connection if they are different.
  1509. //
  1510. if (!pConEntry->pBindingInfo ||
  1511. BindingInfo->AddressCount !=
  1512. pConEntry->pBindingInfo->AddressCount ||
  1513. !BindingInfo->AddressCount ||
  1514. !RtlEqualMemory(
  1515. &BindingInfo->Address[0],
  1516. &pConEntry->pBindingInfo->Address[0],
  1517. sizeof(IP_LOCAL_BINDING)
  1518. )) {
  1519. NatpUnbindConnection(pConEntry);
  1520. if ( pConEntry->HNetProperties.fIcsPublic )
  1521. {
  1522. FireNATEvent_PublicIPAddressChanged();
  1523. bUPnPEventAlreadyFired = TRUE;
  1524. }
  1525. } else {
  1526. //
  1527. // The bindings are the same, and the interface is bound
  1528. // already, so we won't be needing the newly-retrieved
  1529. // binding information.
  1530. //
  1531. NH_FREE(BindingInfo);
  1532. BindingInfo = NULL;
  1533. }
  1534. }
  1535. }
  1536. } else {
  1537. AdapterIndex = (ULONG)-1;
  1538. Hrasconn = NULL;
  1539. //
  1540. // Obtain the name of the connection
  1541. //
  1542. HRESULT hr;
  1543. LPWSTR wszEntryName;
  1544. hr = pConEntry->pHNetConnection->GetName(&wszEntryName);
  1545. if (SUCCEEDED(hr)) {
  1546. Error =
  1547. RasGetEntryHrasconnW(
  1548. pConEntry->wszPhonebookPath,
  1549. wszEntryName,
  1550. &Hrasconn
  1551. );
  1552. CoTaskMemFree(wszEntryName);
  1553. }
  1554. Active = ((FAILED(hr) || Error || !Hrasconn) ? FALSE : TRUE);
  1555. }
  1556. //
  1557. // Activate or deactivate the shared-connection as needed;
  1558. // when activating a LAN connection, we save the binding information
  1559. // so we can detect address changes later on.
  1560. //
  1561. if (!Active && NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  1562. NatpUnbindConnection(pConEntry);
  1563. if (pConEntry->HNetProperties.fIcsPublic &&
  1564. (FALSE == bUPnPEventAlreadyFired))
  1565. {
  1566. FireNATEvent_PublicIPAddressChanged();
  1567. }
  1568. } else if (Active && !NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  1569. //
  1570. // N.B. When a media-sense event occurs and TCP/IP revokes the IP
  1571. // address for a LAN connection, the connection's IP address becomes
  1572. // 0.0.0.0. We treat that as though we don't have an IP address at all,
  1573. // and bypass the binding below. When the IP address is reinstated,
  1574. // we will rebind correctly, since we will then detect the change.
  1575. //
  1576. if (pConEntry->HNetProperties.fLanConnection) {
  1577. if (BindingInfo->AddressCount != 1 ||
  1578. BindingInfo->Address[0].Address) {
  1579. NatpBindConnection(pConEntry, Hrasconn, AdapterIndex, BindingInfo);
  1580. }
  1581. if (pConEntry->pBindingInfo) {
  1582. NH_FREE(pConEntry->pBindingInfo);
  1583. }
  1584. pConEntry->pBindingInfo = BindingInfo;
  1585. } else {
  1586. NatpBindConnection(pConEntry, Hrasconn, AdapterIndex, BindingInfo);
  1587. }
  1588. if ( pConEntry->HNetProperties.fIcsPublic &&
  1589. (FALSE == bUPnPEventAlreadyFired) &&
  1590. NAT_INTERFACE_BOUND(&pConEntry->Interface))
  1591. {
  1592. FireNATEvent_PublicIPAddressChanged();
  1593. }
  1594. }
  1595. }
  1596. //
  1597. // If we have a shared connection, also need to update the private interface
  1598. //
  1599. if (NatpSharedConnectionPresent) {
  1600. NhUpdatePrivateInterface();
  1601. }
  1602. LeaveCriticalSection(&NatInterfaceLock);
  1603. } // NatpProcessConnectionNotify
  1604. ULONG
  1605. NatpQueryConnectionAdapter(
  1606. PNAT_CONNECTION_ENTRY pConEntry
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. This routine is invoked to determine the adapter index corresponding
  1611. to a connection, if active.
  1612. Arguments:
  1613. pConEntry - the connection entry
  1614. Return Value:
  1615. ULONG - the adapter index if found, otherwise (ULONG)-1.
  1616. Environment:
  1617. Invoked with 'NatInterfaceLock' held by the caller.
  1618. --*/
  1619. {
  1620. ULONG AdapterIndex = (ULONG)-1;
  1621. ULONG Error;
  1622. HRASCONN Hrasconn = NULL;
  1623. RASPPPIPA RasPppIp;
  1624. ULONG Size;
  1625. UNICODE_STRING UnicodeString;
  1626. if (pConEntry->HNetProperties.fLanConnection) {
  1627. RtlStringFromGUID(pConEntry->Guid, &UnicodeString);
  1628. AdapterIndex = NhMapGuidToAdapter(UnicodeString.Buffer);
  1629. RtlFreeUnicodeString(&UnicodeString);
  1630. } else {
  1631. HRESULT hr;
  1632. LPWSTR wszEntryName;
  1633. hr = pConEntry->pHNetConnection->GetName(&wszEntryName);
  1634. if (SUCCEEDED(hr))
  1635. {
  1636. Error =
  1637. RasGetEntryHrasconnW(
  1638. pConEntry->wszPhonebookPath,
  1639. wszEntryName,
  1640. &Hrasconn
  1641. );
  1642. if (!Error && Hrasconn) {
  1643. ZeroMemory(&RasPppIp, sizeof(RasPppIp));
  1644. Size = RasPppIp.dwSize = sizeof(RasPppIp);
  1645. Error =
  1646. RasGetProjectionInfoA(
  1647. Hrasconn,
  1648. RASP_PppIp,
  1649. &RasPppIp,
  1650. &Size
  1651. );
  1652. if (!Error) {
  1653. AdapterIndex =
  1654. NhMapAddressToAdapter(inet_addr(RasPppIp.szIpAddress));
  1655. }
  1656. }
  1657. CoTaskMemFree(wszEntryName);
  1658. }
  1659. }
  1660. NhTrace(TRACE_FLAG_NAT, "NatpQueryConnectionAdapter: %d", AdapterIndex);
  1661. return AdapterIndex;
  1662. } // NatpQueryConnectionAdapter
  1663. PIP_NAT_INTERFACE_INFO
  1664. NatpQueryConnectionInformation(
  1665. PNAT_CONNECTION_ENTRY pConEntry,
  1666. PIP_ADAPTER_BINDING_INFO BindingInfo
  1667. )
  1668. /*++
  1669. Routine Description:
  1670. This routine is invoked to construct the configuration
  1671. of a connection. The configuration consists of basic settings
  1672. (e.g. interface type and flags) as well as extended information loaded
  1673. from the configuration store (e.g. port mappings).
  1674. Arguments:
  1675. pConEntry - the connection entry
  1676. BindingInfo - the binding info for the connection
  1677. Return Value:
  1678. PIP_NAT_INTERFACE_INFO - the configuration allocated;
  1679. on error, returns NULL
  1680. Environment:
  1681. Invoked with 'NatInterfaceLock' held by the caller.
  1682. --*/
  1683. {
  1684. PIP_NAT_PORT_MAPPING Array = NULL;
  1685. ULONG Count = 0;
  1686. ULONG Error;
  1687. PIP_NAT_INTERFACE_INFO Info;
  1688. PRTR_INFO_BLOCK_HEADER Header;
  1689. HRESULT hr;
  1690. ULONG Length;
  1691. PLIST_ENTRY Link;
  1692. PRTR_INFO_BLOCK_HEADER NewHeader;
  1693. PNAT_PORT_MAPPING_ENTRY PortMapping;
  1694. PROFILE("NatpQueryConnectionInformation");
  1695. //
  1696. // Build the port mapping array from the list
  1697. //
  1698. if (pConEntry->PortMappingCount)
  1699. {
  1700. Array =
  1701. reinterpret_cast<PIP_NAT_PORT_MAPPING>(
  1702. NH_ALLOCATE(pConEntry->PortMappingCount * sizeof(IP_NAT_PORT_MAPPING))
  1703. );
  1704. if (NULL == Array)
  1705. {
  1706. NhTrace(
  1707. TRACE_FLAG_NAT,
  1708. "NatpQueryConnectionInformation: Unable to allocate array"
  1709. );
  1710. return NULL;
  1711. }
  1712. for (Link = pConEntry->PortMappingList.Flink;
  1713. Link != &pConEntry->PortMappingList;
  1714. Link = Link->Flink)
  1715. {
  1716. PortMapping = CONTAINING_RECORD(Link, NAT_PORT_MAPPING_ENTRY, Link);
  1717. if (PortMapping->fUdpBroadcastMapping) { continue; }
  1718. Array[Count].PublicAddress = IP_NAT_ADDRESS_UNSPECIFIED;
  1719. Array[Count].Protocol = PortMapping->ucProtocol;
  1720. Array[Count].PublicPort = PortMapping->usPublicPort;
  1721. Array[Count].PrivateAddress = PortMapping->ulPrivateAddress;
  1722. Array[Count].PrivatePort = PortMapping->usPrivatePort;
  1723. Count += 1;
  1724. }
  1725. ASSERT(Count == pConEntry->PortMappingCount);
  1726. }
  1727. //
  1728. // Create an info-block header and add the port-mapping array
  1729. // as the single entry in the info-block.
  1730. // This info-block header will occupy the 'Header' field
  1731. // of the final 'IP_NAT_INTERFACE_INFO'.
  1732. //
  1733. Error = MprInfoCreate(IP_NAT_VERSION, reinterpret_cast<LPVOID*>(&Header));
  1734. if (Error) {
  1735. if (Array) {
  1736. NH_FREE(Array);
  1737. }
  1738. return NULL;
  1739. }
  1740. if (Count) {
  1741. Error =
  1742. MprInfoBlockAdd(
  1743. Header,
  1744. IP_NAT_PORT_MAPPING_TYPE,
  1745. sizeof(IP_NAT_PORT_MAPPING),
  1746. Count,
  1747. (PUCHAR)Array,
  1748. reinterpret_cast<LPVOID*>(&NewHeader)
  1749. );
  1750. MprInfoDelete(Header); NH_FREE(Array); Header = NewHeader;
  1751. if (Error) {
  1752. return NULL;
  1753. }
  1754. } else if (Array) {
  1755. NH_FREE(Array);
  1756. }
  1757. //
  1758. // For firewalled entries, get ICMP settings
  1759. //
  1760. if (pConEntry->HNetProperties.fFirewalled && NhPolicyAllowsFirewall)
  1761. {
  1762. HNET_FW_ICMP_SETTINGS *pIcmpSettings;
  1763. DWORD dwIcmpFlags = 0;
  1764. hr = pConEntry->pHNetConnection->GetIcmpSettings(&pIcmpSettings);
  1765. if (SUCCEEDED(hr))
  1766. {
  1767. if (pIcmpSettings->fAllowOutboundDestinationUnreachable)
  1768. {
  1769. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_DEST_UNREACH;
  1770. }
  1771. if (pIcmpSettings->fAllowOutboundSourceQuench)
  1772. {
  1773. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_SOURCE_QUENCH;
  1774. }
  1775. if (pIcmpSettings->fAllowRedirect)
  1776. {
  1777. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_REDIRECT;
  1778. }
  1779. if (pIcmpSettings->fAllowInboundEchoRequest)
  1780. {
  1781. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_ECHO;
  1782. }
  1783. if (pIcmpSettings->fAllowInboundRouterRequest)
  1784. {
  1785. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_ROUTER;
  1786. }
  1787. if (pIcmpSettings->fAllowOutboundTimeExceeded)
  1788. {
  1789. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_TIME_EXCEEDED;
  1790. }
  1791. if (pIcmpSettings->fAllowOutboundParameterProblem)
  1792. {
  1793. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_PARAM_PROBLEM;
  1794. }
  1795. if (pIcmpSettings->fAllowInboundTimestampRequest)
  1796. {
  1797. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_TIMESTAMP;
  1798. }
  1799. if (pIcmpSettings->fAllowInboundMaskRequest)
  1800. {
  1801. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_MASK;
  1802. }
  1803. CoTaskMemFree(pIcmpSettings);
  1804. Error =
  1805. MprInfoBlockAdd(
  1806. Header,
  1807. IP_NAT_ICMP_CONFIG_TYPE,
  1808. sizeof(DWORD),
  1809. 1,
  1810. (PUCHAR)&dwIcmpFlags,
  1811. reinterpret_cast<LPVOID*>(&NewHeader)
  1812. );
  1813. if (NO_ERROR == Error)
  1814. {
  1815. MprInfoDelete(Header);
  1816. Header = NewHeader;
  1817. }
  1818. }
  1819. else
  1820. {
  1821. NhTrace(
  1822. TRACE_FLAG_NAT,
  1823. "NatpQueryConnectionInformation: GetIcmpSettings 0x%08x",
  1824. hr
  1825. );
  1826. //
  1827. // This is a 'soft' error -- we'll still continue even if we
  1828. // couldn't get the ICMP settings, as our default stance
  1829. // is more secure than if any of the flags were set.
  1830. //
  1831. }
  1832. }
  1833. //
  1834. // Allocate an 'IP_NAT_INTERFACE_INFO' which is large enough to hold
  1835. // the info-block header which we've just constructed.
  1836. //
  1837. Length = FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) + Header->Size;
  1838. Info = reinterpret_cast<PIP_NAT_INTERFACE_INFO>(NH_ALLOCATE(Length));
  1839. if (Info)
  1840. {
  1841. RtlZeroMemory(Info, FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header));
  1842. //
  1843. // Set appropriate flags
  1844. //
  1845. if (pConEntry->HNetProperties.fFirewalled && NhPolicyAllowsFirewall)
  1846. {
  1847. Info->Flags |= IP_NAT_INTERFACE_FLAGS_FW;
  1848. }
  1849. if (pConEntry->HNetProperties.fIcsPublic && NhPolicyAllowsSharing)
  1850. {
  1851. Info->Flags |=
  1852. IP_NAT_INTERFACE_FLAGS_BOUNDARY | IP_NAT_INTERFACE_FLAGS_NAPT;
  1853. }
  1854. //
  1855. // Copy the info-block header into the info structure
  1856. //
  1857. RtlCopyMemory(&Info->Header, Header, Header->Size);
  1858. }
  1859. MprInfoDelete(Header);
  1860. return Info;
  1861. } // NatpQuerySharedConnectionInformation
  1862. VOID NTAPI
  1863. NatpRoutingFailureCallbackRoutine(
  1864. PVOID Context,
  1865. PIO_STATUS_BLOCK IoStatus,
  1866. ULONG Reserved
  1867. )
  1868. /*++
  1869. Routine Description:
  1870. This routine is invoked when a routing-failure notification occurs,
  1871. or when the request is cancelled (e.g. because the request's thread exited).
  1872. Arguments:
  1873. Context - unused
  1874. IoStatus - contains the status of the operation
  1875. Reserved - unused
  1876. Return Value:
  1877. none.
  1878. Environment:
  1879. Invoked with a reference made to the component on our behalf.
  1880. That reference is released here, and if notification is re-requested,
  1881. it is re-acquired.
  1882. --*/
  1883. {
  1884. CHAR DestinationAddress[32];
  1885. ULONG Error;
  1886. IP_NAT_REQUEST_NOTIFICATION RequestNotification;
  1887. PROFILE("NatpRoutingFailureCallbackRoutine");
  1888. //
  1889. // See if cleanup has occurred
  1890. //
  1891. EnterCriticalSection(&NatInterfaceLock);
  1892. if (!NatConnectionNotifyEvent) {
  1893. LeaveCriticalSection(&NatInterfaceLock);
  1894. DEREFERENCE_NAT();
  1895. return;
  1896. }
  1897. LeaveCriticalSection(&NatInterfaceLock);
  1898. //
  1899. // Acquire a new reference, and release the old one
  1900. //
  1901. if (!REFERENCE_NAT()) { DEREFERENCE_NAT(); return; }
  1902. DEREFERENCE_NAT();
  1903. lstrcpyA(
  1904. DestinationAddress,
  1905. inet_ntoa(*(PIN_ADDR)&NatpRoutingFailureNotification.DestinationAddress)
  1906. );
  1907. NhTrace(
  1908. TRACE_FLAG_NAT,
  1909. "NatpRoutingFailureCallbackRoutine: %s->%s",
  1910. inet_ntoa(*(PIN_ADDR)&NatpRoutingFailureNotification.SourceAddress),
  1911. DestinationAddress
  1912. );
  1913. //
  1914. // Request an automatic connection if the notification succeeded
  1915. //
  1916. if (NT_SUCCESS(IoStatus->Status)) {
  1917. //
  1918. // First see if this is a known autodial destination,
  1919. // requesting a connection if so.
  1920. //
  1921. ULONG Count;
  1922. ULONG Size;
  1923. Size = 0;
  1924. Error =
  1925. RasGetAutodialAddressA(
  1926. DestinationAddress,
  1927. NULL,
  1928. NULL,
  1929. &Size,
  1930. &Count
  1931. );
  1932. if (Error != ERROR_BUFFER_TOO_SMALL) {
  1933. //
  1934. // This is not a known destination;
  1935. // try the default shared connection, if any
  1936. //
  1937. NhDialSharedConnection();
  1938. } else {
  1939. //
  1940. // Try initiating a normal autodial connection;
  1941. // normal autodial may yet lead to the shared-connection.
  1942. //
  1943. HINSTANCE Hinstance = LoadLibraryA("RASADHLP.DLL");
  1944. if (Hinstance) {
  1945. BOOL (*WSAttemptAutodialAddr)(PSOCKADDR_IN, INT) =
  1946. (BOOL (*)(PSOCKADDR_IN, INT))
  1947. GetProcAddress(
  1948. Hinstance,
  1949. "WSAttemptAutodialAddr"
  1950. );
  1951. if (WSAttemptAutodialAddr) {
  1952. SOCKADDR_IN SockAddr;
  1953. SockAddr.sin_family = AF_INET;
  1954. SockAddr.sin_addr.s_addr =
  1955. NatpRoutingFailureNotification.DestinationAddress;
  1956. WSAttemptAutodialAddr(&SockAddr, sizeof(SockAddr));
  1957. }
  1958. FreeLibrary(Hinstance);
  1959. }
  1960. }
  1961. }
  1962. //
  1963. // Submit a new request
  1964. //
  1965. EnterCriticalSection(&NatInterfaceLock);
  1966. RequestNotification.Code = NatRoutingFailureNotification;
  1967. NtDeviceIoControlFile(
  1968. NatFileHandle,
  1969. NULL,
  1970. NatpRoutingFailureCallbackRoutine,
  1971. NULL,
  1972. &NatpRoutingFailureIoStatus,
  1973. IOCTL_IP_NAT_REQUEST_NOTIFICATION,
  1974. (PVOID)&RequestNotification,
  1975. sizeof(RequestNotification),
  1976. &NatpRoutingFailureNotification,
  1977. sizeof(NatpRoutingFailureNotification)
  1978. );
  1979. LeaveCriticalSection(&NatInterfaceLock);
  1980. } // NatpRoutingFailureCallbackRoutine
  1981. VOID NTAPI
  1982. NatpRoutingFailureWorkerRoutine(
  1983. PVOID Context
  1984. )
  1985. /*++
  1986. Routine Description:
  1987. This routine initiates the notification of routing-failures.
  1988. Arguments:
  1989. none used.
  1990. Return Value:
  1991. none.
  1992. Environment:
  1993. Invoked in the context of an alertable I/O worker thread.
  1994. --*/
  1995. {
  1996. IP_NAT_REQUEST_NOTIFICATION RequestNotification;
  1997. PROFILE("NatpRoutingFailureWorkerRoutine");
  1998. //
  1999. // Request notification of routing-failures
  2000. //
  2001. EnterCriticalSection(&NatInterfaceLock);
  2002. RequestNotification.Code = NatRoutingFailureNotification;
  2003. NtDeviceIoControlFile(
  2004. NatFileHandle,
  2005. NULL,
  2006. NatpRoutingFailureCallbackRoutine,
  2007. NULL,
  2008. &NatpRoutingFailureIoStatus,
  2009. IOCTL_IP_NAT_REQUEST_NOTIFICATION,
  2010. (PVOID)&RequestNotification,
  2011. sizeof(RequestNotification),
  2012. &NatpRoutingFailureNotification,
  2013. sizeof(NatpRoutingFailureNotification)
  2014. );
  2015. LeaveCriticalSection(&NatInterfaceLock);
  2016. } // NatpRoutingFailureWorkerRoutine
  2017. ULONG
  2018. NatpStartSharedConnectionManagement(
  2019. VOID
  2020. )
  2021. /*++
  2022. Routine Description:
  2023. This routine is called to install routing failure-notification, and
  2024. to enable the router
  2025. Arguments:
  2026. none.
  2027. Return Value:
  2028. ULONG - Win32 status code.
  2029. --*/
  2030. {
  2031. ULONG Error;
  2032. BOOL SharedAutoDial;
  2033. NTSTATUS status;
  2034. PROFILE("NatpStartSharedConnectionManagement");
  2035. //
  2036. // See if the user has enabled shared-autodial.
  2037. // If so, make sure the autodial service is running,
  2038. // since it will be needed for performing on-demand dialing.
  2039. //
  2040. // (IHNetIcsSettings::GetAutodialEnabled just calls the RAS api below,
  2041. // which is why we're not getting the information that way right now...)
  2042. //
  2043. if (!RasQuerySharedAutoDial(&SharedAutoDial) && SharedAutoDial) {
  2044. SC_HANDLE ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  2045. if (ScmHandle) {
  2046. SC_HANDLE ServiceHandle =
  2047. OpenService(ScmHandle, TEXT("RasAuto"), SERVICE_ALL_ACCESS);
  2048. if (ServiceHandle) {
  2049. StartService(ServiceHandle, 0, NULL);
  2050. CloseServiceHandle(ServiceHandle);
  2051. }
  2052. CloseServiceHandle(ScmHandle);
  2053. }
  2054. }
  2055. EnterCriticalSection(&NatInterfaceLock);
  2056. if (NatpEnableRouterEvent) {
  2057. LeaveCriticalSection(&NatInterfaceLock);
  2058. return NO_ERROR;
  2059. }
  2060. //
  2061. // Acquire a component-reference on behalf of
  2062. // (1) the enable-router callback routine
  2063. // (2) the routing-failure-notification worker routine.
  2064. //
  2065. if (!REFERENCE_NAT()) {
  2066. LeaveCriticalSection(&NatInterfaceLock);
  2067. return ERROR_CAN_NOT_COMPLETE;
  2068. } else if (!REFERENCE_NAT()) {
  2069. LeaveCriticalSection(&NatInterfaceLock);
  2070. DEREFERENCE_NAT();
  2071. return ERROR_CAN_NOT_COMPLETE;
  2072. }
  2073. do {
  2074. //
  2075. // Start DNS and DHCP modules
  2076. //
  2077. Error = NhStartICSProtocols();
  2078. if (Error) break;
  2079. //
  2080. // Enable IP forwarding:
  2081. // Create an event to be used in the overlapped I/O structure
  2082. // that will be passed to the 'EnableRouter' API routine,
  2083. // set up the overlapped structure, and schedule the request
  2084. // by signalling the event.
  2085. //
  2086. NatpEnableRouterEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2087. if (!NatpEnableRouterEvent) {
  2088. Error = GetLastError(); break;
  2089. }
  2090. status =
  2091. RtlRegisterWait(
  2092. &NatpEnableRouterWaitHandle,
  2093. NatpEnableRouterEvent,
  2094. NatpEnableRouterCallbackRoutine,
  2095. NULL,
  2096. INFINITE,
  2097. 0
  2098. );
  2099. if (!NT_SUCCESS(status)) {
  2100. Error = RtlNtStatusToDosError(status); break;
  2101. }
  2102. SetEvent(NatpEnableRouterEvent);
  2103. //
  2104. // Queue a work item in whose context we will make a request
  2105. // for routing-failure notification from the NAT driver.
  2106. // We use a work-item rather than issuing the request directly
  2107. // to avoid having our I/O request cancelled if and when the current
  2108. // (thread pool) thread exits.
  2109. //
  2110. RtlQueueWorkItem(
  2111. NatpRoutingFailureWorkerRoutine,
  2112. NULL,
  2113. WT_EXECUTEINIOTHREAD
  2114. );
  2115. LeaveCriticalSection(&NatInterfaceLock);
  2116. return NO_ERROR;
  2117. } while (FALSE);
  2118. if (NatpEnableRouterWaitHandle) {
  2119. RtlDeregisterWait(NatpEnableRouterWaitHandle);
  2120. NatpEnableRouterWaitHandle = NULL;
  2121. }
  2122. if (NatpEnableRouterEvent) {
  2123. CloseHandle(NatpEnableRouterEvent);
  2124. NatpEnableRouterEvent = NULL;
  2125. }
  2126. LeaveCriticalSection(&NatInterfaceLock);
  2127. DEREFERENCE_NAT();
  2128. DEREFERENCE_NAT();
  2129. return Error;
  2130. } // NatpStartSharedConnectionManagement
  2131. ULONG
  2132. NatpStopSharedConnectionManagement(
  2133. VOID
  2134. )
  2135. /*++
  2136. Routine Description:
  2137. This routine is called to stop the DNS & DHCP modules and also
  2138. to remove the routing failure-notification, and
  2139. to disable the router
  2140. Arguments:
  2141. none.
  2142. Return Value:
  2143. ULONG - Win32 status code.
  2144. --*/
  2145. {
  2146. ULONG Error = NO_ERROR;
  2147. PROFILE("NatpStopSharedConnectionManagement");
  2148. EnterCriticalSection(&NatInterfaceLock);
  2149. //
  2150. // Stop the DHCP, DNS, QoSWindowAdjustment and Beacon modules
  2151. //
  2152. Error = NhStopICSProtocols();
  2153. if (NatpEnableRouterWaitHandle) {
  2154. RtlDeregisterWait(NatpEnableRouterWaitHandle);
  2155. NatpEnableRouterWaitHandle = NULL;
  2156. }
  2157. if (NatpEnableRouterEvent) {
  2158. CloseHandle(NatpEnableRouterEvent);
  2159. NatpEnableRouterEvent = NULL;
  2160. NatpEnableRouterCallbackRoutine(NULL, FALSE);
  2161. }
  2162. LeaveCriticalSection(&NatInterfaceLock);
  2163. return Error;
  2164. } // NatpStopSharedConnectionManagement
  2165. BOOLEAN
  2166. NatpUnbindConnection(
  2167. PNAT_CONNECTION_ENTRY pConEntry
  2168. )
  2169. /*++
  2170. Routine Description:
  2171. This routine is invoked to unbind a currently-active connection.
  2172. Arguments:
  2173. Index - index into the connection array
  2174. Return Value:
  2175. TRUE if the entry was previously bound; FALSE otherwise.
  2176. Environment:
  2177. Invoked with 'NatInterfaceLock' held by the caller.
  2178. --*/
  2179. {
  2180. LIST_ENTRY *pLink;
  2181. PNAT_PORT_MAPPING_ENTRY pMapping;
  2182. PROFILE("NatpUnbindConnection");
  2183. if (NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  2184. NatUnbindInterface(
  2185. pConEntry->Interface.Index,
  2186. &pConEntry->Interface
  2187. );
  2188. #ifndef NO_FTP_PROXY
  2189. if (NAT_INTERFACE_ADDED_FTP(&pConEntry->Interface)) {
  2190. FtpRmDeleteInterface(pConEntry->Interface.Index);
  2191. pConEntry->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_FTP;
  2192. }
  2193. #endif
  2194. if (NAT_INTERFACE_ADDED_ALG(&pConEntry->Interface)) {
  2195. AlgRmDeleteInterface(pConEntry->Interface.Index);
  2196. pConEntry->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_ALG;
  2197. }
  2198. if (NAT_INTERFACE_ADDED_H323(&pConEntry->Interface)) {
  2199. H323RmDeleteInterface(pConEntry->Interface.Index);
  2200. pConEntry->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_H323;
  2201. }
  2202. RemoveEntryList(&pConEntry->Interface.Link);
  2203. InitializeListHead(&pConEntry->Interface.Link);
  2204. if (pConEntry->Interface.Info) {
  2205. NH_FREE(pConEntry->Interface.Info);
  2206. pConEntry->Interface.Info = NULL;
  2207. }
  2208. //
  2209. // Clean up the port mapping list
  2210. //
  2211. NatpFreePortMappingList(pConEntry);
  2212. return TRUE;
  2213. }
  2214. return FALSE;
  2215. } // NatpUnbindConnection
  2216. VOID
  2217. NatpUpdateSharedConnectionDomainName(
  2218. ULONG AdapterIndex
  2219. )
  2220. /*++
  2221. Routine Description:
  2222. This routine is called to update the cached DNS domain name, if any,
  2223. for the shared connection.
  2224. Arguments:
  2225. AdapterIndex - the index of the adapter for the shared connection
  2226. Return Value:
  2227. none.
  2228. --*/
  2229. {
  2230. PADAPTER_INFORMATION AdapterInformation;
  2231. ANSI_STRING AnsiString;
  2232. ULONG Count;
  2233. ULONG Error;
  2234. ULONG i;
  2235. PDNS_NETWORK_INFORMATION NetworkInformation = NULL;
  2236. PIP_INTERFACE_NAME_INFO Table = NULL;
  2237. UNICODE_STRING UnicodeString;
  2238. PROFILE("NatpUpdateSharedConnectionDomainName");
  2239. RtlInitAnsiString(&AnsiString, NULL);
  2240. RtlInitUnicodeString(&UnicodeString, NULL);
  2241. EnterCriticalSection(&NatInterfaceLock);
  2242. if (AdapterIndex == (ULONG)-1)
  2243. {
  2244. PLIST_ENTRY Link;
  2245. PNAT_CONNECTION_ENTRY pConEntry;
  2246. //
  2247. // Make sure that the connection list has been initialized; if
  2248. // it hasn't, Flink will be NULL.
  2249. //
  2250. if (!NatpConnectionList.Flink) {
  2251. LeaveCriticalSection(&NatInterfaceLock);
  2252. return;
  2253. }
  2254. //
  2255. // See if we actually have a shared connection
  2256. //
  2257. for (Link = NatpConnectionList.Flink;
  2258. Link != &NatpConnectionList;
  2259. Link = Link->Flink)
  2260. {
  2261. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  2262. if (pConEntry->HNetProperties.fIcsPublic)
  2263. {
  2264. AdapterIndex = NatpQueryConnectionAdapter(pConEntry);
  2265. break;
  2266. }
  2267. }
  2268. if (AdapterIndex == (ULONG)-1) {
  2269. LeaveCriticalSection(&NatInterfaceLock);
  2270. return;
  2271. }
  2272. }
  2273. do {
  2274. //
  2275. // Obtain the GUID for the adapter with the given index,
  2276. // by querying TCP/IP for information on all available interfaces.
  2277. // The GUID will then be used to map the shared connection's adapter
  2278. // to a DNS domain name.
  2279. //
  2280. Error =
  2281. NhpAllocateAndGetInterfaceInfoFromStack(
  2282. &Table, &Count, FALSE, GetProcessHeap(), 0
  2283. );
  2284. if (Error != NO_ERROR) { break; }
  2285. for (i = 0; i < Count && Table[i].Index != AdapterIndex; i++) { }
  2286. if (i >= Count) { Error = ERROR_INTERNAL_ERROR; break; }
  2287. RtlStringFromGUID(Table[i].DeviceGuid, &UnicodeString);
  2288. RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
  2289. //
  2290. // Query the DNS client for the current network parameters,
  2291. // and search through the network parameters to find the entry
  2292. // for the shared-connection's current adapter.
  2293. //
  2294. NetworkInformation = (PDNS_NETWORK_INFORMATION)
  2295. DnsQueryConfigAlloc(
  2296. DnsConfigNetworkInformation,
  2297. NULL );
  2298. if (!NetworkInformation) { Error = ERROR_INTERNAL_ERROR; break; }
  2299. for (i = 0; i < NetworkInformation->cAdapterCount; i++) {
  2300. AdapterInformation = NetworkInformation->aAdapterInfoList[i];
  2301. if (lstrcmpiA(
  2302. AnsiString.Buffer, AdapterInformation->pszAdapterGuidName
  2303. ) == 0) {
  2304. break;
  2305. }
  2306. }
  2307. if (i >= NetworkInformation->cAdapterCount) {
  2308. Error = ERROR_INTERNAL_ERROR;
  2309. break;
  2310. }
  2311. //
  2312. // 'AdapterInformation' is the entry for the shared-connection's
  2313. // current adapter.
  2314. // Clear the previously-cached string, and read in the new value,
  2315. // if any.
  2316. //
  2317. if (NatpSharedConnectionDomainName) {
  2318. NH_FREE(NatpSharedConnectionDomainName);
  2319. NatpSharedConnectionDomainName = NULL;
  2320. }
  2321. if (AdapterInformation->pszDomain) {
  2322. NatpSharedConnectionDomainName =
  2323. reinterpret_cast<PCHAR>(
  2324. NH_ALLOCATE(lstrlenA(AdapterInformation->pszDomain) + 1)
  2325. );
  2326. if (!NatpSharedConnectionDomainName) {
  2327. Error = ERROR_INTERNAL_ERROR;
  2328. break;
  2329. }
  2330. lstrcpyA(
  2331. NatpSharedConnectionDomainName,
  2332. AdapterInformation->pszDomain
  2333. );
  2334. }
  2335. Error = NO_ERROR;
  2336. } while(FALSE);
  2337. if (UnicodeString.Buffer) {
  2338. RtlFreeUnicodeString(&UnicodeString);
  2339. }
  2340. if (AnsiString.Buffer) {
  2341. RtlFreeAnsiString(&AnsiString);
  2342. }
  2343. if (NetworkInformation) {
  2344. DnsFreeConfigStructure(
  2345. NetworkInformation,
  2346. DnsConfigNetworkInformation );
  2347. }
  2348. if (Table) {
  2349. HeapFree(GetProcessHeap(), 0, Table);
  2350. }
  2351. if (Error) {
  2352. if (NatpSharedConnectionDomainName) {
  2353. NH_FREE(NatpSharedConnectionDomainName);
  2354. NatpSharedConnectionDomainName = NULL;
  2355. }
  2356. }
  2357. LeaveCriticalSection(&NatInterfaceLock);
  2358. } // NatpUpdateSharedConnectionDomainName
  2359. PCHAR
  2360. NatQuerySharedConnectionDomainName(
  2361. VOID
  2362. )
  2363. /*++
  2364. Routine Description:
  2365. This routine is called to retrieve a copy of the DNS domain name
  2366. cached for the shared connection, if available. Otherwise, it returns
  2367. the primary DNS domain name for the local machine.
  2368. Arguments:
  2369. none.
  2370. Return Value:
  2371. PCHAR - contains the allocated copy of the DNS domain name.
  2372. --*/
  2373. {
  2374. PCHAR DomainName;
  2375. PROFILE("NatQuerySharedConnectionDomainName");
  2376. //
  2377. // See if there is a cached domain name for the shared connection.
  2378. // If not, refresh the cache. If there is still no domain name,
  2379. // return a copy of the local machine's primary DNS domain name.
  2380. //
  2381. EnterCriticalSection(&NatInterfaceLock);
  2382. if (!NatpSharedConnectionDomainName) {
  2383. NatpUpdateSharedConnectionDomainName((ULONG)-1);
  2384. }
  2385. if (NatpSharedConnectionDomainName) {
  2386. DomainName =
  2387. reinterpret_cast<PCHAR>(
  2388. NH_ALLOCATE(lstrlenA(NatpSharedConnectionDomainName) + 1)
  2389. );
  2390. if (DomainName) {
  2391. lstrcpyA(DomainName, NatpSharedConnectionDomainName);
  2392. }
  2393. } else {
  2394. PCHAR DnsDomainName = (PCHAR) DnsQueryConfigAlloc(
  2395. DnsConfigPrimaryDomainName_A,
  2396. NULL );
  2397. if (!DnsDomainName) {
  2398. DomainName = NULL;
  2399. } else {
  2400. DomainName =
  2401. reinterpret_cast<PCHAR>(
  2402. NH_ALLOCATE(lstrlenA(DnsDomainName) + 1)
  2403. );
  2404. if (DomainName) {
  2405. lstrcpyA(DomainName, DnsDomainName);
  2406. }
  2407. DnsFreeConfigStructure(
  2408. DnsDomainName,
  2409. DnsConfigPrimaryDomainName_A );
  2410. }
  2411. }
  2412. LeaveCriticalSection(&NatInterfaceLock);
  2413. return DomainName;
  2414. } // NatQuerySharedConnectionDomainName
  2415. ULONG
  2416. NatStartConnectionManagement(
  2417. VOID
  2418. )
  2419. /*++
  2420. Routine Description:
  2421. This routine is called to install connection change-notification.
  2422. Arguments:
  2423. none.
  2424. Return Value:
  2425. ULONG - Win32 status code.
  2426. --*/
  2427. {
  2428. ULONG Error;
  2429. NTSTATUS status;
  2430. PROFILE("NatStartConnectionManagement");
  2431. EnterCriticalSection(&NatInterfaceLock);
  2432. if (NatConnectionNotifyEvent) {
  2433. LeaveCriticalSection(&NatInterfaceLock);
  2434. return NO_ERROR;
  2435. }
  2436. //
  2437. // Initialize the connection list
  2438. //
  2439. InitializeListHead(&NatpConnectionList);
  2440. //
  2441. // Acquire a component-reference on behalf of
  2442. // (1) the connection-notification routine
  2443. // (2) the configuration-changed routine
  2444. //
  2445. if (!REFERENCE_NAT()) {
  2446. LeaveCriticalSection(&NatInterfaceLock);
  2447. return ERROR_CAN_NOT_COMPLETE;
  2448. }
  2449. if (!REFERENCE_NAT()) {
  2450. LeaveCriticalSection(&NatInterfaceLock);
  2451. DEREFERENCE_NAT();
  2452. return ERROR_CAN_NOT_COMPLETE;
  2453. }
  2454. do {
  2455. //
  2456. // Create the connection-notification event, register a wait
  2457. // on the event, and register for connect and disconnect notification.
  2458. // We expect at least one invocation as a result of this registration,
  2459. // hence the reference made to the NAT module above.
  2460. //
  2461. NatConnectionNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2462. if (!NatConnectionNotifyEvent) {
  2463. Error = GetLastError(); break;
  2464. }
  2465. status =
  2466. RtlRegisterWait(
  2467. &NatpConnectionNotifyWaitHandle,
  2468. NatConnectionNotifyEvent,
  2469. NatpConnectionNotifyCallbackRoutine,
  2470. NULL,
  2471. INFINITE,
  2472. 0
  2473. );
  2474. if (!NT_SUCCESS(status)) {
  2475. Error = RtlNtStatusToDosError(status); break;
  2476. }
  2477. Error =
  2478. RasConnectionNotification(
  2479. (HRASCONN)INVALID_HANDLE_VALUE,
  2480. NatConnectionNotifyEvent,
  2481. RASCN_Connection|RASCN_Disconnection
  2482. );
  2483. if (Error) { break; }
  2484. //
  2485. // Create the configuartion-change event and register a wait
  2486. // on the event.
  2487. //
  2488. NatConfigurationChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2489. if (!NatConfigurationChangedEvent) {
  2490. Error = GetLastError(); break;
  2491. }
  2492. status =
  2493. RtlRegisterWait(
  2494. &NatpConfigurationChangedWaitHandle,
  2495. NatConfigurationChangedEvent,
  2496. NatpConfigurationChangedCallbackRoutine,
  2497. NULL,
  2498. INFINITE,
  2499. 0
  2500. );
  2501. if (!NT_SUCCESS(status)) {
  2502. Error = RtlNtStatusToDosError(status); break;
  2503. }
  2504. LeaveCriticalSection(&NatInterfaceLock);
  2505. //
  2506. // Pick up any existing connections, by signalling the configuration
  2507. // change event. We cannot invoke the function directly
  2508. // because it invokes service-control functions to start autodial,
  2509. // and we could currently be running in a service-controller thread.
  2510. //
  2511. NtSetEvent(NatConfigurationChangedEvent, NULL);
  2512. return NO_ERROR;
  2513. } while(FALSE);
  2514. //
  2515. // A failure occurred; perform cleanup
  2516. //
  2517. if (NatpConnectionNotifyWaitHandle) {
  2518. RtlDeregisterWait(NatpConnectionNotifyWaitHandle);
  2519. NatpConnectionNotifyWaitHandle = NULL;
  2520. }
  2521. if (NatConnectionNotifyEvent) {
  2522. CloseHandle(NatConnectionNotifyEvent);
  2523. NatConnectionNotifyEvent = NULL;
  2524. }
  2525. if (NatpConfigurationChangedWaitHandle) {
  2526. RtlDeregisterWait(NatpConfigurationChangedWaitHandle);
  2527. NatpConfigurationChangedWaitHandle = NULL;
  2528. }
  2529. if (NatConfigurationChangedEvent) {
  2530. CloseHandle(NatConfigurationChangedEvent);
  2531. NatConfigurationChangedEvent = NULL;
  2532. }
  2533. LeaveCriticalSection(&NatInterfaceLock);
  2534. DEREFERENCE_NAT();
  2535. DEREFERENCE_NAT();
  2536. return Error;
  2537. } // NatStartConnectionManagement
  2538. VOID
  2539. NatStopConnectionManagement(
  2540. VOID
  2541. )
  2542. /*++
  2543. Routine Description:
  2544. This routine is invoked to stop the connection-monitoring activity
  2545. initiated by 'NatStartConnectionManagement' above.
  2546. Arguments:
  2547. none.
  2548. Return Value:
  2549. none.
  2550. Environment:
  2551. Invoked when 'StopProtocol' is received from the IP router-manager.
  2552. --*/
  2553. {
  2554. PLIST_ENTRY Link;
  2555. PNAT_CONNECTION_ENTRY pConEntry;
  2556. PROFILE("NatStopConnectionManagement");
  2557. EnterCriticalSection(&NatInterfaceLock);
  2558. //
  2559. // Cleanup the wait-handle and event used to receive notification
  2560. // of RAS connections and disconnections.
  2561. //
  2562. if (NatpConnectionNotifyWaitHandle) {
  2563. RtlDeregisterWait(NatpConnectionNotifyWaitHandle);
  2564. NatpConnectionNotifyWaitHandle = NULL;
  2565. }
  2566. if (NatConnectionNotifyEvent) {
  2567. RasConnectionNotification(
  2568. (HRASCONN)INVALID_HANDLE_VALUE,
  2569. NatConnectionNotifyEvent,
  2570. 0
  2571. );
  2572. CloseHandle(NatConnectionNotifyEvent);
  2573. NatConnectionNotifyEvent = NULL;
  2574. NatpConnectionNotifyCallbackRoutine(NULL, FALSE);
  2575. }
  2576. if (NatpEnableRouterWaitHandle) {
  2577. RtlDeregisterWait(NatpEnableRouterWaitHandle);
  2578. NatpEnableRouterWaitHandle = NULL;
  2579. }
  2580. if (NatpEnableRouterEvent) {
  2581. CloseHandle(NatpEnableRouterEvent);
  2582. NatpEnableRouterEvent = NULL;
  2583. NatpEnableRouterCallbackRoutine(NULL, FALSE);
  2584. }
  2585. if (NatpConfigurationChangedWaitHandle) {
  2586. RtlDeregisterWait(NatpConfigurationChangedWaitHandle);
  2587. NatpConfigurationChangedWaitHandle = NULL;
  2588. }
  2589. if (NatConfigurationChangedEvent) {
  2590. CloseHandle(NatConfigurationChangedEvent);
  2591. NatConfigurationChangedEvent = NULL;
  2592. NatpConfigurationChangedCallbackRoutine(NULL, FALSE);
  2593. }
  2594. if (NatpConnectionList.Flink)
  2595. {
  2596. //
  2597. // Make certain that all of our connections are disabled
  2598. //
  2599. NatUnbindAllConnections();
  2600. //
  2601. // Walk through the connection list, freeing all of the entries
  2602. //
  2603. while (!IsListEmpty(&NatpConnectionList))
  2604. {
  2605. Link = RemoveHeadList(&NatpConnectionList);
  2606. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  2607. NatpFreeConnectionEntry(pConEntry);
  2608. }
  2609. //
  2610. // Make sure all ICS protocols are stopped
  2611. //
  2612. NhStopICSProtocols();
  2613. }
  2614. //
  2615. // Clean up the DNS domain name cached for the shared connection.
  2616. //
  2617. if (NatpSharedConnectionDomainName) {
  2618. NH_FREE(NatpSharedConnectionDomainName);
  2619. NatpSharedConnectionDomainName = NULL;
  2620. }
  2621. //
  2622. // Reset tracking variables to initial state
  2623. //
  2624. NatpFirewallConnectionCount = 0;
  2625. NatpSharedConnectionPresent = FALSE;
  2626. LeaveCriticalSection(&NatInterfaceLock);
  2627. } // NatStopConnectionManagement
  2628. BOOLEAN
  2629. NatUnbindAllConnections(
  2630. VOID
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. This routine is invoked to unbind a currently-active connection.
  2635. Arguments:
  2636. Index - index into the connection array
  2637. Return Value:
  2638. BOOLEAN - TRUE if any interfaces were unbound.
  2639. Environment:
  2640. Invoked with 'NatInterfaceLock' held by the caller.
  2641. --*/
  2642. {
  2643. PLIST_ENTRY Link;
  2644. PNAT_CONNECTION_ENTRY pConEntry;
  2645. BOOLEAN Result = FALSE;
  2646. PROFILE("NatUnbindAllConnections");
  2647. for (Link = NatpConnectionList.Flink;
  2648. Link != &NatpConnectionList;
  2649. Link = Link->Flink)
  2650. {
  2651. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  2652. Result |= NatpUnbindConnection(pConEntry);
  2653. }
  2654. return Result;
  2655. } // NatpUnbindConnection