diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java index fd686297ee..554d78ee86 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java @@ -9,6 +9,7 @@ import com.google.common.base.Preconditions; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Objects; import org.checkerframework.checker.nullness.qual.Nullable; @@ -19,7 +20,7 @@ public final class ServerInfo implements Comparable { private final String name; - private final InetSocketAddress address; + private final SocketAddress address; /** * Creates a new ServerInfo object. @@ -32,11 +33,44 @@ public ServerInfo(String name, InetSocketAddress address) { this.address = Preconditions.checkNotNull(address, "address"); } + /** + * Creates a new ServerInfo object. + * + * @param name the name for the server + * @param address the address of the server to connect to + */ + public ServerInfo(String name, SocketAddress address) { + this.name = Preconditions.checkNotNull(name, "name"); + this.address = Preconditions.checkNotNull(address, "address"); + } + public final String getName() { return name; } + /** + * Returns the address of this server as an {@link InetSocketAddress}. + * + * @return the address + * @deprecated Use {@link #getSocketAddress()} instead, which supports both TCP and Unix socket + * addresses. + */ + @Deprecated public final InetSocketAddress getAddress() { + if (address instanceof InetSocketAddress inet) { + return inet; + } + throw new UnsupportedOperationException( + "This server is not configured with an InetSocketAddress. Use getSocketAddress() instead."); + } + + /** + * Returns the address of this server as a {@link SocketAddress}. This may be an + * {@link InetSocketAddress} for TCP connections or a Unix domain socket address. + * + * @return the address + */ + public final SocketAddress getSocketAddress() { return address; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/ProxyOptions.java b/proxy/src/main/java/com/velocitypowered/proxy/ProxyOptions.java index d0b7f34f24..82a801de65 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/ProxyOptions.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/ProxyOptions.java @@ -20,7 +20,7 @@ import com.velocitypowered.api.proxy.server.ServerInfo; import com.velocitypowered.proxy.util.AddressUtil; import java.io.IOException; -import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Arrays; import java.util.List; import joptsimple.OptionParser; @@ -109,7 +109,7 @@ public ServerInfo convert(String s) { if (split.length < 2) { throw new ValueConversionException("Invalid server format. Use :
"); } - InetSocketAddress address; + SocketAddress address; try { address = AddressUtil.parseAddress(split[1]); } catch (IllegalStateException e) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 95f10bcbb0..5ee903210e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -78,6 +78,7 @@ import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.net.http.HttpClient; import java.nio.file.Files; import java.nio.file.Path; @@ -455,8 +456,8 @@ private void loadPlugins() { logger.info("Loaded {} plugins", pluginManager.getPlugins().size()); } - public Bootstrap createBootstrap(@Nullable EventLoopGroup group) { - return this.cm.createWorker(group); + public Bootstrap createBootstrap(@Nullable EventLoopGroup group, SocketAddress target) { + return this.cm.createWorker(group, target); } public ChannelInitializer getBackendChannelInitializer() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index e198a07160..945d2015f2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -257,7 +257,7 @@ private void loadFavicon() { } public InetSocketAddress getBind() { - return AddressUtil.parseAndResolveAddress(bind); + return (InetSocketAddress) AddressUtil.parseAndResolveAddress(bind); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java index 50edfaee5f..5a236e07ce 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java @@ -36,6 +36,9 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.unix.DomainSocketAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Optional; import java.util.StringJoiner; import net.kyori.adventure.text.Component; @@ -247,8 +250,14 @@ private void processServerIp(ByteBufDataInput in) { out.writeUTF("ServerIP"); out.writeUTF(info.getServerInfo().getName()); - out.writeUTF(info.getServerInfo().getAddress().getHostString()); - out.writeShort(info.getServerInfo().getAddress().getPort()); + SocketAddress address = info.getServerInfo().getSocketAddress(); + if (address instanceof InetSocketAddress inetAddr) { + out.writeUTF(inetAddr.getHostString()); + out.writeShort(inetAddr.getPort()); + } else { + out.writeUTF("unix://" + ((DomainSocketAddress) address).path()); + out.writeShort(0); + } sendResponseOnConnection(buf); }); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index c40a7aaac6..166694364f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -49,6 +49,8 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -100,9 +102,10 @@ public CompletableFuture connect() { CompletableFuture result = new CompletableFuture<>(); // Note: we use the event loop for the connection the player is on. This reduces context // switches. - server.createBootstrap(proxyPlayer.getConnection().eventLoop()) + SocketAddress destinationAddress = registeredServer.getServerInfo().getSocketAddress(); + server.createBootstrap(proxyPlayer.getConnection().eventLoop(), destinationAddress) .handler(server.getBackendChannelInitializer()) - .connect(registeredServer.getServerInfo().getAddress()) + .connect(destinationAddress) .addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { connection = new MinecraftConnection(future.channel(), server); @@ -143,8 +146,13 @@ String getPlayerRemoteAddressAsString() { private String createLegacyForwardingAddress() { return PlayerDataForwarding.createLegacyForwardingAddress( - proxyPlayer.getVirtualHost().orElseGet(() -> - registeredServer.getServerInfo().getAddress()).getHostString(), + proxyPlayer.getVirtualHost().orElseGet(() -> { + SocketAddress address = registeredServer.getServerInfo().getSocketAddress(); + if (address instanceof InetSocketAddress inetAddr) { + return inetAddr; + } + return InetSocketAddress.createUnresolved("::", 0); + }).getHostString(), getPlayerRemoteAddressAsString(), proxyPlayer.getGameProfile() ); @@ -152,8 +160,13 @@ private String createLegacyForwardingAddress() { private String createBungeeGuardForwardingAddress(byte[] forwardingSecret) { return PlayerDataForwarding.createBungeeGuardForwardingAddress( - proxyPlayer.getVirtualHost().orElseGet(() -> - registeredServer.getServerInfo().getAddress()).getHostString(), + proxyPlayer.getVirtualHost().orElseGet(() -> { + SocketAddress address = registeredServer.getServerInfo().getSocketAddress(); + if (address instanceof InetSocketAddress inetAddr) { + return inetAddr; + } + return InetSocketAddress.createUnresolved("::", 0); + }).getHostString(), getPlayerRemoteAddressAsString(), proxyPlayer.getGameProfile(), forwardingSecret @@ -166,9 +179,13 @@ private void startHandshake() { // Initiate the handshake. ProtocolVersion protocolVersion = proxyPlayer.getConnection().getProtocolVersion(); - String playerVhost = proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString(); + String playerVhost = proxyPlayer.getVirtualHost().orElseGet(() -> { + SocketAddress address = registeredServer.getServerInfo().getSocketAddress(); + if (address instanceof InetSocketAddress inetAddr) { + return inetAddr; + } + return InetSocketAddress.createUnresolved("::", 0); + }).getHostString(); HandshakePacket handshake = new HandshakePacket(); handshake.setIntent(HandshakeIntent.LOGIN); @@ -186,9 +203,10 @@ private void startHandshake() { handshake.setServerAddress(playerVhost); } - handshake.setPort(proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getPort()); + SocketAddress destinationAddr = registeredServer.getServerInfo().getSocketAddress(); + if (destinationAddr instanceof InetSocketAddress) { + handshake.setPort(((InetSocketAddress) destinationAddr).getPort()); + } mc.delayedWrite(handshake); mc.setProtocolVersion(protocolVersion); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java index 7b724f6130..e080375cbb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ConnectionManager.java @@ -35,10 +35,12 @@ import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.WriteBufferWaterMark; +import io.netty.channel.unix.DomainSocketAddress; import io.netty.channel.unix.UnixChannelOption; import io.netty.util.concurrent.GlobalEventExecutor; import io.netty.util.concurrent.MultithreadEventExecutorGroup; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.net.http.HttpClient; import java.util.Collection; import java.util.Map; @@ -184,21 +186,24 @@ public void queryBind(final String hostname, final int port) { } /** - * Creates a TCP {@link Bootstrap} using Velocity's event loops. + * Creates a {@link Bootstrap} using Velocity's event loops. * * @param group the event loop group to use. Use {@code null} for the default worker group. + * @param target the address the client will connect to * @return a new {@link Bootstrap} */ - public Bootstrap createWorker(@Nullable EventLoopGroup group) { + public Bootstrap createWorker(@Nullable EventLoopGroup group, SocketAddress target) { Bootstrap bootstrap = new Bootstrap() - .channelFactory(this.transportType.socketChannelFactory) - .option(ChannelOption.TCP_NODELAY, true) + .channelFactory(this.transportType.getClientChannelFactory(target)) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.server.getConfiguration().getConnectTimeout()) .group(group == null ? this.workerGroup : group) .resolver(this.resolver.asGroup()); - if (server.getConfiguration().useTcpFastOpen()) { - bootstrap.option(ChannelOption.TCP_FASTOPEN_CONNECT, true); + if (!(target instanceof DomainSocketAddress)) { + bootstrap.option(ChannelOption.TCP_NODELAY, true); + if (server.getConfiguration().useTcpFastOpen()) { + bootstrap.option(ChannelOption.TCP_FASTOPEN_CONNECT, true); + } } return bootstrap; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java b/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java index e154e5d541..8d8bb429de 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/TransportType.java @@ -18,18 +18,24 @@ package com.velocitypowered.proxy.network; import com.velocitypowered.proxy.util.concurrent.VelocityNettyThreadFactory; +import io.netty.channel.Channel; import io.netty.channel.ChannelFactory; import io.netty.channel.EventLoopGroup; import io.netty.channel.IoHandlerFactory; import io.netty.channel.MultiThreadIoEventLoopGroup; +import io.netty.channel.ServerChannel; import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollDatagramChannel; +import io.netty.channel.epoll.EpollDomainSocketChannel; import io.netty.channel.epoll.EpollIoHandler; +import io.netty.channel.epoll.EpollServerDomainSocketChannel; import io.netty.channel.epoll.EpollServerSocketChannel; import io.netty.channel.epoll.EpollSocketChannel; import io.netty.channel.kqueue.KQueue; import io.netty.channel.kqueue.KQueueDatagramChannel; +import io.netty.channel.kqueue.KQueueDomainSocketChannel; import io.netty.channel.kqueue.KQueueIoHandler; +import io.netty.channel.kqueue.KQueueServerDomainSocketChannel; import io.netty.channel.kqueue.KQueueServerSocketChannel; import io.netty.channel.kqueue.KQueueSocketChannel; import io.netty.channel.nio.NioIoHandler; @@ -39,11 +45,17 @@ import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.channel.unix.DomainSocketAddress; +import io.netty.channel.unix.DomainSocketChannel; +import io.netty.channel.unix.ServerDomainSocketChannel; import io.netty.channel.uring.IoUring; import io.netty.channel.uring.IoUringDatagramChannel; +import io.netty.channel.uring.IoUringDomainSocketChannel; import io.netty.channel.uring.IoUringIoHandler; +import io.netty.channel.uring.IoUringServerDomainSocketChannel; import io.netty.channel.uring.IoUringServerSocketChannel; import io.netty.channel.uring.IoUringSocketChannel; +import java.net.SocketAddress; import java.util.concurrent.ThreadFactory; import java.util.function.Supplier; @@ -54,35 +66,49 @@ public enum TransportType { NIO("NIO", NioServerSocketChannel::new, NioSocketChannel::new, NioDatagramChannel::new, + null, + null, NioIoHandler::newFactory), EPOLL("epoll", EpollServerSocketChannel::new, EpollSocketChannel::new, EpollDatagramChannel::new, + EpollServerDomainSocketChannel::new, + EpollDomainSocketChannel::new, EpollIoHandler::newFactory), KQUEUE("kqueue", KQueueServerSocketChannel::new, KQueueSocketChannel::new, KQueueDatagramChannel::new, + KQueueServerDomainSocketChannel::new, + KQueueDomainSocketChannel::new, KQueueIoHandler::newFactory), IO_URING("io_uring", IoUringServerSocketChannel::new, IoUringSocketChannel::new, IoUringDatagramChannel::new, + IoUringServerDomainSocketChannel::new, + IoUringDomainSocketChannel::new, IoUringIoHandler::newFactory); final String name; final ChannelFactory serverSocketChannelFactory; final ChannelFactory socketChannelFactory; final ChannelFactory datagramChannelFactory; + final ChannelFactory domainServerSocketChannelFactory; + final ChannelFactory domainSocketChannelFactory; final Supplier ioHandlerFactorySupplier; TransportType(final String name, final ChannelFactory serverSocketChannelFactory, final ChannelFactory socketChannelFactory, final ChannelFactory datagramChannelFactory, + final ChannelFactory domainServerSocketChannelFactory, + final ChannelFactory domainSocketChannelFactory, final Supplier ioHandlerFactorySupplier) { this.name = name; this.serverSocketChannelFactory = serverSocketChannelFactory; this.socketChannelFactory = socketChannelFactory; this.datagramChannelFactory = datagramChannelFactory; + this.domainServerSocketChannelFactory = domainServerSocketChannelFactory; + this.domainSocketChannelFactory = domainSocketChannelFactory; this.ioHandlerFactorySupplier = ioHandlerFactorySupplier; } @@ -91,6 +117,40 @@ public String toString() { return this.name; } + /** + * Returns the channel factory to use to listen on the specified socket address. + * + * @param address the address we want to listen on + * @return the channel factory + */ + public ChannelFactory getServerChannelFactory(SocketAddress address) { + if (address instanceof DomainSocketAddress) { + if (this.domainServerSocketChannelFactory == null) { + throw new IllegalArgumentException( + "Domain sockets are not available for non-Linux platforms"); + } + return this.domainServerSocketChannelFactory; + } + return this.serverSocketChannelFactory; + } + + /** + * Returns the channel factory to use to connect on the specified socket address. + * + * @param address the address we want to connect to + * @return the channel factory + */ + public ChannelFactory getClientChannelFactory(SocketAddress address) { + if (address instanceof DomainSocketAddress) { + if (this.domainSocketChannelFactory == null) { + throw new IllegalArgumentException( + "Domain sockets are not available for non-Linux platforms"); + } + return this.domainSocketChannelFactory; + } + return this.socketChannelFactory; + } + /** * Creates a new event loop group for the given type. * diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java index e58c72b446..c11459871a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java @@ -30,6 +30,8 @@ import com.velocitypowered.proxy.protocol.packet.StatusResponsePacket; import io.netty.channel.EventLoop; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.concurrent.CompletableFuture; /** @@ -58,9 +60,24 @@ public class PingSessionHandler implements MinecraftSessionHandler { public void activated() { HandshakePacket handshake = new HandshakePacket(); handshake.setIntent(HandshakeIntent.STATUS); - handshake.setServerAddress(this.virtualHostString == null || this.virtualHostString.isEmpty() - ? server.getServerInfo().getAddress().getHostString() : this.virtualHostString); - handshake.setPort(server.getServerInfo().getAddress().getPort()); + + SocketAddress address = server.getServerInfo().getSocketAddress(); + + if (this.virtualHostString != null && !this.virtualHostString.isEmpty()) { + handshake.setServerAddress(this.virtualHostString); + if (address instanceof InetSocketAddress socketAddr) { + handshake.setPort(socketAddr.getPort()); + } + } else { + if (address instanceof InetSocketAddress socketAddr) { + handshake.setServerAddress(socketAddr.getHostString()); + handshake.setPort(socketAddr.getPort()); + } else { + // Just fake it + handshake.setServerAddress("::"); + } + } + handshake.setProtocolVersion(version); connection.delayedWrite(handshake); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index e48881f399..cd8d40b8f7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -111,7 +111,7 @@ public CompletableFuture ping(@Nullable EventLoop loop, PingOptions throw new IllegalStateException("No Velocity proxy instance available"); } CompletableFuture pingFuture = new CompletableFuture<>(); - server.createBootstrap(loop).handler(new ChannelInitializer<>() { + server.createBootstrap(loop, serverInfo.getSocketAddress()).handler(new ChannelInitializer<>() { @Override protected void initChannel(Channel ch) { ch.pipeline().addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder(ProtocolUtils.Direction.CLIENTBOUND)) @@ -125,7 +125,7 @@ protected void initChannel(Channel ch) { ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server)); } - }).connect(serverInfo.getAddress()).addListener((ChannelFutureListener) future -> { + }).connect(serverInfo.getSocketAddress()).addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { MinecraftConnection conn = future.channel().pipeline().get(MinecraftConnection.class); PingSessionHandler handler = new PingSessionHandler(pingFuture, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/AddressUtil.java b/proxy/src/main/java/com/velocitypowered/proxy/util/AddressUtil.java index 42c5228e89..8e48594b40 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/AddressUtil.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/AddressUtil.java @@ -19,8 +19,12 @@ import com.google.common.base.Preconditions; import com.google.common.net.InetAddresses; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.unix.DomainSocketAddress; +import io.netty.channel.uring.IoUring; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.net.URI; /** @@ -35,14 +39,16 @@ private AddressUtil() { } /** - * Attempts to parse an IP address of the form {@code 127.0.0.1:25565}. The returned - * {@link InetSocketAddress} is not resolved. + * Attempts to parse a socket address of the form {@code 127.0.0.1:25565}. The returned + * {@link SocketAddress} is not resolved if it is a {@link InetSocketAddress}. * * @param ip the IP to parse * @return the parsed address */ - public static InetSocketAddress parseAddress(String ip) { - Preconditions.checkNotNull(ip, "ip"); + public static SocketAddress parseAddress(String ip) { + if (ip.startsWith("unix://") && (Epoll.isAvailable() || IoUring.isAvailable())) { + return new DomainSocketAddress(ip.substring("unix://".length())); + } URI uri = URI.create("tcp://" + ip); if (uri.getHost() == null) { throw new IllegalStateException("Invalid hostname/IP " + ip); @@ -58,13 +64,16 @@ public static InetSocketAddress parseAddress(String ip) { } /** - * Attempts to parse an IP address of the form {@code 127.0.0.1:25565}. The returned - * {@link InetSocketAddress} is resolved. + * Attempts to parse a socket address of the form {@code 127.0.0.1:25565}. The returned + * {@link SocketAddress} is resolved if it is a {@link InetSocketAddress}. * * @param ip the IP to parse * @return the parsed address */ - public static InetSocketAddress parseAndResolveAddress(String ip) { + public static SocketAddress parseAndResolveAddress(String ip) { + if (ip.startsWith("unix://") && (Epoll.isAvailable() || IoUring.isAvailable())) { + return new DomainSocketAddress(ip.substring("unix://".length())); + } Preconditions.checkNotNull(ip, "ip"); URI uri = URI.create("tcp://" + ip); if (uri.getHost() == null) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java index 59aae3e43e..129ee14132 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java @@ -38,6 +38,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.List; import java.util.Map; @@ -195,14 +196,18 @@ public static String anonymizeInetAddress(InetAddress address) { public static JsonObject collectServerInfo(RegisteredServer server) { JsonObject info = new JsonObject(); info.addProperty("currentPlayers", server.getPlayersConnected().size()); - InetSocketAddress iaddr = server.getServerInfo().getAddress(); - if (iaddr.isUnresolved()) { - // Greetings form Netty 4aa10db9 - info.addProperty("host", iaddr.getHostString()); + SocketAddress address = server.getServerInfo().getSocketAddress(); + if (address instanceof InetSocketAddress inetSocketAddress) { + if (inetSocketAddress.isUnresolved()) { + // Greetings form Netty 4aa10db9 + info.addProperty("host", inetSocketAddress.getHostString()); + } else { + info.addProperty("host", anonymizeInetAddress(inetSocketAddress.getAddress())); + } + info.addProperty("port", inetSocketAddress.getPort()); } else { - info.addProperty("host", anonymizeInetAddress(iaddr.getAddress())); + info.addProperty("bind", address.toString()); } - info.addProperty("port", iaddr.getPort()); return info; }