我在C#中实现了TCP打孔。我得到的是,客户端正在向对方发送SYN消息,但它们被丢弃在相对的路由器上。场景是这样的: 客户端:--------路由器:甲-------- --------服务器路由器:乙--------客户:乙
如果客户端:A将SYN数据包发送到Client:B,它将被丢弃在Router:B,这是明显的NAT行为。但是,根据打孔场景,现在如果客户端:B向客户端发送SYN:A,它应该通过路由器上的NAT:A。在我的情况下,路由器:A也会丢弃此数据包。在netstat中,它显示B与SYN_SENT的连接,几秒后,我收到一条消息,如“客户端没有响应。连接失败”
根据我的研究,放弃的原因可能是沉默下降或主动拒绝。如果它是静音丢弃,那么应该打孔,并且B中的SYN应该通过A处的NAT传递。如果它是主动拒绝,路由器:A将从路由器获得通知消息:B关于丢弃和A将关闭这个洞。
问题是我在A处没有收到任何通知消息。(通过路由器日志检查)。 我还尝试了一个已经实现的TCP漏洞pucnhing示例 https://github.com/jasonpang/tcp-holepunching
但我得到了类似的结果。帮我找出解决方案。 我也对在路由器上打孔的超时表示怀疑。
命名空间HolePunching { 公共类HolePunchingClient { private Socket _clientSocket;
private Socket _serverSocket;
private Socket _connectSocket;
//private Socket _serverSocket;
private Socket _holePunchedSocket;
public HolePunchingClient (IPEndPoint localEndPoint)
{
/*For the moment, only TCP Hole Punching is supported*/
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_clientSocket.Bind(localEndPoint);
//_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//_serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
//_serverSocket.Bind(localEndPoint);
}
private void ProcessClientRequest (object sender, DoWorkEventArgs eventArgs)
{
try
{
IPEndPoint iep = (IPEndPoint)eventArgs.Argument;
_connectSocket.Connect(iep);
Console.WriteLine("Connected correctly with: " + iep);
_serverSocket.Close();
_holePunchedSocket = _connectSocket;
Console.WriteLine("\n\n\nException check clientRequest\n\n\n");
}
catch (Exception e)
{
Console.WriteLine("In ProcessClientRequest: " + e.Message);
return;
}
}
private void ProcessServerRequest (object sender, DoWorkEventArgs eventArgs)
{
try
{
_serverSocket.Listen(10);
Socket s = _serverSocket.Accept();
Console.WriteLine("Received connection from: " + s.RemoteEndPoint);
_holePunchedSocket = s;
Console.WriteLine("\n\n\nException check serverRequest\n\n\n");
}
catch (Exception e)
{
Console.WriteLine("In ProcessServerRequest: " + e.Message);
return;
}
}
private void ProcessRequest (object sender, DoWorkEventArgs eventArgs)
{
while (true)
{
byte[] bytes = new byte[2048];
_clientSocket.Receive(bytes);
MessageType messageType = (MessageType) bytes[0];
Console.WriteLine("MessageType received: " + messageType);
switch (messageType)
{
case MessageType.ConnectClient:
byte[] byteAddress = new byte[4];
byte[] bytePort = new byte[2];
Buffer.BlockCopy(bytes, 1, byteAddress, 0, 4);
Buffer.BlockCopy(bytes, 5, bytePort, 0, 2);
IPEndPoint remoteEndPoint = new IPEndPoint(new IPAddress(byteAddress), BitConverter.ToUInt16(bytePort, 0));
Console.WriteLine("HP will be done towards this address: " + remoteEndPoint);
_connectSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_connectSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_connectSocket.Bind(_clientSocket.LocalEndPoint);
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_serverSocket.Bind(_clientSocket.LocalEndPoint);
BackgroundWorker bwClient = new BackgroundWorker();
bwClient.DoWork += ProcessClientRequest;
BackgroundWorker bwServer = new BackgroundWorker();
bwServer.DoWork += ProcessServerRequest;
bwClient.RunWorkerAsync(remoteEndPoint);
bwServer.RunWorkerAsync();
break;
}
}
}
public void Connect (IPEndPoint serverEndPoint)
{
_clientSocket.Connect(serverEndPoint);
_clientSocket.Send(BitConverter.GetBytes((byte)MessageType.Register));
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += ProcessRequest;
bw.RunWorkerAsync();
}
public Socket HolePunch (IPAddress otherAddress)
{
byte[] bytes = new byte[5];
Buffer.BlockCopy(BitConverter.GetBytes((byte)MessageType.RequestClient), 0, bytes, 0, 1);
Buffer.BlockCopy(otherAddress.GetAddressBytes(), 0, bytes, 1, 4);
_clientSocket.Send(bytes);
while (_holePunchedSocket == null)
{
System.Threading.Thread.Sleep(1500);
}
return _holePunchedSocket;
}
}
}
这是我从上面的链接中获取的客户端代码。我在连接到客户端B / A时收到异常消息“没有来自其他客户端的响应。连接失败”。
客户端A和B都运行该程序的相同副本。它们中的任何一个都会向服务器发送请求以与其他客户端连接。服务器将IP-Port组合发送给两者。客户端代码将继续向对方发送连接请求(最终会超时)