Filter the game portal host for specific CIDR ranges:

- This will make sure that the developer mode is disabled on most public hosts.
- Enable Developer mode by default.
This commit is contained in:
Fabian
2023-05-21 21:30:11 +00:00
parent 8794a0c512
commit d48c7f55b6
5 changed files with 186 additions and 5 deletions

View File

@@ -8,12 +8,17 @@ namespace Arctium.WoW.Launcher;
static class LaunchOptions
{
public static bool IsDevModeAllowed { get; set; }
public static Option<GameVersion> Version = new("--version", () => GameVersion.Retail);
public static Option<string> GamePath = new("--path");
public static Option<string> GameBinary = new("--binary");
public static Option<bool> KeepCache = new("--keepcache", () => true);
public static Option<bool> UseStaticAuthSeed = new("--staticseed");
public static Option<bool> DevMode = new("--dev", () => false);
public static Option<bool> DevMode = new("--dev", () => true);
// Game command line options.
public static Option<string> GameConfig = new("-config", () => "Config.wtf");
public static Parser Instance => new CommandLineBuilder(ConfigureCommandLine(RootCommand))
.UseHelp()
@@ -30,7 +35,8 @@ static class LaunchOptions
GameBinary,
KeepCache,
UseStaticAuthSeed,
DevMode
DevMode,
GameConfig
};
static Command ConfigureCommandLine(Command rootCommand)

View File

