Lo strato applicativo di Internet

Netkit

Netkit è sviluppato presso l'Università di Roma Tre, e permette di simulare su di un unico computer una architettura di rete in cui i diversi dispositivi sono realizzati mediante macchine Linux virtuali, eseguite in user space mediante l'approccio User Mode Linux (UML), ed interconnesse mediante dei Virtual Hub che simulano il dominio di collisione di una LAN. Ad ogni macchina virtuale è associata una finestra terminale mediante la quale è possibile configurare un routing statico, eseguire demoni di routing, DHCP, DNS, ed altri demoni applicativi per servizi email, web e VoIP. Dopo una breve introduzione all'utilizzo, saranno proposti esperimenti di realizzazione di architetture Internet.

Installazione e configurazione

Non approfondiamo questo aspetto, che consideriamo ottimamente descritto dalla documentazione allegata ai pacchetti da utilizzare. Nel seguito, ci riferiamo ad una installazione del software centralizzata presso una macchina del nostro laboratorio (reale), ed esportata mediante NFS (Network File System) presso il mountpoint /media/netkit/ delle altre macchine. Per rendere automatico il montaggio del filesystem remoto, occorre creare una directory vuota con sudo mkdir /media/netkit, ed aggiungere in coda al proprio file /etc/fstab l'istruzione

192.168.100.156:/usr/local/share/netkit /media/netkit nfs ro,hard,user,exec,noauto 0 0

che rende visibile presso la directory /media/netkit i contenuti presenti sul server NFS.

Variabili di ambiente

Affinché la nostra shell possa correttamente eseguire i comandi messi a disposizione da Netkit, occorre prima impartire i comandi

export NETKIT_HOME=/media/netkit
export MANPATH=:$NETKIT_HOME/man
export PATH=$NETKIT_HOME/bin:$PATH
. $NETKIT_HOME/bin/netkit_bash_completion

eseguiti automaticamente importando il file /media/netkit/ambiente con

source /media/netkit/ambiente

Per evitare di dover ogni volta eseguire il comando, può essere utile inserire le istruzioni di cui sopra in fondo al proprio .bashrc, che viene eseguito ogni volta che apriamo una nuova shell.

Architettura

Il progetto User Mode Linux (UML) permette di eseguire un kernel linux nello spazio utente, possibilità sfruttata per collaborare allo svilupo del kernel stesso, e che permette la sperimentazione dei servizi applicativi di rete che possono essere posti in esecuzione sopra ai diversi UML in esecuzione su di un medesimo computer.

Processo 1
Processo 2
...
Kernel Linux
Hardware
senza UML
 
Processo 2
...
Processo 1
User-Mode Linux
Kernel Linux
Hardware
con UML

Virtualizzazione

Ogni macchina virtuale (VM), rappresentata dall'area tratteggiata e detta guest, dispone di memoria, spazio disco ed una o più interfacce di rete, tutte rigorosamente virtuali, e messe a disposizione dal computer ospitante detto host.



I dischi virtuali sono realizzati mediante files presenti sulla macchina host e contengono, oltre al kernel UML usato dalle VM, i programmi che saranno da queste utilizzati.

Virtual Hub e TAP

L'interfaccia di rete dell'host non è necessariamente usata, in quanto le VM possono comunque comunicare tra loro mediante dei Virtual hub, che sono altri processi utente (uml_switch) che fanno uso di socket Unix per comunicare con le diverse VM, ed inoltrare i pacchetti che ricevono da una VM verso tutte le altre. Tutte le VM collegate ad uno stesso Virtual Hub condividono virtualmente lo stesso dominio di collisione, anche se essendo tutto simulato, le collisioni in realtà non avvengono; d'altra parte, lo stesso insieme condivide anche lo stesso dominio di broadcast, ossia tutte ricevono le stesse trame ethernet di broadcast.

Qualora una VM voglia comunicare con l'esterno dell'host, il virtual hub userà un device TAP, che è un device driver del kernel dell'host che realizza una interfaccia di rete speciale, connessa ad applicazioni utente anziché ad un mezzo fisico. Così, le trame Ethernet inviate ad una interfaccia TAP sono recapitate all'applicazione uml_switch, mentre quelle da essa prodotte appaiono al kernel come ricevute dall'interfaccia TAP. Il kernel dell'host configura quindi le funzioni di routing offerte da Iptables in modo da modificare l'indirizzo IP di origine delle trame provenienti dalle VM e dirette all'esterno, usando un indirizzo assegnato all'interfaccia reale dell'host, e realizzando una forma di Source NAT detta Masquerading.

