www.lalitte.com - Réseau

Contenu
Home
Les faqs
Réseau
Elearning
Enigmes
Webmail
L'ancienne page flash
Liens


Mise en place d'une double connexion ADSL sous linux

 Comme son nom l'indique justement, ce document présente la mise en place d'une double connexion
 ADSL sous linux. Mais d'autres points intéressants sont abordés, comme la NAT, le port forwarding,
 la QOS, etc. Tout cela pour pouvoir tirer le meilleur parti de votre double connexion :-)
 Merci à Pierre de Luca pour m'avoir aiguillé vers cette solution ;-)
 Merci à Filip Supera pour ses corrections orthographiques.

 Pourquoi une double connexion ?
  1- Pour garantir un accès à Internet sans coupures.
  2- Pour augmenter la capacité de la bande passante
  3- Pour pouvoir offrir des services qui peuvent difficilement soufrir de coupures de connexion, 
     comme le DNS(serveur de noms) ou le SMTP(mail)
  4- Pour faire de l'hébergement (Votre nom de domaine par exemple)
  5- Pour le fun étant donné que c'est un beau projet réseau :-)

 Voilà en gros les raisons qui m'ont poussé à vouloir mettre en oeuvre une telle configuration, 
 mais les raisons peuvent être tout autres, à vous de voir l'intérêt que vous pouvez y trouver.

Sommaire:

 1- Préambule
 2- Les connexions ADSL
 3- La mise en place des connexions (à venir)
 4- Le routage avancé sous linux
 5- Mise en place du routage pour notre double connexion
 6- Optimisation de l'accès
 7- Tester si ca marche
 8- Gestion d'une coupure d'accès (à venir)

 Le script de connexion complet (02/07/04)
 Le script iptables complet (non testé... 02/07/04)

1- Préambule

 J'ai donc mis en place cette configuration chez moi (Schéma)
 Je dois avouer que ma configuration n'est pas des plus simples, donc en suivant les instructions
 et en essayant de comprendre un minimum ce qui est fait, vous devriez facilement être en mesure
 de reproduire cela chez vous.

 Le principe est donc de se servir en même temps des deux connexions ADSL. Le routeur/NAT
 linux aura donc pour rôle de router alternativement les connexions d'un coté puis de
 l'autre. La balance des connexions entrantes pouvant se faire par un round Robin DNS
 (si ces termes vous semblent barbares, ils sont expliqués plus en détail par la suite)

2- Les connexions ADSL

 Il s'agit d'une connexion ADSL 1024/256 9telecom et d'un accès Free par Freebox dégroupé 
 (j'obtiens un accès en pointe d'environ 4Mbps en download, sans télé ou téléphone)
 L'accès 9telecom se fait par un modem alcatel USB vers la linux. Mais je vous conseille
 d'éviter les connexions USB qui apportent, à mon avis, plus de problèmes que les connexions
 à base d'Ethernet. M'enfin bon, ca met du piment ;-)
 L'accès Free se fait donc par une Freebox connectée à mon routeur/NAT linux Mandrake 9.0
 en Ethernet 10Mbps .

3- La mise en place des connexions (à venir)


4- Le routage avancé sous linux

 Avant de commencer, il faut savoir que cette réalisation est extrèmement simple si vous
 connaissez les principes de routage de base, et même d'ailleurs si vous ne les connaissez
 pas. La suite de la lecture vous permettra de mieux comprendre ce qui est mis en place,
 mais vous pouvez directement passer aux commandes à entrer si la compréhension du sujet ne
 vous intéresse pas.
 On a l'habitude d'utiliser les commandes de gestion IP simples de linux comme "ifconfig",
 "route" ou autres "arp".
 Il faut savoir que linux permet une utilisation avancée des possibilités IP et cela à travers
 la commande "ip" (documentation officielle ici)
 Ce sont ces fonctions avancées que nous allons utiliser pour faire notre balance de charge.
 Elles permettent notamment pour notre cas de mettre en place deux passerelles par défaut
 utilisées alternativement, ainsi que du policy routing pour faire du routage selon l'adresse source.

