lunedì 16 maggio 2016

BGP & SDN : Terza puntata - BGP FlowSpec

Dopo la seconda puntata, continua la saga "BGP & SDN" (il vecchio e il bambino, come la famosa canzone di Guccini, resa famosa anche dai Nomadi). La terza puntata (che al momento non so dirvi se sarà l'ultima, di sicuro al prossimo post passo a MPLS) è in realtà una evoluzione della seconda, dove abbiamo trattato il BGP RTBH, ampiamente utilizzato soprattutto dagli ISP, per contrastare attacchi di tipo DDoS. 

Come visto nel post precedente (seconda puntata), il BGP RTBH prende una sola azione, a fronte di un attacco DDoS: lo scarto dei pacchetti, siano essi diretti verso l'Host attaccato (destination-based RTBH) o quelli provenienti dall'attaccante (source-based RTBH).

L'evoluzione del BGP RTBH è il BGP FlowSpec, standardizzato nella RFC 5575Dissemination of Flow Specification Rules, Agosto 2009. L'estensione a IPv6 è ancora in versione draftdraft-ietf-idr-flow-spec-v6-07 - Dissemination of Flow Specification Rules for IPv6.

Il BGP FlowSpec ha tre differenze fondamentali rispetto al BGP RTBH:
  • Richiede il supporto di una nuova address-family, mentre il BGP RTBH non richiede alcuna funzionalità BGP aggiuntiva ma è basato solo su funzioni "classiche" del BGP.
  • Può prendere azioni di contrasto a livello molto più granulare, non solo sugli indirizzi IP sorgente dell'attaccante e destinazione dell'attaccato, come invece fa il BGP RTBH. L'azione di contrasto può essere anche su singoli micro-flussi (da qui il nome FlowSpec, che è un abbreviazione di Flow Specification).
  • Ha a disposizione più azioni per contrastare gli attacchi DDoS, non solo lo scarto dei pacchetti.
Come sempre, cercherò prima di illustrare a grandi linee la "teoria" e quindi illustrerò un esempio pratico. In ogni caso, BGP RTBH e BGP FlowSpec sono basati sulla stessa idea: a partire da un controller centralizzato, si inviano ai router di edge (router PE), via annunci BGP, delle informazioni (regole) che consentono di mitigare gli effetti degli attacchi DDoS. Qualora si voglia inviare regole diverse a PE diversi, è necessario attivare più sessioni BGP, una per ciascun PE.

BGP FLOWSPEC : LA "TEORIA"
Gli aspetti chiave della "teoria" del BGP FlowSpec sono essenzialmente la codifica dei flussi di traffico su cui agire, e le azioni da intraprendere su di questi. Il primo aspetto è codificato attraverso NLRI di una nuova address-family, mentre il secondo utilizza nuove Extended Community BGP.

La RFC 5575 citata sopra, definisce due nuove address-family, identificate dai seguenti codici AFI/SAFI:
  • AFI/SAFI = 1/133 : indica l'address-family per l'utilizzo in ambito IPv4 unicast. 
  • AFI/SAFI = 1/134 : indica l'address-family per l'utilizzo in ambito L3VPN IPv4 unicast.
Il draft citato sopra poi estende queste due address-family all'utilizzo in ambito IPv6. Come noto il codice AFI di IPv6 è 2, per cui le due nuove address-family per IPv6 hanno codici AFI/SAFI rispettivamente 2/133 e 2/134. In questo post non tratterò l'estensione a IPv6, che comunque non aggiunge nulla di concettuale.

La codifica dei flussi avviene attraverso la definizione di un nuovo NLRI, trasportato dal classico attributo MP_REACH_NLRI (e MP_UNREACH_NLRI nel caso di ritiro) specificato nella ben nota RFC 4760 - Multiprotocol Extensions for BGP-4, Gennaio 2007. In questo attributo non viene utilizzato il campo  Network Address of Next Hop, poiché non significativo. Il nuovo NLRI infatti, non trasporta informazioni di raggiungibilità sui prefissi, ed è per questa ragione che non sono necessarie informazioni sul Next-Hop. Il relativo campo non viene quindi aggiunto nell'attributo MP_REACH_NLRI (il trucco è mettere a zero il valore del campo Length of Next Hop Network Address).

Il formato generico del nuovo NLRI è riportato nella figura seguente, tratta dalla RFC 5575.



Il campo length indica la lunghezza, espressa in 1 o 2 byte, dell'intero NLRI. Solo per curiosità, se la lunghezza del NLRI fosse inferiore o al più uguale a 240 byte (= 0xf0 in esadecimale), verrebbe utilizzata la codifica a singolo byte (es. se il NLRI avesse lunghezza 160 byte, il campo length sarebbe lungo un solo byte e avrebbe il valore esadecimale 0xa0). Nel caso in cui invece la lunghezza fosse maggiore di 240 byte, si utilizza la codifica a due byte, con il primo nibble della notazione esadecimale fisso e pari a f, e i restanti tre pari al valore della lunghezza (es. se il NLRI avesse lunghezza 241 byte, il campo length sarebbe lungo due byte e avrebbe il valore esadecimale 0xf0f1). Ne consegue che la lunghezza massima di un NLRI è pari a 4.095 byte.

Il valore del NLRI, ossia l'informazione trasportata, ossia la specifica del flusso (Flow Specification), consiste di varie sotto-componenti opzionali. Un pacchetto appartiene al flusso specificato se e solo se appartiene a tutte (AND logico) le sotto-componenti specificate nel NLRI. Ciascuna sotto-componente ha una codifica in cui il primo byte costituisce il tipo di sotto-componente, e il resto il contenuto. La RFC 5575 ha definito ben 12 sotto-componenti, di cui specificherò l'intera codifica solo per quelle più significative. Per le altre indicherò solo nome e tipo e vi rimando per il resto alla RFC 5575. Una nota importante è che in un NLRI le sotto-componenti sono si opzionali, ma vanno elencate secondo un ordine ben preciso basato sul valore numerico del tipo.

Tipo 1 : Destination Prefix





Tipo 2 : Source Prefix
Stessa codifica del tipo 1










Tipo 3 : IP Protocol ID
Contiene più coppie del tipo <operatore, valore>, utilizzate per specificare il campo Protocol ID. La codifica è un po' complessa ed è riportata nella figura seguente.











Il campo opzioni è formato da varie flag, il cui significato è il seguente:
  • e - pari a 1 nell'ultima opzione e 0 nelle precedenti.
  • a - il valore 1 indica l'operazione di AND logico tra i vari valori di Protocol ID, il valore 0 l'operazione di OR logico.
  • len - se len = 0 il valore successivo è codificato con 1 byte, se len = 1 in due byte. Per questa codifica è sempre len = 0 (vedi codifica successiva per il caso len =1).
  • lt - operatore "less than".
  • gt - operatore "greater than".
  • eq - operatore "equal".
L'esempio della figura seguente riporta la codifica di un Protocol ID che è o TCP (Protocol ID = 6) o UDP (Protocol ID = 17).









Tipo 4 : Port Number
Stessa codifica del tipo 3, sostituendo Protocol ID con Port Number. Il campo Port Number può essere di 1 o 2 byte. Indica un insieme di porte o sorgente o destinazione. La figura seguente riporta un esempio di codifica della  porta 53.









Tipo 5/6 : Destination/Source Port
Stessa codifica del tipo 4. Solo che serve a indicare o sole porte destinazione (Tipo 5) o sole porte sorgente (Tipo 6).

Tipo 7/8 : ICMP Type/Code
Stessa codifica del tipo 3. Serve a indicare il tipo di pacchetto ICMP (Tipo 7) e il sottocodice (Tipo 8). Maggiori dettagli nella RFC 5575.

Tipo 9 : TCP Flag
Stessa codifica del tipo 3, a parte il formato del campo Option, leggermente diverso. Serve a indicare le flag TCP (es. TCP SYN). Maggiori dettagli nella RFC 5575.

Tipo 10 : Packet Length
Stessa codifica del tipo 3. Serve a indicare pacchetti IP la cui lunghezza è maggiore/minore di un dato valore. Maggiori dettagli nella RFC 5575.

Tipo 11 : DSCP Value
Stessa codifica del tipo 3. Serve a indicare insiemi di valori di DSCP. Maggiori dettagli nella RFC 5575.

Tipo 12 : Fragment
Stessa codifica del tipo 3, dove però in luogo del campo Protocol ID vi è un insieme di bit presenti nel pacchetto IP, per la gestione della frammentazione (es. DF bit). Serve a indicare insiemi di frammenti di pacchetti IP. Maggiori dettagli nella RFC 5575.

Quanto sin qui detto riguarda la definizione dei flussi (Flow Specification). Il secondo aspetto fondamentale è la codifica delle azioni. La RFC 5575 ha specificato quattro tipi di azioni sui flussi, riportate nella figura seguente, tratta dalla RFC.












Le azioni sono aggiunte ai messaggi BGP UPDATE attraverso delle Extended Community, il cui tipo è specificato nella prima colonna (es. per l'azione traffic-rate, il tipo di Extended Community è 0x8006).

L'azione traffic-rate serve a limitare il traffico del flusso a un valore prefissato (espresso in byte/s). Un valore nullo di traffic-rate indica lo scarto dei pacchetti. Solo per curiosità, vi riporto nella figura seguente il formato completo, e un esempio relativo a un traffic-rate di 1 kbyte/s.



Naturalmente vi chiederete da dove ho preso la codifica esadecimale del traffic-rate. Bene, la cosa è un po' complicata e non vi consiglio di approfondire. Il formato deriva dalla rappresentazione floating point IEEE.754.1985 - Standard for Binary Floating-Point Arithmetic, perché così specifica la RFC 5575. Comunque c'è un'àncora di salvezza, ed è questo sito, dove immettendo i dati si ottiene direttamente il risultato. Ad esempio, poiché 1 kbyte/s = 8000.0 bit/s, immettendo i dati si ottiene il valore esadecimale desiderato. Questo è uno snapshot tratto dal sito.











La terza azione viene anche spesso utilizzata. L'idea è redirigere il traffico "malevolo" verso un centro specializzato per l'analisi del traffico (scrubbing center, in modo affettivo chiamato spesso "lavatrice"), che ha il compito di "ripulire" il traffico, eliminando la componente "malevola" (esempi di scrubbing center: F5 Silverline, Akamai Cloud Security, Radware DefensePipe).

Per le altre due azioni, di minore interesse, vi rimando alla RFC 5575.

Bene, con la teoria finisco qui. Chi fosse interessato a ulteriori dettagli può leggersi la RFC 5575. Adesso passiamo alla pratica.

BGP FLOWSPEC NELL'IOS CISCO
Il BGP FlowSpec è stato introdotto nell'IOS Cisco a partire dalla versione 15.5(S) e nell'IOS XE a partire dalla versione 3.14, ma è supportato solo nei Route Reflector e nei BGP speaker che hanno la funzione di Client (ossia, non è supportato nei router con funzione di controller). In modo più completo, è supportato nell'IOS XR a partire dalla versione 5.2.0.

Ai fini della configurazione, Cisco distingue i router come Server e Client. I router con funzione di Server sono i controller, mentre i Client sono i BGP Speaker, che ricevono (via BGP) le regole (azioni) da adottare per i vari flussi. Si noti, come regola generale, che la funzione di controller può essere eseguita da un qualsiasi server che abbia una implementazione BGP che supporti l'address-family BGP FlowSpec (es. ExaBGP).

La configurazione richiede tre passi:
  • Abilitazione al supporto dell'address-family BGP FlowSpec.
  • Definizione del flusso e delle azioni.
  • Trasferimento delle regole sui flussi all'hardware.
L'abilitazione al supporto dell'address-family BGP FlowSpec avviene, per tutte le versioni IOS (IOS, IOS XE, IOS XR) attraverso il comando "address-family { ipv4 | ipv6 | vpnv4 | vpnv6 } flowspec". Questo comando va eseguito sia a livello Client che Server.

La definizione dei flussi utilizza un comando ben noto a chi è familiare con le configurazioni della QoS IP in ambiente Cisco: le class-map. La configurazione da eseguire è la seguente:

class-map type traffic [match-all | match-any] nome-class-map
  match < condizione 1 >
  . . .
  match < condizione N >

Le condizioni "match" supportate includono tutte quelle definite nella RFC 5575 e nella sua estensione a IPv6. Solo a titolo di esempio ne riporto alcune, per le altre potete far riferimento alla documentazione Cisco:
  • match destination-address {ipv4 | ipv6} prefisso/maschera 
  • match source-address {ipv4 | ipv6} address/prefisso/maschera 
  • match protocol {protocol ID |min-value - max-value}
  • match destination-port {porta destinazione |min-value - max-value}
  • match source-port {porta sorgente |min-value - max-value}
  • . . .
La definizione delle azioni utilizza un altro comando ben noto a chi è familiare con le configurazioni della QoS IP in ambiente Cisco: le policy-map. La configurazione da eseguire è la seguente:

policy-map type pbr nome-policy-map
  class type traffic nome-class-map
  < azione 1 >
  . . .
  azione N >

Infine, il trasferimento delle regole sui flussi all'hardware, avviene tramite i comandi:

flowspec
  address-family ipv4
    service-policy type pbr nome-policy-map

Per verificare tutto il procedimento, ho fatto una prova con il VIRL. La topologia è la stessa utilizzata nel post precedente sul BGP RTBH, che riporto anche qui per completezza.



















Il flusso da controllare è definito dagli indirizzi IP utilizzati dall'attaccante, che per ipotesi appartengono alla subnet IP 2.1.1.0/24. L'azione sul traffico da controllare è di tipo policing, con un police-rate fissato a 10 kbps. La configurazione del controller, anche qui simulato da un router con IOS XR, è la seguente (NOTA: come sempre, riporto i soli comandi rilevanti):

router bgp 3269
  address-family ipv4 flowspec
  !
  neighbor < RR >
    remote-as 3269
    update-source Loopback0
    address-family ipv4 flowspec
!
class-map type traffic match-all FLOW1
  match source-address ipv4 2.1.1.0/24
end-class-map
!
policy-map type pbr TEST-BF
  class type traffic FLOW1
    police rate 10 kbps 
end-policy-map
!
flowspec
  address-family ipv4
    service-policy type pbr TEST-BF
!

Sui router RR, PE1 e PE2, che utilizzano l'IOS XE, è sufficiente l'abilitazione dell'address-family BGP FlowSpec

router bgp 3269
  address-family ipv4 flowspec
     neighbor < RR > activate

Per verificare che il controller invii correttamente l'annuncio BGP FlowSpec al Route-Reflector RR, è possibile utilizzare il seguente comando, che consente di verificare  la presenza dell'annuncio, sulla tabella BGP FlowSpec di RR (NOTA: RR è un CSR1000v, che utilizza l'IOS XE).

RR# show bgp ipv4 flowspec detail
BGP routing table entry for Source:2.1.1.0/24, version 7
  Paths: (1 available, best #1, table IPv4-Flowspec-BGP-Table)
  Advertised to update-groups:
     2         
  Refresh Epoch 1
  Local
    0.0.0.0 from 192.168.1.2 (192.168.1.2)
      Origin IGP, localpref 100, valid, internal, best
      Extended Community: FLOWSPEC Traffic-rate:3269,1250
      rx pathid: 0, tx pathid: 0x0

Due sono le cose che vale la pena sottolineare. La prima è che il Next-Hop è posto a 0.0.0.0, che in questo caso non indica, come spesso accade, che l'annuncio è originato localmente, ma che il Next-Hop è "fittizio" (vedi la sezione "Teoria"). La seconda è la Extended Community che trasporta l'informazione sull'azione da eseguire sul flusso specificato (in questo esempio identificato dalla sola subnet sorgente 2.1.1.0/24). La Extended Community indica che l'azione è di tipo "Traffic-rate"; poi viene indicato il numero di AS a cui appartiene il controller (= 3269), e infine il valore del traffic-rate espresso in byte/s (10 kbps = 1250 byte/s).

Per vostra curiosità, ho anche "sniffato" il messaggio BGP UPDATE, contenente l'attributo MP_REACH_NLRI dell'address-family BGP FlowSpec (oltre agli altri classici attributi del BGP), e l'Extended Community dove è contenuta l'azione da eseguire, che il controller invia al RR. Lo potete scaricare qui

Non posso farvi vedere il trasferimento della regola all'hardware (tabella CEF), poiché ancora non implementato nel VIRL.

BGP FLOWSPEC NEL JUNOS
Il BGP FlowSpec è stato introdotto nel JunOS Juniper molto prima di Cisco, a partire dalla versione JunOS 7.3, e con miglioramenti sostanziali a partire dalla versione 11.1.

La logica di configurazione è simile a quella Cisco, non ci sono però comandi per il trasferimento delle regole sui flussi ai PFE (Packet Forwarding Engine), il trasferimento avviene automaticamente. Quello che il JunOS fa è semplicemente convertire gli annunci BGP FlowSpec, che contengono sia la definizione dei flussi che le azioni da intraprendere, in un Firewall Filter (equivalente di una ACL Cisco) che viene inviato ai PFE e applicato in input a tutte le interfacce di ciascuna linecard (Flexible  PIC Concentrator (FPC), nel linguaggio dei router Juniper).

Riporto di seguito, senza ulteriori spiegazioni, la configurazione del controller, anche qui simulato da un router, per la rete esempio illustrata sopra, utilizzando però un flusso diverso e una azione identica (police rate 10 kbps) (NOTA: come sempre, riporto i soli comandi rilevanti):

[edit]
tt@CTRL# show routing-options flow
route FLOW1 {
    match {
        destination 1.1.1.1/32;
        source 2.1.1.0/24;
        protocol tcp;
        port 23;
    }
    then rate-limit 10k;
}

[edit]
tt@CTRL# show protocols bgp
group RR {
    type internal;
    local-address < CTRL >;
    family inet {
        unicast;
        flow;
    }
    neighbor < RR >;
}

Sui router RR, PE1 e PE2 è sufficiente l'abilitazione dell'address-family BGP FlowSpec:

tt@RX# show protocols bgp
group BGP-FS {
    type internal;
    local-address < IP-RX >;
    family inet {
        flow;
    }
    neighbor < IP-RY >;
}

Sulla base di questa semplice configurazione, il controller genera un annuncio BGP FlowSpec, che deposita localmente nella tabella apposita "inetflow.0" e da qui l'annuncio viene propagato secondo le usuali regole del BGP. Alla fine l'annuncio arriva ai router PE, i quali anche loro lo inseriscono nella tabella apposita "inetflow.0". Ad esempio, con il seguente comando si può vedere il dettaglio dell'annuncio sul router PE2:

tt@PE2> show route table inetflow.0 extensive

inetflow.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)
1.1.1.1,2.1.1/24,proto=6,port=23/term:1  (1 entry, 1 announced)
TSI:
KRT in dfwd;
Action(s): rate-limit 10kbps,count
        *BGP    Preference: 170/-101
                Next hop type: Fictitious
                Address: 0x8f2c024
                Next-hop reference count: 1
                State: <Active Int Ext>
                Local AS:  3269 Peer AS:  3269
                Age: 31:09
                Task: BGP_3269.192.168.1.5+64066
                Announcement bits (1): 0-Flow
                AS path: I (Originator) Cluster list:  1.1.1.1
                AS path:  Originator ID: 192.168.1.2  # Indirizzo IP del controller
                Communities: traffic-rate:0:10000
                Accepted
                Localpref: 100
                Router ID: 192.16.1.5  Indirizzo IP del Route Reflector

Anche qui, due sono le cose che vale la pena sottolineare. La prima è che il Next-Hop type è di tipo "Fictitious" che indica che il Next-Hop è "fittizio" (vedi la sezione "Teoria"). La seconda è la Extended Community che trasporta l'informazione sull'azione da eseguire sul flusso specificato. La Extended Community indica che l'azione è di tipo "traffic-rate"; poi viene indicato il numero di AS che il JUNOS, a differenza di Cisco, pone a un valore sempre nullo, e infine il valore del traffic-rate, espresso però in bit/s.

Anche qui, ho "sniffato" il messaggio BGP UPDATE che il controller invia al RR, contenente l'attributo MP_REACH_NLRI dell'address-family BGP FlowSpec, e l'Extended Community dove è contenuta l'azione da eseguire. Lo potete scaricare qui. Due sono le differenze rispetto allo stesso messaggio "sniffato" in ambiente Cisco. La prima è che l'attributo MP_REACH_NLRI contiene più sotto-componenti poiché è stato specificato un flusso più granulare. La seconda è la diversa interpretazione dei parametri AS e Traffic-rate (indicato da wireshark come Rate shaper), contenuti nell'attributo Extended Community. Come visto nella sezione sopra, nel caso Cisco questi parametri sono pari rispettivamente a 3269 (numero di AS a cui appartiene il controller) e 1.250 (= Traffic-rate espresso in byte/s), nel caso Juniper questi sono pari rispettivamente a 0 e 10.000 (= Traffic-rate espresso in bit/s)

Alla ricezione dell'annuncio, il router PE2 crea automaticamente il Firewall Filter "__flowspec_default_inet__" :

tt@PE2> show firewall filter  __flowspec_default_inet__

Filter: __flowspec_default_inet__
Counters:
Name                                                Bytes              Packets
1.1.1.1,2.1.1/24,proto=6,port=23   0                    0
Policers:
Name                                                Bytes              Packets
1.1.1.1,2.1.1/24,proto=6,port=23                         0

E qui si conclude anche la parte pratica. Come sempre, per ulteriori dettagli implementativi è necessario consultare la documentazione ufficiale dei vari costruttori.

CONCLUSIONI
BGP FlowSpec, come visto in questo post, è una evoluzione di BGP RTBH per contrastare attacchi di tipo DDoS. E' molto più sofisticato e più complesso, e per questo non è ampiamente utilizzato. A questo link potete trovare una ricerca sullo stato di utilizzo del BGP FlowSpec, dalla quale si evince che solo il 40 % degli "aventi diritto" lo utilizza, e che tra chi non lo utilizza, solo il 34 % intenzione di implementarlo in futuro. Per gli indecisi, vorrei sottolineare che gli attacchi di tipo DDoS hanno costo via via crescente. Una recente stima, che potete trovare qui, parla di circa 100.000 Dollari/ora (equivalente a circa 88.000 Euro/ora), che non sono proprio "bruscolini", come diceva un noto attore comico.

Al pari del BGP RTBH, anche il BGP FlowSpec è stato accostato recentemente al concetto di SDN poiché, come visto in questo post, l'idea di fondo utilizza un controller centralizzato, per inviare ai router di edge (PE) di una rete delle regole che consentano o di bloccare il traffico generato da un attaccante verso un Host attaccato, o di limitarlo attraverso un policer, o di rimarcarlo (tipicamente a una classe di servizio di bassa qualità), o infine di redirigerlo verso opportuni apparati di "ripulitura". 

Con questo post chiudo per il momento con l'utilizzo del BGP in ambito SDN. Il prossimo riguarderà l'utilizzo MPLS in ambito SDN. In particolare tratterò il protocollo PCEP, i cui principi sono stati introdotti in questo post.

Stay tuned !!!

Se volete saperne di più sul BGP, da zero all'infinito, oppure avete bisogno di ulteriori approfondimenti, potete acquistare il mio libro "BGP: dalla Teoria alla Pratica", Ed. Reiss Romoli, 2011 (al prezzo speciale di 30 Euro per i lettori del blog, spese di spedizione gratuite). Per l'acquisto, poiché il libro è al di fuori dei circuiti tradizionali ed è venduto direttamente da Reiss Romoli srl, inviatemi una e-mail all'indirizzo tiziano.tofoni@ssgrr.com e vi invio tutte le informazioni necessarie. Potete scaricare l'indice qui

E se volete saperne ancora di più, seguite i nostro corsi IPN246 IPN247.

P.S. Vi ricordo che potete essere avvisati via e-mail di ogni nuovo post, utilizzando il riquadro a destra "Seguimi via e-mail", presente nella Home Page del blog (niente di invasivo, tranquilli, una e-mail ogni 15 giorni circa).  Tutto ciò che dovete fare è inserire il vostro indirizzo e-mail, e quindi confermare l'iscrizione rispondendo a una e-mail iniziale. Alcuni amici mi hanno segnalato il problema che questa e-mail viene a volte inserita nella posta indesiderata, per cui se non la vedete controllate che non sia finita lì. 




Nessun commento:

Posta un commento