« ServiceProcessInstaller HelpText has ver... | Main | XmlPreprocess is an elegant hack - or - ... »

I'm sure this has been done before, but it was faster to write it than to google for it. There's some IP Addresses that have been bothering me and I don't have access to a firewall or IIS at my ISP, so...

I can upload a text file called blockedips.txt to my site and the changes happen immediately.

    9 namespace YourModuleNameHere
   10 {
   11     public class IPBlackList : IHttpModule
   12     {
   13         private EventHandler onBeginRequest;
   14 
   15         public IPBlackList()
   16         {
   17             onBeginRequest = new EventHandler(this.HandleBeginRequest);
   18         }
   19 
   20         void IHttpModule.Dispose()
   21         {
   22         }
   23 
   24         void IHttpModule.Init(HttpApplication context)
   25         {
   26             context.BeginRequest += onBeginRequest;
   27         }
   28 
   29         const string BLOCKEDIPSKEY = "blockedips";
   30         const string BLOCKEDIPSFILE = "SiteConfig/blockedips.config";
   31 
   32         public static StringDictionary GetBlockedIPs(HttpContext context)
   33         {
   34             StringDictionary ips = (StringDictionary)context.Cache[BLOCKEDIPSKEY ];
   35             if (ips == null)
   36             {
   37                 ips = GetBlockedIPs(GetBlockedIPsFilePathFromCurrentContext(context));
   38                 context.Cache.Insert(BLOCKEDIPSKEY , ips, new CacheDependency(GetBlockedIPsFilePathFromCurrentContext(context)));
   39             }
   40             return ips;
   41         }
   42 
   43         private static string BlockedIPFileName = null;
   44         private static object blockedIPFileNameObject = new object();
   45         public static string GetBlockedIPsFilePathFromCurrentContext(HttpContext context)
   46         {
   47             if (BlockedIPFileName != null)
   48                 return BlockedIPFileName;
   49             lock(blockedIPFileNameObject)
   50             {
   51                 if (BlockedIPFileName == null)
   52                 {
   53                     BlockedIPFileName = context.Server.MapPath(BLOCKEDIPSFILE);
   54                 }
   55             }
   56             return BlockedIPFileName;
   57         }
   58 
   59         public static StringDictionary GetBlockedIPs(string configPath)
   60         {
   61             StringDictionary retval = new StringDictionary();
   62             using (StreamReader sr = new StreamReader(configPath))
   63             {
   64                 String line;
   65                 while ((line = sr.ReadLine()) != null)
   66                 {
   67                     line = line.Trim();
   68                     if (line.Length != 0)
   69                     {
   70                         retval.Add(line, null);
   71                     }
   72                 }
   73             }
   74             return retval;
   75         }
   76 
   77         private void HandleBeginRequest( object sender, EventArgs evargs )
   78         {
   79             HttpApplication app = sender as HttpApplication;
   80 
   81             if ( app != null )
   82             {
   83                 string IPAddr = app.Context.Request.ServerVariables["REMOTE_ADDR"];
   84                 if (IPAddr == null || IPAddr.Length == 0)
   85                 {
   86                     return;
   87                 }
   88 
   89                 StringDictionary badIPs = GetBlockedIPs(app.Context);
   90                 if (badIPs != null && badIPs.ContainsKey(IPAddr))
   91                 {
   92                     app.Context.Response.StatusCode = 404;
   93                     app.Context.Response.SuppressContent = true;
   94                     app.Context.Response.End();
   95                     return;
   96                 }
   97             }
   98         }
   99     }
  100 }

And in your web.config:

   42 <system.web>
   43    <httpModules>
   44         <add type="YourModuleNameHere.IPBlackList, YourAssemblyNameHere"
   45             name="IPBlackList" />
   46    </httpModules>
   47 </system.web>

No warrenty, express or implied. If it sucks or has bugs/security holes, let me know as it's 9 minutes work.