Aperçu rapide du fonctionnement du routage avancé

 Le routage tel qu'on l'entend se base sur l'utilisation par le système d'exploitation
 d'une table de routage permettant d'aiguiller le traffic en fonction des adresses destination
 voir la faq sur le routage. Rien d'extraordinaire là dedans, il s'agit des principes de base
 du fonctionnement d'Internet.
 Le routage avancé sous linux grâce au logiciel iproute2 permet non seulement de définir plusieurs
 tables de routage, mais aussi de n'utiliser ces tables de routage qu'en fonction de certains
 critères, comme les adresses source dans notre mise en oeuvre.

Le fonctionnement

 Par défaut, trois tables de routage sont en place (Eh oui ! même si vous n'avez rien fait de
 spécial sur votre linux préféré, ces tables sont toujours présentes !) Il s'agit des tables local,
 main et default.
 La table que vous avez l'habitude de voir par la commande "route -n" ou "netstat -nr" est
 en fait la table main. Les autres tables sont présentes et même utilisées, à l'insu de votre
 plein gré !
 Pour lister les tables en place, rien de plus simple, il faut utiliser la commande "ip rule list":

 [root@Belleville init.d]# ip rule list
 0:      from all lookup local
 32766:  from all lookup main
 32767:  from all lookup default

 et pour votre votre table de routage préférée...

 [root@Belleville init.d]# route -n
 Table de routage IP du noyau
 Destination     Passerelle      Genmask         Indic Metric Ref    Use Iface
 62.39.237.1     0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
 192.168.0.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
 82.226.217.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
 127.0.0.0       0.0.0.0         255.0.0.0       U     0      0        0 lo
 0.0.0.0         62.39.237.155   0.0.0.0         UG    0      0        0 ppp0

 Qui n'affiche donc que la table "main".
 Pour pouvoir lister le contenu d'une autre table, il va falloir le demander explicitement
 et utiliser notre commande "ip" pour accéder aux fonctions avancées:

 [root@Belleville root]# ip route list table local
 local 192.168.0.254 dev eth0  proto kernel  scope host  src 192.168.0.254
 broadcast 192.168.0.255 dev eth0  proto kernel  scope link  src 192.168.0.254
 broadcast 127.255.255.255 dev lo  proto kernel  scope link  src 127.0.0.1
 broadcast 82.226.217.255 dev eth1  proto kernel  scope link  src 82.226.217.65
 broadcast 192.168.0.0 dev eth0  proto kernel  scope link  src 192.168.0.254
 broadcast 82.226.217.0 dev eth1  proto kernel  scope link  src 82.226.217.65
 broadcast 127.0.0.0 dev lo  proto kernel  scope link  src 127.0.0.1
 local 82.226.217.65 dev eth1  proto kernel  scope host  src 82.226.217.65
 local 62.39.237.155 dev ppp0  proto kernel  scope host  src 62.39.237.155
 local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1
 local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1

 Et voilà. Maintenant, comment savoir quelle table est utilisée quand un paquet IP
 arrive ?
 C'est très simple, il parcourt simplement les tables une par une jusu'à trouver
 une entrée correspondant à l'adresse IP de destination spécifiée. L'ordre dans
 lequel les tables sont parcourues provient simplement du numéro accocié à la table
 (le numéro qui apparaît en début de ligne lors de la commande "ip rule list")
 Ainsi, dans notre exemple, si aucune entrée n'est trouvée dans la table locale, 
 la table main sera parcourue, puis la table default.
 L'ordre entre les différentes tables est donc très important. Si vous n'y faites
 pas attention, vous risquez d'avoir des surprises...
 Mais maintenant, comment agir sur ces tables, en ajouter ou en enlever ?

