You are here

class AutobanController in Automatic IP ban (Autoban) 8

Provides an Autoban functional.

Hierarchy

Expanded class hierarchy of AutobanController

7 files declare their use of AutobanController
AutobanAnalyzeForm.php in src/Form/AutobanAnalyzeForm.php
AutobanBanForm.php in src/Form/AutobanBanForm.php
AutobanDbLogController.php in modules/autoban_dblog/src/Controller/AutobanDbLogController.php
Contains \Drupal\autoban_dblog\Controller\AutobanDbLogController.php .
AutobanDeleteAllForm.php in src/Form/AutobanDeleteAllForm.php
AutobanFormBase.php in src/Form/AutobanFormBase.php
Class AutobanFormBase.

... See full list

1 string reference to 'AutobanController'
autoban.services.yml in ./autoban.services.yml
autoban.services.yml
1 service uses AutobanController
autoban in ./autoban.services.yml
Drupal\autoban\Controller\AutobanController

File

src/Controller/AutobanController.php, line 16

Namespace

Drupal\autoban\Controller
View source
class AutobanController extends ControllerBase {

  /**
   * Retrieve IP addresses for autoban rule.
   *
   * @param string $rule
   *   Autoban rule ID.
   * @param array $params
   *   Params (type, message) for special query.
   *
   * @return array
   *   IP addresses as query result.
   */
  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();

    // Checking for multiple messages divided by separator.
    $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:

          // Anonymous.
          $query
            ->condition('log.uid', 0);
          break;
        case AutobanUtils::AUTOBAN_USER_AUTHENTICATED:

