Net-IPAddress-Util

 view release on metacpan or  search on metacpan

lib/Net/IPAddress/Util/Range.pm  view on Meta::CPAN

package Net::IPAddress::Util::Range;

use strict;
use warnings;
use 5.012;

use overload (
  '""' => 'as_string',
  '<=>' => '_spaceship',
  'cmp' => '_spaceship',
);

use Net::IPAddress::Util qw( :constr :manip );
require Net::IPAddress::Util::Collection;

our $VERSION = '5.001';

sub new {
  my $class = shift;
  $class = ref($class) || $class;
  my ($arg_ref) = @_;
  my ($l, $u);
  if ($arg_ref->{ lower } && $arg_ref->{ upper }) {
    $arg_ref->{ lower } = IP($arg_ref->{ lower });
    $arg_ref->{ upper } = IP($arg_ref->{ upper });
    if ($arg_ref->{ lower } > $arg_ref->{ upper }) {
      ($arg_ref->{ lower }, $arg_ref->{ upper }) = ($arg_ref->{ upper }, $arg_ref->{ lower });
    }
    return bless $arg_ref => $class;
  }
  elsif ($arg_ref->{ ip }) {
    my $ip;
    my $nm = 2;
    if ($arg_ref->{ netmask }) {
      $ip = IP($arg_ref->{ ip      });
      my $was_ipv4 = $ip->is_ipv4;
      $nm = IP($arg_ref->{ netmask });
      $ip &= $nm;
      $nm = ~$nm;
      if ($was_ipv4) {
        $nm &= ipv4_mask();
      }
      $l = $ip;
      $u = $ip | $nm;
    }
    elsif ($arg_ref->{ ip } =~ m{(.*?)/(\d+)}) {
      my ($t, $cidr) = ($1, $2);
      $ip = IP($t);
      my $was_ipv4 = $ip->is_ipv4;
      my $span
        = ($was_ipv4
        ? 32
        : 128) - $cidr
        ;
      $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
      $ip &= $nm;
      $l = $ip;
      $u = $ip | ~$nm;
    }
    elsif ($arg_ref->{ cidr }) {
      $ip = IP($arg_ref->{ ip });
      my $was_ipv4 = $ip->is_ipv4;
      my $cidr = $arg_ref->{ cidr };
      my $span
        = ($was_ipv4
        ? 32
        : 128) - $cidr
        ;
      $nm = implode_ip(substr(('1' x 128) . ('0' x $span), -128));
      $ip &= $nm;
      $l = $ip;
      $u = $ip | ~$nm;
    }
    else {
      $l = IP($arg_ref->{ ip });
      $u = IP($arg_ref->{ ip });
    }
  }
  return bless { lower => $l, upper => $u } => $class;
}

sub as_string {
  my $self = shift;
  return "($self->{ lower } .. $self->{ upper })";
}

sub outer_bounds {
  my $self = shift;
  my @l = explode_ip($self->{ lower });
  my @u = explode_ip($self->{ upper });
  my @cidr = common_prefix(@l, @u);
  my $cidr = scalar @cidr;
  my $base = implode_ip(ip_pad_prefix(@cidr));
  if ($base->is_ipv4()) {
    $cidr -= 96;
  }
  my @mask = prefix_mask(@l, @u);
  my $nm = implode_ip(ip_pad_prefix(@mask));
  my $x = ~$nm;
  if ($base->is_ipv4()) {
    $nm &= ipv4_mask();
  }
  my $hi = IP($base);
  $hi |= $x;
  return bless {
    lower   => $base,
    cidr    => $cidr,
    netmask => $nm,
    upper   => $hi,
  } => ref($self);
}

sub inner_bounds {
  my $self = shift;
  return $self if $self->{ upper } == $self->{ lower };
  my $bounds = $self->outer_bounds();
  my $new = ref($self)->new($self);
  while ($bounds->{ upper } > $self->{ upper } or $bounds->{ lower } < $self->{ lower }) {
    $new = ref($self)->new({ ip => $self->{ lower }, cidr => $bounds->{ cidr } + 1 });
    $bounds = $new->outer_bounds();
  }
  return $new;
}

sub as_cidr {
  my $self = shift;
  my $hr = $self->outer_bounds();
  return "$hr->{ lower }" . '/' . "$hr->{ cidr }";
}

sub as_netmask {
  my $self = shift;
  my $hr = $self->outer_bounds();
  return "$hr->{ lower }" . ' (' . "$hr->{ netmask }" . ')';
}

sub loose {
  my $self = shift;
  my $hr = $self->outer_bounds();



( run in 0.414 second using v1.01-cache-2.11-cpan-13bb782fe5a )