Appresso, sono approfonditi i passi per realizzare la configurazione illustrata.

Terminale di controllo

Ogni VM comunica con l'utente per mezzo di una console virtuale che compare nello schermo del computer host, che quindi conterrà tante nuove finestre terminale quante sono le VM ospitate. Alla partenza di una VM, la finestra terminale corrispondente mostrerà i messaggi tipici della fase di boot del kernel Linux utilizzato da UML, dopodichè viene effettuato un login automatico come root, permettendo all'utente di impartire comandi da eseguire da parte della VM, come configurarne il routing, eseguire comandi di rete come ping e tcpdump, e lanciare demoni in grado di offrire servizi alle altre VM.

Gestione del Disco

Per quanto riguarda il disco delle VM, questo è virtualizzato da una coppia di files presenti nel disco dell'host, che contengono il Kernel UML da utilizzare, ed un filesystem che rappresenta una vera e propria mini-distribuzione Linux contenente gran parte dei programmi e comandi necessari - ma che viceversa non prevedono l'uso di interfacce grafiche. Tutte le VM attive condividono la stessa copia di filesystem, e salvano le (diverse) modifiche apportate su (diversi) files in accordo alla modalità Copy On Write (COW), in modo che ogni VM veda il filesystem equivalente al risultato della applicazione delle modifiche salvate sul file COW, al filesystem unico condiviso. Infine, la home directory (es, /home/labint) dell'utente che ha lanciato le VM è accessibile dall'interno delle console delle VM stesse, presso il path /hosthome. In tal modo si rende possibile lo scambio di files tra le VM e l'host, consentendo di poterli elaborare e/o visualizzare con strumenti grafici, come può avvenire nel caso di files contenenti il risultato della cattura di traffico, e successivamente visualizzati con wireshark presso l'host.

Comandi

Dopo aver correttamente inizializzato le variabili di ambiente, Netkit mette a disposizione una serie di comandi per eseguire e controllare le VM, sia una ad una (vtools) che collettivamente (ltools). La tabella che segue ne riassume l'utilizzo, e contiene i links alle rispettive pagine di manuale, che pure possono essere visualizzate anche dalla macchina host.

Comando Descrizione
V T O O L S
vstart crea una VM, eventualmente specificando nelle opzioni la configurazione iniziale
vconfig imposta una interfaccia di rete virtuale associata ad una VM
vlist elenca le VM correntemente attive
vhalt arresta in modo gentile una VM in esecuzione
vcrash arresta in modo brusco una VM in esecuzione
vclean ripristina lo stato iniziale del sistema, eliminando files temporanei e processi fuori controllo
L T O O L S
lstart esegue tutte o parte delle VM che realizzano una architettura di laboratorio
ltest verifica la corretta configurazione delle VM che compongono un laboratorio
lhalt arresta in modo gentile le VM in esecuzione per uno stesso laboratorio
lcrash arresta in modo brusco le VM in esecuzione per uno stesso laboratorio
linfo mostra le informazioni relative alle VM che fanno parte di un laboratorio (in esecuzione o meno)
lclean rimuove i files temporanei

netkit.conf

Le effettive modalità operative possono essere modificate sia lanciando i comandi su indicati con delle opzioni, sia intervenendo sul file netkit.conf. Ad esempio, l'opzione --xterm=gnome (o impostando TERM_TYPE=gnome nel .conf) cambierà la console xterm delle VM con quella usata anche da Ubuntu, mentre un valore pari a konsole o konsole-tab userà il terminale di KDE.

Il laboratorio virtuale

Sperimentiamo cosa ci offre una macchina virtuale, come è possibile modificarne il comportamento, e come simulare una intera rete con un solo comando. Come già indicato, occorre aver prima eseguito il comando . /media/netkit/ambiente.

Una singola Virtual Machine

Partenza, arresto, memoria

Può essere fatta partire con il comando

vstart singola 

