Libertonia
Portada · Todo · Software Libre · Desarrolladores · Comunidad · Internet · Tecnología · Meta · Diarios
Enviando eventos de syslog por jabber

atordo's Diary
Por atordo
departamento I'm the eye in the sky looking at youuuu , Sección Diarios
Puesto a las Wed Sep 29th, 2004 at 06:14:59 PM CET
De cómo filtrar y enviar algunos eventos del sistema mediante jabber, monitorizado por daemontools.

 


El tinglado que me he montado está basado en un artículo de linux.com, aunque usando herramientas diferentes (salvo el syslogd). Consta de varias partes:

  1. Modificación de syslog.conf para enviar algunos mensajes a un fichero fifo.
  2. Creación de un script en perl para filtrar los mensajes deseados.
  3. Envío de dichos mensajes mediante una versión modificada de sJab.
  4. Creación de un servicio monitorizable por daemontools.
Vayamos pues, por partes (me ahorro el chiste de Jack el Destripador).

1. Modificación de syslog.conf
Primero debemos crear (como root) el directorio y el fichero fifo:
mkdir /etc/syslog-jabber
chmod o-rx /etc/syslog-jabber
mkfifo /etc/syslog-jabber/fifo

Edítese syslog.conf y añádase lo siguiente:

auth,authpriv.* |/etc/syslog-jabber/fifo

En mi caso sólo he puesto los eventos auth porque son los que me interesan, pero lógicamente se pueden poner otros cualesquiera. (Nota aparte: algún día entenderé por qué en Libertonia algunos bloques entre <code> y </code> salen con tipo de letra a tamaño fijo y otros no). Después hay que hacer que syslogd lea la nueva configuración, con /etc/init.d/sysklogd reload si se trata de un sistema tipo System-V, o buscando su pid y enviándole un HUP (kill -HUP nº_de_pid)

2. Parser en perl
Se trata simplemente de filtrar los mensajes que nos interesen, en mi caso cuando alguien entra al sistema desde fuera y cuando alguien no introduce la contraseña correcta para su. La adaptación a otros mensajes es trivial, basta ver cómo son examinando los diferentes ficheros de /var/log. Al filtro en cuestión lo llamamos parseauth.pl y lo grabamos en el directorio que vamos a usar para todo este cirio (/etc/syslog-jabber).

#!/usr/bin/perl
#

use strict;
my $tema;
my $msj;

open (FIFO, "</etc/syslog-jabber/fifo") || die ("No se pudo abrir el fifo\n");
 
 while (<FIFO>) {
   if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ PAM_unix\[\d+\]: authentication failure; (\w+)\(uid=\d+\) -> \w+ for su service$/) {
      $tema="Fallo en su: $1";
      $msj=$_;
      system("echo '$msj' | /etc/syslog-jabber/sJab -u remitente -p contraseña -t destinatario -q '$tema'");
   }

   if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ sshd\[\d+\]: Accepted password for (\w+) from (\S+) port \d+ ssh2$/) {
      if ($2 ne "miip") {
         $tema="Intruder Alert";
         $msj="$1 ha entrado desde $2";
         system("echo '$msj' | /etc/syslog-jabber/sJab -u remitente -p contraseña -t destinatario -q '$tema'");
      }
   }
}

Hay varias cosas a modificar aquí:

  • remitente: El usuario jabber que se usará para enviar los mensajes. Tiene que estar registrado previamente en el servido jabber que se utilice.
  • destinatario: El BOFH que tiene abierto su cliente jabber y recibe los avisos.
  • contraseña: La de remitente en el servidor jabber.
  • miip: En mi caso no quiero que me avisen cuando yo mismo entro, así que he puesto ese if; cada cual que lo adapte a sus necesidades.
Nota sobre seguridad: si no usáis grsecurity o algo similar, contraseña será visible por cualquier usuario que pueda hacer un ps. Un posible apaño es ponerlo directamente en el scritp sJab.

3. Versión modificada de sJab
La principal modificación sobre la versión oficial es que admite el tema del mensaje como parámetro. Posiblemente tenga otras, ya no lo recuerdo. En todo caso pego aquí el tocho y así cumplo con la GPL :)

#!/usr/bin/perl

