Lo strato applicativo di Internet
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.
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.
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.
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.
senza UML
|
|
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.
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.
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.
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.
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 |
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.
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.
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 |
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.
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.
Per iniziare a sperimentare l'uso di Netkit, svolgiamo i seguenti passi:
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.
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.
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.
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 |
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!