User:Protectbot/source/block-analyzer

From Discworld MUD Wiki
Jump to: navigation, search
#!/usr/bin/perl

# This script is run without arguments.
# To run it, you need to:
#  - Have perl of version 5.10 or later.
#  - Have the 'wget' tool.
#  - Have the 'whois' tool.
#  - Have the 'xmllint' tool.
#  - Manually fill out $password below with the actual password for the
#    account.

use strict;
use 5.010_000;
use URI::Escape;

use constant RESULT_FILENAME => "results.xml";
use constant COOKIE_FILENAME => "cookie.txt";
use constant API_URL => "http://discworld.imaginary-realities.com/w/api.php";
use constant USERNAME => "Protectbot";
use constant NUM_RETURNS => 500;

use constant USER_NAME => 0;
use constant USER_IP => 1;
use constant USER_RANGE => 2;

use constant WHOIS_ARIN => 0;
use constant WHOIS_RIPE => 1;
use constant WHOIS_APNIC => 2;
use constant WHOIS_LACNIC => 3;
use constant WHOIS_AFRINIC => 4;
use constant WHOIS_JPNIC => 5;

my $password = <!-- Fill this out yourself -->;

my %user_ips;
my %net_handles;
my $ip;
my $whois_server;
my $net;

my $login_token;
my $login_userid;
my $login_sessionid;
my $login_cookieprefix;

sub http_login;
sub http_logout;
sub get_blocked_ips;
sub parse_user;

sub query_arin;
sub query_ripe;
sub query_apnic;
sub query_lacnic;
sub query_afrinic;
sub query_jpnic;

# Main execution
&http_login($password);
sleep(1);
&get_blocked_ips();
sleep(1);

foreach $ip (keys %user_ips)
{
  $whois_server = &query_arin($ip);
  if ($whois_server == WHOIS_RIPE)
  {
    &query_ripe($ip);
  }
  elsif ($whois_server == WHOIS_APNIC)
  {
    &query_apnic($ip);
  }
  elsif ($whois_server == WHOIS_LACNIC)
  {
    &query_lacnic($ip);
  }
  elsif ($whois_server == WHOIS_AFRINIC)
  {
    &query_afrinic($ip);
  }
  elsif ($whois_server == WHOIS_JPNIC)
  {
    &query_jpnic($ip);
  }
  sleep(0.5);
}

&http_logout();

print "\n";
print "SUMMARY:\n";
foreach $net (sort { $net_handles{$b} <=> $net_handles{$a} } keys %net_handles)
{
  printf("%-3d: %s\n", $net_handles{$net}, $net);
}

