From a47649bf93eb72885c1a563f2ca7b2840b3a38df Mon Sep 17 00:00:00 2001 From: amy <144570677+amyavi@users.noreply.github.com> Date: Sun, 29 Mar 2026 21:02:12 -0300 Subject: [PATCH] Fix unix domain socket support --- .../server/PaperServerListPingEvent.java | 2 +- .../paper/network/NetworkClient.java | 10 ++++++ .../main/java/org/bukkit/entity/Player.java | 13 +++++++- .../player/AsyncPlayerPreLoginEvent.java | 23 ++++++++++--- .../bukkit/event/player/PlayerLoginEvent.java | 29 ++++++++++++++--- .../event/server/ServerListPingEvent.java | 32 +++++++++++++------ .../network/LegacyQueryHandler.java.patch | 2 +- .../ServerLoginPacketListenerImpl.java.patch | 2 +- .../network/PaperLegacyStatusClient.java | 16 +++++++--- .../paper/network/PaperNetworkClient.java | 10 +++++- .../HorriblePlayerLoginEventHack.java | 3 +- .../craftbukkit/entity/CraftPlayer.java | 9 ++++-- 12 files changed, 121 insertions(+), 30 deletions(-) diff --git a/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java b/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java index 15b12abe17da..abb0262a2a0a 100644 --- a/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java +++ b/paper-api/src/main/java/com/destroystokyo/paper/event/server/PaperServerListPingEvent.java @@ -58,7 +58,7 @@ public class PaperServerListPingEvent extends ServerListPingEvent implements Can @ApiStatus.Internal public PaperServerListPingEvent(@NotNull StatusClient client, @NotNull net.kyori.adventure.text.Component motd, int numPlayers, int maxPlayers, @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon) { - super("", client.getAddress().getAddress(), motd, numPlayers, maxPlayers); + super("", client.getSocketAddress(), motd, numPlayers, maxPlayers); this.client = client; this.numPlayers = numPlayers; this.version = version; diff --git a/paper-api/src/main/java/com/destroystokyo/paper/network/NetworkClient.java b/paper-api/src/main/java/com/destroystokyo/paper/network/NetworkClient.java index 207929a2303a..46a7d4beed06 100644 --- a/paper-api/src/main/java/com/destroystokyo/paper/network/NetworkClient.java +++ b/paper-api/src/main/java/com/destroystokyo/paper/network/NetworkClient.java @@ -1,6 +1,7 @@ package com.destroystokyo.paper.network; import java.net.InetSocketAddress; +import java.net.SocketAddress; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -15,6 +16,15 @@ public interface NetworkClient { * * @return The client's socket address */ + SocketAddress getSocketAddress(); + + /** + * Returns an instance of {@link InetSocketAddress} associated with the + * client's socket address. + * + * @return The client's {@link InetSocketAddress}, or the loopback address + * if this is a Unix socket connection + */ InetSocketAddress getAddress(); /** diff --git a/paper-api/src/main/java/org/bukkit/entity/Player.java b/paper-api/src/main/java/org/bukkit/entity/Player.java index 26d9139886d8..f6446d4fb71a 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Player.java +++ b/paper-api/src/main/java/org/bukkit/entity/Player.java @@ -7,6 +7,7 @@ import io.papermc.paper.math.Position; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.time.Duration; import java.time.Instant; import java.util.Collection; @@ -269,7 +270,17 @@ default net.kyori.adventure.identity.Identity identity() { * @return the player's address */ @Nullable - public InetSocketAddress getAddress(); + SocketAddress getSocketAddress(); + + /** + * Returns an instance of {@link InetSocketAddress} associated with the + * player's socket address. + * + * @return the player's {@link InetSocketAddress}, or the loopback address + * if the player is connecting through a Unix socket + */ + @Nullable + InetSocketAddress getAddress(); // Paper start - Add API to get player's proxy address /** diff --git a/paper-api/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/paper-api/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java index 473d12cb22f3..de045e33ee70 100644 --- a/paper-api/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java @@ -1,6 +1,8 @@ package org.bukkit.event.player; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.UUID; import com.destroystokyo.paper.profile.PlayerProfile; import net.kyori.adventure.text.Component; @@ -31,7 +33,7 @@ public class AsyncPlayerPreLoginEvent extends Event { private static final HandlerList HANDLER_LIST = new HandlerList(); private final InetAddress ipAddress; - private final InetAddress rawAddress; + private final SocketAddress rawAddress; private final String hostname; private final boolean transferred; private Result result; @@ -65,11 +67,11 @@ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetA @ApiStatus.Internal @Deprecated(forRemoval = true) public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile) { - this(name, ipAddress, rawAddress, uniqueId, transferred, profile, "", null); + this(name, ipAddress, new InetSocketAddress(rawAddress, 0), uniqueId, transferred, profile, "", null); } @ApiStatus.Internal - public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @NotNull String hostname, final PlayerLoginConnection playerLoginConnection) { + public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final SocketAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @NotNull String hostname, final PlayerLoginConnection playerLoginConnection) { super(true); this.result = Result.ALLOWED; this.message = Component.empty(); @@ -278,13 +280,24 @@ public void setPlayerProfile(@NotNull com.destroystokyo.paper.profile.PlayerProf this.profile = profile; } + /** + * Gets the raw socket address of the player logging in + * @return The socket address + */ + @NotNull + public SocketAddress getRawSocketAddress() { + return this.rawAddress; + } + /** * Gets the raw address of the player logging in - * @return The address + * @return The address, or the loopback address if the player is connecting + * through a Unix socket */ @NotNull public InetAddress getRawAddress() { - return this.rawAddress; + if (this.rawAddress instanceof InetSocketAddress inet) return inet.getAddress(); + return InetAddress.getLoopbackAddress(); } /** diff --git a/paper-api/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java b/paper-api/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java index 5ff4ca79272f..1a8fef023e6a 100644 --- a/paper-api/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/player/PlayerLoginEvent.java @@ -1,6 +1,8 @@ package org.bukkit.event.player; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import io.papermc.paper.event.connection.PlayerConnectionValidateLoginEvent; import org.bukkit.Warning; import net.kyori.adventure.text.Component; @@ -32,18 +34,23 @@ public class PlayerLoginEvent extends PlayerEvent { private final String hostname; private final InetAddress address; - private final InetAddress realAddress; + private final SocketAddress realAddress; private Result result = Result.ALLOWED; private Component message = Component.empty(); @ApiStatus.Internal - public PlayerLoginEvent(@NotNull final Player player, @NotNull final String hostname, @NotNull final InetAddress address, final @NotNull InetAddress realAddress) { + public PlayerLoginEvent(@NotNull final Player player, @NotNull final String hostname, @NotNull final InetAddress address, final @NotNull SocketAddress realAddress) { super(player); this.hostname = hostname; this.address = address; this.realAddress = realAddress; } + @ApiStatus.Internal + public PlayerLoginEvent(@NotNull final Player player, @NotNull final String hostname, @NotNull final InetAddress address, final @NotNull InetAddress realAddress) { + this(player, hostname, address, new InetSocketAddress(address, 0)); + } + @ApiStatus.Internal public PlayerLoginEvent(@NotNull final Player player, @NotNull final String hostname, @NotNull final InetAddress address) { this(player, hostname, address, address); @@ -88,16 +95,30 @@ public InetAddress getAddress() { return this.address; } + + /** + * Gets the connection socket address of this player, regardless of whether + * it has been spoofed or not. + * + * @return the player's connection socket address + */ + @NotNull + public SocketAddress getRealSocketAddress() { + return this.realAddress; + } + /** * Gets the connection address of this player, regardless of whether it has * been spoofed or not. * - * @return the player's connection address + * @return the player's connection address, or the loopback address if the + * player is connecting through a Unix socket * @see #getAddress() */ @NotNull public InetAddress getRealAddress() { - return this.realAddress; + if (this.realAddress instanceof InetSocketAddress inet) return inet.getAddress(); + return InetAddress.getLoopbackAddress(); } /** diff --git a/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java b/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java index fdc39724354f..e208da275693 100644 --- a/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java +++ b/paper-api/src/main/java/org/bukkit/event/server/ServerListPingEvent.java @@ -2,6 +2,8 @@ import com.google.common.base.Preconditions; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Iterator; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; @@ -28,14 +30,14 @@ public class ServerListPingEvent extends ServerEvent implements Iterable private static final HandlerList HANDLER_LIST = new HandlerList(); private final String hostname; - private final InetAddress address; + private final SocketAddress address; private final int numPlayers; private Component motd; private int maxPlayers; @ApiStatus.Internal @Deprecated(forRemoval = true) - public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int numPlayers, final int maxPlayers) { + public ServerListPingEvent(@NotNull final String hostname, @NotNull final SocketAddress address, @NotNull final String motd, final int numPlayers, final int maxPlayers) { super(true); Preconditions.checkArgument(numPlayers >= 0, "Cannot have negative number of players online", numPlayers); this.hostname = hostname; @@ -47,7 +49,7 @@ public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAd @ApiStatus.Internal @Deprecated(forRemoval = true) - protected ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final String motd, final int maxPlayers) { + protected ServerListPingEvent(@NotNull final String hostname, @NotNull final SocketAddress address, @NotNull final String motd, final int maxPlayers) { super(true); this.numPlayers = MAGIC_PLAYER_COUNT; this.hostname = hostname; @@ -59,11 +61,11 @@ protected ServerListPingEvent(@NotNull final String hostname, @NotNull final Ine @ApiStatus.Internal @Deprecated(forRemoval = true) public ServerListPingEvent(@NotNull final InetAddress address, @NotNull final Component motd, final int numPlayers, final int maxPlayers) { - this("", address, motd, numPlayers, maxPlayers); + this("", new InetSocketAddress(address, 0), motd, numPlayers, maxPlayers); } @ApiStatus.Internal - public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAddress address, @NotNull final Component motd, final int numPlayers, final int maxPlayers) { + public ServerListPingEvent(@NotNull final String hostname, @NotNull final SocketAddress address, @NotNull final Component motd, final int numPlayers, final int maxPlayers) { super(true); this.hostname = hostname; this.address = address; @@ -75,7 +77,7 @@ public ServerListPingEvent(@NotNull final String hostname, @NotNull final InetAd @ApiStatus.Internal @Deprecated(forRemoval = true) protected ServerListPingEvent(@NotNull final InetAddress address, @NotNull final Component motd, final int maxPlayers) { - this("", address, motd, maxPlayers); + this("", new InetSocketAddress(address, 0), motd, maxPlayers); } /* @@ -84,7 +86,7 @@ protected ServerListPingEvent(@NotNull final InetAddress address, @NotNull final * count. */ @ApiStatus.Internal - protected ServerListPingEvent(final @NotNull String hostname, final @NotNull InetAddress address, final @NotNull Component motd, final int maxPlayers) { + protected ServerListPingEvent(final @NotNull String hostname, final @NotNull SocketAddress address, final @NotNull Component motd, final int maxPlayers) { this.numPlayers = MAGIC_PLAYER_COUNT; this.hostname = hostname; this.address = address; @@ -103,14 +105,26 @@ public String getHostname() { return this.hostname; } + /** + * Gets the socket address the ping is coming from. + * + * @return the socket address + */ + @NotNull + public SocketAddress getSocketAddress() { + return this.address; + } + /** * Get the address the ping is coming from. * - * @return the address + * @return the socket address, or the loopback address if the ping is + * coming from a Unix socket */ @NotNull public InetAddress getAddress() { - return this.address; + if (this.address instanceof InetSocketAddress inet) return inet.getAddress(); + return InetAddress.getLoopbackAddress(); } /** diff --git a/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch b/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch index 821b387c4698..1b2e073ffa04 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/LegacyQueryHandler.java.patch @@ -36,7 +36,7 @@ - String string = createVersion0Response(this.server); + LOGGER.debug("Ping: (<1.3.x) from {}", net.minecraft.server.MinecraftServer.getServer().logIPs() ? socketAddress : ""); // Paper - Respect logIPs option + // Paper start - Call PaperServerListPingEvent and use results -+ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), (java.net.InetSocketAddress) socketAddress, 39, null); ++ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(net.minecraft.server.MinecraftServer.getServer(), socketAddress, 39, null); + if (event == null) { + ctx.close(); + byteBuf.release(); diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch index f7a4161d565d..355df4500199 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch @@ -239,7 +239,7 @@ + final org.bukkit.craftbukkit.CraftServer server = ServerLoginPacketListenerImpl.this.server.server; + + // Paper start - Add more fields to AsyncPlayerPreLoginEvent -+ final InetAddress rawAddress = ((InetSocketAddress) this.connection.channel.remoteAddress()).getAddress(); ++ final SocketAddress rawAddress = this.connection.channel.remoteAddress(); + com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitCopy(gameprofile); // Paper - setPlayerProfileAPI + AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, this.transferred, profile, this.connection.hostname, this.paperLoginConnection); // Paper + server.getPluginManager().callEvent(asyncEvent); diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java index cc54b1c20798..dd5e6124acf6 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java @@ -6,27 +6,35 @@ import net.minecraft.server.MinecraftServer; import org.apache.commons.lang3.StringUtils; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import javax.annotation.Nullable; public final class PaperLegacyStatusClient implements StatusClient { - private final InetSocketAddress address; + private final SocketAddress address; private final int protocolVersion; @Nullable private final InetSocketAddress virtualHost; - private PaperLegacyStatusClient(InetSocketAddress address, int protocolVersion, @Nullable InetSocketAddress virtualHost) { + private PaperLegacyStatusClient(SocketAddress address, int protocolVersion, @Nullable InetSocketAddress virtualHost) { this.address = address; this.protocolVersion = protocolVersion; this.virtualHost = virtualHost; } @Override - public InetSocketAddress getAddress() { + public SocketAddress getSocketAddress() { return this.address; } + @Override + public InetSocketAddress getAddress() { + if (this.address instanceof InetSocketAddress inet) return inet; + return new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + } + @Override public int getProtocolVersion() { return this.protocolVersion; @@ -44,7 +52,7 @@ public boolean isLegacy() { } public static PaperServerListPingEvent processRequest(MinecraftServer server, - InetSocketAddress address, int protocolVersion, @Nullable InetSocketAddress virtualHost) { + SocketAddress address, int protocolVersion, @Nullable InetSocketAddress virtualHost) { PaperServerListPingEvent event = new PaperServerListPingEventImpl(server, new PaperLegacyStatusClient(address, protocolVersion, virtualHost), Byte.MAX_VALUE, null); diff --git a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java index 0d2fcedf15a9..0c95a090dd40 100644 --- a/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java +++ b/paper-server/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java @@ -1,6 +1,8 @@ package com.destroystokyo.paper.network; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import javax.annotation.Nullable; import net.minecraft.network.Connection; @@ -13,9 +15,15 @@ public class PaperNetworkClient implements NetworkClient { this.networkManager = networkManager; } + @Override + public SocketAddress getSocketAddress() { + return this.networkManager.getRemoteAddress(); + } + @Override public InetSocketAddress getAddress() { - return (InetSocketAddress) this.networkManager.getRemoteAddress(); + if (this.networkManager.getRemoteAddress() instanceof InetSocketAddress inet) return inet; + return new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); } @Override diff --git a/paper-server/src/main/java/io/papermc/paper/connection/HorriblePlayerLoginEventHack.java b/paper-server/src/main/java/io/papermc/paper/connection/HorriblePlayerLoginEventHack.java index 6f8b41a17238..a9c12fdeb184 100644 --- a/paper-server/src/main/java/io/papermc/paper/connection/HorriblePlayerLoginEventHack.java +++ b/paper-server/src/main/java/io/papermc/paper/connection/HorriblePlayerLoginEventHack.java @@ -3,6 +3,7 @@ import com.mojang.authlib.GameProfile; import com.mojang.logging.LogUtils; import io.papermc.paper.adventure.PaperAdventure; +import java.net.InetSocketAddress; import java.util.HashSet; import java.util.Optional; import java.util.Set; @@ -84,7 +85,7 @@ public static boolean warnReenterConfiguration(final Connection connection) { connection.handledLegacyLoginEvent = true; CraftPlayer horribleBukkitPlayer = player.getBukkitEntity(); - PlayerLoginEvent event = new PlayerLoginEvent(horribleBukkitPlayer, connection.hostname, ((java.net.InetSocketAddress) connection.getRemoteAddress()).getAddress(), ((java.net.InetSocketAddress) connection.channel.remoteAddress()).getAddress()); + PlayerLoginEvent event = new PlayerLoginEvent(horribleBukkitPlayer, connection.hostname, ((java.net.InetSocketAddress) connection.getRemoteAddress()).getAddress(), connection.channel.remoteAddress()); event.disallow(result.result(), PaperAdventure.asAdventure(result.message())); event.callEvent(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index d86ebc4cd182..a294c2f2b5b2 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -318,10 +318,15 @@ public boolean isConnected() { // Paper end @Override - public InetSocketAddress getAddress() { + public SocketAddress getSocketAddress() { if (this.getHandle().connection == null) return null; - SocketAddress addr = this.getHandle().connection.getRemoteAddress(); + return this.getHandle().connection.getRemoteAddress(); + } + + @Override + public InetSocketAddress getAddress() { + SocketAddress addr = this.getSocketAddress(); if (addr instanceof InetSocketAddress) { return (InetSocketAddress) addr; } else {