lalahop

DNAME

Aujourd'hui, on va parler d'un type d'enregistrement DNS : DNAME. Je connaissais ce type d'enregistrement mais je n'avais jamais eu l'occasion de l'utiliser autrement que pour un test bidon. Comme l'occasion s'est présentée récemment, je voulais faire un petit feedback. En conséquence, je vais être assez léger. Pour creuser le sujet, il faudra aller voir sur le blog de Stéphane Bortzmeyer (j'égrène les bons liens au long de ce billet).

Qu'est ce que c'est ?

Delegation Name (DNAME) est un type d'enregistrement DNS défini dans le RFC 6672 (l'original 2672 étant obsolète) qui permet de donner un alias, un synonyme à l'intégralité d'un sous-arbre dans la hiérarchie du DNS. Avec DNAME, le nom lui-même reste inchangé et n'est pas redirigé. En comparaison, le type CNAME permet de créer un alias 1 vers 1 : un unique nom pointe sur un autre. Le sous-arbre du nom aliasé reste inchangé. En gros, mettre un DNAME sur un nom produira le même résultat que de mettre des CNAME sur chacun des sous-noms possibles.

Exemple : mycorporation.example. DNAME ultimatecorporation.example.

www.mycorporation.example. pointe sur www.ultimatecorporation.example. Si ce dernier nom existe, une requête sur www.mycorporation.example produira un résultat. NXDOMAIN dans le cas contraire.

En admettant que le nom ultimatecorporation.example. existe en type AAAA (IPv6), que donnera une demande dig AAAA mycorporation.example. ? Aucun résultat. 🙂 Le nom n'existe pas dans le type demandé. Si vous êtes tombé dans le piège, relisez bien la définition : un DNAME permet de donner un alias à un sous arbre, pas au nom lui-même. Pour résoudre ce problème :

  • n'espérez pas d'ajouter un enregistrement de type CNAME pour mycorporation.example. CNAME ne se combine avec aucun autre type (exception faite des types relatifs à DNSSEC comme RSSIG) !
  • dupliquer l'information. Dans notre cas : dupliquer le type AAAA pour les deux noms (ultimatecorporation.example. et mycorporation.example.). Ce n'est pas un alias : une éventuelle modification devra être faite pour les deux noms !
  • on pourra, peut-être, utiliser un futur nouveau type, comme BNAME ou SHADOW, tous deux proposés à l'IETF, qui permettent de combiner CNAME et DNAME : on crée un alias pour un nom et pour le sous-arbre de ce nom.

À quoi ça sert ?

Le DNAME peut-être utilisé dans les cas suivants :

  • Lorsqu'une même organisation (ou personne) enregistre son nom ou celui d'une de ses marques dans plusieurs voire tous les TLD existants. Le DNAME permet de faire pointer chaque sous-arbre vers un seul sous-arbre. Seul ce dernier devra être maintenu.
  • Lors d'une rachat ou d'une fusion d'entreprises. Pour présenter le DNAME, Stéphane Bortzmeyer utilise le renommage de Vivendi Environnement en Veolia Environnement.
  • Pour les noms de domaine en unicode (IDN). DNAME est utilisé, par exemple, dans le TLD cat.

Limites

Comme le DNAME permet uniquement de donner un alias à un sous-arbre, cela peut être gênant en fonction de l'implémentation de certains scénarios. Par exemple : sous le TLD .cat, lors de l'enregistrement d'un nom IDN, le nom ASCII est aussi réservé et un DNAME redirige le sous-arbre IDN vers le sous-arbre ASCII. Cela signifie que je ne pourrais jamais envoyer de mails à destination du domaine caballè.cat. : ce FQDN est de type DNAME donc seul le sous-arbre est aliasé ! Pas de MX, pas de SRV (XMPP par exemple), pas même de A/AAAA (si pas de MX/SRV, les serveurs de mail/jabber cherchent un A/AAAA). Le mieux serait de déléguer les deux noms (IDN/ASCII) au titulaire et libre à lui d'utiliser DNAME ou pas en complément d'une duplication des type A/AAAA/MX/SRV/SPF/ pour l'apex. C'est d'ailleurs comme cela que procède DotAsia, le registre de asia. .

Comme l'utilisation de DNAME conduit à la synthèse de CNAME, cela signifie qu'il est possible d'avoir des chaînes de CNAME qui sont, normalement, déconseillées. Exemple : si l'on a www.ultimatecorporation.example. CNAME web.ultimatecorporation.example., alors dig A www.mycorporation.example générera la réponse suivante :

mycorporation.example.                  3600	IN	DNAME	ultimatecorporation.example.
www.mycorporation.example.	        0	IN	CNAME	www.ultimatecorporation.example.
www.ultimatecorporation.example.	3600	IN	CNAME	web.ultimatecorporation.example.
web.ultimatecorporation.example.	3600	IN	A	192.0.2.1

Le DNAME est fortement méconnu car, pour les deux usages sur les trois cités plus haut, il peut être remplacé par un fichier de zone avec des noms relatifs et des liens symboliques vers ce fichier pour toutes les zones identiques. La seule limite de cette méthode est la consommation mémoire : au chargement des zones, le serveur duplique les données pour obtenir un exemplaire par zone chargée (alors que les RDATA sont identiques). Cela pose problème pour les cas d'usages où l'on a beaucoup de zones identiques comme les IDN et les variantes.

Mettre en œuvre

DNS

Rien de spécial : c'est un type d'enregistrement, rien de plus.

Si vous avez deux domaines, savoir si vous allez vous les faire déléguer et mettre un DNAME dans le fichier de zone de l'un ou si vous allez demander à l'un des domaines parent de mettre le DNAME directement dans son fichier de zone à lui est un pur choix de votre part (le premier suppose de dupliquer l'apex, le second que vous n'aurez ni mail ni XMPP ni ... sur le domaine lui-même) et en fonction de votre domaine parent (inutile de demander ça à un gTLD/ccTLD hein, je dis ça pour ceux qui obtiennent des domaines via des potes 😉 ).

Postfix

