238 lines
7.5 KiB
C#
238 lines
7.5 KiB
C#
using PacLib;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Text;
|
|
using v2rayN.Mode;
|
|
using v2rayN.Properties;
|
|
using v2rayN.Tool;
|
|
|
|
namespace v2rayN.Handler
|
|
{
|
|
public static class SysProxyHandle
|
|
{
|
|
//private const string _userWininetConfigFile = "user-wininet.json";
|
|
|
|
//private static string _queryStr;
|
|
|
|
// In general, this won't change
|
|
// format:
|
|
// <flags><CR-LF>
|
|
// <proxy-server><CR-LF>
|
|
// <bypass-list><CR-LF>
|
|
// <pac-url>
|
|
private static SysproxyConfig? _userSettings = null;
|
|
|
|
enum RET_ERRORS : int
|
|
{
|
|
RET_NO_ERROR = 0,
|
|
INVALID_FORMAT = 1,
|
|
NO_PERMISSION = 2,
|
|
SYSCALL_FAILED = 3,
|
|
NO_MEMORY = 4,
|
|
INVAILD_OPTION_COUNT = 5,
|
|
};
|
|
|
|
static SysProxyHandle()
|
|
{
|
|
try
|
|
{
|
|
FileManager.UncompressFile(Utils.GetTempPath("sysproxy.exe"),
|
|
Environment.Is64BitOperatingSystem ? Resources.sysproxy64_exe : Resources.sysproxy_exe);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
Utils.SaveLog(ex.Message, ex);
|
|
}
|
|
}
|
|
|
|
|
|
public static bool UpdateSysProxy(Config config, bool forceDisable)
|
|
{
|
|
var type = config.sysProxyType;
|
|
|
|
if (forceDisable && type != ESysProxyType.Unchanged)
|
|
{
|
|
type = ESysProxyType.ForcedClear;
|
|
}
|
|
|
|
try
|
|
{
|
|
int port = LazyConfig.Instance.GetLocalPort(Global.InboundHttp);
|
|
int portSocks = LazyConfig.Instance.GetLocalPort(Global.InboundSocks);
|
|
int portPac = LazyConfig.Instance.GetLocalPort(ESysProxyType.Pac.ToString());
|
|
if (port <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
if (type == ESysProxyType.ForcedChange)
|
|
{
|
|
var strExceptions = $"{config.constItem.defIEProxyExceptions};{config.systemProxyExceptions}";
|
|
|
|
var strProxy = string.Empty;
|
|
if (Utils.IsNullOrEmpty(config.systemProxyAdvancedProtocol))
|
|
{
|
|
strProxy = $"{Global.Loopback}:{port}";
|
|
}
|
|
else
|
|
{
|
|
strProxy = config.systemProxyAdvancedProtocol
|
|
.Replace("{ip}", Global.Loopback)
|
|
.Replace("{http_port}", port.ToString())
|
|
.Replace("{socks_port}", portSocks.ToString());
|
|
}
|
|
SetIEProxy(true, strProxy, strExceptions);
|
|
}
|
|
else if (type == ESysProxyType.ForcedClear)
|
|
{
|
|
ResetIEProxy();
|
|
}
|
|
else if (type == ESysProxyType.Unchanged)
|
|
{
|
|
}
|
|
else if (type == ESysProxyType.Pac)
|
|
{
|
|
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
|
var strProxy = $"{Global.httpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
|
SetIEProxy(false, strProxy, "");
|
|
}
|
|
|
|
if (type != ESysProxyType.Pac)
|
|
{
|
|
PacHandler.Stop();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.SaveLog(ex.Message, ex);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void ResetIEProxy4WindowsShutDown()
|
|
{
|
|
try
|
|
{
|
|
//TODO To be verified
|
|
Utils.RegWriteValue(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", "ProxyEnable", 0);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
public static void SetIEProxy(bool global, string strProxy, string strExceptions)
|
|
{
|
|
string arguments = global
|
|
? $"global {strProxy} {strExceptions}"
|
|
: $"pac {strProxy}";
|
|
|
|
ExecSysproxy(arguments);
|
|
}
|
|
|
|
// set system proxy to 1 (null) (null) (null)
|
|
public static bool ResetIEProxy()
|
|
{
|
|
try
|
|
{
|
|
// clear user-wininet.json
|
|
//_userSettings = new SysproxyConfig();
|
|
//Save();
|
|
// clear system setting
|
|
ExecSysproxy("set 1 - - -");
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static void ExecSysproxy(string arguments)
|
|
{
|
|
// using event to avoid hanging when redirect standard output/error
|
|
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
|
|
// and http://blog.csdn.net/zhangweixing0/article/details/7356841
|
|
using AutoResetEvent outputWaitHandle = new(false);
|
|
using AutoResetEvent errorWaitHandle = new(false);
|
|
using Process process = new();
|
|
|
|
// Configure the process using the StartInfo properties.
|
|
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
|
|
process.StartInfo.Arguments = arguments;
|
|
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
|
|
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
|
process.StartInfo.UseShellExecute = false;
|
|
process.StartInfo.RedirectStandardError = true;
|
|
process.StartInfo.RedirectStandardOutput = true;
|
|
|
|
// Need to provide encoding info, or output/error strings we got will be wrong.
|
|
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
|
|
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
|
|
|
|
process.StartInfo.CreateNoWindow = true;
|
|
|
|
StringBuilder output = new(1024);
|
|
StringBuilder error = new(1024);
|
|
|
|
process.OutputDataReceived += (sender, e) =>
|
|
{
|
|
if (e.Data == null)
|
|
{
|
|
outputWaitHandle.Set();
|
|
}
|
|
else
|
|
{
|
|
output.AppendLine(e.Data);
|
|
}
|
|
};
|
|
process.ErrorDataReceived += (sender, e) =>
|
|
{
|
|
if (e.Data == null)
|
|
{
|
|
errorWaitHandle.Set();
|
|
}
|
|
else
|
|
{
|
|
error.AppendLine(e.Data);
|
|
}
|
|
};
|
|
try
|
|
{
|
|
process.Start();
|
|
|
|
process.BeginErrorReadLine();
|
|
process.BeginOutputReadLine();
|
|
|
|
process.WaitForExit();
|
|
}
|
|
catch (System.ComponentModel.Win32Exception e)
|
|
{
|
|
|
|
// log the arguments
|
|
throw new Exception(process.StartInfo.Arguments);
|
|
}
|
|
string stderr = error.ToString();
|
|
string stdout = output.ToString();
|
|
|
|
int exitCode = process.ExitCode;
|
|
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
|
|
{
|
|
throw new Exception(stderr);
|
|
}
|
|
|
|
//if (arguments == "query")
|
|
//{
|
|
// if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
|
|
// {
|
|
// throw new Exception("failed to query wininet settings");
|
|
// }
|
|
// _queryStr = stdout;
|
|
//}
|
|
}
|
|
|
|
|
|
}
|
|
}
|