Table des matières

Freebox et OpenVPN bonding sur Debian Squeeze

Soit 2 Freebox ADSL plafonnant joyeusement autour de 4Mb/s, et partageant le même réseau local.

Comment agréger les box pour obtenir 8Mb/s ? Avec “OpenVPN Bonding” bien sur… et quelques autres trucs.

~~READMORE~~

reseau

Le réseau local:

2 Freebox:

Je peux choisir la Freebox avec laquelle je surfe par un simple:

# route add default gw 192.168.0.253
# route del default gw 192.168.0.254

En clair:

Aprés un petit lag, les communications reprennent par l'une ou l'autre des Freebox, selon la route sélectionnée.

Maintenant, je voudrais utiliser alternativement et automatiquement, l'une ou l'autre route afin de mutualisé les débits (et accessoirement, aussi, la redondance ).

“Alternativement” mais trés rapidement: suffisament rapidement pour approcher le débit théorique maximum d'une agrégation réussie.

Pour cela il faut un serveur sur Internet, pas trop loin, par exemple une Dedibox . (la distance “IP” entre une “Freebox” et une “Dedibox” correspond a 2 ou 3 sauts).

Cette Dedibox sera la nouvelle sortie sur le Net, et donc, ma nouvelle IP publique aussi. (Accessoirement: Bye bye Hadopi)

Donc:

                     +--> OpenVPN --> Freebox A --> Internet --> OpenVPN --+
                     |                                                     |
Mon PC --> bonding --+                                                     +--> bonding --> Ma Dedibox
                     |                                                     |
                     +--> OpenVPN --> Freebox B --> Internet --> OpenVPN --+

Il faudra jouer avec les “route” et le “nat” aussi.

OpenVPN

On va d'abord mettre en place 2 connexions VPN entre un PC (le mien) et une Dedibox (la mienne).

Donc 2 “openvpn” sur mon PC, et 2 “openvpn” sur ma Dedibox.

Au final, chaque connexion “vpn” passera par une Freebox dédié.

Le but est simplement d’agréger des connexions ADSL, en conséquence, on ne va pas mettre en œuvre la notion de clefs d'authentification et de chiffrement “client/serveur” cher a OpenVPN:

:!: On peut mettre un systeme plus lourd avec easy-rsa TLS/RSA et tout le coin-coin.
Ce n'est pas le but de ce baratin.

Preambule

Donc, il y aura 2 “serveurs” OpenVPN fonctionnant de concert .

( J'ai aussi fait le test avec un seul serveur OpenVPN, et ça fonctionnait. Mais quelques warnings dans les logs m'y ont fait renoncer: “… MULTI: Learn: 192.168.0….. ” )

Pour le transport via le VPN, un petit réseau imaginaire va être mis en place:

10.4.4.64/26

Avec:

10.4.4.65 ma Dedibox
10.4.4.66 mon PC

secret

D'abord créer le secret partagé, soit un mot de passe aléatoire de 256 caractères…

# cd /etc/openvpn
# openvpn --genkey --secret bonding-secret.key

Ce qui créé un fichier ressemblant à ça:

# ls -la | grep secret
-rw-------   1 root root   636 11 oct.  19:15 bonding-secret.key

Donc, lisible et modifiable uniquement par root . Parfait.

les confs

J'ai pour habitude (surement la bonne) , de mettre les conf dans : /etc/openvpn/conf

Puis de faire un lien symbolique vers /etc/openvpn/ pour activer les confs.

Serveur

Sur ma Dedibox donc…

install

(Si pas déjà fait)

# aptitude update && aptitude install openvpn

network

Pour le support du bonding:

# aptitude update && aptitude install ifenslave

Modifier le fichier /etc/network/interfaces afin d'avoir:

auto bond0
iface bond0 inet static
    address 10.4.4.65
    netmask 255.255.255.192
    bond-slaves none
    bond-mode 0
    bond-miimon 300
    bond-use-carrier 0

