Skip to content

Instantly share code, notes, and snippets.

@dgeo
Created January 27, 2017 12:29
Show Gist options
  • Save dgeo/416accc3dfe88d90f33ed3d936bb2d43 to your computer and use it in GitHub Desktop.
Save dgeo/416accc3dfe88d90f33ed3d936bb2d43 to your computer and use it in GitHub Desktop.
get all ip ranges of an org from a single domain name
#!/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