9.2. Configuration du réseau sous Linux

La configuration du réseau nécessite donc la configuration du protocole IP et des services TCP, UDP et ICMP (entre autres). Cette opération se fait en définissant l'adresse IP le masque de sous-réseau et les routes à utiliser. Vient ensuite la configuration du nom de la machine locale, de son domaine, des noms de machines qu'elle peut résoudre elle-même et des serveurs de DNS qu'elle doit utiliser pour les autres noms.

Il est quasiment certain que votre distribution dispose d'un outil permettant d'effectuer la configuration du réseau simplement. Connaissant à présent la signification des termes utilisés dans les réseaux TCP/IP, vous devriez pouvoir parvenir à une configuration valide relativement simplement. Il est fortement recommandé de consulter la documentation de votre distribution. Les commandes de configuration du réseau sont souvent appelées dans les scripts de démarrage de la machine, ou dans les scripts de changement de niveau d'exécution. Toutefois, il peut être utile de connaître ces commandes, ne serait-ce que pour comprendre comment votre système fonctionne. Cette section a donc pour but de vous présenter ces commandes, ainsi que les principaux fichiers de configuration du réseau utilisés sous Linux.

9.2.1. Configuration statique des interfaces réseau

La principale commande permettant de configurer le réseau est la commande ifconfig. Comme son nom l'indique (« InterFace CONFiguration »), elle permet de configurer les interfaces réseau de la machine. Il faut savoir qu'il existe plusieurs types d'interfaces réseau. Les plus courants sont les trois types d'interfaces suivants :

La configuration d'une interface comprend l'initialisation des pilotes nécessaires à son fonctionnement et l'affectation d'une adresse IP à cette interface. La syntaxe générale que vous devrez utiliser est la suivante :

ifconfig interface adresse netmask masque up
interface est le nom de l'interface réseau que vous voulez configurer, adresse est l'adresse IP que cette interface gérera, et masque est le masque de sous-réseau que vous utilisez. Les interfaces que vous aurez à configurer seront certainement des interfaces Ethernet, auquel cas vous devrez utiliser les noms eth0, eth1, etc. dans la commande ifconfig. Si vous désirez configurer l'interface loopback, vous devrez utiliser le nom d'interface lo.

Le paramètre up donné à ifconfig lui indique que l'interface doit être activée. Cela signifie que dès que la commande ifconfig s'achèvera, votre interface réseau sera active et fonctionnelle. On ne peut faire plus simple... Bien entendu, il existe le paramètre inverse : down. Ce paramètre s'utilise tout simplement dans la commande ifconfig avec la syntaxe suivante :

ifconfig interface down
interface est toujours le nom de l'interface.

Un exemple de configuration très classique est le suivant :

ifconfig eth0 192.168.0.1 netmask 255.255.255.0 up

Note : Prenez bien garde, lorsque vous écrivez vos adresses IP, à ne pas rajouter de 0 supplémentaire devant les nombres qui la constituent. En effet, il existe une convention en informatique qui dit que les nombres préfixés d'un 0 sont codés en octal, c'est-à-dire en base 8. Il va de soi qu'une adresse IP codée en octal n'utilise pas les mêmes nombres que lorsqu'elle est exprimée en décimal, aussi éprouveriez-vous quelques difficultés pour diagnostiquer le non fonctionnement de votre réseau si vous faisiez cette erreur !

Le noyau utilisera par défaut le nombre 255 pour les adresses de broadcast dans les composantes de l'adresse IP qui ne fait pas partie de l'adresse de sous-réseau. Si vous désirez utiliser une autre adresse (en général, l'alternative est de prendre l'adresse du sous-réseau), vous devrez utiliser l'option broadcast adresse dans la commande ifconfig. Cependant, le comportement par défaut convient à la plupart des réseaux. La commande de configuration donnée en exemple ci-dessus sera alors :

ifconfig eth0 192.168.0.1 netmask 255.255.255.0 broadcast 192.168.0.0 up

Enfin, il est possible d'affecter plusieurs adresses IP à certaines interfaces réseau. C'est en particulier le cas pour toutes les interfaces réseau classiques, mais bien entendu cela n'est pas réalisable avec les interfaces de type point à point comme les interfaces des connexions ppp. Lorsqu'une interface dispose de plusieurs adresses, la première est considérée comme l'adresse principale de l'interface, et les suivantes comme des alias. Ces alias utilisent comme nom le nom de l'interface réseau principale et le numéro de l'alias, séparés par deux points (caractère ':'). Par exemple, si l'interface eth0 dispose d'un alias, celui-ci sera nommé eth0:0. Ainsi, pour fixer l'adresse d'un alias d'une interface réseau, on utilisera la syntaxe suivante :

ifconfig interface:numéro add adresse netmask masque
interface est toujours le nom de l'interface, numéro est le numéro de l'alias, adresse est l'adresse IP à attribuer à cet alias, et masque est le masque de sous-réseau de cette adresse.

La commande ifconfig est en général appelée dans les scripts d'initialisation du système, qui ont été générés par l'utilitaire de configuration réseau de votre distribution. Si vous effectuez un grep sur « ifconfig » dans le répertoire /etc/rc.d/ (ou /sbin/init.d/, selon votre distribution), vous trouverez la commande de démarrage du réseau. Il se peut qu'une variable d'environnement soit utilisée à la place de l'adresse IP que vous avez choisie. Quoi qu'il en soit, vous devez sans aucun doute avoir les lignes suivantes, qui permettent l'initialisation de l'interface loopback :

ifconfig lo 127.0.0.1 netmask 255.0.0.0 up

9.2.2. Définition des règles de routage

La deuxième étape dans la configuration du réseau est la définition des règles de routage. Il est possible de définir plusieurs règles de routage actives simultanément. L'ensemble de ces règles constitue ce qu'on appelle la table de routage. La règle utilisée est sélectionnée par le noyau en fonction de l'adresse destination du paquet à router. Chaque règle indique donc un critère de sélection sur les adresses, et l'interface vers laquelle doivent être transférés les paquets dont l'adresse destination vérifie cette règle.

La commande utilisée pour définir une route est, chose surprenante, la commande système route. Sa syntaxe est donnée ci-dessous :

route opération [-net | -host] adresse netmask masque interface
opération est l'opération à effectuer sur la table de routage. L'opération la plus courante est simplement l'ajout d'une règle de routage, auquel cas add doit être utilisé. L'option suivante permet d'indiquer si le critère de sélection des paquets se fait sur l'adresse du réseau destination ou plus restrictivement sur l'adresse de la machine destination. En général, il est courant d'utiliser la sélection de toutes les adresses d'un même réseau et de les router vers une même interface. Dans tous les cas, adresse est l'adresse IP de la destination, que celle-ci soit un réseau ou une machine. Si la destination est un réseau, il faut indiquer le masque de sous-réseau masque à l'aide de l'option netmask. Enfin, interface est l'interface réseau vers laquelle doivent être envoyés les paquets qui vérifient les critères de sélection de cette règle.

Par exemple, la règle de routage à utiliser pour l'interface loopback est la suivante :

route add -net 127.0.0.0 netmask 255.0.0.0 lo

Cette règle signifie que tous les paquets dont l'adresse de destination appartient au sous-réseau de classe A 127.0.0.0 doivent être transférés vers l'interface loopback. Cela implique en particulier que les paquets à destination de la machine d'adresse IP 127.0.0.1 (c'est-à-dire la machine locale) seront envoyés vers l'interface loopback (ils reviendront donc sur la machine locale).

Une autre règle de routage classique est la suivante :

route add -net 192.168.0.0 netmask 255.255.255.0 eth0

Elle permet d'envoyer tous les paquets à destination du réseau de classe C 192.168.0.0 vers la première interface Ethernet. C'est typiquement ce genre de règle qu'il faut utiliser pour faire fonctionner un réseau local.

Il n'est normalement pas nécessaire d'ajouter les règles de routage pour les réseaux auxquel la machine est connectée. En effet, la configuration d'une carte réseau à l'aide de la commande ifconfig ajoute automatiquement à la table de routage une règle pour envoyer les paquets à destination de ce réseau par l'interface réseau qui y est connectée. Cependant, la commande route devient réellement nécessaire lorsqu'il faut définir les passerelles à utiliser pour l'envoi des paquets destinés à une machine à laquelle la machine locale ne peut accéder directement. Les règles de routage faisant intervenir une passerelle sont semblables aux règles de routage vues ci-dessus, à ceci près que l'adresse IP de la passerelle à utiliser doit être fournie. Pour cela, on utilise l'option gw (abréviation de l'anglais « Gateway »). La syntaxe utilisée est donc la suivante :

route add [-net | -host] adresse netmask masque gw passerelle interface
passerelle est l'adresse IP de la passerelle à utiliser pour router les paquets qui vérifient les critères de cette règle. Les autres paramètres sont les mêmes que pour les règles de routage classique.

Par exemple, supposons qu'une machine soit connectée à un réseau d'adresse 192.168.0.0, et que sur ce réseau se trouve une passerelle d'adresse 192.168.0.1 permettant d'atteindre un autre réseau, dont l'adresse est 192.168.1.0. Une machine du réseau 192.168.0.0 aura typiquement les règles de routage suivantes :

route add -net 192.168.0.0 netmask 255.255.255.0 eth0
route add -net 192.168.1.0 netmask 255.255.255.0 gw 192.168.0.1 eth0

La première règle permet, comme on l'a déjà vu, de communiquer avec toutes les machines du réseau local. La deuxième règle permet d'envoyer à la passerelle 192.168.0.1 tous les paquets à destination du réseau 192.168.1.0.

Inversement, si la passerelle utilise l'adresse 192.168.1.15 sur le réseau 192.168.1.0, les machines de ce réseau qui voudront accéder au réseau 192.168.0.0 devront spécifier la règle de routage suivante :

route add -net 192.168.0.0 netmask 255.255.255.0 gw 192.168.1.15 eth0

Bien entendu, il est nécessaire que toutes les machines des deux réseaux utilisent ces règles de routage pour que la communication entre les deux réseaux se fasse dans les deux sens.

Le problème de ces règles de routage est qu'elles spécifient l'adresse du réseau destination. Il est évidement hors de question d'utiliser une règle de routage différente pour toutes les adresses de réseaux possibles. Il est donc possible de définir ce qu'on appelle une passerelle par défaut, qui n'est rien d'autre que la passerelle vers laquelle doivent être envoyés tous les paquets qui n'ont pas vérifié les critères des autres règle de routage. La syntaxe à utiliser pour définir la passerelle par défaut est plus simple, puisqu'il n'est plus nécessaire de préciser les critères de sélection :

route add default gw passerelle interface
où la signification des paramètres passerelle et interface est inchangée.

Ainsi, pour reprendre l'exemple précédent, supposons que la machine 192.168.0.47 dispose d'une connexion à Internet et soit configurée pour partager cette connexion avec les machines du réseau local. Pour que toutes les machines du réseau local puisse profiter de cette connexion, il suffit de demander à ce que tous les paquets qui ne vérifient aucune autre règle de routage soient envoyés à la passerelle 192.168.0.47. Cela se fait avec la règle de routage suivante :

route add default gw 192.168.0.47 eth0

9.2.3. Définition du nom de la machine

La configuration du nom d'un ordinateur n'est pas à proprement parler une opération indispensable, mais elle permet de le nommer de manière plus conviviale qu'en utilisant son adresse IP. La commande de base permettant de manipuler le nom de la machine locale est la commande hostname. Appelée telle quelle, elle renvoie le nom actuel de la machine :

hostname

Cette commande permet également de modifier ce nom, simplement avec la syntaxe suivante :

