Skip to content

Instantly share code, notes, and snippets.

@sbassett29
Last active October 29, 2020 21:41
Show Gist options
  • Save sbassett29/2b1140de338d586a1d2e079e42f08685 to your computer and use it in GitHub Desktop.
Save sbassett29/2b1140de338d586a1d2e079e42f08685 to your computer and use it in GitHub Desktop.
Quick and Dirty StopForumSpam bulk IP search and stats
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* https://www.gnu.org/copyleft/gpl.html
*
* @file
*/
namespace SFSIPCheck;
// helper classes
class SFSFileManager {
public $fileMap;
public $fileName;
const cache_dir = './cache';
const cache_expire = 43200;
public function __construct( string $fileId ) {
$this->fileMap = [
'24h' => 'https://www.stopforumspam.com/downloads/listed_ip_1_ipv46_all.gz',
'7d' => 'https://www.stopforumspam.com/downloads/listed_ip_7_ipv46_all.gz',
'30d' => 'https://www.stopforumspam.com/downloads/listed_ip_30_ipv46_all.gz',
'90d' => 'https://www.stopforumspam.com/downloads/listed_ip_90_ipv46_all.gz',
'180d' => 'https://www.stopforumspam.com/downloads/listed_ip_180_ipv46_all.gz',
'1y' => 'https://www.stopforumspam.com/downloads/listed_ip_365_ipv46_all.gz',
];
if( ! array_key_exists( $fileId, $this->fileMap ) )
throw new Exception( 'Bad file ID specified!' );
$this->fileName = $this->fileMap[ $fileId ];
}
public function getRemoteFile( string $fileName ) {
return file_get_contents( $fileName );
}
public function writeCacheFile() {
$fileNameLocal = self::cache_dir . '/' . basename( $this->fileName );
if( is_file( $fileNameLocal ) &&
abs( time() - filemtime( $fileNameLocal ) ) < self::cache_expire ) {
return false;
}
$data = $this->getRemoteFile( $this->fileName );
$MD5data = $this->getRemoteMD5File();
if( md5( $data ) != $MD5data )
throw new Exception( 'MD5 checksum mismatch!' );
if( (bool)file_put_contents ( $fileNameLocal, $data ) )
return true;
else
throw new Exception( 'Unable to write cache file!' );
}
public function getCacheFile() {
$fileNameLocal = self::cache_dir . '/' . basename( $this->fileName );
if( ! is_file( $fileNameLocal ) &&
abs( time() - filemtime( $fileNameLocal ) ) > self::cache_expire ) {
$this->writeCacheFile( $fileNameLocal );
}
return file_get_contents( $fileNameLocal );
}
public function getRemoteMD5File() {
$md5File = $this->fileName . '.md5';
return $this->getRemoteFile( $md5File );
}
}
class SFSCreateIPsReport {
public $fileData;
public $rawRequestVar;
public $processedIPData;
public function __construct( string $rawRequestVar, string $SFSFileData ) {
$this->fileData = preg_split( '/(\r\n|\n|\r)/', $SFSFileData );
$this->rawRequestVar = $rawRequestVar;
$this->processedIPData = $this->parseIPsFromRequestData();
}
public function parseIPsFromRequestData() {
$regExpPat = '/^(((?=.*(::))(?!.*\3.+\3))\3?|([\dA-F]{1,4}(\3|:\b|$)|\2))(?4){5}((?4){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/i';
$search = preg_split( '/(\r\n|\n|\r)/', $this->rawRequestVar );
array_walk( $search, function( &$v ) use ( $regExpPat ) {
$v = trim( basename( $v ) );
if( ! preg_match( $regExpPat, $v ) ) {
$v = null;
}
} );
return array_filter( $search );
}
public function generateBasicStatsArray() {
$found = [];
foreach( $this->fileData as $v ) {
$ip = trim( str_getcsv( $v )[0] );
if( in_array( $ip, $this->processedIPData ) )
$found[] = $ip;
}
return [ 'found' => count( $found ), 'total' => count( $this->processedIPData ) ];
}
public function generateFullIPStatsArray() {
$found = [];
foreach( $this->fileData as $v ) {
$data = str_getcsv( $v );
if( in_array( $data[0], $this->processedIPData ) ) {
$found[] = [
htmlspecialchars( $data[0] ),
htmlspecialchars( $data[1] ),
htmlspecialchars( $data[2] )
];
}
}
return $found;
}
}
class Form {
public static function display() {
echo <<<EOF
<html>
<head><title>SFS IP Check</title></head>
<body>
<h1>Check IPs within stopforumspam.com deny lists</h1>
<h4>(<a href='https://www.stopforumspam.com/downloads' target='_blank'>
https://www.stopforumspam.com/downloads</a>)</h4>
<h4>Enter a newline-separated list of IPs below<br />...or a list of urls like: https://en.wikipedia.org/wiki/Special:Contributions/11.22.33.44</h4>
<form name='sfs-form' method='get' action='/sfsipcheck/'>
<textarea name='IPs' rows='12' cols='70'>
</textarea><br /><br />
<select name='fileId'>
<option value='24h'>IPv4 & IPv6 - Last 24 hours</option>
<option value='7d'>IPv4 & IPv6 - Last 7 days</option>
<option value='30d'>IPv4 & IPv6 - Last 30 days</option>
<option value='90d' selected='true'>IPv4 & IPv6 - Last 90 days</option>
<option value='180d'>IPv4 & IPv6 - Last 180 days</option>
<option value='1y'>IPv4 & IPv6 - Last year</option>
</select><br />
<br /><input type='submit' name='form-submit' value='Check IPs' />
</form>
</body>
</html>
EOF;
}
}
class Report {
public static function display( string $requestVar, string $data ) {
$oStats = new SFSCreateIPsReport( $requestVar, $data );
$basic = $oStats->generateBasicStatsArray();
$full = $oStats->generateFullIPStatsArray();
echo <<<EOF0
<html>
<head><title>SFS IP Check</title></head>
<body>
<h1>Report of IPs within stopforumspam.org deny lists</h1>
<table border='1' cellpadding='4'>
<tr>
<td>Number of IPs checked:</td>
<td><strong>{$basic['total']}</strong></td>
</tr>
<tr>
<td>Number of IPs found in deny list:</td>
<td><strong>{$basic['found']}</strong></td>
</tr>
</table>
EOF0;
if( (int)$basic['found'] > 0 ) {
echo <<<EOF1
<h2>Full IP data</h2>
<table border='1' cellpadding='4'>
<tr><th>IP Address</th><th>Threshold</th><th>Last seen</th></tr>
EOF1;
foreach( $full as $v ) {
if( is_array( $v ) && count( $v ) == 3 )
echo "<tr><td>{$v[0]}</td><td>{$v[1]}</td><td>{$v[2]}</td></tr>\n";
}
echo <<<EOF2
</table>
EOF2;
}
echo <<<EOF3
<div><br /><a href="/sfsipcheck/">Back</a></div>
</body>
</html>
EOF3;
}
}
// controller class
class Controller {
public function run() {
if( count( $_GET ) > 0 ) {
$oFM = new SFSFileManager( $_GET['fileId'] );
$data = gzdecode( $oFM->getCacheFile() );
Report::display( $_GET['IPs'], $data );
}
else
Form::display();
}
}
// run controller
$oCont = new Controller();
$oCont->run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment