Greboca  

LinuxFr.org : les journaux  -  Routage avancé avec marquage de paquet et rp_filter

 -  Septembre 2018 - 

Sommaire

Aujourd'hui, c'est routage. Je pars du principe que vous savez ajouter une route IP, utiliser un minimum ip rule, et une bonne connaissance de iptables.

Ce journal est dupliqué (en anglais) sur ServerFault.

Problème

J'ai une Freebox en mode bridge avec liaison ADSL, une Livebox en mode DMZ avec liaison fibre optique.
Je veux faire passer la majorité du trafic via la Freebox, et du trafic particulier via la Livebox.
C'est comme ça, et si c'était l'inverse, ce serait pareil.

Je vais parler, pour faire simple, du trafic qui transite par le routeur sous Debian GNU/Linux, et pas du trafic qui est généré par ce routeur.

Mon adresse ADSL est 82.236.xxx.xxx et fibre 90.76.xxx.xxx.

Ce qui devrait marcher

On part du principe que la table mangle est vierge.

> ip route show table livebox
default via 192.168.1.1 dev eth_livebox src 192.168.1.253 
82.236.xxx.0/24 dev eth_adsl scope link src 82.236.xxx.xxx 
192.168.0.0/24 dev bridge_local scope link src 192.168.0.253 
192.168.1.0/24 dev eth_livebox scope link src 192.168.1.253 

iptables -t mangle -I PREROUTING --destination 23.23.114.123 -j MARK --set-mark 1
ip rule add from all fwmark 0x1 lookup livebox

Et ça, ça ne marche pas. C'est-à-dire que quand je fais

curl http://api.ipify.org/ --resolve api.ipify.org:80:23.23.114.123

depuis un client sur le réseau local du routeur, ça ne renvoie rien.

Ce qui marche

La table livebox ne change pas.
Par contre, après vidage de la table mangle, on fait ceci :

iptables -t mangle -I PREROUTING --source 23.23.114.123 -j TOS --set-tos 0x10
iptables -t mangle -I PREROUTING --destination 23.23.114.123 -j TOS --set-tos 0x10
ip rule add from all tos 0x10 lookup livebox

Et là :

> curl http://api.ipify.org/ --resolve api.ipify.org:80:23.23.114.123
90.76.xxx.xxx

Pourquoi ?

Entre les deux tentatives, j'ai changé deux choses :
1. J'ai utilisé l'entête TOS du paquet IP au lieu de la marque de pare-feu gérée en interne par le noyau et ses modules.
2. J'ai marqué les paquets qui reviennent.

J'ai menti (par omission) : rp_filter

J'ai oublié de dire que sur toutes mes interfaces, le paramètre rp_filter est à 1.
D'après la documentation du noyau, la valeur de 1 correspond à une vérification stricte du chemin (de routage) inverse selon la RFC 3704.
Pour faire simple, lorsqu'un paquet arrive par une interface, le noyau inverse les champs source et destination des adresses IP et tente de choisir un chemin de routage. Si le chemin choisi sort par l'interface dont vient le paquet, c'est bon, ça passe. Sinon, le paquet est ignoré.

Donc, d'après ma section Ce qui devrait marcher, vu que le paquet qui rentre n'est pas marqué avec la valeur 1, la vérification de routage inverse échoue. En effet, le paquet arrive par l'interface eth_livebox mais sans marque, c'est la table main qui est consulté, et dans cette table, le paquet sort par l'interface eth_adsl. C'est un échec. Et c'est donc la raison du changement nº2.

Pourquoi TOS et pas MARK ?

Ah. Oui, évidemment, j'ai essayé d'utiliser -j MARK sur les paquets qui reviennent. Et ça ne marche pas. À force de chercher, je suis tombé sur ce vieux message :

OK, looking at fib_validate_source(), it looks like how rp_filter
works is just that the kernel takes the packet, reverses src & dst
addrs and interfaces, and tries to do a routing lookup. It totally
ignores marking when building the routing key, but weirdly enough,
it does check the TOS.