# sJab - An simple Jabber command-line client written in Perl.
#
#####################################################################
#                                                                   #
#  Please note that this release is incredibly alpha.  In fact, so  #
#  alpha, it probably shouldn't even be released.                   #
#                                                                   #
#####################################################################
#
# Version : 0.01a
#
# Author  : Kris Merrill (kmerr001@cs.fiu.edu)
# Credits : Ryan Eatmon (Jarl)
#           DJ Adams    (sJabber)
#
# Usage   : To send a message to a user..
#               sJab -u <user> -p <password> -m <message>
#
#           To send a piped stream to a user...
#               <program> | sJab -u <user> -p <password>
#
#           To send a message to a group chat (conference) ...
#               sJab -u <user> -p <password> -c <room> -s <server> -m <message>
#
#           To send a piped stream to a group chat...
#               <program> | sJab -u <user> -p <password> -c <room> -s <server>
#
#####################################################################
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of
#  the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the
#
#               Free Software Foundation, Inc.,
#               59 Temple Place - Suite 330,
#               Boston, MA 02111-1307, USA.
#
#####################################################################
use Net::Jabber qw(Client);
use Getopt::Std;
#use strict;

getopt('upcstmq',\%opts); # Get options

if ($opts{c} && $opts{t}) {
   print "Please specify either a user or conference room.  Not both.\n";
   exit(0);
}

if ((!$opts{u} || !$opts{p}) && (!$opts{c} || !$opts{t})) {
   print
"sJab v0.01a

sJab [-u <user> -p <password>]
     [-c <conference> -s <server>] [-t <recipient>]
     [-m <message>]

     -u   User sJab will login as.
     -p   Password for sJab user.
     -c   Conference room.
     -s   Conference server.
     -t   User to send message.
     -m   Message, if not using standard input.
     -q   tema

     -h   Displays this screen.

Example Usage

To send a message to a user:
   sJab -u user -p password -t JabberUser -m Hello.

To send a message to a conference:
   sJab -u user -p password -c scs -s conference.scs -m Alert.
";
exit;
}

# Jabber-Specific "Constants"
#my $SUBJECT    = "Aviso sJab";
my $SUBJECT     = $opts{q};
my $SERVER     = "servidor_jabber";
my $PORT        = 5222;           # Jabber Port
my $SJABUSER    = $opts{u};   # Jabber User
my $SJABPASSWD  = $opts{p};   # Jabber Password
my $RESOURCE    = "sJab";     # Jabber Presence
my $PRESENCE    = "on";       # Jabber Presence
my $PRIORITY    = 0;

# User Defined Variables
my $conference  = $opts{c};   # Conference Room
my $server      = $opts{s};   # Jabber Server
my $user                = $opts{t}.'@'.$SERVER;
my $msg                 = $opts{m};

# Connect to Jabber Server
$jabber = jabberConnect(
   $SERVER,
   $PORT,
   $SJABUSER,
   $SJABPASSWD,
   $RESOURCE,
   $PRESENCE);

# If a Message is defined, don't use STDIN
if ($opts{t} && $opts{m}) {
   jabberMessage($user, $SUBJECT, $msg);
}
elsif ($opts{c} && $opts{s} && $opts{m}) {
   jabberGroup($conference,$server,$msg);
}
else {
   # Take input from STDIN
   while ($_ = <>) {

      #chomp $_;
      # If $user is defined, send to user
      if ($opts{t}) {
         $msg.=$_;
         #jabberMessage($user, $SUBJECT, $_);
      }
      # Otherwise send to Group Chat Room
      elsif ($opts{c} && $opts{s}) {
        jabberGroup($conference,$server,$_);
      }
      # If all else fails, quit.
      else {
         exit(0);
      }
   }
   jabberMessage($user, $SUBJECT, $msg) if ($opts{t});
}

# Disconnect from Jabber Service
$jabber->Disconnect();
exit;

#################################################
# Subroutines
#################################################

sub jabberConnect {
# desc    | Connects user to Jabber Service.
# accepts | server, port, sjabuser, sjabpasswd, resource, presence
# returns | Net::Jabber connection client

   my ($server, $port, $sjabuser, $sjabpasswd, $resource, $presence) = @_;
   my $connection = new Net::Jabber::Client;

   # Connect
   die "Cannot connect to Jabber server: $server:$port\n"
   unless (defined $connection->Connect(
      hostname => $server,
      port     => $port,
   ));

   print "Connected to Jabber server: $server:$port\n";

   # Identify / Authenticate Oneself to the Server
   my @result  =  $connection->AuthSend(
      username => $sjabuser,
      password => $sjabpasswd,
      resource => $resource
   );
   die "Authentication failed: $result[0] - $result[1].\n"
   if $result[0] ne "ok";

   print "Authentication as $sjabuser was sucessful.\n";

   return $connection;
}

# Message Subroutines
#################################################

sub jabberMessage {
# desc    | Sends Message to User
# accepts | user subject body
# returns | nothing

   my ($user, $subject, $body) = @_;

   # Create Message Object
   my $message = new Net::Jabber::Message;
   $message->SetMessage(
      To      => $user,
      Subject => $subject,
      Body    => $body,
   );

   # Send Message
   $jabber->Send($message);
}


