37e1747a618923800220d8ecd366b01f5207a11a
[spider.git] / perl / create_master_badip_files.pl
1 #!/usr/bin/env perl
2 #
3 # Get the TOR exit and relay lists from the net, extract the exit and relay
4 # node ip addresses and store them, one per line, in the standard places
5 # in /spider/local_data. 
6 #
7
8 use 5.16.1;
9
10 # search local then perl directories
11 use strict;
12
13 BEGIN {
14         # root of directory tree for this system
15         our $root = "/spider"; 
16         $root = $ENV{'DXSPIDER_ROOT'} if $ENV{'DXSPIDER_ROOT'};
17
18         mkdir "$root/local_data", 02777 unless -d "$root/local_data";
19
20         unshift @INC, "$root/perl";     # this IS the right way round!
21         unshift @INC, "$root/local";
22         our $data = "$root/data";
23 }
24
25
26 use DXVars;
27 use SysVar;
28
29 use DXDebug;
30 use DXUtil;
31
32 use LWP::Simple;
33 use JSON;
34 use Date::Parse;
35 use File::Copy;
36 use DXUtil;
37
38 DXDebug::dbginit();
39
40 $ENV{PERL_JSON_BACKEND} = "JSON::XS,JSON::PP";
41
42
43 my $debug;
44
45 if (@ARGV && $ARGV[0] eq '-x') {
46         shift;
47         $debug = 1;
48 }
49 my $url = "https://onionoo.torproject.org/details";
50 my $relayfn = localdata('badip.torrelay');
51 my $exitfn = localdata('badip.torexit');
52
53 my $last_seen_window = 10800;
54 my $content;
55
56 if (@ARGV) {
57         local $/ = undef;
58         my $fn = shift;
59         open IN, $fn or die "$0 cannot open file $fn, $!";
60         $content = <IN>;
61         close IN;
62 } else {
63         $content = get($url) or die "$0: connect error on $url, $!\n";
64 }
65
66 die "No TOR content available $!\n" unless $content;
67
68 my $l = length $content;
69 my $data = decode_json($content);
70 my $now = time;
71 my $ecount = 0;
72 my $rcount = 0;
73 my $error = 0;
74
75 my $rand = rand;
76 open RELAY, ">$relayfn.$rand" or die "$0: cannot open $relayfn $!";
77 open EXIT, ">$exitfn.$rand" or die "$0: cannot open $exitfn $1";
78
79 foreach my $e (@{$data->{relays}}) {
80
81         my $seen = str2time($e->{last_seen});
82         next unless $seen >= $now - $last_seen_window;
83         
84         my @or = clean_addr(@{$e->{or_addresses}}) if exists $e->{or_addresses};
85         my @exit = clean_addr(@{$e->{exit_addresses}}) if exists $e->{exit_addresses} ;
86         my $ors = join ', ', @or;
87         my $es = join ', ', @exit;
88         dbg "$0: $e->{nickname} $e->{last_seen} relays: [$ors] exits: [$es]" if $debug;
89         for (@or) {
90                 if (is_ipaddr($_)) {
91                         print RELAY "$_\n";
92                         ++$rcount;
93                 } else {
94                         print STDERR "$_\n";
95                         ++$error;
96                 }
97         }
98         for (@exit) {
99                 if (is_ipaddr($_)) {
100                         print EXIT "$_\n";
101                         ++$ecount;
102                 } else {
103                         print STDERR "$_\n";
104                         ++$error;
105                 }
106         }
107 }
108
109 close RELAY;
110 close EXIT;
111
112 dbg("$0: $rcount relays $ecount exits $error error(s) found.");
113 move "$relayfn.$rand", $relayfn if $rcount;
114 move "$exitfn.$rand", $exitfn if $ecount;
115 unlink "$relayfn.$rand";
116 unlink "$exitfn.$rand";
117
118 exit $error;
119
120 sub clean_addr
121 {
122         my @out;
123         foreach (@_) {
124                 my ($ipv4) = /^((?:\d+\.){3}\d+)/;
125                 if ($ipv4) {
126                         push @out, $ipv4;
127                         next;
128                 }
129                 my ($ipv6) = /^\[([:a-f\d]+)\]/;
130                 push @out, $ipv6 if $ipv6;
131         }
132         return @out;
133 }