在 Windows 中以编程方式更改 DSL 连接的代理设置

在 Windows 中以编程方式更改 DSL 连接的代理设置

问题描述:

我目前正在编写一个需要更改 Windows 代理设置的 C# 代理程序.每个在线指南仅更改 LAN 连接的代理设置(即在 NAT 后面).这是一个问题,因为中国的许多用户(我的目标受众)直接将 PPPoE 连接从他们的调制解调器连接到他们的计算机,并使用 PPPoE 软件拨号到 DSL(是的,这是糟糕的安全性,所有侦听端口对世界,但事情就是这样).

I'm currently writing a C# proxy program that needs to change Windows proxy settings. Every single guide online only changes the proxy settings for a LAN connection (i.e. behind a NAT). This is a problem, since many users in China (my target audience) directly hook up PPPoE connections from their modem into their computer and use PPPoE software to dial up to DSL (yes, this is sucky security, with all listening ports visible to the world, but that's the way things are).

我将如何更改 DSL 代理?这令人担忧,因为查看我的用户统计信息,大约 20% 的人没有自动更改代理设置.

How would I change the DSL proxy? This is worrying, as looking at my user stats ~20% of people are not getting the proxy settings changed automatically.

这是一个实用程序示例类.你像这样使用它:

Here is a utility sample class that does it. You use it like this:

static void Main(string[] args)
{
    // read direct proxy server (return null if there isn't) of the connection named "MyConn"
    string server = ProxyUtilities.GetDirectProxyServer("MyConn");

    // set a direct proxy server (set to null to disable) to the connection named "MyConn"
    ProxyUtilities.SetDirectProxyServer("MyConn", "myproxy:8080");
}

还有实用程序类:

public static class ProxyUtilities
{
    public static string GetDirectProxyServer(string connectionName)
    {
        List<INTERNET_PER_CONN_OPTION> options = new List<INTERNET_PER_CONN_OPTION>();
        INTERNET_PER_CONN_OPTION option = new INTERNET_PER_CONN_OPTION();
        option.dwOption = INTERNET_PER_CONN_PROXY_SERVER;
        options.Add(option);

        option = new INTERNET_PER_CONN_OPTION();
        option.dwOption = INTERNET_PER_CONN_FLAGS;
        options.Add(option);

        using (var list = INTERNET_PER_CONN_OPTION_LIST.From(connectionName, options))
        {
            int size = list.dwSize;
            if (!InternetQueryOption(IntPtr.Zero, INTERNET_OPTION_PER_CONNECTION_OPTION, list, ref size))
                throw new Win32Exception(Marshal.GetLastWin32Error());

            List<INTERNET_PER_CONN_OPTION> outOptions = list.Options;
            string proxyServer = null;
            if ((outOptions[1].Value.dwValue & PROXY_TYPE_PROXY) != 0)
            {
                proxyServer = Marshal.PtrToStringUni(outOptions[0].Value.pszValue);
            }
            Marshal.FreeHGlobal(outOptions[0].Value.pszValue);
            return proxyServer;
        }
    }

    public static void SetDirectProxyServer(string connectionName, string proxyServer)
    {
        List<INTERNET_PER_CONN_OPTION> options = new List<INTERNET_PER_CONN_OPTION>();
        INTERNET_PER_CONN_OPTION option = new INTERNET_PER_CONN_OPTION();
        option.dwOption = INTERNET_PER_CONN_PROXY_SERVER;
        option.Value.pszValue = proxyServer == null ? IntPtr.Zero : Marshal.StringToHGlobalUni(proxyServer);
        options.Add(option);

        option = new INTERNET_PER_CONN_OPTION();
        option.dwOption = INTERNET_PER_CONN_FLAGS;
        option.Value.dwValue = proxyServer == null ? PROXY_TYPE_DIRECT : PROXY_TYPE_PROXY;
        options.Add(option);

        try
        {
            using (var list = INTERNET_PER_CONN_OPTION_LIST.From(connectionName, options))
            {
                int size = list.dwSize;
                if (!InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PER_CONNECTION_OPTION, list, size))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
        finally
        {
            Marshal.FreeHGlobal(option.Value.pszValue);
        }
    }

    private const int INTERNET_OPTION_PER_CONNECTION_OPTION = 75;
    private const int INTERNET_PER_CONN_FLAGS = 1;
    private const int INTERNET_PER_CONN_PROXY_SERVER = 2;
    private const int PROXY_TYPE_DIRECT = 0x00000001;
    private const int PROXY_TYPE_PROXY = 0x00000002;

    [StructLayout(LayoutKind.Explicit)]
    private struct INTERNET_PER_CONN_OPTION_Value
    {
        [FieldOffset(0)]
        public int dwValue;
        [FieldOffset(0)]
        public IntPtr pszValue;
        [FieldOffset(0)]
        public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct INTERNET_PER_CONN_OPTION
    {
        public int dwOption;
        public INTERNET_PER_CONN_OPTION_Value Value;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private class INTERNET_PER_CONN_OPTION_LIST : IDisposable
    {
        public int dwSize;
        public string pszConnection;
        public int dwOptionCount;
        public int dwOptionError;
        public IntPtr pOptions;

        public static INTERNET_PER_CONN_OPTION_LIST From(string name, IEnumerable<INTERNET_PER_CONN_OPTION> options)
        {
            INTERNET_PER_CONN_OPTION_LIST list = new INTERNET_PER_CONN_OPTION_LIST();
            list.pszConnection = name;
            list.pOptions = Marshal.AllocCoTaskMem(options.Sum(o => Marshal.SizeOf(o)));
            IntPtr current = list.pOptions;
            foreach (var option in options)
            {
                Marshal.StructureToPtr(option, current, false);
                current += Marshal.SizeOf(option);
            }
            list.dwSize = Marshal.SizeOf(list);
            list.dwOptionCount = options.Count();
            return list;
        }

        public List<INTERNET_PER_CONN_OPTION> Options
        {
            get
            {
                List<INTERNET_PER_CONN_OPTION> options = new List<INTERNET_PER_CONN_OPTION>();
                if (pOptions != IntPtr.Zero)
                {
                    IntPtr current = pOptions;
                    for (int i = 0; i < dwOptionCount; i++)
                    {
                        INTERNET_PER_CONN_OPTION option = (INTERNET_PER_CONN_OPTION)Marshal.PtrToStructure(current, typeof(INTERNET_PER_CONN_OPTION));
                        current += Marshal.SizeOf(option);
                        options.Add(option);
                    }
                }
                return options;
            }
        }

        public void Dispose()
        {
            if (pOptions != null)
            {
                Marshal.FreeCoTaskMem(pOptions);
                pOptions = IntPtr.Zero;
            }
        }
    }

    [DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private extern static bool InternetQueryOption(IntPtr hInternet, int dwOption, INTERNET_PER_CONN_OPTION_LIST list, ref int lpdwBufferLength);

    [DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, INTERNET_PER_CONN_OPTION_LIST list, int lpdwBufferLength);
}