Ce qui suit suppose comme acquis tout ce qui est dit dans les chapitres relatifs au routage :
Tous les utilisateurs de GNU/Linux connaissent les commandes route
et ifconfig
. Bien qu'elles soient toujours efficaces, les évolutions des fonctions de routage des noyaux 2.4.x et supérieurs ont fait qu'elles ne rendent plus compte que d'une partie des possibilités.
Pour exploiter au mieux les possibilités de routage des noyaux actuels, il faut installer le paquetage iproute
(iproute2 dans d'autres distributions, comme la Mandrake).
Iproute2, allié à Netfilter, donne un couple capable de faire de grandes choses. Comme il faut bien commencer par un bout , voyons d'abord en quoi iproute2 peut nous aider.
Nous savons que la commande ifconfig
nous montre les interfaces réseau en service sur notre machine :
betelgeuse:~# ifconfig eth0 Link encap:Ethernet HWaddr 00:20:18:2D:D2:91 inet addr:192.168.100.30 Bcast:192.168.100.255 Mask:255.255.255.0 inet6 addr: fe80::220:18ff:fe2d:d291/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:19370201 errors:0 dropped:0 overruns:0 frame:0 TX packets:3279270 errors:0 dropped:0 overruns:0 carrier:0 collisions:150124 txqueuelen:1000 RX bytes:3979103861 (3.7 GiB) TX bytes:376345956 (358.9 MiB) Interrupt:11 Base address:0x2000 eth1 Link encap:Ethernet HWaddr 00:90:27:71:43:C7 inet addr:192.168.0.250 Bcast:192.168.0.255 Mask:255.255.255.0 inet6 addr: fe80::290:27ff:fe71:43c7/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:3129241 errors:0 dropped:0 overruns:0 frame:0 TX packets:3344387 errors:0 dropped:0 overruns:0 carrier:21 collisions:478776 txqueuelen:1000 RX bytes:317538639 (302.8 MiB) TX bytes:2507642937 (2.3 GiB) Interrupt:11 Base address:0x7000 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:28040 errors:0 dropped:0 overruns:0 frame:0 TX packets:28040 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:3395473 (3.2 MiB) TX bytes:3395473 (3.2 MiB) ppp0 Link encap:Point-to-Point Protocol inet addr:80.8.154.12 P-t-P:80.8.128.1 Mask:255.255.255.255 UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1492 Metric:1 RX packets:6405 errors:0 dropped:0 overruns:0 frame:0 TX packets:4791 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3 RX bytes:5209426 (4.9 MiB) TX bytes:662798 (647.2 KiB) tun1 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 inet addr:192.168.18.2 P-t-P:192.168.18.1 Mask:255.255.255.255 UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 RX packets:685 errors:0 dropped:0 overruns:0 frame:0 TX packets:685 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 RX bytes:54460 (53.1 KiB) TX bytes:73640 (71.9 KiB)
Très verbeux, nous avons pas mal d'informations sur les diverses interfaces. L'exemple est pris sur une passerelle qui assure la connexion à l'internet via un lien PPP, et qui présente également un lien vers un tunnel Open VPN (tun1).
Iproute dispose d'une commande : ip
suivie de plusieurs arguments. Utilisons ici ip addr
:
betelgeuse:~# ip addr list 1: lo: <LOOPBACK,UP> mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:20:18:2d:d2:91 brd ff:ff:ff:ff:ff:ff inet 192.168.100.30/24 brd 192.168.100.255 scope global eth0 inet6 fe80::220:18ff:fe2d:d291/64 scope link valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:90:27:71:43:c7 brd ff:ff:ff:ff:ff:ff inet 192.168.0.250/24 brd 192.168.0.255 scope global eth1 inet6 fe80::290:27ff:fe71:43c7/64 scope link valid_lft forever preferred_lft forever 4: sit0: <NOARP> mtu 1480 qdisc noop link/sit 0.0.0.0 brd 0.0.0.0 254: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 3 link/ppp inet 80.8.154.12 peer 80.8.128.1/32 scope global ppp0 255: tun1: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1500 qdisc pfifo_fast qlen 100 link/[65534] inet 192.168.18.2 peer 192.168.18.1/32 scope global tun1
Je vous laisse passer du temps à comparer les deux informations. Formulées de manières différentes (et pas forcément plus lisibles), ce sont, en partie, les mêmes.
Nous avons aussi à notre disposition les commandes :
ip link list
, qui affiche la liste des interfaces :
betelgeuse:~# ip link list 1: lo: <LOOPBACK,UP> mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:20:18:2d:d2:91 brd ff:ff:ff:ff:ff:ff 3: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 00:90:27:71:43:c7 brd ff:ff:ff:ff:ff:ff 4: sit0: <NOARP> mtu 1480 qdisc noop link/sit 0.0.0.0 brd 0.0.0.0 913: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 3 link/ppp 914: tun1: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1500 qdisc pfifo_fast qlen 100 link/[65534]
ip neigh list
, qui affiche la table ARP, un peu à la manière de la commande arp -a
:
betelgeuse:~# ip neigh list 2001:4f8:0:2::8 dev eth0 nud failed 192.168.0.13 dev eth1 lladdr 00:20:18:2f:d1:8c nud stale 192.168.0.12 dev eth1 lladdr 00:20:18:2f:0e:35 nud reachable 192.168.0.11 dev eth1 lladdr 00:20:18:2a:f5:ca nud reachable 192.168.0.67 dev eth1 lladdr 00:90:96:c4:d9:e0 nud stale 192.168.0.10 dev eth1 lladdr 00:05:5d:4a:f1:c8 nud reachable 192.168.0.64 dev eth1 lladdr 00:40:05:de:68:c3 nud stale
Voyons maintenant la commande route
:
betelgeuse:~# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 192.168.18.1 0.0.0.0 255.255.255.255 UH 0 0 0 tun1 80.8.128.1 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0 192.168.100.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1 172.16.0.0 192.168.18.1 255.255.0.0 UG 0 0 0 tun1 0.0.0.0 80.8.128.1 0.0.0.0 UG 0 0 0 ppp0
La commande ip
, suivie de l'argument route
, nous donne :
betelgeuse:~# ip route list 192.168.18.1 dev tun1 proto kernel scope link src 192.168.18.2 80.8.128.1 dev ppp0 proto kernel scope link src 80.8.154.12 192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.30 192.168.0.0/24 dev eth1 proto kernel scope link src 192.168.0.250 172.16.0.0/16 via 192.168.25.1 dev tun1 default via 80.8.128.1 dev ppp0
Moins lisible, assurément. Mais plus riche en informations. Voyons ça de plus près.
Avec route
, nous pensions qu'il n'y avait qu'une table de routage. En réalité, il y en a plusieurs. Dans la terminologie iproute2, les tables sont exploitées en fonction de règles (rules
en anglais). Nous pouvons avoir un aperçu d'un routage standard de la façon suivante :
betelgeuse:/etc/iproute2# ip rule list 0: from all lookup local 32766: from all lookup main 32767: from all lookup default
Tout ceci voudrait dire qu'il y a au moins trois tables de routage, local
, main
et default
, qui seraient auscultées pour router tous les paquets entrant dans le routeur, quelle que soit leur provenance (from all
) et dans l'ordre indiqué par l'index numérique placé juste avant chaque règle ?
Absolument, c'est bien comme ça que ça se passe.
Et donc, il serait possible, avec la commande ip, de voir ce qu'il y a dans chacune de ces tables ?
Oui. Il suffit d'en préciser le nom :
betelgeuse:/etc/iproute2# ip route list table main 192.168.18.1 dev tun1 proto kernel scope link src 192.168.18.2 80.8.128.1 dev ppp0 proto kernel scope link src 80.8.154.12 192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.30 192.168.0.0/24 dev eth1 proto kernel scope link src 192.168.0.250 172.16.0.0/16 via 192.168.25.1 dev tun1 default via 80.8.128.1 dev ppp0
C'est la même que tout à l'heure !
Oui, c'est la même. Preuve que l'antique commande route
ne nous dit pas tout, puisque avant main
, il y a local
, et que cette table n'est pas vide du tout :
betelgeuse:/etc/iproute2# ip route list table local broadcast 192.168.100.0 dev eth0 proto kernel scope link src 192.168.100.30 broadcast 192.168.0.255 dev eth1 proto kernel scope link src 192.168.0.250 broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 local 80.8.154.12 dev ppp0 proto kernel scope host src 80.8.154.12 local 192.168.0.250 dev eth1 proto kernel scope host src 192.168.0.250 local 192.168.18.2 dev tun1 proto kernel scope host src 192.168.18.2 broadcast 192.168.100.255 dev eth0 proto kernel scope link src 192.168.100.30 broadcast 192.168.0.0 dev eth1 proto kernel scope link src 192.168.0.250 broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 local 192.168.100.30 dev eth0 proto kernel scope host src 192.168.100.30 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
Mais comme vous le voyez, cette table ne concerne que le routage local et les « broadcasts », rien de bien palpitant. Quant à la table default
, elle est vide par défaut.
Mais alors, il y aurait la possibilité de créer des tables qui ne seraient utilisées que dans certaines conditions ?
C'est une partie de l'intérêt et de la puissance du modèle Iproute2. Parce qu'en plus de ça, Iproute2 sait faire plein d'autres choses. Pour vous en convaincre, le mieux est de lire la documentation officielle : Advanced Routing HOWTO, dont il existe une version en français. Il n'est bien entendu pas question ici de voir tout ce qu'il est possible de faire, l'objectif est juste de pouvoir réaliser un routage sélectif en fonction d'un numéro de port TCP.
Dans ce qui suit, la machine qui va servir de passerelle miroir s'appelle « saturne ».
La liste des tables qui existent sur votre machine se trouve dans le fichier /etc/iproute2/rt_tables
. Vous ne pourrez pas créer de règles (rules) associées à une table qui n'est pas référencée dans ce fichier. Comme nous aurons besoin d'une table de routage spécifique pour le protocole POP3, nous allons créer une entrée supplémentaire dans ce fichier qui, après modification, aura l'allure suivante :
saturne:~# cat /etc/iproute2/rt_tables # # reserved values # 200 pop3 255 local 254 main 253 default 0 unspec # # local # 1 inr.ruhep
Cette manipulation, en elle même n'apporte rien aux règles en vigueur :
saturne:~# ip rule list 0: from all lookup local 32766: from all lookup main 32767: from all lookup default
Si nous voulons ajouter une règle, il faudra le dire explicitement de la façon suivante (prenez-le comme une recette pour le moment) :
saturne:~# ip rule add fwmark 0x6e table pop3
Ceci a pour effet d'ajouter une règle, que nous comprendrons mieux par la suite. Disons pour le moment que, lorsqu'un paquet contient la marque 0x6e (valeur hexadécimale), il devra être routé en fonction des informations contenues dans la table de routage pop3.
saturne:~# ip rule list
0: from all lookup local
32765: from all fwmark 0x6e lookup pop3
32766: from all lookup main
32767: from all lookup default
Nous voyons effectivement apparaitre une ligne supplémentaire dans la liste des règles.
Mais la table de routage pop3 est vide. Il faut la peupler un petit peu. En réalité, qu'avons-nous besoin de faire, en fonction de la topologie donnée ? Il nous suffit de dire que pour ces paquets, la route par défaut n'est pas 192.168.0.1, mais 192.168.0.3, adresse ip du serveur mandataire. Faisons le :
ip route add default via 192.168.0.3 dev eth0 table pop3
Bien. Pour vérifier :
saturne:~# ip route list table pop3
default via 192.168.0.3 dev eth0
Et si nous regardons la table de routage principale :
saturne:~# ip route list table main
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.2
default via 192.168.0.1 dev eth0
Autrement dit, si tout se passe comme prévu, tous les paquets sortant du poste de travail (qui est configuré pour voir 192.168.0.2 comme passerelle par défaut) seront aiguillés vers 192.168.0.1 (la vraie passerelle vers l'internet), sauf les paquets marqués “6e”, qui, eux, seront aiguillés vers 192.168.0.3 (le futur proxy transparent POP3).
Pour pouvoir vérifier si tout ça fonctionne, il faut commencer par pouvoir marquer ces paquets avec le label 6e
, ce que nous n'avons pas encore fait.
Pour réaliser cette opération, nous aurons recours à Netfilter, avec IPtables.