Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set Proxy UserName and Password using Wininet in C#

Tags:

c#

This is my first question in Stack Overflow. I have had great help from this site.

I am working on an application in C# on .NET 2010. I am trying to set system wide proxy server for http requests. Proxy Server is a Squid based proxy with "basic" authentication enabled. I have been able to set the proxy of IE.

Now after proxy is set in IE, IE asks for username and password for proxy, and now I am trying to automate this functionality, and for last 1 week I have been unable to get it working and have been searching internet but still no success.

Below is the code I am using to set IE proxy.

public static bool SetProxy(string strProxy, string username, string password, string exceptions)
    {

        InternetPerConnOptionList list = new InternetPerConnOptionList();

        int optionCount = string.IsNullOrEmpty(strProxy) ? 1 : (string.IsNullOrEmpty(exceptions) ? 2 : 3);
        InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
        // USE a proxy server ...
        options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
        options[0].m_Value.m_Int = (int)((optionCount < 2) ? PerConnFlags.PROXY_TYPE_DIRECT : (PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY));
        // use THIS proxy server
        if (optionCount > 1)
        {
            options[1].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER;
            options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy);
            // 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);
            }
        }

        // default stuff
        list.dwSize = Marshal.SizeOf(list);
        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);
        // copy the array over into that spot in memory ...
        for (int i = 0; i < options.Length; ++i)
        {
            IntPtr opt = new IntPtr(optionsPtr.ToInt32() + (i * optSize));
            Marshal.StructureToPtr(options[i], opt, false);
        }

        list.options = optionsPtr;

        // and then make a pointer out of the whole list
        IntPtr ipcoListPtr = Marshal.AllocCoTaskMem((Int32)list.dwSize);
        Marshal.StructureToPtr(list, ipcoListPtr, false);

        // and finally, call the API method!
        int returnvalue = NativeMethods.InternetSetOption(IntPtr.Zero,
           InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
           ipcoListPtr, list.dwSize) ? -1 : 0;
        if (returnvalue == 0)
        {  // get the error codes, they might be helpful
            returnvalue = Marshal.GetLastWin32Error();
        }
        // 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());
        }

        return (returnvalue < 0);
    }
}

#region WinInet structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetPerConnOptionList
{
    public int dwSize;               // size of the INTERNET_PER_CONN_OPTION_LIST struct
    public IntPtr szConnection;         // connection name to set/query options
    public int dwOptionCount;        // number of options to set/query
    public int dwOptionError;           // on error, which option failed
    //[MarshalAs(UnmanagedType.)]
    public IntPtr options;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption
{
    static readonly int Size;
    public PerConnOption m_Option;
    public InternetConnectionOptionValue m_Value;
    static InternetConnectionOption()
    {
        InternetConnectionOption.Size = Marshal.SizeOf(typeof(InternetConnectionOption));
    }

    // Nested Types
    [StructLayout(LayoutKind.Explicit)]
    public struct InternetConnectionOptionValue
    {
        // Fields
        [FieldOffset(0)]
        public System.Runtime.InteropServices.ComTypes.FILETIME m_FileTime;
        [FieldOffset(0)]
        public int m_Int;
        [FieldOffset(0)]
        public IntPtr m_StringPtr;
    }
}
#endregion

#region WinInet enums
//
// options manifests for Internet{Query|Set}Option
//
public enum InternetOption : uint
{
    INTERNET_OPTION_PER_CONNECTION_OPTION = 75
}

//
// Options used in INTERNET_PER_CONN_OPTON struct
//
public enum PerConnOption
{
    INTERNET_PER_CONN_FLAGS = 1, // Sets or retrieves the connection type. The Value member will contain one or more of the values from PerConnFlags 
    INTERNET_PER_CONN_PROXY_SERVER = 2, // Sets or retrieves a string containing the proxy servers.  
    INTERNET_PER_CONN_PROXY_BYPASS = 3, // Sets or retrieves a string containing the URLs that do not use the proxy server.  
    INTERNET_PER_CONN_AUTOCONFIG_URL = 4//, // Sets or retrieves a string containing the URL to the automatic configuration script.  
}

//
// PER_CONN_FLAGS
//
[Flags]
public enum PerConnFlags
{
    PROXY_TYPE_DIRECT = 0x00000001,  // direct to net
    PROXY_TYPE_PROXY = 0x00000002,  // via named proxy
    PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,  // autoproxy URL
    PROXY_TYPE_AUTO_DETECT = 0x00000008   // use autoproxy detection
}
#endregion

internal static class NativeMethods
{
    [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);
}

Any help in getting this functionality working would be greatly appreciated.

Regards, Mudasir Mirza.

like image 852
Mudasir Mirza Avatar asked Nov 25 '22 03:11

Mudasir Mirza


1 Answers

When you set a proxy for WinINET, there's no way to store a "global" proxy username and password that all clients will benefit from. You can only cache this username/password on a per-process basis. In the process, you can use the InternetSetOption API to provide the username and password. This will only set the password for WinINET, and not for .NET or other HTTP stacks.

like image 176
EricLaw Avatar answered Jan 08 '23 10:01

EricLaw