allow-hotplug tap0
iface tap0 inet manual
    bond-master bond0

allow-hotplug tap1
iface tap1 inet manual
    bond-master bond0

Monter l'interface “bond0” :

# ifup bond0

L'interface monte, mais elle ne fait rien pour l'instant puisqu'aucune interface “tap” n'y est associée.

:!:

bond-miimon 300 300 ms parce que j'ai un ping autour de 150 ms lorsque je suis a fond
bond-use-carrier 0 FIXME : je ne sais plus.

conf vpn

Voila la configuration du 1er serveur OpenVPN , dans /etc/openvpn/conf/server-bonding-A.conf :

# ----------------------------

#local <IP_QUI_ECOUTE>
port 1195

proto udp

dev tap0
dev-type tap

mode p2p                                                                                                  

#auth none
secret bonding-secret.key

cipher none

# The keepalive directive causes ping-like
keepalive 10 120

txqueuelen 1000

nice 10

# Downgrade privileges after initialization (non-Windows only)
user nobody
group nogroup

# Because we downgrade privileges:
persist-tun
persist-key

comp-lzo

status /etc/openvpn/server-bonding-A-status.log

#verb 5
verb 3

mute 20

cd /etc/openvpn

# ---------
# EOF

Et l'autre fichier /etc/openvpn/conf/server-bonding-B.conf qui contient les differences suivantes:

port 1196

...

dev tap1
 
...

status /etc/openvpn/server-bonding-B-status.log

Finir d'installer par:

# ln -s /etc/openvpn/conf/server-bonding-A.conf /etc/openvpn/.
# ln -s /etc/openvpn/conf/server-bonding-B.conf /etc/openvpn/.

demarrer

Et demarrer les VPNs.

# /etc/init.d/openvpn start server-bonding-A
# /etc/init.d/openvpn start server-bonding-B

On peut aussi simplement tester en tapant:

# openvpn --config /etc/openvpn/server-bonding-A.conf

En coup d'oeil par là :

$ cat /proc/net/bonding/bond0 
Ethernet Channel Bonding Driver: v3.5.0 (November 4, 2008)

Bonding Mode: load balancing (round-robin)
MII Status: up
MII Polling Interval (ms): 300
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: tap0
MII Status: up
Link Failure Count: 0
Permanent HW addr: a6:8e:b7:34:cc:39

Slave Interface: tap1
MII Status: up
Link Failure Count: 0
Permanent HW addr: 62:d9:79:b0:af:a4

Clients

( conf sur mon PC )

On copie la clé “bonding-secret.key” de la Dedibox sur le PC, dans /etc/openvpn/ et en conservant les mêmes droits d'accès !

install

(Si pas déjà fait)

# aptitude update && aptitude install openvpn

network

Comme pour la “Dedibox”, mettre en place les outils nécessaire au “bonding”:

# aptitude update && aptitude install ifenslave

Modifier le fichier /etc/network/interfaces afin d'avoir:

auto bond0
iface bond0 inet static
    address 10.4.4.66
    netmask 255.255.255.192
    bond-slaves none
    bond-mode 0
    bond-miimon 300
    bond-use-carrier 0

allow-hotplug tap0
iface tap0 inet manual
    bond-master bond0

allow-hotplug tap1
iface tap1 inet manual
    bond-master bond0

Monter l'interface “bond0” :

# ifup bond0

conf vpn

Voila le 1er fichier de conf dans /etc/openvpn/conf/client-bonding-A.conf :

# ----------------------------

remote <IP_DE_LA_DEDIBOX> 1195

proto udp

dev tap0
dev-type tap

mode p2p                                                                                                  

#auth none
secret bonding-secret.key

cipher none

# The keepalive directive causes ping-like
keepalive 10 120

txqueuelen 1000

nice 10

nobind

# Downgrade privileges after initialization (non-Windows only)
user nobody
group nogroup

# Because we downgrade privileges:
persist-tun
persist-key

comp-lzo

status /etc/openvpn/client-bonding-A-status.log

#verb 5
verb 3

mute 20

cd /etc/openvpn

# ---------
# EOF

Pour le 2ieme fichier de conf, /etc/openvpn/conf/client-bonding-B.conf , les différences par rapport au premier sont:

remote <IP_DE_LA_DEDIBOX> 1196

... 

dev tap1

...

status /etc/openvpn/client-bonding-B-status.log
:!: Quoi? La même IP ?
Oui: On effectuera un routage différent basé sur l'IP et le numéro de port de destination.

Finir d'installer par:

# ln -s /etc/openvpn/conf/client-bonding-A.conf /etc/openvpn/.
# ln -s /etc/openvpn/conf/client-bonding-B.conf /etc/openvpn/.

demarrer

Et demarrer les VPNs.

# /etc/init.d/openvpn start client-bonding-A
# /etc/init.d/openvpn start client-bonding-B

Test simple

On doit pouvoir pinguer chaque bout du reseau.

Sur le client/PC:

# ping 10.4.4.65

Sur le serveur/Dedibox

# ping 10.4.4.66

Tous les ping doivent passer. Si ce n'est pas le cas, un “vpn” n'est pas connecté.

Sinon: vérifier le “firewall” possiblement en place.

Jeter un coup d'oeil dans /proc/net/bonding/bond0

route vers Freebox B

Hummm…. Pour l'instant, on n'a pas vraiment agréger les Freebox puisque tout passe par la Freebox A (enfin, la gateway par défaut choisit).

Créer une règle pour changer la gateway par defaut

La règle qui va être mise en place dira:

  1. pour tout les paquets marqués avec la valeur “0x0fff0001
  2. appliquer une route par defaut vers l'IP 192.168.0.254 ( qui est la Freebox B).

Dans le fichier /etc/iproute2/rt_tables ajouter un nouveau nom de table, par exemple:

200 gw-freeboxB

Dans /etc/network/if-up.d , créer un script nommé freebox-B-route, et contenant:

#!/bin/bash
#set -x

WFACE="eth0"

# --pour debug--
[ -n "$IFACE" ] || IFACE=$WFACE
[ -n "$MODE" ] || MODE="$1"

[ "$IFACE" = $WFACE ] || exit 0

IPROUTE=/sbin/ip

[ -x $IPROUTE ] || exit 0

if [ -f /etc/ferm/mark-conf ]; then
. /etc/ferm/mark-conf
fi

TABLENAME="gw-freeboxB"
MARK="0x0fff0001"
GATEWAY=192.168.0.254

case "$MODE" in
  start)
      $IPROUTE rule add fwmark $MARK table $TABLENAME
      $IPROUTE route add default via $GATEWAY dev $IFACE table $TABLENAME
      $IPROUTE route flush cache
      ;;
  stop)
      $IPROUTE route del default via $GATEWAY dev $IFACE table $TABLENAME
      $IPROUTE rule del fwmark $MARK table $TABLENAME
      $IPROUTE route flush cache
      ;;
  *)
    echo "$0 {start|stop}"
    exit 1
    ;;
esac

exit 0

Rendre executable:

# chmod a+x freebox-B-route

Ne pas oublier aussi:

# ln -s /etc/networks/ifup-d/freebox-B-route /etc/networks/if-down.d/.

… en effet: le même script sera utilisé lorsque l'interface monte (up/start) ou descend (down/stop).

Puisque l'interface eth0 est déjà en service, le scripte doit être appelé manuellement pour cette fois:

# ./freebox-B-route start

Voila: la règle est chargé et prête a être utilisée.

Appliquer la nouvelle gateway a un client VPN

J'utilise “ferm” pour rediger les règles iptables, ce qui donne:

