1

So I've implemented various approaches of the Ping Class including the most comprehensive one I found thanks to Vinjay B R. However, I can't seem to get any of the solutions to work in production. I can get it to work in VS 2015, but that's not saying much because I don't think the PING even leaves my network (I'm definitely not an expert in Networking so this is an assumption). I also had to implement the Split(":") approach below taking only array element 0 because if I don't, the IPAddress class captures an IP address with ":4321" on the tail end of the core IPAddress. I've tried the full address and the truncated address but neither approach works. I've used the cmd.exe Ping command with the truncated address to check both, I can only accomplish the ping with the truncated one so I've left the Split() in play. I'm at a loss, hopefully someone see's a elephant. My production server is Azure if that helps?

Currently it's throwing the PingException catch.

 public class PingTest
{

    public void Pinger()
    {

        SpeedTest Test = new SpeedTest();

        IPAddress ip = new IPAddress();

        var clientIP = ip.GetIPAddress();

        string[] IPAddresses = clientIP.Split(':');

        string address = IPAddresses[0];

        //set the ping options, TTL 128
        PingOptions pingOptions = new PingOptions(128, true);

        //create a new ping instance
        Ping ping = new Ping();

        //32 byte buffer (create empty)
        byte[] buffer = new byte[32];


        //here we will ping the host 4 times (standard)
        for (int i = 0; i < 4; i++)
        {
            try
            {
                //send the ping 4 times to the host and record the returned data.
                //The Send() method expects 4 items:
                //1) The IPAddress we are pinging
                //2) The timeout value
                //3) A buffer (our byte array)
                //4) PingOptions
                PingReply pingReply = ping.Send(address, 1000, buffer, pingOptions);

                //make sure we dont have a null reply
                if (!(pingReply == null))
                {
                    switch (pingReply.Status)
                    {
                        case IPStatus.Success:
                            Test.Address = pingReply.Address.ToString();
                            Test.ResponseTime = pingReply.RoundtripTime.ToString() + " ms";
                            Test.Status = pingReply.Status.ToString();
                            Test.UserId = User.Identity.GetUserId();
                            Test.TestDate = DateTime.Now;
                            Test.TestType = "Ping";
                            break;
                        case IPStatus.TimedOut:
                            Test.Address = pingReply.Address.ToString();
                            Test.ResponseTime = "";
                            Test.Status = "Connection has timed out...";
                            Test.UserId = User.Identity.GetUserId();
                            Test.TestDate = DateTime.Now;
                            Test.TestType = "Ping";
                            break;
                        default:
                            Test.Address = pingReply.Address.ToString();
                            Test.ResponseTime = "";
                            Test.Status = pingReply.Status.ToString();
                            Test.UserId = User.Identity.GetUserId();
                            Test.TestDate = DateTime.Now;
                            Test.TestType = "Ping";
                            break;
                    }
                }
                else
                {
                    Test.Address = pingReply.Address.ToString();
                    Test.ResponseTime = "";
                    Test.Status = "Connection failed for an unknown reason...";
                    Test.UserId = User.Identity.GetUserId();
                    Test.TestDate = DateTime.Now;
                    Test.TestType = "Ping";
                }
            }
            catch (PingException ex)
            {
                Test.Address = address;
                Test.ResponseTime = "";
                Test.Status = string.Format("Connection Error: {0}", ex.Message);
                Test.UserId = User.Identity.GetUserId();
                Test.TestDate = DateTime.Now;
                Test.TestType = "Ping";

            }
            catch (SocketException ex)
            {
                Test.Address = address;
                Test.ResponseTime = "";
                Test.Status = string.Format("Connection Error: {0}", ex.Message);
                Test.UserId = User.Identity.GetUserId();
                Test.TestDate = DateTime.Now;
                Test.TestType = "Ping";
            }
        }
        using (ApplicationDbContext db = new ApplicationDbContext())
        {

            db.SpeedTest.Add(Test);
            db.SaveChanges();

        }
    }
}

GET IP Address:

public class IPAddress
{
    public string GetIPAddress()
    {
        //The X-Forwarded-For (XFF) HTTP header field is a de facto standard for identifying the originating IP address of a 
        //client connecting to a web server through an HTTP proxy or load balancer
        String ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

        if (string.IsNullOrEmpty(ip))
        {
            ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
        }

        return ip;
    }
}
Community
  • 1
  • 1
JReam
  • 898
  • 2
  • 13
  • 28
  • It seems really odd to me that `IPAddress.GetIPAddress()` would append a port number to the result. Makes no sense to me. – Sam Axe Feb 19 '16 at 01:11
  • Give it a try. Luckily I troubleshot for awhile to figure it out to implement the split() methodology. – JReam Feb 19 '16 at 01:21
  • Oooooh. I missed that you made your own `IPAddress` class. – Sam Axe Feb 19 '16 at 01:24
  • So.. let me know if I got this wrong... Someone makes an HTTP connection to your web server, you grab their IP address, and try to ping them. That seems kind of... silly. `1` Ping (ICMP messages) are not guaranteed to arrive. `2` The fact that you have a connection from the client would indicate that their computer is running. – Sam Axe Feb 19 '16 at 01:27
  • We have labs that users connect to for courses. The lab team wants a speedtest.net type app that shows the ping response time and download speed for a given user. I worked through the download piece, but I'm stuck on ascertaining the Ping response. Logically I agree with you though, if they are logged in then they can connect. That said, I'm not a Network expert so they may have other reasons for wanting the Ping response time. – JReam Feb 19 '16 at 01:31

1 Answers1

2

the IPAddress class captures an IP address with ":4321" on the tail end

The :4321 part is a port number. It should not be supplied in your call to ping.Send().

If you look at the documentation of Ping on MSDN, you'll see liberal use of the phrase

Attempts to send an Internet Control Message Protocol (ICMP) echo message

Attempts is the operative word. Many servers are configured not to respond to ping requests, and many firewalls block such requests.

Your code works locally. If you have the correct IP address of your server, the code should be correct. The most likely reason for the failure is that the network infrastructure or server prevent the request from completing.

To test the assumption, open a command prompt on the client computer and enter

ping 1.2.3.4

Replace 1.2.3.4 with the actual IP address. If you don't get a reply, the ping is being blocked and your code will be unable to complete a ping either.

My production server is Azure if that helps?

Yes, it does.

The ICMP protocol is not permitted through the Azure load balancer.

http://blogs.msdn.com/b/mast/archive/2014/06/22/use-port-pings-instead-of-icmp-to-test-azure-vm-connectivity.aspx

However, all is not lost. You can use a tool such as PsPing to test the availability of a port (such as HTTP port 80) on your server. Note the article talks about connecting from your Azure server to the internet. However, this works in either direction.

Eric J.
  • 147,927
  • 63
  • 340
  • 553
  • Thanks, Eric. Sounds like my code is correct but Azure is preventing me from executing it? I'm using this in an app to test if a user can connect to our infrastructure where our e-labs our hosted. I'm leveraging Azure for testing, but ultimately this app will live behind our firewall. Our clients can be anyone from off the shelf laptops with a local ISP to Govt employees. Will the PSPing allow me to search for open ports on the client dynamically? Sorry for my ignorance, Networking is not my strong suit. – JReam Feb 19 '16 at 01:19
  • `Sounds like my code is correct but Azure is preventing me from executing it?` The code executes but Azure prevents the network messages from passing in or out of the Azure network. The type of control message used for Ping is commonly blocked (due to potential for abuse), and is also not an indication of whether a client will be able to actually connect. If clients will connect to a particular port, just test for the availability of that port. If this is a website, add a page with no authentication e.g. status.html and try loading that from your client code. – Eric J. Feb 19 '16 at 01:25
  • If I can figure out my open port on Azure, does ping.Send() have a param for targeting the open port? – JReam Feb 19 '16 at 01:26
  • `Will the PSPing allow me to search for open ports on the client dynamically` Yes, but if you do that for many ports frequently, network security software in Azure or the client network might mistake you for a hacker. – Eric J. Feb 19 '16 at 01:26
  • `If I can figure out my open port on Azure, does ping.Send() have a param for targeting the open port?` No, it sends an ICMP control message which is different than a TCP/IP request you are probably sending via a port for your application. – Eric J. Feb 19 '16 at 01:29
  • Thanks, Eric! Appreciate the knowledge share! – JReam Feb 19 '16 at 01:34