Freeradius style « DHCP » et haute disponibilité

Aujourd’hui, nous allons installer des serveurs Radius qui distribueront des adresses IP à des équipements munis de cartes SIM Data.

Le contexte

Nous sommes dans une entreprise qui a environ 2000 équipements équipés de cartes SIM Data. Ces équipements doivent être capables de récupérer une adresse IP et des serveurs DNS via un APN dédié.

Facile ! Il suffit d’aller voir Bouygues Telecom, SFR ou Orange (FT, Orange Business Services et C°), et ils nous installent un bel APN dédié avec le nom qu’on veut en 5 minutes (ou plutôt 6 mois minimum avec 100 réunions, 100 tests qui échouent et pas mal d’€ dépensés). Bref le sujet est autre et enfin, un jour, l’APN dédié est livré.

Nous, on souhaite avoir les radius chez nous pour mieux contrôler ce qu’il se passe de bout en bout. On choisit bien entendu une solution Open Source qui sera faite de 2 serveurs Linux Debian Squeeze pour la haute disponibilité et qui embarqueront chacun un service FreeRadius.

Exemple d'architecture redondée

 

 

La gestion de l’authentification et de l’autorisation

Il faut bien comprendre que le client Radius est le GGSN/NAS de l’opérateur Télécom et c’est donc lui qui va demander à notre serveur Radius de délivrer l’adresse IP. Dans un 1er temps, l’équipement va s’authentifier sur l’APN dédié et communiquer son login utilisateur et son mot de passe. Le GGSN va relayer les identifiants de connexion à notre Radius en créant une requête Access-Request qui contiendra la futur IP destinée à l’équipement.

Exemple de requête :

Packet-Type = Access-Request
 Calling-Station-Id = "33650xxxxxx"
 User-Name = "user@mondomaine.fr"
 NAS-IP-Address = 192.xx.xx.xx
 NAS-Identifier = "ggsn1"
 Service-Type = Framed-User
 Framed-Protocol = GPRS-PDP-Context
 NAS-Port-Type = Wireless-Other
 Called-Station-Id = "apn.fr"
 NAS-Port = 235858

Notre Radius va lui répondre par un Access-Accept (ou Access-Reject).

Exemple de requête :

Packet-Type = Access-Accept
 Login-IP-Host = IP du radius
 Framed-Route = (?)
 MS-Primary-DNS-Server = IP DNS primaire
 MS-Secondary-DNS-Server = IP DNS secondaire
 Framed-IP-Address = IP allouée à l'équipement

source : http://en.wikipedia.org/wiki/RADIUS

Accounting request

Une fois que l’équipement est autorisé à utiliser le réseau, le GGSN/NAS va envoyer une requête Accounting Start à notre Radius pour lui indiquer que l’équipement est actuellement connecté au réseau. Lorsque l’équipement se déconnectera du réseau, le GGSN le détectera et l’indiquera à notre Radius en envoyant une requête Accounting Stop. La conséquence pour notre Radius sera de libérer l’adresse IP.

http://en.wikipedia.org/wiki/RADIUS

 

Le module rlm_ippool de Freeradius

Par la suite on comprend vite quand utilisant le module rlm_ippool de Freeradius, on va se retrouver très vite avec un problème au niveau du pool d’adresses IP. En effet le vieillissement des IP n’est pas pris en compte avec ce module.
Lorsqu’un équipement va se connecter la 1ère fois, tout va bien se passer. Puis cet équipement va rebooter ou se déconnecter, alors le GGSN/NAS de l’opérateur Télécom va indiquer à notre Freeradius de libérer l’adresse IP (requête Accounting Stop). Cependant il arrive souvent (par expérience) que la requête de libération d’IP envoyée par le GGSN/NAS n’arrive pas au Radius. Comme l’architecture redondée des GGSN de notre opérateur Télécom fonctionne en ACTIF/ACTIF ou en ACTIF/PASSIF, il se peut que le GGSN qui avait initié la connexion ne soit pas le même qui la termine. Par conséquent, lentement mais surement, il n’y a plus d’adresse à distribuer et plus aucun nouvel équipement ne peut se connecter.

Nous allons donc utiliser dans cet article le module rlm_sqlippool qui permet d’indiquer une durée de vie aux adresses IP, un peu à la façon d’un serveur DHCP.

Installation des Freeradius avec le module rlm_sqlippool

Après avoir installé la Debian, on installe sur chaque serveur :

Mysql

apt-get update
apt-get install mysql-server

Freeradius

apt-get update
apt-get install freeradius
apt-get install freeradius-mysql

Configuration

Mysql

Création de la base :

# mysql -u root -p
mysql> CREATE DATABASE freeradius

Création de l’utilisateur pour la base :

mysql> CREATE USER 'userfreeradius'@'localhost' IDENTIFIED BY 'pwdfreeadius';
mysql> GRANT USAGE ON * . * TO 'userfreeradius'@'localhost' IDENTIFIED BY 'pwdfreeadius';
mysql> GRANT ALL PRIVILEGES ON `freeradius` . * TO 'userfreeradius'@'localhost';

Création des tables :

