mirror of
https://github.com/araxiaonline/WoW-Launcher.git
synced 2026-06-13 01:22:21 -04:00
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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
81
src/Misc/IPFilter.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user