Le BGP est un protocole de routage dynamique qui se base historiquement sur la confiance. En théorie, n’importe qui peut plus ou moins annoncer n’importe quoi, et ça sera pris en compte. En pratique, les peerings BGP sont protégés par des prefix-lists afin de ne propager que ce qui est réellement voulu. Mais cela implique que chaque opérateur soit extrêment consciencieux, et cela étant bien sûr impossibles, nous pouvons recenser denombreux incidents. De nombreuses techniques de préventions ont donc été mises en place au fur et à mesure, et l’ASPA est complémentaires à celles déjà en place. C’est discuté en paragraphe 9 « Comparison to Other Technologies ».
Nous avons vu arriver en février 2012 l’une de ces technique : les Route Origin Authorizations (ROAs) par laRFC 6482. En se basant la Resource Public Key Infrastructure (RPKI) nous pouvons cryptographiquement signer la relation entre un préfixe et le (ou les) AS source ; ainsi, un préfixe annoncé par erreur par un AS se verra très fortement filtré. Cela ne protège par contre pas des attaques volontaires car il suffit de prepend le bon AS lors de l’annonce afin de faire correspondre la source avec le ROA et tout se passera comme si de rien n’était. Petit aparté sur les chiffres : à la fin janvier 2025 je vois 519213 ROAs sur 1001519 annonces (en IPv4), soit un peu plus de la moitié. Je n’ai pas de métriques sur les ASes qui vérifient ou non les ROAs, mais il est clair qu’un transitaire qui ne le fait pas en 2025 est à fuir comme la peste.
Depuis 2019 une discussion est actuellement ouverte à l’IETF afin de pouvoir étendre la RPKI à la vérification de l’AS path au lieu d’uniquement l’AS source, c’estl’ASPA (Autonomous System Provider Authorization). L’idée est qu’un AS va publier quels sont ses fournisseurs, et si un préfixe (signé en ROA évidemment) est vu avec un chemin qui n’a rien à voir avec la choucroute, l’annonce sera rejetée. C’est un peu à voir comme la version 2 des IRRs que l’on trouve dans les whois d’AS.
Tout ceci étant encore en draft, il n’est pas encore possible de publier des entrées ASPA depuis une CA hébergée directement par un RIR, il faut l’héberger soi-même (par exemple aveckrill). Cela limite donc grandement l’adoption, ce qui fait que nous avons une table comprenantseulement 81 entrées. Du côté de la vérification, le support a été ajouté avecbird 2.16, et pour la diffusion des entrées, le support via RTR a été ajouté avecroutinator 0.14.1. Ce n’est pas un hasard si je suivais l’évolution de ces deux logiciels, car ils font partie de la stack du second serveur de routes deBreizh-IX.
Breizh-IX est un point d’échange rennais dont je m’occupe. Comme l’immense majorité des points d’échange nous proposons des serveurs de route, et comme j’aime les choses bien faites je préfère éviter d’annoncer des routes fallacieuses aux membres de l’IX. Pour se faire nous avions déjà mis en place les choses de base comme la vérification des ROAs et la génération de listes de préfixes pour chaque membre, mais aussi des choses moins connues comme la vérification de l’attribut Only to Customer (OTC). Aujourd’hui un pas de plus est fait avec l’ajout d’ASPA.
La mise en place de la partie validation est très simple, il suffit de compiler routinator en version 0.14.1, d’installer les binaires, d’ajouterenable-aspa = true
dans le fichier de configuration et de redémarrer le daemon.
Maintenant que notre serveur RTR (ici routinator) supporte ASPA, il ne reste plus qu’à dire à bird de le prendre en compte.
Après avoir également compilé et installé la version 2.16, il faut créer une table en plus qui servira à stocker les entrées ASPA (en plus de celles pour les ROAs IPv4 et IPv6), et de l’ajouter au protocole RPKI qui correspond au routinator :
roa4 table r4;roa6 table r6;aspa table at;protocol rpki rpki_conan {remote "conan.grifon.fr";roa4 { table r4; };roa6 { table r6; };aspa { table at; };}
Ensuite au reload, le protocole devrait être négocié en version 2 et la nouvelle table va se remplir :
[root@rs2 ~]# birdcBIRD 2.16 ready.bird> show protocols all rpki_conanName Proto Table State Since Inforpki_conan RPKI --- up 20:59:54.811 Established Cache server: 89.234.186.8 Status: Established Transport: Unprotected over TCP Protocol version: 2 Session ID: 12256 Serial number: 19 Last update: before 504.687 s Refresh timer : 648.312/1153 Retry timer : --- Expire timer : 6695.312/7200 Channel roa4 State: UP Table: r4 Preference: 100 Input filter: ACCEPT Output filter: REJECT Routes: 519235 imported, 0 exported, 83 preferred Route change stats: received rejected filtered ignored accepted Import updates: 519247 0 0 0 519247 Import withdraws: 12 0 --- 0 12 Export updates: 0 0 0 --- 0 Export withdraws: 0 --- --- --- 0 Channel roa6 State: UP Table: r6 Preference: 100 Input filter: ACCEPT Output filter: REJECT Routes: 126571 imported, 0 exported, 31 preferred Route change stats: received rejected filtered ignored accepted Import updates: 126589 0 0 0 126589 Import withdraws: 18 0 --- 0 18 Export updates: 0 0 0 --- 0 Export withdraws: 0 --- --- --- 0 Channel aspa State: UP Table: at Preference: 100 Input filter: ACCEPT Output filter: REJECT Routes: 81 imported, 0 exported, 81 preferred Route change stats: received rejected filtered ignored accepted Import updates: 81 0 0 0 81 Import withdraws: 0 0 --- 0 0 Export updates: 0 0 0 --- 0 Export withdraws: 0 --- --- --- 0
Nous pouvons maintenant utiliser les données de cette table dans les filtres d’entrée, grâce à la fonction intégréeaspa_check
:
# https://www.ietf.org/archive/id/draft-ietf-sidrops-aspa-verification-20.html#name-algorithm-for-upstream-pathcase aspa_check(at, bgp_path, true) {ASPA_INVALID:igp_metric = 12;reject "Invalid ASPA:", net, bgp_path;ASPA_VALID:igp_metric = 10;ASPA_UNKNOWN:igp_metric = 11;}
Le premier paramètre de la fonction est la table depuis laquelle nous tirons les informations, le second est l’AS path à évaluer et la dernière est l’algorithme de vérification à utiliser. Les deux premiers étant assez évidents, je vais uniquement m’attarder sur le dernier.
Dans la version actuelle d’ASPA (draft v20), il existe deux algorithmes : un pour évaluer des routes upstream, et un autre pour les routes downstream. Il est explicitement écrit qu’un serveur de route doit utiliser l’algorithme upstream :
The upstream verification algorithm described here is applied when a route is received from a Customer or Peer, or is received by an RS from an RS-client, or is received by an RS-client from an RS.
6.2. Algorithm for Upstream Paths
Les routes ayant un seul AS sur le chemin sont automatiquement considérées comme valides, et bird respecte bien cela :
bird> show route all where igp_metric = 10Table master4:45.94.17.0/24 unicast [bgp_20766_185_1_89_28 21:04:43.510] * (100) [AS20766i]via 185.1.89.28 on vtnet1Type: BGP univigp_metric: 10BGP.origin: IGPBGP.as_path: 20766BGP.next_hop: 185.1.89.28BGP.local_pref: 100BGP.community: (20766,1)BGP.ext_community: BGP.large_community: (206165, 100, 0)45.67.83.0/24 unicast [bgp_207910_185_1_89_26 21:04:43.617] * (100) [AS207910i]via 185.1.89.26 on vtnet1Type: BGP univigp_metric: 10BGP.origin: IGPBGP.as_path: 207910BGP.next_hop: 185.1.89.26BGP.local_pref: 100BGP.ext_community: BGP.large_community: (206165, 100, 0)185.204.199.0/24 unicast [bgp_211733_185_1_89_39 21:04:45.785] * (100) [AS211733i]via 185.1.89.39 on vtnet1Type: BGP univigp_metric: 10BGP.origin: IGPBGP.as_path: 211733BGP.next_hop: 185.1.89.39BGP.local_pref: 100BGP.ext_community: BGP.large_community: (206165, 100, 0)193.222.128.0/24 unicast [bgp_34019_185_1_89_36 21:04:48.454] * (100) [AS34019i]via 185.1.89.36 on vtnet1Type: BGP univigp_metric: 10BGP.origin: IGPBGP.as_path: 34019BGP.next_hop: 185.1.89.36BGP.med: 75BGP.local_pref: 100BGP.community: (34019,34019)BGP.ext_community: BGP.large_community: (206165, 100, 0)37.157.128.0/21 unicast [bgp_57943_185_1_89_19 21:04:43.486] * (100) [AS57943?]via 185.1.89.19 on vtnet1Type: BGP univigp_metric: 10BGP.origin: IncompleteBGP.as_path: 57943BGP.next_hop: 185.1.89.19BGP.local_pref: 100BGP.ext_community: BGP.large_community: (206165, 100, 0)[…]
Nous n’avons pas de route invalide et les autres routes ont bien le statut inconnu :
bird> show route all filtered where igp_metric = 12bird> bird> show route all where igp_metric = 11Table master4:37.60.157.0/24 unicast [bgp_34019_185_1_89_36 21:04:44.346] * (100) [AS201080i]via 185.1.89.36 on vtnet1Type: BGP univigp_metric: 11BGP.origin: IGPBGP.as_path: 34019 201080BGP.next_hop: 185.1.89.36BGP.med: 75BGP.local_pref: 100BGP.community: (34019,20108) (34019,64512) (65512,20001)BGP.ext_community: BGP.large_community: (206165, 100, 0)195.190.3.0/24 unicast [bgp_34019_185_1_89_36 21:04:48.670] * (100) [AS47612i]via 185.1.89.36 on vtnet1Type: BGP univigp_metric: 11BGP.origin: IGPBGP.as_path: 34019 35600 47612BGP.next_hop: 185.1.89.36BGP.med: 75BGP.local_pref: 100BGP.community: (34019,35600) (34019,64512)BGP.ext_community: BGP.large_community: (206165, 100, 0)45.67.83.0/24 unicast [bgp_204092_185_1_89_13 21:04:43.555] (100) [AS207910i]via 185.1.89.13 on vtnet1Type: BGP univigp_metric: 11BGP.origin: IGPBGP.as_path: 204092 207910BGP.next_hop: 185.1.89.13BGP.local_pref: 100BGP.community: (64496,200)BGP.ext_community: BGP.large_community: (204092, 100, 200) (206165, 100, 0) unicast [bgp_34019_185_1_89_36 21:04:44.684] (100) [AS207910i]via 185.1.89.36 on vtnet1Type: BGP univigp_metric: 11BGP.origin: IGPBGP.as_path: 34019 207910BGP.next_hop: 185.1.89.36BGP.med: 75BGP.local_pref: 100BGP.community: (34019,20791) (34019,64512) (65512,20001)BGP.ext_community: BGP.large_community: (206165, 100, 0)185.20.5.0/24 unicast [bgp_34019_185_1_89_36 21:04:47.976] * (100) [AS56648i]via 185.1.89.36 on vtnet1Type: BGP univigp_metric: 11BGP.origin: IGPBGP.as_path: 34019 35600 56648BGP.next_hop: 185.1.89.36[…]
Si nous étions en train de vérifier les annonces d’un fournisseur, nous aurions dû appliquer l’algorithme downstream. Pourquoi avoir deux algorithmes ? Car lors d’une relation client-fournisseur il n’est pas possible de savoir si le fournisseur a appris la route sur un peering ou via l’un des transits de l’AS source (qu’ils auraient en communs). Nous ne pouvons donc pas strictement rechercher si l’un des ASes dans l’entrée ASPA est dans l’AS path, et on se contente alors d’estimer le statut de la route par rapport à longueur de l’AS path.
Par exemple, si on prend une route vers telenor (AS2119) du point de vue de gitoyen (AS20766)
Pour un ordinateur il n’est pas possible de deviner quels sont les chemins légitime ou pas. En tant qu’humain, comme j’ai géré le peering de gandi avant que ça ne tourne au FullBullshit™ et que je connais le peering manager de ielo, je sais que ces deux ASes ont un peering avec telenor, et donc que ces deux chemin sont fiables. Cette théorie se confirme avec un mtr vers l’une des IPs du range qui montre que ça passe par l’AMS-IX :
grifon@gitoyen01:~$ mtr -bzwe 148.122.1.1Start: 2025-01-22T23:16:35+0000HOST: gitoyen01.ring.nlnog.net Loss% Snt Last Avg Best Wrst StDev 1. AS20766 x-ray.probe.gitoyen.net (80.67.163.243) 0.0% 10 0.3 0.2 0.2 0.3 0.0 2. AS20766 vodka.gitoyen.net (80.67.168.7) 0.0% 10 0.9 0.6 0.4 1.3 0.3 3. AS20766 gandi-pa3.gitoyen.net (80.67.168.149) 0.0% 10 0.7 0.7 0.5 1.5 0.3 4. AS??? ti9000b400.ti.telenor.net (80.249.209.192) 0.0% 10 10.7 9.9 9.3 13.0 1.2 5. AS2119 ti3003c400-ae13-0.ti.telenor.net (146.172.105.37) 0.0% 10 29.1 29.7 29.1 31.3 0.9 [MPLS: Lbl 9197 TC 0 S u TTL 1] 6. AS??? ??? 100.0 10 0.0 0.0 0.0 0.0 0.0 7. AS2119 ti0001b400-ae0-0.ti.telenor.net (146.172.105.49) 0.0% 10 29.0 29.9 28.9 38.0 2.8 8. AS2119 148.122.9.50 0.0% 10 30.2 29.4 29.2 30.2 0.3 9. AS2119 tix01c01-fge1-17.tix.telenor.net (148.122.2.81) 0.0% 10 29.2 29.3 29.2 29.6 0.1 [MPLS: Lbl 29 TC 0 S u TTL 1] [MPLS: Lbl 648 TC 0 S u TTL 1] 10. AS2119 tix01d01-fge7-1.tix.telenor.net (148.122.2.66) 0.0% 10 29.3 29.6 29.2 32.1 0.9 [MPLS: Lbl 648 TC 0 S u TTL 1] 11. AS2119 148.122.205.225 0.0% 10 30.0 29.9 29.3 32.7 1.0 12. AS2119 tix01d01-ec2-v100.tix.telenor.net (148.122.205.25) 0.0% 10 31.2 29.6 29.1 31.2 0.6 13. AS2119 part1.online.no (148.122.1.1) 0.0% 10 29.3 29.4 29.3 29.8 0.1
L’IRR de l’AS2119 nous dit que les deux upstreams connus sont telia et level3 et dtag est censé être un peering :
alarig@x280 ~ % whois AS2119 | grep 'accept ANY'import: from AS1299 action pref=100; accept ANYimport: from AS3356 action pref=100; accept ANYalarig@x280 ~ % whois AS2119 | grep 3320import: from AS3320 action pref=100; accept AS3320:AS-DTAGexport: to AS3320 announce AS-TELENOR
Si telenor publiait une entrée ASPA, elle contiendrait a priori les ASes 1299 et 3356. La route que nous voyons ici via telia aurait alors le statut valide. Les deux routes par gandi ou ielo auraient le statut inconnu. Nous pouvons par contre légitimement nous demander si le chemin via Hopus et DTAG est entièrement légitime ou non ; mais les IRRs étant principalement là à titre indicatif, nous ne pouvons pas nous baser dessus à 100%. Bien que DTAG soit un tier 1 de piètre qualité, il serait tout de même étonnant qu’ils réannoncent les préfixes d’un opérateur national sans que ce ne soit l’un de leur clients, même si ce n’est jamais à exclure non plus. En effet, dans ce cas présent la politique tarifaire d’Hopus fait que DTAG gagne de l’argent sur le trafic qui rentre dans son réseau sur ce port. Afin d’augmenter le volume dudit trafic, ils peuvent très bien ré-annoncer leurs peers en plus de leurs clients, bien que ça soit contraire aux pratiques communes.
Pour éviter d’avoir plein d’applications de messagerie instantanée sur mon téléphone, je bridge tout dans matrix et je n’utilise directement que matrix. Ma machine matrix était sur une infra d’hypervision que je n’ai plus vraiment envie d’utiliser, et j’ai depuis une plus grosse …
Cet article est écrit en collaboration avecAxel Viala. Tout au long de l’article nous parlons de serveurs faisant autorité, les révolveurs n’ayant pas ce cas à gérer.
Sur un nom de domaine, on peut se retrouver avec des sous-domaines vides mais ayant des enfants. Nous appelons cela …
Si vous lisez ce blog, vous savez sûrement qu’un riche mégalomane étasunien a racheté twitter, et qu’on en attendait pas moins de son mode de gestion. Cela a entraîné un exode vers mastodon, qui ronronnait tranquillement dans son coin jusqu’ici.
Je vais ici partager les différentes actions …
Internet étant truffé de machines plus ou moins vérolées qui scannent le monde entier, j’ai eu envie de les bloquer à l’échelle complète de mon réseau ; un genre de fail2ban2bgp.
Avec netfilter il n’existe pas de mécanisme pour avoir des règles dynamiques, et donc pas de moyen …
Par défaut, la configuration de net-snmpd ne remonte pas le constructeur et le modèle d’un serveur, ce qui fait que LibreNMS (ou Observium) vont afficher « Generic x86 64-bit » là où on pourrait avoir « Dell Inc. [PowerEdge R510] » ou « HP [ProLiant DL320e Gen8] », ce qui rend plus facile l’inventorisation …
Suite à l’annonce de Valère d’arrêter les services hostux, et donc l’instance mastodon, j’ai décidé de monter la mienne. La principale raison est que je n’ai pas trouvé d’autre instance en Europe avec un TLSA. Je ne vais pas ici expliquer toute l’installation …
Depuis quelques temps, le support de la souris est activé par défaut sur certaines applications CLI, notamment vim. Ceci empêche d’utiliser le presse-papier « clic milieu » et ne sert en outre à rien, c’est donc fort ennuyeux.
J’ai un peu cherché comment désactiver le support de la souris …
Quand on fait partie de la DFZ, on peut en gros annoncer n’importe quel préfixe tant que ça passe les filtres de nos pairs, et on est censé leur faire plus ou moins confiance. Sauf que croire encore à ce système de la confiance en 2020, c’est aussi …
Il m’arrive encore de jouer avec des routeurs soft, et comme à chaque fois il faut bricoler pour avoir ce que l’on veut, ici avoir une table ifAlias correcte. À une époque je le faisais avec FreeBSD, et j’avais trouvé la parade en utilisant un proxy vers …