diff --git a/2.0/ModCloudFlareIIS2.dll b/2.0/ModCloudFlareIIS2.dll index af191cf..cb97f64 100644 Binary files a/2.0/ModCloudFlareIIS2.dll and b/2.0/ModCloudFlareIIS2.dll differ diff --git a/2.0/eExNetworkLibrary.dll b/2.0/eExNetworkLibrary.dll new file mode 100644 index 0000000..47f5fa1 Binary files /dev/null and b/2.0/eExNetworkLibrary.dll differ diff --git a/3.0/ModCloudFlareIIS3.dll b/3.0/ModCloudFlareIIS3.dll index 5eaa50c..11d0923 100644 Binary files a/3.0/ModCloudFlareIIS3.dll and b/3.0/ModCloudFlareIIS3.dll differ diff --git a/3.0/eExNetworkLibrary.dll b/3.0/eExNetworkLibrary.dll new file mode 100644 index 0000000..47f5fa1 Binary files /dev/null and b/3.0/eExNetworkLibrary.dll differ diff --git a/3.5/ModCloudFlareIIS3_5.dll b/3.5/ModCloudFlareIIS3_5.dll index 8f7c54e..4c5b092 100644 Binary files a/3.5/ModCloudFlareIIS3_5.dll and b/3.5/ModCloudFlareIIS3_5.dll differ diff --git a/3.5/eExNetworkLibrary.dll b/3.5/eExNetworkLibrary.dll new file mode 100644 index 0000000..47f5fa1 Binary files /dev/null and b/3.5/eExNetworkLibrary.dll differ diff --git a/4.0/ModCloudFlareIIS4.dll b/4.0/ModCloudFlareIIS4.dll index 57a6fae..0aa66dc 100644 Binary files a/4.0/ModCloudFlareIIS4.dll and b/4.0/ModCloudFlareIIS4.dll differ diff --git a/4.0/eExNetworkLibrary.dll b/4.0/eExNetworkLibrary.dll new file mode 100644 index 0000000..47f5fa1 Binary files /dev/null and b/4.0/eExNetworkLibrary.dll differ diff --git a/4.5/ModCloudFlareIIS4_5.dll b/4.5/ModCloudFlareIIS4_5.dll index 4cf86bf..1d4b832 100644 Binary files a/4.5/ModCloudFlareIIS4_5.dll and b/4.5/ModCloudFlareIIS4_5.dll differ diff --git a/4.5/eExNetworkLibrary.dll b/4.5/eExNetworkLibrary.dll new file mode 100644 index 0000000..47f5fa1 Binary files /dev/null and b/4.5/eExNetworkLibrary.dll differ diff --git a/ModCloudFlare.cs b/ModCloudFlare.cs deleted file mode 100644 index b498c10..0000000 --- a/ModCloudFlare.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.Net; -using LukeSkywalker.IPNetwork; - -namespace ModCloudFlareIIS -{ - public class ModCloudFlare : IHttpModule - { - #region IHttpModule Members - - public void Dispose() - { - } - - public void Init(HttpApplication context) - { - context.PreRequestHandlerExecute += new EventHandler(OnPreRequestHandlerExecute); - context.PostLogRequest += new EventHandler(PostLogEvent); - } - - #endregion - - private static List CloudFlareIPRanges = new List() - { - "204.93.240.0/24", - "204.93.177.0/24", - "199.27.128.0/21", - "173.245.48.0/20", - "103.21.244.0/22", - "103.22.200.0/22", - "103.31.4.0/22", - "141.101.64.0/18", - "108.162.192.0/18", - "190.93.240.0/20", - "188.114.96.0/20", - "197.234.240.0/22", - "198.41.128.0/17", - "162.158.0.0/15", - "104.16.0.0/12" - }; - - public static bool IsCloudFlareIP(string ip) - { - - foreach(string block in CloudFlareIPRanges) - { - IPNetwork network = IPNetwork.Parse(block); - - if (IPNetwork.Contains(network, IPAddress.Parse(ip))) - return true; - } - - return false; - } - - - public void OnPreRequestHandlerExecute(Object source, EventArgs e) - { - HttpApplication app = (HttpApplication)source; - HttpRequest request = app.Context.Request; - - if (!String.IsNullOrEmpty(request["HTTP_CF_CONNECTING_IP"])) - { - if (IsCloudFlareIP(request["REMOTE_ADDR"])) - { - request.ServerVariables.Set("REMOTE_ADDR", request["HTTP_CF_CONNECTING_IP"]); - } - } - } - - public void PostLogEvent(Object source, EventArgs e) - { - HttpApplication app = (HttpApplication)source; - HttpRequest request = app.Context.Request; - - if (!String.IsNullOrEmpty(request["HTTP_CF_CONNECTING_IP"])) - app.Response.AppendToLog("[CloudFlare_Visitor_IP:" + request["HTTP_CF_CONNECTING_IP"] + "]"); - - if (!String.IsNullOrEmpty(request["HTTP_CF_RAY"])) - app.Response.AppendToLog("[CF_RAY:" + request["HTTP_CF_RAY"] + "]"); - - } - } -} diff --git a/ModCloudFlareIIS.cs b/ModCloudFlareIIS.cs new file mode 100644 index 0000000..dc8ad73 --- /dev/null +++ b/ModCloudFlareIIS.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using System.Web; +using LukeSkywalker.IPNetwork; +using System.Net; +using eExNetworkLibrary; +using System.Net.Sockets; +using System.Collections; +using eExNetworkLibrary.IP; + +namespace ModCloudFlareIIS +{ + public class ModCloudFlareIIS : IHttpModule + { + #region IHttpModule Members + + public void Dispose() + { + } + + public void Init(HttpApplication context) + { + context.PreRequestHandlerExecute += new EventHandler(OnPreRequestHandlerExecute); + context.PostLogRequest += new EventHandler(PostLogEvent); + } + + #endregion + + private static List CloudFlareIPRanges = new List() + { + "204.93.240.0/24", + "204.93.177.0/24", + "199.27.128.0/21", + "173.245.48.0/20", + "103.21.244.0/22", + "103.22.200.0/22", + "103.31.4.0/22", + "141.101.64.0/18", + "108.162.192.0/18", + "190.93.240.0/20", + "188.114.96.0/20", + "197.234.240.0/22", + "198.41.128.0/17", + "162.158.0.0/15", + "104.16.0.0/12" + }; + + private static List CloudFlareIPv6Ranges = new List() + { + "2400:cb00::/32", + "2606:4700::/32", + "2803:f800::/32", + "2405:b500::/32", + "2405:8100::/32", + }; + + public static bool IsCloudFlareIP(string ip) + { + IPAddress address = IPAddress.Parse(ip); + + if (address.AddressFamily == AddressFamily.InterNetwork) // IPv4 + { + // Check if IPv4 address is in CloudFlareIPRanges + foreach (string block in CloudFlareIPRanges) + { + IPNetwork network = IPNetwork.Parse(block); + + if (IPNetwork.Contains(network, address)) + return true; + } + } + else if (address.AddressFamily == AddressFamily.InterNetworkV6) // IPv6 + { + // Check if IPv6 input address is in CloudFlare ranges + foreach (string block in CloudFlareIPv6Ranges) + { + if (GetIPv6Range(block).Contains(address)) + return true; + } + } + return false; + } + + private static IPAddress[] GetIPv6Range(string strIn) + { + //Split the string in parts for address and prefix + string strAddress = strIn.Substring(0, strIn.IndexOf('/')); + string strPrefix = strIn.Substring(strIn.IndexOf('/') + 1); + + int ipPrefix = Int32.Parse(strPrefix); + IPAddress ipAddress = IPAddress.Parse(strAddress); + + //Convert the prefix length to a valid SubnetMask + int ipMaskLength = 128; + + BitArray btArray = new BitArray(ipMaskLength); + for (int iC1 = 0; iC1 < ipMaskLength; iC1++) + { + //Index calculation is a bit strange, since you have to make your mind about byte order. + int iIndex = (int)((ipMaskLength - iC1 - 1) / 8) * 8 + (iC1 % 8); + + if (iC1 < (ipMaskLength - ipPrefix)) + { + btArray.Set(iIndex, false); + } + else + { + btArray.Set(iIndex, true); + } + } + + byte[] bMaskData = new byte[ipMaskLength / 8]; + + btArray.CopyTo(bMaskData, 0); + + //Create subnetmask + Subnetmask smMask = new Subnetmask(bMaskData); + + //Get the IP range + IPAddress ipAddressStart = IPAddressAnalysis.GetClasslessNetworkAddress(ipAddress, smMask); + IPAddress ipAddressEnd = IPAddressAnalysis.GetClasslessBroadcastAddress(ipAddress, smMask); + + //Omit the following lines if your network range is large + return IPAddressAnalysis.GetIPRange(ipAddressStart, ipAddressEnd); + } + + public void OnPreRequestHandlerExecute(Object source, EventArgs e) + { + HttpApplication app = (HttpApplication)source; + HttpRequest request = app.Context.Request; + + if (request.HttpMethod != "POST" && !String.IsNullOrEmpty(request["HTTP_CF_CONNECTING_IP"])) + { + if (IsCloudFlareIP(request["REMOTE_ADDR"])) + { + request.ServerVariables.Set("REMOTE_ADDR", request["HTTP_CF_CONNECTING_IP"]); + request.ServerVariables.Set("REMOTE_HOST", request["HTTP_CF_CONNECTING_IP"]); + } + } + } + + public void PostLogEvent(Object source, EventArgs e) + { + HttpApplication app = (HttpApplication)source; + HttpRequest request = app.Context.Request; + + if (!String.IsNullOrEmpty(request["HTTP_CF_CONNECTING_IP"])) + app.Response.AppendToLog("[CloudFlare_Visitor_IP:" + request["HTTP_CF_CONNECTING_IP"] + "]"); + + if (!String.IsNullOrEmpty(request["HTTP_CF_RAY"])) + app.Response.AppendToLog("[CF_RAY:" + request["HTTP_CF_RAY"] + "]"); + + } + } +} diff --git a/README.md b/README.md index ab15ce4..c5f6361 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ IIS Module for CloudFlare users ================================ -*Restores original visitor IP address to web applications running on IIS and using CloudFlare's performance and security service. +*Restores original visitor IP address to web applications running on IIS and using CloudFlare's performance and security service, even on IPv6! *Adds original visitor IP address to logs @@ -13,7 +13,7 @@ Rough installation instructions ------------------------------ 1. Compile, if needed. -2. Copy both .dll files to the BIN folder in the root of your desired application/website folder. If this folder doesn't exist, then create it. +2. Copy all .dll files to the BIN folder in the root of your desired application/website folder. If this folder doesn't exist, then create it. 3. In the IIS Manager, go to the website/application's "Modules" section. 4. Right click, or use the interface to "Add Managed Module" 5. Use "ModCloudFlare" as the name. (This is actually arbitrary.) @@ -27,15 +27,13 @@ Potential issues *This module is likely far from complete and may not cover all methods of retrieving a visitor's IP using ServerVariables -*IPv4 only, for now. - Feedback ------------------------------ Feedback encouraged, preferably via [CloudFlare Support](http://support.cloudflare.com). -__This module uses the IPNetwork library by Luke Skywaler: http://ipnetwork.codeplex.com__ +__This module uses the IPNetwork library by Luke Skywalker: http://ipnetwork.codeplex.com__ Copyright (c) 2009, Luke Skywalker All rights reserved. @@ -50,3 +48,4 @@ Redistribution and use in source and binary forms, with or without modification, THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +__This module uses the eEx Network Library by icefex: https://eex.codeplex.com, licensed under the LGPL.__ diff --git a/eExNetworkLibrary.dll b/eExNetworkLibrary.dll new file mode 100644 index 0000000..47f5fa1 Binary files /dev/null and b/eExNetworkLibrary.dll differ