You are here

fail2ban.module in Fail2ban Firewall Integration 7

Same filename and directory in other branches
  1. 6 fail2ban.module
  2. 7.2 fail2ban.module

File

fail2ban.module
View source
<?php

/**
 * @file
 */

/**
 * Implementation of hook_permission()
 */
function fail2ban_permission() {
  return array(
    'administer fail2ban' => array(
      'title' => t('Administer Fail2Ban'),
      'description' => t('Configure fail2ban module settings.'),
    ),
    'submit addresses to fail2ban' => array(
      'title' => t('Submit Addresses'),
      'description' => t('Submit IP addresses to the fail2ban firewall utility.'),
      'restrict access' => TRUE,
    ),
  );
}

/**
 * Implementation of hook_menu()
 */
function fail2ban_menu() {
  $items['admin/config/people/fail2ban'] = array(
    'title' => 'Fail2ban',
    'description' => 'Fail2ban is a system utility that allows you to automatically add firewall entries.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'fail2ban_admin_settings',
    ),
    'access arguments' => array(
      'administer fail2ban',
    ),
    'file' => 'fail2ban.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_form_FORMID_alter().
 *
 * @see fail2ban_comment_admin_overview_submit()
 */
function fail2ban_form_comment_admin_overview_alter(&$form, $form_state) {
  if (user_access('submit addresses to fail2ban')) {
    module_load_include('inc', 'fail2ban', 'fail2ban.admin');

    // Add copies of the existing options, with the firewall options appended.
    $form['options']['fail2ban'] = array(
      '#type' => 'checkbox',
      '#prefix' => '<br />',
      '#title' => 'Firewall originating IP address',
    );
    $form['#submit'][] = 'fail2ban_comment_admin_overview_submit';
  }
}

/**
 * Form submit handler to mass-report and unpublish or delete comments.
 */
function fail2ban_comment_admin_overview_submit($form, &$form_state) {
  if ($form_state['values']['fail2ban'] == 1) {

    // The mollom module prefixes the operation name with its own guff.
    // Cope with it.
    if (strpos($form_state['values']['operation'], '-' > 0)) {
      list($id, $operation) = explode('-', $form_state['values']['operation']);
    }
    else {
      $operation = $form_state['values']['operation'];
    }
    foreach ($form_state['values']['comments'] as $cid => $value) {
      if ($value) {
        if ($comment = comment_load($cid)) {
          if ($operation == 'unpublish' || $operation == 'delete') {
            fail2ban_syslog($comment->hostname);
          }
        }
      }
    }
  }
}

/**
 * The function that does the actual work, writing a log message.
 *
 * @param $address
 *   String - An IP address or net/mask.
 */
function fail2ban_syslog($address) {
  if (empty($address) || !is_string($address)) {
    return;
  }

  // Check if the address is in the whitelist. If so, just return.
  if (fail2ban_whitelist($address)) {
    drupal_set_message(t('The address !address is !whitelisted and will not be submitted to the firewall', array(
      '!address' => $address,
      '!whitelisted' => l('whitelisted', 'admin/settings/fail2ban'),
    )));
    return;
  }

  // Load all settings.
  $settings = variable_get('fail2ban', fail2ban_defaults());

  // Turn on all the right log options.
  //
  $options = 0;
  foreach ($settings['logopt']['options'] as $option) {
    $options = $options | $option;
  }

  // Get the priority.
  //
  $priority = 0;
  foreach ($settings['logopt']['priority'] as $option) {
    $priority = $priority | $option;
  }

  // Get the log string and replace the placeholder.
  //
  $message = strtr($settings['logstring'], array(
    '!address' => $address,
  ));

  // Open the log stream.
  //
  if (openlog($settings['identifier'], $options, $settings['logopt']['facility']) == FALSE) {
    watchdog('fail2ban', 'Unable to connect to the syslog daemon', NULL, WATCHDOG_ERROR);
    drupal_set_message(t('Unable to connect to the syslog daemon'), 'error');
    return;
  }
  if (syslog($priority, $message) == FALSE) {
    watchdog('fail2ban', 'Cannot write message to the syslog daemon', NULL, WATCHDOG_ERROR);
    drupal_set_message(t('Cannot write message to the syslog daemon'), 'error');
  }
  else {
    drupal_set_message(t('The address !address has been submitted to the firewall', array(
      '!address' => $address,
    )));
  }
  if (closelog() == FALSE) {
    watchdog('fail2ban', 'Cannot close connection to the syslog daemon', NULL, WATCHDOG_ERROR);
  }
}

/**
 * Check if a given address is whitelisted.
 *
 * Shamelessly copied from http://php.net/manual/en/function.ip2long.php
 */
function fail2ban_whitelist($address) {
  $client_ip = ip2long($address);

  // Return true if this is not a valid IP.
  //
  if ($client_ip === FALSE) {
    return TRUE;
  }

  // Load and split the list.
  //
  $settings = variable_get('fail2ban', fail2ban_defaults());
  $list = preg_split("/[\\s,]+/", $settings['whitelist'] . "\n" . ip_address());

  // Iterate.
  //
  foreach ($list as $entry) {
    $network = preg_split("/\\//", trim($entry));

    // Check if we're dealing with a single address.
    //
    if (count($network) == 1 || empty($network[1])) {
      if ($address == $network[0]) {
        return TRUE;
      }
    }
    else {
      if (fail2ban_ip_in_network($address, $network[0], $network[1]) == TRUE) {
        return TRUE;
      }
    }
  }
  return FALSE;
}

/**
 * Check if a given address exists on a network.
 *
 * Shamelessly copied from http://php.net/manual/en/function.ip2long.php
 */
function fail2ban_ip_in_network($ip, $net_addr, $net_mask) {
  if ($net_mask <= 0) {
    return FALSE;
  }
  $ip_binary_string = sprintf("%032b", ip2long($ip));
  $net_binary_string = sprintf("%032b", ip2long($net_addr));
  return substr_compare($ip_binary_string, $net_binary_string, 0, $net_mask) === 0;
}

/**
 * Assemble an array of default settings.
 */
function fail2ban_defaults() {
  return array(
    'logstring' => 'Submitting address [!address] to the firewall',
    'whitelist' => "127.0.0.0/8\n" . ip_address(),
    'logopt' => array(
      'identifier' => 'drupal',
      'options' => array(
        LOG_ODELAY,
      ),
      'facility' => LOG_USER,
      'priority' => array(
        LOG_NOTICE,
      ),
    ),
  );
}

Functions

Namesort descending Description
fail2ban_comment_admin_overview_submit Form submit handler to mass-report and unpublish or delete comments.
fail2ban_defaults Assemble an array of default settings.
fail2ban_form_comment_admin_overview_alter Implements hook_form_FORMID_alter().
fail2ban_ip_in_network Check if a given address exists on a network.
fail2ban_menu Implementation of hook_menu()
fail2ban_permission Implementation of hook_permission()
fail2ban_syslog The function that does the actual work, writing a log message.
fail2ban_whitelist Check if a given address is whitelisted.