Files
linker/linker.tunnel/wanport/TunnelWanPortProtocolStun.cs
snltty 8b47c5533c sync
2024-07-02 16:50:59 +08:00

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;
}
}
}