From 6df0e11148d21e923c89286b5f6970b96fe5c0fc Mon Sep 17 00:00:00 2001 From: XiCoN-FJS- Date: Sat, 19 Oct 2019 23:25:25 +0200 Subject: [PATCH] v2 --- xtr.pl | 153 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 132 insertions(+), 21 deletions(-) diff --git a/xtr.pl b/xtr.pl index cccdaba..4b9b2cf 100644 --- a/xtr.pl +++ b/xtr.pl @@ -4,55 +4,82 @@ use strict; use warnings; use Net::Traceroute; use Net::DNS::Resolver; +use Net::Whois::IP; use Dancer2; -#use JSON::PP; +use Socket; +use DBI; +use File::Fetch; +use PerlIO::gzip; use Data::Dumper; +### README +# to install needed modules on debian: +# * apt-get install libnet-whois-ip-perl libperlio-gzip-perl libdancer2-perl libnet-dns-perl libnet-traceroute-perl libdbi-perl libdbd-sqlite3-perl +### vars +my $dbfile = "ip2asn.db"; +my $ip2asn_csv_url = 'http://iptoasn.com/data/ip2asn-v4-u32.tsv.gz'; + +### connect to database +my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","",""); +$dbh->do("PRAGMA cache_size = 800000"); + +### create database & table if needed and fill with ip information +if(create_db_table($dbh)) { get_ipas_data($dbh,$ip2asn_csv_url); } + +### hook for HTTP "security" hook 'before' => sub { header 'Access-Control-Allow-Origin' => '*'; }; +### main get route get '/:ip' => sub { my $ip = route_parameters->get('ip') || 8.8.8.8; - my $trace = traceit($ip); + my $trace = traceit($dbh,$ip); return encode_json $trace; }; - + +### start the loop start; - +### if you reach this, you're done +exit; sub traceit { - my ($host) = @_; + my ($dbh,$host) = @_; my $tr = Net::Traceroute->new(host => $host, use_icmp => 1, timeout => 1 ); -my @array = (); -if($tr->found) -{ - #print Dumper($tr->hops); - foreach my $hop (@{$tr->{'hops'}}) + my @array = (); + if($tr->found) { - my $sum = sprintf("%.1f",($hop->[0]->[2] + $hop->[1]->[2] + $hop->[2]->[2])/3); - my $res = Net::DNS::Resolver->new; - my $query = $res->query($hop->[0]->[1], 'PTR'); - my $answer = "nonono"; - if($query) + foreach my $hop (@{$tr->{'hops'}}) { - foreach my $rr ($query->answer) + my $sum = sprintf("%.1f",($hop->[0]->[2] + $hop->[1]->[2] + $hop->[2]->[2])/3); + my $res = Net::DNS::Resolver->new; + my $query = $res->query($hop->[0]->[1], 'PTR'); + my $answer = " "; + if($query) { - if($rr->type eq "PTR") + foreach my $rr ($query->answer) { - $answer = $rr->ptrdname; + if($rr->type eq "PTR") + { + $answer = $rr->ptrdname; + } } } + + ### get AS to IP + my $as = 0; + if($hop->[0]->[1] ne "255.255.255.255") + { + $as = find_as($dbh, $hop->[0]->[1]); + } + push(@array, [$hop->[0]->[1],$answer,$sum,$as]); } - # print $hop->[0]->[1]."\t(".$answer.") - ".$sum."\n"; - push(@array, [$hop->[0]->[1],$answer,$sum]); } -} if($tr->found) { @@ -64,3 +91,87 @@ if($tr->found) } } +sub get_ipas_data +{ + my ($dbh,$ip2asn_csv_url) = @_; + + my $ff = File::Fetch->new(uri => $ip2asn_csv_url); + my $temp_file = $ff->fetch( to => '/tmp' ); + + open(FILE,"<:gzip",$temp_file) or die "Can't open file: $!"; + my @data = ; + close(FILE); + + $dbh->do('begin'); + + my $max_commit = 10000; + my $inserted = 0; + my $array_size = @data; + my $last_p = -1; + print "loading data...\n"; + foreach my $line (@data) + { + chomp($line); + if($line=~/^(\d+)\s+(\d+)\s+(\d+)/) + { + if($3 eq "0") { next; } + #my %temp_hash = ('from' => $1, 'to' => $2, 'as' => $3); + #push(@ipaslist,\%temp_hash); + my $insert_cmd .= "INSERT INTO ip2asn VALUES (".$1.",".$2.",".$3.");"; + my $insert_sth = $dbh->prepare($insert_cmd); + $inserted += $insert_sth->execute(); + + # print status for console users + my $p = int($inserted * 100 / $array_size); + if($p != $last_p) { print $p % 10 ? "" : "$p%\n"; } + $last_p = $p; + + # only commit every $max_commit statements (it's faster) + unless ($inserted % $max_commit) + { + $dbh->do('commit'); + $dbh->do('begin'); + } + } + } + + $dbh->do('commit'); + unlink($temp_file); + print "data prepared for searches!\n"; +} + +sub find_as +{ + my ($dbh, $ip) = @_; + my $ip_id = unpack("N", inet_aton($ip)); + + my $get_as_cmd = "SELECT ip_as FROM ip2asn WHERE ip_from < ".$ip_id." AND ip_to > ".$ip_id.";"; + my $get_as_sth = $dbh->prepare($get_as_cmd); + $get_as_sth->execute(); + my $result = $get_as_sth->fetch; + return $result->[0] || 0; +} + +sub create_db_table +{ + my ($dbh) = @_; + + my $check_table_cmd = "SELECT name FROM sqlite_master WHERE type='table' AND name='ip2asn';"; + my $check_table_sth = $dbh->prepare($check_table_cmd); + $check_table_sth->execute(); + if(!$check_table_sth->fetch) + { + print "creating table...\n"; + my $create_table_cmd = "CREATE TABLE ip2asn( ip_from INTEGER, ip_to INTEGER, ip_as INTEGER)"; + my $create_table_sth = $dbh->prepare($create_table_cmd); + $create_table_sth->execute(); + #my $create_index_cmd = "CREATE INDEX ip2asnIndex ON ip2asn(ip_from,ip_to);"; + #my $create_index_sth = $dbh->prepare($create_index_cmd); + #$create_index_sth->execute(); + return 1; + } + else + { + return 0; + } +}