Antivirus: Uso de clamav-daemon desde Vala

En esta entrada vamos a ver como utilizar el demonio ClamAV para escanear ficheros que le vamos a enviar desde una aplicación escrita en Vala. Lo que haremos es lanzar el demonio que se ejecutará en el sistema y correrá en segundo plano, de esta forma no necesita ejecutarse y cargar las firmas de los malwares cada vez que queremos lanzar un escaneo a un fichero. Esto puede acelerar en gran medida los tiempos de proceso.

Lo primero que tenemos que tener es el daemon corriendo en la máquina. Para la instalación en entornos Debian/Ubuntu:

❯ sudo apt install clamav-daemon

Por defecto el daemon no espera conexiones por TCP, por lo que vamos a lanzar el configurador y le indicamos que permita conexiones por TCP:

❯ sudo dpkg-reconfigure clamav-daemon

Configurar ClamAV daemon

Para este ejemplo podemos dejar el resto de opciones en sus valores por defecto.

Comprobamos que tenemos el daemon escuchando pidiéndole que nos muestre la versión. Le enviamos "VERSION" utilizando la herramienta netcat, en este caso desde la propia máquina:

❯ echo VERSION | nc -v 127.0.0.1 3310
Connection to 127.0.0.1 3310 port [tcp/*] succeeded!
ClamAV 0.102.4/26080/Sun Feb 14 13:15:03 2021

Vamos a ver el código de la aplicación. El código que realiza todo el trabajo lo tenemos en una clase que hemos llamado ClamdConn. Al instanciar la clase le indicamos el puerto y la ip donde se encuentra clamav-daemon. Tenemos dos métodos públicos, scan()getVersion(). Ambos utilizan el método Ejecuta() que abre un socket contra el daemon y le envía la petición. Este retorna la respuesta que nos devuelve clamav-daemon:

ClamdConn.vala
/*  
 * ClamdConn.vala  
 *  
 * (c) Author: David Quiroga  
 * e-mail: david (at) clibre (dot) io  
 *  
 ***************************************************************  
 * Descripción:  
 *  
 * Uso del demonio clamav para buscar malware en ficheros  
 *  
 * SPDX-License-Identifier: GPL-3.0  
 *  
*/ 
 
public class ClamdConn : GLib.Object 
{ 
    private string _ip_clamd = null; 
    private uint16 _port = 0; 
    private SocketConnection conn; 
     
    public ClamdConn (string ip_clamd, uint16 port) { 
        _ip_clamd = ip_clamd; 
        _port = port; 
    } 
     
    private void conect_clamd() { 
        try 
        { 
            InetAddress address = new InetAddress.from_string (_ip_clamd); 
             
            var client = new SocketClient(); 
            var addr = new InetSocketAddress( address, _port ); 
            conn = client.connect( addr );  
        } 
        catch (Error e) 
        { 
            stderr.printf( @"$(e.message)\n" ); 
        }  
    } 
     
    private string Ejecuta (string comando) 
    { 
        string salida=""; 
         
        this.conect_clamd(); 
         
        try {  
            conn.output_stream.write( comando.data );  
            var response = new DataInputStream( conn.input_stream );  
            size_t data_read; 
            var data = response.read_upto ("", -1, out data_read, null); 
            salida = "%s".printf ((string) data); 
        } 
        catch (Error e) 
        { 
            stderr.printf( @"$(e.message)\n" ); 
        } 
        return salida; 
    } 
     
    public string getVersion () 
    { 
        return this.Ejecuta ("VERSION"); 
    } 
     
    public string scan (string path) 
    { 
        return this.Ejecuta ("SCAN" + path); 
    } 
} 

Solo necesitamos el cliente que hace uso de la clase:

clclamd.vala
class ClClamav : GLib.Object 
{ 
    public static int main (string[] args) 
    {  
        Intl.setlocale (ALL); 
         
        var clamdconn = new ClamdConn ("192.168.122.139", 3310); 
         
        print (clamdconn.getVersion());  
         
        print (clamdconn.scan ("/home/david/eicarcom2.zip")); 
         
        return 0; 
         
    } 
}  

En este caso clamav-daemon esta corriendo en una máquina virtual con ip 192.168.122.139 en el puerto 3310 y tiene acceso a los ficheros que le indicamos en la ruta.

Construimos el ejecutable:

❯ valac --pkg=gio-2.0 ClamdConn.vala clclamd.vala -o clclamd

y ejecutamos el programa:

❯ ./clclamd 
ClamAV 0.102.4/26102/Mon Mar  8 13:03:13 2021
home/david/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND

que detecta el fichero con la firma de prueba Eicar como era de esperar. Lo que podemos darnos cuenta enseguida es que el tiempo de ejecución es muy rápido. Si comparamos los tiempos que empleaba clamav-devc que hicimos en el post anterior con los tiempos de uso del daemon:

❯ time ~/clamav-devc 
Iniciando motor clamav...
Clamav iniciado: Cargadas 8508081 firmas
Escaneando ficheros:

eicar.com.txt - Virus detectado: Win.Test.EICAR_HDB-1

------
Cargadas 8508081 firmas
Ficheros escaneados: 1
Ficheros no accesibles: 0
Ficheros infectados: 1
Total datos escaneados: 0,00 MB

real    0m9,648s
user    0m9,341s
sys    0m0,304s

y usando el demonio:

❯ time ./clclamd 
ClamAV 0.102.4/26102/Mon Mar  8 13:03:13 2021
home/david/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND

real    0m0,007s
user    0m0,005s
sys    0m0,003s

En el primer caso ha consumido más de 9 segundos y en el segundo caso es inferior al segundo. Esto es debido a tener que cargar las firmas cuando arranca el programa, frente a el daemon que ya tiene las firmas cargadas. Si tenemos que analizar todo un disco no encontraremos muchas diferencias, pero para escanear ficheros que puedan ir llegando de forma intermitente (como el correo electrónico por ejemplo) obtendremos una notable mejora de rendimiento.

 

(3 votos)
Etiquetado como :

Deja un comentario

Asegúrese de introducir toda la información requerida, indicada por un asterisco (*). No se permite código HTML.