74 lines
2.5 KiB
C#
74 lines
2.5 KiB
C#
using System.Buffers.Binary;
|
|
using System.Net;
|
|
using System.Text;
|
|
using FinalFactory.Rendezvous.Contracts;
|
|
|
|
namespace FinalFactory.Rendezvous.Server.Transport;
|
|
|
|
internal static class LiteNetNatRequestCodec
|
|
{
|
|
private const byte NatMessageProperty = 17;
|
|
private const int TypeIdentifierLength = 8;
|
|
private const int TokenLengthPrefix = NatPunchRequestTokenCodec.EncodedLength + 1;
|
|
// LiteNetLib 2.1.4's private NatIntroduceRequest type ID. The native socket
|
|
// integration test deliberately fails if a package upgrade changes this wire value.
|
|
private static ReadOnlySpan<byte> RequestTypeIdentifier =>
|
|
[0x88, 0xbe, 0x10, 0x26, 0xbf, 0xb1, 0x66, 0x9c];
|
|
|
|
public static bool TryDecode(
|
|
ReadOnlySpan<byte> datagram,
|
|
out IPEndPoint? claimedLocalEndpoint,
|
|
out string? token)
|
|
{
|
|
claimedLocalEndpoint = null;
|
|
token = null;
|
|
if (datagram.Length < 1 + TypeIdentifierLength + 1 + 4 + 2 + 2
|
|
+ NatPunchRequestTokenCodec.EncodedLength
|
|
|| datagram[0] != NatMessageProperty
|
|
|| !datagram.Slice(1, TypeIdentifierLength).SequenceEqual(RequestTypeIdentifier))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int offset = 1 + TypeIdentifierLength;
|
|
int addressLength = datagram[offset++] switch
|
|
{
|
|
0 => 4,
|
|
1 => 16,
|
|
_ => 0,
|
|
};
|
|
int expectedLength = offset + addressLength + 2 + 2
|
|
+ NatPunchRequestTokenCodec.EncodedLength;
|
|
if (addressLength == 0 || datagram.Length != expectedLength)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
IPAddress localAddress = new(datagram.Slice(offset, addressLength));
|
|
offset += addressLength;
|
|
int localPort = BinaryPrimitives.ReadUInt16LittleEndian(datagram.Slice(offset, 2));
|
|
offset += 2;
|
|
int encodedTokenLength = BinaryPrimitives.ReadUInt16LittleEndian(datagram.Slice(offset, 2));
|
|
offset += 2;
|
|
if (localPort == 0 || encodedTokenLength != TokenLengthPrefix)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
ReadOnlySpan<byte> tokenBytes = datagram.Slice(
|
|
offset,
|
|
NatPunchRequestTokenCodec.EncodedLength);
|
|
for (int index = 0; index < tokenBytes.Length; index++)
|
|
{
|
|
if (tokenBytes[index] > 0x7f)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
claimedLocalEndpoint = new(localAddress, localPort);
|
|
token = Encoding.ASCII.GetString(tokenBytes);
|
|
return true;
|
|
}
|
|
}
|