Principe du blackhole BGP

Lorsqu'on subit une attaque de type DDoS qui remplit les tuyaux, il ne suffit pas simplement de jeter les paquets quand ils arrivent chez nous. En effet, les paquets encombrent quand même les tuyaux entre nos transitaires et nous, et consomment des ressources sur nos routeurs.

Il est possible de dire à nos transitaires de jeter certains paquets, dans leur propre réseau. Ainsi, ces paquets n'atteignent même plus notre réseau. À leur tour, nos transitaires peuvent indiquer à leurs propres transitaires de jeter les paquets, et ainsi de suite.

Pour celui, on utilise BGP, grâce à des communautés définies à l'avance avec nos transitaires. L'idée est d'annoncer une route plus spécifique avec une communauté indiquant « Merci de jeter les paquets destinés à ce préfixe IP ». Typiquement, on annonce un /32 en IPv4, pour une attaque ciblant une IP particulière.

Cette technique porte le doux nom de RTBH (pour « Remote Triggered Black Hole »).

Mise en place dans Grenode

Pour cela, nous réutilisons en fait la configuration Bird de Gitoyen, disponible ici : https://code.ffdn.org/gitoyen/bird-config/

Marquer les routes à blackholer

Le but est d'avoir un moyen simple de blackholer un préfixe IP. Avec la configuration de Bird décrite ci-dessous, il est possible de blackholer un préfixe (et donc de propager ce blackhole aux transitaires) simplement en ajoutant une route dans le noyau :

ip route add blackhole 192.0.2.50/32

Pour ce faire, on définit un moyen d'identifier les routes à blackholer dans Bird. Le plus simple est d'utiliser une communauté, locale à notre AS. Pour Grenode, on utilise (51083,666).

Ensuite, on dit à Bird de faire le lien entre le blackhole d'une route dans le noyau (via ip route), et le marquage avec la communauté (51083,666) dans Bird :

filter import_kernel {
    if dest = RTD_BLACKHOLE && is_within_grenode() then {
        bgp_community.add ((51083,666));
        accept;
    }
    accept;
}

filter export_kernel {
    if filter( bgp_community, [ (51083,666) ]).len >0 then {
        dest = RTD_BLACKHOLE;
        accept;
    }
    accept;
}

protocol kernel {
    learn;
    scan time 86400;
    import filter import_kernel;
    export filter export_kernel;
    persist;
}

Bien noter que la correspondance est bidirectionnelle : si une route est marquée avec la communauté (51083,666) dans Bird, elle sera insérée dans le noyau comme une route blackhole. Dans un AS avec plusieurs routeurs, cela permet de propager la route blackhole à l'ensemble des routeurs de l'AS. Ainsi, il y a seulement besoin de rajouter une route blackhole dans le noyau d'un des routeurs, pour que tous les routeurs de l'AS se mettent à blackholer ce préfixe !

Attention, pour IPv6 sous Linux, il faut utiliser RTD_UNREACHABLE plutôt que RTD_BLACKHOLE, puisque la notion de route blackhole n'existe pas (curieusement) en IPv6 sous Linux.

Propager le blackhole aux transitaires

Jusqu'ici, le blackhole reste local. Malheureusement, chaque opérateur a une convention différente sur quelle communauté utiliser. Il faut donc maintenir une traduction des communauté à utiliser.

Comme chez gitoyen, on utilise une fonction un peu compliquée comme filtre d'export BGP, voir https://code.ffdn.org/gitoyen/bird-config/-/blob/master/etc/local/bird/common/bgp-filters.conf

À la fin de cette fonction, on définit la correspondance entre les communautés :

# blackhole management
if filter(bgp_community, [ (51083,666) ]).len > 0 then {
    case AS {
        # Gitoyen
        20766:  bgp_community.add ((20766,9999));
        # Ielo
        29075:  bgp_community.add ((29075,0));
        # EDX
        198435: bgp_community.add ((0,666));
        # By default, don't announce the blackhole route, because it would be
        # interpreted as a regular route.  Since it is more specific, it
        # would attract traffic, which is precisely the opposite of the
        # desired behaviour when blackholing...
        else:   return false;
    }
}

Ainsi, notre communauté de blackhole (51083,666) sera traduite au moment de l'annonce au transitaire, selon sa convention de communauté. La communauté de blackhole d'un opérateur donné est généralement indiquée dans ses entrées whois (par exemple whois AS29075), ou peut être trouvée sur certains sites comme http://www.onesc.net/communities/. En dernier recours, il suffit de demander au transitaire en question.

Attention, comme indiqué en commentaire, il vaut mieux ne pas annoncer les routes de blackhole aux pairs qui ne gèrent pas le RTBH (typiquement sur les peerings, et aux transitaires qui ne font pas de RTBH ou dont on ne connaît pas la convention). Sinon, ces routes seront interprétées comme des routes normales...