BGPmon-CPM-Prefix-Finder-1

 view release on metacpan or  search on metacpan

lib/BGPmon/CPM/Prefix/Finder.pm  view on Meta::CPAN


  Input: Array of IP addresses
  Output: Hash of Prefixes

=cut
sub expandWhois{

  ## get the list of prefixes to expand
  my @prefixes = @_;

  my %return_set;
  my @ranges;

  ## perform the expansion for each prefix
  foreach my $p (@prefixes){

    ## if it is formatted as /32 or /128 remove it
    if($p =~ /\/(\d+)/){
      if($1 == 32 || $1 == 128){
        $p =~ s/\/(\d+)//;
      }
    }
    my $version;
    if(ip_is_ipv4($p)){
      $version = 4;
    }elsif(ip_is_ipv6($p)){
      $version = 6;
    }else{
      $return_set{$p}{'msg'} = 'Unable to verify as IPv4 or v6';
      next;
    }

    ## figure out if we have expanded a previous prefix that covers this one.
    ## don't do the same range twice
    my $covered = 0;
    my $elligible = 1;
    foreach my $range (@ranges){
      my ($r,$l) = split('/',$range);
      my ($start,$end) = ip_prefix_to_range($r,$l,$version);
      my $binp = ip_iptobin($p,$version);
      my $bstart = ip_iptobin($start,$version);
      my $bend = ip_iptobin($end,$version);
      if(ip_bincomp($binp,'le',$bend) && ip_bincomp($binp,'ge',$bstart)){
        $covered = $range;
        $elligible = 0;
        last;
      }
    }

    my %ipExpanded;
    ## elligible for expansion
    if(!$covered && $elligible){
      %ipExpanded = BGPmon::CPM::Prefix::Finder::expandIP($p);
      if( $ipExpanded{'error'} ){
        $ipExpanded{'msg'} = $ipExpanded{'error'};
        $return_set{$p} = \%ipExpanded;
        next;
      }
      if( defined($ipExpanded{'orghandle'}) 
            && $ipExpanded{'orghandle'} !~ /UNKNOWN/){
        $ipExpanded{'orgid'} = $ipExpanded{'orghandle'};
        my @nets = BGPmon::CPM::Prefix::Finder::orghandle2nets(
                                                      $ipExpanded{'orghandle'});
        my @new_prefixes;
        foreach my $net (@nets){
          push @new_prefixes,
               BGPmon::CPM::Prefix::Finder::inetnum2prefixes($net);
        }
        $ipExpanded{'nets'} = \@new_prefixes;
        push @ranges,@new_prefixes;
        $ipExpanded{'msg'} = "whois $p ($ipExpanded{'orghandle'})";
      }

      my @new_ranges = BGPmon::CPM::Prefix::Finder::inetnum2prefixes(
                                                        $ipExpanded{'inetnum'});
      push @ranges,@new_ranges;
      $ipExpanded{'range'} = \@new_ranges;
    }elsif($covered){
      $ipExpanded{'msg'} = "$p is covered by $covered";
    }else{
      $ipExpanded{'msg'} = "$p is not elligible for expansion";
    }
    $return_set{$p} = \%ipExpanded;
  }
  return %return_set;
}


=head2 expandIP

This subroutine looks into the whois databases and 
Input: ip address
Output: a hash with as many of the following keys as possible
"netname","inetnum","descr","country","orgid","source","netname",
"orgname","orghandle"

