Skip to content

Instantly share code, notes, and snippets.

@affieuk
Forked from winzig/ClientIP.cs
Created January 5, 2018 14:31
Show Gist options
  • Save affieuk/a592741c97fb77886fa7e6c2606d3213 to your computer and use it in GitHub Desktop.
Save affieuk/a592741c97fb77886fa7e6c2606d3213 to your computer and use it in GitHub Desktop.
If you're using a load balancer that obscures the remote client's true IP address, you can run this IHttpModule to take the first IP address from the X-Forwarded-For header, and overwrite the REMOTE_ADDR and REMOTE_HOST server variables. (We tried to use the URL Rewrite module that everyone normally recommends to do this, but it's buggy.)
using System;
using System.Web;
using System.Text.RegularExpressions;
namespace HttpModules
{
/// <summary>
/// This module handles complications from our load balancer configuration not properly passing the client's true IP
/// address to our code via the REMOTE_ADDR and REMOTE_HOST variables. We tried to use URL Rewrite to compensate for
/// this, but it does not run when default documents are being accessed (a longstanding bug).
///
/// Add a reference to this class to your <modules> section in either applicationHost.config (for your entire server),
/// or the web.config of a specific web server.
/// </summary>
public class ClientIP : IHttpModule
{
/// <summary>
/// The IP we want will be in $1. X-Forwarded-For can carry multiple IPs in a comma-separated
/// list, but the first IP should belong to the original client.
/// </summary>
private static Regex REGEX_FIRST_IP = new Regex(@"^\s*(\d+\.\d+\.\d+\.\d+)", RegexOptions.Compiled);
/// <summary>
/// This overwrites the REMOTE_ADDR and REMOTE_HOST server variables with the first IP taken from the
/// X-Forwarded-For header, if it exists. Otherwise it does nothing.
/// </summary>
void OnBeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
string headervalue = app.Context.Request.Headers["X-Forwarded-For"];
if (headervalue != null)
{
Match m = REGEX_FIRST_IP.Match(headervalue);
if (m.Success)
{
app.Context.Request.ServerVariables["REMOTE_ADDR"] = m.Groups[1].Value;
app.Context.Request.ServerVariables["REMOTE_HOST"] = m.Groups[1].Value;
}
}
}
/// <summary>
/// Put anything here that needs to happen when the module is disposed of.
/// </summary>
void IHttpModule.Dispose()
{
}
/// <summary>
/// This wires up our OnBeginRequest method to the BeginRequest event.
/// </summary>
/// <param name="app"></param>
void IHttpModule.Init(HttpApplication app)
{
app.BeginRequest += OnBeginRequest;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment