mirror of https://github.com/2dust/v2rayN
Fixed Issue #3875 that ProxySetting doesn't support PPPoE connection. Remove sysproxy.exe, which is the unnecessary workaround.
parent
1d0e8434ad
commit
babb548c22
|
@ -1,37 +1,68 @@
|
|||
using Microsoft.Win32;
|
||||
using System.Runtime.InteropServices;
|
||||
using static v2rayN.Handler.ProxySetting.InternetConnectionOption;
|
||||
|
||||
namespace v2rayN.Handler
|
||||
{
|
||||
internal class ProxySetting
|
||||
{
|
||||
/// <summary>
|
||||
// set to use no proxy
|
||||
/// </summary>
|
||||
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||
public static bool UnsetProxy()
|
||||
{
|
||||
return SetProxy(null, null, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set system proxy settings
|
||||
/// </summary>
|
||||
/// <param name="strProxy"> proxy address</param>
|
||||
/// <param name="exceptions">exception addresses that do not use proxy</param>
|
||||
/// <param name="type">type of proxy defined in PerConnFlags
|
||||
/// PROXY_TYPE_DIRECT = 0x00000001, // direct connection (no proxy)
|
||||
/// PROXY_TYPE_PROXY = 0x00000002, // via named proxy
|
||||
/// PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy script URL
|
||||
/// PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
||||
/// </param>
|
||||
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||
/// <returns>true: one of connnection is successfully updated proxy settings</returns>
|
||||
public static bool SetProxy(string? strProxy, string? exceptions, int type)
|
||||
{
|
||||
// set proxy for LAN
|
||||
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
|
||||
// set proxy for dial up connections
|
||||
var connections = EnumerateRasEntries();
|
||||
foreach (var connection in connections)
|
||||
{
|
||||
result |= SetConnectionProxy(connection, strProxy, exceptions, type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
||||
{
|
||||
InternetPerConnOptionList list = new();
|
||||
|
||||
int optionCount = 1;
|
||||
if (type == 1)
|
||||
if (type == 1) // No proxy
|
||||
{
|
||||
optionCount = 1;
|
||||
}
|
||||
else if (type is 2 or 4)
|
||||
else if (type is 2 or 4) // named proxy or autoproxy script URL
|
||||
{
|
||||
optionCount = Utils.IsNullOrEmpty(exceptions) ? 2 : 3;
|
||||
}
|
||||
|
||||
int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
|
||||
PerConnOption m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
||||
if (type == 2)
|
||||
if (type == 2) // named proxy
|
||||
{
|
||||
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
|
||||
m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER;
|
||||
}
|
||||
else if (type == 4)
|
||||
else if (type == 4) // autoproxy script url
|
||||
{
|
||||
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL);
|
||||
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
|
||||
|
@ -47,24 +78,31 @@ namespace v2rayN.Handler
|
|||
if (optionCount > 1)
|
||||
{
|
||||
options[1].m_Option = m_Option;
|
||||
options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy);
|
||||
options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy); // !! remember to deallocate memory 1
|
||||
// except for these addresses ...
|
||||
if (optionCount > 2)
|
||||
{
|
||||
options[2].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_BYPASS;
|
||||
options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions);
|
||||
options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions); // !! remember to deallocate memory 2
|
||||
}
|
||||
}
|
||||
|
||||
// default stuff
|
||||
list.dwSize = Marshal.SizeOf(list);
|
||||
list.szConnection = IntPtr.Zero;
|
||||
if (connectionName != null)
|
||||
{
|
||||
list.szConnection = Marshal.StringToHGlobalAuto(connectionName); // !! remember to deallocate memory 3
|
||||
}
|
||||
else
|
||||
{
|
||||
list.szConnection = IntPtr.Zero;
|
||||
}
|
||||
list.dwOptionCount = options.Length;
|
||||
list.dwOptionError = 0;
|
||||
|
||||
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
||||
// make a pointer out of all that ...
|
||||
IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length);
|
||||
IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
||||
// copy the array over into that spot in memory ...
|
||||
for (int i = 0; i < options.Length; ++i)
|
||||
{
|
||||
|
@ -83,26 +121,82 @@ namespace v2rayN.Handler
|
|||
list.options = optionsPtr;
|
||||
|
||||
// and then make a pointer out of the whole list
|
||||
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize);
|
||||
IntPtr ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
||||
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
||||
|
||||
// and finally, call the API method!
|
||||
int returnvalue = NativeMethods.InternetSetOption(IntPtr.Zero,
|
||||
bool isSuccess = NativeMethods.InternetSetOption(IntPtr.Zero,
|
||||
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
||||
ipcoListPtr, list.dwSize) ? -1 : 0;
|
||||
if (returnvalue == 0)
|
||||
ipcoListPtr, list.dwSize);
|
||||
int returnvalue = 0; // ERROR_SUCCESS
|
||||
if (!isSuccess)
|
||||
{ // get the error codes, they might be helpful
|
||||
returnvalue = Marshal.GetLastWin32Error();
|
||||
returnvalue = Marshal.GetLastPInvokeError();
|
||||
}
|
||||
// FREE the data ASAP
|
||||
Marshal.FreeCoTaskMem(optionsPtr);
|
||||
Marshal.FreeCoTaskMem(ipcoListPtr);
|
||||
if (returnvalue > 0)
|
||||
{ // throw the error codes, they might be helpful
|
||||
//throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
else
|
||||
{
|
||||
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
||||
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
|
||||
NativeMethods.InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
|
||||
}
|
||||
|
||||
return (returnvalue < 0);
|
||||
// FREE the data ASAP
|
||||
if(list.szConnection != IntPtr.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
||||
if (optionCount > 1)
|
||||
{
|
||||
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
||||
if (optionCount > 2)
|
||||
{
|
||||
Marshal.FreeHGlobal(options[2].m_Value.m_StringPtr); // release mem 2
|
||||
}
|
||||
}
|
||||
Marshal.FreeCoTaskMem(optionsPtr); // release mem 4
|
||||
Marshal.FreeCoTaskMem(ipcoListPtr); // release mem 5
|
||||
if (returnvalue != 0)
|
||||
{
|
||||
// throw the error codes, they might be helpful
|
||||
throw new ApplicationException($"Set Internet Proxy failed with error code: {Marshal.GetLastWin32Error()}" );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve list of connections including LAN and WAN to support PPPoE connection
|
||||
/// </summary>
|
||||
/// <returns>A list of RAS connection names. May be empty list if no dial up connection.</returns>
|
||||
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||
private static IEnumerable<string> EnumerateRasEntries()
|
||||
{
|
||||
int entries = 0;
|
||||
// attempt to query with 1 entry buffer
|
||||
RASENTRYNAME[] rasEntryNames = new RASENTRYNAME[1];
|
||||
int bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||
|
||||
uint result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
||||
// increase buffer if the buffer is not large enough
|
||||
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
|
||||
{
|
||||
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
|
||||
for (int i = 0; i < rasEntryNames.Length; i++)
|
||||
{
|
||||
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||
}
|
||||
|
||||
result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
||||
}
|
||||
if (result == 0)
|
||||
{
|
||||
var entryNames = new List<string>();
|
||||
for (int i = 0; i < entries; i++)
|
||||
{
|
||||
entryNames.Add(rasEntryNames[i].szEntryName);
|
||||
}
|
||||
|
||||
return entryNames;
|
||||
}
|
||||
throw new ApplicationException($"RasEnumEntries failed with error code: {result}");
|
||||
}
|
||||
|
||||
#region WinInet structures
|
||||
|
@ -145,6 +239,25 @@ namespace v2rayN.Handler
|
|||
[FieldOffset(0)]
|
||||
public IntPtr m_StringPtr;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct RASENTRYNAME
|
||||
{
|
||||
public int dwSize;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
|
||||
public string szEntryName;
|
||||
|
||||
public int dwFlags;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH + 1)]
|
||||
public string szPhonebookPath;
|
||||
}
|
||||
|
||||
// Constants
|
||||
public const int RAS_MaxEntryName = 256;
|
||||
public const int MAX_PATH = 260; // Standard MAX_PATH value in Windows
|
||||
|
||||
}
|
||||
|
||||
#endregion WinInet structures
|
||||
|
@ -156,7 +269,9 @@ namespace v2rayN.Handler
|
|||
//
|
||||
public enum InternetOption : uint
|
||||
{
|
||||
INTERNET_OPTION_PER_CONNECTION_OPTION = 75
|
||||
INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
|
||||
INTERNET_OPTION_REFRESH = 37,
|
||||
INTERNET_OPTION_SETTINGS_CHANGED = 39
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -182,6 +297,12 @@ namespace v2rayN.Handler
|
|||
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
|
||||
}
|
||||
|
||||
public enum ErrorCode : uint
|
||||
{
|
||||
ERROR_BUFFER_TOO_SMALL = 603,
|
||||
ERROR_INVALID_SIZE = 632
|
||||
}
|
||||
|
||||
#endregion WinInet enums
|
||||
|
||||
internal static class NativeMethods
|
||||
|
@ -189,6 +310,14 @@ namespace v2rayN.Handler
|
|||
[DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength);
|
||||
[DllImport("Rasapi32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern uint RasEnumEntries(
|
||||
string? reserved, // Reserved, must be null
|
||||
string? lpszPhonebook, // Pointer to full path and filename of phone-book file. If this parameter is NULL, the entries are enumerated from all the remote access phone-book files
|
||||
[In, Out] RASENTRYNAME[]? lprasentryname, // Buffer to receive RAS entry names
|
||||
ref int lpcb, // Size of the buffer
|
||||
ref int lpcEntries // Number of entries written to the buffer
|
||||
);
|
||||
}
|
||||
|
||||
//判断是否使用代理
|
||||
|
|
|
@ -34,15 +34,7 @@ namespace v2rayN.Handler
|
|||
|
||||
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)
|
||||
|
@ -79,13 +71,11 @@ namespace v2rayN.Handler
|
|||
.Replace("{http_port}", port.ToString())
|
||||
.Replace("{socks_port}", portSocks.ToString());
|
||||
}
|
||||
ProxySetting.SetProxy(strProxy, strExceptions, 2);
|
||||
SetIEProxy(true, strProxy, strExceptions);
|
||||
ProxySetting.SetProxy(strProxy, strExceptions, 2); // set a named proxy
|
||||
}
|
||||
else if (type == ESysProxyType.ForcedClear)
|
||||
{
|
||||
ProxySetting.UnsetProxy();
|
||||
ResetIEProxy();
|
||||
ProxySetting.UnsetProxy(); // set to no proxy
|
||||
}
|
||||
else if (type == ESysProxyType.Unchanged)
|
||||
{
|
||||
|
@ -94,8 +84,7 @@ namespace v2rayN.Handler
|
|||
{
|
||||
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
|
||||
var strProxy = $"{Global.httpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
|
||||
ProxySetting.SetProxy(strProxy, "", 4);
|
||||
SetIEProxy(false, strProxy, "");
|
||||
ProxySetting.SetProxy(strProxy, "", 4); // use pac script url for auto-config proxy
|
||||
}
|
||||
|
||||
if (type != ESysProxyType.Pac)
|
||||
|
@ -121,102 +110,5 @@ namespace v2rayN.Handler
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
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 void ResetIEProxy()
|
||||
{
|
||||
ExecSysproxy("set 1 - - -");
|
||||
}
|
||||
|
||||
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;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -219,25 +219,5 @@ namespace v2rayN.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] sysproxy_exe {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("sysproxy_exe", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找 System.Byte[] 类型的本地化资源。
|
||||
/// </summary>
|
||||
internal static byte[] sysproxy64_exe {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("sysproxy64_exe", resourceCulture);
|
||||
return ((byte[])(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,12 +118,6 @@
|
|||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="sysproxy_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\sysproxy.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="sysproxy64_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\resources\sysproxy64.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name="NotifyIcon1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\NotifyIcon1.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue