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.

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