Un blog mas

Bitácora de vuelo

Apoyándonos en el post anterior como se chequea el sensor de temperatura y humedad DHT22 desde una placa Arduino, decidimos agregarle un poco de complejidad al proyecto e incluir este sensor a nuestro sistema de monitoreo Icinga (ex Nagios), quien sensará la placa mediante el protocolo snmp. Para ello debemos incluir nuevas librerías que nos facilitarán el manejo de este protocolo.

Agentuino

Agentuino es una librería ligera de SNMP que implementa la versión 1 del protocolo. Actualmente la base del desarrollo actual es sincrónico, esto significa que el sistema no ejecutará ningún otro código hasta que procese la solicitud y envíe la respuesta al solicitante. A continuación resaltamos las líneas de mayor relevancia en el proyecto:

    SNMP_PDU pdu;	// Define la clase
 
    const char snmp_temperature[]     PROGMEM     = "1.3.6.1.3.2016.5.1.0";     		// OID Custom definido para Temperatua 
    ...
    void pduReceived()
      ...
      else if ( strcmp_P(oid, snmp_temperature ) == 0 ) {					// Si es el OID que nos interesa
      ...
	} else { 										// viene del if ( pdu.type == SNMP_PDU_SET ) 
	  status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, dtostrf(temperature,6,2,result));	// Retorna el valor temperature casteado de Float
 
 
    void setup(){
      api_status = Agentuino.begin();								// Inicializa el objeto
      if ( api_status == SNMP_API_STAT_SUCCESS ) {
	Agentuino.onPduReceive(pduReceived);							// Llama a pduReceived()
      ...
 
    void loop(){ 
      Agentuino.listen();									// Espera solicitudes de SNMP entrantes
    }

Limitaciones
Las limitaciones de Agentuino están dadas por la cantidad de SRAM disponible.

  • Longitud máxima del Nombre de comunidad (Get / Set): 20 bytes
  • Longitud máxima del identificador de objetos: 64 bytes
  • Longitud máxima del valor: 64 bytes
  • Longitud máxima del paquete: 153 bytes

Requerimientos
Los desarrolladores especifican las siguientes dependencias de software:

  • Ethernet Library 0019 o superior
  • SPI Library 0019 o superior
  • Streaming Library
  • Flash Library
  • MemoryFree Library

Referencias de la librería Agentuino
https://code.google.com/archive/p/agentuino/
https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol
https://github.com/1sw/Agentuino
https://github.com/PaulStoffregen/SPI
https://github.com/geneReeves/ArduinoStreaming
https://github.com/mikalhart/Flash
https://github.com/mpflaga/Arduino-MemoryFree

DHT
Esta librería nos permite realizar de manera sencilla la lectura de los sensores de temepratura y humedad DHT11 y DHT22 sin tener que preocuparnos por el protocolo de comunicación entre el Arduino y los sensores. Las siguientes lineas definen los pasos mas importantes para obtener una lectura del sensor:

    #define DHTPIN 2				// Nro. de pin donde se encuentra conectado el sensor
    #define DHTTYPE DHT22			// Modelo de sensor, puede ser DHT11, DHT21 o DHT22
    DHT dht(DHTPIN, DHTTYPE);			// Definicion del sensor
 
    dht.begin();				// Inicializacion del sensor
 
    float humidity = dht.readHumidity();	// Lectura de humedad
    float temperature = dht.readTemperature();	// Lectura de Temperatura en grados Celsius, con "true" como parametro del metodo readTemperature se obtiene el valor en grados Fahrenheit

Referencias de la librería DHT
http://www.naylampmechatronics.com/blog/40_Tutorial-sensor-de-temperatura-y-humedad-DHT1.html
https://github.com/adafruit/DHT-sensor-library

El código completo

/*************************************************
  Como sensar temperatura y humedad con un 
  Arduino Uno y el sensor DHT22 para enviando 
  los datos por snmp.
  Version: 0.1
  Fecha: 08/02/2018
  Mas informacion: https://pablo.sarubbi.com.ar
**************************************************/
 
 
#include <Ethernet.h>                                          // Libreria para manejo de pila de TCP/IP
#include <SPI.h>                                               // Requerido por Libreria Agentuino
#include <Streaming.h>                                         // Requerido por Libreria Agentuino
#include <Flash.h>                                             // Requerido por Libreria Agentuino
#include <MemoryFree.h>                                        // Requerido por Libreria Agentuino
#include <Agentuino.h>                                         // Libreria que implementa el protocolo SMNPv1 
#include <DHT.h>                                               // Libreria que implementa de manera sencilla la lectura del sensor de temperatura/humedad
 
static byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };    //Mac Address for Arduino Ethernet Shield
static byte ip[] = { 192, 168, 1, 100 };
static byte ip_dns[] = { 192, 168, 1, 1 };
static byte ip_gateway[] = { 192, 168, 1, 1};
static byte subnet[] = { 255, 255, 0, 0 };
 
//Constants
#define DHTPIN 2                                              // Nro. de pin donde se encuentra conectado el sensor
#define DHTTYPE DHT22                                         // Modelo de sensor, puede ser DHT11, DHT21 o DHT22
DHT dht(DHTPIN, DHTTYPE);                                     // Inicializacion del sensor 
 
//Variables
float humidity=0;
float temperature=0;
char result[8];
 
const char sysDescr[] PROGMEM      = "1.3.6.1.2.1.1.1.0";  // System Description
const char sysContact[] PROGMEM    = "1.3.6.1.2.1.1.4.0";  // System Contact
const char sysName[] PROGMEM       = "1.3.6.1.2.1.1.5.0";  // System Name
const char sysLocation[] PROGMEM   = "1.3.6.1.2.1.1.6.0";  // System Location
const char sysServices[] PROGMEM   = "1.3.6.1.2.1.1.7.0";  // System Services
 
//My Custom OIDs
const char snmp_temperature[]     PROGMEM     = "1.3.6.1.3.2016.5.1.0";     // Temperatua en grados Celsius
const char snmp_humidity[]        PROGMEM     = "1.3.6.1.3.2016.5.1.1";     // Humedad porcentual
 
// RFC1213 local values
static char locDescr[]              = "SNMP - Arduino - DHT22";             // read-only (static)
static char locContact[50]          = "Contacto";                           // should be stored/read from EEPROM - read/write (not done for simplicity)
static char locName[20]             = "Nombre";                             // should be stored/read from EEPROM - read/write (not done for simplicity)
static char locLocation[20]         = "BA - Argentina";                     // should be stored/read from EEPROM - read/write (not done for simplicity)
static int32_t locServices          = 2;                                    // read-only (static)
 
uint32_t prevMillis = millis();
char oid[SNMP_MAX_OID_LEN];
SNMP_API_STAT_CODES api_status;
SNMP_ERR_CODES status;
//EthernetServer server(80);
 
void pduReceived()
{
  SNMP_PDU pdu;
  api_status = Agentuino.requestPdu(&pdu);
  //
  if ((pdu.type == SNMP_PDU_GET || pdu.type == SNMP_PDU_GET_NEXT || pdu.type == SNMP_PDU_SET)
    && pdu.error == SNMP_ERR_NO_ERROR && api_status == SNMP_API_STAT_SUCCESS ) {
    //
    pdu.OID.toString(oid);
 
    if ( strcmp_P(oid, sysDescr ) == 0 ) {
      // handle sysDescr (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) {
        // response packet from set-request - object is read-only
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = SNMP_ERR_READ_ONLY;
      } else {
        // response packet from get-request - locDescr
        status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locDescr);
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      } 
    } else if ( strcmp_P(oid, sysName ) == 0 ) {
      // handle sysName (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) {
        // response packet from set-request - object is read/write
        status = pdu.VALUE.decode(locName, strlen(locName)); 
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      } else {
        // response packet from get-request - locName
        status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locName);
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      }
      //
    } else if ( strcmp_P(oid, sysContact ) == 0 ) {
      // handle sysContact (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) {
        // response packet from set-request - object is read/write
        status = pdu.VALUE.decode(locContact, strlen(locContact)); 
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      } else {
        // response packet from get-request - locContact
        status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locContact);
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      }
      //
    } else if ( strcmp_P(oid, sysLocation ) == 0 ) {
      // handle sysLocation (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) {
        // response packet from set-request - object is read/write
        status = pdu.VALUE.decode(locLocation, strlen(locLocation)); 
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      } else {
        // response packet from get-request - locLocation
        status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, locLocation);
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      }
      //
    } else if ( strcmp_P(oid, sysServices) == 0 ) {
      // handle sysServices (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) {
        // response packet from set-request - object is read-only
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = SNMP_ERR_READ_ONLY;
      } else {
        // response packet from get-request - locServices
        status = pdu.VALUE.encode(SNMP_SYNTAX_INT, locServices);
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      }
      //
    }
    else if ( strcmp_P(oid, snmp_temperature ) == 0 ) 
    {
      // handle sysName (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) 
      {      
        // response packet from set-request - object is read-only
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = SNMP_ERR_READ_ONLY;
      } 
      else 
      {
        status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, dtostrf(temperature,6,2,result));
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      }
    } 
        else if ( strcmp_P(oid, snmp_humidity ) == 0 ) 
    {
      // handle sysName (set/get) requests
      if ( pdu.type == SNMP_PDU_SET ) 
      {      
        // response packet from set-request - object is read-only
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = SNMP_ERR_READ_ONLY;
      } 
      else 
      {
        status = pdu.VALUE.encode(SNMP_SYNTAX_OCTETS, dtostrf(humidity,6,2,result));
        pdu.type = SNMP_PDU_RESPONSE;
        pdu.error = status;
      }
    }   
    else {
      // oid does not exist
      // response packet - object not found
      pdu.type = SNMP_PDU_RESPONSE;
      pdu.error = SNMP_ERR_NO_SUCH_NAME;
    }
    Agentuino.responsePdu(&pdu);
  }
 
  Agentuino.freePdu(&pdu);
 
}
 
