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.

1406 lines
38 KiB

  1. //
  2. // proxy.c - Generic application level proxy for IPv6/IPv4
  3. //
  4. // This program accepts TCP connections on one socket and port, and
  5. // forwards data between in and another socket to a given address
  6. // (default loopback) and port (default same as listening port).
  7. //
  8. // For example, it can make an unmodified IPv4 server look like an IPv6 server.
  9. // Typically, the proxy will run on the same machine as
  10. // the server it is fronting, but that doesn't have to be the case.
  11. //
  12. // Copyright (C) Microsoft Corporation.
  13. // All rights reserved.
  14. //
  15. // History:
  16. // Original code by Brian Zill.
  17. // Made into a service by Dave Thaler.
  18. //
  19. #include "precomp.h"
  20. #pragma hdrstop
  21. //
  22. // Configuration parameters.
  23. //
  24. #define BUFFER_SIZE (4 * 1024)
  25. typedef enum {
  26. Connect,
  27. Accept,
  28. Receive,
  29. Send
  30. } OPERATION;
  31. CONST CHAR *OperationName[]={
  32. "Connect",
  33. "Accept",
  34. "Receive",
  35. "Send"
  36. };
  37. typedef enum {
  38. Inbound = 0, // Receive from client, send to server.
  39. Outbound, // Receive from server, send to client.
  40. NumDirections
  41. } DIRECTION;
  42. typedef enum {
  43. Client = 0,
  44. Server,
  45. NumSides
  46. } SIDE;
  47. //
  48. // Information we keep for each port we're proxying on.
  49. //
  50. #define ADDR_BUFF_LEN (16+sizeof(SOCKADDR_IN6))
  51. typedef struct _PORT_INFO {
  52. LIST_ENTRY Link;
  53. ULONG ReferenceCount;
  54. SOCKET ListenSocket;
  55. SOCKET AcceptSocket;
  56. BYTE AcceptBuffer[ADDR_BUFF_LEN*2];
  57. WSAOVERLAPPED Overlapped;
  58. OPERATION Operation;
  59. SOCKADDR_STORAGE LocalAddress;
  60. ULONG LocalAddressLength;
  61. SOCKADDR_STORAGE RemoteAddress;
  62. ULONG RemoteAddressLength;
  63. //
  64. // A lock protects the connection list for this port.
  65. //
  66. CRITICAL_SECTION Lock;
  67. LIST_ENTRY ConnectionHead;
  68. } PORT_INFO, *PPORT_INFO;
  69. //
  70. // Information we keep for each direction of a bi-directional connection.
  71. //
  72. typedef struct _DIRECTION_INFO {
  73. WSABUF Buffer;
  74. WSAOVERLAPPED Overlapped;
  75. OPERATION Operation;
  76. struct _CONNECTION_INFO *Connection;
  77. DIRECTION Direction;
  78. } DIRECTION_INFO, *PDIRECTION_INFO;
  79. //
  80. // Information we keep for each client connection.
  81. //
  82. typedef struct _CONNECTION_INFO {
  83. LIST_ENTRY Link;
  84. ULONG ReferenceCount;
  85. PPORT_INFO Port;
  86. BOOL HalfOpen; // Has one side or the other stopped sending?
  87. LONG Closing;
  88. SOCKET Socket[NumSides];
  89. DIRECTION_INFO DirectionInfo[NumDirections];
  90. } CONNECTION_INFO, *PCONNECTION_INFO;
  91. //
  92. // Global variables.
  93. //
  94. LIST_ENTRY g_GlobalPortList;
  95. LPFN_CONNECTEX ConnectEx = NULL;
  96. //
  97. // Function prototypes.
  98. //
  99. VOID
  100. ProcessReceiveError(
  101. IN ULONG NumBytes,
  102. IN LPOVERLAPPED Overlapped,
  103. IN ULONG Status
  104. );
  105. VOID
  106. ProcessSendError(
  107. IN ULONG NumBytes,
  108. IN LPOVERLAPPED Overlapped,
  109. IN ULONG Status
  110. );
  111. VOID
  112. ProcessAcceptError(
  113. IN ULONG NumBytes,
  114. IN LPOVERLAPPED Overlapped,
  115. IN ULONG Status
  116. );
  117. VOID
  118. ProcessConnectError(
  119. IN ULONG NumBytes,
  120. IN LPOVERLAPPED Overlapped,
  121. IN ULONG Status
  122. );
  123. VOID APIENTRY
  124. TpProcessWorkItem(
  125. IN ULONG Status,
  126. IN ULONG NumBytes,
  127. IN LPOVERLAPPED Overlapped
  128. );
  129. //
  130. // Inline functions.
  131. //
  132. __inline
  133. ReferenceConnection(
  134. IN PCONNECTION_INFO Connection
  135. )
  136. {
  137. InterlockedIncrement(&Connection->ReferenceCount);
  138. }
  139. __inline
  140. DereferenceConnection(
  141. IN OUT PCONNECTION_INFO *ConnectionPtr
  142. )
  143. {
  144. ULONG Value;
  145. Value = InterlockedDecrement(&(*ConnectionPtr)->ReferenceCount);
  146. if (Value == 0) {
  147. FREE(*ConnectionPtr);
  148. *ConnectionPtr = NULL;
  149. }
  150. }
  151. __inline
  152. VOID
  153. ReferencePort(
  154. IN PPORT_INFO Port
  155. )
  156. {
  157. InterlockedIncrement(&Port->ReferenceCount);
  158. }
  159. __inline
  160. VOID
  161. DereferencePort(
  162. IN OUT PPORT_INFO *PortPtr
  163. )
  164. {
  165. ULONG Value;
  166. Value = InterlockedDecrement(&(*PortPtr)->ReferenceCount);
  167. if (Value == 0) {
  168. DeleteCriticalSection(&(*PortPtr)->Lock);
  169. FREE(*PortPtr);
  170. *PortPtr = NULL;
  171. }
  172. }
  173. //
  174. // Allocate and initialize state for a new client connection.
  175. //
  176. PCONNECTION_INFO
  177. NewConnection(
  178. IN SOCKET ClientSocket,
  179. IN ULONG ConnectFamily
  180. )
  181. {
  182. PCONNECTION_INFO Connection;
  183. //
  184. // Allocate space for a CONNECTION_INFO structure and two buffers.
  185. //
  186. Connection = (CONNECTION_INFO *)MALLOC(sizeof(*Connection) + (2 * BUFFER_SIZE));
  187. if (Connection == NULL) {
  188. return NULL;
  189. }
  190. //
  191. // Fill everything in.
  192. //
  193. Connection->HalfOpen = FALSE;
  194. Connection->Closing = FALSE;
  195. Connection->Socket[Client] = ClientSocket;
  196. Connection->DirectionInfo[Inbound].Direction = Inbound;
  197. Connection->DirectionInfo[Inbound].Operation = Receive; // Start out receiving.
  198. Connection->DirectionInfo[Inbound].Buffer.len = BUFFER_SIZE;
  199. Connection->DirectionInfo[Inbound].Buffer.buf = (char *)(Connection + 1);
  200. Connection->DirectionInfo[Inbound].Connection = Connection;
  201. Connection->Socket[Server] = socket(ConnectFamily, SOCK_STREAM, 0);
  202. Connection->DirectionInfo[Outbound].Direction = Outbound;
  203. Connection->DirectionInfo[Outbound].Operation = Receive; // Start out receiving.
  204. Connection->DirectionInfo[Outbound].Buffer.len = BUFFER_SIZE;
  205. Connection->DirectionInfo[Outbound].Buffer.buf = Connection->DirectionInfo[Inbound].Buffer.buf + BUFFER_SIZE;
  206. Connection->DirectionInfo[Outbound].Connection = Connection;
  207. Connection->ReferenceCount = 0;
  208. ReferenceConnection(Connection);
  209. Trace2(FSM, _T("R++ %d %x NewConnection"), Connection->ReferenceCount, Connection);
  210. return Connection;
  211. }
  212. //
  213. // Create state information for a client.
  214. //
  215. CONNECTION_INFO *
  216. CreateConnectionState(
  217. IN SOCKET ClientSocket,
  218. IN SOCKET ServerSocket
  219. )
  220. {
  221. CONNECTION_INFO *Conn;
  222. //
  223. // Allocate space for a CONNECTION_INFO structure and two buffers.
  224. //
  225. Conn = (CONNECTION_INFO *)MALLOC(sizeof(*Conn) + (2 * BUFFER_SIZE));
  226. if (Conn == NULL) {
  227. return NULL;
  228. }
  229. //
  230. // Fill everything in.
  231. //
  232. Conn->HalfOpen = FALSE;
  233. //
  234. // Start out in the receiving state in both directions.
  235. //
  236. Conn->Socket[Client] = ClientSocket;
  237. Conn->DirectionInfo[Inbound].Direction = Inbound;
  238. Conn->DirectionInfo[Inbound].Operation = Receive;
  239. Conn->DirectionInfo[Inbound].Buffer.len = BUFFER_SIZE;
  240. Conn->DirectionInfo[Inbound].Buffer.buf = (char *)(Conn + 1);
  241. Conn->DirectionInfo[Inbound].Connection = Conn;
  242. Conn->Socket[Server] = ServerSocket;
  243. Conn->DirectionInfo[Outbound].Direction = Outbound;
  244. Conn->DirectionInfo[Outbound].Operation = Receive;
  245. Conn->DirectionInfo[Outbound].Buffer.len = BUFFER_SIZE;
  246. Conn->DirectionInfo[Outbound].Buffer.buf =
  247. Conn->DirectionInfo[Inbound].Buffer.buf + BUFFER_SIZE;
  248. Conn->DirectionInfo[Outbound].Connection = Conn;
  249. return Conn;
  250. }
  251. //
  252. // Start an asynchronous accept.
  253. //
  254. // Assumes caller holds a reference on Port.
  255. //
  256. DWORD
  257. StartAccept(
  258. IN PPORT_INFO Port
  259. )
  260. {
  261. ULONG Status, Junk;
  262. ASSERT(Port->ReferenceCount > 0);
  263. //
  264. // Count another reference for the operation.
  265. //
  266. ReferencePort(Port);
  267. Port->AcceptSocket = socket(Port->LocalAddress.ss_family, SOCK_STREAM, 0);
  268. if (Port->AcceptSocket == INVALID_SOCKET) {
  269. Status = WSAGetLastError();
  270. ProcessAcceptError(0, &Port->Overlapped, Status);
  271. return Status;
  272. }
  273. Trace2(SOCKET, _T("Starting an accept with new socket %x ovl %p"),
  274. Port->AcceptSocket, &Port->Overlapped);
  275. Port->Overlapped.hEvent = NULL;
  276. Port->Operation = Accept;
  277. if (!AcceptEx(Port->ListenSocket,
  278. Port->AcceptSocket,
  279. Port->AcceptBuffer, // only used to hold addresses
  280. 0,
  281. ADDR_BUFF_LEN,
  282. ADDR_BUFF_LEN,
  283. &Junk,
  284. &Port->Overlapped)) {
  285. Status = WSAGetLastError();
  286. if (Status != ERROR_IO_PENDING) {
  287. ProcessAcceptError(0, &Port->Overlapped, Status);
  288. return Status;
  289. }
  290. }
  291. return NO_ERROR;
  292. }
  293. //
  294. // Start an asynchronous connect.
  295. //
  296. // Assumes caller holds a reference on Connection.
  297. //
  298. DWORD
  299. StartConnect(
  300. IN PCONNECTION_INFO Connection,
  301. IN PPORT_INFO Port
  302. )
  303. {
  304. ULONG Status, Junk;
  305. SOCKADDR_STORAGE LocalAddress;
  306. //
  307. // Count a reference for the operation.
  308. //
  309. ReferenceConnection(Connection);
  310. Trace2(FSM, _T("R++ %d %x StartConnect"), Connection->ReferenceCount, Connection);
  311. Connection->Socket[Server] = socket(Port->RemoteAddress.ss_family,
  312. SOCK_STREAM, 0);
  313. if (Connection->Socket[Server] == INVALID_SOCKET) {
  314. Status = WSAGetLastError();
  315. ProcessConnectError(0, &Connection->DirectionInfo[Inbound].Overlapped,
  316. Status);
  317. return Status;
  318. }
  319. Connection->DirectionInfo[Inbound].Overlapped.hEvent = NULL;
  320. Connection->DirectionInfo[Outbound].Overlapped.hEvent = NULL;
  321. ZeroMemory(&LocalAddress, Port->RemoteAddressLength);
  322. LocalAddress.ss_family = Port->RemoteAddress.ss_family;
  323. if (bind(Connection->Socket[Server], (LPSOCKADDR)&LocalAddress,
  324. Port->RemoteAddressLength) == SOCKET_ERROR) {
  325. Status = WSAGetLastError();
  326. ProcessConnectError(0, &Connection->DirectionInfo[Inbound].Overlapped,
  327. Status);
  328. return Status;
  329. }
  330. if (!BindIoCompletionCallback((HANDLE)Connection->Socket[Server],
  331. TpProcessWorkItem,
  332. 0)) {
  333. Status = GetLastError();
  334. ProcessConnectError(0, &Connection->DirectionInfo[Inbound].Overlapped,
  335. Status);
  336. return Status;
  337. }
  338. if (ConnectEx == NULL) {
  339. GUID Guid = WSAID_CONNECTEX;
  340. if (WSAIoctl(Connection->Socket[Server],
  341. SIO_GET_EXTENSION_FUNCTION_POINTER,
  342. &Guid,
  343. sizeof(Guid),
  344. &ConnectEx,
  345. sizeof(ConnectEx),
  346. &Junk,
  347. NULL, NULL) == SOCKET_ERROR) {
  348. ProcessConnectError(0,
  349. &Connection->DirectionInfo[Inbound].Overlapped,
  350. WSAGetLastError());
  351. }
  352. }
  353. Trace2(SOCKET,
  354. _T("Starting a connect with socket %x ovl %p"),
  355. Connection->Socket[Server],
  356. &Connection->DirectionInfo[Inbound].Overlapped);
  357. Connection->DirectionInfo[Inbound].Operation = Connect;
  358. if (!ConnectEx(Connection->Socket[Server],
  359. (LPSOCKADDR)&Port->RemoteAddress,
  360. Port->RemoteAddressLength,
  361. NULL, 0,
  362. &Junk,
  363. &Connection->DirectionInfo[Inbound].Overlapped)) {
  364. Status = WSAGetLastError();
  365. if (Status != ERROR_IO_PENDING) {
  366. ProcessConnectError(0,
  367. &Connection->DirectionInfo[Inbound].Overlapped,
  368. Status);
  369. return Status;
  370. }
  371. }
  372. return NO_ERROR;
  373. }
  374. //
  375. // Start an asynchronous receive.
  376. //
  377. // Assumes caller holds a reference on DirectionInfo.
  378. //
  379. VOID
  380. StartReceive(
  381. IN PDIRECTION_INFO DirectionInfo
  382. )
  383. {
  384. ULONG BytesRcvd, Status;
  385. PCONNECTION_INFO Connection = CONTAINING_RECORD(DirectionInfo, CONNECTION_INFO,
  386. DirectionInfo[DirectionInfo->Direction]);
  387. Trace3(SOCKET, _T("starting ReadFile on socket %x with Dir %p ovl %p"),
  388. Connection->Socket[DirectionInfo->Direction], DirectionInfo,
  389. &DirectionInfo->Overlapped);
  390. //
  391. // Count a reference for the operation.
  392. //
  393. ReferenceConnection(Connection);
  394. Trace2(FSM, _T("R++ %d %x StartReceive"), Connection->ReferenceCount, Connection);
  395. ASSERT(DirectionInfo->Overlapped.hEvent == NULL);
  396. ASSERT(DirectionInfo->Buffer.len > 0);
  397. ASSERT(DirectionInfo->Buffer.buf != NULL);
  398. DirectionInfo->Operation = Receive;
  399. Trace5(SOCKET, _T("ReadFile %x %p %d %p %p"),
  400. Connection->Socket[DirectionInfo->Direction],
  401. &DirectionInfo->Buffer.buf,
  402. DirectionInfo->Buffer.len,
  403. &BytesRcvd,
  404. &DirectionInfo->Overlapped);
  405. //
  406. // Post receive buffer.
  407. //
  408. if (!ReadFile((HANDLE)Connection->Socket[DirectionInfo->Direction],
  409. DirectionInfo->Buffer.buf,
  410. DirectionInfo->Buffer.len,
  411. &BytesRcvd,
  412. &DirectionInfo->Overlapped)) {
  413. Status = GetLastError();
  414. if (Status != ERROR_IO_PENDING) {
  415. ProcessReceiveError(0, &DirectionInfo->Overlapped, Status);
  416. return;
  417. }
  418. }
  419. }
  420. //
  421. // Start an asynchronous send.
  422. //
  423. // Assumes caller holds a reference on DirectionInfo.
  424. //
  425. VOID
  426. StartSend(
  427. IN PDIRECTION_INFO DirectionInfo,
  428. IN ULONG NumBytes
  429. )
  430. {
  431. ULONG BytesSent, Status;
  432. PCONNECTION_INFO Connection = CONTAINING_RECORD(DirectionInfo, CONNECTION_INFO,
  433. DirectionInfo[DirectionInfo->Direction]);
  434. Trace3(SOCKET, _T("starting WriteFile on socket %x with Dir %p ovl %p"),
  435. Connection->Socket[1 - DirectionInfo->Direction], DirectionInfo,
  436. &DirectionInfo->Overlapped);
  437. //
  438. // Count a reference for the operation.
  439. //
  440. ReferenceConnection(Connection);
  441. Trace2(FSM, _T("R++ %d %x StartSend"), Connection->ReferenceCount, Connection);
  442. DirectionInfo->Operation = Send;
  443. //
  444. // Post send buffer.
  445. //
  446. if (!WriteFile((HANDLE)Connection->Socket[1 - DirectionInfo->Direction],
  447. DirectionInfo->Buffer.buf,
  448. NumBytes,
  449. &BytesSent,
  450. &DirectionInfo->Overlapped)) {
  451. Status = GetLastError();
  452. if (Status != ERROR_IO_PENDING) {
  453. Trace1(ERR, _T("WriteFile 1 failed %d"), Status);
  454. ProcessSendError(0, &DirectionInfo->Overlapped, Status);
  455. return;
  456. }
  457. }
  458. }
  459. //
  460. // This gets called when we want to start proxying for a new port.
  461. //
  462. DWORD
  463. StartUpPort(
  464. IN PPORT_INFO Port
  465. )
  466. {
  467. ULONG Status = NO_ERROR;
  468. CHAR LocalBuffer[256];
  469. CHAR RemoteBuffer[256];
  470. ULONG Length;
  471. //
  472. // Add an initial reference.
  473. //
  474. ReferencePort(Port);
  475. InitializeCriticalSection(&Port->Lock);
  476. InitializeListHead(&Port->ConnectionHead);
  477. Port->ListenSocket = socket(Port->LocalAddress.ss_family, SOCK_STREAM, 0);
  478. if (Port->ListenSocket == INVALID_SOCKET) {
  479. Status = WSAGetLastError();
  480. Trace1(ERR, _T("socket() failed with error %u"), Status);
  481. return Status;
  482. }
  483. if (bind(Port->ListenSocket, (LPSOCKADDR)&Port->LocalAddress,
  484. Port->LocalAddressLength) == SOCKET_ERROR) {
  485. Trace1(ERR, _T("bind() failed with error %u"), WSAGetLastError());
  486. goto Fail;
  487. }
  488. if (listen(Port->ListenSocket, 5) == SOCKET_ERROR) {
  489. Trace1(ERR, _T("listen() failed with error %u"), WSAGetLastError());
  490. goto Fail;
  491. }
  492. if (!BindIoCompletionCallback((HANDLE)Port->ListenSocket,
  493. TpProcessWorkItem,
  494. 0)) {
  495. Trace1(ERR, _T("BindIoCompletionCallback() failed with error %u"),
  496. GetLastError());
  497. goto Fail;
  498. }
  499. Length = sizeof(LocalBuffer);
  500. LocalBuffer[0] = '\0';
  501. WSAAddressToStringA((LPSOCKADDR)&Port->LocalAddress,
  502. Port->LocalAddressLength, NULL, LocalBuffer, &Length);
  503. Length = sizeof(RemoteBuffer);
  504. RemoteBuffer[0] = '\0';
  505. WSAAddressToStringA((LPSOCKADDR)&Port->RemoteAddress,
  506. Port->RemoteAddressLength, NULL, RemoteBuffer, &Length);
  507. Trace2(FSM, _T("Proxying %hs to %hs"), LocalBuffer, RemoteBuffer);
  508. //
  509. // Start an asynchronous accept
  510. //
  511. return StartAccept(Port);
  512. Fail:
  513. closesocket(Port->ListenSocket);
  514. Port->ListenSocket = INVALID_SOCKET;
  515. return WSAGetLastError();
  516. }
  517. VOID
  518. CloseConnection(
  519. IN OUT PCONNECTION_INFO *ConnectionPtr
  520. )
  521. {
  522. PCONNECTION_INFO Connection = (*ConnectionPtr);
  523. PPORT_INFO Port = Connection->Port;
  524. if (InterlockedExchange(&Connection->Closing, TRUE) != FALSE) {
  525. //
  526. // Nothing to do.
  527. //
  528. return;
  529. }
  530. Trace2(SOCKET, _T("Closing client socket %x and server socket %x"),
  531. Connection->Socket[Client],
  532. Connection->Socket[Server]);
  533. closesocket(Connection->Socket[Client]);
  534. closesocket(Connection->Socket[Server]);
  535. EnterCriticalSection(&Port->Lock);
  536. {
  537. RemoveEntryList(&Connection->Link);
  538. }
  539. LeaveCriticalSection(&Port->Lock);
  540. Trace2(FSM, _T("R-- %d %x CloseConnection"),
  541. Connection->ReferenceCount, Connection);
  542. DereferenceConnection(ConnectionPtr);
  543. }
  544. //
  545. // This gets called when we want to stop proxying for a given port.
  546. //
  547. VOID
  548. ShutDownPort(
  549. IN PPORT_INFO *PortPtr
  550. )
  551. {
  552. PCONNECTION_INFO Connection;
  553. PPORT_INFO Port = *PortPtr;
  554. //
  555. // Close any connections.
  556. //
  557. EnterCriticalSection(&Port->Lock);
  558. while (!IsListEmpty(&Port->ConnectionHead)) {
  559. Connection = CONTAINING_RECORD(Port->ConnectionHead.Flink,
  560. CONNECTION_INFO, Link);
  561. CloseConnection(&Connection);
  562. }
  563. LeaveCriticalSection(&Port->Lock);
  564. closesocket(Port->ListenSocket);
  565. Port->ListenSocket = INVALID_SOCKET;
  566. Trace1(FSM, _T("Shut down port %u"), RtlUshortByteSwap(SS_PORT(&Port->RemoteAddress)));
  567. //
  568. // Release the reference added by StartUpPort.
  569. //
  570. DereferencePort(PortPtr);
  571. }
  572. typedef enum {
  573. V4TOV4,
  574. V4TOV6,
  575. V6TOV4,
  576. V6TOV6
  577. } PPTYPE, *PPPTYPE;
  578. typedef struct {
  579. ULONG ListenFamily;
  580. ULONG ConnectFamily;
  581. PWCHAR KeyString;
  582. } PPTYPEINFO, *PPPTYPEINFO;
  583. #define KEY_V4TOV4 L"v4tov4"
  584. #define KEY_V4TOV6 L"v4tov6"
  585. #define KEY_V6TOV4 L"v6tov4"
  586. #define KEY_V6TOV6 L"v6tov6"
  587. #define KEY_PORTS L"System\\CurrentControlSet\\Services\\PortProxy"
  588. PPTYPEINFO PpTypeInfo[] = {
  589. { AF_INET, AF_INET, KEY_V4TOV4 },
  590. { AF_INET, AF_INET6, KEY_V4TOV6 },
  591. { AF_INET6, AF_INET, KEY_V6TOV4 },
  592. { AF_INET6, AF_INET6, KEY_V6TOV6 },
  593. };
  594. //
  595. // Given new configuration data, make any changes needed.
  596. //
  597. VOID
  598. ApplyNewPortList(
  599. IN OUT PLIST_ENTRY pNewList
  600. )
  601. {
  602. PPORT_INFO Port, pCurr;
  603. PLIST_ENTRY pleCurr, plePort, pleNext;
  604. //
  605. // Compare against current port list.
  606. //
  607. for (pleCurr = g_GlobalPortList.Flink; pleCurr != &g_GlobalPortList; pleCurr = pleNext) {
  608. pleNext = pleCurr->Flink;
  609. pCurr = CONTAINING_RECORD(pleCurr, PORT_INFO, Link);
  610. for (plePort = pNewList->Flink; plePort != pNewList; plePort = plePort->Flink) {
  611. Port = CONTAINING_RECORD(plePort, PORT_INFO, Link);
  612. if (SS_PORT(&Port->RemoteAddress) == SS_PORT(&pCurr->RemoteAddress)) {
  613. break;
  614. }
  615. }
  616. if (plePort == pNewList) {
  617. //
  618. // Shut down an old proxy port.
  619. //
  620. RemoveEntryList(pleCurr);
  621. ShutDownPort(&pCurr);
  622. }
  623. }
  624. for (plePort = pNewList->Flink; plePort != pNewList; plePort = pleNext) {
  625. pleNext = plePort->Flink;
  626. Port = CONTAINING_RECORD(plePort, PORT_INFO, Link);
  627. for (pleCurr = g_GlobalPortList.Flink; pleCurr != &g_GlobalPortList; pleCurr = pleCurr->Flink) {
  628. pCurr = CONTAINING_RECORD(pleCurr, PORT_INFO, Link);
  629. if (SS_PORT(&Port->LocalAddress) == SS_PORT(&pCurr->LocalAddress)) {
  630. //
  631. // Update remote address.
  632. //
  633. pCurr->RemoteAddress = Port->RemoteAddress;
  634. pCurr->RemoteAddressLength = Port->RemoteAddressLength;
  635. break;
  636. }
  637. }
  638. if (pleCurr == &g_GlobalPortList) {
  639. //
  640. // Start up a new proxy port.
  641. //
  642. RemoveEntryList(plePort);
  643. InsertTailList(&g_GlobalPortList, plePort);
  644. StartUpPort(Port);
  645. }
  646. }
  647. }
  648. //
  649. // Reads from the registry one type of proxying (e.g., v6-to-v4).
  650. //
  651. VOID
  652. AppendType(
  653. IN PLIST_ENTRY Head,
  654. IN HKEY hPorts,
  655. IN PPTYPE Type
  656. )
  657. {
  658. ADDRINFO ListenHints, ConnectHints;
  659. ADDRINFO *LocalAi, *RemoteAi;
  660. ULONG ListenChars, dwType, ConnectBytes, i;
  661. WCHAR ListenBuffer[256], *ListenAddress, *ListenPort;
  662. WCHAR ConnectAddress[256], *ConnectPort;
  663. PPORT_INFO Port;
  664. ULONG Status;
  665. HKEY hType, hProto;
  666. ZeroMemory(&ListenHints, sizeof(ListenHints));
  667. ListenHints.ai_family = PpTypeInfo[Type].ListenFamily;
  668. ListenHints.ai_socktype = SOCK_STREAM;
  669. ListenHints.ai_flags = AI_PASSIVE;
  670. ZeroMemory(&ConnectHints, sizeof(ConnectHints));
  671. ConnectHints.ai_family = PpTypeInfo[Type].ConnectFamily;
  672. ConnectHints.ai_socktype = SOCK_STREAM;
  673. Status = RegOpenKeyExW(hPorts, PpTypeInfo[Type].KeyString, 0,
  674. KEY_QUERY_VALUE, &hType);
  675. if (Status != NO_ERROR) {
  676. return;
  677. }
  678. Status = RegOpenKeyExW(hType, L"tcp", 0, KEY_QUERY_VALUE, &hProto);
  679. if (Status != NO_ERROR) {
  680. RegCloseKey(hType);
  681. return;
  682. }
  683. for (i=0; ; i++) {
  684. ListenChars = sizeof(ListenBuffer)/sizeof(WCHAR);
  685. ConnectBytes = sizeof(ConnectAddress);
  686. Status = RegEnumValueW(hProto, i, ListenBuffer, &ListenChars, NULL,
  687. &dwType, (PVOID)ConnectAddress, &ConnectBytes);
  688. if (Status != NO_ERROR) {
  689. break;
  690. }
  691. if (dwType != REG_SZ) {
  692. continue;
  693. }
  694. ListenPort = wcschr(ListenBuffer, L'/');
  695. if (ListenPort) {
  696. //
  697. // Replace slash with NULL, so we have 2 strings to pass
  698. // to getaddrinfo.
  699. //
  700. if (ListenBuffer[0] == '*') {
  701. ListenAddress = NULL;
  702. } else {
  703. ListenAddress = ListenBuffer;
  704. }
  705. *ListenPort++ = '\0';
  706. } else {
  707. //
  708. // If the address data didn't include a connect address
  709. // use NULL.
  710. //
  711. ListenAddress = NULL;
  712. ListenPort = ListenBuffer;
  713. }
  714. ConnectPort = wcschr(ConnectAddress, '/');
  715. if (ConnectPort) {
  716. //
  717. // Replace slash with NULL, so we have 2 strings to pass
  718. // to getaddrinfo.
  719. //
  720. *ConnectPort++ = '\0';
  721. } else {
  722. //
  723. // If the address data didn't include a remote port number,
  724. // use the same port as the local port number.
  725. //
  726. ConnectPort = ListenPort;
  727. }
  728. Status = GetAddrInfoW(ConnectAddress, ConnectPort, &ConnectHints,
  729. &RemoteAi);
  730. if (Status != NO_ERROR) {
  731. continue;
  732. }
  733. Status = GetAddrInfoW(ListenAddress, ListenPort, &ListenHints,
  734. &LocalAi);
  735. if (Status != NO_ERROR) {
  736. freeaddrinfo(RemoteAi);
  737. continue;
  738. }
  739. Port = MALLOC(sizeof(PORT_INFO));
  740. if (Port) {
  741. ZeroMemory(Port, sizeof(PORT_INFO));
  742. InsertTailList(Head, &Port->Link);
  743. memcpy(&Port->RemoteAddress, RemoteAi->ai_addr, RemoteAi->ai_addrlen);
  744. Port->RemoteAddressLength = (ULONG)RemoteAi->ai_addrlen;
  745. memcpy(&Port->LocalAddress, LocalAi->ai_addr, LocalAi->ai_addrlen);
  746. Port->LocalAddressLength = (ULONG)LocalAi->ai_addrlen;
  747. }
  748. freeaddrinfo(RemoteAi);
  749. freeaddrinfo(LocalAi);
  750. }
  751. RegCloseKey(hProto);
  752. RegCloseKey(hType);
  753. }
  754. //
  755. // Read new configuration data from the registry and see what's changed.
  756. //
  757. VOID
  758. UpdateGlobalPortState(
  759. IN PVOID Unused
  760. )
  761. {
  762. LIST_ENTRY PortHead;
  763. HKEY hPorts;
  764. ULONG Status = NO_ERROR;
  765. PLIST_ENTRY ple;
  766. InitializeListHead(&PortHead);
  767. //
  768. // Read new port list from registry and initialize per-port proxy state.
  769. //
  770. Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KEY_PORTS, 0, KEY_QUERY_VALUE,
  771. &hPorts);
  772. AppendType(&PortHead, hPorts, V4TOV4);
  773. AppendType(&PortHead, hPorts, V4TOV6);
  774. AppendType(&PortHead, hPorts, V6TOV4);
  775. AppendType(&PortHead, hPorts, V6TOV6);
  776. RegCloseKey(hPorts);
  777. ApplyNewPortList(&PortHead);
  778. //
  779. // Free new port list.
  780. //
  781. while (!IsListEmpty(&PortHead)) {
  782. ple = PortHead.Flink;
  783. RemoveEntryList(ple);
  784. FREE(ple);
  785. }
  786. }
  787. //
  788. // Force UpdateGlobalPortState to be executed in a persistent thread,
  789. // since we need to make sure that the asynchronous IO routines are
  790. // started in a thread that won't go away before the operation completes.
  791. //
  792. BOOL
  793. QueueUpdateGlobalPortState(
  794. IN PVOID Unused
  795. )
  796. {
  797. NTSTATUS nts = QueueUserWorkItem(
  798. (LPTHREAD_START_ROUTINE)UpdateGlobalPortState,
  799. (PVOID)Unused,
  800. WT_EXECUTEINPERSISTENTTHREAD);
  801. return NT_SUCCESS(nts);
  802. }
  803. VOID
  804. InitializePorts(
  805. VOID
  806. )
  807. {
  808. InitializeListHead(&g_GlobalPortList);
  809. }
  810. VOID
  811. UninitializePorts(
  812. VOID
  813. )
  814. {
  815. LIST_ENTRY Empty;
  816. // Check if ports got initialized to begin with.
  817. if (g_GlobalPortList.Flink == NULL)
  818. return;
  819. InitializeListHead(&Empty);
  820. ApplyNewPortList(&Empty);
  821. }
  822. //////////////////////////////////////////////////////////////////////////////
  823. // Event handlers
  824. //////////////////////////////////////////////////////////////////////////////
  825. //
  826. // This is called when an asynchronous accept completes successfully.
  827. //
  828. VOID
  829. ProcessAccept(
  830. IN ULONG NumBytes,
  831. IN LPOVERLAPPED Overlapped
  832. )
  833. {
  834. PPORT_INFO Port = CONTAINING_RECORD(Overlapped, PORT_INFO, Overlapped);
  835. SOCKADDR_IN6 *psinLocal, *psinRemote;
  836. int iLocalLen, iRemoteLen;
  837. PCONNECTION_INFO Connection;
  838. ULONG Status;
  839. //
  840. // Accept incoming connection.
  841. //
  842. GetAcceptExSockaddrs(Port->AcceptBuffer,
  843. 0,
  844. ADDR_BUFF_LEN,
  845. ADDR_BUFF_LEN,
  846. (LPSOCKADDR*)&psinLocal,
  847. &iLocalLen,
  848. (LPSOCKADDR*)&psinRemote,
  849. &iRemoteLen );
  850. if (!BindIoCompletionCallback((HANDLE)Port->AcceptSocket,
  851. TpProcessWorkItem,
  852. 0)) {
  853. Status = GetLastError();
  854. Trace2(SOCKET,
  855. _T("BindIoCompletionCallback failed on socket %x with error %u"),
  856. Port->AcceptSocket, Status);
  857. ProcessAcceptError(NumBytes, Overlapped, Status);
  858. return;
  859. }
  860. //
  861. // Call SO_UPDATE_ACCEPT_CONTEXT so that the AcceptSocket will be valid
  862. // in other winsock calls like shutdown().
  863. //
  864. if (setsockopt(Port->AcceptSocket,
  865. SOL_SOCKET,
  866. SO_UPDATE_ACCEPT_CONTEXT,
  867. (char *)&Port->ListenSocket,
  868. sizeof(Port->ListenSocket)) == SOCKET_ERROR) {
  869. Status = WSAGetLastError();
  870. Trace2(SOCKET,
  871. _T("SO_UPDATE_ACCEPT_CONTEXT failed on socket %x with error %u"),
  872. Port->AcceptSocket, Status);
  873. ProcessAcceptError(NumBytes, Overlapped, Status);
  874. return;
  875. }
  876. //
  877. // Create connection state.
  878. //
  879. Connection = NewConnection(Port->AcceptSocket,
  880. Port->RemoteAddress.ss_family);
  881. Port->AcceptSocket = INVALID_SOCKET;
  882. //
  883. // Add connection to port's list.
  884. //
  885. EnterCriticalSection(&Port->Lock);
  886. {
  887. Connection->Port = Port;
  888. InsertTailList(&Port->ConnectionHead, &Connection->Link);
  889. }
  890. LeaveCriticalSection(&Port->Lock);
  891. //
  892. // Connect to real server on client's behalf.
  893. //
  894. StartConnect(Connection, Port);
  895. //
  896. // Start next accept.
  897. //
  898. StartAccept(Port);
  899. //
  900. // Release the reference from the original accept.
  901. //
  902. DereferencePort(&Port);
  903. }
  904. //
  905. // This is called when an asynchronous accept completes with an error.
  906. //
  907. VOID
  908. ProcessAcceptError(
  909. IN ULONG NumBytes,
  910. IN LPOVERLAPPED Overlapped,
  911. IN ULONG Status
  912. )
  913. {
  914. PPORT_INFO Port = CONTAINING_RECORD(Overlapped, PORT_INFO, Overlapped);
  915. if (Status == ERROR_MORE_DATA) {
  916. ProcessAccept(NumBytes, Overlapped);
  917. return;
  918. } else {
  919. //
  920. // This happens at shutdown time when the accept
  921. // socket gets closed.
  922. //
  923. Trace3(ERR, _T("Accept failed with port=%p nb=%d err=%x"),
  924. Port, NumBytes, Status);
  925. }
  926. //
  927. // Release the reference from the accept.
  928. //
  929. DereferencePort(&Port);
  930. }
  931. //
  932. // This is called when an asynchronous connect completes successfully.
  933. //
  934. VOID
  935. ProcessConnect(
  936. IN ULONG NumBytes,
  937. IN LPOVERLAPPED Overlapped
  938. )
  939. {
  940. PDIRECTION_INFO pInbound = CONTAINING_RECORD(Overlapped, DIRECTION_INFO,
  941. Overlapped);
  942. PCONNECTION_INFO Connection = CONTAINING_RECORD(pInbound, CONNECTION_INFO,
  943. DirectionInfo[Inbound]);
  944. ULONG Status;
  945. Trace3(SOCKET, _T("Connect succeeded with %d bytes with ovl %p socket %x"),
  946. NumBytes, Overlapped, Connection->Socket[Server]);
  947. //
  948. // Call SO_UPDATE_CONNECT_CONTEXT so that the socket will be valid
  949. // in other winsock calls like shutdown().
  950. //
  951. if (setsockopt(Connection->Socket[Server],
  952. SOL_SOCKET,
  953. SO_UPDATE_CONNECT_CONTEXT,
  954. NULL,
  955. 0) == SOCKET_ERROR) {
  956. Status = WSAGetLastError();
  957. Trace2(SOCKET,
  958. _T("SO_UPDATE_CONNECT_CONTEXT failed on socket %x with error %u"),
  959. Connection->Socket[Server], Status);
  960. ProcessConnectError(NumBytes, Overlapped, Status);
  961. return;
  962. }
  963. StartReceive(&Connection->DirectionInfo[Inbound]);
  964. StartReceive(&Connection->DirectionInfo[Outbound]);
  965. //
  966. // Release the reference from the connect.
  967. //
  968. Trace2(FSM, _T("R-- %d %x ProcessConnect"), Connection->ReferenceCount, Connection);
  969. DereferenceConnection(&Connection);
  970. }
  971. //
  972. // This is called when an asynchronous connect completes with an error.
  973. //
  974. VOID
  975. ProcessConnectError(
  976. IN ULONG NumBytes,
  977. IN LPOVERLAPPED Overlapped,
  978. IN ULONG Status
  979. )
  980. {
  981. PDIRECTION_INFO pInbound = CONTAINING_RECORD(Overlapped, DIRECTION_INFO,
  982. Overlapped);
  983. PCONNECTION_INFO Connection = CONTAINING_RECORD(pInbound, CONNECTION_INFO,
  984. DirectionInfo[Inbound]);
  985. Trace1(ERR, _T("ProcessConnectError saw error %x"), Status);
  986. CloseConnection(&Connection);
  987. //
  988. // Release the reference from the connect.
  989. //
  990. Trace2(FSM, _T("R-- %d %x ProcessConnectError"), Connection->ReferenceCount, Connection);
  991. DereferenceConnection(&Connection);
  992. }
  993. //
  994. // This is called when an asynchronous send completes successfully.
  995. //
  996. VOID
  997. ProcessSend(
  998. IN ULONG NumBytes,
  999. IN LPOVERLAPPED Overlapped
  1000. )
  1001. {
  1002. PDIRECTION_INFO DirectionInfo = CONTAINING_RECORD(
  1003. Overlapped, DIRECTION_INFO, Overlapped);
  1004. PCONNECTION_INFO Connection = CONTAINING_RECORD(
  1005. DirectionInfo, CONNECTION_INFO,
  1006. DirectionInfo[DirectionInfo->Direction]);
  1007. //
  1008. // Post another recv request since we but live to serve.
  1009. //
  1010. StartReceive(DirectionInfo);
  1011. //
  1012. // Release the reference from the send.
  1013. //
  1014. Trace2(FSM, _T("R-- %d %x ProcessSend"), Connection->ReferenceCount, Connection);
  1015. DereferenceConnection(&Connection);
  1016. }
  1017. //
  1018. // This is called when an asynchronous send completes with an error.
  1019. //
  1020. VOID
  1021. ProcessSendError(
  1022. IN ULONG NumBytes,
  1023. IN LPOVERLAPPED Overlapped,
  1024. IN ULONG Status
  1025. )
  1026. {
  1027. PDIRECTION_INFO DirectionInfo = CONTAINING_RECORD(Overlapped, DIRECTION_INFO, Overlapped);
  1028. PCONNECTION_INFO Connection = CONTAINING_RECORD(DirectionInfo, CONNECTION_INFO,
  1029. DirectionInfo[DirectionInfo->Direction]);
  1030. Trace3(FSM, _T("WriteFile on ovl %p failed with error %u = 0x%x"),
  1031. Overlapped, Status, Status);
  1032. if (Status == ERROR_NETNAME_DELETED) {
  1033. struct linger Linger;
  1034. Trace2(FSM, _T("Connection %p %hs was reset"), Connection,
  1035. (DirectionInfo->Direction == Inbound)? "inbound" : "outbound");
  1036. //
  1037. // Prepare to forward the reset, if we can.
  1038. //
  1039. ZeroMemory(&Linger, sizeof(Linger));
  1040. setsockopt(Connection->Socket[DirectionInfo->Direction],
  1041. SOL_SOCKET, SO_LINGER, (char*)&Linger,
  1042. sizeof(Linger));
  1043. } else {
  1044. Trace1(ERR, _T("Send failed with error %u"), Status);
  1045. }
  1046. if (Connection->HalfOpen == FALSE) {
  1047. //
  1048. // Other side is still around, tell it to quit.
  1049. //
  1050. Trace1(SOCKET, _T("Starting a shutdown on socket %x"),
  1051. Connection->Socket[DirectionInfo->Direction]);
  1052. if (shutdown(Connection->Socket[DirectionInfo->Direction], SD_RECEIVE)
  1053. == SOCKET_ERROR) {
  1054. Status = WSAGetLastError();
  1055. Trace2(SOCKET, _T("shutdown failed with error %u = 0x%x"),
  1056. Status, Status);
  1057. CloseConnection(&Connection);
  1058. } else {
  1059. Connection->HalfOpen = TRUE;
  1060. }
  1061. } else {
  1062. CloseConnection(&Connection);
  1063. }
  1064. //
  1065. // Release the reference from the send.
  1066. //
  1067. Trace2(FSM, _T("R-- %d %x ProcessSendError"), Connection->ReferenceCount, Connection);
  1068. DereferenceConnection(&Connection);
  1069. }
  1070. //
  1071. // This is called when an asynchronous receive completes successfully.
  1072. //
  1073. VOID
  1074. ProcessReceive(
  1075. IN ULONG NumBytes,
  1076. IN LPOVERLAPPED Overlapped
  1077. )
  1078. {
  1079. PDIRECTION_INFO DirectionInfo;
  1080. PCONNECTION_INFO Connection;
  1081. if (NumBytes == 0) {
  1082. //
  1083. // Other side initiated a close.
  1084. //
  1085. ProcessReceiveError(0, Overlapped, ERROR_NETNAME_DELETED);
  1086. return;
  1087. }
  1088. DirectionInfo = CONTAINING_RECORD(Overlapped, DIRECTION_INFO, Overlapped);
  1089. Connection = CONTAINING_RECORD(DirectionInfo, CONNECTION_INFO,
  1090. DirectionInfo[DirectionInfo->Direction]);
  1091. DirectionInfo->Buffer.buf[NumBytes] = 0;
  1092. Trace3(SOCKET, _T("Dir %d got %d bytes: !%hs!"), DirectionInfo->Direction,
  1093. NumBytes, DirectionInfo->Buffer.buf);
  1094. //
  1095. // Connection is still active, and we received some data.
  1096. // Post a send request to forward it onward.
  1097. //
  1098. StartSend(DirectionInfo, NumBytes);
  1099. //
  1100. // Release the reference from the receive.
  1101. //
  1102. Trace2(FSM, _T("R-- %d %x ProcessReceive"), Connection->ReferenceCount, Connection);
  1103. DereferenceConnection(&Connection);
  1104. }
  1105. //
  1106. // This is called when an asynchronous receive completes with an error.
  1107. //
  1108. VOID
  1109. ProcessReceiveError(
  1110. IN ULONG NumBytes,
  1111. IN LPOVERLAPPED Overlapped,
  1112. IN ULONG Status
  1113. )
  1114. {
  1115. PDIRECTION_INFO DirectionInfo = CONTAINING_RECORD(Overlapped,
  1116. DIRECTION_INFO, Overlapped);
  1117. PCONNECTION_INFO Connection = CONTAINING_RECORD(
  1118. DirectionInfo,
  1119. CONNECTION_INFO,
  1120. DirectionInfo[DirectionInfo->Direction]);
  1121. Trace3(ERR, _T("ReadFile on ovl %p failed with error %u = 0x%x"),
  1122. Overlapped, Status, Status);
  1123. if (Status == ERROR_NETNAME_DELETED) {
  1124. struct linger Linger;
  1125. Trace2(FSM, _T("Connection %p %hs was reset"), Connection,
  1126. (DirectionInfo->Direction == Inbound)? "inbound" : "outbound");
  1127. //
  1128. // Prepare to forward the reset, if we can.
  1129. //
  1130. ZeroMemory(&Linger, sizeof(Linger));
  1131. setsockopt(Connection->Socket[1 - DirectionInfo->Direction],
  1132. SOL_SOCKET, SO_LINGER, (char*)&Linger,
  1133. sizeof(Linger));
  1134. } else {
  1135. Trace1(ERR, _T("Receive failed with error %u"), Status);
  1136. }
  1137. if (Connection->HalfOpen == FALSE) {
  1138. //
  1139. // Other side is still around, tell it to quit.
  1140. //
  1141. Trace1(SOCKET, _T("Starting a shutdown on socket %x"),
  1142. Connection->Socket[1 - DirectionInfo->Direction]);
  1143. if (shutdown(Connection->Socket[1 - DirectionInfo->Direction], SD_SEND)
  1144. == SOCKET_ERROR) {
  1145. Status = WSAGetLastError();
  1146. Trace2(SOCKET, _T("shutdown failed with error %u = 0x%x"),
  1147. Status, Status);
  1148. CloseConnection(&Connection);
  1149. } else {
  1150. Connection->HalfOpen = TRUE;
  1151. }
  1152. } else {
  1153. CloseConnection(&Connection);
  1154. }
  1155. //
  1156. // Release the reference from the receive.
  1157. //
  1158. Trace2(FSM, _T("R-- %d %x ProcessReceiveError"), Connection->ReferenceCount, Connection);
  1159. DereferenceConnection(&Connection);
  1160. }
  1161. //
  1162. // Main dispatch routine
  1163. //
  1164. VOID APIENTRY
  1165. TpProcessWorkItem(
  1166. IN ULONG Status,
  1167. IN ULONG NumBytes,
  1168. IN LPOVERLAPPED Overlapped
  1169. )
  1170. {
  1171. OPERATION Operation;
  1172. Operation = *(OPERATION*)(Overlapped+1);
  1173. Trace4(SOCKET,
  1174. _T("TpProcessWorkItem got err %x operation=%hs ovl %p bytes=%d"),
  1175. Status, OperationName[Operation], Overlapped, NumBytes);
  1176. if (Status == NO_ERROR) {
  1177. switch(Operation) {
  1178. case Accept:
  1179. ProcessAccept(NumBytes, Overlapped);
  1180. break;
  1181. case Connect:
  1182. ProcessConnect(NumBytes, Overlapped);
  1183. break;
  1184. case Receive:
  1185. ProcessReceive(NumBytes, Overlapped);
  1186. break;
  1187. case Send:
  1188. ProcessSend(NumBytes, Overlapped);
  1189. break;
  1190. }
  1191. } else if (Overlapped) {
  1192. switch(Operation) {
  1193. case Accept:
  1194. ProcessAcceptError(NumBytes, Overlapped, Status);
  1195. break;
  1196. case Connect:
  1197. ProcessConnectError(NumBytes, Overlapped, Status);
  1198. break;
  1199. case Receive:
  1200. ProcessReceiveError(NumBytes, Overlapped, Status);
  1201. break;
  1202. case Send:
  1203. ProcessSendError(NumBytes, Overlapped, Status);
  1204. break;
  1205. }
  1206. }
  1207. }