hostname nom
nom est le nom à utiliser. Il est d'usage de n'utiliser que le nom de la machine, sans son domaine. Le nom de domaine est déterminé automatiquement par le système à partir des informations issues de la configuration de la résolution des noms de domaine. Nous verrons cela dans le paragraphe suivant.

Cette commande est donc très simple à utiliser, et elle est en général appelée dans les scripts de démarrage du système. La plupart des distributions utilisent le fichier /etc/HOSTNAME pour stocker le nom de la machine. Vous êtes bien entendu libre de choisir le nom que vous voulez pour votre ordinateur, mais vous devez vous assurer que ce nom est unique dans votre domaine !

9.2.4. Résolution des noms de domaine

La commande hostname ne permet de fixer que le nom de la machine locale. Pour les autres machines du réseau, il faut mettre en place les mécanismes de résolution de noms de domaine. Comme il l'a déjà été indiqué au début de ce chapitre, il existe deux solutions pour trouver l'adresse IP d'une machine à partir de son nom : la consultation d'une liste de noms stockée en local, soit l'interrogation d'un serveur de noms de domaine.

Le fichier /etc/host.conf permet de définir le comportement du système lors de la résolution d'un nom. Sa structure est très simple, puisqu'il y a une option de recherche par ligne. Dans la plupart des cas, les lignes suivantes sont suffisantes :

order hosts,bind
multi on

Elles permettent d'indiquer que la recherche des noms pour leur résolution doit se faire d'abord localement, puis par appel aux DNS si la recherche précédente a échoué. C'est en général le comportement désiré. La deuxième ligne permet de faire en sorte que toutes les adresses correspondant à une machine soient renvoyées. Si l'on avait utilisé l'option multi off, seule la première adresse IP trouvée aurait été renvoyée.

