BGP Route Filtering : Prefix Lists, Filtres AS-Path, Rejet des Bogons et GTSM

17 min de lecture·Matthieu·bgpbird2frrroute-filteringnetwork-securityrpkimanrs|

Référence pratique pour durcir les sessions BGP sur Linux avec des filtres en couches. Couvre les prefix-lists, le rejet des bogons, les filtres AS-path, les limites max-prefix et le GTSM en syntaxe BIRD2 et FRR avec étapes de vérification.

RPKI valide qu'un AS est autorisé à originer un préfixe. Il ne protège pas contre les fuites de routes (route leaks), l'injection de bogons, l'explosion de table depuis un pair mal configuré, ou les paquets BGP usurpés depuis des hôtes non adjacents. Cet article couvre les filtres qui gèrent tout ce que RPKI ne couvre pas.

Chaque filtre est présenté en syntaxe BIRD2 et FRR, avec des exemples IPv4 et IPv6. Chaque section explique ce que le filtre empêche, donne la configuration, puis montre comment vérifier qu'il fonctionne.

Si vous n'avez pas encore configuré la validation d'origine RPKI, faites-le d'abord. Voir RPKI ROA pour BGP : créer des ROAs, valider les routes dans BIRD2 et FRR.

Pour la configuration de base d'une session BGP, voir Configuration BGP avec BIRD2 sur un VPS Linux (BIRD2) ou Configuration BGP avec FRRouting sur un VPS Linux (FRR). Cet article suppose que vous avez déjà une session BGP fonctionnelle et que vous souhaitez la durcir.

Pourquoi BGP a-t-il besoin de filtrage de routes au-delà de RPKI ?

Le filtrage de routes BGP consiste à accepter ou rejeter des annonces BGP en fonction du préfixe, de l'AS-path ou des attributs d'origine. Il prévient les fuites de routes, les détournements de préfixes (prefix hijacks), l'injection de bogons et l'explosion de la table de routage. RPKI couvre uniquement la validation d'origine. Sans filtres supplémentaires, votre routeur est exposé à toutes les autres catégories d'incidents BGP.

Voici ce que chaque couche empêche :

Type de filtre Menace bloquée Ce qui se passe sans lui
Rejet de préfixes bogons Espace privé/réservé dans le DFZ Votre routeur achemine le trafic vers l'espace RFC 1918. Black hole.
Rejet de petits préfixes Détournements plus-spécifiques (/25+, /49+) Un attaquant annonce un /32 couvrant une partie d'un /24 que vous acceptez. Sa route gagne par longest match.
Filtrage bogon AS-path ASNs privés/réservés dans les chemins Des routes avec AS 65535 ou AS 4200000000 s'infiltrent dans votre table. Vous acheminez du trafic basé sur des chemins invalides.
Limite de longueur AS-path Attaques par inflation de chemin, gonflement de table Un pair envoie des routes avec 50+ sauts AS. Votre mémoire se remplit d'entrées inutiles.
Limite max-prefix Fuites de routes, surcharge de session Un pair laisse fuiter une table complète (1M+ préfixes) dans votre session. Votre routeur manque de mémoire.
GTSM (sécurité TTL) Paquets BGP usurpés depuis des hôtes distants Un attaquant à plusieurs sauts de distance injecte des paquets BGP OPEN ou UPDATE dans votre session.
Validation d'origine RPKI Détournements d'origine Quelqu'un origine votre préfixe depuis son AS. Déjà couvert dans RPKI ROA pour BGP : créer des ROAs, valider les routes dans BIRD2 et FRR.

Des incidents réels montrent pourquoi chaque couche compte. En 2008, Pakistan Telecom a annoncé des routes plus-spécifiques pour les préfixes de YouTube afin d'appliquer un ordre de censure domestique. Ces routes ont fuité vers des fournisseurs de transit internationaux et ont mis YouTube en black hole globalement pendant des heures. Un filtre bogon ou petits-préfixes chez les fournisseurs de transit aurait écarté ces annonces. En juin 2019, un petit FAI en Pennsylvanie (AS396531) a accidentellement fait fuiter des routes pour Cloudflare, Amazon et Linode vers Verizon, qui les a propagées globalement. Une limite max-prefix aurait terminé la session avant que la fuite ne se propage.

Comment filtrer les préfixes bogons dans BIRD2 et FRR ?

Les préfixes bogons sont des plages d'adresses qui ne doivent jamais apparaître dans la table de routage globale. Ils incluent l'espace privé RFC 1918, les adresses link-local, les plages de documentation et les blocs réservés. Les accepter signifie que votre routeur va tenter d'acheminer du trafic vers des adresses qui n'ont pas de destination globale légitime, créant des black holes.

