Présentation d'une méthode qui permet à tout geek d'accomplir un de ses plus beaux rêves : la connexion simultanée à deux fournisseurs d'accès Internet.

Attention, accrochez-vous; vous allez manger de l'iptables et du routage ad nauseum.

Cette méthode :

  • Ne permet pas directement de doubler la bande passante.
  • Permet de rediriger certains services ou certaines applications ou encore certains sites vers tel ou tel réseau. Cela habilement fait, permet effectivement d'optimiser ses flux.
  • Permet de s'affranchir du bridage DNS de certains proxys type université.
  • Ne marche que sous Linux/GNU
  • Est une excellente alternative à la virtualisation type VMware plutôt gourmande en ressources, bien que permettant au final de faire la même chose en retirant une interface type carte wifi USB du système pour se l'approprier directement.
  • N'est pas un encouragement à chourer la connexion du voisin (quoique).

Sommaire

Configuration du réseau

Il faudra configurer les réseaux manuellement, c'est plus pratique pour savoir ce qu'on fait.
Il faudra aussi s'arranger pour que les adressages des deux réseaux soient différents (réseau en 192.168.0.x et 192.168.1.x). Allez voir les configurations de vos box !

La configuration du wifi se fait via wpa_supplicant si le réseau est en WPA, ou simplement iwconfig si le réseau est en WEP. Les documentations sur le net sont suffisamment nombreuses. Je décrirai brièvement les connexions WEP et WPA en fin de tuto.

On distinguera deux interfaces réseau. Chez moi ça sera:

  • wlan0 => réseau par défaut => interface1
  • wlan1 => réseau secondaire => interface2 (interface qui fera passer le trafic dérouté. ex: téléphone (ordiphone) en mode modem).

Vous pouvez activer le DHCP sur l'interface par défaut (dhclient wlan0) mais il faudra mémoriser l'adressage réseau obtenu (via ifconfig wlan0 ou ip addr). Pour l'interface secondaire, il faudra passer par ifconfig histoire d'éviter le bazar au niveau des passerelles par défaut.

Chez moi et durant la suite du tuto on aura:

interface1=wlan0
ip1=192.168.1.10
passerelle1=192.168.1.254

interface2=wlan1
ip2=192.168.0.10
passerelle2=192.168.0.1

Ainsi pour la configuration de l'adressage de l'interface2:

ifconfig wlan1 inet 192.168.0.10 netmask 255.255.255.0

