#!/usr/bin/perl # # Coinpass # Version 1.7 use Socket; $COINPASS_SERVER = "www.coinpass.com"; $COINPASS_PORT = "80"; $COINPASS_VERSION="1.7"; $COINPASS_BLOCK_URL = "http://www.coinpass.com/blocked.html"; $COINPASS_HASH = "70691hhh5de7248b0687558aeaff0f4f" ; $BAPS = 2; $BAPM = 20; $BAPS_TIME = 120; # Signal Handler $SIG{'HUP'} = sub { exit(0) }; if (defined($ENV{'SCRIPT_FILENAME'})) { # Unblock Output $|=1; # Extract the QUERY STRING variables %params = (); @query_string = split(/[&;]/, $ENV{'QUERY_STRING'}); foreach $i (0 .. $#query_string) { # Split $params[$i] =~ s/\+/ /g; ($key, $val) = split(/=/,$query_string[$i],2); $key =~ s/%(..)/pack("c",hex($1))/ge; $val =~ s/%(..)/pack("c",hex($1))/ge; $params{$key} .= "\0" if (defined($query_string{$key})); $params{$key} .= $val; } ($CGIBIN_PATH, $ignore) = &SplitPath ($ENV{'SCRIPT_FILENAME'}); $CGIBIN_PATH =~ s/\/$//; if (($CGIBIN_PATH =~ /cgiwrap/) && (-r $ENV{'PATH_TRANSLATED'})) { ($CGIBIN_PATH, $ignore) = &SplitPath ($ENV{'PATH_TRANSLATED'}); $CGIBIN_PATH =~ s/\/$//; } print "Content-type: text/html\n\n"; &WelcomeScreen; &TestSetup($COINPASS_HASH); exit(0); } $SIG{CHLD} = sub { wait }; %hits = (); %bytes = (); %blocked = (); %baps = (); %bapm = (); ($last_minute, $last_second) = &GetTime(); #cgi.main.txt while ($line = ) { chomp ($line); if ($line =~ /^\d+\.\d+\.\d+\.\d+\|.+\|\d+\|[\d-]+\|.+\|.+$/) { ($ip, $username, $status, $bytes, $workdir, $blocked_flag) = split (/\|/, $line); if (((($status eq "200")) || (($status eq "401")&&($username ne "-")))) { $subnet = $ip; $subnet =~ s/\.\d+$//; # 401 Handler if ($status eq "401") { $username = '$-PPP-$'; $subnet = $ip; $status = "200"; } # Redirect logger $username = '$-PPPR-$' if ($blocked_flag eq "1"); # Get the time ($this_minute, $this_second) = &GetTime(); # Add to the running totals defined($hits{"$username\|$subnet"}) ? ($hits{"$username\|$subnet"} += 1) : ($hits{"$username\|$subnet"} = 1); defined($bytes{"$username\|$subnet"}) ? ($bytes{"$username\|$subnet"} += $bytes) : ($bytes{"$username\|$subnet"} = $bytes); defined($baps{"$username\|$subnet\|$this_second"}) ? ($baps{"$username\|$subnet\|$this_second"} += 1) : ($baps{"$username\|$subnet\|$this_second"} = 1); defined($bapm{"$username\|$subnet\|$this_minute"}) ? ($bapm{"$username\|$subnet\|$this_minute"} += 1) : ($bapm{"$username\|$subnet\|$this_minute"} = 1); # BAPS and BAPM checking if ($username eq "\$-PPP-\$") { if ((($baps{"$username\|$subnet\|$this_second"} >= $BAPS) || ($bapm{"$username\|$subnet\|$this_minute"} >= $BAPM)) && ($blocked{"$subnet"} ne "1")) { &AddRule ($subnet, $COINPASS_HASH, $BAPS_TIME, $workdir,''); $blocked{"$subnet"} = "1"; # Add this to our blocked list $username = '$-PPPB-$'; defined($hits{"$username\|$subnet"}) ? ($hits{"$username\|$subnet"} += 1) : ($hits{"$username\|$subnet"} = 1); defined($bytes{"$username\|$subnet"}) ? ($bytes{"$username\|$subnet"} += $bytes) : ($bytes{"$username\|$subnet"} = $bytes); } } # Check the current minute if ($this_minute != $last_minute) { if (fork() == 0) { # Process all the stats @disables = &ProcessHits (\%hits, \%bytes); # Process any disables we got foreach $todisable (@disables) { ($account, $blocktime,$redirecturl ) = split (/\|/, $todisable); &AddRule ($account,$COINPASS_HASH, $blocktime, $workdir,$redirecturl); } # Expire blocked files &ExpireFiles($workdir); # Exit child process exit(0); } %hits = (); %bytes = (); %blocked = (); %baps = (); %bapm = (); $last_minute = $this_minute; } } } } exit; #cgi.processhits.txt sub ProcessHits { local ($hits, $bytes) = @_; local ($combo, $numhits); local ($query, $rin, $win, $ein, $timeout, $nfound, $timeleft) = ""; local (@disables) = (); if (&EstablishConnection) { print PPP "POST /coinpass/blocker/mycoinpass.php HTTP/1.0\n"; print PPP "Connection: Keep-Alive\n"; print PPP "User-Agent: COINPASS\n"; print PPP "Host: www.coinpass.com\n"; print PPP "Content-type: application/x-www-form-urlencoded\n"; # Construct the content string $query = "COINPASS_VERSION=$COINPASS_VERSION"."&"."COINPASS_HASH=$COINPASS_HASH"."&DATA="; while (($combo, $numhits) = each (%$hits)) { ($username, $ip) = split (/\|/, $combo); $bytez = $$bytes{$combo} || 0; $query .= &Escape("$username\|$ip\|$numhits\|$bytez\n"); } # Calculate the length of the content print PPP "Content-length: ".length($query)."\n"; # Print the content print PPP "\n$query\n"; # Wait for any response or max 30 seconds $rin = $win = $ein = ''; vec($rin,fileno(PPP),1) = 1; $ein = $rin | $win; $timeout = 30; ($nfound,$timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout); # Read in all the lines we get back while ($line = ) { chomp ($line); push (@disables, $line) if ($line =~/^.*\|\d+\|.*$/) } # Close the connection &CloseConnection; # Return the list of disables return (@disables); } } sub EstablishConnection { local ($pppaddr, $oldfh); # Get the server address $pppaddr = ($COINPASS_SERVER =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) ? pack('C4',$1,$2,$3,$4) : (gethostbyname($COINPASS_SERVER))[4]; # Get the socket $proto = (getprotobyname('tcp'))[2]; if (!socket(PPP, AF_INET, SOCK_STREAM, $proto)) { return (0); } if (!(connect(PPP, sockaddr_in($COINPASS_PORT, $pppaddr)))) { return (0); } # Unbuffer the output $oldfh = select(PPP); $| = 1; select($oldfh); # Return Success return (1); } sub CloseConnection { shutdown (PPP, 2); } sub GetTime { local ($sec, $min, $ignore, $ignore, $ignore, $ignore) = localtime(time); return ($min, $sec); } sub Escape { local ($text) = @_; local ($escapes); return undef unless defined $text; # Build the escape hash for (0..255) { $escapes{chr($_)} = sprintf("%%%02X", $_); } # Default unsafe characters. (RFC 2396 ^uric) $text =~ s/([^;\/?:@&=+\$,A-Za-z0-9\-_.!~*'()])/$escapes{$1}/g; return ($text); } #cgi.addrule.txt sub AddRule { local ($data, $hash, $time, $directory, $redirecturl) = @_; my ($hashdir) = "$directory/$hash"; my ($filename) = "$hashdir/$data"; my ($redirfile) = "$hashdir/redirect.coinpass"; # Create the sub-directory if it doesnt exist mkdir ($hashdir, 0777) or return ("Unable to create directory $hashdir") if (!(-d $hashdir)); chmod 0777, $hashdir; # Write out the data if (!(-e $filename)) { open (OUTPUT, "> $filename") or return ("Unable to open file $filename"); close (OUTPUT); chmod 0777, $filename; } # Change the file modification time local ($now) = time() + $time; utime $now, $now, $filename; if (($redirecturl ne "") || (!(-e $redirfile))) { $redirecturl = $COINPASS_BLOCK_URL if ($redirecturl eq ""); open (OUTPUT, "> $redirfile") or return ("Unable to open file $redirfile"); print OUTPUT "Status: 200 OK\nContent-type: text/html\n\n"; close (OUTPUT); chmod 0777, $redirfile; } # Return return ("Disable rule successfully written:\n$filename\n"); } #cgi.expirefiles.txt sub ExpireFiles { local ($workdir) = @_; local ($dir, $file, $age); local (@files) = (); # Get all the files opendir (DIR, $workdir); while ($dir = readdir(DIR)) { # Test to see if it's a directory if ((-d ("$workdir/$dir")) && ($dir !~ /^\./)) { # Get all files within the directory opendir (FILES, "$workdir/$dir"); while ($file = readdir(FILES)) { if (-f "$workdir/$dir/$file") { push (@files, "$workdir/$dir/$file"); } } closedir (FILES); } } closedir (DIR); for (@files) { local ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($_); # Remove the block if the file has 'expired' if ((time() > $mtime) && ($size == 0)) { unlink ($_); } } } sub WelcomeScreen { print << "EOF"; Coinpass Blocker Ver 1.7