Préfixes bogons IPv4

Préfixe Référence Objet
0.0.0.0/8 RFC 1122 Réseau « This »
10.0.0.0/8 RFC 1918 Espace privé
100.64.0.0/10 RFC 6598 NAT de niveau opérateur
127.0.0.0/8 RFC 1122 Loopback
169.254.0.0/16 RFC 3927 Link-local
172.16.0.0/12 RFC 1918 Espace privé
192.0.2.0/24 RFC 5737 TEST-NET-1
192.88.99.0/24 RFC 7526 Relais 6to4 déprécié
192.168.0.0/16 RFC 1918 Espace privé
198.18.0.0/15 RFC 2544 Benchmarking
198.51.100.0/24 RFC 5737 TEST-NET-2
203.0.113.0/24 RFC 5737 TEST-NET-3
224.0.0.0/4 RFC 5771 Multicast
240.0.0.0/4 RFC 1112 Réservé pour usage futur

Préfixes bogons IPv6

Préfixe Référence Objet
::/8 Divers Compatible IPv4, loopback, mappé
100::/64 RFC 6666 Discard-only
2001:2::/48 RFC 5180 Benchmarking BMWG
2001:10::/28 RFC 4843 ORCHID
2001:db8::/32 RFC 3849 Documentation
3fff::/20 RFC 9637 Documentation
2002::/16 RFC 7526 6to4 déprécié
3ffe::/16 RFC 3701 Ancien 6bone
5f00::/16 RFC 9602 SRv6 SIDs
fc00::/7 RFC 4193 Unicast local unique
fe80::/10 RFC 4291 Unicast link-local
fec0::/10 RFC 3879 Site-local déprécié
ff00::/8 RFC 4291 Multicast

Ces listes changent quand l'IANA alloue de nouveaux blocs ou déprécie d'anciens. La référence bogon de Team Cymru fournit un flux BGP de fullbogons (espace non alloué + réservé) qui se met à jour automatiquement. Pour les listes statiques, consultez le NLNOG BGP Filter Guide périodiquement.

Filtre bogon BIRD2

# /etc/bird/bogons.conf - include this from your main bird.conf

define BOGON_PREFIXES_V4 = [
    0.0.0.0/8+,
    10.0.0.0/8+,
    100.64.0.0/10+,
    127.0.0.0/8+,
    169.254.0.0/16+,
    172.16.0.0/12+,
    192.0.2.0/24+,
    192.88.99.0/24+,
    192.168.0.0/16+,
    198.18.0.0/15+,
    198.51.100.0/24+,
    203.0.113.0/24+,
    224.0.0.0/4+,
    240.0.0.0/4+
];

define BOGON_PREFIXES_V6 = [
    ::/8+,
    0100::/64+,
    2001:2::/48+,
    2001:10::/28+,
    2001:db8::/32+,
    3fff::/20+,
    2002::/16+,
    3ffe::/16+,
    5f00::/16+,
    fc00::/7+,
    fe80::/10+,
    fec0::/10+,
    ff00::/8+
];

