From 7a227d7d3b62ded9bf539da69b5a577f9d470ffe Mon Sep 17 00:00:00 2001 From: Andrew Steinborn <git@steinborn.me> Date: Sun, 23 May 2021 07:18:50 -0400 Subject: [PATCH] Add Unix domain socket support (#5611) Tested-by: Mariell Hoversholm <proximyst@proximyst.com> Reviewed-by: Mariell Hoversholm <proximyst@proximyst.com> --- .../Add-Unix-domain-socket-support.patch | 141 ++++++++++++++++++ .../Add-Velocity-IP-Forwarding-Support.patch | 7 +- ...ent-to-allow-plugins-to-handle-clien.patch | 7 +- 3 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 Spigot-Server-Patches/Add-Unix-domain-socket-support.patch diff --git a/Spigot-Server-Patches/Add-Unix-domain-socket-support.patch b/Spigot-Server-Patches/Add-Unix-domain-socket-support.patch new file mode 100644 index 0000000000..1a2c0f6c96 --- /dev/null +++ b/Spigot-Server-Patches/Add-Unix-domain-socket-support.patch @@ -0,0 +1,141 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Steinborn <git@steinborn.me> +Date: Tue, 11 May 2021 17:39:22 -0400 +Subject: [PATCH] Add Unix domain socket support + +For Windows and ARM support, JEP-380 is required: +https://inside.java/2021/02/03/jep380-unix-domain-sockets-channels/ +This will be possible as of the Minecraft 1.17 Java version bump. + +Tested-by: Mariell Hoversholm <proximyst@proximyst.com> +Reviewed-by: Mariell Hoversholm <proximyst@proximyst.com> + +diff --git a/src/main/java/net/minecraft/network/NetworkManager.java b/src/main/java/net/minecraft/network/NetworkManager.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/network/NetworkManager.java ++++ b/src/main/java/net/minecraft/network/NetworkManager.java +@@ -0,0 +0,0 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> { + // Spigot Start + public SocketAddress getRawAddress() + { ++ // Paper start - this can be nullable in the case of a Unix domain socket, so if it is, fake something ++ if (this.channel.remoteAddress() == null) { ++ return new java.net.InetSocketAddress(java.net.InetAddress.getLoopbackAddress(), 0); ++ } ++ // Paper end + return this.channel.remoteAddress(); + } + // Spigot End +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer + this.i(dedicatedserverproperties.enforceWhitelist); + // this.saveData.setGameType(dedicatedserverproperties.gamemode); // CraftBukkit - moved to world loading + DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode); ++ // Paper start - Unix domain socket support ++ java.net.SocketAddress bindAddress; ++ if (this.getServerIp().startsWith("unix:")) { ++ if (!io.netty.channel.epoll.Epoll.isAvailable()) { ++ DedicatedServer.LOGGER.fatal("**** INVALID CONFIGURATION!"); ++ DedicatedServer.LOGGER.fatal("You are trying to use a Unix domain socket but you're not on a supported OS."); ++ return false; ++ } else if (!com.destroystokyo.paper.PaperConfig.velocitySupport && !org.spigotmc.SpigotConfig.bungee) { ++ DedicatedServer.LOGGER.fatal("**** INVALID CONFIGURATION!"); ++ DedicatedServer.LOGGER.fatal("Unix domain sockets require IPs to be forwarded from a proxy."); ++ return false; ++ } ++ bindAddress = new io.netty.channel.unix.DomainSocketAddress(this.getServerIp().substring("unix:".length())); ++ } else { + InetAddress inetaddress = null; + + if (!this.getServerIp().isEmpty()) { +@@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer + if (this.getPort() < 0) { + this.setPort(dedicatedserverproperties.serverPort); + } ++ bindAddress = new java.net.InetSocketAddress(inetaddress, this.getPort()); ++ } ++ // Paper end + + this.P(); + DedicatedServer.LOGGER.info("Starting Minecraft server on {}:{}", this.getServerIp().isEmpty() ? "*" : this.getServerIp(), this.getPort()); + + try { +- this.getServerConnection().a(inetaddress, this.getPort()); ++ this.getServerConnection().bind(bindAddress); // Paper - Unix domain socket support + } catch (IOException ioexception) { + DedicatedServer.LOGGER.warn("**** FAILED TO BIND TO PORT!"); + DedicatedServer.LOGGER.warn("The exception was: {}", ioexception.toString()); +diff --git a/src/main/java/net/minecraft/server/network/HandshakeListener.java b/src/main/java/net/minecraft/server/network/HandshakeListener.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/network/HandshakeListener.java ++++ b/src/main/java/net/minecraft/server/network/HandshakeListener.java +@@ -0,0 +0,0 @@ public class HandshakeListener implements PacketHandshakingInListener { + this.c.setProtocol(EnumProtocol.LOGIN); + // CraftBukkit start - Connection throttle + try { ++ if (!(this.c.channel.localAddress() instanceof io.netty.channel.unix.DomainSocketAddress)) { // Paper - the connection throttle is useless when you have a Unix domain socket + long currentTime = System.currentTimeMillis(); + long connectionThrottle = this.b.server.getConnectionThrottle(); + InetAddress address = ((java.net.InetSocketAddress) this.c.getSocketAddress()).getAddress(); +@@ -0,0 +0,0 @@ public class HandshakeListener implements PacketHandshakingInListener { + } + } + } ++ } // Paper - add closing bracket for if check above + } catch (Throwable t) { + org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t); + } +@@ -0,0 +0,0 @@ public class HandshakeListener implements PacketHandshakingInListener { + //if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above! + String[] split = packethandshakinginsetprotocol.hostname.split("\00"); + if ( ( split.length == 3 || split.length == 4 ) && ( BYPASS_HOSTCHECK || HOST_PATTERN.matcher( split[1] ).matches() ) ) { // Paper ++ // Paper start - Unix domain socket support ++ java.net.SocketAddress socketAddress = c.getSocketAddress(); + packethandshakinginsetprotocol.hostname = split[0]; +- c.socketAddress = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) c.getSocketAddress()).getPort()); ++ c.socketAddress = new java.net.InetSocketAddress(split[1], socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0); ++ // Paper end + c.spoofedUUID = com.mojang.util.UUIDTypeAdapter.fromString( split[2] ); + } else + { +diff --git a/src/main/java/net/minecraft/server/network/ServerConnection.java b/src/main/java/net/minecraft/server/network/ServerConnection.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConnection.java ++++ b/src/main/java/net/minecraft/server/network/ServerConnection.java +@@ -0,0 +0,0 @@ public class ServerConnection { + this.c = true; + } + ++ // Paper start + public void a(@Nullable InetAddress inetaddress, int i) throws IOException { ++ bind(new java.net.InetSocketAddress(inetaddress, i)); ++ } ++ public void bind(java.net.SocketAddress address) throws IOException { ++ // Paper end + List list = this.listeningChannels; + + synchronized (this.listeningChannels) { +@@ -0,0 +0,0 @@ public class ServerConnection { + LazyInitVar lazyinitvar; + + if (Epoll.isAvailable() && this.e.l()) { ++ if (address instanceof io.netty.channel.unix.DomainSocketAddress) { ++ oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class; ++ } else { + oclass = EpollServerSocketChannel.class; ++ } + lazyinitvar = ServerConnection.b; + ServerConnection.LOGGER.info("Using epoll channel type"); + } else { +@@ -0,0 +0,0 @@ public class ServerConnection { + ((NetworkManager) object).setPacketListener(new HandshakeListener(ServerConnection.this.e, (NetworkManager) object)); + io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper + } +- }).group((EventLoopGroup) lazyinitvar.a()).localAddress(inetaddress, i)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit ++ }).group((EventLoopGroup) lazyinitvar.a()).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper + } + } + diff --git a/Spigot-Server-Patches/Add-Velocity-IP-Forwarding-Support.patch b/Spigot-Server-Patches/Add-Velocity-IP-Forwarding-Support.patch index f06769b490..d75f2ceb46 100644 --- a/Spigot-Server-Patches/Add-Velocity-IP-Forwarding-Support.patch +++ b/Spigot-Server-Patches/Add-Velocity-IP-Forwarding-Support.patch @@ -268,7 +268,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; + } + -+ this.networkManager.socketAddress = new java.net.InetSocketAddress(com.destroystokyo.paper.proxy.VelocityProxy.readAddress(buf), ((java.net.InetSocketAddress) this.networkManager.getSocketAddress()).getPort()); ++ java.net.SocketAddress listening = this.networkManager.getSocketAddress(); ++ int port = 0; ++ if (listening instanceof java.net.InetSocketAddress) { ++ port = ((java.net.InetSocketAddress) listening).getPort(); ++ } ++ this.networkManager.socketAddress = new java.net.InetSocketAddress(com.destroystokyo.paper.proxy.VelocityProxy.readAddress(buf), port); + + this.setGameProfile(com.destroystokyo.paper.proxy.VelocityProxy.createProfile(buf)); + diff --git a/Spigot-Server-Patches/Add-handshake-event-to-allow-plugins-to-handle-clien.patch b/Spigot-Server-Patches/Add-handshake-event-to-allow-plugins-to-handle-clien.patch index a512e8e811..c4e6764d91 100644 --- a/Spigot-Server-Patches/Add-handshake-event-to-allow-plugins-to-handle-clien.patch +++ b/Spigot-Server-Patches/Add-handshake-event-to-allow-plugins-to-handle-clien.patch @@ -27,8 +27,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + boolean handledByEvent = false; + // Try and handle the handshake through the event + if (com.destroystokyo.paper.event.player.PlayerHandshakeEvent.getHandlerList().getRegisteredListeners().length != 0) { // Hello? Can you hear me? -+ java.net.InetSocketAddress socketAddress = (java.net.InetSocketAddress) this.getNetworkManager().socketAddress; -+ com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packethandshakinginsetprotocol.hostname, socketAddress.getAddress().getHostAddress(), !proxyLogicEnabled); ++ java.net.SocketAddress socketAddress = this.getNetworkManager().socketAddress; ++ String hostnameOfRemote = socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getHostString() : InetAddress.getLoopbackAddress().getHostAddress(); ++ com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packethandshakinginsetprotocol.hostname, hostnameOfRemote, !proxyLogicEnabled); + if (event.callEvent()) { + // If we've failed somehow, let the client know so and go no further. + if (event.isFailed()) { @@ -39,7 +40,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + if (event.getServerHostname() != null) packethandshakinginsetprotocol.hostname = event.getServerHostname(); -+ if (event.getSocketAddressHostname() != null) this.getNetworkManager().socketAddress = new java.net.InetSocketAddress(event.getSocketAddressHostname(), socketAddress.getPort()); ++ if (event.getSocketAddressHostname() != null) this.getNetworkManager().socketAddress = new java.net.InetSocketAddress(event.getSocketAddressHostname(), socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0); + this.getNetworkManager().spoofedUUID = event.getUniqueId(); + this.getNetworkManager().spoofedProfile = gson.fromJson(event.getPropertiesJson(), com.mojang.authlib.properties.Property[].class); + handledByEvent = true; // Hooray, we did it!