Colourblind

Welcome to Colourblind.

This is the personal web space of Tom Milsom. As much as possible everything is free (as in speach and as in beer).


Make text: Smaller Bigger

Checking for Private IPs in .NET

Posted by Tom on 15/02/2011 11:11:20

We've got a client who is doing IP-based geolocation when a user first hits to the site via a third-party service. They've got a very limited number of lookups they can make per day, and it turns out the hosting company's heartbeat service is eating up a fair amount of these. What we wanted is to filter out calls made from private IP addresses. I was expecting to come across something in .NET to do this, but I'm damned if I can find it.

According to RFC 1918 we have 3 blocks of IPs in the private address space:

  • 10.0.0.0/24
  • 172.16.0.0/20
  • 192.168.0.0/16

Since the easiest way to perform the comparison is going to be using the IP in integer format, first we need a method for converting an IP from the more widely used dotted octet. I'm pretty much rewriting the System.Net.IPAddress.Address property, which has been deprecated since the dawn of time.

   1:  using System;
   2:   
   3:  public static class IpUtils
   4:  {
   5:      private static readonly long[] _privateBlocks;
   6:   
   7:      static IpUtils()
   8:      {
   9:          _privateBlocks = new long[]
  10:          { 
  11:              IpToInteger("10.0.0.0"), 
  12:              IpToInteger("172.16.0.0"), 
  13:              IpToInteger("192.168.0.0") 
  14:          };
  15:      }
  16:   
  17:      public static long IpToInteger(string ip)
  18:      {
  19:          long result = 0;
  20:          string [] octets = ip.ToString().Split(new char [] { '.' });
  21:          result = Convert.ToInt64(
  22:                    Int32.Parse(octets[0]) * Math.Pow(2, 24)
  23:                  + Int32.Parse(octets[1]) * Math.Pow(2, 16)
  24:                  + Int32.Parse(octets[2]) * Math.Pow(2, 8)
  25:                  + Int32.Parse(octets[3]) * Math.Pow(2, 0));
  26:          return result;
  27:      }
  28:   
  29:      public static bool IsPrivateIp(string ip)
  30:      {
  31:          long ipInt = IpToInteger(ip);
  32:          return (ipInt >= _privateBlocks[0] && ipInt < _privateBlocks[0] + Math.Pow(2, 24))
  33:              || (ipInt >= _privateBlocks[1] && ipInt < _privateBlocks[1] + Math.Pow(2, 20))
  34:              || (ipInt >= _privateBlocks[2] && ipInt < _privateBlocks[2] + Math.Pow(2, 16));
  35:      }
  36:  }

This is coded for the sake of readability and is very inefficient. All of the Math.Pow calls are constants (does the compiler work this out? Or the JIT? Answers on a postcard) and we could swap out all of that _privateBlocks stuff in favour of 167772160, 2886729728 and 3232235520 if you want. And using bit-shifts rather than multiplication would probably save you a few micro-seconds . . .

Tags: dotNet

Comments

Add Comment




Good luck with that

Please type the characters from the image above into the box below
or click here to get a new one


Submit