85

If we let users input a couple of ip ranges, e.g., 172.16.11.5 - 100, how could I write a function to check if a IP (172.16.11.50) falls in the ranges?

Is there any existing library in .NET to leverage?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Ricky
  • 34,377
  • 39
  • 91
  • 131
  • One note of caution - if you are implementing this in order to see if an IP is on a particular subnet, then you can't reliably do this without taking into account the subnet mask as well. – Rob Levine Jan 26 '10 at 10:28
  • Looks like he's not specifying a subnet mask though. If he were you'd use a single IP and specify the subnet, rather than a range of IP address. Range's are normally used because a lotta people don't know what subnet's are... – Ian Jan 26 '10 at 10:55
  • similar/possible duplicate - http://stackoverflow.com/questions/1820661/comparing-ipaddress-stored-as-varbinary/1821016#1821016 – ram Jan 26 '10 at 20:09
  • The answer https://stackoverflow.com/questions/9622967/how-to-see-if-an-ip-address-belongs-inside-of-a-range-of-ips-using-cidr-notation/9626981#9626981 suggests the IPNetwork library https://github.com/lduchosal/ipnetwork nuget install IPNetwork2 – Michael Freidgeim May 01 '22 at 21:36

10 Answers10

134

There's nothing built into the framework, but it wouldn't take much effort to create an IPAddressRange class.

You'd compare the ranges by calling IPAddress.GetAddressBytes on the lower address, upper address and comparison address. Starting at the first byte, check if the comparison address is in the range of the upper/lower address.

This method works for both IPv4 and IPv6 addresses.

public class IPAddressRange
{
    readonly AddressFamily addressFamily;
    readonly byte[] lowerBytes;
    readonly byte[] upperBytes;

    public IPAddressRange(IPAddress lowerInclusive, IPAddress upperInclusive)
    {
        // Assert that lower.AddressFamily == upper.AddressFamily

        this.addressFamily = lowerInclusive.AddressFamily;
        this.lowerBytes = lowerInclusive.GetAddressBytes();
        this.upperBytes = upperInclusive.GetAddressBytes();
    }

    public bool IsInRange(IPAddress address)
    {
        if (address.AddressFamily != addressFamily)
        {
            return false;
        }

        byte[] addressBytes = address.GetAddressBytes();

        bool lowerBoundary = true, upperBoundary = true;

        for (int i = 0; i < this.lowerBytes.Length && 
            (lowerBoundary || upperBoundary); i++)
        {
            if ((lowerBoundary && addressBytes[i] < lowerBytes[i]) ||
                (upperBoundary && addressBytes[i] > upperBytes[i]))
            {
                return false;
            }

            lowerBoundary &= (addressBytes[i] == lowerBytes[i]);
            upperBoundary &= (addressBytes[i] == upperBytes[i]);
        }

        return true;
    }
}

NB: The above code could be extended to add public static factory methods FromCidr(IPAddress address, int bits)

Richard Szalay
  • 83,269
  • 19
  • 178
  • 237
  • 2
    it would be false for the case: lower - 222.168.2.1, upper - 222.168.5.10 and the target - 222.168.3.55 – Ricky Jan 27 '10 at 08:49
  • When you set the boundaries you could replace the &= by = for simplicity... Right? – Bombinosh Mar 25 '16 at 10:59
  • 2
    @Bombinosh It's been a while since I've looked at this code, but no, `&=` ensures that once false, it stays false. If it were `=`, it could potentially become `true` again. – Richard Szalay Apr 06 '16 at 22:17
  • @Richard, Thanks for the code, but is it inclusive or exclusive? – Soroush Falahati Apr 09 '16 at 01:52
  • What is "lower" in the code? I mean, there is undefined value in this line; this.addressFamily = lower.AddressFamily; – Lost_In_Library May 17 '17 at 08:47
  • @Lost_In_Library Just an error from a previous edit where I tried to make the argument names less ambiguous. Fixed now, thanks for letting me know. – Richard Szalay May 17 '17 at 20:12
  • @Ricky I just tested your case and it seems to be working with the current solution by Richard Szalay. – Martin Žid Mar 17 '21 at 13:41
  • @RichardSzalay Nice post, it would be a great help if you can also add the code on how to use this IPAddressRange, especially on how to give the lowerInclusive and upperInclusive. Thanks – Sibeesh Venu Aug 15 '23 at 15:35
69

You might want to consider this library by @jsakamoto, which allows you to parse range of IP address strings such as "192.168.0.0/24" and "192.168.0.0/255.255.255.0" and "192.168.0.0-192.168.0.255", and can contains check. This library supports both IPv4 and IPv6.

https://github.com/jsakamoto/ipaddressrange

It can also be installed via NuGet:

http://www.nuget.org/packages/IPAddressRange/