La liste de noms locale est stockée dans le fichier /etc/hosts (cela explique le nom hosts utilisé pour l'option order dans le fichier /etc/host.conf). Votre ordinateur connaîtra directement l'adresse IP de toutes les machines référencées dans ce fichier. Il est bon de placer ici une entrée pour les ordinateurs les plus couramment utilisés sur le réseau. Chaque entrée commence par une adresse IP, et est suivie de la liste des noms de la machine possédant cette adresse, séparés par des espaces. Pour ceux qui ne disposent pas de réseau local, ce fichier doit être relativement simple : seule la ligne affectant l'adresse 127.0.0.1 à la machine locale (appelée « localhost ») doit s'y trouver.

127.0.0.1    localhost

De la même manière, le fichier /etc/networks contient les adresses des réseaux. Ce fichier est utilisé par la commande route pour donner un nom aux différents réseaux. Chaque entrée est constituée du nom du réseau, suivi de son adresse IP. Encore une fois, ce fichier se réduit à sa plus simple expression pour ceux qui n'ont pas de réseau local, puisqu'il ne contiendra tout au plus qu'une entrée pour le réseau « loopback », sur lequel se trouve l'adresse de retour 127.0.0.1. Cette entrée aura donc la forme suivante :

loopback    127.0.0.0

La configuration des serveurs de noms est en revanche une opération nécessaire si l'on désire accéder à des machines dont on ne connaît que le nom. Le fichier de configuration utilisé est cette fois le fichier /etc/resolv.conf. Sa structure est encore une fois très simple, avec une option par ligne, chaque option étant introduite par un mot clé.

Le mot clé domain permet d'indiquer le nom du domaine dont fait partie votre machine. Par exemple, si votre nom de domaine est « andromede.galaxie », vous devrez utiliser la ligne suivante :

domain andromede.galaxie

Le mot clé search permet quant à lui de spécifier une liste de noms de domaines à ajouter par défaut aux noms de machines non complètement qualifiés. Les éléments de cette liste doivent être séparés par des espaces. La recherche d'une machine dont le nom ne comprend pas la partie de nom de domaine s'effectue en ajoutant au nom de la machine les noms des domaines indiqués ici, jusqu'à ce que la résolution du nom en adresse IP réussisse. Cette recherche commence bien entendu par le nom de domaine local, s'il a été défini. Il est donc recommandé d'indiquer votre nom de domaine dans cette liste de noms de domaines. Par exemple, si votre machine fait partie du domaine « andromede.galaxie », vous devrez utiliser la ligne suivante :

search andromede.galaxie

Ainsi, si vous recherchez l'adresse de la machine « krypton », la requête au DNS se fera avec le nom complètement qualifié « krypton.andromede.galaxie ». Vous êtes bien entendu libre d'ajouter d'autres noms de domaines pour le cas où la résolution de nom échouerait sur ce domaine.

Enfin, l'option nameserver est essentielle, puisqu'elle permet de donner les adresses IP des serveurs de DNS auxquels doivent être adressées les requêtes de résolution de noms. Par exemple, si vous disposez de deux serveurs DNS, un primaire, d'adresse 192.168.0.10, et un secondaire, d'adresse 192.168.0.15, vous utiliserez la ligne suivante :

nameserver 192.168.0.10 192.168.0.15

Cette ligne est évidemment obligatoire, faute de quoi la résolution des noms de machines en adresse IP échouera pour toute machine qui ne se trouve pas dans votre fichier /etc/hosts.

9.2.5. Utilisation des protocoles DHCP et BOOTP

Généralement, la gestion des adresses IP des machines devient rapidement une tâche difficile sur les grands réseaux, pour trois raisons. Premièrement, il faut toujours s'assurer que chaque machine dispose bien d'une adresse qui lui est propre, ce qui peut être difficile si l'on ne s'organise pas en conséquence. Deuxièmement, il faut que les fichiers /etc/hosts de toutes les machines soient à jour, ce qui nécessite un travail proportionnel au nombre de machines administrées. Enfin, le nombre d'adresses IP disponibles peut se réduire, ce qui peut devenir gênant à terme.

Afin de résoudre ces problèmes de configuration réseau, le protocole DHCP (abréviation de l'anglais « Dynamic Host Configuration Protocol ») a été défini. Il s'agit d'un protocole qui permet aux machines connectées sur un réseau d'interroger un « serveur d'adresses » du réseau capable de gérer une liste d'adresses et de les affecter dynamiquement aux machines du réseau. En fait, ce protocole permet de fournir plus d'informations que les simples adresses IP, comme par exemple la route par défaut que les machines doivent utiliser, ainsi que les adresses des serveurs de noms du réseau.

Un autre protocole semblable à DHCP a également été développé dans le but de permettre la configuration réseau des machines dès leur démarrage : le protocole BOOTP (abréviation de l'anglais « BOOTstrap Protocol »). Ce protocole est évidemment plus léger que DHCP, mais permet aux machines d'obtenir dynamiquement leur configuration réseau dès leur démarrage, avant même que ne soient montés les systèmes de fichiers. Ce protocole est donc particulièrement utile pour faire démarrer des machines sans disque, pour lesquelles le système de fichiers racine est monté en NFS.

La manière la plus simple de configurer les protocoles DHCP et BOOTP sur un poste client est d'utiliser les fonctionnalités d'auto-configuration du noyau. Cependant, il est également possible d'effectuer cette configuration au niveau utilisateur à l'aide de programmes complémentaires. Les deux sections suivantes décrivent ces deux techniques.

9.2.5.1. Autoconfiguration des clients DHCP et BOOTP

La configuration des protocoles DHCP et BOOTP ne comporte aucune difficulté particulière lorsque l'on utilise les fonctionnalités d'autoconfiguration du noyau. Ces fonctionnalités étant prises en charge au niveau du noyau, il va vous falloir recompiler un nouveau noyau pour en bénéficier. Cette opération en revanche est relativement technique, et doit être faite avec soin. La manière de procéder a été décrite en détail dans la Section 7.3.

L'option à activer pour permettre l'utilisation du protocole BOOTP est l'option « IP: kernel level autoconfiguration » du menu « Networking options ». Cette option vous permettra de sélectionner le protocole d'auto-configuration réseau que le noyau devra utiliser lors de son amorçage. Vous devrez alors choisir l'option « IP: DHCP support (NEW) » ou l'option « IP: BOOTP support (NEW) » pour activer respectivement les protocoles DHCP et BOOTP.

Note : Vous remarquerez qu'il existe également un autre protocole d'auto-configuration du réseau au démarrage : le protocole RARP. Ce protocole fournit les mêmes services que le protocole BOOTP, mais est plus ancien. Il n'est donc plus conseillé de l'utiliser, sauf vous vous trouvez sur un réseau pour lequel seul le protocole RARP est disponible.

Une fois ces options sélectionnées, vous pourrez recompiler votre noyau, l'installer et redémarrer la machine. Lors du démarrage, le noyau doit chercher un serveur DHCP ou un serveur BOOTP sur le réseau local pour effectuer la configuration réseau de votre carte réseau.

Note : Vous devrez peut-être également activer les options « NFS file system support » et « Root file system on NFS » du menu « Network File Systems » si vous désirez faire démarrer votre machine sur un système de fichiers racine monté en NFS lors du démarrage.

9.2.5.2. Configuration d'un client DHCP au niveau utilisateur

Il est également possible de configurer les clients DHCP au niveau utilisateur, à l'aide de programmes complémentaires. Comme sur la plupart des machines Unix, le programme à utiliser est le programme dhclient. Ce programme est généralement lancé dans les scripts de démarrage des machines, et envoie des paquets de demande de configuration sur le réseau à l'adresse de diffusion générale 255.255.255.255. Ces paquets sont donc susceptibles d'être captées par toutes les machines du réseau, mais seuls les serveurs DHCP y répondent. Les réponses obtenues sont alors analysés par dhclient, qui configure en conséquence l'interface réseau et passe ensuite en arrière-plan.

Les informations envoyées par les serveurs DHCP peuvent être plus ou moins complètes, la base étant bien sûr l'adresse IP de la machine et son masque de sous-réseau. Il est toutefois possible de donner plus d'informations, comme par exemple les adresses des serveurs de noms, des routes par défaut et des passerelles à utiliser.

Les adresses IP attribuées aux clients ne sont pas permanentes, car le protocole DHCP est avant tout destiné à la configuration automatique des postes itinérants ou susceptibles de redémarrer souvent. Par conséquent, ces adresses sont fournies dans le cadre d'un bail, dont la durée maximum est fixée par le serveur. Dès que le bail obtenu par un client expire, celui-ci doit chercher à le renouveler. C'est encore le programme dhclient qui s'en charge. C'est la raison pour laquelle celui-ci passe en arrière-plan après avoir configuré l'interface pour la première fois : il attend la fin des baux de la machine sur laquelle il tourne et cherche à les renouveler. Si un client ne renouvelle pas ce bail (parce qu'il est arrêté par exemple), le serveur DHCP peut réutiliser son adresse IP et l'affecter à une autre machine. Bien que les serveurs DHCP s'efforcent généralement de conserver les adresses IP des clients à chaque bail, un client configuré par DHCP ne peut donc pas considérer que son adresse IP restera toujours la même. C'est la contrepartie de la flexibilité.

Si aucun serveur DHCP ne peut être contacté lors du démarrage, dhclient abandonne temporairement et réessaie au bout d'un temps aléatoire. Au bout d'un certain nombre d'essais non fructueux, il peut décider de configurer les interfaces réseau avec les adresses IP des anciens baux obtenus par la machine. Pour cela, il mémorise dans le fichier de configuration /var/db/dhclient.lease les adresses IP de ces anciens baux. Ce fichier est périodiquement réécrit avec la liste des adresses des baux valides afin d'éviter qu'il ne se remplisse ad vitam eternam.

Bien entendu, les postes clients ne peuvent pas choisir leurs adresses IP sans vérification d'unicité. Dans le cas de l'absence de serveur DHCP (et donc d'autorité centrale), les clients qui démarrent interrogent les machines déjà présentes sur le réseau pour déterminer si l'adresse qu'ils envisagent de prendre est bien libre. Dans le cas contraire, une autre adresse est essayée, et ainsi de suite. Ainsi, même en cas de panne de tous les serveurs DHCP d'un réseau, les postes clients peuvent toujours travailler ensemble sans conflit d'adresses IP.

Comme vous pouvez le constater, le comportement de dhclient est relativement complexe et dépend de nombre de paramètres. Tous ces paramètres peuvent être définis dans le fichier de configuration /etc/dhclient.conf. Ce fichier contient en particulier les différentes durées intervenant dans le choix des adresses IP, comme par exemple la durée minimale d'un bail, les durées entre chaque tentatives de configuration, les informations qui doivent être récupérées des serveurs DHCP, ainsi que les valeurs par défaut pour ces informations lorsque les serveurs ne les fournissent pas. Le fichier de configuration dhclient.conf est donc relativement complexe. Heureusement, dhclient utilise des options par défaut qui conviennent dans la plupart des cas, aussi est-il fortement probable que votre fichier dhclient.conf soit vide. Si toutefois vous désirez en savoir plus, vous pouvez consulter la page de manuel dhclient.conf.

La configuration DHCP pour les postes clients se réduit donc à l'essentiel : le lancement de dhclient. Celui-ci s'utilise avec la syntaxe suivante :

dhclient interface0 [interface1 [...]]
interface0, interface1, etc., sont les interfaces réseau qui doivent être configurées par DHCP. On ne peut donc pas faire plus simple...

Note : Sous Linux, le programme dhclient utilise les fonctionnalité d'accès direct aux cartes réseau et de filtrage des paquets. Ces deux fonctionnalités peuvent être activées dans la configuration du noyau à l'aide des options « Packet socket », « Packet socket: mmapped IO » et « Socket Filtering » du menu « Networking options ». L'option « IP: multicasting » de la liste des options du protocole IP devra également être activée. Le détail de la configuration et de la compilation du noyau a été vu dans la Section 7.3.

9.2.6. Définition des protocoles de haut niveau

Comme nous l'avons vu plus haut, le protocole IP fournit les mécanismes de base pour la transmission des paquets. Plusieurs protocoles de plus haut niveau ont été définis pour fournir des services à valeur ajoutée, qui satisfont donc plus aux besoins des applications. Tous ces protocoles sont encapsulés dans le protocole IP, ce qui signifie que leurs informations sont transmises en tant que données dans les paquets IP.

En réalité, les paquets du protocole IP contiennent un champ permettant de signaler le type de protocole de haut niveau dont ils transportent les informations. À chaque protocole est donc attribué un identificateur numérique qui lui est propre, et qui permet aux services réseau d'interpréter les données des paquets.

Tout comme les adresses IP, ces numéros identifiant les protocoles ne sont pas très intéressants pour les humains, qui leur préfère évidemment le nom du protocole. Certains programmes réseau utilisent donc ces noms pour identifier les protocoles. Pour leur permettre de faire l'association entre ces noms et les identificateurs numériques, le fichier /etc/protocols est utilisé.

Le format de ce fichier est très simple. Il contient une ligne pour chaque protocole, constituée du nom du protocole, de la valeur de son identificateur, et des autres noms que ce protocole peut avoir (c'est-à-dire ses alias). Parmi ces protocoles, les plus importants sont les suivants :

NomNuméroAlias
ip0IP
icmp1ICMP
tcp6TCP
udp17UDP

Comme on le voit, le protocole IP dispose lui-même d'un identificateur de protocole (qui vaut 0 en l'occurrence). Cet identificateur est un identificateur de « pseudo protocole », parce qu'IP est en fait le protocole de base. ICMP est identifié par le numéro 1, TCP par le numéro 6 et UDP par le numéro 27. Il existe beaucoup d'autres protocoles, qui ne seront pas décrits ici. Bien entendu, le fichier /etc/protocols fourni avec votre distribution doit déjà contenir la définition de la plupart des protocoles.

De la même manière, la plupart des ports TCP et UDP sont affectés à des services bien définis, et certains programmes réseau peuvent chercher à faire la correspondance entre les noms de ces services et les numéros de ports. Cette correspondance est stockée dans le fichier de configuration /etc/services.

Les informations concernant les services sont données à raison d'une ligne par service. Chaque ligne suit la syntaxe suivante :

nom    port/protocole    alias
nom est le nom du service décrit par cette ligne, port est le numéro du port utilisé par ce service, protocole est le nom du protocole utilisé par ce service (ce peut être « tcp » ou « udp »), et alias la liste des autres noms sous lesquels ce service est également connu.

Vous trouverez les principaux services dans l'extrait donné ci-dessous :

ServicePort/Protocole
ftp21/tcp
telnet23/tcp
smtp25/tcp
pop3110/tcp
irc194/tcp
irc194/udp

Comme vous pouvez le constater, ces services n'ont pas d'alias. Ces informations sont données uniquement à titre d'exemple. Il va de soi que le fichier /etc/services fourni avec votre distribution contient la définition d'un grand nombre de services, et vous n'aurez en général pas à y toucher.

9.2.7. Les super-démons inetd et xinetd

La plupart des services réseau sont gérés par des programmes qui s'exécutent en permanence et qui attendent des connexions sur un port TCP ou UDP. Ces programmes consomment relativement peu de ressources car ils passent la plupart de leur temps à attendre ces connexions. Ils ne se réveillent que lorsqu'un client se connecte effectivement et leur envoie une requête.

Cependant, ils peuvent être relativement nombreux, et si tous les services sont lancés simultanément, ils peuvent finir par consommer une part non négligeable des ressources système. C'est pour cette raison que les super-démons inetd (de l'anglais « InterNET Daemon ») et xinetd (de l'anglais «  eXtended INETD ») ont été créés. Ces démons sont à l'écoute des demandes de connexion des clients pour les autres services réseau, et ne lancent ceux-ci que lorsqu'un client se connecte sur leurs ports. Une fois lancés, les véritables démons reprennent la main et communiquent directement avec leurs clients. Ainsi, inetd et xinetd écoutent les ports pour tout le monde, et sont la plupart du temps les seuls à fonctionner. Les ressources système sont donc économisées et les services réseau sont démarrés et arrêtés à la demande.

Le super-démon xinetd est appelé à remplacer inetd, qui lui est beaucoup plus ancien et nettement moins souple. En pratique, un seul de ces super-démons doit être démarré sur une machine (il est inutile de les lancer tous les deux, car les clients ne peuvent se connecter qu'à un seul d'entre-eux de toutes manières). Les deux sections suivantes décrivent la configuration de ces super-démons.

9.2.7.1. Le super-démon inetd

Le super-démon inetd laisse de plus en plus la main au nouveau super-démon xinetd qui est beaucoup plus puissant, mais reste toutefois très utilisé sur de nombreuses machines. Sa description n'est donc pas inutile, car toutes les distributions n'utilisent pas encore xinetd.

Le super-démon inetd utilise le fichier de configuration /etc/inetd.conf pour déterminer les ports sur lesquels il doit attendre des connexions de la part des clients, et pour trouver le service réseau qu'il doit lancer lorsqu'une telle connexion arrive. Ce fichier est structuré en lignes, dont chacune décrit un des services que le démon inetd prend en charge. Les informations données sur ces lignes sont les suivantes :

  • le nom du service (tel qu'il est défini dans la première colonne du fichier /etc/services) dont inetd doit surveiller les requêtes ;

  • le type de canal de communication réseau utilisé, en général « stream » (pour les communications en mode connecté, donc en général celles qui utilisent le protocole TCP) ou « dgram » (pour les communications basées sur les datagrammes, donc typiquement les communications utilisant le protocole UDP) ;

  • le protocole réseau utilisé (« tcp » ou «udp ») par ce service ;

  • l'un des mots clés wait ou nowait, qui permettent d'indiquer si inetd doit attendre la fin de l'exécution du démon gérant le service ou s'il peut attendre de nouvelles requêtes de la part des clients ;

  • le nom de l'utilisateur au nom duquel le démon gérant ce service doit fonctionner (en général, c'est l'utilisateur root) ;

  • le chemin sur le fichier exécutable de ce démon ;

  • les éventuels paramètres en ligne de commande pour ce démon, en commençant par l'argument 0, qui doit toujours être le nom du fichier exécutable du programme lui-même.

Par exemple, la ligne suivante permet de lancer le démon telnetd sur toute requête via le protocole TCP pour le service telnet :

telnet  stream  tcp     nowait  root    /usr/sbin/in.telnetd  in.telnetd

Il est supposé ici que le démon en charge de ce service peut être lancé avec le programme /usr/sbin/in.telnetd.

Le démon inetd est capable de fournir lui-même un certain nombre de services de base, et il n'est pas nécessaire de fournir un démon pour ces services. Dans ce cas, il faut utiliser le mot clé internal à la place du nom du fichier exécutable du démon de ce service. Les paramètres doivent également être remplacés par le mot clé internal.

En fait, il est fort peu probable que votre fichier de configuration /etc/inetd.conf définisse les services comme indiqué dans cette section. En effet, un programme intermédiaire en charge d'assurer des contrôles de sécurité est souvent intercalé entre inetd et les démons gérant les services. Nous verrons ce que fait exactement ce programme dans une prochaine section.

9.2.7.2. Le super-démon xinetd

Le super-démon xinetd utilise un autre fichier de configuration que celui du super-démon inetd. Pour xinetd, la définition des services mis à disposition des clients se fait dans le fichier de configuration /etc/xinetd.conf. Toutefois, contrairement au fichier inetd.conf, le fichier xinetd.conf peut inclure d'autres fichiers de configuration et référencer des répertoires contenant les fichiers de configuration spécifiques aux services. Ainsi, la configuration des services est beaucoup plus modulaire et se fait plus facilement.

En pratique, il est d'usage de définir les options par défaut pour tous les services dans le fichier de configuration /etc/xinetd.conf, et de décrire les différents services dans des fichiers complémentaires stockés dans le répertoire /etc/xinetd.d/. Ce répertoire est alors inclus directement dans le fichier xinetd.conf à l'aide de la directive includedir dédiée à cet usage.

Les fichiers de configuration de xinetd sont constitués de sections permettant de décrire les services pris en charge, ou tout simplement les options par défaut applicables à tous les services. La forme générale de ces sections est la suivante :

service
{
    option opérateur valeur [valeur [...]]
    option opérateur valeur [valeur [...]]
    ...
}
service est le nom du service (ou defaults pour les options par défaut), option est un mot-clé identifiant une des options de ce service, et opérateur est l'un des opérateurs '=' (pour la définition de la valeur d'une option ou l'écrasement de sa valeur précédente), '+=' (pour compléter la liste de valeurs d'une option) ou '-= (pour supprimer une valeur de la liste de valeurs d'une option). Les valeurs des options peuvent être multiples, et leur nature dépend des options utilisées.

Les principales options utilisables dans ces sections sont les suivantes :

OptionSignification
id

Identificateur du service, pour le cas où plusieurs sections devraient être définies pour un même service. Cette possibilité est utilisée lorsque l'on désire fournir des options différentes pour un même service. L'entrée choisie (et donc le jeu d'options choisi) dépend dans ce cas de critères définis par exemple sur l'interface réseau ou sur les adresses des clients.

type

Permet d'indiquer la nature du service décrit par cette section. Généralement, cette option n'a pas à être donnée, sauf lorsque l'on veut forcer la méthode d'implémentation d'un service. Par exemple, il est possible de donner la valeur INTERNAL à cette option pour utiliser l'un des services implémentés par xinetd en interne.

server

Permet de donner le chemin sur l'exécutable du démon prenant en charge le service décrit.

server_args

Permet de donner les paramètres en ligne de commande du démon prenant en charge le service. Notez que, contrairement à ce qui se fait avec inetd, il ne faut généralement pas donner le nom de l'exécutable en premier argument dans cette option. Cette règle peut toutefois être rendue fausse en ajoutant la valeur NAMEINARGS dans l'option flags décrite ci-dessous.

socket_type

Le type de canal de communication utilisé (« stream » ou « dgram », comme pour inetd).

protocol

Le protocole réseau utilisé par le service (« tcp » ou « udp », comme pour inetd).

port

Le port sur lequel le service peut être trouvé. Cette option est facultative. Si elle n'est pas indiquée, le numéro de port utilisé sera celui indiqué dans le fichier de configuration /etc/services pour le service en cours de configuration.

wait

L'indicateur de capacité du démon à gérer plusieurs connexions simultanément. Les valeurs que l'on peut donner à cette option sont « yes » et « no », respectivement pour indiquer que le démon peut gérer plusieurs connexions simultanément ou non. Dans ce dernier cas, le démon xinetd lancera plusieurs instances du démon gérant le service si plusieurs clients cherchent à se connecter simultanément. Le nombre maximum d'instance peut toutefois être contrôlé à l'aide des options instances et per_source décrites ci-dessous.

flags

Les paramètres permettant de contrôler différents aspects du service. Les options les plus courantes sont « IDONLY », qui permet de n'autoriser que les connexions provenant de machines disposant d'un serveur d'identification des clients, « NORETRY », qui permet d'éviter de réessayer de lancer le démon du service si le lancement précédent a échoué, et « NAMEINARGS», qui permet d'indiquer que le nom de l'exécutable doit être spécifié en premier paramètre dans l'option server_args.

user

Le compte utilisateur dans lequel le démon prenant en charge le service doit être lancé. Cette option ne peut bien entendu pas être utilisée pour les services gérés en interne par xinetd.

interface

L'interface à laquelle le service est attaché. Cette option permet de définir plusieurs configurations pour un même service et d'affecter ces différentes configurations à des interfaces réseau distinctes. Pour l'heure, seul l'adresse IP de l'interface réseau peut être spécifiée grâce à cette option, ce qui impose d'avoir des adresses IP fixes.

only_from

La liste des adresses des machines autorisées à se connecter. Il est possible de spécifier les adresses IP explicitement ou à l'aide d'une adresse et d'un masque de sous-réseau. Les noms de domaines peuvent également être utilisés. Dans ce cas, le nom n'est pas transformé en adresse IP. Au contraire, c'est l'adresse du client qui est retransformée en nom de machine pour vérifier s'il a le droit de se connecter. Notez que l'absence de ce champ indique que, par défaut, l'accès est accordé à toutes les machines (sauf celles explicitement interdites de connexion par l'option no_access décrite ci-dessous). En revanche, la présence de ce champ mais sans valeur permet d'interdire l'accès à toutes les machines.

no_access

La liste des adresses des machines qui n'ont pas le droit de se connecter. Les adresses peuvent être spécifiées de la même manière que pour l'option only_from. Si une adresse vérifie les critères des deux options only_from et no_access, c'est l'option dont le critère est le plus précis qui est choisie.

access_times

La période pendant laquelle le service est accessible. Cette période peut être exprimée sous la forme d'une liste d'intervalles « heure:minute-heure:minute ».

instances

Permet d'indiquer le nombre maximum d'instances d'un même démon que xinetd peut lancer. Cette option permet donc de spécifier un nombre de connexions maximum pour chaque service.

per_source

Permet d'indiquer le nombre maximum d'instances d'un même démon que xinetd peut lancer pour un même client (identifié par son adresse IP). Cette option permet donc de limiter le nombre de connexions d'un client, de manière indépendante du nombre de connexions total donné par l'option instances.

cps

Permet de limiter dans le temps le nombre de connexions entrantes pour un service, afin d'éviter les attaques par déni de service. Cette option prend deux paramètres, le premier étant le nombre maximum de demandes de connexion par seconde que xinetd peut accepter. Si ce nombre est dépassé le service est désactivé pendant le nombre de secondes indiqué par le deuxième paramètre.

disabled

Permet de désactiver globalement des services, en indiquant leurs noms en paramètre. Par défaut, aucun service n'est désactivé. Cette option ne peut être utilisée que dans la section defaults, car elle permet de désactiver globalement et rapidement un ensemble de services.

enabled

Permet de donner la liste des services pris en charge. Cette option fonctionne de manière similaire à l'option disabled, à ceci près qu'elle fonctionne en logique inverse. L'absence de cette option implique l'activation de tous les services, sauf ceux qui sont listés dans l'option disabled. En revanche, dès que cette option est définie, seuls les services listés sont démarrés. Tout comme l'option disabled, cette option ne peut être utilisée que dans la section globale defaults.

disable

Permet de désactiver les services de manière unitaire. Cette option est utilisée dans les sections des services, afin d'indiquer de manière plus fine qu'avec les options enabled et disabled s'ils doivent être activés ou non. Cette option peut prendre deux valeurs : « yes » ou « no ». La première permet de désactiver le service et la deuxième de le garder fonctionnel. Notez que les options enabled et disabled ont priorité l'option disable. Ainsi, un service désactivé par l'une de ces options ne peut pas être réactivé en attribuant la valeur no à l'option disable.

log_type

Méthode d'enregistrement des événements du démon xinetd. Il est possible d'utiliser le démon syslog pour enregistrer les événements de connexion et de déconnexion des utilisateurs, ou directement un fichier texte. Dans le premier cas, il faut utiliser la valeur SYSLOG suivie de la classe d'enregistrement (généralement daemon) et du niveau de trace (généralement info). Dans le deuxième cas, il faut spécifier la valeur FILE et indiquer les limites basse et haute de la taille du fichier au delà desquelles un avertissement est généré, puis les traces sont arrêtées.

log_on_success

Informations enregistrées lors de l'acceptation d'une connexion. xinetd peut enregistrer différentes informations lorsqu'une nouvelle connexion est acceptée. Ces informations sont indiquées grâce à la liste des mots-clés spécifiés par cette option. Les mots-clés utilisables sont « PID », pour enregistrer l'identifiant de processus du démon qui traitera la requête, « HOST », pour enregistrer le nom de la machine cliente, « USERID », pour enregistrer le nom de l'utilisateur (si celui-ci peut être obtenu par le service d'identification de sa machine), « EXIT », pour enregistrer la terminaison du démon qui traite la requête, et « DURATION », pour enregistrer la durée de la connexion.

log_on_failure

Informations enregistrées lors d'un refus de connexion. Les informations enregistrées lors d'un refus de connexion peuvent être spécifiées à l'aide de cette option, de la même manière que les informations de connexion peuvent être enregistrées à l'aide de l'option log_on_success. Les mots-clés utilisables avec cette option sont « ATTEMPT », pour signaler simplement que la tentative a échoué, « HOST », pour enregistrer le nom de la machine depuis laquelle la tentative a été effectuée, et « USERID », pour enregistrer le nom de l'utilisateur tel qu'indiqué par le service d'identification de sa machine.

Toutes les options disponibles ne sont pas décrites dans le tableau précédent. Vous pourrez obtenir de plus amples renseignements en consultant la page de manuel xinetd.conf.

La section « defaults » permet de définir les options par défaut applicables à tous les services. Les options qui y sont définies peuvent toutefois être redéfinies ou précisées à l'aide des opérateurs =, += et -= dans les sections des différents services. Les options utilisables dans la section defaults et que l'on a vu ci-dessus sont les options bind, log_type, log_on_success, log_on_failure, instances, per_source, only_from, no_access, disabled et enabled.

Généralement, le fichier /etc/xinetd.conf ne contient que la section default et une ligne d'inclusion du répertoire /etc/xinetd.d/, dans lequel se trouvent les fichiers de configuration des différents services. L'exemple suivant présente donc un fichier xinetd.conf typique :

# Définition des options par défaut :
defaults
{
    # On interdit la connexion à tout le monde par défaut :
    only_from =

    # On désactive les services internes :
    disabled = echo time daytime chargen discard

    # On désactive les services d'administration de xinetd :
    disabled += servers services xadmin

    # On limite le nombre d'instances total des services :
    instances = 15

    # On définit les règles de suivi des connexions :
    log_type        = FILE /var/log/servicelog 
    log_on_success  = HOST PID USERID DURATION EXIT 
    log_on_failure  = HOST USERID RECORD
}

# Inclusion des fichiers de configuration des services :
includedir /etc/xinetd.d

L'exemple suivant présente la définition du service telnet située dans le fichier de configuration /etc/xinetd.d/telnet :

service telnet
{
    socket_type     = stream
    # Le numéro de port et le protocole utilisés peuvent être omis
    # car ils sont déjà définis dans /etc/services.

    server          = /usr/sbin/in.telnetd
    user            = root
    wait            = no
    only_from		= localhost
    disable			= no
}

Note : xinetd n'inclue pas les fichiers contenant un point (caractère '.') ni ceux finissant par un tilde (caractère '~'). En particulier, on évitera de mettre une extension aux fichiers de configuration des services, puisque dans ce cas ils contiendraient un point et ne seraient pas lus.

9.2.8. Configuration de la sécurité du réseau

La sécurité d'un réseau n'est pas quelque chose à prendre à la légère, surtout lorsqu'on commence à transmettre des données personnelles sur le réseau. Internet n'est absolument pas sûr, car nombre de personnes curieuses, peu discrètes ou franchement mal intentionnées ont un accès privilégié aux machines qui s'y trouvent.

Bien qu'il soit impossible de réaliser un système sûr à 100%, la situation actuelle est franchement catastrophique et si cela continue comme cela, la seule chose de sûre, c'est qu'on va aller droit dans le mur. Entre ne rien faire du tout et se fixer un niveau de sécurité raisonnable permettant de limiter les dégâts, il y a un grand pas. Cette section n'a donc pas pour but de vous transformer en expert en sécurité (n'en étant pas un moi-même, je serais bien incapable d'en écrire une ayant cet objectif), mais de vous présenter les principes de base et le minimum requis pour laisser les mauvaises surprises aux autres.

Le principe de base de la sécurité est de ne faire confiance qu'au minimum possible de gens. Ce n'est pas un comportement paranoïaque, mais simplement du bon sens : puisqu'on ne peut garantir la fiabilité d'un système à 100%, il faut en restreindre les accès aux personnes habilitées. D'une manière générale, la plupart des surprises désagréables dans le monde environnant proviennent du mauvais jugement des personnes. Il est est de même dans le domaine de la sécurité informatique, il ne faut donner un accès qu'aux personnes que l'on connaît réellement bien, et ne fournir des services réseau qu'aux personnes et machines qualifiées de « sûres ». Il va de soi que lorsqu'il y a un loup dans la bergerie, tout peut aller très mal très vite.

Cela est d'autant plus important que la plupart des démons ont besoin d'avoir les privilèges du compte root pour s'exécuter. Cela peut générer des problèmes de sécurité si d'aventure une personne mal intentionnée découvrait le moyen de les détourner de leur fonction initiale et de leur faire accomplir des tâches au nom de l'administrateur. Bien entendu, les démons sont des programmes très bien écrits, qui vérifient généralement toutes les requêtes demandées par les clients avant de les satisfaire. Cependant, tout programme peut comporter des failles et laisser ainsi un accès indésiré au sein du système. Autant éliminer directement le problème en ne lançant que les services réellement nécessaires sur votre machine.

La première des règles est donc de réduire au maximum les services offerts par votre machine sur le réseau. Mais cela ne suffit pas pour dormir tranquille : le fait de ne laisser aucune connexion entrante se faire n'empêche pas un cracker potentiel de prendre votre identité sur les autres machines du réseau... Il faut donc également s'assurer que vos communications sortantes se réalisent dans des conditions de sécurité suffisantes. Or, et c'est sans doute là le plus gros problème, la plupart des protocoles réseau ne cryptent pas leur données et laissent passer toutes les informations en clair sur le réseau, y compris les mots de passe ! Il est donc impératif, lorsque l'on désire transmettre des informations sensibles, de recourir à des techniques de cryptage fiables.

Les sections suivantes vous présenteront donc la manière de procéder pour limiter au maximum les services disponibles sur votre machine, contrôler l'accès aux différents services de votre machine, réaliser des connexions fiables entre deux machines, et pour créer un réseau privé virtuel crypté, même via un canal peu sûr comme peu l'être Internet.

9.2.8.1. Limitation des services au strict minimum

Les services réseau d'un système Linux sont nombreux, mais la plupart du temps inutiles pour l'emploi que l'on veut faire de son ordinateur. Par conséquent, il vaut mieux tout simplement ne pas les proposer au monde extérieur, simplement en ne lançant pas les démons correspondants. Pour cela, il suffit de commentant les lignes des services inutiles dans le fichier /etc/inetd.conf ou d'ajouter une ligne « disable = true » dans les fichiers de configuration des services inutiles du répertoire /etc/xinetd.d/ si votre distribution utilise le super-démon xinetd. Faire le ménage dans ces fichiers et dans les fichiers d'initialisation du réseau réduit donc de 90% les risques d'une intrusion dans votre système.

9.2.8.2. Définition de règles de contrôle d'accès

Restreindre le nombre de services accessibles n'est toutefois pas suffisant, il faut également restreindre le nombre des personnes et des machines auxquels les services réseau restants sont proposés. Sur une machine de particulier, l'équation est souvent simple : personne ne doit pouvoir s'y connecter par le réseau, pour quelque service que ce soit ! Bien entendu, certains particuliers possèdent un réseau privé et devront donc affiner cette règle pour ne permettre les connexions que sur le réseau local. Il faut donc être capable d'empêcher les accès provenant de certaines machines, considérées comme peu fiables. La règle est encore une fois très simple : doit être considérée comme dangereuse tout machine étrangère au réseau local.

La manière de procéder dépend du super-démon utilisé. En effet, alors que xinetd permet de définir les adresses des machines autorisées à se connecter de manière précise, inetd ne permet pas de le faire lui-même et requiert l'aide d'un autre démon, le démon tcpd.

9.2.8.2.1. Restrictions d'accès avec tcpd

Le principe de fonctionnement du démon tcpd est le suivant : il s'intercale entre le super-démon inetd et les démons que celui-ci est supposé lancer lorsqu'un client le demande. Ainsi, il lui est possible d'effectuer des vérifications de sécurité primaires, principalement basées sur les adresses IP des clients.

Comme vous pouvez sans doute le constater dans le fichier /etc/inetd.conf de votre système, tcpd est lancé par inetd pour quasiment tous les services, et reçoit en paramètres de la ligne de commande le nom du démon à lancer si la machine cliente en a l'autorisation, ainsi que les paramètres à communiquer à ce démon. L'accès à quasiment tous les services est donc contrôlé par tcpd.

tcpd utilise les deux fichiers de configuration /etc/hosts.allow et /etc/hosts.deny pour déterminer si une machine a le droit d'accéder à un service donné. Le premier de ces fichiers indique quelles sont les machines autorisées à utiliser certains services locaux. Le deuxième fichier indique au contraire les machines qui ne sont pas considérées comme sûres et qui doivent se voir refuser toute demande de connexion sur les services locaux.

Le format de ces deux fichiers est identique. Il est constitué de lignes permettant de définir les règles d'accès pour certains démons. Chaque ligne utilise la syntaxe suivante :

démons : machines [: commande]
démons est une liste de noms de démons, séparés par des virgules, et machines est une liste de noms de machines ou d'adresses IP, également séparés par des virgules. commande est un paramètre optionnel permettant de faire exécuter une action à tcpd lorsque la règle indiquée par cette ligne est prise en compte.

Une règle définie par une de ces lignes est utilisée dès qu'une des machines indiquées dans la liste des machines tente une connexion à l'un des services de la liste des services. Si la règle se trouve dans le fichier /etc/hosts.allow, la connexion est autorisée et le service est lancé par tcpd. Si elle se trouve dans le fichier /etc/hosts.deny, la connexion est systématiquement refusée. Si aucune règle n'est utilisée, la connexion est acceptée par défaut.

Les listes de machines peuvent contenir des noms de machines partiels, et utiliser des caractères génériques. Il est également possible d'interdire la connexion à toutes les machines d'un domaine en ne donnant que le nom de domaine (précédé d'un point). Enfin, des mots clés spéciaux permettent de représenter des ensembles de machines. Par exemple, le mot clé ALL représente toutes les machines et LOCAL représente toutes les machines du réseau local. Le mot clé ALL permet également de représenter l'ensemble des démons dans la liste des démons.

Par exemple, le fichier /etc/hosts.deny devrait contenir la ligne suivante :

# Exemple de fichier /etc/hosts.deny :
ALL : ALL

Cela permet de garantir que, par défaut, aucune demande de connexion n'est acceptée, ce qui est un comportement sain. Les machines ayant le droit de se connecter doivent être spécifiées au cas par cas dans le fichier /etc/hosts.allow, comme dans l'exemple suivant :

# Exemple de fichier /etc/hosts.allow :
telnetd, ftpd : LOCAL

Cela permet d'autoriser les connexions telnet et ftp pour toutes les machines du réseau local uniquement.

Vous trouverez de plus amples renseignements sur le fonctionnement de tcpd dans la page de manuel hosts_access(5).

Note : Comme vous pouvez le constater si vous comparez les lignes du fichier de configuration /etc/inetd.conf utilisant tcpd et celles qui ne l'utilisent pas, la liste des paramètres passés à tcpd par inetd est différente de celle utilisée pour les démons lancés directement. En effet, elle ne comprend pas le nom de tcpd lui-même, alors que pour les démons, elle contient le nom du démon en premier paramètre. Cette différence provient du fait que le premier argument passé en ligne de commande est le nom du programme lui-même, sauf pour tcpd. En effet, tcpd suppose que ce paramètre contient le nom du démon dont il contrôle l'accès, et non son propre nom.

La sécurité basée sur tcpd suppose que les adresses IP source des paquets reçus sont effectivement les adresses IP des machines qui les ont envoyées. Malheureusement, cette hypothèse ne peut pas être vérifiée pour les adresses autres que les adresses des réseaux considérés comme sûrs (par exemple le réseau local), car le protocole IP n'inclut aucun mécanisme d'authentification. Par conséquent, n'importe qui peut tenter de communiquer avec votre machine au nom d'une autre machine (technique nommée « IP spoofing » en anglais), qu'il aura au préalable mis hors d'état de se manifester (par exemple par une attaque de type DoS, « Denial of Service » en anglais). tcpd tente par défaut de contrôler ce genre de pratique en vérifiant que le nom indiqué par la machine qui se connecte correspond bien à l'adresse IP qu'elle utilise. Ainsi, pour passer cette protection, il faut d'abord infecter un DNS. Cependant, ce genre d'attaque (dite d'interposition) reste courant, surtout sur les réseaux dont les DNS sont insuffisamment protégés (une étude récente a montré que c'était le cas de trois DNS sur quatre en France). Par conséquent, vous ne devez pas vous reposer uniquement sur tcpd et les techniques de firewalling si vous devez créer un site réellement sûr. En particulier, vous devriez vous intéresser aux réseaux virtuels et au cryptage des données, choses que l'on décrira dans la Section 9.2.8.4. Le protocole Ipv6 intégrera des mécanismes d'authentification et sera donc nettement plus sûr. Bien entendu, cela dépasse le cadre de ce document.

Le démon tcpd peut également être utilisé avec le démon xinetd. Toutefois, une telle utilisation est superflue, étant donné que xinetd permet de définir ses propres règles de contrôle d'accès.

9.2.8.2.2. Restrictions d'accès avec xinetd

Le super-démon xinetd intègre d'office un mécanisme de contrôle d'accès similaire à celui utilisé par tcpd. Grâce aux options only_from et no_access, il est possible de spécifier pour chaque service les machines qui sont autorisées à l'utiliser, ou inversement les machines qui doivent être explicitement rejetées.

Il faut toutefois prendre garde au fait que, comme pour tcpd, ne rien dire signifie accepter les connexions provenant de toutes les machines. La règle d'or est donc, encore une fois, de tout interdire par défaut et d'autoriser au compte-gouttes les accès aux services ouverts. Pour cela, il suffit d'ajouter la ligne suivante :

only_from =
dans la section de définition des options par défaut de xinetd. Avec cette ligne, contrairement à ce qui se passe si rien n'est spécifié, les accès ne sont autorisés qu'à partir d'aucune machine. Autrement dit, ils sont toujours interdits.

Il faut ensuite redonner les droits sur les machines autorisées service par service. Ainsi, les connexions par telnet peuvent être autorisées sur le réseau local (supposé sûr) grâce à la ligne suivante :

only_from += 192.168.0.0/24 127.0.0.1
dans la section décrivant le service telnet de la configuration de xinetd.

On prendra garde également au fait que xinetd implémente quelques services internes permettant de l'administrer par le réseau. Il est évident que ces services doivent être désactivés. Ces services sont respectivement les services servers, sercices et xadmin. Leur désactivation se fait classiquement en ajoutant la ligne suivante :

disabled = servers services xadmin
dans la section defaults du fichier de configuration /etc/xinetd.conf.

9.2.8.3. Contrôle des utilisateurs au niveau des services

Certains services ne peuvent pas être supprimés complètement, tout simplement parce que l'on peut en avoir besoin. Dans ce cas, il faut au moins s'assurer que l'accès à ces services n'est autorisé que pour les utilisateurs qui en ont réellement besoin. La règle est cette fois que l'utilisateur root ne doit pas avoir accès aux services réseau par une connexion non locale. En effet, un pirate attaque toujours par le réseau et, même s'il arrive à trouver le mot de passe d'un utilisateur normal, il lui restera encore pas mal de boulot pour trouver le mot de passe de l'utilisateur root (attention cependant, si vous êtes dans cette situation, il vaut mieux réagir très très vite).

Le service le plus sensible est bien entendu le service de login. Il est possible de fournir le service de login aux connexions extérieures, et il est évident que cela constitue déjà un point d'entrée pour qui peut trouver un mot de passe valide. Il est impératif ici d'interdire une telle connexion à l'utilisateur root. Il reste toutefois concevable que cet utilisateur puisse se connecter sur la console locale (c'est-à-dire, avec votre clavier et votre écran...). Il est donc nécessaire de choisir les terminaux à partir desquels l'utilisateur root pourra se connecter. Ces informations sont stockées dans le fichier de configuration /etc/securetty.

Le format de ce fichier est très simple, puisqu'il est constitué de la liste des terminaux à partir desquels l'utilisateur root peut se connecter, à raison d'un terminal par ligne. Un fichier de configuration /etc/securetty typique contient donc la liste des terminaux virtuels de la machine :

# Exemple de fichier /etc/securetty
tty1
tty2
tty3
tty4
tty5
tty6

Il est fortement déconseillé de placer dans ce fichier les autres terminaux (en particulier, les terminaux série ttyS0 et suivants).

Un autre service sensible est le service de téléchargement de fichiers. Il est recommandé d'interdire aux utilisateurs privilégiés les transferts de fichiers par FTP. En effet, si une personne parvient à accéder au système de fichiers, il peut supprimer tous les mécanismes de sécurité. De la même manière que l'on a interdit à l'utilisateur root de se connecter sur les terminaux distants, il faut lui interdire (ainsi qu'aux autres comptes sensibles) les connexions par FTP.