impartito da un terminale dell'host, e che causa l'apertura di una finestra xterm (la cui barra del titolo riporta il nome singola, ma poteva essere qualunque altro nome) in cui compare la sequenza di messaggi di boot della nostra VM, e su cui ci troviamo automaticamente loggati come root. Impartendo i comandi ip link e ip addr notiamo come manchino le interfacce ethernet ethN, che possono essere aggiunte impartendo (sempre sulla macchina host) il comando

vconfig singola --eth0=COLL-DOM-A --eth1=COLL-DOM-B

il cui esito possiamo verificare ripetendo i comandi ip link e ip addr sulla VM, ed a cui possiamo ora assegnare un indirizzo come ad esempio

ip addr add 192.168.1.1/24 dev eth0
ip addr add 192.168.1.2/24 dev eth1
ip link set eth0 up
ip link set eth1 up

in cui gli ultimi due comandi attivano le interfacce (che ora risultano UP nel comando ip link), e creano l'instradamento per i prefissi della LAN di cui le interfacce fanno parte (verificabile con il comando ip route).

Se eseguiamo ora i comandi ps ax e top, constatiamo che la VM esegue un numero molto ridotto di processi, e che ha a disposizione una esigua quantità di memoria (32 MB). Quest'ultima può essere impostata in fase di partenza, mediante l'opzione -M del comando vstart. Per provare, prima  chiudiamo la VM, poi verifichiamo che non sia più attiva, quindi ri-lanciamola con il nuovo comando, ed infine verifichiamo il risultato; ovvero:

vhalt singola         # chiude la VM
vlist                 # verifica che si sia chiusa
vstart singola -M 64 --eth0=COLL-DOM-A --eth1=COLL-DOM-B
vlist

Il filesystem

Come anticipato, la VM non è dotata di interfaccia grafica, ma possiamo comunque esplorare agevolmente il suo filesystem, ricorrendo ad es. al programma Midnight Commander (mc). Questo ci consente, tra le tante altre cose, di

Possiamo constatare come siano presenti un gran numero di files che ci aspettiamo di trovare in una normale distribuzione, tutti presenti nell'unica immagine di disco /media/netkit/fs/netkit-fs. Inoltre, troviamo due directory particolari che permettono lo scambio di dati tra le VM e l'host, ovvero

In questo modo se una VM scrive qualcosa in una delle due directory, questo può essere acceduto anche dall'host, o anche da altre VM; viceversa, l'host può scriverci qualcosa, che poi è disponibile anche da parte delle VM.

D'altro canto, se la VM scrive qualcosa nel proprio filesystem (ad esempio, in /root/prova) questo viene salvato (in modo del tutto particolare) nel file singola.disk localizzato nella directory dell'host dalla quale la VM è stata lanciata, e che contiene solo le modifiche che la VM singola ha apportato al filesystem condiviso. Se la VM viene arrestata, e poi ri-lanciata, singola.disk è letto di nuovo, e le modifiche ri-applicate, in modo da non perdere il lavoro precedentemente svolto. Viceversa, se dopo aver arrestato la VM, il file singola.disk è cancellato dalla directory dell'host, una nuova esecuzione della VM mostrerà il filesystem intatto, come la prima volta.

Un intero laboratorio

Se desideriamo simulare uno scenario in cui sono presenti diverse VM, alcune delle quali assolvono la funzione di router per interconnettere domini di collisione diversi, occorre un modo più semplice di procedere, onde evitare di dover configurare le VM ad una ad una. A questo scopo Netkit definisce un laboratorio come il contenuto di una directory che definisce il comportamento di un insieme di VM, in modo da poterle eseguire e configurare con un solo comando. Proseguiamo l'esposizione facendo riferimento alla directory /media/netkit/labs/labtest, che copieremo presso /home/labint per poter lavorare su di un filesystem abilitato alla scrittura. Chi segue da casa, può usare la versione on-line.

Ogni directory presente in labtest rappresenta una diversa VM, ed il file labtest/lab.conf mostrato sotto descrive come queste sono interconnesse, con riferimento al seguente diagramma che mostra l'architettura desiderata, composta da due router che interconnettono a livello di rete tre diversi domini di collisione, e la cui simbologia è descritta dalla corrispondenza a lato.



