diff --git a/xtr.pl b/xtr.pl index 73a5131..344e667 100644 --- a/xtr.pl +++ b/xtr.pl @@ -12,24 +12,66 @@ use File::Fetch; use PerlIO::gzip; use LWP::UserAgent; use HTTP::Request; +use Data::Validate::IP qw(is_ipv4); 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"; + +### README ######################################################################################################################################### +# This is the client for the XTR (XiCoN Trace Route). It opens a port and listening to HTTP requests. It answers with a traceroute +# in a json hash. The hash contains for each hop the IP, the PTR, the request time and the AS (Autonomous System). +# +# This client also tries to connect to a "master server" which helps keeping track of all the traceroute clients and their availability. +# +# This software uses the iptoasn database (https://iptoasn.com/) to determine the AS for each hop. To keep track of all ip to asn relations, +# this software creates a local database file "ip2asn.db", which is a simple SQLite3 database with an index for faster searches. +# +# For now, the traceroutes are only IPv4. This will change in the future. +###################################################################################################################################################### + + +### INSTALL ######################################################################################################################################## +# This is a standalone software which usually runs in the "foreground". Starting it in a screen session or via init.d/systemd/rc.d is +# highly recommended. For testing, starting this script in a screen session is also fine. +# +# Either install all listed modules with "cpan -i " or use your system's package manager (apt, yum, yast). +# +# On Debian just install there packages: +# libnet-whois-ip-perl +# libperlio-gzip-perl +# libdancer2-perl +# libnet-dns-perl +# libnet-traceroute-perl +# libdbi-perl +# libdbd-sqlite3-perl +# libdata-validate-ip-perl +# +###################################################################################################################################################### + + +### VARS ########################################################################################################################################### +my $VERSION = "0.4"; +my $dbfile = 'ip2asn.db'; my $ip2asn_csv_url = 'http://iptoasn.com/data/ip2asn-v4-u32.tsv.gz'; -my $master_server = "xtr-master.xicon.eu"; -my $my_ip = get_my_ipv4(); +my $master_server = 'xtr-master.xicon.eu'; +my $get_my_ip_service = 'http://ipv4.xicon.eu/'; # some service, which returns just the ip of the requesting host (in this case, us.) +my $client_protocol_version = 3; +my $my_ip = get_my_ipv4($get_my_ip_service); my $my_ext_ip = ""; # set different ip, if access differs from default public ip -my $my_port = 3000; +my $my_port = 12111; my $my_ext_port = 0; # set different port, if public access port differs from app port +###################################################################################################################################################### + + +###################################################################################################################################################### +### NOTHING TO CHANGE BELOW HERE ################################################################################################################### +###################################################################################################################################################### + ### set vars set port => $my_port; if($my_ext_ip eq "") { $my_ext_ip = $my_ip; } +if($my_ext_ip eq "0.0.0.0") { die "Couldn't determine my own IP"; } if($my_ext_port eq 0 || $my_ext_port eq "") { $my_ext_port = $my_port; } ### connect to database @@ -45,12 +87,18 @@ hook 'before' => sub { }; ### main get route -get '/:ip' => sub { +get '/v3/client/request/:ip' => sub { my $ip = route_parameters->get('ip') || 8.8.8.8; + if(!is_ipv4($ip)) { status('bad_request'); return "invalid IP address" } my $trace = traceit($dbh,$ip); return encode_json $trace; }; +### return client protocol verison +get '/v3/client/info/version' => sub { + return $client_protocol_version; +}; + ### give the master server the info, that we are available if(send_server_status($master_server,$my_ext_ip,$my_ext_port,"1")) { @@ -64,17 +112,19 @@ else ### catch "INT" signal to send the status to the master server $SIG{'INT'} = sub { send_server_status($master_server,$my_ext_ip,$my_ext_port,"0"); exit; }; -### start the loop +### start the main loop start; ### if you reach this, you're done exit; + + sub send_server_status { my ($master_server,$hostname,$port,$status) = @_; - my $url = "http://".$master_server."/v2/server/".$hostname."/".$port."/".$status; - my $ua = LWP::UserAgent->new(timeout => 10); + my $url = "http://".$master_server."/v3/server/add/".$hostname."/".$port."/".$status; + my $ua = LWP::UserAgent->new(timeout => 2); my $req = HTTP::Request->new("PUT", $url); my $response = $ua->request($req); return $response->is_success; @@ -82,9 +132,18 @@ sub send_server_status sub get_my_ipv4 { + my ($ip_service) = @_; my $ua = LWP::UserAgent->new(timeout => 10); - my $response = $ua->get("http://ipv4.xicon.eu/"); - return $response->decoded_content; + my $response = $ua->get($ip_service); + if(is_ipv4($response->decoded_content)) + { + return $response->decoded_content; + } + else + { + # no valid ip returned from ip service + return "0.0.0.0"; + } } sub traceit @@ -200,15 +259,18 @@ sub create_db_table 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"; + print "creating main 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(); + + print "creating index table...\n"; + 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