Forcer une application à utiliser une interface réseau donnée sur GNU/Linux (ou comment utiliser deux connexions Internet en même temps)
J'habite dans un endroit reculé que n'a pas encore atteint la civilisation des Lolcats. Comprenez par là que dans mon coin, les connexions Internet culminent à un faramineux 2Mbps quand tout fonctionne bien et qu'on n'est pas trop loin de son DSLAM. Pour ceux qui ne visualisent pas bien, cela donne en moyenne et selon les opérateurs dans les 250 kio/s en download et de 10 à 25 kio/s en upload. Oui, je sais, c'est ridicule dans la France du XXIe siècle.
En attendant l'hypothétique jour où cela changera, cette situation peut se révéler franchement gênante dès lors que vous faites autre chose que mettre à jour votre statut sur un réseau social ou lire vos emails. À propos d'emails, je vous laisse imaginer les difficultés pour envoyer le moindre message pourvu d'une pièce jointe de 100 kio, ça peut être assez folklorique. Si en plus vous êtes en train de télécharger le film de vacances de votre grand-mère qu'elle a gracieusement mis à votre disposition sur le FTP familial, c'est la cata ! Vous n'avez plus comme solution que de mettre le téléchargement en pause le temps de vaquer à votre occupation, qu'elle soit d'envoyer un email ou simplement afficher un site en moins de 20s, parce que voir votre navigateur mouliner aussi longtemps pour simplement afficher duckduckgo.com, c'est über-frustrant.
Fort heureusement, j'ai la chance d'avoir pour voisine une dame adorable en plus d'être pourvue d'une connexion Internet et de faire de délicieuses pâtisseries. Cette gente dame m'a fort courtoisement autorisé à utiliser son Wifi à discrétion, elle même n'utilisant que très peu sa connexion Internet. Je me retrouve donc avec deux connexions à Internet : la mienne chez OVH que j'utilise en ethernet depuis mon PC principal et la sienne chez Orange, que je vais utiliser en Wifi toujours depuis mon PC principal. C'est pratique en cas de besoin, c'est à dire si ma connexion venait à fail lamentablement, mais pas que : et si j'utilisais sa connexion pour télécharger ledit film de vacances de mon aïeule afin de pouvoir utiliser la mienne tranquillement pendant ce temps là ? En voilà une idée qu'elle est bonne ! Voyons donc par quel miracle du dieu Routage ceci peut être réalisé :
Pré-requis
— afin d'utiliser certaines des commandes qui suivent, vous devez disposer du paquet net-tools, que je vous laisse installer selon votre distribution (il l'est sûrement déjà, ceci dit)
— ma solution utilise iptables. Vous devez donc disposer d'iptables dans votre distribution. À ma connaissance, c'est le cas.
Mise en œuvre
Il y a plusieurs solutions pour arriver au résultat voulu, mais j'ai retenu celle qui consiste à créer un utilisateur qui servira à lancer les applications à router vers le Wifi de ma voisine. J'aurais pu aussi me baser sur le PID du processus de l'application, mais les PID sont changeants. J'aurais pu, sinon, utiliser un filtrage basé sur le port de connexion mais je préfère avoir la liberté de lancer deux fois l'application simultanément mais qu'une seule des deux instances soit routée.
Pour commencer, on crée donc cet utilisateur spécial, sans shell ni répertoire personnel :
# adduser --shell /bin/false --no-create-home rtuser
Ensuite, il faut créer une table de routage qui servira à recevoir la règle de routage des paquets générés par notre rtuser nouvellement créé :
# echo 200 wlan-route >> /etc/iproute2/rt_tables
Ceci fait, on crée la règle qui routera les paquets. L'IP passerelle de la Livebox est 192.168.1.1 et l'interface qui me sert à m'y connecter est wlan0 :
# ip route add default via 192.168.1.1 dev wlan0 table wlan-route
Maintenant, on crée une règle permettant de router les paquets marqués d'un 1 vers notre nouvelle table de routage :
# ip rule add fwmark 0x1 table wlan-route
Enfin, il faut créer les règles de routage dans iptables :
# iptables -t mangle -A OUTPUT -o eth0 -p TCP -m owner --uid-owner rtuser -j MARK --set-mark 0x1 # iptables -t nat -A POSTROUTING -o wlan0 -p TCP -j SNAT --to 192.168.1.13
— La deuxième règle permet de router correctement les paquets qui reviennent vers la machine, sinon les réponses aux paquets envoyés via la connexion de ma voisine (wlan0) arriveraient sur l'autre interface (eth0) qui ne saurait donc pas quoi en faire… 192.168.1.13 est l'adresse IP locale avec laquelle je suis connecté à la Livebox. Concrètement, donc, tous les paquets provenant d'applications lancées par rtuser se verront marqués d'un 1. Ensuite, les règles feront que tous les paquets marqués d'un 1 seront envoyés via wlan0 (la Livebox de ma voisine) au lieu d'eth0 (mon routeur OVH). On peut vérifier que tout est bien en place :
# ip route show table wlan-route default via 192.168.1.1 dev wlan0 # ip rule show 0: from all lookup local 32765: from all fwmark 0x1 lookup wlan-route 32766: from all lookup main 32767: from all lookup default # iptables -L -t mangle […] Chain OUTPUT (policy ACCEPT) target prot opt source destination MARK tcp -- anywhere anywhere owner UID match fzuser MARK set 0x1 […] # iptables -L -t nat […] Chain POSTROUTING (policy ACCEPT) target prot opt source destination SNAT tcp -- anywhere anywhere to:192.168.1.13
Maintenant, il va falloir désactiver la protection du kernel contre l'IP spoofing, sinon ça ne fonctionnera pas, malheureusement :
# for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $f; done # echo 1 > /proc/sys/net/ipv4/route/flush
Vérifions que rtuser passe effectivement par la connexion internet de ma voisine :
$ curl ip.appspot.com 109.190.x.x $ sudo -u rtuser curl ip.appspot.com 86.219.x.x
L'IP publique de rtuser est donc bien celle de ma voisine. Je peux maintenant lancer FileZilla en tant que rtuser afin d'utiliser cette seconde connexion pour télécharger le film de mamie en laissant la mienne libre pour le reste :
$ sudo -u rtuser filezilla
Il est fort possible que rtuser ne soit pas autorisé à lancer d'applications graphiques. Pour y remédier, il suffit de lancer un petit
$ xhost +local:rtuser
et voilà !
Pour aller plus loin
— elle ne résiste pas à une perte de connexion Wifi : dans ce cas, la règle dans la route wlan-route disparaît et la connexion bascule sur eth0, la connexion par défaut. Il faut donc recréer la règle après s'être reconnecté.
— elle ne persiste pas après un reboot : la route disparaît et les règles iptables sont effacées.
#!/bin/bash #~ Configuration ~# # Table de routage vers laquelle le traffic sera redirigé RT_TABLE="wlan-route" # L'utilisateur qui va lancer les applications redirigées RT_USER="rtuser" # Nom de l'interface sur laquelle le trafic sera redirigé IFACE_D="wlan0" # Nom de l'interface depuis laquelle le trafic sera redirigé IFACE_O="eth0" # Adresse IP LAN sur l'interface visée IP_LOCAL=`ifconfig $IFACE_D | grep 'inet adr:' | cut -d: -f2 | cut -d" " -f1` # Adresse IP de la passerelle sur l'interface visée IP_GW="192.168.1.1" #~ Rien à modifier ci-dessous ~# echo 200 $RT_TABLE >> /etc/iproute2/rt_tables ip rule add fwmark 0x1 table $RT_TABLE ip route add default via $IP_GW dev $IFACE_D table $RT_TABLE iptables -t mangle -A OUTPUT -o $IFACE_O -p TCP -m owner --uid-owner $RT_USER -j MARK --set-mark 0x1 iptables -t nat -A POSTROUTING -o $IFACE_D -p TCP -j SNAT --to $IP_LOCAL for f in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $f; done echo 1 > /proc/sys/net/ipv4/route/flush
Photo zigazou76