PfCentinel V2 – Manager Update Platform/Packages for pfSense Multisite



  • Hola

    pfCentinel V2 – Manager Update Platform/Packages for pfSense Multisite.
    pfCentinel V2 – Gestor de actualizaciones de plataforma/paquetes para varios sitios pfSense.

    Lanzo la versión 2 de esta utilidad (Versión 1 >> https://forum.pfsense.org/index.php?topic=115294.0 )

    Gestor de actualizaciones de Plataforma/Paquetes para varios (Multisite) pfSense. La he testeado con navegador Firefox 47.0.1 en un pfSense 2.3.2 amd64 controlando en remoto las actualizaciones de pfSense con versiones:

    2.3
        2.3.1
        2.3.1_1
        2.3.1_5
        2.3.2

    Tras la actualización de pfSense a la v 2.3.2, el script, si se ejecuta desde un pfSense 2.3.2,  ya no soporta usar localhost (127.0.0.1) como uno de los registros de machines.csv, para 127.0.0.1 dará aviso de NO CONEXION o AUTHENTICATION ERROR.

    También he comprobado que si se ejecuta el script desde un pfSense con versión menor a 2.3.2, la conexión php ssh (ssh2_connect) contra un pfSense 2.3.2 da NO CONEXION, esto es debido a que pfSense 2.3.2 al actualizar openSSH está usando como algoritmo de intercambio de key ssh2 a curve25519.

    Por lo que para que el script sea eficiente, se debe de ejecutar en la última actualización de pfSense (a día de hoy V 2.3.2)

    También, por motivos obvios de seguridad, se recomienda que se usen IPs de túneles, ya que el pfSense que ejecuta el script (Central) efectua conexiones ssh2 sobre los hosts de la base de datos /scripts/machines.csv. Y es recomendable no tener acceso ssh vía interfaz wan, pero sí vía tunel (OpenVPN o IPSec).

    La mejora de esta versión es que ya no hay que esperar todo el tiempo de ejecución del script con el navegador en blanco. Ahora se mostrará una barra de progreso y el cursor en estilo wait indicando que el proceso del script se está ejecutando (Esto lo he implementado con AJAX/JQUERY/JSON)

    La filosofía o flujo de la utilidad es la misma que su versión 1.:

    Primero se aloja el cli php script pfCentinel-Setup-v2.php en un directorio o carpeta como /tmp o /scripts. Se ejecuta desde shell:

    php /scripts/pfCentinel-Setup-v2.php

    Y se crea la base de datos /scripts/machines.csv, y si ya existe se pueden añadir más hosts.

    Tras eso, se aloja el GUI php script pfCentinel-Central-v2.php en la ruta /usr/local/www/ o una subcarpeta por debajo de www, como seria /usr/local/www/pfCentinel/ y se ejecuta dese navegador:

    https://ip-pfsense-central/pfCentinel-Central-v2.php

    o si se aloja en una subcarpeta:

    https://ip-pfsense-central/pfCentinel/pfCentinel-Central-v2.php

    La primera vez que se ejecute mostrará algo similar a:

    Si no exixtiera el fichero de la bbdd /scripts/machines.csv se veria:

    Avisando que se debe de ejecutar vía shell pfCentinel-Setup-v2.php para crear la bbdd.

    Una vez tengamos la bbdd y ejecutado vía navegador pfCentinel-Central-v2.php, para actualizar los datos solo resta clikar en el botón verde [ + Refresh Now: Status Platforms and Packages ], y se lanzará el proceso.

    Una vez finalizado, se auto refrescarán los datos, mostrando los resultados (que se guardan en machines.csv, las claves, al igual que la versión 1, se guardan encriptadas). En la columna Local Date Last refresh tendremos la fecha y hora (local del pfSense Central) de la última comprobación de cada registro.

    Salu2

    Referencia: https://www.javcasta.com/pfcentinel-v2-manager-update-platformpackages-for-pfsense-multisite/

    Descarga: http://www.javcasta.com/?smd_process_download=1&download_id=33291



  • Woow. Mañana lo  chequeo  :)



  • Hola

    El código de:

    pfCentinel-Setup-v2.php

    
    /*
    	pfCentinel-Setup-v2.php
    
    	Copyright (c) 2016 Javier Castañon
      javier@javcasta.com - https://javcasta.com/
    	All rights reserved.
    
    	Redistribution and use in source and binary forms, with or without
    	modification, are permitted provided that the following conditions are met:
    
    	1\. Redistributions of source code must retain the above copyright notice,
    	   this list of conditions and the following disclaimer.
    
    	2\. Redistributions in binary form must reproduce the above copyright
    	   notice, this list of conditions and the following disclaimer in the
    	   documentation and/or other materials provided with the distribution.
    
    	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
    	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
    	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
    	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
    	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    	POSSIBILITY OF SUCH DAMAGE.
    */
    
    set_time_limit(0);
    ini_set('max_execution_time', '0');
    //si no existe dir /scripts lo creamos
    if(!is_dir('/scripts')) {
      mkdir('/scripts');
    }
    
    $existemachines = false;
    if (file_exists('/scripts/machines.csv')) {
      $existemachines = true;    
    }
    
    echo "\033[34m################################################### \033[0m \n";
    echo "\033[31m#         Setup     pfCentinel       2016         # \033[0m \n";
    echo "\033[34m################################################### \033[0m \n";
    echo "\033[34m#by Javier Castan?on.javcasta https://javcasta.com# \033[0m \n";
    echo "\033[34m################################################### \033[0m \n";
    echo "\033[34m################################################### \033[0m \n";
    echo "\033[34m#   host pfCentinel-Setup.php  in /tmp  folder    # \033[0m \n";
    echo "\033[34m################################################### \033[0m \n";
    echo "\033[34m# run via shell: # php /tmp/pfCentinel-Setup.php  # \033[0m \n";
    echo "\033[34m################################################### \033[0m \n";
    // rutina introduccion datos > /scrips/machines.csv
    $goon = true;
    $i = 0;
    
    // condiciones necesarias:
    // cada host tenga habilitado sshd (Enable Secure Shell) en puerto tcp22
    // y no tengan restricciones a conectarse vía ssh al tcp22 desde otro host
    // por lo que es muy recomendable que las IPs de los hosts sean accesibles
    // vía tunel openVPN o IPSec , etc
    
    //Para 5 hosts de media tardará 1 minuto el script pfCenter-central.php
    //por cada host se toma de 10 a 30 sg, para 5 hosts: [ 50 .. 150 ] sg
    
    if ($existemachines) { 
      echo "\n Already exists /scripts/machines.csv \n";
      $muestra = shell_exec("/bin/cat /scripts/machines.csv");
      echo $muestra . "\n";
      $adddata = readline("Do you want add another host to /scripts/machines.csv ? (y/n): ");
      if ($adddata == "n") die("\nFin.\n");
    }
    
    while ( $goon ) {
      //&& $i <= 4
      $i++;
      echo "...\n";
      echo "\033[31m Data entry for Host $i \033[0m \n";
      $descripcion = readline("Enter description for Host (p.e: pfMadrid): ");
      $elhost = readline("Enter IP for Host (p.e: 10.0.0.254): ");
      $eluser = readline("Enter user name for host $descripcion (p.e: root): ");
      echo "Enter password for the user name $eluser: ";
      `/bin/stty -echo`;
      $lapass = readline();
      `/bin/stty echo`;
      echo "\n";
      echo "Testing connectivity, user:password ...\n";
      @fdoit($elhost, 22, $eluser, $lapass);
      $escribir = readline("Add host $descripcion to /scripts/machines.csv ?(y/n):");
      if ($escribir == "y") fmachinesupdate($descripcion, $elhost, "??????", "??????", $eluser, fenydesencripta($lapass, true)); 
      $continuar = readline("Continue? (y/n): ");
      if ( $continuar == "n" ) $goon = false;
    
    }
    
    echo "END.\n";
    
    function fdoit($host, $port, $username, $password) {
      $paquetes = "";
      $comando = "pkg update";
      fshh($host, $port, $username, $password, $comando);
      $comando = "pkg version > /tmp/pfcenter-status.tmp";
      fshh($host, $port, $username, $password, $comando);
      echo "Host: $host\n";
      echo "=====================\n";
      $comando = "cat /tmp/pfcenter-status.tmp | grep '^pfSense-pkg' | grep '<' | cut -f 1 -d ' '";
      $paquetes = @fshh($host, $port, $username, $password, $comando);
      if (strpos($paquetes, "ERROR_AUTENTICACION") !== false) { echo "AUTHENTICATION ERROR\n"; return "AUTHENTICATION ERROR"; }
      if (strpos($paquetes, "NO_CONEXION") !== false) { echo "NO CONEXION\n"; return "NO CONEXION"; }
      if (strlen($paquetes) < 5) { echo "NO UPDATE PACKAGES\n"; echo " \n"; }
      else echo "UPDATES PACKAGES: Packages for update:\n" . $paquetes . "\n";
      $comando = "cat /tmp/pfcenter-status.tmp | grep '^pfSense-2' | cut -c 9- | cut -f 1 -d ' '";
      $vactual = fshh($host, $port, $username, $password, $comando);
      echo "Current Version pfSense: " . $vactual . "\n";
      $comando = "pkg rquery %v pfSense";
      $vdisponible = fshh($host, $port, $username, $password, $comando);
      echo "Available Version pfSense: " . $vdisponible . "\n";
      if ($vactual !== $vdisponible) echo "THERE PLATFORM UPDATE\n";
      echo " \n";
    }
    
    function fpingssh($phost, $pport) {
      $waitTimeoutInSeconds = 2;
      try {
      if($fp = @fsockopen($phost,$pport,$errCode,$errStr,$waitTimeoutInSeconds)){   
       // It worked 
       return true;
      } else {
       // It didn't work
       return false; 
      } 
      fclose($fp);
      } catch(Exception $e) { return false; }
    }
    
    function fshh ( $vhost, $vport, $vuser, $vpass, $vcomando ){
      //if(!$connection) $connection = ssh2_connect($vhost, $vport)or die("The SSH2 connection could not be established.");
      if(fpingssh($vhost, $vport)) {
        set_time_limit(30);
        if(!$connection) {
          $connection = @ssh2_connect($vhost, $vport);
          if (!$authentication) {
            $errorautenticacion = false;
            $authentication = @ssh2_auth_password($connection, $vuser, $vpass) or $errorautenticacion = true; //die("Could not authenticate '{$vuser}'");
            if ($errorautenticacion) return "AUTHENTICATION_ERROR";
            $stream = ssh2_exec($connection, $vcomando) or die("Command Error...");
            stream_set_blocking( $stream, true );
            $cmd = stream_get_contents($stream);
            return $cmd;
            fclose($stream);
            sleep(1);
          } else return "NO_CONEXION";
        }
        } else {
          return "NO_CONEXION";
        }
      //flush();
    }  
    
    function fenydesencripta($vcadena, $modo) {
      //AES-256 / CBC / ZeroBytePadding - ref http://php.net/manual/es/function.mcrypt-encrypt.php
      $key = pack('H*', "dcb34c7d113abc17b53763052cef08cc66ace029fddbae4e1d427a1cfb2a10b2");
      $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
      $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
      if ($modo) {
        // $modo = true => encripta
        $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $vcadena, MCRYPT_MODE_CBC, $iv);
        $ciphertext = $iv . $ciphertext;
        $ciphertext_base64 = base64_encode($ciphertext);
        return $ciphertext_base64;
      } else {
        // $modo = false => desencripta
        $ciphertext_dec = base64_decode($vcadena);
        $iv_dec = substr($ciphertext_dec, 0, $iv_size);
        $ciphertext_dec = substr($ciphertext_dec, $iv_size);
        $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
        return $plaintext_dec;
      }
    }
    
    function fmachinesupdate($vdescr, $vhost, $vplatform, $vpackage, $vuser, $vpass, $vldate) {
      $cabeza = '"descr";"host";"platform";"packages";"user";"password";"LDATE"'."\n";
      if (!file_exists('/scripts/machines.csv'))  
      file_put_contents('/scripts/machines.csv', $cabeza );
      $vlinea = '"'.$vdescr.'"'.';'.'"'.$vhost.'"'.';'.'"'.$vplatform.'"'.';'.'"'.$vpackage.'"'.';'.'"'.$vuser.'"'.';'.'"'.$vpass.'";"'.$vldate.'"'."\n";
      file_put_contents('/scripts/machines.csv', $vlinea, FILE_APPEND | LOCK_EX);
    }
    
    ?>
    [/code]
    
    Salu2
    


  • Hola
    El código de:
    pfCentinel-Central-v2.php

    
    Feel Free to paypal me [ --- By Javier Castan?on - @JavCasta - 2016][0]";
    
    if( isset($_GET['id']) && $_GET['id'] !== '0'  ) {
        flongjob ($_GET['id']);
    }
    
    $form = new Form;
    $section = new Form_Section('pfCentinel v2: CENTRAL (highly recommended to work with tunnels openVPN or IPsec)');
    
    $form->add($section);
    
    //if not exists /scripts create it - si no existe dir /scripts lo creamos
    if(!is_dir('/scripts')) {
      mkdir('/scripts');
    }
    $existemachines = false;
    if (file_exists('/scripts/machines.csv')) {
      $existemachines = true;    
    }
    //csv file to array
    function csv_in_array($url, $delm=";", $encl="\"", $head=true) {
        $out = Array();
        //ref http://php.net/manual/es/function.file.php#105772
        $csvxrow = file($url);   // ---- csv rows to array ----
        $csvxrow[0] = chop($csvxrow[0]);
        $csvxrow[0] = str_replace($encl,'',$csvxrow[0]);
        $keydata = explode($delm,$csvxrow[0]);
        $keynumb = count($keydata);
       
        if ($head === true) {
        $anzdata = count($csvxrow);
        $z=0;
        for($x=1; $x
    

    Salu2



  • Ok, me va bien,  lo corro desde un 2.3.2



  • Hola

    Me alegro. :)

    Para la versión 3 implementaré la base de datos de machines.csv en SQLite3 y a ver si hago un formulario para editar los registros de los hosts de esa bbdd y que sea todo por GUI y no por cli.

    Salu2


Log in to reply