table mangle chain OUTPUT of eth0 
  daddr <IP_DE_LA_DEDIBOX> proto udp dport 1196
  mod mark mark 0x00000000 MARK set-mark 0x0fff0001;

Ou avec la commande IpTables :

# iptables -t mangle -A OUTPUT --out-interface eth0 --destination <IP_DE_LA_DEDIBOX> --protocol udp --dport 1196 --match mark --mark 0x00000000 --jump MARK --set-mark 0x0fff0001

Ce qui signifie dans les 2 cas:

Pour les paquets sortant de l'interface “eth0” , a destination de l'IP <IP_DE_LA_DEDIBOX> avec le protocole udp a destination du port 1196 , et dont le marquage est actuellement “0” , alors marquer le paquet avec la valeur “0x0fff0001” .

Voila:

Reseau Simple

Pour l'instant, on a une configuration simple où mon PC a l'IP 10.4.4.66 et peut communiquer avec l'IP 10.4.4.65 .

Un test de débit:

$ scp 10.4.4.65:~/debian.iso .
debian.iso                          2%   14MB 864.2KB/s   12:31 ETA

YES! : 8 Mb/s , entre mon PC et ma Dedibox :-)

:!: De temps en temps, le débit retombe dans les limbes de 400 Mb/s !!!
Mais je crois avoir compris que les paquets arrivent plus fréquemment dans le désordre ce qui perturbe la pile TCP/IP.

Gateway pour un utilisateur

Le but est simplement de créer 1 utilisateur qui sera routé par defaut via l'interface “bond0”.

sur mon PC

user

Donc, d'abord créé un simple utilisateur:

# adduser zorro

Et accésoirement:

# adduser zorro audio
# adduser zorro video

Retour en tant qu'utilisateur simple , en l'occurence “thierry”.

Dans mon KDE, je créé un petit script là: ~/.kde/Autostart/xhost4zorro , et contenant:

#!/bin/sh
xhost +local:zorro
exit 0

Rendre executable:

$ chmod a+x ~/.kde/Autostart/xhost4zorro

A moins de redemarrer “KDE”, executer le script maintenant:

$ ~/.kde/Autostart/xhost4zorro

Voila: l'utilisateur “zorro” pourra jouir de mon environnement fenêtrés sous KDE.

route

Créer une nouvelle règle “netfilter/iptables” de “routage” pour changer la gateway par défaut pour cette utilisateur.

En “ferm” :

table mangle chain OUTPUT mod owner uid-owner zorro {
  daddr ( 192.168.0.0/16 10.20.0.0/16 172.16.0.0/12 ) RETURN;
  daddr ( 212.27.40.240 212.27.40.241 ) RETURN;
  mod mark mark $MARK_UNDEF MARK set-mark 0x0fff0001;
  RETURN;
}

En “iptables” :

# iptables -t mangle -A OUTPUT --match owner --uid-owner zorro --destination 192.168.0.0/16 --jump RETURN                                                                                                 
# iptables -t mangle -A OUTPUT --match owner --uid-owner zorro --destination 10.20.0.0/16 --jump RETURN                                                                                                   
# iptables -t mangle -A OUTPUT --match owner --uid-owner zorro --destination 172.16.0.0/12 --jump RETURN                                                                                                  
# iptables -t mangle -A OUTPUT --match owner --uid-owner zorro --destination 212.27.40.240 --jump RETURN
# iptables -t mangle -A OUTPUT --match owner --uid-owner zorro --destination 212.27.40.241 --jump RETURN
# iptables -t mangle -A OUTPUT --match owner --uid-owner zorro --match mark --mark 0x00000000 --jump MARK --set-mark 0x0fff0002
# iptables -t mangle -A OUTPUT --match owner --uid-owner zorro --jump RETURN
:!: ces règles peuvent être largement optimisées

En clair:

sur la Dedibox

( le serveur )