EOF } sub TestSetup { local ($hash) = @_; local ($pppaddr); @Form = split(/&/,$ENV{'QUERY_STRING'}); foreach $i (@Form) { ($name, $value) = split(/=/,$i); } if(($name eq "file")&&($value ne "")) { $file_to_del="coinpass/".$COINPASS_HASH."/".$value; # unlink command unlink($file_to_del); print "deleted ".$file_to_del; exit; } exit if (length($CGIBIN_PATH) == 0); # Check to see if the 'COINPASS' directory exists print "Checking for COINPASS sub directory: "; if (!(-d "$CGIBIN_PATH/coinpass")) { print "Failed!
\n"; exit; } else { print "Success!
\n"; } # Make sure the COINPASS directory is writeable print "Making sure COINPASS directory is writeable: "; if (!(-w "$CGIBIN_PATH/coinpass")) { print "Failed!
\n"; exit; } else { print "Success!
\n"; } print "

"; print "Add these lines to your httpd.conf file
(Inside the corresponding VirtualHost for your site or members section>


\n"; print << "EOF";
EOF } sub SplitPath { my ($path) = @_; my ($directory,$file) = ('','',''); $path =~ m|^ ( (?: .* / (?: \.\.?\z )? )? ) ([^/]*) |xs; return ($1, $2); }