On suppose que le serveur est configuré pour traiter les mails au départ/à destination du domaine mycorporation.example. On veut aussi qu'il s'occupe du nouveau domaine équivalent ultimatecorporation.example.. Pour l'identification, j'utilise SASL.

J'utilise les directives « virtual_alias_domains » et « virtual_alias_maps » :

virtual_alias_domains = ultimatecorporation.example
virtual_alias_maps = hash:/etc/postfix/virtual_aliases

/etc/postfix/virtual_aliases contient :

@ultimatecorporation.example        @mycorporation.example

Les mails adressés à guigui@ultimatecorporation.example seront redirigés vers guigui@mycorporation.example et delivrés si cette boîte existe.

Pour pouvoir envoyer des mails avec une adresse @ultimatecorporation.example, il suffit de rajouter une entrée dans une table passée en argument de « smtpd_sender_login_maps ». Exemple ici avec ce qui deviendra une hashmap :

guigui@ultimatecorporation.example        guigui@mycorporation.example

ejabberd

Il suffit simplement d'ajouter le nouveau nom dans la directive « hosts » comme le montre l'exemple commenté dans le fichier de configuration :

{hosts, ["mycorporation.example", "ultimatecorporation.example"]}

Routeurs logiciels et OSPF

Aujourd'hui, on va parler routeurs logiciels et OSPF. Les sujets abordés vont être assez variés : mode commit ou pas, configurations de base et résolution d'un problème àlacon.

Table des matières

Commit

Le "mode commit" permet d'appliquer une série de modifications en une seule fois, one-shot : vous tapez des commandes de configuration, elles sont bufferisées. Quand vous avez finis, vous tapez la commande qui va bien (« commit » la plupart du temps, logique 😛 ) et les modifications sont réellement appliquées. C'est pratique pour éviter les bourdes et pour éviter les fluctuations sur le réseau dûes à des modifications successives. La présence d'un mode commit est l'une des différences principales entre Cisco et Juniper.

Bilan de présence de nos jours (je n'ai pas vérifié si chaque implémentation est complète, juste qu'elle existe) :

  • Cisco : un mode commit est disponible sur certaines séries comme XR.
  • Juniper : disponible partout à ma connaissance.
  • Quagga : pas de mode commit ni d'équivalent.
  • BIRD : pas de mode commit mais le fonctionnement de BIRD (modification du fichier de config, reload/configure) permet de simuler un début de mode commit.
  • XORP : un mode commit est disponible.

Appliquons à un cas concret : on a un réseau interne avec de l'OSPF (ou ISIS) qui tourne. On veut changer le poids sur plusieurs liens d'un même routeur. Pour les besoins d'une expérience de recherche, on a besoin que toutes les modifications soient faites en une seule fois et que le routeur en question n'émette qu'un seul LSA Update (ce point est fondamental). Quelles implémentations de routeur purement logiciel sont compatibles ?

  • XORP : malgré son mode commit, XORP émet autant de LSA Update que de liens dont le poids a changé pour refléter les changements.
  • BIRD : on modifie le poids des interfaces dans le fichier de configuration, on reload BIRD et ça juste marche : un seul LSA Update émis.

Configurations OSPF basiques pour les routeurs logiciels

Quand on veut une configuration minimale pour faire de l'OSPF juste pour tester deux-trois trucs, on trouve de tout sur le web et pas que des configurations allégées (authentification OSPF, tuning des différents timers, identification dans la CLI, ...). Mention spéciale aux développeurs de XORP et à ceux de BIRD qui fournissent des exemples minimalistes dans leur documentation.

Voici quelques configs de base qui juste fonctionnent. Une machine, deux interfaces eth0-198.18.0.2/30 eth1-198.18.0.5/30, une seule aire OSPF, pas de sécurité.

Quagga

ospfd.conf :

hostname ospfd
 
line vty
	no login
 
log syslog warnings
 
router ospf
        router-id 198.18.0.2
	network 198.18.0.0/16 area 0

zebra.conf :

hostname Router
 
line vty
	no login
 
log syslog warnings

BIRD

router id 198.18.0.2;
 
log syslog {warning, error, fatal};
 
protocol kernel {
        scan time 20;
        export all;
        import all;
}
 
protocol device {
        scan time 10;
}
 
protocol ospf {
        import all;
        export all;
 
        area 0 {
                interface "eth0", "eth1"; 
        };
}

XORP

interfaces {
	interface eth0 {
		default-system-config
	}
 
	interface eth1 {
		default-system-config
	}
}
 
protocols {
	ospf4 {
		router-id: 198.18.0.2
 
		area 0.0.0.0 {
 
			interface eth0 {
				vif eth0 {
					address 198.18.0.2 {
					}
				}
			}
 
			interface eth1 {
				vif eth1 {
					address 198.18.0.5 {
					}
				}
			}
		}
	}
}

Interopérabilité des implémentations de routeurs logiciels

Un petit mot sur l'interopérabilité des routeurs logiciels en ce qui concerne OSPF :

  • Quagga-BIRD : OK
  • Quagga-XORP : OK
  • BIRD-XORP : OK sauf avec des liens point-to-point. J'ai essayé plusieurs configurations sans obtenir de résultat. Mais l'erreur est sans doute de mon côté : j'ai encore un peu de mal avec XORP. Sans liens ptp, j'ai aussi observé des comportements étranges : BIRD/XORP boucle sur "DB Description" ou une avalanche continue de LSA Request/Update/Ack. Un petit restart des routeurs et ça part correctement.

Un problème bien lourd

J'ai une maquette de test bateau :

R1-eth0:198.18.0.1/30-----eth0:198.18.0.2/30-R2-eth1:198.18.0.5/30-----eth0:198.18.0.6/30-R3

R1 et R3 pourraient être des routeurs de bordure du réseau (BGP, tout ça) et R2 l'un des routeurs interne du réseau.