using NetTools;
...
// rangeA.Begin is "192.168.0.0", and rangeA.End is "192.168.0.255".
var rangeA = IPAddressRange.Parse("192.168.0.0/255.255.255.0");
rangeA.Contains(IPAddress.Parse("192.168.0.34")); // is True.
rangeA.Contains(IPAddress.Parse("192.168.10.1")); // is False.
rangeA.ToCidrString(); // is 192.168.0.0/24

// rangeB.Begin is "192.168.0.10", and rangeB.End is "192.168.10.20".
var rangeB1 = IPAddressRange.Parse("192.168.0.10 - 192.168.10.20");
rangeB1.Contains(IPAddress.Parse("192.168.3.45")); // is True.
rangeB1.Contains(IPAddress.Parse("192.168.0.9")); // is False.

// Support shortcut range description. 
// ("192.168.10.10-20" means range of begin:192.168.10.10 to end:192.168.10.20.)
var rangeB2 = IPAddressRange.Parse("192.168.10.10-20");

// Support CIDR expression and IPv6.
var rangeC = IPAddressRange.Parse("fe80::/10"); 
rangeC.Contains(IPAddress.Parse("fe80::d503:4ee:3882:c586%3")); // is True.
rangeC.Contains(IPAddress.Parse("::1")); // is False.
BuddhiP
  • 6,231
  • 5
  • 36
  • 56
26
public static bool IsInRange(string startIpAddr, string endIpAddr, string address)
{
    long ipStart = BitConverter.ToInt32(IPAddress.Parse(startIpAddr).GetAddressBytes().Reverse().ToArray(), 0);

    long ipEnd = BitConverter.ToInt32(IPAddress.Parse(endIpAddr).GetAddressBytes().Reverse().ToArray(), 0);

    long ip = BitConverter.ToInt32(IPAddress.Parse(address).GetAddressBytes().Reverse().ToArray(), 0);

    return ip >= ipStart && ip <= ipEnd; //edited
}

Console.WriteLine(IsInRange("100.0.0.1", "110.0.0.255", "102.0.0.4"));//true
Igor Turman
  • 2,165
  • 1
  • 22
  • 25
artwl
  • 3,502
  • 6
  • 38
  • 53
9

The best is to convert these addresses to an integer and then perform comparisons.

Example from here: IP to Integer

To convert an IP address to integer, break it into four octets. For example, the ip address you provided can be broken into:

First Octet:    217
Second Octet:   110
Third Octet:    18
Fourth Octet:   206

To calculate the decimal address from a dotted string, perform the following calculation.

    (first octet * 256³) + (second octet * 256²) + (third octet * 256) + (fourth octet)
=   (first octet * 16777216) + (second octet * 65536) + (third octet * 256) + (fourth octet)
=   (217 * 16777216) + (110 * 65536) + (18 * 256) + (206)
=   3647869646

Considering IPv6, you can convert them to integers (128bit vs 32bit IPv4) as well. Have a look at this question: Formatting IPv6 as an int in C# and storing it in SQL Server

The simplest route is to get the framework to do this for you. Use IPAddress.Parse to parse the address, then IPAddress.GetAddressBytes to get the "number" as byte[].

maxshuty
  • 9,708
  • 13
  • 64
  • 77
4

I used this code on codeproject before, which may be of use to you.

http://www.codeproject.com/KB/IP/ipnumbers.aspx

You have the possibility to add to IPList a range of IP numbers defined by a From IP and a To IP number. The method breaks up the range into standard IP ranges and finds their masks. So the range "10.0.0.5" to "10.0.0.20" will be broken up to the following ranges and added to the list: 10.0.0.5, 10.0.0.20, 10.0.0.6/31, 10.0.0.16/30 and 10.0.0.8/29 and you'll have the possibility to check against that.

Disclaimer: The Class is only tested with simple data sets, and the Class lacks validation of the IP numbers and IP masks provided. This should be fixed before it is used in production environments.

Razvan Dumitru
  • 11,815
  • 5
  • 34
  • 54
Aim Kai
  • 2,934
  • 1
  • 22
  • 34
3

reposting my answer from here

A while ago, I had to find the location of a given IP. We got the IP from the request. There are free databases which gave us this mapping. In IPv4, when we say the IP as "a.b.c.d" it is essentially a * (256^3) + b * (256^2) + c * (256) + d.

http://www.aboutmyip.com/AboutMyXApp/IP2Integer.jsp

so when you say you want an IP address starting with "a", you are looking for IPs between a * 256^ 3 and a * 256^3 + 256 * (256^2) (b = 256) + 256 *(256) (c=256) + 256( d=256) (lower / upper limit may vary a little bit depending on whether you want to include/exclude the limits).

That said, there are specific IPs reserved for specific purposes(like 127.0.0.1 which is localhost, 0.0.0.0 cannot be an IP etc).

So your linq query would be

from i in iList where i >= MIN && i <= MAX select i;

where iList is your initial list MIN is your min value for your range MAX is your max value for your range

Razvan Dumitru
  • 11,815
  • 5
  • 34
  • 54
ram
  • 11,468
  • 16
  • 63
  • 89
1

Could you figure out the subnet mask from your IP range?

If so then maybe you could use this IsInSameSubnet method..

Ian
  • 33,605
  • 26
  • 118
  • 198
1

I want to +1 BuddhiP's answer above which recommends the IPAddressRange package from NuGet: https://www.nuget.org/packages/IPAddressRange/

But because code formatting is hard in a comment I'll just add a practical code example here on how to use IPAddressRange.

CheckIPWhitelist reads a setting called IPWhitelist and assumes a semi-colon delimited list of IP ranges (such as "192.168.10.10-20;192.168.125.1-150;192.168.123.1-150") that IPAddressRange can parse. The function iterates the ranges and will and return true if present, false if not found.

This function is VB.NET and assumes some ASP.NET dependencies are present (such as the System.Web.HttpRequest namespace)

Imports NetTools ' ref. https://www.nuget.org/packages/IPAddressRange/

Function CheckIPWhitelist() As Boolean
    Dim match As Boolean = False
    Dim SourceIP As String = Request.UserHostAddress()

    ' Examples of valid IPWhitelist ranges 
    ' one range in longhand range format: "192.168.0.10 - 192.168.10.20"
    ' one range in shorthand range format: "192.168.10.10-20"
    ' multiple ranges separated by semicolons in shorthand range format: "192.168.10.10-20;192.168.125.1-150;192.168.123.1-150"
    Dim IPWhitelist As String = ConfigurationManager.AppSettings("IPWhitelist")

    Dim arrRanges As String() = IPWhitelist.Split(";")
    For i As Integer = 0 To arrRanges.Length - 1
        If arrRanges(i) IsNot Nothing Then
            Dim range As NetTools.IPAddressRange = IPAddressRange.Parse(arrRanges(i))
            If range.Contains(IPAddressRange.Parse(SourceIP)) = True Then
                match = True ' IP is in the whitelist, set a boolean
                Exit For
            End If
        End If
    Next
    Return match
End Function
Jeff Mergler
  • 1,384
  • 20
  • 27
1

The .NET 8 has introduced a new type IPNetwork with a Contains method. It retruns true if the given IPAddress is part of the IP network. Otherwise, returns false.

var splitPrefix = addressRange.Split('/');
var ipValidator = new IPNetwork(IPAddress.Parse(splitPrefix[0]),Convert.ToInt16(splitPrefix[1]));
var res = ipValidator.Contains(ipAddressToCheck);

In the code above the variable addressRange is a string that represents IP Address Range and ipAddressToCheck is the IP Address to check.

/// <summary>
/// Create a new <see cref="IPNetwork"/> with the specified <see cref="IPAddress"/> and prefix length.
/// </summary>
/// <param name="prefix">The <see cref="IPAddress"/>.</param>
/// <param name="prefixLength">The prefix length.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="prefixLength"/> is out of range.</exception>
public IPNetwork(IPAddress prefix, int prefixLength) : this(prefix, prefixLength, true)
{
}

public bool Contains(IPAddress address)
{
    if (Prefix.AddressFamily != address.AddressFamily)
    {
        return false;
    }

    var addressBytes = address.GetAddressBytes();
    for (int i = 0; i < PrefixBytes.Length && Mask[i] != 0; i++)
    {
        if ((PrefixBytes[i] & Mask[i]) != (addressBytes[i] & Mask[i]))
        {
            return false;
        }
    }

    return true;
}

The code above is copied from here. You can learn more about this IPNetwork.Contains(IPAddress) method here. Make sure to select the version .NET 8 for the doc.

If you can't use .Net 8, you can implement your own class by taking the code from here.

Sibeesh Venu
  • 18,755
  • 12
  • 103
  • 140
-1

You can remove dot at the middle of them and convert all IP to long at first, Then check them in an if :

var givenIp = Convert.ToInt64(clientIp.Replace(".", ""));
var startIp = Convert.ToInt64(startRange.Replace(".", ""));
var endIp = Convert.ToInt64(endRange.Replace(".", ""));

if (givenIp != startIp && givenIp != endIp && (givenIp < startIp || givenIp > endIp))
{
   Console.WriteLine("your ip does not allow to access!");
}
vernou
  • 6,818
  • 5
  • 30
  • 58
  • This is broken as hell. Say start range is: 100.100.100.100 and end range is 1.100.100.100 then startIp will be 100100100100 and endIp will be 1100100100. – Stephan Møller Oct 05 '21 at 09:16