feat: implement authenticated NAT mediator (#11)
quality-gate / quality (push) Successful in 59s
quality-gate / quality (push) Successful in 59s
Closes #11
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user