Wednesday, 29 September 2010

ASP.NET - Get IPv4 Address, even if the user is using a proxy or an intranet user


Today I was working on some PayPal integration for an internal web application when part of the API suggested I needed an IP Address for the user to enhance security.

Realising this was an intranet application which could be used externally, I had to cater for all aspects. Getting an IP Address for an internal users involves looking up the host addresses using the System.Net.Dns namespace, rather than a simple peek in a server variable. As well as this, I needed to make sure I could identify real IP Addresses for users behind a proxy. If that wasn;t enough, the PayPal API doesn't support IPv6, so I had to search the host list for a IPv4 address and use that.... PayPal requires an IP or it will fail, so if everything else fails, it will return the loopback address (ack!). here's what I came up with...

UPDATE - Feb 2013
I have provided a couple of updates to this code in light of the comments. Thanks for the input!

Code Snippet
  1.  
  2. // Invoker
  3. string IPAddress = IPHelper.GetIPAddress(Request.ServerVariables["HTTP_VIA"],
  4.                                                 Request.ServerVariables["HTTP_X_FORWARDED_FOR"],
  5.                                                 Request.ServerVariables["REMOTE_ADDR"]);
  6.  
  7.  
  8.  
  9. public class IPHelper
  10. {
  11.     /// <summary>
  12.     /// Gets the user's IP Address
  13.     /// </summary>
  14.     /// <param name="httpVia">HTTP_VIA Server variable</param>
  15.     /// <param name="httpXForwardedFor">HTTP_X_FORWARDED Server variable</param>
  16.     /// <param name="RemoteAddr">REMOTE_ADDR Server variable</param>
  17.     /// <returns>user's IP Address</returns>
  18.     public static string GetIPAddress(string HttpVia, string HttpXForwardedFor, string RemoteAddr)
  19.     {
  20.         // Use a default address if all else fails.
  21.         string result = "127.0.0.1";
  22.  
  23.         // Web user - if using proxy
  24.         string tempIP = string.Empty;
  25.         if (HttpVia != null)
  26.             tempIP = HttpXForwardedFor;
  27.         else // Web user - not using proxy or can't get the Client IP
  28.             tempIP = RemoteAddr;
  29.  
  30.         // If we can't get a V4 IP from the above, try host address list for internal users.
  31.         if (!IsIPV4(tempIP) || tempIP == "127.0.0.1 ")
  32.         {
  33.             try
  34.             {
  35.                 string hostName = System.Net.Dns.GetHostName();
  36.                 foreach (System.Net.IPAddress ip in System.Net.Dns.GetHostAddresses(hostName))
  37.                 {
  38.                     if (IsIPV4(ip))
  39.                     {
  40.                         result = ip.ToString();
  41.                         break;
  42.                     }
  43.                 }
  44.             }
  45.             catch { }
  46.         }
  47.         else
  48.         {
  49.             result = tempIP;
  50.         }
  51.  
  52.         return result;
  53.     }
  54.  
  55.     /// <summary>
  56.     /// Determines weather an IP Address is V4
  57.     /// </summary>
  58.     /// <param name="input">input string</param>
  59.     /// <returns>Is IPV4 True or False</returns>
  60.     private static bool IsIPV4(string input)
  61.     {
  62.         bool result = false;
  63.         System.Net.IPAddress address = null;
  64.  
  65.         if (System.Net.IPAddress.TryParse(input, out address))
  66.             result = IsIPV4(address);
  67.  
  68.         return result;
  69.     }
  70.  
  71.     /// <summary>
  72.     /// Determines weather an IP Address is V4
  73.     /// </summary>
  74.     /// <param name="address">input IP address</param>
  75.     /// <returns>Is IPV4 True or False</returns>
  76.     private static bool IsIPV4(System.Net.IPAddress address)
  77.     {
  78.         bool result = false;
  79.  
  80.         switch (address.AddressFamily)
  81.         {
  82.             case System.Net.Sockets.AddressFamily.InterNetwork:   // we have IPv4
  83.                 result = true;
  84.                 break;
  85.             case System.Net.Sockets.AddressFamily.InterNetworkV6: // we have IPv6
  86.                 break;
  87.             default:
  88.                 break;
  89.         }
  90.  
  91.         return result;
  92.     }
  93. }
End of Code Snippet

7 comments:

Pedro said...

Thanks, thanks and thanks!! Great piece of code, weeks looking for something like this!

Yura said...

Thanks a lot. Very helpful, readable code. Thaks a lot again and again.

mrdyrden said...

Thanks man for sharing your knowledge and helping out the little people :)

FasterRaf said...

This was exactly what I was looking for ! Thnx

I made one small adaptation in my code for the case where you/debug run the application on localhost. Then the REMOTE_ADDR is the loopback ip 127.0.0.1 which is correct but not what we are looking for. So also in that case I look up the ip via the hostname adpting the code as follows :

// If we can't get a V4 IP from the above, try host address list for internal users.

if (!IsIPV4(tempIP) || tempIP=="127.0.0.1")

Hallur Holm Johannessen said...

Is it me that just don´t understand the code, but you are never returning the value in the tempIP variable. So if you have an IP address that is not an IPv6, you will always get the default of 127.0.0.1 returned.

Sean G said...

Thanks for the comments guys, I've provided an update to the code in light of these comments!

Adrián said...

Amazing knowledge of .Net, thanks for sharing this code. I was stuck on this problem!.... totally solved! Thanks.