Si je mets que du Quagga sur les trois routeurs, ça juste marche.
Si je mets que du BIRD, ça juste marche.
Si je mets que du XORP, ça juste marche.
Si je mets du XORP et du Quagga (que ce soit Quagga ou XORP sur R2 et l'inverse ailleurs), ça marche.
Si je mets du BIRD et du Quagga ou du XORP : ça ne marche pas.

« Ça ne marche pas » = les routeurs communiquent entre eux, s'échangent des LSA Update mais le préfixe n'apparaît pas dans la table de routage de R1 ni dans celle de R3.

Les Hello-interval (délai entre deux messages Hello) et les Dead-interval (si je ne reçois pas de Hello, en combien de temps je considère que mon pair est mort), qui doivent être les mêmes pour tous les routeurs d'un même réseau et qui sont définis, dans les implémentations, à 10 secondes et 40 secondes respectivement pour un réseau local (RFC 2328, annexe C3, page 223) ne sont pas en cause : les routeurs communiquent et échangent des LSA Update.

Je vous passe les différentes hypothèses que j'ai émis et les différents tests que j'ai fait pour les invalider une par une, pour en arriver à la conclusion : /30 et /31 sont des subnet d'interconnexion : il ne peut y avoir que deux machines tout au plus. Il faut donc le préciser aux routeurs logiciels (pas que à BIRD mais bien aux deux extrémités !). Cela se fait avec les directives suivantes :

Quagga (ospfd.conf) :

interface eth0
	ip ospf network point-to-point
 
interface eth1
	ip ospf network point-to-point

BIRD :

interface "eth0", "eth1" {
        type ptp;
};

Je ne sais pas pourquoi cela fonctionne quand on utilise le même logiciel sur tous les nœuds ou quand on utilise Quagga et XORP ... J'imagine que BIRD fait un traitement plus strict ...

Ça saute aux yeux quand on n'est pas plongé dans ses configs, c'est une erreur de débutant mais si ça peut servir à d'autres ...

Mesurer la propagation d’une annonce BGP pour s’amuser

Les copains d'Alsace Réseau Neutre, FAI associatif neutre en Alsace ont racké leurs machines en début de semaine et ils ont monté leur première session BGPoIPv4 hier soir. L'idée m'est venue de constater le temps de propagation de leur préfixe à travers les Internets.

Table des matières

Que mesure-t-on ?

Je précise d'abord, pour les mesures-nazi qui passeraient par là, que je ne cherche pas à faire une mesure précise et fiable. L'idée n'est pas de démontrer quelque chose ni d'argumenter une publication scientifique. On est plus dans le domaine du "for ze fun" parce que, oui, voir son préfixe apparaître dans les tables de routage de routeurs à l'autre bout du monde, c'est beau. :')

Et puis avoir une idée et voir les outils disponibles pour la réaliser, c'est formateur.

L'idée est donc de voir comment/à quelle vitesse se propage la première annonce BGP d'ARN de routeur de bordure en routeur de bordure, à travers les Internets.

Nous chercherons à obtenir une chronologie de la propagation. Exemple fictif :
21h00m00 : ARN lance la session BGP.
21h00m49 : Le préfixe apparaît chez notre transitaire
.... : le préfixe apparaît dans tel point d'échange européen
.... : le préfixe apparaît la table d'un routeur à Sydney
Etc, etc.

Comment mesure-t-on ?

On sent, de manière assez intuitive, que la mesure doit être faite depuis d'autres réseaux.

Plusieurs idées peuvent venir en tête :

  • On peut utiliser des looking glasses ou des traceroute mis à la disposition par des opérateurs. Exemples : le préfixe v4 d'ARN dans le looking glass du FAI associatif toulousain Tetaneutral.net, traceroute.org. Inconvénient : à part un mass-F5-autoreload, ça me semble difficilement automatisable.
  • On peut utiliser le service Routing Information Service (RIS) du RIPE. Exemple : le préfixe v4 d'ARN dans RIS (on remarquera au passage qu'il y a une annonce large invalide dans la nature : 88.0.0.0/6 par 3303 depuis le 20/04/2013 ). C'est simple mais ça ne permet pas d'obtenir la chronologie que nous voulons. ÉDIT du 19/07/2013 à 10h30 : En revanche, l'outil BGPlay permet une visualisation très sympathique de la timeline. Exemple : le préfixe v4 d'ARN dans BGPlay. Fin de l'édit
  • On peut utiliser les routeurs en accès libre du projet Route Views. Avec l'outil ctel (du package cssh dont je vous ai déjà parlé), il est possible d'exécuter la même commande en parallèle sur plusieurs collecteurs du projet Route-Views. Le projet permet même de récupérer les archives des annonces BGP vues par les différents collecteurs du projet. Les archives sont disponibles par tranches de 15 minutes.
  • Utiliser les sondes du projet Atlas du RIPE pour lancer un traceroute depuis plusieurs points des Internets. Le résultat doit être intéressant mais je n'ai ni sonde, ni crédit.

Déroulement

RIS

Rien de spécial à faire : à partir du lancement du démon de routing (BIRD dans le cas d'ARN), il suffit de recharger la page à une fréquence donnée.

Route-Views

Avant l'instant I, il suffit de préparer ctel en ajoutant les routeurs que l'on souhaite interroger dans .clusterssh/clusters. Exemple :

ARN-test route-views.sydney.routeviews.org route-views.saopaulo.routeviews.org route-views2.routeviews.org rpki-rtr.ripe.net

Les lecteurs attentifs remarqueront rpki-rtr.ripe.net qui n'est pas un collecteur du projet Route-Views mais un routeur Cisco mis à disposition par le RIPE pour jouer avec RPKI+ROA. L'username est ripe, sans mot de passe.

Peu avant le lancement du démon de routing, il suffira de se connecter aux machines :

ctel ARN-test

et de saisir :

show bgp ipv4 unicast 89.234.141.0/24

ou

show bgp ipv6 [unicast] 2a00:5881:8100::/40

Il faudra maintenir les connexions avec une activité car il y a des timeout. 😉

Suite au lancement de BIRD, il suffit normalement de relancer la commande plusieurs fois (fleche haut-entrée, classique) pour voir les différences.

Archives Route-Views

Les archives sont au format MRT. Il nous faut donc un outil pour les lire. J'ai choisi arbitrairement bgpparser. Attention : la version 0.3b2 distribuée sur le site officiel ne compile pas.

On installe les dépendances nécessaires :

sudo apt-get update && sudo apt-get install libxml2 libxml2-dev liblog4cxx10 liblog4cxx10-dev libboost-all-dev git

On récupère le dépôt git :

git clone https://github.com/cawka/bgpparser.git

Les commandes classiques :

./bootstrap.sh
./configure

make
sudo make install

Il faut penser à ajouter /usr/local/lib en tant que dossier où chercher des bibliothèques (/usr/local/lib est déjà indiqué dans /etc/ld.so.conf.d/libc.conf sinon, il faudrait le faire nous même avant de lancer la commande) :

ldconfig

Ensuite, il suffit de récupérer une archive. Comme écrit sur la page web du projet Route-Views : de nos jours, les fichiers sont nommés en fonction de l'heure UTC (bon, il y a une exception mais ce n'est pas important ici 😛 ). Donc pour un événement qui s'est produit vers 20h31/20h32 UTC+2 le 17 juillet 2013, il faut récupérer un fichier de la forme : updates.20130717.1830.bz2. Ce fichier couvre donc de 20h30 à 20h44m59s UTC+2 du 17 juillet 2013 pour un collecteur donné.