Ajout de tables et de routes au sein d'une table

 Pour ajouter une table, il faut utiliser la commande "ip rule add". Mais avant 
 cela, il faut faire connaître à iproute le nom de notre table:

 [root@Belleville init.d]# echo 201 nom_de_table >> /etc/iproute2/rt_tables

 Puis ajouter notre table:

 [root@Belleville init.d]# ip rule add lookup nom_de_table
 [root@Belleville init.d]# ip rule list
 0:      from all lookup local
 32765:  from lookup nom_de_table
 32766:  from all lookup main
 32767:  from all lookup default

 C'est bien, mais si vous avez saisi le principe, l'ajout de notre table ne nous
 apporte pas grand chose à partir du moment ou elle ne se différencie pas des
 autres tables présentes. Nous pourrions par exemple ajouter des critères à notre
 table pour qu'elle ne soit parcourue que dans certains cas, et c'est là où
 l'utilisation de plusieurs tables va s'avérer puissante.
 Par exemple, nous allons créer une table qui ne sera parcourue que si l'adresse
 source du paquet IP est l'adresse voulue (ici, ma machine ayant pour adresse 
 10.0.0.1) Ainsi, nous pourrons aiguiller les paquets de façon spécifique pour
 telle ou telle machine.

 [root@Belleville init.d]# echo 202 pour_ma_machine >> /etc/iproute2/rt_tables
 [root@Belleville init.d]# ip rule add from 10.0.0.1 lookup pour_ma_machine
 [root@Belleville init.d]# ip rule list
 0:      from all lookup local
 32764:  from 10.0.0.1 lookup pour_ma_machine
 32765:  from lookup nom_de_table
 32766:  from all lookup main
 32767:  from all lookup default
 
 Maintenant, un paquet ayant pour adresse ip source 10.0.0.1 passera par la table 
 pour_ma_machine.
 La table est vide pour l'instant, mais si nous y ajoutons par exemple une route
 par défaut, ma machine utilisera toujours cette route par défaut, et non celle
 spécifiée dans la table "main". Ajoutons par exemple une route par défaut dans la
 table "pour_ma_machine":

 [root@Belleville init.d]# ip route add default via 10.0.0.254 table pour_ma_machine
 
 et hop:

 [root@Belleville init.d]# ip route list table pour_ma_machine
 default via 10.0.0.254 dev eth1

Ajout d'une double route par défaut

 L'intérêt majeur de l'utilisation d'iproute2 dans notre cas est avant tout celui-ci, 
 c'est à dire de pouvoir spécifier deux routes par défaut qui seront toutes deux utilisées.
 Pour cela, iproute bénéficie d'une commande très simple et efficace 
 "ip route add default equalize"
 Ce qui nous donne par exemple:
 
 [root@Belleville init.d]# ip route add default equalize nexthop via 10.0.0.253 dev ppp0 \
                              weight 1 nexthop via 192.168.0.254 dev eth1 weight 1

 Nous n'avons pas spécifié de table pour l'entrée de cette route, elle sera donc ajoutée
 à la table main.

 [root@Belleville init.d]# ip route list table main
 10.0.0.1 dev ppp0  proto kernel  scope link  src 62.39.237.155
 192.168.0.1/24 dev eth1  proto kernel  scope link  src 82.226.217.65
 127.0.0.0/8 dev lo  scope link
 default equalize
        nexthop via 10.0.0.253  dev ppp0 weight 1
        nexthop via 192.168.0.254  dev eth1 weight 1
 
 Et maintenant nos paquets vont alternativement passer par les passerelles 10.0.0.253 et
 192.168.0.254.

 Maintenant que nous avons abordé la majorité des concepts nécessaires, nous allons mettre
 cela en oeuvre pour notre double accès ADSL.