Tracked by:
http://www.robzelt.com/blog/PermaLink.aspx?guid=c475e8a6-45a1-4641-a55b-3d9a2f32... [Pingback]
"re: Trackback spammers on the loose, killing blogs" (Pretty stupid for a smart ... [Trackback]


Tuesday, December 14, 2004 10:03:05 PM (Pacific Standard Time, UTC-08:00)
Thats cool Scott! We have something similar running under IIS as an ISAPI filter that we use to allow/disallow access to certain urls.

As someone who keeps meaning to get more into ASP.NET and doesn't seem to ever find the time, it's interesting to see this kind of solution, along with the cache use.

Nice use of 9 minutes!
Wednesday, December 15, 2004 7:10:48 AM (Pacific Standard Time, UTC-08:00)
FYI: Might not matter since you may be using the dotted-decimal IP representation, but the StringDictionary will force lowercase on all your keys. This may cause the ContainsKey method to return false unless you also lowercase the argument to ContainsKey.
jond
Wednesday, December 15, 2004 7:12:46 AM (Pacific Standard Time, UTC-08:00)
Doh! My bad...ContainsKey will lowercase the argument for you...sorry about that.
jond
Wednesday, December 15, 2004 10:53:57 AM (Pacific Standard Time, UTC-08:00)
Thanks for the code Scott. This will come in handy.
Friday, December 17, 2004 10:07:03 AM (Pacific Standard Time, UTC-08:00)
I read some guidance once that suggested using HttpApplication.CompleteRequest() instead of HttpResponse.End() as you do in line 94.

However, I don't think I fully understood the reason, or when it was appropriate to use one over the other, so I'm not saying your code is "wrong".

The only difference I can tell is that Response.End raises a ThreadAbortException, while CompleteRequest() just ends the request. And raising an exception is more expensive than not, so maybe the guidance was performance related?

Anyone have any input on this?
Friday, December 17, 2004 1:26:41 PM (Pacific Standard Time, UTC-08:00)
Good info....interesting....CompleteRequest is on the Application, and sets an internal bool:

public void CompleteRequest()
{
this._requestCompleted = true;
}


and HttpResponse.End does this (notice that it calls CompleteRequest() also...


public void End()
{
if (this._context.IsInCancellablePeriod)
{
InternalSecurityPermissions.ControlThread.Assert();
Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
}
else if (!this._flushing)
{
this.Flush();
this._ended = true;
this._context.ApplicationInstance.CompleteRequest();
}
}


I'll do some testing and look at the differences...thanks!

Scott
Scott Hanselman
Sunday, December 19, 2004 11:25:20 AM (Pacific Standard Time, UTC-08:00)
What would it take to turn this into a module people can drop into any IIS website and turn on?

What would it take to make it reference some DNS based RBL?

Would that DNS RBL end comment spam for it's users?
Sunday, December 19, 2004 12:01:06 PM (Pacific Standard Time, UTC-08:00)
1. It already is a module you can drop into any (ASP.NET) IIS website. You're looking at it.
2. Show me a blacklist to point to.
3. Probably not.

Scott Hanselman
Sunday, December 19, 2004 4:13:44 PM (Pacific Standard Time, UTC-08:00)
Sorbs has lists for open http proxies and open socks proxies: http://www.dnsbl.nl.sorbs.net/using.shtml
Sunday, January 16, 2005 10:55:49 AM (Pacific Standard Time, UTC-08:00)
Great code Scott. I've already had it in use for a couple weeks now. I was going through the code changing a couple things for a new implementation when I noticed tha common oversight at line 67:

line.Trim();
if (line.Length != 0)
{
retval.Add(line, null);
}

Just an explanation for anyone who does not know, since I brought it up. Trim() only returns a new trimmed string, it does not operate on the variable itself. You need to assign the Trim() method's return value to a string in order to get the trimmed value. If the 'line' variable only contained four spaces, it's tested length would still be 4. To trim the string the code should be:

line = line.Trim();
Sunday, January 16, 2005 12:42:30 PM (Pacific Standard Time, UTC-08:00)
You're totally right...brain fart. Thanks!
Scott Hanselman
Comments are closed.

Contact

Sponsors

Hosting By

Hot Topics

Tags

Calendar

<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Archives

March, 2010 (8)
February, 2010 (17)
January, 2010 (13)
December, 2009 (13)
November, 2009 (7)
October, 2009 (19)
September, 2009 (11)
August, 2009 (12)
July, 2009 (21)
June, 2009 (26)
May, 2009 (16)
April, 2009 (13)
March, 2009 (17)
February, 2009 (17)
January, 2009 (18)
December, 2008 (32)
November, 2008 (17)
October, 2008 (22)
September, 2008 (16)
August, 2008 (14)
July, 2008 (25)
June, 2008 (19)
May, 2008 (17)
April, 2008 (17)
March, 2008 (26)
February, 2008 (21)
January, 2008 (28)
December, 2007 (19)
November, 2007 (17)
October, 2007 (31)
September, 2007 (39)
August, 2007 (37)
July, 2007 (43)
June, 2007 (37)
May, 2007 (32)
April, 2007 (38)
March, 2007 (29)
February, 2007 (46)
January, 2007 (31)
December, 2006 (27)
November, 2006 (31)
October, 2006 (32)
September, 2006 (39)
August, 2006 (34)
July, 2006 (40)
June, 2006 (18)
May, 2006 (31)
April, 2006 (34)
March, 2006 (30)
February, 2006 (38)
January, 2006 (44)
December, 2005 (19)
November, 2005 (34)
October, 2005 (24)
September, 2005 (37)
August, 2005 (20)
July, 2005 (24)
June, 2005 (33)
May, 2005 (16)
April, 2005 (22)
March, 2005 (34)
February, 2005 (15)
January, 2005 (37)
December, 2004 (28)
November, 2004 (30)
October, 2004 (34)
September, 2004 (22)
August, 2004 (34)
July, 2004 (18)
June, 2004 (64)
May, 2004 (49)
April, 2004 (21)
March, 2004 (29)
February, 2004 (29)
January, 2004 (36)
December, 2003 (25)
November, 2003 (24)
October, 2003 (59)
September, 2003 (42)
August, 2003 (24)
July, 2003 (44)
June, 2003 (29)
May, 2003 (21)
April, 2003 (30)
March, 2003 (27)
February, 2003 (47)
January, 2003 (50)
December, 2002 (31)
November, 2002 (38)
October, 2002 (44)
September, 2002 (15)
May, 2002 (2)
April, 2002 (4)

Google Ads