1

I am trying to connect to external IP address but I am behind company firewall, so I need to connect over the proxy.

I run a test with curl:

curl -v https://IP_ADDRESS_OF_EXTERNAL_CLIENT:6125 -x http://MyComparyProxyAddress.com:8080 -U MYUSERNAME:MYPASSWORD

but I am failing to replicate aforementioned cUrl command in C#:

private static Socket CreateTunnelThruProxy(string destIP, int destPort)
        {
            string destUriWithPort = $"{destIP}:{destPort}";
            UriBuilder uriBuilder = new UriBuilder(destUriWithPort);
            Uri destUri = uriBuilder.Uri;

            var proxy = new WebProxy("http://MyComparyProxyAddress.com", 8080);
            proxy.UseDefaultCredentials = false;
            proxy.Credentials = new NetworkCredential("MYUSERNAME", "MYPASSWORD");
            WebRequest.DefaultWebProxy = proxy;

            IWebProxy webProxy = WebRequest.DefaultWebProxy;

            try
            {
                if (webProxy.IsBypassed(destUri))
                    return null;
            }
            catch (PlatformNotSupportedException)
            {
                // .NET Core doesn't support IWebProxy.IsBypassed
                // (because .NET Core doesn't have access to Windows-specific services, of course)
                return null;
            }

            Uri proxyUri = webProxy.GetProxy(destUri);
            if (proxyUri == null)
                return null;

            IPAddress[] proxyEntry = Dns.GetHostAddresses(proxyUri.Host);
            int iPort = proxyUri.Port;
            IPAddress address = proxyEntry.First(a => a.AddressFamily == AddressFamily.InterNetwork);
            IPEndPoint proxyEndPoint = new IPEndPoint(address, iPort);
            Socket socketThruProxy = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketThruProxy.Connect(proxyEndPoint);

            string proxyMsg = $"CONNECT {destIP}:{destPort} HTTP/1.1 \n\n";
            byte[] buffer = Encoding.ASCII.GetBytes(proxyMsg);
            byte[] buffer12 = new byte[50000];
            socketThruProxy.Send(buffer, buffer.Length, 0);
            int msg = socketThruProxy.Receive(buffer12, 50000, 0);
            string data;
            data = Encoding.ASCII.GetString(buffer12);
            int index = data.IndexOf("200");

            if (index < 0)
                throw new ApplicationException(
                    $"Connection failed to {destUriWithPort} through proxy server {proxyUri.ToString()}.");

            return socketThruProxy;
        }

I keep getting following information from my company proxy:

HTTP/1.1 407 Proxy Authentication Required
Proxy-Authenticate: NEGOTIATE
Proxy-Authenticate: NTLM
Proxy-Authenticate: BASIC realm="ztb"
Cache-Control: no-cache
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Proxy-Connection: close
Connection: close
Content-Length: 797

<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD>
<BODY>
<body bgcolor="#FFFFEA">
<blockquote>
<TABLE border=0 cellPadding=1 width="80%">
<TR><TD>
<FONT face="Verdana">
<big>Access Denied (authentication_failed)</big>
<BR>
<BR>
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana">
Your credentials could not be authenticated: "Credentials are missing.". You will not be permitted access until your credentials can be verified.
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana">
This is typically caused by an incorrect username and/or password, but could also be caused by network problems.
</FONT>
</TD></TR>
<TR><TD>
<FONT face="Verdana" SIZE=2>
<BR>
For assistance, contact your Tech Desk . PXFFM25
</FONT>
</TD></TR>
</TABLE>
</blockquote>
</FONT>
</BODY></HTML>

I can clearly see that webProxy object contains credentials set by me, the same credentials that are working with cUrl.

Also I am getting the same error when trying simply calling:

IWebProxy webProxy = WebRequest.GetSystemWebProxy();

instead of setting credentials manually, as per code snippet above. So it looks like my credentials are not taken into account....

Any ideas ?

Jack
  • 350
  • 2
  • 15
  • 1
    Do you need to be an Admin? Running inside VS you are not Admin unless you start VS by right click shortcut and select Run As Admin. – jdweng Jun 25 '21 at 14:18
  • I am not starting Visual Studio in an Admin mode, since this is blocked for me. However that should not be required, since "cUrl" works OK. But anyway, I tried running binaries as an admin, and I keep getting same exception. – Jack Jul 01 '21 at 13:55
  • 1
    I would try using HTTPS instead of HTTP. See -x option in following : https://curl.se/docs/manpage.html Try also default credentials : CredentialCache.DefaultCredentials; – jdweng Jul 01 '21 at 15:29
  • I tried https proxy, no luck. I am getting exactly same exception from proxy when trying with CredentialCache.DefaultCredentials. Which means that my attempts to override credentials manually (as per code snipped above) is not taken into account by proxy. – Jack Jul 02 '21 at 12:25
  • 1
    How long dies it take for error? If a proxy isn't found usually the code wait 30 seconds before the proxy error is reported. It think you are going to the wrong Domain. From cmd.exe >IPConfig/All which will give you the number of network adapters (IP) and masks. Also try with HTTP instead of HTTPS. You are inside the company firewall and may not need to secure connection. Curl may be going back to HTTP. what could be happening is Curl is using IPV4 and c# using IPV6. Do IPV4 say prefer? – jdweng Jul 02 '21 at 12:40
  • It definitely connect to the proxy, as I get immediate response (if I try incorrect proxy details then it timeouts after 20 seconds). It is IPV4, since my addressS.AddressFamily = InterNetwork, so IPV4. So definitely proxy gets hit by the code, I updated my question with the FULL response from proxy. – Jack Jul 02 '21 at 14:41
  • Workaround: https://stackoverflow.com/a/18570201/600135 – kol Jul 08 '21 at 12:54

