NAME

Net::IPAM::Block - A library for reading, formatting, sorting and converting IP-blocks.

SYNOPSIS

use Net::IPAM::Block;

# parse and normalize
my $cidr  = Net::IPAM::Block->new('10.0.0.0/24')       // die 'wrong format,';
my $range = Net::IPAM::Block->new('fe80::2-fe80::e')   // die 'wrong format,';
my $host  = Net::IPAM::Block->new('2001:db8::1')       // die 'wrong format,';

DESCRIPTION

A block is an IP-network or IP-range, e.g.

192.168.0.1/24              # network, with CIDR mask
::1/128                     # network, with CIDR mask
10.0.0.3-10.0.17.134        # range
2001:db8::1-2001:db8::f6    # range

The parsed block is represented as an object with:

base
last
mask    # if block is a CIDR, otherwise undef

This representation is fast sortable without conversions to/from the different IP versions.

METHODS

new

$b = Net::IPAM::Block->new('fe80::/10');

new() parses the input as CIDR, range or address (or IP object, see below) and returns the Net::IPAM::Block object.

Example for valid input strings:

2001:db8:dead::/38
10.0.0.0/8

2001:db8::1-2001:db8::ff00:35
192.168.2.3-192.168.7.255

If a begin-end range can be represented as a CIDR, new() calculates the netmask and returns the range as CIDR block with a proper mask_ip.

Plain IP addresses as input strings or objects are converted to /32 or /128 CIDRs.

0.0.0.0                       => 0.0.0.0/32
::ffff:127.0.0.1              => 127.0.0.1/32
::                            => ::/128
Net::IPAM::IP->new('1.2.3.4') => 1.2.3.4/32


$range = Net::IPAM::Block->new('10.2.0.17-10.3.67.255') // die 'wrong block format,';
$range = Net::IPAM::Block->new('fe80::-fe80::1234')     // die 'wrong block format,';

$cidr_24  = Net::IPAM::Block->new('10.0.0.0/24') // die 'wrong block format,';
$cidr_32  = Net::IPAM::Block->new('192.168.0.1') // die 'wrong block format,';
$cidr_128 = Net::IPAM::Block->new('2001:db8::1') // die 'wrong block format,';

