How to Check If an Ip Address Is Within a Particular Subnet

How to check if an IP address is within a particular subnet

Using the answers from Thomas and Chris together with Ciscos Subnetting Examples I finally got something to work for IPv4 and IPv6 if you use the CIDR notation (IPAddress/PrefixLength). My IPv6-Implementation might be a bit too straight forward but as there is no UInt128-datatype I couldn't adapt Thomas's solution. Here is the code that seems to work well:

public static bool IsInSubnet(this IPAddress address, string subnetMask)
{
var slashIdx = subnetMask.IndexOf("/");
if (slashIdx == -1)
{ // We only handle netmasks in format "IP/PrefixLength".
throw new NotSupportedException("Only SubNetMasks with a given prefix length are supported.");
}

// First parse the address of the netmask before the prefix length.
var maskAddress = IPAddress.Parse(subnetMask.Substring(0, slashIdx));

if (maskAddress.AddressFamily != address.AddressFamily)
{ // We got something like an IPV4-Address for an IPv6-Mask. This is not valid.
return false;
}

// Now find out how long the prefix is.
int maskLength = int.Parse(subnetMask.Substring(slashIdx + 1));

if (maskLength == 0)
{
return true;
}

if (maskLength < 0)
{
throw new NotSupportedException("A Subnetmask should not be less than 0.");
}

if (maskAddress.AddressFamily == AddressFamily.InterNetwork)
{
// Convert the mask address to an unsigned integer.
var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray(), 0);

// And convert the IpAddress to an unsigned integer.
var ipAddressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray(), 0);

// Get the mask/network address as unsigned integer.
uint mask = uint.MaxValue << (32 - maskLength);

// https://stackoverflow.com/a/1499284/3085985
// Bitwise AND mask and MaskAddress, this should be the same as mask and IpAddress
// as the end of the mask is 0000 which leads to both addresses to end with 0000
// and to start with the prefix.
return (maskAddressBits & mask) == (ipAddressBits & mask);
}

if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
// Convert the mask address to a BitArray. Reverse the BitArray to compare the bits of each byte in the right order.
var maskAddressBits = new BitArray(maskAddress.GetAddressBytes().Reverse().ToArray());

// And convert the IpAddress to a BitArray. Reverse the BitArray to compare the bits of each byte in the right order.
var ipAddressBits = new BitArray(address.GetAddressBytes().Reverse().ToArray());
var ipAddressLength = ipAddressBits.Length;

if (maskAddressBits.Length != ipAddressBits.Length)
{
throw new ArgumentException("Length of IP Address and Subnet Mask do not match.");
}

// Compare the prefix bits.
for (var i = ipAddressLength - 1; i >= ipAddressLength - maskLength; i--)
{
if (ipAddressBits[i] != maskAddressBits[i])
{
return false;
}
}

return true;
}

throw new NotSupportedException("Only InterNetworkV6 or InterNetwork address families are supported.");
}

And this are the XUnit tests I tested it with:

public class IpAddressExtensionsTests
{
[Theory]
[InlineData("192.168.5.85/24", "192.168.5.1")]
[InlineData("192.168.5.85/24", "192.168.5.254")]
[InlineData("10.128.240.50/30", "10.128.240.48")]
[InlineData("10.128.240.50/30", "10.128.240.49")]
[InlineData("10.128.240.50/30", "10.128.240.50")]
[InlineData("10.128.240.50/30", "10.128.240.51")]
[InlineData("192.168.5.85/0", "0.0.0.0")]
[InlineData("192.168.5.85/0", "255.255.255.255")]
public void IpV4SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress)
{
var ipAddressObj = IPAddress.Parse(ipAddress);
Assert.True(ipAddressObj.IsInSubnet(netMask));
}

[Theory]
[InlineData("192.168.5.85/24", "192.168.4.254")]
[InlineData("192.168.5.85/24", "191.168.5.254")]
[InlineData("10.128.240.50/30", "10.128.240.47")]
[InlineData("10.128.240.50/30", "10.128.240.52")]
[InlineData("10.128.240.50/30", "10.128.239.50")]
[InlineData("10.128.240.50/30", "10.127.240.51")]
public void IpV4SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
{
var ipAddressObj = IPAddress.Parse(ipAddress);
Assert.False(ipAddressObj.IsInSubnet(netMask));
}