void setup()
{
  dht.begin();
 
  Ethernet.begin(mac, ip, ip_dns, ip_gateway, subnet);    // Se inicializa Ethernet Shield
  api_status = Agentuino.begin();                         // Begin Snmp agent on Ethernet shield
 
  if ( api_status == SNMP_API_STAT_SUCCESS ) {
    Agentuino.onPduReceive(pduReceived);
    delay(10);
    return;
  }
  delay(10);
}
 
void loop()
{ 
  Agentuino.listen();                                      //Listen/Handle for incoming SNMP requests
  if(millis()-prevMillis>2000){
    humidity = dht.readHumidity();
    temperature = dht.readTemperature();
    prevMillis = millis();
  }
}

El sistema funcionando se puede consultar desde una consola con el comando snmpget

pablo@laptop:~# watch -n 5 snmpget -v 1 -c public 192.168.1.100 1.3.6.1.3.2016.5.1.0
Every 1.0s: snmpget -v 1 -c public 10.10.0.75 1.3.6.1.3.2016.5.1.0           Thu Feb  8 13:40:08 2018
 
iso.3.6.1.3.2016.5.1.0 = STRING: " 28.60"

Configurando Icinga o Nagios
Ene el directorio /etc/nagios-plugins/config/ vamos a crear un nuevo comando llamado check_snmp_temp el cual ejecutará una consulta similar a la que hicimos con el comando snmpget, al que le adicionaremos dos argumentos que serán los valores aceptados para notificaciones por Warning y Error.

