Border Gateway Protocol (BGP): il protocollo che tiene insieme Internet
Il Border Gateway Protocol (BGP) è il protocollo di routing che permette a Internet di funzionare come una rete globale interconnessa. Mentre i protocolli di routing interni (IGP) come OSPF o IS-IS gestiscono il traffico all'interno di una singola organizzazione, BGP opera tra organizzazioni diverse, scambiando informazioni di raggiungibilità tra i cosiddetti Autonomous System (AS). Senza BGP, Internet sarebbe una collezione di reti isolate incapaci di comunicare tra loro in modo coerente e scalabile.
La versione attualmente in uso è BGP-4, definita nella RFC 4271 (gennaio 2006), che sostituisce le versioni precedenti e introduce il supporto per il Classless Inter-Domain Routing (CIDR). Si tratta di un protocollo estremamente longevo: la sua prima versione risale al 1989 (RFC 1105) e, nonostante le evoluzioni, l'architettura di base è rimasta sostanzialmente invariata.
Concetti fondamentali
Per comprendere BGP è necessario partire dal concetto di Autonomous System. Un AS è un insieme di reti IP e router sotto il controllo amministrativo di una singola entità (un ISP, una grande azienda, un'università, un cloud provider) che presenta una politica di routing comune verso l'esterno. Ogni AS è identificato univocamente da un numero, l'Autonomous System Number (ASN), assegnato dalla IANA tramite i Regional Internet Registry (ARIN, RIPE NCC, APNIC, LACNIC, AFRINIC).
Originariamente gli ASN erano numeri a 16 bit (da 1 a 65535), ma l'esaurimento dello spazio ha portato all'introduzione degli ASN a 32 bit (RFC 6793), che estendono il range fino a circa 4,29 miliardi. Esistono anche ASN privati riservati all'uso interno: 64512–65534 per gli ASN a 16 bit e 4200000000–4294967294 per quelli a 32 bit.
BGP opera in due modalità distinte:
- eBGP (External BGP): scambia informazioni di routing tra AS differenti. È la modalità che costituisce il tessuto connettivo di Internet.
- iBGP (Internal BGP): scambia informazioni di routing tra router BGP appartenenti allo stesso AS. Serve a propagare le rotte apprese da eBGP all'interno dell'AS.
Funzionamento del protocollo
BGP è un protocollo di tipo path vector: ogni annuncio di rotta include il percorso completo degli AS attraversati per raggiungere la destinazione. Questa caratteristica permette di prevenire i loop di routing in modo elegante: se un router riceve un annuncio che contiene il proprio ASN nel percorso, lo scarta automaticamente.
BGP utilizza TCP come protocollo di trasporto sulla porta 179. Questa scelta è significativa: a differenza di OSPF che usa IP direttamente o RIP che usa UDP, BGP delega a TCP la gestione dell'affidabilità, del controllo di flusso e della frammentazione. I peer BGP stabiliscono una connessione TCP persistente e scambiano messaggi su di essa.
La sessione BGP attraversa diversi stati definiti da una macchina a stati finiti:
- Idle: stato iniziale, nessuna risorsa allocata.
- Connect: il router attende il completamento della connessione TCP.
- Active: il router tenta attivamente di stabilire la connessione TCP.
- OpenSent: è stato inviato un messaggio OPEN e si attende quello del peer.
- OpenConfirm: il messaggio OPEN del peer è stato ricevuto e validato.
- Established: la sessione è operativa e i peer possono scambiare informazioni di routing.
Tipi di messaggi BGP
BGP-4 definisce quattro tipi principali di messaggi, ciascuno con uno scopo specifico nel ciclo di vita della sessione:
Il messaggio OPEN è il primo inviato dopo l'apertura della connessione TCP. Contiene la versione del protocollo, l'ASN del mittente, l'hold time proposto, il BGP Identifier (tipicamente l'indirizzo IP più alto del router) e parametri opzionali come le capability negoziate.
Il messaggio UPDATE è il cuore del protocollo: trasporta le informazioni di routing. Contiene tre sezioni: le rotte ritirate (withdrawn routes), gli attributi di percorso (path attributes) e le rotte annunciate sotto forma di prefissi NLRI (Network Layer Reachability Information).
Il messaggio KEEPALIVE è un messaggio molto semplice (solo l'header di 19 byte) inviato periodicamente per mantenere viva la sessione. Tipicamente viene inviato ogni terzo dell'hold time negoziato.
Il messaggio NOTIFICATION segnala condizioni di errore e provoca la chiusura immediata della sessione. Include un codice di errore principale, un sottocodice e dati opzionali per il debugging.
Attributi di percorso
Gli attributi di percorso (path attributes) sono il meccanismo attraverso cui BGP veicola le informazioni necessarie per il processo decisionale. Si classificano in quattro categorie in base a due flag binari: well-known/optional e mandatory/discretionary.
Gli attributi più rilevanti sono:
- ORIGIN: indica l'origine della rotta (IGP, EGP, INCOMPLETE).
- AS_PATH: la sequenza di ASN che la rotta ha attraversato.
- NEXT_HOP: l'indirizzo IP del prossimo hop per raggiungere la destinazione.
- LOCAL_PREF: preferenza locale, usata in iBGP per influenzare la scelta del path in uscita.
- MED (Multi-Exit Discriminator): suggerimento al peer eBGP su quale punto di ingresso preferire quando esistono più connessioni.
- COMMUNITY: tag amministrativi usati per applicare policy di routing in modo flessibile.
Il processo decisionale BGP
Quando un router BGP riceve più rotte per la stessa destinazione, deve sceglierne una sola da installare nella tabella di routing e annunciare. Il processo decisionale segue un algoritmo deterministico che valuta gli attributi in un ordine ben definito. Sebbene le implementazioni di vendor diversi possano introdurre piccole varianti, l'ordine canonico è il seguente:
- Preferire la rotta con il weight più alto (attributo proprietario Cisco, locale al router).
- Preferire la rotta con il LOCAL_PREF più alto.
- Preferire le rotte originate localmente sul router.
- Preferire la rotta con l'AS_PATH più corto.
- Preferire la rotta con l'ORIGIN più basso (IGP < EGP < INCOMPLETE).
- Preferire la rotta con il MED più basso.
- Preferire eBGP rispetto a iBGP.
- Preferire la rotta con la metrica IGP più bassa verso il next hop.
- Preferire la rotta con il BGP Identifier più basso del peer.
- Preferire la rotta dall'indirizzo del peer più basso.
Esempio di sessione BGP con BGP4-Go
Per illustrare come stabilire una sessione BGP a livello programmatico, vediamo un esempio in Go utilizzando la libreria GoBGP, una delle implementazioni open source più mature. Il seguente codice configura un peer BGP e annuncia un prefisso:
package main
import (
"context"
"log"
"time"
api "github.com/osrg/gobgp/v3/api"
"github.com/osrg/gobgp/v3/pkg/server"
apb "google.golang.org/protobuf/types/known/anypb"
)
func main() {
// Inizializzazione del server BGP locale
bgpServer := server.NewBgpServer()
go bgpServer.Serve()
// Configurazione globale: ASN locale e router ID
if err := bgpServer.StartBgp(context.Background(), &api.StartBgpRequest{
Global: &api.Global{
Asn: 65001,
RouterId: "192.0.2.1",
ListenPort: 179,
},
}); err != nil {
log.Fatalf("avvio BGP fallito: %v", err)
}
// Definizione del peer remoto
peer := &api.Peer{
Conf: &api.PeerConf{
NeighborAddress: "192.0.2.2",
PeerAsn: 65002,
},
Timers: &api.Timers{
Config: &api.TimersConfig{
ConnectRetry: 10,
HoldTime: 90,
KeepaliveInterval: 30,
},
},
}
if err := bgpServer.AddPeer(context.Background(), &api.AddPeerRequest{
Peer: peer,
}); err != nil {
log.Fatalf("aggiunta peer fallita: %v", err)
}
// Attesa per consentire la negoziazione della sessione
time.Sleep(5 * time.Second)
// Annuncio di un prefisso IPv4
nlri, _ := apb.New(&api.IPAddressPrefix{
Prefix: "203.0.113.0",
PrefixLen: 24,
})
originAttr, _ := apb.New(&api.OriginAttribute{
Origin: 0, // origine IGP
})
nextHopAttr, _ := apb.New(&api.NextHopAttribute{
NextHop: "192.0.2.1",
})
_, err := bgpServer.AddPath(context.Background(), &api.AddPathRequest{
Path: &api.Path{
Family: &api.Family{Afi: api.Family_AFI_IP, Safi: api.Family_SAFI_UNICAST},
Nlri: nlri,
Pattrs: []*apb.Any{originAttr, nextHopAttr},
},
})
if err != nil {
log.Fatalf("annuncio del prefisso fallito: %v", err)
}
log.Println("prefisso annunciato correttamente")
// Mantenimento attivo del processo
select {}
}
Monitoraggio delle sessioni BGP in Python
Per chi desidera analizzare il routing globale senza dover gestire una sessione BGP completa, esistono progetti come RIPE RIS e RouteViews che offrono dati pubblici. Il seguente esempio in Python utilizza l'API di RIPEstat per ottenere informazioni sugli annunci di un prefisso:
import requests
from typing import Any
def get_bgp_announcements(prefix: str) -> dict[str, Any]:
"""Recupera gli annunci BGP correnti per un dato prefisso."""
base_url = "https://stat.ripe.net/data/announced-prefixes/data.json"
params = {"resource": prefix}
response = requests.get(base_url, params=params, timeout=10)
response.raise_for_status()
return response.json()
def get_routing_history(prefix: str) -> dict[str, Any]:
"""Recupera lo storico delle rotte per un prefisso."""
base_url = "https://stat.ripe.net/data/routing-history/data.json"
params = {"resource": prefix, "max_rows": 50}
response = requests.get(base_url, params=params, timeout=10)
response.raise_for_status()
return response.json()
def analyze_origin_changes(prefix: str) -> list[dict[str, Any]]:
"""Identifica i cambi di AS di origine per un prefisso."""
history = get_routing_history(prefix)
changes = []
by_origin = history.get("data", {}).get("by_origin", [])
for entry in by_origin:
origin_asn = entry.get("origin")
timelines = entry.get("timelines", [])
for timeline in timelines:
changes.append({
"origin_asn": origin_asn,
"starttime": timeline.get("starttime"),
"endtime": timeline.get("endtime"),
})
# Ordinamento cronologico dei cambi rilevati
changes.sort(key=lambda x: x["starttime"])
return changes
if __name__ == "__main__":
target_prefix = "8.8.8.0/24"
announcements = get_bgp_announcements(target_prefix)
print(f"Annunci correnti per {target_prefix}:")
print(announcements.get("data", {}).get("prefixes", []))
origin_changes = analyze_origin_changes(target_prefix)
print(f"\nCambi di origine rilevati: {len(origin_changes)}")
for change in origin_changes[:5]:
print(f" AS{change['origin_asn']} dal {change['starttime']}")
Sicurezza di BGP
BGP è stato progettato in un'epoca in cui Internet era una rete piccola e i partecipanti si fidavano reciprocamente. Questo retaggio si manifesta nella sua principale debolezza: per default, BGP non offre alcun meccanismo per verificare che chi annuncia un prefisso ne sia il legittimo titolare. Questa lacuna ha causato negli anni numerosi incidenti, tra cui famosi episodi di BGP hijacking e route leak.
Un BGP hijack avviene quando un AS annuncia, intenzionalmente o per errore, prefissi che non gli appartengono. Il caso più celebre è quello del 2008, quando Pakistan Telecom annunciò un prefisso più specifico di YouTube nel tentativo di bloccarne l'accesso a livello nazionale, ma l'annuncio si propagò globalmente rendendo YouTube irraggiungibile per circa due ore.
Per mitigare questi problemi sono state introdotte diverse contromisure:
- RPKI (Resource Public Key Infrastructure, RFC 6480): un'infrastruttura crittografica che permette ai titolari di risorse Internet di firmare digitalmente l'autorizzazione ad annunciare i propri prefissi tramite oggetti chiamati ROA (Route Origin Authorization).
- BGPsec (RFC 8205): un'estensione che firma crittograficamente l'intero AS_PATH, proteggendo contro la manipolazione del percorso. La sua adozione è però ancora limitata a causa dell'overhead computazionale.
- MANRS (Mutually Agreed Norms for Routing Security): un'iniziativa che promuove l'adozione di buone pratiche tra ISP, come il filtraggio dei prefissi, la validazione RPKI e l'anti-spoofing.
Validazione RPKI in Java
L'esempio seguente mostra come interrogare un validatore RPKI per verificare lo stato di una coppia prefisso/ASN. Utilizziamo il client HTTP standard introdotto in Java 11:
package com.example.rpki;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class RpkiValidator {
private static final String VALIDATOR_URL = "https://rpki-validator.ripe.net/api/v1/validity";
private final HttpClient httpClient;
public RpkiValidator() {
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
}
public String checkValidity(int asn, String prefix) throws Exception {
// Costruzione dell'URL di validazione
String url = String.format("%s/AS%d/%s", VALIDATOR_URL, asn, prefix);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Accept", "application/json")
.timeout(Duration.ofSeconds(15))
.GET()
.build();
HttpResponse<String> response = httpClient.send(
request, HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new RuntimeException(
"validazione fallita con status: " + response.statusCode()
);
}
return response.body();
}
public static void main(String[] args) throws Exception {
RpkiValidator validator = new RpkiValidator();
// Verifica della validità dell'annuncio
String result = validator.checkValidity(15169, "8.8.8.0/24");
System.out.println("Risultato della validazione:");
System.out.println(result);
}
}
BGP nei data center moderni
Negli ultimi anni BGP ha trovato un impiego interessante anche all'interno dei data center, in una variante nota come BGP unnumbered o BGP in the data center (RFC 7938). Grandi operatori come Facebook, Microsoft e Google utilizzano BGP come unico protocollo di routing nelle loro fabric Clos a tre livelli, abbandonando i tradizionali IGP.
Le ragioni di questa scelta sono diverse: BGP è un protocollo policy-driven estremamente flessibile, scala meglio di OSPF in topologie con migliaia di nodi, è ampiamente supportato da tutti i vendor e permette una gestione uniforme dal core fino al singolo server tramite estensioni come BGP Add-Path e l'uso di private ASN per ogni rack.
Conclusioni
BGP è uno di quei protocolli che, pur essendo critici per il funzionamento di Internet, restano spesso invisibili agli utenti finali. La sua progettazione, basata sul principio della fiducia tra operatori, riflette le origini accademiche e cooperative della rete, ma rappresenta oggi una delle principali superfici di attacco e di fragilità dell'infrastruttura globale. L'adozione sempre più ampia di RPKI, l'iniziativa MANRS e la spinta verso BGPsec stanno gradualmente trasformando BGP in un protocollo più sicuro, anche se il percorso è ancora lungo.
Per chi opera nel campo del networking, dello sviluppo di infrastrutture cloud o della sicurezza, una conoscenza approfondita di BGP non è più un'opzione: è un prerequisito per comprendere come funziona davvero Internet e per progettare sistemi distribuiti robusti, resilienti e sicuri.