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' => 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(); } } } /** * Implementation of hook_help(). */ function troll_help($path, $arg) { switch ($path) { case 'admin/user/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/user/troll/settings'))); } break; } } /** * Implementation of hook_perm(). */ function troll_perm() { return array( 'administer troll' => array( 'title' => t('Administer Troll'), 'description' => t('Set which IP addresses are blocked or whitelisted and which blacklists to use.') ) ); } /** * Implementation of hook_menu(). * * @return array */ function troll_menu() { $items['admin/user/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'), 'weight' => 0 ); $items['admin/user/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'), 'weight' => 0 ); $items['admin/user/troll/search/view'] = array( 'title' => 'Search Users', 'page callback' => 'troll_search_user_detail', 'access arguments' => array('administer troll'), 'type' => MENU_CALLBACK ); $items['admin/user/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'), 'type' => MENU_CALLBACK ); $items['admin/user/troll/ip_ban'] = array( 'title' => 'IP Banning', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_ip_ban'), 'access arguments' => array('administer troll'), 'type' => MENU_LOCAL_TASK, 'weight' => 1 ); $items['admin/user/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'), 'type' => MENU_CALLBACK ); $items['admin/user/troll/ip_ban/user'] = array( 'title' => 'IP Ban Form', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_confirm_ban_ip_form'), 'access arguments' => array('administer troll'), 'type' => MENU_CALLBACK ); $items['admin/user/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'), 'type' => MENU_CALLBACK ); $items['admin/user/troll/ip_blacklist'] = array( 'title' => 'Blacklists', 'page callback' => 'troll_blacklist_summary', 'access arguments' => array('administer troll'), 'type' => MENU_LOCAL_TASK, 'weight' => 2 ); $items['admin/user/troll/ip_blacklist/summary'] = array( 'title' => 'Summary', 'page callback' => 'troll_blacklist_summary', 'access arguments' => array('administer troll'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 0 ); $items['admin/user/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'), 'type' => MENU_LOCAL_TASK, 'weight' => 1 ); $items['admin/user/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'), 'type' => MENU_LOCAL_TASK, 'weight' => 2 ); $items['admin/user/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'), 'type' => MENU_LOCAL_TASK, 'weight' => 3 ); $items['admin/user/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'), 'type' => MENU_CALLBACK ); $items['admin/user/troll/ip_blacklist/whitelist'] = array( 'title' => 'Whitelist', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_whitelist_form'), 'access arguments' => array('administer troll'), 'type' => MENU_LOCAL_TASK, 'weight' => 4 ); $items['admin/user/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'), 'type' => MENU_CALLBACK ); $items['admin/user/troll/dnsbl'] = array( 'title' => 'DNS Blacklist', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_dnsbl_settings'), 'access arguments' => array('administer troll'), 'weight' => 5, 'type' => MENU_LOCAL_TASK ); $items['admin/user/troll/dnsbl/test'] = array( 'title' => 'IP test', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_dnsbl_test_form'), 'access arguments' => array('administer troll'), 'type' => MENU_CALLBACK ); $items['admin/user/troll/settings'] = array( 'title' => 'Settings', 'page callback' => 'drupal_get_form', 'page arguments' => array('troll_admin_settings'), 'access arguments' => array('administer site configuration'), '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; } function troll_user_load($arg) { $user = user_load($arg); if (!empty($user)) { return $user->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); } /** * Implementation of 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 $ip string * @return integer */ function _troll_longip($ip) { $longip = ip2long($ip); if ($longip === FALSE || $longip == -1) { drupal_set_message(t('IP %ip not valid!', array('%ip' => $ip))); drupal_goto('admin/user/troll/ip_blacklist'); } return $longip; } /** * Removes an IP ban from the database. */ function troll_remove_ip($iid) { $deleted = db_delete('troll_ip_ban') ->condition('iid', $iid) ->execute(); if ($deleted) { drupal_set_message(t('IP ban removed.')); } else { drupal_set_message(t('An error occurred. IP ban not removed.')); } } /** * Removes IP block from the blacklist * * @param $edit array */ 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.')); } else { drupal_set_message(t('An error occurred. Blacklist block not removed.')); } } /** * Removes IP block from the whitelist. * * @param $edit array */ 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 removed.')); } else { drupal_set_message(t('An error occurred, IP whitelist not removed.')); } } /** * Inserts an IP ban into the database. * * @param $edit array */ 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']))); } else { drupal_set_message(t('An error occurred. IP ban not created.')); } } /** * Updates an IP ban in the database. * * @param $edit array */ function troll_update_ip($edit) { 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']))); } else { drupal_set_message(t('An error occurred. IP ban not updated.')); } } /** * 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 integer zero if whitelisted or not blacklisted, otherwise the number of IP blacklist 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', array(':longip' => $longip), 0, 1)->fetchField(); if ($whitelisted) { return FALSE; } return (bool)db_query_range('SELECT 1 FROM {troll_blacklist} b WHERE b.net <= :longip AND b.bcast >= :longip', array(':longip' => $longip), 0, 1)->fetchField(); } } /** * Bans a user. * * @param $uid int */ function troll_block_user($uid) { // block them $user_edit['status'] = 0; // remove all their permissions roles $user_edit['roles'] = array(); $user = user_load($uid); user_save($user, $user_edit); sess_destroy_uid($uid); if (variable_get('troll_block_role', NULL)) { $name = db_query_range('SELECT name FROM {users} WHERE uid = :uid', array(':uid' => $uid), 0, 1)->fetchField(); $role = db_query_range('SELECT name FROM {role} WHERE rid = :rid', array(':rid' => variable_get('troll_block_role', 0)), 0, 1)->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/user/troll/search/view/$uid"), '%role' => $role))); } else { drupal_set_message(t('Blocked user !link.', array('!link' => l($name, "admin/user/troll/search/view/$uid")))); } } /** * Implementation of 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.')); 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 $ip the IP to check. * @return 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 $ip the IP to check * @param $server the DNS to check. * @return 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 the list of default servers. */ function _troll_dnsbl_default_servers() { return variable_get('troll_dnsbl_list', implode("\n", array( 'dnsbl.sorbs.net', 'bl.spamcop.net', 'dnsbl.njabl.org', 'cbl.abuseat.org', 'sbl-xbl.spamhaus.org' ))); }