mark: A photo of Mark kneeling on top of the Taal Volcano in the Philippines. It was a long hike. (Default)
Mark Smith ([staff profile] mark) wrote in [site community profile] changelog2010-05-03 06:49 am

[dw-free] http://bugs.dwscoalition.org/show_bug.cgi?id=2523

[commit: http://hg.dwscoalition.org/dw-free/rev/29d5f1a356f5]

http://bugs.dwscoalition.org/show_bug.cgi?id=2523

Add ability to detect if someone is coming in via a Tor exit.

Patch by [staff profile] mark.

Files modified:
  • bin/update-tor-exits
  • bin/upgrading/en.dat
  • bin/upgrading/update-db-general.pl
  • cgi-bin/Apache/LiveJournal.pm
  • cgi-bin/DW/Shop.pm
  • cgi-bin/sysban.pl
  • doc/config-local.pl.txt
  • doc/config-private.pl.txt
--------------------------------------------------------------------------------
diff -r f808bb62f298 -r 29d5f1a356f5 bin/update-tor-exits
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/update-tor-exits	Mon May 03 06:49:48 2010 +0000
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+#
+# DW::Setting::AwesomeNewFeature
+#
+# This file is the accompanying settings package for AwesomeNewFeature. It allows users to set and
+# clear their setting choices.
+#
+# Authors:
+#      Mark Smith <mark@dreamwidth.org>
+#
+# Copyright (c) 2010 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself.  For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+#
+
+use strict;
+use lib "$ENV{LJHOME}/cgi-bin";
+require 'ljlib.pl';
+
+die "\$LJ::USE_TOR_CONFIGS is disabled.\n" unless $LJ::USE_TOR_CONFIGS;
+die "\$LJ::EXTERNAL_IP is not set.\n" unless $LJ::EXTERNAL_IP;
+
+my $ua = LJ::get_useragent( role => 'tor', timeout => 30 ) or die "No useragent.\n";
+$ua->agent( "$LJ::SITENAME (Tor exit downloader; $LJ::ADMIN_EMAIL)" );
+
+my $res = $ua->get( "https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=" . $LJ::EXTERNAL_IP );
+my $content = $res && $res->is_success ? $res->content : undef;
+
+die "Failed to fetch exit list from Tor.\n" unless $content;
+
+my $dbh = LJ::get_db_writer() or die "Failed to get dbh.\n";
+$dbh->do( 'DELETE FROM tor_proxy_exits' );
+
+my $ct = 0;
+while ( $content =~ /^(\d+\.\d+\.\d+\.\d+)$/mg ) {
+    $ct++;
+
+    $dbh->do( 'REPLACE INTO tor_proxy_exits (addr) VALUES (?)', undef, $1 );
+    die "Failed on $1: " . $dbh->errstr . "\n" if $dbh->err;
+}
+
+print "Found $ct Tor exits.\n";
diff -r f808bb62f298 -r 29d5f1a356f5 bin/upgrading/en.dat
--- a/bin/upgrading/en.dat	Mon May 03 05:31:11 2010 +0000
+++ b/bin/upgrading/en.dat	Mon May 03 06:49:48 2010 +0000
@@ -1144,6 +1144,8 @@ entryform.xpost.manage=Manage accounts
 entryform.xpost.manage=Manage accounts
 
 error.badpassword2=You typed the wrong password. If you make too many wrong login attempts in a row, your account access will be temporarily blocked, so you may want to <a [[aopts]]>reset your password</a> if you aren't sure what it is.
+
+error.blocked=Sorry, you are currently blocked from reaching the page you are attempting to visit.  The block type is: [[blocktype]].  Please email us at [[email]] and reference this message for further assistance.
 
 error.code.comm_not_comm=Account is not a community
 
diff -r f808bb62f298 -r 29d5f1a356f5 bin/upgrading/update-db-general.pl
--- a/bin/upgrading/update-db-general.pl	Mon May 03 05:31:11 2010 +0000
+++ b/bin/upgrading/update-db-general.pl	Mon May 03 06:49:48 2010 +0000
@@ -3047,6 +3047,12 @@ CREATE TABLE cc_log (
 )
 EOC
 
+register_tablecreate('tor_proxy_exits', <<'EOC');
+CREATE TABLE tor_proxy_exits (
+    addr VARCHAR(15) NOT NULL,
+    PRIMARY KEY (addr)
+)
+EOC
 
 
 # NOTE: new table declarations go ABOVE here ;)
diff -r f808bb62f298 -r 29d5f1a356f5 cgi-bin/Apache/LiveJournal.pm
--- a/cgi-bin/Apache/LiveJournal.pm	Mon May 03 05:31:11 2010 +0000
+++ b/cgi-bin/Apache/LiveJournal.pm	Mon May 03 06:49:48 2010 +0000
@@ -52,6 +52,7 @@ my %RQ;       # per-request data
 my %RQ;       # per-request data
 my %USERPIC;  # conf related to userpics
 my %REDIR;
+my ( $TOR_UPDATE_TIME, %TOR_EXITS );
 
 # Mapping of MIME types to image types understood by the blob functions.
 my %MimeTypeMapd6 = (
@@ -252,6 +253,33 @@ sub blocked_anon
     return OK;
 }
 
+# returns whether or not an IP address is from the Tor proxy exit list, but only if we're configured
+# to actually use this data
+sub ip_is_via_tor {
+    return unless $LJ::USE_TOR_CONFIGS;
+
+    # try to load the data every few minutes so that we keep it reasonably fresh, but so that we don't
+    # hammer the database all of the time
+    unless ( defined $TOR_UPDATE_TIME && $TOR_UPDATE_TIME > time ) {
+        # either way, wait a few minutes before trying again, that way we don't hammer things if the
+        # database is down or something
+        $TOR_UPDATE_TIME = time + 300;
+
+        # be very conscientious not to get rid of data if we get a db error
+        my $dbh = LJ::get_db_writer() or return;
+        my $ips = $dbh->selectcol_arrayref( 'SELECT addr FROM tor_proxy_exits' );
+        return if $dbh->err;
+
+        if ( $ips && ref $ips eq 'ARRAY' ) {
+            %TOR_EXITS = ();
+            $TOR_EXITS{$_} = 1 foreach @$ips;
+        }
+    }
+
+    # regardless of what happened above we can check and return
+    return exists $TOR_EXITS{$_[0]};
+}
+
 sub trans
 {
     my $r = shift;
@@ -427,6 +455,9 @@ sub trans
                 $r->push_handlers( PerlResponseHandler => \&blocked_bot );
                 return OK;
             }
+
+            # determine if this IP is one of the tor exits and set a note on the request
+            $r->notes->{via_tor_exit} = 1 if ip_is_via_tor( $ip );
         }
         if ( LJ::Hooks::run_hook( "forbid_request", $r ) ) {
             $r->handler( "perl-script" );
diff -r f808bb62f298 -r 29d5f1a356f5 cgi-bin/DW/Shop.pm
--- a/cgi-bin/DW/Shop.pm	Mon May 03 05:31:11 2010 +0000
+++ b/cgi-bin/DW/Shop.pm	Mon May 03 06:49:48 2010 +0000
@@ -157,14 +157,18 @@ sub remote_sysban_check {
 
     # do sysban checks:
     if ( LJ::sysban_check( 'pay_uniq', LJ::UniqCookie->current_uniq ) ) {
-        return BML::ml( '/shop.bml.paymentblock', { blocktype => "computer", email => $LJ::ACCOUNTS_EMAIL } );
+        return BML::ml( 'error.blocked', { blocktype => "computer", email => $LJ::ACCOUNTS_EMAIL } );
     } elsif ( my $remote = LJ::get_remote() ) {
         if ( LJ::sysban_check( 'pay_user', $remote->user ) ) {
-            return BML::ml( '/shop.bml.paymentblock', { blocktype => "account", email => $LJ::ACCOUNTS_EMAIL } );
+            return BML::ml( 'error.blocked', { blocktype => "account", email => $LJ::ACCOUNTS_EMAIL } );
         } elsif ( LJ::sysban_check( 'pay_email', $remote->email_raw ) ) {
-            return BML::ml( '/shop.bml.paymentblock', { blocktype => "email address", email => $LJ::ACCOUNTS_EMAIL } );
+            return BML::ml( 'error.blocked', { blocktype => "email address", email => $LJ::ACCOUNTS_EMAIL } );
         }
     }
+
+    # now do a tor check
+    return BML::ml( 'error.blocked', { blocktype => "Tor proxy", email => $LJ::ACCOUNTS_EMAIL } )
+        if LJ::tor_check( 'shop' );
 
     # looks good
     return undef;
diff -r f808bb62f298 -r 29d5f1a356f5 cgi-bin/sysban.pl
--- a/cgi-bin/sysban.pl	Mon May 03 05:31:11 2010 +0000
+++ b/cgi-bin/sysban.pl	Mon May 03 06:49:48 2010 +0000
@@ -219,6 +219,13 @@ sub sysban_populate {
 }
 
 
+# here because it relates to sysbans ...
+sub tor_check {
+    return 0 unless $LJ::USE_TOR_CONFIGS && $LJ::TOR_CONFIG{$_[0]};
+    return DW::Request->get->note( 'via_tor_exit' ) ? 1 : 0;
+}
+
+
 sub _db_sysban_populate {
     my ($where, $what) = @_;
     my $dbh = LJ::get_db_writer();
diff -r f808bb62f298 -r 29d5f1a356f5 doc/config-local.pl.txt
--- a/doc/config-local.pl.txt	Mon May 03 05:31:11 2010 +0000
+++ b/doc/config-local.pl.txt	Mon May 03 06:49:48 2010 +0000
@@ -51,6 +51,14 @@
             private_key => $DW::PRIVATE::RECAPTCHA{private_key},
         );
 
+    # If enabled, disable people coming in over Tor exits from using various parts of the site.
+    $USE_TOR_CONFIGS = 0;
+
+    # Configure what you want blocked here.  Requires $USE_TOR_CONFIGS to be on.
+    %TOR_CONFIG = (
+        shop => 1,     # Disallow Tor users from accessing the Shop.
+    )
+
     # PayPal configuration.  If you want to use PayPal, uncomment this
     # section and make sure to fill in the fields at the bottom of config-private.pl.
     #%PAYPAL_CONFIG = (
diff -r f808bb62f298 -r 29d5f1a356f5 doc/config-private.pl.txt
--- a/doc/config-private.pl.txt	Mon May 03 05:31:11 2010 +0000
+++ b/doc/config-private.pl.txt	Mon May 03 06:49:48 2010 +0000
@@ -94,6 +94,9 @@
         'ljsite.tld',
     );
 
+    # Set this to the IP address of your main site.  This is used for Tor exit checking.
+    #$EXTERNAL_IP = '127.0.0.1';
+
     # configuration/ID for statistics tracker modules which apply to
     # site pages (www, non-journal)
     %SITE_PAGESTAT_CONFIG = (
--------------------------------------------------------------------------------