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.

586 lines
13 KiB

  1. /*++
  2. Copyright (c) 1997, Microsoft Corporation
  3. Module Name:
  4. nbt.c
  5. Abstract:
  6. This module contains code for the NAT's NetBT support.
  7. The support consists of an outbound-data handler for NetBT's datagram
  8. service, which runs over UDP port 138.
  9. Author:
  10. Abolade Gbadegesin (t-abolag) 25-Aug-1997
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // Registration structure for NBT datagram-service editing
  17. //
  18. IP_NAT_REGISTER_EDITOR NbtRegisterEditor;
  19. typedef struct _NBT_PSEUDO_HEADER {
  20. PUCHAR MessageType;
  21. PUCHAR Flags;
  22. // PUSHORT DatagramId;
  23. PULONG SourceAddress;
  24. PUSHORT SourcePort;
  25. // PUSHORT DatagramLength;
  26. // PUSHORT PacketOffset;
  27. PUCHAR SourceName;
  28. PUCHAR DestinationName;
  29. } NBT_PSEUDO_HEADER, *PNBT_PSEUDO_HEADER;
  30. #define NBT_HEADER_FIELD(RecvBuffer, DataOffsetp, Header, Field, Type) \
  31. FIND_HEADER_FIELD(RecvBuffer, DataOffsetp, Header, Field, NBT_HEADER, Type)
  32. //
  33. // NBT MAPPING MANAGEMENT ROUTINES (alphabetically)
  34. //
  35. NTSTATUS
  36. NatCreateNbtMapping(
  37. PNAT_INTERFACE Interfacep,
  38. ULONG PrivateAddress,
  39. ULONG PublicAddress,
  40. UCHAR SourceName[],
  41. PLIST_ENTRY InboundInsertionPoint,
  42. PNAT_NBT_MAPPING* MappingCreated
  43. )
  44. /*++
  45. Routine Description:
  46. This routine is called to allocate and initialize an NBT mapping.
  47. It assumes that the interface is locked.
  48. Arguments:
  49. PrivateAddress - the private address for the mapping
  50. PublicAddress - the public address for the mapping
  51. SourceName - the NetBIOS name for the mapping's private machine
  52. InboundInsertionPoint - optionally supplies the point of insertion
  53. in the list of NBT mappings
  54. MappingCreated - receives the mapping created
  55. Return Value:
  56. NTSTATUS - success/failure code.
  57. --*/
  58. {
  59. PNAT_NBT_MAPPING Mapping;
  60. CALLTRACE(("NatCreateNbtMapping\n"));
  61. *MappingCreated = NULL;
  62. //
  63. // Allocate space for the new mapping
  64. //
  65. Mapping = ALLOCATE_NBT_BLOCK();
  66. if (!Mapping) {
  67. TRACE(NBT, ("NatCreateNbtMapping: allocation failed\n"));
  68. return STATUS_NO_MEMORY;
  69. }
  70. RtlZeroMemory(Mapping, sizeof(*Mapping));
  71. Mapping->PrivateAddress = PrivateAddress;
  72. Mapping->PublicAddress = PublicAddress;
  73. RtlCopyMemory(Mapping->SourceName, SourceName, NBT_NAME_LENGTH);
  74. KeQueryTickCount((PLARGE_INTEGER)&Mapping->LastAccessTime);
  75. //
  76. // Find the insertion point if necessary
  77. //
  78. if (!InboundInsertionPoint &&
  79. NatLookupInboundNbtMapping(
  80. Interfacep,
  81. PublicAddress,
  82. SourceName,
  83. &InboundInsertionPoint
  84. )) {
  85. TRACE(
  86. NBT, ("NatCreateNbtMapping: duplicate %d.%d.%d.%d/%d.%d.%d.%d\n",
  87. ADDRESS_BYTES(PublicAddress), ADDRESS_BYTES(PrivateAddress)
  88. ));
  89. return STATUS_UNSUCCESSFUL;
  90. }
  91. //
  92. // Insert the new mapping
  93. //
  94. InsertTailList(InboundInsertionPoint, &Mapping->Link);
  95. *MappingCreated = Mapping;
  96. return STATUS_SUCCESS;
  97. } // NatCreateNbtMapping
  98. PNAT_NBT_MAPPING
  99. NatLookupInboundNbtMapping(
  100. PNAT_INTERFACE Interfacep,
  101. ULONG PublicAddress,
  102. UCHAR SourceName[],
  103. PLIST_ENTRY* InboundInsertionPoint
  104. )
  105. /*++
  106. Routine Description:
  107. This routine is invoked to search the list of mappings for a given entry.
  108. Arguments:
  109. Interfacep - the interface whose mapping-list is to be searched
  110. PublicAddress - the public address of the mapping
  111. SourceName - the private NBT endpoint's source-name
  112. InboundInsertionPoint - optionally receives the insertion point
  113. if the mapping is not found.
  114. Return Value:
  115. PNAT_NBT_MAPPING - the mapping if found, otherwise NULL
  116. --*/
  117. {
  118. LONG cmp;
  119. PLIST_ENTRY Link;
  120. PNAT_NBT_MAPPING Mapping;
  121. TRACE(PER_PACKET, ("NatLookupInboundNbtMapping\n"));
  122. for (Link = Interfacep->NbtMappingList.Flink;
  123. Link != &Interfacep->NbtMappingList;
  124. Link = Link->Flink
  125. ) {
  126. Mapping = CONTAINING_RECORD(Link, NAT_NBT_MAPPING, Link);
  127. if (PublicAddress > Mapping->PublicAddress) { continue; }
  128. else
  129. if (PublicAddress < Mapping->PublicAddress) { break; }
  130. cmp = memcmp(SourceName, Mapping->SourceName, NBT_NAME_LENGTH);
  131. if (cmp > 0) { continue; }
  132. else
  133. if (cmp < 0) { break; }
  134. //
  135. // We've found the item.
  136. //
  137. return Mapping;
  138. }
  139. //
  140. // The item wasn't found; store the insertion point if possible.
  141. //
  142. if (InboundInsertionPoint) { *InboundInsertionPoint = Link; }
  143. return NULL;
  144. } // NatLookupInboundNbtMapping
  145. //
  146. // NBT EDITOR HANDLER ROUTINES (alphabetically)
  147. //
  148. NTSTATUS
  149. NatInitializeEditorNbt(
  150. VOID
  151. )
  152. /*++
  153. Routine Description:
  154. This routine registers the NBT datagram-service editor with the NAT.
  155. Arguments:
  156. none.
  157. Return Value:
  158. NTSTATUS - indicates success/failure.
  159. --*/
  160. {
  161. CALLTRACE(("NatInitializeEditorNbt\n"));
  162. NbtRegisterEditor.Version = IP_NAT_VERSION;
  163. NbtRegisterEditor.Flags = 0;
  164. NbtRegisterEditor.Protocol = NAT_PROTOCOL_UDP;
  165. NbtRegisterEditor.Port = NTOHS(NBT_DATAGRAM_PORT);
  166. NbtRegisterEditor.Direction = NatOutboundDirection;
  167. NbtRegisterEditor.EditorContext = NULL;
  168. NbtRegisterEditor.CreateHandler = NULL;
  169. NbtRegisterEditor.DeleteHandler = NULL;
  170. NbtRegisterEditor.ForwardDataHandler = NatOutboundDataHandlerNbt;
  171. NbtRegisterEditor.ReverseDataHandler = NULL;
  172. return NatCreateEditor(&NbtRegisterEditor);
  173. } // NatInitializeEditorNbt
  174. NTSTATUS
  175. NatOutboundDataHandlerNbt(
  176. IN PVOID InterfaceHandle,
  177. IN PVOID SessionHandle,
  178. IN PVOID DataHandle,
  179. IN PVOID EditorContext,
  180. IN PVOID EditorSessionContext,
  181. IN PVOID RecvBuffer,
  182. IN ULONG DataOffset
  183. )
  184. /*++
  185. Routine Description:
  186. This routine is invoked for each datagram sent using NetBT's datagram
  187. service. It replaces the address/port pair in the NetBT header with
  188. the publicly visible address/port pair.
  189. Arguments:
  190. InterfaceHandle - handle to the outgoing NAT_INTERFACE
  191. SessionHandle - the session's NAT_DYNAMIC_MAPPING
  192. DataHandle - the packet's NAT_XLATE_CONTEXT
  193. EditorContext - unused
  194. EditorSessionContext - unused
  195. RecvBuffer - contains the received packet
  196. DataOffset - offset of the protocol data in 'RecvBuffer
  197. Return Value:
  198. NTSTATUS - indicates success/failure
  199. --*/
  200. {
  201. #define RECVBUFFER ((IPRcvBuf*)RecvBuffer)
  202. NBT_PSEUDO_HEADER Header;
  203. PNAT_NBT_MAPPING Mapping;
  204. LONG Offset = (LONG)DataOffset;
  205. ULONG PrivateAddress;
  206. ULONG PublicAddress;
  207. USHORT PublicPort;
  208. UCHAR SourceName[NBT_NAME_LENGTH];
  209. NTSTATUS status;
  210. CALLTRACE(("NatOutboundDataHandlerNbt\n"));
  211. //
  212. // Retrieve the message type
  213. //
  214. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, MessageType, PUCHAR);
  215. if (!RecvBuffer) { return STATUS_UNSUCCESSFUL; }
  216. //
  217. // Only allow DIRECT_{UNIQUE|GROUP} messages, since they're the only ones
  218. // that can be translated.
  219. //
  220. if (*Header.MessageType != NBT_MESSAGE_DIRECT_UNIQUE &&
  221. *Header.MessageType != NBT_MESSAGE_DIRECT_GROUP
  222. ) {
  223. return STATUS_UNSUCCESSFUL;
  224. }
  225. //
  226. // Now retrieve the flags
  227. //
  228. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, Flags, PUCHAR);
  229. if (!RecvBuffer) { return STATUS_UNSUCCESSFUL; }
  230. //
  231. // There's nothing to translate in datagram fragments,
  232. // since they don't include the header.
  233. //
  234. if (!(*Header.Flags & NBT_FLAG_FIRST_FRAGMENT)) {
  235. return STATUS_SUCCESS;
  236. }
  237. //
  238. // Consult the NAT to get the public address/port info
  239. //
  240. NbtRegisterEditor.QueryInfoSession(
  241. SessionHandle,
  242. NULL,
  243. NULL,
  244. NULL,
  245. NULL,
  246. &PublicAddress,
  247. &PublicPort,
  248. NULL
  249. );
  250. //
  251. // Retrieve the source-address and source-port fields
  252. //
  253. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, SourceAddress, PULONG);
  254. if (!RecvBuffer) { return STATUS_UNSUCCESSFUL; }
  255. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, SourcePort, PUSHORT);
  256. if (!RecvBuffer) { return STATUS_UNSUCCESSFUL; }
  257. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, SourceName, PUCHAR);
  258. if (!RecvBuffer) { return STATUS_UNSUCCESSFUL; }
  259. PrivateAddress = *Header.SourceAddress;
  260. //
  261. // Copy the SourceName to a local buffer
  262. //
  263. COPY_FROM_BUFFER(
  264. SourceName,
  265. RECVBUFFER,
  266. NBT_NAME_LENGTH,
  267. (ULONG)(Header.SourceName-RECVBUFFER->ipr_buffer)
  268. );
  269. //
  270. // Attempt to create a mapping for the NBT datagram
  271. //
  272. status =
  273. NatCreateNbtMapping(
  274. InterfaceHandle,
  275. PrivateAddress,
  276. PublicAddress,
  277. SourceName,
  278. NULL,
  279. &Mapping
  280. );
  281. if (!NT_SUCCESS(status)) {
  282. //
  283. // The mapping may already exist; be quiet if we can't create it.
  284. //
  285. return STATUS_SUCCESS;
  286. }
  287. //
  288. // Translate the datagram-header source information
  289. //
  290. NatEditorEditLongSession(
  291. DataHandle, Header.SourceAddress, PublicAddress
  292. );
  293. NatEditorEditShortSession(
  294. DataHandle, Header.SourcePort, PublicPort
  295. );
  296. return STATUS_SUCCESS;
  297. #undef RECVBUFFER
  298. } // NatOutboundDataHandlerNbt
  299. FORWARD_ACTION
  300. NatTranslateNbt(
  301. PNAT_INTERFACE Interfacep,
  302. IP_NAT_DIRECTION Direction,
  303. PNAT_XLATE_CONTEXT Contextp,
  304. IPRcvBuf** InRecvBuffer,
  305. IPRcvBuf** OutRecvBuffer
  306. )
  307. /*++
  308. Routine Description:
  309. This routine is called to translate an incoming NetBT datagram message,
  310. by looking up the destination name in the interface's list of NBT mappings.
  311. Arguments:
  312. Interfacep - the boundary interface over which to translate.
  313. Direction - the direction in which the packet is traveling
  314. Contextp - initialized with context-information for the packet
  315. InRecvBuffer - input buffer-chain
  316. OutRecvBuffer - receives modified buffer-chain.
  317. Return Value:
  318. FORWARD_ACTION - indicates action to take on the packet.
  319. --*/
  320. {
  321. #define RECVBUFFER ((IPRcvBuf*)RecvBuffer)
  322. #define UDPHEADER ((PUDP_HEADER)Contextp->ProtocolHeader)
  323. ULONG Checksum;
  324. ULONG ChecksumDelta = 0;
  325. UCHAR DestinationName[NBT_NAME_LENGTH];
  326. NBT_PSEUDO_HEADER Header;
  327. PNAT_NBT_MAPPING Mapping;
  328. LONG Offset;
  329. ULONG PublicAddress;
  330. IPRcvBuf* RecvBuffer = Contextp->ProtocolRecvBuffer;
  331. TRACE(PER_PACKET, ("NatTranslateNbt\n"));
  332. //
  333. // Initialize the context for accessing UDP data fields
  334. //
  335. Contextp->ProtocolDataOffset =
  336. (ULONG)( (PUCHAR)UDPHEADER - Contextp->ProtocolRecvBuffer->ipr_buffer)
  337. + sizeof(UDP_HEADER);
  338. Offset = (LONG)Contextp->ProtocolDataOffset;
  339. //
  340. // Retrieve the message type
  341. //
  342. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, MessageType, PUCHAR);
  343. if (!RecvBuffer) { return FORWARD; }
  344. //
  345. // Only allow DIRECT_{UNIQUE|GROUP} messages, since they're the only ones
  346. // that can be translated.
  347. //
  348. if (*Header.MessageType != NBT_MESSAGE_DIRECT_UNIQUE &&
  349. *Header.MessageType != NBT_MESSAGE_DIRECT_GROUP
  350. ) {
  351. return FORWARD;
  352. }
  353. //
  354. // Now retrieve the flags
  355. //
  356. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, Flags, PUCHAR);
  357. if (!RecvBuffer) { return FORWARD; }
  358. //
  359. // There's nothing to translate in datagram fragments,
  360. // since they don't include the header.
  361. //
  362. if (!(*Header.Flags & NBT_FLAG_FIRST_FRAGMENT)) {
  363. TRACE(NBT, ("NatTranslateNbt: NBT fragment ignored\n"));
  364. return FORWARD;
  365. }
  366. //
  367. // Retrieve the public address from the IP header
  368. //
  369. PublicAddress = Contextp->DestinationAddress;
  370. //
  371. // Get the destination name from within the NetBIOS header
  372. //
  373. NBT_HEADER_FIELD(RECVBUFFER, &Offset, &Header, DestinationName, PUCHAR);
  374. if (!RecvBuffer) { return FORWARD; }
  375. RtlCopyMemory(DestinationName, Header.DestinationName, NBT_NAME_LENGTH);
  376. //
  377. // Lookup an NBT mapping for the datagram,
  378. // using the public address and the destination name.
  379. //
  380. Mapping =
  381. NatLookupInboundNbtMapping(
  382. Interfacep,
  383. PublicAddress,
  384. DestinationName,
  385. NULL
  386. );
  387. if (!Mapping) { return FORWARD; }
  388. //
  389. // Translate the IP header
  390. //
  391. CHECKSUM_LONG(ChecksumDelta, ~PublicAddress);
  392. Contextp->Header->DestinationAddress = Mapping->PrivateAddress;
  393. CHECKSUM_LONG(ChecksumDelta, Contextp->Header->DestinationAddress);
  394. CHECKSUM_UPDATE(Contextp->Header->Checksum);
  395. if (UDPHEADER->Checksum) {
  396. CHECKSUM_UPDATE(UDPHEADER->Checksum);
  397. }
  398. KeQueryTickCount((PLARGE_INTEGER)&Mapping->LastAccessTime);
  399. *OutRecvBuffer = *InRecvBuffer; *InRecvBuffer = NULL;
  400. return FORWARD;
  401. #undef RECVBUFFER
  402. #undef UDPHEADER
  403. } // NatTranslateNbt