using System.Windows.Forms; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.IO; using Shadowsocks.Model; namespace Shadowsocks.Controller { public static class SystemProxy { [DllImport("wininet.dll")] public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); public const int INTERNET_OPTION_SETTINGS_CHANGED = 39; public const int INTERNET_OPTION_REFRESH = 37; static bool _settingsReturn, _refreshReturn; public static void NotifyIE() { // These lines implement the Interface in the beginning of program // They cause the OS to refresh the settings, causing IP to realy update _settingsReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); _refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); } private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public static long ToUnixEpochMilliseconds(this DateTime dt) => (long)(dt - UnixEpoch).TotalMilliseconds; private static string GetTimestamp(DateTime value) { return value.ToString("yyyyMMddHHmmssfff"); } public static void Update(Configuration config, bool forceDisable) { bool global = config.global; bool enabled = config.enabled; if (forceDisable) { enabled = false; } try { var registry = Registry.CurrentUser .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); if (enabled) { if (global) { registry.SetValue("ProxyEnable", 1); registry.SetValue("ProxyServer", "127.0.0.1:" + config.localPort.ToString()); registry.SetValue("AutoConfigURL", ""); } else { string pacUrl; if (config.useOnlinePac && !config.pacUrl.IsNullOrEmpty()) pacUrl = config.pacUrl; else pacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}"; registry.SetValue("ProxyEnable", 0); var readProxyServer = registry.GetValue("ProxyServer"); registry.SetValue("ProxyServer", ""); registry.SetValue("AutoConfigURL", pacUrl); } } else { registry.SetValue("ProxyEnable", 0); registry.SetValue("ProxyServer", ""); registry.SetValue("AutoConfigURL", ""); } //Set AutoDetectProxy IEAutoDetectProxy(!enabled); NotifyIE(); //Must Notify IE first, or the connections do not chanage CopyProxySettingFromLan(); } catch (Exception e) { Logging.LogUsefulException(e); // TODO this should be moved into views MessageBox.Show(I18N.GetString("Failed to update registry")); } } private static void CopyProxySettingFromLan() { var registry = Registry.CurrentUser .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true); var defaultValue = registry.GetValue("DefaultConnectionSettings"); try { var connections = registry.GetValueNames(); foreach (var each in connections) { switch (each.ToUpperInvariant()) { case "DEFAULTCONNECTIONSETTINGS": case "LAN CONNECTION": case "SAVEDLEGACYSETTINGS": continue; default: //set all the connections's proxy as the lan registry.SetValue(each, defaultValue); continue; } } NotifyIE(); } catch (IOException e) { Logging.LogUsefulException(e); } } /// /// Checks or unchecks the IE Options Connection setting of "Automatically detect Proxy" /// /// Provide 'true' if you want to check the 'Automatically detect Proxy' check box. To uncheck, pass 'false' private static void IEAutoDetectProxy(bool set) { var registry = Registry.CurrentUser .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true); var defConnection = (byte[])registry.GetValue("DefaultConnectionSettings"); var savedLegacySetting = (byte[])registry.GetValue("SavedLegacySettings"); const int versionOffset = 4; const int optionsOffset = 8; if (set) { defConnection[optionsOffset] = (byte)(defConnection[optionsOffset] | 8); savedLegacySetting[optionsOffset] = (byte)(savedLegacySetting[optionsOffset] | 8); } else { defConnection[optionsOffset] = (byte)(defConnection[optionsOffset] & ~8); savedLegacySetting[optionsOffset] = (byte)(savedLegacySetting[optionsOffset] & ~8); } BitConverter.GetBytes( unchecked(BitConverter.ToUInt32(defConnection, versionOffset) + 1)) .CopyTo(defConnection, versionOffset); BitConverter.GetBytes( unchecked(BitConverter.ToUInt32(savedLegacySetting, versionOffset) + 1)) .CopyTo(savedLegacySetting, versionOffset); registry.SetValue("DefaultConnectionSettings", defConnection); registry.SetValue("SavedLegacySettings", savedLegacySetting); } } }