mirror of
https://github.com/snltty/linker.git
synced 2025-10-21 16:19:27 +08:00
75 lines
2.5 KiB
C#
75 lines
2.5 KiB
C#
using linker.libs.extends;
|
|
using System.Buffers.Binary;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
|
|
namespace linker.tunnel.wanport
|
|
{
|
|
public sealed class TunnelWanPortProtocolStun : ITunnelWanPortProtocol
|
|
{
|
|
public string Name => "Stun Udp";
|
|
public TunnelWanPortType Type => TunnelWanPortType.Stun;
|
|
|
|
public TunnelWanPortProtocolType ProtocolType => TunnelWanPortProtocolType.Udp;
|
|
|
|
public TunnelWanPortProtocolStun()
|
|
{
|
|
}
|
|
|
|
public async Task<TunnelWanPortEndPoint> GetAsync(IPEndPoint server)
|
|
{
|
|
UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork);
|
|
udpClient.Client.Reuse();
|
|
udpClient.Client.WindowsUdpBug();
|
|
try
|
|
{
|
|
byte[] stunRequest = new byte[] {
|
|
0x00, 0x01,
|
|
0x00, 0x00,
|
|
0x21, 0x12, 0xA4, 0x42,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00,0x01,0x00,0x00
|
|
};
|
|
await udpClient.SendAsync(stunRequest, stunRequest.Length);
|
|
|
|
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
|
|
UdpReceiveResult stunResponse = await udpClient.ReceiveAsync();
|
|
|
|
Memory<byte> data = stunResponse.Buffer.AsMemory(20);
|
|
ushort attrTyoe = BitConverter.ToUInt16(data.Span);
|
|
data = data.Slice(2);
|
|
ushort length = BitConverter.ToUInt16(data.Span);
|
|
data = data.Slice(2);
|
|
|
|
//reserved
|
|
data = data.Slice(1);
|
|
|
|
//AddressFamily
|
|
byte afa = data.Span[0];
|
|
data = data.Slice(1);
|
|
|
|
ushort port = (ushort)(BinaryPrimitives.ReadUInt16BigEndian(data.Span) ^ 0x2112);
|
|
data = data.Slice(2);
|
|
|
|
IPAddress ip = null;
|
|
if (afa == 0x01)
|
|
{
|
|
uint value = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(0, 4).Span) ^ 0x2112A442;
|
|
ip = new IPAddress(BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(value)));
|
|
}
|
|
else
|
|
{
|
|
ip = new IPAddress(data.Slice(0, 16).Span);
|
|
}
|
|
|
|
return new TunnelWanPortEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = new IPEndPoint(ip, port) };
|
|
|
|
}
|
|
catch (Exception)
|
|
{
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|