mirror of
https://github.com/Empostor/Empostor.git
synced 2026-10-19 15:51:39 +00:00
Port Authentication
This commit is contained in:
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(
|
||||
|
||||
@@ -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>
|
||||
Reference in new issue
Block a user