D'abord, s'assurer que:

Forward

Il faut activer le “forward” entre interface, parce qu'on va avoir les interfaces “eth0” et “bond0” qui vont devoir s’échanger des paquets IP.

Si ce n'est pas déjà le cas, pour activer le “forward” , on peut créer un fichier dans /etc/sysctl.d/ , nommé local.conf , et contenant:

# Les requetes ARP ne traversent pas
net.ipv4.conf.all.arp_ignore=1
# Activer forward
net.ipv4.ip_forward=1
# ---------------

Et puis appliquer immédiatement le forward:

# sysctl -p /etc/sysctl.d/local.conf

Ensuite, il faut sans doute activer des règles au niveau du firewall, par exemple avec ferm :

 chain FORWARD if bond0 of eth0 saddr 10.4.4.66 ACCEPT;
 chain FORWARD if eth0 of bond0 daddr 10.4.4.66 ACCEPT;
:!: En pratique, il faudra être plus rigoureux en interdisant les subnet privés (genre 172.16.0.0/24) et en appliquant un tracking des connexions

NAT

En sortie vers le WAN/Internet, il faudra “simplement” jouer avec “SNAT” ou “MASQUERADE” pour l'IP de mon PC: 10.4.4.66.

Exemple en ferm:

table nat chain POSTROUTING of eth0 saddr 10.4.4.66 SNAT to <IP_DE_LA_DEDIBOX> ;

ou

table nat chain POSTROUTING of eth0 saddr 10.4.4.66 MASQUERADE ;

test a partir de mon PC

# su - zorro
$ firefox &
:!: le ping ne semble pas routé , mais je crois que c'est intrinsèque au fonctionnement de “ping” … (à vérifier)

Un petit de test de transfert entre mon PC et le reste du Monde… enfin, les serveurs ftp de proxad :-)

$ curl -o /dev/null ftp://ftp.proxad.net/pub/Distributions_Linux/debian-cd/current/armel/iso-cd/debian-6.0.6-armel-CD-1.iso
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                                                                                                                                                                                
                               Dload  Upload   Total   Spent    Left  Speed                                                                                                                                                                                                  
3  639M    3 25.2M    0     0  1077k      0  0:10:07  0:00:23  0:09:44 1122k
...

Là, je suis clairement au dela des 8 Mb/s !

Un petit bilan

Le bonding c'est fantastique:

Mais, il subsiste quelques problèmes:

A faire:

Dans la Freebox

in the DSLAM

J'imagine qu'on pourrait intégrer les interfaces “bond” dans les DSLAM.

Dans ces conditions, on n'a pas besoin d'OpenVPN dans la Freebox ou dans les DSLAMs !

Client <---->[Freebox principale] ------- ADSL ------- DSLAM-A <----> Reseau Free <---> Reste du Monde
                |                                         |
             [Freebox secondaire 1] ----- ADSL ------- DSLAM-B
                |                                         |
             [Freebox secondaire 2] ----- ADSL ------- DSLAM-B
                |                                         |
             [ etc... ]------------------ ADSL ------- DSLAM-A 

Cela suppose que:

in the Cloud

Sinon, les DSLAM restent passif en font juste le transport jusqu'a un cloud de Dedibox ou de serveur Free.

Client <---->[Freebox principale] ------- Internet -------+---> Cloud VPN <---> Reste du Monde
                |                                         |
             [Freebox secondaire 1] ----- Internet -------+
                |                                         |
             [Freebox secondaire 2] ----- Internet -------+
                |                                         |
             [ etc... ]------------------ Internet -------+

Cela suppose d'ajouter OpenVPN dans les Freebox: sans chiffrement , ça reste (peut être) possible.

Sources

Liens:

A l'origine, je souhaitais juste voir le live de Devin Townsend dans de meilleures conditions ! Objectif atteint, grâce au “bonding”, a mon plus grand plaisir :