5- Mise en place du routage pour notre double connexion

 Le but dans un premier temps va donc simplement être de balancer la charge entre nos
 deux connexions Internet (Schéma)
 Le premier problème rencontré est l'adressage de la passerelle coté 9telecom. Etant
 donné que cette adresse est dynamique, il nous est impossible de la mettre en dur 
 dans le script qui va gérer le routage. Pour régler ce problème, nous allons utiliser
 une variable qui va chercher la valeur de l'adresse IP coté 9telecom ainsi que 
 l'adresse de la passerelle par défaut.

 NEUF_IP=`ifconfig | grep inet | grep P- | cut -d : -f 2 | cut -d P -f 1`
 NEUF_GW=`ifconfig | grep inet | grep P- | cut -d : -f 3 | cut -d M -f 1`

 Pour la suite, nous mettons simplement en place une double route par défaut dans
 notre table "main" (en pensant bien à effacer préalablement toute trace d'ancienne route
 par défaut):

 ip route add default equalize nexthop via $NEUF_GW dev ppp0 weight 1 nexthop \
    via 82.226.217.254 dev eth1 weight 1
 
 On peut remarquer que pour l'instant, j'ai mis un poids égal pour chacun des liens.
 Ceci pourra être changé par la suite.
 Normalement, si tout se passe bien, la balance de charge dynamique devrait
 maintenant fonctionner. Mais en lisant bien la doc sur le routage avancé, il est dit
 de mettre en place des routes de retour pour chacun des deux liens (ici)
 Je n'ai absolument pas compris pourquoi ceci était nécessaire pour l'instant. Si 
 quelqu'un a l'info, elle est la bienvenue :-)
 On crée donc deux tables dans lesquelles on place une route par défaut vers le réseau
 local.

 ip rule add from $NEUF_IP lookup 1
 ip rule add from 82.226.217.65 lookup 2
 ip route add 192.168.0.0/24 via 192.168.0.254 table 1
 ip route add 192.168.0.0/24 via 192.168.0.254 table 2

 Il ne nous reste plus qu'à mettre en place la NAT sur iptables pour chacun des fournisseurs
 d'accès:

 # Pour l'accès  9telecom
 NEUF_IP=`ifconfig | grep inet | grep P- | cut -d : -f 2 | cut -d P -f 1`
 NEUF_IFACE="ppp0"
 # Pour l'accès Free
 FREE_IP="82.226.217.65"
 FREE_IFACE="eth1"
 iptables -t nat -A POSTROUTING -o $NEUF_IFACE -j SNAT --to-source $NEUF_IP
 iptables -t nat -A POSTROUTING -o $FREE_IFACE -j SNAT --to-source $FREE_IP

 Maintenant, ca roule, notre double connexion à Internet fonctionne !
 On pourrait se dire que c'est gagné... et bien non, à l'usage on se rend vite compte que
 quelques problèmes sont rencontrés...

Le problème des serveurs DNS et SMTP des fournisseurs d'accès

 Bizarrement, la connexion ne fonctionne que par intermitence. En y regardant de plus près,
 on peut remarquer que les requêtes DNS ne fonctionnent pas très bien. Et c'est normal.
 Pour des raisons de charge, les fournisseurs d'accès n'autorisent que les adresses IP qu'ils
 allouent eux-mêmes à accéder à leurs serveurs. Ainsi, si un de mes clients décide d'interroger
 le serveur DNS de free, et que le routage dynamique le fait passer par 9telecom, la réponse
 à la requête n'aboutira pas. Il faut donc s'assurer que les requêtes pour les serveurs DNS de 
 Free passeront bien par Free, et de même pour 9telecom.
 Pour cela, il nous suffit de mettre en place des routes dédiées pour les adresses IP des 
 serveurs DNS de Free et 9telecom (et de même pour les serveurs POP et SMTP)

 # Les DNS de Free
 ip route add 212.27.32.176 via 82.226.217.254 table main
 ip route add 212.27.32.177 via 82.226.217.254 table main
 # Les DNS 9telecom
 ip route add 212.30.96.108 via $NEUF_GW table main
 ip route add 213.203.124.146 via $NEUF_GW table main
 # Le POP 9telecom
 ip route add 212.30.113.205 via $NEUF_GW table main
 # Le SMTP 9telecom
 ip route add 62.62.156.10 via $NEUF_GW table main
 ip route add 62.62.156.27 via $NEUF_GW table main
 ip route add 62.62.156.28 via $NEUF_GW table main

 Bon, maintenant c'est sûr ça y est, ça marche !
 Oui, mais ce n'est pas vraiment optimisé...

 !Attention!: Il est important que les adresses des serveurs DNS des deux opérateurs soient 
 configurées sur les postes clients, sans quoi l'accès à Internet serait perdu si jamais un 
 des liens venait à tomber.