(Nous n'avons besoin ici que d'une adresse IP, du masque de sous-réseau, et de l'interface concernée évidemment)

Démonstration:

Si l'envie vous prend de vouloir manipuler les requêtes DNS, il faudra choisir le serveur DNS du réseau qui devra fournir le service ou indiquer des serveurs DNS "neutres" comme ceux de Google:

echo "nameserver 8.8.8.8" > /etc/resolv.conf
echo "nameserver 8.8.4.4" >> /etc/resolv.conf

Démonstration:

Configuration d'iptables

Iptables est LE pare-feu des plateformes de Linux/GNU. Il est TRÈS complexe mais aussi TRÈS complet. À côté de lui le pare-feu de Windows fait figure de gros blob infâme pour dingues du clic-bouton chronophage.

Bref, regardons le schéma du parcourt des paquets à travers iptables :

Source : Lien.

En haut on a ce qui arrive sur la machine et en bas ce qui en sort.
Dans notre cas, notre machine génère les requêtes; la partie supérieure ne nous intéresse donc pas. Idem pour la branche de droite qui présente le trajet des paquets transitant par notre machine mais ne la concernant pas.

Ici, on cherche à corriger l'adressage des paquets avant la décision de routage. Deux tables seront donc utilisées: mangle avec la chaine OUTPUT, et nat avec la chaine POSTROUTING.

Destruction des règles préexistantes:

iptables --flush
iptables --table nat --flush
iptables --table mangle --flush
iptables --delete-chain
iptables --table nat --delete-chain

Règles de capture:

iptables -t mangle -A OUTPUT -p udp --dport 53 -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -m owner --uid-owner root -j MARK --set-mark 1

La première ligne va repérer le trafic UDP sur le port 53 (c.-à-d. les requêtes DNS).
La deuxième ligne va repérer le trafic généré par toute application lancée par l'utilisateur root. Ce n'est qu'un exemple, vous pouvez créer un utilisateur par application et par règle :

adduser --shell /bin/false --no-create-home myappuser
sudo -u myappuser myapp

-j MARK --set-mark 1 marque le paquet pour qu'il soit reconnu par la suite. Ce marquage est interne à la machine et disparait quand le paquet en sort.

Règles d'envoi:

iptables -t nat -A POSTROUTING -o wlan0 -j SNAT --to-source 192.168.1.10
iptables -t nat -A POSTROUTING -o wlan1 -j SNAT --to-source 192.168.0.10

SNAT permet de remplacer les adresses IP source de chaque paquet sortant par une interface, par l'adresse IP source de la machine sur le réseau concerné.

Un paquet arrivant sur cette table POSTROUTING, aura été marqué ou non par les règles de capture; puis aura été éventuellement redirigé vers la bonne interface par les tables de routage que l'on verra juste après.

Il faut bien comprendre que ces règles, permettent d'éviter à un paquet initialement destiné à circuler sur le réseau en 192.168.1.x, marqué et routé pour et sur le réseau en 192.168.0.x, de garder comme source 192.168.1.10 (pour reprendre ma configuration);
En effet, le réseau en 192.168.0.x ne sait pas où est la machine 192.168.1.10.
Au mieux le paquet suivra sa destination initiale, au pire il sera détruit.

À tout moment, on peut suivre les redirections en temps réel sur les deux tables via:

iptables -t mangle -nvL
iptables -t nat -nvL

(On notera que le trafic DNS atteint quelques dizaines de Ko pour quelques heures d'utilisation...)

Démonstration:

Les tables de routage

Pour le moment nous n'avons qu'une table de routage principale, attribuée au réseau par défaut wlan0, via DHCP ou configuration manuelle complète.

Pour visualiser sa table principale (main):

root@bt:~# ip route show table main
default via 192.168.1.254 dev wlan0
192.168.0.0/24 dev wlan1  proto kernel  scope link  src 192.168.0.10
192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.10

default via 192.168.1.254 dev wlan0 est la route par défaut, elle est unique, tant mieux...

Il va falloir créer une nouvelle table qui sera utilisée uniquement pour les paquets marqués par iptables.

Nous allons dupliquer tout cela, SAUF la route par défaut vers une table nommée 1 (même chiffre utilisé pour le marquage des paquets pour éviter de se perdre) via:

ip route flush table 1
ip route show table main | grep -Ev ^default | while read ROUTE ; do ip route add table 1 $ROUTE; done

À ce moment-là, on aura dans table 1:

root@bt:~# ip route show table 1
192.168.0.0/24 dev wlan1  proto kernel  scope link  src 192.168.0.10
192.168.1.0/24 dev wlan0  proto kernel  scope link  src 192.168.1.10

Ajoutons maintenant la route par défaut liée à cette interface:

ip route add default via 192.168.0.1 dev wlan1 table 1

Démonstration:

Reverse path filtering

Avant d'activer la table que l'on vient de créer, il faut modifier le comportement par défaut de ce module.

En effet, une session est composée d'une requête envoyée vers le serveur qui va nous renvoyer un paquet et ainsi de suite. Encore faut-il que tous les paquets d'une même session passent par la même interface. Par défaut, la réponse tentera de passer par la route par défaut, or impossible de communiquer vers l'extérieur avec 2 sources; Les paquets seront détruits.

Situation probablement mieux expliquée ici.

Voir le schéma :

Deux commandes, une pour chaque interface concernée:

sysctl -w net.ipv4.conf.wlan0.rp_filter=2
sysctl -w net.ipv4.conf.wlan1.rp_filter=2

Démonstration:

Activation des tables de routage

ip rule add fwmark 1 table 1
ip route flush cache

Après avoir ajouté la table qui nous intéresse (table 1), et son critère d'activation (fwmark 1), on détruit les routes présentes dans le cache pour activer immédiatement la configuration.

Pour contrôler l'ajout de la table:

root@bt:~# ip rule show
0:      from all lookup local
32765:  from all fwmark 0x1 lookup 1
32766:  from all lookup main
32767:  from all lookup default

Démonstration:

Exemples de résultats:

On voit clairement que eMule tourne sur wlan0, et Multiup Manager (lancé sur un utilisateur spécifique avec kdesudo) sur wlan1. Ce qui revient effectivement à un doublement de la bande passante montante :)

La surveillance du trafic via Wireshark, montre que comme prévu, wlan1 ne sert qu'à faire transiter les requêtes DNS.

Conclusion et sources

Voilà j'espère avoir apporté une réponse à ceux qui se demandaient comment faire et ne trouvaient rien sur le net. J'ai personnellement fait beaucoup de recherches pour avoir un truc fonctionnel...

Une configuration tout à fait similaire peut être faite sur une machine qui servirait de routeur ou de pré-routeur. C'est à dire sur laquelle plusieurs autres machines viendraient se connecter via 1 ou plusieurs réseaux indépendants.

La règle iptables à ajouter serait du type : mangle PREROUTING. La configuration est décrite ici.

Une autre technique peut être plus simple mais pas adaptée à la même utilisation, est le load-balancing.
Le net recense bien plus de documents à ce sujet. Le switch entre deux réseaux se fait de manière transparente en fonction de la charge de telle ou telle branche. Mais il n'est pas en temps réel car il faut attendre que les routes dans le cache arrivent à la fin de leurs baux. Le load-balancing est plus adapté à un service devant être opérationnel en continu et qui se sert d'une 2ième branche réseau quand la branche principale tombe en panne.

Voir :

L'utilisation du pare-feu Shorewall peut probablement apporter une configuration similaire voire plus pointue (voir http://www.shorewall.net/MultiISP.html.) Pour ma part, je n'aurais pas le courage de lire ce topic...

Je ne suis pas un expert de tous les sujets et les outils abordés ici, certaines choses peuvent être mal comprises et mal expliquées, je prends les corrections...

Voilà un script de configuration à adapter au niveau des quelques premières lignes de configuration et en ayant configuré au préalable la connexion internet sur l'interface principale (interface1) comme d'habitude.

interface1=wlan1
ip1=192.168.0.XX
passerelle1=192.168.0.1

interface2=wlan0
ip2=192.168.1.XX
passerelle2=192.168.1.254

echo "Configuration de l'interface wifi..."
#ifconfig $interface2 up
#iwconfig $interface2 essid BOX_EN_WEP channel 6 rate auto key XX:XX:XX:XX ap XX:XX:XX:XX:XX:XX txpower auto
#ifconfig $interface2 inet $ip2 netmask 255.255.255.0

ifconfig $interface2 up

killall wpa_supplicant

rm /etc/wpa_supplicant.conf
rm /etc/resolv.conf
rm /var/run/wpa_supplicant/$interface2

echo ctrl_interface=/var/run/wpa_supplicant >> /etc/wpa_supplicant.conf
echo >> /etc/wpa_supplicant.conf
echo ap_scan=1 >> /etc/wpa_supplicant.conf
echo >> /etc/wpa_supplicant.conf
echo network={ >> /etc/wpa_supplicant.conf
echo ssid=\"BOX_EN_WPA\" >> /etc/wpa_supplicant.conf
echo scan_ssid=1 >> /etc/wpa_supplicant.conf
echo proto=WPA >> /etc/wpa_supplicant.conf
echo key_mgmt=WPA-PSK >> /etc/wpa_supplicant.conf
echo pairwise=TKIP >> /etc/wpa_supplicant.conf
echo auth_alg=OPEN >> /etc/wpa_supplicant.conf
echo group=CCMP TKIP >> /etc/wpa_supplicant.conf
echo psk=CLE_WPA_A_32_CARACTERES_OU_64_HEXADECIMAUX(différencier pmk et psk..) >> /etc/wpa_supplicant.conf
echo } >> /etc/wpa_supplicant.conf

wpa_supplicant -B -i $interface2 -c /etc/wpa_supplicant.conf
sleep 3
ifconfig $interface2 inet $ip2 netmask 255.255.255.0

echo
echo "RAZ des règles iptables..."
iptables --flush
iptables --table nat --flush
iptables --delete-chain
iptables --table nat --delete-chain

iptables --flush
iptables --table mangle --flush
iptables --delete-chain
iptables --table nat --delete-chain

echo
echo "Configuration iptables..."
iptables -t mangle -A OUTPUT -p udp --dport 53 -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -m owner --uid-owner loadbalancinguser -j MARK --set-mark 1

iptables -t nat -A POSTROUTING -o $interface1 -j SNAT --to-source $ip1
iptables -t nat -A POSTROUTING -o $interface2 -j SNAT --to-source $ip2

iptables -t mangle -nvL
iptables -t nat -nvL

echo
echo "Résolution DNS par google..."
echo "nameserver 8.8.8.8" > /etc/resolv.conf
echo "nameserver 8.8.4.4" >> /etc/resolv.conf

echo
echo "Routage : conception des tables..."
ip route flush table 1
ip route show table main | grep -Ev ^default | while read ROUTE ; do ip route add table 1 $ROUTE; done

ip route add default via $passerelle2 dev $interface2 table 1

ip route show table main
ip route show table 1

echo
echo "rp_filter..."
sysctl -w net.ipv4.conf.$interface1.rp_filter=2
sysctl -w net.ipv4.conf.$interface2.rp_filter=2

echo
echo "Routage : activation des tables..."
ip rule del fwmark 1 table 1
ip rule add fwmark 1 table 1
ip route flush cache

ip rule show

sleep 3
ping -i 2 $passerelle2

Références