Salta al contenuto
Note per Studenti Routing avanzato in Katharà

Routing avanzato in Katharà

In questa pagina 6

Questo laboratorio (LAB3) ripete la configurazione di Routing statico in KatharàLaboratorio 2 (LAB2). Due LAN (195.11.14.0/24 e 200.1.1.0/24) sono unite da due router r1 e r2 collegati da una rete 100.0.0.8/30. Una interfaccia attiva inserisce da sola nella tabella di instradamento solo la rete direttamente collegata: per le altre servono rotte inserite a mano. I PC usano una rotta predefinita (route add default gw 195.11.14.1), i router rotte statiche (route add -net 195.11.14.0/24 gw 100.0.0.9 dev eth1). Senza la rotta di ritorno su r2 le richieste di ping arrivano ma le risposte no: la raggiungibilità vale solo se c'è un percorso in entrambi i versi. A configurazione finita ping da pc1 a pc2 risponde con ttl=62 (64 meno 2 router).Routing statico in Katharà → su una rete più grande: una rete a triangolo, con maschere di lunghezza diversa. Obiettivo dichiarato nelle slide: ogni dispositivo deve poter fare ping a qualunque altro dispositivo; per gli esercizi, a tutte le interfacce (cioè a tutti gli indirizzi IP) di ogni altro dispositivo. Teoria: Instradamento e inoltroL'inoltro (forwarding) mette il pacchetto sulla strada verso la destinazione, un salto alla volta (hop by hop). Se la destinazione è nella stessa rete del mittente l'inoltro è diretto (si usa l'ARP per il MAC del destinatario), altrimenti è indiretto: il pacchetto va al router successivo (next hop) indicato dalla tabella di instradamento, o al default gateway. Con le netmask: l'inoltro è diretto attraverso l'interfaccia $x$ se $\text{IP(dst)}\ \text{AND}\ \text{NM}(x)=\text{IP}(x)\ \text{AND}\ \text{NM}(x)$; altrimenti si scorre la tabella dalla maschera più lunga (longest prefix match) e si usa il primo match. La riga con rete $0.0.0.0$ e maschera $0.0.0.0$ (default route) corrisponde sempre. L'aggregazione di rotte (route aggregation) riduce la tabella, e nell'inoltro con etichette (MPLS) la tabella si consulta per indice.Instradamento e inoltro →, Subnetting e supernettingIl subnetting divide un blocco di indirizzi in sottoblocchi più piccoli allungando la maschera ($n_{\text{sub}}=n_{\text{rete}}+s$, con $2^s$ sottoreti); il supernetting (aggregazione CIDR) fa l'opposto, accorciando il prefisso per unire blocchi contigui in uno più grande. Regole di progetto: ogni sottorete ha un numero di indirizzi potenza di 2 ($M=2^k\ge$ host richiesti $+2$), prefisso $n=32-k$, indirizzo iniziale multiplo di $M$; si assegnano prima le sottoreti più grandi. Per aggregare $2^j$ blocchi di prefisso $n$ servono blocchi contigui il cui primo indirizzo sia multiplo della dimensione dell'aggregato, e il nuovo prefisso è $n-j$.Subnetting e supernetting →.

La topologia

                          pc1  96.96.0.1/24
                           |   rete A = 96.96.0.0/24
                       eth2 .254
                          [r1]
            eth1 30.0.0.2 /   \ eth0 10.0.0.1
        rete X = 30.0.0.0/30   rete Y = 10.0.0.0/30
            eth0 30.0.0.1 /     \ eth1 10.0.0.2
                       [r3]----[r2]
              eth1 20.0.0.2   eth0 20.0.0.1        rete Z = 20.0.0.0/30
   pc2 -- eth2 (rete B)          eth2 (rete C) -- pc3
   192.192.192.1/20              128.128.0.1/20
   B = 192.192.192.0/20          C = 128.128.0.0/20