@@ -10,7 +10,7 @@ static class Launcher
{
public static readonly CancellationTokenSource CancellationTokenSource = new();
public static string PrepareGameLaunch(ParseResult commandLineResult)
public static string PrepareGameLaunch(ParseResult commandLineResult, IPFilter ipFilter)
{
var gameVersion = commandLineResult.GetValueForOption(LaunchOptions.Version);
var (SubFolder, BinaryName, MajorGameVersion, MinGameBuild) = gameVersion switch
@@ -86,6 +86,27 @@ static class Launcher
}
}
var configPath = $"{gameFolder}/WTF/{commandLineResult.GetValueForOption(LaunchOptions.GameConfig)}";
if (!File.Exists(configPath))
LaunchOptions.IsDevModeAllowed = false;
else
{
var config = File.ReadAllText(configPath);
LaunchOptions.IsDevModeAllowed = IsDevModeAllowed(ipFilter, config);
}
if (!LaunchOptions.IsDevModeAllowed)
LaunchOptions.DevMode = new("--dev", () => false);
var devModeEnabled = commandLineResult.GetValueForOption(LaunchOptions.DevMode) && LaunchOptions.IsDevModeAllowed;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Developer mode: {(devModeEnabled ? "Enabled" : "Disabled")}");
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
return gameBinaryPath;
}
@@ -177,7 +198,7 @@ static class Launcher
memory.QueuePatch(Patterns.Windows.CertCommonName, Patches.Windows.CertCommonName, "CertCommonName", 5)
}, CancellationTokenSource.Token);
}
else if (commandLineResult.GetValueForOption(LaunchOptions.DevMode))
else if (LaunchOptions.IsDevModeAllowed && commandLineResult.GetValueForOption(LaunchOptions.DevMode))
{
Task.WaitAll(new[]
{
@@ -274,6 +295,8 @@ static class Launcher
return false;
}
static bool IsDevModeAllowed(IPFilter ipFilter, string config) => ipFilter.IsInRange(ParsePortal(config));
static long GenerateAuthSeedFunctionPatch(WinMemory memory, long modulusOffset)
{
#if x64

View File

@@ -1,6 +1,8 @@
// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Net;
namespace Arctium.WoW.Launcher.Misc;
static class Helpers
@@ -41,4 +43,40 @@ static class Helpers
Console.WriteLine();
Console.WriteLine($"Operating System: {RuntimeInformation.OSDescription}");
}
public static ReadOnlySpan<char> ParsePortal(string config)
{
const string portalKey = "SET portal";
var portalIndex = config.IndexOf(portalKey, StringComparison.Ordinal);
if (portalIndex == -1)
throw new ArgumentException("Config file does not contain the portal variable.");
var startQuoteIndex = config.IndexOf('"', portalIndex);
if (startQuoteIndex == -1)
throw new ArgumentException("Invalid format for the portal variable.");
var endQuoteIndex = config.IndexOf('"', startQuoteIndex + 1);
if (endQuoteIndex == -1)
throw new ArgumentException("Invalid format for the portal variable.");
var portalLength = endQuoteIndex - startQuoteIndex - 1;
var portalSpan = config.AsSpan(startQuoteIndex + 1, portalLength);
var colonIndex = portalSpan.IndexOf(':');
var ipSpan = colonIndex != -1 ? portalSpan[..colonIndex] : portalSpan;
var portalString = ipSpan.ToString().Trim();
if (IPAddress.TryParse(portalString, out var ipAddress))
return ipAddress.ToString().AsSpan();
var ipv4Address = Dns.GetHostAddresses(portalString).FirstOrDefault(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork);
if (ipv4Address == null)
throw new Exception("No IPv4 address found for the provided hostname.");
return ipv4Address.ToString().AsSpan();
}
}

81
src/Misc/IPFilter.cs Normal file
View File

@@ -0,0 +1,81 @@
// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Net;
namespace Arctium.WoW.Launcher.Misc;
public class IPFilter
{
readonly ICollection<(IPAddress, IPAddress)> _ipRanges;
public IPFilter()
{
_ipRanges = new List<(IPAddress, IPAddress)>();
}
public void AddCidrRange(ReadOnlySpan<char> cidr)
{
var separatorIndex = cidr.IndexOf('/');
if (separatorIndex < 0)
return;
var subnetMaskLengthSpan = cidr[(separatorIndex + 1)..];
if (!int.TryParse(subnetMaskLengthSpan, out var subnetMaskLength))
return;
Span<byte> subnetMaskBytes = stackalloc byte[4];
for (var i = 0; i < subnetMaskLength; i++)
subnetMaskBytes[i / 8] |= (byte)(1 << (7 - i % 8));
if (!IPAddress.TryParse(cidr[..separatorIndex], out var ip))
return;
ReadOnlySpan<byte> ipBytes = ip.GetAddressBytes();
Span<byte> networkAddressBytes = stackalloc byte[4];
Span<byte> broadcastAddressBytes = stackalloc byte[4];
for (var i = 0; i < 4; i++)
{
networkAddressBytes[i] = (byte)(ipBytes[i] & subnetMaskBytes[i]);
broadcastAddressBytes[i] = (byte)(networkAddressBytes[i] | ~subnetMaskBytes[i]);
}
_ipRanges.Add((new(networkAddressBytes), new(broadcastAddressBytes)));
}
public bool IsInRange(ReadOnlySpan<char> targetIP)
{
if (!IPAddress.TryParse(targetIP, out var ip))
return false;
ReadOnlySpan<byte> targetBytes = ip.GetAddressBytes();
foreach (var range in _ipRanges)
{
ReadOnlySpan<byte> networkAddressBytes = range.Item1.GetAddressBytes();
ReadOnlySpan<byte> broadcastAddressBytes = range.Item2.GetAddressBytes();
var isInRange = true;
for (var i = 0; i < 4; i++)
{
if ((targetBytes[i] & networkAddressBytes[i]) != networkAddressBytes[i] ||
(targetBytes[i] & broadcastAddressBytes[i]) != targetBytes[i])
{
isInRange = false;
break;
}
}
if (isInRange)
return true;
}
return false;
}
}

View File

@@ -13,15 +13,48 @@ PrintHeader("WoW Client Launcher");
LaunchOptions.RootCommand.SetHandler(context =>
{
var appPath = Launcher.PrepareGameLaunch(context.ParseResult);
CreateDevIPFilter(out var ipFilter);
var appPath = Launcher.PrepareGameLaunch(context.ParseResult, ipFilter);
var gameCommandLine = string.Join(" ", context.ParseResult.UnmatchedTokens);
// Add config parameter to the game command line.
gameCommandLine += $" -config {context.ParseResult.GetValueForOption(LaunchOptions.GameConfig)}";
if (string.IsNullOrEmpty(appPath) || !Launcher.LaunchGame(appPath, gameCommandLine, context.ParseResult))
WaitAndExit(5000);
});
await LaunchOptions.Instance.InvokeAsync(args);
void CreateDevIPFilter(out IPFilter ipFilter)
{
ipFilter = new IPFilter();
ipFilter.AddCidrRange("0.0.0.0/8");
ipFilter.AddCidrRange("10.0.0.0/8");
ipFilter.AddCidrRange("100.64.0.0/10");
ipFilter.AddCidrRange("127.0.0.0/8");
ipFilter.AddCidrRange("169.254.0.0/16");
ipFilter.AddCidrRange("172.16.0.0/12");
ipFilter.AddCidrRange("192.0.0.0/24");
ipFilter.AddCidrRange("192.0.0.0/29");
ipFilter.AddCidrRange("192.0.0.8/32");
ipFilter.AddCidrRange("192.0.0.9/32");
ipFilter.AddCidrRange("192.0.0.170/32");
ipFilter.AddCidrRange("192.0.0.171/32");
ipFilter.AddCidrRange("192.0.2.0/24");
ipFilter.AddCidrRange("192.31.196.0/24");
ipFilter.AddCidrRange("192.52.193.0/24");
ipFilter.AddCidrRange("192.88.99.0/24");
ipFilter.AddCidrRange("192.168.0.0/16");
ipFilter.AddCidrRange("192.175.48.0/24");
ipFilter.AddCidrRange("198.18.0.0/15");
ipFilter.AddCidrRange("198.51.100.0/24");
ipFilter.AddCidrRange("203.0.113.0/24");
ipFilter.AddCidrRange("240.0.0.0/4");
ipFilter.AddCidrRange("255.255.255.255/32");
}
static void WaitAndExit(int ms = 2000)
{