Contexte et problématique ¶
Le filtrage de paquets est largement utilisé dans plusieurs appliances et applications réseau, en particulier pour bloquer le trafic malveillant (protéger les infrastructures réseau via des pare-feu et des systèmes de détection d'intrusion) et à déployer sur les routeurs, les commutateurs et les équilibreurs de charge pour la classification des paquets.
Ce mécanisme s'appuie sur les champs d'en-tête du paquet pour filtrer ce trafic en utilisant des règles de plage d'adresses IP ou de ports.
Cependant, l'ensemble de filtres de paquets doit gérer un nombre croissant de nœuds connectés et nombre d'entre eux sont compromis et utilisés comme sources d'attaques.
Par exemple, les ensembles de filtres IP disponibles dans les listes noires peuvent atteindre plusieurs millions d'entrées et peuvent nécessiter un espace mémoire important pour leur stockage dans les appareils de filtrage.
Numeryx propose une nouvelle méthode basée sur une représentation de préfixe IP à double masque avec un algorithme de transformation linéaire pour construire un ensemble minimisé de règles de plage.
Les règles de représentation du double masque sont définies formellement sur la plage et ils prouvent que le nombre de masques requis pour toute plage est au plus de 2w 4, où w est la longueur d'un champ.
Présentation de la solution ¶
Grâce à ses travaux de R&D menés depuis plusieurs années, la société Numeryx Technologies a pu développer une solution de sécurisation légère et performante, aujourd’hui brevetée : le filtrage IP à double masque.
La méthode de filtrage de paquets basée sur une nouvelle représentation des préfixes IP, associée à̀ un algorithme de transformation linéaire. Il s’agit de construire un ensemble minimisé de règles de plage.
La représentation contient 3 parties :
- Netref : utilisée pour représenter l'adresse réseau.
- Masque 1 : définit toutes les adresses IP acceptées.
- Masque 2 : toutes les adresses IP exclues de la liste des adresses IP acceptées.
Considérons l’exemple illustré le principe de fonctionnement du double masque dans la figure suivante :
Dans cette représentation, toute adresse sélectionnée (ou filtrée) doit avoir ses 26 premiers bits égaux aux 26 premiers bits 192.168.100.100, qui est égal au format binaire à 11000000.10101000.01100100.01 et au moins l'un des 2 bits suivants (27ème ou 28ème) ne doit pas être égal à sa valeur correspondante dans 192.168.100.100.
La figure ci-dessous illustre le fonctionnement du filtrage à double masque pour cet exemple spécifique.
Les listes noires d’IP ont été fournies par l’INRIA à travers des projets de partenariats avec notre société et se renforceront lors des nouveaux partenariats ou avec les clients.
L'utilisation de cette représentation permet d’augmenter la sécurité des réseaux et de configuration d’accès des pare-feux :
- Nous pouvons compresser, optimiser et distribuer les règles de filtrage puisque nous pouvons accepter et rejeter des adresses IP à l'aide d'une seule règle ;
- La configuration devient plus simple puisque l'ordre des règles n'affecte pas la décision finale de rapprochement ;
- On ajoute plus de flexibilité et efficacité dans le déploiement des règles.
Notre solution permet donc de garantir une continuité et une disponibilité du système.
Cette technologie a été utilisée par Numeryx Technologies et dans le cadre d’une thèse CIFRE sur les flux de routage en partenariat avec l’INRIA.
Les résultats de compression des règles sont présentés dans la figure suivante, dans le cas de données d’entrées synthétiques.
Les avantages qualitatifs et quantitatifs de la solution par rapport à une solution de filtrage IP standard sont les suivants :
- Diminution du nombre de règles de filtrage de 80 % dans le cas de données synthétisées ;
- Augmentation de l’efficacité du filtrage ;
- Réduction des contraintes d’une TCAM pour maximiser le stockage des règles de routage et de filtrage ;
- Diminution du temps de traitement des requêtes firewall ;
- Gain en ressources (CPU, RAM, DISK).
Conception et Cycle de vie ¶
Le plugin fdm est conçu pour être paramétrer depuis une interface utilisateur(front-end) et aussi depuis la ligne de commande (back-end).
Ceci dit , le plugin fdm interagit avec différentes composantes du DMSsdwan et dévéloppé en utilisant différents langages de programmation qui sont :
- HTML5 + CSS3 + javascript + jQuery ( front-end )
- PHP7 ( back-end part 1 )
- C ( back-end part 2 : kernel UNIX BSD )
Le modèle ci-dessus présente le cycle de vie et le fonctionnement du service "Filtre double masque".
Le cycle de vie du fdm nous permettera de comprendre son fonctionnement ainsi que les différentes parties du systeme avec les quelles il interagit :
- L'action qui suit est attachée à l'activation ET le sauvegarde d'une nouvelle régle dans le pare-feu : fdm charge le fichier XML situé dans /conf/config.xml et extrait les regles <rule> qui sont dans la balise <filter>
-
Le controlleur du plugin fdm situé dans
/usr/local/dmssdwan/mvc/app/controllers/DMSsdwan/fmd/Api/SettingsController.php
se charge du traitement des régles extraites
pour les comprésser selon les techniques des algorithmes double masques, et les transformer en une structure qui nous est propre et les sauvgarder dans un fichier xml situé sous
/conf/fdm.xml.
chaque régle du fichier fdm.xml comprend une <action>, une <source_sm>, et une/ou plusieurs <destin_dm>.
Le noeud <brut_trace> est là pour des raisons de débugage, le noeud <brut> contient les donnée qui seront traitées par le noyau UNIX par la suite. - Le fichier SettingsController.php communique avec le fichier pfctl.c à travers les fonctions C : void disable_fdm(void) qui permet de désactiver le plugin, et la fonction C void enable_fdm(void) qui permet d'activer le plugin.
-
Lors de son activation, fdm écrit dans se qu'on appelle des "character devices" (/dev/), l'un est nomé "fdm_s" et dans lequel le status du fdm est sauvgardé (enabled=1, disabled=0), l'autre est nomé "fd_masks" et dans lequel le contenu du noeud <brut> , précédement défini, est sauvgardé.
La creation de ces "character devices" se fait au niveau du fichier pf.c.
Dans le fichier pfctl.c, les commandes suivantes sont définis : "pfctl -w" pour désactiver le fdm, et "pfctl -y" pour activer le fdm.
NB:Si vous remarquez un comportement anormal du plugin fdm, pensez à augmentez la taille de la mémoire réservée pour le "brut" dans le fichier pfctl.c
char brut_content[10000];
char command[12800]; -
Le fdm est intégré pour fonctionner en parfaite harmonie avec le module Kernel PF(packet filtering).
Au niveau du noyau UNIX, on fait un "hook" du fdm attaché à la fonction de filtrage du PF nomée "pf_test()" et défini dans le fichier pf.c, ainsi, si notre plugin est activé, on traite l'adresse IP avec des fonctions qui sont propres au double masques (définis dans pf.c), sinon le PF fera sont travail ordinaire.
C'est la fonction pf_test() qui est responsable de prendre la décision de faire passer ou bloquer une adresse IP donnée (PF_PASS et PF_DROP).
Intégration du module ¶
Objectif ¶
L'objectif du module « Filter à double masque » que nous créons dans l'exemple est de filtrer les adresses IPs.
Des lignes directrices ¶
Des lignes directrices et styles de codage
Pour tous les modules et applications DMSsdwan, il existe des guides de style et de codage de base à utiliser.
Appellation ¶
Lors de la création de modules pour DMSsdwan, nommez toujours vos composants comme suit: VendorName / ModuleName
Dans notre cas, ce serait: DMSsdwan/fdm
Code PHP ¶
Utilisez le style PSR-2 ( http://www.php-fig.org/psr/psr-2/ ) pour tout nouveau code.
Architecture ¶
Assurez-vous toujours qu'il y a une séparation claire des préoccupations, les appels back-end (tels que les scripts shell) doivent être implémentés à l'aide du système configd, toutes les communications avec le client doivent être effectuées à partir d'un point de terminaison API. (L'exemple fournit plus d'informations sur la façon dont cela fonctionne).
Les programmes back-end ne doivent pas avoir un accès direct à config.xml si les données sont laissées au système standard gérer la sortie souhaitée (la plupart des applications, démons et outils fournissent leur propre configuration de format souhaitée). Il n'y a généralement aucune bonne raison d'éviter ces normes déjà présentes.
Si vous suivez ces règles de base, vous créez automatiquement une structure de commande pour les administrateurs système et fournissez un lien vers les outils tiers dans l'API de votre composant.
Squelette ¶
Configurer un squelette frontend / middleware
La première étape de notre projet est de créer un squelette qui contient la structure de notre frontend / middleware.
Modèle ¶
Pour l'exemple de notre application, nous souhaitons configurer certaines données de configuration qui, pour tous les nouveaux projets de type, doivent vivre dans leur propre modèle.
Nous commençons par créer deux fichiers dans le répertoire models/DMSsdwan/fdm.
Le premier est le passe-partout pour la classe de modèle, qui doit contenir des méthodes de modèle spécifiques et (en le dessinant à partir de BaseModel) comprend automatiquement le deuxième fichier.
<?php
namespace DMSsdwan\fdm;
use DMSsdwan\Base\BaseModel;
class fdm extends BaseModel
{
}
Tous les modules ne contiennent pas de code supplémentaire dans la classe PHP, parfois tout le comportement standard est déjà suffisant pour vos modules/application.
Quel est le modèle XML standard, notre squelette commence par quelque chose comme ceci:
<model>
<mount>//DMSsdwan/fdm</mount>
<description>
the DMSsdwan IP Filter double masks (fdm)
</description>
<items>
</items>
</model>
Le contenu de la balise mount est très important, c'est l'emplacement dans le fichier config.xml où ce modèle est responsable. Les autres modèles ne peuvent pas écrire de données dans la même zone. Vous devez nommer cet emplacement avec le nom de votre fournisseur et du module pour vous assurer que d'autres puissent facilement l'identifier.
Utilisez la balise de description pour identifier votre modèle, la dernière balise est la balise items, où la définition réelle vivra. Nous le laissons vide pour le moment alors que nous passons à l'étape suivante de création de notre squelette.
Vue ¶
Modèle de page (vue)
Nous devons ajouter un modèle (Volt) à utiliser sur notre page d'index de module. nous utiliserons la même convention de nommage ici.
Créez un modèle nommé index.volt dans le répertoire views/DMSsdwan/fdm qui contient les données suivantes:
<h1>Filtre à double masque</h1>
Contrôleur ¶
L'étape suivante consiste à ajouter des contrôleurs, qui seront automatiquement récupérés par le routage du système. Un contrôleur associe l'interaction de l'utilisateur à la logique et à la présentation.
Chaque module DMSsdwan doit séparer la présentation de la logique, c'est-à-dire parce qu'il doit toujours y avoir plusieurs contrôleurs par module.
Le premier contrôleur gère les performances du modèle pour l'utilisateur et connecte la vue utilisateur que nous venons de créer. Nous commençons par créer un fichier PHP dans controllers/DMSsdwan/fdm/ avec le nom suivant IndexController.php et le contenu:
<?php
namespace DMSsdwan\fdm;
class IndexController extends \DMSsdwan\Base\IndexController
{
public function indexAction()
{
// pick the template to serve to our users.
$this->view->pick('DMSsdwan/fdm/index');
}
}
À ce stade, vous devriez être en mesure de vérifier si votre travail a réussi jusqu'à présent en vous rendant à l'emplacement suivant (après vous être connecté au pare-feu en tant qu'utilisateur root):
http[s]://<your ip>/ui/fdm/
Cela vous servira "Filtre à double masque" texte que vous avez ajouté au modèle.
Les deux prochains contrôleurs que nous allons créer seront utilisés pour l'API dans le système, ils devront s'occuper des actions de service et de la récupération / modification des données de configuration.
Ils doivent résider dans un sous-répertoire du contrôleur appelé Api et étendre l'ordre correspondant.
Nous créons un contrôleurs d'API, pour contrôler les paramètres et pour effectuer des actions de service(Named SettingsController.php).
<?php
namespace DMSsdwan\fdm\Api;
use \DMSsdwan\Base\ApiControllerBase;
class SettingsController extends ApiControllerBase
{
}
Premier formulaire ¶
Création du premier formulaire d'activation
La première étape de la création de formulaires consiste à déterminer les informations que nous devons collecter.
Notre application simple activer le module en utilisant les données de notre configuration xml. Pour ce module, nous souhaitons collecter l'élément suivant :
Propriété |
Défaut |
La description |
---|---|---|
General.Enabled |
Enabled (1) |
Si ce module est activé (booléen) |
Ajouter des champs ¶
Ajouter des champs à votre modèle
Lors de la construction du squelette, nous avons créé un modèle vierge (XML), que nous allons maintenant remplir avec quelques attributs. La section des objets du modèle XML doit contenir la structure que vous souhaitez utiliser pour votre propre application, vous pouvez créer des arborescences pour contenir les données ici. Toutes les feuilles doivent contenir un type de champ permettant d'identifier et de valider son contenu. La liste des attributs de notre application peut être traduite en:
………
<items>
<!-- container -->
<general>
<!-- fields -->
<Enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</Enabled>
</general>
</items>
………
Tous les types de champs disponibles se trouvent dans le répertoire models/DMSsdwan/Base/FieldTypes. Si certains types de champs prennent en charge des paramètres supplémentaires, par exemple la validation, ils doivent également être enregistrés dans le modèle (tout comme la balise par défaut dans Activé).
Présentation XML ¶
Créez une présentation XML pour alimenter votre modèle
Parce que la création de formulaires est l'un des atouts clés du système, nous avons créé des wrappers faciles à utiliser pour vous guider tout au long du processus. Nous créons d'abord un fichier XML pour la présentation, qui définit les champs à utiliser et ajoute des informations pour rendre votre modèle. Créez un fichier dans le répertoire de votre contrôleur à l'aide des formulaires de sous-répertoire et nommez-le General.xml. Copie suivante dans le contenu suivant:
<form>
<field>
<id>fdm.general.Enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help>Enable DMSsdwan IP Filter double masks</help>
</field>
</form>
Toutes les données doivent contenir au moins un ID (où mapper les données de / vers), un type (mode d'affichage) et une étiquette, qui l'identifie à l'utilisateur. Facultatif, vous pouvez ajouter des champs supplémentaires comme l'aide ou marquer des fonctionnalités comme étant réservées aux utilisateurs avancés. (Le modèle Volt définit quels attributs sont utilisables.)
Maintenant, nous devons dire au contrôleur d'utiliser ces informations et de les transmettre à votre modèle, modifier IndexController.php et ajouter cette ligne:
$this->view->generalForm = $this->getForm("general");
Et nous sommes prêts à mettre à jour la modèle (Volt) avec ces informations. Supprimons la ligne "<h1> Filtre à double masque </h1>" et remplaçons-la par quelque chose comme ceci:
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_GeneralSettings'])}}
Cela indique au système de modèles d'ajouter un formulaire en utilisant le contenu de generalForm et de le nommer frm_GeneralSettings sur la page HTML. Basé sur une partie standard d'un modèle qui fait déjà partie du système standard, il est appelé base_form.volt.
Lorsque vous rouvrirez la page, elle ressemblera à ceci:
Générer des appels API ¶
Générer des appels API pour la récupération et le stockage des données
Le framework fournit des utilitaires utiles pour récupérer et définir des données à partir de et dans la configuration XML à l'aide de votre modèle spécifié. La première étape de la liaison de votre modèle au système consiste à ajouter une méthode à SettingsController pour récupérer les données de notre configuration (ou fournir des valeurs par défaut s'il n'y a pas de contenu).
Nous commençons par ajouter le modèle à SettingsController, en l'ajoutant à la section «utilisation»:
use \DMSsdwan\fdm\fdm;
Cela inclut notre modèle dans le contrôleur. Nous créons ensuite une action pour récupérer les données de notre système et les placer dans un objet json pour le client (navigateur) pour analyse, en utilisant les wrappers déjà présents dans notre modèle.
/* retrieve fdm general settings
* @return array general settings
*/
public function getAction()
{
// define list of configurable settings
$result = array();
if ($this->request->isGet()) {
$mdlfdm = new fdm();
$result['fdm'] = $mdlfdm->getNodes();
}
return $result;
}
Vous remarquerez probablement la valeur de retour de l'action, c'est une tableau standard qui utilise « fdm » pour tous les attributs de getNodes () qui seront automatiquement convertis par le framework en objet json pour le client. La méthode getNodes elle-même renvoie un arbre en valeurs, tel que défini par votre modèle.
Vous pouvez tester le résultat (en étant connecté en tant que root) en allant sur:
http[s]://<your ip>/api/fdm/settings/get
Pour sauvegarder les données, nous avons besoin d'un type d'appel similaire, appelons-le « set » et ajoutons-le au même fichier php:
/**
* update fdm settings
* @return array status
*/
public function setAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlfdm = new fdm();
$mdlfdm->setNodes($this->request->getPost("fdm"));
// perform validation
$valMsgs = $mdlfdm->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["general.".$msg->getField()] = $msg->getMessage();
}
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlfdm->serializeToConfig();
Config::getInstance()->save();
$status = $mdlfdm->getNodes()['general']['Enabled'];
if (empty($status)){
exec ('/sbin/pfctl -w');
}
$result["result"] = "saved";
$result["status"] = $status;
}
}
return $result;
}
La commande /sbin/pfctl -w est pour la désactivation du module et /sbin/pfctl -y pour l'activer, pour le fonctionnement des commandes il faut ajouter quelques instructions au niveau du fichier pfctl.c comme suit :
...
void disable_fdm(void);
void enable_fdm(void);
int system(const char *command);
void disable_fdm(void){
system("echo - n 0 > /dev/fdm_s");
}
void enable_fdm(void){
FILE *pipe_brut;
char brut_content[10000];
char command[12800];
pipe_brut = popen("xmllint --xpath '//dm_filter/brut/text()' /conf/fdm.xml","r");
fgets(brut_content, 10000, pipe_brut);
pclose(pipe_brut);
snprintf(command, sizeof(command) , "echo -n \"%s\" > /dev/fd_masks", brut_content);
system(command);
system("echo - n 1 > /dev/fdm_s");
}
int main(int argc, char *argv[]){
...
switch (ch){
case 'w' :
disable_fdm();
break;
case 'y' :
enable_fdm();
break;
...
Et incluez la classe Config de notre système principal en l'ajoutant à la section « use »:
use \DMSsdwan\Core\Config;
Prise en charge des appels d'API jQuery ¶
Mettez à jour la vue pour prendre en charge les appels d'API à l'aide de jQuery
Maintenant, nous devons associer les événements au code backend afin que nous puissions charger et enregistrer notre formulaire, en utilisant les bibliothèques DMSsdwan, vous pouvez valider vos propres données automatiquement.
Ajoutez ceci au modèle index.volt de fdm:
<script type="text/javascript">
$( document ).ready(function() {
var data_get_map = {'frm_GeneralSettings':"/api/fdm/settings/get"};
mapDataToFormUI(data_get_map).done(function(data){
// place actions to run after load, for example update form styles.
});
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/fdm/settings/set",formid='frm_GeneralSettings',callback_ok=function(){
// action to run after successful save, for example reconfigure service.
});
});
});
</script>
<div class="col-md-12">
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
Le premier morceau de code javascript gère le chargement des données lors de l'ouverture du formulaire, puis un bouton est associé à l'événement de sauvegarde.
Essayons-le et sauvegardons nos données, sans les modifier au préalable.
Ajouter des actions ¶
Ajouter une activité au module
Notre module de base fournit un moyen de lire et de modifier les données de configuration à l'aide de l'interface Web (et à terme également d'autres consommateurs utilisant l'API). L'étape suivante consiste à ajouter une activité à notre système, toutes les applications backend doivent utiliser leur propre configuration, que dans la vraie vie nous garderions aussi standard que possible.
Pour notre module, nous suivrons le même processus que pour tout autre service.
Tout d'abord, nous ajoutons une fonction intialAction(), a comme rôle de convertir le fichier /conf/fdm.xml en un objet et de retourner un tableau contien le nombre des règles ou retourne le status du module
...
public function initialAction()
{
$mdlfdm = new fdm();
$result['fdm'] = $mdlfdm->getNodes()['general']['Enabled']
if (!empty($status)) {
$xml = simplexml_load_file( '/conf/fdm.xml' );
$returned['conf_rls_nbr'] = $xml->config_rules_nbr;
$returned['dm_rls_nbr'] = $xml->dm_rules_nbr;
return $returned;
}else{
return $status;
}
}
Activation du filtre à double masque
Maintenant, nous devons pouvoir activer ce module en ajoutant une action d'activation dans notre SettingsController. Editez controllers/DMSsdwan/fdm/Api/SettingsController.php
...
public function activateAction()
{
$xml = simplexml_load_file( '/conf/fdm.xml' );
if ($xml===false) {
return "no config.xml file";
}
$interfaces = array();
$protocols = array();
$in_out = array();
$config_rules_nbr = 0;
$dm_rules_nbr = 0;
foreach ($xml->filter->rule as $rule){
//1- Parcourir l'objet xml
//2- Récupérer la liste des noms des interfaces dans le tableau $interfaces
//3- Récupérer la liste des ports dans le tableau $protocols
//4- à chaque itération la variable $config_rules_nbr incrémente par 1
}
...
if ($pivot!=='') {
$to_array = exploade(",",$in_out[$pivot]['destin'];
$double_mask = $this->do_double_masque($to_array);
$in_out[$pivot]['destin'] = $double_mask;
}
...
}
cidr2range($ipv4)
cette fonction renvoie une plage d'adresse [@ip1,@ip2]
bin2ip($bin)
Convertir une adresse en binaire à une adresse ip
longest_common($a,$b)
Retourn la chaine commune entre les deux adresses en binaire
do_double_masque($ip_list)
L'action prend comme paramètre une liste des adresses, qui va générer un ensemble de masques correspondant. Cela est fait par la division de l’intervalle en sous-intervalles et, à chaque fois, l’appel à la procédure compute_dm.
compute_dm($ip_1, $ip_2)
Donnée 1 : soit la variable “c” représentant le plus long préfix commun entre les représentations binaires de “a” et “b”.
La procédure a comme rôle de faire le calcul de la représentation double-mask de chaque sous-intervalle de la “donnée 1”. Cette procédure prend comme paramètre “x” qui sera successivement substituée par “a” et “b” dans l’algorithme principal DoubleMasks afin de générer les représentations nécessaires.
compute_masks($ip, $prefix, $beta)
L’algorithme a été intégré dans le code afin de supporter la correspondance de la règle OpenFlow de double-masque avec soit l’IP source, soit l’IP destination d’un paquet.
Lorsqu’une correspondance est détectée au niveau du contrôleur, la règle est envoyée simultanément au switch et à l’application Web.
En ce moment-là, le switch l’ajoute directement à la table des flux pour que désormais, la correspondance se fait automatiquement sans devoir passer par le contrôleur.
La règle est aussi ajoutée à la base de données afin de générer quelques statistiques comme la classification des règles par leur importance en se basant sur le nombre de fois une correspondance est détectée entre un paquet et une règle bien spécifique.
generateXML($data, $conf_rls_nbr, $dm_rls_nbr)
Cette action permet de générer le fichier xml fdm.xml
Plugin pour le contrôle d'accès (ACL) ¶
Si nous voulons autoriser les utilisateurs à accéder à ce module, nous pouvons ajouter une ACL à ce module. Sans cela, seuls les administrateurs peuvent y accéder. Créez un fichier XML dans le nom du répertoire du modèle ACL / ACL.xml et collez-y le contenu suivant:
<acl>
<!-- unique acl key, must be globally unique for all ACLs -->
<page-services-fdm>
<name> Services: IP Filter double masks! </name>
<description>Allow access to the fdm! module</description>
<patterns>
<pattern>ui/fdm/*</pattern>
<pattern>api/fdm/*</pattern>
</patterns>
</page-services-fdm>
</acl>
Cela génère une clé ACL nommée "page-services-fdm" qui autorise l'accès aux URL d'interface utilisateur et d'API de cette application. Vous pouvez maintenant accorder l'accès à ce module depuis le gestionnaire d'utilisateurs du système.