# 'snmp_temp' command definition
define command{
        command_name    check_snmp_temp
        command_line    /usr/lib/nagios/plugins/check_snmp -H '$HOSTADDRESS$' -C 'public' -o 1.3.6.1.3.2016.5.1.0 -w$ARG1$ -c$ARG2$ -l temp
}

Una vez definido el comando check_snmp_temp, agregamos un host MonitorDeTemperatura con este servicio de la siguiente manera:

define host{
        use                     generic-host
        host_name               MonitorDeTemperatura
        alias                   MonitorDeTemperatura
        address                 192.168.1.100
        notification_period     24x7
}
 
define service{
        use                     generic-service
        host_name               MonitorDeTemperatura
        notifications_enabled   0
        service_description     Servicio de Temperatura
        check_command           check_snmp_temp!26!30
}

Estos parámetros hacen que el Icinga de un alerta por Warning cuando el monitor de temperatura pase los 26 grados centrígrados, y un aviso de Error cuando se superen los 30 grados centrígrados.

Por ser nuestro primer proyecto con un Arduino, vamos a ser lo mas detallado que podamos, así que empezamos por descargar el IDE de https://www.arduino.cc/en/Main/Software para continuar con los pasos de instalación que no son mas que descomprimir y correr el script ./install.sh . Como último paso debemos agregar nuestro usuario al grupo dialout con “sudo usermod -a -G dialout ” y reiniciar la sesión para que tome los cambios. Este procedimiento agrega la aplicación Arduino IDE en nuestra barra de inicio.

Los principales comandos se ejecutan desde la barra de menú principal, Verificar el código (con el ícono de Tilde) y enviar el programa al Arduino (con el ícono de la flecha). Ambos se pueden observar en la siguiente imagen:

En el menú superior, dentro de Herramientas -> Placa definimos el modelo de Arduino que utilizamos, en nuestro caso el Arduino GenuinoUno

