X-Forwarded-For Log Filter for Windows Servers

For those that don't know what X-Forwarded-For is, then you might as well close your browser because this post likely will mean nothing to you…

A Little Background

Now, if you are still reading this, then you likely are having issues with determining the origin client connections to your web servers.  When web requests are passed through proxies, load balancers, application delivery controllers, etc, the client no longer has a direct connection with the destination server and all traffic looks like it's coming from the last server in the chain.  In the following diagram, Proxy2 is the last hop in the chain before the request hits the destination server.  Relying on connection information alone, the server thinks that all connections come from Proxy2, not from the Client that initiated the connection.

The only one in the chain here who knows who the client really is (as determined by it's client IP Address, is Proxy1.  The problem is that application owners rely on source client information for many reasons ranging from analyzing client demographics to targeting Denial of Service attacks.

That's where the X-Forwarded-For header comes in.  It is non-RFC standard HTTP request header that is used for identifying the originating IP address of a client connecting to a web server through a proxy.  The format of the header is:

X-Forwarded-For: client, proxy1, proxy, …

X-Forwarded-For header logging is supported in Apache (with mod_proxy) but Microsoft IIS does not have a direct way to support the translation of the X-Forwarded-For value into the client ip (c-ip) header value used in its webserver logging.

Back in September, 2005 I wrote an ISAPI filter that can be installed within IIS to perform this transition.  This was primarily for F5 customers but I figured that I might as well release it into the wild as others would find value out of it.

Recently folks have asked for 64 bit versions (especially with the release of Windows 2008 Server).  This gave me the opportunity to brush up on my C skills.  In addition to building targets for 64 bit windows, I went ahead and added a few new features that have been asked for.

Proxy Chain Support

The original implementation did not correctly parse the "client, proxy1, proxy2,…" format and assumed that there was a single IP address following the X-Forwarded-For header.  I've added code to tokenize the values and strip out all but the first token in the comma delimited chain for inclusion in the logs.

Header Name Override

Others have asked to be able to change the header name that the filter looked for from "X-Forwarded-For" to some customized value.  In some cases they were using the X-Forwarded-For header for another reason and wanted to use iRules to create a new header that was to be used in the logs.  I implemented this by adding a configuration file option for the filter.  The filter will look for a file named F5XForwardedFor.ini in the same directory as the filter with the following format:


The value of "Alternate-Header-Name" can be changed to whatever header you would like to use. 


I've updated the original distribution file so that folks hitting my previous blog post would get the updates.  The following zip file includes 32 and 64 bit release versions of the F5XForwardedFor.dll that you can install under IIS6 or IIS7.Installation


Follow these steps to install the filter.

  1. Download and unzip the F5XForwardedFor.zip distribution.
  2. Copy the F5XForwardedFor.dll file from the x86\Release or x64\Release directory (depending on your platform) into a target directory on your system.  Let's say C:\ISAPIFilters.
  3. Ensure that the containing directory and the F5XForwardedFor.dll file have read permissions by the IIS process.  It's easiest to just give full read access to everyone.
  4. Open the IIS Admin utility and navigate to the web server you would like to apply it to.
  5. For IIS6, Right click on your web server and select Properties.  Then select the "ISAPI Filters" tab.  From there click the "Add" button and enter "F5XForwardedFor" for the Name and the path to the file "c:\ISAPIFilters\F5XForwardedFor.dll" to the Executable field and click OK enough times to exit the property dialogs.  At this point the filter should be working for you.  You can go back into the property dialog to determine whether the filter is active or an error occurred.
  6. For II7, you'll want to select your website and then double click on the "ISAPI Filters" icon that shows up in the Features View.  In the Actions Pane on the right select the "Add" link and enter "F5XForwardedFor" for the name and "C:\ISAPIFilters\F5XForwardedFor.dll" for the Executable.  Click OK and you are set to go.

I'd love to hear feedback on this and if there are any other feature request, I'm wide open to suggestions. The source code is included in the download distribution so if you make any changes yourself, let me know!

Good luck and happy filtering!


Published Aug 19, 2009
Version 1.0

Was this article helpful?


  • @Mendel, not sure what changed between the older and newer versions. The source is available if you want to take a look.



    @Prasad, shouldn't be an issue as long as IIS has read access on the filter.
  • Shawn, the filter doesn't modify any inbound variables. On the inbound stream in IIS before it get's to the web application, it stores the value contained in the "X-Forwarded-For" HTTP header value (if it exists). Then after the server responds and IIS is about to add an entry into the IIS HTTP Logs, it replaces the value of the internal "c-ip" value (client ip) with the value contained in the X-Forwarded-For header. the REMOTE_ADDR server variable isn't a HTTP header, it's a value IIS sets based on the clients address that established the connection (in this case the LTM). As far as I know, the REMOTE_ADDR server variable is read-only from the context of a filter.



    If you are flowing through a BIG-IP, then you can always write an iRule that creates a custom HTTP header containing the value of the client's address on the virtual but it won't replace the REMOTE_ADDR variable because, as I said, that isn't a HTTP header, just a server variable inside of IIS.



    Hope this helps...



  • I know this is super old, but while switching to IIS 10 from 7, there's no more Advanced Logging.


    With Advanced Logging, we can do what your app does but on the IIS level.

    However, with the release of IIS 8.5, we cannot configure our logs the same way and I've been searching every avenue of the internet to find a solution to put the XFF IP into the Client IP, with no luck so far.


    Could this module work with IIS 10 or newer F5s?