Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
import com.velocitypowered.proxy.tablist.KeyedVelocityTabList;
import com.velocitypowered.proxy.tablist.VelocityTabList;
import com.velocitypowered.proxy.tablist.VelocityTabListLegacy;
import com.velocitypowered.proxy.util.AddressUtil;
import com.velocitypowered.proxy.util.ClosestLocaleMatcher;
import com.velocitypowered.proxy.util.DurationUtils;
import com.velocitypowered.proxy.util.TranslatableMapper;
Expand All @@ -111,6 +112,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -890,8 +892,17 @@ private Optional<RegisteredServer> getNextServerToTry(@Nullable RegisteredServer
String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString)
.orElse("")
.toLowerCase(Locale.ROOT);
serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(virtualHostStr,
Collections.emptyList());
serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(
virtualHostStr,
server.getConfiguration()
.getForcedHosts()
.entrySet()
.stream()
.filter(entry -> AddressUtil.isHostMatchingPattern(entry.getKey(), virtualHostStr))
.map(Map.Entry::getValue)
.findFirst()
.orElse(Collections.emptyList())
Comment thread
lllincoln marked this conversation as resolved.
Outdated
);
}

if (serversToTry.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@
import com.velocitypowered.proxy.config.PingPassthroughMode;
import com.velocitypowered.proxy.config.VelocityConfiguration;
import com.velocitypowered.proxy.server.VelocityRegisteredServer;
import com.velocitypowered.proxy.util.AddressUtil;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -175,7 +177,16 @@ public CompletableFuture<ServerPing> getInitialPing(VelocityInboundConnection co
.map(str -> str.toLowerCase(Locale.ROOT))
.orElse("");
List<String> serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(
virtualHostStr, server.getConfiguration().getAttemptConnectionOrder());
virtualHostStr,
server.getConfiguration()
.getForcedHosts()
.entrySet()
.stream()
.filter(entry -> AddressUtil.isHostMatchingPattern(entry.getKey(), virtualHostStr))
.map(Map.Entry::getValue)
.findFirst()
.orElse(server.getConfiguration().getAttemptConnectionOrder())
);
return attemptPingPassthrough(connection, passthroughMode, serversToTry, shownVersion, virtualHostStr);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,37 @@ public static InetSocketAddress parseAndResolveAddress(String ip) {
int port = uri.getPort() == -1 ? DEFAULT_MINECRAFT_PORT : uri.getPort();
return new InetSocketAddress(uri.getHost(), port);
}

/**
* Tests whether a host matches a pattern whose labels may be the
* wildcard {@code "*"}. Each {@code "*"} matches exactly one label; all other
* labels match case-insensitively.
*
* @param pattern the pattern to match against, for example, {@code *.soulrealms.net}
* @param host the virtual host to test, for example, {@code play.soulrealms.net}
Comment thread
lllincoln marked this conversation as resolved.
Outdated
* @return true if the host matches the pattern, false otherwise
*/
public static boolean isHostMatchingPattern(String pattern, String host) {
Comment thread
lllincoln marked this conversation as resolved.
Outdated
if (host == null || pattern == null) {
return false;
}

String[] patternDomains = pattern.split("\\.");
String[] strDomains = host.split("\\.");

if (patternDomains.length != strDomains.length) {
return false;
}

for (int i = 0; patternDomains.length > i; i++) {
Comment thread
lllincoln marked this conversation as resolved.
Outdated
String patternDomain = patternDomains[i];
String strDomain = strDomains[i];

if (!patternDomain.equals("*") && !strDomain.equalsIgnoreCase(patternDomain)) {
return false;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2018-2021 Velocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.connection.client;

import com.velocitypowered.proxy.util.AddressUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class ForcedHostsTest {
@Test
void testIsHostMatchingPattern() {
Comment thread
lllincoln marked this conversation as resolved.
Outdated
Assertions.assertTrue(AddressUtil.isHostMatchingPattern("*.miscpvp.org", "play.miscpvp.org"));
Assertions.assertTrue(AddressUtil.isHostMatchingPattern("*.miscpvp.org", "yt.miscpvp.org"));
Assertions.assertTrue(AddressUtil.isHostMatchingPattern("*.miscpvp.org", "ip.miscpvp.org"));
Assertions.assertTrue(AddressUtil.isHostMatchingPattern("test.*.miscpvp.org", "test.example.miscpvp.org"));
Assertions.assertFalse(AddressUtil.isHostMatchingPattern("*.miscpvp.org", "test.example.miscpvp.org"));
Assertions.assertFalse(AddressUtil.isHostMatchingPattern("*.miscpvp.org", "miscpvp.org"));
Assertions.assertFalse(AddressUtil.isHostMatchingPattern("miscpvp.minehunt.gg", "ip.miscpvp.org"));
Comment thread
lllincoln marked this conversation as resolved.
Outdated
}
}