Port Authentication

This commit is contained in:
FangkuaiYa committed 2026-08-13 20:53:54 +08:00
1 parent 715de1002d
commit 48ba15ca09
4 files changed
+72 -14

No files matched your search

@@ -199,7 +199,7 @@ namespace Empostor.Server.Net.Manager
}
}
// Fallback: match by IP
// Fallback: match by IP (used by shared/default delta ports)
if (authInfo == null && clientIp != null)
{
authInfo = _authCache.FindByIp(clientIp);
@@ -210,6 +210,21 @@ namespace Empostor.Server.Net.Manager
"#{Id} {Name} │ {Ip} │ {Location} │ {Lang} │ {Platform} │ FC {FriendCode} │ {HashPuid}{Reactor}",
id, name, NormalizeIp(clientIp), locationStr, lang, platformStr, friendCode ?? "unknown", HashPuid(authInfo.ProductUserId), reactorStr);
}
else if (deltaPort > 0 && !_portPool.IsSharingLastPort)
{
// Dynamic delta mode: an active port that has no auth info
// bound to it (neither by port nor by IP) is an
// unauthenticated UDP connection — reject it instead of
// admitting an anonymous client.
// When the pool is down to its last port (shared mode) we
// skip this check: everyone shares one port and matches by
// IP, so requiring a per-port binding would block players.
_logger.LogWarning(
"#{Id} {Name} │ no auth │ port {Port} │ {Ip} │ rejecting unauthenticated UDP connection",
id, name, deltaPort, NormalizeIp(clientIp));
await connection.CustomDisconnectAsync(DisconnectReason.Custom, "Authentication required. Please rejoin through the game server.");
return;
}
else
{
_logger.LogWarning(
+27 -13
View File
@@ -197,20 +197,34 @@ namespace Empostor.Server.Net
private async ValueTask OnNewConnection(NewConnectionEventArgs e, int port)
{
// Deserialize handshake without matchmakerToken
Empostor.Api.Net.Messages.C2S.HandshakeC2S.Deserialize(
e.HandshakeData,
out var clientVersion,
out var name,
out var language,
out var chatMode,
out var platformSpecificData);
HazelConnection? connection = null;
var connection = new HazelConnection(e.Connection, _connectionLogger, _antiCheatOptions);
await _eventManager.CallAsync(new ClientConnectionEvent(connection, e.HandshakeData));
await _clientManager.RegisterConnectionAsync(
connection, name, clientVersion, language, chatMode, platformSpecificData,
deltaPort: port);
try
{
// Deserialize handshake without matchmakerToken
Empostor.Api.Net.Messages.C2S.HandshakeC2S.Deserialize(
e.HandshakeData,
out var clientVersion,
out var name,
out var language,
out var chatMode,
out var platformSpecificData);
connection = new HazelConnection(e.Connection, _connectionLogger, _antiCheatOptions);
await _eventManager.CallAsync(new ClientConnectionEvent(connection, e.HandshakeData));
await _clientManager.RegisterConnectionAsync(
connection, name, clientVersion, language, chatMode, platformSpecificData,
deltaPort: port);
}
catch (Exception ex)
{
// Malformed / unauthenticated UDP handshake. Dispose the
// underlying connection so an attacker's socket is closed and
// removed from the listener — never leave it half-initialised.
_logger.LogDebug(ex, "Rejecting invalid UDP handshake on port {Port}", port);
connection?.DisposeInnerConnection();
e.Connection.Dispose();
}
}
private void OnPortReturned(int port)
@@ -47,6 +47,14 @@ public sealed class PortPoolService : IDisposable
}
}
/// <summary>
/// Gets a value indicating whether the pool has only one port left and
/// is therefore sharing that last port across all new players. In this
/// mode authentication falls back to IP matching, so the server should
/// not hard-require a per-port auth binding.
/// </summary>
public bool IsSharingLastPort => IsEnabled && _availablePorts.Count <= 1;
/// <summary>
/// Invoked when a port is returned to the pool (via disconnect or timeout expiry).
/// Subscribers should stop the delta listener and close firewall rules.
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<DeleteExistingFiles>false</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>
<ProjectGuid>1b0390af-a4f3-4fe4-b093-708b0135c0b3</ProjectGuid>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>