next up previous contents
Siguiente: Políticas de acceso Subir: Detalles Implementación Anterior: Comprobación de datos de   Índice General


Calidad de servicio

Para empezar con la calidad de servicio se invoca el script inicioQoS desde dentro del script initialize.fw que es ejecutado al iniciar la pasarela. El script inicioQoS es el siguiente:
#!/bin/bash

#Creamos la discipllina de cola de subida
tc qdisc del dev $ExternalDevice root
tc qdisc add dev $ExternalDevice root handle 1 htb default 10

#Creamos la disciplina de cola de bajada
tc qdisc del dev $InternalDevice root
tc qdisc add dev $InternalDevice root handle 1 htb default 10

#Creamos la clase raiz de subida
tc class add dev $ExternalDevice parent 1: classid 1:2 htb rate 
  $MaxBandWidthUp burst 2k

#Creamos la clase por defecto de subida
tc class add dev $ExternalDevice parent 1:2 classid 1:3 htb rate 
  $MinBandWidthUp ceil $MaxBandWidthUp burst 2k prio 6
tc qdisc add dev $ExternalDevice parent 1:3 handle 3 sfq perturb 10

#Creamos la clase raiz de bajada
tc class add dev $InternalDevice parent 1: classid 1:2 htb rate 
  $MaxBandWidthDown burst 2k

#Creamos la clase por defecto de bajada
tc class add dev $InternalDevice parent 1:2 classid 1:3 htb rate 
  $MinBandWidthDown ceil $MaxBandWidthDown burst 2k prio 6
tc qdisc add dev $InternalDevice parent 1:3 handle 3 sfq perturb 10

# Marcamos los paquetes segun el tipo de servicio
iptables -A OUTPUT -t mangle -p tcp --dport 22 -j TOS --set-tos Minimize-Delay
iptables -A OUTPUT -t mangle -p tcp --dport 80 -j TOS 
  --set-tos Maximize-Throughput
iptables -A OUTPUT -t mangle -p tcp --dport 443 -j TOS 
  --set-tos Maximize-Throughput

# End
Una vez que han sido iniciadas las clases, la pasarela espera que alguien se conecte. Cuando alguien intenta conectarse y es redirigido al servidor, es cuando se ejecuta el script login.cgi, y cuando se crea el mensaje que recibe la pasarela con los parámetros de la conexión. Nosotros necesitamos incluir en este mensaje el identificador de cola y los valores de los parámetros rate, ceil y prio. Para ello hemos utilizado la función consulta_qos, que devuelve los parámetros del grupo al que pertenece el usuario. Conretamente esta función consulta la tabla grupos y devuelve una array con los siguientes parámetros: id_cola, rate, ceil y prio. El id_cola es un parámetro muy delicado, ya que hay que sacarlo de la pila y volver a dejarlo en ella cuando deje de estar en uso. El script login.cgi se ejecutará una vez cada 45 segundos por cada usuario, y cada vez que se ejecuta va a llamar a la función consulta_qos. Para devolver el parámetro id_cola lo primero que hace esta función es mirar si el usuario está en la tabla conexiones, si está en ella coge el parámetro de esta tabla. Si el usuario no está conectado es que está haciendo login y hay que asignarle un identificador nuevo de la pila. En este caso sacamos un identificador de la pila. Cuando el mensaje sea recibido por la pasarela se invocará el script conexion y automáticamente se rellenará la tabla conexiones con el id_cola. Podemos ver en la página  [*] el script login.cgi, y en el primer fragmento comentado está incluido la recogida de parámetros con la función consulta_qos y su posterior asignación a las variables del cgi para que sean incluidos en el mensaje. Cuando la pasarela recibe este mensaje lo desencripta y recibe los parámetros: id_cola, rate, ceil y prio. Veamos las modificaciones realizadas en el método punch_ticket de la clase Captive.pm, que es el que se encarga de comprobar la veracidad del mensaje y guardar los valores recibidos:

sub punch_ticket {
    my ( $self, $msg, $id ) = @_;
    my %auth = $msg->parse;

    my $client = $self->{Peer}{$id} ;
    if (not $client )
    {

#  Si no tiene id se termina y hay que devolver el id_cola a la pila del serv.
#
      if ($auth{Id_cola})
      {
        my $id=$auth{Id_cola};
        my $servidor=$self->{AuthServiceAddr};
        open(FIFO,">/home/nocat/param_fifo");
        print FIFO "$servidor libera_id $id";
        close FIFO;
        $self->log(5,"Liberamos el identificador de cola $id");
      }
      return  $self->log( 2, "Unknown ID notify from $id!" );
    }


# Si hay algun error hay que liberar el id_cola
#
    if ($client->user and $client->user ne $auth{User})
    {
      if ($auth{Id_cola})
      {
        my $id=$auth{Id_cola};
        my $servidor=$self->{AuthServiceAddr};
        open(FIFO,">/home/nocat/param_fifo");
        print FIFO "$servidor libera_id $id";
        close FIFO;
        $self->log(5,"Liberamos el identificador de cola $id");
      }
      return $self->log( 2,"Bad user/id match
                   from $id: $auth{User} != " . $client->user );
    }
    if ($client->token ne $auth{Token})
    {   

      if ($auth{Id_cola})
      {
        my $id=$auth{Id_cola};
        my $servidor=$self->{AuthServiceAddr};
        open(FIFO,">/home/nocat/param_fifo");
        print FIFO "$servidor libera_id $id";
        close FIFO;
        $self->log(5,"Liberamos el identificador de cola $id");
      }
      return $self->log( 2, "Bad token match
                  from $id: $auth{Token} != " . $client->token );
    }

    if (not $self->{IgnoreMAC} and $client->mac ne $auth{Mac})
    {      

      if ($auth{Id_cola})
      {
        my $id=$auth{Id_cola};
        my $servidor=$self->{AuthServiceAddr};
        open(FIFO,">/home/nocat/param_fifo");
        print FIFO "$servidor libera_id $id";
        close FIFO;
        $self->log(5,"Liberamos el identificador de cola $id");
      }
      return $self->log( 2,"Bad MAC match
                      from $id: $auth{Mac} != "  . $client->mac );
    }

    # Identify the user and class.
    $client->user( $auth{User} );
    $client->groups( $auth{Member} );

# Asignamos id_cola,ceil y prio
#
    $client->id_cola( $auth{Id_cola} );
    $client->rate( $auth{Rate} );
    $client->ceil( $auth{Ceil} );
    $client->prio( $auth{Prio} );

    # Store the new token away for when the peer renews its login.
    $client->token(1);

    # Perform the requested action.
    if ( $auth{Action} eq PERMIT ) {
      $self->permit( $client );
    } elsif ( $auth{Action} eq DENY ) {
      $self->deny( $client );
    }

    $self->log( 9, "Available MACs: @{[ keys %{$self->{Peer}} ]}" );

    return \%auth;
}

En el último fragmento es donde se asignan estos parámetros, como se puede observar se usan nuevos métodos en la clase peer.pm:
package NoCat::Peer;

.........

sub id_cola {
    my ( $self, $id_cola ) = @_;
    $self->{Id_cola} = $id_cola if defined $id_cola;
    return $self->{Id_cola};
}

sub rate {
    my ( $self, $rate ) = @_;
    $self->{Rate} = $rate if defined $rate;
    return $self->{Rate};
}

sub ceil {
    my ( $self, $ceil ) = @_;
    $self->{Ceil} = $ceil if defined $ceil;
    return $self->{Ceil};
}

sub prio {
    my ( $self, $prio ) = @_;
    $self->{Prio} = $prio if defined $prio;
    return $self->{Prio};
}
Estos métodos, a su vez definen variables de la clase Peer que guardan un valor para los parámetros id_cola, rate, ceil y prio de cada cliente. Ya tenemos los parámetros disponibles en la pasarela como unas variables más del cliente. Para crear la nueva clase que corresponde a un cliente con sus parámetros usamos el script qos.fw:
#!/bin/sh

#
# Note: your PATH is inherited from the gateway process
#

action=$1
ip=$2
id_cola=$3
rate=$4Kbit
ceil=$5Kbit
prio=$6


if [ -z "$action" -o -z "$ip" -o -z "$id_cola" ]; then
  echo
  echo Usage: $0 [add\|del] [IP] [Classid] [OPTIONS]
  echo add OPTIONS: [Ceil] [Prio]
  echo Example: $0 add 10.0.0.105 20 100 5
  echo        : $0 del 10.1.1.1 20
  exit 1
elif [ "$action" = "add" ]; then
  if [ -z "$rate" -o -z "$ceil" -o -z "$prio" ]; then
    echo
    echo Usage: $0 [add\|del] [IP] [Classid] [OPTIONS]
    echo add OPTIONS: [Rate] [Ceil] [Prio]
    echo Example: $0 add 10.0.0.105 2F 35 100 5
    echo        : $0 del 10.1.1.1 20
    exit 1
  fi
fi

#Se crea una clase, se le conecta con una disciplina de colas y un filtro 
# que dirige los paquetes del cliente a esa clase.
if [ "$action" = "add" ]; then
  tc class add dev $InternalDevice parent 1:2 classid 1:$id_cola htb 
    rate $rate ceil $ceil burst 2k prio $prio
  tc qdisc add dev $InternalDevice parent 1:$id_cola handle $id_cola 
    sfq perturb 10
  tc filter add dev $InternalDevice parent 1:0 protocol ip prio 0x$id_cola 
    u32 match ip dst $ip classid 1:$id_cola

#Para borrarlo se hace en orden inverso
elif [ "$action" = "del" ]; then
  tc filter del dev $InternalDevice parent 1:0 protocol ip prio 0x$id_cola 
    u32 match ip dst $ip classid 1:$id_cola
  tc qdisc del dev $InternalDevice parent 1:$id_cola handle $id_cola 
    sfq perturb 10
  tc class del dev $InternalDevice parent 1:2 classid 1:$id_cola
else
    echo "FATAL: Accion incorrecta:  $action!"
    exit 1
fi

#
# Fin
#
Para invocar el scrip qos.fw se han creado tres métodos nuevos en la clase Firewall:
package NoCat::Firewall;
......
@REQUIRED   = qw( ResetCmd PermitCmd DenyCmd GatewayMode 
                  InsertQoSCmd DeleteQoSCmd);
......
my @Perform_Export = qw(
    InternalDevice ExternalDevice LocalNetwork AuthServiceAddr DNSAddr
    GatewayAddr GatewayPort IncludePorts ExcludePorts AllowedWebHosts
    MembersOnly RouteOnly IgnoreMAC
    Policy1 Policy2 Policy3 Policy4 Policy5 Policy6
    MarkPolicy1 MarkPolicy2 MarkPolicy3 MarkPolicy4 MarkPolicy5 MarkPolicy6
    MaxBandWidthDown MaxBandWidthUp MinBandWidthDown MinBandWidthUp
);
......
sub ins_qos
{
  my $self = shift;
  $self->actua( InsertQoS => @_ );
}
sub del_qos
{
  my $self = shift;
  $self->actua( DeleteQoS => @_ );
}
sub actua {
  my ( $self, $action, $ip, $id_cola, $rate, $ceil, $prio ) = @_;

  my $cmd = $self->format( $self->{"\u${action}Cmd"}, {
	Id_cola => $id_cola,
	Rate    => $rate,
	Ceil    => $ceil,
        Prio    => $prio,
	IP      => $ip,
  });

  local %ENV = %ENV;
  $ENV{$_} =(defined( $self->{$_}) ? $self->{$_} : "" ) for @Perform_Export;
  $ENV{PATH} = 
  "$FindBin::Bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";
  system $cmd;
}
Para que esto funcione se han definido en el archivo de configuración de la pasarela las directivas:
# Ancho de banda minimo y maximo por defecto
MinBandWidthDown 35Kbit
MinBandWidthUp 23Kbit
MaxBandWidthDown 140Kbit
MaxBandWidthUp 95Kbit
Los métodos ins_qos y del_qos del firewall se invocan en el momento que el usuario entra en el sistema y cuando sale del mismo respectivamente: Recapitulando, ya hemos visto como pasar los parámetros de calidad del servidor, como crear la nueva clase para ese usuario y como borrarla. Lo que nos falta por ver es la forma de devolver al servidor el identificador de cola de dicha clase, para que lo introduzca otra vez en la pila. Para esto se ha creado un pequeño script en el servidor que llama a la función libera_id del módulo ControlNocat.pm. Lo único que hace esta función es insertar una nueva fila en la tabla id_cola con el identificador devuelto. Este script debe ser invocado por la pasarela en varios casos: Para invocar el script libera_id la pasarela vuelve a usar el proceso p_remoto.
next up previous contents
Siguiente: Políticas de acceso Subir: Detalles Implementación Anterior: Comprobación de datos de   Índice General
Jesús Martín 2003-09-16
e-REdING. Biblioteca de la Escuela Superior de Ingenieros de Sevilla.


SISTEMA DE CONTROL, TARIFICACIÓN Y ADMINISTRACIÓN DEL ACCESO A INTERNET DESDE REDES HETEROGÉNEAS

: Martín Ruiz, Jesús
: Ingeniería Telecomunicación
Contenido del proyecto: