Remplacer la box Swisscom par un routeur sous Linux

Vincent Bernat

J’ai récemment déménagé à Lausanne, en Suisse. Le coût de l’accès à Internet est plus élevé qu’en France. Alors que Free propose un accès FTTH à 1 Gbps1 pour environ 38 € (TV et téléphone inclus), Swisscom fournit le même service pour environ 200 €2. Mon appartement est éligible à l’offre fibre de Swisscom. J’ai opté pour le forfait de 40 Mbps sans ligne téléphonique pour environ 80 €.

Comme de nombreux FAI, Swisscom fournit un boîtier Internet ainsi qu’un second boîtier pour la télévision que j’ai laissé dans son carton. Le boîtier Internet comprend quelques fonctionnalités sympathiques comme la possibilité de configurer le pare-feu, un réseau wifi pour les invités et le support de quelques protocoles de partage de fichiers. Mais pas d’accès shell !

J’ai acheté un petit PC pour prendre sa place. J’y ai installé la prochaine Debian Jessie. La quasi-intégralité de sa configuration logicielle est disponible dans un dépôt Git.

Je ne décris ici que les éléments spécifiques à Swisscom (ainsi que la QoS). Je vous invite à consulter ces deux articles connexes pour plus de détails sur d’autres aspects :

Ethernet#

Le boîtier Internet est fourni avec un SFP 1000BX de marque Siligence3. La réception et la transmission se font sur la même fibre en utilisant des longueurs d’onde différentes pour chaque direction.

Plutôt que d’investir dans une carte avec un port SFP, j’ai opté pour un switch Netgear GS110TP qui dispose de 8 ports cuivres et de 2 ports SFP. C’est un switch assez économique disposant de pas mal de fonctionnalités intéressantes comme les VLAN et LLDP. Il fonctionne correctement tant que l’on n’exige pas trop de lui.

IPv4#

La connectivité IPv4 est fournie sur le VLAN 10. Un client DHCP est obligatoire pour l’obtenir. Il est nécessaire de publier l’option DHCP « vendor class identifier » (option 60) lors de la demande de bail. Avec le client ISC DHCP, il suffit d’ajouter la ligne suivante dans le fichier /etc/dhcp/dhclient.conf :

send vendor-class-identifier "100008,0001,,Debian";

Les deux premiers nombres identifient le service demandé. Le reste n’a pas d’importance. Une fois le bail DHCP obtenu, un navigateur est nécessaire lors de la première utilsation pour s’identifier auprès de Swisscom.

IPv6#

Swisscom fournit IPv6 à travers le protocole 6rd. Cela fait partie des mécanismes pour faciliter la migration vers IPv6 sans changer le cœur de réseau. Un tunnel est mis en place au-dessus d’IPv4. Ce type de tunnel est supporté nativement sous Linux depuis le noyau 2.6.33.

Pour configurer IPv6, il faut obtenir le préfixe à utiliser et l’IP de la passerelle 6rd. Certains FAI fournissent ces valeurs dans la réponse DHCP (option 212) mais ce n’est pas le cas de Swisscom. La passerelle est 6rd.swisscom.com et le préfixe est 2a02:1200::/28. Après avoir ajouté l’adresse IPv4 au préfixe, il reste 4 bits pour créer des sous-réseaux internes.

Swisscom ne fournit pas d’IPv4 fixe. On ne peut donc pas construire à l’avance son préfixe IPv6. Le script suivant, à placer dans /etc/dhcp/dhclient-exit-hooks.d/6rd, met en place le tunnel :

sixrd_iface=internet6
sixrd_mtu=1472                  # This is 1500 - 20 - 8 (PPPoE header)
sixrd_ttl=64
sixrd_prefix=2a02:1200::/28     # No way to guess, just have to know it.
sixrd_br=193.5.29.1             # That's "6rd.swisscom.com"

sixrd_down() {
    ip tunnel del ${sixrd_iface} || true
}

sixrd_up() {
    ipv4=${new_ip_address:-$old_ip_address}

    sixrd_subnet=$(ruby <<EOF
require 'ipaddr'
prefix = IPAddr.new "${sixrd_prefix}", Socket::AF_INET6
prefixlen = ${sixrd_prefix#*/}
ipv4 = IPAddr.new "${ipv4}", Socket::AF_INET
ipv6 = IPAddr.new (prefix.to_i + (ipv4.to_i << (64 + 32 - prefixlen))), Socket::AF_INET6
puts ipv6
EOF
)

    # Let's configure the tunnel
    ip tunnel add ${sixrd_iface} mode sit local $ipv4 ttl $sixrd_ttl
    ip tunnel 6rd dev ${sixrd_iface} 6rd-prefix ${sixrd_prefix}
    ip addr add ${sixrd_subnet}1/64 dev ${sixrd_iface}
    ip link set mtu ${sixrd_mtu} dev ${sixrd_iface}
    ip link set ${sixrd_iface} up
    ip route add default via ::${sixrd_br} dev ${sixrd_iface}
}

case $reason in
    BOUND|REBOOT)
        sixrd_down
        sixrd_up
        ;;
    RENEW|REBIND)
        if [ "$new_ip_address" != "$old_ip_address" ]; then
            sixrd_down
            sixrd_up
        fi
        ;;
    STOP|EXPIRE|FAIL|RELEASE)
        sixrd_down
        ;;
esac

Plutôt que de tenter de construire le préfixe IPv6 avec des commandes shell, un court script Ruby s’en charge. Le module ipaddr est très primitif mais on s’en sort.

Swisscom utilise le même MTU pour tous les clients. Certains sont en PPPoE et donc le MTU à l’intérieur du tunnel est de 1472 et non de 1480. Un outil en ligne permet de vérifier cela rapidement.

Il n’est pas impossible que le PMTUD soit cassé à certains points d’Internet. Bien que non idéal, l’utilisation de TCP MSS permet de contourner les problèmes aléatoires qui peuvent survenir quand on a un MTU inférieur à 1500 :

ip6tables -t mangle -A POSTROUTING -o internet6 \
          -p tcp --tcp-flags SYN,RST SYN \
          -j TCPMSS --clamp-mss-to-pmtu

QoS#

Mise à jour (11.2014)

Cette section était malheureusement incorrecte, y compris la promesse qu’elle véhiculait. Lisez le commentaire de Dave Taht pour en savoir plus. Le wiki de Gentoo contient des instructions simples pour mettre en plus une QoS efficace.


  1. Débit descendant de 1 Gbps et débit montant de 200 Mbps. ↩︎

  2. Il s’agissait du forfait Vivo XL dont le prix est de CHF 169.– pour 300 Mbps. Pour atteindre 1 Gbps, il faut ajouter CHF 80.–. Désormais, ce forfait permet d’obtenir 1 Gbps symétriques pour le même prix. ↩︎

  3. Il y a deux références sur le SFP : SGA 441SFP0-1Gb et OST-1000BX-S34-10DI. La transmission se fait sur la longueur d’onde 1310 nm et la réception sur 1490 nm. ↩︎