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.

534 lines
14 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2001 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: nathelp.c
  6. * Content: usage for nat helper DLL
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 02/22/2001 aarono Original
  12. * 04/16/2001 vanceo Use one of the split DirectPlayNATHelp interfaces only.
  13. *
  14. * Notes:
  15. *
  16. ***************************************************************************/
  17. #define INCL_WINSOCK_API_TYPEDEFS 1 // includes winsock 2 fn proto's, for getprocaddress
  18. #define FD_SETSIZE 1
  19. #include <winsock2.h>
  20. #include "dpsp.h"
  21. #include "mmsystem.h"
  22. #if USE_NATHELP
  23. #include "dpnathlp.h"
  24. BOOL natGetCapsUpdate(LPGLOBALDATA pgd)
  25. {
  26. HRESULT hr;
  27. //
  28. // Get Nat Capabilities - may block for a second.
  29. //
  30. memset(&pgd->NatHelpCaps,0,sizeof(DPNHCAPS));
  31. pgd->NatHelpCaps.dwSize=sizeof(DPNHCAPS);
  32. hr=IDirectPlayNATHelp_GetCaps(pgd->pINatHelp, &pgd->NatHelpCaps, DPNHGETCAPS_UPDATESERVERSTATUS);
  33. if(FAILED(hr))
  34. {
  35. DPF(0,"NatHelp failed to GetCaps, hr=%x\n",hr);
  36. return FALSE;
  37. }
  38. if (hr == DPNHSUCCESS_ADDRESSESCHANGED)
  39. {
  40. DPF(1,"NAT Help reports addresses changed, possible connection problems may occur.");
  41. }
  42. return TRUE;
  43. }
  44. /*=============================================================================
  45. natInit - Initialize nat helper i/f
  46. Description:
  47. Parameters:
  48. pgd - Service Provider's global data blob for this instance
  49. Return Values:
  50. -----------------------------------------------------------------------------*/
  51. BOOL natInit(LPGLOBALDATA pgd,LPGUID lpguidSP)
  52. {
  53. HRESULT hr;
  54. char szNATHelpPath[256];
  55. PFN_DIRECTPLAYNATHELPCREATE pfnNatHelpCreate = NULL;
  56. char *apszNATHelps[3];
  57. HMODULE ahNatHelps[3];
  58. IDirectPlayNATHelp *apINatHelps[3];
  59. DPNHCAPS adpnhcNatHelpCaps[3];
  60. DWORD dwNumNatHelps = 0;
  61. DWORD dwCurrentNatHelp;
  62. pgd->hNatHelp = NULL;
  63. pgd->pINatHelp = NULL;
  64. pgd->hNatHelpTCP = 0;
  65. pgd->hNatHelpUDP = 0;
  66. // build an internet INADDRANY
  67. memset(&pgd->INADDRANY,0,sizeof(SOCKADDR));
  68. pgd->INADDRANY.sa_family=AF_INET;
  69. memset(ahNatHelps, 0, sizeof(ahNatHelps));
  70. memset(apINatHelps, 0, sizeof(apINatHelps));
  71. //
  72. // See if there's a registry setting.
  73. //
  74. hr = GetNATHelpDLLFromRegistry((LPGUID) (&DPSPGUID_TCPIP), szNATHelpPath, 256);
  75. if (hr == S_OK)
  76. {
  77. DPF(1, "Got NAT Help DLL \"%s\" from registry.\n", szNATHelpPath);
  78. apszNATHelps[dwNumNatHelps++] = szNATHelpPath;
  79. }
  80. else
  81. {
  82. DPF(4, "Couldn't get NAT Help DLL from registry, hr=%x.\n", hr);
  83. }
  84. //
  85. // Add the default entries if the registry didn't already specify them.
  86. //
  87. if (_strnicmp(szNATHelpPath + strlen(szNATHelpPath) - strlen("dpnhupnp.dll"), "dpnhupnp.dll", strlen("dpnhupnp.dll")) != 0)
  88. {
  89. apszNATHelps[dwNumNatHelps++] = "dpnhupnp.dll";
  90. }
  91. if (_strnicmp(szNATHelpPath + strlen(szNATHelpPath) - strlen("dpnhpast.dll"), "dpnhpast.dll", strlen("dpnhpast.dll")) != 0)
  92. {
  93. apszNATHelps[dwNumNatHelps++] = "dpnhpast.dll";
  94. }
  95. //
  96. // Loop through the registry specified and default NAT Helpers and attempt
  97. // to load them.
  98. //
  99. for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
  100. {
  101. pgd->hNatHelp = LoadLibrary(apszNATHelps[dwCurrentNatHelp]);
  102. if (pgd->hNatHelp != NULL)
  103. {
  104. pfnNatHelpCreate = (PFN_DIRECTPLAYNATHELPCREATE) GetProcAddress(pgd->hNatHelp,
  105. "DirectPlayNATHelpCreate");
  106. if (pfnNatHelpCreate != NULL)
  107. {
  108. hr = pfnNatHelpCreate(&IID_IDirectPlayNATHelp, (void **) (&pgd->pINatHelp));
  109. if (hr == DP_OK)
  110. {
  111. //
  112. // Initialize the NAT Helper interface.
  113. //
  114. hr = IDirectPlayNATHelp_Initialize(pgd->pINatHelp, 0);
  115. if (hr == DP_OK)
  116. {
  117. //
  118. // Get the capabilities. If it succeeds, remember the information and move on.
  119. //
  120. if (natGetCapsUpdate(pgd))
  121. {
  122. DPF(3, "Successfully retrieved caps for NAT Help \"%s\", flags = 0x%x.",
  123. apszNATHelps[dwCurrentNatHelp], pgd->NatHelpCaps.dwFlags);
  124. ahNatHelps[dwCurrentNatHelp] = pgd->hNatHelp;
  125. pgd->hNatHelp = NULL;
  126. apINatHelps[dwCurrentNatHelp] = pgd->pINatHelp;
  127. pgd->pINatHelp = NULL;
  128. memcpy(&adpnhcNatHelpCaps[dwCurrentNatHelp], &pgd->NatHelpCaps, sizeof(DPNHCAPS));
  129. continue;
  130. }
  131. else
  132. {
  133. DPF(0, "Couldn't get NAT Help \"%s\" caps, hr=%x!", apszNATHelps[dwCurrentNatHelp], hr);
  134. }
  135. IDirectPlayNATHelp_Close(pgd->pINatHelp, 0);
  136. }
  137. else
  138. {
  139. DPF(0, "NAT Help \"%s\" failed to initialize, hr=%x!", apszNATHelps[dwCurrentNatHelp], hr);
  140. }
  141. IDirectPlayNATHelp_Release(pgd->pINatHelp);
  142. pgd->pINatHelp = NULL;
  143. }
  144. else
  145. {
  146. DPF(0, "Couldn't create NAT Help \"%s\" interface, hr = %x!", apszNATHelps[dwCurrentNatHelp], hr);
  147. }
  148. }
  149. else
  150. {
  151. DPF(0, "Couldn't get NAT Help DLL \"%s\" entry point!", apszNATHelps[dwCurrentNatHelp]);
  152. }
  153. FreeLibrary(pgd->hNatHelp);
  154. pgd->hNatHelp = NULL;
  155. }
  156. else
  157. {
  158. DPF(0, "Couldn't load NAT Help DLL \"%s\"!", apszNATHelps[dwCurrentNatHelp]);
  159. }
  160. }
  161. //
  162. // Now go through and pick the first helper that detected a NAT.
  163. //
  164. for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
  165. {
  166. if ((apINatHelps[dwCurrentNatHelp] != NULL) &&
  167. (adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags & DPNHCAPSFLAG_GATEWAYPRESENT))
  168. {
  169. DPF(2, "Gateway detected by NAT Help \"%s\", flags = 0x%x.",
  170. apszNATHelps[dwCurrentNatHelp], adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags);
  171. pgd->hNatHelp = ahNatHelps[dwCurrentNatHelp];
  172. ahNatHelps[dwCurrentNatHelp] = NULL;
  173. pgd->pINatHelp = apINatHelps[dwCurrentNatHelp];
  174. apINatHelps[dwCurrentNatHelp] = NULL;
  175. memcpy(&pgd->NatHelpCaps, &adpnhcNatHelpCaps[dwCurrentNatHelp], sizeof(DPNHCAPS));
  176. break;
  177. }
  178. }
  179. //
  180. // If we didn't get a helper that way, pick the first one that detected a firewall.
  181. //
  182. if (pgd->pINatHelp != NULL)
  183. {
  184. for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
  185. {
  186. if ((apINatHelps[dwCurrentNatHelp] != NULL) &&
  187. (adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags & DPNHCAPSFLAG_LOCALFIREWALLPRESENT))
  188. {
  189. DPF(2, "Firewall detected by NAT Help \"%s\", flags = 0x%x.",
  190. apszNATHelps[dwCurrentNatHelp], adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags);
  191. pgd->hNatHelp = ahNatHelps[dwCurrentNatHelp];
  192. ahNatHelps[dwCurrentNatHelp] = NULL;
  193. pgd->pINatHelp = apINatHelps[dwCurrentNatHelp];
  194. apINatHelps[dwCurrentNatHelp] = NULL;
  195. memcpy(&pgd->NatHelpCaps, &adpnhcNatHelpCaps[dwCurrentNatHelp], sizeof(DPNHCAPS));
  196. break;
  197. }
  198. }
  199. }
  200. //
  201. // Now go through and release all the other NAT helpers, or pick the first one that
  202. // successfully loaded if we didn't pick one already.
  203. //
  204. for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
  205. {
  206. if (apINatHelps[dwCurrentNatHelp] != NULL)
  207. {
  208. if (pgd->pINatHelp == NULL)
  209. {
  210. DPF(2, "Using first loaded NAT Help \"%s\", flags = 0x%x.",
  211. apszNATHelps[dwCurrentNatHelp], adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags);
  212. pgd->hNatHelp = ahNatHelps[dwCurrentNatHelp];
  213. ahNatHelps[dwCurrentNatHelp] = NULL;
  214. pgd->pINatHelp = apINatHelps[dwCurrentNatHelp];
  215. apINatHelps[dwCurrentNatHelp] = NULL;
  216. memcpy(&pgd->NatHelpCaps, &adpnhcNatHelpCaps[dwCurrentNatHelp], sizeof(DPNHCAPS));
  217. }
  218. else
  219. {
  220. IDirectPlayNATHelp_Close(apINatHelps[dwCurrentNatHelp], 0);
  221. IDirectPlayNATHelp_Release(apINatHelps[dwCurrentNatHelp]);
  222. apINatHelps[dwCurrentNatHelp] = NULL;
  223. FreeLibrary(ahNatHelps[dwCurrentNatHelp]);
  224. ahNatHelps[dwCurrentNatHelp] = NULL;
  225. }
  226. }
  227. }
  228. if (pgd->pINatHelp == NULL)
  229. {
  230. DPF(1, "No NAT Help loaded.");
  231. pgd->NatHelpCaps.dwRecommendedGetCapsInterval = INFINITE;
  232. return FALSE;
  233. }
  234. #ifdef DEBUG
  235. if (! (pgd->NatHelpCaps.dwFlags & DPNHCAPSFLAG_PUBLICADDRESSAVAILABLE))
  236. {
  237. DPF(1, "NAT Help loaded, no NAT/firewall detected, or it doesn't currently have a public address (flags = 0x%x).",
  238. pgd->NatHelpCaps.dwFlags);
  239. }
  240. #endif // DEBUG
  241. return TRUE;
  242. }
  243. /*=============================================================================
  244. natFini - Shut down NATHELP support
  245. Description:
  246. Parameters:
  247. pgd - Service Provider's global data blob for this instance
  248. Return Values:
  249. None.
  250. -----------------------------------------------------------------------------*/
  251. VOID natFini(LPGLOBALDATA pgd)
  252. {
  253. // natDeregisterPorts(pgd); - vance says we don't need to do this.
  254. if(pgd->pINatHelp)
  255. {
  256. IDirectPlayNATHelp_Close(pgd->pINatHelp, 0);
  257. pgd->hNatHelpTCP = 0;
  258. pgd->hNatHelpUDP = 0;
  259. IDirectPlayNATHelp_Release(pgd->pINatHelp);
  260. pgd->pINatHelp=NULL;
  261. }
  262. if(pgd->hNatHelp)
  263. {
  264. FreeLibrary(pgd->hNatHelp);
  265. pgd->hNatHelp=NULL;
  266. }
  267. }
  268. /*=============================================================================
  269. natRegisterPort - Get a port mapping.
  270. Description:
  271. Note only one mapping each for TCP and UDP are supported (for simplicity).
  272. Parameters:
  273. pgd - Service Provider's global data blob for this instance
  274. Return Values:
  275. None.
  276. -----------------------------------------------------------------------------*/
  277. HRESULT natRegisterPort(LPGLOBALDATA pgd, BOOL ftcp_udp, WORD port)
  278. {
  279. SOCKADDR_IN sockaddr_in, sockaddr_inpublic;
  280. DWORD dwFlags, dwSize;
  281. DPNHHANDLE hPortMapping;
  282. HRESULT hr=DP_OK;
  283. memset(&sockaddr_in , 0 ,sizeof(sockaddr_in));
  284. sockaddr_in.sin_family = AF_INET;
  285. sockaddr_in.sin_addr.S_un.S_addr= INADDR_ANY;
  286. sockaddr_in.sin_port = htons(port);
  287. if (ftcp_udp)
  288. {
  289. dwFlags = DPNHREGISTERPORTS_TCP;
  290. }
  291. else
  292. {
  293. dwFlags = 0;
  294. }
  295. hr=IDirectPlayNATHelp_RegisterPorts(pgd->pINatHelp, (SOCKADDR *)&sockaddr_in, sizeof(sockaddr_in), 1, 15*60000, &hPortMapping, dwFlags);
  296. if (hr != DPNH_OK)
  297. {
  298. DPF(0,"NATHelp_RegisterPorts registration failed, hr=%x",hr);
  299. hr = DPERR_GENERIC;
  300. }
  301. else
  302. {
  303. dwSize=sizeof(sockaddr_inpublic);
  304. hr = IDirectPlayNATHelp_GetRegisteredAddresses(pgd->pINatHelp, hPortMapping, (SOCKADDR *)&sockaddr_inpublic, &dwSize, NULL, NULL, 0);
  305. switch (hr)
  306. {
  307. case DPNH_OK:
  308. {
  309. DPF(2, "NATHelp successfully mapped port to %s:%u.",
  310. inet_ntoa(sockaddr_inpublic.sin_addr), ntohs(sockaddr_inpublic.sin_port) );
  311. if (ftcp_udp)
  312. {
  313. ASSERT(!pgd->hNatHelpTCP);
  314. if(pgd->hNatHelpTCP)
  315. {
  316. DPF(0,"WARNING: trying to map a TCP connection when one is already mapped?\n");
  317. }
  318. pgd->hNatHelpTCP=hPortMapping;
  319. memcpy(&pgd->saddrpubSystemStreamSocket, &sockaddr_inpublic, sizeof(SOCKADDR_IN));
  320. }
  321. else
  322. {
  323. ASSERT(!pgd->hNatHelpUDP);
  324. if (pgd->hNatHelpUDP)
  325. {
  326. DPF(0,"WARNING: trying to map a UDP connection when one is already mapped?\n");
  327. }
  328. pgd->hNatHelpUDP=hPortMapping;
  329. memcpy(&pgd->saddrpubSystemDGramSocket, &sockaddr_inpublic, sizeof(SOCKADDR_IN));
  330. }
  331. break;
  332. }
  333. case DPNHERR_PORTUNAVAILABLE:
  334. {
  335. DPF(0, "NATHelp reported port %u is unavailable!", port);
  336. hr=IDirectPlayNATHelp_DeregisterPorts(pgd->pINatHelp, hPortMapping, 0);
  337. if (hr != DP_OK)
  338. {
  339. DPF(0,"NATHelp_DeregisterPorts returned %x\n",hr);
  340. }
  341. hr = DPNHERR_PORTUNAVAILABLE;
  342. break;
  343. }
  344. default:
  345. {
  346. DPF(1, "NATHelp couldn't map port %u, (err = 0x%lx).", port, hr);
  347. if (ftcp_udp)
  348. {
  349. ASSERT(!pgd->hNatHelpTCP);
  350. if(pgd->hNatHelpTCP)
  351. {
  352. DPF(0,"WARNING: trying to map a TCP connection when one is already mapped?\n");
  353. }
  354. pgd->hNatHelpTCP=hPortMapping;
  355. }
  356. else
  357. {
  358. ASSERT(!pgd->hNatHelpUDP);
  359. if (pgd->hNatHelpUDP)
  360. {
  361. DPF(0,"WARNING: trying to map a UDP connection when one is already mapped?\n");
  362. }
  363. pgd->hNatHelpUDP=hPortMapping;
  364. }
  365. hr = DPERR_GENERIC;
  366. break;
  367. }
  368. }
  369. }
  370. return hr;
  371. }
  372. /*=============================================================================
  373. natDeregisterPort - Get rid of either UDP or TCP port mappings
  374. Description:
  375. Parameters:
  376. pgd - Service Provider's global data blob for this instance
  377. Return Values:
  378. None.
  379. -----------------------------------------------------------------------------*/
  380. VOID natDeregisterPort(LPGLOBALDATA pgd, BOOL ftcp_udp)
  381. {
  382. HRESULT hr;
  383. if(ftcp_udp && pgd->hNatHelpTCP){
  384. DPF(8,"Deregister TCP port\n");
  385. hr=IDirectPlayNATHelp_DeregisterPorts(pgd->pINatHelp, pgd->hNatHelpTCP, 0);
  386. if(hr!=DP_OK){
  387. DPF(0,"NATHelp_DeRegisterPorts returned %x\n",hr);
  388. }
  389. pgd->hNatHelpTCP=0;
  390. memset(&pgd->saddrpubSystemStreamSocket, 0, sizeof(SOCKADDR_IN));
  391. }
  392. if(!ftcp_udp && pgd->hNatHelpUDP){
  393. DPF(8,"Deregistering UDP port\n");
  394. hr=IDirectPlayNATHelp_DeregisterPorts(pgd->pINatHelp, pgd->hNatHelpUDP, 0);
  395. if(hr!=DP_OK){
  396. DPF(0,"NATHelp_DeRegisterPorts returned %x\n",hr);
  397. }
  398. pgd->hNatHelpUDP=0;
  399. memset(&pgd->saddrpubSystemDGramSocket, 0, sizeof(SOCKADDR_IN));
  400. }
  401. }
  402. /*=============================================================================
  403. natIsICSMachine - Return TRUE if this machine is a Windows ICS machine, FALSE otherwise
  404. Description:
  405. Parameters:
  406. pgd - Service Provider's global data blob for this instance
  407. Return Values:
  408. None.
  409. -----------------------------------------------------------------------------*/
  410. BOOL natIsICSMachine(LPGLOBALDATA pgd)
  411. {
  412. if (pgd->pINatHelp != NULL)
  413. {
  414. if ((pgd->NatHelpCaps.dwFlags & DPNHCAPSFLAG_GATEWAYPRESENT) &&
  415. (pgd->NatHelpCaps.dwFlags & DPNHCAPSFLAG_GATEWAYISLOCAL))
  416. {
  417. DPF(1, "Local internet gateway present, flags = 0x%x.", pgd->NatHelpCaps.dwFlags);
  418. return TRUE;
  419. }
  420. else
  421. {
  422. DPF(1, "No local internet gateway present, flags = 0x%x.", pgd->NatHelpCaps.dwFlags);
  423. }
  424. }
  425. else
  426. {
  427. DPF(1, "NAT Help not loaded.");
  428. }
  429. return FALSE;
  430. }
  431. #endif