Ah. Donc je me documente un peu, et comme je suis en recherche de solution, je fais du vite fait mal fait. Et ça marche. C'est donc la raison du changement nº1.

Peut-on faire mieux ?

Je vous laisse regarder par vous-même le code de fib_validate_source(). Personnellement, c'est trop pour moi :)

Mais pour moi, le résultat est incohérent. Je sais bien que TOS fait partie de l'en-tête IP, et que les marques sont des attributs spécifiques à l'hôte. Sauf que voilà, ip rule permet justement de faire une route soit sur la valeur de l'en-tête TOS, soit sur la valeur d'une marque du pare-feu avec fwmark.

Je suis un peu partagé sur la suite, et voici les solutions, non exclusives d'ailleurs.

Laisser tomber rp_filter sur les interfaces publiques

Le but de rp_filter, c'est d'éviter les DDoS, mais aussi d'éviter de laisser sortir des paquets de clients un peu malicieux sur le réseau public. C'est un peu comme SPF, ça protège les autres.
Sur mes interfaces publiques, j'ai déjà une règle de routage de type defaut via IP, donc de toutes façons, rp_filter va dire « ah ouais ok, c'est bon, je vais pouvoir lui répondre ». Et effectivement, si un paquet est arrivé jusque là, bon, c'est que mes fournisseurs d'accès l'ont laissé passer, et surtout ont réussi à le router.

Donc je pourrais laisser tomber et mettre rp_filter à 0 sur ces interfaces (attention, c'est la valeur maximale entre net.ipv4.conf.eth_livebox.rp_filter et net.ipv4.conf.all.rp_filter qui est appliquée).

Rapporter ce « bogue » aux développeurs du noyau

Pour moi, c'est vraiment incohérent, et surtout mal documenté. D'un côté ip rule permet de faire des règles qui marchent pour les paquets qui sortent, mais pas pour ceux qui rentrent : anomalie de fonctionnement.

Seulement voilà, je n'ai pas le temps d'acquérir les compétences pour lire le code, le comprendre, et tenter de le corriger. Sans compter qu'il y a peut-être une bonne raison pour que ça soit fait comme ça, comme le fait que les informations du pare-feu ne sont pas disponibles lors de l'appel à fib_validate_source.

Mais si quelqu'un ici me dit qu'on peut le rapporter à quelqu'un qui va m'écouter, et m'expliquer, voire corriger et améliorer, je veux bien prendre la peine de le faire.

Commentaires : voir le flux atom ouvrir dans le navigateur

par Glandos

LinuxFr.org : les journaux

LinuxFr.org : Journaux

Regata OS 24 “Arctic Fox” avec KDE Plasma 6 et d'autres améliorations

 -  27 mars - 

Regata OS 24 “Arctic Fox” avec KDE Plasma 6 et d'autres améliorationsLa version 24 de Regata OS, baptisée "Arctic Fox", est une distribution basée (...)


Redis Open Source bronsonisé

 -  22 mars - 

Bonjour Nal.Désolé pour ce titre un peu putaclick. Personne n'est décédé cette fois ci.Juste Redis qui change de licence, passant de BSD3 a une (...)


PullRequest d'une application en Rust

 -  16 mars - 

Sommaire Le commencement Description du pool de stockage de BackupPC Le format des fichiers compressés Le format des fichiers d'attributs Le (...)


Jouons un peu avec linuxfr et CSS3

 -  16 mars - 

De temps en temps, j'ai besoin de me détendre, et je joue un peu avec les tech du web, entre deux déploiements.J'aime bien HTML5 et CSS, (...)


Traduction : Payer ne permet pas d'échapper aux monopoles

 -  6 mars - 

Sommaire Contexte Traduction ContexteAyant récemment découvert dans la section liens de LinuxFr le plus récent blog de C. Doctorow, le caractère (...)