5

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.

Mudasir Mirza
  • 171
  • 3
  • 13

3 Answers3

1

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.

EricLaw
  • 56,563
  • 7
  • 151
  • 196
0

I got the similar problem with WebBrowser control while dealing with authentication and irritating "Windows security" window. First, set proxy address with WinINET and then call navigate method with your credentials. It helps to store proxy credentials per one process:

WebBrowser.Navigate("http://user:pass@geoip.hidemyass.com/");

WinINET method sets proxy address perfect, however your code uses INTERNET_OPTION_PER_CONNECTION_OPTION which is not suitable for your "global proxy" idea (as @EricLaw said). Try to work around with INTERNET_OPTION_PROXY (documentaion)

Furthermore there are four different approaches with no direct solution. But they are very handy.

Trinitron
  • 374
  • 3
  • 12
-1

Have a look at the WebProxy class and see if that allows you to do what you want?

use it in the following way (I'm going to assume that exceptions are separated by a ';'):

public static void SetProxy(string proxyAddress, string userName, string password, string exceptions)
{
    var credential = new NetworkCredential(userName, password);

    string[] bypassList = null;

    if (!string.IsNullOrEmpty(exceptions))
    {
        bypassList = exceptions.Split(';');
    }

    WebRequest.DefaultWebProxy = new WebProxy(proxyAddress, true, bypassList, credential);
}

to call the method:

SetProxy("http://proxy:8080", "user", "password", "http://site1;http://site2");
Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60
  • Hi @TrevorPilley is there any way to change the `ProxyEnable` checkbox. – Scorpion Feb 17 '12 at 12:20
  • Hi,I tried it the way you mentioned, but still no success. This function is not even setting the proxy server for IE or any other browser. – Mudasir Mirza Feb 17 '12 at 18:07
  • That won't set the proxy for IE but will for the .net application which is running it, if that's not what you wanted, sorry I missunderstood what you wanted. – Trevor Pilley Feb 17 '12 at 22:35
  • The application is setting proxy for IE, that is not the issue. The issue is I am unable to set the Proxy credentials for IE using C#. I am just stuck at this, cant get the Proxy Credentials properly set for IE using C# – Mudasir Mirza Feb 18 '12 at 13:05
  • @Hayer , The code I provided above can set the Proxy Server for IE and Chrome. Just pass "null" to this function and Proxy will be disabled. – Mudasir Mirza Feb 18 '12 at 13:09
  • hi @MudasirMirza, actually I want to make a window service to set `ProxyEnable` = true and `ProxyEnable` = falsey at specific times. is that possible with this method? – Scorpion Feb 27 '12 at 14:14
  • 1
    Hi, @Hayer, I can not say about Windows Service, but yes it is possible to enable disable proxy at any given time. However the main issue will be that only those softwares that system proxy will get the settings, softwares like Firefox and Safari might not get updated because they check their own little proxy settings. I did figure out a way of changing proxy for firefox. – Mudasir Mirza Feb 27 '12 at 18:33
  • Thanks @MudasirMirza, I only need it for IE and Chrome. – Scorpion Feb 28 '12 at 09:40