Files
Opportunity 70ec5df5b0 Add temp folder path selection (#1827)
* Translation
* Environment Variables support
2018-05-12 20:31:59 +08:00

178 lines
6.3 KiB
C#

using System;
using System.Diagnostics;
using System.IO;
using Shadowsocks.Controller;
using Shadowsocks.Properties;
using Shadowsocks.Model;
using System.Text;
using Newtonsoft.Json;
namespace Shadowsocks.Util.SystemProxy
{
public static class Sysproxy
{
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 Sysproxy()
{
try
{
FileManager.UncompressFile(Utils.GetTempPath("sysproxy.exe"),
Environment.Is64BitOperatingSystem ? Resources.sysproxy64_exe : Resources.sysproxy_exe);
}
catch (IOException e)
{
Logging.LogUsefulException(e);
}
}
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
{
Read();
if (!_userSettings.UserSettingsRecorded)
{
// record user settings
ExecSysproxy("query");
ParseQueryStr(_queryStr);
}
string arguments;
if (enable)
{
arguments = global
? $"global {proxyServer} <local>;localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*"
: $"pac {pacURL}";
}
else
{
// restore user settings
var flags = _userSettings.Flags;
var proxy_server = _userSettings.ProxyServer ?? "-";
var bypass_list = _userSettings.BypassList ?? "-";
var pac_url = _userSettings.PacUrl ?? "-";
arguments = $"set {flags} {proxy_server} {bypass_list} {pac_url}";
// have to get new settings
_userSettings.UserSettingsRecorded = false;
}
Save();
ExecSysproxy(arguments);
}
private static void ExecSysproxy(string arguments)
{
using (var process = new Process())
{
// 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;
process.Start();
var stderr = process.StandardError.ReadToEnd();
var stdout = process.StandardOutput.ReadToEnd();
process.WaitForExit();
var exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
throw new ProxyException(stderr);
}
if (arguments == "query")
{
if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
{
// we cannot get user settings
throw new ProxyException("failed to query wininet settings");
}
_queryStr = stdout;
}
}
}
private static void Save()
{
try
{
using (StreamWriter sw = new StreamWriter(File.Open(Utils.GetTempPath(_userWininetConfigFile), FileMode.Create)))
{
string jsonString = JsonConvert.SerializeObject(_userSettings, Formatting.Indented);
sw.Write(jsonString);
sw.Flush();
}
}
catch (IOException e)
{
Logging.LogUsefulException(e);
}
}
private static void Read()
{
try
{
string configContent = File.ReadAllText(Utils.GetTempPath(_userWininetConfigFile));
_userSettings = JsonConvert.DeserializeObject<SysproxyConfig>(configContent);
}
catch (Exception)
{
// Suppress all exceptions. finally block will initialize new user config settings.
}
finally
{
if (_userSettings == null) _userSettings = new SysproxyConfig();
}
}
private static void ParseQueryStr(string str)
{
string[] userSettingsArr = str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
_userSettings.Flags = userSettingsArr[0];
// handle output from WinINET
if (userSettingsArr[1] == "(null)") _userSettings.ProxyServer = null;
else _userSettings.ProxyServer = userSettingsArr[1];
if (userSettingsArr[2] == "(null)") _userSettings.BypassList = null;
else _userSettings.BypassList = userSettingsArr[2];
if (userSettingsArr[3] == "(null)") _userSettings.PacUrl = null;
else _userSettings.PacUrl = userSettingsArr[3];
_userSettings.UserSettingsRecorded = true;
}
}
}