Pour le collecteur de Sydney, on aura donc :

wget http://archive.routeviews.org/route-views.sydney/bgpdata/2013.07/UPDATES/updates.20130717.1830.bz2

Il ne reste plus qu'à lire ce fichier :

bgpparser2 --file updates.20130717.1830.bz2 --ipv4 | grep 89.234.141.0/24

BGP4MP|1374085909|A|202.167.228.20|4739|89.234.141.0/24|4739 3356 1299 42456 60630|IGP|202.167.228.20|0|0|4739:0|NAG||

BGP4MP|1374085922|A|202.167.228.74|4826|89.234.141.0/24|4826 6939 42456 60630|IGP|202.167.228.74|0|0|4826:5901 4826:6150|NAG||

BGP4MP|1374085924|A|202.167.228.37|38809|89.234.141.0/24|38809 2914 1299 42456 60630|IGP|202.167.228.37|0|0|2914:420 2914:1005 2914:2000 2914:3000 65504:1299|NAG||

BGP4MP|1374085930|A|202.167.228.44|10026|89.234.141.0/24|10026 1299 42456 60630|IGP|202.167.228.44|0|10051|10026:3050 10026:31840 10026:40903|NAG||

BGP4MP|1374085936|A|202.167.228.20|4739|89.234.141.0/24|4739 1239 1299 42456 60630|IGP|202.167.228.20|0|0|4739:0|NAG||

BGP4MP|1374086082|A|202.167.228.44|10026|89.234.141.0/24|10026 1299 42456 60630|IGP|202.167.228.44|0|10052|10026:3050 10026:31840 10026:40912|NAG||

ÉDIT du 19/07/2013 à 12h30 :
ou

bgpparser2 --file updates.20130719.0915.bz2 --ipv6 | grep 2a00:5881:8100::/40

BGP4MP|1374226150|A|2001:12f8::20|28571|2a00:5881:8100::/40|28571 1251 20080 6939 42456 60630|IGP|2001:12f8::20|0|0||NAG||

BGP4MP|1374226150|A|2001:12f8::218:21|52888|2a00:5881:8100::/40|52888 1251 20080 6939 42456 60630|IGP|2001:12f8::218:21|0|0||NAG||

BGP4MP|1374226150|A|2001:12f8::20|28571|2a00:5881:8100::/40|28571 1251 20080 6939 1299 42456 60630|IGP|2001:12f8::20|0|0||NAG||

BGP4MP|1374226150|A|2001:12f8::20|28571|2a00:5881:8100::/40|28571 22548 3549 1299 42456 60630|IGP|2001:12f8::20|0|0|3549:2471 3549:30840|NAG||

BGP4MP|1374226150|A|2001:12f8::218:21|52888|2a00:5881:8100::/40|52888 1251 20080 6939 42456 60630|IGP|2001:12f8::218:21|0|0||NAG||

BGP4MP|1374226150|A|2001:12f8::20|28571|2a00:5881:8100::/40|28571 1916 6939 42456 60630|IGP|2001:12f8::20|0|0|1916:1250|NAG||

[...]

Fin de l'édit

On a : le type de message, le timestamp du message, le sous-type (ajout de route (« A »), suppression (« W »)), l'IP du peer, l'ASN du peer puis le message BGP qui se décompose en préfixe, AS_PATH, origine, next-hop, localpref, MED, communautés, pas d'aggrégation (« NAG »).

Pour convertir le timestamp, utilisez votre langage favori (troll inside) comme :

php -r 'echo date ("d/m/Y H:i:s", "1374085909")."\n";'
17/07/2013 20:31:49

Comme c'est tout bien classé par ordre chronologique, on voit que le collecteur de Sydney a reçu la première annonce d'ARN à 20h31m49s.

Donc, les résultats ?

(Temps en UTC+2)

RIS

20h31m?s : lancement de BIRD (première vue : 2013-07-17 20:31:48)
21h : 76% de visibilité
21h30 : 89% de visibilité
22h : 97% de visibilité

Route-Views

IPv4

LINX : 17/07/2013 à 20:31:48
São Paulo : 17/07/2013 à 20:31:48
Sydney : 17/07/2013 à 20:31:49
Oregon : 17/07/2013 à 20:32:07
Tokyo : 17/07/2013 à 20:32:17

IPv6