# Group Subroutines
#################################################

sub jabberGroupJoin {
# desc    | Join a Jabber Group
# accepts | gname gserver
# returns | nothing

   my ($gname, $gserver) = @_;

   # Join Group / Send User Presence
   my $presence = new Net::Jabber::Presence;
   $presence->SetTo($gname.'@'.$gserver.'/'.$SJABUSER);

   # Send
   $jabber->Send($presence);
}

sub jabberGroupMsg {
# desc    | Write Message to Group
# accepts | gname gserver body
# returns | nothing

   my ($gname, $gserver, $body) = @_;

   # Create Message
   my $groupmessage = new Net::Jabber::Message;
   $groupmessage->SetMessage(
      To   => $gname.'@'.$gserver,
      Body => $body,
   );

   # Send
   $jabber->Send($groupmessage);
}

sub jabberGroupLeave {
# desc    | Leave a Jabber Group
# accepts | nothing
# returns | nothing

   # Join Group / Send User Presence
   my $presence = new Net::Jabber::Presence;
   $presence->SetPresence(
      Type => 'unavailable',
      To   => $gname.'@'.$gserver,
   );
}

sub jabberGroup {
# desc    | Joins a Group and Sends Message
# accepts | gname gserver body
# returns | nothing

   my ($gname, $gserver, $body) = @_;

   jabberGroupJoin($gname, $gserver);           # Join Group
   jabberGroupMsg($gname, $gserver, $body);     # Send Message
   jabberGroupLeave($gname, $gserver);          # Leave
}
Aquí deberemos cambiar servidor_jabber por el servidor en el que estén registrados nuestros amigos destinatario y remitente. Grábese en el directorio /etc/syslog-jabber.

4. Creación del servicio
Tal como está ya funcionaría el sistema (ejecutando parseauth.pl), pero si tenemos daemontools podemos utilizarlas para que lo vigilen como un servicio más. Creamos /etc/syslog-jabber/run con el siguiente contenido:

#!/bin/sh
echo Iniciando syslog-jabber
# direct std err to std out, for log
exec 2>&1
exec /usr/bin/perl /etc/syslog-jabber/parseauth.pl

Damos permiso de ejecución y creamos el directorio para el log:

chmod 700 /etc/syslog-jabber/run
mkdir /etc/syslog-jabber/log

Creamos /etc/syslog-jabber/log/run con el siguiente contenido:

#!/bin/sh
# with tai64n time format and 3 logfiles of size 50000 kB
multilog t s50000 n3 ./main

Y le damos permiso de ejecución (chmod 700 /etc/syslog-jabber/log/run). Ya sólo queda dar de alta el servicio: ln -s /etc/syslog-jabber /service/syslog-jabber, que por obra y gracia de daemontools empezará a funcionar. Como en cualquier otro servicio de estos, lo podemos parar con svc -d syslog-jabber y volver a levantar con svc -u syslog-jabber.
< Cómo configurar Jabber para usar MySQL como Base de Datos (7 comments) | Nuevo record de velocidad. (8 comments) >
Enlaces Relacionados
· Freshmeat
· jabber
· daemontools
· un artículo de linux.com
· sJab
· grsecurity
· More on atordo's Diary
· Also by atordo

Menu
· crear cuenta
· FAQ
· búsqueda
· Fuentes de Noticias

Login
Nueva cuenta
Usuario:
Contraseña:

