View source
<?php
namespace Drupal\autoban\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\autoban\Entity\Autoban;
use Drupal\Core\Database\Database;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\autoban\AutobanUtils;
use Drupal\Component\Utility\Html;
class AutobanController extends ControllerBase {
public function getBannedIp($rule, array $params = []) {
$query_mode = $this
->config('autoban.settings')
->get('autoban_query_mode');
$use_wildcards = $this
->config('autoban.settings')
->get('autoban_use_wildcards') ?: FALSE;
$regexp_query_mode = $query_mode == 'regexp';
$from_analyze = AutobanUtils::isFromAnalyze($rule) && !empty($params);
if ($from_analyze) {
$entity = NULL;
$message = Html::decodeEntities(trim($params['message']));
$type = trim($params['type']);
$threshold = 1;
$referer = NULL;
$user_type = AutobanUtils::AUTOBAN_USER_ANY;
}
else {
$entity = Autoban::load($rule);
$message = trim($entity->message);
$type = trim($entity->type);
$threshold = (int) $entity->threshold;
$referer = trim($entity->referer);
$user_type = (int) $entity->user_type;
}
$connection = Database::getConnection();
$query = $connection
->select('watchdog', 'log');
$query
->fields('log', [
'hostname',
]);
$group = $query
->orConditionGroup();
$message_items = explode('|', $message);
if (count($message_items) > 1) {
foreach ($message_items as $message_item) {
if ($from_analyze) {
$group
->condition('log.message', trim($message_item))
->condition('log.variables', trim($message_item));
}
else {
if ($regexp_query_mode) {
$group
->condition('log.message', trim($message_item), 'REGEXP')
->condition('log.variables', trim($message_item), 'REGEXP');
}
else {
if (!$use_wildcards) {
$group
->condition('log.message', '%' . $query
->escapeLike(trim($message_item)) . '%', 'LIKE')
->condition('log.variables', '%' . $query
->escapeLike(trim($message_item)) . '%', 'LIKE');
}
else {
$group
->condition('log.message', trim($message_item), 'LIKE')
->condition('log.variables', trim($message_item), 'LIKE');
}
}
}
}
}
else {
if ($from_analyze) {
$group
->condition('log.message', $message)
->condition('log.variables', $message);
}
else {
if ($regexp_query_mode) {
$group
->condition('log.message', $message, 'REGEXP')
->condition('log.variables', $message, 'REGEXP');
}
else {
if (!$use_wildcards) {
$group
->condition('log.message', '%' . $query
->escapeLike($message) . '%', 'LIKE')
->condition('log.variables', '%' . $query
->escapeLike($message) . '%', 'LIKE');
}
else {
$group
->condition('log.message', $message, 'LIKE')
->condition('log.variables', $message, 'LIKE');
}
}
}
}
$query
->condition('log.type', $type)
->condition($group);
if (!empty($referer)) {
$query
->condition('log.referer', '%' . $query
->escapeLike($referer) . '%', 'LIKE');
}
if ($user_type > 0) {
switch ($user_type) {
case AutobanUtils::AUTOBAN_USER_ANONYMOUS:
$query
->condition('log.uid', 0);
break;
case AutobanUtils::AUTOBAN_USER_AUTHENTICATED:
$query
->condition('log.uid', 0, '>');
break;
}
}
$query
->groupBy('log.hostname');
$query
->addExpression('COUNT(log.hostname)', 'hcount');
$query
->having('COUNT(log.hostname) >= :cnt', [
':cnt' => $threshold,
]);
$result = $query
->execute()
->fetchAll();
return $result;
}
public function getBanManagerData($provider) {
$banProvider = $this
->getBanProvidersList($provider);
if ($banProvider) {
$service = $banProvider['service'];
if ($service) {
$connection = Database::getConnection();
return [
'ban_manager' => $service
->getBanIpManager($connection),
'ban_name' => $service
->getName(),
'ban_type' => $service
->getBanType(),
];
}
}
return NULL;
}
public function getBanManagerDataRule($rule) {
$entity = Autoban::load($rule);
return $this
->getBanManagerData($entity->provider);
}
public function getBanProvidersList($provider_id = NULL) {
$banProvidersList = [];
$container = \Drupal::getContainer();
$kernel = $container
->get('kernel');
$services = $kernel
->getCachedContainerDefinition()['services'];
foreach ($services as $service_id => $value) {
$service_def = unserialize($value);
if (!empty($service_def['properties']) && !empty($service_def['properties']['_serviceId'])) {
$service_id = $service_def['properties']['_serviceId'];
$aservices = explode('.', $service_id);
if (!empty($aservices[1]) && $aservices[1] == 'ban_provider') {
$service = $container
->get($service_id);
$id = $service
->getId();
$name = $service
->getName();
$banProvidersList[$id] = [
'name' => $name,
'service' => $service,
];
}
}
}
if (!empty($provider_id)) {
return isset($banProvidersList[$provider_id]) ? $banProvidersList[$provider_id] : NULL;
}
else {
return $banProvidersList;
}
}
public function banIpAction($ips, $provider) {
$banManagerData = $this
->getBanManagerData($provider);
$ips_arr = explode(',', $ips);
foreach ($ips_arr as $ip) {
$banned = $this
->banIp($ip, $banManagerData, TRUE);
if ($banned) {
$this
->messenger()
->addMessage($this
->t('IP %ip has been banned (@provider).', [
'%ip' => $ip,
'@provider' => $banManagerData['ban_name'],
]));
}
else {
$this
->messenger()
->addMessage($this
->t('IP %ip has not been banned', [
'%ip' => $ip,
]), 'warning');
}
}
$destination = $this
->getDestinationArray();
if (!empty($destination)) {
$url = Url::fromUserInput($destination['destination']);
return new RedirectResponse($url
->toString());
}
}
public function banIp($ip, array $banManagerData, $debug = FALSE) {
if (empty($banManagerData)) {
if ($debug) {
$this
->messenger()
->addMessage($this
->t('Empty banManagerData.'), 'warning');
}
return FALSE;
}
$banManager = $banManagerData['ban_manager'];
if (!$this
->canIpBan($ip)) {
if ($debug) {
$this
->messenger()
->addMessage($this
->t('Cannot ban this IP.'), 'warning');
}
return FALSE;
}
if ($banManager
->isBanned($ip)) {
if ($debug) {
$this
->messenger()
->addMessage($this
->t('This IP already banned.'), 'warning');
}
return FALSE;
}
$banType = $banManagerData['ban_type'];
switch ($banType) {
case 'single':
$banManager
->banIp($ip);
break;
case 'range':
$ip_range = $this
->createIpRange($ip);
if (empty($ip_range)) {
$banManager
->banIp($ip);
}
else {
$banManager
->banIp($ip_range['ip_start'], $ip_range['ip_end']);
}
break;
}
return TRUE;
}
public function banIpList(array $ip_list, $rule) {
$count = 0;
if (!empty($ip_list) && $rule) {
$banManagerData = $this
->getBanManagerDataRule($rule);
if ($banManagerData) {
foreach ($ip_list as $item) {
$banStatus = $this
->banIp($item->hostname, $banManagerData);
if ($banStatus) {
$count++;
$this
->messenger()
->addMessage($this
->t('IP %ip has been banned (@provider).', [
'%ip' => $item->hostname,
'@provider' => $banManagerData['ban_name'],
]));
}
}
}
else {
$this
->messenger()
->addMessage($this
->t('No ban manager for rule %rule', [
'%rule' => $rule,
]), 'error');
}
}
return $count;
}
public function canIpBan($ip) {
if ($ip == \Drupal::request()
->getClientIp()) {
return FALSE;
}
if ($this
->whitelistIp($ip)) {
return FALSE;
}
return TRUE;
}
private function cidrMatch($ip, $network, $cidr) {
return (ip2long($ip) & ~((1 << 32 - $cidr) - 1)) == ip2long($network);
}
private function whitelistIp($ip) {
$autoban_whitelist = $this
->config('autoban.settings')
->get('autoban_whitelist');
if (!empty($autoban_whitelist)) {
$real_host = gethostbyaddr($ip);
$autoban_whitelist_arr = explode("\n", $autoban_whitelist);
foreach ($autoban_whitelist_arr as $whitelist_ip) {
$whitelist_ip = trim($whitelist_ip);
if (empty($whitelist_ip)) {
continue;
}
if (substr($whitelist_ip, 0, 1) == '#') {
continue;
}
$whitelist_ip_arr = explode('#', $whitelist_ip);
if (count($whitelist_ip_arr) > 1) {
$whitelist_ip = trim($whitelist_ip_arr[0]);
}
$whitelist_ip_arr = explode('/', $whitelist_ip);
if (count($whitelist_ip_arr) > 1) {
$in_list = $this
->cidrMatch($ip, $whitelist_ip_arr[0], (int) $whitelist_ip_arr[1]);
}
else {
$in_list = $whitelist_ip == $ip;
}
if ($in_list) {
return TRUE;
}
if ($real_host) {
$real_host_arr = explode($whitelist_ip, $real_host);
if (count($real_host_arr) == 2 && empty($real_host_arr[1])) {
return TRUE;
}
}
}
}
return FALSE;
}
private function createIpRange($hostname) {
if (!ip2long($hostname)) {
return NULL;
}
$parts = explode('.', $hostname);
if (count($parts) == 4) {
$parts[3] = '0';
$ip_start = implode('.', $parts);
$parts[3] = '255';
$ip_end = implode('.', $parts);
return [
'ip_start' => $ip_start,
'ip_end' => $ip_end,
];
}
return NULL;
}
public function userTypeList($index = NULL) {
$user_types = [
AutobanUtils::AUTOBAN_USER_ANY => $this
->t('Any'),
AutobanUtils::AUTOBAN_USER_ANONYMOUS => $this
->t('Anonymous'),
AutobanUtils::AUTOBAN_USER_AUTHENTICATED => $this
->t('Authenticated'),
];
if ($index === NULL) {
return $user_types;
}
else {
if (!isset($user_types[$index])) {
$index = AutobanUtils::AUTOBAN_USER_ANY;
}
return $user_types[$index];
}
}
public function ruleTypeList($index = NULL) {
$rule_types = [
AutobanUtils::AUTOBAN_RULE_ANY => $this
->t('Any'),
AutobanUtils::AUTOBAN_RULE_MANUAL => $this
->t('Manual'),
AutobanUtils::AUTOBAN_RULE_AUTO => $this
->t('Automatic'),
];
if ($index === NULL) {
return $rule_types;
}
else {
if (!isset($rule_types[$index])) {
$index = AutobanUtils::AUTOBAN_RULE_ANY;
}
return $rule_types[$index];
}
}
}