Dispositivo eth0 eth1 eth2
r1 10.0.0.1/30 (Y) 30.0.0.2/30 (X) 96.96.0.254/24 (A)
r2 20.0.0.1/30 (Z) 10.0.0.2/30 (Y) 128.128.15.254/20 (C)
r3 30.0.0.1/30 (X) 20.0.0.2/30 (Z) 192.192.207.254/20 (B)
pc1 96.96.0.1/24 (A)
pc2 192.192.192.1/20 (B)
pc3 128.128.0.1/20 (C)

Le reti (verificate con Python):

Rete Prefisso Maschera Broadcast Host utilizzabili
A 96.96.0.0/24 255.255.255.0 96.96.0.255 .1 – .254
B 192.192.192.0/20 255.255.240.0 192.192.207.255 192.192.192.1 – 192.192.207.254
C 128.128.0.0/20 255.255.240.0 128.128.15.255 128.128.0.1 – 128.128.15.254
X, Y, Z 30.0.0.0/30, 10.0.0.0/30, 20.0.0.0/30 255.255.255.252 .3 2 indirizzi

Come si ricavano maschera e broadcast di una /20. Una /20 ha 2020 bit di rete: i primi due ottetti interi (1616 bit) più i primi 44 bit del terzo. Il terzo ottetto della maschera è quindi 111100002=128+64+32+16=24011110000_2=128+64+32+16=240 (maschera 255.255.240.0), e i bit dell'host sono 32−20=1232-20=12: gli indirizzi sono 212=40962^{12}=4096, dei quali 22 sono riservati (rete e broadcast), quindi 40944094 host. Per B il terzo ottetto è 192=110000002192=11000000_2: i primi 4 bit (1100) sono di rete e gli altri 4 liberi, quindi il terzo ottetto varia da 1100 0000 =192=192 a 1100 1111 =207=207 (Basi di numerazione e conversioni - binario, ottale ed esadecimaleUn numero in base $r$ vale $\sum a_i r^i$ (cifre $a_i\in{0,\dots,r-1}$). Conversioni: base $r\to$ decimale con la somma pesata; decimale $\to$ base $r$ per divisioni successive (parte intera, resti letti dal basso) e moltiplicazioni successive (parte frazionaria, parti intere lette dall'alto); binario $\leftrightarrow$ ottale/esadecimale a gruppi di 3/4 bit. Somma, differenza e prodotto binari seguono le regole decimali con cifre 0 e 1; la differenza ha prestiti, il prodotto somma prodotti parziali traslati.Basi di numerazione e conversioni - binario, ottale ed esadecimale →): la rete va da 192.192.192.0 a 192.192.207.255 (broadcast, host tutti a 11). Per C il terzo ottetto è 0=0000000020=00000000_2: varia da 0000 0000 =0=0 a 0000 1111 =15=15, quindi da 128.128.0.0 a 128.128.15.255. Se invece si usasse per sbaglio una /24, 128.128.0.1 e il router 128.128.15.254 risulterebbero in reti diverse (128.128.0.0 e 128.128.15.0) e non si vedrebbero (Subnetting e supernettingIl subnetting divide un blocco di indirizzi in sottoblocchi più piccoli allungando la maschera ($n_{\text{sub}}=n_{\text{rete}}+s$, con $2^s$ sottoreti); il supernetting (aggregazione CIDR) fa l'opposto, accorciando il prefisso per unire blocchi contigui in uno più grande. Regole di progetto: ogni sottorete ha un numero di indirizzi potenza di 2 ($M=2^k\ge$ host richiesti $+2$), prefisso $n=32-k$, indirizzo iniziale multiplo di $M$; si assegnano prima le sottoreti più grandi. Per aggregare $2^j$ blocchi di prefisso $n$ servono blocchi contigui il cui primo indirizzo sia multiplo della dimensione dell'aggregato, e il nuovo prefisso è $n-j$.Subnetting e supernetting →, Algebra di Boole e porte logicheVariabili booleane, operatori AND, OR, NOT e derivati (NAND, NOR, XOR, XNOR) con tabelle di verità; assiomi e teoremi dell'algebra di Boole, De Morgan; porte logiche e completezza di NAND e NOR; semplificazione algebrica con esempio.Algebra di Boole e porte logiche → per l'AND tra indirizzo e maschera).