In pratica, le lettere cerchiate rapresentano i domini di collisione, e i router sono realizzati da due VM (r1 ed r2) con due interfacce ciascuna. Il file lab.conf adotta una sintassi piuttosto semplice per rappresentare questa topologia, e contiene (oltre ad altre cose) le direttive

r1[0]=A
r1[1]=B
r2[0]=A
r2[1]=C

che rappresentano la connessione di r1 ai domini di collisione A e B mediante le interfacce eth0 ed eth1 rispettivamente, mentre r2 interconnette i domini A e C mediante le (sue) interfacce eth0 ed eth1. Infine, i comandi che impostano gli indirizzi da assegnare alle diverse interfacce vengono scritti nei files nomeVM.startup (nel nostro caso, r1.startup e r2.startup), anch'essi presenti nella directory labtest. Ad esempio, r1.startup contiene

ip addr add 30.0.0.1/30 dev eth0
ip addr add 10.0.0.1/8 dev eth1
ip link set eth0 up
ip link set eth1 up

A questo punto, l'intera configurazione può essere fatta partire dalla shell della macchina host, posizionandosi nella directory labtest, ed impartendo il comando lstart. E per chiudere tutto, basta un lhalt.

Esercitazione

Per iniziare a sperimentare l'uso di Netkit, svolgiamo i seguenti passi:

  1. apriamo una finestra terminale, e verifichiamo che il filesystem /media/netkit sia effettivamente montato
  2. importiamo le variabili di ambiente eseguendo . /media/netkit/ambiente
  3. creiamo la directory /home/labint/labs dove salvare lo stato delle sperimentazioni
  4. copiamo /media/netkit/labs/labtest in /home/labint/labs/labtest (utilizzando Nautilus, oppure con il comando cp con le opzioni di recursione)
  5. portiamo il terminale nella directory /home/labint/labs/labtest e verifichiamo quanto svolto finora impartendo il comando linfo, che dovrà dichiarare "The lab is made up of 2 virtual machines (r1 r2)"
  6. facciamo partire la simulazione con lstart, e posizioniamo gli xterm delle VM mantenendo sullo sfondo lo schema della rete
  7. eseguiamo sull'xterm di r2 il comando ping 30.0.0.1 che raggiunge l'altro router ed osserviamo il ritardo medio
  8. eseguiamo sull'xterm di r2 il comando ping 30.0.0.2 che raggiunge eth0 di r2, e confrontiamo il ritardo medio con il precedente
  9. eseguiamo sull'xterm di r2 il comando ping 10.0.0.1 che raggiunge eth1 di r1, e... constatiamo che la destinazione non può essere raggiunta. Perché?
  10. una volta deciso il metodo da adottare, attuiamolo, osserviamo il risultato con il comando ip route, ed eseguiamo di nuovo il ping per verificare che tutto sia andato a buon fine. Quindi
    1. memorizziamo il comando usato per estendere il routing nel file r2.startup
    2. abbattiamo le VM con il comando lhalt, rilanciamole con lstart, e verifichiamo che le cose funzionino ancora (il comando ping è rimasto nella history di r2, salvata nel suo file .disk)
  11. eseguiamo sull'xterm di r1 il comando tcpdump -i any -s 0 -w /hosthome/cattura.pcap che cattura il traffico su tutte le interfacce, e lo salva nel file /home/labint/cattura.pcap situato presso la macchina host, e quindi
    1. su r2 eseguiamo di nuovo il ping 10.0.0.1
    2. dopo una ventina di pacchetti, interrompiamo il ping con control-c
    3. interrompiamo anche il tcpdump con control-c
  12. osserviamo la presenza del file cattura.pcap nella /home/labint dell'host, apriamolo con wireshark, verifichiamone il contenuto
    1. sono presenti pacchetti arp? In caso negativo, interrogare la cache con il comando arp, e svuotarla con arp -d indirizzoIP. Quindi, ripetere il ping mentre è attivo un tcpdump -i any (senza salvare sul file). Ora, compaiono le richieste arp?
    2. lasciando proseguire il ping 10.0.0.1 su r2, proviamo ora ad eseguire su r1 un tcpdump -i eth1, catturando quindi ciò che passa sulla interfaccia di sinistra. Osserviamo qualcosa? no? Perché?