(Pour les curieux : non, nous ne considérons pas l'annonce du 19/07/2013 à 00h20 comme étant la première)

LINX : 19/07/2013 à 11:29:09
São Paulo : 19/07/2013 à 11:29:10
Sydney : 19/07/2013 à 11:29:09
Oregon : 19/07/2013 à 11:29:09
Tokyo : 19/07/2013 à 11:29:21

J'avais toujours entendu dire qu'il fallait 3 à 4 minutes pour qu'un préfixe nouvellement annoncé apparaisse dans 90% des réseaux des Internets. Avec cette mise en pratique, je constate que c'est jouable en 1 minute. 🙂 Bon, ok, les sessions BGP avec notre transitaire étaient déjà montées au moment du reload de BIRD qui a provoqué l'annonce. Forcement, on gagne un peu. 😀

Atlas

ÉDIT du 19/07/2013 à 12h30 :
Merci à Stéphane Bortzmeyer.

IPv4 :

Monde :
 
Measurement #1013491 to 89.234.141.1 uses 400 probes
400 probes reported
Test done at 2013-07-19T08:16:35Z
Tests: 398 successful tests (99.5 %), 0 errors (0.0 %), 2 timeouts (0.5 %), average RTT: 71 ms
 
Europe :
 
Measurement #1013493 to 89.234.141.1 uses 399 probes
399 probes reported
Test done at 2013-07-19T08:21:20Z
Tests: 398 successful tests (99.7 %), 0 errors (0.0 %), 1 timeouts (0.3 %), average RTT: 52 ms
 
Asie (toujours moins bien) :
 
Measurement #1013494 to 89.234.141.1 uses 114 probes
113 probes reported
Test done at 2013-07-19T08:24:20Z
Tests: 107 successful tests (94.7 %), 0 errors (0.0 %), 6 timeouts (5.3 %), average RTT: 298 ms
 
Measurement #1013495 to 89.234.141.1 uses 115 probes
115 probes reported
Test done at 2013-07-19T08:43:21Z
Tests: 112 successful tests (97.4 %), 0 errors (0.0 %), 3 timeouts (2.6 %), average RTT: 298 ms

IPv6 :

Monde : 
 
Measurement #1013513 to 2a00:5881:8100::1 uses 396 probes
396 probes reported
Test done at 2013-07-19T13:22:53Z
Tests: 344 successful tests (86.9 %), 17 errors (4.3 %), 35 timeouts (8.8 %), average RTT: 71 ms

Fin de l'édit

ÉDIT du 26/10/2013 à 16h30 :
D'autres stats IPv6 homemade cette fois-ci :

Monde : 
392 probes, 938 successful tests (79.8 %), 144 errors (12.3 %), 93 timeout (7.9 %), average RTT: 75
 
Europe : 
396 probes, 971 successful tests (81.6 %), 114 errors (9.6 %), 105 timeout (8.8 %), average RTT: 51
 
Asie : 
52 probes, 119 successful tests (76.3 %), 27 errors (17.3 %), 10 timeout (6.4 %), average RTT: 314
 
Amérique :
151 probes, 295 successful tests (65.1 %), 93 errors (20.5 %), 65 timeout (14.3 %), average RTT: 146

Fin de l'édit

Conclusion

Je vais être bref : expérience enrichissante.

Du WiFi mesh pour s’amuser

Ce billet va parler, de manière très concise, de la mise en place d'un réseau WiFi mesh avec Babel.

Table des matières

Un peu de théorie

Le terme « mesh » désigne une topologie réseau où chaque nœud est relié à tous les autres nœuds. Donc le terme est extrêmement générique et peut s'appliquer, par exemple à une topologie BGP que l'on dira full-mesh (chaque routeur de bordure d'un réseau a une session iBGP avec chacun des autres routeurs de bordures) . C'est pour ça que je préfère parler de réseau WiFi mesh : afin de dissiper tous les doutes.

Il y a plusieurs approches pour faire du WiFi mesh :

  • On reprend les protocoles de routage filaires et on les adapte pour les conditions hostiles des réseaux mesh (l'instabilité est la règle, l'interface d'entrée d'un paquet peut aussi être l'interface de sortie de ce même paquet, ...). C'est l'approche de Babel.
  • On repart de 0. C'est l'approche de B.A.T.M.A.N ou OLSR.

Parmi les protocoles de routage, il existe des paradigmes de fonctionnement différents :

  • B.A.T.M.A.N émule un réseau ethernet classique par dessus le réseau WiFi mesh. Donc tous les concepts du L2 filaires demeurent : ARP/NDP, DHCP, ...
  • Babel agit au niveau 3 donc IP donc les concepts précédents ne valent plus : pas d'ARP/NDP, pas de DHCP mais une implémentation équivalente de configuration automatique avec état (ahcp), ...

Voilà pour les quelques points de théorie que je voulais mettre en avant. Si vous voulez en apprendre plus sur Babel et sur le routage dans les réseauw WiFi maillés, je vous conseille les ressources suivantes :

Comment monter un petit réseau WiFi mesh pour s'amuser avec Babel

Ici, nous partirons du principe qu'une seule machine distribuera la configuration sur le réseau. Tout comme avec DHCP, il est possible d'avoir plusieurs machines dédiées à cette tâche.

Commençons par configurer cette machine.

D'abord, on crée le fichier /etc/ahcpd.conf avec le contenu suivant :

mode server
 
prefix 2001:2::/48
prefix 198.18.1.0/24
lease-dir /var/ahcpd/

Les préfixes utilisés sont réservés à l'IANA pour faire des tests. Ils ne sont pas dans la DFZ et peu utilisés (ça permet d'éviter les conflits). Il faut évidemment créer le dossier /var/ahcpd/

Ensuite, on installe et on lance les logiciels nécessaires (en root, of course) :

apt-get update && apt-get install babeld ahcpd
 
# Si vous avez un logiciel qui configure automatiquement vos interfaces comme 
# le Network Manager de GNOME, il est indispensable de l'arrêter
service network-manager stop
 
# On vérifie que l'interface WiFi est down, ce qui élimine certains problèmes comme :
# « Error for wireless request "Set Mode" (8B06) : SET failed on device wlan0 ; Device or resource busy. » 
# (erreur récupérée sur une WG111v2/v3 basée sur les puces Realtek 8187B/L
ip link set down dev wlan0
 
# On passe l'interface WiFi en mode ad-hoc
iwconfig wlan0 mode ad-hoc channel 11 essid "nom-du-reseau"

# On up l'interface
ip link set up dev wlan0
 
# On lance Babel
babeld wlan0 &
 
# On lance le serveur ahcpd 
ahcpd -c /etc/ahcpd.conf wlan0

Sur les autres nœuds du réseau, on suit la même démarche mais l'on remplace simplement « ahcpd -c /etc/ahcpd.conf wlan0 » par :

ahcpd wlan0

On peut surveiller l'attribution des adresses avec la commande suivante :

watch "ls -l /var/ahcpd/"

Si ahcpd ne fonctionne pas (et ça arrive ...), les nœuds peuvent quand même rejoindre le réseau en s'attribuant manuellement une adresse (attention aux doublons !) :

ip addr add 198.18.1.X/24 dev wlan0

Il est possible d'avoir un accès à Internet depuis le réseau mesh.

  • Soit en ajoutant manuellement une route vers une passerelle filaire/radio sur chaque nœud :
    ip r a default via 198.18.1.254 dev wlan0
  • Soit en demandant à un (ou plusieurs :D) nœud(s) de distribuer une route par défaut :
    babeld -C 'redistribute ip 0.0.0.0/0 le 0 metric 128' wlan0

    (ça peut aussi se mettre proprement dans un fichier de configuration babeld.conf qui sera indiqué au démon -c /etc/babeld.conf, par exemple.

Dans les deux cas, ne pas oublier d'activer le masquerade sur la(les) passerelle(s) :

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Pas besoin d'activer l'ip_forward, il l'est déjà : principe du mesh, tout ça 😉

Quelques petites notes

  • Toutes les cartes WiFi ne supportent pas le mode ad-hoc.
  • Certains drivers ne supportent pas non plus le mode ad-hoc.
  • Si vous avez Quagga sur votre machine, utilisez le chemin complet pour appeler babeld sinon c'est l'implémentation (bugguée, utilisez Quagga-RE si vous voulez une intégration de babel dans Quagga) de babel inclue dans Quagga qui sera lancée.
  • Babel peut-être utilisé en milieu hybride (filaire et radio) pour, par exemple, interconnecter des îles mesh entre elles quand celles-ci sont séparées par une distance inatteignables en radio.

Usages

Pour ceux qui se demandent à quoi servent les réseaux mesh dans la vraie vie :

  • À construire de grands réseaux qui juste marchent en vrai. Liste.. De ce que j'ai vu, Guifi.net en Espagne et Freifunk.net en Allemagne sont juste impressionnants.
  • Pour des projets humanitaires. Exemple : GAST.
  • Les armées sont aussi très intéressées pour guider les hommes dans les milieux hostiles et leur fournir des informations complètes, rapidement et en toute indépendance.

Quelques pistes pour aller plus loin

  • Essayer babelweb pour avoir une visualisation graphique de votre réseau. Exemple de visualisation babelweb.
  • Essayer B.A.T.M.A.N qui n'est pas basé sur le même paradigme (voir plus haut).
  • Comme tous les nœuds émettent sur la même fréquence, les interférences peuvent être fortes et nuirent au débit. Il est possible de mixer les canaux utilisés. Il faut, bien sûr, des machines avec des radios présentes sur les différents canaux utilisés. On peut ensuite demander aux différents nœuds Babel d'en tenir compte dans leur calcul de route avec l'option « z ».
  • Utiliser votre petit routeur perso sous OpenWRT pour faire une config double point d'accès WiFi et passerelle mesh vers Internet : Routeur OpenWrt hybride (mesh babel + AP et Internet)
  • Enfin, du 19 au 21 juillet 2013 (fin de cette semaine quoi), il y aura un hackathon autour de Babel au Loop (hackerspace parisien). Plus d'infos : Hackathon Babel au Loop.

VPN unipersonnel avec une IP failover en sortie sur un dédié OVH

L'idée du jour est d'utiliser un serveur dédié chez OVH, qui sert déjà à autre chose, pour se monter un petit VPN sans prétention. Quand je dis sans prétention c'est que je prévois ça pour un usage personnel (unipersonnel) et que je ne destine pas ce VPN à l'échange de flux hautement confidentiels (sinon ça ne finirait pas chez OVH ...). Donc si vous cherchez une config blindée haute sécurité, ce n'est pas le bon billet, désolé.

Le but de ce VPN est de me permettre d'être sur Internet quand je veux faire des tests ou autre (exemple parmi d'autres : nmap mon serveur pour vérifier qu'il n'y a rien de plus qui est ouvert sur l'extérieur que ce que je veux). Quand je dis « être sur Internet », je veux dire : être capable d'émettre et de recevoir tous les contenus et toutes les applications de mon choix sans aucune discrimination ... Ho ! La définition de la neutralité du net ! Donc éviter un filtrage de ports à la con, éviter un filtrage du type "ne peut entrer sur le réseau que ce qui fait suite à une demande de l'intérieur" (en gros : impossible d'héberger des services). C'est rageant d'être perturbé par notre FAI (Fournisseur d'Accès à son Intranet dans le cas présent) quand on veut observer quelque chose ou monter un service.

Attention toutefois : le tunnel sort chez OVH et il faut savoir qu'OVH n'a pas un impératif de neutralité. Des usages y sont clairement interdits ou soumis à autorisation préalable comme, par exemple mais pas seulement, héberger un proxy ou un nœud TOR ou utiliser des logiciels de P2P. OVH duplique aussi tous les mails sortants pour analyse temps-réel anti-spam ... Donc si vous cherchez un vrai accès à Internet, même grâce à un VPN, je vous conseille plutôt les FAI associatifs de la Fédération FDN qui offrent une telle garantie par design, sans fluctuation ni d'exceptions.

En supplément, "depuis Internet", je souhaite que mon client VPN soit vu avec une IP distincte de celle attribuée à mon dédié. Il faut donc utiliser une IP failover et faire en sorte que le trafic sorte et entre de notre dédié par cette IP.

Table des matières

Sources

Je clos le suspens de suite : ce billet est une arnaque ! On trouve les morceaux de config OpenVPN à peu près partout : OpenVPN sur le Wiki Debian.org, le man d'OpenVPN est bien fait et le petit morceau de conf pour sortir du VPN avec une IP failover est aussi documenté un peu partout : Utiliser un VPN avec une IP failover chez kdecherf (git)-[blog] %. Pour ceux qui cherchent comment monter un serveur VPN sur leur dédié OVH sans utiliser une IP failover : il suffit de faire un SNAT sur l'IP principale du serveur ou, au pire, un masquerade sur ce qui sort par eth0.

Néanmoins, parce que je vous aime bien, je vais vous donner ma config.

Trêve de blabla, on commence !

Au niveau d'OVH, c'est très simple : il suffit de commander une IP failover, de la payer et d'attendre un peu qu'elle soit active. Rien de plus. Pas besoin de définir une MAC virtuelle, rien.

Point to point et chiffrement symétrique

Dans un premier temps, on va utiliser une topologie point à point avec un chiffrement symétrique.

On installe OpenVPN sur le serveur et sur le client :

apt-get install openvpn

Pour l'instant, je ne veux pas qu'OpenVPN démarre tout seul au boot donc je lance la commande suivante sur le client et sur le serveur :

update-rc.d -f openvpn remove

On crée la config côté serveur (dans /etc/openvpn/server.conf par exemple) :

proto udp
port 1194
dev tun
 
mode p2p
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 198.18.0.2
script-security 2
up /etc/openvpn/up.sh
plugin /usr/lib/openvpn/openvpn-down-root.so /etc/openvpn/down.sh

Quelques remarques :

  • Pour le choix tun/tap (route/bridge) : comme je n'ai pas besoin des fonctionnalités des tap (broadcast, donc possibilité d'utiliser NetBios/SMB, possibilité d'utiliser d'autres protocoles de couches 3, ... voir : What is the difference between bridging and routing? sur OpenVPN.net et Bridging vs. routing sur OpenVPN community), j'ai choisi le mode router/tun pour profiter de l'avantage d'avoir moins d'overhead.
  • Pour l'adressage du serveur et du client, j'ai pris le bloc 198.18.0.0/30 qui est englobé dans 198.18.0.0/15 qui est un préfixe réservé à l'IANA pour les tests et qui n'est donc pas annoncé globalement. L'idée est d'éviter une éventuelle collision. Comme ce préfixe est méconnu et que les réseaux auxquels je me connecte sont adressés soit en public soit avec les préfixes du RFC 1918, je suis sûr d'être tranquille. Notez qu'il serait peut-être plus pertinent de prendre un préfixe /30 dans 10.0.0.0/8. La probabilité de se connecter à un réseau existant utilisant ce bloc me paraît faible.
  • « plugin /usr/lib/openvpn/openvpn-down-root.so » permet de lancer le script de fin avec les droits root alors même qu'OpenVPN a, comme on le lui a demandé, perdu, dès la fin de l'initialisation, les droits root pour ceux de l'utilisateur openvpn et du groupe openvpn.

On crée la config côté client (dans /etc/openvpn/client.conf, par exemple) :

proto udp
remote <IP PRINCIPALE DU SERVEUR> 1194
dev tun
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
ifconfig 198.18.0.2 198.18.0.1
route-gateway 198.18.0.1
redirect-gateway def1

Sur le serveur, on crée les deux scripts. D'abord /etc/openvpn/up.sh :

#!/bin/bash
 
ifconfig br0:1 <IP FAILOVER> netmask 255.255.255.255 broadcast <IP FAILOVER>
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 198.18.0.0/30 ! -d 198.18.0.0/30 -j SNAT --to-source <IP FAILOVER>
iptables -t nat -A PREROUTING -d <IP FAILOVER> -j DNAT --to-destination 198.18.0.2

Puis le script /etc/openvpn/down.sh :

#!/bin/bash
 
echo 0 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -D POSTROUTING -s 198.18.0.0/30 ! -d 198.18.0.0/30 -j SNAT --to-source <IP FAILOVER>
iptables -t nat -D PREROUTING -d <IP FAILOVER> -j DNAT --to-destination 198.18.0.2
ifconfig br0:1 down

Quelques remarques :

  • J'ai configuré l'alias sur br0 car j'utilise un bridge pour attribuer des IP failover à mes conteneurs LXC (voir Utiliser LXC sur un Kimsufi). Si vous n'avez pas de VM ni de conteneurs LXC ou autre montage du même type, alors il faudra faire l'alias sur eth0.
  • Mapper 198.18.0.2 à l'IP failover suffit amplement. Néanmoins, j'ai voulu jouer la prudence au cas où le serveur émettrait avec 198.18.0.1 car je ne suis pas sur mon réseau mais sur celui d'OVH. Ce scénario ne devrait jamais se produire mais bon ... Au moins comme ça, ça sortira avec l'IP failover. Si je ne vois rien passer, OVH m'indiquera un problème avec cette IP et je saurai alors que le problème vient du VPN sans passer 5h à essayer de comprendre. Indiquer un /30 est par facilité : on pourrait utiliser les ip set pour indiquer les 2 adresses IP précises.
  • Le DNAT n'est clairement pas obligatoire. C'est pour le fun ... Si l'on veut héberger des services derrière ce VPN ...
  • Pour ceux qui cherchent comment monter un serveur VPN sur leur dédié OVH sans utiliser une IP failover, seule la première règle iptables change :
    iptables -t nat -D POSTROUTING -s 198.18.0.0/30 ! -d 198.18.0.0/30 -j SNAT --to-source <IP PRINCIPALE DU SERVEUR>

    Forcement, vous ne pouvez alors pas faire de DNAT complet mais uniquement pour certains ports que vous voulez rediriger vers votre client VPN.

  • Enfin, selon votre configuration, il faudra autoriser le transfert de paquet depuis/vers le VPN. Cela se fait dans chaîne FORWARD. 😉

On rend ces scripts exécutables :

chmod u+x /etc/openvpn/up.sh /etc/openvpn/down.sh

On crée l'utilisateur openvpn :

adduser openvpn --disabled-login --no-create-home --shell /bin/false

Sur le serveur ou sur le client, on génère la clé cryptographique :

openvpn --genkey --secret /etc/openvpn/vpn-static.key

Il faudra la transférer à l'autre partie via scp puis vérifier les droits : root:root 400.

Enfin, selon votre configuration, il faudra autoriser OpenVPN dans votre firewall, en entrée et en sortie. Aussi bien sur le client que sur le serveur.

Il est l'heure de tester (sur le client et le serveur) :

service openvpn restart

Normalement, le client doit pouvoir pinguer 198.18.0.1 et sortir sur Internet par le VPN. L'adresse IP "vue depuis Internet" doit être l'IP failover.

Pour ceux que ça intéresse, voici les configurations équivalentes mais en utilisant des tap. Pour le serveur :

proto udp
port 1194
dev tap
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3

persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 255.255.255.252
script-security 2
up /etc/openvpn/up.sh
plugin /usr/lib/openvpn/openvpn-down-root.so "/etc/openvpn/down.sh"

Pour le client :

proto udp
remote <IP PRINCIPALE DU SERVEUR> 1194
dev tap
 
cipher AES-256-CBC
secret /etc/openvpn/vpn-static.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
ifconfig 198.18.0.2 255.255.255.252
route-gateway 198.18.0.1
redirect-gateway def1

Point to point et chiffrement asymétrique

L'inconvénient principal du chiffrement symétrique est qu'il ne permet pas le perfect forward secrecy. Bien que, comme je l'ai déjà dit, mon VPN me servira principalement à faire des tests et ne transmettra pas mes secrets les plus noirs, je me dis qu'il peut être intéressant de faire une topologie p2p avec du chiffrement asymétrique, for ze fun.

Attention à ne pas mal interpréter mes propos : le chiffrement du tunnel reste symétrique. Simplement, lors de l'initialisation, le client et le serveur échangent une clé temporaire pour réaliser le chiffrement symétrique du tunnel. C'est cet échange initial qui se fait en utilisant la cryptographie asymétrique.

Pour cette partie, on va suivre d'encore plus près le tutoriel du wiki Debian.org. Reportez-vous à la partie « TLS-enabled VPN ». La génération du matériel cryptographique est identique : seules les configurations d'OpenVPN sont différentes.

Voici la configuration du serveur :

proto udp
port 1194
dev tun
 
mode p2p
tls-server
 
ca      /etc/openvpn/easy-rsa/keys/ca.crt
cert    /etc/openvpn/easy-rsa/keys/server.crt
key     /etc/openvpn/easy-rsa/keys/server.key
dh      /etc/openvpn/easy-rsa/keys/dh1024.pem
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 198.18.0.2
script-security 2
up /etc/openvpn/up.sh
plugin /usr/lib/openvpn/openvpn-down-root.so /etc/openvpn/down.sh

ÉDIT du 12/01/2014 à 13h10 : Il faudra prévoir la révocation des certificats clients. C'est toujours utile en cas de perte ou de compromission, surtout si vous distribuez des accès (oui oui, le titre du billet cause d'un VPN unipersonnel mais bon) ... Fin de l'édit

La configuration du client :

proto udp
remote <IP PRINCIPALE DU SERVEUR> 1194
dev tun
 
tls-client
 
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/guigui.crt
key /etc/openvpn/easy-rsa/keys/guigui.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
ifconfig 198.18.0.2 198.18.0.1
route-gateway 198.18.0.1
redirect-gateway def1

Il est l'heure de tester (sur le client et le serveur) :

service openvpn restart

Normalement, le client doit toujours pouvoir pinguer 198.18.0.1 et sortir sur Internet par le VPN. L'adresse IP "vue depuis Internet" doit toujours être l'IP failover.

La même mais en mieux

Le résultat obtenu jusque-là est pas mal. Il manque un dernier truc : pour l'instant le script up est exécuté au démarrage d'OpenVPN, juste après la création de l'interface tun. Le down est exécuté à l'arrêt d'OpenVPN. J'aimerais que les scripts soient exécutés uniquement lorsque le client se connecte/déconnecte de mon VPN. Comme ça, le reste du temps je n'ai pas de la config qui ne sert à rien en train de tourner. Pas de forward, pas de NAT, l'IP failover ne répond pas aux requêtes, ...

Cela est possible en utilisant les directives client-connect/client-disconnect d'OpenVPN. Mais elles sont disponibles uniquement en mode serveur. Ce mode requiert l'utilisation d'un /29 au minimum donc on va avoir un peu de configuration à changer.

On s'occupe d'abord des configurations OpenVPN. Celle du serveur :

proto udp
port 1194
 
dev tun
 
mode server
max-clients 1
 
tls-server
ca      /etc/openvpn/easy-rsa/keys/ca.crt
cert    /etc/openvpn/easy-rsa/keys/server.crt
key     /etc/openvpn/easy-rsa/keys/server.key
dh      /etc/openvpn/easy-rsa/keys/dh1024.pem
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
 
user openvpn
group openvpn
 
ifconfig 198.18.0.1 198.18.0.2
ifconfig-pool 198.18.0.5 198.18.0.6
route 198.18.0.0 255.255.255.240
push "route 198.18.0.1"
 
script-security 2
client-connect "/usr/bin/sudo -u root /etc/openvpn/up.sh"
client-disconnect "/usr/bin/sudo -u root /etc/openvpn/down.sh"

La configuration du client :

proto udp
port 1194
 
dev tun
 
client
remote <IP PRINCIPALE DU SERVEUR> 1194
 
tls-client
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/guigui.crt
key /etc/openvpn/easy-rsa/keys/guigui.key
 
comp-lzo
 
verb 3
 
persist-key
persist-tun
ping 30
ping-exit 90
explicit-exit-notify
 
user openvpn
group openvpn
 
redirect-gateway def1

On remarque l'utilisation de sudo pour lancer les scripts à la connexion/déconnexion. En effet, lorsque le client se connectera ou se déconnectera, il y aura longtemps que le serveur OpenVPN aura perdu les droits root. Il faut donc rajouter une ligne au fichier /etc/sudoers :

openvpn		ALL=(root)	NOPASSWD:/etc/openvpn/up.sh,/etc/openvpn/down.sh

Les scripts d'up et de down changent aussi : on NAT le /29 et on redirige le DNAT sur la bonne IP :

#!/bin/bash
 
echo 0 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -D POSTROUTING -s 198.18.0.0/29 ! -d 198.18.0.0/29 -j SNAT --to-source <IP FAILOVER>
iptables -t nat -D PREROUTING -d <IP FAILOVER> -j DNAT --to-destination 198.18.0.6
ifconfig br0:1 down

Les mêmes modifications s'appliquent au script de déconnexion. Je vous laisse faire les changements. 🙂

Voilà, on arrive à la fin de ce que je voulais vous montrer.