          // 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;
  }

  /**
   * Get IP Ban Manager data from provider name.
   *
   * @param string $provider
   *   Ban provider ID.
   *
   * @return array
   *   Ban manager object, ban_name, ban_type.
   */
  public function getBanManagerData($provider) {

    // Retrieve Ban provider data for the current provider.
    $banProvider = $this
      ->getBanProvidersList($provider);
    if ($banProvider) {

      // Get Ban Manager object from AutobanProviderInterface implementation.
      $service = $banProvider['service'];
      if ($service) {
        $connection = Database::getConnection();

        // Return Ban Provider's Ban IP Manager and Ban Type.
        return [
          'ban_manager' => $service
            ->getBanIpManager($connection),
          'ban_name' => $service
            ->getName(),
          'ban_type' => $service
            ->getBanType(),
        ];
      }
    }
    return NULL;
  }

  /**
   * Get IP Ban Manager data from autoban rule.
   *
   * @param string $rule
   *   Autoban rule ID.
   *
   * @return array
   *   Ban manager object and ban_type.
   */
  public function getBanManagerDataRule($rule) {
    $entity = Autoban::load($rule);
    return $this
      ->getBanManagerData($entity->provider);
  }

  /**
   * Get Ban providers list.
   *
   * @param string $provider_id
   *   Ban provider ID.
   *
   * @return array
   *   List ban providers or provider's data.
   */
  public function getBanProvidersList($provider_id = NULL) {
    $banProvidersList = [];
    $container = \Drupal::getContainer();
    $kernel = $container
      ->get('kernel');

    // Get all services list.
    $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);

        // Filter for services with ban_provider.
        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;
    }
  }

  /**
   * Direct ban controller.
   *
   * @param string $ips
   *   IP addresses (comma delimited).
   * @param string $provider
   *   Ban provider name.
   *
   * @return bool
   *   IP banned status.
   */
  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());
    }
  }

  /**
   * Ban address.
   *
   * @param string $ip
   *   IP address.
   * @param array $banManagerData
   *   Ban manager data.
   * @param bool $debug
   *   Show debug message.
   *
   * @return bool
   *   IP banned status.
   */
  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)) {

          // If cannot create IP range banned single IP.
          $banManager
            ->banIp($ip);
        }
        else {
          $banManager
            ->banIp($ip_range['ip_start'], $ip_range['ip_end']);
        }
        break;
    }
    return TRUE;
  }

  /**
   * Ban addresses.
   *
   * @param array $ip_list
   *   IP addresses list.
   * @param string $rule
   *   Autoban rule ID.
   *
   * @return int
   *   IP banned count.
   */
  public function banIpList(array $ip_list, $rule) {
    $count = 0;
    if (!empty($ip_list) && $rule) {

      // Retrieve Ban manager object for current 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;
  }

  /**
   * Check IP address for ban.
   *
   * @param string $ip
   *   IP candidate for ban.
   *
   * @return bool
   *   Can ban.
   */
  public function canIpBan($ip) {

    // You cannot ban your current IP address.
    if ($ip == \Drupal::request()
      ->getClientIp()) {
      return FALSE;
    }

    // The IP address must not be whitelisted.
    if ($this
      ->whitelistIp($ip)) {
      return FALSE;
    }
    return TRUE;
  }

  /**
   * Is IP address in subnet?
   *
   * @param string $ip
   *   IP address for match check.
   * @param string $network
   *   IP subnet.
   * @param string $cidr
   *   CIDR.
   *
   * @return bool
   *   IP mathes for subnet.
   */
  private function cidrMatch($ip, $network, $cidr) {
    return (ip2long($ip) & ~((1 << 32 - $cidr) - 1)) == ip2long($network);
  }

  /**
   * Is IP address in whitelist?
   *
   * @param string $ip
   *   IP address for check.
   *
   * @return bool
   *   IP address in whitelist.
   */
  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;
        }

        // Block comment.
        if (substr($whitelist_ip, 0, 1) == '#') {
          continue;
        }

        // Inline comment.
        $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);

        // CIDR match.
        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;
        }

        // Check for domain.
        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;
  }

  /**
   * Create IP range from single IP.
   *
   * @param string $hostname
   *   IP address for ban.
   *
   * @return array
   *   IP range string for insert to ban table.
   */
  private function createIpRange($hostname) {

    // Make range IP from aaa.bbb.ccc.ddd to aaa.bbb.ccc.0 - aaa.bbb.ccc.255 .
    if (!ip2long($hostname)) {

      // Only IPV4 is available for IP range.
      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;
  }

  /**
   * Get user type names list.
   *
   * @param int $index
   *   User type index (optional).
   *
   * @return string|array
   *   User type name or user type names list.
   */
  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];
    }
  }

  /**
   * Get rule type names list.
   *
   * @param int $index
   *   Rule type index (optional).
   *
   * @return string|array
   *   User rule name or rule type names list.
   */
  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];
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AutobanController::banIp public function Ban address.
AutobanController::banIpAction public function Direct ban controller.
AutobanController::banIpList public function Ban addresses.
AutobanController::canIpBan public function Check IP address for ban.
AutobanController::cidrMatch private function Is IP address in subnet?
AutobanController::createIpRange private function Create IP range from single IP.
AutobanController::getBanManagerData public function Get IP Ban Manager data from provider name.
AutobanController::getBanManagerDataRule public function Get IP Ban Manager data from autoban rule.
AutobanController::getBannedIp public function Retrieve IP addresses for autoban rule.
AutobanController::getBanProvidersList public function Get Ban providers list.
AutobanController::ruleTypeList public function Get rule type names list.
AutobanController::userTypeList public function Get user type names list.
AutobanController::whitelistIp private function Is IP address in whitelist?
ControllerBase::$configFactory protected property The configuration factory.
ControllerBase::$currentUser protected property The current user service. 1
ControllerBase::$entityFormBuilder protected property The entity form builder.
ControllerBase::$entityManager protected property The entity manager.
ControllerBase::$entityTypeManager protected property The entity type manager.
ControllerBase::$formBuilder protected property The form builder. 2
ControllerBase::$keyValue protected property The key-value storage. 1
ControllerBase::$languageManager protected property The language manager. 1
ControllerBase::$moduleHandler protected property The module handler. 2
ControllerBase::$stateService protected property The state service.
ControllerBase::cache protected function Returns the requested cache bin.
ControllerBase::config protected function Retrieves a configuration object.
ControllerBase::container private function Returns the service container.
ControllerBase::create public static function Instantiates a new instance of this class. Overrides ContainerInjectionInterface::create 40
ControllerBase::currentUser protected function Returns the current user. 1
ControllerBase::entityFormBuilder protected function Retrieves the entity form builder.
ControllerBase::entityManager Deprecated protected function Retrieves the entity manager service.
ControllerBase::entityTypeManager protected function Retrieves the entity type manager.
ControllerBase::formBuilder protected function Returns the form builder service. 2
ControllerBase::keyValue protected function Returns a key/value storage collection. 1
ControllerBase::languageManager protected function Returns the language manager service. 1
ControllerBase::moduleHandler protected function Returns the module handler. 2
ControllerBase::redirect protected function Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait::redirect
ControllerBase::state protected function Returns the state storage service.
LinkGeneratorTrait::$linkGenerator protected property The link generator. 1
LinkGeneratorTrait::getLinkGenerator Deprecated protected function Returns the link generator.
LinkGeneratorTrait::l Deprecated protected function Renders a link to a route given a route name and its parameters.
LinkGeneratorTrait::setLinkGenerator Deprecated public function Sets the link generator service.
LoggerChannelTrait::$loggerFactory protected property The logger channel factory service.
LoggerChannelTrait::getLogger protected function Gets the logger for a specific channel.
LoggerChannelTrait::setLoggerFactory public function Injects the logger channel factory.
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
RedirectDestinationTrait::$redirectDestination protected property The redirect destination service. 1
RedirectDestinationTrait::getDestinationArray protected function Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url.
RedirectDestinationTrait::getRedirectDestination protected function Returns the redirect destination service.
RedirectDestinationTrait::setRedirectDestination public function Sets the redirect destination service.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
UrlGeneratorTrait::$urlGenerator protected property The url generator.
UrlGeneratorTrait::getUrlGenerator Deprecated protected function Returns the URL generator service.
UrlGeneratorTrait::setUrlGenerator Deprecated public function Sets the URL generator service.
UrlGeneratorTrait::url Deprecated protected function Generates a URL or path for a specific route based on the given parameters.