Client: Improved NetBios over TCP support

This commit is contained in:
Tal Aloni 2020-01-25 21:57:11 +02:00
parent fce8082b52
commit 0a89a84434
2 changed files with 170 additions and 47 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2014-2019 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
/* Copyright (C) 2014-2020 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
@ -44,6 +44,9 @@ namespace SMBLibrary.Client
private List<SMB1Message> m_incomingQueue = new List<SMB1Message>();
private EventWaitHandle m_incomingQueueEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
private SessionPacket m_sessionResponsePacket;
private EventWaitHandle m_sessionResponseEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
private ushort m_userID;
private byte[] m_serverChallenge;
private byte[] m_securityBlob;
@ -64,29 +67,55 @@ namespace SMBLibrary.Client
if (!m_isConnected)
{
m_forceExtendedSecurity = forceExtendedSecurity;
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int port;
if (transport == SMBTransportType.DirectTCPTransport)
{
port = DirectTCPPort;
}
else
if (transport == SMBTransportType.NetBiosOverTCP)
{
port = NetBiosOverTCPPort;
}
try
else
{
m_clientSocket.Connect(serverAddress, port);
port = DirectTCPPort;
}
catch (SocketException)
if (!ConnectSocket(serverAddress, port))
{
return false;
}
ConnectionState state = new ConnectionState();
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
if (transport == SMBTransportType.NetBiosOverTCP)
{
SessionRequestPacket sessionRequest = new SessionRequestPacket();
sessionRequest.CalledName = NetBiosUtils.GetMSNetBiosName("*SMBSERVER", NetBiosSuffix.FileServiceService);
sessionRequest.CallingName = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService);
TrySendPacket(m_clientSocket, sessionRequest);
SessionPacket sessionResponsePacket = WaitForSessionResponsePacket();
if (!(sessionResponsePacket is PositiveSessionResponsePacket))
{
m_clientSocket.Close();
if (!ConnectSocket(serverAddress, port))
{
return false;
}
NameServiceClient nameServiceClient = new NameServiceClient(serverAddress);
string serverName = nameServiceClient.GetServerName();
if (serverName == null)
{
return false;
}
sessionRequest.CalledName = serverName;
TrySendPacket(m_clientSocket, sessionRequest);
sessionResponsePacket = WaitForSessionResponsePacket();
if (!(sessionResponsePacket is PositiveSessionResponsePacket))
{
return false;
}
}
}
bool supportsDialect = NegotiateDialect(m_forceExtendedSecurity);
if (!supportsDialect)
{
@ -100,6 +129,25 @@ namespace SMBLibrary.Client
return m_isConnected;
}
private bool ConnectSocket(IPAddress serverAddress, int port)
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
m_clientSocket.Connect(serverAddress, port);
}
catch (SocketException)
{
return false;
}
ConnectionState state = new ConnectionState();
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
return true;
}
public void Disconnect()
{
if (m_isConnected)
@ -111,13 +159,6 @@ namespace SMBLibrary.Client
private bool NegotiateDialect(bool forceExtendedSecurity)
{
if (m_transport == SMBTransportType.NetBiosOverTCP)
{
SessionRequestPacket sessionRequest = new SessionRequestPacket();
sessionRequest.CalledName = NetBiosUtils.GetMSNetBiosName("*SMBSERVER", NetBiosSuffix.FileServiceService); ;
sessionRequest.CallingName = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService);
TrySendPacket(m_clientSocket, sessionRequest);
}
NegotiateRequest request = new NegotiateRequest();
request.Dialects.Add(NTLanManagerDialect);
@ -440,13 +481,10 @@ namespace SMBLibrary.Client
{
// [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
}
else if (packet is PositiveSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
else if ((packet is PositiveSessionResponsePacket || packet is NegativeSessionResponsePacket) && m_transport == SMBTransportType.NetBiosOverTCP)
{
}
else if (packet is NegativeSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
{
m_clientSocket.Close();
m_isConnected = false;
m_sessionResponsePacket = packet;
m_sessionResponseEventHandle.Set();
}
else if (packet is SessionMessagePacket)
{
@ -503,6 +541,26 @@ namespace SMBLibrary.Client
return null;
}
internal SessionPacket WaitForSessionResponsePacket()
{
const int TimeOut = 5000;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds < TimeOut)
{
if (m_sessionResponsePacket != null)
{
SessionPacket result = m_sessionResponsePacket;
m_sessionResponsePacket = null;
return result;
}
m_sessionResponseEventHandle.WaitOne(100);
}
return null;
}
private void Log(string message)
{
System.Diagnostics.Debug.Print(message);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2017-2019 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
/* Copyright (C) 2017-2020 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
@ -37,6 +37,9 @@ namespace SMBLibrary.Client
private List<SMB2Command> m_incomingQueue = new List<SMB2Command>();
private EventWaitHandle m_incomingQueueEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
private SessionPacket m_sessionResponsePacket;
private EventWaitHandle m_sessionResponseEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
private uint m_messageID = 0;
private SMB2Dialect m_dialect;
private bool m_signingRequired;
@ -56,29 +59,55 @@ namespace SMBLibrary.Client
m_transport = transport;
if (!m_isConnected)
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int port;
if (transport == SMBTransportType.DirectTCPTransport)
{
port = DirectTCPPort;
}
else
if (transport == SMBTransportType.NetBiosOverTCP)
{
port = NetBiosOverTCPPort;
}
try
else
{
m_clientSocket.Connect(serverAddress, port);
port = DirectTCPPort;
}
catch (SocketException)
if (!ConnectSocket(serverAddress, port))
{
return false;
}
ConnectionState state = new ConnectionState();
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
if (transport == SMBTransportType.NetBiosOverTCP)
{
SessionRequestPacket sessionRequest = new SessionRequestPacket();
sessionRequest.CalledName = NetBiosUtils.GetMSNetBiosName("*SMBSERVER", NetBiosSuffix.FileServiceService);
sessionRequest.CallingName = NetBiosUtils.GetMSNetBiosName(Environment.MachineName, NetBiosSuffix.WorkstationService);
TrySendPacket(m_clientSocket, sessionRequest);
SessionPacket sessionResponsePacket = WaitForSessionResponsePacket();
if (!(sessionResponsePacket is PositiveSessionResponsePacket))
{
m_clientSocket.Close();
if (!ConnectSocket(serverAddress, port))
{
return false;
}
NameServiceClient nameServiceClient = new NameServiceClient(serverAddress);
string serverName = nameServiceClient.GetServerName();
if (serverName == null)
{
return false;
}
sessionRequest.CalledName = serverName;
TrySendPacket(m_clientSocket, sessionRequest);
sessionResponsePacket = WaitForSessionResponsePacket();
if (!(sessionResponsePacket is PositiveSessionResponsePacket))
{
return false;
}
}
}
bool supportsDialect = NegotiateDialect();
if (!supportsDialect)
{
@ -92,6 +121,25 @@ namespace SMBLibrary.Client
return m_isConnected;
}
private bool ConnectSocket(IPAddress serverAddress, int port)
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
m_clientSocket.Connect(serverAddress, port);
}
catch (SocketException)
{
return false;
}
ConnectionState state = new ConnectionState();
NBTConnectionReceiveBuffer buffer = state.ReceiveBuffer;
m_clientSocket.BeginReceive(buffer.Buffer, buffer.WriteOffset, buffer.AvailableLength, SocketFlags.None, new AsyncCallback(OnClientSocketReceive), state);
return true;
}
public void Disconnect()
{
if (m_isConnected)
@ -328,13 +376,10 @@ namespace SMBLibrary.Client
{
// [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer
}
else if (packet is PositiveSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
else if ((packet is PositiveSessionResponsePacket || packet is NegativeSessionResponsePacket) && m_transport == SMBTransportType.NetBiosOverTCP)
{
}
else if (packet is NegativeSessionResponsePacket && m_transport == SMBTransportType.NetBiosOverTCP)
{
m_clientSocket.Close();
m_isConnected = false;
m_sessionResponsePacket = packet;
m_sessionResponseEventHandle.Set();
}
else if (packet is SessionMessagePacket)
{
@ -391,6 +436,26 @@ namespace SMBLibrary.Client
return null;
}
internal SessionPacket WaitForSessionResponsePacket()
{
const int TimeOut = 5000;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (stopwatch.ElapsedMilliseconds < TimeOut)
{
if (m_sessionResponsePacket != null)
{
SessionPacket result = m_sessionResponsePacket;
m_sessionResponsePacket = null;
return result;
}
m_sessionResponseEventHandle.WaitOne(100);
}
return null;
}
private void Log(string message)
{
System.Diagnostics.Debug.Print(message);