2022-12-20 22:41:14 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Net;
|
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
|
using System.Net.Sockets;
|
2022-09-06 19:13:23 +02:00
|
|
|
|
using Starksoft.Aspen.Proxy;
|
2022-10-05 15:02:30 +08:00
|
|
|
|
using Tomlet.Attributes;
|
2014-05-31 01:59:03 +02:00
|
|
|
|
|
|
|
|
|
|
namespace MinecraftClient.Proxy
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Automatically handle proxies according to the app Settings.
|
|
|
|
|
|
/// Note: Underlying proxy handling is taken from Starksoft, LLC's Biko Library.
|
|
|
|
|
|
/// This library is open source and provided under the MIT license. More info at biko.codeplex.com.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
|
|
|
|
public static class ProxyHandler
|
|
|
|
|
|
{
|
2022-10-05 15:02:30 +08:00
|
|
|
|
public static Configs Config = new();
|
|
|
|
|
|
|
|
|
|
|
|
[TomlDoNotInlineObject]
|
|
|
|
|
|
public class Configs
|
|
|
|
|
|
{
|
2022-12-20 22:41:14 +08:00
|
|
|
|
[NonSerialized] // Compatible with old settings.
|
|
|
|
|
|
public bool? Enabled_Login = false, Enabled_Ingame = false, Enabled_Update = false;
|
2022-12-01 22:55:48 +08:00
|
|
|
|
|
2022-12-20 22:41:14 +08:00
|
|
|
|
[TomlInlineComment("$Proxy.Ingame_Proxy$")]
|
|
|
|
|
|
public ProxyPreferenceType Ingame_Proxy = ProxyPreferenceType.disable;
|
2022-10-05 15:02:30 +08:00
|
|
|
|
|
2022-12-20 22:41:14 +08:00
|
|
|
|
[TomlInlineComment("$Proxy.Login_Proxy$")]
|
|
|
|
|
|
public ProxyPreferenceType Login_Proxy = ProxyPreferenceType.follow_system;
|
|
|
|
|
|
|
|
|
|
|
|
[TomlInlineComment("$Proxy.MCC_Update_Proxy$")]
|
|
|
|
|
|
public ProxyPreferenceType MCC_Update_Proxy = ProxyPreferenceType.follow_system;
|
2022-10-05 15:02:30 +08:00
|
|
|
|
|
2022-11-30 16:22:48 +08:00
|
|
|
|
[TomlInlineComment("$Proxy.Server$")]
|
2022-10-05 15:02:30 +08:00
|
|
|
|
public ProxyInfoConfig Server = new("0.0.0.0", 8080);
|
|
|
|
|
|
|
2022-11-30 16:22:48 +08:00
|
|
|
|
[TomlInlineComment("$Proxy.Proxy_Type$")]
|
2022-10-05 15:02:30 +08:00
|
|
|
|
public ProxyType Proxy_Type = ProxyType.HTTP;
|
|
|
|
|
|
|
2022-11-30 16:22:48 +08:00
|
|
|
|
[TomlInlineComment("$Proxy.Username$")]
|
2022-12-20 22:41:14 +08:00
|
|
|
|
public string Username = string.Empty;
|
2022-10-05 15:02:30 +08:00
|
|
|
|
|
2022-11-30 16:22:48 +08:00
|
|
|
|
[TomlInlineComment("$Proxy.Password$")]
|
2022-12-20 22:41:14 +08:00
|
|
|
|
public string Password = string.Empty;
|
2022-10-05 15:02:30 +08:00
|
|
|
|
|
2022-12-20 22:41:14 +08:00
|
|
|
|
public void OnSettingUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
{ // Compatible with old settings.
|
|
|
|
|
|
if (Enabled_Login.HasValue && Enabled_Login.Value)
|
|
|
|
|
|
Login_Proxy = ProxyPreferenceType.custom;
|
|
|
|
|
|
if (Enabled_Ingame.HasValue && Enabled_Ingame.Value)
|
|
|
|
|
|
Ingame_Proxy = ProxyPreferenceType.custom;
|
|
|
|
|
|
if (Enabled_Update.HasValue && Enabled_Update.Value)
|
|
|
|
|
|
MCC_Update_Proxy = ProxyPreferenceType.custom;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-10-05 15:02:30 +08:00
|
|
|
|
|
|
|
|
|
|
public struct ProxyInfoConfig
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Host;
|
|
|
|
|
|
public ushort Port;
|
|
|
|
|
|
|
|
|
|
|
|
public ProxyInfoConfig(string host, ushort port)
|
|
|
|
|
|
{
|
|
|
|
|
|
Host = host;
|
|
|
|
|
|
Port = port;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public enum ProxyType { HTTP, SOCKS4, SOCKS4a, SOCKS5 };
|
2022-12-20 22:41:14 +08:00
|
|
|
|
|
|
|
|
|
|
public enum ProxyPreferenceType { custom, follow_system, disable };
|
2022-10-05 15:02:30 +08:00
|
|
|
|
}
|
2014-05-31 01:59:03 +02:00
|
|
|
|
|
2022-12-20 22:41:14 +08:00
|
|
|
|
public enum ClientType { Ingame, Login, Update };
|
|
|
|
|
|
|
2022-10-02 18:31:08 +08:00
|
|
|
|
private static readonly ProxyClientFactory factory = new();
|
|
|
|
|
|
private static IProxyClient? proxy;
|
2014-05-31 01:59:03 +02:00
|
|
|
|
private static bool proxy_ok = false;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Create a regular TcpClient or a proxied TcpClient according to the app Settings.
|
|
|
|
|
|
/// </summary>
|
2015-10-22 20:56:08 +02:00
|
|
|
|
/// <param name="host">Target host</param>
|
|
|
|
|
|
/// <param name="port">Target port</param>
|
|
|
|
|
|
/// <param name="login">True if the purpose is logging in to a Minecraft account</param>
|
2014-05-31 01:59:03 +02:00
|
|
|
|
|
2022-12-20 22:41:14 +08:00
|
|
|
|
public static TcpClient NewTcpClient(string host, int port, ClientType clientType)
|
2014-05-31 01:59:03 +02:00
|
|
|
|
{
|
2022-12-20 22:41:14 +08:00
|
|
|
|
if (clientType == ClientType.Update)
|
|
|
|
|
|
throw new NotSupportedException();
|
2014-05-31 01:59:03 +02:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2022-12-20 22:41:14 +08:00
|
|
|
|
Configs.ProxyPreferenceType proxyPreference = clientType == ClientType.Ingame ? Config.Ingame_Proxy : Config.Login_Proxy;
|
|
|
|
|
|
if (proxyPreference == Configs.ProxyPreferenceType.custom)
|
2014-05-31 01:59:03 +02:00
|
|
|
|
{
|
|
|
|
|
|
ProxyType innerProxytype = ProxyType.Http;
|
|
|
|
|
|
|
2022-10-05 15:02:30 +08:00
|
|
|
|
switch (Config.Proxy_Type)
|
2014-05-31 01:59:03 +02:00
|
|
|
|
{
|
2022-10-05 15:02:30 +08:00
|
|
|
|
case Configs.ProxyType.HTTP: innerProxytype = ProxyType.Http; break;
|
|
|
|
|
|
case Configs.ProxyType.SOCKS4: innerProxytype = ProxyType.Socks4; break;
|
|
|
|
|
|
case Configs.ProxyType.SOCKS4a: innerProxytype = ProxyType.Socks4a; break;
|
|
|
|
|
|
case Configs.ProxyType.SOCKS5: innerProxytype = ProxyType.Socks5; break;
|
2014-05-31 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-12-11 13:00:19 +08:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(Config.Username) && !string.IsNullOrWhiteSpace(Config.Password))
|
2022-10-05 15:02:30 +08:00
|
|
|
|
proxy = factory.CreateProxyClient(innerProxytype, Config.Server.Host, Config.Server.Port, Config.Username, Config.Password);
|
|
|
|
|
|
else
|
|
|
|
|
|
proxy = factory.CreateProxyClient(innerProxytype, Config.Server.Host, Config.Server.Port);
|
2014-05-31 01:59:03 +02:00
|
|
|
|
|
|
|
|
|
|
if (!proxy_ok)
|
|
|
|
|
|
{
|
2022-11-30 16:08:55 +08:00
|
|
|
|
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.proxy_connected, Config.Server.Host, Config.Server.Port));
|
2014-05-31 01:59:03 +02:00
|
|
|
|
proxy_ok = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return proxy.CreateConnection(host, port);
|
|
|
|
|
|
}
|
2022-12-20 22:41:14 +08:00
|
|
|
|
else if (proxyPreference == Configs.ProxyPreferenceType.follow_system)
|
|
|
|
|
|
{
|
|
|
|
|
|
Uri? webProxy = WebRequest.GetSystemWebProxy().GetProxy(new("http://" + host));
|
|
|
|
|
|
if (webProxy != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
proxy = factory.CreateProxyClient(ProxyType.Http, webProxy.Host, webProxy.Port);
|
|
|
|
|
|
|
|
|
|
|
|
if (!proxy_ok)
|
|
|
|
|
|
{
|
|
|
|
|
|
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.proxy_connected, webProxy.Host, webProxy.Port));
|
|
|
|
|
|
proxy_ok = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return proxy.CreateConnection(host, port);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return new TcpClient(host, port);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
return new TcpClient(host, port);
|
|
|
|
|
|
}
|
2014-05-31 01:59:03 +02:00
|
|
|
|
}
|
2015-04-20 17:26:16 +02:00
|
|
|
|
catch (ProxyException e)
|
2014-05-31 01:59:03 +02:00
|
|
|
|
{
|
2015-04-20 17:26:16 +02:00
|
|
|
|
ConsoleIO.WriteLineFormatted("§8" + e.Message);
|
|
|
|
|
|
proxy = null;
|
2019-04-17 05:59:02 +02:00
|
|
|
|
throw new SocketException((int)SocketError.HostUnreachable);
|
2014-05-31 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-12-20 22:41:14 +08:00
|
|
|
|
|
|
|
|
|
|
public static HttpClient NewHttpClient(ClientType clientType, HttpClientHandler? httpClientHandler = null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (clientType == ClientType.Ingame)
|
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
|
|
|
|
|
|
|
httpClientHandler ??= new();
|
|
|
|
|
|
AddProxySettings(clientType, ref httpClientHandler);
|
|
|
|
|
|
return new HttpClient(httpClientHandler);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void AddProxySettings(ClientType clientType, ref HttpClientHandler httpClientHandler)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (clientType == ClientType.Ingame)
|
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
|
|
|
|
|
|
|
Configs.ProxyPreferenceType proxyPreference = clientType == ClientType.Login ? Config.Login_Proxy : Config.MCC_Update_Proxy;
|
|
|
|
|
|
|
|
|
|
|
|
if (proxyPreference == Configs.ProxyPreferenceType.custom)
|
|
|
|
|
|
{
|
|
|
|
|
|
httpClientHandler ??= new();
|
|
|
|
|
|
|
|
|
|
|
|
string proxyAddress;
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(Settings.Config.Proxy.Username) && !string.IsNullOrWhiteSpace(Settings.Config.Proxy.Password))
|
|
|
|
|
|
proxyAddress = string.Format("{0}://{3}:{4}@{1}:{2}",
|
|
|
|
|
|
Settings.Config.Proxy.Proxy_Type.ToString().ToLower(),
|
|
|
|
|
|
Settings.Config.Proxy.Server.Host,
|
|
|
|
|
|
Settings.Config.Proxy.Server.Port,
|
|
|
|
|
|
Settings.Config.Proxy.Username,
|
|
|
|
|
|
Settings.Config.Proxy.Password);
|
|
|
|
|
|
else
|
|
|
|
|
|
proxyAddress = string.Format("{0}://{1}:{2}",
|
|
|
|
|
|
Settings.Config.Proxy.Proxy_Type.ToString().ToLower(),
|
|
|
|
|
|
Settings.Config.Proxy.Server.Host, Settings.Config.Proxy.Server.Port);
|
|
|
|
|
|
|
|
|
|
|
|
httpClientHandler.Proxy = new WebProxy(proxyAddress, true);
|
|
|
|
|
|
httpClientHandler.UseProxy = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (proxyPreference == Configs.ProxyPreferenceType.follow_system)
|
|
|
|
|
|
{
|
|
|
|
|
|
httpClientHandler.Proxy = WebRequest.GetSystemWebProxy();
|
|
|
|
|
|
httpClientHandler.UseProxy = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (proxyPreference == Configs.ProxyPreferenceType.disable)
|
|
|
|
|
|
{
|
|
|
|
|
|
httpClientHandler ??= new();
|
|
|
|
|
|
httpClientHandler.UseProxy = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotSupportedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-05-31 01:59:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|