Created
December 21, 2012 20:31
-
-
Save maxfridbe/4355603 to your computer and use it in GitHub Desktop.
get ip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//http://stackoverflow.com/a/10407992/51841 | |
using System; | |
using System.Linq; | |
using System.Net; | |
using System.Web; | |
public class RequestHelpers | |
{ | |
public static string GetClientIpAddress(HttpRequestBase request) | |
{ | |
try | |
{ | |
var userHostAddress = request.UserHostAddress; | |
// Attempt to parse. If it fails, we catch below and return "0.0.0.0" | |
// Could use TryParse instead, but I wanted to catch all exceptions | |
IPAddress.Parse(userHostAddress); | |
var xForwardedFor = request.ServerVariables["X_FORWARDED_FOR"]; | |
if (string.IsNullOrEmpty(xForwardedFor)) | |
return userHostAddress; | |
// Get a list of public ip addresses in the X_FORWARDED_FOR variable | |
var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IsPrivateIpAddress(ip)).ToList(); | |
// If we found any, return the last one, otherwise return the user host address | |
return publicForwardingIps.Any() ? publicForwardingIps.Last() : userHostAddress; | |
} | |
catch (Exception) | |
{ | |
// Always return all zeroes for any failure (my calling code expects it) | |
return "0.0.0.0"; | |
} | |
} | |
private static bool IsPrivateIpAddress(string ipAddress) | |
{ | |
// http://en.wikipedia.org/wiki/Private_network | |
// Private IP Addresses are: | |
// 24-bit block: 10.0.0.0 through 10.255.255.255 | |
// 20-bit block: 172.16.0.0 through 172.31.255.255 | |
// 16-bit block: 192.168.0.0 through 192.168.255.255 | |
// Link-local addresses: 169.254.0.0 through 169.254.255.255 (http://en.wikipedia.org/wiki/Link-local_address) | |
var ip = IPAddress.Parse(ipAddress); | |
var octets = ip.GetAddressBytes(); | |
var is24BitBlock = octets[0] == 10; | |
if (is24BitBlock) return true; // Return to prevent further processing | |
var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31; | |
if (is20BitBlock) return true; // Return to prevent further processing | |
var is16BitBlock = octets[0] == 192 && octets[1] == 168; | |
if (is16BitBlock) return true; // Return to prevent further processing | |
var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254; | |
return isLinkLocalAddress; | |
} | |
} | |
And here are some NUnit tests against that code (I'm using Rhino Mocks to mock the HttpRequestBase, which is the M<HttpRequestBase> call below): | |
using System.Web; | |
using NUnit.Framework; | |
using Rhino.Mocks; | |
using Should; | |
[TestFixture] | |
public class HelpersTests : TestBase | |
{ | |
HttpRequestBase _httpRequest; | |
private const string XForwardedFor = "X_FORWARDED_FOR"; | |
private const string MalformedIpAddress = "MALFORMED"; | |
private const string DefaultIpAddress = "0.0.0.0"; | |
private const string GoogleIpAddress = "74.125.224.224"; | |
private const string MicrosoftIpAddress = "65.55.58.201"; | |
private const string Private24Bit = "10.0.0.0"; | |
private const string Private20Bit = "172.16.0.0"; | |
private const string Private16Bit = "192.168.0.0"; | |
private const string PrivateLinkLocal = "169.254.0.0"; | |
[SetUp] | |
public void Setup() | |
{ | |
_httpRequest = M<HttpRequestBase>(); | |
} | |
[TearDown] | |
public void Teardown() | |
{ | |
_httpRequest = null; | |
} | |
[Test] | |
public void PublicIpAndNullXForwardedFor_Returns_CorrectIp() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(GoogleIpAddress); | |
} | |
[Test] | |
public void PublicIpAndEmptyXForwardedFor_Returns_CorrectIp() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(string.Empty); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(GoogleIpAddress); | |
} | |
[Test] | |
public void MalformedUserHostAddress_Returns_DefaultIpAddress() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(MalformedIpAddress); | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(null); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(DefaultIpAddress); | |
} | |
[Test] | |
public void MalformedXForwardedFor_Returns_DefaultIpAddress() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MalformedIpAddress); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(DefaultIpAddress); | |
} | |
[Test] | |
public void SingleValidPublicXForwardedFor_Returns_XForwardedFor() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(MicrosoftIpAddress); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(MicrosoftIpAddress); | |
} | |
[Test] | |
public void MultipleValidPublicXForwardedFor_Returns_LastXForwardedFor() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(GoogleIpAddress + "," + MicrosoftIpAddress); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(MicrosoftIpAddress); | |
} | |
[Test] | |
public void SinglePrivateXForwardedFor_Returns_UserHostAddress() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(Private24Bit); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(GoogleIpAddress); | |
} | |
[Test] | |
public void MultiplePrivateXForwardedFor_Returns_UserHostAddress() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
const string privateIpList = Private24Bit + "," + Private20Bit + "," + Private16Bit + "," + PrivateLinkLocal; | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(GoogleIpAddress); | |
} | |
[Test] | |
public void MultiplePublicXForwardedForWithPrivateLast_Returns_LastPublic() | |
{ | |
// Arrange | |
_httpRequest.Stub(x => x.UserHostAddress).Return(GoogleIpAddress); | |
const string privateIpList = Private24Bit + "," + Private20Bit + "," + MicrosoftIpAddress + "," + PrivateLinkLocal; | |
_httpRequest.Stub(x => x.ServerVariables[XForwardedFor]).Return(privateIpList); | |
// Act | |
var ip = RequestHelpers.GetClientIpAddress(_httpRequest); | |
// Assert | |
ip.ShouldEqual(MicrosoftIpAddress); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment