Installation et utilisation de OpenSER comme un routeur SIP

2007-04-10

Switzernet Sàrl

 

Introduction. 1

Installation. 2

Pré requis. 2

MySQL. 2

Programmes utiles. 3

SSH. 3

NTP. 3

Syslog. 3

Divers. 4

Installation d’OpenSER. 4

Configuration d’OpenSER. 5

Paramètres globaux. 6

Adresse du serveur 6

Mode debug. 6

Mode normal (service) 6

Modules. 7

tm.so. 7

mysql.so. 8

dispatcher.so. 8

acc.so. 8

pdt.so. 8

xlog.so. 9

Configuration réseau avec VPN. 10

Configuration OpenSER. 10

Configuration Debian. 10

Interfaces réseau. 10

Routage. 11

 

Introduction

On décrit ici l’installation et l’utilisation d’un serveur OpenSER sous Linux Debian. Après avoir suivi ce guide, on aura un serveur opérationnel (mais non configuré). OpenSER est un fork de SIP Express Router (SER). Ils présentent donc de très grandes similitudes, et leurs fichiers de configuration sont en grande partie compatibles. Comme principales différences, OpenSER est mieux documenté et intègre plus rapidement de nouvelles fonctionnalités.

 

OpenSER a de nombreuses fonctionnalités dans le cadre des appels VOIP. Il peut gérer les registrations, l’accounting, les échanges RADIUS, etc. Ici, nous traiterons principalement de la partie routage d’appels SIP (utilisation de SER en tant que softswitch). Voici un exemple typique d’utilisation de notre routeur SIP :

 

Installation

Pré requis

MySQL

Pour pouvoir loguer les paquets SIP et utiliser le routage selon l’indicatif avec une base de données, on doit installer une base de données MySQL (ou PostgreSQL selon les préférences).

 

Toujours avec Synaptics ou apt-get, on installe le paquet mysql-server (c’est un méta paquet, qui installera dans notre cas mysql-server-5.0 et ses dépendances). Si le service n’est pas démarré automatiquement, la commande "/etc/init.d/mysql start" va le lancer.

 

Un script est fourni pour gérer la base de données MySQL utilisée par OpenSER. Ici on va simplement créer un utilisateur et une base de données openser, ainsi que les tables nécessaires. Il suffit d’exécuter le script /usr/sbin/openser_mysql avec l’argument "create". On peut garder toutes les valeurs par défaut (on appuie simplement sur entrée à chaque choix) :

 

switzernet8:~# /usr/sbin/openser_mysql create

MySql password for root:

Domain (realm) for the default user 'admin':

creating database openser ...

Enter password:

Install SERWEB tables ?(y/n):y

 

L’utilisateur openser aura des droits différents en fonction du mot de passé utilisé :

 

On peut se loguer directement sur MySQL pour vérifier que tout est correct. On utilise toujours le compte openserrw :

 

switzernet8:~# mysql -p -u openser

Enter password:

Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 13

Server version: 5.0.38-Debian_1-log Debian etch distribution

 

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

 

mysql> show databases;

+--------------------+

| Database           |

+--------------------+

| information_schema |

| openser            |

+--------------------+

 

Si l’utilisateur "openser" peut bien se loguer avec le mot de passe "openserrw" et que la base de données "openser" a bien été créée, tout est bien configuré.

Programmes utiles

SSH

Pour administrer le serveur à distance, il est indispensable d’utiliser un serveur SSH. On installe donc le paquet "ssh", méta paquet qui installera "openssh-server". On démarre ensuite le serveur par la commande :

 

/etc/init.d/ssh start

NTP

Pour toujours avoir l’heure et la date correctement réglées, on va installer un client NTP, qui permettra à notre serveur de se connecter à un serveur de temps sur internet. On installe donc le paquet "ntp". La configuration par défaut est suffisante, il nous suffit donc de lancer le service par la commande :

 

/etc/init.d/ntp start

 

Par contre, il faut ici avoir configuré le DNS correctement, sinon on ne pourra pas se connecter au serveur NTP. On peut aussi vérifier que le fuseau horaire soit correctement configuré (dans le fichier "/etc/timezone") :

 

openser2:~# cat /etc/timezone

Europe/Zurich

Syslog

Syslog est installé par défaut sous Debian (ainsi que sur quasiment toute distribution Linux). On va ici simplement le configurer pour rediriger les logs d’OpenSER vers un fichier particulier. La configuration se fait dans "/etc/syslog.conf". On y ajoute simplement une ligne qui va indiquer dans quel fichier envoyer les logs provenant d’OpenSER. Le matching se base sur le log facility et le niveau d’alerte, sous forme "<facility>.<level>". Ici on utilise le facility "local0" comme défini dans la configuration d’OpenSER, et tous les niveaux d’alerte ".*". On choisit enfin d’envoyer les logs concernés vers le fichier "/var/log/ser.log".

 

 

mail.*                          -/var/log/mail.log

user.*                          -/var/log/user.log

uucp.*                          /var/log/uucp.log

 

# OpenSER

local0.*                        /var/log/ser.log

 

Finalement, on redémarre le service syslog :

 

/etc/init.d/sysklogd restart

 

Si le fichier ser.log n’est pas crée automatiquement on peut le créer avec la commande :

 

touch /var/log/ser.log

Divers

 

Par exemple pour une installation de Debian Etch, on aura :

 

# deb cdrom:[Debian GNU/Linux testing _Etch_ - Official Beta i386 CD Binary-1 20070317-21:45]/ etch contrib main

 

            Une fois mis en commentaire.

 

 

apt-get update                                        Met à jour la liste des paquets

apt-get install <package_name>           Installe le paquet désiré

 

 

 

Installation d’OpenSER

On va maintenant installer le serveur OpenSER. Sous Linux Debian (et la plupart des autres distributions), il est intégré dans le gestionnaire de paquets. On peut donc l’installer directement par exemple avec Synaptic si une interface graphique est présente sur le serveur :

 

 

Cependant, si on veut avoir la dernière version disponible d’OpenSER (version 1.2.0 au moment de l’écriture de ce guide), qui permet par exemple d’utiliser des variables dans le script de configuration, on ne peut pas utiliser directement les dépôts par défaut. De même, nous n’avons pas utilisé le dépôt officiel d’OpenSER, car celui-ci proposait encore seulement des paquets pour Debian Sarge, ce qui créait des incompatibilités de version à l’installation du module SQL.

 

On l’installe donc à la main, en récupérant d’abord les paquets pour Debian Etch sur le site d’OpenSER :

 

http://www.openser.org/pub/openser/latest/packages/deb-etch/

 

Le paquet de base est openser. On a aussi besoin de openser-mysql-module pour le lien avec une base de données MySQL (pour l’accounting et le module PDT), et openser-radius-modules si on veut utiliser l’authentification par RADIUS. On installe ensuite les paquets désirés avec la commande :

 

dpkg --install <paquet.deb>

 

Configuration d’OpenSER

Les fichiers de configuration d’OpenSER sont installés par défaut dans le répertoire /etc/openser. Le fichier principal est openser.cfg. La configuration se fait en écrivant un script qui décrit les actions à effectuer pour chaque paquet reçu. On a donc une très grande flexibilité pour gérer les appels SIP.

Paramètres globaux

Adresse du serveur

On indique l’adresse du serveur et le (les) ports sur lesquels écouter. Par défaut on écoute uniquement sur une seule interface réseau, et sur le port de signalisation SIP 5060 :

 

listen=<adresse IP du serveur SER>

port=5060

 

Si on écoute sur plusieurs interfaces (réelles ou virtuelles), il est très utile d’utiliser le paramètre "mhomed", qui permettra à OpenSER de savoir à partir de quelle interface envoyer les paquets sortants :

 

#Set the server to try to locate outbound interface on multihomed host.

#By default is not (0) - it is rather time consuming.

#no need of force_send_socket()

mhomed=1

 

listen=<adresse IP #1>

listen=<adresse IP #2>

port=5060

Mode debug

Pour mettre au point notre configuration de départ, il est beaucoup plus pratique de lancer openser en mode debug. Le programme va donc rester en avant-plan, et les messages vont s’imprimer sur la sortie standard (ici la console) au lieu d’être loggués par Syslog. On peut régler le niveau de debug selon la quantité d’information qu’on veut obtenir.

 

debug=3

fork=no

log_stderror=yes

 

En mode de debug, on lance openser par la commande :

 

"openser" ou "openser –f <fichier de configuration>".

Mode normal (service)

En mode normal, le programme va lancer de multiples instances et se comporter comme un démon. On adapte donc le fichier de configuration d’Openser en conséquence :

 

debug=3

fork=yes

log_stderror=no

log_facility=LOG_LOCAL0

log_name="SER"

 

En mode service, il est recommandé d’utiliser un niveau de log de 3. Deux nouveaux paramètres nous permettent de contrôler la destination et le format des logs qui seront transmis à Syslog. Ici on utilise la facility "LOG_LOCAL0" (vérifier que cela correspond à la configuration de Syslog), et on modifie le nom qui apparaîtra dans les logs pour ne pas afficher trop de choses inutiles.

 

Au final, on obtiendra donc dans le fichier "/var/log/ser.log" des informations sous la forme :

 

May 23 12:02:54 localhost SER[9359]: [+4121693XXXX to +4121550XXXX] ACK +4121550XXXX@195.XXX.XXX.XXX, 212.XXX.XXX.XXX to 195.XXX.XXX.XXX (390-0)

May 23 12:02:58 localhost SER[9360]: [+4121693XXXX to +4121550XXXX] ACK +4121550XXXX@195.XXX.XXX.XXX, 212.XXX.XXX.XXX to 195.XXX.XXX.XXX (390-0)

 

Evidemment tout dépendra de ce qu’on décide de loguer dans le fichier de configuration d’OpenSER.

 

La configuration générale du service se trouve dans le fichier "/etc/default/openser". On a juste à changer la valeur de la variable "RUN_OPENSER", de "no" à "yes" :

 

#

# OpenSER startup options

#

 

# Set to yes to enable openser, once configured properly.

RUN_OPENSER=yes

 

# User to run as

USER=openser

 

# Group to run as

GROUP=openser

 

# Amount of memory to allocate for the running OpenSER server (in Mb)

MEMORY=64

 

# Enable the server to leave a core file when it crashes.

# Set this to 'yes' to enable OpenSER to leave a core file when it crashes

# or 'no' to disable this feature. This option is case sensitive and only

# accepts 'yes' and 'no' and only in lowercase letters.

DUMP_CORE=no

 

Le service OpenSER se lancera automatiquement au démarrage de l’ordinateur. On peut aussi démarrer ou stopper OpenSER avec le script d’init fourni :

 

/etc/init.d/openser start/stop/restart

Modules

Dans OpenSER, les modules sont des librairies chargées à la demande, qui fournissent des fonctionnalités supplémentaires (de nouvelles fonctions ou variables). Les principaux modules utilisés par défaut sont ceux qui gèrent les transactions, en stateful ou stateless (tm.so et sl.so) ainsi que le modules fournissant les fonctions de routage (rr.so). La documentation des différents modules est disponible à l’adresse (à adapter à la version utilisée) :

 

http://www.openser.org/docs/modules/1.2.x/

 

En plus des modules de base chargés par la configuration par défaut, on va utiliser certains modules supplémentaires. On indique les modules à utiliser dans le fichier de configuration, avec la commande loadmodule "<nom du module>.so".

 

Pour éviter d’entrer le chemin complet de chaque module, on peut spécifier le répertoire ou sont situés les modules au début du fichier de configuration d’OpenSER :

 

mpath="/usr/lib/openser/modules"

tm.so

Ce module prend en charge toute la partie transaction "stateful" lors des échanges SIP. C’est un module indispensable et chargé par défaut. Comme paramètres utiles, on peut modifier les délais de timeout. Par exemple pour diminuer à 10 secondes le délai avant d’annuler l’appel au cas ou un hôte ne répond pas, on peut utiliser :

 

modparam("tm", "fr_timer", 10)

mysql.so

Ce module permet de communiquer avec une base de données MySQL. Il sera utilisé pour l’accounting et le module PDT.

dispatcher.so

Ce module fournit une méthode automatisée pour gérer le load balancing entre différents gateways SIP.

acc.so

Ce module effectue l’accounting (logue les paquets reçus). On peut l’utiliser soit avec une base de données, soit en envoyant les informations à Syslog. Pour loguer les paramètres dans la base de données, on entre les paramètres suivants :

 

modparam("acc", "db_url", "mysql://openser:openserrw@localhost/openser")

modparam("acc", "db_flag", 1)            # flag pour les "appels réussis"

modparam("acc", "db_missed_flag", 2)     # flag pour les "appels manqués"

 

Par défaut, les paquets avec un statut d’erreur seront inscrits dans la table missed_calls, et les paquets avec un statut normal dans la table acc. Toutefois, il faut marquer nous-même le statut du paquet dans le script de configuration, en utilisant dans notre cas les commandes :

 

setflag(1); ou setflag(2);

 

La table MySQL ou seront stockées les informations d’accounting contient les champs suivants :

 

+------------+--------------+------+-----+---------------------+-------+

| Field      | Type         | Null | Key | Default             | Extra |

+------------+--------------+------+-----+---------------------+-------+

| sip_from   | varchar(128) | NO   |     |                     |       |

| sip_to     | varchar(128) | NO   |     |                     |       |

| sip_status | varchar(128) | NO   |     |                     |       |

| sip_method | varchar(16)  | NO   |     |                     |       |

| i_uri      | varchar(128) | NO   |     |                     |       |

| o_uri      | varchar(128) | NO   |     |                     |       |

| from_uri   | varchar(128) | NO   |     |                     |       |

| to_uri     | varchar(128) | NO   |     |                     |       |

| sip_callid | varchar(128) | NO   | MUL |                     |       |

| username   | varchar(64)  | NO   | MUL |                     |       |

| domain     | varchar(128) | NO   |     |                     |       |

| fromtag    | varchar(128) | NO   |     |                     |       |

| totag      | varchar(128) | NO   |     |                     |       |

| time       | datetime     | NO   |     | 0000-00-00 00:00:00 |       |

| timestamp  | timestamp    | NO   |     | CURRENT_TIMESTAMP   |       |

| src_leg    | varchar(128) | YES  |     | NULL                |       |

| dst_leg    | varchar(128) | YES  |     | NULL                |       |

+------------+--------------+------+-----+---------------------+-------+

 

On remarque ici que SER ne gère pas l’appel complet, mais a uniquement la notion des transactions SIP. Par exemple on n’aura pas ici la durée d’appel, mais une entrée pour chaque transaction (avec les messages INVITE, ACK, CANCEL et BYE logués séparément).

 

Pour utiliser le module acc avec une sortie vers Syslog, on utilise le paramètre suivant :

modparam("acc", "log_level", 1)

pdt.so

Ce module permet d’utiliser une table SQL avec des règles de routage selon le pattern du numéro appelé et l’adresse IP du serveur source (sdomain). On l’utilise pour changer l’adresse IP du serveur de destination (domain). Ces règles de routage sont stockées dans la table pd_multidomain de la base de donnée pdt.

Création de la table :

La base de données pdt n’est pas crée par le script fourni par OpenSER, mais un script spécifique au module est disponible. Comme il est utile de le modifier pour ajouter un attribut "description" à chaque couple sdomain/prefix, on utilise un script (pdt.sql) légèrement modifié est disponible :

 

DROP DATABASE IF EXISTS pdt;

CREATE DATABASE pdt;

USE pdt;

 

-- create table

CREATE TABLE pd_multidomain (

        sdomain VARCHAR(255) NOT NULL,

        prefix VARCHAR(32) NOT NULL,

        domain VARCHAR(255) NOT NULL DEFAULT "",

        description VARCHAR(255) NOT NULL DEFAULT "",

        PRIMARY KEY (sdomain, prefix)

);

 

-- give permissions tu openser user

GRANT ALL ON pdt.pd_multidomain TO openser;

 

Après l’avoir exécuté (avec les droits de l’utilisateur MySQL root), on a donc une nouvelle base de données pdt, qui contient la table pd_multidomain :

 

+-------------+--------------+------+-----+---------+-------+

| Field       | Type         | Null | Key | Default | Extra |

+-------------+--------------+------+-----+---------+-------+

| sdomain     | varchar(255) | NO   | PRI |         |       |

| prefix      | varchar(32)  | NO   | PRI |         |       |

| domain      | varchar(255) | NO   |     |         |       |

| description | varchar(255) | NO   |     |         |       |

+-------------+--------------+------+-----+---------+-------+

 

On peut par exemple y insérer une nouvelle ligne avec la commande suivante :

INSERT INTO pd_multidomain VALUES("128.179.67.78", "41", "128.179.67.35", "SIP1");

 

+----------------+---------+----------------+-------------+

| sdomain        | prefix  | domain         | description |

+----------------+---------+----------------+-------------+

| 128.179.67.76  | 41      | 212.XXX.XX.XXX | OUT1        |

| 128.179.67.78  | 4121550 | 128.179.67.35  | SIP1        |

+----------------+---------+----------------+-------------+

Problemes à revoir:

1)       il faut absolument mettre une destination (est-ce qu’on peut mettre ‘%’ pour tous les destinations ?) et domain source

xlog.so

Ce module simplifie l’affichage de messages, où on peut utiliser des variables et des couleurs.

Variables :

De nombreuses variables peuvent aussi être affichées, en utilisant la syntaxe $<nom de variable>. La liste des variables utilisables est disponible dans la documentation :

 

http://openser.org/dokuwiki/doku.php/pseudovariables:1.2.x

 

Pour du routage simple, on utilise principalement les variables suivantes :

$fd                  "From domain", le domaine source du paquet

$tu                  "To URI", URI SIP de destination du paquet (reste fixe)

$ruri              URI SIP de destination du paquet (est mise à jour après des opérations telles que "rewritehost")

Couleurs :

Pour les couleurs on utilise des balises notées $Cab, ou le "a" représente la couleur du premier plan, et le "b" la couleur de l’arrière-plan. De plus, la lettre "x" représente la couleur par défaut du terminal.

 

Par exemple pour écrire une ligne en bleu sur fond blanc (sur un terminal blanc à l’origine), on utilise :

 

xlog("$CbxLigne de texte.$Cxx\n);

 

Le $Cxx final remet les couleurs par défaut du terminal.

 

Configuration réseau avec VPN

Si l’un des serveurs SIP de destination filtre les adresses IP de destinations des paquets SIP, ou en cas de configuration particulière (par exemple utilisation d’un tunnel IPSec), il peut être utile d’avoir plusieurs interfaces réseau sur le serveur OpenSER. Ici nous décrivons l’utilisation d’OpenSER avec une interface réseau réelle et une autre virtuelle. Dans ce cas particulier, l’adresse IP de l’interface virtuelle n’est pas routable.

Configuration OpenSER

Pour la configuration d’OpenSER, rien ne distingue les interfaces réelles et virtuelles. Il suffit de mettre deux paramètres "listen" dans la configuration d’OpenSER. Si l’on a défini "mhomed=1" dans le fichier de configuration, le serveur devrait découvrir par quelle interface envoyer chaque paquet. Sans ce paramètre, on peut spécifier l’interface à utiliser en sortie avec la commande "force_send_socket(<adresse IP>)".

Configuration Debian

Interfaces réseau

Sous Linux Debian, on déclare une interface virtuelle dans le même fichier que les interfaces réelles, "/etc/network/interfaces". Sur notre serveur, la configuration est la suivante :

 

# This file describes the network interfaces available on your system

# and how to activate them. For more information, see interfaces(5).

 

# The loopback network interface

auto lo

iface lo inet loopback

 

# The primary network interface

allow-hotplug eth0

iface eth0 inet static

        address 212.XXX.XXX.XXX

        netmask 255.255.255.240

        broadcast 212.XXX.XXX.XXX

        gateway 212.XXX.XXX.XXX

auto eth0

 

iface eth0:0 inet static

        address 195.XXX.XXX.XXX

        netmask 255.255.255.255

        post-up /etc/network/if-post-up.d/add_routes_SIP.sh

auto eth0:0

 

eth0 est l’interface réelle. Elle est configurée traditionnellement. C’est donc là qu’on définit le gateway par défaut.

 

Sur cette interface on définit notre interface virtuelle, eth0:0. On utilise un masque de sous réseau de 255.255.255.255, comme elle ne fait pas partie d’un réseau (et n’est même pas routable).

 

Après redémarrage du réseau, cette configuration crée une route par défaut, qui renvoie les paquets à destination du sous réseau réel vers le gateway.

 

openser2:~# route -n

Kernel IP routing table

Destination    Gateway         Genmask         Flags Metric Ref    Use Iface

212.XXX.XX.X   0.0.0.0         255.255.255.240 U     0      0        0 eth0

0.0.0.0        212.XXX.XX.X    0.0.0.0         UG    0      0        0 eth0

 

On peut aussi vérifier que tout soit correct et que les interfaces sont bien montées ("up") avec la commande "ifconfig" :

 

openser2:~# ifconfig

eth0    Link encap:Ethernet  HWaddr 00:18:F3:FC:D3:CA

        inet addr:212.XXX.XX.X Bcast:212.XXX.XX.XX Mask:255.255.255.240

        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

        RX packets:759138 errors:0 dropped:0 overruns:0 frame:0

        TX packets:877477 errors:0 dropped:0 overruns:0 carrier:0

        collisions:0 txqueuelen:1000

        RX bytes:297606244 (283.8 MiB)  TX bytes:626141253 (597.1 MiB)

        Interrupt:177 Base address:0xe000

 

eth0:0  Link encap:Ethernet  HWaddr 00:18:F3:FC:D3:CA

        inet addr:195.XXX.XXX.XX Bcast:195.XXX.XXX.XXX Mask:255.255.255.255

        UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

        Interrupt:177 Base address:0xe000

 

lo      Link encap:Local Loopback

        inet addr:127.0.0.1  Mask:255.0.0.0

        inet6 addr: ::1/128 Scope:Host

        UP LOOPBACK RUNNING  MTU:16436  Metric:1

        RX packets:134109 errors:0 dropped:0 overruns:0 frame:0

        TX packets:134109 errors:0 dropped:0 overruns:0 carrier:0

        collisions:0 txqueuelen:0

        RX bytes:257876593 (245.9 MiB)  TX bytes:257876593 (245.9 MiB)

Routage

On va ensuite ajouter des règles de routage spécifiques, qui vont envoyer les paquets à destination de certaines adresses vers une destination particulière, et faire qu’ils proviennent de l’interface virtuelle eth0:0. Ici, on utilise ce système pour envoyer certains paquets SIP vers le point d’accès d’entrée d’un tunnel IPSec. En sortie du tunnel, les paquets seront donc vus comme provenant de l’interface virtuelle 195.XXX.XXX.XX.

 

On ajoute les règles suivantes, définies dans le fichier "/etc/network/if-post-up.d/add_routes_SIP.sh". Ce fichier est exécuté automatiquement après que l’interface eth0 soit montée. Ne pas oublier de le rendre exécutable avec la commande "chmod +x <fichier.sh>". Les route sont définies comme suit :

 

#!/bin/bash

 

route add -host 212.XXX.XX.XXX dev eth0:0 gw 212.XXX.XX.XX

route add -host 62.XXX.XX.X dev eth0:0 gw 212.XXX.XX.XX

 

Nous avons maintenant deux nouvelles règles dans notre table de routage (on remarque que la commande route indique eth0 et non eth0:0 pour l’interface utilisée, mais le routage spécifié est malgré tout correctement pris en compte) :

 

openser2:~# route -n

Kernel IP routing table

Destination    Gateway         Genmask         Flags Metric Ref    Use Iface

62.XXX.XX.X    212.XXX.XX.XX   255.255.255.255 UGH   0      0        0 eth0

212.XXX.XX.XXX 212.XXX.XX.XX   255.255.255.255 UGH   0      0        0 eth0

212.XXX.XX.X   0.0.0.0         255.255.255.240 U     0      0        0 eth0

0.0.0.0        212.XXX.XX.X    0.0.0.0         UG    0      0        0 eth0