Perché GRE su IPsec
Nella guida Tunnel GRE tra un router Cisco e Ubuntu Linux abbiamo costruito un tunnel GRE funzionante, ma in chiaro. Qui lo proteggiamo con IPsec senza cambiare indirizzi, interfacce e rotte.
Perché non usare direttamente una VPN IPsec? Perché GRE porta vantaggi che IPsec da solo non offre:
- Multicast: nel tunnel passano i protocolli di routing dinamico come OSPF ed EIGRP.
- Più reti senza toccare le SA: IPsec protegge un solo flusso, il GRE tra i due IP pubblici. Le reti che ci passano dentro le decide il routing.
- Interoperabilità: ogni apparato capisce GRE, e la parte IPsec si riduce a una sola Child SA semplice.
Oggi una VTI (vedi VPN IPsec tra Cisco e Ubuntu con strongSwan) copre molti di questi casi con meno overhead. GRE su IPsec resta la scelta giusta se ti serve multicast, se hai già un’infrastruttura GRE o se l’altro capo non supporta interfacce IPsec.
Lo scenario
Gli indirizzi sono quelli della guida GRE. Il tunnel GRE resta com’è; IPsec, in modalità trasporto, cifra i pacchetti GRE che viaggiano tra 198.51.100.1 e 203.0.113.10.
| Elemento | Sede A (Cisco) | Sede B (Ubuntu) |
|---|---|---|
| IP pubblico e identità IKE | 198.51.100.1 su Gi0/0 | 203.0.113.10 su ens18 |
| LAN | 192.168.10.0/24, gateway .1 su Gi0/1 | 192.168.20.0/24, gateway .1 su ens19 |
| Interfaccia tunnel | Tunnel0 – 10.255.255.1/30 | gre1 – 10.255.255.2/30 |
| Traffico protetto | GRE (protocollo IP 47) tra 198.51.100.1 e 203.0.113.10, modalità trasporto | |
Gli algoritmi sono gli stessi della guida IPsec: IKE con aes256gcm16-prfsha256-ecp256 (AES-256-GCM, PRF SHA-256, gruppo DH 19), ESP con aes256gcm16-ecp256 (AES-256-GCM con PFS gruppo 19). Lì trovi anche la tabella di corrispondenza tra i nomi Cisco e strongSwan.
Overhead, MTU e MSS
In modalità tunnel IPsec aggiungerebbe una nuova intestazione IP davanti al pacchetto GRE, che ne ha già una. In modalità trasporto l’intestazione esterna del GRE viene riusata: ESP si inserisce tra questa e l’intestazione GRE. Risparmi 20 byte per pacchetto, e il traffico è comunque tutto cifrato.
Facciamo i conti su un collegamento con MTU 1500:
| Voce | AES-256-GCM | AES-256-CBC + SHA-256 |
|---|---|---|
| GRE (IP esterno + GRE) | 24 | 24 |
| Intestazione ESP (SPI + sequenza) | 8 | 8 |
| IV | 8 | 16 |
| Trailer (padding + 2 byte) | 2–5 | 2–17 |
| ICV | 16 | 16 |
| NAT-T (se presente) | 8 | 8 |
| Totale, caso peggiore | 69 | 89 |
Il caso peggiore lascia circa 1431 byte con GCM e 1411 con CBC. Su PPPoE (MTU 1492) togli altri 8 byte. Per questo il valore consigliato è un MTU del tunnel di 1400: copre tutti i casi con un piccolo margine, ed è lo stesso che usa Cisco nei suoi esempi. L’MSS è l’MTU meno 40 byte di intestazioni IP e TCP: 1360.
Guadagnare 30 byte su 1400 vale il 2% di banda, ma un MTU troppo alto provoca frammentazione dopo la cifratura, che costa molto di più in CPU e in pacchetti persi. Usa 1400 su entrambi i lati: con OSPF è anche obbligatorio che i due MTU coincidano.
Configurazione del router Cisco
La parte IKEv2 è identica a quella della guida IPsec: proposta, policy, keyring e profilo. Se l’hai già configurata, riusala.
configure terminal
!
crypto ikev2 proposal PROP-GCM256
encryption aes-gcm-256
prf sha256
group 19
!
crypto ikev2 policy POL-GCM256
match address local 198.51.100.1
proposal PROP-GCM256
!
crypto ikev2 keyring KR-SEDE-B
peer UBUNTU-SEDE-B
address 203.0.113.10
pre-shared-key Cambia-Questa-Chiave-Esempio-0000
!
crypto ikev2 profile IKEV2-SEDE-B
match identity remote address 203.0.113.10 255.255.255.255
identity local address 198.51.100.1
authentication remote pre-share
authentication local pre-share
keyring local KR-SEDE-B
dpd 10 3 periodicCambia la parte IPsec: il transform-set è in modalità trasporto e il profilo si applica al tunnel GRE esistente.
crypto ipsec transform-set TS-GCM256-TR esp-gcm 256
mode transport
!
crypto ipsec profile IPSEC-GRE-SEDE-B
set transform-set TS-GCM256-TR
set pfs group19
set ikev2-profile IKEV2-SEDE-B
!
interface Tunnel0
ip mtu 1400
ip tcp adjust-mss 1360
tunnel mode gre ip
tunnel protection ipsec profile IPSEC-GRE-SEDE-B
!
end
write memoryIndirizzo, sorgente, destinazione e rotta statica di Tunnel0 restano quelli della guida GRE. Con tunnel protection il Cisco propone come selettori di traffico il solo GRE tra i due IP pubblici: 198.51.100.1/32 protocollo 47 verso 203.0.113.10/32 protocollo 47.
Appena applichi tunnel protection, il tunnel GRE resta giù finché anche Ubuntu non è pronto. Se gestisci uno dei due capi passando dal tunnel, perderai la connessione: lavora dalla rete locale o da un accesso alternativo. Vale anche per la PSK: Cambia-Questa-Chiave-Esempio-0000 è un segnaposto; genera la tua con openssl rand -base64 32 e usala identica sui due lati.
Aggiorna l’access list in ingresso sulla WAN: da ora accetta IKE ed ESP, e non più GRE in chiaro.
ip access-list extended WAN-IN
permit udp host 203.0.113.10 host 198.51.100.1 eq isakmp
permit udp host 203.0.113.10 host 198.51.100.1 eq non500-isakmp
permit esp host 203.0.113.10 host 198.51.100.1
no permit gre host 203.0.113.10 host 198.51.100.1Configurazione di Ubuntu
1. Adeguare l’MTU del tunnel GRE
Nel file Netplan della guida GRE porta l’MTU da 1476 a 1400:
network:
version: 2
tunnels:
gre1:
mode: gre
local: 203.0.113.10
remote: 198.51.100.1
addresses:
- 10.255.255.2/30
mtu: 1400
routes:
- to: 192.168.10.0/24
via: 10.255.255.1sudo netplan try
sudo netplan apply
2. Installare strongSwan
sudo apt update
sudo apt install strongswan-swanctl charon-systemd
3. Configurare la connessione in modalità trasporto
connections {
sede-a-gre {
version = 2
local_addrs = 203.0.113.10
remote_addrs = 198.51.100.1
proposals = aes256gcm16-prfsha256-ecp256
rekey_time = 24h
dpd_delay = 10s
local {
auth = psk
id = 203.0.113.10
}
remote {
auth = psk
id = 198.51.100.1
}
children {
gre {
mode = transport
# solo GRE (protocollo 47) tra i due IP pubblici
local_ts = 203.0.113.10[gre]
remote_ts = 198.51.100.1[gre]
esp_proposals = aes256gcm16-ecp256
rekey_time = 1h
start_action = start
dpd_action = restart
}
}
}
}
secrets {
ike-sede-a {
id = 198.51.100.1
secret = "Cambia-Questa-Chiave-Esempio-0000"
}
}[gre] limita i selettori al protocollo GRE: strongSwan accetta il nome del protocollo o il numero, quindi [47] è equivalente. Il resto del traffico tra i due server (SSH, monitoraggio) resta fuori da IPsec.
sudo chmod 600 /etc/swanctl/conf.d/sede-a-gre.conf
sudo systemctl enable --now strongswan
sudo swanctl --load-all
4. Firewall e MSS
Nel firewall sostituisci la regola che accettava GRE dal Cisco: ora entrano IKE ed ESP, e GRE è accettato solo se è arrivato cifrato.
table inet filtro {
chain input {
# ... regole esistenti ...
ip saddr 198.51.100.1 udp dport { 500, 4500 } accept
ip saddr 198.51.100.1 meta l4proto esp accept
# GRE solo se decifrato da IPsec
ip saddr 198.51.100.1 ip protocol gre meta ipsec exists accept
iifname "gre1" ip saddr 10.255.255.0/30 accept
}
chain forward {
# ... regole esistenti ...
tcp flags syn tcp option maxseg size set rt mtu
iifname "ens19" oifname "gre1" accept
iifname "gre1" oifname "ens19" accept
}
}Anche senza la regola nftables, il kernel scarta il GRE in chiaro dal Cisco: la policy IPsec in ingresso, installata da strongSwan, lo richiede cifrato. La regola esplicita rende la scelta visibile a chi legge il firewall.
Verifiche
Sul router Cisco
show crypto ikev2 sa ! Status READY
show crypto ipsec sa peer 203.0.113.10 ! "in use settings ={Transport, }"
show crypto session detail
show interfaces Tunnel0 ! "Tunnel protection via IPSec"
ping 10.255.255.2 source Tunnel0
ping 192.168.20.1 source GigabitEthernet0/1
In show crypto ipsec sa controlla le righe local ident e remote ident: devono riportare /47/0, cioè il protocollo GRE. I contatori #pkts encaps e #pkts decaps devono crescere mentre fai ping.
Su Ubuntu
sudo swanctl --list-sas # ESTABLISHED, e la Child SA "INSTALLED, TRANSPORT"
sudo ip xfrm policy # policy con "proto gre"
ping -c 3 10.255.255.1
ping -c 3 -I 192.168.20.1 192.168.10.1
sudo journalctl -u strongswan -f
La prova decisiva è guardare la WAN:
sudo tcpdump -ni ens18 'esp or udp port 4500' # qui deve passare il traffico
sudo tcpdump -ni ens18 'ip proto 47' # qui non deve comparire nulla
Se con il secondo comando vedi pacchetti GRE, il tunnel sta viaggiando in chiaro: la Child SA non è attiva o i selettori non corrispondono. Infine controlla l’MTU da un client della LAN B:
ping -M do -s 1372 192.168.10.10 # 1372 + 28 = 1400: deve passare
ping -M do -s 1400 192.168.10.10 # deve fallire con "mtu = 1400"
Opzionale: OSPF sopra il tunnel
Con GRE su IPsec puoi sostituire le rotte statiche con OSPF: ogni nuova rete in una sede viene annunciata all’altra senza toccare la VPN. Ecco una configurazione minima, tutta in area 0.
Sul router Cisco
interface Tunnel0
ip ospf network point-to-point
!
router ospf 1
router-id 10.255.255.1
passive-interface GigabitEthernet0/1
network 10.255.255.0 0.0.0.3 area 0
network 192.168.10.0 0.0.0.255 area 0
!
no ip route 192.168.20.0 255.255.255.0 10.255.255.2Su Ubuntu con FRRouting
sudo apt install frr
sudo sed -i 's/^ospfd=no/ospfd=yes/' /etc/frr/daemons
sudo systemctl restart frr
interface gre1
ip ospf network point-to-point
!
interface ens19
ip ospf passive
!
router ospf
ospf router-id 10.255.255.2
network 10.255.255.0/30 area 0
network 192.168.20.0/24 area 0sudo systemctl reload frr
sudo vtysh -c "show ip ospf neighbor"
Togli poi il blocco routes: dal file Netplan di gre1, altrimenti la rotta statica resta e prevale su quella OSPF. Nel firewall di Ubuntu accetta OSPF (protocollo 89) dal tunnel:
iifname "gre1" ip protocol 89 accept
OSPF confronta l’MTU delle interfacce: se Tunnel0 e gre1 non sono entrambe a 1400, l’adiacenza non arriva mai a FULL. Allinea gli MTU invece di usare ip ospf mtu-ignore.
Problemi comuni
| Sintomo | Causa probabile | Cosa fare |
|---|---|---|
NO_PROPOSAL_CHOSEN | Algoritmi IKE o ESP diversi | Confronta le proposte con la tabella della guida IPsec; il log di strongSwan elenca quelle ricevute |
AUTHENTICATION_FAILED | PSK o identità diverse | Allinea id in swanctl con identity local e match identity remote sul Cisco; ricopia la chiave |
TS_UNACCEPTABLE | Selettori diversi: per esempio il Cisco usa un IP sorgente diverso da 198.51.100.1 | Verifica tunnel source e tunnel destination; local_ts e remote_ts devono essere i due IP pubblici con [gre] |
| Child SA in modalità TUNNEL invece di TRANSPORT | Un lato non chiede la modalità trasporto | Controlla mode transport nel transform-set e mode = transport nella child; funziona lo stesso, ma con 20 byte in più |
| SA attive, ma Tunnel0 non passa traffico | Netplan o firewall: GRE scartato dopo la decifratura | ip -d link show gre1; controlla la regola meta ipsec exists e rp_filter |
| Il tunnel cade dopo circa un’ora | PFS configurato da una sola parte, fallisce il rekey | Allinea set pfs group19 e ecp256 in esp_proposals |
| Dopo il riavvio di un capo il tunnel resta giù | DPD assente | Verifica dpd sul Cisco e dpd_action = restart su strongSwan |
| Ubuntu dietro un router con NAT | In trasporto i selettori contengono l’IP pubblico, che Ubuntu non ha | Preferisci IP pubblici diretti; in alternativa usa la modalità tunnel o una VTI con NAT-T |
| Ping OK, ma siti e condivisioni si bloccano | MTU/MSS | MTU 1400 su Tunnel0 e gre1, MSS 1360 sul Cisco, regola MSS su Ubuntu |
In produzione e passi successivi
La chiave condivisa va bene per due sedi. In produzione preferisci i certificati: ogni capo ha la propria chiave privata e puoi revocarne uno senza toccare gli altri (sul Cisco authentication local rsa-sig con un trustpoint PKI, su strongSwan auth = pubkey).
Se non ti servono multicast né routing dinamico, una VPN IPsec con VTI è più semplice e ha meno overhead: la trovi nella guida VPN IPsec tra Cisco e Ubuntu con strongSwan. Per ripassare il tunnel di partenza, vedi Tunnel GRE tra un router Cisco e Ubuntu Linux.
Prova sempre la configurazione in laboratorio, salva quella attuale prima di modificarla e tieni un accesso di emergenza (console o accesso fuori banda) quando lavori su firewall e VPN da remoto.