[Theory]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF")]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0001:0000:0000:0000")]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFF0")]
[InlineData("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:5000:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:57ff:ffff:ffff:ffff:ffff")]
[InlineData("2001:db8:abcd:0012::0/0", "::")]
[InlineData("2001:db8:abcd:0012::0/0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]
public void IpV6SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress)
{
var ipAddressObj = IPAddress.Parse(ipAddress);
Assert.True(ipAddressObj.IsInSubnet(netMask));
}

[Theory]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFFF")]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0001:0000:0000:0000")]
[InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFF0")]
[InlineData("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0001")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:4999:0000:0000:0000:0000")]
[InlineData("2001:db8:abcd:5678::0/53", "2001:0db8:abcd:5800:0000:0000:0000:0000")]
public void IpV6SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
{
var ipAddressObj = IPAddress.Parse(ipAddress);
Assert.False(ipAddressObj.IsInSubnet(netMask));
}
}

As base for the tests I used Ciscos Subnetting Examples and IBMs IPV6 address examples.

I hope someone finds this helpful ;)

How to check if an IP address is from a particular network/netmask in Java?

Apache Commons Net has org.apache.commons.net.util.SubnetUtils that appears to satisfy your needs. It looks like you do something like this:

SubnetInfo subnet = (new SubnetUtils("10.10.10.0", "255.255.255.128")).getInfo();
boolean test = subnet.isInRange("10.10.10.10");

Note, as carson points out, that Apache Commons Net has a bug that prevents it from giving the correct answer in some cases. Carson suggests using the SVN version to avoid this bug.

Standard/safe way to check if IP address is in range/subnet

Is the internal representation consistent from system to system, or do I ever need to do Endian-ness checks/correction on the s_addr field?

s_addr is always in network (big endian) byte order on all platforms.

Are there standard macros along the lines of CLASS_C_NETMASK, CLASS_B_NETMASK, etc, that would be more appropriate than using manually generated masks (ie: 0xFF000000, 0x00FF0000, etc).

No, nor would it make sense to use such macros, as subnet masks are not fixed from one network to another. You need to provide your code with an actual network IP and its subnet mask (prompt the user, query the OS, etc). You can then calculate the subnet's starting and ending IPs to compare against your target IP:

uint32_t ip = ...; // value to check
uint32_t netip = ...; // network ip to compare with
uint32_t netmask = ...; // network ip subnet mask
uint32_t netstart = (netip & netmask); // first ip in subnet
uint32_t netend = (netstart | ~netmask); // last ip in subnet
if ((ip >= netstart) && (ip <= netend))
// is in subnet range...
else
// not in subnet range...

Or simpler, mask both network IP and target IP with the subnet mask and see if the resulting values are the same (ie, they are the same subnet):

uint32_t ip = ...; // value to check
uint32_t netip = ...; // network ip to compare with
uint32_t netmask = ...; // network ip subnet mask
if ((netip & netmask) == (ip & netmask))
// is on same subnet...
else
// not on same subnet...

Are there any existing functions in the sockets library that will do checks if an IP address is in a range of IP addresses or matches a subnet mask?

No. But it is trivial to implement manually, it only takes a few lines of code, as shown above.

Determining if an IP is within a specific range on Android

I've found the solution here:

https://github.com/titpetric/wowza-geoip/blob/master/src/NetMaskLookupService.java

import java.net.InetAddress;
import java.net.UnknownHostException;

import java.util.StringTokenizer;
import java.util.Vector;

import android.app.Activity;