También en el menú superior, dentro de Herramientas -> Puerto se define en donde está conectada la placa, en nuestro caso al /dev/ttyACM0

y por último, otro menú a destacar está en el menú superior, Programa -> Incluir Libreria -> Añadir Libreria .ZIP, desde donde importaremos las librerías que se llaman desde los #include desgargados en formato .zip en su mayoría desde github.

La Placa Arduino Uno

Arduino es una plataforma de electrónica open source facil de usar compuesta por un microcontrolador y una serie de puertos de entrada y salida, y es por ser de código abierto que encontraremos varios formatos, precios y colores basados en este proyecto.

Para dar nuestros primeros pasos el Arduino Uno tiene suficiente cantidad de entradas/salidas y muchas referencias en internet como para descargar código de pruebas.

El sensor

Los DHT11 y DHT22 son sensores digitales de temperatura y humedad que utilizan un termistor para medir la temperatura del aire circundante y un sensor capacitivo para obtener la humedad. Estos datos se transmiten sobre un único pin, el segundo de izquierda a derecha visto de frente. Una desventaja que tiene este componente es la velocidad de lectura, donde se recomienda obtener un dato pasado los 2 segundos sobre la lectura anterior. Para solucionar esta restricción tenemos el siguiente fragmento de nuestro código dentro del loop() del Arduino.

  if(millis()-prevMillis>2000){
    humidity = dht.readHumidity();
    temperature = dht.readTemperature();
    prevMillis = millis();
  }

El sensor DHT11 trabaja con un rango de medición de temperatura de 0 a 50 grados centígrados con una precisión de +/-2.0 y un rango de humedad de 20% a 90%RH con precisión de 4%. El sensor DHT22 tiene un rango de medición de temperatura de -40 a 80 grados centígrados y un rango de humedad de 0 a 100%RH con precisión de 2%RH.

El conexionado

El valor de la resistencia puede estar entre 4k7 y 10k ohms

Comparativa entre sensores DHT11 y DHT22
http://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_dht22_dht11_sht71.html

Este proyecto involucra manejo del protocolos de red y obviamente procesos de lecturas sobre el sensor de humedad y temperatura. Para ello vamos a necesitar incluir algunas librerías.

Ethernet

La librería Ethernet es la usada para manejar el Ethernet Shield que implementa la pila de protocolos TCP/IP y dentro de Arduino se implementan los protocolos en la capa de aplicación.

Para manejar el Ethernet Shield deberemos conocer todos los métodos que nos ofrece la librería Ethernet y así poder usarla.

Referencias de librería Ethernet:
http://arduino.cc/en/Reference/Ethernet
https://aprendiendoarduino.wordpress.com/2016/07/05/libreria-ethernet/

Ethernet.begin(mac, ip, ip_dns, ip_gateway, subnet) // Inicializa la librería Ethernet (Constructor)

DHT
Esta librería nos permite realizar de manera sencilla la lectura de los sensores de temepratura y humedad DHT11 y DHT22 sin tener que preocuparnos por el protocolo de comunicación entre el Arduino y los sensores. Las siguientes lineas definen los pasos mas importantes para obtener una lectura del sensor:

    #define DHTPIN 2				// Nro. de pin donde se encuentra conectado el sensor
    #define DHTTYPE DHT22			// Modelo de sensor, puede ser DHT11, DHT21 o DHT22
    DHT dht(DHTPIN, DHTTYPE);			// Definicion del sensor
 
    dht.begin();				// Inicializacion del sensor
 
    float humidity = dht.readHumidity();	// Lectura de humedad
    float temperature = dht.readTemperature();	// Lectura de Temperatura en grados Celsius, con "true" como parametro del metodo readTemperature se obtiene el valor en grados Fahrenheit

Referencias de la librería DHT
http://www.naylampmechatronics.com/blog/40_Tutorial-sensor-de-temperatura-y-humedad-DHT1.html
https://github.com/adafruit/DHT-sensor-library

El código completo

/*************************************************
  Como sensar temperatura y humedad con un 
  Arduino Uno y el sensor DHT22 para visualizar
  los datos por la web.
  Version: 0.1
  Fecha: 08/02/2018
  Mas informacion: https://pablo.sarubbi.com.ar
**************************************************/
 
#include <Ethernet.h>                                          // Libreria para manejo de pila de TCP/IP
#include <DHT.h>                                               // Libreria que implementa de manera sencilla la lectura del sensor de temperatura/humedad
 
static byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };    //Mac Address for Arduino Ethernet Shield
static byte ip[] = { 192, 168, 1, 100 };
static byte ip_dns[] = { 192, 168, 1, 1 };
static byte ip_gateway[] = { 192, 168, 1, 1};
static byte subnet[] = { 255, 255, 0, 0 };
 
//Constants
#define DHTPIN 2                                              // Nro. de pin donde se encuentra conectado el sensor
#define DHTTYPE DHT22                                         // Modelo de sensor, puede ser DHT11, DHT21 o DHT22
DHT dht(DHTPIN, DHTTYPE);                                     // Inicializacion del sensor 
 
//Variables
float humidity=0;
float temperature=0;
uint32_t prevMillis = millis();
 
EthernetServer server(80);
 
void setup()
{
  dht.begin();
  Ethernet.begin(mac, ip, ip_dns, ip_gateway, subnet);    // Se inicializa Ethernet Shield
  server.begin();                                         // Se inicializa el WebServer
}
 
void loop()
{ 
 
  if(millis()-prevMillis>2000){
    humidity = dht.readHumidity();
    temperature = dht.readTemperature();
    prevMillis = millis();
  }
 
  // Servicio Web para lectura online de Temperatura y Humedad
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println("Refresh: 5"); // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<head>");
          client.println("\t<title>Arduino Uno + DHT22</title>");
          client.println("</head>");
          client.println("<body>");
          client.print("\t<b>Temperatura:</b> "); client.println(temperature);
          client.print("\t<br /><b>Humedad:</b> "); client.println(humidity);
          client.println("</body>");
          client.print("</html>");
          break;
      }
    }
  }
  delay(1);
  client.stop(); 
}

Accediendo desde un browser a http://192.168.1.100 podemos ver las lecturas como se muestra en la siguiente captura

Fail2ban es una herramienta que monitorea los logs y se activa (ejecutando una acción) cuando detecta un patrón sospechoso previamente definido (filtro).

Para instalar Fail2ban y sus dependencias en Ubuntu solo debemos ejecutar en una terminal el siguiente comando:

sudo apt-get install fail2ban

El archivo de configuraci&ocaute;n principal está es /etc/fail2ban/jail.conf y contiene de conjunción de los patrones a buscar y acciones a ejecutar por cada servicio monitoreado. Un ejemplo que viene configurado por default en el archivo es la sección [ssh] donde podemos ver habilitado el filtro sshd que buscará sobre el archivo log /var/log/auth.log la cantidad de maxretry definidas (en este caso 6).

[ssh]
 
enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 6

La entrada “filter = sshd” está definida en el archivo /etc/fail2ban/filter.d/sshd que básicamente se compone por una expresión regular que tratará de encajar sobre el log pasado como parámetro.

Debemos reiniciar el servicio para que los cambios tengan efecto:

sudo service fail2ban restart

Pero esta regla solo generará una entrada en el log /var/log/fail2ban.log con el siguiente aviso.

2018-01-24 12:30:59,401 fail2ban.actions: WARNING [ssh] Ban 10.10.10.10

Si queremos ir un paso adelante, podemos construir reglas reactivas que bloqueen la IP del host que está intentando conectarse a nuestro server. Para ello vamos a modificar un poco la sección [ssh-iptables-ipset4] en primer lugar habilitando dicha regla, luego apuntando el logpath al archivo correcto y para finalizar definiendo una acción a ejecutar la cual bloqueará la IP en cuestión mediante el comando definido en iptables-ipset-proto4.

[ssh-iptables-ipset4]
 
enabled  = true
port     = ssh
filter   = sshd
banaction = iptables-ipset-proto4
logpath  = /var/log/auth.log
maxretry = 6

Donde ahora tenemos establecido el parámetro banaction que se define en el archivo /etc/fail2ban/action.d/iptables-ipset-proto4.conf que modifica las reglas de nuestro firewall mediante iptables y ipset*

* Si no tenemos ipset instalado, ejecutar sudo apt-get install ipset

Si ahora intentamos un acceso desde nuestro HOST de prueba 10.10.10.10 no solo veremos en el log de fail2ban la siguiente linea:

2018-01-24 12:39:33,325 fail2ban.actions: WARNING [ssh-iptables-ipset4] Ban 10.10.10.10

sino que además en las reglas de iptables tendremos una entrada como la siguiente:

REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22 match-set fail2ban-ssh-iptables-ipset4 src reject-with icmp-port-unreachable

donde el set de IPs a bloquear ahora incluye la 10.10.10.10