Laboratori

Gli sviluppatori di Netkit propongono alcune configurazioni preimpostate per l'approfondimento del funzionamento di diversi aspetti delle applicazioni di rete, così come fanno diversi corsi di studio, che pure lo hanno adottato. Durante il resto del corso, ne faremo uso.

RIP

Una esercitazione riguarda la sperimentazione del Routing Information Protocol, che ripercorre i passi descritti nella presentazione originale, relativa alla topologia mostrata appresso


Per eseguire il laboratorio, copiamo la directory /media/netkit/labs/official/netkit-lab_rip (ad es.) nella nostra scrivania, apriamo una finestra terminale, spostiamoci in quella directory, importiamo le variabili di ambiente con source /media/netkit/ambiente. e finalmente mandiamo il lab in esecuzione con lstart. Quindi, seguiamo i passi proposti nelle slides originali, eventualmente corredate da quelle che spiegano la configurazione dei demoni di routing offerti da zebra/quagga. Ma prima di far partire RIP con /etc/init.d/zebra start, attiviamo la cattura dei pacchetti su di un router (ad es. r4) mediante il comando tcpdump -i any -s 0 -w /hostlab/cattura.pcap; quindi lanciamo RIP sui diversi router, e dopo un pò di tempo (almeno un minuto) possiamo analizzare il tipo di traffico sviluppato. Osserviamo che i messaggi RIP sono indirizzati verso la porta 520 dell'indirizzo multicast 224.0.0.9, con un TTL IP pari ad 1, in modo che raggiungano tutti i router direttamente connessi, ma non li oltrepassino. Compare inoltre un diverso indirizzo multicast, il 224.0.0.22, verso cui sono diretti i pacchetti IGMP che annunciano l'adesione al 224.0.0.9. Possiamo osservare sia la presenza di messaggi di richiesta, con il quale il router stimola le risposte degli altri, sia messaggi di risposta, con il quale annuncia i propri instradamenti, a cui dopo un pò si aggiungono anche gli instradamenti appresi.

Aggiornamento della distribuzione delle VM

Può succedere di voler estendere la dotazione di programmi preinstallati nel filesytem usato dalle macchine virtuali, installando altri package dai repository di Debian, o scaricando e compilando i sorgenti. Sono possibili almeno due modi di procedere, ossia operare direttamente dall'host, oppure usare una VM configurata in modo da consentirgli di uscire su Internet. I dettagli di queste due modalità sono ottimamente illustrati presso il sito di Netkit; qui sotto, descriviamo invece solo il prerequisto al secondo metodo, perché di interesse più generale.

Uscire su Internet

Per attivare il device TAP, e permettere ad una VM di raggiungere il resto di Internet (ad esempio, per scaricare degli aggiornamenti), occorre mandarla in esecuzione con il comando

vstart gw --ethN=tap,TAPaddr,guestaddr

dove gw (mnemonico di gateway) è il nome della VM, ethN (N = 0,1,...) è l'interfaccia virtuale che vogliamo usare per uscire, tap indica il desiderio di connetterla con l'esterno, TAPaddr verrà assegnato all'interfaccia TAP dell'host, e guestaddr sarà assegnato all'interfaccia (virtuale) della VM. Come risultato, la VM userà TAPaddr come suo default gateway, e l'host eseguirà a sua volta il forward verso il proprio DG. Oltre a queste assegnazioni, il comando vstart provvede anche ad impostare iptables dell'host, in modo che il traffico in uscita dal TAP sia NATtato con il suo IP pubblico, e che quelli di risposta siano inoltrati alla VM per mezzo del TAP. Le cose di cui tener conto in questa operazione, sono che

esempio:

vstart gw --eth0=tap,10.0.1.1,10.0.1.2

Riferimenti

x
Logo

Lo Strato Applicativo
di Internet

Dal TCP al VoIP, dal DNS all'Email alla crittografia, tutto ciò che accade dietro le quinte di Internet, completo di cattura del traffico.
Scopri come effettuare il download, ricevere gli aggiornamenti, e contribuire!


Realizzato con Document made with Kompozer da Alessandro Falaschi -
Capitolo: Investigazioni di Rete