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.

531 lines
14 KiB

  1. /*++
  2. Copyright (c) 2001, Microsoft Corporation
  3. Module Name:
  4. csaupdate.cpp
  5. Abstract:
  6. Implementation of CSharedAccessUpdate -- notification sink for
  7. configuration changes.
  8. Author:
  9. Jonathan Burstein (jonburs) 20 April 2001
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "beacon.h"
  15. //
  16. // Define a macro version of ntohs which can be applied to constants,
  17. // and which can thus be computed at compile time.
  18. //
  19. #define NTOHS(p) ((((p) & 0xFF00) >> 8) | (((UCHAR)(p) << 8)))
  20. //
  21. // H.323/LDAP proxy ports
  22. //
  23. #define H323_Q931_PORT NTOHS(1720)
  24. #define H323_LDAP_PORT NTOHS(389)
  25. #define H323_LDAP_ALT_PORT NTOHS(1002)
  26. #define INADDR_LOOPBACK_NO 0x0100007f // 127.0.0.1 in network order
  27. //
  28. // Interface methods
  29. //
  30. STDMETHODIMP
  31. CSharedAccessUpdate::ConnectionPortMappingChanged(
  32. GUID *pConnectionGuid,
  33. GUID *pPortMappingGuid,
  34. BOOLEAN fProtocolChanged
  35. )
  36. {
  37. BOOLEAN fEnabled;
  38. BOOLEAN fRebuildDhcpList = TRUE;
  39. HRESULT hr = S_OK;
  40. IHNetPortMappingBinding *pBinding;
  41. PNAT_CONNECTION_ENTRY pConnection;
  42. PNAT_PORT_MAPPING_ENTRY pPortMapping;
  43. IHNetPortMappingProtocol *pProtocol;
  44. ULONG ulError;
  45. USHORT usNewPort = 0;
  46. UCHAR ucNewProtocol = 0;
  47. USHORT usOldPort = 0;
  48. UCHAR ucOldProtocol = 0;
  49. PROFILE("ConnectionPortMappingChanged");
  50. EnterCriticalSection(&NatInterfaceLock);
  51. do
  52. {
  53. pConnection = NatFindConnectionEntry(pConnectionGuid);
  54. if (NULL == pConnection) { break; }
  55. //
  56. // If the connection is not yet bound then there's nothing
  57. // that we need to do here.
  58. //
  59. if (!NAT_INTERFACE_BOUND(&pConnection->Interface)) { break; }
  60. //
  61. // Locate the old port mapping entry. This entry won't exist if
  62. // this port mapping wasn't previously enabled.
  63. //
  64. pPortMapping = NatFindPortMappingEntry(pConnection, pPortMappingGuid);
  65. if (NULL != pPortMapping)
  66. {
  67. //
  68. // Remove this entry from the connection list and
  69. // delete the old ticket / UDP broadcast entry.
  70. //
  71. RemoveEntryList(&pPortMapping->Link);
  72. if (pPortMapping->fUdpBroadcastMapping)
  73. {
  74. if (0 != pPortMapping->pvBroadcastCookie)
  75. {
  76. ASSERT(NULL != NhpUdpBroadcastMapper);
  77. hr = NhpUdpBroadcastMapper->CancelUdpBroadcastMapping(
  78. pPortMapping->pvBroadcastCookie
  79. );
  80. pPortMapping->pvBroadcastCookie = 0;
  81. }
  82. pConnection->UdpBroadcastPortMappingCount -= 1;
  83. }
  84. else
  85. {
  86. ulError =
  87. NatDeleteTicket(
  88. pConnection->AdapterIndex,
  89. pPortMapping->ucProtocol,
  90. pPortMapping->usPublicPort,
  91. IP_NAT_ADDRESS_UNSPECIFIED,
  92. pPortMapping->usPrivatePort,
  93. pPortMapping->ulPrivateAddress
  94. );
  95. pConnection->PortMappingCount -= 1;
  96. }
  97. //
  98. // Store the old protocol / port information so that
  99. // we can notify H.323 (if necessary) and the ALG manager.
  100. //
  101. ucOldProtocol = pPortMapping->ucProtocol;
  102. usOldPort = pPortMapping->usPublicPort;
  103. //
  104. // Check to see if this mapping is still enabled. (We ignore
  105. // errors from above.)
  106. //
  107. hr = pPortMapping->pBinding->GetEnabled(&fEnabled);
  108. if (FAILED(hr) || !fEnabled)
  109. {
  110. //
  111. // We'll need to rebuild the DHCP reservation
  112. // list only if this was a named-based mapping.
  113. //
  114. fRebuildDhcpList = pPortMapping->fNameActive;
  115. NatFreePortMappingEntry(pPortMapping);
  116. break;
  117. }
  118. }
  119. else
  120. {
  121. //
  122. // Allocate a new port mapping entry
  123. //
  124. pPortMapping =
  125. reinterpret_cast<PNAT_PORT_MAPPING_ENTRY>(
  126. NH_ALLOCATE(sizeof(*pPortMapping))
  127. );
  128. if (NULL == pPortMapping)
  129. {
  130. hr = E_OUTOFMEMORY;
  131. break;
  132. }
  133. ZeroMemory(pPortMapping, sizeof(*pPortMapping));
  134. pPortMapping->pProtocolGuid =
  135. reinterpret_cast<GUID*>(
  136. CoTaskMemAlloc(sizeof(GUID))
  137. );
  138. if (NULL != pPortMapping->pProtocolGuid)
  139. {
  140. CopyMemory(
  141. pPortMapping->pProtocolGuid,
  142. pPortMappingGuid,
  143. sizeof(GUID));
  144. }
  145. else
  146. {
  147. hr = E_OUTOFMEMORY;
  148. break;
  149. }
  150. //
  151. // Load the protocol and binding
  152. //
  153. IHNetCfgMgr *pCfgMgr;
  154. IHNetProtocolSettings *pProtocolSettings;
  155. hr = NhGetHNetCfgMgr(&pCfgMgr);
  156. if (SUCCEEDED(hr))
  157. {
  158. hr = pCfgMgr->QueryInterface(
  159. IID_PPV_ARG(IHNetProtocolSettings, &pProtocolSettings)
  160. );
  161. pCfgMgr->Release();
  162. }
  163. if (SUCCEEDED(hr))
  164. {
  165. hr = pProtocolSettings->FindPortMappingProtocol(
  166. pPortMappingGuid,
  167. &pPortMapping->pProtocol
  168. );
  169. if (SUCCEEDED(hr))
  170. {
  171. hr = pConnection->pHNetConnection->GetBindingForPortMappingProtocol(
  172. pPortMapping->pProtocol,
  173. &pPortMapping->pBinding
  174. );
  175. }
  176. pProtocolSettings->Release();
  177. }
  178. if (SUCCEEDED(hr))
  179. {
  180. //
  181. // Check if this protocol is enabled
  182. //
  183. hr = pPortMapping->pBinding->GetEnabled(&fEnabled);
  184. }
  185. if (FAILED(hr) || !fEnabled)
  186. {
  187. //
  188. // We don't need to rebuild the DHCP reservations.
  189. //
  190. fRebuildDhcpList = FALSE;
  191. NatFreePortMappingEntry(pPortMapping);
  192. break;
  193. }
  194. //
  195. // Since this is a new entry we always need to load the
  196. // protocol.
  197. //
  198. fProtocolChanged = TRUE;
  199. }
  200. //
  201. // Gather the new information
  202. //
  203. if (fProtocolChanged)
  204. {
  205. //
  206. // Need to reload the protocol information
  207. //
  208. hr = pPortMapping->pProtocol->GetIPProtocol(&pPortMapping->ucProtocol);
  209. if (SUCCEEDED(hr))
  210. {
  211. hr = pPortMapping->pProtocol->GetPort(&pPortMapping->usPublicPort);
  212. }
  213. if (FAILED(hr))
  214. {
  215. NatFreePortMappingEntry(pPortMapping);
  216. break;
  217. }
  218. }
  219. //
  220. // Load the binding information
  221. //
  222. if (pConnection->HNetProperties.fIcsPublic)
  223. {
  224. hr = pPortMapping->pBinding->GetTargetComputerAddress(&pPortMapping->ulPrivateAddress);
  225. if (SUCCEEDED(hr)
  226. && INADDR_LOOPBACK_NO == pPortMapping->ulPrivateAddress)
  227. {
  228. //
  229. // If the port mapping targets the loopback address
  230. // we want to use the address from the binding
  231. // info instead.
  232. //
  233. pPortMapping->ulPrivateAddress =
  234. pConnection->pBindingInfo->Address[0].Address;
  235. }
  236. }
  237. else
  238. {
  239. pPortMapping->ulPrivateAddress = pConnection->pBindingInfo->Address[0].Address;
  240. }
  241. if (SUCCEEDED(hr))
  242. {
  243. hr = pPortMapping->pBinding->GetTargetPort(&pPortMapping->usPrivatePort);
  244. }
  245. if (SUCCEEDED(hr))
  246. {
  247. BOOLEAN fOldNameActive = pPortMapping->fNameActive;
  248. hr = pPortMapping->pBinding->GetCurrentMethod(&pPortMapping->fNameActive);
  249. if (!fOldNameActive && !pPortMapping->fNameActive)
  250. {
  251. fRebuildDhcpList = FALSE;
  252. }
  253. }
  254. if (FAILED(hr))
  255. {
  256. NatFreePortMappingEntry(pPortMapping);
  257. break;
  258. }
  259. //
  260. // Create the ticket / UDP broadcast
  261. //
  262. if (NAT_PROTOCOL_UDP == pPortMapping->ucProtocol
  263. && 0xffffffff == pPortMapping->ulPrivateAddress)
  264. {
  265. DWORD dwAddress;
  266. DWORD dwMask;
  267. DWORD dwBroadcastAddress;
  268. if (NhQueryScopeInformation(&dwAddress, &dwMask))
  269. {
  270. dwBroadcastAddress = (dwAddress & dwMask) | ~dwMask;
  271. pPortMapping->fUdpBroadcastMapping = TRUE;
  272. hr = NhpUdpBroadcastMapper->CreateUdpBroadcastMapping(
  273. pPortMapping->usPublicPort,
  274. pConnection->AdapterIndex,
  275. dwBroadcastAddress,
  276. &pPortMapping->pvBroadcastCookie
  277. );
  278. }
  279. else
  280. {
  281. hr = E_FAIL;
  282. }
  283. if (SUCCEEDED(hr))
  284. {
  285. InsertTailList(&pConnection->PortMappingList, &pPortMapping->Link);
  286. pConnection->UdpBroadcastPortMappingCount += 1;
  287. }
  288. else
  289. {
  290. NatFreePortMappingEntry(pPortMapping);
  291. break;
  292. }
  293. }
  294. else
  295. {
  296. ulError =
  297. NatCreateTicket(
  298. pConnection->AdapterIndex,
  299. pPortMapping->ucProtocol,
  300. pPortMapping->usPublicPort,
  301. IP_NAT_ADDRESS_UNSPECIFIED,
  302. pPortMapping->usPrivatePort,
  303. pPortMapping->ulPrivateAddress
  304. );
  305. if (NO_ERROR == ulError)
  306. {
  307. InsertTailList(&pConnection->PortMappingList, &pPortMapping->Link);
  308. pConnection->PortMappingCount += 1;
  309. }
  310. else
  311. {
  312. hr = HRESULT_FROM_WIN32(ulError);
  313. NhTrace(
  314. TRACE_FLAG_NAT,
  315. "ConnectionPortMappingModified: NatCreateTicket=%d",
  316. ulError
  317. );
  318. NatFreePortMappingEntry(pPortMapping);
  319. break;
  320. }
  321. }
  322. //
  323. // Store the old protocol / port information so that
  324. // we can notify H.323 (if necessary) and the ALG manager.
  325. //
  326. ucNewProtocol = pPortMapping->ucProtocol;
  327. usNewPort = pPortMapping->usPublicPort;
  328. }
  329. while (FALSE);
  330. //
  331. // Determine if we need to notify the H.323 proxy or
  332. // the ALG manager. We must have found a bound connection
  333. // above to do this.
  334. //
  335. if (NULL != pConnection && NAT_INTERFACE_BOUND(&pConnection->Interface))
  336. {
  337. //
  338. // If this connection is bound to the H.323 proxy and either
  339. // the old or new protocol/port combination is applicable
  340. // remove and add this connection from the that proxy.
  341. //
  342. if (NAT_INTERFACE_ADDED_H323(&pConnection->Interface)
  343. && (IsH323Protocol(ucOldProtocol, usOldPort)
  344. || IsH323Protocol(ucNewProtocol, usNewPort)))
  345. {
  346. H323RmDeleteInterface(pConnection->Interface.Index);
  347. pConnection->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_H323;
  348. ulError =
  349. H323RmAddInterface(
  350. NULL,
  351. pConnection->Interface.Index,
  352. PERMANENT,
  353. IF_TYPE_OTHER,
  354. IF_ACCESS_BROADCAST,
  355. IF_CONNECTION_DEDICATED,
  356. NULL,
  357. IP_NAT_VERSION,
  358. 0,
  359. 0
  360. );
  361. if (NO_ERROR == ulError)
  362. {
  363. pConnection->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_H323;
  364. ulError =
  365. H323RmBindInterface(
  366. pConnection->Interface.Index,
  367. pConnection->pBindingInfo
  368. );
  369. }
  370. if (NO_ERROR == ulError)
  371. {
  372. ulError = H323RmEnableInterface(pConnection->Interface.Index);
  373. }
  374. }
  375. //
  376. // Inform the ALG manager of the changes
  377. //
  378. if (0 != ucOldProtocol && 0 != usOldPort)
  379. {
  380. AlgRmPortMappingChanged(
  381. pConnection->Interface.Index,
  382. ucOldProtocol,
  383. usOldPort
  384. );
  385. }
  386. if (0 != ucNewProtocol && 0 != usNewPort
  387. && (ucOldProtocol != ucNewProtocol
  388. || usOldPort != usNewPort))
  389. {
  390. AlgRmPortMappingChanged(
  391. pConnection->Interface.Index,
  392. ucNewProtocol,
  393. usNewPort
  394. );
  395. }
  396. }
  397. LeaveCriticalSection(&NatInterfaceLock);
  398. //
  399. // We may also need to rebuild the DHCP reservation list
  400. //
  401. if (fRebuildDhcpList)
  402. {
  403. EnterCriticalSection(&NhLock);
  404. NhFreeDhcpReservations();
  405. NhBuildDhcpReservations();
  406. LeaveCriticalSection(&NhLock);
  407. }
  408. return hr;
  409. }
  410. //
  411. // Private methods
  412. //
  413. BOOLEAN
  414. CSharedAccessUpdate::IsH323Protocol(
  415. UCHAR ucProtocol,
  416. USHORT usPort
  417. )
  418. {
  419. return (NAT_PROTOCOL_TCP == ucProtocol
  420. && (H323_Q931_PORT == usPort
  421. || H323_LDAP_PORT == usPort
  422. || H323_LDAP_ALT_PORT == usPort));
  423. }
  424. STDMETHODIMP
  425. CSharedAccessUpdate::PortMappingListChanged()
  426. {
  427. HRESULT hr = S_OK;
  428. hr = FireNATEvent_PortMappingsChanged();
  429. return hr;
  430. }