# ipset list fail2ban-ssh-iptables-ipset4
Name: fail2ban-ssh-iptables-ipset4
Type: hash:ip
Revision: 2
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16520
References: 1
Members:
10.10.10.10

Podemos verificar el funcionamiento de las reglas de firewall intentando conectarnos nuevamente.

# ssh pablo@10.10.10.1
ssh: connect to host 10.10.10.1 port 22: Connection refused

Las secciones en el archivo /etc/fail2ban/jail.conf otros parámetros que se pueden definir.

bantime = 600 # Tiempo de baneado en segundos.
destemail = usuario@ejemplo.com # Destinatario de correo para aviso de visitante bloqueado

Probar una regla
Existe una forma sencilla de probar las expresiones regulares de nuevas reglas sobre un archivo log para verificar si aplica como nosotros queremos, sin que este afecte al sistema.

# fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf 
 
Running tests
=============
 
Use   failregex file : /etc/fail2ban/filter.d/sshd.conf
Use         log file : /var/log/auth.log
 
 
Results
=======
 
Failregex: 13 total
|-  #) [# of hits] regular expression
|   3) [11] ^\s*(<[^.]+\.[^.]+>)?\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:?)?\s(?:\[ID \d+ \S+\])?\s*Failed \S+ for .*? from <HOST>(?: port \d*)?(?: ssh\d*)?(: (ruser .*|(\S+ ID \S+ \(serial \d+\) CA )?\S+ (?:[\da-f]{2}:){15}[\da-f]{2}(, client user ".*", client host ".*")?))?\s*$
|   5) [2] ^\s*(<[^.]+\.[^.]+>)?\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:?)?\s(?:\[ID \d+ \S+\])?\s*[iI](?:llegal|nvalid) user .* from <HOST>\s*$
`-
 
Ignoreregex: 0 total
 
Date template hits:
|- [# of hits] date format
|  [888] MONTH Day Hour:Minute:Second
`-
 
Lines: 888 lines, 0 ignored, 13 matched, 875 missed
Missed line(s):: too many to print.  Use --print-all-missed to print all 875 lines

Algunos filtros mas

en /etc/fail2ban/filter.d/

# Fail2Ban configuration file qmail-auth.conf
# Author: Efra - Pablo
# Version 0.1
#
# 2018-01-24T10:02:17.562375-03:00 vps smtp_auth: smtp_auth: FAILED: support - password incorrect from (null)@walkerj2351.example.com [91.200.12.197]
[Definition]
failregex = (.* smtp_auth: FAILED: .* password incorrect from .*) \[<HOST>\]
ignoreregex =

en /etc/fail2ban/jail.conf

[qmail-auth]
enabled = true
filter  = qmail-auth
action  = iptables-allports[name=qmail-auth]
logpath  = /usr/local/psa/var/log/maillog

en /etc/fail2ban/filter.d/

# Fail2Ban configuration file wordpress-login.conf
# Author: Efra - Pablo
# Version 0.1
# Bloquea accesos al administrador de WP
#
# 91.200.12.49 - - [26/Apr/2017:11:42:02 -0300] "POST /wp-login.php HTTP/1.1" 200 3157 "https://pablo.sarubbi.com.ar/wp-login.php" "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; 125LA; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)"
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*\/wp-login.php HTTP\/.*$
ignoreregex =

en /etc/fail2ban/jail.conf

[wordpress-login]
enabled  = true
filter   = wordpress-login
action   = iptables-multiport[name=wordpressLogin, port="http,https"]
logpath  = /var/www/vhosts/*/statistics/logs/access_log
bantime  = 172800
maxretry = 5
findtime = 60

en /etc/fail2ban/filter.d/

# Fail2Ban configuration file wordpress-uploads.conf 
# Author: Efra - Pablo
# Version 0.1
# Bloquea accesos a archivos .php en directorio uploads de WP
# 98.130.0.199 - - [25/Apr/2017:07:25:14 -0300] "POST /wp-content/uploads/2011/09/footer92.php HTTP/1.0" 200 255 "https://pablo.sarubbi.com.ar/wp-content/uploads/2011/09/footer92.php" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36"
[Definition]
failregex = ^<HOST> -.*"(GET|POST).*\/uploads\/.*\.php HTTP\/.*$
ignoreregex =

en /etc/fail2ban/jail.conf

[wordpress-uploads]
enabled  = true
filter   = wordpress-uploads
action   = iptables-multiport[name=wordpressUploads, port="http,https"]
logpath  = /var/www/vhosts/*/statistics/logs/access_log
bantime  = 172800
maxretry = 1

