Projet

Général

Profil

Mes travaux perso relatifs à Tetaneutral

Auteur : Id2ndR

Virtualisation

Au dessus, de libvirt, je fais tourner quelques VM sur ma machine Zbox ID18 http://www.ldlc.com/fiche/PB00158714.html : Celeron double cœurs supportant le VT, avec 8Go de RAM

OpenWRT

Je possède un TP-Link WDR3600 gigabit et double bande N. Il tourne sous Barrier Breaker 14.04.

Objectifs :
- connecter le routeur à Internet via une connexion 4G
- sortir sur une VM tournant sur ma machine à Tetaneutral, pour avoir un accès réseau complet (IP fixe, IPv6, téléphonie SIP, pas de bridage ni de modification du flux via les proxys transparents)
- brancher un téléphone IP ethernet (offre Plug&Phone d'OVH) qui passe dans le VPN, et qui fonctionne normalement sans aucune configuration

4G

Inspiré de http://wiki.openwrt.org/doc/howto/usb.tethering

root@OpenWrt:~# opkg update
root@OpenWrt:~# opkg install kmod-usb-net-rndis
root@OpenWrt:~# insmod usbnet
root@OpenWrt:~# insmod cdc_ether
root@OpenWrt:~# insmod rndis_host
root@OpenWrt:~# ifconfig usb0
usb0      Link encap:Ethernet  HWaddr 02:34:68:55:02:03  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

Dans Luci, Network > Interfaces : créer une interface nommée 4G exploitant l'interface usb0, en client dhcp

Pinguer depuis le routeur.

OpenVPN

Mise en place :
  • Certificat SSL du serveur (VM) : généré par CA-Cert (je n'ai jamais pu faire marcher le VPN sur OpenWRT avec un certificat auto-signé)
  • Certificat d'un certificat client : généré avec easy-rsa (build-ca, build-key-server, build-key). Remarque : il n'est pas nécessaire que ces certificats soient issues du certificat du serveur vérifié à la connexion, car le serveur connaît son référentiel de clef, indépendament du certificat serveur présenté sur le port d'écoute.
  • Configuration du serveur :
    id2ndr@id2ndr-vm: ~$ cat /etc/openvpn/id2ndr.conf 
    ##################################
    dev tun
    proto udp
    port 1194
    
    ca /etc/openvpn/easy-rsa/keys/class3.crt
    cert /etc/openvpn/easy-rsa/keys/id2ndr.toulan.fr.crt
    key /etc/openvpn/easy-rsa/keys/id2ndr.toulan.fr.key
    dh /etc/openvpn/easy-rsa/keys/dh1024.pem
    
    user nobody
    group nogroup
    server 10.9.0.0 255.255.255.0
    
    persist-key
    #persist-tun
    
    keepalive 10 100
    
    status /var/log/openvpn-status.log
    verb 3
    client-to-client
    
    #push "redirect-gateway def1" 
    #set the dns servers
    #push "dhcp-option DNS 8.8.8.8" 
    #push "dhcp-option DNS 8.8.4.4" 
    push "redirect-gateway def1" 
    push dhcp-option DNS 91.224.149.254
    
    log-append /var/log/openvpn
    comp-lzo adaptive
    
  • Installation du client :
    root@OpenWrt:~# opkg update; opkg install openvpn-openssl
    root@OpenWrt:~# uci set openvpn.custom_config.enabled=1
    root@OpenWrt:~# uci commit
    root@OpenWrt:~# cat /etc/openvpn/my-vpn.conf 
    dev tun
    client
    #proto tcp
    proto udp
    remote id2ndr.toulan.fr 1195
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    ca /etc/openvpn/class3.crt
    cert /etc/openvpn/Id2ndR.crt
    key /etc/openvpn/Id2ndR.key
    comp-lzo no
    verb 3
    root@OpenWrt:/etc/openvpn# wget http://www.cacert.org/certs/class3.crt
    root@OpenWrt:~# vi /etc/openvpn/Id2ndR.crt
    root@OpenWrt:~# vi /etc/openvpn/Id2ndR.key
    root@OpenWrt:~# uci set openvpn.custom_config.enabled=1
    root@OpenWrt:~# uci commit
    root@OpenWrt:~# /etc/init.d/openvpn start
    root@OpenWrt:~# logread
    [..]
    Sat Dec  6 19:35:15 2014 daemon.warn openvpn(custom_config)[25584]: WARNING: file '/etc/openvpn/Id2ndR.key' is group or others accessible
    Sat Dec  6 19:35:15 2014 daemon.notice netifd: Interface 'wan_vpn' is disabled
    Sat Dec  6 19:35:15 2014 daemon.notice openvpn(custom_config)[25584]: Socket Buffers: R=[163840->131072] S=[163840->131072]
    Sat Dec  6 19:35:15 2014 daemon.notice openvpn(custom_config)[25584]: UDPv4 link local: [undef]
    Sat Dec  6 19:35:15 2014 daemon.notice openvpn(custom_config)[25584]: UDPv4 link remote: [AF_INET]91.224.149.109:1195
    Sat Dec  6 19:35:15 2014 daemon.notice openvpn(custom_config)[25584]: TLS: Initial packet from [AF_INET]91.224.149.109:1195, sid=2e0c718b e9ec8be6
    Sat Dec  6 19:35:15 2014 daemon.notice openvpn(custom_config)[25584]: VERIFY OK: depth=1, O=CAcert Inc., OU=http://www.CAcert.org, CN=CAcert Class 3 Root
    Sat Dec  6 19:35:15 2014 daemon.notice openvpn(custom_config)[25584]: VERIFY OK: depth=0, CN=id2ndr.toulan.fr
    Sat Dec  6 19:35:16 2014 daemon.notice openvpn(custom_config)[25584]: Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
    Sat Dec  6 19:35:16 2014 daemon.notice openvpn(custom_config)[25584]: Data Channel Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
    Sat Dec  6 19:35:16 2014 daemon.notice openvpn(custom_config)[25584]: Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
    Sat Dec  6 19:35:16 2014 daemon.notice openvpn(custom_config)[25584]: Data Channel Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
    Sat Dec  6 19:35:16 2014 daemon.notice openvpn(custom_config)[25584]: Control Channel: TLSv1.0, cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA, 2048 bit RSA
    Sat Dec  6 19:35:16 2014 daemon.notice openvpn(custom_config)[25584]: [id2ndr.toulan.fr] Peer Connection Initiated with [AF_INET]91.224.149.109:1195
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: SENT CONTROL [id2ndr.toulan.fr]: 'PUSH_REQUEST' (status=1)
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: PUSH: Received control message: 'PUSH_REPLY,redirect-gateway def1,dhcp-option DNS 91.224.149.254,route 10.9.0.0 255.255.255.0,topology net30,ping 30,ping-restart 100,ifconfig 10.9.0.6 10.9.0.5'
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: OPTIONS IMPORT: timers and/or timeouts modified
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: OPTIONS IMPORT: --ifconfig/up options modified
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: OPTIONS IMPORT: route options modified
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: TUN/TAP device tun0 opened
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: TUN/TAP TX queue length set to 100
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: /sbin/ifconfig tun0 10.9.0.6 pointopoint 10.9.0.5 mtu 1500
    Sat Dec  6 19:35:18 2014 daemon.notice openvpn(custom_config)[25584]: /sbin/route add -net 91.224.149.109 netmask 255.255.255.255 gw 192.168.0.1
    
Résultats :
  • j'ai mesuré environ 70% d'utilisation CPU sur le routeur pour faire passer 17 méga. Ceci est cohérent avec Benchmark_VPN.
  • en 4G, avec une SIM Red, je fais passé en général 6 méga down / 1 méga up (mais parfois beaucoup plus)

Routage

  • Nat via le VPN : inspiré de http://wiki.openwrt.org/doc/howto/vpn.server.openvpn.tun Use-Case 3
    • Dans Luci, Network > Interfaces : créer une interface nommée wan_vpn exploitant l'interface tun0, en client dhcp
    • Dans Luci, Network > Firewall : créer une zone wan_vpn avec l'interface wan_vpn en activant Masquerading
    • Dans Luci, Network > Firewall : supprimer la zone lan existante. Créer la zone lan avec le forward vers la zone wan_vpn
    • Depuis un PC derrière le routeur : traceroute google.fr doit sortir par h7.tetaneutral.net (4ème nœuds chez moi, à cause de la VM)
Résultats :
  • Le VPN ajoute en général 20-25ms par rapport à une route directe (vers un autre site que tetaneutral).
  • Le VPN ne réduit pas le débit par rapport à la connexion hors VPN.
  • La VoIP (SIP) fonctionne très bien via le VPN
Limites :
  • Pour les jeux en ligne, on tourne autour de 100-105ms de ping avec le VPN contre 80ms en connexion direct.
  • Pas de sélection des flux à faire passer dans le VPN, et ceux à faire passer directement en 4G :
    • Le masquerade d'OpenWRT fait via luci fonctionne par zone, et s'il est possible d'autoriser le forward d'une zone vers plusieurs zones, seule la dernière zone est prise en compte
    • Il n'est pas possible via Luci d'utiliser une même zone dans plusieurs règles de forward vers chacun une zone différente
    • La table de routage du noyau linux ne permet pas de définir plusieurs passerelles par défaut.

Piste à explorer pour contourner les limites ci-dessus : installer iproute2, et ajouter des étiquettes sur les différents flux, pour faire un routage plus évolué.

Raspberry Pi

Objectifs :
  • Transformer le rPi en routeur, avec comme interface de sortie vers Internet un appareil en usb, et comme interface LAN, le port ethernet
  • Encapsuler la connexion des clients sur le LAN dans le VPN
  • Faire du filtrage pour choisir explicitement quoi router dans le VPN, et quoi faire passer en direct

Routage

  • Configurer l'interface ethernet en hotplug, avec une IP fixe; et l'usb en dhcp (Internet)
    auto eth0
    allow-hotplug eth0
    iface eth0 inet static
            address 192.168.1.1
            netmask 255.255.255.0
            post-up iptables-restore < /etc/network/iptables
    
    auto usb0
    allow-hotplug usb0
            iface usb0 inet dhcp
    
  • Installer le paquet dnsmasq, et lui donner la page d'IP à allouer en DHCP. dnsmasq fait office de relai DNS de manière automatique, et fourni également la route par défaut (il indique que le rPi fait office de passerelle vers Internet) : echo "dhcp-range=eth0,192.168.1.2,192.168.1.10,4h" | sudo tee /etc/dnsmasq.d/raspberry.conf
  • Activer le routage sur le rPi :
    • l'ip forward : Décommenter la ligne net.ipv4.ip_forward=1 dans /etc/sysctl.conf, et appliquer les modifications avec sudo sysctl -p /etc/sysctl.conf (vérification : sudo sysctl net.ipv4.ip_forward)
    • le nat : sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE; sudo iptables-save | sudo tee /etc/network/iptables

OpenVPN

  • Installer le paquet openvpn.
  • Recopier la conf (4 fichier) dans /etc/openvpn
  • Redémarrer le service

TODO : tester 2 connexions VPN en //, pour éventuellement faire du bounding (si FreeMobile limite le débit vers tetaneutral par flux)

TODO : mettre en place de l'IPv6

Routage sélectif

TODO : avec iproute2

Ici le rPi :
  • prend le net via la 4G, soit en usb, soit en wifi, cela ne change rien (sauf l'IP de la passerelle utilisée ci-dessous)
  • partage le net via son port ethernet, branché sur un switch, en faisant serveur DHCP

Objectif : faire transiter tous les flux dans le VPN, sauf ceux qui ne doivent pas être ralentis (ping ou bridage FreeMobile)
Source : http://irp.nain-t.net/doku.php/100iproute:020_iproute2

Démo : ici on va faire passer le web via la 4G, et le reste dans le VPN.

id2ndr@raspberrypi ~ $ sudo vim.tiny /etc/iproute2/rt_tables                    # Ajout de la ligne "200    4G" 
id2ndr@raspberrypi ~ $ sudo ip rule add fwmark 80 table 4G
id2ndr@raspberrypi ~ $ ip rule list
0:      from all lookup local 
32764:  from all fwmark 0x50 lookup 4G 
32765:  from all fwmark 0x50 lookup 4G 
32766:  from all lookup main 
32767:  from all lookup default 
id2ndr@raspberrypi ~ $ ip a s dev wlan0
4: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    link/ether 00:08:a1:ac:cf:ab brd ff:ff:ff:ff:ff:ff
    inet 192.168.43.241/24 brd 192.168.43.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::208:a1ff:feac:cfab/64 scope link 
       valid_lft forever preferred_lft forever
id2ndr@raspberrypi ~ $ sudo ip route add default via 192.168.43.1 table 4G
id2ndr@raspberrypi ~ $ ip r s
0.0.0.0/1 via 10.9.0.5 dev tun0 
default via 192.168.43.1 dev wlan0 
10.9.0.0/24 via 10.9.0.5 dev tun0 
10.9.0.5 dev tun0  proto kernel  scope link  src 10.9.0.6 
128.0.0.0/1 via 10.9.0.5 dev tun0 
192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.1 
192.168.43.0/24 dev wlan0  proto kernel  scope link  src 192.168.43.241 
id2ndr@raspberrypi ~ $ ip r s table 4G
default via 192.168.43.1 dev wlan0 
id2ndr@raspberrypi ~ $ sudo iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 -j MARK --set-mark 80

En activant ou non la règle iptables à la fin, on peut comparer un speedtest passant dans le VPN ou en direct

Tests :
  • sudo tcptraceroute google.fr 80 # doit sortir en direct
  • sudo tcptraceroute google.fr 100 # doit passer par tetaneutral
Mise en place permanente :
  • Contenu de /home/id2ndr/scripts/4G_direct_FreeMobile.sh :
    #!/bin/bash
    
    sudo ip route add default via 192.168.43.1 table 4G
    sudo ip rule add fwmark 80 table 4G
    # Web
    sudo iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 80 -j MARK --set-mark 80
    # Jeu en ligne (pour le ping) : Steam
    sudo iptables -t mangle -A PREROUTING -i eth0 -p udp --dport 27000:27015 -j MARK --set-mark 80
    sudo iptables -t mangle -A PREROUTING -i eth0 -p tcp --dport 27030:27039 -j MARK --set-mark 80
    
  • Ajout de post-up /home/id2ndr/scripts/4G_direct_FreeMobile.sh dans /etc/network/interfaces pour eth0

IPv6 et VPN

Les VPN peuvent faire transiter de l'IPv6, mais ce protocole étant assez vaste par nature, le contrôle fait par les VPN pose souvent problème.
Dans mon cas, je n'ai pas réussi à router correctement l'IPv6 au dela du VPN lorsque je spécifiais des sous-réseaux IPv6 dans la conf des VPN (OpenVPN et tinc).

Le plus simple est de ne pas indiquer au VPN qu'il y a de l'IPv6, pour après faire la configuration avec iproute2. Cette solution est d'ailleurs utilisée à TTN pour faire transiter l'IPv6 à travers les ponts wifi.
  • Avec OpenVPN, il faut le lancer en ligne de commande avec les options en argument (je n'ai pas réussi à le faire fonctionner avec un fichier de configuration) ; exemple sur le client sudo openvpn --dev tunipv6 --dev-type tun --lport 0 --proto udp --daemon --remote 91.224.149.109 65002 --secret /etc/openvpn/secret.key --keepalive 10 60 --verb 3 --log-append /tmp/tunipv6.log --mssfix 1389
  • Avec Tinc, il suffit de le faire fonctionner au niveau 2 (ethernet) : Mode = switch dans /etc/tinc/tinc.conf

Routage et configuration automatique

L'idée est d'apporter l'IPv6 aux clients derrière le VPN, qui sont derrière un switch physique.
  • Plan réseau : <Internet>---</56 TTN sur le serveur>---VPN---</64 sur le LAN>
  • Voici mon architecture matérielle : <Internet>---<Serveur à TTN>---4G---<smartphone>---usb---<Odroid_C1>--eth---<switch_wifi>---<PCs>
Éléments techniques pour le routage :
  • Conteneur docker sur le serveur : déclare le sous-réseau en /64 à router dans le VPN
  • Pas d'IPv6 global à l'entrée et à la sortie du tunnel VPN : l'utilisation des adresses de liens permettra de pousser le /64 au delà du Odroid_C1 : sur le LAN
  • Proxy NDP pour pouvoir router le trafic unicast à travers les liens-locaux

Mise en place

  • Tinc :
    • Serveur :
      • mkdir /docker_volumes/tinc ; cd /docker_volumes/tinc ; echo -e "Name = tinc_ipv6\nForwarding = kernel\nMode = switch" > tinc.conf ; echo "Address = id2ndr.tetaneutral.net" > hosts/tinc_ipv6 ; echo -e "#!/bin/sh\nip link set $INTERFACE up\nip link set mtu 1400 dev $INTERFACE\nip -6 addr add fe80::81:6d03/64 dev $INTERFACE\nip -6 route add 2a01:6600:8081:6d03::/64 dev $INTERFACE" > tinc-up ; chmod +x tinc-up
      • docker run -d --name tinc --net=host --device=/dev/net/tun --cap-add NET_ADMIN --volume /docker_volumes/tinc:/etc/tinc jenserat/tinc start -D
      • docker exec -ti tinc tinc init # Génère les clefs de l'hôte
      • docker exec -ti tinc tinc export # Récupérer la conf hosts/tinc_ipv6
      • docker restart tinc
    • Client :
      • apt install tinc
      • cd /etc/tinc ; echo -e "Name = tinc_ipv6_odroid\nForwarding = kernel\nMode = switch" > tinc.conf ; echo -e "Name = tinc_ipv6_odroid\nInterface=vpn6\nConnectTo = tinc_ipv6" > hosts/tinc_ipv6_odroid ; echo -e "#!/bin/sh\nip link set $INTERFACE up\nip link set mtu 1400 $INTERFACE\nip -6 route add default via fe80::81:6d03 dev $INTERFACE > tinc-up ; chmod +x tinc-up ; echo "Import de hosts/tinc_ipv6"
      • tincd -K # Génère les clefs de l'hôte
      • tincd # Puis dans docker, on vérifie la connexion avec : tinc dump node
      • apt install radvd # Va indiquer le sous-réseau à utiliser pour les PC sur le LAN
      • echo -e "interface eth0\n{\n AdvSendAdvert on;\n prefix 2a01:6600:8081:6d03::/64\n {\n AdvRouterAddr on; \n };\n RDNSS 2a01:6600:8081:ffff:: {\n };\n};" > /etc/radvd.conf
      • sudo service radvd start
      • echo "Télécharger NDPPD sur https://github.com/DanielAdolfsson/ndppd/releases"
      • make
      • echo -e "proxy vpn6 {\n router yes\n timeout 500 \n ttl 30000\n rule 2a01:6600:8081:6d03::/64 {\n static\n }\n}" > /etc/ndppd.conf # static permet de répondre à toutes les requêtes : permet de résoudre les éventuels problèmes de transmission de paquet sur le Lan/wifi, et permet également à l'Odroid l'accès au réseau global IPv6 grace à son IP construite sur l'interface eth0.
      • ./ndppd -d # A intégrer dans le tinc-up
Ensuite on teste :
  • Écoute du trafic un peu partout : sudo tcpdump ip6 and icmp6 -i vpn6 -n
  • ping6 sur l'adresse de lien (odroid vers conteneur) : ping6 fe80::81:6d31%vpn6
  • ping6 sur adresse global depuis l'odroid : ok (uniquement si le proxy NDP est réglé sur "static", car sinon il ne fait que relayer les requêtes arrivant sur l'interface eth0)
  • ping6 sur id2ndr.tetaneutral.net depuis un PC : OK
  • wget -6 google.fr