sub http_login
{
  my ($password) = @_;
  my $post_data;
  my $command;
  
  # Build the POST data
  $post_data = "lgname=".USERNAME."&lgpassword=".uri_escape($password);
  
  # Execute login
  print "Logging in... ";
  $command = "wget -q --save-cookies=".COOKIE_FILENAME." --output-document=".RESULT_FILENAME." --post-data=\"".$post_data."\" \"".API_URL."?action=login&format=xml\"";
  `$command`;
  
  open(RESULTS, RESULT_FILENAME) or die "Could not find ".RESULT_FILENAME."\n";
  $_ = <RESULTS>;
  close(RESULTS);
  
  # Check the login was successful
  if (!(/login result=\"Success\"/))
  {
    print "FAILED\n";
    print $_;
    die; 
  }
  
  print "OK\n";
  
  # Save off the tokens
  /lguserid=\"(?<userid>[^\"]+)\".*lgtoken=\"(?<token>[^\"]+)\" cookieprefix=\"(?<cp>[^\"]+)\" sessionid=\"(?<sessionid>[^\"]+)\"/;  
  $login_userid = $+{userid};
  $login_token = $+{token};
  $login_cookieprefix = $+{cp};
  $login_sessionid = $+{sessionid};
  
  print "Userid:        ".$login_userid."\n";
  print "Token:         ".$login_token."\n";
  print "Cookie prefix: ".$login_cookieprefix."\n";
  print "Session ID:    ".$login_sessionid."\n";  
}

sub http_logout
{
  my ($password) = @_;
  my $post_data;
  my $command;
  
  # Execute logout
  print "Logging out... ";
  $command = "wget -q --load-cookies=".COOKIE_FILENAME." --output-document=".RESULT_FILENAME." \"".API_URL."?action=logout&format=xml\"";
  `$command`;
  
  # There aren't any useful results to speak of, and there's little we can do 
  # if the logout fails, so just end here.
  print "OK\n";
}

sub get_blocked_ips
{
  my $command;
  my $output;
  my @user_data;
  my $user_line;
  my $user;
  my $user_type;
  
  # Execute API query to get the following for all templates:
  # - title
  # - Current protection level
  $command = "wget -q --load-cookies=".COOKIE_FILENAME." --output-document=".RESULT_FILENAME." \"".API_URL."?action=query&list=blocks&bkprop=user&bklimit=".NUM_RETURNS."&format=xml\"";
  `$command`;    
 
  open(RESULTS, RESULT_FILENAME) or die "Could not find ".RESULT_FILENAME."\n";
  $output = <RESULTS>;
  close(RESULTS);
  
  # Parse out the individual user data
  @user_data = split(/</, $output);
  shift(@user_data);
 
  foreach $user_line (@user_data)
  {
    chomp($user_line);
    if (!($user_line =~ /block user=\"([^\"]*)\"/))
    {
      next;
    }
    $user = $1;
    $user_type = &parse_user($user);
    if ($user_type == USER_IP)
    {
      print "User IP: ".$user."\n";
      $user_ips{$user} = 1;
    }        
  }  
}

sub parse_user
{
  my ($user) = @_;
  my $result;
  
  if ($user =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\/([0-9]{1,2})/)
  {
    # Possible IP range
    if (($1 < 256) && ($2 < 256) && ($3 < 256) && ($4 < 256) && ($5 <= 32))
    {
      # IP range
      $result = USER_RANGE;
    }
    else
    {
      # General
      $result = USER_NAME;
    }
  }
  elsif ($user =~ /([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/)
  {
    # Possible IP
    if (($1 < 256) && ($2 < 256) && ($3 < 256) && ($4 < 256) && ($5 <= 32))
    {
      # IP
      $result = USER_IP;
    }
    else
    {
      # General
      $result = USER_NAME;
    }
  }
  else
  {
    # General
      $result = USER_NAME;
  }
  
  return $result;
}

sub query_arin
{
  my ($target) = @_;
  my $command;
  my $output;
  my $line;
  my @lines;
  my $org;
  my $handle;
  my $result = WHOIS_ARIN;
  
  $command = "xmllint --format http://whois.arin.net/rest/ip/".$target;
  $output = `$command`;
  
  @lines = split(/\n/, $output);
  foreach $line (@lines)
  {
    chomp $line;
    if ($line =~ /<orgRef name=\"([^\"]+)\" handle=\"([^\"]+)\"/)
    {
      $org = $1;
      $handle = $2;
      
      if ($handle eq "APNIC")
      {
        $result = WHOIS_APNIC;
      }
      elsif ($handle eq "RIPE")
      {
        $result = WHOIS_RIPE;
      }
      elsif ($handle eq "LACNIC")
      {
        $result = WHOIS_LACNIC;
      }
      elsif ($handle eq "AFRINIC")
      {
        $result = WHOIS_AFRINIC;
      }
      elsif ($handle eq "JNIC")
      {
        $result = WHOIS_JPNIC;
      }
      else
      {
        printf("%-15s: [ARIN: %s] %s\n", $target, $handle, $org);
        if (exists $net_handles{$handle})
        {
          $net_handles{$handle} = $net_handles{$handle} + 1;
        }
        else
        {
          $net_handles{$handle} = 1;
        }      
      }
      last;
    }
  }
  
  return $result;
}

sub query_ripe
{
  my ($target) = @_;
  my $command;
  my $output;
  my $line;
  my @lines;
  my $org = "";
  my $handle;
  
  $command = "whois -h whois.ripe.net -r \"".$target."\" -T inetnum";
  $output = `$command`;
  
  @lines = split(/\n/, $output);
  foreach $line (@lines)
  {
    chomp $line;
    if ($line =~ /^netname:[ ]*(.*)$/)
    {
      $handle = $1;
    }
    if (($line =~ /^descr:[ ]*(.*)$/) && ($org eq ""))
    {
      $org = $1;
    }
  }
  printf("%-15s: [RIPE: %s] %s\n", $target, $handle, $org);
  if (exists $net_handles{$handle})
  {
    $net_handles{$handle} = $net_handles{$handle} + 1;
  }
  else
  {
    $net_handles{$handle} = 1;
  }        
}

sub query_apnic
{
  my ($target) = @_;
  my $command;
  my $output;
  my $line;
  my @lines;
  my $org = "";
  my $handle;
  
  $command = "whois -h whois.apnic.net -r \"".$target."\"";
  $output = `$command`;
  
  @lines = split(/\n/, $output);
  foreach $line (@lines)
  {
    chomp $line;
    if ($line =~ /^netname:[ ]*(.*)$/)
    {
      $handle = $1;
    }
    if (($line =~ /^descr:[ ]*(.*)$/) && ($org eq ""))
    {
      $org = $1;
    }
  }
  printf("%-15s: [APNIC: %s] %s\n", $target, $handle, $org);
  if (exists $net_handles{$handle})
  {
    $net_handles{$handle} = $net_handles{$handle} + 1;
  }
  else
  {
    $net_handles{$handle} = 1;
  }        
}

sub query_lacnic
{
  my ($target) = @_;
  my $command;
  my $output;
  my $line;
  my @lines;
  my $org = "";
  my $handle;
  
  $command = "whois -h whois.lacnic.net \"".$target."\"";
  $output = `$command`;
  
  @lines = split(/\n/, $output);
  foreach $line (@lines)
  {
    chomp $line;
    if ($line =~ /^ownerid:[ ]*(.*)$/)
    {
      $handle = $1;
    }
    if (($line =~ /^owner:[ ]*(.*)$/) && ($org eq ""))
    {
      $org = $1;
    }
  }
  printf("%-15s: [LACNIC: %s] %s\n", $target, $handle, $org);
  if (exists $net_handles{$handle})
  {
    $net_handles{$handle} = $net_handles{$handle} + 1;
  }
  else
  {
    $net_handles{$handle} = 1;
  }        
}

sub query_afrinic
{
  my ($target) = @_;
  my $command;
  my $output;
  my $line;
  my @lines;
  my $org = "";
  my $handle;
  
  $command = "whois -h whois.afrinic.net -r \"".$target."\"";
  $output = `$command`;
  
  @lines = split(/\n/, $output);
  foreach $line (@lines)
  {
    chomp $line;
    if ($line =~ /^netname:[ ]*(.*)$/)
    {
      $handle = $1;
    }
    if (($line =~ /^descr:[ ]*(.*)$/) && ($org eq ""))
    {
      $org = $1;
    }
  }
  printf("%-15s: [AFRINIC: %s] %s\n", $target, $handle, $org);
  if (exists $net_handles{$handle})
  {
    $net_handles{$handle} = $net_handles{$handle} + 1;
  }
  else
  {
    $net_handles{$handle} = 1;
  }        
}

sub query_jpnic
{
  my ($target) = @_;
  my $command;
  my $output;
  my $line;
  my @lines;
  my $org = "";
  my $handle;
  
  $command = "whois -h whois.nic.ad.jp \"NET ".$target."\"";
  $output = `$command`;
  
  @lines = split(/\n/, $output);
  foreach $line (@lines)
  {
    chomp $line;
    if ($line =~ /\[Network Name\][ ]*(.*)$/)
    {
      $handle = $1;
    }
    if (($line =~ /\[Organization\][ ]*(.*)$/) && ($org eq ""))
    {
      $org = $1;
    }
  }
  printf("%-15s: [JPNIC: %s] %s\n", $target, $handle, $org);
  if (exists $net_handles{$handle})
  {
    $net_handles{$handle} = $net_handles{$handle} + 1;
  }
  else
  {
    $net_handles{$handle} = 1;
  }        
}