en /etc/fail2ban/filter.d/

# Fail2Ban configuration file  horde-login.conf 
# Author: Efra - Pablo
# Version 0.1
# Bloquea accesos al webmail Horde
# Jan 24 14:34:31 HORDE [error] [imp] FAILED LOGIN for zaraza@sarubbi.com.ar [139.162.9.175] to {localhost:143 [imap/notls]} [pid 21241 on line 139 of "/usr/share/psa-horde/imp/lib/Auth/imp.php"]
[Definition]
failregex = (.* FAILED LOGIN for .*) \[<HOST>\] to .*$
ignoreregex =

en /etc/fail2ban/jail.conf

[horde-login]
enabled  = true
filter   = horde-login
action   = iptables-multiport[name=horde-login, port="http,https"]
logpath  = /var/log/psa-horde/psa-horde.log
bantime  = 7200
maxretry = 5
findtime = 1200

Certbot es una herramienta para administrar certificados de manera automatizada desarrollado por la EFF (Electronic Frontier Foundation) como cliente oficial de la CA de Let’s Encrypt. La instalación en Ubuntu es muy sencilla:

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-apache

Generar el certificado

$ sudo certbot certonly --manual -d pablo.sarubbi.com.ar

Con el parámetro -d se pueden agregar mas dominios separados por espacios.
El sistema nos advierte que va intentar leer archivo con el siguiente nombre y contenido para validar nuestra propiedad.

-------------------------------------------------------------------------------
Create a file containing just this data:
 
NHhlywEu46fGY0YLEAIiFFeeNNEQfS0pwJbiUkjqM-E.8Ep8-mh5ETXinamOr3Z3pd6qmlRiLklJy-lpP4Q64SI
 
And make it available on your web server at this URL:
 
http://pablo.sarubbi.com.ar/.well-known/acme-challenge/NHhlywEu46fGY0YLEAIiFFeeNNEQfS0pwJbiUkjqM-E
 
-------------------------------------------------------------------------------
Press Enter to Continue

Durante este proceso debemos crear el archivo con el nombre, ubicación y contenido exacto que nos define, y luego continuar con el proceso para que verifique su existencia. Hay que estar atentos porque el último paso comprueba directamente las URLs y si no fueron creadas, tendremos que ejecutar nuevamente el procedimiento.

$ sudo mkdir -p .well-known/acme-challenge/
$ sudo echo NHhlywEu46fGY0YLEAIiFFeeNNEQfS0pwJbiUkjqM-E.8Ep8-mh5ETXinamOr3Z3pd6qmlRiLklJy-lpP4Q64SI > .well-known/acme-challenge/JNHhlywEu46fGY0YLEAIiFFeeNNEQfS0pwJbiUkjqM-E
-------------------------------------------------------------------------------
Press Enter to Continue
Waiting for verification...
Cleaning up challenges
 
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/sarubbi.com.ar/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/sarubbi.com.ar/privkey.pem
   Your cert will expire on 2018-01-28. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:
 
   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
-------------------------------------------------------------------------------

Como bien dice el log, se generaron 3 archivos con el certificado, la clave privada y el CA con caducidad de seis meses. Resta apuntar correctamente el archivo de configuración del Apache a los que generamos recientemente:

<VirtualHost *:443>
 
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/sarubbi.com.ar/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/sarubbi.com.ar/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/sarubbi.com.ar/chain.pem
$ sudo service apache2 restart

Modificando el WordPress

Antes que nada debemos exportar la BBDD para reapuntar todos los links internos a la nueva URL con el https delante. Lo mas conveniente es trabajar sobre una BBDD nueva, en este caso la crearemos con el nombre wp_saru_seg y los mismos permisos de acceso. Generamos un backup de la base original y reemplazamos todas las URLs no seguras por el nuevo dominio con https. Importamos nuevamente el archivo sobre la base wp_saru_seg a la cual apuntaremos el WordPress en un paso futuro.

mysqldump --skip-dump-date -uadmin -p wp_saru > bkp_saru.sql
sed -i -e 's/http:\/\/pablo.sarubbi.com.ar/https:\/\/pablo..com.ar/g' bkp_saru.sql 
mysql -uadmin -p wp_saru_seg < wp_saru.sql

Copiamos todos los archivos manteniendo los permisos y solo para estar seguros, verificamos que no haya quedado ninguna URL apuntando al sitio viejo.

