Documenting Problems That Were Difficult To Find The Answer To

Perl Script to Calculate IP Blocks Given a Range of IP Addresses

Finding IP Blocks in a Range of IP Addresses

This is not an uncommon problem. You look through your web logs to find hack attempts from a range of IP addresses around the same area. To protect your machine you want to set up a series of iptables (firewall for Linux) rules for that general address range. You look up the address range using the whois tool – and sometimes the range of addresses allocated to an AS (autonomous system) are not a simple /24 or /16. So how do you quickly and easily work out the netblocks involved to feed your firewall?

I’ve written a simple Perl script below to calculate the IP blocks that fit within a given IP range (from the lower IP address to the upper IP address, inclusive).

If you save the below code as and call it thus you will get the following output:

user@host:~$ perl -w
#!/usr/bin/perl -w

use strict;

sub ipstr_to_int {
    my ( $s ) = @_;
    my @z = split( /\./, $s );
    return( ($z[0] << 24) + ($z[1] << 16) + ($z[2] << 8) + $z[3] );

sub int_to_ipstr {
    my ( $i ) = @_;
    my $s = sprintf( 
        "%d.%d.%d.%d", ($i>>24)&0xFF, ($i>>16)&0xFF, ($i>>8)&0xFF, $i & 0xFF
    return( $s );

my @ip_masks = (

my @ip_ranges = (

sub calc_ranges {
    my ( $ip_from, $ip_to ) = @_;

    # convert IP strings into integers
    my ( $int_ip_from ) = ipstr_to_int( $ip_from );
    my ( $int_ip_to ) = ipstr_to_int( $ip_to );
    my @results = (); # holding variable for results
    # iterate until we've found blocks for all parts of the range
    my $int_ip_next = $int_ip_from;
    while ( $int_ip_next <= $int_ip_to ) {
        # find widest netblock/mask that commences from this IP
        my $netmask_bits = 31; # we could start at 32 but pointless
        while ( $netmask_bits > 0 ) {
            # check - does this block start below our minimum address?
            my $mask = $ip_masks[$netmask_bits];
            last if ( $int_ip_next != ( $int_ip_next & $mask ) );
            # check - does this block exceed the range we want?
            my $this_block_ip_to = $int_ip_next + $ip_ranges[$netmask_bits] - 1;
            last if ( $this_block_ip_to > $int_ip_to );
            # widen netmask/range for this block and try again
        # last block was 1 bit too wide
        push( @results, int_to_ipstr( $int_ip_next ) . "/$netmask_bits" );
        $int_ip_next += $ip_ranges[$netmask_bits];
    return( @results );

# demonstration routine
# you can call from command line like:
#   perl -w
my $from = shift;
my $to = shift;
my @results = calc_ranges( $from, $to );
print( "  $_\n" ) foreach ( @results );

In the code I’ve used hard coded arrays for the binary netmask and IP range. Subroutines can be used instead but, of course, they will be a lot slower – especially given that for every block up to 32 netmasks can be “tried” for fit.

This Perl code should be easily/trivially translated to other languages if you have the need for such a tool yourself.

4 responses to “Perl Script to Calculate IP Blocks Given a Range of IP Addresses

  1. Matthew August 13, 2012 at 4:04 pm

    perl -MNet::IP -e ‘$ip = new Net::IP (“$ARGV[0] – $ARGV[1]”); print map { “$_\n” } $ip->find_prefixes();’ “” “”

    No error checking or validating of inputs, but it still does what you wanted (it matches your output when using your example). I doubt it would make such an impressive blog post though!

    • newspaint August 13, 2012 at 4:08 pm

      Great response! The CPAN module Net::IP is easily available in the Debian/Ubuntu package libnet-ip-perl, too.

      The blog post may allow those using different languages to easily port the function to their environment of choice.

  2. neuhru March 25, 2013 at 10:58 pm

    I am trying to determine the IP address given a specific range and I find this example useful. I am a newbie and have some questions.

    (remainder of the question removed by editor)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: