2021-05-21 01:12:10 -06:00
< ? php
// Minimum message length checks
const MSG_MIN_CHARS = 20 ;
const MSG_MIN_WORDS = 5 ;
// Banned words check, file should be one match (word or phrase) per line
2021-05-21 16:45:27 -06:00
const BANNED_WORDLIST = __DIR__ . " /../resources/net.contactspam/bannedwords.txt " ;
2021-05-21 01:12:10 -06:00
// Banned email domain check, one domain per line, useful if you get lots of spam from
// a domain your customers probably won't legitimately use
2024-02-14 15:09:31 -07:00
const BANNED_EMAIL_DOMAINS = __DIR__ . " /../resources/net.contactspam/banneddomains.txt " ;
const BANNED_SPAM_DOMAINS = __DIR__ . " /../resources/net.contactspam/toxic_domains_whole.txt " ;
2021-05-21 16:45:27 -06:00
const BANNED_IP_LIST = __DIR__ . " /../resources/net.contactspam/bannedips.txt " ;
const BANNED_IP_CIDR = __DIR__ . " /../resources/net.contactspam/toxic_ip_cidr.txt " ;
2021-07-20 19:54:28 -06:00
// Domains to skip looking up for SURBL
const WHITELIST_DOMAINS = __DIR__ . " /../resources/net.contactspam/whitelistdomains.txt " ;
2021-05-21 01:12:10 -06:00
$message = $VARS [ " message " ] ? ? " " ;
$fromemail = $VARS [ " email " ] ? ? " " ;
$clientip = $VARS [ " ipaddr " ] ? ? " " ;
$contactformdomain = trim ( strtolower ( $VARS [ " domain " ] ? ? " " ));
$msg_lower = trim ( strtolower ( $message ));
$email_lower = trim ( strtolower ( $fromemail ));
$email_parts = explode ( " @ " , $email_lower );
$email_domain = $email_parts [ count ( $email_parts ) - 1 ];
//
// If message too short (chars and/or words)
//
if ( isset ( $VARS [ " message " ])) {
if ( strlen ( $msg_lower ) < MSG_MIN_CHARS ) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " length_chars " , " hit " => " " , " message " => " Message too short. " ]);
} else if ( str_word_count ( $msg_lower ) < MSG_MIN_WORDS ) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " length_words " , " hit " => " " , " message " => " Message too short. " ]);
}
}
//
// Check email domain
//
2024-02-14 15:09:31 -07:00
$banneddomainlist = file ( BANNED_EMAIL_DOMAINS , FILE_IGNORE_NEW_LINES );
2021-05-21 01:12:10 -06:00
foreach ( $banneddomainlist as $domain ) {
if ( $email_domain == $domain ) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " domain " , " hit " => $domain , " message " => " Emails from \" " . htmlspecialchars ( $domain ) . " \" are not allowed because of spam/abuse. " . ( $domain == " googlemail.com " ? " (Hint: use gmail.com instead) " : " " )]);
}
}
//
// Check if email address is sketchy
//
if ( ! empty ( $email_parts ) && count ( $email_parts ) == 2 ) {
if ( $email_parts [ 0 ] == $email_parts [ 1 ]) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " email_fake " , " hit " => " " , " message " => " Unacceptable email address. " ]);
}
}
if ( ! empty ( $contactformdomain )) {
if ( $contactformdomain == $email_domain && $email_parts [ 0 ] != " test " ) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " email_self " , " hit " => " " , " message " => " Please use your own email address, not ours. " ]);
}
}
//
// Check for blocked spammy words
//
$bannedwordlist = file ( BANNED_WORDLIST , FILE_IGNORE_NEW_LINES );
foreach ( $bannedwordlist as $word ) {
if ( strpos ( $msg_lower , $word ) !== false ) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " word " , " hit " => $word , " message " => " \" " . htmlspecialchars ( $word ) . " \" is not allowed because of spam/abuse. " ]);
}
}
//
// Lookup reported client IP address against stopforumspam.com CIDR range list
//
/**
* https :// stackoverflow . com / a / 594134
*/
function cidr_match ( $ip , $range ) {
list ( $subnet , $bits ) = explode ( '/' , $range );
if ( $bits === null ) {
$bits = 32 ;
}
$ip = ip2long ( $ip );
$subnet = ip2long ( $subnet );
$mask = - 1 << ( 32 - $bits );
$subnet &= $mask ; # nb: in case the supplied subnet wasn't correctly aligned
return ( $ip & $mask ) == $subnet ;
}
if ( filter_var ( $clientip , FILTER_VALIDATE_IP , [ FILTER_FLAG_IPV4 ])) {
$bannedipcidrlist = file ( BANNED_IP_CIDR , FILE_IGNORE_NEW_LINES );
foreach ( $bannedipcidrlist as $cidr ) {
if ( cidr_match ( $clientip , $cidr )) {
2024-02-14 15:09:31 -07:00
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " stopforumspam_toxic_ip_cidr " , " hit " => $clientip , " message " => " Your computer's IP address is on a spam blacklist. " ]);
2021-05-21 01:12:10 -06:00
}
}
}
//
// Lookup reported client IP address against stopforumspam.com full IP list
//
2024-02-14 15:09:31 -07:00
if ( filter_var ( $clientip , FILTER_VALIDATE_IP )) {
2021-05-21 01:12:10 -06:00
$bannediplist = file ( BANNED_IP_LIST , FILE_IGNORE_NEW_LINES );
foreach ( $bannediplist as $ip ) {
if ( $clientip == $ip ) {
2024-02-14 15:09:31 -07:00
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " stopforumspam_banned_ip " , " hit " => $clientip , " message " => " Your computer's IP address is blacklisted for sending spam. " ]);
2021-05-21 01:12:10 -06:00
}
}
}
//
// Lookup reported client IP address to see if it's in a botnet or something and sending spam
//
try {
if ( filter_var ( $clientip , FILTER_VALIDATE_IP , [ FILTER_FLAG_IPV4 ])) {
$blacklist = " xbl.spamhaus.org " ;
$url = implode ( " . " , array_reverse ( explode ( " . " , $clientip ))) . " . " . $blacklist ;
// Cache IPs so we don't do a DNS lookup each time
$cacheresp = $memcache -> get ( " net.contactspam. $url " );
if ( $cacheresp !== false ) {
$dns_result = $cacheresp ;
} else {
$dns_result = `host -t A $url b.gns.spamhaus.org` ;
$memcache -> set ( " net.contactspam. $url " , $dns_result , 60 * 60 * 24 );
}
if ( strpos ( $dns_result , " NXDOMAIN " ) === false && strpos ( $dns_result , " 127.0. " ) !== false ) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " spamhaus_xbl " , " hit " => $clientip , " message " => " Your computer or a device on your network is infected with a virus and is sending spam messages, so our system is blocking your message. " ]);
}
}
} catch ( Exception $ex ) {
2025-04-02 17:28:53 -06:00
\Sentry\captureException ( $ex );
2021-05-21 01:12:10 -06:00
}
2021-07-20 19:54:28 -06:00
//
// Check domains in message against blacklists
//
$lists = [
" multi.surbl.org " ,
" dbl.spamhaus.org " ,
" black.uribl.com "
];
2024-02-14 15:09:31 -07:00
$bannedspamdomains = file ( BANNED_SPAM_DOMAINS , FILE_IGNORE_NEW_LINES );
2021-07-20 19:54:28 -06:00
try {
// Matches domain names
$regex = " /([a-zA-Z0-9][a-zA-Z0-9-] { 1,61}[a-zA-Z0-9](?: \ .[a-zA-Z] { 2,})+)/i " ;
preg_match_all ( $regex , urldecode ( $message ), $matches );
// Remove any domains on the whitelist before doing lookup
$domainlist = [];
$whitelistdomainlist = file ( WHITELIST_DOMAINS , FILE_IGNORE_NEW_LINES );
foreach ( $matches [ 0 ] as $match ) {
$match = strtolower ( $match );
$found = false ;
foreach ( $whitelistdomainlist as $domain ) {
if ( $domain == $match ) {
$found = true ;
}
}
if ( ! $found ) {
$domainlist [] = $match ;
2024-02-14 15:18:47 -07:00
if ( strpos ( $match , " www. " ) === 0 ) {
// starts with www, let's strip it and add both to the list to check
$domainlist [] = substr ( $match , 4 );
}
2021-07-20 19:54:28 -06:00
}
}
foreach ( $domainlist as $d ) {
2024-02-14 15:09:31 -07:00
// check local domain blacklist
foreach ( $bannedspamdomains as $word ) {
if ( $word == $d ) {
2024-02-14 15:15:28 -07:00
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " stopforumspam_domains " , " hit " => $word , " message " => " Your message contains a domain ( $d ) that has been linked to recent spam. Message not sent. " ]);
2024-02-14 15:09:31 -07:00
}
}
2024-02-14 15:21:12 -07:00
}
// do online searches only after we've checked the local lists
foreach ( $domainlist as $d ) {
2024-02-14 15:09:31 -07:00
// check online blacklists
2021-07-20 19:54:28 -06:00
foreach ( $lists as $blacklist ) {
$url = " $d . $blacklist " ;
2024-02-14 15:09:31 -07:00
// Cache result so we don't do a DNS lookup each time
2021-07-20 19:54:28 -06:00
$cacheresp = $memcache -> get ( " net.contactspam. $url " );
if ( $cacheresp !== false ) {
$dns_result = $cacheresp ;
} else {
$dns_results = dns_get_record ( $url );
$dns_result = count ( $dns_results ) > 0 ;
$memcache -> set ( " net.contactspam. $url " , " $dns_result " , 60 * 60 * 24 );
}
if ( $dns_result ) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " $blacklist " , " hit " => $d , " message " => " Your message contains a domain ( $d ) that has been linked to recent spam or criminal activity. Message not sent. " ]);
}
}
}
} catch ( Exception $ex ) {
2025-04-02 17:28:53 -06:00
\Sentry\captureException ( $ex );
2021-07-20 19:54:28 -06:00
}
2021-07-10 18:12:27 -06:00
// Check local spammer database
if ( env ( " require_database " )) {
2024-02-14 15:09:31 -07:00
try {
if ( ! empty ( $clientip )) {
if ( $database -> has ( " net_contactspam_spammers " , [ " ip " => $clientip ])) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " netsyms_ip_blacklist " , " hit " => $clientip , " message " => " A computer at your IP address has sent spam in the past. Your message has been blocked. " ]);
}
2021-07-10 18:12:27 -06:00
}
2024-02-14 15:09:31 -07:00
if ( ! empty ( $email_lower )) {
if ( $database -> has ( " net_contactspam_spammers " , [ " email " => $email_lower ])) {
exitWithJson ([ " status " => " OK " , " clean " => false , " filter " => " netsyms_email_blacklist " , " hit " => $email_lower , " message " => " Someone put your email as the from address on a spam message. Your message has been blocked. " ]);
}
2021-07-10 18:12:27 -06:00
}
2024-02-14 15:09:31 -07:00
} catch ( Exception $ex ) {
// skip
2021-07-10 18:12:27 -06:00
}
}
2021-05-21 01:12:10 -06:00
//
// Well if we got here then the message tested negative for spam
//
exitWithJson ([ " status " => " OK " , " clean " => true , " filter " => null , " hit " => null ]);