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.

1354 lines
40 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ALGconn.c
  5. Abstract:
  6. This module contains code for the ALG transparent proxy's connection
  7. management.
  8. Author:
  9. Qiang Wang (qiangw) 10-Apr-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <ipnatapi.h>
  15. #include <mswsock.h>
  16. #include <rasuip.h>
  17. ULONG AlgNextConnectionId = 0;
  18. ULONG AlgNextEndpointId = 0;
  19. typedef struct _ALG_CLOSE_CONNECTION_CONTEXT {
  20. ULONG InterfaceIndex;
  21. ULONG ConnectionId;
  22. } ALG_CLOSE_CONNECTION_CONTEXT, *PALG_CLOSE_CONNECTION_CONTEXT;
  23. //
  24. // FORWARD DECLARATIONS
  25. //
  26. ULONG NTAPI
  27. AlgpCloseConnectionWorkerRoutine(
  28. PVOID Context
  29. );
  30. ULONG
  31. AlgActivateActiveEndpoint(
  32. PALG_INTERFACE Interfacep,
  33. PALG_ENDPOINT Endpointp
  34. )
  35. /*++
  36. Routine Description:
  37. This routine is invoked to initiate data transfer on an active endpoint
  38. once it is connected to both the client and the host.
  39. Arguments:
  40. Interfacep - the interface on which the endpoint was accepted
  41. Endpointp - the endpoint to be activated
  42. Return Value:
  43. ULONG - Win32/Winsock2 status code.
  44. Environment:
  45. Invoked with the interface's lock held by the caller, and with two
  46. references made to the interface on behalf of the read-requests that will
  47. be issued here. If a failure occurs, it is this routine's responsibility
  48. to release those references.
  49. --*/
  50. {
  51. ULONG Error;
  52. PROFILE("AlgActivateActiveEndpoint");
  53. //
  54. // Clear the 'initial-endpoint' flag on the endpoint,
  55. // now that it is successfully connected.
  56. //
  57. Endpointp->Flags &= ~ALG_ENDPOINT_FLAG_INITIAL_ENDPOINT;
  58. //
  59. // Initiate read-requests on each of the endpoint's sockets.
  60. // Note that it is the callee's responsibility to release the references
  61. // made to the interface on our behalf.
  62. //
  63. Error =
  64. AlgReadActiveEndpoint(
  65. Interfacep,
  66. Endpointp,
  67. Endpointp->ClientSocket,
  68. ALG_BUFFER_FLAG_FROM_ACTUAL_HOST
  69. );
  70. if (Error) {
  71. NhTrace(
  72. TRACE_FLAG_ALG,
  73. "AlgActivateActiveEndpoint: read error %d",
  74. Error
  75. );
  76. ALG_DEREFERENCE_INTERFACE(Interfacep);
  77. } else {
  78. Error =
  79. AlgReadActiveEndpoint(
  80. Interfacep,
  81. Endpointp,
  82. Endpointp->HostSocket,
  83. ALG_BUFFER_FLAG_FROM_ACTUAL_CLIENT
  84. );
  85. }
  86. return Error;
  87. } // AlgActivateActiveEndpoint
  88. VOID
  89. AlgCloseActiveEndpoint(
  90. PALG_ENDPOINT Endpointp,
  91. SOCKET ClosedSocket
  92. )
  93. /*++
  94. Routine Description:
  95. This routine is invoked when a graceful close indication is received
  96. on one of the sockets for an endpoint. If both the client and the host
  97. have closed their sockets, the endpoint is deleted here.
  98. Arguments:
  99. Endpointp - the endpoint for the closed socket
  100. ClosedSocket - the socket whose remote end has been closed
  101. Return Value:
  102. none.
  103. Environment:
  104. Invoked with the interface's lock held by the caller.
  105. --*/
  106. {
  107. PROFILE("AlgCloseActiveEndpoint");
  108. //
  109. // Propagate the shutdown from one control-channel socket to the other,
  110. // i.e. from client to server or server to client.
  111. //
  112. if (ClosedSocket == Endpointp->ClientSocket) {
  113. if (Endpointp->Flags & ALG_ENDPOINT_FLAG_CLIENT_CLOSED) {
  114. NhTrace(
  115. TRACE_FLAG_ALG,
  116. "AlgCloseActiveEndpoint: endpoint %d client-end already closed",
  117. Endpointp->EndpointId
  118. );
  119. return;
  120. }
  121. shutdown(Endpointp->HostSocket, SD_SEND);
  122. Endpointp->Flags |= ALG_ENDPOINT_FLAG_CLIENT_CLOSED;
  123. } else {
  124. if (Endpointp->Flags & ALG_ENDPOINT_FLAG_HOST_CLOSED) {
  125. NhTrace(
  126. TRACE_FLAG_ALG,
  127. "AlgCloseActiveEndpoint: endpoint %d host-end already closed",
  128. Endpointp->EndpointId
  129. );
  130. return;
  131. }
  132. shutdown(Endpointp->ClientSocket, SD_SEND);
  133. Endpointp->Flags |= ALG_ENDPOINT_FLAG_HOST_CLOSED;
  134. }
  135. //
  136. // If both the client and server have closed their ends of the endpoint
  137. // we can close the sockets and delete the endpoint.
  138. //
  139. if ((Endpointp->Flags & ALG_ENDPOINT_FLAG_CLIENT_CLOSED) &&
  140. (Endpointp->Flags & ALG_ENDPOINT_FLAG_HOST_CLOSED)) {
  141. NhTrace(
  142. TRACE_FLAG_ALG,
  143. "AlgCloseActiveEndpoint: both sockets closed, deleting endpoint %d",
  144. Endpointp->EndpointId
  145. );
  146. AlgDeleteActiveEndpoint(Endpointp);
  147. }
  148. } // AlgCloseActiveEndpoint
  149. ULONG
  150. AlgCreateActiveEndpoint(
  151. PALG_CONNECTION Connectionp,
  152. ALG_ENDPOINT_TYPE Type,
  153. SOCKET ListeningSocket,
  154. SOCKET AcceptedSocket,
  155. PUCHAR AcceptBuffer,
  156. ULONG TargetAddress,
  157. USHORT TargetPort,
  158. ULONG BoundaryAddress,
  159. OUT PALG_ENDPOINT* EndpointCreated OPTIONAL
  160. )
  161. /*++
  162. Routine Description:
  163. This routine is invoked to create a new active endpoint when a TCP
  164. connection is accepted. It creates an entry for the new endpoint
  165. and initiates a connection-attempt to the ultimate destination
  166. as specified by 'Type' and 'TargetPort'.
  167. Arguments:
  168. Connectionp - the connection on which the TCP connection was accepted
  169. Type - indicates whether the TCP connection is from a client or a host
  170. ListeningSocket - the listening socket on which the TCP connection was
  171. accepted
  172. AcceptedSocket - the local socket for the accepted TCP connection
  173. AcceptBuffer - buffer holding connection-acceptance information
  174. TargetAddress - the IP address to which the secondary proxy connection
  175. must be made on the alternate socket for the new endpoint
  176. TargetPort - the port to which the secondary proxy connection must be made
  177. on the alternate socket for the new endpoint
  178. BoundaryAddress - the IP address of the boundary interface from which the
  179. first proxy connection is from
  180. EndpointCreated - on output, optionally receives the newly created
  181. endpoint
  182. Return Value:
  183. ULONG - Win32 status code.
  184. Environment:
  185. Invoked with the interface's lock held by the caller, and with two
  186. references made to the interface for the connection-attempt which is
  187. initiated here and the close-notification which is requested on the
  188. accepted socket. If a failure occurs, it is this routine's responsibility
  189. to release those references.
  190. --*/
  191. {
  192. PALG_ENDPOINT Endpointp = NULL;
  193. ULONG Error;
  194. PLIST_ENTRY InsertionPoint;
  195. PALG_INTERFACE Interfacep = Connectionp->Interfacep;
  196. ULONG Length;
  197. SOCKADDR_IN SockAddr;
  198. SOCKET UdpSocket;
  199. PROFILE("AlgCreateActiveEndpoint");
  200. do {
  201. //
  202. // Update the context associated with the accepted socket,
  203. // to allow Winsock routines to be used with the resulting file-handle.
  204. //
  205. Error =
  206. setsockopt(
  207. AcceptedSocket,
  208. SOL_SOCKET,
  209. SO_UPDATE_ACCEPT_CONTEXT,
  210. (PCHAR)&ListeningSocket,
  211. sizeof(ListeningSocket)
  212. );
  213. if (Error == SOCKET_ERROR) {
  214. Error = WSAGetLastError();
  215. NhTrace(
  216. TRACE_FLAG_ALG,
  217. "AlgCreateActiveEndpoint: error %d updating accept context",
  218. Error
  219. );
  220. break;
  221. }
  222. //
  223. // Allocate and initialize a new endpoint, and insert it in the list
  224. // of endpoints for its interface, as well as the list of active
  225. // endpoints for its connection.
  226. //
  227. Endpointp = reinterpret_cast<PALG_ENDPOINT>(
  228. NH_ALLOCATE(sizeof(*Endpointp))
  229. );
  230. if (!Endpointp) { Error = ERROR_NOT_ENOUGH_MEMORY; break; }
  231. ZeroMemory(Endpointp, sizeof(*Endpointp));
  232. Endpointp->EndpointId = InterlockedIncrement(
  233. reinterpret_cast<LPLONG>(&AlgNextEndpointId)
  234. );
  235. Endpointp->ConnectionId = Connectionp->ConnectionId;
  236. Endpointp->Interfacep = Interfacep;
  237. AlgLookupInterfaceEndpoint(
  238. Interfacep, Endpointp->EndpointId, &InsertionPoint
  239. );
  240. InsertTailList(InsertionPoint, &Endpointp->InterfaceLink);
  241. AlgLookupActiveEndpoint(
  242. Connectionp, Endpointp->EndpointId, &InsertionPoint
  243. );
  244. InsertTailList(InsertionPoint, &Endpointp->ConnectionLink);
  245. Endpointp->Type = Type;
  246. Endpointp->ClientSocket = INVALID_SOCKET;
  247. Endpointp->HostSocket = INVALID_SOCKET;
  248. Endpointp->BoundaryAddress = BoundaryAddress;
  249. //
  250. // We create a temporary UDP socket, connect the socket to the
  251. // actual client's IP address, extract the IP address to which
  252. // the socket is implicitly bound by the TCP/IP driver, and
  253. // discard the socket. This leaves us with the exact IP address
  254. // that we need to use to contact the client.
  255. //
  256. SockAddr.sin_family = AF_INET;
  257. SockAddr.sin_port = 0;
  258. SockAddr.sin_addr.s_addr = TargetAddress;
  259. Length = sizeof(SockAddr);
  260. if ((UdpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) ==
  261. INVALID_SOCKET ||
  262. connect(UdpSocket, (PSOCKADDR)&SockAddr, sizeof(SockAddr)) ==
  263. SOCKET_ERROR ||
  264. getsockname(UdpSocket, (PSOCKADDR)&SockAddr, (int*)&Length) ==
  265. SOCKET_ERROR) {
  266. Error = WSAGetLastError();
  267. if (Error == WSAEHOSTUNREACH && Type == AlgHostEndpointType) {
  268. Error = RasAutoDialSharedConnection();
  269. if (Error != ERROR_SUCCESS) {
  270. NhTrace(
  271. TRACE_FLAG_ALG,
  272. "AlgCreateActiveEndpoint:"
  273. " RasAutoDialSharedConnection failed [%d]",
  274. Error
  275. );
  276. if (UdpSocket != INVALID_SOCKET) { closesocket(UdpSocket); }
  277. ALG_DEREFERENCE_INTERFACE(Interfacep);
  278. ALG_DEREFERENCE_INTERFACE(Interfacep);
  279. break;
  280. }
  281. } else {
  282. NhTrace(
  283. TRACE_FLAG_ALG,
  284. "AlgCreateActiveEndpoint: error %d routing endpoint %d "
  285. "using UDP", Error, Endpointp->EndpointId
  286. );
  287. if (UdpSocket != INVALID_SOCKET) { closesocket(UdpSocket); }
  288. ALG_DEREFERENCE_INTERFACE(Interfacep);
  289. ALG_DEREFERENCE_INTERFACE(Interfacep);
  290. break;
  291. }
  292. }
  293. closesocket(UdpSocket);
  294. //
  295. // Check the type of the endpoint before proceeding further:
  296. // 'AlgClientEndpointType' - the endpoint was accepted on a client's
  297. // behalf from a remote host
  298. // 'AlgHostEndpointType' - the endpoint was accepted on a host's
  299. // behalf from a remote client
  300. //
  301. if (Type == AlgClientEndpointType) {
  302. //
  303. // This active endpoint was accepted on behalf of a client.
  304. //
  305. Endpointp->ClientSocket = AcceptedSocket;
  306. Endpointp->ActualClientAddress = TargetAddress;
  307. Endpointp->ActualClientPort = TargetPort;
  308. NhQueryAcceptEndpoints(
  309. AcceptBuffer,
  310. NULL,
  311. NULL,
  312. &Endpointp->ActualHostAddress,
  313. &Endpointp->ActualHostPort
  314. );
  315. //
  316. // We now need to initiate a proxy connection to the actual client.
  317. // Before doing so, we need to bind to a specific IP address,
  318. // and issue a redirect so that the actual client will think
  319. // that our connection-request is coming from the actual host.
  320. // Create a stream socket bound to the extracted IP address,
  321. // determine the socket's port number, and create a redirect
  322. // to transform our connection-request in the eyes of the client.
  323. //
  324. Error =
  325. NhCreateStreamSocket(
  326. SockAddr.sin_addr.s_addr, 0, &Endpointp->HostSocket
  327. );
  328. if (Error) {
  329. ALG_DEREFERENCE_INTERFACE(Interfacep);
  330. ALG_DEREFERENCE_INTERFACE(Interfacep);
  331. break;
  332. }
  333. EnterCriticalSection(&AlgGlobalInfoLock);
  334. Error =
  335. NatCreateRedirectEx(
  336. AlgTranslatorHandle,
  337. NatRedirectFlagLoopback,
  338. NAT_PROTOCOL_TCP,
  339. Endpointp->ActualClientAddress,
  340. Endpointp->ActualClientPort,
  341. SockAddr.sin_addr.s_addr,
  342. NhQueryPortSocket(Endpointp->HostSocket),
  343. TargetAddress,
  344. TargetPort,
  345. Endpointp->ActualHostAddress,
  346. Endpointp->ActualHostPort,
  347. 0,
  348. NULL,
  349. NULL,
  350. NULL
  351. );
  352. LeaveCriticalSection(&AlgGlobalInfoLock);
  353. if (Error) {
  354. ALG_DEREFERENCE_INTERFACE(Interfacep);
  355. ALG_DEREFERENCE_INTERFACE(Interfacep);
  356. NhTrace(
  357. TRACE_FLAG_ALG,
  358. "AlgCreateActiveEndpoint: error %d creating redirect",
  359. Error
  360. );
  361. break;
  362. }
  363. NhTrace(
  364. TRACE_FLAG_ALG,
  365. "AlgCreateActiveEndpoint: endpoint %d connecting socket %d "
  366. "to client at %s/%d",
  367. Endpointp->EndpointId, Endpointp->HostSocket,
  368. INET_NTOA(TargetAddress), RtlUshortByteSwap(TargetPort)
  369. );
  370. Error =
  371. NhConnectStreamSocket(
  372. &AlgComponentReference,
  373. Endpointp->HostSocket,
  374. TargetAddress,
  375. TargetPort,
  376. NULL,
  377. AlgConnectEndpointCompletionRoutine,
  378. AlgCloseEndpointNotificationRoutine,
  379. Interfacep,
  380. UlongToPtr(Endpointp->EndpointId)
  381. );
  382. if (Error) {
  383. ALG_DEREFERENCE_INTERFACE(Interfacep);
  384. ALG_DEREFERENCE_INTERFACE(Interfacep);
  385. NhTrace(
  386. TRACE_FLAG_ALG,
  387. "AlgCreateActiveEndpoint: error %d connecting to %s",
  388. Error,
  389. INET_NTOA(TargetAddress)
  390. );
  391. break;
  392. }
  393. } else {
  394. ULONG AddressToUse;
  395. //
  396. // This active endpoint was accepted on behalf of a host.
  397. // We now initiate a proxy connection to the actual host.
  398. //
  399. Endpointp->HostSocket = AcceptedSocket;
  400. Endpointp->ActualHostAddress = TargetAddress;
  401. Endpointp->ActualHostPort = TargetPort;
  402. NhQueryAcceptEndpoints(
  403. AcceptBuffer,
  404. NULL,
  405. NULL,
  406. &Endpointp->ActualClientAddress,
  407. &Endpointp->ActualClientPort
  408. );
  409. //
  410. // If we grabbed a send address above, use it to bind the
  411. // socket; otherwise, leave the address unspecified
  412. //
  413. AddressToUse = AlgFirewallIfCount
  414. ? SockAddr.sin_addr.s_addr
  415. : INADDR_NONE;
  416. //
  417. // Initiate a connection to the actual host
  418. //
  419. Error =
  420. NhCreateStreamSocket(
  421. AddressToUse, 0, &Endpointp->ClientSocket
  422. );
  423. if (Error) {
  424. ALG_DEREFERENCE_INTERFACE(Interfacep);
  425. ALG_DEREFERENCE_INTERFACE(Interfacep);
  426. break;
  427. }
  428. //
  429. // If we have a firwewall interface, possibly install a
  430. // shadow redirect for this connection. The shadow redirect
  431. // is necessary to prevent this connection from also being
  432. // redirected to the proxy (setting in motion an infinite loop...)
  433. //
  434. if (AlgFirewallIfCount) {
  435. ULONG SourceAddress =
  436. NhQueryAddressSocket(Endpointp->ClientSocket);
  437. USHORT SourcePort =
  438. NhQueryPortSocket(Endpointp->ClientSocket);
  439. Error =
  440. NatCreateRedirectEx(
  441. AlgTranslatorHandle,
  442. 0,
  443. NAT_PROTOCOL_TCP,
  444. TargetAddress,
  445. TargetPort,
  446. SourceAddress,
  447. SourcePort,
  448. TargetAddress,
  449. TargetPort,
  450. SourceAddress,
  451. SourcePort,
  452. 0,
  453. NULL,
  454. NULL,
  455. NULL
  456. );
  457. if (Error) {
  458. NhTrace(
  459. TRACE_FLAG_ALG,
  460. "AlgCreateActiveEndpoint: Unable to create shadow"
  461. " redirect for connection to %s/%d",
  462. INET_NTOA(TargetAddress),
  463. RtlUshortByteSwap(TargetPort)
  464. );
  465. ALG_DEREFERENCE_INTERFACE(Interfacep);
  466. ALG_DEREFERENCE_INTERFACE(Interfacep);
  467. break;
  468. }
  469. }
  470. NhTrace(
  471. TRACE_FLAG_ALG,
  472. "AlgCreateActiveEndpoint: endpoint %d connecting socket %d "
  473. "to host at %s/%d",
  474. Endpointp->EndpointId, Endpointp->ClientSocket,
  475. INET_NTOA(TargetAddress), RtlUshortByteSwap(TargetPort)
  476. );
  477. Error =
  478. NhConnectStreamSocket(
  479. &AlgComponentReference,
  480. Endpointp->ClientSocket,
  481. TargetAddress,
  482. TargetPort,
  483. NULL,
  484. AlgConnectEndpointCompletionRoutine,
  485. AlgCloseEndpointNotificationRoutine,
  486. Interfacep,
  487. UlongToPtr(Endpointp->EndpointId)
  488. );
  489. if (Error) {
  490. ALG_DEREFERENCE_INTERFACE(Interfacep);
  491. ALG_DEREFERENCE_INTERFACE(Interfacep);
  492. NhTrace(
  493. TRACE_FLAG_ALG,
  494. "AlgCreateActiveEndpoint: error %d connecting to host %s",
  495. Error,
  496. INET_NTOA(TargetAddress)
  497. );
  498. break;
  499. }
  500. }
  501. ALG_DEREFERENCE_INTERFACE(Interfacep);
  502. if (EndpointCreated) { *EndpointCreated = Endpointp; }
  503. return NO_ERROR;
  504. } while(FALSE);
  505. if (Endpointp) {
  506. AlgDeleteActiveEndpoint(Endpointp);
  507. } else {
  508. NhDeleteStreamSocket(AcceptedSocket);
  509. ALG_DEREFERENCE_INTERFACE(Interfacep);
  510. ALG_DEREFERENCE_INTERFACE(Interfacep);
  511. }
  512. return Error;
  513. } // AlgCreateActiveEndpoint
  514. ULONG
  515. AlgCreateConnection(
  516. PALG_INTERFACE Interfacep,
  517. SOCKET ListeningSocket,
  518. SOCKET AcceptedSocket,
  519. PUCHAR AcceptBuffer,
  520. PALG_CONNECTION* ConnectionCreated OPTIONAL
  521. )
  522. /*++
  523. Routine Description:
  524. This routine is invoked to create a connection-object corresponding
  525. to a newly-accepted connection. It creates and inserts the entry,
  526. queries the kernel-mode translator to determine the client's target server,
  527. and creates an active endpoint which is connected to that server.
  528. Arguments:
  529. Interfacep - the interface on which the connection was accepted
  530. ListeningSocket - the socket on which the connection was accepted
  531. AcceptedSocket - the accepted socket
  532. AcceptBuffer - contains address/port information for the local and remote
  533. endpoints.
  534. ConnectionCreated - on output, optionally receives a pointer
  535. to the connection created
  536. Return Value:
  537. ULONG - Win32/Winsock2 status code.
  538. Environment:
  539. Invoked with the interface's lock held by the caller, and with two
  540. references made to the interface on behalf of this routine. If a failure
  541. occurs here, this routine is responsible for releasing those references.
  542. --*/
  543. {
  544. PALG_CONNECTION Connectionp = NULL;
  545. PALG_ENDPOINT Endpointp = NULL;
  546. ULONG Error;
  547. PLIST_ENTRY InsertionPoint;
  548. ULONG LocalAddress;
  549. USHORT LocalPort;
  550. ULONG Length;
  551. NAT_KEY_SESSION_MAPPING_EX_INFORMATION Key;
  552. ULONG ActualClientAddress;
  553. USHORT ActualClientPort;
  554. IP_NAT_PORT_MAPPING PortMapping;
  555. PROFILE("AlgCreateConnection");
  556. do {
  557. //
  558. // Retrieve the local and remote endpoint information from the
  559. // connection-acceptance buffer, and use them to query the kernel-mode
  560. // translation module for the host to which the client was destined
  561. // before we redirected it to our listening socket.
  562. //
  563. NhQueryAcceptEndpoints(
  564. AcceptBuffer,
  565. &LocalAddress,
  566. &LocalPort,
  567. &ActualClientAddress,
  568. &ActualClientPort
  569. );
  570. Length = sizeof(Key);
  571. EnterCriticalSection(&AlgGlobalInfoLock);
  572. Error =
  573. NatLookupAndQueryInformationSessionMapping(
  574. AlgTranslatorHandle,
  575. NAT_PROTOCOL_TCP,
  576. LocalAddress,
  577. LocalPort,
  578. ActualClientAddress,
  579. ActualClientPort,
  580. &Key,
  581. &Length,
  582. NatKeySessionMappingExInformation
  583. );
  584. LeaveCriticalSection(&AlgGlobalInfoLock);
  585. if (Error) {
  586. NhTrace(
  587. TRACE_FLAG_ALG,
  588. "AlgCreateConnection: error %d querying session-mapping",
  589. Error
  590. );
  591. break;
  592. } else {
  593. NhTrace(
  594. TRACE_FLAG_ALG,
  595. "AlgCreateConnection: accepted client for %s/%d",
  596. INET_NTOA(Key.DestinationAddress), ntohs(Key.DestinationPort)
  597. );
  598. }
  599. //
  600. // Create and initialize a new connection.
  601. //
  602. Connectionp = reinterpret_cast<PALG_CONNECTION>(
  603. NH_ALLOCATE(sizeof(*Connectionp))
  604. );
  605. if (!Connectionp) { Error = ERROR_NOT_ENOUGH_MEMORY; break; }
  606. ZeroMemory(Connectionp, sizeof(Connectionp));
  607. Connectionp->ConnectionId =
  608. InterlockedIncrement(
  609. reinterpret_cast<LPLONG>(&AlgNextConnectionId)
  610. );
  611. AlgLookupConnection(
  612. Interfacep, Connectionp->ConnectionId, &InsertionPoint
  613. );
  614. InsertTailList(InsertionPoint, &Connectionp->Link);
  615. Connectionp->Interfacep = Interfacep;
  616. InitializeListHead(&Connectionp->ActiveEndpointList);
  617. //
  618. // Create a new active endpoint, which will contact the client's
  619. // actual host and transfer data between the client and the host.
  620. // Note that the callee will release the two references to the
  621. // interface if a failure occurs. Once the endpoint is created,
  622. // we set the 'initial-endpoint' flag on it before releasing
  623. // the interface lock. This ensures that if the endpoint cannot
  624. // connect to the actual host, we delete the whole connection.
  625. // The flag is later cleared in 'AlgActivateActiveEndpoint'
  626. // when the endpoint is activated.
  627. //
  628. if (NAT_IFC_BOUNDARY(Interfacep->Characteristics) &&
  629. Interfacep->AdapterIndex ==
  630. NhMapAddressToAdapter(Key.DestinationAddress)) {
  631. //
  632. // Inbound
  633. //
  634. ASSERT(ALG_INTERFACE_MAPPED(Interfacep));
  635. Error =
  636. AlgCreateActiveEndpoint(
  637. Connectionp,
  638. AlgClientEndpointType,
  639. ListeningSocket,
  640. AcceptedSocket,
  641. AcceptBuffer,
  642. Interfacep->PortMapping.PrivateAddress,
  643. Interfacep->PortMapping.PrivatePort,
  644. Key.DestinationAddress,
  645. &Endpointp
  646. );
  647. } else {
  648. //
  649. // Outbound
  650. //
  651. Error =
  652. AlgCreateActiveEndpoint(
  653. Connectionp,
  654. AlgHostEndpointType,
  655. ListeningSocket,
  656. AcceptedSocket,
  657. AcceptBuffer,
  658. Key.DestinationAddress,
  659. Key.DestinationPort,
  660. IP_NAT_ADDRESS_UNSPECIFIED,
  661. &Endpointp
  662. );
  663. }
  664. if (Error) {
  665. NhTrace(
  666. TRACE_FLAG_ALG,
  667. "AlgCreateConnection: error %d creating active endpoint",
  668. Error
  669. );
  670. break;
  671. } else {
  672. Endpointp->Flags |= ALG_ENDPOINT_FLAG_INITIAL_ENDPOINT;
  673. }
  674. if (ConnectionCreated) { *ConnectionCreated = Connectionp; }
  675. return NO_ERROR;
  676. } while(FALSE);
  677. if (Connectionp) {
  678. AlgDeleteConnection(Connectionp);
  679. } else {
  680. NhDeleteStreamSocket(AcceptedSocket);
  681. ALG_DEREFERENCE_INTERFACE(Interfacep);
  682. ALG_DEREFERENCE_INTERFACE(Interfacep);
  683. }
  684. return Error;
  685. }
  686. VOID
  687. AlgDeleteActiveEndpoint(
  688. PALG_ENDPOINT Endpointp
  689. )
  690. /*++
  691. Routine Description:
  692. This routine is invoked to destroy an active endpoint.
  693. Arguments:
  694. Endpoint - the endpoint to be destroyed
  695. Return Value:
  696. none.
  697. Environment:
  698. Invoked with the interface's lock held by the caller.
  699. --*/
  700. {
  701. PALG_INTERFACE Interfacep;
  702. PALG_CONNECTION Connectionp = NULL;
  703. PROFILE("AlgDeleteActiveEndpoint");
  704. RemoveEntryList(&Endpointp->ConnectionLink);
  705. RemoveEntryList(&Endpointp->InterfaceLink);
  706. if (Endpointp->ClientSocket != INVALID_SOCKET) {
  707. NhDeleteStreamSocket(Endpointp->ClientSocket);
  708. }
  709. if (Endpointp->HostSocket != INVALID_SOCKET) {
  710. NhDeleteStreamSocket(Endpointp->HostSocket);
  711. }
  712. if (Endpointp->ReservedPort != 0) {
  713. PTIMER_CONTEXT TimerContextp;
  714. NatCancelRedirect(
  715. AlgTranslatorHandle,
  716. NAT_PROTOCOL_TCP,
  717. Endpointp->DestinationAddress,
  718. Endpointp->DestinationPort,
  719. Endpointp->SourceAddress,
  720. Endpointp->SourcePort,
  721. Endpointp->NewDestinationAddress,
  722. Endpointp->NewDestinationPort,
  723. Endpointp->NewSourceAddress,
  724. Endpointp->NewSourcePort
  725. );
  726. TimerContextp = reinterpret_cast<PTIMER_CONTEXT>(
  727. NH_ALLOCATE(sizeof(TIMER_CONTEXT))
  728. );
  729. if (TimerContextp != NULL) {
  730. TimerContextp->TimerQueueHandle = AlgTimerQueueHandle;
  731. TimerContextp->ReservedPort = Endpointp->ReservedPort;
  732. CreateTimerQueueTimer(
  733. &(TimerContextp->TimerHandle),
  734. AlgTimerQueueHandle,
  735. AlgDelayedPortRelease,
  736. (PVOID)TimerContextp,
  737. ALG_PORT_RELEASE_DELAY,
  738. 0,
  739. WT_EXECUTEDEFAULT
  740. );
  741. } else {
  742. NhTrace(
  743. TRACE_FLAG_ALG,
  744. "AlgDeleteActiveEndpoint:"
  745. " memory allocation failed for timer context"
  746. );
  747. NhErrorLog(
  748. IP_ALG_LOG_ALLOCATION_FAILED,
  749. 0,
  750. "%d",
  751. sizeof(TIMER_CONTEXT)
  752. );
  753. }
  754. Endpointp->ReservedPort = 0;
  755. }
  756. //
  757. // If this endpoint is the first one for the connection and a failure
  758. // occurred before it ever even connected to the actual host, or if this
  759. // endpoint is the last one for the connection and it has been deleted,
  760. // queue a work-item to delete the connection.
  761. //
  762. EnterCriticalSection(&AlgInterfaceLock);
  763. Interfacep = AlgLookupInterface(Endpointp->Interfacep->Index, NULL);
  764. if (!Interfacep || !ALG_REFERENCE_INTERFACE(Interfacep)) {
  765. Interfacep = NULL;
  766. }
  767. LeaveCriticalSection(&AlgInterfaceLock);
  768. if (Interfacep != NULL) {
  769. ACQUIRE_LOCK(Interfacep);
  770. Connectionp =
  771. AlgLookupConnection(Interfacep, Endpointp->ConnectionId, NULL);
  772. if (Connectionp != NULL &&
  773. IsListEmpty(&Connectionp->ActiveEndpointList)) {
  774. Endpointp->Flags |= ALG_ENDPOINT_FLAG_DELETE_CONNECTION;
  775. }
  776. RELEASE_LOCK(Interfacep);
  777. ALG_DEREFERENCE_INTERFACE(Interfacep);
  778. }
  779. if ((Endpointp->Flags &
  780. (ALG_ENDPOINT_FLAG_INITIAL_ENDPOINT |
  781. ALG_ENDPOINT_FLAG_DELETE_CONNECTION)) &&
  782. REFERENCE_ALG()) {
  783. PALG_CLOSE_CONNECTION_CONTEXT Contextp =
  784. reinterpret_cast<PALG_CLOSE_CONNECTION_CONTEXT>(
  785. NH_ALLOCATE(sizeof(*Contextp))
  786. );
  787. if (!Contextp) {
  788. DEREFERENCE_ALG();
  789. } else {
  790. Contextp->InterfaceIndex = Endpointp->Interfacep->Index;
  791. Contextp->ConnectionId = Endpointp->ConnectionId;
  792. if (!QueueUserWorkItem(
  793. AlgpCloseConnectionWorkerRoutine, Contextp, 0
  794. )) {
  795. NH_FREE(Contextp);
  796. DEREFERENCE_ALG();
  797. } else {
  798. NhTrace(
  799. TRACE_FLAG_ALG,
  800. "AlgDeleteActiveEndpoint: queued connection %d deletion",
  801. Endpointp->ConnectionId
  802. );
  803. }
  804. }
  805. }
  806. NH_FREE(Endpointp);
  807. } // AlgDeleteActiveEndpoint
  808. VOID
  809. AlgDeleteConnection(
  810. PALG_CONNECTION Connectionp
  811. )
  812. /*++
  813. Routine Description:
  814. This routine is invoked to destroy a connection-object.
  815. In the process, it destroys all endpoints for the connection.
  816. Arguments:
  817. Connectionp - the connection to be deleted
  818. Return Value:
  819. none.
  820. Environment:
  821. Invoked with the interface's lock held by the caller.
  822. --*/
  823. {
  824. PALG_ENDPOINT Endpointp;
  825. PLIST_ENTRY Link;
  826. PROFILE("AlgDeleteConnection");
  827. RemoveEntryList(&Connectionp->Link);
  828. while (!IsListEmpty(&Connectionp->ActiveEndpointList)) {
  829. Link = Connectionp->ActiveEndpointList.Flink;
  830. Endpointp = CONTAINING_RECORD(Link, ALG_ENDPOINT, ConnectionLink);
  831. AlgDeleteActiveEndpoint(Endpointp);
  832. }
  833. NH_FREE(Connectionp);
  834. } // AlgDeleteConnection
  835. PALG_ENDPOINT
  836. AlgLookupActiveEndpoint(
  837. PALG_CONNECTION Connectionp,
  838. ULONG EndpointId,
  839. PLIST_ENTRY* InsertionPoint OPTIONAL
  840. )
  841. /*++
  842. Routine Description:
  843. This routine is invoked to retrieve a pointer to an active endpoint given
  844. its unique 32-bit identifier.
  845. Arguments:
  846. Connectionp - the connection on which to search for the endpoint
  847. EndpointId - the 32-bit identifier of the endpoint to be found
  848. InsertionPoint - on output, optionally receives the location at which
  849. the endpoint would be inserted, if the endpoint is not in the list.
  850. Return Value:
  851. PALG_ENDPOINT - the endpoint, if found.
  852. Environment:
  853. Invoked with the interface's lock held by the caller.
  854. --*/
  855. {
  856. PALG_ENDPOINT Endpointp;
  857. PLIST_ENTRY Link;
  858. for (Link = Connectionp->ActiveEndpointList.Flink;
  859. Link != &Connectionp->ActiveEndpointList; Link = Link->Flink) {
  860. Endpointp = CONTAINING_RECORD(Link, ALG_ENDPOINT, ConnectionLink);
  861. if (EndpointId > Endpointp->EndpointId) {
  862. continue;
  863. } else if (EndpointId < Endpointp->EndpointId) {
  864. break;
  865. }
  866. return Endpointp;
  867. }
  868. if (InsertionPoint) { *InsertionPoint = Link; }
  869. return NULL;
  870. } // AlgLookupActiveEndpoint
  871. PALG_CONNECTION
  872. AlgLookupConnection(
  873. PALG_INTERFACE Interfacep,
  874. ULONG ConnectionId,
  875. PLIST_ENTRY* InsertionPoint OPTIONAL
  876. )
  877. /*++
  878. Routine Description:
  879. This routine is invoked to retrieve a pointer to a connection given its
  880. unique 32-bit identifier.
  881. Arguments:
  882. Interfacep - the interface on which to search for the connection
  883. ConnectionId - the 32-bit identifier of the connection to be found
  884. InsertionPoint - on output, optionally receives the location at which
  885. the connection would be inserted, if the connection is not in the list.
  886. Return Value:
  887. PALG_CONNECTION - the connection, if found.
  888. Environment:
  889. Invoked with the interface's lock held by the caller.
  890. --*/
  891. {
  892. PALG_CONNECTION Connectionp;
  893. PLIST_ENTRY Link;
  894. for (Link = Interfacep->ConnectionList.Flink;
  895. Link != &Interfacep->ConnectionList; Link = Link->Flink) {
  896. Connectionp = CONTAINING_RECORD(Link, ALG_CONNECTION, Link);
  897. if (ConnectionId > Connectionp->ConnectionId) {
  898. continue;
  899. } else if (ConnectionId < Connectionp->ConnectionId) {
  900. break;
  901. }
  902. return Connectionp;
  903. }
  904. if (InsertionPoint) { *InsertionPoint = Link; }
  905. return NULL;
  906. } // AlgLookupConnection
  907. PALG_ENDPOINT
  908. AlgLookupInterfaceEndpoint(
  909. PALG_INTERFACE Interfacep,
  910. ULONG EndpointId,
  911. PLIST_ENTRY* InsertionPoint OPTIONAL
  912. )
  913. /*++
  914. Routine Description:
  915. This routine is invoked to retrieve a pointer to any endpoint given
  916. its unique 32-bit identifier, by searching the endpoints interface list.
  917. Arguments:
  918. Interfacep - the interfacep on which to search for the endpoint
  919. EndpointId - the 32-bit identifier of the endpoint to be found
  920. InsertionPoint - on output, optionally receives the location at which
  921. the endpoint would be inserted, if the endpoint is not in the list.
  922. Return Value:
  923. PALG_ENDPOINT - the endpoint, if found.
  924. Environment:
  925. Invoked with the interface's lock held by the caller.
  926. --*/
  927. {
  928. PALG_ENDPOINT Endpointp;
  929. PLIST_ENTRY Link;
  930. for (Link = Interfacep->EndpointList.Flink;
  931. Link != &Interfacep->EndpointList; Link = Link->Flink) {
  932. Endpointp = CONTAINING_RECORD(Link, ALG_ENDPOINT, InterfaceLink);
  933. if (EndpointId > Endpointp->EndpointId) {
  934. continue;
  935. } else if (EndpointId < Endpointp->EndpointId) {
  936. break;
  937. }
  938. return Endpointp;
  939. }
  940. if (InsertionPoint) { *InsertionPoint = Link; }
  941. return NULL;
  942. } // AlgLookupInterfaceEndpoint
  943. ULONG
  944. AlgpCloseConnectionWorkerRoutine(
  945. PVOID Context
  946. )
  947. /*++
  948. Routine Description:
  949. This routine is scheduled to run when a connection's main endpoint is
  950. deleted. It deletes the connection, destroying all of its endpoints.
  951. Arguments:
  952. Context - identifies the connection to be deleted
  953. Return Value:
  954. ULONG - always NO_ERROR.
  955. Environment:
  956. Invoked in the context of a system worker thread, with a reference made
  957. to the interface, as well as to the component. Both references are
  958. released here.
  959. --*/
  960. {
  961. PALG_CONNECTION Connectionp;
  962. PALG_CLOSE_CONNECTION_CONTEXT Contextp =
  963. (PALG_CLOSE_CONNECTION_CONTEXT)Context;
  964. PALG_INTERFACE Interfacep;
  965. PROFILE("AlgpCloseConnectionWorkerRoutine");
  966. EnterCriticalSection(&AlgInterfaceLock);
  967. Interfacep = AlgLookupInterface(Contextp->InterfaceIndex, NULL);
  968. if (!Interfacep || !ALG_REFERENCE_INTERFACE(Interfacep)) {
  969. LeaveCriticalSection(&AlgInterfaceLock);
  970. } else {
  971. LeaveCriticalSection(&AlgInterfaceLock);
  972. ACQUIRE_LOCK(Interfacep);
  973. Connectionp =
  974. AlgLookupConnection(Interfacep, Contextp->ConnectionId, NULL);
  975. if (Connectionp) {
  976. NhTrace(
  977. TRACE_FLAG_ALG,
  978. "AlgpCloseConnectionWorkerRoutine: deleting connection %d",
  979. Connectionp->ConnectionId
  980. );
  981. AlgDeleteConnection(Connectionp);
  982. }
  983. RELEASE_LOCK(Interfacep);
  984. ALG_DEREFERENCE_INTERFACE(Interfacep);
  985. }
  986. DEREFERENCE_ALG();
  987. NH_FREE(Context);
  988. return NO_ERROR;
  989. } // AlgpCloseConnectionWorkerRoutine
  990. ULONG
  991. AlgReadActiveEndpoint(
  992. PALG_INTERFACE Interfacep,
  993. PALG_ENDPOINT Endpointp,
  994. SOCKET Socket,
  995. ULONG UserFlags OPTIONAL
  996. )
  997. /*++
  998. Routine Description:
  999. This routine is invoked to initiate the retrieval of a full message from
  1000. the socket for the given endpoint.
  1001. Arguments:
  1002. Interfacep - the interface on which the endpoint was accepted
  1003. Endpointp - the endpoint for which to read a message
  1004. Socket - the socket from which to read the message
  1005. UserFlags - optionally supplies flags to be included in the 'UserFlags'
  1006. field of the message-buffer
  1007. Return Value:
  1008. ULONG - Win32/Winsock2 status code.
  1009. Environment:
  1010. Invoked with the interface's lock held by the caller, and with a reference
  1011. made to the interface on behalf of the read-completion routine. If the read
  1012. cannot be issued here, this routine is responsible for releasing that
  1013. reference.
  1014. --*/
  1015. {
  1016. PNH_BUFFER Bufferp;
  1017. ULONG Error;
  1018. PROFILE("AlgReadActiveEndpoint");
  1019. //
  1020. // Initiate a read on the socket to obtain the next message header.
  1021. // We will do as many reads as it takes to get the full header,
  1022. // which contains the length of the full message.
  1023. // We will then do as many reads as it takes to get the full message.
  1024. //
  1025. // We begin by initializing 'BytesToTransfer' to the size of a message
  1026. // header. This will be decremented with each successfully-read block
  1027. // of data. When it drops to zero, we examine the resulting buffer
  1028. // to determine the full message's length, and begin reading that many
  1029. // bytes into another buffer, after copying the message-header into it.
  1030. //
  1031. Bufferp = NhAcquireVariableLengthBuffer(NH_BUFFER_SIZE);
  1032. if (!Bufferp) {
  1033. ALG_DEREFERENCE_INTERFACE(Interfacep);
  1034. return ERROR_CAN_NOT_COMPLETE;
  1035. }
  1036. Bufferp->UserFlags = UserFlags;
  1037. Bufferp->BytesToTransfer = NH_BUFFER_SIZE - ALG_BUFFER_RESERVE;
  1038. Bufferp->TransferOffset = 0;
  1039. Error =
  1040. NhReadStreamSocket(
  1041. &AlgComponentReference,
  1042. Socket,
  1043. Bufferp,
  1044. Bufferp->BytesToTransfer,
  1045. Bufferp->TransferOffset,
  1046. AlgReadEndpointCompletionRoutine,
  1047. Interfacep,
  1048. UlongToPtr(Endpointp->EndpointId)
  1049. );
  1050. if (Error) { ALG_DEREFERENCE_INTERFACE(Interfacep); }
  1051. return Error;
  1052. } // AlgReadActiveEndpoint
  1053. ULONG
  1054. AlgWriteActiveEndpoint(
  1055. PALG_INTERFACE Interfacep,
  1056. PALG_ENDPOINT Endpointp,
  1057. SOCKET Socket,
  1058. PNH_BUFFER Bufferp,
  1059. ULONG Length,
  1060. ULONG UserFlags OPTIONAL
  1061. )
  1062. /*++
  1063. Routine Description:
  1064. This routine is invoked to initiate the transmission of a full message on
  1065. the socket for the given endpoint.
  1066. Arguments:
  1067. Interfacep - the interface on which the connection was accepted
  1068. Connectionp - the connection on whose endpoint to write a message
  1069. Socket - the endpoint on which to write the message
  1070. Bufferp - supplies the buffer containing the message to be written
  1071. Length - supplies the length of the message to be written
  1072. UserFlags - optionally supplies flags to be included in the 'UserFlags'
  1073. field of the message-buffer
  1074. Return Value:
  1075. ULONG - Win32/Winsock2 status code.
  1076. Environment:
  1077. Invoked with the interface's lock held by the caller, and with a reference
  1078. made to the interface on behalf of the write-completion routine. If the
  1079. write cannot be issued here, this routine is responsible for releasing that
  1080. reference.
  1081. --*/
  1082. {
  1083. ULONG Error;
  1084. PROFILE("AlgWriteActiveEndpoint");
  1085. //
  1086. // Initiate a write on the socket for the full buffer size
  1087. // We will do as many writes as it takes to send the full message.
  1088. //
  1089. // We begin by initializing 'BytesToTransfer' to the size of a message.
  1090. // This will be decremented with each successfully-read block
  1091. // of data. When it drops to zero, we are done.
  1092. //
  1093. Bufferp->UserFlags = UserFlags;
  1094. Bufferp->BytesToTransfer = Length;
  1095. Bufferp->TransferOffset = 0;
  1096. Error =
  1097. NhWriteStreamSocket(
  1098. &AlgComponentReference,
  1099. Socket,
  1100. Bufferp,
  1101. Bufferp->BytesToTransfer,
  1102. Bufferp->TransferOffset,
  1103. AlgWriteEndpointCompletionRoutine,
  1104. Interfacep,
  1105. UlongToPtr(Endpointp->EndpointId)
  1106. );
  1107. if (Error) { ALG_DEREFERENCE_INTERFACE(Interfacep); }
  1108. return Error;
  1109. } // AlgWriteActiveEndpoint