NameServer.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* Copyright (C) 2014 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Net;
  10. using System.Net.Sockets;
  11. using System.Text;
  12. using System.Threading;
  13. using SMBLibrary.NetBios;
  14. using Utilities;
  15. namespace SMBLibrary.Server
  16. {
  17. /// <summary>
  18. /// NetBIOS name service server
  19. /// </summary>
  20. public class NameServer
  21. {
  22. public const int NetBiosNameServicePort = 137;
  23. public const string WorkgroupName = "WORKGROUP";
  24. private IPAddress m_serverAddress;
  25. private UdpClient m_client;
  26. private bool m_listening;
  27. public NameServer(IPAddress serverAddress)
  28. {
  29. m_serverAddress = serverAddress;
  30. }
  31. public void Start()
  32. {
  33. if (!m_listening)
  34. {
  35. m_listening = true;
  36. m_client = new UdpClient(new IPEndPoint(m_serverAddress, NetBiosNameServicePort));
  37. m_client.BeginReceive(ReceiveCallback, null);
  38. ThreadStart threadStart = new ThreadStart(RegisterNetBIOSName);
  39. Thread thread = new Thread(threadStart);
  40. thread.Start();
  41. }
  42. }
  43. public void Stop()
  44. {
  45. m_listening = false;
  46. m_client.Close();
  47. }
  48. private void ReceiveCallback(IAsyncResult result)
  49. {
  50. if (!m_listening)
  51. {
  52. return;
  53. }
  54. IPEndPoint remoteEP = null;
  55. byte[] buffer;
  56. try
  57. {
  58. buffer = m_client.EndReceive(result, ref remoteEP);
  59. m_client.BeginReceive(ReceiveCallback, null);
  60. }
  61. catch (ObjectDisposedException)
  62. {
  63. return;
  64. }
  65. catch (SocketException)
  66. {
  67. return;
  68. }
  69. // Process buffer
  70. if (buffer.Length > NameServicePacketHeader.Length)
  71. {
  72. NameServicePacketHeader header = new NameServicePacketHeader(buffer, 0);
  73. if (header.OpCode == NameServiceOperation.QueryRequest)
  74. {
  75. NameQueryRequest request = null;
  76. try
  77. {
  78. request = new NameQueryRequest(buffer, 0);
  79. }
  80. catch
  81. {
  82. }
  83. if (request != null)
  84. {
  85. if (request.Question.Type == NameRecordType.NB)
  86. {
  87. string name = NetBiosUtils.GetNameFromMSNetBiosName(request.Question.Name);
  88. NetBiosSuffix suffix = (NetBiosSuffix)request.Question.Name[15];
  89. bool nameMatch = String.Equals(name, Environment.MachineName, StringComparison.InvariantCultureIgnoreCase);
  90. if (nameMatch && ((suffix == NetBiosSuffix.WorkstationService) || (suffix == NetBiosSuffix.FileServiceService)))
  91. {
  92. PositiveNameQueryResponse response = new PositiveNameQueryResponse();
  93. response.Header.TransactionID = request.Header.TransactionID;
  94. response.Resource.Name = request.Question.Name;
  95. NameFlags nameFlags = new NameFlags();
  96. response.Addresses.Add(m_serverAddress.GetAddressBytes(), nameFlags);
  97. byte[] responseBytes = response.GetBytes();
  98. m_client.Send(responseBytes, responseBytes.Length, remoteEP);
  99. }
  100. }
  101. else // NBStat
  102. {
  103. NodeStatusResponse response = new NodeStatusResponse();
  104. response.Header.TransactionID = request.Header.TransactionID;
  105. response.Resource.Name = request.Question.Name;
  106. NameFlags nameFlags = new NameFlags();
  107. string name1 = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService);
  108. string name2 = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.FileServiceService);
  109. NameFlags nameFlags3 = new NameFlags();
  110. nameFlags3.WorkGroup = true;
  111. string name3 = NetBiosUtils.GetMSNetBiosName(WorkgroupName, NetBiosSuffix.WorkstationService);
  112. response.Names.Add(name1, nameFlags);
  113. response.Names.Add(name2, nameFlags);
  114. response.Names.Add(name3, nameFlags3);
  115. byte[] responseBytes = response.GetBytes();
  116. try
  117. {
  118. m_client.Send(responseBytes, responseBytes.Length, remoteEP);
  119. }
  120. catch (ObjectDisposedException)
  121. {
  122. }
  123. }
  124. }
  125. }
  126. }
  127. try
  128. {
  129. m_client.BeginReceive(ReceiveCallback, null);
  130. }
  131. catch (ObjectDisposedException)
  132. {
  133. }
  134. catch (SocketException)
  135. {
  136. }
  137. }
  138. private void RegisterNetBIOSName()
  139. {
  140. NameRegistrationRequest request1 = new NameRegistrationRequest(Environment.MachineName, NetBiosSuffix.WorkstationService, m_serverAddress);
  141. NameRegistrationRequest request2 = new NameRegistrationRequest(Environment.MachineName, NetBiosSuffix.FileServiceService, m_serverAddress);
  142. NameRegistrationRequest request3 = new NameRegistrationRequest(WorkgroupName, NetBiosSuffix.WorkstationService, m_serverAddress);
  143. request3.NameFlags.WorkGroup = true;
  144. RegisterName(request1);
  145. RegisterName(request2);
  146. RegisterName(request3);
  147. }
  148. private IPAddress GetLocalSubnetBroadcastAddress(IPAddress address)
  149. {
  150. byte[] broadcastAddress = m_serverAddress.GetAddressBytes();
  151. broadcastAddress[3] = 0xFF;
  152. return new IPAddress(broadcastAddress);
  153. }
  154. private void RegisterName(NameRegistrationRequest request)
  155. {
  156. byte[] packet = request.GetBytes();
  157. IPAddress broadcastAddress = GetLocalSubnetBroadcastAddress(m_serverAddress);
  158. IPEndPoint broadcastEP = new IPEndPoint(broadcastAddress, NetBiosNameServicePort);
  159. for (int index = 0; index < 4; index++)
  160. {
  161. try
  162. {
  163. m_client.Send(packet, packet.Length, broadcastEP);
  164. }
  165. catch (ObjectDisposedException)
  166. {
  167. }
  168. if (index < 3)
  169. {
  170. System.Threading.Thread.Sleep(250);
  171. }
  172. }
  173. }
  174. }
  175. }