Ver: Modo: Orden:
Enviando eventos de syslog por jabber | 5 comentarios (5 temáticos, editoriales, 0 ocultos)
Más jabber, ummm interesante. (none / 0) (#1)
por m4t1t0 (rafa.matito -at- gmail -dot- com) a las Thu Sep 30th, 2004 at 10:32:41 AM CET
(Información Usuario)

Al final se va a llenar la portada de artículos sobre jabber, pero ya que está tan currado sería un desperdicio no pasarlo a portada. ¿Te animas?

------------------------------
Un egoísta es una persona que se preocupa más de sí misma que de mí.


Portada (none / 0) (#2)
por atordo a las Tue Oct 5th, 2004 at 01:21:37 AM CET
(Información Usuario)

Casi prefiero dejarlo donde está. Aunque llevo algún tiempo por aquí confieso que aún no me he enterado muy bien de cuáles son "las noticias que le interesan" a Libertonia :) (y esta entrada ni siquiera es una noticia).

[ Padre ]


Envíalo a la cola (none / 0) (#4)
por man ls a las Tue Oct 5th, 2004 at 09:42:27 AM CET
(Información Usuario)

La única forma de saber qué artículos interesan es enviarlos a la cola de noticias y ver qué vota la gente. Anímate, es muy diver mirar cada 5 minutos si te ha votado alguien y maldecir a todos los que votan en contra :)

[ Padre ]


Portada (none / 0) (#5)
por atordo a las Mon Oct 11th, 2004 at 10:31:15 PM CET
(Información Usuario)

Parece una actividad bastante entretenida, pero me siento demasiado vago para maquetarlo otra vez. Además aquí ya cumple su cometido fundamental (que es servirme de chuleta si quiero reproducir el tinglado en otro sitio).

[ Padre ]


 
Algunas mejoras (none / 0) (#3)
por atordo a las Tue Oct 5th, 2004 at 01:48:20 AM CET
(Información Usuario)

Usuario no privilegiado

No es aconsejable ejecutar el script como Ruth, lo mejor es crear uno al efecto o usar alguno de los que tienen /bin/false como shell en /etc/passwd. Para ello hemos de darle al usuario los siguientes permisos:
  • Lectura en /etc/syslog-jabber y /etc/syslog-jabber/log.
  • Lectura y escritura en /etc/syslog-jabber/supervise, /etc/syslog-jabber/log/main y /etc/syslog-jabber/log/supervise.


Después hay que cambiar los ficheros run para que utilicen setuidgid.
  • /etc/syslog-jabber/run:
    #!/bin/sh
    echo Iniciando syslog-jabber
    # direct std err to std out, for log
    exec 2>&1
    exec setuidgid usuario /usr/bin/perl /etc/syslog-jabber/parseauth.pl
    
  • /etc/syslog-jabber/log/run:
    #!/bin/sh
    # with tai64n time format and 3 logfiles of size 50000 kB
    exec setuidgid usuario multilog t s50000 n3 ./main
    


Parser

He hecho una nueva versión que detecta dos eventos más: el fallo al introducir una contraseña por ssh y el inicio del sistema. Para este último es necesario que syslog también envíe al fichero fifo los avisos del kelmer (sustitúyase la modificación de /etc/syslog.conf por auth,authpriv,kern.* |/etc/syslog-jabber/fifo).

#!/usr/bin/perl
#

use strict;
my $tema;
my $msj;

open (FIFO, "</etc/syslog-jabber/fifo") || die ("No se pudo abrir el fifo\n");
 
 while (<FIFO>) {

   if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ PAM_unix\[\d+\]: authentication failure; (\w+)\(uid=\d+\) -> \w+ for su service$/) {
      $tema="Fallo en su: $1";
      $msj=$_;
   }
   if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ sshd\[\d+\]: Accepted password for (\w+) from (\S+) port \d+ ssh2$/) {
      if ($2 ne "miip") {
         $tema="Intruder Alert";
         $msj="$1 ha entrado desde $2";
      }
   }
   if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ sshd\[\d+\]: Failed password for (\w+) from (\S+) port \d+ ssh2$/) {
      $tema="Fallo clave ssh";
      $msj="$1 desde $2";
   }
   if (m/^\w\w\w\s+\d+ \d\d:\d\d:\d\d \w+ kernel: klogd .*, log source = \/proc\/kmsg started\.$/) {
     $tema="Inicio del sistema";
     $msj=$_;
   }

   system("echo '$msj' | /etc/syslog-jabber/sJab -u remitente -p contraseña -t destinatario -q '$tema'")
      if ($tema && $msj);
   $tema="";
   $msj="";


}



Por cierto que al estar el parser escrito en un lenguaje interpretado, siempre hay un perl ejecutándose. Esto no es problema con las máquinas actuales, pero no estaría mal sustituirlo por uno compilado. Claro que con lo agradecido que es perl para estos menesteres, da muchísima pereza ponerse a escribir un parser en C. Si alguien conoce alguno ya hecho que se pueda adaptar, se agradecen sugerencias.



 
Enviando eventos de syslog por jabber | 5 comentarios (5 temáticos, editoriales, 0 ocultos)
Ver: Modo: Orden:

ecol Logo Powered by Scoop
Todas las Marcas Registradas y copyrights de esta página son propiedad de sus respectivos dueños.
Los comentarios son propiedad del que los escribe.
Los iconos de las noticias y el logotipo son propiedad de Javier Malonda.
El Resto © 2002 Escomposlinux.org y aledaños.

Puedes sindicar los contenidos de libertonia en formato RSS 1.0 y RDF 0.9. También se puede sindicar la cola de envíos pendientes de moderación.

El proyecto escomposlinux.org está dedicado a la memoria de tas

crear cuenta | faq | búsqueda