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.

2093 lines
60 KiB

  1. /*++
  2. Copyright (c) 1997, Microsoft Corporation
  3. Module Name:
  4. pptp.c
  5. Abstract:
  6. Contains routines for managing the NAT's PPTP session-mappings
  7. and for editing PPTP control-session messages.
  8. Author:
  9. Abolade Gbadegesin (t-abolag) 19-Aug-1997
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. //
  15. // Structure: PPTP_PSEUDO_HEADER
  16. //
  17. // This structure serves as a pseudo-header for a PPTP control message.
  18. // Its fields are initialized by 'NatBuildPseudoHeaderPptp' with pointers
  19. // to the positions in a buffer-chain of the given PPTP header fields.
  20. // This allows us to access header-fields through a structure even though
  21. // the actual fields may be spread through the received buffer-chain.
  22. //
  23. typedef struct _PPTP_PSEUDO_HEADER {
  24. PUSHORT PacketLength;
  25. #if 0
  26. PUSHORT PacketType; // currently unused
  27. #endif
  28. ULONG UNALIGNED * MagicCookie;
  29. PUSHORT MessageType;
  30. PUSHORT CallId;
  31. PUSHORT PeerCallId;
  32. } PPTP_PSEUDO_HEADER, *PPPTP_PSEUDO_HEADER;
  33. //
  34. // Structure: PPTP_DELETE_WORK_ITEM
  35. //
  36. typedef struct _PPTP_DELETE_WORK_ITEM {
  37. ULONG64 PrivateKey;
  38. ULONG64 PortKey;
  39. PIO_WORKITEM IoWorkItem;
  40. } PPTP_DELETE_WORK_ITEM, *PPPTP_DELETE_WORK_ITEM;
  41. //
  42. // GLOBAL DATA DEFINITIONS
  43. //
  44. NPAGED_LOOKASIDE_LIST PptpLookasideList;
  45. LIST_ENTRY PptpMappingList[NatMaximumDirection];
  46. KSPIN_LOCK PptpMappingLock;
  47. IP_NAT_REGISTER_EDITOR PptpRegisterEditorClient;
  48. IP_NAT_REGISTER_EDITOR PptpRegisterEditorServer;
  49. //
  50. // FORWARD DECLARATIONS
  51. //
  52. IPRcvBuf*
  53. NatBuildPseudoHeaderPptp(
  54. IPRcvBuf* ReceiveBuffer,
  55. PLONG DataOffset,
  56. PPPTP_PSEUDO_HEADER Header
  57. );
  58. VOID
  59. NatDeleteHandlerWorkItemPptp(
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN PVOID Context
  62. );
  63. //
  64. // PPTP MAPPING MANAGEMENT ROUTINES (alphabetically)
  65. //
  66. NTSTATUS
  67. NatAllocatePublicPptpCallId(
  68. ULONG64 PublicKey,
  69. PUSHORT CallIdp,
  70. PLIST_ENTRY *InsertionPoint OPTIONAL
  71. )
  72. /*++
  73. Routine Description:
  74. This routine allocates a public call-ID for a PPTP mapping.
  75. Arguments:
  76. PublicKey - the public key (public and remote addresses) of the mapping
  77. the public call ID is for
  78. CallIdp - receives the allocated public call ID
  79. InsertionPoint -- receives the correct location to insert the mapping
  80. on the inbound list
  81. Return Value:
  82. NTSTATUS - indicates success/failure
  83. Environment:
  84. Invoked with 'PptpMappingLock' held by the caller.
  85. --*/
  86. {
  87. USHORT CallId;
  88. PLIST_ENTRY Link;
  89. PNAT_PPTP_MAPPING Mapping;
  90. CALLTRACE(("NatAllocatePublicPptpCallId\n"));
  91. CallId = 1;
  92. for (Link = PptpMappingList[NatInboundDirection].Flink;
  93. Link != &PptpMappingList[NatInboundDirection];
  94. Link = Link->Flink) {
  95. Mapping =
  96. CONTAINING_RECORD(
  97. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  98. );
  99. if (PublicKey > Mapping->PublicKey) {
  100. continue;
  101. } else if (PublicKey < Mapping->PublicKey) {
  102. break;
  103. }
  104. //
  105. // Primary key equal; see if the call-ID we've chosen
  106. // collides with this one
  107. //
  108. if (CallId > Mapping->PublicCallId) {
  109. continue;
  110. } else if (CallId < Mapping->PublicCallId) {
  111. break;
  112. }
  113. //
  114. // The call-ID's collide; choose another and go on
  115. //
  116. ++CallId;
  117. }
  118. if (Link == &PptpMappingList[NatInboundDirection] && !CallId) {
  119. //
  120. // We are at the end of the list, and all 64K-1 call-IDs are taken
  121. //
  122. return STATUS_UNSUCCESSFUL;
  123. }
  124. *CallIdp = CallId;
  125. if (InsertionPoint) {*InsertionPoint = Link;}
  126. return STATUS_SUCCESS;
  127. } // NatAllocatePublicPptpCallId
  128. NTSTATUS
  129. NatCreatePptpMapping(
  130. ULONG RemoteAddress,
  131. ULONG PrivateAddress,
  132. USHORT CallId,
  133. ULONG PublicAddress,
  134. PUSHORT CallIdp,
  135. IP_NAT_DIRECTION Direction,
  136. USHORT PrivatePort,
  137. USHORT PublicPort,
  138. USHORT RemotePort,
  139. PNAT_PPTP_MAPPING* MappingCreated
  140. )
  141. /*++
  142. Routine Description:
  143. This routine creates and initializes a mapping for a PPTP session.
  144. The mapping is created when a client issues an IncomingCallRequest
  145. message, at which point only the client's call-ID is available.
  146. The mapping is therefore initially marked as half-open.
  147. When the IncomingCallReply is received from the server, the server's
  148. call-ID is recorded, and when the IncomingCallConnected is issued
  149. by the client, the 'half-open' flag is cleared.
  150. Arguments:
  151. RemoteAddress - the address of the remote PPTP endpoint (server)
  152. PrivateAddress - the address of the private PPTP endpoint (client)
  153. CallId - the call-ID specified by the PPTP endpoint. For outbound,
  154. this is the private call ID; for inbound, it is the remote
  155. call ID
  156. PublicAddress - the publicly-visible address for the PPTP session
  157. CallIdp - the call-ID to be used publicly for the PPTP session,
  158. or NULL if a call-ID should be allocated. Ignored for inbound.
  159. Direction - the initial list that this mapping should be placed on
  160. MappingCreated - receives the mapping created
  161. Return Value:
  162. NTSTATUS - indicates success/failure
  163. Environment:
  164. Invoked with 'PptpMappingLock' held by the caller.
  165. --*/
  166. {
  167. PLIST_ENTRY Link;
  168. PLIST_ENTRY InsertionPoint;
  169. PNAT_PPTP_MAPPING Mapping;
  170. NTSTATUS Status;
  171. PNAT_PPTP_MAPPING Temp;
  172. TRACE(PPTP, ("NatCreatePptpMapping\n"));
  173. //
  174. // Allocate and initialize a new mapping, marking it half-open
  175. // since we don't yet know what the remote machine's call-ID will be.
  176. //
  177. Mapping = ALLOCATE_PPTP_BLOCK();
  178. if (!Mapping) {
  179. ERROR(("NatCreatePptpMapping: allocation failed.\n"));
  180. return STATUS_NO_MEMORY;
  181. }
  182. RtlZeroMemory(Mapping, sizeof(*Mapping));
  183. Mapping->Flags = NAT_PPTP_FLAG_HALF_OPEN;
  184. Mapping->PublicKey = MAKE_PPTP_KEY(RemoteAddress, PublicAddress);
  185. Mapping->PrivateKey = MAKE_PPTP_KEY(RemoteAddress, PrivateAddress);
  186. Mapping->PortKey =
  187. MAKE_PPTP_PORT_KEY(PrivatePort, PublicPort, RemotePort);
  188. if (NatOutboundDirection == Direction) {
  189. //
  190. // CallId refers to the private id -- select an id to use
  191. // as the public id, and put the mapping on the inbound list
  192. //
  193. Mapping->PrivateCallId = CallId;
  194. //
  195. // Select the public call-ID to be used for the mapping.
  196. // This may either be specified by the caller, or allocated automatically
  197. // from the next available call-ID unused in our list of mappings.
  198. //
  199. if (CallIdp) {
  200. //
  201. // Use the caller-specified call-ID
  202. //
  203. Mapping->PublicCallId = *CallIdp;
  204. if (NatLookupInboundPptpMapping(
  205. Mapping->PublicKey,
  206. Mapping->PublicCallId,
  207. &InsertionPoint
  208. )) {
  209. //
  210. // Conflicting call-ID
  211. //
  212. TRACE(
  213. PPTP, (
  214. "NatCreatePptpMapping: Conflicting Call-ID %i\n",
  215. *CallIdp
  216. ));
  217. FREE_PPTP_BLOCK(Mapping);
  218. return STATUS_UNSUCCESSFUL;
  219. }
  220. } else {
  221. //
  222. // Find the next available call-ID
  223. // by searching the list of inbound mappings
  224. //
  225. Status = NatAllocatePublicPptpCallId(
  226. Mapping->PublicKey,
  227. &Mapping->PublicCallId,
  228. &InsertionPoint
  229. );
  230. if (!NT_SUCCESS(Status)) {
  231. TRACE(
  232. PPTP, (
  233. "NatCreatePptpMapping: Unable to allocate public Call-Id\n"
  234. ));
  235. FREE_PPTP_BLOCK(Mapping);
  236. return STATUS_UNSUCCESSFUL;
  237. }
  238. }
  239. //
  240. // Insert the mapping in the inbound list
  241. //
  242. InsertTailList(InsertionPoint, &Mapping->Link[NatInboundDirection]);
  243. //
  244. // We can't insert the mapping in the outbound list
  245. // until we have the remote call-ID; for now leave it off the list.
  246. // Note that the mapping was marked 'half-open' above.
  247. //
  248. InitializeListHead(&Mapping->Link[NatOutboundDirection]);
  249. } else {
  250. //
  251. // The call id refers to the remote call id. All that needed to
  252. // be done here is to place the mapping on the outbound list
  253. //
  254. Mapping->RemoteCallId = CallId;
  255. if (NatLookupOutboundPptpMapping(
  256. Mapping->PrivateKey,
  257. Mapping->RemoteCallId,
  258. &InsertionPoint
  259. )) {
  260. //
  261. // Duplicate mapping
  262. //
  263. TRACE(
  264. PPTP, (
  265. "NatCreatePptpMapping: Duplicate mapping 0x%016I64X/%i\n",
  266. Mapping->PrivateKey,
  267. Mapping->RemoteCallId
  268. ));
  269. FREE_PPTP_BLOCK(Mapping);
  270. return STATUS_UNSUCCESSFUL;
  271. }
  272. InsertTailList(InsertionPoint, &Mapping->Link[NatOutboundDirection]);
  273. //
  274. // We can't insert the mapping in the inbound list
  275. // until we have the public call-ID; for now leave it off the list.
  276. // Note that the mapping was marked 'half-open' above.
  277. //
  278. InitializeListHead(&Mapping->Link[NatInboundDirection]);
  279. }
  280. *MappingCreated = Mapping;
  281. return STATUS_SUCCESS;
  282. } // NatCreatePptpMapping
  283. PNAT_PPTP_MAPPING
  284. NatLookupInboundPptpMapping(
  285. ULONG64 PublicKey,
  286. USHORT PublicCallId,
  287. PLIST_ENTRY* InsertionPoint
  288. )
  289. /*++
  290. Routine Description:
  291. This routine is called to lookup a PPTP session mapping in the list
  292. which is sorted for inbound-access, using <RemoteAddress # PublicAddress>
  293. as the primary key and 'PublicCallId' as the secondary key.
  294. Arguments:
  295. PublicKey - the primary search key
  296. PublicCallId - the publicly visible call-ID, which is the secondary key
  297. InsertionPoint - receives the point at which the mapping should be inserted
  298. if the mapping is not found.
  299. Return Value:
  300. PNAT_PPTP_MAPPING - the mapping found, if any.
  301. Environment:
  302. Invoked with 'PptpMappingLock' held by the caller.
  303. --*/
  304. {
  305. PLIST_ENTRY Link;
  306. PNAT_PPTP_MAPPING Mapping;
  307. TRACE(PER_PACKET, ("NatLookupInboundPptpMapping\n"));
  308. for (Link = PptpMappingList[NatInboundDirection].Flink;
  309. Link != &PptpMappingList[NatInboundDirection]; Link = Link->Flink) {
  310. Mapping =
  311. CONTAINING_RECORD(
  312. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  313. );
  314. if (PublicKey > Mapping->PublicKey) {
  315. continue;
  316. } else if (PublicKey < Mapping->PublicKey) {
  317. break;
  318. }
  319. //
  320. // Primary keys equal, check secondary keys
  321. //
  322. if (PublicCallId > Mapping->PublicCallId) {
  323. continue;
  324. } else if (PublicCallId < Mapping->PublicCallId) {
  325. break;
  326. }
  327. //
  328. // Secondary keys equal, we got it.
  329. //
  330. return Mapping;
  331. }
  332. //
  333. // Mapping not found, return insertion point
  334. //
  335. if (InsertionPoint) { *InsertionPoint = Link; }
  336. return NULL;
  337. } // NatLookupInboundPptpMapping
  338. PNAT_PPTP_MAPPING
  339. NatLookupOutboundPptpMapping(
  340. ULONG64 PrivateKey,
  341. USHORT RemoteCallId,
  342. PLIST_ENTRY* InsertionPoint
  343. )
  344. /*++
  345. Routine Description:
  346. This routine is called to lookup a PPTP session mapping in the list
  347. which is sorted for outbound-access, using <RemoteAddress # PrivateAddress>
  348. as the primary key and 'RemoteCallId' as the secondary key.
  349. Arguments:
  350. PrivateKey - the primary search key
  351. RemoteCallId - the remote endpoint's call-ID, which is the secondary key
  352. InsertionPoint - receives the point at which the mapping should be inserted
  353. if the mapping is not found.
  354. Return Value:
  355. PNAT_PPTP_MAPPING - the mapping found, if any.
  356. Environment:
  357. Invoked with 'PptpMappingLock' held by the caller.
  358. --*/
  359. {
  360. PLIST_ENTRY Link;
  361. PNAT_PPTP_MAPPING Mapping;
  362. TRACE(PER_PACKET, ("NatLookupOutboundPptpMapping\n"));
  363. for (Link = PptpMappingList[NatOutboundDirection].Flink;
  364. Link != &PptpMappingList[NatOutboundDirection]; Link = Link->Flink) {
  365. Mapping =
  366. CONTAINING_RECORD(
  367. Link, NAT_PPTP_MAPPING, Link[NatOutboundDirection]
  368. );
  369. if (PrivateKey > Mapping->PrivateKey) {
  370. continue;
  371. } else if (PrivateKey < Mapping->PrivateKey) {
  372. break;
  373. }
  374. //
  375. // Primary keys equal, check secondary keys
  376. //
  377. if (RemoteCallId > Mapping->RemoteCallId) {
  378. continue;
  379. } else if (RemoteCallId < Mapping->RemoteCallId) {
  380. break;
  381. }
  382. //
  383. // Secondary keys equal, we got it.
  384. //
  385. return Mapping;
  386. }
  387. //
  388. // Mapping not found, return insertion point
  389. //
  390. if (InsertionPoint) { *InsertionPoint = Link; }
  391. return NULL;
  392. } // NatLookupOutboundPptpMapping
  393. //
  394. // PPTP EDITOR ROUTINES (alphabetically)
  395. //
  396. #define RECVBUFFER ((IPRcvBuf*)ReceiveBuffer)
  397. //
  398. // Macro: PPTP_HEADER_FIELD
  399. //
  400. #define PPTP_HEADER_FIELD(ReceiveBuffer, DataOffsetp, Header, Field, Type) \
  401. FIND_HEADER_FIELD( \
  402. ReceiveBuffer, DataOffsetp, Header, Field, PPTP_HEADER, Type \
  403. )
  404. IPRcvBuf*
  405. NatBuildPseudoHeaderPptp(
  406. IPRcvBuf* ReceiveBuffer,
  407. PLONG DataOffset,
  408. PPPTP_PSEUDO_HEADER Header
  409. )
  410. /*++
  411. Routine Description:
  412. This routine is called to initialize a pseudo-header with pointers
  413. to the fields of a PPTP header.
  414. Arguments:
  415. ReceiveBuffer - the buffer-chain containing the PPTP message
  416. DataOffset - on input, contains the offset to the beginning of the
  417. PPTP header. On output, contains a (negative) value indicating
  418. the offset to the beginning of the same PPTP header in the returned
  419. 'IPRcvBuf'. Adding the 'PacketLength' to the value gives the beginning
  420. of the next PPTP message in the buffer chain.
  421. Header - receives the header-field pointers.
  422. Return Value:
  423. IPRcvBuf* - a pointer to the buffer in the chain from which the last
  424. header-field was read. Returns NULL on failure.
  425. --*/
  426. {
  427. //
  428. // Note that the pseudo-header's fields must be initialized in-order,
  429. // i.e. fields appearing earlier in PPTP header must be set before
  430. // fields appearing later in the PPTP header.
  431. // (See comment on 'PPTP_HEADER_FIELD' for more details).
  432. //
  433. PPTP_HEADER_FIELD(ReceiveBuffer, DataOffset, Header, PacketLength, PUSHORT);
  434. if (!ReceiveBuffer) { return NULL; }
  435. if (!*Header->PacketLength) {return NULL;}
  436. PPTP_HEADER_FIELD(ReceiveBuffer, DataOffset, Header, MagicCookie, PULONG);
  437. if (!ReceiveBuffer) { return NULL; }
  438. if (*Header->MagicCookie != PPTP_MAGIC_COOKIE) { return NULL; }
  439. PPTP_HEADER_FIELD(ReceiveBuffer, DataOffset, Header, MessageType, PUSHORT);
  440. if (!ReceiveBuffer) { return NULL; }
  441. PPTP_HEADER_FIELD(ReceiveBuffer, DataOffset, Header, CallId, PUSHORT);
  442. if (!ReceiveBuffer) { return NULL; }
  443. PPTP_HEADER_FIELD(ReceiveBuffer, DataOffset, Header, PeerCallId, PUSHORT);
  444. if (!ReceiveBuffer) { return NULL; }
  445. //
  446. // Return the updated 'ReceiveBuffer'.
  447. // Note that any call to 'PPTP_HEADER_FIELD' above may fail
  448. // if it hits the end of the buffer chain while looking for a field.
  449. //
  450. return ReceiveBuffer;
  451. } // NatBuildPseudoHeaderPptp
  452. NTSTATUS
  453. NatClientToServerDataHandlerPptp(
  454. IN PVOID InterfaceHandle,
  455. IN PVOID SessionHandle,
  456. IN PVOID DataHandle,
  457. IN PVOID EditorContext,
  458. IN PVOID EditorSessionContext,
  459. IN PVOID ReceiveBuffer,
  460. IN ULONG DataOffset,
  461. IN IP_NAT_DIRECTION Direction
  462. )
  463. /*++
  464. Routine Description:
  465. This routine is invoked for each TCP segment sent from the client
  466. to the server of a PPTP control channel.
  467. The routine is responsible for creating PPTP mappings to allow
  468. the NAT to translate PPTP data-connections, and for translating
  469. the 'CallId' field of PPTP control-messages.
  470. We also use the messages seen to detect when tunnels are to be torn down.
  471. Arguments:
  472. InterfaceHandle - handle to the outgoing NAT_INTERFACE
  473. SessionHandle - the connection's NAT_DYNAMIC_MAPPING
  474. DataHandle - the packet's NAT_XLATE_CONTEXT
  475. EditorContext - unused
  476. EditorSessionContext - unused
  477. ReceiveBuffer - contains the received packet
  478. DataOffset - offset of the protocol data in 'ReceiveBuffer
  479. Direction - the direction of the packet (inbound or outbound)
  480. Return Value:
  481. NTSTATUS - indicates success/failure
  482. --*/
  483. {
  484. PPTP_PSEUDO_HEADER Header;
  485. PLIST_ENTRY Link;
  486. PNAT_PPTP_MAPPING Mapping;
  487. ULONG64 PortKey;
  488. ULONG PrivateAddress;
  489. ULONG64 PrivateKey;
  490. USHORT PrivatePort;
  491. ULONG PublicAddress;
  492. USHORT PublicPort;
  493. ULONG RemoteAddress;
  494. USHORT RemotePort;
  495. ULONG64 Key;
  496. NTSTATUS status;
  497. CALLTRACE(("NatClientToServerDataHandlerPptp\n"));
  498. //
  499. // Perform processing for each PPTP control message in the packet
  500. //
  501. for (ReceiveBuffer =
  502. NatBuildPseudoHeaderPptp(RECVBUFFER, &DataOffset, &Header);
  503. ReceiveBuffer;
  504. ReceiveBuffer =
  505. NatBuildPseudoHeaderPptp(RECVBUFFER, &DataOffset, &Header)
  506. ) {
  507. //
  508. // Process any client-to-server messages which require translation
  509. //
  510. switch(NTOHS(*Header.MessageType)) {
  511. case PPTP_OUTGOING_CALL_REQUEST: {
  512. TRACE(PPTP, ("OutgoingCallRequest\n"));
  513. //
  514. // Create a NAT_PPTP_MAPPING for the PPTP session.
  515. //
  516. PptpRegisterEditorClient.QueryInfoSession(
  517. SessionHandle,
  518. &PrivateAddress,
  519. &PrivatePort,
  520. &RemoteAddress,
  521. &RemotePort,
  522. &PublicAddress,
  523. &PublicPort,
  524. NULL
  525. );
  526. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  527. status =
  528. NatCreatePptpMapping(
  529. RemoteAddress,
  530. PrivateAddress,
  531. *Header.CallId,
  532. PublicAddress,
  533. NULL,
  534. Direction,
  535. PrivatePort,
  536. PublicPort,
  537. RemotePort,
  538. &Mapping
  539. );
  540. if (NT_SUCCESS(status) && NatOutboundDirection == Direction) {
  541. //
  542. // For outbound messages, 'CallId' corresponds here to
  543. // 'PrivateCallId': replace the private call-ID in the message
  544. // with the public call-ID allocated in the new mapping.
  545. //
  546. NatEditorEditShortSession(
  547. DataHandle, Header.CallId, Mapping->PublicCallId
  548. );
  549. }
  550. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  551. if (!NT_SUCCESS(status)) { return STATUS_UNSUCCESSFUL; }
  552. break;
  553. }
  554. case PPTP_CALL_CLEAR_REQUEST: {
  555. BOOLEAN Found = FALSE;
  556. TRACE(PPTP, ("CallClearRequest\n"));
  557. //
  558. // Look up the NAT_PPTP_MAPPING for the PPTP session.
  559. PptpRegisterEditorClient.QueryInfoSession(
  560. SessionHandle,
  561. &PrivateAddress,
  562. NULL,
  563. &RemoteAddress,
  564. NULL,
  565. &PublicAddress,
  566. NULL,
  567. NULL
  568. );
  569. if( NatOutboundDirection == Direction) {
  570. //
  571. // 'CallId' corresponds here to 'PrivateCallId',
  572. // so we retrieve 'PrivateAddress' and 'RemoteAddress',
  573. // which together comprise 'PrivateKey', and use that key
  574. // to search the inbound-list.
  575. //
  576. Key = MAKE_PPTP_KEY(RemoteAddress, PrivateAddress);
  577. //
  578. // Search exhaustively for PrivateCallId in the inbound list.
  579. //
  580. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  581. for (Link = PptpMappingList[NatInboundDirection].Flink;
  582. Link != &PptpMappingList[NatInboundDirection];
  583. Link = Link->Flink) {
  584. Mapping =
  585. CONTAINING_RECORD(
  586. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  587. );
  588. if (Key != Mapping->PrivateKey ||
  589. *Header.CallId != Mapping->PrivateCallId) {
  590. continue;
  591. }
  592. Found = TRUE; break;
  593. }
  594. if (Found) {
  595. NatEditorEditShortSession(
  596. DataHandle, Header.CallId, Mapping->PublicCallId
  597. );
  598. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  599. }
  600. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  601. if (!Found) { return STATUS_UNSUCCESSFUL; }
  602. } else {
  603. //
  604. // 'CallId' corresponds here to 'RemoteCallId',
  605. // so we retrieve 'PublicAddress' and 'RemoteAddress',
  606. // which together comprise 'PublicKey', and use that key
  607. // to search the outbound-list.
  608. //
  609. Key = MAKE_PPTP_KEY(RemoteAddress, PublicAddress);
  610. //
  611. // Search exhaustively for RemoteCallId in the outbound list.
  612. //
  613. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  614. for (Link = PptpMappingList[NatOutboundDirection].Flink;
  615. Link != &PptpMappingList[NatOutboundDirection];
  616. Link = Link->Flink) {
  617. Mapping =
  618. CONTAINING_RECORD(
  619. Link, NAT_PPTP_MAPPING, Link[NatOutboundDirection]
  620. );
  621. if (Key != Mapping->PublicKey ||
  622. *Header.CallId != Mapping->RemoteCallId) {
  623. continue;
  624. }
  625. Found = TRUE; break;
  626. }
  627. if (Found) {
  628. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  629. }
  630. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  631. if (!Found) { return STATUS_UNSUCCESSFUL; }
  632. }
  633. break;
  634. }
  635. case PPTP_ECHO_REQUEST:
  636. case PPTP_ECHO_REPLY: {
  637. TRACE(PPTP, ("EchoRequest / EchoReply\n"));
  638. //
  639. // Search for all PPTP mappings that belong to this
  640. // control connection in order to update their
  641. // last access time.
  642. //
  643. PptpRegisterEditorClient.QueryInfoSession(
  644. SessionHandle,
  645. &PrivateAddress,
  646. &PrivatePort,
  647. &RemoteAddress,
  648. &RemotePort,
  649. NULL,
  650. &PublicPort,
  651. NULL
  652. );
  653. PrivateKey = MAKE_PPTP_KEY(RemoteAddress, PrivateAddress);
  654. PortKey =
  655. MAKE_PPTP_PORT_KEY(PrivatePort, PublicPort, RemotePort);
  656. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  657. //
  658. // Since we don't care about updating the timestamp for
  659. // half-open connections we only need to search the inbound
  660. // list. (It's OK that this may update the timestamp on some
  661. // half-open entries, though.)
  662. //
  663. for (Link = PptpMappingList[NatInboundDirection].Flink;
  664. Link != &PptpMappingList[NatInboundDirection];
  665. Link = Link->Flink) {
  666. Mapping =
  667. CONTAINING_RECORD(
  668. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  669. );
  670. if (PrivateKey != Mapping->PrivateKey
  671. || PortKey != Mapping->PortKey) {
  672. continue;
  673. }
  674. KeQueryTickCount((PLARGE_INTEGER)&Mapping->LastAccessTime);
  675. }
  676. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  677. break;
  678. }
  679. }
  680. //
  681. // Advance to the next message, if any
  682. //
  683. DataOffset += NTOHS(*Header.PacketLength);
  684. }
  685. return STATUS_SUCCESS;
  686. } // NatClientToServerDataHandlerPptp
  687. NTSTATUS
  688. NatDeleteHandlerPptp(
  689. IN PVOID InterfaceHandle,
  690. IN PVOID SessionHandle,
  691. IN PVOID EditorContext,
  692. IN PVOID EditorSessionContext
  693. )
  694. /*++
  695. Routine Description:
  696. This routine is invoked when a PPTP control connection is deleted.
  697. At this point we queue an executive work-item to mark all PPTP tunnel
  698. mappings as disconnected. Note that we cannot mark them during this call,
  699. because to do so we need to acquire the interface lock, and we cannot
  700. do so from this context, because we are a 'DeleteHandler' and hence
  701. we may be called with the interface-lock already held.
  702. Arguments:
  703. SessionHandle - used to obtain information on the session.
  704. EditorContext - unused
  705. EditorSessionContext - unused
  706. Return Value:
  707. NTSTATUS - indicates success/failure.
  708. --*/
  709. {
  710. ULONG PrivateAddress;
  711. ULONG64 PrivateKey;
  712. USHORT PrivatePort;
  713. USHORT PublicPort;
  714. ULONG RemoteAddress;
  715. USHORT RemotePort;
  716. PPPTP_DELETE_WORK_ITEM WorkItem;
  717. TRACE(PPTP, ("NatDeleteHandlerPptp\n"));
  718. //
  719. // Get information about the session being deleted
  720. //
  721. NatQueryInformationMapping(
  722. (PNAT_DYNAMIC_MAPPING)SessionHandle,
  723. NULL,
  724. &PrivateAddress,
  725. &PrivatePort,
  726. &RemoteAddress,
  727. &RemotePort,
  728. NULL,
  729. &PublicPort,
  730. NULL
  731. );
  732. PrivateKey = MAKE_PPTP_KEY(RemoteAddress, PrivateAddress);
  733. //
  734. // Allocate a work-queue item which will mark as disconnected
  735. // all the tunnels of the control session being deleted
  736. //
  737. WorkItem =
  738. ExAllocatePoolWithTag(
  739. NonPagedPool, sizeof(PPTP_DELETE_WORK_ITEM), NAT_TAG_WORK_ITEM
  740. );
  741. if (!WorkItem) { return STATUS_UNSUCCESSFUL; }
  742. WorkItem->PrivateKey = PrivateKey;
  743. WorkItem->PortKey = MAKE_PPTP_PORT_KEY(PrivatePort, PublicPort, RemotePort);
  744. WorkItem->IoWorkItem = IoAllocateWorkItem(NatDeviceObject);
  745. if (!WorkItem->IoWorkItem) {
  746. ExFreePool(WorkItem);
  747. return STATUS_UNSUCCESSFUL;
  748. }
  749. //
  750. // Queue the work item, and return
  751. //
  752. IoQueueWorkItem(
  753. WorkItem->IoWorkItem,
  754. NatDeleteHandlerWorkItemPptp,
  755. DelayedWorkQueue,
  756. WorkItem
  757. );
  758. return STATUS_SUCCESS;
  759. } // NatDeleteHandlerPptp
  760. VOID
  761. NatDeleteHandlerWorkItemPptp(
  762. IN PDEVICE_OBJECT DeviceObject,
  763. IN PVOID Context
  764. )
  765. /*++
  766. Routine Description:
  767. This routine is called to complete the deletion of a PPTP control session.
  768. It marks all the control-session's tunnels as disconnected.
  769. Arguments:
  770. DeviceObject - unused.
  771. Context - contains a PPTP_DELETE_WORK_ITEM from 'NatDeleteHandlerPptp'
  772. Return Value:
  773. none.
  774. --*/
  775. {
  776. KIRQL Irql;
  777. PLIST_ENTRY Link;
  778. PNAT_PPTP_MAPPING Mapping;
  779. PPPTP_DELETE_WORK_ITEM WorkItem;
  780. TRACE(PPTP, ("NatDeleteHandlerWorkItemPptp\n"));
  781. WorkItem = (PPPTP_DELETE_WORK_ITEM)Context;
  782. IoFreeWorkItem(WorkItem->IoWorkItem);
  783. //
  784. // All tunnel mappings over the given control connection
  785. // must now be marked as disconnected.
  786. // Walk the inbound and outbound list.
  787. //
  788. KeAcquireSpinLock(&PptpMappingLock, &Irql);
  789. for (Link = PptpMappingList[NatInboundDirection].Flink;
  790. Link != &PptpMappingList[NatInboundDirection]; Link = Link->Flink) {
  791. Mapping =
  792. CONTAINING_RECORD(
  793. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  794. );
  795. if (WorkItem->PrivateKey != Mapping->PrivateKey
  796. || WorkItem->PortKey != Mapping->PortKey) {
  797. continue;
  798. }
  799. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  800. }
  801. for (Link = PptpMappingList[NatOutboundDirection].Flink;
  802. Link != &PptpMappingList[NatOutboundDirection]; Link = Link->Flink) {
  803. Mapping =
  804. CONTAINING_RECORD(
  805. Link, NAT_PPTP_MAPPING, Link[NatOutboundDirection]
  806. );
  807. if (WorkItem->PrivateKey != Mapping->PrivateKey
  808. || WorkItem->PortKey != Mapping->PortKey) {
  809. continue;
  810. }
  811. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  812. }
  813. KeReleaseSpinLock(&PptpMappingLock, Irql);
  814. //
  815. // Delete the work-item
  816. //
  817. ExFreePool(WorkItem);
  818. } // NatDeleteHandlerWorkItemPptp
  819. NTSTATUS
  820. NatInboundDataHandlerPptpClient(
  821. IN PVOID InterfaceHandle,
  822. IN PVOID SessionHandle,
  823. IN PVOID DataHandle,
  824. IN PVOID EditorContext,
  825. IN PVOID EditorSessionContext,
  826. IN PVOID RecvBuffer,
  827. IN ULONG DataOffset
  828. )
  829. /*++
  830. Routine Description:
  831. This routine is invoked for each TCP segment received by a private
  832. PPTP client machine
  833. Arguments:
  834. InterfaceHandle - the receiving NAT_INTERFACE
  835. SessionHandle - the connection's NAT_DYNAMIC_MAPPING
  836. DataHandle - the packet's NAT_XLATE_CONTEXT
  837. EditorContext - unused
  838. EditorSessionContext - unused
  839. RecvBuffer - contains the received packet
  840. DataOffset - offset of the protocol data in 'ReceiveBuffer'
  841. Return Value:
  842. NTSTATUS - indicates success/failure
  843. --*/
  844. {
  845. CALLTRACE(("NatInboundDataHandlerPptpClient\n"));
  846. return
  847. NatServerToClientDataHandlerPptp(
  848. InterfaceHandle,
  849. SessionHandle,
  850. DataHandle,
  851. EditorContext,
  852. EditorSessionContext,
  853. RecvBuffer,
  854. DataOffset,
  855. NatInboundDirection
  856. );
  857. } // NatInboundDataHandlerPptpClient
  858. NTSTATUS
  859. NatInboundDataHandlerPptpServer(
  860. IN PVOID InterfaceHandle,
  861. IN PVOID SessionHandle,
  862. IN PVOID DataHandle,
  863. IN PVOID EditorContext,
  864. IN PVOID EditorSessionContext,
  865. IN PVOID RecvBuffer,
  866. IN ULONG DataOffset
  867. )
  868. /*++
  869. Routine Description:
  870. This routine is invoked for each TCP segment received by a private
  871. PPTP server machine
  872. Arguments:
  873. InterfaceHandle - the receiving NAT_INTERFACE
  874. SessionHandle - the connection's NAT_DYNAMIC_MAPPING
  875. DataHandle - the packet's NAT_XLATE_CONTEXT
  876. EditorContext - unused
  877. EditorSessionContext - unused
  878. RecvBuffer - contains the received packet
  879. DataOffset - offset of the protocol data in 'ReceiveBuffer'
  880. Return Value:
  881. NTSTATUS - indicates success/failure
  882. --*/
  883. {
  884. CALLTRACE(("NatInboundDataHandlerPptpServer\n"));
  885. return
  886. NatClientToServerDataHandlerPptp(
  887. InterfaceHandle,
  888. SessionHandle,
  889. DataHandle,
  890. EditorContext,
  891. EditorSessionContext,
  892. RecvBuffer,
  893. DataOffset,
  894. NatInboundDirection
  895. );
  896. } // NatInboundDataHandlerPptpServer
  897. NTSTATUS
  898. NatInitializePptpManagement(
  899. VOID
  900. )
  901. /*++
  902. Routine Description:
  903. This routine initializes the PPTP management module and, in the process,
  904. registers the PPTP control-session editor with the NAT.
  905. Arguments:
  906. none.
  907. Return Value:
  908. NTSTATUS - indicates success/failure.
  909. --*/
  910. {
  911. NTSTATUS Status;
  912. CALLTRACE(("NatInitializePptpManangement\n"));
  913. KeInitializeSpinLock(&PptpMappingLock);
  914. InitializeListHead(&PptpMappingList[NatInboundDirection]);
  915. InitializeListHead(&PptpMappingList[NatOutboundDirection]);
  916. ExInitializeNPagedLookasideList(
  917. &PptpLookasideList,
  918. NatAllocateFunction,
  919. NULL,
  920. 0,
  921. sizeof(NAT_PPTP_MAPPING),
  922. NAT_TAG_PPTP,
  923. PPTP_LOOKASIDE_DEPTH
  924. );
  925. PptpRegisterEditorClient.Version = IP_NAT_VERSION;
  926. PptpRegisterEditorClient.Flags = 0;
  927. PptpRegisterEditorClient.Protocol = NAT_PROTOCOL_TCP;
  928. PptpRegisterEditorClient.Port = NTOHS(PPTP_CONTROL_PORT);
  929. PptpRegisterEditorClient.Direction = NatOutboundDirection;
  930. PptpRegisterEditorClient.EditorContext = NULL;
  931. PptpRegisterEditorClient.CreateHandler = NULL;
  932. PptpRegisterEditorClient.DeleteHandler = NatDeleteHandlerPptp;
  933. PptpRegisterEditorClient.ForwardDataHandler = NatOutboundDataHandlerPptpClient;
  934. PptpRegisterEditorClient.ReverseDataHandler = NatInboundDataHandlerPptpClient;
  935. Status = NatCreateEditor(&PptpRegisterEditorClient);
  936. if (!NT_SUCCESS(Status)) {
  937. return Status;
  938. }
  939. PptpRegisterEditorServer.Version = IP_NAT_VERSION;
  940. PptpRegisterEditorServer.Flags = 0;
  941. PptpRegisterEditorServer.Protocol = NAT_PROTOCOL_TCP;
  942. PptpRegisterEditorServer.Port = NTOHS(PPTP_CONTROL_PORT);
  943. PptpRegisterEditorServer.Direction = NatInboundDirection;
  944. PptpRegisterEditorServer.EditorContext = NULL;
  945. PptpRegisterEditorServer.CreateHandler = NULL;
  946. PptpRegisterEditorServer.DeleteHandler = NatDeleteHandlerPptp;
  947. PptpRegisterEditorServer.ForwardDataHandler = NatInboundDataHandlerPptpServer;
  948. PptpRegisterEditorServer.ReverseDataHandler = NatOutboundDataHandlerPptpServer;
  949. return NatCreateEditor(&PptpRegisterEditorServer);
  950. } // NatInitializePptpManagement
  951. NTSTATUS
  952. NatOutboundDataHandlerPptpClient(
  953. IN PVOID InterfaceHandle,
  954. IN PVOID SessionHandle,
  955. IN PVOID DataHandle,
  956. IN PVOID EditorContext,
  957. IN PVOID EditorSessionContext,
  958. IN PVOID RecvBuffer,
  959. IN ULONG DataOffset
  960. )
  961. /*++
  962. Routine Description:
  963. This routine is invoked for each TCP segment sent from a private
  964. PPTP client machine
  965. Arguments:
  966. InterfaceHandle - the receiving NAT_INTERFACE
  967. SessionHandle - the connection's NAT_DYNAMIC_MAPPING
  968. DataHandle - the packet's NAT_XLATE_CONTEXT
  969. EditorContext - unused
  970. EditorSessionContext - unused
  971. RecvBuffer - contains the received packet
  972. DataOffset - offset of the protocol data in 'ReceiveBuffer'
  973. Return Value:
  974. NTSTATUS - indicates success/failure
  975. --*/
  976. {
  977. CALLTRACE(("NatOutboundDataHandlerPptpClient\n"));
  978. return
  979. NatClientToServerDataHandlerPptp(
  980. InterfaceHandle,
  981. SessionHandle,
  982. DataHandle,
  983. EditorContext,
  984. EditorSessionContext,
  985. RecvBuffer,
  986. DataOffset,
  987. NatOutboundDirection
  988. );
  989. } // NatOutboundDataHandlerPptpClient
  990. NTSTATUS
  991. NatOutboundDataHandlerPptpServer(
  992. IN PVOID InterfaceHandle,
  993. IN PVOID SessionHandle,
  994. IN PVOID DataHandle,
  995. IN PVOID EditorContext,
  996. IN PVOID EditorSessionContext,
  997. IN PVOID RecvBuffer,
  998. IN ULONG DataOffset
  999. )
  1000. /*++
  1001. Routine Description:
  1002. This routine is invoked for each TCP segment sent from a private
  1003. PPTP server machine
  1004. Arguments:
  1005. InterfaceHandle - the receiving NAT_INTERFACE
  1006. SessionHandle - the connection's NAT_DYNAMIC_MAPPING
  1007. DataHandle - the packet's NAT_XLATE_CONTEXT
  1008. EditorContext - unused
  1009. EditorSessionContext - unused
  1010. RecvBuffer - contains the received packet
  1011. DataOffset - offset of the protocol data in 'ReceiveBuffer'
  1012. Return Value:
  1013. NTSTATUS - indicates success/failure
  1014. --*/
  1015. {
  1016. CALLTRACE(("NatOutboundDataHandlerPptpServer\n"));
  1017. return
  1018. NatServerToClientDataHandlerPptp(
  1019. InterfaceHandle,
  1020. SessionHandle,
  1021. DataHandle,
  1022. EditorContext,
  1023. EditorSessionContext,
  1024. RecvBuffer,
  1025. DataOffset,
  1026. NatOutboundDirection
  1027. );
  1028. } // NatOutboundDataHandlerPptpServer
  1029. NTSTATUS
  1030. NatServerToClientDataHandlerPptp(
  1031. IN PVOID InterfaceHandle,
  1032. IN PVOID SessionHandle,
  1033. IN PVOID DataHandle,
  1034. IN PVOID EditorContext,
  1035. IN PVOID EditorSessionContext,
  1036. IN PVOID ReceiveBuffer,
  1037. IN ULONG DataOffset,
  1038. IN IP_NAT_DIRECTION Direction
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. This routine is invoked for each TCP segment sent from the server
  1043. to the client on a PPTP control channel
  1044. The routine is responsible for translating inbound PPTP control messages.
  1045. It also uses the messages seen to detect when tunnels are to be torn down.
  1046. Arguments:
  1047. InterfaceHandle - the receiving NAT_INTERFACE
  1048. SessionHandle - the connection's NAT_DYNAMIC_MAPPING
  1049. DataHandle - the packet's NAT_XLATE_CONTEXT
  1050. EditorContext - unused
  1051. EditorSessionContext - unused
  1052. ReceiveBuffer - contains the received packet
  1053. DataOffset - offset of the protocol data in 'ReceiveBuffer'
  1054. Direction - the direction of the segment (inbound or outbound)
  1055. Return Value:
  1056. NTSTATUS - indicates success/failure
  1057. --*/
  1058. {
  1059. PPTP_PSEUDO_HEADER Header;
  1060. PLIST_ENTRY InsertionPoint;
  1061. PLIST_ENTRY Link;
  1062. BOOLEAN Found = FALSE;
  1063. PNAT_PPTP_MAPPING Mapping;
  1064. ULONG64 PortKey;
  1065. ULONG PrivateAddress;
  1066. ULONG64 PrivateKey;
  1067. USHORT PrivatePort;
  1068. ULONG PublicAddress;
  1069. ULONG64 PublicKey;
  1070. USHORT PublicPort;
  1071. ULONG RemoteAddress;
  1072. USHORT RemotePort;
  1073. NTSTATUS status;
  1074. CALLTRACE(("NatServerToClientDataHandlerPptp\n"));
  1075. //
  1076. // Perform processing for each PPTP control message in the packet
  1077. //
  1078. for (ReceiveBuffer =
  1079. NatBuildPseudoHeaderPptp(RECVBUFFER, &DataOffset, &Header);
  1080. ReceiveBuffer;
  1081. ReceiveBuffer =
  1082. NatBuildPseudoHeaderPptp(RECVBUFFER, &DataOffset, &Header)) {
  1083. //
  1084. // Process any server-to-client messages which require translation
  1085. //
  1086. switch(NTOHS(*Header.MessageType)) {
  1087. case PPTP_OUTGOING_CALL_REPLY: {
  1088. TRACE(PPTP, ("OutgoingCallReply\n"));
  1089. //
  1090. // Look up the NAT_PPTP_MAPPING for the PPTP session,
  1091. // record the peer's call ID, mark the session as open,
  1092. // and possibly translate the 'PeerCallId'
  1093. //
  1094. PptpRegisterEditorClient.QueryInfoSession(
  1095. SessionHandle,
  1096. &PrivateAddress,
  1097. NULL,
  1098. &RemoteAddress,
  1099. NULL,
  1100. &PublicAddress,
  1101. NULL,
  1102. NULL
  1103. );
  1104. PublicKey = MAKE_PPTP_KEY(RemoteAddress, PublicAddress);
  1105. if (NatInboundDirection == Direction) {
  1106. //
  1107. // 'PeerCallId' corresponds here to 'PublicCallId',
  1108. // so search for a mapping using 'PublicKey'
  1109. //
  1110. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1111. Mapping =
  1112. NatLookupInboundPptpMapping(
  1113. PublicKey,
  1114. *Header.PeerCallId,
  1115. NULL
  1116. );
  1117. if (Mapping
  1118. && !NAT_PPTP_DISCONNECTED(Mapping)
  1119. && NAT_PPTP_HALF_OPEN(Mapping)) {
  1120. ASSERT(0 == Mapping->RemoteCallId);
  1121. ASSERT(IsListEmpty(&Mapping->Link[NatOutboundDirection]));
  1122. Mapping->RemoteCallId = *Header.CallId;
  1123. if (NatLookupOutboundPptpMapping(
  1124. Mapping->PrivateKey,
  1125. Mapping->RemoteCallId,
  1126. &InsertionPoint
  1127. )) {
  1128. //
  1129. // A duplicate exists; disconnect the mapping.
  1130. //
  1131. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  1132. Mapping = NULL;
  1133. } else {
  1134. //
  1135. // Insert the mapping on the outbound list.
  1136. //
  1137. InsertTailList(
  1138. InsertionPoint,
  1139. &Mapping->Link[NatOutboundDirection]
  1140. );
  1141. Mapping->Flags &= ~NAT_PPTP_FLAG_HALF_OPEN;
  1142. }
  1143. }
  1144. if (Mapping && !NAT_PPTP_DISCONNECTED(Mapping)) {
  1145. //
  1146. // Replace the public call-ID in the message
  1147. // with the original private call-ID
  1148. //
  1149. NatEditorEditShortSession(
  1150. DataHandle,
  1151. Header.PeerCallId,
  1152. Mapping->PrivateCallId
  1153. );
  1154. }
  1155. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1156. } else {
  1157. //
  1158. // 'PeerCallId' corresponds here to 'RemoteCallId',
  1159. // so we search for a mapping using 'PrivateKey'
  1160. //
  1161. PrivateKey = MAKE_PPTP_KEY(RemoteAddress, PrivateAddress);
  1162. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1163. Mapping =
  1164. NatLookupOutboundPptpMapping(
  1165. PrivateKey,
  1166. *Header.PeerCallId,
  1167. NULL
  1168. );
  1169. if (Mapping
  1170. && !NAT_PPTP_DISCONNECTED(Mapping)
  1171. && NAT_PPTP_HALF_OPEN(Mapping)) {
  1172. ASSERT(0 == Mapping->PrivateCallId);
  1173. ASSERT(0 == Mapping->PublicCallId);
  1174. ASSERT(IsListEmpty(&Mapping->Link[NatInboundDirection]));
  1175. Mapping->PrivateCallId = *Header.CallId;
  1176. //
  1177. // Allocate a public call ID for the mapping.
  1178. //
  1179. status = NatAllocatePublicPptpCallId(
  1180. PublicKey,
  1181. &Mapping->PublicCallId,
  1182. &InsertionPoint
  1183. );
  1184. if (NT_SUCCESS(status)) {
  1185. //
  1186. // Insert the mapping on the inbound list and
  1187. // mark the mapping as fully open
  1188. //
  1189. InsertTailList(
  1190. InsertionPoint,
  1191. &Mapping->Link[NatInboundDirection]
  1192. );
  1193. Mapping->Flags &= ~NAT_PPTP_FLAG_HALF_OPEN;
  1194. } else {
  1195. //
  1196. // Unable to allocate the public call ID --
  1197. // disconnect the mapping
  1198. //
  1199. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  1200. Mapping = NULL;
  1201. }
  1202. }
  1203. if (Mapping && !NAT_PPTP_DISCONNECTED(Mapping)) {
  1204. //
  1205. // Translate the call-ID
  1206. //
  1207. NatEditorEditShortSession(
  1208. DataHandle,
  1209. Header.CallId,
  1210. Mapping->PublicCallId
  1211. );
  1212. }
  1213. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1214. }
  1215. if (!Mapping) { return STATUS_UNSUCCESSFUL; }
  1216. break;
  1217. }
  1218. case PPTP_SET_LINK_INFO:
  1219. case PPTP_INCOMING_CALL_CONNECTED:
  1220. case PPTP_WAN_ERROR_NOTIFY: {
  1221. TRACE(PPTP, ("SetLinkInfo|IncomingCallConnected|WanErrorNotify\n"));
  1222. if (NatInboundDirection == Direction) {
  1223. //
  1224. // Look up the NAT_PPTP_MAPPING for the PPTP session
  1225. // and translate the 'CallId' field with the private call-ID
  1226. // 'CallId' corresponds here to 'PublicCallId',
  1227. // so we search for a mapping using 'PublicKey'.
  1228. //
  1229. PptpRegisterEditorClient.QueryInfoSession(
  1230. SessionHandle,
  1231. NULL,
  1232. NULL,
  1233. &RemoteAddress,
  1234. NULL,
  1235. &PublicAddress,
  1236. NULL,
  1237. NULL
  1238. );
  1239. PublicKey = MAKE_PPTP_KEY(RemoteAddress, PublicAddress);
  1240. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1241. Mapping =
  1242. NatLookupInboundPptpMapping(
  1243. PublicKey,
  1244. *Header.CallId,
  1245. NULL
  1246. );
  1247. if (Mapping) {
  1248. NatEditorEditShortSession(
  1249. DataHandle, Header.CallId, Mapping->PrivateCallId
  1250. );
  1251. //
  1252. // Also, update the timestamp on the mapping.
  1253. //
  1254. KeQueryTickCount(
  1255. (PLARGE_INTEGER)&Mapping->LastAccessTime
  1256. );
  1257. }
  1258. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1259. if (!Mapping) { return STATUS_UNSUCCESSFUL; }
  1260. }
  1261. //
  1262. // For the outbound case, CallId refers to the remote call ID,
  1263. // so no translation is necessary.
  1264. //
  1265. break;
  1266. }
  1267. case PPTP_CALL_DISCONNECT_NOTIFY: {
  1268. TRACE(PPTP, ("CallDisconnectNotify\n"));
  1269. //
  1270. // Look up the NAT_PPTP_MAPPING for the PPTP session
  1271. // and mark it for deletion.
  1272. //
  1273. PptpRegisterEditorClient.QueryInfoSession(
  1274. SessionHandle,
  1275. &PrivateAddress,
  1276. NULL,
  1277. &RemoteAddress,
  1278. NULL,
  1279. &PublicAddress,
  1280. NULL,
  1281. NULL
  1282. );
  1283. if (NatOutboundDirection == Direction) {
  1284. //
  1285. // 'CallId' corresponds here to 'PrivateCallId',
  1286. // so we retrieve 'PrivateAddress' and 'RemoteAddress',
  1287. // which together comprise 'PrivateKey', and use that key
  1288. // to search the inbound-list.
  1289. //
  1290. PrivateKey = MAKE_PPTP_KEY(RemoteAddress, PrivateAddress);
  1291. //
  1292. // Search exhaustively for PrivateCallId in the inbound list.
  1293. //
  1294. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1295. for (Link = PptpMappingList[NatInboundDirection].Flink;
  1296. Link != &PptpMappingList[NatInboundDirection];
  1297. Link = Link->Flink) {
  1298. Mapping =
  1299. CONTAINING_RECORD(
  1300. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  1301. );
  1302. if (PrivateKey != Mapping->PrivateKey ||
  1303. *Header.CallId != Mapping->PrivateCallId) {
  1304. continue;
  1305. }
  1306. Found = TRUE; break;
  1307. }
  1308. if (Found) {
  1309. NatEditorEditShortSession(
  1310. DataHandle, Header.CallId, Mapping->PublicCallId
  1311. );
  1312. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  1313. }
  1314. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1315. if (!Found) { return STATUS_UNSUCCESSFUL; }
  1316. } else {
  1317. //
  1318. // 'CallId' corresponds here to 'RemoteCallId',
  1319. // so we retrieve 'PublicAddress' and 'RemoteAddress',
  1320. // which together comprise 'PublicKey', and use that key
  1321. // to search the outbound-list.
  1322. //
  1323. PublicKey = MAKE_PPTP_KEY(RemoteAddress, PublicAddress);
  1324. //
  1325. // Search exhaustively for RemoteCallId in the outbound list.
  1326. //
  1327. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1328. for (Link = PptpMappingList[NatOutboundDirection].Flink;
  1329. Link != &PptpMappingList[NatOutboundDirection];
  1330. Link = Link->Flink) {
  1331. Mapping =
  1332. CONTAINING_RECORD(
  1333. Link, NAT_PPTP_MAPPING, Link[NatOutboundDirection]
  1334. );
  1335. if (PublicKey != Mapping->PublicKey ||
  1336. *Header.CallId != Mapping->RemoteCallId) {
  1337. continue;
  1338. }
  1339. Found = TRUE; break;
  1340. }
  1341. if (Found) {
  1342. Mapping->Flags |= NAT_PPTP_FLAG_DISCONNECTED;
  1343. }
  1344. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1345. if (!Found) { return STATUS_UNSUCCESSFUL; }
  1346. }
  1347. break;
  1348. }
  1349. case PPTP_ECHO_REQUEST:
  1350. case PPTP_ECHO_REPLY: {
  1351. TRACE(PPTP, ("EchoRequest / EchoReply\n"));
  1352. //
  1353. // Search for all PPTP mappings that belong to this
  1354. // control connection in order to update their
  1355. // last access time.
  1356. //
  1357. PptpRegisterEditorClient.QueryInfoSession(
  1358. SessionHandle,
  1359. &PrivateAddress,
  1360. &PrivatePort,
  1361. &RemoteAddress,
  1362. &RemotePort,
  1363. NULL,
  1364. &PublicPort,
  1365. NULL
  1366. );
  1367. PrivateKey = MAKE_PPTP_KEY(RemoteAddress, PrivateAddress);
  1368. PortKey =
  1369. MAKE_PPTP_PORT_KEY(PrivatePort, PublicPort, RemotePort);
  1370. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1371. //
  1372. // Since we don't care about updating the timestamp for
  1373. // half-open connections we only need to search the inbound
  1374. // list. (It's OK that this may update the timestamp on some
  1375. // half-open entries, though.)
  1376. //
  1377. for (Link = PptpMappingList[NatInboundDirection].Flink;
  1378. Link != &PptpMappingList[NatInboundDirection];
  1379. Link = Link->Flink) {
  1380. Mapping =
  1381. CONTAINING_RECORD(
  1382. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  1383. );
  1384. if (PrivateKey != Mapping->PrivateKey
  1385. || PortKey != Mapping->PortKey) {
  1386. continue;
  1387. }
  1388. KeQueryTickCount((PLARGE_INTEGER)&Mapping->LastAccessTime);
  1389. }
  1390. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1391. break;
  1392. }
  1393. }
  1394. //
  1395. // Advance to the next message, if any
  1396. //
  1397. DataOffset += NTOHS(*Header.PacketLength);
  1398. }
  1399. return STATUS_SUCCESS;
  1400. } // NatInboundDataHandlerPptp
  1401. VOID
  1402. NatShutdownPptpManagement(
  1403. VOID
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. This routine is called to shutdown operations for the PPTP editor module.
  1408. It handles cleanup of all existing data structures.
  1409. Arguments:
  1410. none.
  1411. Return Value:
  1412. none.
  1413. --*/
  1414. {
  1415. CALLTRACE(("NatShutdownPptpManagement"));
  1416. ExDeleteNPagedLookasideList(&PptpLookasideList);
  1417. } // NatShutdownPptpManagement
  1418. FORWARD_ACTION
  1419. NatTranslatePptp(
  1420. PNAT_INTERFACE Interfacep OPTIONAL,
  1421. IP_NAT_DIRECTION Direction,
  1422. PNAT_XLATE_CONTEXT Contextp,
  1423. IPRcvBuf** InReceiveBuffer,
  1424. IPRcvBuf** OutReceiveBuffer
  1425. )
  1426. /*++
  1427. Routine Description:
  1428. This routine is called to translate a PPTP data packet,
  1429. which is encapsulated inside a GRE header.
  1430. Arguments:
  1431. Interfacep - the boundary interface over which to translate, or NULL
  1432. if the packet is received on an interface unknown to the NAT.
  1433. Direction - the direction in which the packet is traveling
  1434. Contextp - initialized with context-information for the packet
  1435. InReceiveBuffer - input buffer-chain
  1436. OutReceiveBuffer - receives modified buffer-chain.
  1437. Return Value:
  1438. FORWARD_ACTION - indicates action to take on the packet.
  1439. Environment:
  1440. Invoked with reference made to 'Interfacep' by the caller.
  1441. --*/
  1442. {
  1443. FORWARD_ACTION act;
  1444. ULONG Checksum;
  1445. ULONG ChecksumDelta = 0;
  1446. PGRE_HEADER GreHeader;
  1447. ULONG i;
  1448. PIP_HEADER IpHeader;
  1449. PNAT_PPTP_MAPPING Mapping;
  1450. ULONG64 PrivateKey;
  1451. ULONG64 PublicKey;
  1452. BOOLEAN FirewallMode;
  1453. TRACE(XLATE, ("NatTranslatePptp\n"));
  1454. FirewallMode = Interfacep && NAT_INTERFACE_FW(Interfacep);
  1455. IpHeader = Contextp->Header;
  1456. GreHeader = (PGRE_HEADER)Contextp->ProtocolHeader;
  1457. if (Direction == NatInboundDirection) {
  1458. //
  1459. // Look for the PPTP mapping for the data packet
  1460. //
  1461. PublicKey =
  1462. MAKE_PPTP_KEY(
  1463. Contextp->SourceAddress,
  1464. Contextp->DestinationAddress
  1465. );
  1466. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1467. Mapping =
  1468. NatLookupInboundPptpMapping(
  1469. PublicKey,
  1470. GreHeader->CallId,
  1471. NULL
  1472. );
  1473. if (!Mapping) {
  1474. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1475. return ((*Contextp->DestinationType < DEST_REMOTE) && !FirewallMode
  1476. ? FORWARD : DROP);
  1477. }
  1478. //
  1479. // Translate the private call-ID
  1480. //
  1481. GreHeader->CallId = Mapping->PrivateCallId;
  1482. if (!Contextp->ChecksumOffloaded) {
  1483. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->DestinationAddress);
  1484. IpHeader->DestinationAddress = PPTP_KEY_PRIVATE(Mapping->PrivateKey);
  1485. CHECKSUM_LONG(ChecksumDelta, IpHeader->DestinationAddress);
  1486. CHECKSUM_UPDATE(IpHeader->Checksum);
  1487. } else {
  1488. IpHeader->DestinationAddress = PPTP_KEY_PRIVATE(Mapping->PrivateKey);
  1489. NatComputeIpChecksum(IpHeader);
  1490. }
  1491. } else {
  1492. //
  1493. // Look for the PPTP mapping for the data packet
  1494. //
  1495. PrivateKey =
  1496. MAKE_PPTP_KEY(
  1497. Contextp->DestinationAddress,
  1498. Contextp->SourceAddress
  1499. );
  1500. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  1501. Mapping =
  1502. NatLookupOutboundPptpMapping(
  1503. PrivateKey,
  1504. GreHeader->CallId,
  1505. NULL
  1506. );
  1507. if (!Mapping) {
  1508. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1509. if (NULL != Interfacep) {
  1510. //
  1511. // Make sure this packet has a valid source address
  1512. // for this interface.
  1513. //
  1514. act = DROP;
  1515. for (i = 0; i < Interfacep->AddressCount; i++) {
  1516. if (Contextp->SourceAddress ==
  1517. Interfacep->AddressArray[i].Address
  1518. ) {
  1519. act = FORWARD;
  1520. break;
  1521. }
  1522. }
  1523. } else {
  1524. act = FORWARD;
  1525. }
  1526. return act;
  1527. }
  1528. //
  1529. // For outbound packets the Call-ID is the remote ID,
  1530. // and hence needs no translation.
  1531. //
  1532. if (!Contextp->ChecksumOffloaded) {
  1533. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->SourceAddress);
  1534. IpHeader->SourceAddress = PPTP_KEY_PUBLIC(Mapping->PublicKey);
  1535. CHECKSUM_LONG(ChecksumDelta, IpHeader->SourceAddress);
  1536. CHECKSUM_UPDATE(IpHeader->Checksum);
  1537. } else {
  1538. IpHeader->SourceAddress = PPTP_KEY_PUBLIC(Mapping->PublicKey);
  1539. NatComputeIpChecksum(IpHeader);
  1540. }
  1541. }
  1542. KeQueryTickCount((PLARGE_INTEGER)&Mapping->LastAccessTime);
  1543. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  1544. *OutReceiveBuffer = *InReceiveBuffer; *InReceiveBuffer = NULL;
  1545. *Contextp->DestinationType = DEST_INVALID;
  1546. return FORWARD;
  1547. } // NatTranslatePptp