5 Answers5

0

I tried this scenario before and it works with me by creating a custom proxy class that inherits IWebProxy

public class MyProxy : IWebProxy
    {
        public ICredentials Credentials
        {
            get { return new NetworkCredential("your username","your password"); }
            set { }
        }

        public Uri GetProxy(Uri destination)
        {
            return new Uri("http://MyComparyProxyAddress.com:8080");
        }

        public bool IsBypassed(Uri host)
        {
            return false;
        }
    } 

and in the app configuration file add this part inside the configuration node

  <system.net>
    <defaultProxy enabled="true" useDefaultCredentials="false">
      <module type="yournamespace.MyProxy, your assembly name" />
    </defaultProxy>
  </system.net>
MHassan
  • 415
  • 4
  • 9
  • unfortunately this encapsulation did not do the work, I keep getting same exception.. Please note that I send Socket message: socketThruProxy.Send(buffer, buffer.Length, 0); where buffer=$"CONNECT {destIP}:{destPort} HTTP/1.1 \n\n" – Jack Jul 09 '21 at 13:31
  • @Jack system.net configuration in the configuration file will work on all Net connections established by your app as a client either you connect through socket, web client, or connect to web services. however, I will try to simulate the case on my end and if it works for me I will update the answer. goodluck – MHassan Jul 09 '21 at 19:38
0

I'd add this as a comment if it would let me, but does adding the domain help? In the past when I've authenticated, I've had to make sure the domain is correct. Per Network Credential docs

There is a constructor that takes the domain or you can set it as a property.

Jon
  • 86
  • 1
  • 6
0

Do not try to remediate this issue within you code. Use a local proxy like https://github.com/genotrance/px for providing your user credentials to the enterprise proxy. Otherwise you will found one day a developer password within your source control.

ycrumeyrolle
  • 495
  • 4
  • 15
0

I've had this issue with one of my projects, the company uses a firewall (to be exact Barracuda's firewall). I've tried to set WebProxy and also set the machine proxy with no luck.

Here is how I solved it :

I've asked the security team to whitelist the IPs along with the ports that would be used for the service. so any outgoing or incoming connections won't be blocked. Then, from the application, I've set the proxy in web.config like this :

<system.net>
    <defaultProxy>
        <proxy usesystemdefault="False" proxyaddress="http://proxy_ip" bypassonlocal="False" />
    </defaultProxy>
</system.net>

Also, the same proxy is set on the server that the application is running on.

This made things work as expected.

After a week or so, the service stopped suddenly. When I checked the connection with Fiddler it showed me that the API were redirected to another server (different IP), which the firewall blocks it. So, I asked the security team to whitelist it as well, and the service was back to live again.

iSR5
  • 3,274
  • 2
  • 14
  • 13
0

This can be accomplished in the following way:

 if (IsProxyProvided(settings))
            {
                IPAddress[] proxyEntry = Dns.GetHostAddresses(settings.ProxyHost);
                IPAddress address = proxyEntry.First(a => a.AddressFamily == AddressFamily.InterNetwork);
                IPEndPoint proxyEndPoint = new IPEndPoint(address, settings.ProxyPort);
                socket.Connect(proxyEndPoint);

                if (AreProxyCredntialsProvided(settings))
                {
                    var basicAuthBase64 = Convert.ToBase64String(
                        Encoding.GetEncoding("ISO-8859-1").GetBytes($"{settings.ProxyUserName}:{settings.ProxyUserNamePassword}"));
                    var proxyMessage = $"Proxy-Authorization: {string.Format("Basic {0}", basicAuthBase64)} \r\n";
                    var keepAlive = "Connection: keep-alive\r\n";
                    var request = $"CONNECT {endpoint.Address}:{endpoint.Port} HTTP/1.1 \r\n" + proxyMessage + keepAlive + "\r\n";
                    byte[] buffer = Encoding.ASCII.GetBytes(request);
                    socket.Send(buffer, buffer.Length, 0);
                }
            }

Thanks to Victor Victor Stone who had similar issue here

Jack
  • 350
  • 2
  • 15