function reject_bogon_prefixes_v4() {
    if (net ~ BOGON_PREFIXES_V4) then {
        print "REJECTED bogon prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

function reject_bogon_prefixes_v6() {
    if (net ~ BOGON_PREFIXES_V6) then {
        print "REJECTED bogon prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

Le + après chaque préfixe signifie « ce préfixe et tous ses plus-spécifiques ». 10.0.0.0/8+ correspond à 10.0.0.0/8, 10.0.0.0/9, 10.1.0.0/16, etc. Cela attrape un attaquant annonçant un /24 dans l'espace RFC 1918.

Appelez ces fonctions dans votre filtre d'import :

filter import_from_upstream_v4 {
    reject_bogon_prefixes_v4();
    # ... other filters ...
    accept;
}

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ipv4 {
        import filter import_from_upstream_v4;
        export none;
    };
}

Filtre bogon FRR

! IPv4 bogon prefix-list
ip prefix-list BOGONS_v4 seq 10 deny 0.0.0.0/8 le 32
ip prefix-list BOGONS_v4 seq 20 deny 10.0.0.0/8 le 32
ip prefix-list BOGONS_v4 seq 30 deny 100.64.0.0/10 le 32
ip prefix-list BOGONS_v4 seq 40 deny 127.0.0.0/8 le 32
ip prefix-list BOGONS_v4 seq 50 deny 169.254.0.0/16 le 32
ip prefix-list BOGONS_v4 seq 60 deny 172.16.0.0/12 le 32
ip prefix-list BOGONS_v4 seq 70 deny 192.0.2.0/24 le 32
ip prefix-list BOGONS_v4 seq 80 deny 192.88.99.0/24 le 32
ip prefix-list BOGONS_v4 seq 90 deny 192.168.0.0/16 le 32
ip prefix-list BOGONS_v4 seq 100 deny 198.18.0.0/15 le 32
ip prefix-list BOGONS_v4 seq 110 deny 198.51.100.0/24 le 32
ip prefix-list BOGONS_v4 seq 120 deny 203.0.113.0/24 le 32
ip prefix-list BOGONS_v4 seq 130 deny 224.0.0.0/4 le 32
ip prefix-list BOGONS_v4 seq 140 deny 240.0.0.0/4 le 32
ip prefix-list BOGONS_v4 seq 999 permit 0.0.0.0/0 le 32

! IPv6 bogon prefix-list
ipv6 prefix-list BOGONS_v6 seq 10 deny ::/8 le 128
ipv6 prefix-list BOGONS_v6 seq 20 deny 100::/64 le 128
ipv6 prefix-list BOGONS_v6 seq 30 deny 2001:2::/48 le 128
ipv6 prefix-list BOGONS_v6 seq 40 deny 2001:10::/28 le 128
ipv6 prefix-list BOGONS_v6 seq 50 deny 2001:db8::/32 le 128
ipv6 prefix-list BOGONS_v6 seq 60 deny 3fff::/20 le 128
ipv6 prefix-list BOGONS_v6 seq 70 deny 2002::/16 le 128
ipv6 prefix-list BOGONS_v6 seq 80 deny 3ffe::/16 le 128
ipv6 prefix-list BOGONS_v6 seq 90 deny 5f00::/16 le 128
ipv6 prefix-list BOGONS_v6 seq 100 deny fc00::/7 le 128
ipv6 prefix-list BOGONS_v6 seq 110 deny fe80::/10 le 128
ipv6 prefix-list BOGONS_v6 seq 120 deny fec0::/10 le 128
ipv6 prefix-list BOGONS_v6 seq 130 deny ff00::/8 le 128
ipv6 prefix-list BOGONS_v6 seq 999 permit ::/0 le 128

Les clauses le 32 (IPv4) et le 128 (IPv6) correspondent au préfixe et à tous ses plus-spécifiques, comme l'opérateur + dans BIRD2. La dernière ligne permit à seq 999 autorise tout ce qui n'a pas été refusé.

Appliquez la prefix-list à votre voisin :

router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 address-family ipv4 unicast
  neighbor 198.51.100.1 prefix-list BOGONS_v4 in
 address-family ipv6 unicast
  neighbor 2001:db8::1 prefix-list BOGONS_v6 in

Attention. Cette entrée 2001:db8::/32 est dans la liste bogon. N'utilisez pas des adresses de documentation en production. Remplacez les adresses de voisin ci-dessus par vos vraies IPs de pairs.

Rejet des préfixes trop petits

Les routes plus petites que /24 (IPv4) ou /48 (IPv6) ne se propagent pas de façon fiable dans le DFZ global. Plus important, les accepter vous expose à des attaques par détournement plus-spécifique. Filtrez-les en entrée.

BIRD2 :

function reject_small_prefixes_v4() {
    if (net.len > 24) then {
        print "REJECTED too-small prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

function reject_small_prefixes_v6() {
    if (net.len > 48) then {
        print "REJECTED too-small prefix: ", net, " path: ", bgp_path;
        reject;
    }
}

FRR :

! Add to the same prefix-lists, before the final permit
ip prefix-list BOGONS_v4 seq 150 deny 0.0.0.0/0 ge 25 le 32
ipv6 prefix-list BOGONS_v6 seq 140 deny ::/0 ge 49 le 128

Cela attrape tout préfixe plus spécifique que /24 (IPv4) ou /48 (IPv6). Placez ces lignes avant les entrées seq 999 permit.

Comment les filtres AS-path empêchent-ils les fuites de routes ?

Les filtres AS-path inspectent la séquence des systèmes autonomes qu'une route a traversés. Ils détectent trois problèmes : les ASNs bogons qui ne doivent jamais apparaître dans un chemin, les chemins excessivement longs qui indiquent des fuites ou des manipulations, et les ASNs privés qui n'ont pas été supprimés avant l'annonce.

Filtrage des ASNs bogons

Les ASNs bogons sont des numéros réservés qui ne doivent jamais apparaître dans un chemin BGP sur l'internet public :

Plage ASN Référence Objet
0 RFC 7607 Réservé
23456 RFC 4893 AS_TRANS (transition AS 4 octets)
64496-64511 RFC 5398 Documentation/exemples
64512-65534 RFC 6996 Usage privé (16 bits)
65535 RFC 7300 Dernier ASN 16 bits
65536-65551 RFC 5398 Documentation/exemples (32 bits)
65552-131071 IANA Réservé
4200000000-4294967294 RFC 6996 Usage privé (32 bits)
4294967295 RFC 7300 Dernier ASN 32 bits

BIRD2 :

define BOGON_ASNS = [
    0,
    23456,
    64496..64511,
    64512..65534,
    65535,
    65536..65551,
    65552..131071,
    4200000000..4294967294,
    4294967295
];

function reject_bogon_asns()
int set bogon_asns;
{
    bogon_asns = BOGON_ASNS;
    if (bgp_path ~ bogon_asns) then {
        print "REJECTED bogon ASN in path: ", net, " path: ", bgp_path;
        reject;
    }
}

L'opérateur bgp_path ~ bogon_asns vérifie si un ASN du chemin est membre de l'ensemble. Un seul ASN bogon n'importe où dans le chemin déclenche le rejet.

FRR :

bgp as-path access-list BOGON_ASNS deny _0_
bgp as-path access-list BOGON_ASNS deny _23456_
bgp as-path access-list BOGON_ASNS deny _6449[6-9]_
bgp as-path access-list BOGON_ASNS deny _6450[0-9]_
bgp as-path access-list BOGON_ASNS deny _6451[01]_
bgp as-path access-list BOGON_ASNS deny _64[5-9][1-9][2-9]_
bgp as-path access-list BOGON_ASNS deny _6[5-9][0-9][0-9][0-9]_
bgp as-path access-list BOGON_ASNS deny _[1-9][0-9][0-9][0-9][0-9]_
bgp as-path access-list BOGON_ASNS deny _[1-3][0-9][0-9][0-9][0-9][0-9]_
bgp as-path access-list BOGON_ASNS permit .*

FRR utilise la correspondance regex sur la chaîne AS-path. Les underscores _ correspondent aux délimiteurs AS-path (espace, début, fin). Cette approche regex est moins précise que la correspondance par ensemble d'entiers de BIRD2. Pour une approche plus simple mais moins granulaire, utilisez une route-map avec l'as-path access-list :

route-map IMPORT_FILTER deny 10
 match as-path BOGON_ASNS
route-map IMPORT_FILTER permit 100

router bgp 64500
 address-family ipv4 unicast
  neighbor 198.51.100.1 route-map IMPORT_FILTER in

Note : les patterns regex ci-dessus sont simplifiés. Faire correspondre la plage complète des ASNs privés 32 bits (4200000000-4294967294) avec regex est source d'erreurs. Pour les déploiements en production, utilisez bgpq4 pour générer des prefix-lists et des filtres AS-path depuis les données IRR, ce qui est plus précis et automatisable.

Limitation de la longueur AS-path

Un chemin BGP légitime dépasse rarement 10-15 ASNs. Les chemins plus longs indiquent généralement une fuite de route, une manipulation de chemin, ou un prepending mal configuré. Fixez une limite stricte.

BIRD2 :

function reject_long_paths() {
    if (bgp_path.len > 25) then {
        print "REJECTED long AS-path (", bgp_path.len, "): ", net, " path: ", bgp_path;
        reject;
    }
}

FRR :

bgp as-path access-list LONG_PATHS deny ^([0-9]+_){25,}
bgp as-path access-list LONG_PATHS permit .*

route-map IMPORT_FILTER deny 20
 match as-path LONG_PATHS

Une limite de 25 est conservative. La plupart des routes légitimes ont des chemins inférieurs à 10. Si vous recevez une table complète, inspectez les chemins les plus longs dans votre RIB avant de choisir un seuil :

# BIRD2
birdc 'show route where bgp_path.len > 15' | head -20

# FRR
vtysh -c "show ip bgp regexp ^([0-9]+_){15,}"

Suppression des ASNs privés en sortie

Si vous utilisez iBGP avec des ASNs privés en interne, assurez-vous qu'ils ne fuitent pas vers vos upstreams.

BIRD2 :

filter export_to_upstream_v4 {
    # Strip private ASNs before advertising
    bgp_path.delete([64512..65534, 4200000000..4294967294]);
    # ... your export policy ...
    accept;
}

FRR :

router bgp 64500
 address-family ipv4 unicast
  neighbor 198.51.100.1 remove-private-AS all

Le mot-clé all supprime chaque ASN privé même lorsque des ASNs publics sont présents dans le chemin. Sans all, FRR ne supprime les ASNs privés que si le chemin entier ne contient que des ASNs privés.

Quelle est la limite max-prefix correcte pour une session BGP ?

Une limite max-prefix est une soupape de sécurité qui ferme une session BGP si un pair annonce plus de préfixes que le seuil configuré. Elle empêche l'explosion de la table de routage quand un pair laisse accidentellement fuiter une table complète ou est compromis. Sans elle, un seul pair mal configuré peut pousser votre routeur hors mémoire.

Fixez la limite en fonction de ce que vous attendez de chaque pair :

Type de pair Préfixes attendus (IPv4) Limite suggérée Limite suggérée (IPv6)
Upstream table complète ~1 200 000 (mars 2026) 1 500 000 300 000
Table partielle / pair IXP Variable 1,5x le nombre actuel 1,5x le nombre actuel
Client single-homed 1-10 50 50
Client multi-homed 10-100 200 200

Vérifiez la taille actuelle de la table complète sur bgp.potaroo.net avant de fixer les limites upstream. Fixez la limite à environ 1,2x le nombre attendu pour absorber la croissance normale sans faux déclenchements.

BIRD2 :

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ipv4 {
        import limit 1500000 action restart;
        import filter import_from_upstream_v4;
        export none;
    };
}

protocol bgp customer_v4 {
    local as 64500;
    neighbor 203.0.113.10 as 64502;
    ipv4 {
        import limit 50 action disable;
        import filter import_from_customer_v4;
        export filter export_to_customer_v4;
    };
}

BIRD2 propose trois actions quand la limite est atteinte :

  • action restart - ferme la session et redémarre après un délai. Idéal pour les upstreams.
  • action disable - ferme et désactive le protocole. Nécessite un birdc enable manuel pour restaurer. Idéal pour les clients où atteindre la limite indique un problème sérieux.
  • action block - stoppe l'import de nouvelles routes mais maintient la session. Utile si vous souhaitez garder les routes existantes pendant l'investigation.

FRR :

router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 address-family ipv4 unicast
  neighbor 198.51.100.1 maximum-prefix 1500000 90 restart 5

 neighbor 203.0.113.10 remote-as 64502
 address-family ipv4 unicast
  neighbor 203.0.113.10 maximum-prefix 50 80

Dans FRR, maximum-prefix 1500000 90 restart 5 signifie : avertir à 90% (1 350 000 préfixes), fermer à 1 500 000, et redémarrer la session après 5 minutes. Sans le mot-clé restart, FRR ferme la session et nécessite un clear bgp neighbor manuel pour la restaurer.

Vérifier la configuration max-prefix

# BIRD2 - check current prefix count and limit
birdc show protocols all upstream_v4 | grep -E "Routes|Limit"

# FRR - check prefix count per neighbor
vtysh -c "show ip bgp summary"

La sortie affiche le nombre actuel de préfixes à côté de la limite configurée. Si le nombre est proche de la limite, augmentez le seuil avant qu'elle se déclenche.

Comment GTSM protège-t-il les sessions BGP contre les paquets usurpés ?

GTSM (Generalized TTL Security Mechanism, RFC 5082) restreint les paquets BGP acceptés aux pairs directement connectés en vérifiant le champ TTL/Hop Limit. Quand il est activé, les paquets BGP sont envoyés avec TTL 255. Le récepteur rejette tout paquet BGP avec un TTL inférieur à 254 (pour un pair directement connecté). Comme les routeurs décrémentent le TTL à chaque saut, un attaquant à plus d'un saut ne peut pas envoyer des paquets qui arrivent avec TTL 255.

Cela bloque l'injection distante de TCP RST, les SYN floods ciblant le port BGP 179, et les paquets BGP OPEN/UPDATE forgés depuis des attaquants non adjacents. GTSM est mutuellement exclusif avec eBGP multihop sur la même session. Les deux pairs doivent l'activer.

BIRD2 :

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ttl security yes;
    ipv4 {
        import limit 1500000 action restart;
        import filter import_from_upstream_v4;
        export none;
    };
}

FRR :

router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 neighbor 198.51.100.1 ttl-security hops 1

hops 1 signifie que le pair doit être exactement à 1 saut (directement connecté). Fixez cette valeur pour correspondre au nombre de sauts réels. Pour les pairs eBGP sur un fabric de commutation IXP, hops 1 est correct. Pour les sessions multihop (par exemple BGP sur un tunnel GRE), vous ne pouvez pas utiliser GTSM. Utilisez plutôt l'authentification MD5 :

Alternative MD5 BIRD2 :

protocol bgp multihop_peer {
    local as 64500;
    neighbor 198.51.100.5 as 64503;
    multihop 2;
    password "your-md5-secret";
    # ...
}

Alternative MD5 FRR :

router bgp 64500
 neighbor 198.51.100.5 remote-as 64503
 neighbor 198.51.100.5 ebgp-multihop 2
 neighbor 198.51.100.5 password your-md5-secret

Stockez le mot de passe MD5 dans un fichier avec permissions restreintes (chmod 600) plutôt que dans la configuration principale. Pour FRR, référencez-le depuis /etc/frr/frr.conf qui doit déjà être en 640 appartenant à frr:frr. Pour BIRD2, gardez /etc/bird/bird.conf en 640 appartenant à bird:bird.

Quels filtres BGP MANRS exige-t-il ?

MANRS (Mutually Agreed Norms for Routing Security) définit des actions de référence pour les opérateurs réseau. Les actions 1, 3 et 4 sont requises pour devenir participant MANRS. Voici comment les filtres de cet article correspondent aux actions MANRS.

Action 1 : Empêcher la propagation d'informations de routage incorrectes.

C'est l'action de filtrage principale. Elle exige des filtres explicites au niveau des préfixes sur les connexions clients et recommande des filtres AS-path pour prévenir les fuites de routes.

Filtre de cet article Couverture MANRS Action 1
Filtrage prefix-list (bogons) Empêche d'annoncer/accepter l'espace réservé
Rejet des petits préfixes Bloque les routes plus-spécifiques qui indiquent des détournements
Filtrage bogon AS-path Rejette les routes avec des ASNs privés/réservés
Limites max-prefix Stoppe la propagation de tables complètes fuitées
Filtres de préfixes clients Pas dans cet article. Construisez-les par client depuis IRR avec bgpq4.

Action 2 (recommandée) : Empêcher le trafic avec des adresses source usurpées.

Ce n'est pas un filtre BGP. Il s'agit de la validation d'adresse source BCP 38/84 (uRPF). Hors du périmètre de cet article mais tout aussi important.

Action 3 : Faciliter la communication opérationnelle globale.

Maintenez vos coordonnées à jour dans PeeringDB et votre base de données RIR. Ce n'est pas un filtre, mais les opérateurs qui utilisent des filtres corrects tendent aussi à maintenir leurs informations de contact.

Action 4 : Faciliter l'information de routage à l'échelle globale.

Publiez votre politique de routage dans IRR (RIPE, RADB) avec des objets RPSL. Créez des ROAs pour RPKI. Cela permet à vos pairs de construire des filtres de préfixes précis pour vos annonces.

La combinaison filtrage bogon (préfixes + ASNs) + rejet petits préfixes + limites max-prefix + prefix-lists clients couvre l'Action 1 MANRS. Ajoutez RPKI (RPKI ROA pour BGP : créer des ROAs, valider les routes dans BIRD2 et FRR) et l'enregistrement IRR pour l'Action 4.

Tout assembler : un filtre d'import complet

Voici un filtre d'import combiné utilisant toutes les techniques ci-dessus.

Filtre d'import complet BIRD2

# /etc/bird/filters.conf

include "/etc/bird/bogons.conf";  # BOGON_PREFIXES_V4, BOGON_PREFIXES_V6, BOGON_ASNS

function import_checks_v4() {
    # 1. Reject bogon prefixes
    if (net ~ BOGON_PREFIXES_V4) then {
        print "REJECT bogon prefix: ", net, " ", bgp_path;
        reject;
    }

    # 2. Reject too-small prefixes
    if (net.len > 24) then {
        print "REJECT small prefix: ", net, " ", bgp_path;
        reject;
    }

    # 3. Reject bogon ASNs in path
    if (bgp_path ~ [0, 23456, 64496..64511, 64512..65534, 65535,
                     65536..65551, 65552..131071,
                     4200000000..4294967294, 4294967295]) then {
        print "REJECT bogon ASN: ", net, " ", bgp_path;
        reject;
    }

    # 4. Reject excessively long paths
    if (bgp_path.len > 25) then {
        print "REJECT long path: ", net, " ", bgp_path;
        reject;
    }

    # 5. Reject RPKI invalid (if RPKI is configured)
    if (roa_check(rpki4, net, bgp_path.last) = ROA_INVALID) then {
        print "REJECT RPKI invalid: ", net, " ", bgp_path;
        reject;
    }
}

filter import_upstream_v4 {
    import_checks_v4();
    accept;
}

protocol bgp upstream_v4 {
    local as 64500;
    neighbor 198.51.100.1 as 64501;
    ttl security yes;
    ipv4 {
        import limit 1500000 action restart;
        import filter import_upstream_v4;
        export none;
    };
}

Filtre d'import complet FRR

! /etc/frr/frr.conf

! --- Prefix lists (bogons + small prefix rejection) ---
ip prefix-list IMPORT_V4 seq 10 deny 0.0.0.0/8 le 32
ip prefix-list IMPORT_V4 seq 20 deny 10.0.0.0/8 le 32
ip prefix-list IMPORT_V4 seq 30 deny 100.64.0.0/10 le 32
ip prefix-list IMPORT_V4 seq 40 deny 127.0.0.0/8 le 32
ip prefix-list IMPORT_V4 seq 50 deny 169.254.0.0/16 le 32
ip prefix-list IMPORT_V4 seq 60 deny 172.16.0.0/12 le 32
ip prefix-list IMPORT_V4 seq 70 deny 192.0.2.0/24 le 32
ip prefix-list IMPORT_V4 seq 80 deny 192.88.99.0/24 le 32
ip prefix-list IMPORT_V4 seq 90 deny 192.168.0.0/16 le 32
ip prefix-list IMPORT_V4 seq 100 deny 198.18.0.0/15 le 32
ip prefix-list IMPORT_V4 seq 110 deny 198.51.100.0/24 le 32
ip prefix-list IMPORT_V4 seq 120 deny 203.0.113.0/24 le 32
ip prefix-list IMPORT_V4 seq 130 deny 224.0.0.0/4 le 32
ip prefix-list IMPORT_V4 seq 140 deny 240.0.0.0/4 le 32
ip prefix-list IMPORT_V4 seq 150 deny 0.0.0.0/0 ge 25 le 32
ip prefix-list IMPORT_V4 seq 999 permit 0.0.0.0/0 le 32

! --- AS-path filters (bogon ASNs + path length) ---
bgp as-path access-list BOGON_ASNS deny _0_
bgp as-path access-list BOGON_ASNS deny _23456_
bgp as-path access-list BOGON_ASNS deny _6449[6-9]_
bgp as-path access-list BOGON_ASNS deny _6450[0-9]_
bgp as-path access-list BOGON_ASNS deny _6451[01]_
bgp as-path access-list BOGON_ASNS permit .*

bgp as-path access-list LONG_PATHS deny ^([0-9]+_){25,}
bgp as-path access-list LONG_PATHS permit .*

! --- Route-map combining all checks ---
route-map IMPORT_UPSTREAM deny 10
 match as-path BOGON_ASNS
route-map IMPORT_UPSTREAM deny 20
 match as-path LONG_PATHS
route-map IMPORT_UPSTREAM permit 100

! --- BGP neighbor configuration ---
router bgp 64500
 neighbor 198.51.100.1 remote-as 64501
 neighbor 198.51.100.1 ttl-security hops 1
 address-family ipv4 unicast
  neighbor 198.51.100.1 prefix-list IMPORT_V4 in
  neighbor 198.51.100.1 route-map IMPORT_UPSTREAM in
  neighbor 198.51.100.1 maximum-prefix 1500000 90 restart 5

Dans FRR, la prefix-list et la route-map sont toutes les deux évaluées. La prefix-list s'exécute en premier et rejette les préfixes bogons et les petits préfixes. Les routes qui passent la prefix-list arrivent ensuite à la route-map, qui vérifie les filtres AS-path. Les deux doivent autoriser la route pour qu'elle soit acceptée.

Comment vérifier que les filtres de routes BGP fonctionnent ?

Les filtres ne sont utiles que s'ils rejettent vraiment ce qu'ils doivent. Vérifiez après chaque modification.

Vérification BIRD2

# Check what routes were rejected (requires print statements in filters)
grep "REJECT" /var/log/bird.log | tail -20

# Show the routing table with filter details
birdc show route filtered

# Show routes from a specific protocol
birdc show route protocol upstream_v4

# Count accepted routes per protocol
birdc show protocols all upstream_v4 | grep "Routes:"

# Test a specific prefix against your import filter
birdc show route for 10.0.0.0/8 all

La commande show route filtered affiche les routes qui ont été reçues mais rejetées par le filtre d'import. Si votre filtre bogon fonctionne, vous devriez voir zéro préfixe bogon dans la table acceptée et les bogons reçus dans la table filtrée.

Vérification FRR

# Show accepted routes from a neighbor
vtysh -c "show ip bgp neighbors 198.51.100.1 received-routes"

# Show routes filtered by inbound policy
vtysh -c "show ip bgp neighbors 198.51.100.1 filtered-routes"

# Check the prefix count per neighbor
vtysh -c "show ip bgp summary"

# Test if a specific prefix is accepted
vtysh -c "show ip bgp 10.0.0.0/8"

# Check max-prefix status
vtysh -c "show ip bgp neighbors 198.51.100.1" | grep -A2 "Maximum prefix"

Pour que received-routes et filtered-routes fonctionnent, vous devez activer la soft-reconfiguration inbound sur le voisin :

router bgp 64500
 address-family ipv4 unicast
  neighbor 198.51.100.1 soft-reconfiguration inbound

Cela utilise de la mémoire supplémentaire (stocke toutes les routes reçues avant filtrage). Sur une session table complète, c'est environ 2x la mémoire pour le RIB. Sur des routeurs en production avec peu de RAM, utilisez-le sélectivement.

Vérification externe

Vos filtres protègent votre propre RIB. Pour vérifier ce que vous annoncez aux autres, utilisez des looking glasses externes :

  • bgp.tools - recherchez votre ASN pour voir quels préfixes vous annoncez globalement
  • RIPE RIS - service d'information de routage BGP, affiche la visibilité des routes sur les collecteurs
  • Hurricane Electric BGP Toolkit - recherche de préfixes et d'ASN

Vérifiez après des changements de filtres pour confirmer que vous ne filtrez pas accidentellement des routes légitimes ou que vous ne fuitez pas des routes que vous ne devriez pas annoncer.

Pour la surveillance automatisée, voir Surveiller les annonces BGP avec BGPalerter sur Linux.

Comparaison de syntaxe BIRD2 vs FRR

Référence rapide pour passer d'un daemon à l'autre :

Type de filtre BIRD2 FRR
Préfixe bogon if (net ~ BOGON_PREFIXES) then reject ip prefix-list BOGONS deny 10.0.0.0/8 le 32
Petit préfixe if (net.len > 24) then reject ip prefix-list X deny 0.0.0.0/0 ge 25 le 32
ASN bogon if (bgp_path ~ [64512..65534]) then reject bgp as-path access-list X deny _64[5-9][1-9][2-9]_
Longueur de chemin if (bgp_path.len > 25) then reject bgp as-path access-list X deny ^([0-9]+_){25,}
Max-prefix import limit 50 action disable neighbor X maximum-prefix 50
GTSM ttl security yes neighbor X ttl-security hops 1
Auth MD5 password "secret" neighbor X password secret
Suppression AS privé bgp_path.delete([64512..65534]) neighbor X remove-private-AS all
Appliquer le filtre import filter name neighbor X prefix-list/route-map name in

BIRD2 utilise une seule fonction de filtre qui combine toutes les vérifications. FRR répartit les vérifications entre prefix-lists (correspondance de préfixes), as-path access-lists (correspondance de chemins) et route-maps (combinant plusieurs conditions de correspondance). Les deux approches fonctionnent. L'approche BIRD2 est plus lisible pour des politiques complexes. L'approche FRR est plus familière aux opérateurs Cisco.

Quelque chose s'est mal passé ?

Session fermée par max-prefix : Vérifiez journalctl -u bird ou journalctl -u frr pour le message d'atteinte de limite. Augmentez la limite si le pair a légitimement grandi, ou investiguez s'il s'agit d'une fuite. Dans BIRD2, réactivez avec birdc enable upstream_v4. Dans FRR, effacez avec vtysh -c "clear bgp 198.51.100.1".

Routes légitimes filtrées : Vérifiez birdc show route filtered ou vtysh -c "show ip bgp neighbors X filtered-routes" pour voir ce qui a été rejeté. Cause fréquente : votre liste bogon est trop agressive, ou votre seuil de petits préfixes rejette des /25 légitimes d'un client. Ajustez le filtre et rechargez : birdc configure ou vtysh -c "write memory" puis systemctl reload frr.

GTSM rejetant un pair valide : Les deux côtés doivent activer GTSM. Si un côté l'a activé et l'autre non, les paquets arrivent avec TTL 1 et sont rejetés par le côté avec GTSM activé. Vérifiez avec tcpdump -i eth0 port 179 -v et regardez la valeur TTL.

Filtres sans effet après modification : Dans BIRD2, lancez birdc configure pour recharger. Dans FRR, si vous modifiez une prefix-list ou une route-map, déclenchez une réinitialisation douce : vtysh -c "clear bgp 198.51.100.1 in". Sans cela, les routes existantes dans le RIB ne sont pas réévaluées contre le nouveau filtre.

Logs : Les deux daemons journalisent via systemd journal par défaut.

# BIRD2
journalctl -u bird -f

# FRR
journalctl -u frr -f

Les instructions print dans les fonctions de filtre BIRD2 écrivent dans le log bird. Dans FRR, activez la journalisation debug avec debug bgp updates dans vtysh pour un dépannage temporaire. Désactivez-la quand vous avez terminé car elle génère de grandes quantités de logs.


Cet article fait partie de la série BGP et Bring Your Own IP sur un VPS : le guide complet.