6- Optimisation de l'accès

 Encore une fois, à l'usage je me suis vite rendu compte que la connexion n'était pas vraiment
 optimisée. Cela est notamment dû au fait que le débit de mes deux liens vers Internet est 
 asymétrique (le débit de Free est à peu près 4 fois plus gros que celui de 9telecom)
 Donc quand je téléchargeais par Free c'était la fête, mais quand ça passait par 9tel, ca
 l'était moins :-( C'est un peu dommage de télécharger à 100kbps alors qu'on peut le faire
 à 400kbps.
 Il faut donc maintenant que les flux de download passent par free, et qu'au contraire, les 
 flux qui ne nécessitent pas une grande bande passante passent par 9telecom.
 Le problème est que comme tout routeur, la table de routage ne peut normalement pas aiguiller
 les paquets en fonction de critères de couche 4 (ici, les ports HTTP et FTP) mais seulement de
 couche 3. La solution vient d'iptables qui peut mettre une marque dans l'en-tête IP en 
 fonction de ses différents critères d'analyse. Notamment, en fonction des ports TCP/UDP 
 utilisés. Il sufit donc de marquer les paquets selon le port, avant qu'ils soient routés.
 Par exemple pour les flux HTTP et FTP:

 iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 -j MARK --set-mark 80
 iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 21 -j MARK --set-mark 21 

 Il faut maintenant créer une table de routage pour chacun des flux (ou une seule si l'on préfère
 regrouper les critères) et mettre comme route par défaut le routeur de Free:

 echo 201 http >> /etc/iproute2/rt_tables
 echo 202 ftp >> /etc/iproute2/rt_tables
 ip rule add fwmark 80 table http
 ip rule add fwmark 21 table ftp
 ip route add default via 82.226.217.254 table ftp
 ip route add default via 82.226.217.254 table http

 Bon, maintenant, ca commence quand même à fonctionner pas mal :-)
 En faisant de même pour tous les flux critiques, on arrive à bien optimiser les connexions.
 Il ne nous reste plus qu'à mettre en place de la QOS en amont sur l'OpenBSD, et à mettre en
 place les scripts qui permettront de changer les tables de routage si jamais un lien vient à
 tomber.

7- Tester si ca marche

 A priori tout fonctionne bien, vous êtes assez content de vous, mais comment être sûr
 que la balance de charge fonctionne bien ?
 Il y a plusieurs façons de faire. Le plus simple à mon avis, si vous n'avez pas mis de
 route particulière en fonction du protocole est de tester à travers des pages web qui 
 affichent l'adresse IP avec laquelle vous vous connectez chez elles. Voici quelques 
 sites qui font cela:
 www.myip.com
 www.bellamyjc.net
 www.whatismyip.com
 www.whatismyipaddress.com
 whatismyipaddress.net
 !! Attention !!
 Pour bien vous rendre compte que la balance de charge est effective, il faut faire le test 
 sur plusieurs sites. En effet, étant donné qu'une route est conservée en cache un certain
 temps, le même chemin sera employé pour un même site. La visite d'un seul site n'est donc 
 pas du tout significative du fonctionnement de la balance de charge.
 Mais si vous avez balancé le traffic en fonction du protocole, le plus simple est peut-être
 d'utiliser le programme traceroute (ou tracert sous windows)
 Vous verrez ainsi par lequel des deux fournisseurs d'accès vous passez. Si vous passez
 toujours par le même, c'est qu'il doit y avoir un problème quelque part. Repassez par
 la case départ, ou contactez-moi.

8- Gestion d'une coupure d'accès (à venir)

 Bla bla

Dernière mise à jour le 07/06/04.
Envoyez vos commentaires à eric@lalitte.com

MBA Program