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.

3571 lines
90 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. //
  642. // Add the interface the the ALG proxy, if this has not yet
  643. // happened.
  644. //
  645. if (!NAT_INTERFACE_ADDED_ALG(&pConEntry->Interface)) {
  646. Error =
  647. AlgRmAddInterface(
  648. NULL,
  649. pConEntry->Interface.Index,
  650. PERMANENT,
  651. IF_TYPE_OTHER,
  652. IF_ACCESS_BROADCAST,
  653. IF_CONNECTION_DEDICATED,
  654. NULL,
  655. IP_NAT_VERSION,
  656. 0,
  657. 0
  658. );
  659. if (Error) {
  660. NhTrace(
  661. TRACE_FLAG_INIT,
  662. "NatpBindConnection: AlgRmAddInterface=%d",
  663. Error
  664. );
  665. return Error;
  666. }
  667. pConEntry->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_ALG;
  668. }
  669. //
  670. // Bind and enable the interface for ALG
  671. //
  672. Error = AlgRmBindInterface(pConEntry->Interface.Index, BindingInfo);
  673. if (Error) {
  674. NhTrace(
  675. TRACE_FLAG_INIT,
  676. "NatpBindConnection: AlgRmBindInterface=%d",
  677. Error
  678. );
  679. return Error;
  680. }
  681. Error = AlgRmEnableInterface(pConEntry->Interface.Index);
  682. if (Error) {
  683. NhTrace(
  684. TRACE_FLAG_INIT,
  685. "NatpBindConnection: AlgRmEnableInterface=%d",
  686. Error
  687. );
  688. return Error;
  689. }
  690. //
  691. // Add the interface the the H.323 proxy, if this has not yet
  692. // happened.
  693. //
  694. if (!NAT_INTERFACE_ADDED_H323(&pConEntry->Interface)) {
  695. Error =
  696. H323RmAddInterface(
  697. NULL,
  698. pConEntry->Interface.Index,
  699. PERMANENT,
  700. IF_TYPE_OTHER,
  701. IF_ACCESS_BROADCAST,
  702. IF_CONNECTION_DEDICATED,
  703. NULL,
  704. IP_NAT_VERSION,
  705. 0,
  706. 0
  707. );
  708. if (Error) {
  709. NhTrace(
  710. TRACE_FLAG_INIT,
  711. "NatpBindConnection: H323RmAddInterface=%d",
  712. Error
  713. );
  714. return Error;
  715. }
  716. pConEntry->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_H323;
  717. }
  718. //
  719. // Bind and enable the interface for H323
  720. //
  721. Error = H323RmBindInterface(pConEntry->Interface.Index, BindingInfo);
  722. if (Error) {
  723. NhTrace(
  724. TRACE_FLAG_INIT,
  725. "NatpBindConnection: H323RmBindInterface=%d",
  726. Error
  727. );
  728. return Error;
  729. }
  730. Error = H323RmEnableInterface(pConEntry->Interface.Index);
  731. if (Error) {
  732. NhTrace(
  733. TRACE_FLAG_INIT,
  734. "NatpBindConnection: H323RmEnableInterface=%d",
  735. Error
  736. );
  737. return Error;
  738. }
  739. if (pConEntry->HNetProperties.fIcsPublic) {
  740. //
  741. // Finally, update the DNS domain name cached for the shared connection.
  742. //
  743. NatpUpdateSharedConnectionDomainName(AdapterIndex);
  744. }
  745. return NO_ERROR;
  746. } // NatpBindConnection
  747. HRESULT
  748. NatpBuildPortMappingList(
  749. PNAT_CONNECTION_ENTRY pConEntry,
  750. PIP_ADAPTER_BINDING_INFO pBindingInfo
  751. )
  752. /*++
  753. Routine Description:
  754. Builds the list of port mappings for a connection entry
  755. Arguments:
  756. pConEntry - the entry to build the list for
  757. pBindingInfo - the binding info for that entry
  758. Return Value:
  759. Standard HRESULT.
  760. Environment:
  761. NatInterfaceLock must be held by the caller.
  762. --*/
  763. {
  764. HRESULT hr;
  765. IHNetPortMappingBinding *pBinding;
  766. PNAT_PORT_MAPPING_ENTRY pEntry;
  767. IEnumHNetPortMappingBindings *pEnum;
  768. PLIST_ENTRY pLink;
  769. IHNetPortMappingProtocol *pProtocol;
  770. ULONG ulCount;
  771. PROFILE("NatpBuildPortMappingList");
  772. hr = pConEntry->pHNetConnection->EnumPortMappings(TRUE, &pEnum);
  773. if (FAILED(hr))
  774. {
  775. NhTrace(
  776. TRACE_FLAG_NAT,
  777. "NatpBuildPortMappingList: EnumPortMappings 0x%08x",
  778. hr
  779. );
  780. return hr;
  781. }
  782. //
  783. // Process enumeration, creating the port mapping entries.
  784. //
  785. do
  786. {
  787. hr = pEnum->Next(1, &pBinding, &ulCount);
  788. if (SUCCEEDED(hr) && 1 == ulCount)
  789. {
  790. pEntry =
  791. reinterpret_cast<PNAT_PORT_MAPPING_ENTRY>(
  792. NH_ALLOCATE(sizeof(*pEntry))
  793. );
  794. if (NULL != pEntry)
  795. {
  796. ZeroMemory(pEntry, sizeof(*pEntry));
  797. //
  798. // Get the protocol for the binding
  799. //
  800. hr = pBinding->GetProtocol(&pProtocol);
  801. }
  802. else
  803. {
  804. hr = E_OUTOFMEMORY;
  805. }
  806. if (SUCCEEDED(hr))
  807. {
  808. //
  809. // Fill out the entry
  810. //
  811. hr = pProtocol->GetGuid(&pEntry->pProtocolGuid);
  812. if (SUCCEEDED(hr))
  813. {
  814. hr = pProtocol->GetIPProtocol(&pEntry->ucProtocol);
  815. }
  816. if (SUCCEEDED(hr))
  817. {
  818. hr = pProtocol->GetPort(&pEntry->usPublicPort);
  819. }
  820. if (SUCCEEDED(hr))
  821. {
  822. hr = pBinding->GetTargetPort(&pEntry->usPrivatePort);
  823. }
  824. if (SUCCEEDED(hr))
  825. {
  826. //
  827. // We need to know if the name is active in order to
  828. // avoid rebuilding the DHCP reservation list more
  829. // than necessary.
  830. //
  831. hr = pBinding->GetCurrentMethod(&pEntry->fNameActive);
  832. }
  833. if (SUCCEEDED(hr))
  834. {
  835. hr = NatpGetTargetAddressForPortMappingEntry(
  836. pConEntry->HNetProperties.fIcsPublic,
  837. pEntry->fNameActive,
  838. pBindingInfo->Address[0].Address,
  839. pBinding,
  840. &pEntry->ulPrivateAddress
  841. );
  842. }
  843. if (SUCCEEDED(hr))
  844. {
  845. pEntry->pBinding = pBinding;
  846. pEntry->pBinding->AddRef();
  847. pEntry->pProtocol = pProtocol;
  848. pEntry->pProtocol->AddRef();
  849. //
  850. // Check to see if this mapping is:
  851. // 1) targeted at the broadcast address, and
  852. // 2) is UDP.
  853. //
  854. if (NAT_PROTOCOL_UDP == pEntry->ucProtocol
  855. && 0xffffffff == pEntry->ulPrivateAddress)
  856. {
  857. pEntry->fUdpBroadcastMapping = TRUE;
  858. pConEntry->UdpBroadcastPortMappingCount += 1;
  859. }
  860. else
  861. {
  862. pConEntry->PortMappingCount += 1;
  863. }
  864. InsertTailList(&pConEntry->PortMappingList, &pEntry->Link);
  865. }
  866. else
  867. {
  868. NatFreePortMappingEntry(pEntry);
  869. }
  870. pProtocol->Release();
  871. }
  872. //
  873. // If anything failed above we still want to continue operation --
  874. // it's preferable to have the firewall running w/ some port
  875. // mapping entries missing instead of not having the firewall
  876. // run at all.
  877. //
  878. hr = S_OK;
  879. pBinding->Release();
  880. }
  881. } while (SUCCEEDED(hr) && 1 == ulCount);
  882. pEnum->Release();
  883. if (FAILED(hr))
  884. {
  885. //
  886. // Free the port mapping list
  887. //
  888. NatpFreePortMappingList(pConEntry);
  889. }
  890. return hr;
  891. }// NatpBuildPortMappingList
  892. VOID NTAPI
  893. NatpConfigurationChangedCallbackRoutine(
  894. PVOID Context,
  895. BOOLEAN TimedOut
  896. )
  897. /*++
  898. Routine Description:
  899. This routine is invoked upon a change in the NAT/Firewall
  900. configuration.
  901. It may also be invoked when cleanup is in progress.
  902. Arguments:
  903. Context - unused
  904. TimedOut - unused
  905. Return Value:
  906. none.
  907. Environment:
  908. The routine runs in the context of an Rtl wait-thread.
  909. (See 'RtlRegisterWait'.)
  910. A reference to the component will have been made on our behalf
  911. when 'RtlRegisterWait' was called. The reference is released
  912. and re-acquired here.
  913. --*/
  914. {
  915. BOOLEAN ComInitialized = TRUE;
  916. HRESULT hr;
  917. PROFILE("NatpConfigurationChangedCallbackRoutine");
  918. //
  919. // See whether cleanup has occurred
  920. //
  921. EnterCriticalSection(&NatInterfaceLock);
  922. if (!NatConfigurationChangedEvent) {
  923. LeaveCriticalSection(&NatInterfaceLock);
  924. DEREFERENCE_NAT();
  925. return;
  926. }
  927. LeaveCriticalSection(&NatInterfaceLock);
  928. //
  929. // Acquire a new reference to the component (and release
  930. // our original reference on failure).
  931. //
  932. if (!REFERENCE_NAT()) { DEREFERENCE_NAT(); return; }
  933. //
  934. // Make sure the thread is COM-initialized
  935. //
  936. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
  937. if (FAILED(hr))
  938. {
  939. ComInitialized = FALSE;
  940. if (RPC_E_CHANGED_MODE == hr)
  941. {
  942. ASSERT(FALSE);
  943. hr = S_OK;
  944. NhTrace(
  945. TRACE_FLAG_NAT,
  946. "NatpConfigurationChangedCallbackRoutine: Unexpectedly in STA."
  947. );
  948. }
  949. }
  950. //
  951. // Process connection notifications
  952. //
  953. if (SUCCEEDED(hr))
  954. {
  955. NatpProcessConfigurationChanged();
  956. }
  957. //
  958. // Uninitialize COM, if necessary
  959. //
  960. if (TRUE == ComInitialized)
  961. {
  962. CoUninitialize();
  963. }
  964. //
  965. // Release our original reference to the component.
  966. //
  967. DEREFERENCE_NAT();
  968. } // NatpConfigurationChangedCallbackRoutine
  969. VOID NTAPI
  970. NatpConnectionNotifyCallbackRoutine(
  971. PVOID Context,
  972. BOOLEAN TimedOut
  973. )
  974. /*++
  975. Routine Description:
  976. This routine is invoked upon connection or disconnection
  977. of a RAS phonebook entry.
  978. It may also be invoked when cleanup is in progress.
  979. Arguments:
  980. Context - unused
  981. TimedOut - unused
  982. Return Value:
  983. none.
  984. Environment:
  985. The routine runs in the context of an Rtl wait-thread.
  986. (See 'RtlRegisterWait'.)
  987. A reference to the component will have been made on our behalf
  988. when 'RtlRegisterWait' was called. The reference is released
  989. and re-acquired here.
  990. --*/
  991. {
  992. BOOLEAN ComInitialized = TRUE;
  993. HRESULT hr;
  994. PROFILE("NatpConnectionNotifyCallbackRoutine");
  995. //
  996. // See whether cleanup has occurred
  997. //
  998. EnterCriticalSection(&NatInterfaceLock);
  999. if (!NatConnectionNotifyEvent) {
  1000. LeaveCriticalSection(&NatInterfaceLock);
  1001. DEREFERENCE_NAT();
  1002. return;
  1003. }
  1004. LeaveCriticalSection(&NatInterfaceLock);
  1005. //
  1006. // Acquire a new reference to the component (and release
  1007. // our original reference on failure).
  1008. //
  1009. if (!REFERENCE_NAT()) { DEREFERENCE_NAT(); return; }
  1010. //
  1011. // Make sure the thread is COM-initialized
  1012. //
  1013. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE );
  1014. if (FAILED(hr))
  1015. {
  1016. ComInitialized = FALSE;
  1017. if (RPC_E_CHANGED_MODE == hr)
  1018. {
  1019. ASSERT(FALSE);
  1020. hr = S_OK;
  1021. NhTrace(
  1022. TRACE_FLAG_NAT,
  1023. "NatpConnectionNotifyCallbackRoutine: Unexpectedly in STA."
  1024. );
  1025. }
  1026. }
  1027. //
  1028. // Process connection notifications
  1029. //
  1030. if (SUCCEEDED(hr))
  1031. {
  1032. NatpProcessConnectionNotify();
  1033. }
  1034. //
  1035. // Uninitialize COM, if necessary
  1036. //
  1037. if (TRUE == ComInitialized)
  1038. {
  1039. CoUninitialize();
  1040. }
  1041. //
  1042. // Release our original reference to the component.
  1043. //
  1044. DEREFERENCE_NAT();
  1045. } // NatpConnectionNotifyCallbackRoutine
  1046. VOID NTAPI
  1047. NatpEnableRouterCallbackRoutine(
  1048. PVOID Context,
  1049. BOOLEAN TimedOut
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. This routine is invoked upon completion or cancellation of an outstanding
  1054. request to enable IP forwarding. It determines whether the module is still
  1055. running and, if so, re-enables forwarding. Otherwise, it cancels any
  1056. existing request and returns control immediately.
  1057. Arguments:
  1058. none used.
  1059. Return Value:
  1060. none.
  1061. Environment:
  1062. The routine runs in the context of an Rtl wait-thread.
  1063. (See 'RtlRegisterWait'.)
  1064. A reference to the component will have been made on our behalf
  1065. when 'RtlRegisterWait' was called. The reference is released
  1066. and re-acquired here.
  1067. --*/
  1068. {
  1069. ULONG Error;
  1070. HANDLE UnusedHandle;
  1071. PROFILE("NatpEnableRouterCallbackRoutine");
  1072. //
  1073. // See whether cleanup has occurred and, if so, restore forwarding
  1074. // to its original setting. Otherwise, acquire a new reference to the
  1075. // component, and release the original reference.
  1076. //
  1077. EnterCriticalSection(&NatInterfaceLock);
  1078. if (!NatpEnableRouterEvent || !REFERENCE_NAT()) {
  1079. UnenableRouter(&NatpEnableRouterOverlapped, NULL);
  1080. LeaveCriticalSection(&NatInterfaceLock);
  1081. DEREFERENCE_NAT();
  1082. return;
  1083. }
  1084. DEREFERENCE_NAT();
  1085. //
  1086. // Re-enable forwarding
  1087. //
  1088. ZeroMemory(&NatpEnableRouterOverlapped, sizeof(OVERLAPPED));
  1089. NatpEnableRouterOverlapped.hEvent = NatpEnableRouterEvent;
  1090. Error = EnableRouter(&UnusedHandle, &NatpEnableRouterOverlapped);
  1091. if (Error != ERROR_IO_PENDING) {
  1092. NhTrace(
  1093. TRACE_FLAG_NAT,
  1094. "NatpEnableRouterCallbackRoutine: EnableRouter=%d", Error
  1095. );
  1096. }
  1097. LeaveCriticalSection(&NatInterfaceLock);
  1098. } // NatpEnableRouterCallbackRoutine
  1099. VOID
  1100. NatpFreeConnectionEntry(
  1101. PNAT_CONNECTION_ENTRY pConEntry
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Frees all resources associated with a connection entry. This entry
  1106. must have already been removed from the connection list.
  1107. Arguments:
  1108. pConEntry - the entry to free
  1109. Return Value:
  1110. none.
  1111. --*/
  1112. {
  1113. PROFILE("NatpFreeConnectionEntry");
  1114. if (NULL != pConEntry->pInterfaceInfo)
  1115. {
  1116. NH_FREE(pConEntry->pInterfaceInfo);
  1117. }
  1118. if (NULL != pConEntry->pBindingInfo)
  1119. {
  1120. NH_FREE(pConEntry->pBindingInfo);
  1121. }
  1122. if (NULL != pConEntry->pHNetConnection)
  1123. {
  1124. pConEntry->pHNetConnection->Release();
  1125. }
  1126. if (NULL != pConEntry->pHNetFwConnection)
  1127. {
  1128. pConEntry->pHNetFwConnection->Release();
  1129. }
  1130. if (NULL != pConEntry->pHNetIcsPublicConnection)
  1131. {
  1132. pConEntry->pHNetIcsPublicConnection->Release();
  1133. }
  1134. if (NULL != pConEntry->wszPhonebookPath)
  1135. {
  1136. CoTaskMemFree(pConEntry->wszPhonebookPath);
  1137. }
  1138. NatpFreePortMappingList(pConEntry);
  1139. NH_FREE(pConEntry);
  1140. } // NatpFreeConnectionEntry
  1141. VOID
  1142. NatpFreePortMappingList(
  1143. PNAT_CONNECTION_ENTRY pConEntry
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. Frees the port mapping list for a connection entry. This
  1148. includes cancelling any active UDP broadcast mappings.
  1149. Arguments:
  1150. pConEntry - the entry to free
  1151. Return Value:
  1152. none.
  1153. Environment:
  1154. Invoked w/ NatInterfaceLock held by the caller
  1155. --*/
  1156. {
  1157. PLIST_ENTRY pLink;
  1158. PNAT_PORT_MAPPING_ENTRY pMapping;
  1159. while (!IsListEmpty(&pConEntry->PortMappingList))
  1160. {
  1161. pLink = RemoveHeadList(&pConEntry->PortMappingList);
  1162. pMapping = CONTAINING_RECORD(pLink, NAT_PORT_MAPPING_ENTRY, Link);
  1163. if (pMapping->fUdpBroadcastMapping &&
  1164. NULL != pMapping->pvBroadcastCookie)
  1165. {
  1166. ASSERT(NULL != NhpUdpBroadcastMapper);
  1167. NhpUdpBroadcastMapper->CancelUdpBroadcastMapping(
  1168. pMapping->pvBroadcastCookie
  1169. );
  1170. }
  1171. NatFreePortMappingEntry(pMapping);
  1172. }
  1173. pConEntry->PortMappingCount = 0;
  1174. pConEntry->UdpBroadcastPortMappingCount = 0;
  1175. } // NatpFreePortMappingList
  1176. HRESULT
  1177. NatpGetTargetAddressForPortMappingEntry(
  1178. BOOLEAN fPublic,
  1179. BOOLEAN fNameActive,
  1180. ULONG BindingAddress,
  1181. IHNetPortMappingBinding *pBinding,
  1182. OUT ULONG *pPrivateAddress
  1183. )
  1184. /*++
  1185. Routine Description:
  1186. This routine is invoked to get the binding address for the port mapping.
  1187. If this is a FW only connection, we return the address from the binding
  1188. info and not the protocol binding. If its a public connection, and the
  1189. target address is a client machine, we return its address. We check to
  1190. see if we can find the clients' current address, if so, we choose it
  1191. instead of the address currently in our store - refresh of the WMI store
  1192. is done as needed.
  1193. Arguments:
  1194. fPublic - if the interface is public or not
  1195. fNameActive - if the mapping is active by name (TRUE) or IP address (FALSE)
  1196. BindingAddress - binding address from BindingInfo
  1197. pBinding - pointer to port mapping binding
  1198. pPrivateAddress - receives relevant binding address
  1199. Return Value:
  1200. Standard HRESULT
  1201. --*/
  1202. {
  1203. HRESULT hr = S_OK;
  1204. //
  1205. // If this is a FW-only connection, use the address from
  1206. // our binding info instead of the protocol binding.
  1207. //
  1208. if (!fPublic)
  1209. {
  1210. *pPrivateAddress = BindingAddress;
  1211. }
  1212. else
  1213. {
  1214. hr = pBinding->GetTargetComputerAddress(pPrivateAddress);
  1215. if (SUCCEEDED(hr))
  1216. {
  1217. if (INADDR_LOOPBACK_NO == *pPrivateAddress)
  1218. {
  1219. //
  1220. // If the port mapping targets the loopback address
  1221. // we want to use the address from the binding
  1222. // info instead.
  1223. //
  1224. *pPrivateAddress = BindingAddress;
  1225. }
  1226. else if (fNameActive)
  1227. {
  1228. PWCHAR pszICSDomainSuffix = NULL;
  1229. NTSTATUS status;
  1230. PWSTR pszName = NULL;
  1231. ULONG CurrentAddress = 0;
  1232. ULONG DhcpScopeAddress = 0;
  1233. ULONG DhcpScopeMask = 0;
  1234. IHNetCfgMgr *pCfgMgr = NULL;
  1235. IHNetIcsSettings *pIcsSettings = NULL;
  1236. do
  1237. {
  1238. //
  1239. // Get computer name
  1240. //
  1241. hr = pBinding->GetTargetComputerName(
  1242. &pszName
  1243. );
  1244. if (FAILED(hr))
  1245. {
  1246. break;
  1247. }
  1248. //
  1249. // Get the ICS Domain Suffix (if any)
  1250. //
  1251. status = NhQueryICSDomainSuffix(
  1252. &pszICSDomainSuffix
  1253. );
  1254. if (!NT_SUCCESS(status))
  1255. {
  1256. //
  1257. // error in creating the suffix string
  1258. //
  1259. break;
  1260. }
  1261. hr = NhGetHNetCfgMgr(&pCfgMgr);
  1262. if (FAILED(hr))
  1263. {
  1264. break;
  1265. }
  1266. //
  1267. // Get the ICS settings interface
  1268. //
  1269. hr = pCfgMgr->QueryInterface(
  1270. IID_PPV_ARG(IHNetIcsSettings, &pIcsSettings)
  1271. );
  1272. if (FAILED(hr))
  1273. {
  1274. break;
  1275. }
  1276. //
  1277. // Get DHCP scope information
  1278. //
  1279. hr = pIcsSettings->GetDhcpScopeSettings(
  1280. &DhcpScopeAddress,
  1281. &DhcpScopeMask
  1282. );
  1283. if (FAILED(hr))
  1284. {
  1285. break;
  1286. }
  1287. CurrentAddress = NhQueryHostByName(
  1288. pszName,
  1289. pszICSDomainSuffix,
  1290. (DhcpScopeAddress & DhcpScopeMask),
  1291. DhcpScopeMask
  1292. );
  1293. //
  1294. // keep the current address if the following match
  1295. // (1) its non-zero
  1296. // (2) it doesnt match what has already been reserved
  1297. //
  1298. if (CurrentAddress && (CurrentAddress != *pPrivateAddress))
  1299. {
  1300. hr = pIcsSettings->RefreshTargetComputerAddress(
  1301. pszName,
  1302. CurrentAddress
  1303. );
  1304. if (SUCCEEDED(hr))
  1305. {
  1306. NhTrace(
  1307. TRACE_FLAG_NAT,
  1308. "NatpGetTargetAddressForPortMappingEntry: "
  1309. "old address (0x%08x) "
  1310. "new address (0x%08x) for %S",
  1311. *pPrivateAddress,
  1312. CurrentAddress,
  1313. pszName
  1314. );
  1315. *pPrivateAddress = CurrentAddress;
  1316. }
  1317. }
  1318. } while (FALSE);
  1319. if (pszName)
  1320. {
  1321. CoTaskMemFree(pszName);
  1322. }
  1323. if (NULL != pszICSDomainSuffix)
  1324. {
  1325. NH_FREE(pszICSDomainSuffix);
  1326. }
  1327. if (NULL != pIcsSettings)
  1328. {
  1329. pIcsSettings->Release();
  1330. }
  1331. if (NULL != pCfgMgr)
  1332. {
  1333. pCfgMgr->Release();
  1334. }
  1335. }
  1336. }
  1337. }
  1338. return hr;
  1339. }
  1340. VOID
  1341. NatpProcessConfigurationChanged(
  1342. VOID
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. This routine is invoked to see when the NAT/Firewall configuration
  1347. changes. It unbinds the old interfaces, and binds the new ones.
  1348. It is also responsible for making sure that the autodial service
  1349. is running.
  1350. Arguments:
  1351. none.
  1352. Return Value:
  1353. none.
  1354. --*/
  1355. {
  1356. PLIST_ENTRY Link;
  1357. PNAT_CONNECTION_ENTRY pConEntry;
  1358. HRESULT hr;
  1359. IHNetCfgMgr *pCfgMgr = NULL;
  1360. IHNetFirewallSettings *pFwSettings;
  1361. IHNetIcsSettings *pIcsSettings;
  1362. IEnumHNetFirewalledConnections *pFwEnum;
  1363. IHNetFirewalledConnection *pFwConn;
  1364. IEnumHNetIcsPublicConnections *pIcsEnum;
  1365. IHNetIcsPublicConnection *pIcsConn;
  1366. ULONG ulCount;
  1367. UNICODE_STRING UnicodeString;
  1368. PROFILE("NatpProcessConfigurationChanged");
  1369. EnterCriticalSection(&NatInterfaceLock);
  1370. //
  1371. // Start by deleting all of our current connections
  1372. //
  1373. while (!IsListEmpty(&NatpConnectionList))
  1374. {
  1375. Link = RemoveHeadList(&NatpConnectionList);
  1376. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  1377. NatpUnbindConnection(pConEntry);
  1378. NatpFreeConnectionEntry(pConEntry);
  1379. }
  1380. //
  1381. // Reset other items to initial state
  1382. //
  1383. NatpFirewallConnectionCount = 0;
  1384. NatpSharedConnectionPresent = FALSE;
  1385. if (NULL != NatpSharedConnectionDomainName)
  1386. {
  1387. NH_FREE(NatpSharedConnectionDomainName);
  1388. NatpSharedConnectionDomainName = NULL;
  1389. }
  1390. //
  1391. // Get the configuration manager
  1392. //
  1393. hr = NhGetHNetCfgMgr(&pCfgMgr);
  1394. if (NhPolicyAllowsFirewall)
  1395. {
  1396. if (SUCCEEDED(hr))
  1397. {
  1398. //
  1399. // Get the firewall settings interface
  1400. //
  1401. hr = pCfgMgr->QueryInterface(
  1402. IID_PPV_ARG(IHNetFirewallSettings, &pFwSettings)
  1403. );
  1404. }
  1405. if (SUCCEEDED(hr))
  1406. {
  1407. //
  1408. // Get the enumeration of firewalled connections
  1409. //
  1410. hr = pFwSettings->EnumFirewalledConnections(&pFwEnum);
  1411. pFwSettings->Release();
  1412. }
  1413. if (SUCCEEDED(hr))
  1414. {
  1415. //
  1416. // Process the enumeration
  1417. //
  1418. do
  1419. {
  1420. hr = pFwEnum->Next(1, &pFwConn, &ulCount);
  1421. if (SUCCEEDED(hr) && 1 == ulCount)
  1422. {
  1423. //
  1424. // We don't check the return code for NatpAddConnectionEntry.
  1425. // NatpAddConnectionEntry will clean up gracefully if an
  1426. // error occurs and will leave the system in a consistent
  1427. // state, so an error will not prevent us from processing
  1428. // the rest of the connections.
  1429. //
  1430. NatpAddConnectionEntry(pFwConn);
  1431. pFwConn->Release();
  1432. }
  1433. }
  1434. while (SUCCEEDED(hr) && 1 == ulCount);
  1435. pFwEnum->Release();
  1436. }
  1437. }
  1438. //
  1439. // If we don't yet have a shared connection (i.e., none of the
  1440. // firewalled connections were also IcsPublic), retrieve that
  1441. // enumeration now.
  1442. //
  1443. if (FALSE == NatpSharedConnectionPresent
  1444. && NULL != pCfgMgr
  1445. && NhPolicyAllowsSharing)
  1446. {
  1447. //
  1448. // Get the IcsSettings interface
  1449. //
  1450. hr = pCfgMgr->QueryInterface(
  1451. IID_PPV_ARG(IHNetIcsSettings, &pIcsSettings)
  1452. );
  1453. if (SUCCEEDED(hr))
  1454. {
  1455. //
  1456. // Get the enumeration of ICS public connections
  1457. //
  1458. hr = pIcsSettings->EnumIcsPublicConnections(&pIcsEnum);
  1459. pIcsSettings->Release();
  1460. }
  1461. if (SUCCEEDED(hr))
  1462. {
  1463. //
  1464. // See if we can get a connection out of the enum
  1465. //
  1466. hr = pIcsEnum->Next(1, &pIcsConn, &ulCount);
  1467. if (SUCCEEDED(hr) && 1 == ulCount)
  1468. {
  1469. //
  1470. // We don't check the return code for NatpAddConnectionEntry.
  1471. // NatpAddConnectionEntry will clean up gracefully if an
  1472. // error occurs and will leave the system in a consistent
  1473. // state, so an error will not prevent us from processing
  1474. // the rest of the connections.
  1475. //
  1476. NatpAddConnectionEntry(pIcsConn);
  1477. pIcsConn->Release();
  1478. }
  1479. pIcsEnum->Release();
  1480. }
  1481. }
  1482. if (TRUE == NatpSharedConnectionPresent && NhPolicyAllowsSharing)
  1483. {
  1484. //
  1485. // Make sure shared connection management is started
  1486. //
  1487. NatpStartSharedConnectionManagement();
  1488. }
  1489. else
  1490. {
  1491. //
  1492. // Stop shared connection management
  1493. //
  1494. NatpStopSharedConnectionManagement();
  1495. }
  1496. //
  1497. // Notify the firewall subsystem as to whether it needs to
  1498. // start or stop logging. (These calls are effectively no-ops if
  1499. // the logger is already in the correct state.)
  1500. //
  1501. if (NatpFirewallConnectionCount > 0 && NhPolicyAllowsFirewall)
  1502. {
  1503. FwStartLogging();
  1504. }
  1505. else
  1506. {
  1507. FwStopLogging();
  1508. }
  1509. //
  1510. // Bind connections
  1511. //
  1512. NatpProcessConnectionNotify();
  1513. if (NULL != pCfgMgr)
  1514. {
  1515. pCfgMgr->Release();
  1516. }
  1517. LeaveCriticalSection(&NatInterfaceLock);
  1518. } // NatpProcessConfigurationChanged
  1519. VOID
  1520. NatpProcessConnectionNotify(
  1521. VOID
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. This routine is invoked to see if the shared or firewall connections,
  1526. if any, have been connected or disconnected since its last invocation.
  1527. Arguments:
  1528. none.
  1529. Return Value:
  1530. none.
  1531. --*/
  1532. {
  1533. PLIST_ENTRY Link;
  1534. PNAT_CONNECTION_ENTRY pConEntry;
  1535. BOOLEAN Active;
  1536. ULONG i;
  1537. ULONG AdapterIndex;
  1538. PIP_ADAPTER_BINDING_INFO BindingInfo = NULL;
  1539. ULONG Error;
  1540. HRASCONN Hrasconn;
  1541. GUID Guid;
  1542. UNICODE_STRING UnicodeString;
  1543. NTSTATUS Status;
  1544. BOOLEAN bUPnPEventAlreadyFired = FALSE;
  1545. PROFILE("NatpProcessConnectionNotify");
  1546. EnterCriticalSection(&NatInterfaceLock);
  1547. //
  1548. // Walk through the connection list
  1549. //
  1550. for (Link = NatpConnectionList.Flink;
  1551. Link != &NatpConnectionList;
  1552. Link = Link->Flink)
  1553. {
  1554. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  1555. //
  1556. // If the connection is a LAN connection,
  1557. // it is always active.
  1558. //
  1559. // If the connection is a dialup connection,
  1560. // find out whether the connection is active.
  1561. //
  1562. if (pConEntry->HNetProperties.fLanConnection) {
  1563. Hrasconn = NULL;
  1564. Active = TRUE;
  1565. //
  1566. // The connection is a LAN connection, so we need to detect
  1567. // any changes to its IP address if it is already bound.
  1568. // To do so we retrieve the current binding information
  1569. // and compare it to the active binding information.
  1570. // If the two are different, we unbind the interface and rebind.
  1571. //
  1572. Status =
  1573. RtlStringFromGUID(pConEntry->Guid, &UnicodeString);
  1574. if (NT_SUCCESS(Status)) {
  1575. AdapterIndex = NhMapGuidToAdapter(UnicodeString.Buffer);
  1576. RtlFreeUnicodeString(&UnicodeString);
  1577. } else {
  1578. AdapterIndex = (ULONG)-1;
  1579. NhTrace(
  1580. TRACE_FLAG_NAT,
  1581. "NatpProcessConnectionNotify: RtlStringFromGUID failed"
  1582. );
  1583. }
  1584. if (AdapterIndex == (ULONG)-1) {
  1585. NhTrace(
  1586. TRACE_FLAG_NAT,
  1587. "NatpProcessConnectionNotify: MapGuidToAdapter failed"
  1588. );
  1589. Active = FALSE;
  1590. } else {
  1591. BindingInfo = NhQueryBindingInformation(AdapterIndex);
  1592. if (!BindingInfo) {
  1593. NhTrace(
  1594. TRACE_FLAG_NAT,
  1595. "NatpProcessConnectionNotify: QueryBinding failed"
  1596. );
  1597. Active = FALSE;
  1598. } else if (0 == BindingInfo->AddressCount) {
  1599. NhTrace(
  1600. TRACE_FLAG_NAT,
  1601. "NatpProcessConnectionNotify: Adapter has no addresses"
  1602. );
  1603. Active = FALSE;
  1604. NH_FREE(BindingInfo);
  1605. BindingInfo = NULL;
  1606. } else if (NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  1607. //
  1608. // The interface is already bound;
  1609. // compare the retrieved binding to the active binding,
  1610. // and unbind the connection if they are different.
  1611. //
  1612. if (!pConEntry->pBindingInfo ||
  1613. BindingInfo->AddressCount !=
  1614. pConEntry->pBindingInfo->AddressCount ||
  1615. !RtlEqualMemory(
  1616. &BindingInfo->Address[0],
  1617. &pConEntry->pBindingInfo->Address[0],
  1618. sizeof(IP_LOCAL_BINDING)
  1619. )) {
  1620. NatpUnbindConnection(pConEntry);
  1621. if ( pConEntry->HNetProperties.fIcsPublic )
  1622. {
  1623. FireNATEvent_PublicIPAddressChanged();
  1624. bUPnPEventAlreadyFired = TRUE;
  1625. }
  1626. } else {
  1627. //
  1628. // The bindings are the same, and the interface is bound
  1629. // already, so we won't be needing the newly-retrieved
  1630. // binding information.
  1631. //
  1632. NH_FREE(BindingInfo);
  1633. BindingInfo = NULL;
  1634. }
  1635. }
  1636. }
  1637. } else {
  1638. AdapterIndex = (ULONG)-1;
  1639. Hrasconn = NULL;
  1640. //
  1641. // Obtain the name of the connection
  1642. //
  1643. HRESULT hr;
  1644. LPWSTR wszEntryName;
  1645. hr = pConEntry->pHNetConnection->GetName(&wszEntryName);
  1646. if (SUCCEEDED(hr)) {
  1647. Error =
  1648. RasGetEntryHrasconnW(
  1649. pConEntry->wszPhonebookPath,
  1650. wszEntryName,
  1651. &Hrasconn
  1652. );
  1653. CoTaskMemFree(wszEntryName);
  1654. }
  1655. Active = ((FAILED(hr) || Error || !Hrasconn) ? FALSE : TRUE);
  1656. }
  1657. //
  1658. // Activate or deactivate the shared-connection as needed;
  1659. // when activating a LAN connection, we save the binding information
  1660. // so we can detect address changes later on.
  1661. //
  1662. if (!Active && NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  1663. NatpUnbindConnection(pConEntry);
  1664. if (pConEntry->HNetProperties.fIcsPublic &&
  1665. (FALSE == bUPnPEventAlreadyFired))
  1666. {
  1667. FireNATEvent_PublicIPAddressChanged();
  1668. }
  1669. } else if (Active && !NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  1670. //
  1671. // N.B. When a media-sense event occurs and TCP/IP revokes the IP
  1672. // address for a LAN connection, the connection's IP address becomes
  1673. // 0.0.0.0. We treat that as though we don't have an IP address at all,
  1674. // and bypass the binding below. When the IP address is reinstated,
  1675. // we will rebind correctly, since we will then detect the change.
  1676. //
  1677. if (pConEntry->HNetProperties.fLanConnection) {
  1678. if (BindingInfo->AddressCount != 1 ||
  1679. BindingInfo->Address[0].Address) {
  1680. NatpBindConnection(pConEntry, Hrasconn, AdapterIndex, BindingInfo);
  1681. }
  1682. if (pConEntry->pBindingInfo) {
  1683. NH_FREE(pConEntry->pBindingInfo);
  1684. }
  1685. pConEntry->pBindingInfo = BindingInfo;
  1686. } else {
  1687. NatpBindConnection(pConEntry, Hrasconn, AdapterIndex, BindingInfo);
  1688. }
  1689. if ( pConEntry->HNetProperties.fIcsPublic &&
  1690. (FALSE == bUPnPEventAlreadyFired) &&
  1691. NAT_INTERFACE_BOUND(&pConEntry->Interface))
  1692. {
  1693. FireNATEvent_PublicIPAddressChanged();
  1694. }
  1695. }
  1696. }
  1697. //
  1698. // If we have a shared connection, also need to update the private interface
  1699. //
  1700. if (NatpSharedConnectionPresent && NhPolicyAllowsSharing) {
  1701. NhUpdatePrivateInterface();
  1702. }
  1703. LeaveCriticalSection(&NatInterfaceLock);
  1704. } // NatpProcessConnectionNotify
  1705. ULONG
  1706. NatpQueryConnectionAdapter(
  1707. PNAT_CONNECTION_ENTRY pConEntry
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. This routine is invoked to determine the adapter index corresponding
  1712. to a connection, if active.
  1713. Arguments:
  1714. pConEntry - the connection entry
  1715. Return Value:
  1716. ULONG - the adapter index if found, otherwise (ULONG)-1.
  1717. Environment:
  1718. Invoked with 'NatInterfaceLock' held by the caller.
  1719. --*/
  1720. {
  1721. ULONG AdapterIndex = (ULONG)-1;
  1722. ULONG Error;
  1723. HRASCONN Hrasconn = NULL;
  1724. RASPPPIPA RasPppIp;
  1725. ULONG Size;
  1726. NTSTATUS Status;
  1727. UNICODE_STRING UnicodeString;
  1728. if (pConEntry->HNetProperties.fLanConnection) {
  1729. Status = RtlStringFromGUID(pConEntry->Guid, &UnicodeString);
  1730. if (NT_SUCCESS(Status)) {
  1731. AdapterIndex = NhMapGuidToAdapter(UnicodeString.Buffer);
  1732. RtlFreeUnicodeString(&UnicodeString);
  1733. }
  1734. } else {
  1735. HRESULT hr;
  1736. LPWSTR wszEntryName;
  1737. hr = pConEntry->pHNetConnection->GetName(&wszEntryName);
  1738. if (SUCCEEDED(hr))
  1739. {
  1740. Error =
  1741. RasGetEntryHrasconnW(
  1742. pConEntry->wszPhonebookPath,
  1743. wszEntryName,
  1744. &Hrasconn
  1745. );
  1746. if (!Error && Hrasconn) {
  1747. ZeroMemory(&RasPppIp, sizeof(RasPppIp));
  1748. Size = RasPppIp.dwSize = sizeof(RasPppIp);
  1749. Error =
  1750. RasGetProjectionInfoA(
  1751. Hrasconn,
  1752. RASP_PppIp,
  1753. &RasPppIp,
  1754. &Size
  1755. );
  1756. if (!Error) {
  1757. AdapterIndex =
  1758. NhMapAddressToAdapter(inet_addr(RasPppIp.szIpAddress));
  1759. }
  1760. }
  1761. CoTaskMemFree(wszEntryName);
  1762. }
  1763. }
  1764. NhTrace(TRACE_FLAG_NAT, "NatpQueryConnectionAdapter: %d", AdapterIndex);
  1765. return AdapterIndex;
  1766. } // NatpQueryConnectionAdapter
  1767. PIP_NAT_INTERFACE_INFO
  1768. NatpQueryConnectionInformation(
  1769. PNAT_CONNECTION_ENTRY pConEntry,
  1770. PIP_ADAPTER_BINDING_INFO BindingInfo
  1771. )
  1772. /*++
  1773. Routine Description:
  1774. This routine is invoked to construct the configuration
  1775. of a connection. The configuration consists of basic settings
  1776. (e.g. interface type and flags) as well as extended information loaded
  1777. from the configuration store (e.g. port mappings).
  1778. Arguments:
  1779. pConEntry - the connection entry
  1780. BindingInfo - the binding info for the connection
  1781. Return Value:
  1782. PIP_NAT_INTERFACE_INFO - the configuration allocated;
  1783. on error, returns NULL
  1784. Environment:
  1785. Invoked with 'NatInterfaceLock' held by the caller.
  1786. --*/
  1787. {
  1788. PIP_NAT_PORT_MAPPING Array = NULL;
  1789. ULONG Count = 0;
  1790. ULONG Error;
  1791. PIP_NAT_INTERFACE_INFO Info;
  1792. PRTR_INFO_BLOCK_HEADER Header;
  1793. HRESULT hr;
  1794. ULONG Length;
  1795. PLIST_ENTRY Link;
  1796. PRTR_INFO_BLOCK_HEADER NewHeader;
  1797. PNAT_PORT_MAPPING_ENTRY PortMapping;
  1798. PROFILE("NatpQueryConnectionInformation");
  1799. //
  1800. // Build the port mapping array from the list
  1801. //
  1802. if (pConEntry->PortMappingCount)
  1803. {
  1804. Array =
  1805. reinterpret_cast<PIP_NAT_PORT_MAPPING>(
  1806. NH_ALLOCATE(pConEntry->PortMappingCount * sizeof(IP_NAT_PORT_MAPPING))
  1807. );
  1808. if (NULL == Array)
  1809. {
  1810. NhTrace(
  1811. TRACE_FLAG_NAT,
  1812. "NatpQueryConnectionInformation: Unable to allocate array"
  1813. );
  1814. return NULL;
  1815. }
  1816. for (Link = pConEntry->PortMappingList.Flink;
  1817. Link != &pConEntry->PortMappingList;
  1818. Link = Link->Flink)
  1819. {
  1820. PortMapping = CONTAINING_RECORD(Link, NAT_PORT_MAPPING_ENTRY, Link);
  1821. if (PortMapping->fUdpBroadcastMapping) { continue; }
  1822. Array[Count].PublicAddress = IP_NAT_ADDRESS_UNSPECIFIED;
  1823. Array[Count].Protocol = PortMapping->ucProtocol;
  1824. Array[Count].PublicPort = PortMapping->usPublicPort;
  1825. Array[Count].PrivateAddress = PortMapping->ulPrivateAddress;
  1826. Array[Count].PrivatePort = PortMapping->usPrivatePort;
  1827. Count += 1;
  1828. }
  1829. ASSERT(Count == pConEntry->PortMappingCount);
  1830. }
  1831. //
  1832. // Create an info-block header and add the port-mapping array
  1833. // as the single entry in the info-block.
  1834. // This info-block header will occupy the 'Header' field
  1835. // of the final 'IP_NAT_INTERFACE_INFO'.
  1836. //
  1837. Error = MprInfoCreate(IP_NAT_VERSION, reinterpret_cast<LPVOID*>(&Header));
  1838. if (Error) {
  1839. if (Array) {
  1840. NH_FREE(Array);
  1841. }
  1842. return NULL;
  1843. }
  1844. if (Count) {
  1845. Error =
  1846. MprInfoBlockAdd(
  1847. Header,
  1848. IP_NAT_PORT_MAPPING_TYPE,
  1849. sizeof(IP_NAT_PORT_MAPPING),
  1850. Count,
  1851. (PUCHAR)Array,
  1852. reinterpret_cast<LPVOID*>(&NewHeader)
  1853. );
  1854. MprInfoDelete(Header); NH_FREE(Array); Header = NewHeader;
  1855. if (Error) {
  1856. return NULL;
  1857. }
  1858. } else if (Array) {
  1859. NH_FREE(Array);
  1860. }
  1861. //
  1862. // For firewalled entries, get ICMP settings
  1863. //
  1864. if (pConEntry->HNetProperties.fFirewalled && NhPolicyAllowsFirewall)
  1865. {
  1866. HNET_FW_ICMP_SETTINGS *pIcmpSettings;
  1867. DWORD dwIcmpFlags = 0;
  1868. hr = pConEntry->pHNetConnection->GetIcmpSettings(&pIcmpSettings);
  1869. if (SUCCEEDED(hr))
  1870. {
  1871. if (pIcmpSettings->fAllowOutboundDestinationUnreachable)
  1872. {
  1873. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_DEST_UNREACH;
  1874. }
  1875. if (pIcmpSettings->fAllowOutboundSourceQuench)
  1876. {
  1877. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_SOURCE_QUENCH;
  1878. }
  1879. if (pIcmpSettings->fAllowRedirect)
  1880. {
  1881. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_REDIRECT;
  1882. }
  1883. if (pIcmpSettings->fAllowInboundEchoRequest)
  1884. {
  1885. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_ECHO;
  1886. }
  1887. if (pIcmpSettings->fAllowInboundRouterRequest)
  1888. {
  1889. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_ROUTER;
  1890. }
  1891. if (pIcmpSettings->fAllowOutboundTimeExceeded)
  1892. {
  1893. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_TIME_EXCEEDED;
  1894. }
  1895. if (pIcmpSettings->fAllowOutboundParameterProblem)
  1896. {
  1897. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_OB_PARAM_PROBLEM;
  1898. }
  1899. if (pIcmpSettings->fAllowInboundTimestampRequest)
  1900. {
  1901. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_TIMESTAMP;
  1902. }
  1903. if (pIcmpSettings->fAllowInboundMaskRequest)
  1904. {
  1905. dwIcmpFlags |= IP_NAT_ICMP_ALLOW_IB_MASK;
  1906. }
  1907. CoTaskMemFree(pIcmpSettings);
  1908. Error =
  1909. MprInfoBlockAdd(
  1910. Header,
  1911. IP_NAT_ICMP_CONFIG_TYPE,
  1912. sizeof(DWORD),
  1913. 1,
  1914. (PUCHAR)&dwIcmpFlags,
  1915. reinterpret_cast<LPVOID*>(&NewHeader)
  1916. );
  1917. if (NO_ERROR == Error)
  1918. {
  1919. MprInfoDelete(Header);
  1920. Header = NewHeader;
  1921. }
  1922. }
  1923. else
  1924. {
  1925. NhTrace(
  1926. TRACE_FLAG_NAT,
  1927. "NatpQueryConnectionInformation: GetIcmpSettings 0x%08x",
  1928. hr
  1929. );
  1930. //
  1931. // This is a 'soft' error -- we'll still continue even if we
  1932. // couldn't get the ICMP settings, as our default stance
  1933. // is more secure than if any of the flags were set.
  1934. //
  1935. }
  1936. }
  1937. //
  1938. // Allocate an 'IP_NAT_INTERFACE_INFO' which is large enough to hold
  1939. // the info-block header which we've just constructed.
  1940. //
  1941. Length = FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) + Header->Size;
  1942. Info = reinterpret_cast<PIP_NAT_INTERFACE_INFO>(NH_ALLOCATE(Length));
  1943. if (Info)
  1944. {
  1945. RtlZeroMemory(Info, FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header));
  1946. //
  1947. // Set appropriate flags
  1948. //
  1949. if (pConEntry->HNetProperties.fFirewalled && NhPolicyAllowsFirewall)
  1950. {
  1951. Info->Flags |= IP_NAT_INTERFACE_FLAGS_FW;
  1952. }
  1953. if (pConEntry->HNetProperties.fIcsPublic && NhPolicyAllowsSharing)
  1954. {
  1955. Info->Flags |=
  1956. IP_NAT_INTERFACE_FLAGS_BOUNDARY | IP_NAT_INTERFACE_FLAGS_NAPT;
  1957. }
  1958. //
  1959. // Copy the info-block header into the info structure
  1960. //
  1961. RtlCopyMemory(&Info->Header, Header, Header->Size);
  1962. }
  1963. MprInfoDelete(Header);
  1964. return Info;
  1965. } // NatpQuerySharedConnectionInformation
  1966. VOID NTAPI
  1967. NatpRoutingFailureCallbackRoutine(
  1968. PVOID Context,
  1969. PIO_STATUS_BLOCK IoStatus,
  1970. ULONG Reserved
  1971. )
  1972. /*++
  1973. Routine Description:
  1974. This routine is invoked when a routing-failure notification occurs,
  1975. or when the request is cancelled (e.g. because the request's thread exited).
  1976. Arguments:
  1977. Context - unused
  1978. IoStatus - contains the status of the operation
  1979. Reserved - unused
  1980. Return Value:
  1981. none.
  1982. Environment:
  1983. Invoked with a reference made to the component on our behalf.
  1984. That reference is released here, and if notification is re-requested,
  1985. it is re-acquired.
  1986. --*/
  1987. {
  1988. CHAR DestinationAddress[32];
  1989. ULONG Error;
  1990. IP_NAT_REQUEST_NOTIFICATION RequestNotification;
  1991. PROFILE("NatpRoutingFailureCallbackRoutine");
  1992. //
  1993. // See if cleanup has occurred
  1994. //
  1995. EnterCriticalSection(&NatInterfaceLock);
  1996. if (!NatConnectionNotifyEvent) {
  1997. LeaveCriticalSection(&NatInterfaceLock);
  1998. DEREFERENCE_NAT();
  1999. return;
  2000. }
  2001. LeaveCriticalSection(&NatInterfaceLock);
  2002. //
  2003. // Acquire a new reference, and release the old one
  2004. //
  2005. if (!REFERENCE_NAT()) { DEREFERENCE_NAT(); return; }
  2006. DEREFERENCE_NAT();
  2007. lstrcpyA(
  2008. DestinationAddress,
  2009. inet_ntoa(*(PIN_ADDR)&NatpRoutingFailureNotification.DestinationAddress)
  2010. );
  2011. NhTrace(
  2012. TRACE_FLAG_NAT,
  2013. "NatpRoutingFailureCallbackRoutine: %s->%s",
  2014. inet_ntoa(*(PIN_ADDR)&NatpRoutingFailureNotification.SourceAddress),
  2015. DestinationAddress
  2016. );
  2017. //
  2018. // Request an automatic connection if the notification succeeded
  2019. //
  2020. if (NT_SUCCESS(IoStatus->Status)) {
  2021. //
  2022. // First see if this is a known autodial destination,
  2023. // requesting a connection if so.
  2024. //
  2025. ULONG Count;
  2026. ULONG Size;
  2027. Size = 0;
  2028. Error =
  2029. RasGetAutodialAddressA(
  2030. DestinationAddress,
  2031. NULL,
  2032. NULL,
  2033. &Size,
  2034. &Count
  2035. );
  2036. if (Error != ERROR_BUFFER_TOO_SMALL) {
  2037. //
  2038. // This is not a known destination;
  2039. // try the default shared connection, if any
  2040. //
  2041. NhDialSharedConnection();
  2042. } else {
  2043. //
  2044. // Try initiating a normal autodial connection;
  2045. // normal autodial may yet lead to the shared-connection.
  2046. //
  2047. HINSTANCE Hinstance = LoadLibraryA("RASADHLP.DLL");
  2048. if (Hinstance) {
  2049. BOOL (*WSAttemptAutodialAddr)(PSOCKADDR_IN, INT) =
  2050. (BOOL (*)(PSOCKADDR_IN, INT))
  2051. GetProcAddress(
  2052. Hinstance,
  2053. "WSAttemptAutodialAddr"
  2054. );
  2055. if (WSAttemptAutodialAddr) {
  2056. SOCKADDR_IN SockAddr;
  2057. SockAddr.sin_family = AF_INET;
  2058. SockAddr.sin_addr.s_addr =
  2059. NatpRoutingFailureNotification.DestinationAddress;
  2060. WSAttemptAutodialAddr(&SockAddr, sizeof(SockAddr));
  2061. }
  2062. FreeLibrary(Hinstance);
  2063. }
  2064. }
  2065. }
  2066. //
  2067. // Submit a new request
  2068. //
  2069. EnterCriticalSection(&NatInterfaceLock);
  2070. RequestNotification.Code = NatRoutingFailureNotification;
  2071. NtDeviceIoControlFile(
  2072. NatFileHandle,
  2073. NULL,
  2074. NatpRoutingFailureCallbackRoutine,
  2075. NULL,
  2076. &NatpRoutingFailureIoStatus,
  2077. IOCTL_IP_NAT_REQUEST_NOTIFICATION,
  2078. (PVOID)&RequestNotification,
  2079. sizeof(RequestNotification),
  2080. &NatpRoutingFailureNotification,
  2081. sizeof(NatpRoutingFailureNotification)
  2082. );
  2083. LeaveCriticalSection(&NatInterfaceLock);
  2084. } // NatpRoutingFailureCallbackRoutine
  2085. VOID NTAPI
  2086. NatpRoutingFailureWorkerRoutine(
  2087. PVOID Context
  2088. )
  2089. /*++
  2090. Routine Description:
  2091. This routine initiates the notification of routing-failures.
  2092. Arguments:
  2093. none used.
  2094. Return Value:
  2095. none.
  2096. Environment:
  2097. Invoked in the context of an alertable I/O worker thread.
  2098. --*/
  2099. {
  2100. IP_NAT_REQUEST_NOTIFICATION RequestNotification;
  2101. PROFILE("NatpRoutingFailureWorkerRoutine");
  2102. //
  2103. // Request notification of routing-failures
  2104. //
  2105. EnterCriticalSection(&NatInterfaceLock);
  2106. RequestNotification.Code = NatRoutingFailureNotification;
  2107. NtDeviceIoControlFile(
  2108. NatFileHandle,
  2109. NULL,
  2110. NatpRoutingFailureCallbackRoutine,
  2111. NULL,
  2112. &NatpRoutingFailureIoStatus,
  2113. IOCTL_IP_NAT_REQUEST_NOTIFICATION,
  2114. (PVOID)&RequestNotification,
  2115. sizeof(RequestNotification),
  2116. &NatpRoutingFailureNotification,
  2117. sizeof(NatpRoutingFailureNotification)
  2118. );
  2119. LeaveCriticalSection(&NatInterfaceLock);
  2120. } // NatpRoutingFailureWorkerRoutine
  2121. ULONG
  2122. NatpStartSharedConnectionManagement(
  2123. VOID
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. This routine is called to install routing failure-notification, and
  2128. to enable the router
  2129. Arguments:
  2130. none.
  2131. Return Value:
  2132. ULONG - Win32 status code.
  2133. --*/
  2134. {
  2135. ULONG Error;
  2136. BOOL SharedAutoDial;
  2137. NTSTATUS status;
  2138. PROFILE("NatpStartSharedConnectionManagement");
  2139. //
  2140. // See if the user has enabled shared-autodial.
  2141. // If so, make sure the autodial service is running,
  2142. // since it will be needed for performing on-demand dialing.
  2143. //
  2144. // (IHNetIcsSettings::GetAutodialEnabled just calls the RAS api below,
  2145. // which is why we're not getting the information that way right now...)
  2146. //
  2147. if (!RasQuerySharedAutoDial(&SharedAutoDial) && SharedAutoDial) {
  2148. SC_HANDLE ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  2149. if (ScmHandle) {
  2150. SC_HANDLE ServiceHandle =
  2151. OpenService(ScmHandle, TEXT("RasAuto"), SERVICE_ALL_ACCESS);
  2152. if (ServiceHandle) {
  2153. StartService(ServiceHandle, 0, NULL);
  2154. CloseServiceHandle(ServiceHandle);
  2155. }
  2156. CloseServiceHandle(ScmHandle);
  2157. }
  2158. }
  2159. EnterCriticalSection(&NatInterfaceLock);
  2160. if (NatpEnableRouterEvent) {
  2161. LeaveCriticalSection(&NatInterfaceLock);
  2162. return NO_ERROR;
  2163. }
  2164. //
  2165. // Acquire a component-reference on behalf of
  2166. // (1) the enable-router callback routine
  2167. // (2) the routing-failure-notification worker routine.
  2168. //
  2169. if (!REFERENCE_NAT()) {
  2170. LeaveCriticalSection(&NatInterfaceLock);
  2171. return ERROR_CAN_NOT_COMPLETE;
  2172. } else if (!REFERENCE_NAT()) {
  2173. LeaveCriticalSection(&NatInterfaceLock);
  2174. DEREFERENCE_NAT();
  2175. return ERROR_CAN_NOT_COMPLETE;
  2176. }
  2177. do {
  2178. //
  2179. // Start DNS and DHCP modules
  2180. //
  2181. Error = NhStartICSProtocols();
  2182. if (Error) break;
  2183. //
  2184. // Enable IP forwarding:
  2185. // Create an event to be used in the overlapped I/O structure
  2186. // that will be passed to the 'EnableRouter' API routine,
  2187. // set up the overlapped structure, and schedule the request
  2188. // by signalling the event.
  2189. //
  2190. NatpEnableRouterEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2191. if (!NatpEnableRouterEvent) {
  2192. Error = GetLastError(); break;
  2193. }
  2194. status =
  2195. RtlRegisterWait(
  2196. &NatpEnableRouterWaitHandle,
  2197. NatpEnableRouterEvent,
  2198. NatpEnableRouterCallbackRoutine,
  2199. NULL,
  2200. INFINITE,
  2201. 0
  2202. );
  2203. if (!NT_SUCCESS(status)) {
  2204. Error = RtlNtStatusToDosError(status); break;
  2205. }
  2206. SetEvent(NatpEnableRouterEvent);
  2207. //
  2208. // Queue a work item in whose context we will make a request
  2209. // for routing-failure notification from the NAT driver.
  2210. // We use a work-item rather than issuing the request directly
  2211. // to avoid having our I/O request cancelled if and when the current
  2212. // (thread pool) thread exits.
  2213. //
  2214. RtlQueueWorkItem(
  2215. NatpRoutingFailureWorkerRoutine,
  2216. NULL,
  2217. WT_EXECUTEINIOTHREAD
  2218. );
  2219. LeaveCriticalSection(&NatInterfaceLock);
  2220. return NO_ERROR;
  2221. } while (FALSE);
  2222. if (NatpEnableRouterWaitHandle) {
  2223. RtlDeregisterWait(NatpEnableRouterWaitHandle);
  2224. NatpEnableRouterWaitHandle = NULL;
  2225. }
  2226. if (NatpEnableRouterEvent) {
  2227. CloseHandle(NatpEnableRouterEvent);
  2228. NatpEnableRouterEvent = NULL;
  2229. }
  2230. LeaveCriticalSection(&NatInterfaceLock);
  2231. DEREFERENCE_NAT();
  2232. DEREFERENCE_NAT();
  2233. return Error;
  2234. } // NatpStartSharedConnectionManagement
  2235. ULONG
  2236. NatpStopSharedConnectionManagement(
  2237. VOID
  2238. )
  2239. /*++
  2240. Routine Description:
  2241. This routine is called to stop the DNS & DHCP modules and also
  2242. to remove the routing failure-notification, and
  2243. to disable the router
  2244. Arguments:
  2245. none.
  2246. Return Value:
  2247. ULONG - Win32 status code.
  2248. --*/
  2249. {
  2250. ULONG Error = NO_ERROR;
  2251. PROFILE("NatpStopSharedConnectionManagement");
  2252. EnterCriticalSection(&NatInterfaceLock);
  2253. //
  2254. // Stop the DHCP, DNS, QoSWindowAdjustment and Beacon modules
  2255. //
  2256. Error = NhStopICSProtocols();
  2257. if (NatpEnableRouterWaitHandle) {
  2258. RtlDeregisterWait(NatpEnableRouterWaitHandle);
  2259. NatpEnableRouterWaitHandle = NULL;
  2260. }
  2261. if (NatpEnableRouterEvent) {
  2262. CloseHandle(NatpEnableRouterEvent);
  2263. NatpEnableRouterEvent = NULL;
  2264. NatpEnableRouterCallbackRoutine(NULL, FALSE);
  2265. }
  2266. LeaveCriticalSection(&NatInterfaceLock);
  2267. return Error;
  2268. } // NatpStopSharedConnectionManagement
  2269. BOOLEAN
  2270. NatpUnbindConnection(
  2271. PNAT_CONNECTION_ENTRY pConEntry
  2272. )
  2273. /*++
  2274. Routine Description:
  2275. This routine is invoked to unbind a currently-active connection.
  2276. Arguments:
  2277. Index - index into the connection array
  2278. Return Value:
  2279. TRUE if the entry was previously bound; FALSE otherwise.
  2280. Environment:
  2281. Invoked with 'NatInterfaceLock' held by the caller.
  2282. --*/
  2283. {
  2284. LIST_ENTRY *pLink;
  2285. PNAT_PORT_MAPPING_ENTRY pMapping;
  2286. PROFILE("NatpUnbindConnection");
  2287. if (NAT_INTERFACE_BOUND(&pConEntry->Interface)) {
  2288. NatUnbindInterface(
  2289. pConEntry->Interface.Index,
  2290. &pConEntry->Interface
  2291. );
  2292. if (NAT_INTERFACE_ADDED_ALG(&pConEntry->Interface)) {
  2293. AlgRmDeleteInterface(pConEntry->Interface.Index);
  2294. pConEntry->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_ALG;
  2295. }
  2296. if (NAT_INTERFACE_ADDED_H323(&pConEntry->Interface)) {
  2297. H323RmDeleteInterface(pConEntry->Interface.Index);
  2298. pConEntry->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_H323;
  2299. }
  2300. RemoveEntryList(&pConEntry->Interface.Link);
  2301. InitializeListHead(&pConEntry->Interface.Link);
  2302. if (pConEntry->Interface.Info) {
  2303. NH_FREE(pConEntry->Interface.Info);
  2304. pConEntry->Interface.Info = NULL;
  2305. }
  2306. //
  2307. // Clean up the port mapping list
  2308. //
  2309. NatpFreePortMappingList(pConEntry);
  2310. return TRUE;
  2311. }
  2312. return FALSE;
  2313. } // NatpUnbindConnection
  2314. VOID
  2315. NatpUpdateSharedConnectionDomainName(
  2316. ULONG AdapterIndex
  2317. )
  2318. /*++
  2319. Routine Description:
  2320. This routine is called to update the cached DNS domain name, if any,
  2321. for the shared connection.
  2322. Arguments:
  2323. AdapterIndex - the index of the adapter for the shared connection
  2324. Return Value:
  2325. none.
  2326. --*/
  2327. {
  2328. PDNS_ADAPTER_INFOA AdapterInformation;
  2329. ANSI_STRING AnsiString;
  2330. ULONG Count;
  2331. ULONG Error;
  2332. ULONG i;
  2333. PDNS_NETWORK_INFOA NetworkInformation = NULL;
  2334. NTSTATUS Status;
  2335. PIP_INTERFACE_NAME_INFO Table = NULL;
  2336. UNICODE_STRING UnicodeString;
  2337. PROFILE("NatpUpdateSharedConnectionDomainName");
  2338. RtlInitAnsiString(&AnsiString, NULL);
  2339. RtlInitUnicodeString(&UnicodeString, NULL);
  2340. EnterCriticalSection(&NatInterfaceLock);
  2341. if (AdapterIndex == (ULONG)-1)
  2342. {
  2343. PLIST_ENTRY Link;
  2344. PNAT_CONNECTION_ENTRY pConEntry;
  2345. //
  2346. // Make sure that the connection list has been initialized; if
  2347. // it hasn't, Flink will be NULL.
  2348. //
  2349. if (!NatpConnectionList.Flink) {
  2350. LeaveCriticalSection(&NatInterfaceLock);
  2351. return;
  2352. }
  2353. //
  2354. // See if we actually have a shared connection
  2355. //
  2356. for (Link = NatpConnectionList.Flink;
  2357. Link != &NatpConnectionList;
  2358. Link = Link->Flink)
  2359. {
  2360. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  2361. if (pConEntry->HNetProperties.fIcsPublic)
  2362. {
  2363. AdapterIndex = NatpQueryConnectionAdapter(pConEntry);
  2364. break;
  2365. }
  2366. }
  2367. if (AdapterIndex == (ULONG)-1) {
  2368. LeaveCriticalSection(&NatInterfaceLock);
  2369. return;
  2370. }
  2371. }
  2372. do {
  2373. //
  2374. // Obtain the GUID for the adapter with the given index,
  2375. // by querying TCP/IP for information on all available interfaces.
  2376. // The GUID will then be used to map the shared connection's adapter
  2377. // to a DNS domain name.
  2378. //
  2379. Error =
  2380. NhpAllocateAndGetInterfaceInfoFromStack(
  2381. &Table, &Count, FALSE, GetProcessHeap(), 0
  2382. );
  2383. if (Error != NO_ERROR) { break; }
  2384. for (i = 0; i < Count && Table[i].Index != AdapterIndex; i++) { }
  2385. if (i >= Count) { Error = ERROR_INTERNAL_ERROR; break; }
  2386. Status = RtlStringFromGUID(Table[i].DeviceGuid, &UnicodeString);
  2387. if (!NT_SUCCESS(Status)) { break; }
  2388. Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
  2389. if (!NT_SUCCESS(Status)) { break; }
  2390. //
  2391. // Query the DNS client for the current network parameters,
  2392. // and search through the network parameters to find the entry
  2393. // for the shared-connection's current adapter.
  2394. //
  2395. NetworkInformation = (PDNS_NETWORK_INFOA)
  2396. DnsQueryConfigAlloc(
  2397. DnsConfigNetworkInfoA,
  2398. NULL );
  2399. if (!NetworkInformation) { Error = ERROR_INTERNAL_ERROR; break; }
  2400. for (i = 0; i < NetworkInformation->AdapterCount; i++) {
  2401. AdapterInformation = &NetworkInformation->AdapterArray[i];
  2402. if (lstrcmpiA(
  2403. AnsiString.Buffer,
  2404. AdapterInformation->pszAdapterGuidName
  2405. ) == 0) {
  2406. break;
  2407. }
  2408. }
  2409. if (i >= NetworkInformation->AdapterCount) {
  2410. Error = ERROR_INTERNAL_ERROR;
  2411. break;
  2412. }
  2413. //
  2414. // 'AdapterInformation' is the entry for the shared-connection's
  2415. // current adapter.
  2416. // Clear the previously-cached string, and read in the new value,
  2417. // if any.
  2418. //
  2419. if (NatpSharedConnectionDomainName) {
  2420. NH_FREE(NatpSharedConnectionDomainName);
  2421. NatpSharedConnectionDomainName = NULL;
  2422. }
  2423. if (AdapterInformation->pszAdapterDomain) {
  2424. NatpSharedConnectionDomainName =
  2425. reinterpret_cast<PCHAR>(
  2426. NH_ALLOCATE(lstrlenA(AdapterInformation->pszAdapterDomain) + 1)
  2427. );
  2428. if (!NatpSharedConnectionDomainName) {
  2429. Error = ERROR_INTERNAL_ERROR;
  2430. break;
  2431. }
  2432. lstrcpyA(
  2433. NatpSharedConnectionDomainName,
  2434. AdapterInformation->pszAdapterDomain
  2435. );
  2436. }
  2437. Error = NO_ERROR;
  2438. } while(FALSE);
  2439. if (UnicodeString.Buffer) {
  2440. RtlFreeUnicodeString(&UnicodeString);
  2441. }
  2442. if (AnsiString.Buffer) {
  2443. RtlFreeAnsiString(&AnsiString);
  2444. }
  2445. if (NetworkInformation) {
  2446. DnsFreeConfigStructure(
  2447. NetworkInformation,
  2448. // DnsConfigNetworkInformation );
  2449. DnsConfigNetworkInfoA ); // <--- jwesth: this seems to be the correct freetype
  2450. }
  2451. if (Table) {
  2452. HeapFree(GetProcessHeap(), 0, Table);
  2453. }
  2454. if (Error) {
  2455. if (NatpSharedConnectionDomainName) {
  2456. NH_FREE(NatpSharedConnectionDomainName);
  2457. NatpSharedConnectionDomainName = NULL;
  2458. }
  2459. }
  2460. LeaveCriticalSection(&NatInterfaceLock);
  2461. } // NatpUpdateSharedConnectionDomainName
  2462. PCHAR
  2463. NatQuerySharedConnectionDomainName(
  2464. VOID
  2465. )
  2466. /*++
  2467. Routine Description:
  2468. This routine is called to retrieve a copy of the DNS domain name
  2469. cached for the shared connection, if available. Otherwise, it returns
  2470. the primary DNS domain name for the local machine.
  2471. Arguments:
  2472. none.
  2473. Return Value:
  2474. PCHAR - contains the allocated copy of the DNS domain name.
  2475. --*/
  2476. {
  2477. PCHAR DomainName;
  2478. PROFILE("NatQuerySharedConnectionDomainName");
  2479. //
  2480. // See if there is a cached domain name for the shared connection.
  2481. // If not, refresh the cache. If there is still no domain name,
  2482. // return a copy of the local machine's primary DNS domain name.
  2483. //
  2484. EnterCriticalSection(&NatInterfaceLock);
  2485. if (!NatpSharedConnectionDomainName) {
  2486. NatpUpdateSharedConnectionDomainName((ULONG)-1);
  2487. }
  2488. if (NatpSharedConnectionDomainName) {
  2489. DomainName =
  2490. reinterpret_cast<PCHAR>(
  2491. NH_ALLOCATE(lstrlenA(NatpSharedConnectionDomainName) + 1)
  2492. );
  2493. if (DomainName) {
  2494. lstrcpyA(DomainName, NatpSharedConnectionDomainName);
  2495. }
  2496. } else {
  2497. PCHAR DnsDomainName = (PCHAR) DnsQueryConfigAlloc(
  2498. DnsConfigPrimaryDomainName_A,
  2499. NULL );
  2500. if (!DnsDomainName) {
  2501. DomainName = NULL;
  2502. } else {
  2503. DomainName =
  2504. reinterpret_cast<PCHAR>(
  2505. NH_ALLOCATE(lstrlenA(DnsDomainName) + 1)
  2506. );
  2507. if (DomainName) {
  2508. lstrcpyA(DomainName, DnsDomainName);
  2509. }
  2510. DnsFreeConfigStructure(
  2511. DnsDomainName,
  2512. DnsConfigPrimaryDomainName_A );
  2513. }
  2514. }
  2515. LeaveCriticalSection(&NatInterfaceLock);
  2516. return DomainName;
  2517. } // NatQuerySharedConnectionDomainName
  2518. ULONG
  2519. NatStartConnectionManagement(
  2520. VOID
  2521. )
  2522. /*++
  2523. Routine Description:
  2524. This routine is called to install connection change-notification.
  2525. Arguments:
  2526. none.
  2527. Return Value:
  2528. ULONG - Win32 status code.
  2529. --*/
  2530. {
  2531. ULONG Error;
  2532. NTSTATUS status;
  2533. PROFILE("NatStartConnectionManagement");
  2534. EnterCriticalSection(&NatInterfaceLock);
  2535. if (NatConnectionNotifyEvent) {
  2536. LeaveCriticalSection(&NatInterfaceLock);
  2537. return NO_ERROR;
  2538. }
  2539. //
  2540. // Initialize the connection list
  2541. //
  2542. InitializeListHead(&NatpConnectionList);
  2543. //
  2544. // Acquire a component-reference on behalf of
  2545. // (1) the connection-notification routine
  2546. // (2) the configuration-changed routine
  2547. //
  2548. if (!REFERENCE_NAT()) {
  2549. LeaveCriticalSection(&NatInterfaceLock);
  2550. return ERROR_CAN_NOT_COMPLETE;
  2551. }
  2552. if (!REFERENCE_NAT()) {
  2553. LeaveCriticalSection(&NatInterfaceLock);
  2554. DEREFERENCE_NAT();
  2555. return ERROR_CAN_NOT_COMPLETE;
  2556. }
  2557. do {
  2558. //
  2559. // Create the connection-notification event, register a wait
  2560. // on the event, and register for connect and disconnect notification.
  2561. // We expect at least one invocation as a result of this registration,
  2562. // hence the reference made to the NAT module above.
  2563. //
  2564. NatConnectionNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2565. if (!NatConnectionNotifyEvent) {
  2566. Error = GetLastError(); break;
  2567. }
  2568. status =
  2569. RtlRegisterWait(
  2570. &NatpConnectionNotifyWaitHandle,
  2571. NatConnectionNotifyEvent,
  2572. NatpConnectionNotifyCallbackRoutine,
  2573. NULL,
  2574. INFINITE,
  2575. 0
  2576. );
  2577. if (!NT_SUCCESS(status)) {
  2578. Error = RtlNtStatusToDosError(status); break;
  2579. }
  2580. Error =
  2581. RasConnectionNotification(
  2582. (HRASCONN)INVALID_HANDLE_VALUE,
  2583. NatConnectionNotifyEvent,
  2584. RASCN_Connection|RASCN_Disconnection
  2585. );
  2586. if (Error) { break; }
  2587. //
  2588. // Create the configuartion-change event and register a wait
  2589. // on the event.
  2590. //
  2591. NatConfigurationChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  2592. if (!NatConfigurationChangedEvent) {
  2593. Error = GetLastError(); break;
  2594. }
  2595. status =
  2596. RtlRegisterWait(
  2597. &NatpConfigurationChangedWaitHandle,
  2598. NatConfigurationChangedEvent,
  2599. NatpConfigurationChangedCallbackRoutine,
  2600. NULL,
  2601. INFINITE,
  2602. 0
  2603. );
  2604. if (!NT_SUCCESS(status)) {
  2605. Error = RtlNtStatusToDosError(status); break;
  2606. }
  2607. LeaveCriticalSection(&NatInterfaceLock);
  2608. //
  2609. // Pick up any existing connections, by signalling the configuration
  2610. // change event. We cannot invoke the function directly
  2611. // because it invokes service-control functions to start autodial,
  2612. // and we could currently be running in a service-controller thread.
  2613. //
  2614. NtSetEvent(NatConfigurationChangedEvent, NULL);
  2615. return NO_ERROR;
  2616. } while(FALSE);
  2617. //
  2618. // A failure occurred; perform cleanup
  2619. //
  2620. if (NatpConnectionNotifyWaitHandle) {
  2621. RtlDeregisterWait(NatpConnectionNotifyWaitHandle);
  2622. NatpConnectionNotifyWaitHandle = NULL;
  2623. }
  2624. if (NatConnectionNotifyEvent) {
  2625. CloseHandle(NatConnectionNotifyEvent);
  2626. NatConnectionNotifyEvent = NULL;
  2627. }
  2628. if (NatpConfigurationChangedWaitHandle) {
  2629. RtlDeregisterWait(NatpConfigurationChangedWaitHandle);
  2630. NatpConfigurationChangedWaitHandle = NULL;
  2631. }
  2632. if (NatConfigurationChangedEvent) {
  2633. CloseHandle(NatConfigurationChangedEvent);
  2634. NatConfigurationChangedEvent = NULL;
  2635. }
  2636. LeaveCriticalSection(&NatInterfaceLock);
  2637. DEREFERENCE_NAT();
  2638. DEREFERENCE_NAT();
  2639. return Error;
  2640. } // NatStartConnectionManagement
  2641. VOID
  2642. NatStopConnectionManagement(
  2643. VOID
  2644. )
  2645. /*++
  2646. Routine Description:
  2647. This routine is invoked to stop the connection-monitoring activity
  2648. initiated by 'NatStartConnectionManagement' above.
  2649. Arguments:
  2650. none.
  2651. Return Value:
  2652. none.
  2653. Environment:
  2654. Invoked when 'StopProtocol' is received from the IP router-manager.
  2655. --*/
  2656. {
  2657. PLIST_ENTRY Link;
  2658. PNAT_CONNECTION_ENTRY pConEntry;
  2659. PROFILE("NatStopConnectionManagement");
  2660. EnterCriticalSection(&NatInterfaceLock);
  2661. //
  2662. // Cleanup the wait-handle and event used to receive notification
  2663. // of RAS connections and disconnections.
  2664. //
  2665. if (NatpConnectionNotifyWaitHandle) {
  2666. RtlDeregisterWait(NatpConnectionNotifyWaitHandle);
  2667. NatpConnectionNotifyWaitHandle = NULL;
  2668. }
  2669. if (NatConnectionNotifyEvent) {
  2670. RasConnectionNotification(
  2671. (HRASCONN)INVALID_HANDLE_VALUE,
  2672. NatConnectionNotifyEvent,
  2673. 0
  2674. );
  2675. CloseHandle(NatConnectionNotifyEvent);
  2676. NatConnectionNotifyEvent = NULL;
  2677. NatpConnectionNotifyCallbackRoutine(NULL, FALSE);
  2678. }
  2679. if (NatpEnableRouterWaitHandle) {
  2680. RtlDeregisterWait(NatpEnableRouterWaitHandle);
  2681. NatpEnableRouterWaitHandle = NULL;
  2682. }
  2683. if (NatpEnableRouterEvent) {
  2684. CloseHandle(NatpEnableRouterEvent);
  2685. NatpEnableRouterEvent = NULL;
  2686. NatpEnableRouterCallbackRoutine(NULL, FALSE);
  2687. }
  2688. if (NatpConfigurationChangedWaitHandle) {
  2689. RtlDeregisterWait(NatpConfigurationChangedWaitHandle);
  2690. NatpConfigurationChangedWaitHandle = NULL;
  2691. }
  2692. if (NatConfigurationChangedEvent) {
  2693. CloseHandle(NatConfigurationChangedEvent);
  2694. NatConfigurationChangedEvent = NULL;
  2695. NatpConfigurationChangedCallbackRoutine(NULL, FALSE);
  2696. }
  2697. if (NatpConnectionList.Flink)
  2698. {
  2699. //
  2700. // Make certain that all of our connections are disabled
  2701. //
  2702. NatUnbindAllConnections();
  2703. //
  2704. // Walk through the connection list, freeing all of the entries
  2705. //
  2706. while (!IsListEmpty(&NatpConnectionList))
  2707. {
  2708. Link = RemoveHeadList(&NatpConnectionList);
  2709. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  2710. NatpFreeConnectionEntry(pConEntry);
  2711. }
  2712. //
  2713. // Make sure all ICS protocols are stopped
  2714. //
  2715. NhStopICSProtocols();
  2716. }
  2717. //
  2718. // Clean up the DNS domain name cached for the shared connection.
  2719. //
  2720. if (NatpSharedConnectionDomainName) {
  2721. NH_FREE(NatpSharedConnectionDomainName);
  2722. NatpSharedConnectionDomainName = NULL;
  2723. }
  2724. //
  2725. // Reset tracking variables to initial state
  2726. //
  2727. NatpFirewallConnectionCount = 0;
  2728. NatpSharedConnectionPresent = FALSE;
  2729. LeaveCriticalSection(&NatInterfaceLock);
  2730. } // NatStopConnectionManagement
  2731. BOOLEAN
  2732. NatUnbindAllConnections(
  2733. VOID
  2734. )
  2735. /*++
  2736. Routine Description:
  2737. This routine is invoked to unbind a currently-active connection.
  2738. Arguments:
  2739. Index - index into the connection array
  2740. Return Value:
  2741. BOOLEAN - TRUE if any interfaces were unbound.
  2742. Environment:
  2743. Invoked with 'NatInterfaceLock' held by the caller.
  2744. --*/
  2745. {
  2746. PLIST_ENTRY Link;
  2747. PNAT_CONNECTION_ENTRY pConEntry;
  2748. BOOLEAN Result = FALSE;
  2749. PROFILE("NatUnbindAllConnections");
  2750. for (Link = NatpConnectionList.Flink;
  2751. Link != &NatpConnectionList;
  2752. Link = Link->Flink)
  2753. {
  2754. pConEntry = CONTAINING_RECORD(Link, NAT_CONNECTION_ENTRY, Link);
  2755. Result |= NatpUnbindConnection(pConEntry);
  2756. }
  2757. return Result;
  2758. } // NatpUnbindConnection