$cidr_128 = Net::IPAM::Block->new( Net::IPAM::IP->new('2001:db8::1') // die 'wrong IP format,' );

Returns undef on illegal input.

version

$v = $b->version

Returns 4 or 6.

to_string

Returns the block in canonical form.

say Net::IPAM::Block->new('fe80::aa/10')->to_string;        # fe80::/10
say Net::IPAM::Block->new('1.2.3.4-1.2.3.36')->to_string;   # 1.2.3.4-1.2.3.36
say Net::IPAM::Block->new('127.0.0.1')->to_string;          # 127.0.0.1/32

Stringification is overloaded with to_string

my $b = Net::IPAM::Block->new('fe80::/10');
say $b;                                      # fe80::/10

is_cidr

$b->is_cidr

Returns true if the block is a CIDR.

Net::IPAM::Block->new('fe80::aa/10')->is_cidr        # true
Net::IPAM::Block->new('1.2.3.1-1.2.3.2')->is_cidr    # false

cidrsplit

@cidrs = $b->cidrsplit

Returns the next 2 cidrs splitted from block.

Net::IPAM::Block->new('0.0.0.0/7')->cidrsplit    # 0.0.0.0/8  1.0.0.0/8
Net::IPAM::Block->new('fe80::/12')->cidrsplit    # fe80::/13  fe88::/13

Returns undef if cidr mask is at maximum or if block is no CIDR.

to_cidrs

@cidrs = $b->to_cidrs

Returns a list of Net::IPAM::Block objects as true CIDRs, representing the range.

Net::IPAM::Block->new('17.0.0.1-17.0.0.2')->to_cidrs  # 17.0.0.1/32 17.0.0.2/32
Net::IPAM::Block->new('fe80::aa-fe80::ac')->to_cidrs  # fe80::aa/127 fe80::ac/128
Net::IPAM::Block->new('1.2.3.0-1.2.3.101')->to_cidrs  # 1.2.3.0/26 1.2.3.64/27 1.2.3.96/30 1.2.3.100/31

If the range is a CIDR, just returns the CIDR:

Net::IPAM::Block->new('10.0.0.0/8')->to_cidrs         # 10.0.0.0/8
Net::IPAM::Block->new('::1')->to_cidrs                # ::1/128

base

$ip = $b->base

Returns the base IP, as Net::IPAM::IP object.

$b = Net::IPAM::Block->new('fe80::ffff/10');
say $b->base;  # fe80::/10

last

$ip = $b->last

Returns the last IP, as Net::IPAM::IP object.

$b = Net::IPAM::Block->new('10.0.0.0/30')
say $b->last;  # 10.0.0.3

mask

$ip = $b->mask

Returns the netmask as Net::IPAM::IP object.

$b = Net::IPAM::Block->new('10.0.0.0/24')
say $b->mask if defined $b->mask;  # 255.255.255.0

The mask is only defined for real CIDR blocks.

Example:

1.2.3.4            => mask is /32  = 255.255.255.255
::1                => mask is /128 = ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff

10.0.0.0-10.0.0.15 => mask is /28  = 255.255.255.240
::-::f             => mask is /124 = ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0

10.0.0.0/24        => mask is /24  = 255.255.255.0
fe80::/10          => mask is /10  = ffc0:0000:0000:0000:0000:0000:0000:0000

10.0.0.0-10.0.0.13 => mask is undef
::-::5             => mask is undef

hostmask

$ip = $b->hostmask

Returns the hostmask as Net::IPAM::IP object.

$b = Net::IPAM::Block->new('10.0.0.0/24')
say $b->mask;      # 255.255.255.0
say $b->hostmask;  # 0.0.0.255

$b = Net::IPAM::Block->new('fe80::/10')
say $b->mask;      # ffc0::
say $b->hostmask;  #   3f:ffff:ffff:ffff:ffff:ffff:ffff:ffff

The hostmask is only defined for real CIDR blocks.

cmp

$a->cmp($b)

Compares two IP blocks:

print $this->cmp($other);
@sorted_blocks = sort { $a->cmp($b) } @unsorted_blocks;

cmp() returns -1, 0, +1:

 0 if $a == $b,

-1 if $a is v4 and $b is v6
+1 if $a is v6 and $b is v4

-1 if $a->base < $b->base
+1 if $a->base > $b->base

-1 if $a->base == $b->base and $a->last > $b->last # $a is super-set of $b
+1 if $a->base == $b->base and $a->last < $b->last # $a is sub-set of $b

is_disjunct_with

$a->is_disjunct_with($b)

Returns true if the blocks are disjunct

a       |----------|
b |---|

a |------|
b          |---|

print "a and b are disjunct" if $a->is_disjunct_with($b)

overlaps_with

$a->overlaps_with($b)

Returns true if the blocks overlap.

a    |-------|
b |------|

a |------|
b    |-------|

a |----|
b      |---------|

a      |---------|
b |----|

contains

$a->contains($b)

Returns true if block a contains block b. a and b may NOT coincide.

if ( $a->contains($b) ) {
  print "block a contains block b\n";
}

a |-----------------| |-----------------| |-----------------|
b   |------------|    |------------|           |------------|

The argument may also be a Net::IPAM::IP address object.

if ( $a->contains($ip) ) {
  print "block a contains ip\n";
}

find_free_cidrs

@cidrs = $outer->find_free_cidrs(@inner)

Returns all free CIDR blocks (of max possible bitlen) within given CIDR, minus the inner CIDR blocks. Croaks if inner blocks are no subset of (or not equal to) outer block.

my $outer = Net::IPAM::Block->new("192.168.2.0/24");
my @inner = (
	Net::IPAM::Block->new("192.168.2.0/26"),
	Net::IPAM::Block->new("192.168.2.240-192.168.2.249"),
);

my @free = $outer->find_free_cidrs(@inner);

# outer: 192.168.2.0/24 - inner: [192.168.2.0/26 192.168.2.240-192.168.2.249]
# free: [192.168.2.64/26 192.168.2.128/26 192.168.2.192/27 192.168.2.224/28 192.168.2.250/31 192.168.2.252/30]

FUNCTIONS

aggregate

@cidrs = aggregate(@blocks)

Returns the minimal number of CIDRs spanning the range of input blocks.

AUTHOR

Karl Gaissmaier, <karl.gaissmaier(at)uni-ulm.de>

BUGS

Please report any bugs or feature requests to bug-net-ipam-block at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-IPAM-Block. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Net::IPAM::Block

You can also look for information at:

  • on github

    TODO

SEE ALSO

Net::IPAM::IP

LICENSE AND COPYRIGHT

This software is copyright (c) 2020 by Karl Gaissmaier.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.