Fix ipv6 for new dedicated server

Change bind IP to ipv6 unspecified address "::" from "0.0.0.0"
use sockaddr_storage instead of sockaddr_in
changed TryGetNumericRemoteIp to use getnameinfo instead of inet_ntop
This commit is contained in:
Brendon 2026-03-15 19:58:41 -07:00
parent 60cf7534fd
commit d8537f6fa6
4 changed files with 44 additions and 20 deletions

View file

@ -248,16 +248,19 @@ bool WinsockNetLayer::HostGame(int port, const char* bindIp)
const char* resolvedBindIp = (bindIp != NULL && bindIp[0] != 0) ? bindIp : NULL;
struct addrinfo hints = {};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (resolvedBindIp == NULL)
{
hints.ai_family = AF_INET6;
hints.ai_flags = AI_PASSIVE;
else if (IsNumericAddress(resolvedBindIp))
hints.ai_flags = AI_NUMERICHOST;
}
else
hints.ai_flags = 0;
{
hints.ai_family = AF_UNSPEC;
hints.ai_flags = IsNumericAddress(resolvedBindIp) ? AI_NUMERICHOST : 0;
}
struct addrinfo* result = NULL;
int iResult = getaddrinfo(resolvedBindIp, portStr, &hints, &result);
@ -278,8 +281,14 @@ bool WinsockNetLayer::HostGame(int port, const char* bindIp)
return false;
}
DWORD ipv6only = 0;
setsockopt(s_listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&ipv6only, sizeof(ipv6only));
if (result->ai_family == AF_INET6)
{
DWORD ipv6only = 0;
if (setsockopt(s_listenSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&ipv6only, sizeof(ipv6only)) == SOCKET_ERROR)
{
app.DebugPrintf("setsockopt() failed: %d\n", WSAGetLastError());
}
}
iResult = ::bind(s_listenSocket, result->ai_addr, static_cast<int>(result->ai_addrlen));
freeaddrinfo(result);
@ -551,7 +560,7 @@ static bool RecvExact(SOCKET sock, BYTE* buf, int len)
}
#if defined(MINECRAFT_SERVER_BUILD)
static bool TryGetNumericRemoteIp(const sockaddr_in &remoteAddress, std::string *outIp)
static bool TryGetNumericRemoteIp(const sockaddr_storage& remoteAddress, int remoteAddressLength, std::string* outIp)
{
if (outIp == nullptr)
{
@ -559,14 +568,17 @@ static bool TryGetNumericRemoteIp(const sockaddr_in &remoteAddress, std::string
}
outIp->clear();
char ipBuffer[64] = {};
const char *ip = inet_ntop(AF_INET, (void *)&remoteAddress.sin_addr, ipBuffer, sizeof(ipBuffer));
if (ip == nullptr || ip[0] == 0)
char host[NI_MAXHOST] = {};
if (getnameinfo((const sockaddr*)&remoteAddress, remoteAddressLength, host, sizeof(host), nullptr, 0, NI_NUMERICHOST) != 0)
{
return false;
}
if (host[0] == 0)
{
return false;
}
*outIp = ip;
*outIp = host;
return true;
}
#endif
@ -605,7 +617,7 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
{
while (s_active)
{
sockaddr_in remoteAddress;
sockaddr_storage remoteAddress;
ZeroMemory(&remoteAddress, sizeof(remoteAddress));
int remoteAddressLength = sizeof(remoteAddress);
SOCKET clientSocket = accept(s_listenSocket, (sockaddr*)&remoteAddress, &remoteAddressLength);
@ -621,7 +633,7 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
#if defined(MINECRAFT_SERVER_BUILD)
std::string remoteIp;
const bool hasRemoteIp = TryGetNumericRemoteIp(remoteAddress, &remoteIp);
const bool hasRemoteIp = TryGetNumericRemoteIp(remoteAddress, remoteAddressLength, &remoteIp);
const char *remoteIpForLog = hasRemoteIp ? remoteIp.c_str() : "unknown";
if (g_Win64DedicatedServer)
{

View file

@ -71,7 +71,7 @@ static const ServerPropertyDefault kServerPropertyDefaults[] =
{ "motd", "A Minecraft Server" },
{ "natural-regeneration", "true" },
{ "pvp", "true" },
{ "server-ip", "0.0.0.0" },
{ "server-ip", "::" },
{ "server-name", "DedicatedServer" },
{ "server-port", "25565" },
{ "white-list", "false" },
@ -815,7 +815,7 @@ ServerPropertiesConfig LoadServerPropertiesConfig()
config.worldSaveId = worldSaveId;
config.serverPort = ReadNormalizedIntProperty(&merged, "server-port", kDefaultServerPort, 1, 65535, &shouldWrite);
config.serverIp = ReadNormalizedStringProperty(&merged, "server-ip", "0.0.0.0", 255, &shouldWrite);
config.serverIp = ReadNormalizedStringProperty(&merged, "server-ip", "::", 255, &shouldWrite);
config.lanAdvertise = ReadNormalizedBoolProperty(&merged, kLanAdvertisePropertyKey, false, &shouldWrite);
config.whiteListEnabled = ReadNormalizedBoolProperty(&merged, "white-list", false, &shouldWrite);
config.serverName = ReadNormalizedStringProperty(&merged, "server-name", "DedicatedServer", 16, &shouldWrite);

View file

@ -297,7 +297,7 @@ static void ApplyServerPropertiesToDedicatedConfig(const ServerPropertiesConfig
strncpy_s(
config->bindIP,
sizeof(config->bindIP),
serverProperties.serverIp.empty() ? "0.0.0.0" : serverProperties.serverIp.c_str(),
serverProperties.serverIp.empty() ? "::" : serverProperties.serverIp.c_str(),
_TRUNCATE);
strncpy_s(
config->name,
@ -351,7 +351,7 @@ int main(int argc, char **argv)
{
DedicatedServerConfig config;
config.port = WIN64_NET_DEFAULT_PORT;
strncpy_s(config.bindIP, sizeof(config.bindIP), "0.0.0.0", _TRUNCATE);
strncpy_s(config.bindIP, sizeof(config.bindIP), "::", _TRUNCATE);
strncpy_s(config.name, sizeof(config.name), "DedicatedServer", _TRUNCATE);
config.maxPlayers = MINECRAFT_NET_MAX_PLAYERS;
config.worldSize = e_worldSize_Classic;
@ -616,7 +616,13 @@ int main(int argc, char **argv)
}
LogStartupStep("server startup complete");
LogInfof("startup", "Dedicated server listening on %s:%d", g_Win64MultiplayerIP, g_Win64MultiplayerPort);
const std::string displayIp = strchr(g_Win64MultiplayerIP, ':')
? "[" + std::string(g_Win64MultiplayerIP) + "]" //ipv6 address will always have a :
: g_Win64MultiplayerIP;
LogInfof("startup", "Dedicated server listening on %s:%d", displayIp.c_str(), g_Win64MultiplayerPort);
if (worldBootstrap.status == eWorldBootstrap_CreatedNew && !IsShutdownRequested() && !app.m_bShutdown)
{
// Windows64 suppresses saveToDisc right after new world creation

View file

@ -5,7 +5,7 @@ SERVER_DIR="/srv/mc"
SERVER_EXE="Minecraft.Server.exe"
# ip & port are fixed since they run inside the container
SERVER_PORT="25565"
SERVER_BIND_IP="0.0.0.0"
SERVER_BIND_IP="::"
PERSIST_DIR="/srv/persist"
WINE_CMD=""
@ -87,5 +87,11 @@ args=(
-bind "${SERVER_BIND_IP}"
)
echo "[info] Starting ${SERVER_EXE} on ${SERVER_BIND_IP}:${SERVER_PORT}"
if [[ "$SERVER_BIND_IP" == *:* ]]; then
display_ip="[${SERVER_BIND_IP}]"
else
display_ip="$SERVER_BIND_IP"
fi
echo "[info] Starting ${SERVER_EXE} on ${display_ip}:${SERVER_PORT}"
exec "${WINE_CMD}" "${SERVER_EXE}" "${args[@]}"