File Coverage

blib/lib/Zonemaster/Engine/ASNLookup.pm
Criterion Covered Total %
statement 46 47 97.8
branch 10 12 83.3
condition 2 3 66.6
subroutine 8 8 100.0
pod 2 2 100.0
total 68 72 94.4


line stmt bran cond sub pod time code
1             package Zonemaster::Engine::ASNLookup;
2              
3 26     26   184 use version; our $VERSION = version->declare("v1.0.4");
  26         52  
  26         141  
4              
5 26     26   2224 use 5.014002;
  26         90  
6 26     26   149 use warnings;
  26         54  
  26         671  
7              
8 26     26   131 use Zonemaster::Engine::Net::IP;
  26         54  
  26         962  
9              
10 26     26   613 use Zonemaster::Engine;
  26         54  
  26         543  
11 26     26   142 use Zonemaster::Engine::Nameserver;
  26         59  
  26         10573  
12              
13             our @roots;
14              
15             sub get_with_prefix {
16 38     38 1 2002 my ( $class, $ip ) = @_;
17              
18 38 100       144 if ( not @roots ) {
19 3         9 @roots = map { Zonemaster::Engine->zone( $_ ) } @{ Zonemaster::Engine->config->asnroots };
  9         41  
  3         20  
20             }
21              
22 38 100 66     327 if ( not ref( $ip ) or not $ip->isa( 'Zonemaster::Engine::Net::IP' ) ) {
23 4         13 $ip = Zonemaster::Engine::Net::IP->new( $ip );
24             }
25              
26 38         239 my $reverse = $ip->reverse_ip;
27 38         2594 foreach my $zone ( @roots ) {
28 40         1367 my $domain = $zone->name->string;
29 40         229 my $pair = {
30             'in-addr.arpa.' => "origin.$domain",
31             'ip6.arpa.' => "origin6.$domain",
32             };
33 40         121 foreach my $root ( keys %{$pair} ) {
  40         150  
34 57 100       795 if ( $reverse =~ s/$root/$pair->{$root}/ix ) {
35 38         189 my $p = $zone->query_persistent( $reverse, 'TXT' );
36 38 100       188 next if not $p;
37              
38 37         170 my ( $rr ) = $p->get_records( 'TXT' );
39 37 50       301 return if not $rr;
40              
41 37         1989 my $str = $rr->txtdata;
42 37         637 $str =~ s/"([^"]+)"/$1/x;
43 37         285 my @fields = split( /[ ]\|[ ]?/x, $str );
44 37         150 my @asns = split( /\s+/x, $fields[0] );
45              
46 37         252 return \@asns, Zonemaster::Engine::Net::IP->new( $fields[1] ), $str;
47             }
48             }
49             } ## end foreach my $zone ( @roots )
50 1         9 return;
51             } ## end sub get_with_prefix
52              
53             sub get {
54 1     1 1 932 my ( $class, $ip ) = @_;
55              
56 1         4 my ( $asnref, $prefix, $raw ) = $class->get_with_prefix( $ip );
57              
58 1 50       4 if ( $asnref ) {
59 1         4 return @{$asnref};
  1         6  
60             }
61             else {
62 0           return;
63             }
64             }
65              
66             1;
67              
68             =head1 NAME
69              
70             Zonemaster::Engine::ASNLookup - do lookups of ASNs for IP addresses
71              
72             =head1 SYNOPSIS
73              
74             my ($asnref, $prefix) = Zonemaster::Engine::ASNLookup->get_with_prefix( '8.8.4.4' );
75             my $asnref = Zonemaster::Engine::ASNLookup->get( '192.168.0.1' );
76              
77             =head1 FUNCTION
78              
79             =over
80              
81             =item get($addr)
82              
83             Takes a string (or a L<Net::IP> object) with a single IP address, does a lookup
84             in a Cymru-style DNS zone and returns a list of AS numbers for the address, if
85             any can be found.
86              
87             =item get_with_prefix($addr)
88              
89             As L<get()>, except it returns a list of a reference to a list with the AS
90             numbers, and a Net::IP object representing the prefix of the AS.
91              
92             =back
93              
94             =cut