=cut
sub expandIP{

  my $ip = shift;
  my %org_info;

  ## step 1: query arin to find the organization (this may be under 
  ##         netname or ??)
  my $ua = LWP::UserAgent->new;
  my $res = $ua->get("http://whois.arin.net/rest/ip/$ip.json",
                     "Content_Type"=>"application/json");
  my $res_struct = decode_json($res->content);
  my $org_handle =  $res_struct->{'net'}->{'orgRef'}->{'@handle'};
  if(!defined($org_handle)){
    $org_handle = "";
    $org_info{'source'} = 'UNKNOWN';
    $org_info{'netname'} = $res_struct->{'net'}->{'name'}->{'$'};
    $org_info{'orgname'} = 'UNKNOWN'; 
    $org_info{'orghandle'} = 'UNKNOWN'; 
    $org_info{'inetnum'} = $res_struct->{'net'}->{'startAddress'}->{'$'} .
                           "-" . $res_struct->{'net'}->{'endAddress'}->{'$'} ;
  }elsif($org_handle =~ /APNIC|AFRINIC|LACNIC|RIPE/ ){
  ## if we have been referred to another RIR search RIPE
  #if(grep /$org_handle/, ("APNIC","AFRINIC","LACNIC","RIPE" )){
    $res = $ua->get("http://apps.db.ripe.net/whois/search?query-string=$ip".
                    "&source=$org_handle&flags=Crl",
                    'Accept'=>'application/json');
    if(!$res->is_success){
      $org_info{'source'} = $org_handle;
      $org_info{'error'} = "whois lookup failed"; 
    }else{
      $res_struct = decode_json($res->content);

      my @attributes;
      if($res_struct->{'whois-resources'}->{'objects'}->{'object'} =~ /HASH/){
        @attributes = @{$res_struct->{'whois-resources'}->{'objects'}->
                        {'object'}->{'attributes'}->{'attribute'}};
      }elsif($res_struct->{'whois-resources'}->{'objects'}->{'object'}
             =~/ARRAY/){
        foreach my $obj(
              @{$res_struct->{'whois-resources'}->{'objects'}->{'object'}}){
          push @attributes, @{$obj->{'attributes'}->{'attribute'}};
        }
      }
      foreach my $att (@attributes){
        if(grep /$att->{'name'}/, 
              ("netname","inetnum","descr","source","country")){
          $org_info{$att->{'name'}} = $att->{'value'};
        }    
        if(grep /$att->{'name'}/, ("remarks")){
          if($att->{'value'} =~ /org-id:\s*(\S+)/){
            $org_info{'orgid'} = $1;
          }
        }
        
      }
    }
  ## get the data about the organization out of the original structure
  }else{
    $org_info{'source'} = 'ARIN';
    $org_info{'netname'} = $res_struct->{'net'}->{'name'}->{'$'};
    $org_info{'orgname'} = $res_struct->{'net'}->{'orgRef'}->{'@name'};
    $org_info{'orghandle'} = $res_struct->{'net'}->{'orgRef'}->{'@handle'};
    $org_info{'inetnum'} = $res_struct->{'net'}->{'startAddress'}->{'$'} .
                           "-" . $res_struct->{'net'}->{'endAddress'}->{'$'} ;

  }
  return %org_info;
}

=head2 inetnum2prefixes

This subroutine expands an inetnum into a list of prefixes that cover the space.

Input: inetnum
Output: array of prefixes

=cut
sub inetnum2prefixes{

  my $inetnum = shift;
  my ($start,$end) = split /-/,$inetnum;
  my @prefixes;
  $start =~ s/\s*//g;
  $end =~ s/\s*//g;

  my $version = 0;
  if(ip_is_ipv4($start) && ip_is_ipv4($end)){
    $version = 4;
  }elsif(ip_is_ipv6($start) && ip_is_ipv6($end)){
    $version = 6;
  }else{
    return @prefixes;
  }
  my $sbin = ip_iptobin($start,$version);
  my $ebin = ip_iptobin($end,$version);
  if(!defined($sbin) || !defined($ebin)){
    return @prefixes;
  }
  return ip_range_to_prefix($sbin,$ebin,$version);
}

=head2 netname2prefixes

This subroutine expands a netname to a list of prefixes

Input: source and netname
Output: array of prefixes

=cut
sub netname2prefixes{
  my $source = shift;



( run in 2.579 seconds using v1.01-cache-2.11-cpan-302cb4679cc )