Dettagli da notare: le due LAN B e C sono /20/20, cioè 4094 host, e il loro ultimo indirizzo utilizzabile è 192.192.207.254 (per B) e 128.128.15.254 (per C), che sono gli indirizzi dei router; per questo l'esercizio avverte: «reti diverse hanno maschere diverse», e ifconfig va sempre usato con il prefisso. Ogni router ha tre reti collegate direttamente e tre «lontane».

Esercizio 1: creare le macchine e assegnare gli indirizzi

Con i v-commands (una macchina alla volta, vedi Katharà - emulare una reteKatharà è un emulatore di rete: ogni dispositivo (host, router, server) è un container Docker, e i container sono collegati da "domini di collisione" virtuali (reti locali). Un laboratorio è una cartella con lab.conf (topologia), un file <dispositivo>.startup per ogni macchina (comandi eseguiti all'avvio) e, se serve, una cartella per dispositivo con i file da copiare nel suo filesystem. Si avvia con lstart, si ferma con lclean; le macchine si configurano con ifconfig, si provano con ping e si osservano con tcpdump (file .pcap da aprire con Wireshark).Katharà - emulare una rete →):

bash
kathara vstart -n pc1 --eth 0:A                # pc1 con eth0 sul dominio A
kathara vstart -n r1 --eth 0:Y 1:X 2:A         # r1: eth0 su Y, eth1 su X, eth2 su A

--eth 0:Y 1:X 2:A si legge «interfaccia 0 sul dominio Y, interfaccia 1 sul dominio X, interfaccia 2 sul dominio A». Lo stesso con gli altri dispositivi (r2: 0:Z 1:Y 2:C; r3: 0:X 1:Z 2:B; pc2 0:B; pc3 0:C). Come laboratorio completo si scrive lab.conf con le stesse righe (r1[0]=Y, r1[1]=X, r1[2]=A, ...) e un .startup per macchina.

Indirizzi (in ogni macchina, ifconfig con maschera e broadcast):

bash
# pc1
ifconfig eth0 96.96.0.1 netmask 255.255.255.0 broadcast 96.96.0.255 up
# r1
ifconfig eth0 10.0.0.1 netmask 255.255.255.252 broadcast 10.0.0.3 up      # collegamento Y
ifconfig eth1 30.0.0.2 netmask 255.255.255.252 broadcast 30.0.0.3 up      # collegamento X
ifconfig eth2 96.96.0.254 netmask 255.255.255.0 broadcast 96.96.0.255 up  # LAN A

L'ultima riga di r1 mette eth2 nella rete A con lo stesso broadcast di pc1: devono coincidere. Per gli altri dispositivi vale la tabella sopra; per esempio

bash
ifconfig eth0 192.192.192.1/20 up       # su pc2
ifconfig eth0 128.128.0.1/20 up         # su pc3
ifconfig eth2 128.128.15.254/20 up      # su r2 (LAN C)
ifconfig eth2 192.192.207.254/20 up     # su r3 (LAN B)

Esercizio 2: le tabelle di instradamento

Regole del foglio: gli host possono avere una rotta predefinita; i router solo rotte statiche, il default è vietato.

Host. Una sola uscita ciascuno, il router della propria LAN:

bash
pc1: route add default gw 96.96.0.254          # r1.eth2
pc2: route add default gw 192.192.207.254      # r3.eth2
pc3: route add default gw 128.128.15.254       # r2.eth2

Router. Ogni router ha tre reti lontane (quelle a cui non è collegato) e serve una rotta per ognuna:

Router Rete lontana Next hop Interfaccia
r1 Z = 20.0.0.0/30 10.0.0.2 (r2) eth0
r1 C = 128.128.0.0/20 10.0.0.2 (r2) eth0
r1 B = 192.192.192.0/20 30.0.0.1 (r3) eth1
r2 X = 30.0.0.0/30 10.0.0.1 (r1) eth1
r2 A = 96.96.0.0/24 10.0.0.1 (r1) eth1
r2 B = 192.192.192.0/20 20.0.0.2 (r3) eth0
r3 Y = 10.0.0.0/30 30.0.0.2 (r1) eth0
r3 A = 96.96.0.0/24 30.0.0.2 (r1) eth0
r3 C = 128.128.0.0/20 20.0.0.1 (r2) eth1

Comandi (i dispositivi sono tutti vicini, quindi il next hop è sempre l'indirizzo di un'interfaccia sul collegamento diretto):

bash
# r1
route add -net 20.0.0.0/30 gw 10.0.0.2 dev eth0         # Z passa da r2
route add -net 128.128.0.0/20 gw 10.0.0.2 dev eth0      # C è dietro r2
route add -net 192.192.192.0/20 gw 30.0.0.1 dev eth1    # B è dietro r3
# r2
route add -net 30.0.0.0/30 gw 10.0.0.1 dev eth1
route add -net 96.96.0.0/24 gw 10.0.0.1 dev eth1
route add -net 192.192.192.0/20 gw 20.0.0.2 dev eth0
# r3
route add -net 10.0.0.0/30 gw 30.0.0.2 dev eth0
route add -net 96.96.0.0/24 gw 30.0.0.2 dev eth0
route add -net 128.128.0.0/20 gw 20.0.0.1 dev eth1

Perché sono corrette:

  • ogni rotta ha un next hop in una rete direttamente collegata al router (per esempio 10.0.0.2 sta nella Y, collegata a eth0 di r1);
  • per le reti /30/30 X, Y, Z la scelta tra i due percorsi è indifferente: sono tutti a un salto. Per esempio r1 verso Z può passare da r2 (10.0.0.2) o da r3 (30.0.0.1); si è scelta r2. In termini di salti, l'unica differenza è per l'indirizzo 20.0.0.2 (di r3), che passando da r2 costa un salto in più che passando da r3;
  • le reti lontane A, B, C si raggiungono sempre per il percorso più corto (un solo router intermedio).

Simulando l'inoltro hop per hop con Python (ricerca del prefisso più lungo su ogni router) si verifica che tutti i 60 ping richiesti (ogni dispositivo verso ogni interfaccia di ogni altro, con risposta) hanno un percorso di andata e di ritorno.

Da dove vengono i 60 ping. Le interfacce totali sono 3 (PC)⋅1+3 (router)⋅3=123\,(\text{PC})\cdot1+3\,(\text{router})\cdot3=12. Ogni PC ha 11 interfaccia e deve contattare le altre 12−1=1112-1=11: 3⋅11=333\cdot11=33. Ogni router ne ha 33 e deve contattare le altre 12−3=912-3=9: 3⋅9=273\cdot9=27. Totale 33+27=6033+27=60.

Come un router sceglie la rotta (esempio). r1 riceve da pc1 un pacchetto per 128.128.0.1. Confronta l'indirizzo con ciascuna riga della tabella, applicando la maschera della riga: 128.128.0.1 AND 255.255.255.252 non è né 10.0.0.0 né 30.0.0.0 né 20.0.0.0 (reti collegate o di collegamento), non è 96.96.0.0/24; con la rotta 128.128.0.0/20, 128.128.0.1 AND 255.255.240.0 == 128.128.0.0: coincide, quindi il next hop è 10.0.0.2 (r2). Se più righe corrispondono si sceglie quella con il prefisso più lungo (la più specifica); qui ne corrisponde una sola. Il ttl tra i PC è 64−2=6264-2=62 perché il pacchetto attraversa due router (per esempio pc1 →\to r1 →\to r2 →\to pc3), e ognuno sottrae 11.

Provare tutti i ping

Il foglio dice: TRY ALL THE PINGS. Per r1 sono i ping verso eth0 di pc1, pc2, pc3 e verso eth0, eth1, eth2 di r2 e di r3. Per non scriverli a mano si usa uno script nella cartella condivisa /shared:

bash
#!/usr/bin/env bash
# show_pings.sh: prova un ping verso ogni nome della lista
pcins="pc1 pc2 pc3 r1e0 r1e1 r1e2 r2e0 r2e1 r2e2 r3e0 r3e1 r3e2"
for pcin in ${pcins}
do
    if [[ "${pcin}" != *"${HOSTNAME}"* ]]            # salta se stesso
    then
        ping_status=`ping -w 1 -c 1 ${pcin} | grep ", 0%" > /dev/null 2>&1`   # un solo pacchetto, attesa 1 s
        if [ $? -eq "0" ]
        then echo "ping from ${HOSTNAME} to ${pcin}: OK"
        else echo "ping from ${HOSTNAME} to ${pcin}: Fails"
        fi
    fi
done

Spiegazione: -c 1 invia un solo pacchetto, -w 1 aspetta al più un secondo, grep ", 0%" cerca «0% packet loss» nella riga delle statistiche e il codice di uscita di grep dice se è andato a buon fine. I nomi (r1e0, r2e1, ...) sono definiti in un file /etc/hosts copiato da /shared: r1e0 è 10.0.0.1, r1e1 è 30.0.0.2, e così via (la cartella shared contiene anche resolv.conf e un .bashrc_add che stampa un messaggio di benvenuto). Lo script COLLECT_RESULTS.sh lancia questo controllo su tutte e sei le macchine con kathara exec e calcola la percentuale di ping riusciti (qui 100%100\%).

Esercizio 3: e se si potessero usare i default?

Con rotte predefinite le tabelle dei router si accorciano, ma i percorsi possono allungarsi e, in una rete con un anello, ci si può infilare in un giro che non finisce.

Caso estremo: un solo default per router, disposti in cerchio (r1 →\to r2 →\to r3 →\to r1). Ogni tabella ha una sola rotta, ma:

  • pc3 →\to pc1 passa per r2, r3, r1 (tre router) invece di r2, r1 (due), perché r2 manda tutto a r3;
  • r1 →\to 192.192.192.1 (pc2) passa per r2 e r3 invece di r3 soltanto;
  • un pacchetto verso un indirizzo che non esiste gira r1 →\to r2 →\to r3 →\to r1 fino a quando il TTL va a 00 e ICMP time exceeded lo ferma.

Compromesso efficiente: un default più le rotte specifiche per i percorsi in cui il default non è il più breve. Esempio che mantiene tutti i percorsi più corti (verificato con Python): r1 default verso r2 e rotta specifica per B verso r3; r2 default verso r1 e rotta specifica per B verso r3; r3 default verso r1 e rotta specifica per C verso r2. Tabelle da due righe invece di tre. Quindi: più compatto, ma non sempre più efficiente nei percorsi; il vantaggio vero è per reti con un solo router di uscita, dove un default sostituisce un elenco intero.

Esercizio 4: traceroute e intestazioni IP

Quando tutte le reti sono collegate, da un estremo all'altro (per esempio da pc1 a pc3):

bash
root@pc1:~$ traceroute 128.128.0.1
traceroute to 128.128.0.1 (128.128.0.1), 64 hops max, 40 byte packets
 1  96.96.0.254   ...     # r1 (interfaccia verso pc1)
 2  10.0.0.2      ...     # r2 (interfaccia verso r1)
 3  128.128.0.1   ...     # pc3

(indirizzi attesi dalla topologia; ogni riga ha tre tempi, uno per ogni tentativo). Da pc1 a pc2 i router sono 96.96.0.254 (r1) e 30.0.0.1 (r3). Come funziona, e che cosa si vede in Wireshark sulle catture:

  1. traceroute manda datagrammi con TTL = 1, poi 2, poi 3 e così via (tre sonde per valore), di norma UDP verso porte alte;
  2. il datagramma con TTL 1 arriva a r1 che lo decrementa a 00: lo scarta e risponde a pc1 con un messaggio ICMP time exceeded (tipo 11), il cui indirizzo IP sorgente è quello del router (l'interfaccia da cui il router risponde, di solito quella da cui è entrato il pacchetto). Così pc1 impara il primo router;
  3. con TTL 2 il primo router lo inoltra (TTL 1), il secondo lo azzera e risponde: si scopre il secondo router, e così via;
  4. quando il pacchetto arriva alla destinazione finale non c'è nessun time exceeded: l'host risponde con ICMP destination unreachable - port unreachable (la porta UDP è chiusa), e traceroute si ferma.

Nelle intestazioni IP dei pacchetti sniffati si nota: indirizzo sorgente e destinazione invariati per tutte le sonde (pc1 e pc3); TTL che cresce di una unità a ogni gruppo di sonde; protocollo UDP (17) nelle sonde e ICMP (1) nelle risposte; il campo identification che cambia per ogni datagramma. I router non conoscono il percorso completo: ciascuno, quando vede la destinazione 128.128.0.1, applica la propria tabella (corrispondenza più specifica) e passa il datagramma al next hop, cioè i pacchetti «trovano» le connessioni intermedie salto dopo salto (vedi Protocollo ICMPIPv4 non ha meccanismi per segnalare o correggere gli errori né per interrogare host e router: li fornisce l'ICMP (Internet Control Message Protocol), un protocollo di rete i cui messaggi viaggiano dentro datagrammi IP con campo Protocol $=1$. I messaggi sono di errore (destination unreachable, tipo 3; time exceeded, tipo 11; redirect, tipo 5; parameter problem, tipo 12), sempre inviati alla sorgente originale e con l'intestazione IP più i primi 8 byte del datagramma che ha causato l'errore, oppure di interrogazione (echo request 8 e reply 0, timestamp 13-14). ICMP segnala ma non corregge. Con l'echo si fanno ping (RTT) e scoperta dell'MTU (bit D, codice 4, payload massimo $1500-20-8=1472$ byte); con time exceeded e port unreachable si fa traceroute ($n+1$ messaggi con TTL crescente). Attacchi: smurf e redirect.Protocollo ICMP → e Datagramma IP e frammentazioneIPv4 è un servizio senza connessione, non affidabile, best effort: i pacchetti (datagrammi) possono essere persi, corrotti, riordinati o ritardati. L'intestazione ha 20-60 byte (HLen conta parole da 4 byte, da 5 a 15); il campo Total Length (16 bit) dà la lunghezza totale fino a 65 535 byte; TTL limita i salti, Protocol identifica il protocollo trasportato (1 ICMP, 6 TCP, 17 UDP), il checksum copre solo l'intestazione. Se un datagramma è più grande dell'MTU del collegamento viene frammentato: solo il payload si divide, ogni frammento ha un'intestazione propria; l'Offset (13 bit) è in unità di 8 byte, MF=1 in tutti i frammenti tranne l'ultimo, e il riassemblaggio avviene solo a destinazione.Datagramma IP e frammentazione →).

Errori tipici

  • Dimenticare la maschera giusta: le LAN B e C sono /20/20, non /24/24.
  • Dimenticare una rotta di ritorno: serve una rotta per ogni rete lontana su ogni router.
  • Usare come next hop l'indirizzo dell'interfaccia sbagliata (per esempio 10.0.0.1 su r1 invece di 10.0.0.2).
  • Provare solo il ping tra i PC: il foglio chiede tutte le interfacce dei router.
  • Mettere un default dove è vietato (il foglio ammette solo rotte statiche sui router).

Versione ripasso

bash
# r1
route add -net 20.0.0.0/30 gw 10.0.0.2 dev eth0            # Z passa da r2
route add -net 128.128.0.0/20 gw 10.0.0.2 dev eth0         # C sta dietro r2
route add -net 192.192.192.0/20 gw 30.0.0.1 dev eth1       # B sta dietro r3

Lezioni in cui compare

Teoria collegata