From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Andrew Steinborn 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 Reviewed-by: Mariell Hoversholm diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java index c0e822386bdc3724ca1f24a0ed4fb60e96d9b9eb..34728cebe2de88e0a935707ea9969e068c0f6d7e 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -219,6 +219,20 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface this.setEnforceWhitelist(dedicatedserverproperties.enforceWhitelist); // this.worldData.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.getLocalIp().startsWith("unix:")) { + if (!io.netty.channel.epoll.Epoll.isAvailable()) { + DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); + DedicatedServer.LOGGER.error("You are trying to use a Unix domain socket but you're not on a supported OS."); + return false; + } else if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled && !org.spigotmc.SpigotConfig.bungee) { + DedicatedServer.LOGGER.error("**** INVALID CONFIGURATION!"); + DedicatedServer.LOGGER.error("Unix domain sockets require IPs to be forwarded from a proxy."); + return false; + } + bindAddress = new io.netty.channel.unix.DomainSocketAddress(this.getLocalIp().substring("unix:".length())); + } else { InetAddress inetaddress = null; if (!this.getLocalIp().isEmpty()) { @@ -228,12 +242,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface if (this.getPort() < 0) { this.setPort(dedicatedserverproperties.serverPort); } + bindAddress = new java.net.InetSocketAddress(inetaddress, this.getPort()); + } + // Paper end this.initializeKeyPair(); DedicatedServer.LOGGER.info("Starting Minecraft server on {}:{}", this.getLocalIp().isEmpty() ? "*" : this.getLocalIp(), this.getPort()); try { - this.getConnection().startTcpServerListener(inetaddress, this.getPort()); + this.getConnection().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/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java index 2ea40a23539898b9c817440aafc91f4b5fd10977..2e7540b0e100347cd91624c9d61a5c4688a52b26 100644 --- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java @@ -76,7 +76,12 @@ public class ServerConnectionListener { this.running = true; } + // Paper start public void startTcpServerListener(@Nullable InetAddress address, int port) throws IOException { + bind(new java.net.InetSocketAddress(address, port)); + } + public void bind(java.net.SocketAddress address) throws IOException { + // Paper end List list = this.channels; synchronized (this.channels) { @@ -84,7 +89,13 @@ public class ServerConnectionListener { EventLoopGroup eventloopgroup; if (Epoll.isAvailable() && this.server.isEpollEnabled()) { + // Paper start + if (address instanceof io.netty.channel.unix.DomainSocketAddress) { + oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class; + } else { oclass = EpollServerSocketChannel.class; + } + // Paper end eventloopgroup = (EventLoopGroup) ServerConnectionListener.SERVER_EPOLL_EVENT_GROUP.get(); ServerConnectionListener.LOGGER.info("Using epoll channel type"); } else { @@ -115,7 +126,7 @@ public class ServerConnectionListener { ((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper } - }).group(eventloopgroup).localAddress(address, port)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit + }).group(eventloopgroup).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper } } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 60b03c03bd5497acc617b81ef9a47910d9a9a8c9..b69d5c474d2cb1bd40c09ff1c644db4546530f80 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -2453,6 +2453,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // 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 (connection.channel.remoteAddress() == null) { + return new java.net.InetSocketAddress(java.net.InetAddress.getLoopbackAddress(), 0); + } + // Paper end return this.connection.channel.remoteAddress(); } // Spigot End diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java index 5d372b390f3046b4ce19296803c5fbfee798e69b..2824369960130fa3d0ad416a3961024c8f8d5f52 100644 --- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java @@ -45,6 +45,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL this.connection.setClientboundProtocolAfterHandshake(ClientIntent.LOGIN); // CraftBukkit start - Connection throttle try { + if (!(this.connection.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.server.server.getConnectionThrottle(); InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress(); @@ -73,6 +74,7 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL } } } + } // Paper - add closing bracket for if check above } catch (Throwable t) { org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t); } @@ -121,8 +123,11 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL // Paper end // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above! if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.BYPASS_HOSTCHECK || ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) { // Paper + // Paper start - Unix domain socket support + java.net.SocketAddress socketAddress = connection.getRemoteAddress(); connection.hostname = split[0]; - connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort()); + connection.address = new java.net.InetSocketAddress(split[1], socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0); + // Paper end connection.spoofedUUID = com.mojang.util.UndashedUuid.fromStringLenient( split[2] ); } else {