|
|
@@ -0,0 +1,248 @@ |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
|
|
|
|
namespace Shadowsocks.Util.SystemProxy |
|
|
|
{ |
|
|
|
public enum InternetOptions |
|
|
|
{ |
|
|
|
Refresh = 37, |
|
|
|
SettingsChanged = 39, |
|
|
|
PerConnectionOption = 75, |
|
|
|
ProxySettingChanged = 95, |
|
|
|
} |
|
|
|
|
|
|
|
public enum InternetPerConnectionOptionEnum |
|
|
|
{ |
|
|
|
Flags = 1, |
|
|
|
ProxyServer = 2, |
|
|
|
ProxyBypass = 3, |
|
|
|
AutoConfigUrl = 4, |
|
|
|
AutoDiscovery = 5, |
|
|
|
AutoConfigSecondaryUrl = 6, |
|
|
|
AutoConfigReloadDelay = 7, |
|
|
|
AutoConfigLastDetectTime = 8, |
|
|
|
AutoConfigLastDetectUrl = 9, |
|
|
|
FlagsUI = 10, |
|
|
|
} |
|
|
|
|
|
|
|
[Flags] |
|
|
|
public enum InternetPerConnectionFlags |
|
|
|
{ |
|
|
|
Direct = 0x01, |
|
|
|
Proxy = 0x02, |
|
|
|
AutoProxyUrl = 0x04, |
|
|
|
AutoDetect = 0x08, |
|
|
|
} |
|
|
|
|
|
|
|
[StructLayout(LayoutKind.Explicit)] |
|
|
|
public struct InternetPerConnectionOptionUnion : IDisposable |
|
|
|
{ |
|
|
|
[FieldOffset(0)] |
|
|
|
public int dwValue; |
|
|
|
|
|
|
|
[FieldOffset(0)] |
|
|
|
public IntPtr pszValue; |
|
|
|
|
|
|
|
[FieldOffset(0)] |
|
|
|
public System.Runtime.InteropServices.ComTypes.FILETIME ftValue; |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
Dispose(true); |
|
|
|
GC.SuppressFinalize(this); |
|
|
|
} |
|
|
|
|
|
|
|
private void Dispose(bool disposing) |
|
|
|
{ |
|
|
|
if (disposing) |
|
|
|
{ |
|
|
|
if (pszValue != IntPtr.Zero) |
|
|
|
{ |
|
|
|
Marshal.FreeHGlobal(pszValue); |
|
|
|
pszValue = IntPtr.Zero; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)] |
|
|
|
public struct InternetPerConnectionOption |
|
|
|
{ |
|
|
|
public int dwOption; |
|
|
|
public InternetPerConnectionOptionUnion Value; |
|
|
|
} |
|
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] |
|
|
|
public struct InternetPerConnectionOptionList : IDisposable |
|
|
|
{ |
|
|
|
public int Size; |
|
|
|
|
|
|
|
// The connection to be set. NULL means LAN. |
|
|
|
public IntPtr Connection; |
|
|
|
|
|
|
|
public int OptionCount; |
|
|
|
public int OptionError; |
|
|
|
|
|
|
|
// List of INTERNET_PER_CONN_OPTIONs. |
|
|
|
public System.IntPtr pOptions; |
|
|
|
|
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
Dispose(true); |
|
|
|
GC.SuppressFinalize(this); |
|
|
|
} |
|
|
|
private void Dispose(bool disposing) |
|
|
|
{ |
|
|
|
if (disposing) |
|
|
|
{ |
|
|
|
if (Connection != IntPtr.Zero) |
|
|
|
{ |
|
|
|
Marshal.FreeHGlobal(Connection); |
|
|
|
Connection = IntPtr.Zero; |
|
|
|
} |
|
|
|
|
|
|
|
if (pOptions != IntPtr.Zero) |
|
|
|
{ |
|
|
|
Marshal.FreeHGlobal(pOptions); |
|
|
|
pOptions = IntPtr.Zero; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class WinINet |
|
|
|
{ |
|
|
|
// TODO: Save, Restore, |
|
|
|
// TODO: Query, Set, |
|
|
|
|
|
|
|
public static void ProxyGlobal(string server, string bypass) |
|
|
|
{ |
|
|
|
List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption> |
|
|
|
{ |
|
|
|
GetOption(InternetPerConnectionOptionEnum.FlagsUI,InternetPerConnectionFlags.Proxy), |
|
|
|
GetOption(InternetPerConnectionOptionEnum.ProxyServer,server), |
|
|
|
GetOption(InternetPerConnectionOptionEnum.ProxyBypass,bypass), |
|
|
|
}; |
|
|
|
Exec(options); |
|
|
|
} |
|
|
|
public static void ProxyPAC(string url) |
|
|
|
{ |
|
|
|
List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption> |
|
|
|
{ |
|
|
|
GetOption(InternetPerConnectionOptionEnum.FlagsUI,InternetPerConnectionFlags.AutoProxyUrl), |
|
|
|
GetOption(InternetPerConnectionOptionEnum.ProxyServer,url), |
|
|
|
}; |
|
|
|
Exec(options); |
|
|
|
} |
|
|
|
public static void Direct() |
|
|
|
{ |
|
|
|
List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption> |
|
|
|
{ |
|
|
|
GetOption(InternetPerConnectionOptionEnum.FlagsUI,InternetPerConnectionFlags.Direct), |
|
|
|
}; |
|
|
|
Exec(options); |
|
|
|
} |
|
|
|
|
|
|
|
private static InternetPerConnectionOption GetOption( |
|
|
|
InternetPerConnectionOptionEnum option, |
|
|
|
InternetPerConnectionFlags flag |
|
|
|
) |
|
|
|
{ |
|
|
|
return new InternetPerConnectionOption |
|
|
|
{ |
|
|
|
dwOption = (int)option, |
|
|
|
Value = |
|
|
|
{ |
|
|
|
dwValue = (int)flag, |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
private static InternetPerConnectionOption GetOption( |
|
|
|
InternetPerConnectionOptionEnum option, |
|
|
|
string param |
|
|
|
) |
|
|
|
{ |
|
|
|
return new InternetPerConnectionOption |
|
|
|
{ |
|
|
|
dwOption = (int)option, |
|
|
|
Value = |
|
|
|
{ |
|
|
|
pszValue = Marshal.StringToCoTaskMemAuto(param), |
|
|
|
} |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
private static void Exec(List<InternetPerConnectionOption> options) |
|
|
|
{ |
|
|
|
Exec(options, null); |
|
|
|
foreach (var conn in RAS.GetAllConnections()) |
|
|
|
{ |
|
|
|
Exec(options, conn); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static void Exec(List<InternetPerConnectionOption> options, string connName) |
|
|
|
{ |
|
|
|
int len = options.Sum(o => Marshal.SizeOf(o)); |
|
|
|
|
|
|
|
IntPtr buf = Marshal.AllocCoTaskMem(len); |
|
|
|
IntPtr cur = buf; |
|
|
|
|
|
|
|
foreach (var o in options) |
|
|
|
{ |
|
|
|
Marshal.StructureToPtr(o, cur, false); |
|
|
|
cur += Marshal.SizeOf(o); |
|
|
|
} |
|
|
|
InternetPerConnectionOptionList optionList = new InternetPerConnectionOptionList |
|
|
|
{ |
|
|
|
pOptions = buf, |
|
|
|
Connection = string.IsNullOrEmpty(connName) |
|
|
|
? IntPtr.Zero |
|
|
|
: Marshal.StringToHGlobalAuto(connName), |
|
|
|
OptionCount = options.Count, |
|
|
|
OptionError = 0, |
|
|
|
}; |
|
|
|
int listSize = Marshal.SizeOf(optionList); |
|
|
|
optionList.Size = listSize; |
|
|
|
|
|
|
|
IntPtr unmanagedList = Marshal.AllocCoTaskMem(listSize); |
|
|
|
Marshal.StructureToPtr(optionList, unmanagedList, true); |
|
|
|
|
|
|
|
bool ok = InternetSetOption( |
|
|
|
IntPtr.Zero, |
|
|
|
(int)InternetOptions.PerConnectionOption, |
|
|
|
unmanagedList, |
|
|
|
listSize |
|
|
|
); |
|
|
|
|
|
|
|
Marshal.FreeCoTaskMem(buf); |
|
|
|
Marshal.FreeCoTaskMem(unmanagedList); |
|
|
|
|
|
|
|
if (!ok) throw new Exception(); |
|
|
|
ok = InternetSetOption( |
|
|
|
IntPtr.Zero, |
|
|
|
(int)InternetOptions.ProxySettingChanged, |
|
|
|
IntPtr.Zero, |
|
|
|
0 |
|
|
|
); |
|
|
|
if (!ok) throw new Exception(); |
|
|
|
ok = InternetSetOption( |
|
|
|
IntPtr.Zero, |
|
|
|
(int)InternetOptions.Refresh, |
|
|
|
IntPtr.Zero, |
|
|
|
0 |
|
|
|
); |
|
|
|
if (!ok) throw new Exception(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] |
|
|
|
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); |
|
|
|
} |
|
|
|
|
|
|
|
} |