Cette opération peut être réalisée en ajoutant le nom de chaque utilisateur sensible dans le fichier de configuration /etc/ftpusers. Ce fichier a la même structure que le fichier securetty, puisqu'il faut donner un nom d'utilisateur par ligne :

# Exemple de fichier /etc/ftpusers
root
uucp
mail

Bien entendu, la liste des utilisateurs privilégiés de votre système dépend de la distribution que vous avez installé. Le fichier /etc/ftpusers fourni avec cette distribution est donc, en général, approprié.

9.2.8.4. Cryptage des connexions

L'outil le plus utilisé pour permettre des connexions sécurisées au travers d'un réseau non sûr est sans aucun doute SSH (abréviation de l'anglais « Secure SHell »). Il s'agit d'un protocole de communication réseau crypté et d'une suite d'outils permettant de l'utiliser, initialement développés par une société commerciale. Ces outils sont diffusés en Open Source et leur usage est gratuit pour les particuliers, mais ils ne sont absolument pas libres. Une implémentation libre a donc été développée pour le système FreeBSD, puis portée pour les autres systèmes d'exploitation, dont Linux. Cette implémentation est celle qui est utilisée par la plupart des distributions actuellement, il s'agit de « OpenSSH ». Nous ne décrirons ici que l'utilisation d'OpenSSH.

Pour garantir la confidentialité des données, SSH utilise des techniques de cryptographie avancées. Ces techniques permettent de s'assurer que personne ne peut lire les informations qui circulent sur le réseau d'une part, et de garantir l'authentification des machines auxquelles on se connecte d'autre part. De plus, SSH permet de rediriger les protocoles réseau non cryptés dans son propre canal de communication, et résout donc la plupart des problèmes de sécurité. SSH a donc pour but premier de remplacer les applications non sûres permettant de se connecter à distance sur une machine ou d'y exécuter des commandes. Les applications ainsi rendues obsolètes sont, entre autres, telnet, rlogin et rsh. Enfin, SSH est également utilisable pour chiffrer automatiquement les connexions X11, ce qui permet d'utiliser l'environnement graphique X Window à distance en toute sécurité.

Note : Officiellement, il est interdit d'utiliser en France des techniques de cryptage aussi poussées que celles mises en œuvre par SSH, sauf à demander une dérogation. Il y a de fortes pressions pour permettre la légalisation de ces techniques, mais elles n'ont pas encore abouti. Plus précisément, le gouvernement a pris position pour une libéralisation de l'usage de la cryptographie, mais la loi n'a pas encore été votée. Les sinistres événements du 11 novembre 2001 risquent fort de retarder encore, si ce n'est de compromettre, cette libéralisation. En effet, l'argument principal des opposants à cette légalisation est qu'elle permettrait aux truands de crypter leurs communications. L'argument est bien entendu fallacieux : comme s'ils attendaient d'en avoir le droit pour le faire...

En fait, il existe une implémentation gratuite (mais non libre) de SSH qui a été déclarée et qui peut donc être utilisée en France. Il s'agit de la version de Bernard Perrot, nommée « SSF », que l'on pourra trouver à l'adresse http://perso.univ-rennes1.fr/bernard.perrot/SSF/index.html. Si vous désirez absolument être sans reproches vis à vis de la loi actuellement en vigueur en France, vous devriez remplacer la version d'OpenSSH fournie avec votre distribution (dont l'usage est donc illégal) par SSF. Sachez cependant que SSF restreint la taille des clefs de sessions à 128 bits seulement d'une part (condition sine qua non pour qu'on puisse l'utiliser), qu'il n'est pas utilisable commercialement, et qu'il est susceptible de ne pas être à jour en ce qui concerne les correctifs de bogues et les failles de sécurité que l'on a pu trouver récemment dans SSH ou OpenSSH. La sécurité apportée par SSF est donc très relative, mais c'est mieux que rien du tout.

Il existe deux versions du protocole réseau SSH, qui ont tous deux été adoptés en tant que standards. La première version souffrait d'un trou de sécurité majeur, qui depuis a largement pu être utilisé. Il ne faut donc surtout pas utiliser cette version et se rabattre systématiquement sur le protocole SSHv2. Ce protocole permet de garantir l'authentification des machines et des utilisateurs et est nettement plus fiable. Aucune attaque n'a permis de le casser à ce jour, sachez toutefois qu'il existe encore des points douteux dans ce protocole qui permettraient, en théorie, de parvenir à s'immiscer dans une communication ou d'en décrypter une partie.

Sachez également que les différentes implémentations de SSH, aussi bien libres que commerciales, sont soumises au même régime que les autres programmes : elles peuvent avoir des bogues et des trous de sécurité qu'un attaquant peut utiliser. De nombreuses attaques ont été découvertes ces derniers temps, aussi est-il recommandé de s'assurer que l'on dispose de la dernière version d'OpenSSH. La dernière version stable est la 3.4p1 (les versions antérieures doivent être évitées à tout prix). Cela dit, mener une attaque contre SSH relève le niveau de difficulté nettement au dessus de ce qui est nécessaire pour pénétrer un système qui ne l'utilise pas.

9.2.8.4.1. Principes de base de cryptographie

Commençons par quelques définitions. Le cryptage, encore appelé chiffrement, est l'opération qui consiste à transformer une information en clair en une information codée afin d'éviter qu'elle ne puisse être utilisée par une personne non autorisée. Le déchiffrement est l'opération inverse du chiffrement, qui permet donc de retrouver l'information initiale à partir de l'information codée. Le décryptage est l'opération qui consiste à déchiffrer une information sans y être autorisé. La cryptographie est la science qui se charge d'étudier la manière de crypter les informations. La cryptoanalyse est l'étude des moyens de décryptage. Cette science va de paire avec la cryptographie, puisqu'elle permet de déterminer la fiabilité des techniques mises en œuvre pour le cryptage. Enfin, un cracker est une personne désirant s'introduire de manière illicite dans un système, ou désirant détourner une application de son contexte d'utilisation normal. Il ne faut pas confondre les crackers avec les hackers, qui sont des personnes extrêmement compétentes en informatique et qui ne font rien de mal (par exemple, les développeurs du noyau Linux sont souvent appelés des hackers).

Il existe un grand nombre de techniques de cryptographie, qui sont plus ou moins efficaces. La première technique, qui est aussi la plus simple et la moins sûre, est celle qui consiste à utiliser un algorithme de chiffrement réversible (ou une une paire d'algorithmes ayant un effet inverse l'un de l'autre) pour crypter une information. Dans ce cas, la sécurité des données est assujettie au maintien au secret de l'algorithme utilisé. Il est évident que ce type de technique n'est pas utilisable avec les logiciels dont les sources sont diffusées (comme Linux), puisque l'algorithme est alors connu de tout le monde. C'est également la technique la moins sûre, parce qu'il est en général très facile de déterminer cet algorithme. Un exemple d'un tel algorithme est le codage classique qui consiste à décaler toutes les lettres de l'alphabet (A devient B, B devient C, etc.).

Une autre technique se base sur un algorithme connu de tout le monde, mais dont l'effet est paramétré par une clef tenue secrète. Le déchiffrement des informations ne peut se faire que si l'on connaît cette clef. Les algorithmes de ce type sont souvent qualifiés de « symétriques », en raison du fait que la clef utilisée pour le déchiffrement est la même que celle utilisée pour le chiffrement. Cette technique n'est satisfaisante que dans la mesure où les personnes qui communiquent peuvent s'échanger cette clef de manière sûre. La clef utilisée ne devant être connue que des personnes autorisées à participer à la communication, cet échange doit se faire soit de visu, soit dans un canal déjà crypté (mais dans ce cas, il faut échanger la clef de déchiffrement du canal, et on se retrouve devant le problème de l'œuf et de la poule), soit à l'aide d'un protocole d'échange de clef sûr. Les algorithmes de ce type sont également connus sous le nom d'algorithmes à clef secrète en raison de cette particularité. Il existe un grand nombre d'algorithmes à clef secrète, les plus connus étant DES, AES et IDEA.

Figure 9-7. Algorithme de cryptage symétrique

La technique la plus sûre actuellement, et aussi la plus rusée, est d'utiliser un algorithme de chiffrement asymétrique. À la différence des algorithmes symétriques, les algorithmes asymétriques utilisent deux clefs différentes pour le chiffrement et pour le déchiffrement. Ces algorithmes se basent sur des fonctions mathématiques dont la fonction inverse est extrêmement difficile à déterminer sans une information également difficile à calculer. Cette information fait office de « trappe » permettant de retrouver l'information en clair. Toute la ruse ici est que la clef servant au déchiffrement peut ne plus être échangée du tout, ce qui supprime la nécessité de réaliser un échange de clefs généralement risqué. En fait, seule la clef de chiffrement doit (et peut sans crainte) être publiée. C'est en raison de cette propriété que les algorithmes asymétriques sont également appelés algorithmes à clef publique. Le principe est donc le suivant : une clef publique, utilisée pour chiffrer les informations, est fournie à tout le monde, et seul celui qui dispose de la clef privée associée à cette clef publique peut déchiffrer le texte. Ainsi, il est possible d'échanger des informations de manière sûre avec tous les intervenants en utilisant simplement leur clefs publiques respectives. Aucun échange d'information sensible n'est effectué en clair. Les algorithmes à clef publique les plus connus sont RSA et DSA.

Figure 9-8. Algorithme de cryptage asymétriques

La gestion des clefs des algorithmes à clef publique est techniquement laborieuse, de même que les calculs mis en œuvre par les algorithmes utilisés. Il est donc courant d'amorcer une communication avec un algorithme à clef publique, comme RSA par exemple, puis de l'utiliser pour échanger une clef secrète permettant de poursuivre la communication avec un algorithme symétrique. Il existe également des algorithmes spécialisés dans les échanges de clefs dans un canal non sûr, comme par exemple l'algorithme Diffie Hellman.

Enfin, sachez également qu'il existe des algorithmes de chiffrement à sens unique qui ne permettre pas de retrouver l'information initiale. Ces algorithmes sont souvent utilisés pour calculer une « emprunte digitale » de l'information, qui permet d'identifier l'information de manière unique. Cette emprunte digitale, également appelée un « condensé » (« hash » en anglais), est souvent utilisée pour authentifier l'intégrité des données diffusées dans un environnement peu sûr. Pour cela, celui qui réalise la diffusion crypte un condensé des informations diffusées avec sa clef privée. Tout le monde peut donc décrypter ce condensé avec la clef publique de cette personne, et avoir la certitude qu'il provient bien de son auteur. Il est alors facile de vérifier l'intégrité de l'information rendue publique. Les algorithmes de calcul d'emprunte les plus connus sont MD5 et SHA.

Note : Notez que les algorithmes de cryptage à clef publique nécessitent malgré tout que l'on soit sûr que l'on utilise la bonne clef publique pour s'adresser à une personne. Or, rien ne nous garantit que la clef publique d'une personne diffusée sur le réseau provienne bien de cette personne ! Il est donc toujours nécessaire d'échanger les clefs publiques de main à main, ou de trouver une tierce personne digne de confiance et dont on connaît déjà la clef publique pour garantir que la clef que l'on reçoit est bien celle de la personne qui prétend en être le propriétaire. Tout cela est contraignant. Mais, contrairement aux algorithmes de chiffrement à clef secrète, il n'est pas grave de perdre les clefs échangées, puiqu'elles sont destinées à être publiques...

9.2.8.4.2. Principes de base de l'authentification SSH

La grande difficulté dans les mécanismes d'authentification est d'être capable de prouver son identité sans fournir suffisamment d'information pour que quelqu'un d'autre puisse se faire passer pour soi par la suite. La technique du mot de passe utilisé par les systèmes Unix est absolument insuffisante, car elle requiert justement de fournir ce mot de passe. Même si les mots de passe ne sont pas stockés en clair sur la machine (ce qui est la moindre des choses), il est possible de se faire passer pour une tierce personne. Les mécanismes d'authentification comparent souvent une emprunte du mot de passe avec l'emprunte stockée dans les fichiers de définition des mots de passe, mais rien n'empêche un intrus de capter cette emprunte et de l'utiliser directement pour s'authentifier, même sans connaître le mot de passe en clair. En réalité, l'authentification Unix n'est valide que sur une machine donnée, et que si les programmes qui réalisent l'authentification sont exécutés dans un contexte sûr. C'est heureusement le cas lorsqu'on se connecte à partir d'une console locale, mais ne l'est pas dès que l'on passe par un média de communication quelconque. En particulier, une connexion par X11 n'est absolument pas sûre, même sur la machine locale, puisque les informations de connexion passent par un canal de communication réseau.

SSH ne transmet donc ni les mots de passe ni leurs condensés en clair sur le réseau. Il établit d'abord un canal de communication crypté à l'aide d'un des algorithmes d'échange de clef (la technique utilisée dépend de la version utilisée du protocole SSH). Une fois le canal crypté établi, la machine serveur est authentifiée à l'aide de sa clef publique. Pour que cela fonctionne, il faut bien entendu que la clef publique de la machine serveur soit connue du client et ait été authentifiée comme étant bien celle de ce serveur. Inversement, le client peut être authentifié par le serveur. SSH fournit plusieurs possibilités pour cela, les deux plus courantes étant l'authentification par mot de passe et l'authentification par un algorithme à clef publique.

L'authentification par mot de passe est strictement la même que celle utilisée pour le login Unix classique, à la différence près que les informations du mot de passe sont transmises dans le canal crypté, vers un serveur authentifié. La sécurité de ce mot de passe est donc garantie, du moins tant que le serveur n'est pas compromis. Ce type d'authentification permet d'utiliser SSH exactement comme les commandes classiques rsh ou telnet. L'utilisation de SSH est donc complètement transparente pour les utilisateurs.

Cela dit, il est possible de faciliter encore plus l'authentification des clients tout en augmentant le niveau de sécurité, en utilisant l'authentification par clef publique. Dans ce mode d'authentification, chaque client dispose également d'un couple de clefs privée et publique. Les clefs publiques de ces clients sont diffusées dans les comptes utilisateurs auxquels ils ont accès au niveau du serveur. Ainsi, il n'est plus nécessaire de fournir un mot de passe, car le serveur peut authentifier le client du seul fait qu'il est le seul à connaître sa clef privée. La connexion est donc automatique (une fois le serveur correctement configuré, bien entendu) et aucun échange d'information sensible comme le mot de passe n'est réalisé (même si le fait que cet échange était réalisé dans un canal crypté par SSH était déjà une bonne garantie).

Les clefs privées et publiques sont bien entendu stockées sur disque, dans les fichiers de configuration des serveurs et des clients. Il va de soi que si les clefs publiques peuvent être lues, il est impératif que les clefs privées ne soient lisibles que par leurs propriétaires. Les droits d'accès sur les fichiers de configuration doivent donc être fixées de manière correcte pour garantir la sécurité du système. En fait, le point faible du mécanisme d'authentification des clients est toujours au niveau des utilisateurs, qui peuvent perdre leur clef privée ou la communiquer à d'autres sans même savoir qu'ils font une erreur fondamentale (de la même manière qu'ils peuvent choisir un mot de passe trop facile à trouver ou simplement le communiquer à une tierce personne). C'est pour cela qu'il est possible d'encrypter les clefs privées avec un algorithme de cryptage symétrique. L'utilisateur doit, dans ce cas, fournir une phrase clef à chaque fois qu'il désire réaliser une connexion SSH.

9.2.8.4.3. Compilation et installation d'OpentSSH

Comme nous l'avons dit plus haut, il est recommandé d'utiliser la dernière version d'OpenSSH, à savoir la version 3.5.p1. Il est probable que votre distribution fournisse une mise à jour sur son site, et il est recommandé d'utiliser ces mises à jours.

Si, toutefois, vous désirez effectuer l'installation à partir des fichiers sources, vous pourrez procéder comme suit. Il vous faudra récupérer l'archive des fichiers sources en premier lieu sur le site OpenSSH. Pour Linux, il faut prendre l'archive 3.5p1, le 'p' signifiant ici qu'il s'agit d'un portage des sources pour Linux. Une fois cela fait, vous pourrez exécuter la commande suivante dans le répertoire des sources :

./configure --prefix=/usr --sysconfdir=/etc/ssh --with-tcp-wrappers --with-pam
Cette commande permet de configurer OpenSSH pour qu'il remplace la version existante dans votre système. Elle indique également que le support du démon tcpd doit être activé, ainsi que celui des modules d'authentification PAM (options « --with-tcp-wrapppers » et « --with-pam »). Bien entendu, si votre distribution n'utilise pas ces fonctionnalités, vous devez supprimer ces options.

La compilation et l'installation en soi ne posent pas de problème particulier. Pour les réaliser, il vous suffira d'exécuter les deux commandes suivantes :

make
make install
Vous constaterez que le programme d'installation génère automatiquement des fichiers de clefs publiques et privées pour votre machine. Nous verrons dans les sections suivantes comment ces clefs peuvent être utilisées.

Note : Vous devrez créer un compte utilisateur « sshd » non privilégié avant d'installer SSH. Ce compte est en effet utilisé par le démin sshd pour réaliser les communications réseau une fois la phase d'authentification réalisée. Cela permet de garantir que, même en cas d'exploitation d'une éventuelle faille de sécurité du démon sshd, l'accès à la machine sera extrêmement limité.

9.2.8.4.4. Configuration d'OpenSSH côté serveur

OpenSSH utilise un démon nommé sshd pour prendre en charge les requêtes de connexion de la part des clients. Ce démon est à l'écoute des demandes de connexion et effectue les opérations d'authentification du serveur auprès des clients. Il vérifie également les droits du client avant de le laisser utiliser la connexion cryptée.

Le démon sshd utilise un fichier de configuration général /etc/sshd_config et plusieurs fichiers contenant les clefs publiques et privées de la machine pour les différents protocoles cryptographiques utilisés par les clients. Les protocoles disponibles sont le protocole RSA pour la version 1 du protocole SSH, et les protocoles RSA et DSA pour la version 2. Comme il existe deux fichiers pour les clefs du serveur (un premier fichier lisible par tous les utilisateurs, pour la clef publique, et un fichier lisible uniquement par l'utilisateur root, pour la clef privée), il peut exister au total six fichiers de clefs. Ces fichiers sont nommés respectivement /etc/ssh_host_key et /etc/ssh_host_key.pub pour les clefs privées et publiques du protocole de version 1, et /etc/ssh_host_rsa_key, /etc/ssh_host_rsa_key.pub, /etc/ssh_host_dsa_key et /etc/ssh_host_dsa_key.pub respectivement pour les algorithmes RSA et DSA du protocole SSH de version 2.

Normalement, les fichiers de clefs du serveur ont été créés automatiquement lors de l'installation de SSH. Cependant, si vous installez SSH à partir d'une archive de distribution, ils peuvent ne pas être présents, et vous devrez générer ces clefs vous-même. Pour cela, il faut utiliser la commande ssh-keygen, dont la syntaxe est la suivante :

ssh-keygen [-t type]
type est le type de clef à générer pour le protocole de version 2. Les types disponibles sont rsa et dsa. Pour le protocole de version 1, il ne faut pas utiliser l'option -t, les clefs générées étant forcément des clefs RSA.

Lorsque l'on invoque la commande ssh-keygen, celui-ci demande le chemin du fichier dans lequel la clef privée doit être écrite. Le fichier contenant la clef publique aura le même nom, mais portera l'extension .pub. Vous devez donc saisir le chemin du fichier correspondant au type de clef généré. ssh-keygen demande ensuite le mot de passe à utiliser pour le cryptage de la clef privée. Dans le cas d'un serveur, il ne faut pas utiliser de mot de passe, car dans ce cas le démon sshd ne pourrait pas accéder à la clef privée de la machine. Il faut donc, dans ce cas, valider simplement sans rien taper.

Une fois les fichiers de clefs du serveur générés, vous pouvez vous intéresser au fichier de configuration sshd_config. Ce fichier de configuration contient un certain nombre d'options qui indiquent les paramètres que le démon doit utiliser. Vous trouverez ci-dessous un exemple de fichier de configuration :

# Paramètres de connexion :
Port 22
ListenAddress 0.0.0.0
KeepAlive yes

# Protocoles utilisables :
Protocol 2

# Chemin sur les fichiers de clefs :
HostKey /etc/ssh_host_rsa_key
HostKey /etc/ssh_host_dsa_key

# Paramètres des messages de traces :
SyslogFacility AUTH
LogLevel INFO

# On définit les modes d'authentification utilisables :

# Authentification par clef publique :
RSAAuthentication no
PubkeyAuthentication yes

# Authentification par type de machine :
RhostsAuthentication no
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no

# Authentification par mot de passe :
PasswordAuthentication no
PermitEmptyPasswords no

# Options générales :

# L'utilisateur root ne doit pouvoir se loguer qu'en local :
PermitRootLogin no

# Utilise le compte non privilégié sshd
# pour les communications réseau :
UsePrivilegeSeparation yes

# On n'autorise la connexion que pour les utilisateurs dont
# les fichiers de configuration sont correctement protégés :
StrictModes yes

# Encapsulation automatique du protocole X :
X11Forwarding yes
X11DisplayOffset 10

# Affichage des informations habituelles au login :
PrintMotd no
PrintLastLog yes

Comme vous pouvez le constater, un grand nombre d'options sont disponibles. Les options Port et ListenAddress permettent de définir l'adresse IP sur laquelle le démon sshd se mettra en attente de demandes de connexion, ainsi que le port TCP utilisé pour cela. L'adresse 0.0.0.0 signifie ici qu'il doit se mettre en attente sur toutes les adresses de la machine. L'option KeepAlive permet de demander au démon de vérifier régulièrement que la liaison est toujours valide, afin de fermer les connexions automatiquement en cas d'arrêt du client. L'option Protocol permet de spécifier les versions utilisables du protocole SSH. La version 1 étant obsolète, on spécifiera systématiquement la valeur 2 ici. L'option HostKey permet, comme son nom l'indique, de donner les noms des fichiers contenant les clefs pour les différents protocoles d'authentification. Les options SyslogFacility et LogLevel permettent d'indiquer le type et le niveau des messages de traces générés par le démon sshd dans le fichier de traces du système.

Viennent ensuite les options spécifiques aux différents modes d'authentification. Les options RSAAuthentication et PubkeyAuthentication permettent d'activer et de désactiver l'authentification par clef publique des clients, respectivement pour les protocoles SSH de version 1 et 2. Les options RhostsAuthentication, IgnoreRhosts, RhostsRSAAuthentication et HostbasedAuthentication permettent de contrôler un protocole d'authentification basé sur l'identité des machines. Ce type d'authentification n'a pas été présenté car il est extrêmement peu sûr, et il faut impérativement désactiver ces fonctionnalités. Enfin, les options PasswordAuthentication et PermitEmptyPasswords permettent d'activer ou de désactiver l'authentification par mot de passe. Vous êtes libre d'utiliser ou non ces fonctionnalités.

Le fichier de configuration peut également contenir des options complémentaires. Les plus importantes pour la sécurité sont sans doute PermitRootLogin et StrictModes, qui permettent d'interdire la connexion par le réseau à l'utilisateur root d'une part, et d'interdire la connexion aux utilisateurs qui n'ont pas bien fixé les droits d'accès sur leurs fichiers de configuration personnels dans leur compte local (il est donc impossible de garantir que ces fichiers n'ont pas été trafiqués par d'autres utilisateurs pour accéder à leur compte). L'option UsePrivilegeSeparation permet de demander au démon sshd de n'effectuer les communications réseau que dans le compte spécial sshd, compte auquel on n'affectera que le minimum de droits. Cette technique permet de protéger le système contre l'exploitation d'une éventuelle faille de sécurité dans le démon sshd. L'option X11Forwarding permet d'activer l'encapsulation automatique du protocole X et peut être relativement pratique. Le numéro de display auquel les utilisateurs devront connecter leurs applications sera alors décalé du nombre indiqué par l'option X11DisplayOffset. Cette option est utile pour éviter les conflits avec les serveurs X locaux. Vous trouverez de plus amples informations sur le protocole X11 et l'environnement graphique dans le Chapitre 10. Enfin, les options PrintMotd et PrintLastLog permettent de spécifier les informations affichées par le démon sshd lorsque la connexion des clients est acceptée. Il existe bien d'autres options, vous pourrez obtenir de plus amples renseignements dans la page de manuel du démon sshd.

9.2.8.4.5. Utilisation d'OpenSSH côté client

Les clients peuvent se connecter à un serveur SSH à l'aide de la commande ssh. Cette commande s'utilise exactement de la même manière que les commandes rsh ou rlogin. La syntaxe de la commande ssh est la suivante :

ssh [-l nom] machine [commande]
ou :
ssh nom@machine [commande]
nom est ici le nom d'utilisateur à utiliser pour la connexion, et machine la machine distante. Si aucun nom d'utilisateur n'est spécifié, le nom de l'utilisateur sur la machine local est pris par défaut. Il est possible d'exécuter une commande sur la machine distante en la spécifiant après le nom de la machine. Si aucune commande n'est spécifiée, un shell interactif est lancé.

Selon le mode d'authentification du client choisi par le serveur, il peut être nécessaire ou non de définir des clefs pour le client. Tout comme pour les clefs publiques et privées d'un serveur, la génération de ces clefs se fait à l'aide de la commande ssh-keygen. Cependant, contrairement à ce qui se passait pour le serveur, les chemins par défaut proposés pour stocker les clefs sont ici corrects, et il est vivement recommandé de saisir un mot de passe pour crypter la clef privée. Les fichiers de clefs générés par ssh-keygen sont les fichiers identity et identity.pub pour le protocole d'authentification RSA de la version 1 du protocole SSH, et les fichiers id_rsa, id_rsa.pub, id_dsa et id_dsa.pub respectivement pour les protocoles RSA et DSA de la version 2 du protocole SSH. Tous ces fichiers sont stockés dans le répertoire .ssh/ du répertoire personnel de l'utilisateur qui les génère. Il va de soi que les fichiers des clefs privées doivent ne doivent pas être lisibles pour les autres utilisateurs, et que les fichiers des clefs publiques ne doivent pas pouvoir être écrits si l'on veut éviter qu'un usurpateur prenne notre place sur notre propre machine.

Afin de bénéficier de l'authentification des serveurs auxquels on se connecte, il faut placer les clefs publiqes de ces derniers dans le fichier .ssh/known_hosts. Si, lors d'une connexion à un serveur, la clef publique de celui-ci n'est pas connue, ssh vous le signalera. Il indiquera un message d'erreur indiquant que le serveur auquel on se connecte n'est pas forcément celui qu'il prétend être, et affiche un condensé de sa clef publique. Vous devrez vous assurer que ce condensé est bien celui de la clef publique du serveur auquel vous vous connectez, et ce par un moyen sûr (déplacement physique et connection en local par exemple). Si vous acceptez cette clef, ssh la placera pour vous dans votre fichier known_hosts, ce qui vous permettra de vous connecter par la suite en toute quiétude. Attention, le fichier known_hosts ne doit pas être accessible en écriture aux autres utilisateurs, car dans ce cas un pirate pourrait capter toutes vos communications !

Si le mode d'authentification utilisé est le mot de passe, ssh vous demandera de saisir le mot de passe du compte distant. Dans ce cas, ssh se comporte exactement comme rsh, à ceci près que votre mot de passe ne circulera pas en clair sur le réseau (quel progrès !).

Si, en revanche, le mode d'authentification utilisé est une authentification par clef publique, alors vous devrez avoir défini vos clefs privées et publiques. Pour que le démon sshd de la machine distante accepte la connexion, vous devrez placer vos clefs publiques dans le fichier authorized_keys du répertoire ./ssh/ du répertoire du compte distant. Cela permettra au démon sshd de s'assurer que c'est bien vous qui vous connectez. Attention, le fichier authorized_keys ne doit pas être accessible en écriture, faute de quoi un autre utilisateur de la machine distante pourrait se connecter en votre nom. Il est également impératif de réaliser l'écriture soi-même dans ce fichier par un moyen sûr (déplacement physique). En aucun cas la communication de votre clef publique à l'administrateur distant ne pourra être considérée comme un moyen sûr pour écrire cette clef : en effet, un pirate pourrait tout aussi bien lui demander d'écrire sa propre clef dans votre fichier !

Vous constaterez qu'un certain nombre de précautions doivent être prises pour les manipulations de clefs. Comme il l'a déjà été indiqué plus haut, le point faible est bel et bien l'authentification des clients. Cela concerne en premier lieu le client bien entendu, dont le compte peut être piraté, mais c'est aussi un trou de sécurité énorme pour le serveur, car une fois le loup dans la bergerie, il peut faire beaucoup de dégâts et chercher à accroître ses droits (jusqu'à devenir root) par d'autres techniques.

9.2.8.4.6. Création d'un tunnel SSH

L'un des principaux avantages de SSH est qu'il est possible de l'utiliser pour encapsuler n'importe quel protocole réseau TCP dans le canal de communication d'une connexion sécurisée. Un tel canal est communément appelé un « tunnel », en raison du fait qu'il est utilisé par les informations sensibles pour traverser un réseau non sûr. Grâce aux tunnels SSH, il est possible d'utiliser tous les protocoles classiques sans avoir à s'inquiéter de la confidentialité des informations transmises. SSH permet même de réaliser cette opération automatiquement pour le protocole X du système de fenêtrage X Window, ce qui est très commode si l'on désire afficher localement les fenêtres graphiques des programmes lancés sur le serveur.

Encapsuler le protocole X dans SSH est donc extrêmement aisé. En effet, il suffit simplement de donner la valeur « yes » à l'option X11Forwarding dans le fichier de configuration du serveur /etc/sshd_config et dans le fichier de configuration des clients (les valeurs par défaut pour tous les utilisateurs peuvent être définies dans le fichier de configuration /etc/ssh_config et être redéfinies par chaque utilisateur dans le fichier config de leur répertoire .ssh/). Si ces options sont activées, SSH se charge de fixer la variable d'environnement DISPLAY de la machine distante à un serveur X virtuel de cette machine. Les programmes X se connectent alors à ce serveur, et celui-ci effectue automatiquement le transfert des communications vers le serveur X du client. Il ne faut donc pas, quand on utilise SSH, modifier manuellement la variable d'environnement DISPLAY. Vous trouverez plus d'information sur X Window dans le Chapitre 10.

Pour les autres protocoles, les opérations ne sont pas réalisées automatiquement par SSH. Il faut donc établir un réseau privé virtuel manuellement. Le principe est le suivant : les programmes clients sont paramétrés pour se connecter sur un port local différent de celui utilisé habituellement pour leur protocole. Ainsi, ils ne s'adressent pas directement au serveur distant, mais plutôt à un proxy local établi par SSH pour l'occasion. Ce proxy établit un canal de communication crypté avec le démon sshd de la machine distante. Toutes les informations du protocole encapsulé passent alors par le canal crypté, et le démon sshd de la machine distante retransmet ces informations au service distant auquel le client devait se connecter.

Tout ce mécanisme ne fonctionne que parce qu'il est possible de rediriger les clients sur un port réservé par SSH sur leur machine locale. Cette redirection peut être initiée aussi bien du côté serveur que du côté client, lors de la connexion. Du côté du client, la redirection de port peut être réalisée avec la commande suivante :

ssh -Llocal:serveur:port machine [commande]
local est le port de la machine locale auquel il faudra se connecter pour accéder au service distant, fonctionnant sur le port port de la machine serveur. Cette commande ouvre une session SSH sur la machine machine (qui, normalement, est la même que serveur), et réalise la redirection du flux destiné au port local dans le canal de cette session.

Il faut bien comprendre que cette redirection se fait en plus de la connexion SSH, et que la syntaxe donnée ci-dessus ouvre une connexion sur la machine distante (ou exécute la commande spécifiée en paramètre, s'il en est spécifiée une). Si l'on désire simplement établir un tunnel, on peut refermer la session juste après avoir lancé le programme qui doit utiliser ce tunnel. En effet, SSH maintient le tunnel ouvert tant qu'un programme détient une connexion sur le port redirigé. On peut aussi exécuter une commande sleep sur un délai arbitraire, qui permettra de se connecter sur le port redirigé et qui se terminera automatiquement.

Du côté serveur, la syntaxe est similaire. Cette fois, la commande permet d'indiquer le port que le client devra utiliser pour accéder à un service non sécurisé du serveur. La syntaxe à utiliser est la suivante :

ssh -Rport:client:local machine [commande]
port est le port que le client devra utiliser, client est la machine cliente, et local est le port local utilisé par le service que l'on veut exposer de manière sécurisée au client. Encore une fois, cette commande ouvre une connexion SSH, il faut donc spécifier la machine à laquelle on se connecte (en l'occurrence, le client). Une commande peut être spécifiée de manière optionnelle, s'il n'y en a pas, un shell sera lancé sur la machine distante.

Note : Prenez bien conscience que SSH ne s'assure du chiffrement que des données transmises sur le réseau. Si la machine cliente ou la machine serveur ne sont pas correctement configurées, un pirate peut espionner les communications réseau internes à cette machine. Pour éviter ce type de risque, il faut utiliser des protocoles réseau eux-mêmes cryptés. Autrement dit, une fois sorti du tunnel SSH, vous vous exposez à nouveau aux risques d'intrusion.

Il existe d'autres méthodes de tunneling sous Linux, qui sont sans aucun doute plus ergonomiques que SSH. En effet, non seulement les tunnels SSH ne peuvent pas être créés automatiquement (ils nécessitent une connexion), mais en plus les connexions SSH se terminent dès que le dernier client disparaît. En fait, les fonctionnalités de SSH sont un plus, mais elles ne sont pas destinées à remplacer des solutions plus adaptées pour réaliser des tunnels. Vous trouverez plus d'informations sur les réseaux privés virtuels ci-dessous. Pour information, une évolution du protocole IP a été définie pour permettre les communications cryptées et garantissant l'authenticité des machines. Il s'agit du protocole IPSec, dont vous trouverez une implémentation libre pour Linux sur le site de FreeSwan.