cp -a /var/www/httpdocs/* /var/www/httpsdocs/
find /var/www/httpsdocs/ -type f -name "*.php" | xargs grep http://pablo.sarubbi.com.ar

Cambiamos el archivo de configuración para que apunte a la nueva BBDD y si todo anda bien podemos eliminar el sitio no seguro y la base de datos original.

$ rm -R /var/www/httpdocs/*
$ sed -i -e 's/wp_saru/wp_saru_seg/g' /var/www/httpsdocs/wp-config.php

Nos resta redirigir el trafico a las URLs que teniamos antes para que tengan como destino el sitio seguro. Esto lo hacemos mediante un Redirect en el .htaccess

echo "Redirect 301 / https://pablo.sarubbi.com.ar/" > /var/www/httpdocs/.htaccess

Con un poco de suerte y muy poco tiempo tenés configurado tu WordPress en un dominio con SSL y disponible por https://, en tu servidor Linux.

Gracias al aporte de Paulino Calderon (@calderpwn) tenemos disponible desde hace unas horas un script para sumar a nuestra colección en nmap que nos permite con un solo comando escanear la red y descubrir aquellos equipos que podrían ser afectados por el último ransomware WannaCry.

Lo que hace este script es conectarse al $IPC y ejecutar una transacción sobre FID 0 para verificar el error “STATUS_INSUFF_SERVER_RESOURCES” y así determinar si el equipo fue parcheado o no contra MS17-010.

El único requerimiento (además de un nmap actualizado) es descargar el script de github y copiarlo al directorio /scripts

wget https://raw.githubusercontent.com/cldrn/nmap-nse-scripts/master/scripts/smb-vuln-ms17-010.nse
mv smb-vuln-ms17-010.nse /opt/nmap-7.40/scripts/
sudo ./nmap -sC -p445 --open --max-hostgroup 3 --script smb-vuln-ms17-010.nse 192.168.1.0/24

Un ejemplo de equipo vulnerable retornaría algo similar a:

Nmap scan report for 192.168.1.2
Host is up (0.00079s latency).
PORT    STATE SERVICE
445/tcp open  microsoft-ds
 
Host script results:
| smb-vuln-ms17-010: 
|   VULNERABLE:
|   Remote Code Execution vulnerability in Microsoft SMBv1 servers (ms17-010)
|     State: VULNERABLE
|     IDs:  CVE:CVE-2017-0143
|     Risk factor: HIGH
|       A critical remote code execution vulnerability exists in Microsoft SMBv1
|        servers (ms17-010).
|       
|     Disclosure date: 2017-03-14
|     References:
|       https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-0143
|       https://blogs.technet.microsoft.com/msrc/2017/05/12/customer-guidance-for-wannacrypt-attacks/
|_      https://technet.microsoft.com/en-us/library/security/ms17-010.aspx

Para solucionar esta vulnerabilidad debemos aplicar los parches que tan gentilmente nos ofrece Microsoft tanto para los sistemas mantenidos como para los XP y 2003.

Para Windows XP y 2003 descargar y aplicar los siguientes parches de seguridad (requiere reinicio)
https://blogs.technet.microsoft.com/msrc/2017/05/12/customer-guidance-for-wannacrypt-attacks/?utm_content=buffer8d9ab&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer

Para las versiones actuales de Windows descargar y aplicar los siguientes parches de seguridad (requiere reinicio)
https://technet.microsoft.com/en-us/library/security/ms17-010.aspx

Actualización:
Si cuando ejecutamos el escaneo obtenemos como respuesta es un error similar al siguiente:

NSE: smb-vuln-ms17-010 against 192.168.1.2 threw an error!
/usr/bin/../share/nmap/scripts/smb-vuln-ms17-010.nse:85: variable 'debug1' is not declared
stack traceback:
        [C]: in function 'error'
        /usr/bin/../share/nmap/nselib/strict.lua:80: in function '__index'
        /usr/bin/../share/nmap/scripts/smb-vuln-ms17-010.nse:85: in function 'check_ms17010'
        /usr/bin/../share/nmap/scripts/smb-vuln-ms17-010.nse:160: in function </usr/bin/../share/nmap/sc...

Es probable que necesitemos actualizar el nmap, tarea relativamente sencilla siguiendo estos pasos:

wget https://nmap.org/dist/nmap-7.40.tar.bz2
bzip2 -cd nmap-7.40.tar.bz2 | tar xvf -
cd nmap-7.40
./configure
make
sudo make install
Stop SOPA