# mysql -u userfreeradius -p pwdfreeadius freeradius < /etc/freeradius/sql/mysql/schema.sql
# mysql -u userfreeradius -p pwdfreeadius freeradius< /etc/freeradius/sql/mysql/nas.sql
# mysql -u userfreeradius -p pwdfreeadius freeradius < /etc/freeradius/sql/mysql/ippool.sql

Paramétrage des fichiers Freeradius

– Éditer le fichier /etc/freeradius/radiusd.conf et décommenter dans la section « modules » les lignes suivantes :

$INCLUDE sqlippool.conf
$INCLUDE sql.conf

– Éditer le fichier /etc/freeradius/sql.conf et renseigner les champs relatifs à la base de données :

sql {
 database = "mysql"
 driver = "rlm_sql_${database}"
 server = "localhost"
 #port = 3306
 login = "userfreeradius"
 password = "pwdfreeradius"
 radius_db = "freeradius"
 acct_table1 = "radacct"
 acct_table2 = "radacct"
 postauth_table = "radpostauth"
 authcheck_table = "radcheck"
 authreply_table = "radreply"
 groupcheck_table = "radgroupcheck"
 groupreply_table = "radgroupreply"
 usergroup_table = "radusergroup"
 read_groups = yes
 deletestalesessions = yes
 sqltrace = no
 sqltracefile = ${logdir}/sqltrace.sql
 num_sql_socks = 150
 connect_failure_retry_delay = 60
 lifetime = 0
 max_queries = 0
 readclients = yes
 nas_table = "nas"
 $INCLUDE sql/${database}/dialup.conf
}

– Éditer le fichier /etc/freeradius/users. C’est ce fichier qui indique comment on authentifie et on autorise les clients. C’est aussi dans ce fichier que vous indiquez les DNS qui seront reçus par les clients. (man page : http://freeradius.org/radiusd/man/users.html et pour la liste des attributs : http://www.freeradius.org/rfc/attributes.html)

user@mondomaine.fr Pool-Name := "pool1", # indique le pool IP à utiliser
 NAS-IP-Address == 192.X.X.X, # vérifie l'adresse IP du GGSN (NAS)
 User-Password := "test", # vérifie le mot de passe utilisateur
 MS-Primary-DNS-Server = @IP_DNS_PRIMAIRE,
 MS-Secondary-DNS-Server = @IP_DNS_SECONDAIRE,
 Fall-Through = yes # si les conditions ne sont pas remplies, il faut tester avec la suite
user@mondomaine.fr Pool-Name := "pool2", # indique le pool IP à utiliser
 NAS-IP-Address == 192.Y.Y.Y, # vérifie l'adresse IP du GGSN (NAS)
 User-Password := "test", # vérifie le mot de passe utilisateur
 MS-Primary-DNS-Server = @IP_DNS_PRIMAIRE,
 MS-Secondary-DNS-Server = @IP_DNS_SECONDAIRE,

– Éditer le fichier /etc/freeradius/sqlippool.conf :

sqlippool {
 sql-instance-name = "sql"
 ippool_table = "radippool"

 ## IP lease duration. (Indiquez ici la durée de vie des IP)
 lease-duration = 86400 # 24 H

 pool-key = "%{NAS-Port}"
 $INCLUDE sql/mysql/ippool.conf

 ...
}

– Éditer le fichier /etc/freeradius/sites-available/default et modifier la section « accounting » tel que :

#  Return an address to the IP Pool when we see a stop record.
# main_pool
sqlippool

Et dans la section « post-auth » :

#  Get an address from the IP Pool.
# main_pool
sqlippool

Vérifiez qu’il existe bien un lien symbolique de /etc/freeradius/sites-enable/default vers /etc/freeradius/sites-available/default

 

– Éditer le fichier /etc/freeradius/clients.conf et indiquer l’adresse IP des 2 GGSN ainsi que le secret partagé :

client 192.xx.xx.xx {
      secret    = mysecret
      shortname = GGSN1
      nastype   = other
}

client 192.yy.yy.yy {
      secret    = mysecret
      shortname = GGSN2
      nastype   = other
}

Création du Pool IP

Ajouter le pool d’IP dans la table radippool pour le GGSN1 :

mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool1', '192.168.0.1');
mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool1', '192.168.0.2');
mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool1', '192.168.0.3');
mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool1', '192.168.0.4');
...

Puis pour le GGSN2 :

mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool2', '192.169.0.1');
mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool2', '192.169.0.2');
mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool2', '192.169.0.3');
mysql> INSERT INTO radippool (pool_name, framedipaddress) VALUES ('pool2', '192.169.0.4');
...

Test

L’équipement se connecte le 08/06/2010 à 17h17 et on a dans la base de données :

id
pool_name
framedipaddress
nasipaddress
callingstationid
expiry_time
username
pool_key
1
pool1
192.168.0.1
192.xx.xx.xx
33650xxxxxx
2010-06-09 17:17:47
user@mondomaine.fr
136042

Quand l’équipement se déconnectera, soit le GGSN envoie bien une requête « Accounting Stop » et le champ « expiry_time » passera à NULL, soit nos radius ne reçoivent rien et l’adresse IP pourra être à nouveau utilisée lorsque sa durée de vie aura expirée.

Vus : 3834
Publié par Vince : 7