Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Extending the IPAddress object to allow relative comparisons of two IP addresses

2.92/5 (5 votes)
1 Jun 2008CPOL3 min read 1   299  
This article outlines how to extend the IPAddress object to provide additional functionality for relative numeric comparisons of two IP addresses.

Introduction

It is occasionally necessary to determine the relative position of two IP addresses or if a particular IP address falls within a particular range. In the 1.0 and 1.1 frameworks, the IPAddress object had an 'Address' property. This returned a long value as a representation of an IP address, and allowed simple numeric comparison of IP addresses to determine their relative values.

In the 2.0 framework, the Address property is deprecated. This may be due to the advent of support for IPv6 addressing. IPv4 addresses can be represented with 32 bits of data, and therefore can be represented as a long. IPv6 addresses are made up of 128 bits of data, and this poses a problem if trying to be represented as a long value.

In the 2.0 framework, the IPAddress object has an Equal() method to determine if two IPAddress objects are the same, but there is no inbuilt method to determine the relative position of two addresses that are not equal. In looking for existing solutions available, the only ones that I could find used text comparisons to determine the relative values of two IP addresses. I've created a solution that doesn't use text comparisons, by using existing methods and extending the existing IPAddress object.

Solution

The IPAddress object can be inherited to extend the functionality. This article looks at a basic method to add functionality to the base object to determine the relative position of two addresses and to determine if an address is within a given range. These functions will support both IPv4 and IPv6.

Key Concept

The 2.0 framework IPAddress object has a method called GetAddressBytes() which returns a byte array representation of the stored address. For IPv4, this byte array has a length = 4; for IPv6, the array length = 16. Given two addresses, by comparing the relative value of each pair of bytes, it is trivial to determine the relative position of the two IP addresses.

Comparing two addresses from different address families is not supported. It is impossible to determine if an IPv4 address is higher or lower than an IPv6 address.

ComparibleIPAddress

The derived object will be called ComparibleIPAddress. It should inherit from System.Net.IPAddress.

Constructors

You must specify a constructor for the inherited object. All the constructor must do is call the constructor of the base object. This is necessary as, in this case, the base object doesn't have a parameter-less constructor.

For consistency, I have included a constructor to mirror each of the available constructors in the base object.

C#
public ComparibleIPAddress(byte[] address)
    : base(address)
{
    // must override this constructor to enable build //    
}

public ComparibleIPAddress(Int64 address)
    : base(address)
{
    // must override this constructor to enable
    // build / compatibility with base class constructors
}

public ComparibleIPAddress(byte[] address, Int64 scopeid)
    : base(address, scopeid)
{
    // must override this constructor to enable
    // build / compatibility with base class constructors
}

CompareTo Function

The purpose of this function is to allow us to compare the current IP address to a given value and determine their relative positions. If the current IP address and the passed address are not in the same address family, the function throws an ArgumentOutOfRangeException.

Each address is converted to a byte array.

Each pair in the two byte arrays are compared with each other. If they are not equal, their relative values are determined and processing is completed.

C#
public int CompareTo(ComparibleIPAddress value)
{
    int returnVal = 0;
    if (this.AddressFamily == value.AddressFamily)
    {
        byte[] b1 = this.GetAddressBytes();
        byte[] b2 = value.GetAddressBytes();

        for (int i = 0; i < b1.Length; i++)
        {
            if (b1[i] < b2[i])
            {
                returnVal = -1;
                break;
            }
            else if (b1[i] > b2[i])
            {
                returnVal = 1;
                break;
            }
        }
    }
    else
    {
        throw new ArgumentOutOfRangeException("value", 
              "Cannot compare two addresses no in the same Address Family.");
    }

    return returnVal;
}

IsInRange Function

This is an extension of the CompareTo function. Once we are able to determine the relative position of two addresses, it is trivial to determine if a given addresses is within a range of addresses.

This function checks that all addresses are within the same address families. Again, an ArgumentOutOfRangeException is thrown if they are not.

C#
public bool IsInRange(ComparibleIPAddress rangeStartAddress, 
                      ComparibleIPAddress rangeEndAddress)
{
    bool returnVal = false;
    // ensure that all addresses are of the same type otherwise reject //
    if (rangeStartAddress.AddressFamily != rangeEndAddress.AddressFamily)
    {
        throw new ArgumentOutOfRangeException("rangeStartAddress",
        String.Format("The Start Range type {0} and End Range type {1}" + 
                      " are not compatible ip address families.", 
                      rangeStartAddress.AddressFamily.ToString(), 
                      rangeEndAddress.AddressFamily.ToString()));
    }

    if (rangeStartAddress.AddressFamily == this.AddressFamily)
    {
        returnVal = (CompareTo(rangeStartAddress) >= 0 
                       && CompareTo(rangeEndAddress) <= 0);   
        // no need to check for -2 value as this
        // check has already been undertaken to get into this block //
    }
    else
    {
        throw new ArgumentOutOfRangeException("rangeStartAddress", 
            String.Format("The range type {0} and current value type {1}" + 
                          " are not compatible ip address families", 
                          rangeStartAddress.AddressFamily.ToString(), 
                          this.AddressFamily.ToString()));
    }

    return returnVal;

}

Summary

A derived class can easily be created to provide additional functions for IP addresses.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)