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.

517 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. hr = pPortMapping->pBinding->GetTargetPort(&pPortMapping->usPrivatePort);
  223. if (SUCCEEDED(hr))
  224. {
  225. BOOLEAN fOldNameActive = pPortMapping->fNameActive;
  226. hr = pPortMapping->pBinding->GetCurrentMethod(&pPortMapping->fNameActive);
  227. if (!fOldNameActive && !pPortMapping->fNameActive)
  228. {
  229. fRebuildDhcpList = FALSE;
  230. }
  231. }
  232. if (SUCCEEDED(hr))
  233. {
  234. hr = NatpGetTargetAddressForPortMappingEntry(
  235. pConnection->HNetProperties.fIcsPublic,
  236. pPortMapping->fNameActive,
  237. pConnection->pBindingInfo->Address[0].Address,
  238. pPortMapping->pBinding,
  239. &pPortMapping->ulPrivateAddress
  240. );
  241. }
  242. if (FAILED(hr))
  243. {
  244. NatFreePortMappingEntry(pPortMapping);
  245. break;
  246. }
  247. //
  248. // Create the ticket / UDP broadcast
  249. //
  250. if (NAT_PROTOCOL_UDP == pPortMapping->ucProtocol
  251. && 0xffffffff == pPortMapping->ulPrivateAddress)
  252. {
  253. DWORD dwAddress;
  254. DWORD dwMask;
  255. DWORD dwBroadcastAddress;
  256. if (NhQueryScopeInformation(&dwAddress, &dwMask))
  257. {
  258. dwBroadcastAddress = (dwAddress & dwMask) | ~dwMask;
  259. pPortMapping->fUdpBroadcastMapping = TRUE;
  260. hr = NhpUdpBroadcastMapper->CreateUdpBroadcastMapping(
  261. pPortMapping->usPublicPort,
  262. pConnection->AdapterIndex,
  263. dwBroadcastAddress,
  264. &pPortMapping->pvBroadcastCookie
  265. );
  266. }
  267. else
  268. {
  269. hr = E_FAIL;
  270. }
  271. if (SUCCEEDED(hr))
  272. {
  273. InsertTailList(&pConnection->PortMappingList, &pPortMapping->Link);
  274. pConnection->UdpBroadcastPortMappingCount += 1;
  275. }
  276. else
  277. {
  278. NatFreePortMappingEntry(pPortMapping);
  279. break;
  280. }
  281. }
  282. else
  283. {
  284. ulError =
  285. NatCreateTicket(
  286. pConnection->AdapterIndex,
  287. pPortMapping->ucProtocol,
  288. pPortMapping->usPublicPort,
  289. IP_NAT_ADDRESS_UNSPECIFIED,
  290. pPortMapping->usPrivatePort,
  291. pPortMapping->ulPrivateAddress
  292. );
  293. if (NO_ERROR == ulError)
  294. {
  295. InsertTailList(&pConnection->PortMappingList, &pPortMapping->Link);
  296. pConnection->PortMappingCount += 1;
  297. }
  298. else
  299. {
  300. hr = HRESULT_FROM_WIN32(ulError);
  301. NhTrace(
  302. TRACE_FLAG_NAT,
  303. "ConnectionPortMappingModified: NatCreateTicket=%d",
  304. ulError
  305. );
  306. NatFreePortMappingEntry(pPortMapping);
  307. break;
  308. }
  309. }
  310. //
  311. // Store the old protocol / port information so that
  312. // we can notify H.323 (if necessary) and the ALG manager.
  313. //
  314. ucNewProtocol = pPortMapping->ucProtocol;
  315. usNewPort = pPortMapping->usPublicPort;
  316. }
  317. while (FALSE);
  318. //
  319. // Determine if we need to notify the H.323 proxy or
  320. // the ALG manager. We must have found a bound connection
  321. // above to do this.
  322. //
  323. if (NULL != pConnection && NAT_INTERFACE_BOUND(&pConnection->Interface))
  324. {
  325. //
  326. // If this connection is bound to the H.323 proxy and either
  327. // the old or new protocol/port combination is applicable
  328. // remove and add this connection from the that proxy.
  329. //
  330. if (NAT_INTERFACE_ADDED_H323(&pConnection->Interface)
  331. && (IsH323Protocol(ucOldProtocol, usOldPort)
  332. || IsH323Protocol(ucNewProtocol, usNewPort)))
  333. {
  334. H323RmDeleteInterface(pConnection->Interface.Index);
  335. pConnection->Interface.Flags &= ~NAT_INTERFACE_FLAG_ADDED_H323;
  336. ulError =
  337. H323RmAddInterface(
  338. NULL,
  339. pConnection->Interface.Index,
  340. PERMANENT,
  341. IF_TYPE_OTHER,
  342. IF_ACCESS_BROADCAST,
  343. IF_CONNECTION_DEDICATED,
  344. NULL,
  345. IP_NAT_VERSION,
  346. 0,
  347. 0
  348. );
  349. if (NO_ERROR == ulError)
  350. {
  351. pConnection->Interface.Flags |= NAT_INTERFACE_FLAG_ADDED_H323;
  352. ulError =
  353. H323RmBindInterface(
  354. pConnection->Interface.Index,
  355. pConnection->pBindingInfo
  356. );
  357. }
  358. if (NO_ERROR == ulError)
  359. {
  360. ulError = H323RmEnableInterface(pConnection->Interface.Index);
  361. }
  362. }
  363. //
  364. // Inform the ALG manager of the changes
  365. //
  366. if (0 != ucOldProtocol && 0 != usOldPort)
  367. {
  368. AlgRmPortMappingChanged(
  369. pConnection->Interface.Index,
  370. ucOldProtocol,
  371. usOldPort
  372. );
  373. }
  374. if (0 != ucNewProtocol && 0 != usNewPort
  375. && (ucOldProtocol != ucNewProtocol
  376. || usOldPort != usNewPort))
  377. {
  378. AlgRmPortMappingChanged(
  379. pConnection->Interface.Index,
  380. ucNewProtocol,
  381. usNewPort
  382. );
  383. }
  384. }
  385. LeaveCriticalSection(&NatInterfaceLock);
  386. //
  387. // We may also need to rebuild the DHCP reservation list
  388. //
  389. if (fRebuildDhcpList)
  390. {
  391. EnterCriticalSection(&NhLock);
  392. NhFreeDhcpReservations();
  393. NhBuildDhcpReservations();
  394. LeaveCriticalSection(&NhLock);
  395. }
  396. return hr;
  397. }
  398. //
  399. // Private methods
  400. //
  401. BOOLEAN
  402. CSharedAccessUpdate::IsH323Protocol(
  403. UCHAR ucProtocol,
  404. USHORT usPort
  405. )
  406. {
  407. return (NAT_PROTOCOL_TCP == ucProtocol
  408. && (H323_Q931_PORT == usPort
  409. || H323_LDAP_PORT == usPort
  410. || H323_LDAP_ALT_PORT == usPort));
  411. }
  412. STDMETHODIMP
  413. CSharedAccessUpdate::PortMappingListChanged()
  414. {
  415. HRESULT hr = S_OK;
  416. hr = FireNATEvent_PortMappingsChanged();
  417. return hr;
  418. }