From bff7d4e7b4833f8f6d460e0893bcce25b17566e0 Mon Sep 17 00:00:00 2001 From: XiCoN-FJS- Date: Sat, 19 Oct 2019 23:29:02 +0200 Subject: [PATCH] v2 --- xtrd.pl | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 xtrd.pl diff --git a/xtrd.pl b/xtrd.pl new file mode 100644 index 0000000..3b01dda --- /dev/null +++ b/xtrd.pl @@ -0,0 +1,203 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Dancer2; +use Socket; +use DBI; +use File::Fetch; +use PerlIO::gzip; +use Data::Dumper; + +### README +# to install needed modules on debian: +# * apt-get install libperlio-gzip-perl libdancer2-perl libdbi-perl libdbd-sqlite3-perl + +### vars +my $dbfile = "xtrd.db"; +my $ip2asn_csv_url = 'http://iptoasn.com/data/ip2asn-v4-u32.tsv.gz'; +set port => 12110; + +### connect to database +my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","",""); +$dbh->do("PRAGMA cache_size = 800000"); + +### create ip2asn database & table if needed and fill with ip information +if(create_db_table($dbh,"ip2asn","ip2asn( ip_from INTEGER, ip_to INTEGER, ip_as INTEGER)","ip2asnIndex ON ip2asn(ip_from,ip_to);")) +{ + get_ipas_data($dbh,$ip2asn_csv_url); +} + +### create server database & table if needed +create_db_table($dbh,"server","server( server_ip TEXT, server_port INTEGER, server_as INTEGER, server_status INTEGER)",""); + + + +### hook for HTTP "security" +hook 'before' => sub { + header 'Access-Control-Allow-Origin' => '*'; +}; + +### main get route +get '/v2/server' => sub { + my $server = get_server($dbh,"1"); + return encode_json $server; +}; + +put '/v2/server/:ip/:port/:status' => sub { + my $ip = route_parameters->get('ip'); + my $port = route_parameters->get('port'); + my $status = route_parameters->get('status'); + my $result = add_server($dbh,$ip,$port,$status); + return encode_json $result; +}; + +### start the loop +start; + +### if you reach this, you're done +exit; + +sub add_server +{ + my ($dbh,$ip,$port,$status) = @_; + my $id = get_server_id($dbh,$ip,$port); + if($id ne "0") + { + # update server status + set_server_status($dbh,$id,$status); + my $return_code = {"status" => "1"}; + return $return_code; + } + else + { + # create + my $resolve = gethostbyname($ip); + my $a_record = inet_ntoa($resolve); + my $as = find_as($dbh,$a_record); + my $add_server_cmd = "INSERT INTO server VALUES ('".$ip."','".$port."','".$as."','".$status."');"; + my $add_server_sth = $dbh->prepare($add_server_cmd); + $add_server_sth->execute(); + my $return_code = {"status" => "1"}; + return $return_code; + } +} + +sub set_server_status +{ + my ($dbh,$id,$status) = @_; + + my $set_status_cmd = "UPDATE server set server_status = '".$status."' WHERE _rowid_ = '".$id."';"; + my $set_status_sth = $dbh->prepare($set_status_cmd); + $set_status_sth->execute(); +} + +sub get_server_id +{ + my ($dbh,$ip,$port) = @_; + + my $get_id_cmd = "SELECT _rowid_ FROM server WHERE server_ip = '".$ip."' AND server_port = '".$port."';"; + my $get_id_sth = $dbh->prepare($get_id_cmd); + $get_id_sth->execute(); + my $result = $get_id_sth->fetch; + return $result->[0] || 0; +} + +sub get_server +{ + my ($dbh,$status) = @_; + if($status eq "") { $status = 1; } + my $get_server_cmd = "SELECT * FROM server WHERE server_status = '".$status."';"; + my $get_server_sth = $dbh->prepare($get_server_cmd); + $get_server_sth->execute(); + my $result = $get_server_sth->fetchall_arrayref;; + return $result; +} + +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,$table,$schema,$schema_index) = @_; + + my $check_table_cmd = "SELECT name FROM sqlite_master WHERE type='table' AND name='".$table."';"; + my $check_table_sth = $dbh->prepare($check_table_cmd); + $check_table_sth->execute(); + if(!$check_table_sth->fetch) + { + print "creating table '".$table."'...\n"; + my $create_table_cmd = "CREATE TABLE ".$schema; + my $create_table_sth = $dbh->prepare($create_table_cmd); + $create_table_sth->execute(); + if($schema_index ne "") + { + my $create_index_cmd = "CREATE INDEX ".$schema_index; + my $create_index_sth = $dbh->prepare($create_index_cmd); + $create_index_sth->execute(); + } + return 1; + } + else + { + return 0; + } +}