From 44e07295e53b9ddb0c2aa261467c3e9c9a3d13fc Mon Sep 17 00:00:00 2001 From: Zeke Roa Date: Fri, 26 Apr 2019 17:28:27 -0700 Subject: [PATCH 01/12] Add IPHub querying support --- inc/config.php | 14 ++++++++++++++ inc/functions.php | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/inc/config.php b/inc/config.php index 746fcad6..da37ab93 100644 --- a/inc/config.php +++ b/inc/config.php @@ -236,6 +236,19 @@ // To prevent bump atacks; returns the thread to last position after the last post is deleted. $config['anti_bump_flood'] = false; + // IPHub API key for checking for bad proxies (leave blank to not use IPHub) https://iphub.info/api + $config['iphub_key'] = ""; + + // If you find that a lot of spammers are comming from a specific ISP, or ASN, + // you can put the ISP in iphub_banned_isps and/or the ASN in iphub_banned_asns + // USE THIS WITH CAUTION, IT MAY PREVENT NON-SPAMMERS FROM POSTING + $config['iphub_banned_isps'] = []; + $config['iphub_banned_asns'] = []; + + // IPs in this array won't be checked by IPHub + // This can be used if legitimate posters are getting blocked by IPHub + $config['iphub_whitelisted_ips'] = []; + /* * Introduction to Tinyboard's spam filter: * @@ -1198,6 +1211,7 @@ // Error messages $config['error']['bot'] = _('You look like a bot.'); + $config['error']['proxy'] = _('You seem to be using an unathorized proxy.'); $config['error']['referer'] = _('Your browser sent an invalid or no HTTP referer.'); $config['error']['toolong'] = _('The %s field was too long.'); $config['error']['toolong_body'] = _('The body was too long.'); diff --git a/inc/functions.php b/inc/functions.php index 644cefbe..6df52894 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1823,6 +1823,47 @@ function buildJavascript() { file_write($config['file_script'], $script); } +function checkIPAPI() { + global $config; + + // query IPHub's database with the poster's IP + if (isset($config['iphub_key']) && $config['iphub_key'] !== "") { + if (isset($config['iphub_whitelisted_ips']) && array_search($_SERVER['REMOTE_ADDR'], $config['iphub_whitelisted_ips']) !== false) { + // IP is whitelisted, don't bother querying + error("return true;"); + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, "http://v2.api.iphub.info/ip/" . $_SERVER['REMOTE_ADDR']); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Key: " . $config['iphub_key'])); + $reply = curl_exec($ch); + if ($reply == "") { + return false; + } + + $json = json_decode($reply); + if (isset($json->error)) { + $logdata = array(); + $logdata['time'] = date(DATE_ATOM); + $logdata['action'] = 'iphub_query'; + $logdata['msg'] = $json->error; + + $logline = json_encode($logdata); + error_log($logline); + return false; + } + + if ($json->block == 1 + || (isset($config['iphub_banned_asns']) && array_search($json->asn, $config['iphub_banned_asns']) !== false) + || (isset($config['iphub_banned_isps']) && array_search($json->isp, $config['iphub_banned_isps']) !== false)) { + error($config['error']['proxy']); + return true; + } + } + return false; +} + function checkDNSBL() { global $config; From e7bae1d97203240e671813c933be1f5a080caecb Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sun, 6 Oct 2024 12:25:53 +0200 Subject: [PATCH 02/12] functions.php: refactor IPHub --- inc/functions.php | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 6df52894..014c7be1 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1823,40 +1823,46 @@ function buildJavascript() { file_write($config['file_script'], $script); } -function checkIPAPI() { +/** + * @param string $ip The IP to check. + * @return bool True if the IP should be blocked. + */ +function checkIPAPI(string $ip): bool { global $config; - // query IPHub's database with the poster's IP - if (isset($config['iphub_key']) && $config['iphub_key'] !== "") { - if (isset($config['iphub_whitelisted_ips']) && array_search($_SERVER['REMOTE_ADDR'], $config['iphub_whitelisted_ips']) !== false) { - // IP is whitelisted, don't bother querying - error("return true;"); + // Query IPHub's database with the poster's IP. + if ($config['iphub_key'] && !empty($config['iphub_key'])) { + if (array_search($ip, $config['iphub_whitelisted_ips']) !== false) { + // IP is whitelisted, don't bother querying. + return false; } $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, "http://v2.api.iphub.info/ip/" . $_SERVER['REMOTE_ADDR']); + curl_setopt($ch, CURLOPT_URL, "http://v2.api.iphub.info/ip/$ip"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Key: " . $config['iphub_key'])); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-Key: {$config['iphub_key']}" ]); $reply = curl_exec($ch); - if ($reply == "") { + if ($reply === false) { + $curl_err = curl_error($ch); + curl_close($ch); + error_log("IPHub query failed: api call failed with curl error $curl_err"); + return false; + } + curl_close($ch); + if (empty($reply)) { + error_log('IPHub query failed: api returned an empty response'); return false; } $json = json_decode($reply); if (isset($json->error)) { - $logdata = array(); - $logdata['time'] = date(DATE_ATOM); - $logdata['action'] = 'iphub_query'; - $logdata['msg'] = $json->error; - - $logline = json_encode($logdata); - error_log($logline); + error_log("IPHub query failed: $json->error"); return false; } if ($json->block == 1 - || (isset($config['iphub_banned_asns']) && array_search($json->asn, $config['iphub_banned_asns']) !== false) - || (isset($config['iphub_banned_isps']) && array_search($json->isp, $config['iphub_banned_isps']) !== false)) { + || array_search($json->asn, $config['iphub_banned_asns']) !== false + || array_search($json->isp, $config['iphub_banned_isps']) !== false) { error($config['error']['proxy']); return true; } From 1cc87c31aaa4e1558423565b4f3b8a586d7d94df Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sun, 6 Oct 2024 12:37:45 +0200 Subject: [PATCH 03/12] config.php: refactor IPHub api to be a more generic IP api --- inc/config.php | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/inc/config.php b/inc/config.php index da37ab93..62b6b84a 100644 --- a/inc/config.php +++ b/inc/config.php @@ -236,18 +236,23 @@ // To prevent bump atacks; returns the thread to last position after the last post is deleted. $config['anti_bump_flood'] = false; - // IPHub API key for checking for bad proxies (leave blank to not use IPHub) https://iphub.info/api - $config['iphub_key'] = ""; - - // If you find that a lot of spammers are comming from a specific ISP, or ASN, - // you can put the ISP in iphub_banned_isps and/or the ASN in iphub_banned_asns - // USE THIS WITH CAUTION, IT MAY PREVENT NON-SPAMMERS FROM POSTING - $config['iphub_banned_isps'] = []; - $config['iphub_banned_asns'] = []; - - // IPs in this array won't be checked by IPHub - // This can be used if legitimate posters are getting blocked by IPHub - $config['iphub_whitelisted_ips'] = []; + // Use 3rd part APIs to check if an IP should be blocked. + $config['ip_api'] = [ + 'iphub' => [ + // Enable or disable the IPHub API backend. + 'enabled' => false, + // IPHub API key for checking for bad proxies (https://iphub.info/api). + 'key' => '', + ], + // If you find that a lot of spammers are coming from a specific ISP, or ASN, + // you can put the ISP in isp_blacklist and/or the ASN in asn_blacklist + // USE THIS WITH CAUTION, IT MAY PREVENT NON-SPAMMERS FROM POSTING + 'isp_blacklist' => [], + 'asn_blacklist' => [], + // IPs in this array won't be checked. + // This can be used if known legitimate posters are getting blocked by a backend. + 'ip_whitelist' => [] + ]; /* * Introduction to Tinyboard's spam filter: From f008f8879df39e31df7da29d5044636a700db24d Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sun, 6 Oct 2024 12:43:22 +0200 Subject: [PATCH 04/12] functions.php: use updated config format --- inc/functions.php | 80 ++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 014c7be1..d9e8e588 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1830,43 +1830,51 @@ function buildJavascript() { function checkIPAPI(string $ip): bool { global $config; - // Query IPHub's database with the poster's IP. - if ($config['iphub_key'] && !empty($config['iphub_key'])) { - if (array_search($ip, $config['iphub_whitelisted_ips']) !== false) { - // IP is whitelisted, don't bother querying. - return false; - } - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, "http://v2.api.iphub.info/ip/$ip"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-Key: {$config['iphub_key']}" ]); - $reply = curl_exec($ch); - if ($reply === false) { - $curl_err = curl_error($ch); - curl_close($ch); - error_log("IPHub query failed: api call failed with curl error $curl_err"); - return false; - } - curl_close($ch); - if (empty($reply)) { - error_log('IPHub query failed: api returned an empty response'); - return false; - } - - $json = json_decode($reply); - if (isset($json->error)) { - error_log("IPHub query failed: $json->error"); - return false; - } - - if ($json->block == 1 - || array_search($json->asn, $config['iphub_banned_asns']) !== false - || array_search($json->isp, $config['iphub_banned_isps']) !== false) { - error($config['error']['proxy']); - return true; - } + if (!$config['ip_api']['iphub']['enabled']) { + return false; } + $iphub_key = $config['ip_api']['iphub']['key']; + if (empty($iphub_key)) { + error_log('IP api backend is enabled but IPHub API is empty!'); + return false; + } + + // Query IPHub's database with the poster's IP. + if (array_search($ip, $config['ip_api']['ip_whitelist']) !== false) { + // IP is whitelisted, don't bother querying. + return false; + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, "http://v2.api.iphub.info/ip/$ip"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-Key: $iphub_key" ]); + $reply = curl_exec($ch); + if ($reply === false) { + $curl_err = curl_error($ch); + curl_close($ch); + error_log("IPHub query failed: api call failed with curl error $curl_err"); + return false; + } + curl_close($ch); + if (empty($reply)) { + error_log('IPHub query failed: api returned an empty response'); + return false; + } + + $json = json_decode($reply); + if (isset($json->error)) { + error_log("IPHub query failed: $json->error"); + return false; + } + + if ($json->block == 1 + || array_search($json->isp, $config['ip_api']['isps_blacklist']) !== false + || array_search($json->asn, $config['ip_api']['asns_blacklist']) !== false) { + error($config['error']['proxy']); + return true; + } + return false; } From 2337f990783dc3309eaa4f4c29f6d7d497eb334d Mon Sep 17 00:00:00 2001 From: Zankaria Date: Fri, 11 Oct 2024 00:02:12 +0200 Subject: [PATCH 05/12] functions.php: grammar --- inc/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index d9e8e588..4a8aa053 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1869,8 +1869,8 @@ function checkIPAPI(string $ip): bool { } if ($json->block == 1 - || array_search($json->isp, $config['ip_api']['isps_blacklist']) !== false - || array_search($json->asn, $config['ip_api']['asns_blacklist']) !== false) { + || array_search($json->isp, $config['ip_api']['isp_blacklist']) !== false + || array_search($json->asn, $config['ip_api']['asn_blacklist']) !== false) { error($config['error']['proxy']); return true; } From a422122dd49caf8f0a1bb3965a8fa47f9f900362 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sun, 6 Oct 2024 12:48:51 +0200 Subject: [PATCH 06/12] post.php: add IP API check --- post.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/post.php b/post.php index ae1361ce..a42c1959 100644 --- a/post.php +++ b/post.php @@ -469,6 +469,10 @@ function handle_delete() checkDNSBL(); + if (checkIPAPI($_SERVER['REMOTE_ADDR'])) { + error($config['error']['proxy']); + } + // Check if board exists if (!openBoard($_POST['board'])) { error($config['error']['noboard']); @@ -577,6 +581,10 @@ function handle_report() checkDNSBL(); + if (checkIPAPI($_SERVER['REMOTE_ADDR'])) { + error($config['error']['proxy']); + } + // Check if board exists. if (!openBoard($_POST['board'])) { error($config['error']['noboard']); @@ -855,6 +863,10 @@ function handle_post() checkDNSBL(); + if (checkIPAPI($_SERVER['REMOTE_ADDR'])) { + error($config['error']['proxy']); + } + // Check if banned checkBan($board['uri']); From 61d58d77075dc393d5e5d15476da808d3847413f Mon Sep 17 00:00:00 2001 From: Zankaria Date: Sun, 6 Oct 2024 13:00:00 +0200 Subject: [PATCH 07/12] functions.php: add caching to IP api checks --- inc/functions.php | 83 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 22 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 4a8aa053..b515ef29 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1845,32 +1845,71 @@ function checkIPAPI(string $ip): bool { return false; } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, "http://v2.api.iphub.info/ip/$ip"); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-Key: $iphub_key" ]); - $reply = curl_exec($ch); - if ($reply === false) { - $curl_err = curl_error($ch); + $ret = false; + if ($config['cache']['enabled']) { + $ret = cache::get("ip_api_block_$ip"); + } + + if ($ret === false) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, "http://v2.api.iphub.info/ip/$ip"); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ "X-Key: $iphub_key" ]); + $reply = curl_exec($ch); + if ($reply === false) { + $curl_err = curl_error($ch); + curl_close($ch); + error_log("IPHub query failed: api call failed with curl error $curl_err"); + + if ($config['cache']['enabled']) { + // Store the result for 4 hours. + cache::set("ip_api_block_$ip", 'api_error', 14400); + } + + return false; + } curl_close($ch); - error_log("IPHub query failed: api call failed with curl error $curl_err"); - return false; - } - curl_close($ch); - if (empty($reply)) { - error_log('IPHub query failed: api returned an empty response'); + if (empty($reply)) { + error_log('IPHub query failed: api returned an empty response'); + + if ($config['cache']['enabled']) { + // Store the result for 4 hours. + cache::set("ip_api_block_$ip", 'api_error', 14400); + } + + return false; + } + + $json = json_decode($reply); + if (isset($json->error)) { + error_log("IPHub query failed: $json->error"); + + if ($config['cache']['enabled']) { + // Store the result for 4 hours. + cache::set("ip_api_block_$ip", 'api_error', 14400); + } + + return false; + } + + $ret = [ + 'block' => $json['block'], + 'isp' => $json['isp'], + 'asn' => $json['asn'] + ]; + + if ($config['cache']['enabled']) { + // Store the result for 2 days. + cache::set("ip_api_block_$ip", $ret, 172800); + } + } elseif (!is_array($ret)) { + // Cache previously reported an error, just return. return false; } - $json = json_decode($reply); - if (isset($json->error)) { - error_log("IPHub query failed: $json->error"); - return false; - } - - if ($json->block == 1 - || array_search($json->isp, $config['ip_api']['isp_blacklist']) !== false - || array_search($json->asn, $config['ip_api']['asn_blacklist']) !== false) { + if ($ret['block'] == 1 + || array_search($ret['isp'], $config['ip_api']['isp_blacklist']) !== false + || array_search($ret['asn'], $config['ip_api']['asn_blacklist']) !== false) { error($config['error']['proxy']); return true; } From f7676d13d40e2ddc89e4ba427e63f9529ccb5976 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Thu, 10 Oct 2024 22:24:06 +0200 Subject: [PATCH 08/12] config.php: add ip block on api suggestion --- inc/config.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/inc/config.php b/inc/config.php index 62b6b84a..708dd3c3 100644 --- a/inc/config.php +++ b/inc/config.php @@ -251,7 +251,11 @@ 'asn_blacklist' => [], // IPs in this array won't be checked. // This can be used if known legitimate posters are getting blocked by a backend. - 'ip_whitelist' => [] + 'ip_whitelist' => [], + // Block according to the API suggestion. + // Use 0 to ignore this field, 1 to block those which are strongly suggested to be blocked, + // 2 to block all which aren't known good actors. + 'ip_block' => 0 ]; /* From f1bbd0975102e5f63c32c21bcaf1caa966268ff0 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Thu, 10 Oct 2024 22:27:38 +0200 Subject: [PATCH 09/12] functions.php: block on API suggestion --- inc/functions.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index b515ef29..42cf41bc 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1907,9 +1907,10 @@ function checkIPAPI(string $ip): bool { return false; } - if ($ret['block'] == 1 - || array_search($ret['isp'], $config['ip_api']['isp_blacklist']) !== false - || array_search($ret['asn'], $config['ip_api']['asn_blacklist']) !== false) { + if (($config['ip_api']['ip_block'] == 1 && $ret['block'] == 1) + || $config['ip_api']['ip_block'] == 2 && $ret['block'] != 0 + || array_search($ret['isp'], $config['ip_api']['isp_blacklist']) !== false + || array_search($ret['asn'], $config['ip_api']['asn_blacklist']) !== false) { error($config['error']['proxy']); return true; } From 155a6eae841d17563af30bf7bb6a1a3a959e5479 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Thu, 10 Oct 2024 22:20:14 +0200 Subject: [PATCH 10/12] functions.php: handle bad json from iphub --- inc/functions.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/inc/functions.php b/inc/functions.php index 42cf41bc..cd83013d 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1881,6 +1881,17 @@ function checkIPAPI(string $ip): bool { } $json = json_decode($reply); + if ($json === null) { + error_log('IPHub query failed: api returned incorrect json'); + + if ($config['cache']['enabled']) { + // Store the result for 4 hours. + cache::set("ip_api_block_$ip", 'api_error', 14400); + } + + return false; + } + if (isset($json->error)) { error_log("IPHub query failed: $json->error"); From 9b9698210b925b2cda52c7649033194a4787e787 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Thu, 10 Oct 2024 23:59:47 +0200 Subject: [PATCH 11/12] config.php: add add_note option to ip api --- inc/config.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/config.php b/inc/config.php index 708dd3c3..f4656328 100644 --- a/inc/config.php +++ b/inc/config.php @@ -244,6 +244,8 @@ // IPHub API key for checking for bad proxies (https://iphub.info/api). 'key' => '', ], + // If true, add a note to the IP explaining why it was banned. + 'add_note' => false, // If you find that a lot of spammers are coming from a specific ISP, or ASN, // you can put the ISP in isp_blacklist and/or the ASN in asn_blacklist // USE THIS WITH CAUTION, IT MAY PREVENT NON-SPAMMERS FROM POSTING From ad2431893c79834f0345db63d20acd2cc37308b6 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Thu, 10 Oct 2024 23:50:44 +0200 Subject: [PATCH 12/12] functions.php: add note on rejected ip for IP API --- inc/functions.php | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index cd83013d..7745c2e8 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1828,6 +1828,15 @@ function buildJavascript() { * @return bool True if the IP should be blocked. */ function checkIPAPI(string $ip): bool { + function add_note(string $ip, string $note) { + $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)'); + $query->bindValue(':ip', $ip); + $query->bindValue(':mod', -1, PDO::PARAM_INT); + $query->bindValue(':time', time(), PDO::PARAM_INT); + $query->bindValue(':body', "IP API automatic note: $note"); + $query->execute() or error(db_error($query)); + } + global $config; if (!$config['ip_api']['iphub']['enabled']) { @@ -1918,10 +1927,28 @@ function checkIPAPI(string $ip): bool { return false; } - if (($config['ip_api']['ip_block'] == 1 && $ret['block'] == 1) - || $config['ip_api']['ip_block'] == 2 && $ret['block'] != 0 - || array_search($ret['isp'], $config['ip_api']['isp_blacklist']) !== false - || array_search($ret['asn'], $config['ip_api']['asn_blacklist']) !== false) { + $add_note_mode = (int)$config['ip_api']['add_note']; + + if (($config['ip_api']['ip_block'] == 1 && $ret['block'] == 1) || ($config['ip_api']['ip_block'] == 2 && $ret['block'] != 0)) { + if ($add_note_mode !== 0) { + add_note($ip, _('IP was rejected for being blacklisted by the API')); + } + error($config['error']['proxy']); + return true; + } + + if (array_search($ret['isp'], $config['ip_api']['isp_blacklist']) !== false) { + if ($add_note_mode !== 0) { + add_note($ip, _("IP was rejected because the \"{$ret['isp']}\" ISP is blacklisted.")); + } + error($config['error']['proxy']); + return true; + } + + if (array_search($ret['asn'], $config['ip_api']['asn_blacklist']) !== false) { + if ($add_note_mode !== 0) { + add_note($ip, _("IP was rejected because the \"{$ret['asn']}\" ASN is blacklisted.")); + } error($config['error']['proxy']); return true; }