/** This class checks that an IP exists in a specified subnet specified via netmask.

Supported netmask formats are:

1.1.1.1/255.255.255.255
1.1.1.1/32 (CIDR-style)

@todo: IPv6 support

*/
public class iprange extends Activity
{
/** Validate that IPAddress exists in NetMask address space */
public static boolean ValidateIP(String IPAddress, String NetMask) throws UnknownHostException, Exception
{
int ip, network, netmask, cidr, tokens = 0;

// convert IP to int
if (!validateInetAddress(IPAddress)) {
return false;
}
ip = toInt(InetAddress.getByName(IPAddress));

// split network/netmask
Vector<Object> nm = new Vector<Object>();
StringTokenizer nmt = new StringTokenizer(NetMask,"/");
while (nmt.hasMoreTokens()) {
nm.add(nmt.nextToken());
tokens++;
}
// we have an ip without netmask, assume /32
if (tokens==1) {
nm.add("32");
}

// network to int
if (!validateInetAddress(nm.get(0).toString())) {
return false;
}
network = toInt(InetAddress.getByName(nm.get(0).toString()));

// generate netmask int from cidr/network notations
if (nm.get(1).toString().length() < 3) {
cidr = Integer.parseInt( nm.get(1).toString() );
if (!validateCIDR(cidr, NetMask)) {
return false;
}
netmask = 0x80000000 >> (cidr - 1); // 1st bit is sticky
} else {
if (!validateInetAddress(nm.get(1).toString())) {
return false;
}
cidr = Integer.bitCount( toInt(InetAddress.getByName(nm.get(1).toString())) );
// if we get 255.127.1.0 it's considered like 255.255.0.0 ... add netmask validation?
}
if (cidr == 32) {
return ip==network;
}
netmask = 0x80000000 >> (cidr - 1);
return ((ip & netmask) == network);
}

/** Check cidr value in bounds */
private static boolean validateCIDR(int cidr, String NetMask) throws Exception
{
if (cidr<0 || cidr>32) {
throw new Exception("CIDR value out of bounds [0..32]: "+NetMask);
}
return true;
}

/** Validate the IP address doesn't have any out of bound values */
private static boolean validateInetAddress(String IPAddress) throws Exception
{
int i = 0;
StringTokenizer tokens = new StringTokenizer(IPAddress, ".");
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken().toString();
if (!Integer.toString((Integer.parseInt(token)&0xff)).equals(token)) {
throw new Exception("Can't validate IP Address: "+IPAddress);
}
i++;
}
if (i>4) {
throw new Exception("IP Address has more than 4 parts: "+IPAddress);
}
return true;
}

/** Convert InetAddress to int */
private static int toInt(InetAddress inetAddress)
{
byte[] address = inetAddress.getAddress();
int net = 0;
for (int i=0; i<address.length; i++) {
net = (net<<8) | (address[i] & 0xff);
}
return net;
}
}

How to check a input IP fall in a specific IP range

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

Go - check if IP address is in a network

The Go net package includes the following functions:

  • ParseCIDR: takes a string representing an IP/mask and returns an
    IP and an IPNet
  • IPNet.Contains: checks whether an IP is in a
    network

This should cover your needs.

How can I check if an ip is in a network in Python?

This article shows you can do it with socket and struct modules without too much extra effort. I added a little to the article as follows:

import socket,struct

def makeMask(n):
"return a mask of n bits as a long integer"
return (2L<<n-1) - 1

def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack('L',socket.inet_aton(ip))[0]

def networkMask(ip,bits):
"Convert a network address to a long integer"
return dottedQuadToNum(ip) & makeMask(bits)

def addressInNetwork(ip,net):
"Is an address in a network"
return ip & net == net

address = dottedQuadToNum("192.168.1.1")
networka = networkMask("10.0.0.0",24)
networkb = networkMask("192.168.0.0",24)
print (address,networka,networkb)
print addressInNetwork(address,networka)
print addressInNetwork(address,networkb)

This outputs:

False
True

If you just want a single function that takes strings it would look like this:

import socket,struct

def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack('L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netmask = struct.unpack('L',socket.inet_aton(netaddr))[0] & ((2L<<int(bits)-1) - 1)
return ipaddr & netmask == netmask

Efficient way to see if an IP address is in a list of subnets

Since CIDRs are contiguous, you could add two columns: the minimum and maximum IP addresses in range, and create indexes on those. I wrote a gist here if you want to see the whole thing and play with it.

Basically:

create table mod_ipdesc
as select addr, category,
inet(host(network(addr))) as amin,
inet(host(broadcast(addr))) as amax
from ipdesc;

create index mod_ipdesc_addr on mod_ipdesc(amin, amax);

Then:

select *
from test a
left outer join mod_ipdesc b
on (a.ip between b.amin and b.amax);

On your table definition, plus a test table with a few ip values (as inet), we get:



Leave a reply



Submit