« Routage sélectif vers plusieurs connexions internet » : différence entre les versions

De Le Wiki du Forum-Debian.fr
Aller à la navigation Aller à la recherche
mAucun résumé des modifications
m (remarque : changement de la passerelle par défaut)
Ligne 160 : Ligne 160 :
<pre># ip rule add fwmark 50 table 50
<pre># ip rule add fwmark 50 table 50
# ip rule add fwmark 51 table 51
# ip rule add fwmark 51 table 51
</pre>
À noter que&nbsp; la duplication de la table de routage de l'accès par défaut permettra par la suite de définir des stratégies figées (telles connexions forcées sur tel ou tel accès internet) tout en laissant la possibilité,&nbsp;à l'aide d'une simple série de commandes, de modifier l'accès internet par défaut pour les connexions non marquées :
<pre># ip route del table main default
# ip route add table main default via {IP de la passerelle par défaut} dev {nom de l'interface par défaut}
# ip route flush cache
</pre>  
</pre>  
<br>  
<br>  
Ligne 191 : Ligne 196 :
'''Note&nbsp;:''' cette opération de recopie devra avoir lieu à chaque fois que la table de routage principale sera modifiée, ce qui inclut les changements d'état des diverses interfaces. Encore une fois, les évènements '''up''' et '''down''' des interfaces concernées sont vos amis&nbsp;!<br>  
'''Note&nbsp;:''' cette opération de recopie devra avoir lieu à chaque fois que la table de routage principale sera modifiée, ce qui inclut les changements d'état des diverses interfaces. Encore une fois, les évènements '''up''' et '''down''' des interfaces concernées sont vos amis&nbsp;!<br>  


<br>
<br>  


= Règles iptables<br>  =
= Règles iptables<br>  =

Version du 12 mai 2010 à 11:06

On dispose de plusieurs accès internet distincts, et l'on souhaite pouvoir rediriger (re-router) arbitrairement certaines connexions réseau vers l'un ou l'autre de ces accès.

Autrement dit, nous allons gérer de manière sélective le load-balancing entre plusieurs accès à internet. Comme nous le verrons par la suite, les critères déterminant quelle connexion doit utiliser quel accès ne sont qu'une toute petite partie du problème.


Un autre aspect important, le fail-over en cas d'indisponibilité d'un des accès, n'est pas traité ici : on considérera que les stratégies de routage doivent s'appliquer de manière stricte (si une connexion est censée utiliser un accès indisponible elle sera tout simplement refusée). Ceci peut assez facilement être rajouté par la suite en rajoutant des scripts (attachés aux évènements up et down des interfaces ou surveillant en tâche de fond l'état de santé des accès internet) qui seront chargés de modifier dynamiquement la configuration de routage et d'iptables en fonction des interfaces disponibles. Par souci de simplicité nous omettrons cette partie qui est laissée comme exercice pour le lecteur.


Ces accès internet peuvent prendre de nombreuses formes : ADSL, fibre optique, Wifi, modem, tunnel IP, PPP, VPN, ...

De manière générale on se trouve face à deux cas distincts :

  • Une seule passerelle internet est accessible via une interface réseau donnée.
  • Plusieurs passerelles internet sont accessibles via une même interface réseau donnée.

Pour que ce tutoriel fonctionne, on s'intéressera uniquement au premier cas. Autrement dit, on appliquera systématiquement la règle « 1 interface réseau = 1 passerelle = 1 accès internet », sachant que la notion d'interface réseau correspond à la vue fournie par la commande # ip address plutôt que # ifconfig (qui a le défaut d'afficher des doublons lorsqu'une interface dispose de plusieurs adresses IP).
Si une interface donnée permet l'accès à plusieurs passerelles, il faudra malheureusement faire un choix pour n'en utiliser qu'une seule.


On utilisera la combinaison d'outils suivante :

  • Marquage de paquets (iptables -j MARK) pour déterminer quelle connexions réseau nous devons traiter.
  • Marquage de connexions (iptables -j CONNMARK) pour gérer l'affinité d'une connexion avec un accès donné.
  • Tables de routage (iproute2) pour router les connexions vers l'une ou l'autre passerelle.
  • Translation NAT (iptables -j SNAT) pour assurer le transit correct des paquets re-routés.


Note : un récapitulatif [TODO: lien] est disponible à la fin de ce document, qui résume toutes les commandes nécessaires à la création des diverses règles. Il n'est donc pas utile (et même contre-indiqué) de saisir les commandes au fil du tutoriel. Que cela ne vous empêche pas de lire les explications, leur compréhension est nécessaire pour vous éviter de faire des bêtises !

Sachez que si vous vous retrouvez sans connexion internet (ce qui peut arriver quand on manipule n'importe comment les tables de routage) et sans savoir comment réparer la situation, un simple reboot de votre machine suffira à rétablir votre configuration d'origine.


Obtenir de l'aide

Ce tutoriel était à l'origine un T&A sur le forum debian-fr.org. Étant donné l'ampleur que ce document a pris, il m'est difficile de maintenir une version équivalente sur le forum en ne disposant que de BBCode.

Cependant, le fil de discussion associé est toujours d'actualité pour la partie support. N'hésitez pas à y poser vos questions ou à partager vos trucs et astuces !

Avertissement

Le sujet traité serait assez complexe si l'on voulait être complet, je me suis donc permis de prendre des raccourcis au niveau des explications pour simplifier certains concepts. Si vous souhaitez apporter des précisions concernant certains points traités un peu trop vite et/ou de manière peu précise, demandez-vous simplement auparavant s'il ne s'agit pas d'une vulgarisation ou généralisation, et si un utilisateur lambda a réellement besoin de faire la distinction aussi finement. Ça évitera les discussions sans fin alors que nous sommes probablement d'accord... Mais que ça ne vous empêche pas de poser des questions si quelque chose ne vous paraît pas clair !


Configuration réseau utilisée

On supposera disposer de la configuration réseau suivante :

  • eth0 : adresse 192.168.1.100/24, passerelle 192.168.1.1, correspondant à l'accès internet par défaut utilisé actuellement.
  • eth1 : adresse 192.168.2.100/24, passerelle 192.168.2.1, correspondant à un accès internet non utilisé actuellement.

Il est bien évident que la technique présentée ici peut gérer sans problème plus de deux accès internet, il suffit d'adapter la configuration et les diverses règles en conséquence.


Problématiques rencontrées

Stratégies de routage

Le but de ce tutoriel étant de router arbitrairement des connexions via l'accès internet de notre choix, il est bien évident qu'il faudra porter une attention particulière aux règles que l'on choisira pour décider quelle connexion transitera par quel accès.

Les possibilités sont infinies, en voici quelques exemples :

  • Connexions e-mail (ports TCP 25 et 110) vers une connexion secondaire lente.
  • Trafic web (ports TCP 80 et 443) vers un FAI différent pour pouvoir profiter des offres réservées à ses abonnés.
  • Forcer les communications avec un serveur particulier à utiliser un accès sécurisé.
  • Faire transiter toutes les connexions d'un programme donné via un accès spécifique.
  • Etc...

On peut bien sûr avoir plusieurs stratégies actives en parallèle, encore une fois il s'agit simplement d'adapter les règles.


Tout au long de ce tutoriel, nous nous intéresserons plus particulièrement à une option très simple : router le trafic SSH (à destination du port TCP 22) vers l'accès internet fourni par la passerelle 192.168.2.1 sur eth1.
Mais ne vous inquiétez pas, le récapitulatif final [TODO: lien] contient plusieurs autres « recettes » qui vous seront probablement plus utiles que ça.


Affinité des connexions

Un problème majeur est de savoir comment gérer les connexions lorsqu'un des accès internet devient indisponible.

En effet, on ne peut pas changer en cours de route l'accès internet utilisé par une connexion existante : la machine distante avec laquelle on discute ne reconnaîtrait pas les paquets comme appartenant à la connexion, et les ignorerait probablement sans nous répondre. Le résultat final serait que le programme émetteur, sur notre machine, se retrouverait bloqué jusqu'à ce que tous les timeouts prennent effet, ce qui peut être assez long (de l'ordre de plusieurs minutes voire dizaines de minutes).

Le problème réel est que lorsqu'une interface réseau devient indisponible (par exemple une connexion point à point fermée par le pair), toutes les entrées correspondantes sont supprimées des tables de routage, ce qui a pour effet de re-router automatiquement les paquets vers un autre accès internet sans que nous puissions contrôler ce qui se passe.


La solution à ce problème particulier est de gérer la notion d'affinité d'une connexion réseau donnée avec un certain accès internet : lorsqu'une connexion a commencé à utiliser un accès, elle continuera de l'utiliser quels que soient les changements de configuration qui interviennent.

Si un accès devient indisponible, les connexions existantes qui l'utilisent seront réinitialisées.

Concernant les nouvelles connexions censées utiliser l'accès indisponible, on se retrouve face à plusieurs choix :

  • Les autoriser à utiliser l'accès internet par défaut.
  • Les forcer à utiliser un autre accès internet spécifique.
  • Leur interdire d'utiliser un autre accès internet que celui prévu.

Pour des raisons de simplicité nous ne nous intéresserons ici qu'à la troisième option, ce qui a l'avantage d'homogénéiser le comportement d'une passerelle « classique » (disponible sur un LAN via une interface fiable de type Ethernet ou Wifi, mais n'offrant pas de garantie que l'accès internet soit fonctionnel) et celui des connexions point à point (dont la présence de l'interface virtuelle est dépendante de la disponibilité de l'accès internet).


Cela signifie donc qu'une connexion prévue pour utiliser un accès donné sera tout simplement refusée si cet accès est indisponible.

Encore une fois, comme précisé dans l'introduction, il est relativement aisé de rajouter sur le tard des scripts de gestion d'indisponibilité (fail-over) mais nous n'entrerons pas ici dans les détails pour ne pas surcharger ce tutoriel.


Détermination des diverses constantes

Pour chacun des accès internet utilisés, nous devons choisir plusieurs valeurs numériques :

  • Une valeur utilisée pour le marquage des paquets dans iptables (entre 1 et 4294967295) qui servira entre autres à nous aiguiller vers la bonne passerelle (via une table de routage spécifique).
  • Une valeur utilisée pour le marquage des connexions dans iptables (entre 1 et 4294967295) qui servira à gérer l'affinité d'une connexion avec un accès internet donné et, le cas échéant, à détecter automatiquement si une connexion doit être réinitialisée suite à l'indisponibilité de l'interface qu'elle utilise.
  • Une valeur utilisée pour identifier la table de routage permettant d'accéder à la passerelle internet (entre 1 et 2147483647 sauf 253, 254 et 255). Attention : les valeurs supérieures ou égales à 256 ne peuvent pas être supprimées par la commande # ip rule del table mais doivent être supprimées par # ip rule del priority ce qui rend l'automatisation de la tâche beaucoup plus délicate (pas impossible cependant si on est suffisamment têtu). Pour des raisons de simplicité, nous nous contenterons donc de valeurs comprises entre 0 et 252.


Nous devons également choisir une valeur pour le marquage des connexions dans iptables, utilisée spécifiquement pour indiquer qu'une connexion doit être réinitialisée (cf. Affinité des connexions).

Enfin, nous aurons besoin d'une valeur pour identifier une table de routage supplémentaire servant à bloquer les connexions à destination des éventuelles interfaces indisponibles (cf. Affinité des connexions à nouveau).


Afin de simplifier les choses, pour un même accès internet nous utiliserons une seule valeur identique pour le marquage de paquets, le marquage de connexions, et l'identification des tables de routage. Cela limite donc notre choix aux valeurs possibles pour les tables de routage.

On doit en outre s'assurer que les valeurs choisies ne rentrent pas en conflit les unes avec les autres, ni avec une configuration de marquage ou de routage pré-existante. Si vous ne savez si vous utilisez déjà du marquage ou des tables de routage spécifiques, c'est que ce n'est probablement pas le cas.


Valeurs utilisées dans ce tutoriel :

  • Table de routage de blocage : 250.
  • Marquage de connexions pour réinitialisation : 4321.
  • Marquage de paquets / connexions et tables de routage pour eth0 : 50.
  • Marquage de paquets / connexions et tables de routage pour eth1 : 51.


Tables de routage

Blocage des connexions vers les interfaces indisponibles

Pour réaliser le blocage des connexions discuté dans Affinité des connexions, on va créer une table de routage spécifique (la 250) ne contenant qu'une seule entrée spécifiant qu'il n'y a aucune route disponible.

On créera également des liens de routage entre cette table et les marquages de paquets correspondant à chacun des accès internet :

# ip route flush table 250
# ip route add table 250 unreachable default
# ip rule add fwmark 50 table 250
# ip rule add fwmark 51 table 250


Liens de routage

Pour chaque accès internet, il nous faut créer un lien de routage entre le marquage des paquets et les tables de routage que nous allons créer par la suite :

# ip rule add fwmark 50 table 50
# ip rule add fwmark 51 table 51

À noter que  la duplication de la table de routage de l'accès par défaut permettra par la suite de définir des stratégies figées (telles connexions forcées sur tel ou tel accès internet) tout en laissant la possibilité, à l'aide d'une simple série de commandes, de modifier l'accès internet par défaut pour les connexions non marquées :

# ip route del table main default
# ip route add table main default via {IP de la passerelle par défaut} dev {nom de l'interface par défaut}
# ip route flush cache


Création des tables de routage spécifiques

Par défaut, notre machine comporte une table de routage principale (la 254, nommée main) qui comporte toutes les informations nécessaires pour utiliser le(s) réseau(x) local(aux) ainsi que l'accès internet par défaut (eth0 dans notre cas).

Pour chacun des accès internet on va recopier cette table en remplaçant la passerelle par défaut par la passerelle correspondant à l'accès en question :

#!/bin/sh

copyRoutingTable()
{
  local TABLE="$1"
  local IFACE="$2"
  local GATEWAY="$3"
  ip route flush table $TABLE
  ip route show table main \
    | grep -Ev ^default \
    | while read ROUTE ;
    do
      ip route add table $TABLE $ROUTE
    done
  ip route add table $TABLE default via $GATEWAY dev $IFACE
}

copyRoutingTable 50 eth0 192.168.1.1
copyRoutingTable 51 eth1 192.168.2.1
ip route flush cache

Note : cette opération de recopie devra avoir lieu à chaque fois que la table de routage principale sera modifiée, ce qui inclut les changements d'état des diverses interfaces. Encore une fois, les évènements up et down des interfaces concernées sont vos amis !


Règles iptables

Suivi de l'affinité des connexions

Translation NAT

Marquage des paquets en fonction des stratégies de routage