Check if an IP is in a subnet in Perl

From Mike A. Leonetti

Jump to: navigation, search

For a new program I was writing I needed a way to search for IPs in a subnet range using a netmask and some other options without the overhead of a module like NetAddr::IP or any other Perl modules that would do the same. So I spent some time writing one. As always, please contact me with any bugs or issues. I hope this helps somebody as it helped me!

The script also contains a function that's like ip2long for PHP that I found on PerlMonks (see references at bottom).

Contents

Introduction

The following script contains two functions that will be able to detect if an IP is in a subnet. The script will evaluate different types of IP ranges.

  1. With the subnet mask /xx for example 192.168.0.0/24
  2. With the subnet mask /xxx.xxx.xxx.xxx for example 192.168.0.0/255.255.255.0
  3. With a range using -xxx for example 192.168.0.100-200
  4. With a range using asterisks for example 192.168.*.*

Examples

/xx subnet

# ./in_subnet.pl 10.0.1.5 10.0.0.0/16
It's in the subnet

/xxx.xxx.xxx.xxx subnet

# ./in_subnet.pl 10.1.3.5 10.0.0.0/255.0.0.0
It's in the subnet

Hyphen ranges

# ./in_subnet.pl 10.0.0.10 10.0.0.5-230
It's in the subnet

Asterisk matching

# ./in_subnet.pl 10.0.2.10 10.0.*.*
It's in the subnet

The script

#!/usr/bin/perl

use strict;

use Socket qw( inet_aton );

sub ip2long($);
sub in_subnet($$);

my $ip = $ARGV[0];
my $subnet = $ARGV[1];

if( in_subnet( $ip, $subnet ) )
{
	print "It's in the subnet\n";
}
else
{
	print "It's NOT in the subnet\n";
}

sub ip2long($)
{
	return( unpack( 'N', inet_aton(shift) ) );
}

sub in_subnet($$)
{
	my $ip = shift;
	my $subnet = shift;

	my $ip_long = ip2long( $ip );

	if( $subnet=~m|(^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$| )
	{
		my $subnet = ip2long( $1 );
		my $mask = ip2long( $2 );

		if( ($ip_long & $mask)==$subnet )
		{
			return( 1 );
		}
	}
	elsif( $subnet=~m|(^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/(\d{1,2})$| )
	{
		my $subnet = ip2long( $1 );
		my $bits = $2;
		my $mask = -1<<(32-$bits);

		$subnet&= $mask;

		if( ($ip_long & $mask)==$subnet )
		{
			return( 1 );
		}
	}
	elsif( $subnet=~m|(^\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})-(\d{1,3})$| )
	{
		my $start_ip = ip2long( $1.$2 );
		my $end_ip = ip2long( $1.$3 );

		if( $start_ip<=$ip_long and $end_ip>=$ip_long )
		{
			return( 1 );
		}
	}
	elsif( $subnet=~m|^[\d\*]{1,3}\.[\d\*]{1,3}\.[\d\*]{1,3}\.[\d\*]{1,3}$| )
	{
		my $search_string = $subnet;

		$search_string=~s/\./\\\./g;
		$search_string=~s/\*/\.\*/g;

		if( $ip=~/^$search_string$/ )
		{
			return( 1 );
		}
	}

	return( 0 );
}

References

Personal tools
Google AdSense