uid) { $track = db_query("SELECT COUNT(ip_address) FROM {troll_ip_track} WHERE uid = :uid AND ip_address = :ip_address", array(':uid' => $user->uid, ':ip_address' => ip_address()))->fetchField(); if (!empty($track)) { // A record for this IP exists. Update accessed timestamp. db_update('troll_ip_track') ->fields(array( 'accessed' => REQUEST_TIME, 'uid' => $user->uid, 'ip_address' => ip_address(), )) ->condition(db_and()->condition('uid', $user->uid)->condition('ip_address', ip_address())) ->execute(); } else { // Insert new IP record for user. db_insert('troll_ip_track') ->fields(array( 'uid' => $user->uid, 'ip_address' => ip_address(), 'created' => REQUEST_TIME, 'accessed' => REQUEST_TIME, )) ->execute(); } } if (variable_get('troll_enable_ip_ban', 1)) { $ban = db_query('SELECT COUNT(ip_address) FROM {troll_ip_ban} WHERE (expires > :expires OR expires = 0) AND ip_address = :ip_address', array(':expires' => REQUEST_TIME, ':ip_address' => ip_address()))->fetchField(); if (!empty($ban->ip_address)) { global $base_url; watchdog('troll', 'IP Ban: !addr', array('!addr' => ip_address()), WATCHDOG_NOTICE); $troll_ip_ban_redirect = variable_get('troll_ip_ban_redirect', ''); if (empty($troll_ip_ban_redirect)) { include_once 'includes/common.inc'; $page = drupal_get_path('module', 'troll') . '/blocked.html'; } else { $page = $troll_ip_ban_redirect; } header('Location: ' . $base_url . '/' . $page); die(); } } } /** * Implements hook_help(). */ function troll_help($path, $arg) { switch ($path) { case 'admin/people/troll/ip_ban': if (!variable_get('troll_enable_ip_ban', 1)) { return '
' . t('IP banning is currently disabled. You can enable it in the !settings page.', array('!settings' => l(t('settings'), 'admin/people/troll/settings'))); } break; } } /** * Implements hook_permission(). */ function troll_permission() { return array( 'administer troll' => array( 'title' => t('Administer Troll'), 'description' => t('Set which IP addresses are blocked or whitelisted and which blacklists to use.'), ), ); } /** * Implements hook_menu(). */ function troll_menu() { $items['admin/people/troll'] = array( 'title' => 'Troll', 'description' => 'Manage visitor IP banning.', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_search_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'weight' => 0, 'type' => MENU_LOCAL_TASK, ); $items['admin/people/troll/search'] = array( 'title' => 'Search Users', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_search_form'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'weight' => 0, ); $items['admin/people/troll/search/view'] = array( 'title' => 'Search Users', 'page callback' => 'troll_search_user_detail', // Probably this is needed, but not in D6 version // 'page arguments' => array(1), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/search/block'] = array( 'title' => 'Block User', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_confirm_block_user_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/ip_ban'] = array( 'title' => 'IP Banning', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_ip_ban'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items['admin/people/troll/ip_ban/edit'] = array( 'title' => 'IP Ban Form', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_ip_ban_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/ip_ban/user'] = array( 'title' => 'IP Ban User IP', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_confirm_block_ip_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/ip_ban/delete'] = array( 'title' => 'Remove Ban', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_confirm_delete_ip_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/ip_blacklist'] = array( 'title' => 'Blacklists', 'page callback' => 'troll_blacklist_summary', 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); $items['admin/people/troll/ip_blacklist/summary'] = array( 'title' => 'Summary', 'page callback' => 'troll_blacklist_summary', 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 0, ); $items['admin/people/troll/ip_blacklist/punishment'] = array( 'title' => 'Visitor Punishment', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_blacklist_punishment_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items['admin/people/troll/ip_blacklist/import'] = array( 'title' => 'Import Blacklist', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_blacklist_import_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); $items['admin/people/troll/ip_blacklist/search'] = array( 'title' => 'Search Blacklisted IPs', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_blacklist_search_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 3, ); $items['admin/people/troll/ip_blacklist/deleteblack'] = array( 'title' => 'Delete Blacklisted IPs', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_confirm_delete_black_block_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/ip_blacklist/whitelist'] = array( 'title' => 'Whitelist', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_whitelist_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 4, ); $items['admin/people/troll/ip_blacklist/deletewhite'] = array( 'title' => 'Delete Whitelisted IPs', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_confirm_delete_white_block_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/dnsbl'] = array( 'title' => 'DNS Blacklist', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_dnsbl_settings'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 5, ); $items['admin/people/troll/dnsbl/test'] = array( 'title' => 'IP test', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_dnsbl_test_form'), 'access arguments' => array('administer troll'), 'file' => 'troll.admin.inc', 'type' => MENU_CALLBACK, ); $items['admin/people/troll/settings'] = array( 'title' => 'Settings', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_admin_settings'), 'access arguments' => array('administer site configuration'), 'file' => 'troll.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 6, ); $items['user/%troll_user/troll'] = array( 'title' => 'Troll Track', 'page callback' => 'troll_search_user_detail', 'page arguments' => array(1), 'access arguments' => array('administer troll'), 'type' => MENU_LOCAL_TASK, 'file' => 'troll.admin.inc', ); return $items; } /** * Implements hook_user(). */ function troll_user_load($uid) { if (is_object($uid) && !empty($uid->uid) || is_numeric($uid)) { $account = ''; if (is_numeric($uid)) { $account = user_load($uid); } else { $account = user_load($uid->uid); if (!empty($account)) { $uid = $account->uid; } } return $uid; } } /** * Helper function to lookup the last known IP Address for a given user. */ function _troll_last_ip($uid) { $query = db_select('troll_ip_track', 't'); $query->addField('t', 'ip_address', 'ip_address'); $query->condition('uid', $uid, '='); $query->orderBy('accessed', 'DESC'); $query->range(0, 1); $result = $query->execute(); return $result->fetchField(0); } /** * Implements hook_comment_view(). */ function troll_comment_view($comment) { $comment->troll_last_ip = _troll_last_ip($comment->uid); } /** * Convert dotted decimal IP to long integer and check for validity. * * @param string $ip * A IP in decimal format * * @return int * returns the integer value of the IP address */ function _troll_longip($ip) { $longip = ip2long($ip); if ($longip === FALSE || $longip == -1) { drupal_set_message(t('IP @ip not valid!', array('@ip' => $ip)), 'error'); drupal_goto('admin/people/troll/ip_blacklist'); } return $longip; } /** * Removes an IP ban from the database. */ function troll_remove_ip($ip) { $deleted = db_delete('troll_ip_ban') ->condition('ip_address', $ip) ->execute(); if ($deleted) { drupal_set_message(t('%ip IP ban has been removed.', array('%ip' => $ip)), 'status'); } else { drupal_set_message(t('An error occurred. IP ban not removed.'), 'error'); } } /** * Removes IP block from the blacklist. * * @param int $net * The int value of the network IP * @param int $bcast * The integer value of the network IP */ function troll_remove_blacklist($net, $bcast) { $deleted = db_delete('troll_blacklist') ->condition(db_and()->condition('net', $net)->condition('bcast', $bcast)) ->execute(); if ($deleted) { drupal_set_message(t('Blacklist block removed.'), 'status'); } else { drupal_set_message(t('An error occurred. Blacklist block not removed.'), 'status'); } } /** * Removes IP block from the whitelist. * * @param int $net * The int value of the network IP * @param int $bcast * The integer value of the network IP */ function troll_remove_whitelist($net, $bcast) { $deleted = db_delete('troll_whitelist') ->condition(db_and()->condition('net', $net) ->condition('bcast', $bcast)) ->execute(); if ($deleted) { drupal_set_message(t('IP whitelist address removed.'), 'status'); } else { drupal_set_message(t('An error occurred, IP whitelist not removed.'), 'error'); } } /** * Inserts an IP ban into the database. * * @param array $edit * trolls $edit array values to work with */ function troll_insert_ip($edit) { global $user; $expires = ($edit['expires'] == 1) ? mktime(23, 59, 0, $edit['month'], $edit['day'], $edit['year']) : 0; db_delete('troll_ip_ban') ->condition('ip_address', $edit['ip_address']) ->execute(); $insert = db_insert('troll_ip_ban') ->fields(array( 'ip_address' => $edit['ip_address'], 'domain_name' => $edit['domain_name'], 'created' => REQUEST_TIME, 'expires' => $expires, 'uid' => $user->uid, )) ->execute(); if ($insert) { drupal_set_message(t('IP ban added: %ip', array('%ip' => $edit['ip_address'])), 'status'); } else { drupal_set_message(t('An error occurred. IP ban not created.'), 'error'); } } /** * Updates an IP ban in the database. * * @param array $edit * trolls $edit array values to work with */ function troll_update_ip($edit) { if (!is_array($edit)) { return FALSE; } global $user; $expires = ($edit['expires'] == 1) ? mktime(23, 59, 0, $edit['month'], $edit['day'], $edit['year']) : 0; $num_updated = db_update('troll_ip_ban') ->fields(array( 'ip_address' => $edit['ip_address'], 'domain_name' => $edit['domain_name'], 'expires' => $expires, 'uid' => $user->uid, )) ->condition('iid', $edit['iid']) ->execute(); if ($num_updated) { drupal_set_message(t('%num record(s) updated for IP ban: %ip', array('%num' => $num_updated, '%ip' => $edit['ip_address'])), 'status'); } else { drupal_set_message(t('An error occurred. IP ban not updated.'), 'error'); } } /** * Logs IP information for users in the database. */ function troll_check_ip() { global $user; $check = db_query("SELECT COUNT(uid) FROM {troll_ip_track} WHERE ip_address = :ip_address AND uid = :uid", array(':ip_address' => ip_address(), ':uid' => $user->uid))->fetchField(); if (!empty($check)) { db_insert('troll_ip_track') ->fields(array( 'uid' => $user->uid, 'ip_address' => ip_address(), 'created' => REQUEST_TIME, )) ->execute(); } } /** * Checks remote IP to see if it is blacklisted. * * @return int * zero if whitelisted or not blacklisted, otherwise the number of the IP * blacklist the block matches */ function troll_is_blacklisted() { static $blacklisted, $whitelisted; if (isset($blacklisted) && isset($whitelisted)) { return $whitelisted ? FALSE : $blacklisted; } $longip = ip2long(ip_address()); if ($longip === FALSE || $longip == -1) { return FALSE; } else { $whitelisted = (bool) db_query_range('SELECT 1 FROM {troll_whitelist} w WHERE w.net <= :longip AND w.bcast >= :longip', 0, 1, array(':longip' => $longip))->fetchField(); if ($whitelisted) { return FALSE; } return (bool) db_query_range('SELECT 1 FROM {troll_blacklist} b WHERE b.net <= :longip AND b.bcast >= :longip', 0, 1, array(':longip' => $longip))->fetchAll(); } } /** * Bans a user. * * @param int $uid * User ID to block */ function troll_block_user($uid) { // Block them. $user_edit['status'] = 0; // Remove all their permission roles. $user_edit['roles'] = array(); // Set variable. $name = null; $user = user_load($uid); user_save($user, $user_edit); if (variable_get('troll_block_role', NULL)) { $name = db_query_range('SELECT name FROM {users} WHERE uid = :uid', 0, 1, array(':uid' => $uid))->fetchField(); $role = db_query_range('SELECT name FROM {role} WHERE rid = :rid', 0, 1, array(':rid' => variable_get('troll_block_role', 0)))->fetchField(); db_insert('users_roles') ->fields(array( 'uid' => $uid, 'rid' => variable_get('troll_block_role', '0'), ) )->execute(); drupal_set_message(t('Blocked user !link and assigned role %role.', array( '!link' => l($name, "admin/people/troll/search/view/$uid"), '%role' => $role, )), 'status'); } else { drupal_set_message(t('Blocked user !link.', array( '!link' => l($name, "admin/people/troll/search/view/$uid"), )), 'status'); } } /** * Implements hook_comment(). */ function troll_comment($comment, $op) { if (variable_get('troll_dnsbl_active', 0) != 1) { return; } switch ($op) { case 'insert': case 'update': $comment = (object) $comment; $ip = ip_address(); $blacklisted = _troll_dnsbl_blacklisted($ip); if ($blacklisted == TRUE) { $operation = comment_operations('unpublish'); $query = $operation['unpublish'][1]; db_query($query, $comment->cid); drupal_set_message(t('Your comment has been queued for moderation by site administrators and will be published after approval.'), 'status'); watchdog('troll', 'Comment unpublished for DNSBL: %subject.', array('%subject' => $comment->subject), WATCHDOG_INFO, l(t('view'), 'node/' . $comment->nid, array('fragment' => 'comment-' . $comment->cid))); } else { watchdog('troll', 'IP %ip is not DNS blacklisted.', array('%ip' => $ip), WATCHDOG_INFO, l(t('view'), 'node/' . $comment->nid, array('fragment' => 'comment-' . $comment->cid))); } return; default: return; } } /** * Check if an IP is blacklisted or not. * * @param string $ip * the IP to check. * * @return bool * true if blacklisted or false */ function _troll_dnsbl_blacklisted($ip) { $servers = _troll_dnsbl_default_servers(); $servers = explode("\n", $servers); $threshold = variable_get('troll_dnsbl_threshold', 1); foreach ($servers as $server) { // We trim because we end up with a new line at the end of each server // for an obscure reason! if (_troll_dnsbl_check($ip, trim($server))) { $threshold--; } if ($threshold == 0) { return TRUE; } } return FALSE; } /** * Perform a DNS query. * * @param string $ip * the IP to check * @param string $server * the DNS to check. * * @return bool * true if the entry is there otherise false even if there's an error. */ function _troll_dnsbl_check($ip, $server) { // Let's reverse the IP. $ip = implode('.', array_reverse(explode('.', $ip))); $request = implode('.', array($ip, $server)); $result = gethostbyname($request); if ($request == $result) { // No domain. return FALSE; } else { $octats = explode('.', $result); return $octats[0] == 127; } } /** * Return the list of default DNSBL servers. * * @return array * the list of default servers. */ function _troll_dnsbl_default_servers() { return array( 'access.redhawk.org', 'b.barracudacentral.org', 'bl.shlink.org', 'bl.spamcannibal.org', 'bl.spamcop.net', 'bl.tiopan.com', 'blackholes.wirehub.net', 'blacklist.sci.kun.nl', 'block.dnsbl.sorbs.net', 'blocked.hilli.dk', 'bogons.cymru.com', 'cart00ney.surriel.com', 'cbl.abuseat.org', 'cblless.anti-spam.org.cn', 'dev.null.dk', 'dialup.blacklist.jippg.org', 'dialups.mail-abuse.org', 'dialups.visi.com', 'dnsbl.abuse.ch', 'dnsbl.ahbl.org', 'dnsbl.anticaptcha.net', 'dnsbl.antispam.or.id', 'dnsbl.dronebl.org', 'dnsbl.justspam.org', 'dnsbl.kempt.net', 'dnsbl.sorbs.net', 'dnsbl.tornevall.org', 'dnsbl-1.uceprotect.net', 'duinv.aupads.org', 'dnsbl-2.uceprotect.net', 'dnsbl-3.uceprotect.net', 'dul.dnsbl.sorbs.net', 'dul.ru', 'escalations.dnsbl.sorbs.net', 'hil.habeas.com', 'black.junkemailfilter.com', 'http.dnsbl.sorbs.net', 'intruders.docs.uu.se', 'ips.backscatterer.org', 'korea.services.net', 'l2.apews.org', 'mail-abuse.blacklist.jippg.org', 'misc.dnsbl.sorbs.net', 'msgid.bl.gweep.ca', 'new.dnsbl.sorbs.net', 'no-more-funn.moensted.dk', 'old.dnsbl.sorbs.net', 'opm.tornevall.org', 'pbl.spamhaus.org', 'proxy.bl.gweep.ca', 'psbl.surriel.com', 'pss.spambusters.org.ar', 'rbl.schulte.org', 'rbl.snark.net', 'recent.dnsbl.sorbs.net', 'relays.bl.gweep.ca', 'relays.bl.kundenserver.de', 'relays.mail-abuse.org', 'relays.nether.net', 'rsbl.aupads.org', 'sbl.spamhaus.org', 'smtp.dnsbl.sorbs.net', 'socks.dnsbl.sorbs.net', 'spam.dnsbl.sorbs.net', 'spam.olsentech.net', 'spamguard.leadmon.net', 'spamsources.fabel.dk', 'tor.ahbl.org', 'tor.dnsbl.sectoor.de', 'ubl.unsubscore.com', 'web.dnsbl.sorbs.net', 'xbl.spamhaus.org', 'zen.spamhaus.org', 'zombie.dnsbl.sorbs.net', 'dnsbl.inps.de', 'dyn.shlink.org', 'rbl.megarbl.net', 'bl.mailspike.net', ); }