Una Introducción a Expect

El módulo Expect será estudiado en mas detalle en la sección 8.1. Esta sección es una rápida introducción al módulo. Expect resuelve el problema de la comunicación bidireccional con un proceso externo.

Bastiones

Como ejemplo escribiremos un guión que realiza una conexión ssh con una red protegida por un bastion. Un bastión es un ordenador que es el único punto de entrada/salida a internet desde una red interna. Los bastiones se usan para disminuir los problemas de seguridad al establecer una barrera entre las zonas públicas y privadas.

Nuestro guión supone que hay un ordenador bastión el cual permite una conexión ssh. Una vez validada la conexión mediante el username y el password se nos pregunta a que máquina queremos conectarnos. Suponemos que dependiendo de la máquina será necesario introducir de nuevo la clave o no.

pp2@nereida:~/src/perl/expect$ cat -n bastion
 1  #!/usr/bin/perl -w
 2  use strict;
 3  use Getopt::Long;
 4  use Pod::Usage;
 5  use List::MoreUtils qw(any);
 6  use Expect;
 7
 8  my $VERSION = "1.0";
 9  my $RSH = `which ssh`;
10  chomp($RSH);
11  my $password = "";
12  my $user = $ENV{USER};
13  my $machine = 'millo';
14  my $bastion;
15  my $config;
16
17  my $delay = 1;
18  my $passwordprompt = 'word:\s$';
19  my $machineprompt = 'salir\)(\s)+$';
20  my @MOREPASSWORDS = ();
21
22  GetOptions(
23      'ssh=s'       => \$RSH,
24      'password=s'  => \$password,
25      'user=s'      => \$user,
26      'machine=s'   => \$machine,
27      'bastion=s'   => \$bastion,
28      'config=s'    => \$config,
29      'version'     => \&version,
30      'help'        => \&man,
31    ) or croak usage();
32
33
34  ($config) = @ARGV if @ARGV;
35
36  $config = ".bastion.conf" if !$config and !$bastion and -r ".bastion.conf";
37  $config = "$ENV{HOME}/.bastion.conf" if !$config and !$bastion and -r "$ENV{HOME}/.bastion.conf";
38
39  eval_config($config) if $config and -r $config;
40
41  die man() unless $bastion and $bastion =~ m{(\w+\.?)+};
42  my $host_to_login_to=$user.'@'.$bastion;

El Fichero de Configuración

El programa comienza obteniendo los valores desde la línea de comandos o desde un fichero de configuración (opción config).

31  my ($passwordprompt, $machineprompt, $delay, @MOREPASSWORDS);
32
33  eval_config($config) if $config and -r $config;
El fichero de configuración esta escrito en Perl y es evaluado de manera parecida a como se hizo en la práctica 1.9.

Estos son los contenidos de un fichero de configuración:

pp2@nereida:~/src/perl/expect$ cat -n bastion.conf
 1  $password = 'password';
 2  $user = 'user';
 3  $machine = 'banot';
 4  #$machine = 'millo';
 5  $bastion = 'exthost.instituto.ull.es';
 6
 7  # Seconds to wait before leaving
 8  $delay = 3;
 9
10  # user@instituto's password:
11  $passwordprompt = 'word:\s$';
12
13  # Nombre de la máquina?:(q para salir)
14  $machineprompt = 'salir\)(\s)+$';
15
16  @MOREPASSWORDS = qw(timple manis banot tonga);

El Código Principal

42  my $host_to_login_to=$user.'@'.$bastion;
43
44  my $rsh=Expect->spawn($RSH,$host_to_login_to);
45
46  $rsh->expect($delay,'-re', $passwordprompt)||(die"Never got password prompt\n");
47  print $rsh "$password\r";
48
49  $rsh->expect($delay,'-re',$machineprompt)||(die"Never got machine prompt\n");
50  print $rsh "$machine\r";
51
52  if (any { /^$machine$/ } @MOREPASSWORDS ) {
53    $rsh->expect($delay,'-re', $passwordprompt)||(die"Never got password prompt\n");
54    print $rsh "$password\r";
55  }
56  # Retornar control al usuario
57  $rsh->interact();
..  .............. # subrutinas de apoyo

El método spawn

El método spawn ejecuta el comando (línea 37) creando una seudoterminal como vía de comunicación entre el comando y el programa cliente.

Seudoterminales

Una seudoterminal es un proceso que proporciona un canal de comunicaciones entre los dos procesos implicados mediante la emulación de una terminal de texto. Casi todos los programas admiten una comunicación vía una terminal y alguno (editores, el programa para cambiar la clave de usuario, etc.) solo admiten una comunicación via una seudoterminal. Además, la comunicación con seudoterminales no esta bufferada. Se evita asi el riesgo de bloqueo que introduce la presencia de memorias auxiliares.

El Método expect

Despues de creado el objeto seudoterminal $rsh se establece un diálogo con el comando lanzado (lineas 39-40, 42-43 y 46-47). El método expect permite analizar la salida del comando hasta que case con la expresión regular proporcionada como argumento. La llamada termina si no se produce el casamiento en menos de $delay segundos.

El Método print

Mediante llamadas a print en el manejador de la seudoterminal $rsh proporcionamos la entrada al comando lanzado.

El Método any de List::MoreUtils

Si la máquina de la red interna a la que entramos requiere una validación adicional (esta entre las descritas en el array @MOREPASSWORDS) la (misma) clave es introducida de nuevo.

El Método interact

El método interact (línea 50) devuelve el control de la entrada/salida a los manejadores de fichero habituales STDIN, STDOUT y STDERR.

Ejercicio 8.2.1   Estudie la siguiente cuestion (Module Net::SSH::Expect - Cannot interact) en PerlMonks. ¿Cuales son sus sugerencias?



Subsecciones
Casiano Rodríguez León
2012-02-29