Created
January 27, 2017 12:29
-
-
Save dgeo/416accc3dfe88d90f33ed3d936bb2d43 to your computer and use it in GitHub Desktop.
get all ip ranges of an org from a single domain name
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
# | |
# un p'tit script pour lister les adresses liées à un domaine. | |
# | |
# algo: domaine -> DNS -> IP -> whois -> listes de blocs | |
# | |
use strict; | |
use warnings; | |
use JSON; | |
use Net::CIDR ':all'; | |
use LWP::Simple; | |
use LWP::UserAgent; | |
use List::MoreUtils qw(zip); | |
use Net::Whois::IP qw(whoisip_query); | |
use Socket; | |
use Data::Dumper; | |
my $org; | |
my $debug=0; | |
if (@ARGV < 1) { | |
print "usage: $0 domaine [domaine2 …]\n"; | |
print " domaine: nom DNS, ou 'aws'\n"; | |
exit; | |
} | |
# infos depuis l'API du RIPE | |
sub ripe_get_ips() { | |
my $orgs = shift; | |
if (ref $orgs ne 'ARRAY') { | |
$orgs = [ {'att'=>'admin-c','value'=>$orgs } ]; | |
} | |
my ($content,$url,$org,$pc)=undef; | |
while (my $o = shift @$orgs) { | |
$org = $o->{value}; | |
$url = "http://rest.db.ripe.net/search.json?query-string=".$o->{value}."&type-filter=inet6num&type-filter=inetnum&inverse-attribute=".$o->{att}."&flags=no-filtering"; | |
print STDERR "RIPE: ".$o->{value}." URL: $url\n" if ($debug); | |
$content = get($url);# or next; | |
$content = get($url) or next; | |
#print STDERR $content; | |
$pc = from_json($content) or next; | |
#print STDERR $pc; | |
last if (@{$pc->{'objects'}->{'object'}}); | |
} | |
return undef if (!$pc); | |
my @ranges4=(); | |
my @ranges6=(); | |
my @cidrlist=(); | |
my @cidr6list=(); | |
foreach my $obj (@{$pc->{'objects'}->{'object'}}) { | |
if ($obj->{'type'} eq 'inetnum') { | |
push @ranges4, $obj->{'primary-key'}->{'attribute'}->[0]->{'value'}; | |
} elsif ($obj->{'type'} eq 'inet6num') { | |
push @ranges6, $obj->{'primary-key'}->{'attribute'}->[0]->{'value'}; | |
} | |
@cidrlist=Net::CIDR::cidradd(@ranges4); | |
@cidr6list=Net::CIDR::cidradd(@ranges6); | |
} | |
return \@cidrlist,\@cidr6list,"ORG: $org URL: $url"; | |
} | |
# infos depuis l'API ARIN | |
sub arin_get_ips() { | |
my $o = shift; | |
my $url = "https://whois.arin.net/rest/org/".$o."/nets" or return undef; | |
print STDERR "ARIN: $o: $url\n" if ($debug); | |
my $ua = LWP::UserAgent->new; | |
$ua->default_header( 'Accept' => 'application/json'); | |
my $r = $ua->get($url) or return undef; | |
#print STDERR Dumper($r->content); | |
my $pc = from_json($r->content); | |
#print STDERR Dumper($pc); | |
my @ranges4=(); | |
my @ranges6=(); | |
my @cidrlist=(); | |
my @cidr6list=(); | |
foreach my $nr (@{$pc->{'nets'}->{'netRef'}}) { | |
my $range=$nr->{'@startAddress'}."-".$nr->{'@endAddress'}; | |
if ($nr->{'@startAddress'} =~ m/:/) { | |
push @ranges6, $range; | |
} else { | |
push @ranges4, $range; | |
} | |
@cidr6list = Net::CIDR::range2cidr(@ranges6); | |
@cidrlist = Net::CIDR::range2cidr(@ranges4); | |
} | |
return \@cidrlist,\@cidr6list,"ORG: $o URL: $url"; | |
} | |
# listes des IPs amazon | |
sub get_amazon_aws_ips() { | |
my $content = get("https://ip-ranges.amazonaws.com/ip-ranges.json"); | |
my $pc = from_json($content); | |
my @cidrlist=(); | |
my @cidr6list=(); | |
foreach my $prefix (@{$pc->{'prefixes'}}) { | |
@cidrlist=Net::CIDR::cidradd($prefix->{'ip_prefix'},@cidrlist); | |
} | |
foreach my $prefix (@{$pc->{'ipv6_prefixes'}}) { | |
@cidr6list=Net::CIDR::cidradd($prefix->{'ipv6_prefix'},@cidr6list); | |
} | |
return \@cidrlist,\@cidr6list,"AMAZON AWS, URL: https://ip-ranges.amazonaws.com/ip-ranges.json"; | |
} | |
sub get_whois_domain() { | |
my $dom = shift; | |
my $ip = gethostbyname($dom); | |
if (defined($ip)) { | |
$ip = inet_ntoa($ip); | |
} | |
my $w = whoisip_query($ip) or die "Can't connect to Whois server\n"; | |
my $s; | |
my $o = []; | |
# pour le RIPE selon les domaines on cherche avec deux attributs differents (mnt-by ou admin-c/nic-hdl) | |
if (exists($w->{'source'}) && ($w->{'source'} eq "RIPE")) { | |
push @$o,{'att'=>'admin-c','value'=>$w->{'nic-hdl'}} if exists($w->{'nic-hdl'}); | |
push @$o,{'att'=>'mnt-by','value'=>$w->{'mnt-by'}} if exists($w->{'mnt-by'}); | |
$s = $w->{'source'} if exists ($w->{'source'}); | |
} elsif (exists($w->{'OrgTechHandle'}) && ($w->{'OrgTechHandle'} =~ /-ARIN/)) { | |
$o = $w->{'OrgId'} if exists ($w->{'OrgId'}); | |
$s = 'ARIN'; | |
} else { | |
print STDERR "source inconnue pour $ip\n"; | |
die "Not implemented"; | |
} | |
return $o,$s; | |
} | |
my @liste; | |
foreach my $domain (@ARGV) { | |
my ($cidrs,$cidr6s,$comment)=undef; | |
if ($domain eq "aws") { | |
($cidrs,$cidr6s,$comment)=&get_amazon_aws_ips(); | |
} else { | |
my ($o,$s) = &get_whois_domain($domain) or next; | |
if ($s eq 'RIPE') { | |
($cidrs,$cidr6s,$comment)=&ripe_get_ips($o) or die "ripe_get_ips $o failed"; | |
} elsif ($s eq 'ARIN') { | |
($cidrs,$cidr6s,$comment)=&arin_get_ips($o) or die "arin_get_ips $o failed"; | |
} else { | |
print STDERR "ni RIPE ni ARIN: reste a coder\n"; | |
next; | |
} | |
if (($s eq 'ARIN') && ($o =~ /^(AT-88-|AMA)Z/)) { | |
($cidrs,$cidr6s,$comment)=&get_amazon_aws_ips(); | |
} | |
if ((!$cidrs)&&(!$cidr6s)) { | |
print STDERR "rien pour $domain\n"; | |
next; | |
} | |
} | |
push @liste,"# $domain: $comment"; | |
foreach my $c (@$cidrs) { push @liste,$c;}; | |
foreach my $c (@$cidr6s) { push @liste,$c;}; | |
} | |
print join("\n",@liste)."\n"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment