Strato Applicativo di Internet

Transcript

Strato Applicativo di Internet
Alessandro Falaschi
Lo strato applicativo di Internet
Web edition - Maggio 2008
Autore
Alessandro Falaschi
Copertina
Marco Sebastiani
Editing
Composto in HTML con
Renderizzato in PDF con Prince
Licenza
Creative Commons
Attribuzione - Non commerciale - Condividi allo stesso modo
Liberatoria L'eventuale inclusione non autorizzata di materiale protetto da copyright è da considerasi
transitoria, almeno fino a quando non si avrà il tempo di riprodurre delle copie originali dello
stesso. Ove possibile, sono forniti i riferimenti all'origine del materiale. L'autore si impegna alla
rimozione immediata dei contenuti che saranno ritenuti lesivi dei diritti altrui.
2
Prefazione
Questa è la versione PDF del materiale didattico organizzato per l'erogazione di un corso
universitario del terzo anno della Laurea in Ingegneria dell'Informazione presso la sede di
Cisterna di Latina dell'Università Sapienza di Roma.
Sono presi in esame quegli aspetti e tecnologie del software, rilevanti per i sistemi di
telecomunicazione basati su Internet, con particolare riguardo a quanto a disponibile come
Software Libero. Da sempre, le telecomunicazioni sono state associate all'idea di telefono: da
alcuni anni a questa parte, è sempre più sensato pensarle invece come rese possibili da un
computer connesso ad Internet.
Partendo dalle basi operative di una rete IP, si illustra l'interfaccia socket, che permette alle
applicazioni di comunicare in rete, e si descrive come queste possono essere raggiunte attraverso
l'uso di Nomi a Dominio. Sono quindi illustrati i concetti legati alle comunicazioni email ed ai loro
formati, assieme ai meccanismi di autenticazione e confidenzialità, ed approfonditi gli aspetti di
sicurezza. Si passa poi a descrivere il mondo del Web, dei linguaggi di descrizione, dell'HTTP, CGI
e CMS. Infine, si affronta il tema della Telemedialità, con le applicazioni VoIP, Video, e di
collaborazione.
Parallelamente agli aspetti descrittivi, il corso prevede un intenso programma di prove pratiche
di laboratorio, in cui si potranno toccare con mano i componenti della architettura Internet, e si
potrà verificare la loro interazione effettiva.
Contenuti
1.
2.
3.
4.
5.
6.
7.
Network Programming
Risoluzione degli indirizzi applicativi
Posta Elettronica
Sicurezza
WWW
VoIP
Streaming
Esercitazioni
1.
2.
3.
4.
5.
6.
7.
8.
9.
Mondo Linux
Cattura del traffico e uso dei Socket
Investigazioni di Rete
Domain Name System
Posta Elettronica
Aspetti di sicurezza
HTML e CSS
Server Apache
OpenSER e Twinkle
Licenza
Prefazione
Licenza
I contenuti di questo testo sono frutto di un lavoro di ricerca e raccolta operata a partire da
svariate fonti, sia editoriali che di accesso pubblico. Ovunque si sia ritenuto opportuno lo sforzo
di un approfondimento, è stato inserito un rimando a risorse reperibili in rete, in particolare
presso Wikipedia, che per la sua vocazione alla neutralità del punto di vista, rappresenta una
impagabile fonte di conoscenza. Alcune delle illustrazioni presenti nel presente testo, sono state
invece tratte da pubblicazioni editoriali, senza nessuna richiesta di consenso, e per quelle, spero
di non aver commesso nessuna azione illegale. Quel che invece è il frutto di un contributo
assolutamente personale, ossia il lavoro di sintesi e raccordo tra i diversi argomenti, viene
rilasciato sotto una licenza Creative Commons.
Edizione
• Web Edition: Maggio 2008
• Prima edizione PDF (generata con Prince): Aprile 2008
• Inizio del corso: Gennaio 2007
4
Lo strato applicativo di Internet
Network programming
In questo capitolo sono illustrati i meccanismi di base che consentono ad un programma
(applicazione) in esecuzione su di un computer ospite (host) di comunicare con un altro, posto ad
una diversa estremità della rete Internet.
• Trasmissione Internet
•
•
•
•
Commutazione di circuito, instradamento, multiplazione
Commutazione di pacchetto
Modello Internet
Stratificazione funzionale
• Incapsulamento
• Lo stack dei protocolli, dall'applicazione alla trasmissione
• Indirizzi Internet
• IP: lo strato di rete
•
•
•
•
•
•
Intestazione IP
Instradamento
Maschera di sottorete
Router e tabelle di routing
Sistemi autonomi
Indirizzi privati e NAT
• Rete locale: strato di collegamento
• Intestazione Ethernet
• Risoluzione ARP, broadcast
• Riassumendo
• Bridge e switch
• TCP e UDP: strato di trasporto
•
•
•
•
•
•
•
•
•
•
•
•
Servizio con o senza connessione
Canale virtuale e circuito virtuale
Arricchimento del servizio di rete
Controllo di errore, di flusso, e congestione
Intestazione TCP
Entità TCP
Apertura connessione
Protocollo a finestra
Controllo di errore
Controllo di flusso
Controllo di congestione
Esempio di capture
• Applicazioni di rete
• Tipologie di serventi
• Comunicazione tra processi in rete
• Creazione di un socket
• Utilizzo dei socket
Trasmissione Internet
Network programming
• Processi e Fork
• Un esempio di server parallelo
•
•
•
•
•
Segnali
Errori
Opzioni del socket
Indirizzi speciali
Rappresentazione degli interi e reperimento degli indirizzi
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Big endian
Little endian
Host to Network Order
Network to Ascii
gethostbyname
Un esempio di client
Connessioni di tipo DGRAM
ICMP
Frammentazione di pacchetto e riassemblaggio
I/O multiplato sincrono
Socket non bloccante
Client broadcast
Riepilogando
Riferimenti
Trasmissione Internet
Il modello Internet stabilisce che i servizi di telecomunicazione siano localizzati ai bordi della
rete, mentre la rete svolge esclusivamente la funzione di recapitare le unità informative da un
estremo all'altro. Ciò costituisce una enorme differenza rispetto alle tradizionali reti
telefoniche, in cui si è praticamente vincolati ad usare i servizi offerti dal proprio operatore, il
quale ci consente l'accesso alla rete. Per questo, il modello di trasmissione Internet si traduce in
• una netta separazione di ruoli tra gli operatori di telecomunicazioni, ed i fornitori di
servizi;
• una maggiore concorrenza tra fornitori di connettività da un lato, e fornitori di servizi
dall'altro;
• possibilità di sviluppo di servizi innovativi, replicabili e indipendenti.
Lo studio delle applicazioni Internet, pertanto, potrebbe essere svolto in modo quasi del tutto
indipendente dalla comprensione del funzionamento della rete Internet; d'altra parte, una
percezione di ciò che avviene dietro le quinte (e come vedremo, anche all'interno del nostro
computer di casa) aiuta senz'altro nella ottimizzazione delle prestazioni.
Lo origini di Internet sono legate all'esigenza del Dipartimento della Difesa (DoD) degli USA di far
comunicare tra loro computer di diversa fabbricazione. Alla base del funzionamento di Internet,
troviamo le caratteristiche di
•
•
•
•
poter continuare a funzionare anche in presenza di malfunzionamenti ed anomalie;
assenza di un controllo centralizzato;
trasmissione numerica di unità autonome denominate pacchetti dati;
adozione di specifiche pubbliche e replicabili da costruttori indipendenti.
In questa prima parte del capitolo, ci occupiamo appunto di descrivere i meccanismi di
funzionamento alla base della rete Internet. Ma prima di tutto, vanno definiti alcuni concetti di
base.
6
Lo strato applicativo di Internet
Alessandro Falaschi
Commutazione di circuito, instradamento, multiplazione
Descriviamo innanzitutto cosa non è Internet, illustrando
brevissimamente i principi di funzionamento di una rete telefonica
pubblica (PSTN), basata sulla commutazione di circuito, e sulla
multiplazione a divisione di tempo.
Agli albori della telefonia, ossia nell'epoca dei telefoni a
manovella, con la cornetta appesa al muro, la comunicazione si
basava sulla creazione di un vero proprio circuito elettrico, grazie
all'operato di un centralinista umano, che collegava fisicamente
tra loro le terminazioni dei diversi utenti. Nel caso in
cui intervengano più centralinisti in cascata, la chiamata risulta
instradata attraverso più centralini. Da allora, il termine
commutazione di circuito individua il caso in cui
• è necessaria una fase di setup precedente alla
comunicazione vera e propria, in cui vengono riservate le
risorse;
• nella fase di setup si determina anche l'instradamento della chiamata nell'ambito della
rete, che rimane lo stesso per tutta la durata della medesima;
• le risorse trasmissive restano impegnate in modo esclusivo per l'intera durata della
conversazione.
Le cose non sono cambiate di
molto (da un punto di vista
concettuale) con l'avvento
della telefonia numerica: in
tal caso, più segnali vocali
sono campionati e quantizzati
in modo sincrono, ed il
risultato (numerico) è
multiplato in una trama PCM, in cui viene riservato un intervallo temporale per ognuno dei flussi
tributari.
Il processo di multiplazione è tale
per cui il flusso binario risultante
da N tributari uguali, deve essere
trasmesso ad una velocità binaria
pari ad N volte quella del singolo
tributario. Ad esempio nel caso
del PCM, in cui si estraggono per
ogni sorgente 8000 campioni a
secondo, e ognuno di questi è
quantizzato con 8 bit, si ottiene (per ogni tributario) un contributo di
8 bit/campione * 8.000 campioni/secondo = 64.000 bit/secondo.
7
Trasmissione Internet
Network programming
La trama PCM si ottiene
multiplando assieme 32
tributari, e quindi la velocità
complessiva risulta essere di
64.000 * 32 = 2.048.000 bit/
secondo, comunemente
indicato come flusso a 2
Megabit, ovvero, in accordo
alla nomenclatura ITU-T,
come circuito E1. In realtà,
due dei 32 intervalli temporali possono essere riservati ad informazioni di segnalazione, ma
questo... potrà essere oggetto di altri corsi.
Per ciò che ci riguarda, possiamo concludere questa brevissima rassegna, specificando che
nell'attraversamento di nodi di commutazione, più flussi PCM possono essere ulteriormente
raggruppati, producendo quella che viene indicata come gerarchia digitale plesiocrona (PDH),
attualmente sostituita dalla gerarchia digitale sincrona (SDH).
Commutazione di pacchetto
Una grande differenza tra il caso della trasmissione di segnale vocale (sia pur digitalizzato) e
quello della trasmissione dati, è che in questo secondo caso non è necessario impegnare il mezzo
trasmissivo in modo esclusivo, ma la trasmissione può avvenire in modalità sporadica, ed i dati
inviati ad intervalli irregolari. Questo motivo, assieme alla dimensione variabile delle singole
comunicazioni, porta a suddividere la comunicazione in unità autonome indicate come pacchetto
dati.
La trasmissione
dei pacchetti può
avvenire in
forma multiplata
(ovvero, condividendo
lo stesso mezzo
trasmissivo tra più
comunicazioni) in modo
statistico, ovvero senza
riservare con esattezza risorse a questo o quel tributario. Infatti, in questo caso il multiplatore si
limita ad inserire i pacchetti ricevuti in apposite code, da cui li preleva per poterli trasmettere
in sequenza. La presenza di code, comporta
• la presenza di un ritardo variabile ed impredicibile
• la possibilità che la coda sia piena, ed il pacchetto in ingresso venga scartato
Per contro, se ogni pacchetto reca con sé le informazioni necessarie al suo recapito, la rete di
trasmissione non necessita di una apposita fase di setup dell'instradamento: nel caso della
commutazione di pacchetto, ogni pacchetto fa caso a sè.
Modello Internet
Ora che abbiamo discusso le differenze più evidenti tra reti a circuito e reti a pacchetto, e prima
di sviluppare la descrizione delle modalità di sviluppo di una applicazione Internet, ovvero di un
programma che operi tramite questa rete, affrontiamo l'analisi dei meccanismi alla base del
funzionamento effettivo di Internet, assieme alle tecnologie di collegamento e di trasmissione
più comunemente adottate in quest'ambito. L'insieme di questi aspetti, porta alla definizione di
8
Lo strato applicativo di Internet
Alessandro Falaschi
un modello concettuale, che si basa sulla stratificazione funzionale, sulla pacchettizzazione e
sull'incapsulamento dei dati.
Stratificazione funzionale
Nel 1978 l'International Organization for Standardization emise uno standard denominato Open
Systems Interconnection, che definisce una nomenclatura di riferimento per la descrizione di
come dei Sistemi Aperti possano comunicare tra loro, allo scopo di favorire l'interoperabilità tra
costruttori diversi.
Nella figura (tratta da MMC) viene evidenziato come si possa stabilire una relazione gerarchica
tra le diverse funzioni, individuando un pila (stack) di strati (layer). Le entità di pari livello N
sono da ritenersi virtualmente in colloquio tra loro (tra pari, o peer), mediante lo scambio logico
di Protocol Data Unit (PDU), mentre in effetti queste si avvalgono dei servizi offerti dallo strato
inferiore N-1, ed a loro volta, offrono dei servizi allo strato superiore N+1.
Incapsulamento
In base a questo formalismo, le PDU di livello N (o N PDU) sono costruite a partire dalle (N+1)
PDU, aggiungendo a queste delle intestazioni (Protocol Control Information, PCI) che permettono
lo scambio logico tra entità di livello N. Il meccanismo si ripete con lo strato immediatamente
soggiacente, via via finchè le unità informative non raggiungono lo strato più inferiore, a diretto
contatto con il mezzo trasmissivo, che permette lo scambio fisico tra entità.
L'aggiunta delle PCI alle PDU provenienti dallo strato superiore prende il nome di
incapsulamento, dato che ricorda molto da vicino il processo di racchiudere un plico ricevuto, in
una nuova busta esterna.
Il modello ISO/OSI individua sette livelli funzionali, di cui i più rilevanti per ciò che riguarda le
applicazioni Internet, sono quelli di trasporto e di rete, indicati rispettivamente come TCP (o
9
Trasmissione Internet
Network programming
UDP) e IP.
Lo stack dei protocolli, dall'applicazione alla trasmissione
La figura seguente mostra le relazioni che intercorrono tra i diversi strati funzionali presenti in
un computer connesso ad Internet.
In particolare, è mostrato come i processi applicativi (AP) affidino i dati generati/richiesti, ad
uno strato inferiore (di trasporto, TCP o UDP). L'AP all'altro estremo della comunicazione, non si
avvede neanche dell'esistenza di uno strato di trasporto, e la trasmissione delle Application
Protocol Data Unit (APDU) sembra avvenire direttamente tra i due AP Client e Server.
Ma come fare per distinguere i diversi processi contemporaneamente in esecuzione al computer
ricevente? Ciò è possibile in base alle informazioni presenti nell'intestazione (header) aggiunta
alla PDU dallo strato di trasporto, che infatti contiene un numero di porta (altrimenti detto SAP,
o Service Access Point) che identifica l'AP con cui dialoga.
Il processo si ripete, invocando i servizi offerti dallo strato di rete (IP), che ha il compito di
recapitare i singoli pacchetti tramite i nodi (router) di Internet. Viene aggiunto un nuovo header
(IP), che contiene un protocol field in grado di specificare quale entità dello strato di trasporto
viene incapsulata. Infine, viene aggiunto un header ulteriore (di link), in cui un type field
identifica il protocollo di rete trasportato. La trama (frame) così composta, può essere
effettivamente trasmessa sul mezzo che interconnette i nodi di rete, e recapitata a quello con
l'indirizzo di collegamento specificato nel Frame Header.
10
Lo strato applicativo di Internet
Alessandro Falaschi
Nella figura sottostante, ovvero in quest'altra, viene posto in evidenza come i router si limitino a
dialogare solo fino allo strato di rete (IP) delle entità a cui sono collegate, senza cioè leggere
nulla più interno della intestazione IP.
Indirizzi Internet
Internet nasce per interconnettere reti diverse ed eterogenee, e coinvolge la coesistenza di
indirizzi di diversa natura, ognuno legato ad uno strato funzionale:
11
Trasmissione Internet
Network programming
Per ognuno dei quattro tipi di indirizzo, è previsto un meccanismo di traduzione nell'indirizzo
necessario allo strato inferiore, in accordo al seguente schema
Indirizzo
per lo strato applicativo
l'indirizzo prende il
nome di
URI
con la forma
proto://fqdn/
risorsa
oppure
proto:user@fqdn
per lo strato di rete, si
ha un indirizzo
IP
lo strato di
collegamento spesso è
una LAN Ethernet, e gli
indirizzi sono detti
Traduzione
• ogni protocollo proto (es HTTP, FTP) è associato di
default ad un indirizzo di trasporto (ad es porte TCP 80,
21), in accordo alle corrispondenze registrate presso
IANA, indicate anche come porte ben note. Viceversa, il
numero di porta può anche essere indicato in modo
esplicito, con una sintassi del tipo fqdn:port
• il Fully Qualified Domain Name fqdn si traduce,
mediante interrogazione al DNS, nell'indirizzo IP
necessario allo strato di rete per consegnare i pacchetti
alla LAN dove risiede l'host di destinazione
• risorsa, e user, costituiscono un sotto-indirizzamento
la cui semantica è definita nel contesto dell'applicazione
che gestisce proto
• i 4 bytes x.y.w.z dell'indirizzo IP sono utilizzati,
all'interno della rete locale, dal protocollo ARP per
conoscere l'indirizzo Ethernet dell'host di destinazione
• i 6 byte dell'indirizzo Ethernet vengono usati dallo strato
di collegamento per individuare un computer fisicamente
connesso alla stessa rete LAN
MAC
ovvero Media Access
Control
Ogni diversa classe di indirizzo ha un significato di localizzazione, relativo al proprio strato
funzionale, come ad esempio un indirizzo postale del tipo Persona/via e numero civico/Città/
Nazione è la concatenazione di 4 diversi indirizzi. Quindi, mentre un indirizzo MAC (Media Access
Control) individua un computer dentro una LAN, un indirizzo IP individua un computer su
Internet, ed un indirizzo di trasporto, una applicazione in esecuzione su quel computer. Nel resto
del corso, non approfondiremo le particolarità degli strati inferiori, se non per ciò che coinvolge
quelli applicativi.
IP: lo strato di rete
IP significa Internet Protocol, ed in effetti rappresenta la quintessenza della filosofia su cui è
basata Internet: ogni comunicazione è suddivisa in pacchetti, ognuno dei quali presenta nella
intestazione IP, gli indirizzi a 4 byte che identificano il computer di partenza e di destinazione.
12
Lo strato applicativo di Internet
Alessandro Falaschi
Intestazione IP
Si compone di un minimo di 20 byte, in 5 file da
4. Il campo VER indica quale versione si sta
utilizzando, quella tuttora in uso è IPv4. HLEN e
TLEN indicano rispettivamente la lunghezza
dell'header e di tutto il pacchetto, mentre TOS
codifica un Type of Service che può essere usato
per differenziare il tipo di traffico.
L'identificazione riporta lo stesso valore per
tutti i frammenti di uno stesso datagramma,
e l'Offset di frammento indica la posizione del
frammento nel datagramma, espresso come
multiplo di 8 byte.
Solo 2 dei tre bit di Flag sono usati, DF (Don't Fragment) per richiedere alla rete di non
frammentare il datagramma, e MF (More Fragments) per indicare che seguiranno altri frammenti.
Il TTL (Time To Live) determina la massima permanenza del pacchetto nella rete, il Protocollo
indica il tipo di pacchetto incapsulato, ovvero a chi consegnare il datagramma all'arrivo (ad es.
TCP o UDP), in accordo ai codici registrati presso IANA, ed infine Checksum serve per verificare
l'assenza di errori nell'header.
Gli Indirizzi IP di sorgente e destinazione individuano i computer all'interno di Internet, e servono
allo strato di rete per recapitare il messaggio e la risposta associata, mentre il campo Opzioni ha
una lunghezza variabile, può essere omesso, e consente ad esempio di richiedere il tracciamento
della serie di router attraversati.
I pacchetti IP non sono di dimensione fissa, ma possono variare tra un minimo ed un massimo:
• le dimensioni minime sono dettate sia dalla presenza della intestazioni, sia da
considerazioni legate al mezzo fisico che verrà usato per la trasmissione;
• quelle massime, pongono un limite alla probabilità che qualche bit del pacchetto inviato,
si affetto da errori di trasmissione. Con i 16 bit del campo TLEN, si ha un massimo
di 65,535 byte, mai raggiunto nella pratica. Dato che lo strato fisico delle reti attraversate
impone spesso una dimensione di pacchetto molto inferiore, lo strato di trasporto tenta di
consegnare allo strato IP segmenti di dimensione sufficientemente ridotta, tale da non
dover subire frammentazione.
Instradamento
Ogni computer connesso ad Internet è identificato globalmente mediante un indirizzo di rete
(associato appunto allo strato di rete, ossia, l'indirizzo IP) di 4 byte (es 151.100.122.171).
Se due computer sono connessi alla medesima rete locale (LAN), come nel caso dei computer
ospitati in uno stesso edificio, questi comunicano in modo diretto, come nel caso (#1) tra LH2 e
LH3 della figura seguente, mediante l'indirizzo Ethernet (o MAC) di sei byte, che identifica le
rispettive schede di rete. Il pacchetto passa inalterato, attraverso un dispositivo chiamato
switch, che si limita prendere in considerazione la sola intestazione di strato di collegamento.
13
Trasmissione Internet
Network programming
Quando l'indirizzo IP di destinazione è esterno alla LAN di partenza, come nel caso (#3), allora il
datagramma è inviato a destinazione in modo indiretto, per il tramite di un Host speciale
presente nella LAN, il Default Gateway (R1 nella figura), che svolge le funzioni di router verso il
resto di internet. Di li in poi, il pacchetto IP viene rilanciato di router in router, esaminando ogni
volta l'indirizzo di destinazione, ed inoltrando il pacchetto sulla interfaccia nella direzione
corretta, via via fino a quello che ha accesso alla LAN di destinazione.
La direzione giusta viene stabilita in base alla analisi di apposite tabelle di routing, che possono
modificarsi nel tempo, così come i collegamenti, possono andare a volte fuori servizio. Per questi
motivi, nulla vieta ai pacchetti di una stessa comunicazione di seguire instradamenti alternativi,
ed anzi è proprio questo ciò che accade:
Flash
Pertanto,
i pacchetti IP possono giungere a destinazione in un ordine diverso da quello di partenza.
14
Lo strato applicativo di Internet
Alessandro Falaschi
Maschera di sottorete
Ma come fa un computer, a capire che il destinatario è nella stessa LAN??
Innanzitutto, va detto che i computer che risiedono fisicamente sulla stessa LAN, devono avere
essere stati configurati con degli indirizzi IP tra loro simili, che abbiano in comune tra loro lo
stesso prefisso binario, un pò come i telefoni fissi di una stessa città, hanno numeri che iniziano
con lo stesso prefisso. Dei trentadue bit di indirizzo IP, la parte che costituisce il prefisso, e che
è la stessa per tutti i computer della LAN, ha una lunghezza ben determinata, ed è individuata in
base alla conoscenza della cosidetta maschera di sottorete, ovvero una sequenza di 4 byte i cui
bit sono posti (a partire dal più significativo) tutti ad 1, finché da un certo punto in poi, sono
tutti posti a zero. La lunghezza della sequenza di bit pari ad uno, rappresenta appunto di
quanti bit (a partire da sinistra) è composto il prefisso che identifica la LAN. Ad esempio, una
network mask pari a 255.255.252.0, lunga 22 bit, una volta applicata ad un indirizzo del tipo
192.168.121.10, fornisce un indirizzo di sottorete pari a 192.168.120.0/22, in quanto:
Indirizzo IP/maschera
192.168.121.10/22
solo i primi 22 bit identificano la LAN
IP in binario
11000000.10101000.01111001.00001010
tutti e 32 i bit sono l'indirizzo completo
parte sottorete
11000000.10101000.01111000.00000000
costituita dai primi 22 bit
indirizzo di sottorete
192.168.120.0/22
i bit oltre il prefisso sono posti a zero
L'indirizzo di sottorete così ottenuto, identifica un sottoinsieme di indirizzi IP contigui, che
nell'esempio sono tutti gli indirizzi tali che, ponendo a zero gli ultimi 32-22=10 bit, equivalgono
all'indirizzo 192.168.120.0. Questo insieme, può essere partizionato in ulteriori sotto-reti,
adottando una maschera più lunga. Ad esempio, i computer con indirizzo IP 192.168.120.X,
appartengono alla sottorete 192.168.120.0/24, contenuta dentro a quella con maschera /22.
In particolare, la sottorete con maschera di ventidue bit (/22), contiene al suo interno le quattro
LAN con maschera a 24 bit, ed indirizzo di sottorete 192.168.120.0/24, 192.168.121.0/24,
192.168.122.0/24, 192.168.123.0/24.
D.: Si, ma come fa il mittente a capire che il destinatario è nella sua stessa sottorete ?
R.: Mette in AND l'indirizzo IP di destinazione con la Network Mask, e confronta il risultato
con l'AND del proprio indirizzo, per la stessa maschera. Se i risultati coincidono, gli
indirizzi appartengono alla stessa LAN
Esempio: 192.168.121.32 e 192.168.122.45, messi in AND una maschera di lunghezza 22
bit, forniscono lo stesso risultato, ovvero 192.168.120.0. Morale, tutti i computer della stessa
LAN, devono utilizzare la stessa Network Mask!! Altrimenti, per potendo comunicare tra loro in
modo diretto, necessiterebbero della presenza di un router
Router e tabelle di routing
Un router ha almeno due interfacce di rete, appartenenti a due LAN (o sottoreti) diverse, ed
opera sui pacchetti scapsulandoli fino al livello di rete, ed esaminando l'indirizzo IP di
destinazione. Quindi, per ogni linea contenuta nelle proprie tabelle di instradamento, l'IP di
destinazione viene messo in AND con la maschera di sottorete, e verificato se l'IP appartiene o
meno alla sottorete associata. Al termine di questo precesso, nel caso si sia verificato più di un
successo, viene individuato tra questi quello relativo alla riga con il prefisso più lungo, ed il
pacchetto inviato sull'interfaccia associata a tale riga. Viceversa, nel caso in cui non si verifichi
nessuna corrispondenza, il pacchetto viene scartato, e viene generato un pacchetto ICMP
Network Unreachable diretto verso l'IP mittente del pacchetto scartato.
15
Trasmissione Internet
Network programming
Ad esempio, nel caso (#2), l'host mittente LH4 si avvede che il destinatario LS1 ha un IP che
appartiene ad una diversa sottorete, e spedisce il pacchetto usando l'indirizzo MAC del proprio
Default Gateway R2. Questo, anzichè reindirizzare il pacchetto verso R1 e di lì verso Internet, lo
inoltra correttamente sull'interfaccia che collega LS1.
Qui sotto, è mostrato un esempio di come potrebbero apparire le tabelle di instradamento IP,
per i router che interconnettono quattro diverse LAN. Per i diversi indirizzi di sottorete, è
indicato il router da utilizzare per raggiungerla.
Le tabelle di instradamento dei router sono popolate a seguito di continue comunicazioni con gli
altri router di Internet. Nel caso di esempio della figura soprastante, R1 annuncia ad R2, R3 e R4
la raggiungibilità della rete 11.0.0..0/8, provocando in questi l'inserimento dell'informazione che
per raggiunere quella rete, occorre consegnare il pacchetto ad R1. Quando R4 annuncia la sua
raggiungibilità per la rete 14.0.0.0/8, questo annuncio viene ri-propagato da R1, in modo che la
rete 14 risulti raggiungibuile per il suo tramite. Quindi, in termini semplificati, ogni router
annuncia a quelli a lui collegati, quali sottoreti può raggiungere, che così diventano raggiungibili
anche da questi secondi router, che a loro volta, propagano l'annuncio.
Il compito dei protocolli di routing, è quello di coordinare questo processo, rendendolo
efficiente, convergente, e pronto a recepire i cambiamenti di configurazione.
Nel caso in cui un router si accorga di conoscere gli istradamenti per tutte le sottoreti contenute
sotto una stessa network mask più corta, può leggitimamente aggregare gli instradamenti, ed
annunciare la raggiungibilità dell'unica sottorete più grande. Ad esempio, un router che avesse
accesso alle reti 192.168.120.0/24, 192.168.121.0/24, 192.168.122.0/24,
16
Lo strato applicativo di Internet
Alessandro Falaschi
192.168.123.0/24, annuncerà la raggiungibilità per la sola rete 192.168.120.0/22, che le
racchiude tutte e quattro.
Sistemi autonomi
Un Sistema Autonomo è un insieme di LAN, interconnesse da router, che intendono apparire al
resto di Internet come una unica entità, come ad esempio è il caso di un ISP, o di una azienda.
Per questo, un sistema autonomo si interconnette con gli altri solo mediante alcuni dei suoi
router, che annunciano all'esterno la raggiungibilità delle LAN interne. I protocolli di routing
eseguiti all'interno ed all'esterno sono diversi, e prendono rispettivamente il nome di Interior ed
Exterior routing protocols; in pratica, il protocollo di comunicazione ufficiale tra router di diversi
SA, è il Border Gateway Protocol (BGP).
Indirizzi privati e NAT
Ad un certo punto dello sviluppo di Internet, sembrava quasi che gli indirizzi IP stessero per
esaurirsi di lì a poco. Vennero prese una serie di contromisure, e si iniziò a fare un uso molto
diffuso delle classi di indirizzi privati. Si tratta di sottoreti che i router di Internet rifiutano di
inoltrare, e che quindi ognuno può usare nel suo privato, per creare una LAN disconnessa da
Internet.
Le classi di indirizzi privati sono descritte dagli indirizzi di sottorete 10.0.0.0/8, 172.16.0.0/12, e
192.168.0.0/16. Tutti gli altri indirizzi (con le dovute eccezioni), sono per contro detti pubblici.
Ma... la possibilità di uscire su Internet, esiste
anche per i computer con IP privato, ricorrendo ad
un dispositivo NAT (Network Address Translator). Si
tratta di un router potenziato, che sul lato
pubblico utilizza un IP (appunto) pubblico, e che
oltre ad inoltrare i pacchetti, li modifica. Ad
esempio nel caso del Source NAT, sostituisce all'IP
privato di un computer sorgente, con il proprio
(pubblico), ed al posto dell'indirizzo di trasporto
originario, ne mette un altro scelto da lui, in modo
che il destinatario creda di stare parlando con lui,
anzichè con il computer dotato di IP privato.
Quando torna un pacchetto di risposta, il NAT si
avvede che la porta di trasporto di destinazione è una di quelle scelte da lui, e ne usa il valore,
per sostituire di nuovo IP e porta, con quelle originariamente usate dal computer con IP privato,
a cui finalmente consegna il pacchetto.
Il principale svantaggio di un NAT, è che i computer con IP privato possono assumere solamente il
ruolo di Client, ma non di Server, dato che non possono ospitare servizi raggiungibili dall'esterno,
ovvero per i quali i pacchetti devono entrare prima di uscire. A meno di non configurare il
Router-NAT, in modo da redirigere le richieste indirizzate ad un particolare indirizzo di
trasporto, verso un computer ben preciso.
Rete locale: strato di collegamento
Soffermiamoci ora su ciò che accade al di quà del Default Gateway.
17
Trasmissione Internet
Network programming
Intestazione Ethernet
Quando l'indirizzo IP di destinazione ricade nella stessa sottorete (LAN) del trasmettitore, i due
computer (oppure computer e Default Gateway) possono comunicare direttamente, purché chi
vuol trasmettere, riesca a conoscere l'indirizzo fisico (o Ethernet, o MAC) del destinatario. In tal
caso, lo strato MAC Ethernet definito dall'IEEE 802.3, incapsula la SDU proveniente dal Logical
Link Control (LLC) definito dall'IEEE 802.2 (che a sua volta contiene il pacchetto IP) in accordo ad
un formato di trama Ethernet II (detto anche DIX) mostrato appresso.
Nel campo Type è presente un codice a 16 bit che indica il protocollo incapsulato (ad es. 0x0800
per IPv4), mentre nei campi indirizzo sorgente e destinazione, trovano posto gli indirizzi
Ethernet (di 6 bytes ognuno) delle interfacce di rete agli estremi del collegamento. La parte
disegnata in rosa, rappresenta il preambolo necessario al ricevitore per acquisire i sincronismi di
trasmissione, seguito da un codice Start Frame Delimiter che segnala l'inizio della intestazione
Ethernet.
Quando un computer della LAN, osserva transitare sull'interfaccia di rete un pacchetto che
riporta il suo indirizzo Ethernet nel campo destinazione, lo "tira su", e lo passa agli strati
superiori.
D.: Come fa il mittente a conoscere l'indirizzo Ethernet del destinatario, di cui conosce
l'indirizzo IP??
R.: per mezzo dell'Address Resolution Protocol (ARP)
Risoluzione ARP, broadcast
I pacchetti ARP sono anch'essi incapsulati nelle trame ethernet, in cui ora il campo type ha il
valore 0x0806. La figura seguente mostra l'ordine temporale con cui opera l'ARP, nel caso in
cui Host A voglia comunicare con Host B, trovandosi entrambi nella stessa LAN.
Ogni computer mantiene una cache (1)
delle risoluzioni (gli indirizzi MAC
associati agli IP) già ottenute di recente,
in modo da evitare il ricorso ad ARP ogni
volta. Le corrispondenza della cache
sono mantenute per un periodo breve,
(es 10 minuti), e possono essere
visualizzate con il comando arp -a.
La richiesta ARP (2) è inviata in
broadcast, un pò come se qualcuno si
affacciasse in corridoio, e gridasse: chi
ha questo IP ? Ciò si ottiene indirizzando
la richiesta ARP verso un indirizzo Ethernet di destinazione, pari ad una sequenza di uni. Le
18
Lo strato applicativo di Internet
Alessandro Falaschi
interfacce di rete di tutti i computer della LAN, quando osservano transitare un pacchetto
Broadcast, sono obbligate a riceverlo, e passarlo allo strato superiore, che valuta le eventuali
azioni da intraprendere. Host B quindi, invia la sua risposta ARP (4) in unicast, ossia usando
l'indirizzo Ethernet di Host A come destinazione, comunicando così il proprio indirizzo MAC, usato
come mittente.
Possiamo verificare ciò che si verifica effettivamente, analizzando il risultato di questo capture
prodotto con il comando ping www.libero.it, eseguito sul computer 192.168.120.40,
avendo impostato il Default Gateway verso 192.168.120.1, che ospita anche il DNS locale.
No. Time
Source
Destination
Protocol Info
--------------------------------------------------------------------------------------------------------------------1 0.000000
Intel_54:3b:a5
Broadcast
ARP
Who has 192.168.120.1? Tell 192.168.120.40
2 0.001191
Asiarock_5d:78:5d Intel_54:3b:a5
ARP
192.168.120.1 is at 00:13:8f:5d:78:5d
3 0.001207
192.168.120.40
192.168.120.1
DNS
Standard query A www.libero.it
4 0.104855
192.168.120.1
192.168.120.40
DNS
Standard query response CNAME vs-fe.iol.it A 195.210.91.8
5 0.105211
192.168.120.40
195.210.91.83
ICMP Echo (ping) request
6 0.131673
195.210.91.83
192.168.120.40
ICMP Echo (ping) reply
7 0.136285
192.168.120.40
192.168.120.1
DNS
Standard query PTR 83.91.210.195.in-addr.arpa
8 0.393369
192.168.120.1
192.168.120.40
DNS
Standard query response PTR vs-fe.iol.it
9 1.104211
192.168.120.40
195.210.91.83
ICMP Echo (ping) request
10 1.130009
195.210.91.83
192.168.120.40
ICMP Echo (ping) reply
11 1.130200
192.168.120.40
192.168.120.1
DNS
Standard query PTR 83.91.210.195.in-addr.arpa
12 1.131326
192.168.120.1
192.168.120.40
DNS
Standard query response PTR vs-fe.iol.it
13 5.103641
Asiarock_5d:78:5d Intel_54:3b:a5
ARP
Who has 192.168.120.40? Tell 192.168.120.1
14 5.103666
Intel_54:3b:a5
Asiarock_5d:78:5d ARP
192.168.120.40 is at 00:16:6f:54:3b:a5
Innanzitutto, osserviamo (p 1-2) la richiesta-risposta ARP necessaria a determinare l'indirizzo
Ethernet del DNS, in modo da poter inoltrare verso lo stesso, la richiesta (p 3-4) necessaria a
risolvere il nome di dominio www.libero.it in un indirizzo IP. Poi (p 5-6) osserviamo la
richiesta-risposta ICMP echo (notiamo come il DNS introduca una latenza di 10 msec, ed il ping
solo di 3 msec), fatta passare attraverso il Default Gateway, seguita a sua volta (p. 7-8) da una
richiesta di risoluzione inversa al DNS, eseguita allo scopo di poter scrivere a schermo il nome di
dominio di chi ha risposto al ping; notiamo che stavolta, la latenza del DNS è di 20 msec. Dopo la
seconda richiesta ICMP, osserviamo (p 11-12) una seconda richiesta di risoluzione inversa
indirizzata al DNS, che stavolta viene servita in modo praticamente immediato, essendo la
risposta già presente nella cache del DNS locale. Per finire, osserviamo (p. 13-14) una richiesta di
risoluzione ARP, diretta stavolta dal Default Gateway verso il computer su cui stiamo operando,
ed originata probabilmente dallo scadere della cache ARP del router.
Possiamo verificare come i pacchetti ARP siano privi di intestazione IP, essendo la loro
circolazione esclusivamente interna alla rete locale. Si veda Wikipedia, per una breve discussione
delle vulnerabilità introdotte da ARP.
Riassumendo
La figura seguente, illustra le fasi della risoluzione da URI a IP a MAC.
19
Trasmissione Internet
Network programming
Bridge e switch
Il protocollo Ethernet originario prevedeva solamente la trasmissione a 10 Mbit/sec mediante un
cavo coassiale su cui si affacciavano tutti i computer; lo stesso mezzo trasmissivo veniva quindi
usato "a turno" dai diversi computer, mediante ad una tecnica di accesso condiviso denominata
Carrier Sense Multiple Access, Collision Detect (CSMA/CD), attuata dallo strato MAC 802.3, su cui
non ci soffermiamo.
Attualmente, oltre a prevedere velocità di trasmissione di 100 Mbit/sec, 1 Gbit/sec e 10 Gbit/
sec, adottando due coppie ritorte, o la fibra ottica, i computer di una stessa LAN vengono
sempre più spesso interconnessi secondo una topologia a stella, o ad albero, i cui nodi di transito
sono denominati switch, ed i computer sono interconnessi su collegamenti full-duplex (es.
100BASE-TX). Gli switch sono dotati di più porte, ognuna delle quali gestisce le comunicazioni
con un diverso computer (oppure con un altro switch, od un router). In questo modo, più
20
Lo strato applicativo di Internet
Alessandro Falaschi
computer di una stessa LAN possono trasmettere simultaneamente, senza interferenze
reciproche, in quanto i domini di collisione restano separati per ognuna delle porte.
Lo switch non usa un proprio indirizzo Ethernet, ma instrada sulle porte in uscita le stesse
identiche trame che riceve sulle porte in ingresso. Quando un computer connesso allo switch
trasmette verso una destinazione per la quale non si è mai osservato traffico, le trame sono
ritrasmesse su tutte le porte; d'altra parte, ogni switch attraversato prende nota dell'indirizzo
Ethernet del mittente, e riempie una propria tabella di instradamento, mettendo così in
corrispondenza l'indirizzo, con la porta di provenienza.
Da quel momento in poi, ogni volta che lo switch riceverà un pacchetto indirizzato ad un
computer di cui conosce la porta di connessione, ritrasmetterà il pacchetto solo su quella porta,
evitando di disturbare gli altri.
Allo scopo di accellerare il processo di apprendimento da parte dello switch, è possibile che
all'accensione, i computer inviino dei pacchetti ARP di annuncio, detti gratuitous ARP, in cui
21
Trasmissione Internet
Network programming
affermano l'indirizzo MAC di se stessi. In tal modo, comunicano allo switch il proprio indirizzo
Ethernet; nel caso il computer abbia cambiato la porta di connessione, lo switch provvede anche
ad aggiornare la tabella di instradamento.
Uno strumento per stimolare l'emissione di richieste ARP, è l'uso del comando ping, che invia un
pacchetto ICMP (Internet Control message Protocol) di tipo Echo Request che, per raggiungere la
destinazione, suscita appunto una richiesta ARP. Nel caso in cui quest'ultima non dovesse
comparire, può essere benissimo il caso che la risoluzione sia già stata acquista dal proprio
computer, e salvata nella cache: questo può essere investigato, invocando il comando arp -a.
TCP e UDP: strato di trasporto
Come già specificato, lo strato di trasporto esiste solo nei terminali posti ai bordi della rete,
sorgente e destinazione delle unità informative generati dai processi applicativi (AP). Il
paradigma Internet prevede due modalità di trasporto, indicate come UDP e TCP, e che si
differenziano essenziamente per il fatto che
• UDP offre un servizio di trasporto a datagramma, non garantisce la corretta consegna dei
dati, e i pacchetti che compongono la comunicazione vengono trasmessi uno alla volta in
modo indipendente;
• TCP offre un servizio di trasporto a circuito virtuale, gestisce le eventuali ritrasmissioni
delle unità non ricevute, ed effettua il riordino dei pacchetti fuori sequenza. Nel TCP,
esiste una fase precedente alla comunicazione vera e propria, mediante la quale su
entrambi gli estremi vengono predisposti dei buffer, e viene creato uno stato presso i due
terminali, che tiene traccia dei pacchetti inviati.
Per meglio illustrare la genesi del termine con o senza connessione, e comprendere come lo
strato di trasporto possa arrichire la modalità di trasferimento delle informazioni offerta dallo
strato di rete, facciamo di nuovo un passo indietro.
Servizio con o senza connessione
Quando abbiamo definito la multiplazione statistica in una rete a commutazione di pacchetto,
abbiamo fatto un esempio basato su di un solo collegamento tra due nodi. Pur restando
nell'ambito di una rete a commutazione di pacchetto, sono definite due possibili diverse modalità
di instradamento dei pacchetti da uno nodo di rete all'altro. La prima è quella già discussa a
proposito della rete IP, ed è chiamata a datagramma, in cui ogni pacchetto
•
•
•
•
contiene l'informazione dell'indirizzo di destinazione,
viaggia in modo indipendente dagli altri che fanno parte della stessa comunicazione,
ogni nodo deve decidere da che parte reinviarlo,
può essere consegnato in un ordine diverso da quello con cui era partito.
In questo caso la trasmissione è detta senza connessione, a rimarcare il fatto che non esiste una
fase iniziale, in cui si individua un unico instradamento, e si riservano delle risorse. Dato che UDP
non aggiunge nulla a questa impostazione, limitandosi in pratica a specificare le porte sorgente e
destinazione, il risultato è che il servizio di trasporto offerto è detto anch'esso a datagramma, o
senza connessione.
Un approccio del tutto diverso, è quello delle reti a commutazione di pacchetto a circuito
virtuale, come la rete X.25, una architettura ormai praticamente abbandonata,
con origini precedenti ad Internet; lo stesso concetto, è poi stato nuovamente applicato
nell'ambito delle reti ATM ed MPLS. In questo caso, l'instradamento viene determinato una volta
per tutte all'inizio della trasmissione, durante una fase di richiesta di connessione, la cui
presenza determina appunto la denominazione di servizio con connessione. Dopodiché, i
pacchetti di uno stesso messaggio seguono tutti lo stesso percorso.
22
Lo strato applicativo di Internet
Alessandro Falaschi
Canale virtuale e circuito virtuale
La commutazione di pacchetto a circuito virtuale si basa su di una intestazione di pacchetto che,
anziché presentare l'indirizzo di rete del nodo di destinazione, contiene invece un identificativo
di connessione, che individua un canale virtuale (CV) tra coppie di nodi di rete, determinandone
l'appartenenza ad una delle diverse trasmissioni contemporaneamente in transito tra i due nodi.
Il CV presente nel pacchetto, funge da chiave di accesso alle tabelle di routing presenti nei nodi,
tabelle che sono ora generate nella fase di richiesta di connessione iniziale, durante la quale
vengono inviati dei pacchetti di controllo che contengono l'indirizzo di rete del nodo di
destinazione, che causano ai nodi attraversati la memorizzazioine della porta di uscita, che sarà
la stessa per tutti i successivi pacchetti dati appartenenti ad uno stesso messaggio.
Facciamo un esempio: una sorgente, a seguito
della fase di instradamento, invia i pacchetti
con identificativo CV = 1 al primo nodo
individuato dal ruoting. Consultando la propria
tabella, il nodo trova che il canale virtuale 1
sulla porta di ingresso (P.I.) A si connette al CV
3 sulla porta di uscita (P.U.) C. Ora i pacchetti
escono da C con CV = 3, ed una volta giunti al
nodo seguente sulla P.I. A, escono dalla P.U. B
con CV = 2, e giungono finalmente a
destinazione.
Nel collegamento tra due nodi, numeri di CV
diversi identificano le diverse comunicazioni in
transito, ed uno stesso numero di canale
virtuale, può essere riutilizzato su porte
differenti dello stesso nodo. La concatenazione
dei canali virtuali attraversati viene infine
indicata con il termine Circuito Virtuale, per
similitudine con il caso di commutazione di
circuito: tale similitudine trae origine dal fatto
che, essendo l'instradamento lo stesso per tutti i pacchetti, questi viaggiano per così dire in fila
indiana, e sono consegnati nello stesso ordine con cui sono partiti, un pò come se si fosse
tracciato un vero e proprio Circuito.
Arricchimento del servizio di rete
Anche se il TCP, essendo un protocollo di trasporto, non ha nulla a che fare con l'instradamento,
il fatto che garantisca al ricevitore la consegna dei pacchetti nello stesso ordine con cui sono
partiti, e che par fare questo, preveda una fase di setup precedente alla trasmissione vera e
propria, gli vale il merito di estendere anche a questo caso il termine di protocollo con
connessione, risolvendo così a livello di trasporto, il problema del corretto sequenziamento dei
pacchetti instradati attraverso una rete a datagramma.
Controllo di errore, di flusso, e congestione
Una serie di problemi legati alla inaffidabilità di una rete a commutazione di pacchetto, basata
sulla multiplazione statistica e sulle code, riguardano
• come ritrasmettere i pacchetti persi (controllo di errore);
• come permettere al ricevitore di rallentare l'invio (controllo di flusso)
23
Trasmissione Internet
Network programming
• come ridurre e/o sospendere le trasmissioni nel caso in cui le prestazioni della rete siano
eccessivamente degradate, in modo da non peggiorare la situazione (controllo di
congestione)
Un elemento comune alla soluzione di questi problemi, è costituito dalla numerazione
progressiva dei pacchetti spediti (il numero di sequenza), e da una serie di pacchetti di ritorno,
chiamati riscontri (o ACKnoledgment), mediante i quali il ricevitore conferma la corretta
ricezione. Questi elementi sono utilizzati nell'ambito dei protocolli riscontrati, detti anche
protocolli Automatic Repeat reQuest (ARQ), basati sull'uso di una finestra scorrevole, e
sviluppatisi per gestire la comunicazione diretta, a livello di collegamento, tra due entità, e poi
ri-utilizzati anche da un estremo all'altro della rete, a livello di trasporto, come avviene per il
TCP, oppure anche a livello applicativo, come devono essere pronte a fare le applicazioni che si
avvalgono del trasporto UDP.
Ad ogni buon conto, osserviamo esplicitamente che il TCP non invia riscontri negativi, ma solo
positivi. Nel caso di ricezione di un pacchetto corrotto, questo è assimilato a quello di un
pacchetto perso, per il quale non viene inviato nessun riscontro. Ogni pacchetto (che in questo
caso è chiamato segmento) ricevuto correttamente è riscontrato dal ricevente, ed in mancanza
di tale riscontro, una volta scaduto il timeout, il mittente provvede a ritrasmettere il segmento.
Intestazione TCP
L'intestazione TCP ha anch'essa dimensioni minime di 20 byte, in cui troviamo, tra le altre cose
• i numeri delle porte sorgente e destinazione, che individuano il processo applicativo che
lo ha prodotto, ed a cui è destinato il segmento;
• i numeri di sequenza, espressi nei termini di numero di bye trasmessi, che permettono
• di ri-ordinare i pacchetti ricevuti in base al Sequence number, depositandoli al
punto giusto, all'interno del buffer di ricezione;
24
Lo strato applicativo di Internet
Alessandro Falaschi
• di riscontrare i pacchetti ricevuti mediante l'Acknowledgement number, in modo
che il trasmettitore possa liberare i buffer di trasmissione di tutto ciò che è stato
riscontrato, ovvero di accorgersi se manca qualche riscontro, e quindi di
ritrasmettere il segmento corrispondente.
• un gruppo di 8 bit detti flag, che caratterizzano il tipo di pacchetto, come di apertura
(SYN) o di chiusura (FIN, RST) della connessione, ovvero contenente un riscontro (ACK), o
dei dati urgenti (PSH, URG)
• una dimensione di finestra, che indica quanti byte potranno essere accettati, a partire da
quello referenziato dall'ACK number, mediante la quale il ricevitore può modulare la
velocità del trasmettitore.
Entità TCP
Nella figura che segue viene evidenziato come i processi applicativi che risiedono nello user
space, accedano al servizio di trasporto offerto dagli strati inferiori che risiedono all'interno del
kernel, per mezzo di primitive dette socket. Al suo interno, l'implementazione della entità di
trasporto (in questo caso, TCP) immagazzina i dati in transito da/verso lo strato applicativo nei
send e receive buffer, mentre per dialogare con lo strato IP (che gli permette di usufruire del
servizio di rete) fa uso di ulteriori memorie che (in trasmissione) gli permettono di ri-trasmettere
gli eventuali pacchetti persi, e (in ricezione) consentono il corretto sequenziamento dei
pacchetti ricevuti.
Apertura connessione
Analizziamo più in dettaglio, il comportamento del TCP in corrispondenza della fase di
attivazione della connessione.
25
Trasmissione Internet
Network programming
Come illustrato nella figura a fianco, il
lato server (applicativo B) a seguito della
sequenza di system call socket(),
bind(), listen(), accept(), effettua
una cosiddetta apertura passiva, mentre il
lato client (applicativo A), con la
connect(), invia un primo segmento di
sincronizzazione, con il flag SYN attivo, in
cui comunica che intende iniziare a
contare i byte trasmessi da x (NS=x). Il
server risponde inviando il riscontro (flag
ACK pari ad 1) del primo segmento
ricevuto, in cui dichiara di essere in
attesa di ricevere il byte x+1 (NR=x+1);
nello stesso segmento, sincronizza anche
(NS=y) il numero di sequenza con cui conterà i dati inviati nelle risposte. A questo punto
sembrerebbe tutto terminato, ma resta invece da riscontrare il server della ricezione del suo
SYN, e questo avviene ad opera del terzo segmento. Questa modalità di sincronizzazione, prende
il nome di stretta di mano a tre vie (three way handshake).
Protocollo a finestra
Allo scopo di realizzare un controllo di flusso, il TCP mittente prevede l'uso del Numero di
Riscontro (NR) inviato dal ricevente, per dosare il ritmo con cui trasmettere i propri pacchetti.
La dimensione massima di Finestra è
comunicata con il SYN del ricevente, e
determina la quantità di memoria
riservata dal trasmittente per i buffer
dedicati alla connessione, gestita come
una memoria a scorrimento o finestra
scorrevole, e che contiene i bit già
trasmessi ed in attesa di riscontro. Man
mano che sono trasmessi segmenti, il limite superiore della finestra viene spostato a destra,
finché la finestra non raggiunge la sua ampiezza massima, dopodichè la trasmissione si arresta;
la ricezione di pacchetti di riscontro con NR maggiore del limite inferiore; causa lo spostamento
a destra del limite superiore della finestra, restringendola, in modo che nuovi pacchetti possano
essere trasmessi.
L'ampiezza massima della finestra è determinata come il minimo tra tre diversi criteri:
• il primo è quello basato su di una stima del round-trip delay (RTT) del collegamento, in
modo da poter trasmettere con continuità;
• questa ampiezza massima può essere ridotta su intervento del ricevitore, allo scopo di
realizzare un controllo di flusso, riducendo la velocità del trasmettitore, fino
eventualmente ad azzerarla, oppure
• può restringersi su iniziativa del trasmettitore, qualora si avveda di una situazione di
congestione.
Una finestra simile è adottata anche dal ricevente, per ricostituire l'ordine originario dei
pacchetti, che possono essere consegnati disordinatamente dallo strato IP di rete. Non appena il
ricevente completa un segmento contiguo al limite inferiore, sposta quest'ultimo in avanti, di
tanti bit quanti ne è riuscito a leggere in modo contiguo, ed invia un riscontro, con NR pari al più
basso numero di bit che ancora non è pervenuto.
26
Lo strato applicativo di Internet
Alessandro Falaschi
Controllo di errore
Trascorso un certo tempo (detto timeout) nell'attesa di un riscontro, il trasmittente ritiene che
il pacchetto sia andato perso, e lo re-invia. Il valore del timeout viene calcolato dinamicamente
dal TCP in base alle sue misure di round-trip delay. In questo modo il TCP si adatta alle
condizioni di carico della rete, ed evita di ri-spedire pacchetti troppo presto, o di attendere più
del necessario. In particolare, nel caso di rete congestionata, la frequenza dei pacchetti persi
aumenta, e valori di timeout troppo ridotti potrebbero peggiorare la situazione.
Controllo di flusso
Il meccanismo a finestra scorrevole determina, istante per istante, il numero massimo di bytes
che possono essere trasmessi verso il destinatario, e consente al nodo meno veloce di adeguare
la velocità di tramissione alle proprie capacità. Infatti, la dimensione della finestra di
trasmissione può essere variata (su iniziativa del ricevente) nel corso della connessione, in
accordo al valore presente nel campo Finestra presente nella intestazione TCP dei pacchetti
inviati in occasione degli ACK.
Durante il transitorio iniziale della comunicazione, in cui la stima di RTT non è ancora
consolidata, la trasmissione inizia con una dimensione di finestra ridotta, che viene poi
aumentata nel caso in cui non si verifichino errori, la rete sopporti il traffico, ed i nodi abbiano
memoria disponibile.
Controllo di congestione
Il TCP usa la sua stima di round-trip time, come un indicatore di congestione della rete, e lo
scadere di un timeout,come un segnale del peggioramento della congestione. In tal caso, la
dimensione della finestra di trasmissione viene ridotta (tipicamente, dimezzata), riducendo così
in modo reattivo, il carico della rete. Se lo stato di congestione persiste, ovvero continuano anon
pervenire riscontri, il trasmettitore, oltre a reiterare la ritrasmisione, riduce ulteriormente la
finestra, e così via: dopo un certo numero di ritrasmissioni, la connessione è dichiarata persa, ed
abbattuta. Viceversa, nel caso in cui tutti i riscontri pervengano regolarmente, l'ampiezza della
finestra torna gradatamente a crescere, come avviene all'inizio del collegamento.
In una rete congestionata, i nodi iniziano a scartare pacchetti. Possono essere scartati i pacchetti
di riscontro, o quelli spediti. Nel primo caso, il pacchetto ritrasmesso, se arriva a destinazione,
viene scartato dal ricevitore perché duplicato, ma è riscontrato comunque.
Esempio di capture
In questo esempio possiamo osservare l'apertura della conessione, la variazione della finestra
annunciata dal ricevitore, l'andamento di numeri di sequenza , e di riscontro.
Applicazioni di rete
A differenza delle applicazioni desktop, che per funzionare non hanno bisogno di una connessione
in rete, le applicazioni di rete sono quei programmi che di mestiere interagiscono con altri
programmi in esecuzione su computer remoti. I paradigmi più diffusi per le applicazioni di rete
sono:
• cliente/servente (client/server);
• paritetico (p2p, peer to peer);
• a tre livelli (three-tier).
27
Applicazioni di rete
Network programming
Il modello a tre livelli, di cui non ci occupiamo ora, prevede di disaccoppiare le tre funzioni di
interfaccia utente, logica di calcolo, ed accesso ai dati, che sono svolti da processi indipendenti.
Il modello paritetico (peer to peer) ha acquisito importanza e notorietà grazie alla diffusione dei
servizi di condivisione di file multimediali, e pure non verrà per ora affrontato. Il modello su cui
ora ci focalizzeremo, è quello cliente/servente, sia nel caso di protocolli di trasporto orientati
alla connessione (TCP) che non (UDP).
In una applicazione client-server i computer in comunicazione non hanno ruoli identici, ma sono
definite, per così dire, due personalità, in cui uno (il client) svolge la funzione di richiedente,
mentre l'altro (il server) risponde. Nel caso in cui anche il computer server si trovi nella necessità
di effettuare delle richieste, allora esisterà al suo interno un diverso processo, avente funzione
di client.
Tipologie di serventi
Dal punto di vista dello strato di trasporto, una applicazione server risponde presso un numero di
porta ben noto, tipicamente elencato nel file /etc/services, e possedere i privilegi necessari ad
aprirla. Il client quindi inserisce nell'intestazione di trasporto, questo numero di porta ben noto
come destinazione; viceversa, il numero di porta di origine usato dal client è detto effimero,
perché deciso in modo estemporaneo al momento della richiesta, come evidenziato nelle figure
che seguono, tratte da BAF. A seconda del modo in cui sono gestite le richieste, possiamo
classificare i server come
• iterativi, o seriali: rispondono alle richieste e restano occupati fino al loro
completamento, dopodiché tornano disponibili. E' questo il caso in cui le richieste e le
risposte impegnino un solo pacchetto IP, come nel trasporto UDP, e la generazione delle
risposte duri un tempo trascurabile;
28
Lo strato applicativo di Internet
Alessandro Falaschi
• concorrenti, o paralleli: creano processi figli (o thread) incaricati di rispondere, e tornano
in ascolto di altre richieste. I processi figli, una volta esaurito il loro compito, terminano.
Si tratta del caso in cui l'interazione avvenga utilizzando un trasporto con connessione ed
affidabile, ovvero il TCP, e l'intervallo tra due richiese sia generalmente superiore a quello
necessario a generare una risposta.
29
Comunicazione tra processi in rete
Network programming
In realtà ci sono almeno altri due modi per realizzare un server parallelo, di cui ci occuperemo
più avanti:
• multiplazione sincrona dell' I/O: il server riesce allo stesso tempo ad accettare nuove
connessioni ed a servire quelle già attive, grazie all'uso di una istruzione un pò particolare,
la select();
• polling ciclico: il server si pone in modalità non bloccante, e si occupa periodicamente di
controllare se ci sono nuove connessioni e di servire quelle attive. Ma è da evitare.
Comunicazione tra processi in rete
L'interfaccia software o API (Application Program(ming) Interface) di comunicazione in assoluto
più utilizzata fra processi in rete, sono i socket di Berkeley, di Unix BSD, definita nel 1982 in C
per Unix BSD 4.1c, ed è rimasta sostanzialmente invariata da allora. Socket è la parola inglese
che indica una presa (elettrica), significando in questo caso l'inserimento metaforico di uno
spinotto, da parte di un programma, nella presa che lo collega ad un altro, per il tramite della
rete. Ma dato che l'I/O di un programma, non è un segnale elettrico bensì numerico, è più
appropriato pensare al socket come ad un identificatore di FILE, che ci permette di leggere/
scrivere su/da un altro programma, anziché su/da disco. Dal punto di vista della stratificazione
funzionale offerta dal modello ISO-OSI, nella sua implementazione semplificata offerta dal
modello TCP/IP, un socket rappresenta il SAP (Service Access Point) dello strato di trasporto, nei
confronti del quale il processo applicativo si comporta come il client che utilizza i servizi di
trasporto e di rete.
Creazione di un socket
In rete esistono valide risorse (BJN, GaPiL, SOG, IIC) relative al network programming. Inoltre,
moltissime chiamate di sistema Unix sono documentate con gran dettaglio nelle pagine MAN
30
Lo strato applicativo di Internet
Alessandro Falaschi
richiamabili da linea di comando. In particolare, la chiamata socket(2)
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol)
è quella che ci permette di collegarci allo
strato di trasporto. La parametro domain
è uno dei define presenti in bits/
socket.h, incluso in sys/socket.h, e
definisce la Protocol Family da usare, che
per Internet è PF_INET. Il campo type
specifica il tipo di trasporto da usare
nell'ambito della famiglia, e può essere
impostato come SOCK_STREAM per il
TCP, SOCK_DGRAM (datagram) per UDP, o
SOCK_RAW per bypassare lo strato di
trasporto ed inviare in rete pacchetti
forgiati a mano. Infine il parametro
protocol, per PF_INET, può essere
posto a zero.
In caso di successo, la
chiamata socket()
restituisce un intero, o
handle (maniglia), che
identifica il descrittore
relativo al socket
creato, e che è
costituito da una
struct C contenente
i campi illustrati nella
figura a lato, in
cui famiglia, tipo e
protocollo sono quelli
specificati nella
chiamata, mentre le due
sotto-strutture indirizzo, di tipo sockaddr_in, identificano i due estremi della comunicazione.
Le strutture C che rappresentano entrambi i socket locale e remoto, sono costituite dai campi
riportati nella figura in basso a sinistra, in cui il primo e l'ultimo campo non sono in genere
usati, sin_family è di nuovo posto a PF_INET, e sin_port, sin_addr identificano l'indirizzo
di trasporto (un numero di porta TCP o UDP) e di rete (i 4 byte di indirizzo IP) del socket, tanto
che proprio questi due numeri (porta ed IP) sono, in definitiva, l'incarnazione più concreta di un
socket. Come si vede dalla definizione, l'indirizzo IP sin_addr è in realtà descritto mediante la
struttura in_addr, che come riportiamo sotto a destra, è composta da un solo membro,
s_addr, che consiste di un intero senza segno, e che appunto rappresenta i 32 bit associati
all'indirizzo IP
31
Comunicazione tra processi in rete
Network programming
Utilizzo dei socket
La creazione di un socket, è solo la prima delle richieste che lo strato applicativo effettua verso
la API offerta dall'interfaccia socket, che si compone di una serie di possibili chiamate. La figura
che segue esemplifica il caso di un client che accede ad un server remoto operante in modalità
parallela, e ci serve come linea guida per collocare le diverse chiamate nel rispettivo ruolo
funzionale e sequenza temporale.
32
Lo strato applicativo di Internet
Alessandro Falaschi
Nella figura, le trasmissioni che si svolgono internamente allo stack TCP/IP e non fuoriescono
dall'interfaccia socket, sono mostrate con una linea tratteggiata, e rappresentano l'applicazione
dei protocolli tra pari strettamente sottostanti lo strato applicativo, come ad esempio, il three
way handshake, o la trasmissione degli ACK.
Dopo la creazione del socket, la chiamata a bind()
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
sul lato server, serve a specificare l'indirizzo locale su cui porsi in ascolto. Nei parametri che
vengono passati, sockfd è pari all'handle del socket precedentemente creato, my_addr dovrà
essere opportunamente inizializzato con indirizzo IP e porta locale (vedi
esempio), mentre addrlen prende il valore di sizeof(struct sockaddr). Se tutto va bene,
bind() restituisce 0, altrimenti -1, ad es. quando la porta è già occupata, ovvero un'altra
applicazione ha già aperto un socket, su quella stessa porta.
33
Comunicazione tra processi in rete
Network programming
La chiamata seguente, listen()
int listen(int sockfd, int backlog);
è quella che effettivamente abilita il socket sockfd ad accettare le richieste in arrivo, che se
giungono in questa fase, vengono parcheggiate in una coda (e non è inviata nessuna risposta) di
dimensione backlog; al riempimento della coda, il server risponde con dei messaggi di rifiuto.
L'istruzione successiva, accept(),
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
è di tipo bloccante, ovvero se la coda delle richieste è vuota, il server rimane in attesa. Se
invece c'é già una richiesta, o quando ne arriva una, accept() ritorna, e scrive nella struttura
puntata da addr gli estremi del socket remoto relativo al lato client. Prima della chiamata,
*addrlen è preimpostato a sizeof(struct sockaddr_in), allo scopo di impedire ad
accept() di sovrascrivere altre parti di memoria, ed a sua volta, accept() modifica
*addrlen assegnandogli il numero di byte scritti. L'intero di ritorno, costituisce in realtà un
nuovo handle di socket, che dovrà essere usato nelle successive operazioni di lettura/scrittura;
nel caso di errori, invece, accept() restituirà -1. Il server si troverà ora a disporre di due
socket, come evidenziato nella figura più in basso: uno, è quello che resta in attesa di nuove
chiamate, e l'altro è quello connesso con la chiamata accettata, e che verrà chiuso al termine
del servizio.
Dal lato client, notiamo che dopo la chiamata a socket(), manca la chiamata a bind().
Infatti, la scelta del numero di porta locale da utilizzare viene demandato al kernel,
ovvero, viene usata una porta effimera; l'indirizzo IP locale viene invece scelto (nel caso il
computer sia multihomed) sempre dal kernel, come quello associato alla interfaccia in grado di
raggiungere l'indirizzo di destinazione. Si, ma la destinazione qual'è ? ... E' specificata nella
chiamata a connect()
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
anch'essa di tipo bloccante, ovvero non ritorna finchè il server non ha risposto, in modo positivo
o negativo. Prima della chiamata, *serv_addr è preimpostato con IP e porta della
destinazione, e addrlen è posto a sizeof(struct sockaddr). Al ritorno, connect()
restituirà -1 in caso di fallimento.
Ora che finalmente le due parti sono collegate, avendo richiesto un socket() di tipo
SOCK_STREAM, queste possono inviarsi dati usando le chiamate send() e recv(),
indipendentemente da chi sia il server od il client:
int send(int sockfd, const void *msg, int len, int flags);
in cui sockfd è l'handle del socket locale sui cui inviare i dati (restituito dalla chiamata a
socket() per il client, ovvero quello restituito dalla accept() per il server); msg è un
puntatore ai dati da inviare, e len è la lunghezza dei dati, in bytes; flags può essere 0, ovvero
essere posto ad uno o più dei valori descritti nella manpage di send(). Il valore di ritorno indica
il numero di bytes effettivamente inviati, e nel caso sia inferiore a len, è compito
dell'applicazione reinviare successivamene i dati mancanti. Dall'altro lato della connessione,
34
Lo strato applicativo di Internet
Alessandro Falaschi
occorre invocare recv()
int recv(int sockfd, void *buf, int len, unsigned int flags);
dove sockfd è l'handle da cui leggere, buf punta a dove le informazioni ricevute devono essere
scritte, len rappresenta la dimensione del buffer, e flags può nuovamente essere posto a zero,
od a quanto indicato nella manpage di recv(2).
Una volta che lo scambio di dati è terminato, si può chiudere la connessione, invocando
close(sockfd);
oppure
int shutdown(int sockfd, int how);
La differenza, è che mentre close() ha un effetto di chiusura totale, con shutdown() la
connessione può essere chiusa anche in sola direzione; per liberare del tutto l'handle del socket,
occorrà comunque chiamare lo stesso close().
Processi e Fork
Ancora con riferimento alla figura precedente, osserviamo che quando la accept() del server
ritorna, questo esegue una fork().
pid_t fork();
Ciò significa che il processo che sta eseguendo il codice del server viene clonato, ovvero vengono
duplicate le sue aree di memoria programma e memoria dati, che vengono associate ad un nuovo
PID (Process IDentifier). Ad esempio, per conoscere il pid di tutti i programmi in esecuzione sul
proprio computer Linux, è sufficiente impartire il comando
ps ax
in cui ps sta per process status, e ax sono due opzioni che permettono di vederli tutti. Il
programma clonato è detto figlio (child), ed inizia la sua esecuzione esattamente dallo stesso
punto in cui si trovava il padre al momento del fork(): in effetti, è stato clonato anche il
program counter, completo del suo valore! E.. come si distinguono padre e figlio, tra loro?
semplice ! la fork() restituisce zero al figlio, ed il pid del figlio, al padre, come esemplificato
qui sotto:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main (void) {
pid_t pid;
pid = fork();
if (pid != 0) {
35
Processi e Fork
Network programming
printf ("Il processid del padre è %ld e quello del figlio è %ld\n", (long)getpid(), pid);
} else {
printf ("Il processid del figlio è %ld, e quello del padre %ld\n", (long)getpid(),
(long)getppid());
}
}
Come si vede, lo stesso programma contiene sia il codice del padre che quello del figlio, cosicché
a seguito dell'esecuzione della fork(), tutti i descrittori di file aperti, così come i descrittori
dei socket, vengono duplicati, come mostrato nella figura che segue. Come già discusso, dopo
l'esecuzione della accept() il processo possiede due socket, uno ancora in ascolto e l'altro
connesso al client, ed a seguito della fork(), entrambi si duplicano. Quindi, il processo padre
provvederà a chiudere la sua copia del socket connesso, ed il processo figlio chiuderà la sua
copia del socket in ascolto.
36
Lo strato applicativo di Internet
Alessandro Falaschi
Un esempio di server parallelo
Siamo finalmente pronti a mostrare un diagramma di flusso che descrive in modo chiaro le
operazioni fin qui discusse.
Osserviamo che nel disegno precedente, vengono utilizzate le istruzioni write() e
read() anziché send() e recv(): le prime sono esattamente le stesse che è possibile usare
37
Un esempio di server parallelo
Network programming
con dei files su disco; le seconde, permettono di specificare dei parametri in più, come ad
esempio dei flags, così chiamati perché associati ognuno, ai diversi bit presenti in unica parola.
L'uso dei flag permette di variare il comportamento del socket in situazioni particolari. Ad
esempio la write(), nel caso in cui la dimensione dei dati da spedire sia eccessiva, rimane
bloccata finché i buffer di alimentazione del TCP non siano stati liberati; specificando invece tra
i flag di send(), la macro MSG_DONTWAIT, è possibile ottenere un comportamento non
bloccante, e permettere alla chiamata di tornare subito, restituendo l'errore EAGAIN. Allo stesso
modo, la recv() resta di per sé bloccata se non c'é nulla da leggere, mentre se invocata con il
flag MSG_DONTWAIT, assume un comportamento non bloccante, e nella stessa circostanza,
ritorna con un errore. Ma per concretizzare le idee, non resta che mostrare il codice di una
implementazione reale:
1
2
3
/*
** server.c -- a stream socket server demo
*/
4
5
6
7
8
9
10
11
12
13
14
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<unistd.h>
<errno.h>
<string.h>
<sys/types.h>
<sys/socket.h>
<netinet/in.h>
<arpa/inet.h>
<sys/wait.h>
<signal.h>
15 #define MYPORT 3490
16 #define BACKLOG 10
// the port users will be connecting to
// how many pending connections queue will hold
17 void sigchld_handler(int s) {
18
while(waitpid(-1, NULL, WNOHANG) > 0);
19 }
20 int main(void) {
21
22
23
24
25
26
int sockfd, new_fd;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
socklen_t sin_size;
struct sigaction sa;
int yes=1;
27
28
29
30
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
31
32
33
34
35
36
37
38
39
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
40
41
42
43
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
44
45
46
47
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
48
49
50
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(my_addr.sin_zero), '\0', 8);
// listen on sock_fd, new connection on new_fd
// my address information
// connector's address information
//
//
//
//
host byte order
short, network byte order
automatically fill with my IP
zero the rest of the struct
// reap all dead processes
38
Lo strato applicativo di Internet
Alessandro Falaschi
51
52
53
54
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
55
56
57
58
59
60
61
while (1) {
// main accept() loop
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n", inet_ntoa(their_addr.sin_addr));
62
63
64
65
66
67
68
69
70
71
if (!fork()) {
// this is the child process
close(sockfd);
// child doesn't need the listener
if (send(new_fd, "Hello, world!\n", 14, 0) == -1)
perror("send");
close(new_fd);
exit(0);
// child ends here
}
close(new_fd);
// parent doesn't need this
}
return 0;
72 }
Una implementazione alternativa che fa uso di thread anziché di processi figli, può essere
trovata presso code.box. Qui sotto, spieghiamo alcuni degli elementi che ancora ci mancano per
comprendere le operazioni compiute dal listato del server.
Segnali
I processi possono comunicare tra loro in modo molto primitivo, inviandosi dei segnali, che non
portano altra informazione oltre al loro tipo (il numero di segnale), scelto tra pochi. Sono usati
dal kernel per notificare situazioni eccezionali ai processi, e per notificare eventi tra processi,
come ad es. la terminazione di un processo figlio, o la richiesta di interruzione espressa con una
combinazione di tastiera (es Control-C). Si possono inviare segnali ai processi, mediante il
comando
kill [ -signal ] pid
in cui pid indica il processo a cui inviare il segnale, ed i numeri più usati per signal sono
riportati appresso:
Name
Num
ALRM
HUP
INT
KILL
PIPE
TERM
CHLD
URG
STOP
CONT
ABRT
FPE
ILL
QUIT
SEGV
TRAP
14
1
2
9
13
15
6
8
4
3
11
5
Action Description
exit
exit
exit
exit
exit
exit
ignore
ignore
stop
restart
core
core
core
core
core
core
il processo si re-inizializza
terminazione forzata - non può essere bloccato
non può essere bloccato
continua se stoppato, altrimenti ignora
Ad esempio, Control-C equivale ad inviare il 15, mentre con il 9 termina di sicuro. Tornando alla
39
Un esempio di server parallelo
Network programming
nostra trattazione, quando un processo figlio termina, invia al padre il segnale CHLD, ed anche
se le risorse da esso impegnato (memoria, buffer) sono liberate, il descrittore del suo processo
rimane in memoria (producendo un cosiddetto processo zombie) finchè il processo padre non
esegue una istruzione waitpid() per leggere il suo stato di uscita. Nella tabella di sopra, la
colonna Action indica cosa succede al processo che riceve il segnale, ed osserviamo che nel
caso di SIGCHLD, non accade nulla. Allora, la funzione sigaction() (linea 51) per così dire
arma il segnale, nel senso che specifica quale subroutine eseguire alla ricezione di un dato
segnale. Questa viene assegnata dalla istruzione sa.sa_handler = sigchld_handler; in cui
sigchld_handler è appunto il gestore del segnale, e sa è una struct sigaction, i cui
campi sa_mask e sa_flag vengono pure inizializzati congruentemente. Alla ricezione del
segnale SIGCHLD quindi, il processo padre interrompe il normale flusso del codice, e si porta ad
eseguire il codice contenuto nell'handler, come fosse una subroutine invocata dal programma
stesso. Per quanto riguarda la procedura sigaction(), questa si limita a loopare finché si sono
processi zombie da mietere (reap dead processes), e poi termina.
Errori
Osserviamo che spesso viene verificato l'intero restituito dalle system call, che se negativo indica
una condizione di errore. In tal caso, viene effettuata una chiamata (vedi linee 28, 32, 41, 45,
52, 58, 65) a
#include <stdio.h>
void perror(const char *s);
che ha l'effetto di stampare su standard error il messaggio associato all'ultima condizione di
errore che si è verificata, preceduto dalla stringa posta in argomento, più due punti ed uno
spazio, in modo che si capisca in che punto si è verificato l'errore. Quando una system call
fallisce, imposta una variabile interna ad un valore (errno) che identifica appunto il tipo di
errore; questo valore viene quindi usato dalla funzione perror() come indice nell'array di stringhe
sys_errlist[], che contiene le descrizioni testuali dei motivi di errore
#include <errno.h>
const char *sys_errlist[];
int sys_nerr;
int errno;
Opzioni del socket
Alla linea 31 troviamo l'invocazione di setsockopt(), che permette di agire sui parametri che
modificano il comportamento del socket, e che possono essere specificati ai diversi livelli della
pila protocollare: il secondo argomento posto pari a SOL_SOCKET, specifica che si deve
intervenire a livello di socket, ed il terzo posto pari a SO_REUSEADDR, permette a bind() di
avere successo, anche se una altro processo occupa già la stessa porta, come potrebbe accadere,
ad esempio, se un processo figlio (di una precedente istanza del server) è rimasto in esecuzione,
ed in collegamento con un client remoto.
40
Lo strato applicativo di Internet
Alessandro Falaschi
Indirizzi speciali
Nell'esempio di server riportato sopra, osserviamo che l'indirizzo my_addr.sin_addr.s_addr
viene impostato (linea 38) a INADDR_ANY. Questa costante è un intero a trentadue bit, tutti pari
a zero, definita all'interno dell'header netinet/in.h, ed è il modo per indicare questo host su
questa rete: nella pratica ciò vuol dire che, anche se il computer possiede più di un indirizzo,
qualunque questo sia, per il solo fatto che lo strato IP l'abbia accettato, deve pure essere
accettato dal socket. Viceversa, assegnando a my_addr.sin_addr.s_addr un indirizzo
specifico tra quelli dell'host, imponiamo che il server venga raggiunto solo dalle richieste
destinate esattamente a quell'indirizzo. In netinet/in.h sono anche definiti altri indirizzi
speciali, come INADDR_BROADCAST posto a tutti uno, che quando usato come destinazione,
specifica tutti gli host su questa sottorete; INADDR_LOOPBACK che vale 127.0.0.1, e specifica lo
stesso host da cui parte il pacchetto (qualunque esso sia), ed impone allo strato IP di non
inoltrare il pacchetto verso lo strato di collegamento.
Rappresentazione degli interi e reperimento degli indirizzi
Nell'esempio di server, la variabile my_addr.sin_port viene impostata (linea 37) al
valore htons(MYPORT). La chiamata a htons() è resa necessaria, per convertire dalla
possibili diverse rappresentazioni degli interi nella architettura utilizzata, ossia da come questi
vengono organizzati in memoria, verso il modo in cui gli stessi interi sono invece disposti nelle
intestazioni dei pacchetti, il network order. Le due diverse disposizioni in memoria sono le
cosiddette Big endian e Little endian:
Big endian
La disposizione big
endian dispone in
memoria i bytes
iniziando dal più
significativo (Most
Significant, MS) al
meno (less)
significativo (LS), ed è
quella adottata, oltre
che per il network order, dai mainframe IBM e dai processori Motorola, PowerPC, SPARC.
Little endian
La disposizione little
endian al contrario,
dispone i byte in
memoria dal meno al
più significativo, ed è
adottata dai processori
Intel.
41
Un esempio di server parallelo
Network programming
Host to Network Order
Per rendere indipendente lo strato
di rete, che opera in modalità big
endian, da quello dello strato
applicativo, che rappresenta gli
interi in accordo alla propria
dotazione harware, sono definite
due funzioni per convertire dall'Host
order, verso il Network order
(hton=host to network,
ntoh=network to host), per i due
casi di intero corto (16 bit, short)
od intero lungo (32 bit, long), che
devono essere chiamate ogni volta
che si scambiano dati nelle direzioni.
Dichiariamo ora, due altre funzioni molto utili.
Network to Ascii
La chiamata a inet_aton() è il modo per convertire un
dirizzo dato come stringa (ascii) nella forma
"192.168.151.122", nella rappresentazione di intero a 32
bit in network byte order. Ovviamente, inet_ntoa()
svolge la conversione inversa.
gethostbyname
La chiamata a gethostbyname()
permette al processo applicativo di
risalire all'indirizzo IP, a partire dalla parte fqdn che compare nell'indirizzo applicativo, ossia ad
esempio www.domino.org. L'operazione coinvolge quasi sempre una interrogazione al DNS,
operata dal componente resolver del sistema operativo. Il risultato della chiamata è la
struttura hostent, che presenta i campi illustrati nel seguito. h_name punta al nome ufficiale
dell'host; h_aliases ad un array di stringhe contenenti i nomi alternativi; h_addrtype; vale
AF_INET o AF_INET6; h_length è la lunghezza in byte dell'indirizzo; e h_addr_list punta
ad un array contenente tutti gli indirizzi IP del computer.
42
Lo strato applicativo di Internet
Alessandro Falaschi
Un esempio di client
Di nuovo sul sito di Brian "Beej" Hall, troviamo il codice di un Client TCP che contatta il server
stream illustrato sopra. Senza riportarlo qui, osserviamo innanzitutto che il programma richiede
che l'indirizzo di destinazione sia passato come parametro al momento della chiamata. Quindi, si
usa la funzione gethostbyname() illustrata sopra, in modo da ottenere l'IP del server, e costruire
nella struttura their_addr l'indirizzo da contattare. Quindi, dopo che la connect() è andata
buon fine, con recv() otteniamo il messaggio "Hello, world!" inviato senza molta fantasia
dal server, lo stampiamo ed usciamo. C'é da notare che recv() esce dal suo stato di ricezione,
in quanto il lato server chiude la connessione dopo l'invio del messagio.
Connessioni di tipo DGRAM
Ancora sul sito di Brian "Beej" Hall, possiamo trovare un esempio di server (listener) e di client
(talker) che fanno uso di una connessione di tipo SOCK_DGRAM, ossia senza connessione. Stavolta
è il client che invia qualcosa al server, che termina subito dopo la ricezione, mentre il client
termina subito dopo la trasmissione, che sia andata a buon fine o meno. Dal lato listener,
osserviamo che dopo aver creato il socket ed aver effettuato il bind sulla propria porta, si esegue
direttamente il recvfrom(), che resta bloccato in attesa. Una volta ricevuto un messaggio,
questo viene stampato, e listener esce. Dal lato talker, osserviamo che oltre al nome del
computer remoto, è presente un altro parametro di input al programma, e cioé il messaggio da
inviare al server. Di nuovo, costruiamo in their_addr l'indirizzo da contattare, dopo averlo
ottenuto in network byte order tramite la gethostbyname(), ed aver convertito il numero di
porta con htons(). Quindi, si invia il messaggio mediante sendto(), e si chiude il socket, in
modo che la recvfrom() del server possa uscire.
ICMP
Esponiamo ora la funzione di un protocollo (ICMP) già comparso nella figura sul TCP/IP, dove è
evidenziato come, sebbene le sue PDU siano incapsulate dentro IP, queste non vengano
consegnate allo strato di trasporto, ma siano invece elaborate all'interno dello strato di rete.
L'ICMP (Internet Control Message Protocol) ha lo scopo di veicolare informazioni relative al
corretto funzionamento della rete, e può seguire sia un protocollo di richiesta-risposta, sia avere
una semplice funzione di indicazione non sollecitata, qualora debba segnalare problemi relativi
ad un pacchetto IP in transito. In quel caso, l'applicazione che ha generato il paccheto IP
originario, può essere notificata dell'evento.
43
ICMP
Network programming
Come mostrato in figura,
l'intestazione minima di ICMP si
compone di una sola parola di
32 bit, di cui i primi 8
contengono un codice (type)
che qualifica la funzione del
pacchetto, ed i secondi otto
possono contenere un
sotto-tipo. A seconda del tipo,
possono poi essere presenti
altre parole di
intestazione. Ecco alcuni dei
tipi pù frequenti:
• 0 Echo reply
• 3 Destinazione
irraggiungibile
• 5 Redirect
• 8 Echo request
• 11 Time Exceeded
• 13 Timestamp request
• 14 Timestamp reply
• 30 Traceroute
Come esempi applicativi, il caso più noto è quello associato all'uso del comando ping, impiegato
per verificare la connettività con un altro computer, inviando un pacchetto ICMP di tipo Echo
request. Il computer di destinazione, se operativo ed effettivamente raggiunto, risponde con
un pacchetto ICMP di tipo Echo reply, al che il comando ping in esecuzione sul primo
computer, scrive a video il tempo intercorso tra andata e ritorno, o Round Trip Time (RTT). Il
ciclo si ripete all'infinito, e viene interrotto premendo control-c, al che il ping stampa delle
statistiche sui tempi rilevati, e termina.
Nel caso in cui il computer di destinazione (od una applicazione che dovrebbe essere in ascolto
su di una porta di trasporto) non possa essere raggiunto (dal paccheto ICMP di tipo Echo
request, o da qualunque altro pacchetto IP), i router di transito, od il computer di
destinazione, possono generare un pacchetto ICMP di tipo Destinazione
irraggiungibile, il cui campo code contiene un valore che indica il possibile motivo della
irraggiungibiità, come ad esempio
Code Description
0
Network unreachable error.
1
Host unreachable error.
3
Port unreachable error (the designated protocol is unable to inform the host of the incoming
message).
4
The datagram is too big. Packet fragmentation is required but the 'don't fragment' (DF) flag
is on.
13
Communication administratively prohibited (administrative filtering prevents packet from
being forwarded).
in cui i codici Network e Host unreachable sono generati dal router che dovrebbe
consegnare il pacchetto, Port unreachable è prodotto dall'host di destinazione, quando
sul numero di porta di destinazione non è in ascolto nessun processo server, mentre i
codici Fragmentation Required e Communication administratively prohibited,
44
Lo strato applicativo di Internet
Alessandro Falaschi
sono generati dai router di transito, nei casi in cui rispettvamente sarebbe richiesta la
frammentazione del pacchetto, ma è settato il bit "don't fragment", oppure sia presente un
firewall che impedisce il transito di un pacchetto per quella destinazione.
In tutti i casi, il pacchetto ICMP di
ritorno viene assemblato a partire
da quello (IP) di andata, come
mostrato in figura. In particolare,
l'intestazione IP ricevuta, ed i primi
8 byte di ciò che segue (es TCP),
viene prefissa dalla intestazione
ICMP, che è poi ulteriormente
prefissa dalla intestazione IP che
serve a recapitare il pacchetto
all'indietro. In questo modo, il
mittente originario ha tutti gli estremi per ri-associare il messaggio ICMP alla connessione
uscente che ha prodotto il pacchetto IP originario.
Il tipo Time Exceeded è sfruttato dalla utility traceroute, che invia verso la destinazione un
pacchetto con un valore di TTL IP particolarmente basso. Quando questo si azzera, il router lo
scarta, ed invia all'indietro, appunto, un pacchetto ICMP Time Exceeded. Quindi, traceroute
incrementa il TTL, allo scopo di scoprire il prossimo router che scarterà il pacchetto, finché
questo non arriva a destinazione.
Infine, il tipo Destinazione irraggiungibile, codice Fragmentation Required, viene
usato nell'ambito di una procedura chiamata path MTU discovery, volta a determinare qual'è la
dimensione massima di pacchetto che può essere inviata, senza che questo debba essere
frammentato. In questo caso, prima di iniziare il collegamento, il computer sorgente invia verso
la destinazione dei pacchetti IP con il bit don't fragment settato, e se il pacchetto arriva a
destinazione, tutto è filato liscio. Viceversa, se il pacchetto incontra sezioni della rete che
devono causare frammentazione, viene generato appunto il messaggio ICMP Destination
unreachable, fragmentation required, ed il mittente capisce che deve ridurre la
dimensione di pacchetto; ripete quindi la procedura con il pacchetto ridotto, finchè non va.
Frammentazione di pacchetto e riassemblaggio
Forniamo qui di seguito, un esempio pratico relativo a ciò che accade nel caso di
frammentazione IP. L'host source ha pronto un pacchetto IP di 7000 Bytes, completo delle
intestazioni di trasporto. Per arrivare all'host destinazione, il pacchetto dovrà attraversare due
reti eterogenee, una con architettura Token Ring, ed una seconda Ethernet. Queste due reti,
impongono una dimensione massima (MTU) alle trame di strato fisico, rispettivamente di 4000 e
di 1500 Bytes.
Considerando che lo strato IP, di suo, aggiunge una intestazione di 20 Byte, si ottiene una
dimensione massima dei frammenti pari a 4000 - 20 = 3980 per la prima tratta, e 1500 - 20 =
1480 per la seconda. Però, come precedentemente illustrato, il campo "fragment offset"
presente nella intestazione IP individua la posizione di ogni frammento in modo per così dire
quantizzato come multiplo di 8 Byte, e pertanto, la dimensione dei frammenti (eccetto l'ultimo)
è vincolata ad essere divisibile per 8. Fortunatamente, 1480 è proprio multiplo di 8 (8 * 185 =
1480), mentre per la sezione Token Ring, occorre ridurre la dimensione del frammento rispetto
alla massima, a 3976 (= 496 * 8).
45
Frammentazione di pacchetto e riassemblaggio
Network programming
E così, i 7000 bytes originari, si suddividono in due pacchetti di 3976 e 3024 byte. Quando
questi giungono alla sezione Ethernet, vengono frammentati ulteriormente, ed in particolare, il
primo (da 3976) ne genera 3 (2 da 1480 ed uno da 1016 bytes), ed il secondo (da 3024) altri tre (2
da 1480 ed uno da 64 bytes). Nelle tabelle (b) e (c), si evidenziano i contenuti più rilevanti delle
intestazioni IP per la prima e la seconda tratta, mostrando come il campo identificazione sia lo
stesso per tutti, così come la lunghezza totale, in modo che il ricevente sia in grado di
riassemblare il pacchetto. Inoltre, il bit more fragments è sempre settato, tranne che per
l'ultimo. Infine, notiamo come il fragment offset (da moltiplicare per 8 per avere la reale
posizione) del (iv) pacchetto della tratta Ethernet, sia esattamente uguale a quello del (ii)
pacchetto della sezione Token Ring.
Svolgiamo ora la considerazione che, in caso di mancata consegna anche di uno solo dei
frammenti a destinazione, il pacchetto non può essere riassemblato per intero, ed allo scadere di
un timeout, lo strato di trasporto dell'host sorgente sarà obbligato alla ritrasmissione dell'intero
pacchetto originario da 7000 bytes. Pertanto, si preferisce evitare l'insorgenza di
frammentazione di pacchetto, ed affidarsi a tecniche come la Path MTU discovery prima
illustrata.
46
Lo strato applicativo di Internet
Alessandro Falaschi
I/O multiplato sincrono
Sebbene il modello di programmazione di rete che fa uso di processi figli o di thread sia tutto
sommato semplice ed elegante, e permetta di scrivere del codice ben leggible, in cui
l'interazione con la specifica entità connessa all'altro estremo della rete è ben delimitata, spesso
si preferisce ricorre ad una soluzione diversa. Nel caso dei processi figli infatti, ognuno di essi
determina una nuova occupazione di memoria, ed anche se nel caso dei thread questo avviene in
forma molto ridotta, la fase di inizializzazione delle nuove istanze del flusso di controllo può
portare ad un aumento del tempo di risposta, e dell'impegno di risorse di calcolo. Inoltre, come
abbiamo visto, la chiamata alla accept(), così alla recv(), sono di tipo bloccante, ovvero non
restituiscono il controllo finché non sopraggiunge una connessione, o sono pronti dei dati da
leggere, cosicchè si possono verificare problemi di sincronizzazione tra i diversi sotto processi, e
lo stato di blocco di alcuni di essi potrebbe causare un blocco generalizzato.
Al contrario, nel caso dell'I/O
multiplato [SMI] un unico processo
si pone contemporaneamente in
ascolto di tutti i socket attivi, ad
ognuno dei quali è connesso un
diverso client, e provvede a gestire
il colloquio con ciascuno di essi,
non appena sono disponibili nuovi
dati. In questo modo, sono
virtualmente risolti tutti i problemi
di sincronizzazione, ed il server
può conseguire una elevata
scalabilità (ossia servire un numero
molto elevato di connessioni
contemporanee). Il lato negativo, è
che il codice risulta meno leggibile,
dovendo gestire diversi casi nello
stesso flusso di controllo.
Il funzionamento dell'I/O sincrono si basa sull'uso della chiamata select(), il cui prototipo
POSIX è
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
mostra come il suo funzionamento dipenda da tre insiemi di descrittori di file (fds), che
individuano tutti i canali di cui occorre monitorare lo stato, in attesa di un suo cambiamento. Gli
insiemi raccolgono i descrittori da cui vogliamo leggere (readfds), in cui vogliamo scrivere
(writefds), e di cui vogliamo monitorare gli errori (exceptfds). Questi insiemi (set) vengono
modificati dalle chiamate
void
void
int
void
FD_SET
FD_CLR
FD_ISSET
FD_ZERO
(int fd, fd_set *set);
(int fd, fd_set *set);
(int fd, fd_set *set);
(fd_set *set);
/*
/*
/*
/*
aggiunge il descritore fd all'insieme set */
rimuove il descrittore fd dall'insieme set */
verifica se il descrittore fd appartiene all'insieme set */
rimuove tutti i descritori dall'insieme set */
In pratica, occorre prima popolare gli insiemi con FD_SET(), e poi chiamare select(), che non
torna finché uno (o più) dei descrittori compresi dagli insiemi non cambia stato. Quando
47
I/O multiplato sincrono
Network programming
select() ritorna, modifica i fds, lasciandovi dentro solo i fd il cui stato è cambiato. A questo
punto, invocando FD_ISSET() per ognuno dei descrittori e degli insiemi, si individua quale(i) di
questi è cambiato, in modo che il programma possa svolgere le azioni previste per quel caso
particolare. Per ciò che riguarda gli altri due parametri della chiamata a select(), nfds è pari
al numero (più uno) del descrittore con il numero più elevato (ad es, se i descrittori settati sono
1, 4 e 7, nfds deve valere 8 = 7+1), mentre timeout codifica per quanto tempo al massimo
select() resterà in attesa, ed è espresso mediante la struct timeval:
struct timeval {
int tv_sec;
int tv_usec;
};
/* secondi
*/
/* microsecondi */
Ad esempio, dopo aver posto un socket in ascolto con listen() ed averlo inserito in readfds,
quando questo riceve una richiesta di connessione da parte del client, select() ritorna, e
possiamo invocare subito la accept(), senza restare bloccati. Se invece la connessione è già
instaurata, dopo aver inserito l'accepting socket in readfds, select() ritornerà dopo che il
kernel ha effettivamente ricevuto un nuovo pacchetto, e potremo subito invocare recv(), di
nuovo senza rimanere bloccati. Negli insiemi, è ovviamente (!) possibile inserire anche i
descrittori associati a standard input, standard output e standard error, anzi questo
è fortemente raccomandato, se il programma deve anche poter gestire l'I/O da tastiera. Nel caso
in cui si voglia monitorare un solo insieme, select() può ricevere NULL al posto di un fd_set
*; ponendo tv_sec e tv_usec a zero, select() tornerà immediatamente, mentre passando
NULL al posto di struct timeval *, select() userà un timeout infinito.
Per riassumere i concetti esposti, e fornire un esempio pratico, mostriamo di seguito un esempio
ancora tratto da BJN, che realizza un semplice server di chat multiutente. Una volta posto in
esecuzione, se da altre finestre-terminale, o da altri computer, si esegue telnet hostname
9034, (telnet apre una connessione TCP collegando lo standard output ed input di un computer
ad un sever remoto), tutto ciò che viene scritto da un client, viene mostrato a tutti gli altri.
1
2
3
/*
** selectserver.c -- a cheezy multiperson chat server
*/
4
5
6
7
8
9
10
11
#include
#include
#include
#include
#include
#include
#include
#include
12
#define PORT 9034
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main(void)
{
fd_set master;
fd_set read_fds;
struct sockaddr_in myaddr;
struct sockaddr_in remoteaddr;
int fdmax;
int listener;
int newfd;
char buf[256];
int nbytes;
int yes=1;
socklen_t addrlen;
int i, j;
27
<stdio.h>
<stdlib.h>
<string.h>
<unistd.h>
<sys/types.h>
<sys/socket.h>
<netinet/in.h>
<arpa/inet.h>
FD_ZERO(&master);
// port we're listening on
//
//
//
//
//
//
//
//
master file descriptor list
temp file descriptor list for select()
server address
client address
maximum file descriptor number
listening socket descriptor
newly accept()ed socket descriptor
buffer for client data
// for setsockopt() SO_REUSEADDR, below
// clear the master and temp sets
48
Lo strato applicativo di Internet
Alessandro Falaschi
28
FD_ZERO(&read_fds);
29
30
31
32
33
// get the listener
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
34
35
36
37
38
// lose the pesky "address already in use" error message
if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
39
40
41
42
43
44
45
46
47
// bind
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = INADDR_ANY;
myaddr.sin_port = htons(PORT);
memset(&(myaddr.sin_zero), '\0', 8);
if (bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) == -1) {
perror("bind");
exit(1);
}
48
49
50
51
52
53
54
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(1);
}
// add the listener to the master set
FD_SET(listener, &master);
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
== -1) {
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
// main loop
for (;;) {
read_fds = master;
// copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(1);
}
// run through the existing connections looking for data to read
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
// we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof(remoteaddr);
if ((newfd = accept(listener, (struct sockaddr *)&remoteaddr, &addrlen))
perror("accept");
} else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) {
// keep track of the maximum
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n", inet_ntoa(remoteaddr.sin_addr), newfd);
}
} else {
// handle data from a client
if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
printf("selectserver: socket %d hung up\n", i);
} else {
perror("recv");
}
close(i);
// bye!
FD_CLR(i, &master);
// remove from master set
} else {
// we got some data from a client
for(j = 0; j <= fdmax; j++) {
// send to everyone!
if (FD_ISSET(j, &master)) {
// except the listener socket and the sender
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
49
Socket non bloccante
99
100
101
102
103
104
105
106
107
108
Network programming
}
}
}
}
// it's SO UGLY!
}
}
}
return 0;
}
Come possiamo osservare, la select() in linea 60 usa solo l'insieme di lettura, che alla linea 59
viene posto pari a master. Questo a sua volta, definito alla linea 15, è inizializzato a zero alla
linea 27, e quindi popolato alla linea 54 con il descrittore del socket di ascolto, ottenuto alla
linea 30 dopo l'invocazione di socket(). La select() è posta all'interno di un loop infinito che
ha inizio alla linea 58, e la prima volta che viene eseguita, riceve come primo parametro (l'intero
superiore del numero di socket più grande negli insiemi) il numero del socket in ascolto + 1,
come risulta alla linea 56.
Quando select() restituisce il controllo al programma, il for di linea 65 scansiona tutti i
descrittori fino al più grande, e quando la condizione di linea 66 ne trova uno contenuto
nell'insieme read_fds restituito da select(), ci son due possibilità: o si tratta di una nuova
connessione, oppure di un nuovo pacchetto arrivato su di una connessione già attiva. Nel primo
caso (che è il primo a verificarsi!) viene eseguita la accept(), il socket così ottenuto è aggiunto
all'insieme master (che sarà di nuovo copiato in master alla linea 59), e fdmax viene
aggiornato, nel caso in cui il nuovo socket abbia un numero maggiore di quelli già in uso. Nel
secondo caso, si tentano di leggere i dati in arrivo, ed in caso di successo (linee 90-100) questi
vengono re-inviati a tutti gli altri socket presenti nell'insieme master, esclusi i descrittori che
fanno riferimento al listening socket, ed al client mittente. Se invece la recv() fallisce, viene
stampato un diverso messaggio di errore a seconda se sia verificato un errore (linea 85) oppure
non venga letto nulla (linea 83), segno che il socket è stato chiuso dall'altro lato. In entrambi i
casi, il socket viene chiuso, e rimosso dall'insieme master (linee 87 e 88). Notiamo che non
viene neanche tentato di decrementare fdmax, tanto un suo valore eccessivo, non arreca nessun
danno.
Socket non bloccante
Finora il nostro stile di programmazione, è stato completamente vincolato dal fatto che alcune
primitive (accept(), recv(), select(), ma anche send(), nel caso in cui il TCP abbia i
buffer pieni) bloccano, ovvero non restituiscono il controllo al programma che le ha chiamate
finchè non si verifica l'evento di cui sono in attesa. Questo ha il vantaggio che la CPU del
computer che esegue l'applicazione non viene impegnata per nulla, ed il processo resta in uno
stato di sospensione per la maggior parte del tempo.
Una alternativa è quella di modificare il comportamento del socket, andando ad intervenire sui
flag associati al suo descrittore, utilizzando la chiamata a fcntl():
#include <unistd.h>
#include <fcntl.h>
.
.
sockfd = socket(AF_INET, SOCK_STREAM, 0);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
.
.
50
Lo strato applicativo di Internet
Alessandro Falaschi
Questo è possibile perchè in Unix ogni cosa è un file, ed il comportamento di un socket, che è
referenziato da una file descriptor alle stregua di una qualunque altro file, dipende dai flags
dello stesso. Il secondo argomento di fcntl(), settato a F_SETFL, indica appunto l'intenzione
di settare un flag, in particolare il flag O_NONBLOCK, che appunto fa si che le chiamate
bloccanti, anziché sospendere il processo, tornino immediatamente, restituendo però -1, e
settando errno al valore EWOULDBLOCK. In tal modo la chiamata assume il ruolo di una
interrogazione, che il programma può eseguire di continuo, finché il codice di errore non cambia,
e l'operazione può avere buon fine. Ma un programma scritto in questo modo, abusa delle risorse
del computer, la cui CPU viene impegnata di continuo nell'interrogazione del socket, e adottare
questa soluzione, è da sprovveduti.
Client broadcast
L'esempio di chat server precedentemente svolto, mostra un server centralizzato a cui si
connettono tutti client, e che provvede a re-inviare a tutti ciò che ognuno scrive. Evidentemente
questo approccio risulta tanto più pesante per il server, quanti più client si collegano. Un
approccio alla comunicazione di gruppo del tutto diverso, consiste nel non disporre di nessun
server, utilizzare uno strato di trasporto senza connessione (udp), e fare invece affidamento ai
meccanismi offerti dallo strato di rete:
• broadcast: funziona in ambito locale, ovvero tra computer connessi ad una stessa LAN, e
consiste nell'inviare i pacchetti ad un indirizzo IP che abbia settati ad uno i bit della parte
host dell'indirizzo. Tale indirizzo broadcast viene mostrato dal comando ip addr, e può
essere ricavato mediante l'operazione logica network_number OR (NOT netmask). In
alternativa, si può usare l'indirizzo IP di broadcast globale, ovvero 255.255.255.255,
noto anche come INADDR_BROADCAST;
• multicast: funziona (teoricamente) su scala globale, e consiste nell'usare come indirizzo IP
di destinazione (detto gruppo), un indirizzo scelto entro un intervallo opportuno, che i
router riconoscono come speciale, e quindi tentano di consegnare a tutti gli host che si
sono posti in ascolto di quell'indirizzo. Ma non entriamo in dettagli ulteriori.
Ma se utilizziamo il programma talker che appunto invia un messaggio via UDP (vedi sopra),
specificando un indirizzo di destinazione broadcast, riceviamo un errore del tipo sendto:
Permission denied. Prima, infatti, dobbiamo modificare il comportamento del socket,
agendo questa volta su di una sua opzione, mediante il comando setsockopt():
#include <sys/types.h>
#include <sys/socket.h>
.
.
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast);
.
.
Il secondo parametro di setsockopt() identifica il livello a cui si intende operare, e
indicando SOL_SOCKET, si specifica di operare a livello di socket. L'opzione che abilitiamo è
SO_BROADCAST, che appunto permette al socket sia di ricevere che di trasmettere pacchetti
da/verso indirizzi broadcast. Un esempio di client che fa uso di questa opzione è
broadcaster.c, ancora prelevata dalle guide di Brian "Beej" Hall. Lo possiamo mandare in
esecuzione, con il comando ./bradcaster 255.255.255.255 "messaggio di saluto".
Se lanciamo listener.c su diversi computer di una stessa LAN, possiamo osservare che tutto ciò
51
Riepilogando
Network programming
che è scritto da broadcaster, compare sugli schermi di tutti i listener. Bello ! :-) Va però
osservato che, nel rispetto degli altri, fare uso di comunicazioni broadcast con troppa leggerezza
non è una buona pratica, in quanto tutti i computer della stessa LAN si trovano obbligati a
leggere tutti i pacchetti broadcast, eventualmente solo per scoprire che non esiste nessun
processo in ascolto su quella porta.
Riepilogando
Questa, è la tabella riassuntiva dei parametri dei programmi proposti
programma
trasporto Porta modalità trasmissione
client
TCP
-
fork
unicast
server
TCP
3490
fork
unicast
talker
UDP
-
-
unicast
listener
UDP
4950
-
-
selectserver
TCP
9034 select
broadcaster
UDP
-
-
unicast
broadcast
Il codice sorgente dei programmi, è reperibile presso una apposita directory, dove è presente
anche lo script di compilazione, ed il Makefile. Una versione modificata dei programmi, come
suggerito nel corso delle esercitazioni, è fornita nella directory di test, in cui
• server.c è modificato, in modo da inviare un messaggio diverso da Hello, Word!
• servermod.c è la versione modificata di server.c, in cui è possibile specificare un
ritardo programmabile tra bind, listen e accept, e disabilitare la gestione del segnale
SIGCHLD;
• listener.c è modificato in modo da non uscire ad ogni pacchetto ricevuto, ma loopare
per sempre; inoltre, per ogni pacchetto ricevuto, stampa una sola linea;
• selectserver.c stampa anche l'ip mittente del messaggio ricevuto.
Riferimenti
[AL] - Appunti di informatica libera di Daniele Giacomini
[BJN] - Beej's Guide to Network Programming Using Internet Sockets - Brian "Beej Jorgensen" Hall
[GaPiL] - Programmazione di rete di Simone Piccardi (GaPiL = Guida alla Programmazione in
Linux)
[SOG] - Internet: Indirizzi e Protocolli di Vittoria Giannuzzi
[IIC] - Socket da Imparare il C di Marco Latini e Paolo Lulli
[SMI] - Servers Multiprocesso e I/O Multiplexing di Vittorio Ghini, da LABORATORIO di
PROGRAMMAZIONE di RETE
[UPF] - Unix Programming Frequently Asked Questions di Andrew
[MMC] - Multimedia Communications di Fred Halsall, ed. Addison-Wesley 2001, ISBN
0-201-39818-4
[BAF] - I procolli TCP/IP di Behrouz A. Forouzan - Ed McGraw-Hill 2001, ISBN 88-386-6005-0
[TST] - Trasmissione dei Segnali e Sistemi di Telecomunicazione di Alessandro Falaschi - Ed
Aracne 2003, ISBN 88-7999-477-8
[MCX] - man.cx - Tutte le Man page
Computer Networks - di Theo Schouten
52
Lo strato applicativo di Internet
Realizzato con
Alessandro Falaschi
da Alessandro Falaschi - ultimo aggiornamento Marzo 2008
53
Lo strato applicativo di Internet
Risoluzione degli indirizzi applicativi
Come discusso nel capitolo precedente, un aspetto rilevante del funzionamento di Internet, si
basa su di una stratificazione di indirizzi. In questo capitolo, ci occuppiamo di come vengono
assegnati gli indirizzi IP in una rete locale, e di come questi siano messi in corrispondenza con gli
indirizzi di levello applicativo del tipo www.qualcheserver.it. Infine, ci occupiamo di casi
applicativi particolari delle stesse tecnlogie, e che fanno parte di meccanismi più generali come
la Service Discovery, il VoIP, ed il controllo dello Spam.
• Domain Name System
• Resolver
• DNS
•
•
•
•
•
•
•
•
Nomi di dominio
Le zone: un database distribuito
Funzioni del DNS
Recursione
Risoluzione Inversa
BIND
Resource Records
File di zona
• Glue Records
• Strumenti di Indagine
• I pacchetti del DNS
• Indirizzi variabili
• Dynamic Host Configuration Protocul
• Dynamic DNS
• Zeroconf
• Auto-assegnazione degli indirizzi IP
• Risoluzione dei nomi
• Service discovery
• Service Location Protocol
• DNS-SD
• Simple Service Discovery Protocol
• Supporto di DNS al Voice over IP
• SRV RR
• NAPTR
• Selezione di un protocollo di trasporto
• Risoluzione di una URI numerica
• Adesione ad una federazione VoIP
• ENUM
• Anti-Spam DNS Blackhole Lists
• Appendice
• IETF
Lo strato applicativo di Internet
Alessandro Falaschi
Domain Name System
Abbiamo già osservato come un programma applicativo possa invocare la chiamata di sistema
struct hostent *gethostbyname(const char *name);
che, a partire da un nome di dominio, restituisce una struttura dati che contiene tra le altre
cose, l'indirizzo IP del proprio computer. Questa chiamata fa il paio con l'altra
struct hostent *gethostbyaddr(const void *addr, int len, int type);
che permette di popolare la medesima struttura dati, a partire stavolta dall'indirizzo IP a 32
bit x.y.w.z. Nei primi tempi dello sviluppo di Internet, queste funzioni usavano un file
presente nel computer, per l'esattezza /etc/hosts, contenente tutte le corrispondenze tra
nomi ed indirizzi dei computer di Internet, e che veniva scambiato tra i computer stessi. Un
esempio di /etc/hosts è fornito appresso: notiamo che a fianco di ogni indirizzo, sono presenti
due diversi nomi per uno stesso computer, essendo entrambi validi. Inoltre, viene fornita la
corrispondenza standard tra 127.0.0.1 e localhost.
#
# Necessario per il "loopback" IPv4.
#
127.0.0.1 localhost.localdomain localhost
#
# Indirizzi IPv4.
#
192.168.1.1 dinkel.brot.dg dinkel
192.168.1.2 roggen.brot.dg roggen
#
192.168.2.1 weizen.mehl.dg weizen
Ben presto però, con il successo e l'espansione di Arpanet, nel 1983 fu pubblicata la RFC 882
(successivamente modificata dalle RFC 1034 e 1035), in cui si definiva un meccanismo, chiamato
DNS, atto a delocalizzare questa tabella in tutta la rete, e tale da permettere di delegare alle
singole organizzazioni la manutenzione e l'aggiornamento della propria parte di spazio di
indirizzamento.
Resolver
Le chiamate a gethostbyname() e gethostbyaddr() su riportate, sono il punto di accesso
del resolver che è offerto dal sistema operativo, e che provvede ad interrogare sia i files locali,
che la sua cache, che i DNS esterni
Local Host
|
Foreign
|
+---------+ user queries +----------+
| +--------+
|
|-------------->|
| queries | |
|
| User
| gethostby... |
|---------|->| Foreign|
| Program |
| Resolver |
| | Name
|
|
|<--------------|
|<--------|--| Server |
|
| user responses|
|responses| |
|
+---------+
+----------+
| +--------+
|
A
|
cache additions |
| references |
V
|
|
+----------+
|
55
Domain Name System
Risoluzione degli indirizzi applicativi
| cache
|
+----------+
|
|
La figura che segue, illustra più in dettaglio la sequenza di attività che intercorrono tra quando
un programma applicativo effettua la chiamata alla resolver library, e quando effettivamente
riesce ad accedere al computer remoto.
Il comportamento del resolver è definito da un file di configurazione, che tradizionalmente
era /etc/host.conf, e che dalla versione 6 di glibc, è invece /etc/nsswitch.conf, in cui
tra le altre cose, troviamo la linea
hosts:
files dns mdns4
il cui il significato è di provare prima la risoluzione offerta da /etc/hosts, quindi (bind) di
rivolgersi al DNS, ed infine a Zeroconf. Il file locale può ad esempio servire per localizzare i
computer interni ad una stessa LAN, senza che questi debbano avere un nome "pubblico", oppure
per poterli raggiungere anche nel caso in cui il DNS esterno non sia raggiungibile: l'unica
condizione, in questo caso, è che i computer conservino sempre il loro stesso indirizzo, cosa che
invece non avviene, nel caso in cui vengano configurati mediante un server DHCP.
Per accedere ad un DNS esterno, però, occorre conoscere dove si trova, e questo è descritto nel
file /etc/resolv.conf, che nel mio caso contiene
nameserver 193.70.152.15
nameserver 193.70.152.25
che corrispondono alle impostazioni relative al provider Libero. Oltre alla direttiva nameserver,
possono anche essere presenti (ma non contemporaneamente) le direttive
domain ing.uniroma1.it
search ing.uniroma1.it uniroma1.it it
56
Lo strato applicativo di Internet
Alessandro Falaschi
nel caso in cui si voglia tentare di aggiungere automaticamente uno o più suffissi di dominio, nel
caso in cui un nome di computer "singolo" non venga risolto su nessun indirizzo.
DNS
A questo punto, quando una applicazione sul nostro computer deve risolvere un nome di dominio,
il computer indicato come nameserver dal file /etc/resolv.conf riceve un pacchetto UDP,
contenente una richiesta del tipo "qual'è l'indirizzo IP del computer pippo.topolinia.com ?"
Per il nameserver, si può verificare una delle tre possibilità:
1. è lui il DNS autorevole per il dominio topolinia.com e fornisce subito la risposta
cercata;
2. non sa niente del dominio topolinia.com, ma poco fa un'altro client gli aveva fatto la
stessa domanda, e la risposta che aveva ottenuto è ancora valida, quindi la recupera dalla
cache e restituisce quella;
3. non ha la più pallida idea dell'indirizzo richiesto, e si mette in moto per cercare la
risposta.
Nel primo caso, si dice che il DNS in questione è stato delegato da quello autorevole per il
dominio .com, e quest'ultimo a sua volta, è stato delegato dal DNS che è autorevole per il root
domain. Prima di addentrarci nella spiegazione di come si svolgono i passi 2 e 3, approfondiamo
questi concetti.
Nomi di dominio
Un nome a dominio è costituito da una serie di stringhe separate da punti, ad esempio
it.wikipedia.org. A differenza degli indirizzi IP, dove la parte più importante del numero è la
prima partendo da sinistra, in un nome DNS la parte più importante è la prima partendo da
destra, detta dominio di primo livello (o TLD, Top Level Domain), per esempio .org o .it.
Un dominio di secondo livello
consiste in due parti, per
esempio wikipedia.org, e
così via. Ogni ulteriore elemento
specifica un'ulteriore
suddivisione. Quando un dominio
di secondo livello viene
registrato all'assegnatario,
questo è autorizzato a usare i
nomi di dominio relativi ai
successivi livelli come
it.wikipedia.org (dominio di terzo livello) e altri come
some.other.stuff.wikipedia.org (dominio di quinto livello) e così via.
Per ognuno dei punti che si incontrano all'interno di un FQDN, si scende di un livello nella
gerarchia dei nomi, che in effetti è organizzata ad albero, ed in cui da ogni livello, possono
dipartirsi più sotto livelli, fino ad arrivare alle foglie, costituite dai nomi dei computer veri e
propri.
57
Domain Name System
Risoluzione degli indirizzi applicativi
Le zone: un database distribuito
Un DNS autorevole per il penultimo livello dell'albero, conosce unicamente i nomi dei computer
che definiscono l'ultimo livello, mentre i DNS dei livelli superiori, oltre a poter risolvere indirizzi
di host dotati da un nome più corto, delegano l'autorità delle zone associate ai livelli inferiori, ad
altri DNS. I DNS associati al dominio "." (punto e basta) sono detti i root name server, che in
effetti tengono assieme internet, sono 13, e sono messi a disposizione da diverse organizzazioni
sparse per il mondo (ma principalmente negli USA, sebbene alcune di queste adottino tecniche
anycast per distribuire il carico a livello mondiale), e sono coordinati dall'ICANN.
Il dominio parziale per cui un DNS è autorevole, viene denominato zona (su cui appunto, esercita
il dominio), ed a questa zona sono associati uno o più files, le cui righe sono denominate
Resource Record (Record della Risorsa, o RR), che descrivono informazioni relative ai nomi di
quel dominio. Il meccanismo di delega si basa sulla presenza (nel DNS di livello superiore) di
un RR di tipo NS (Name Server), che indica il DNS delegato.
58
Lo strato applicativo di Internet
Alessandro Falaschi
Tutti i root name server, condividono una medesima tabella di RR, che individua i root name
server, autorevoli per i top level domain (.com, .org, .net, .it, .de, .uk...). Per il
County Code dell'Italia ad esempio, la delega spetta ad un istituto del CNR di Pisa, presso il quale
ci si rivolge (direttamente o per il tramite di un rivenditore di hosting), per registrare il proprio
dominio.
Funzioni del DNS
Un server DNS può essere configurato come:
• server autorevole per una o più zone, che è delegato a gestire, sulla base dei record NS
inseriti nella zona (livello) superiore. Spesso sono presenti più server autorevoli per una
stessa zona: un primario, ed uno o più secondari, che copiano i dati di zona dal primario;
• server ricorsivo, che risolve le richieste effettuando una recursione a partire dai root
server, mantiene una cache delle risposte ricevute, ed è indicato a volte come caching
only DNS;
• forwarder, che non risolve le query direttamente, ma interrogando a sua volta un server
ricorsivo.
Lo schema sottostante è disegnato dal punto di vista di un DNS configurato sia come autorevole,
che come recursivo o forwarder. Mostra infatti come, in veste di DNS autorevole, il
nameserver legga da un insieme di master files, i Resource Records che definiscono la sua zona,
in modo da poter rispondere alle richieste che gli pervengono da un resolver esterno. Allo stesso
tempo, il nostro DNS inoltra verso un diverso nameserver le queries a cui non sa fornire
direttamente risposta.
59
Domain Name System
Risoluzione degli indirizzi applicativi
Local Host
|
Foreign
|
+---------+
|
/
/|
|
+---------+ |
+----------+
| +--------+
|
| |
|
|responses| |
|
|
| |
| Name
|---------|->|Foreign |
| Master |-------------->| Server
|
| |Resolver|
| files
| |
|
|<--------|--|
|
|
|/
|
| queries | +--------+
+---------+
+----------+
|
A
|maintenance | +--------+
|
+------------|->|
|
|
queries
| | Foreign|
|
| | Name
|
+------------------|--| Server |
maintenance responses | +--------+
Recursione
Se un DNS non è autorevole per la richiesta, e non trova la risposta nella sua cache, allora deve
effettuare una recursione, andando prima a chiedere ad un root nameserver l'identità dei DNS
autorevoli del tld, e quindi a questi, l'identità del DNS autorevole per il primo livello, e così via
fino a trovare il DNS autorevole per il FQDN desiderato.
Pertanto, anche un nameserver chaching-only, non autorevole su nulla, ha comunque un ruolo
molto utile nel velocizzare la navigazione (ed è utile configurarlo a casa propria). Associato ad
ogni risposta ricevuta durante la recursione, il DNS riceve anche un valore di Time To Live (TTL),
che indica il periodo di validità della risposta ricevuta: finchè questa non scade, il DNS non
effettua nuovamente la stessa richiesta, ma usa il valore presente in cache, risparmiando il
tempo necessario ad inoltrare la richiesta ed attendere risposta. Più tempo il DNS resta in
funzione, e più ricca sarà la cache, eliminando via via quasi del tutto, il bisogno di chiedere
all'esterno la risoluzione dei suffissi ricorrenti.
Risoluzione Inversa
Può aver senso (ed in effetti lo ha) di voler effettuare la risoluzione inversa rispetto a quanto
fatto finora, e cioè determinare il fqdn di un host, a partire dal suo indirizzo IP. Dato che si
tratta sempre degli stessi dati, sembra logico voler affidare questo compito ancora una volta al
DNS; quindi, come un particolare DNS è autorevole per i nomi degli host che ospita, altrettanto
lo è per quanto riguarda il lotto di indirizzi IP a disposizione del provider che ospita il DNS.
C'è da notare un particolare, però, e cioè che mentre per i nomi di dominio, il livello più elevato
è quello scritto più a destra, e quindi l'albero delle deleghe procede aggiungendo i prefissi di
livello inferiore in testa, per gli indirizzi IP la parte più generale è quella scritta a sinistra, e le
sottoreti più specifiche si ottengono aggiungendo i byte in coda. Dato che però il DNS, per come
60
Lo strato applicativo di Internet
Alessandro Falaschi
è fatto, aggiunge i sotto-livelli (più specifici) in testa, allora si è scelto di scrivere gli indirizzi IP
al contrario, e di pensarli come sotto-dominio di un TLD radice fittizio, chiamato in-addr.arpa.
Pertanto, nel chiedere la risoluzione inversa dell'indirizzo IP (ad es.) 151.100.122.144, la query
inoltrata sarà per il nome 144.122.100.151.in-addr.arpa. Questo stratagemma, permette di
distribuire anche le risoluzioni inverse mediante delle zone organizzate gerarchicamente: il name
server autorevole per in-addr.arpa delega l'autorità per il primo byte dell'indirizzo (nell'esempio,
151) ad un DNS gestito dall'organizzazione a cui è assegnato il lotto di indirizzi 151.0.0./8,
questo, delega l'autorità di risolvere il secondo byte dell'indirizzo IP, ai DNS a cui questo è
intestato (nell'esempio, il lotto 151.100.0.0/16), e così via.
BIND
L'implementazione più diffusa di un server DNS è BIND, sviluppato fin dal 1988 presso l'Università
di Berkeley, ed ora mantenuto da ISC (che gestisce anche uno dei root ns). Il processo che viene
lanciato, ha nome named (la d sta per daemon, e ricorre spesso, nel caso di processi che sono
eseguiti in background), e determina il tipo di risposte che potrà fornire, in base al contenuto del
file /etc/bind/named.conf, di cui forniamo un esempio inspirato da AIL, che fornisce una
guida passo-passo alla configurazione di BIND:
named.conf
file di zona
risoluzioni inverse
; /etc/bind/named.conf
include "/etc/bind/
named.conf.options";
zone "." {
type hint;
file "/etc/bind/db.root";
};
zone "localhost" {
type master;
file "/etc/bind/db.local";
};
zone "127.in-addr.arpa" {
type master;
file "/etc/bind/db.127";
};
; /etc/bind/db.local
; /etc/bind/db.127
@ IN SOA localhost.
root.localhost. (
1
; Serial
604800
; Refresh
86400
; Retry
2419200
; Expire
604800 ) ; Min TTL
@ IN SOA localhost.
root.localhost. (
1
; Serial
604800
; Refresh
86400
; Retry
2419200
; Expire
604800 ) ; Min TTL
@
@
@
IN NS
1.0.0 IN PTR
IN
IN
NS
A
localhost.
127.0.0.1
localhost.
localhost.
include "/etc/bind/
named.conf.local";
; /etc/bind/dg
; /etc/bind/named.conf.local
zone "168.192.in-addr.arpa" {
type master;
file "/etc/bind/192.168";
};
zone "dg" {
type master;
file "/etc/bind/dg";
};
zone "brot.dg" {
type master;
file "/etc/bind/brot.dg";
};
@ IN SOA dinkel.brot.dg.
root.dinkel.brot.dg. (
1998031800
; Serial
28800
; Refresh
7200
; Retry
604800
; Expire
86400 ) ; Min TTL
NS
dinkel.brot.dg.
; /etc/bind/brot.dg
@ IN SOA dinkel.brot.dg.
root.dinkel.brot.dg. (
1998031800
; Serial
61
; /etc/bind/192.168
@ IN SOA dinkel.brot.dg.
root.dinkel.brot.dg. (
1998031800
; Serial
28800
; Refresh
7200
; Retry
604800
; Expire
86400 ) ; Min TTL
1.1
2.1
NS
dinkel.brot.dg.
PTR
PTR
dinkel.brot.dg.
roggen.brot.dg.
Domain Name System
Risoluzione degli indirizzi applicativi
28800
7200
604800
86400 )
;
;
;
;
Refresh
Retry
Expire
Min TTL
NS
MX
MX
dinkel.brot.dg.
10 dinkel
20 roggen
www
CNAME
ftp.brot.dg.
dinkel.brot.dg.
CNAME
dinkel
dinkel
roggen
192.168.1.1
192.168.1.2
A
A
La sintassi generale dei files di zona, è illustrata qui di seguito. Per ora osserviamo che in
named.conf si dichiara che:
• in db.root (sotto /etc/bind/) si trova il file di suggerimento (hint) che permette di
localizzare i root name server, autorevoli per i TLD;
• in db.local e db.127, si trovano le informazioni autorevoli (master) relative agli
indirizzi di tipo 127.0.01, e che consentono rispettivamente di effettuare la risoluzione
diretta ed inversa con il nome localhost.
• viene quindi incluso il file /etc/bind/named.conf.local, che a sua volta indica in dg,
brot.dg e 192.168, i nomi dei files contenenti le direttive che rendono il DNS
autorevole (master) rispettivamente per le zone dg, brot.dg, e per il gruppo di indirizzi
locali di tipo 192.168.0.0/16.
Prima di analizzare cosa viene descritto in questi files, illustriamo la sintassi e la tipologia dei
possibili Resource Records (RR) che vi possono comparire.
Resource Records
I file di zona sono essenzialmente costituiti da un elenco di registrazioni di risorse (Resource
Records, o RR), che rappresentano tutte le informazioni su cui il DNS è autorevole. Questi RR
hanno un formato comune, del tipo
[nome] [TTL] [classe] tipo dati_della_risorsa
in cui i termini tra parentesi, se assenti, assumono lo stesso valore presente nel RR
precedente. Prendendo come esempio un file di zona di nome brot.dg, il significato dei campi
è il seguente:
• nome: serve per costruire il FQDN della risorsa descritta dal RR, e può essere espesso nelle
forme
• @ : si pronuncia at, significa "qui", e compare nel primo record del file (lo Start Of
Autority, SOA). E' un meta-simbolo che rappresenta il nome della zona che è
stata dichiarata in named.conf, alla riga che referenzia il file stesso. Se è
presente nei record successivi al SOA, alla sua occorrenza viene sostituito il suo
valore, ossia il nome della zona, ovvero il suffisso di dominio a cui la zona si
riferisce. Il valore di @ può essere modificato mediante l'uso della direttiva
$ORIGIN, che non è un RR, può occupare da sola una linea con la sintassi $ORIGIN
miodominio.org, rimpiazzando così il valore di @;
• nomehost.dominio.tld. : il punto finale indica che il nome è un FQDN;
62
Lo strato applicativo di Internet
Alessandro Falaschi
• nomehost: l'assenza di un punto finale indica che il record è relativo alla zona
corrente, ed il FQDN corrispondente può ottenersi concatenando a nomehost il
valore corrente di @, eventualmente modificato da $ORIGIN
• TTL: è il campo Time To Live, espresso in secondi, e determina la durata di validità delle
informazioni trattenute nelle cache dei server non autorevoli. Non va confuso con il TTL
della intestazione IP. Se è assente, il TTL di un RR è posto pari al valore minTTL
dichiarato dal RR SOA posto all'inizio del file
• classe: è la classe degli indirizzi che vengono risolti dal DNS, e l'unico valore che venga
praticamente usato per questo campo, è IN, che significa INternet (vedi un pò!)
• tipo: è il campo che caratterizza il RR, ed i valori che più frequentemente possono essere
assunti, sono riportati nella tabella che segue
• dati: il significato e la sintassi di questo campo dipende dal valore di tipo, come discusso
di seguito:
Tipo Descrizione
Dati
si ha qui una sintassi piuttosto strutturata, del tipo
nameserver email ( n_seriale refresh retry expire minTTL )
in cui sono indicati, nell'ordine, il CNAME del nameserver
primario e autorevole per la zona, ossia l'host presso
cui risiedono i files di zona, l'emaildel suo
amministratore (ma al posto della @, si usa un punto, per
non creare confusione con il meta-simbolo @ illustrato
sopra), un numero che si incrementa ad ogni modifica del
file, tre valori in secondi che determinano la frequenza
degli aggiornamenti da parte dei secondari, ed il TTL di
default per i RR che non lo dichiarano
SOA
Start Of Authority - è il primo RR che
compare nel file di zona, e definisce
un insieme di parametri comuni a
tutti i RR della stessa zona
NS
Name Server - indica il DNS autorevole
per il dominio del RR, e rappresenta
il meccanismo con cui un dominio di
un certo livello, delega
l'auterevolezza di un sottodominio,
ad un altro DNS. Per uno stesso
sottodominio possono essere presenti
più record NS, ad indicare che il
carico deve essere ripartito su più
macchine
il FQDN dell'host reso autorevole per il dominio
delegato. Generalmente nello stesso file di zona, è
presente anche un RR di tipo A, che ne risolve il nome
del DNS nelegato nel suo indirizzo IP (vedi anche la
definizione di glue records)
A
Address - effettua la traduzione vera e
propria tra il dominio, ed il suo
indirizzo.
l'indirizzo IP nella sua forma dotted decimal x.y.w.z. Ci
possono essere più RR di tipo A, relativi a nomi diversi,
e che vengono risolti con un medesimo indirizzo IP.
Canonical Name - permette di associare
più nomi ad uno stesso host, indicati
con il termine di alias. Qualora vi
siano più indirizzi per uno stesso
CNAME
nome, solo uno questi è canonico. Per
tutti gli altri, questo RR permette
di specificare a quale nome canonico
vadano associati
PTR
Pointer - è presente nelle zone con
estensione in-addr.arpa, e permette
la risoluzione inversa da indirizzo
IP, a FQDN. Nel campo dominio, è
presente la parte di indirizzo IP
sottostante al nome della zona
.in-addr.arpa, scritta da destra a
sinistra.
MX
Mail Exchanger - indica un host
incaricato di ricevere la posta
elettronica (via SMTP) indirizzata
verso gli utenti del dominio del RR.
Possono essere presenti più RR MX per
lo stesso dominio, ognuno con una
associata priorità, per garantire il
servizio anche quando un host è in
manutenzione
il FQDN del nome canonico associato al nome relativo a
questo RR.
Es: weizen.brot.dg.
dinkel.brot.dg.
weizen.brot.dg.
A
192.168.0.1
A
192.168.0.1
CNAME dinkel.brot.dg
il FQDN del nome canonico dell'host a cui è stato assegnato
questo indirizzo. E' infatti possibile inserire un unico RR
di tipo PTR, per uno stesso indirizzo IP.
compaiono due campi, con il formato
priorità FDQN
in cui priorità è un numero, ed il RR con il numero
inferiore, è quello che viene provato per primo; FQDN
invece identifica il server SMTP da utilizzare.
63
Domain Name System
Risoluzione degli indirizzi applicativi
Per un elenco più completo dei tipi, si consulti il sito di ISC. Alcuni altri tipi usati sono:
HINFO descrive la CPU ed il SO usato da un host
AAAA
descrive un indirizzo IPv6
LOC
memorizza i dati geografici GPS del DNS (RFC 1876)
NAPTR name authority pointer (RFC 2915)
SRV
permette di scoprire chi eroga i servizi di rete (RFC 2782)
File di zona
Siamo finalmente in grado di commentare i files di zona forniti nell'esempio:
• sono presenti due file di zona necessari alla risoluzione diretta ed inversa dell'indirizzo
127.0.0.1 con il nome localhost;
• altri tre files di zona permettono di definire l'esistenza di due computer, di nome dinkel
e roggen
• appartenenti al dominio brot.dg, ed
• a cui sono assegnati gli indirizzi 192.168.1.1 e .2
• dinkel ospita il name server, un server HTTP ed il MX primario;
• roggen ospita un server FTP, e l'MX secondario.
Notiamo che i files di zona /etc/bind/dg e /etc/bind/brot.dg contengono sia nomi nella
forma di FQDN, che singoli: in questo secondo caso, vengono automaticamente estesi con il
valore di @. In particolare, questo processo di estensione può avvenire anche nel campo dati del
RR. L'uso di nomi non FQDN, facilita il riuso dei files di zona, qualora lo stesso blocco di indirizzi
venga ri-assegnato ad un diverso nome di dominio. Viceversa, nel file di risoluzione inversa
(/etc/bind/192.168) non è possibile usare i nomi corti per il campo dati, perché in tal caso il
valore di @ non è più pari al suffisso di dominio, ma è invece pari a 168.192.in-addr.arpa.
Notiamo infine che, dato che i file di zona indicano in dinkel il DNS autorevole per le zone dg e
brot.dg, e che questi files dunque, devono risiedere fisicamente proprio su dinkel, allora... il
computer che ospita il DNS, non può che essere dinkel!
Glue records
L'esempio fornito, vede lo stesso DNS autorevole sia per dg, che per brot.dg. Ma cosa sarebbe
successo, se le due zone fossero state ospitate su server diversi? Immaginiamo questo scenario:
• un resolver chiede al suo DNS, l'IP di www.brot.dg;
• la richiesta è inoltrata ai root Name Server, che indicano l'IP del DNS autorevole per .dg:
• il DNS autorevole per .dg viene interrogato, ma tutto quel che potrebbe rispondere, è
che il nameserver autorevole per brot.dg è dinkel.brot.dg, ma... non ne può
conoscere l'indirizzo IP, perché dovrebbe chiederlo a dinkel stesso!!
Per ovviare a questa situazione di stallo, è previsto che nel punto di delega sia aggiunto un RR
non autorevole di tipo A (nel nostro esempio, ad es. di tipo dinkel.brot.dg IN A
192.168.1.3), che permetta al DNS di livello superiore, di fornire la risoluzione dell'indirizzo IP
autorevole per la zona di livello inferiore. Questo caso particolare di risoluzione di un IP per un
computer esterno alla propria zona (ma interno ad un sottodominio delegato) prende il nome di
Glue Record (o collante) in quanto permette, appunto, di tenere assieme due zone. Pertato si
64
Lo strato applicativo di Internet
Alessandro Falaschi
avrebbe:
presso il DNS autorevole per .dg:
192.168.0.1 = dg
presso il DNS autorevole per brot.dg: 192.168.0.3 =
dinkel.brot.dg
; /etc/bind/dg
; /etc/bind/brot.dg
@ IN SOA dg.
root.dinkel.brot.dg. (
1998031800
; Serial
28800
; Refresh
7200
; Retry
604800
; Expire
86400 ) ; Min TTL
brot.dg.
NS
NS
dg.
A
dinkel.brot.dg. A
@ IN SOA dinkel.brot.dg.
root.dinkel.brot.dg. (
1998031800
; Serial
28800
; Refresh
7200
; Retry
604800
; Expire
86400 ) ; Min TTL
dg.
dinkel.brot.dg.
dinkel
roggen
192.168.1.1
192.168.1.3
NS
dinkel.brot.dg.
A
A
192.168.1.3
192.168.1.2
Strumenti di Indagine
Nella sezione apposita delle esercitazioni, illustriamo il funzionamento di alcuni strumenti di
indagine relativi alla configurazione dei DNS, come whois, host, dig, nslookup.
I pacchetti del DNS
Sniffando con Wireshark, possiamo
osservare il formato dei pacchetti UDP
diretti verso la porta 53 a cui risponde
il DNS, e le risposte associate. Il
formato di domande e risposte è
simile, e contiene il medesimo
identificatore; inoltre nelle risposte,
sono riportate anche le domande
relative, che vengono citate nello
spazio delle risposte. Il campo
authority riporta gli estremi della
fonte autorevole da cui la risposta ha
origine, mentre le informazioni
addizionali riferiscono, ad esempio, il
RR di tipo A di un MX il cui nome
canonico è presente nel campo di
risposta. Infine, il campo flags è in
realtà composto da
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode
|AA|TC|RD|RA| Z
|
RCODE
|
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
in cui
•
•
•
•
QR specifica se è una richiesta od una risposta
Opcode specifica il tipo di richiesta
AA segnala che chi risponde, è autorevole per il dominio della query
TC messaggio troncato
65
Indirizzi variabili
•
•
•
•
Risoluzione degli indirizzi applicativi
RD consente la ricorsione
RA ricorsione disponibile
Z sono riservati per un uso futuro
RCODE contiene un codice che identifica il tipo di risposta.
Indirizzi variabili
L'associazione diretta ed inversa tra nome di computer e suo indirizzo IP, è a rigor di logica
possibile, solo nel caso in cui questa non si modifichi nel tempo, ovvero l'host disponga di un
cosiddetto indirizzo IP statico. Al contrario, molto spesso l'indirizzo IP viene assegnato
dinamicamente poco dopo l'accensione del computer (ad es. via DHCP), ed in quel caso, esistono
dei meccanismi (il DDNS) per riconfigurare opportunamente il DNS. Allo stesso tempo, i computer
di una stessa rete locale, dovrebbero poter comunicare anche in assenza di un DNS centralizzato
ed amministrato da qualcuno: a tale scopo, è nata l'iniziativa di Zeroconf.
Dynamic Host Configuration Protocol
Il DHCP, definito nella RFC 2131 come evoluzione di BOOTP, è un protocollo spesso usato dagli
ISP per condividere un certo numero di indirizzi IP tra un numero più elevato di computer,
confidando che una richiesta di servizio contemporanea da parte di tutti, non avverrà
praticamente mai. Ma al di là di questo, affidare la configurazione di una rete ad un meccanismo
dinamico ed automatico è una grande comodità, alla luce della dinamica con cui i computer
della rete entrano/escono e sono sostituiti.
Il protocollo opera sulla porta 67 di UDP, e mediante i passaggi
illustrati in figura, affitta (lease) gli indirizzi di cui dispone, ai
client che ne fanno richiesta.
• l'host appena acceso, invia in broadcast la sua richiesta
(DISCOVERY) di sapere (lui) chi è, od eventualmente,
prova a reclamare il rinnovo dell'affitto per l'indirizzo IP
ricevuto per ultimo. In quest'ultimo caso, il server può
confermare il rinnovo, rifiutarlo, o ignorare la richiesta;
• i server DHCP presenti nella LAN inviano allora in unicast
un messaggio di OFFER verso il client, che contiene, oltre
all'indirizzo IP proposto (ed a lui momentaneamente
riservato), anche altri parametri, come la maschera di
sottorete, il DNS da usare, il default gateway, e la durata
dell'affitto; queste informazioni, possono eventualmente
dipendere dall'indirizzo MAC del richiedente;
• il client sceglie uno tra gli OFFER ricevuti, e trasmette in broadcast un messaggio di
REQUEST, citando sia l'indirizzo che gli è stato offerto, che il server che lo ha offerto, in
modo che gli altri server, ricevendo la comunicazione broadcast, possano rendere
nuovamente disponibili gli altri indirizzi offerti, ma non adottati;
• se non è successo nulla di nuovo e di particolare, il server conferma la richiesta appena
ricevuta mediante un messaggio di ACKNOWLEDGE, in cui conferma i parametri già offerti.
Il processo continua con il client che periodicamente, prima che termini il periodo di affitto, ne
effettua una rinnovo mediante un messaggio di REQUEST, finché il suo funzionamento termina,
ed emette un messaggio di RELEASE. Il comportamento del client può essere rappresentato da
un diagramma di transizione, che evidenza i passaggi di stato che avvengono:
66
Lo strato applicativo di Internet
Alessandro Falaschi
Tenendo aperto il capture di Wireshark, e contemporaneamente disabilitando/riabilitando
l'interfaccia di rete, si possono osservare i passaggi discussi. Nel caso preso in esame però, manca
la fase di DISCOVERY, dato che il computer in questione tenta di riusare l'IP che gli era stato
assegnato precedentemente (192.168.0.215), ed il messaggio di REQUEST viene visualizzato
come "SSL".
La RFC 2132 elenca tutta una serie di ulteriori parametri che possono ulteriormente essere
specificati tramite i messaggi DHCP, come ad esempio (nelle richieste) il nome dell'host, e (nelle
risposte) il dominio che quest'ultimo deve aggiungere alle sue richieste, qualora queste non si
riferiscano ad un fqdn.
Dynamic DNS
Lo standard RFC 2136 definisce un nuovo tipo di messaggio per le richieste al DNS, mediante un
Opcode di tipo UPDATE, ed in cui i restanti campi, anziché contenere una richiesta, contengono
gli estremi di un RR da aggiungere o modificare. In questo modo, un server DHCP può comunicare
al DNS l'indirizzo associato ai lease assegnati, ed associarlo al nome che l'host gli ha comunicato.
Inoltre, la RFC 2845 definisce un metodo di autenticazione di questi messaggi, basato su di un
segreto condiviso. A conclusione dell'A.A 2006-2007, si è svolta una tesina che ha affrontato
l'argomento.
Queste tecniche prendono il nome di DDNS, ma lo stesso acronimo viene utilizzato anche per
67
Indirizzi variabili
Risoluzione degli indirizzi applicativi
identificare tecniche alternative sviluppate indipendentemente dai costruttori di dispositivi.
Inoltre, lo stesso principio è applicato da diversi DDNS provider, che permettono anche agli
utenti dial-up a cui viene assegnato un IP dinamico, di poter essere raggiunti dal resto di Internet
mediante un FQDN. In generale, il TTL dei RR mantenuti aggiornati mediante DDNS sono
piuttosto bassi, dell'ordine della decina di minuti, per permettere alla gerarchia dei DNS di
aggiornare frequentemente le proprie cache, e propagare in fretta i RR modificati più di recente.
Zeroconf
Si tratta di un metodo di configurazione dinamica delle risorse di una rete locale, basato sul
protocollo IP, e che non dipende da altri elementi architetturali, nè da pianificazioni ed accordi
con altre parti. In altre parole, un computer in area locale deve semplicemente essere in grado
di interoperare con altri computer li presenti, senza dipendere da nulla di esterno, un pò come
per la corrente elettrica, nessuna lampadina va configurata prima di accenderla! E' un pò ciò che
avveniva con la rete Appletalk e che avviene con la rete Windows, con la differenza che usando
direttamente IP, uno sviluppatore può sfruttare lo stack TCP/IP anche per le applicazioni di rete
che si svolgono tutte in area locale, e che è disponibile nativamente nelle diverse architetture di
calcolo. Zeroconf è stato principalmente sviluppato da un impiegato di APPLE, come evoluzione
di AppleTalk (video). Per raggiungere gli obiettivi illustrati, occorre che
• gli indirizzi IP siamo assegnati senza ricorrere ad un server DHCP
• la traduzione tra nomi ed indirizzi IP avvenga senza una server DNS centralizzato
• i servizi come stampanti, o directory condivise, siano localizzabili senza ricorrere ad un
directory sever centralizzato
Sebbene non ancora completamente definito dagli standard, zeroconf viene già utilizzato per
accedere, ad esempio, alle stampanti di rete. Illustriamo ora meglio, i tre aspetti sopra
evidenziat:
Auto-assegnazione degli indirizzi IP
I dispositivi che aderiscono a Zeroconf, tentano di auto-assegnarsi un indirizzo link-local di tipo
169.254.*.*, che la RFC 3927 stabilisce possano essere usati nell'ambito di una LAN, e ri-usati
su qualunque altra LAN, in quanto non devono essere instradati dai router, e neanche accettati
dai dispositivi NAT. La definizione delle modalità con cui avviene questa auto-assegnazione è il
frutto del lavoro di un WG IETF, ora chiuso. Il risultato, è che ogni host tenta di attribuirsi (e
difendere) l'uso (per se) di uno di questi indirizzi. Se però un server DHCP effettivamente
risponde, ed assegna all'host un indirizzo instradabile, viene usato quest'ultimo.
Risoluzione dei nomi
L'idea è di far uso di un DNS che risponda a richieste pubbliche, ossia multicast (detto mDNS).
Ogni computer che intenda offrire servizi accessibili mediante indirizzi link-local, ospita un suo
mDNS che risponde, presso la porta UDP 5353, alle richieste indirizzate verso l'indirizzo multicast
224.0.0.251 (questo indirizzo, non viene inoltrato dai router). Inoltre, è stato proposto l'uso
di uno speciale top level domain, di nome .local, in modo che le richieste di nomi del tipo
computer.local vengano dirette, anziché verso il DNS configurato di default, verso l'indirizzo
multicast dove ascolta l'mDNS. Una applicazione client che richieda la risoluzione del nome
sally.local quindi, riceverà la risposta direttamente dall'mDNS in esecuzione presso la
macchina sally.
68
Lo strato applicativo di Internet
Alessandro Falaschi
Al fine di evitare collisioni di nomi, non appena un mDNS parte, prova a verificare se non ci sia
già qualcun altro che rivendica le stesse risorse.
Mentre per mDNS esistono già diverse realizzazioni funzionanti, il WG DNSEXT di IETF ha
recentemente standardizzato una soluzione diversa allo stesso problema, nota come Link-local
Multicast Name Resolution (o LLMNR) (RFC 4795), nata in casa Microsoft, e che sebbene funzioni
in modo del tutto simile a mDNS, permette di usare anche nomi di tld esistenti, con un possibile
effetto di disorientamento.
Service discovery
Con questo termine si intende una funzione basilare necessaria per accedere ad una qualunque
risorsa o servizio disponibile in rete. E' chiaro che noi umani possiamo venire a conoscenza di un
particolare indirizzo perché qualcuno ce ne parla, oppure perché questo viene pubblicizzato su
giornali, TV, siti web, ed email. Al contrario, un computer in rete utilizza un protocollo di
comunicazione, particolarmente progettato per individuare i servizi offerti, descriverne le
caratteristiche (o attributi), ed illustrarne le modalità di fruizione, fornendone l'indirizzo (URL).
Illustriamo ora tre diverse alternative: SLP, DNS-SD, e SSDP.
Service Location Protocol
Un caso piuttosto classico, è quello delle stampanti, che possono comparire "magicamente",
quando desideriamo stampare qualcosa. Il WG SVRLOC di IETF ha elaborato a tale proposito la
RFC 2608 che definisce il Service Location Protocol (SLP), che si basa sulla definizione di tre
entità, un client, un server ed un director, sebbene quest'ultimo sia presente solo su reti di
grosse dimensioni. Anche se lo standard è definito in modo generico, e non orientato unicamente
alle stampanti, è abbastanza comune che queste ultime implementino l'entità SLP server. In
linea generale, quando un SPL client ha bisogno di un servizio, invia in multicast una richiesta
SLP relativa a quel tipo di servizio, e tutti i client che lo offrono, rispondono.
DNS-SD
Il DNS Service Discovery (DNS-SD) permette la scoperta dei servizi basandosi sull'uso dei RR SRV
del DNS, e per questo funziona particolarmente bene in congiunzione con il mDNS, anche se non
ne dipende, nel senso che può essere usato anche con un DNS normale. La sua definizione è
frutto dello stesso autore della definizione degli indirizzi Link-Local e del mDNS, e quindi si
integra perfettamente con la suite definita da Zeroconf, per la quale sono disponibili varie
implementazioni, come ad esempio Bonjour e Avahi (video). Nella sezione degli esercizi, sono
svolti alcuni esperimenti con Avahi.
69
Supporto di DNS al Voice over IP
Risoluzione degli indirizzi applicativi
Simple Service Discovery Protocol
SSDP è un protocollo UPnP, usato da Windows XP ma considerato più complesso di DNS-SD, ed il
cui processo di standardizzazione si è arrestato nel 2000.
Supporto di DNS al Voice over IP
Con Voice over IP (VoIP) si intende la possibiità di effettuare conversazioni audio mediante
Internet, e l'approfondimento di queste tecniche sarà oggetto di una futura sezione del corso.
Sebbene la maggior parte degli utenti di Internet identifichi il VoIP con Skype, questo si basa su
protocolli proprietari e non pubblici; invece, esiste una valida alternativa, il Session Initiation
Protocol (SIP), che è definito da IEFT mediante documenti pubblici. SIP individua gli utenti per
mezzo di URI dal formato simile a quelle delle email, ossia
sip:[email protected]
e, quando un computer connesso ad Internet genera una chiamata SIP diretta a questa
destinazione, si tenta di individuare il server SIP incaricato di localizzare l'utente alef presso il
dominio ing.uniroma1.it, mediante l'interrogazione del DNS a riguardo dei RR di tipo NAPTR
e SRV. Se invece di un utente connesso ad Internet, la chiamata deve partire da, o
raggiungere, un normale utente telefonico connesso alla rete telefonica PSTN, allora sorge il
problema di dover trattare anche semplici numeri, cosidetti E.164. La traduzione da numero
E.164 ad indirizzo SIP, avviene ancora una volta per mezzo del DNS, facendo uso dei RR NAPTR,
in accordo alla raccomandazione ENUM. Ma andiamo con ordine.
SRV RR
Il Resource Record di tipo SRV (SeRVice) è definito nella RFC 2782, e viene effettivamente usato
da applicazioni come il VoIP (protocollo SIP) e la messaggistica (protocollo XMPP, RFC 3920). Esso
realizza una funzione di Service Location basata sul DNS, e permette di scoprire quali computer
offrano, presso un certo dominio, un determinato servizio applicativo, usando il trasporto
specificato. Il risultato di questa query indicherà
• il FQDN del computer cercato
• il numero di porta di trasporto presso la quale è offerto il servizio
Queste caratteristiche ne rendono l'utilizzo simile a quello relativo al RR MX (che permette di
scoprire, ad esempio, che il server email di alice.it è smtp.aliceposta.it (provare host
-t MX alice.it)); in più, il RR SRV permette anche di svincolarsi dall'uso delle porte ben
note, potendo infatti offrire il servizio su di una porta qualsiasi, che viene scoperta dal client
solo al momento del suo utilizzo effettivo. Il formato dei RR di tipo SRV è
_sip._tcp.example.com. 86400 IN
--+- --+- ----+------ --+-- +
|
|
|
|
|
serv proto domain
TTL class
SRV
-+|
TYP
0
|
|
pri
5 5060
|
|
|
|
wei port
sipserver.example.com.
---------+-----------|
target
i cui campi sono descritti al seguente modo:
• Nome, in cui il simbolo _ permette di distinguere tre componenti:
• Service: il nome simbolico del servizio desiderato, qui sip
• Protocol: il trasporto che si intende utilizzare, qui tcp
• Domain name: il dominio nel cui ambito si desidera individuare il servizio, qui
example.com
70
Lo strato applicativo di Internet
•
•
•
•
•
•
Alessandro Falaschi
TTL: il solito Time to Live, qui 86400 secondi, pari a 24 ore
Class: il solito campo classe, qui (e sempre) IN
Priority: la priorità dell'host target, qui 0
Weight: il peso relativo per i record con la stessa priorità, qui 5
Port: la porta (TCP o UDP) su cui si può accedere la servizio servizio, qui 5060
Target: il nome dell'host che eroga il servizio, qui sipserver.example.com
Poniamo che il DNS autorevole per il dominio example.com, ospiti il RR dell'esempio: un resolver
che esegua una query chiedendo il RR di tipo SRV associato a _sip._tcp.example.com, vuol
conoscere quale sia, e su che porta TCP risponda, il SIP Server del dominio example.com. In
analogia con il caso dei RR MX, la query può restituire più RR di tipo SRV, con diversi target,
contraddistinti da diverse priorità e pesi, in modo da poter distribuire il carico su più target, ed
offrire ridondanza.
Nel caso in cui i RR SRV siano erogati da un mDNS, questi possono essere generati dagli stessi
applicativi in esecuzione sull'host su cui gira il mDNS, facendo venir meno l'esigenza di immetterli
manualmente, in accordo al principio di Zeroconf.
NAPTR
L'acronimo NAPTR sta per Naming Authority Pointer Resource Record, definito nella RFC 2915 e
successive, ed ha lo scopo di incorporare nel DNS un insieme di regole, tali da permettere alle
informazioni di delega, di essere ulteriormente ri-delegate. In altri termini, viene resa possibile
la risoluzione di un nome a dominio, in un nuovo nome a dominio, in una URI, o (nello specifico)
in un indirizzo VoIP. Un RR di tipo NAPTR aderisce ad una sintassi dalla forma
Domain TTL Class Type Order Preference Flags Service Regexp Replacement
ed il significato di alcuni dei suoi campi può apparire notevolmente involuto, a causa della
estrema genericità che si è voluta dare a questo tipo di RR. In tutti i modi
• i campi Domain, TTL e Class hanno i significati già visti, Type vale (appunto) NAPTR, ed
Order e Preference hanno lo stesso significato di Priority e Weight del RR SRV, ossia
consentono di mantenere un back-up, e di bilanciare il carico su diverse macchine;
• il campo Flags è costituito da una singola lettera, in cui
• S indica che il prossimo passo, sarà un accesso al DNS, per individuare un RR di tipo
SRV;
• A indica che il prossimo passo, sarà un accesso al DNS, per individuare un RR di tipo
A;
• U indica che il prossimo passo non sarà un accesso al DNS, ma che l'esito della
applicazione della Regexp a Domain, costituisce il risultato desiderato;
• P indica che il prossimo passo è determinato dal protocollo che ha prodotto la query
• il campo Service è una stringa che deve essere riconosciuta dalla applicazione che ha
causato la query, in modo da poter verificare che il risultato è quello atteso. Ad esempio,
se la query è effettuata nel contesto di una risoluzione ENUM, il risultato della
applicazione della Regexp al dominio, dovrà rappresentare una URI SIP, ed allora Service
deve corrispondere al valore "E2U+sip", che sta per E.164 to URI SIP.
• in termini più generali, il campo service si scompone in due campi separati da un
più (+), e indicati rispettivamente come protocol e resolution service (rs). Per ogni
protocollo di strato applicativo (nell'esempio, SIP), deve esistere una RFC che
descriva i tipi di rs invocabili da quel protocollo (nell'esempio, la risoluzione da
numero E.164 in URI, descritta dalla RFC 3971)
71
Supporto di DNS al Voice over IP
Risoluzione degli indirizzi applicativi
• il campo Regexp è una Regular Expression, che costituisce un formalismo (ossia, una
sintassi) per descrivere (e riconoscere) un insieme di stringhe, e descrivere allo stesso
tempo una trasformazione di tali stringhe, in altre stringhe. Nel caso in cui il Flag sia U,
questa Regexp dovrà essere applicata dal client che ha interrogato il DNS, alla chiave
utilizzata nella query, ossia al campo Domain, ed il risultato della applicazione della
regexp, costituirà la risoluzione desiderata;
• Replacement è la stringa che viene restituita come risultato della query, nel caso in cui il
Flag valga S oppure A. L'uso del campo Replacement è mutuamente esclusivo con quello
di Regexp.
Nel caso di una applicazione VoIP, i RR di tipo NAPTR intervengono in almeno tre circostanze:
Selezione di un protocollo di trasporto
La RFC 3263 specifica che, prima di chiamare una URI SIP, si dovrebbe intraprendere un processo
di risoluzione in due passi, che prevede
1. l'interrogazione al DNS, per richiedere i RR di tipo NAPTR relativi al dominio che compare
nella URI sip, e da questi, desumere il protocollo di trasporto da usare (UDP, TCP o TLS su
TCP), e quindi
2. effettuare una nuova query al DNS, utilizzando come chiave i risultati ottenuti al passo
precedente, e richiedendo i RR di tipo SRV, in modo da determinare l'host ed il numero di
porta verso cui dirigere la chiamata.
Ad esempio, volendo chiamare sip:[email protected], il primo passo potrebbe restituire
;
example.com
example.com
example.com
IN NAPTR
IN NAPTR
IN NAPTR
order pref flags service
regexp
50
50 "s" "SIPS+D2T"
""
90
50 "s" "SIP+D2T"
""
100
50 "s" "SIP+D2U"
""
replacement
_sips._tcp.example.com.
_sip._tcp.example.com.
_sip._udp.example.com.
indicando che il dominio example.com supporta SIP sia su UDP che su TCP, e SIP su TLS. Nei tre
casi, la parte RS del campo service assume il significato di Domain to UDP e Domain to TCP.
Come indicato dal flag pari ad s, il risultato delle query è individuato dal campo replacement, e
deve essere seguito da una richiesta dei RR di tipo SRV. Nel caso in cui il chiamante (ad es.) non
supporti SIPS, tenterà di determinare il computer e la porta da chiamare effettivamente, per il
trasporto TCP e UDP, mediante una successiva interrogazione dei RR di tipo SRV:
;
_sip._tcp.example.com
_sip._udp.example.com
IN SRV
IN SRV
Priority Weight Port
0
1
5060
0
2
5060
Target
server1.example.com.
server2.example.com.
a cui farà poi seguito una normale interrogazione al DNS, per conoscere i RR di tipo A, ed
individuare finalmente l'IP da contattare.
Notiamo che nelle due risoluzioni su riportate, i domini di partenza e di arrivo non devono
necessariamente coincidere, offrendo una opportunità di URI portability, potendo infatti
accasare una URI SIP in cui compare un certo dominio, presso i server di un altro provider VoIP.
Infine, nel caso in cui il primo passo fallisca, si può procedere direttamente al secondo,
costruendo le query con il prefisso dei trasporti desiderati. Nel caso in cui fallisca il secondo, si
assumerà di chiamare direttamente l'host associato al nome di dominio della URI, ed usare il
trasporto UDP sulla porta ben nota 5060.
72
Lo strato applicativo di Internet
Alessandro Falaschi
Risoluzione di una URI numerica
Come anticipato, quando la destinazione da chiamare non è data nella forma di una URI sip, ma
di un normale numero di telefono E.164, allora vengono applicate le regole di riscrittura del
numero indicate come ENUM, ed il DNS viene utilizzato prima di tutto, per convertire un numero
E.164 in una URI SIP. In questo caso, i RR rilevanti avranno sempre il Flag pari ad U, ed il campo
Replacement sarà assente (ma sostituito da un punto). Pertanto, poniamo che la query sia
soddisfatta dai RR
$ORIGIN 0.0.6.2.3.3.5.2.0.2.1.e164.arpa.
IN NAPTR 100 10 "u" "E2U+sip"
"!^.*$!sip:[email protected]!"
IN NAPTR 100 20 "u" "E2U+mailto" "!^.*$!mailto:[email protected]!"
.
.
in cui il dominio espresso nella $ORIGIN è il risultato delle regole di riscrittura definite da ENUM,
per il numero E.164 +12025332600. Le regexp che troviamo sono cosiddette greedy, e sono
composte da due campi, delimimitati dai tre punti esclamativi. La prima parte ^.*$ significa
(letteralmente) qualsiasi cosa, e quindi la chiave-dominio espressa dalla $ORIGIN, corrisponde.
Pertanto, quando il client che ha chiesto la risoluzione riceve questa risposta, applica la
sostituzione indicata dal secondo campo della Regexp, che nei due casi di Servizio E2U+sip e
E2U+mailto, corrisponde rispettivamente a sip:[email protected]
e mailto:[email protected]. In altre parole, la query con chiave E.164, ha fornito come
risoluzione a priorità migliore una URI SIP, e se questa chiamata VoIP dovesse fallire, viene
proposta come seconda risoluzione, l'invio di una email. Nella figura che segue, un esempio di
utilizzo delle alternative di reperibilità.
L'applicazione di questa metodologia, prevede che il legittimo intestatario di un numero
telefonico, richieda al provider VoIP che gestisce il DNS delegato a risolvere il proprio numero in
73
Supporto di DNS al Voice over IP
Risoluzione degli indirizzi applicativi
formato ENUM, l'inserimento nel DNS di tanti RR di tipo NAPTR, quanti sono i diversi recapiti che
vuole associare a questo numero. In tal modo, anzichè dover comunicare ai suoi conoscenti tutti i
diversi indirizzi a cui può essere raggiunto, può comunicare loro un unico numero.
In effetti, dopo una risoluzione ENUM, possono ancora essere necessarie le due risoluzioni
previste al punto precendente, più ovviamente, l'individuazione dell'indirizzo IP associato al
dominio finale.
Adesione ad una federazione VoIP
in questo caso, i record NAPTR sono usati nel caso della costituzione di una Federazione SIP,
ossia di un insieme di provider VoIP, che convengono di basarsi su di una Certification Autority
comune, al fine di garantire ai propri utenti l'autenticità delle chiamate in arrivo. La definizione
di questa architettura, denominata SIP Peering, è tuttora oggetto di standardizzazione, ma
l'orientamento che emerge dai draft, è di usare (mediante RR di tipo NAPTR) il DNS per
annunciare le proprie federazioni di appartenenza, in modo che il chiamante e/o il chiamato
possano verificare se esistono delle CA in comune, e comportarsi di conseguenza. In questo caso,
avremo degli elementi del tipo
$ORIGIN vsp-X.example.com
@ IN NAPTR 10 50
"U"
"D2P+SIP:fed" "!^.*$!http://fed-2.example.org/!" .
con cui il quale il provider vsp-X.example.com annuncia la propria adesione alla federazione
indicata dalla URI http://fed-2.example.org, usando un RR di tipo NAPTR presso il proprio
dominio, dove flag pari ad U indica un simbolo terminale, ed il servizio pari a D2P+SIP:fed
indica una risoluzione Domain to Peering relativa al protocollo SIP:fed, ossia, l'estensione a SIP
per supportare le federazioni.
ENUM
L'acronimo ENUM sta per Electronic Number Mapping System ENUM, è descritto dalla RFC 3761, è
implementato in accordo alle linee guida indicate nella RFC 3824, e definisce il metodo per
utilizzare il DNS per la risoluzione dei numeri E.164 in URI. Si basa sulla trasformazione
dei numeri telefonici in Domini Internet, attuata ri-scrivendo il numero da destra a sinistra, con
la cifra più significativa a destra, intercalando le cifre con dei punti, ed aggiungendo (a destra) il
suffisso e164.arpa. Ad esempio, al numero telefonico E.164 +39.081.7507.1 è associato il
nome di dominio: 1.7.0.5.7.1.8.0.9.3.e164.arpa. In questo modo, si definisce un meccanismo di
delega dei sotto-domini, coerente con la struttura gerarchica della numerazione telefonica, in
modo del tutto simile a quanto avviene per la risoluzione inversa degli indirizzi IP.
Dato che sembrano esserci ostacoli sia di natura burocratica che politica alla delega delle
numerazioni nazionali sotto il suffisso e164.arpa, sono state proposte diverse radici alternative
(ossia, suffissi) per la risoluzione ENUM, come la sperimentazione italiana condotta presso
NAMEX, che fa riferimento ad una radice 6.9.3.e164.namex.it, l'iniziativa europea nrenum.net, e
e164.org, che permette gratuitamente ai singoli individui possessori di un qualunque numero
telefonico, di associarvi un indirizzo VoIP. Dato che, noto un numero E.164, non è più ben
chiaro sotto che radice debba essere indirizzata l'interrogazione al DNS, i proxy SIP
possono interrogare in sequenza più alberi ENUM.
74
Lo strato applicativo di Internet
Alessandro Falaschi
Anti-Spam DNS Blackhole Lists
Il fenomeno dello spamming della posta elettronica è noto a tutti, e consiste nell'invio di una
grande quantità di posta elettronica a destinatari sparsi in tutto il mondo, e che non la vogliono
ricevere. Meno nota, è l'origine di questo termine: SPAM è una marca di carne in scatola, la cui
invadenza è stata oggetto di uno schetch televisivo dei Monty Pyhton (video).
Il fenomeno dello spamming si basa sull'uso di OpenRelay e OpenProxy, ovvero host che
rilanciano i messaggi email ricevuti mediante il protocollo SMTP, senza discriminare la loro
provenienza. Mentre la configurazione di un server SMTP ufficiale come OpenRelay può, ai giorni
nostri, avvenire solo a causa di una grave disattenzione del suo amministratore, spesso gli
OpenProxy sono ospitati da host di utenti connessi ad Internet, inconsapevolmente infetti da un
virus, che appunto fa da intermediario tra lo spammer, e il server SMTP che l'utente stesso
utilizza di diritto.
Tra le tecniche di difesa dallo spam, è interessante in questo contesto, citare quella che fa uso
del DNS per distribuire in rete una Blackhole List, come ad esempio quelle di SpamCop e
SpamHaus. Queste organizzazioni, ricevono segnalazioni a riguardo degli indirizzi IP da cui
provengono email di spam, ad esempio perché quel computer ospita un OpenProxy. Quando un
server SMTP riceve una connessione, interroga la BHL per sapere se il mittente è tra i cattivi
oppure no. L'interrogazione avviene come una richiesta di risoluzione DNS, nel seguente modo:
1. l'indirizzo IP del client viene riscritto con i byte invertiti — ad esempio 192.168.1.254
diventa 254.1.168.192;
2. il dominio della DNSBL viene concatenato all'indirizzo IP invertito, ad es.
254.1.168.192.spammers.example.net;
3. viene effettuata una query DNS (di tipo A) per l'host name così ottenuto. Se la risposta
ricevuta è un indirizzo IP (ad es 127.0.0.2), il client è listato, mentre se è NXDOMAIN (No
such domain) il client è buono
Le risposte a tali interrogazioni, vengono salvate nei DNS intermedi che effettuano la ricorsione,
in modo che le email di spam successive, e provenienti dallo stesso OpenProxy, vengono rifiutate
senza interrogare di nuovo il DNS autorevole di chi gestisce il sevizio di DNS BL.
Appendice
IETF
L'Internet Engineering Task Force sviluppa e promuove gli standard di Internet, in collaborazione
con W3C e ISO/IEC, ed è costituita da volontari, senza necessità di appartenenza formale. E'
organizzata in un gran numero di Gruppi di Lavoro (WG), il cui funzionamento è definito dalla
RFC 2418, ognuno relativo ad un argomento specifico, e commissionati a portare a termine un
lavoro, e quindi ad essere chiusi. Ogni gruppo è diretto da uno o più chairman, e gli obiettivi
sono definiti da un charter. Più gruppi sono riuniti all'interno di una stessa area sulla base degli
argomenti, ed ogni area supervisionata da un direttore d'area, che nomina i chair dei WG. I
direttori d'area assieme al chair dello IETF, compongono l'Internet Engineering Steering Group
(IESG), responsabile dell'attività complessiva dello IETF. Ancora, IETF è formalmente una attività
svolta sotto l'ombrello della Internet Society (ISOC), mentre è supervisionata dall'Internet
Architecture Board (IAB).
I gruppi di lavoro si riuniscono fisicamente tre volte l'anno, e negli intervalli, svolgono il lavoro
discutendo per via posta elettronica, costituendo così un luminoso esempio di comunicazione
telematica. Le decisioni vengo prese senza bisogno di votazioni, ma in base al principio del
75
Riferimenti
Risoluzione degli indirizzi applicativi
consenso approssimato. Le mailing list sono ad accesso pubblico, e chiunque vi può intervenire.
Quando la discussione raggiunge un livello di maturità sufficiente, oppure per chiarire meglio un
punto di vista od un approccio, vengono prodotti dei documenti detti draft, che sono lasciati in
visione sui server pubblici per un periodo massimo di sei mesi, dopodiché se non è stata prodotta
una nuova versione del draft, contenente gli emendamenti risultanti dalla discussione
intercorsanel frattempo, vengono ritirati.
Quando il Draft raggiunge uno stato stabile, sempreché abbia ricevuto il consenso, questo evolve
allo stadio di Request for Comments (RFC), ma anche in questo caso, ci sono da fare alcuni
distinguo, e precisamente:
• le specifiche che si prevede possano diventare degli standard internet evolvono secondo
tre livelli di maturità, mantenendo il numero progressivo della RFC con cui sono stati
emessi, e prendono rispettivamente gli appellativi di Proposed Standard, Draft Standard e
Internet Standard: in quest'ultimo caso, gli viene assegnato un secondo numero, nella
serie degli STD.
• le specifiche che non sono sul binario degli standard (standards track) possono essere
etichettate come Experimental, Informational, o Historic, e non sono da considerare
standard in nessun senso.
• La sottoserie delle RFC detto di Best Current Practice (BCP) è un modo per standardizzare
le pratiche che risultano da delibere di comunità, con cui lo IETF definisce e ratifica un
orientamento comune che si è affermato autonomamente nella comunità della gestione
di Internet.
Riferimenti
•
•
•
•
DNS HowTo di Nicolai Langfeldt (in italiano)
Introduzione al DNS, Appunti di Informatica libera
Pro DNS and BIND
Uso di ENUM per le Reti della Ricerca - Marco Sommani (CNR-Pisa), GARR_WS7
76
Lo strato applicativo di Internet
Realizzato con
Alessandro Falaschi
da Alessandro Falaschi - ultimo aggiornamento Novembre 2007
77
Lo strato applicativo di Internet
Posta elettronica
Questa sezione esplora le caratteristiche salienti di una delle più diffuse applicazioni di rete,
l'e-mail, il cui funzionamento è completamente poggiato sui servizi offerti dagli strati
protocollari inferiori (TCP/IP e DNS), acceduti rispettivamente tramite l'interfaccia socket e la
resolver library. L'esposizione si articola nella descrizione di come i messaggi email siano
formattati, e come vengano inoltrati; quindi, si illustrano le caratteristiche descrittive offerte
dalle estensioni MIME. Alla base della scrittura delle email, ci sono i testi, e quindi vengono
discussi gli alfabeti di rappresentazione dei caratteri usati dai vari idiomi della terra. Dopo aver
trattato del prelievo dell'email, e della sicurezza per invio e ricezione, sono elencate le possibili
alternative di comunicazione testuale.
• Elementi architetturali
• Normativa e nomenclatura
• Configurazione
• Protocollo SMTP
•
•
•
•
•
Oggetti email
Codici di risposta
Extended SMTP
Destinatari multipli
Intestazioni
• MIME
• Intestazioni principali
• Content-Type
• Content-Transfer-Encoding
• quoted-printable
• base64
• Encoded Word
• Multipart Content Type
• Multipart Subtypes
• Content-Disposition
• Insiemi di caratteri
• ASCII
• Codepage
• Unicode
• Piani
• Basic Multilingual Plane
• Unicode Tranformation Format
• UTF-8
• Sicurezza
• Autenticazione
• SASL
• SMTP-AUTH
• Confidenzialità, integrità e autenticità
Lo strato applicativo di Internet
Alessandro Falaschi
• StartTLS
• Ricezione dell'email
• POP3
• IMAP
• Webmail
• Altre architetture di telecomunicazione testuale
•
Mailing List
•
•
•
•
Automazione
Gestori
Archiviazione
Netiquette
• Newsgroup
• BBS
• Internet Relay Chat
• Instant Messaging
• Topologia e interlavoro
• Client multiprotocollo
• Standard aperti
• Jabber - XMPP
• Architettura
• Interoperabilità
• SIMPLE
• Presence
• Open Mobile Alliance
• Funzioni Telemediali
Elementi architetturali
La posta elettronica (electronic mail) è un servizio di comunicazione Internet basato sulla
consegna asincrona di PDU dati contenti testo, e/o altri file allegati. I soggetti mittente e
destinatario di una email sono individuati da URI applicative dal formato
mailto:[email protected]
che rappresentano la domiciliazione dell'utente alef presso il suo dominio internet. Sebbene la
consegna delle email sia attuata mediante applicazioni client-server, non accade mai che il
mittente dialoghi direttamente con il destinatario. Invece, sono dislocati in rete dei nodi speciali
detti server di posta, che dialogano tra loro mediante un protocollo applicativo denominato
SMTP, e tramite i quali viene inoltrato il messaggio. Il primo server della catena è
concettualmente simile al default gateway dello strato IP, ed è quello a cui il mittente consegna
(fiducioso) il messaggio da spedire. Questo primo server, una volta chiusa la conessione TCP su
cui avviene la transazione SMTP, può a sua volta inviare (trasformandosi in client) un messaggio
verso un altro server SMTP di sua scelta, oppure direttamente verso il server che gestise la posta
per il dominio presso il quale risiede l'utente destinatario. Il messaggio rimarrà li in giacenza,
finchè l'intestatario della URI di destinazione non lo preleverà, ricorrendo ad un diverso
protocollo.
79
Protocollo SMTP
Posta elettronica
Normativa e nomenclatura
Il Simple Mail Transfer Protocol viene definito nel 1982 dalla RFC 821, scritta da John Postel, e
da allora aggiornata da altri documenti (RFC 2821 e molti altri). Il protocollo SMTP è elaborato da
una applicazione-demone, in ascolto delle connessioni TCP sulla porta 25. La consegna a
destinazione di un messaggio, avviene secondo uno schema di immagazzinamento e rilancio, ad
opera dei server di posta indicati anche come agenti, ovvero intermediari, detti Mail Transfer
Agent (MTA). Questi, dialogano tra loro in SMTP, e rivestono prima il ruolo di server, e poi di
client, occupandosi di inoltrare il messaggio in direzione della destinazione. Il caso
dell'intervento di due soli agenti è descritto dal seguente disegno, trovato presso Liverani:
Il mittente (umano) compone il messaggio da spedire mediante un Mail User Agent (MUA), che si
comporta come un client SMTP, ed invia l'email ad un primo MTA di transito: l'SMTP server
dell'ISP di partenza. Questo a sua volta, assumendo ora il ruolo di client, inoltra il messaggio
verso l'SMTP server situato presso il destinatario, che (attuando la funzione di Mail Delivery
Agent, o MDA) salva localmente il messaggio ricevuto, in attesa che il destinario (umano) lo
prelevi (con il suo MUA) per mezzo del protocollo POP3 o IMAP, e/o lo legga.
Configurazione
Tipicamente il MUA usato dal mittente deve essere configurato manualmente,
inserendo l'indirizzo del server SMTP a cui inoltrare l'email in uscita: nella pratica, questo dovrà
essere proprio il server SMTP disponibile presso l'ISP tramite il quale ci si collega ad
Internet. Infatti, per limitare il fenomeno dello spamming, ogni ISP configura il proprio server
SMTP in modo che questo accetti la posta da recapitare, solo se proveniente da
computer collegati tramite la propria stessa rete. Non solo: sempre per lo stesso motivo, i server
SMTP che operano dal lato di destinazione della comunicazione, si rifiutano di accettare le email
provenienti da lotti di indirizzi che gli ISP assegnano dinamicamente (ad es., via DHCP) ai loro
utenti.
D'altra parte, esistono casi in cui il Server SMTP usato da un mittente casalingo, non è quello del
proprio ISP: ad esempio, si tratta del caso di una email inviata tramite una interfaccia webmail
come Gmail, oppure qualora il computer mittente usi un server SMTP co-residente (rischiando
però di vedersi l'email bloccata dai meccanismi anti-spam).
Protocollo SMTP
Il server SMTP presso l'ISP del mittente, interroga il DNS per conoscere i record MX, ovvero l'SMTP
server, del dominio di destinazione; quindi, conduce con questo una transazione SMTP, del tipo
di quella riportata in quest'esempio. Notiamo che come misura antispam, il ricevente può
verificare (tramite DNS) che il nome dell'host mittente, si risolva effettivamente nell'indirizzo da
cui risulta provenire la connessione. Poi, dopo alcune verifiche sull'effettiva esistenza
80
Lo strato applicativo di Internet
Alessandro Falaschi
dei destinatari, la transazione procede citando il mittente, i destinatari, e quindi il corpo del
messaggio, eventualmente preceduto da altri header testuali, e terminato da una linea isolata,
contenente un solo punto.
il colloquio indicato si svolge sia tra il MUA del mittente (che svolge un ruolo di SMTP client) ed il
suo server SMTP di uscita, che tra l'SMTP server (che anch'esso, si trasforma per l'occasione in
client) dell'ISP del mittente, e quello del destinatario.
Riportiamo appresso il risultato di un capture, in cui le linee prefisse con S: e C: indicano
rispettivamente le stringhe emesse da server e client.
S:
C:
S:
S:
S:
S:
S:
S:
C:
S:
C:
S:
C:
S:
C:
C:
C:
C:
C:
C:
C:
C:
C:
C:
C:
C:
C:
C:
S:
C:
S:
220 smtp-out4.libero.it ESMTP Service (7.3.120) ready
EHLO [192.168.120.40]
250-smtp-out4.libero.it
250-DSN
250-8BITMIME
250-PIPELINING
250-HELP
250 SIZE 30000000
MAIL FROM:<[email protected]> SIZE=358
250 MAIL FROM:<[email protected]> OK
RCPT TO:<[email protected]>
250 RCPT TO:<[email protected]> OK
DATA
354 Start mail input; end with <CRLF>.<CRLF>
Message-ID: <[email protected]>
Date: Mon, 05 Mar 2007 17:06:20 +0100
From: alef <[email protected]>
User-Agent: Mozilla Thunderbird 1.5.0.9 (X11/20070103)
MIME-Version: 1.0
To: [email protected]
Subject: test di capture dell'SMTP
Content-Type: text/plain; charset=ISO-8859-15
Content-Transfer-Encoding: 7bit
salute a tutti
Ale
.
250 <45D9993D01232796> Mail accepted
QUIT
221 smtp-out4.libero.it QUIT
Notiamo le seguenti cose.
Oggetti email
La RFC2821 distingue tra envelope e content. L'envelope è inviato come una serie di unità di
protocollo SMTP, e consiste dell'origine (MAIL FROM), di uno o più recipienti (RCPT TO), e di
eventuali riferimenti ad estensioni. Il contenuto invece, è inviato mediante l'unità di
protocollo DATA, e consiste di due parti, le intestazioni (header) definite da RFC 2822, ed il
corpo (body) che se è strutturato, è definito in accordo a MIME (RFC 2045). Sia header che body,
sono trasmessi usando caratteri a 7 bit, inseriti in byte con il bit più significativo a zero, ed
appartenenti all'alfabeto US-ASCII, tranne per l'eccezione prevista dall'estensione 8BITMIME per il
body, e dalla sintassi Encoded Word per gli headers. Il messaggio è composto da linee terminate
dalla sequenza CR/LF (0D 0A in esadecimale, 13 10 in decimale), e di lunghezza massima di 1000
bytes.
81
Protocollo SMTP
Posta elettronica
Codici di risposta
Ogni risposta del SMTP server è del tipo reason-code reason-phrase, ovvero un numero
seguito da una frase. I codici numerici possono essere usati da un programma per capire la
risposta, mentre la frase è a beneficio della leggibilità, per l'operatore umano. Il significato dei
codici di risposta può essere classificato nell'ambito di 5 categorie, individuate dalla prima cifra
del corrispondente codice numerico, in accordo allo schema
reason code categoria
significato
1xx
Positive
Preliminary Reply
seguirà una risposta ulteriore, prima che il comando richiesto sia
completato
2xx
Positive Completion
Reply
il comando è stato eseguito, e si può iniziare una nuova richiesta
3xx
Positive Intermediate
Reply
ci si aspetta altro input da parte del client
4xx
Transient Negative
Completion Reply
manifestano un errore temporaneo, offrendo la possibilità di ripetere
il comando che ha causato l'errore
5xx
Permanent Negative
Completion Reply
il comando non è stato accettato, l'azione non è stata intrapresa, ed
il client è scoraggiato a ritentare
Extended SMTP
L'Extended SMTP è definito dalle RFC 1869 e RFC 2821, ed il server ne annuncia il supporto,
mediante la sua risposta iniziale. Se in questa, infatti, compare la stringa ESMTP anziché SMTP,
allora vuol dire che il server supporta le estensioni. Il client a sua volta, può manifestare
l'intenzione di tentare di sfruttare una delle estensioni disponibili, asserendo a sua volta la
stringa EHLO, a cui il server risponde con l'elenco delle estensioni disponibili, ognuna definita in
una RFC separata. Altrimenti, nel caso in cui il client si fosse presentato con un semplice HELO,
si procede con un comportamento strettamente conforme alla RFC 821. Tra le estensioni presenti
nell'esempio sopra riportato, notiamo
◦ SIZE (RFC 1870) che indica la massima dimensione accettata, ed evita al MUA di iniziare a
trasmettere qualcosa di più voluminoso;
82
Lo strato applicativo di Internet
Alessandro Falaschi
◦ DSN (RFC 3461) - Delivery Status Notification per delegare all'SMTP il compito di generare
una ricevuta di consegna, ma non è utilizzata praticamente mai;
◦ 8BITMIME (RFC 1652) - l'SMTP è definito per consegnare messaggi scritti con caratteri
ascii a 7 bit, mentre questa estensione consente l'uso (per il body) di caratteri ad 8 bit, in
accordo al formato MIME, qualora il client aggiunga il parametro BODY al comando SMTP
MAIL:
C: MAIL FROM:<[email protected]> BODY=8BITMIME
Dato che invece gli header devono contenere sempre e comunque caratteri US-ASCII, e
che a seguito dell'introduzione dello standard MIME, negli header è comunque presente
l'informazione a riguardo del Content-Transfer-Encoding, si ottiene che l'ESMTP
ricevente ha comunque modo di conoscere l'Encoding del body per questa via, e quindi
l'uso di questo parametro è divenuto opzionale. Si veda infatti questo capture, per un
esempio di messaggio contenente le lettere accentate àèéìòù offerte dall'alfabeto
ISO-8859-15, e trasferito ad 8 bit;
◦ STARTTLS (RFC 3207) permette di invocare i servizi di crittografia offerti dal Transport
Layer Security;
◦ SMTP-AUTH (RFC 2554) permette di restingere l'uso dell'SMTP di uscita ai soli utenti in
grado di autenticarsi, nel tentativo di mitigare il fenomeno dello SPAM. Ma dato che
comunque, non risolve il problema dello SPAM in ingresso al server di destinazione, non
viene particolarmente usato.
Destinatari multipli
Nel caso di più destinatari dello stesso messaggio, questi vengono elencati tutti come
recipienti (RCPT), e poi viene inviata una unica copia del messaggio. Un server SMTP
intermedio, se ha ricevuto un messaggio con destinari molteplici, alcuni dei quali co-locati presso
uno stesso dominio di destinazione, a sua volta invia al server SMTP di quel dominio una unica
copia del messaggio, con tutti i RCPT (in quel dominio) raggruppati assieme.
Intestazioni
Le opzioni dei protocolli analizzati finora (ARP, UDP, TCP, ICMP, DNS...), sono sempre state
codificate in formato binario, e poste all'interno delle intestazioni delle PDU prodotte da quei
protocolli: queste intestazioni, venivano esaminate direttamente dai dispositivi di rete, o dal
kernel dei computer di destinazione. Nel caso attuale invece, l'SMTP è un protocollo di strato
applicativo che opera direttamente tra entità pari, non più integrate dentro ad Internet, ma
concettualmente disposte ai bordi della rete, ed in esecuzione nello User Space dei computer in
comunicazione. Questa profonda differenza, fa sì che l'SMTP adotti una diversa modalità di
rappresentazione delle proprie intestazioni di protocollo, così come accadrà anche nel caso dei
diversi protocolli applicativi che esamineremo in seguito, e che prevede che le intestazioni di
strato applicativo, siano rappresentate in forma umanamente leggibile. Tali intestazioni sono
state inizialmente definite in RFC 822, e quindi in RFC 2822: sono disposte una per linea,
e composte da un nome, seguito da due punti, e quindi un valore; quindi, sono separate dal
body del messaggio vero e proprio, mediante una linea vuota. Le uniche due
intestazioni obbligatorie, sono
• Date: Mon, 05 Mar 2007 17:06:20 +0100 - inserite dallo UA di partenza
• From: Alessandro Falaschi <[email protected]> - il mittente, a cui inviare l'eventuale
risposta
83
Protocollo SMTP
Posta elettronica
Sembra strano che non sia richiesto obbligatoriaente almeno un destinatario? ...il fatto è che
questo può essere espresso mediante tre diversi header (To:, Cc:, e Bcc:), nessuno dei quali è
di per sé obbligatorio. Analizziamo ora però, alcuni altri header che possono essere presenti:
• Sender: segreteria <[email protected]> - chi materialmente invia il messaggio,
per conto del mittente vero;
• Reply-to: scrivimi <[email protected]> - se presente, le risposte vanno qui,
e non al From:
• To: [email protected] - il destinatario, possono essere più d'uno;
• CC: [email protected] - Carbon Copy, un altro destinatario da mettere in copia,
possono essere più d'uno;
• BCC: [email protected] - Blind Carbon Copy, ancora altro destinatario da
mettere in copia, senza che gli altri destinatari lo sappiano; i BCC possono essere più d'uno
• Message-ID: <[email protected]> - inserito dallo UA come identificativo del
particolare messaggio. Questo valore può essere citato come valore degli header
In-Reply_To: e References: che, se presenti in una risposta, permettono di associare
la stessa al messaggio uscente corrispondente
• User-Agent: Mozilla Thunderbird 1.5.0.9 (X11/20070103) - identifica il programa usato
per l'invio
• Subject: test di capture dell'SMTP - identifica l'oggetto della comunicazione. È
considerata buona educazione utilizzare questo campo, per aiutare il destinatario a capire
il contenuto del messaggio.
le seguenti tre intestazioni hanno a che fare con l'alfabeto usato per scrivere il contenuto
della email, e con il modo in cui tale testo viene rappresentato, come descritto di seguito
• MIME-Version: 1.0
• Content-Type: text/plain; charset=ISO-8859-15
• Content-Transfer-Encoding: 7bit
esistono poi delle ulteriori intestazioni, che possono essere aggiunte dai server SMTP di transito,
e che troviamo dal lato di ricezione del messaggio dell'esempio soprastante, come
• Return-Path: <[email protected]>
• Received: from smtp-out4.libero.it (smtp-out4.libero.it [212.52.84.46]) by
infocom.uniroma1.it (8.12.10/8.12.10) with ESMTP id l25GY4aW002416for
<[email protected]>; Mon, 5 Mar 2007 17:34:04 +0100
• Received: from localhost (172.31.0.51) by smtp-out4.libero.it (7.3.120) id
45D9992900FDB3E3 for [email protected]; Mon, 5 Mar 2007 17:06:20 +0100
• X-Scanned: with antispam and antivirus automated system at libero.it
• Received: from smtp-out4.libero.it ([172.31.0.40]) by localhost (asav-out10.libero.it
[192.168.32.38]) (amavisd-new, port 10024) with ESMTP id ttPaRI2Q3Cle for
<[email protected]>; Mon, 5 Mar 2007 17:06:20 +0100 (CET)
• Received: from [192.168.120.40] (151.41.242.192) by smtp-out4.libero.it (7.3.120)
id 45D9993D01232796 for [email protected]; Mon, 5 Mar 2007 17:06:20 +0100
in cui
• il Return-Path: viene inserito dall'ultimo server SMTP della catena, quello relativo al
destinatario, ed indica l'indirizzo a cui inviare eventuali messaggi di errore
• le intestazioni Received: sono aggiunte ognuna, dal basso verso l'alto, dai diversi server
SMTP di transito, e possono tornare utili, per ricostruire il percorso che ha fatto il
messaggio. Indicano l'SMTP mittente, il ricevente, se si è usato l'ESMTP, l'ID unico con il
quale il messaggio è stato registrato nei file di log, il destinatario (potrebbe cambiare, se
elaborato da una mailing list), e la data e ora locali, più la correzione rispetto all'ora di
Greenwitch. Qualora il numero di intestazioni Received: superi un determinato valore
84
Lo strato applicativo di Internet
Alessandro Falaschi
(ad es. 30), si presume che si sia verificato un loop anomalo, l'inoltro viene sospeso, e
viene inviato un messaggio di errore al Return-Path:
• le intestazioni che iniziano per X- (es X-Scanned:) non sono definite da uno standard,
ma possono veicolare informazioni speciali per lo UA di ricezione, o semplicemente per chi
legge
MIME
Il Multipurpose Internet Mail Extensions (MIME) estende il formato delle email, per permettere
•
•
•
•
l'uso di caratteri diversi dall'insieme US-ASCII,
di allegare oggetti, anche diversi da file di testo,
di spedire messaggi composti da più parti, e
di usare caratteri non-ASCII nei valori degli header, come il Subject:
Queste specifiche sono usate anche in ambiti diversi dal traffico email, come per i
protocolli HTTP e SIP, e sono descritte dai documenti RFC 2045, RFC 2046, RFC 2047, RFC 4288,
RFC 4289, RFC 2077, RFC 2231, RFC 3676.
Intestazioni principali
L'intestazione
MIME-Version: 1.0
indica allo User Agent di ricezione, che il messaggio aderisce alle specifiche MIME, e viene
semplicemente ignorato da uno UA non aggiornato, e non in grado di interpretarlo
correttamente.
Content-Type
La presenza di
Content-Type: text/plain; charset=ISO-8859-15
indica il tipo di contenuto presente, nel formato tipo/sottotipo; parametro=valore, e
fornisce allo UA un suggerimento su come visualizzare o riprodurre correttamente il contenuto
ricevuto. Il parametro permette di specificare una particolare caratteristica del tipo/
sottotipo indicato, ed in questo esempio, stabilisce che il body dell'email contiene caratteri
appartenenti all'insieme ISO-8859-15. Nel caso invece in cui si tratti di un contenuto non
direttamente visualizzabile da parte del lettore di email, ossia non testuale, occorre eseguire un
applicativo idoneo (ad es., un player multimediale per contenuto audio o video), associato al
MIME-Type che lo descrive. La lista dei tipi e sottotipi possibili è registrata presso IANA, da
cui possiamo evidenziare alcuni casi particolari:
• Tipo application: contenuti da aprire con programmi appositi
• application/javascript: codice JavaScript; definita in RFC 4329
• application/octet-stream: contenuto binario generico, che può anche
essere un programma eseguibile. Se presente nel messaggio ricevuto, il programma
ricevente può visualizzare una proposta di salvarlo su disco. La RFC 2046 lo
imposta come il tipo di default per sottotipi non riconosciuti, e per questi motivi,
presenta rischi di sicurezza.
85
MIME
Posta elettronica
• application/pdf: definita da RFC 3778
• application/vnd.ms-powerpoint: definita da Sukvinder S. Gill. vnd sta per
vendor e identifica formati proprietari
• application/xml (RFC 3023): i dati sono strutturati in formato XML, e possono
codificare informazioni che necessitano di ulteriore elaborazione per poter essere
usate
• Tipo audio
• audio/mpeg: MP3 o altro audio MPEG audio; definito in RFC 3003
• audio/x-wav: WAV audio. La particella x- indica un tipo non registrato presso
IANA, ma inventato dal mittente, e che in base ad accordi indipendenti, è
riconosciuto dallo UA ricevente.
• Tipo image
• image/gif: immagine GIF image; definito in RFC 2045 and RFC 2046
• image/jpeg: immagine JPEG; definito in RFC 2045 and RFC 2046
• Tipo multipart: questo tipo permette a MIME di inviare messaggi strutturati ad albero,
in cui le singole parti possono essere foglie, con a loro volta un unico Content-Type,
oppure essere altri componenti di tipo multipart. In questo modo, si possono ad
esempio inviare allegati, come illustrato sotto. Definito in RFC 2045 e RFC 2046.
• Tipo text
• text/plain: dati testuali visualizzabili direttamente dallo UA, definito in RFC
2046 e RFC 3676, che raccomanda l'uso del set di caratteri US-ASCII se non
specificato diversamente, attribuendo al parametro charset un valore opportuno
(come as es., ISO-8859-15). In caso di assenza di sottotipo, l'allegato è da
intendersi plain
• text/html: un file HTML che può essere visualizzato con un browser web o dallo
UA stesso; definito da RFC 2854, che suggerisce di specificare il charset mediante
l'uso dell'apposito parametro
• text/xml (RFC 3023): i dati sono strutturati in formato XML, e possono essere
visualizzati da un ricevente generico, come fosse un testo semplice
• Tipo video
• video/mpeg: video in formato MPEG-1 multiplato assieme con audio, definito
in RFC 2045 and RFC 2046
• video/mp4: video MP4, definito in RFC 4337
• video/quicktime: video QuickTime video, registrato presso IANA
• video/x-ms-wmv: Windows Media Video, documentato presso Microsoft KB 288102
Content-Transfer-Encoding
A meno che non sia disponible l'estensione ESMTP di tipo 8BITMIME, le email devono contenere
solamente caratteri US-ASCII, con il bit più significativo di ogni byte posto a zero. Questo
contrasta con l'uso di set di caratteri esteso, come gli alfabeti ISO-8859-x, e con l'invio di allegati
contenenti dati binari qualsiasi. Per questo, lo standard MIME prevede l'uso della intestazione
Content-Transfer-Encoding, come ad esempio
Content-Transfer-Encoding: 7bit
che stabilisce un metodo di codifica del body tale da convertire il suo vero contenuto, qualsiasi,
in una diversa rappresentazione, tale che nel flusso di byte risultante il bit più significativo sia
86
Lo strato applicativo di Internet
Alessandro Falaschi
posto a zero. Il lato trasmittente, una volta noto il formato accettabile dal server SMTP,
converte al volo l'email, ed aggiunge questo header, per indicare la trasformazione effettuata, in
modo che il lato ricevente, noto il Transfer-Encoding utilizzato, possa poi provvedere
ad invertirne la rappresentazione, in modo da ristabilire il flusso binario originario. La RFC 2045
definisce i valori che possono essere assunti dalla intestazione
Content-Transfer-Encoding:, che sono:
adatti all'SMTP normale:
• 7bit - è il valore di default, assunto vero se Content-Transfer-Encoding non è
presente, e prevede la trasmissone di fino a 998 byte per linea, con codici di carattere
nell'intervallo 1..127, ed in cui la sequenza CR e LF (codici 13 e 10) indica la fine di una
linea;
• quoted-printable - trasforma i caratteri ad 8 bit ed i caratteri non stampabili
eventualmente presenti, nella sequenza di 3 caratteri =HH, in cui le due cifre esadecimali
HH (0-9 o A-F) corrispondono al codice binario (in base al charset utilizzato) del carattere
trasformato. Il risultato à ancora direttamente leggibile per la sua parte stampabile,
ed anche se uno UA non supporta la trasformazione inversa, la codifica dei caratteri
trasformati può essere visualizzata senza danno. Ad esempio:
• il carattere US-ASCII form feed (decimale 12) viene rappresentato come =0C
• il carattere é dell'alfabeto ISO-8859-1 (decimale 233, corrispondente ad una e con
accento acuto), si rappresenta con la sequenza =E9
• la parola cioè è rappresentata (in ISO-8859-1) come cio=E8
• base64- trasforma tutti i byte presenti, raggruppando i byte a tre a tre (per un totale di
24 bit), e rappresentandoli con 4 caratteri stampabili, ognuno dei quali rappresenta una
codifica di solo 6 dei 24 bit complessivi, come in questo esempio
1
2
3
00000001
00000010
00000011
/
\
/
\
/
\
000000 01 0000 0010 00 000011
|----| |------| |------| |----|
000000
010000
001000
000011
0
16
8
3
A
Q
I
D
in cui la trasformazione dell'ultima riga avviene interpretando i valori decimali
riportati nella penultima riga, come indici di una tabella di conversione riportata qui
sotto, in cui compare un sottoinsieme di 64 caratteri stampabili dell'alfabeto
US-ASCII.
NUM
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ASCII
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
NUM
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ASCII
Q
R
S
T
U
V
W
X
Y
Z
a
b
c
d
e
f
NUM
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
87
ASCII
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
NUM
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
ASCII
w
x
y
z
0
1
2
3
4
5
6
7
8
9
+
/
MIME
Posta elettronica
Nel caso in cui il testo di partenza non abbia un numero complessivo di byte multiplo
di 3, si aggiungono a destra tanti zeri, quanti ne servono per completare l'ultimo
gruppo di 6 bit in entrata. Quindi, se il numero di simboli BASE64 ottenuti non è un
multiplo di quattro, si aggiungono alla codifica finale uno o due simboli di uguale (=),
in numero pari al numero di simboli mancanti, in modo da segnalarlo al ricevitore.
Ad esempio, mostriamo la codifica della parola cioé, quando inizialmente
rappresentata in ISO-8859-1. In tal caso, la parola si esprime mediante la sequenza
esadecimale 0x63 0x69 0x6F 0xE8 (eseguire man ascii e man iso_8859_1
per verificarlo), ossia binaria 01100011 01101001 01101111 11101000, che si
suddivide in gruppi di 6 bit come 011000 110110 100101 101111 111010
000000, in cui gli ultimi 4 bit sono stati aggiunti, e posti a zero. Riscrivendo
l'ultima sequenza in decimale, otteniamo 24 54 37 47 58 00, che in accordo alla
tabella precedente, fornisce una rappresentazione BASE64 pari a Y2lv6A==, dove i
due simboli = finali sostituiscono i due gruppi di 6 bit mancanti nella penultima
sequenza.
Esistono alcuni siti che calcolano la trasformazione on-line, come quelli qui indicati.
Adatto ad un server ESMTP che supporta l'estensione 8BITMIME:
• 8bit - fino a 998 bytes per linea, con la sequenza CR e LF (codici 13 e 10) che appare solo
alla fine di una linea;
Adatto ad un server ESMTP che supporta l'estensione BINARYMIME (RFC 3030):
• binary - qualunque sequenza di bytes.
Encoded Word
Le intestazioni MIME Content-Type e Content-Transfer-Encoding stabiliscono alfabeto e
codifica del body della email, ma per usare un alfabeto diverso da US-ASCII nel valore di
una intestazione, come ad esempio nel Subject, si ricorre ad un diverso espediente, noto come
Encoded Word (RFC 2047), che definisce una sintassi tale da indicare, in un sol colpo
• il charset originario,
• il transfer-encoding usato,
• il risultato della trasformazione.
La sintassi è
=?charset?encoding?encoded text?=
• charset può essere qualunque, purché registrato presso IANA e tipicamente, sarà lo stesso
charset del body
• encoding può essere sia "Q", ossia quoted-printable, oppure "B", ossia base64
• encoded text è il risultato della trasformazione.
Per esempio,
Subject: =?utf-8?Q?=C2=A1Hola,_se=C3=B1or!?=
88
Lo strato applicativo di Internet
Alessandro Falaschi
è interpretabile come Subject: ¡Hola, señor!. Notiamo, in questo caso, che avendo
adottato come charset utf-8, la codifica per i caratteri ¡ (punto esclamativo rovesciato)
e ñ utilizza due bytes, che con il transfer-encoding di tipo quoted-printable, divengono 6
caratteri US-ASCII.
Multipart Content Type
Un messaggio MIME multiparte è il formato tipico in cui sono realizzate le email che contengono
allegati, o contenuti di tipo diverso dal text/plain. In questo caso, il body del messaggio è
suddiviso mediante una stringa speciale detta confine (boundary), definita nella
intestazione Content-type:, e che non deve comparire in nessuna delle parti: per questo
motivo, il confine tipicamente assume l'aspetto di una sequenza di simboli casuali. Il confine è
inserito tra le diverse parti, allo scopo di demarcare la loro separazione, ed all'inizio ed alla fine
del corpo del messaggio, come segue:
Content-type: multipart/mixed; boundary="frontier"
MIME-version: 1.0
This is a multi-part message in MIME format.
--frontier
Content-type: text/plain
This is the body of the message.
--frontier
Content-type: application/octet-stream
Content-transfer-encoding: base64
PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==
--frontier--
Ogni parte inizia con una sua propria intestazione Content-type, seguita da una eventuale
Content-transfer-encoding, seguita dal corpodella parte. I client dei destinatari che
aderiscono alla specifica MIME ignorano (non visualizzano) quanto è presente prima del primo
confine, che contiene un messaggio rivolto appunto ai possessori di client che non aderiscono a
MIME. Questi infatti, visualizzano il messaggio per intero, così come l'abbiamo mostrato sopra, ed
in cui compare in testa l'avvertimento rivolto loro.
Multipart Subtypes
Il Content-type multipart può essere di diversi sottotipi, che specificano la natura delle parti,
e le loro relazioni reciproche. I sottotipi più comuni sono:
• Mixed - usato per inviare files allegati, con Content-Type differenti dal testo del
messaggio. Se il diverso tipo è ad esempio una immagine, molti client email saranno in
grado di mostrarla direttamente, altrimenti proporranno di eseguire una applicazione
specifica. Defininto nella RFC 2046, sezione 5.1.3
• Digest - Multipart/digest è un modo semplice per inviare più messaggi testuali. Il
content-type di default per ogni parte è message/rfc822. Definito nella RFC 2046,
sezione 5.1.5
• Alternative - Il sottotipo multipart/alternative indica che ogni parte è una versione
alternativa dello stesso contenuto, ognuna in un formato diverso, come indicato
dall'header Content-Type corrispondente. I formati sono ordinati in base al grado di
aderenza all'originale, con il meno aderente per primo, ed il più aderente per ultimo. In
tal modo, il client può scegliere la migliore rappresentazione che è in grado di
visualizzare, come l'ultima parte che è in grado di interpretare. Per questo, il formato
89
MIME
Posta elettronica
text/plain viene posto per primo, in quanto il meno aderente possibile, consentendo ai
client non in grado di interpretare i messaggi multiparte, di visualizzare comunque
qualcosa di leggibile.
Molto spesso le email multipart/alternative sono composte di due parti, la prima di
tipo text/plain, che permette la compatibilità all'indietro con i client meno evoluti, e la
seconda di tipo text/html, che permette l'uso di formattazione ed hyperlinks. Anche se
l'HTML sicuramente risulta più gradevole e permette una maggiore espressività, è buona
norma includere sempre la versione testuale, in modo da potersi far comprendere
comunque, a meno di non essere sicuri che tutti i riceventi siano in grado di visualizzare
correttamente la parte HTML.
Definito nella RFC 2046, Sezione 5.1.4
• Related - Questo sottotipo è usato per indicare che le parti del messaggio non devono
essere considerate individualmente, ma piuttosto come parti di uno stesso aggregato. Il
messaggio consiste di una parte radice (la prima), che referenzia in-linea le altre parti,
per mezzo dell'header Content-ID presente nelle diverse parti. Un uso tipico del
sottotipo Related, è quello che permette di inviare per email una pagina web, completa
di tutte le immagini che contiene. Definito nella RFC 2387
• Report - E' il sottotipo che indica la presenza di dati formattati in modo che possano
essere letti da parte di un mail server; tipicamente, il messaggio è suddiviso in una parte
di tipo text/plain, ed una di tipo message/delivery-status. Definito nella RFC
3462
• Signed - Questo sottotipo è usato per allegare una firma digitale al messaggio, che una
volta firmato, contiene due parti, un body ed una signature. Tutto il body, inclusi gli
header MIME, è usato per creare la parte con la firma, prodotta in uno di diversi tipi
possibili, come indicato dall'header Content-Type presente nella parte con la firma,
che ad es. può riportare application/pgp-signature, o application/
x-pkcs7-signature. Definito in RFC 1847, sezione 2.1
• Encrypted - In questo caso, il messaggio è composto di due parti, dove la prima contiene
le informazioni di controllo necessarie per decrittare la seconda, di tipo application/
octet-stream. Definito in RFC 1847, Section 2.2
• Form Data - Come implica il nome, questo sottotipo è usato per esprimere valori immessi
mediante un modulo di inserimento dati (form), tipicamente compilato mediante una
pagina web. Definito in RFC 2388
Content-Disposition
Illustriamo l'uso di questa intestazione, nell'ambito dei commenti al seguente capture, in cui le
risposte del server SMTP sono visualizzate in corsivo, e corrispondente all'invio di una email
contenente in allegato una immagine jpeg, codificata con il metodo base64.
220 smtp-out2.libero.it ESMTP Service (7.3.120) ready
EHLO [192.168.120.40]
250-smtp-out2.libero.it
250-DSN
250-8BITMIME
250-PIPELINING
250-HELP
250 SIZE 30000000
MAIL FROM:<[email protected]> SIZE=11599
90
Lo strato applicativo di Internet
Alessandro Falaschi
250 MAIL FROM:<[email protected]> OK
RCPT TO:<[email protected]>
250 RCPT TO:<[email protected]> OK
DATA
354 Start mail input; end with <CRLF>.<CRLF>
Message-ID: <[email protected]>
Date: Mon, 05 Mar 2007 20:30:12 +0100
From: alef <[email protected]>
User-Agent: Mozilla Thunderbird 1.5.0.9 (X11/20070103)
MIME-Version: 1.0
To: [email protected]
Subject: prova invio con allegato
Content-Type: multipart/mixed;
boundary="------------060708020103050401060503"
This is a multi-part message in MIME format.
--------------060708020103050401060503
Content-Type: text/plain; charset=ISO-8859-15
Content-Transfer-Encoding: 7bit
vediamo come parte l'allegato
--------------060708020103050401060503
Content-Type: image/jpeg; name="logoalef.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="logoalef.jpg"
/9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD//gAXQ3JlYXRl
ZCB3aXRoIFRoZSBHSU1Q/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsL
DQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQU
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgAZAGk
AwEhAAIRAQMRAf/EABwAAQADAQEBAQEAAAAAAAAAAAABCAkHBgUEA//EAFUQAAAEBAMEBwIH
CQsMAwAAAAABAgMEBhRhBQcRCBITFwkhMVFWldIVcRkiQYGUtNQWIzJVZGWRssQYM0JEYpKh
oqOz0yVDRlJTV2Nyc4KTpabB5P/EABwBAQACAgMBAAAAAAAAAAAAAAABBQQGAgMHCP/EADsR
AAEDAwECCwYFBAMBAAAAAAABAhEDBBIFIZEUFUFRUlRhcZKx0QYTMTIzwSIjYoHwcqGy8RYk
.
..... molte linee omesse
.
DaSHCT3AMlHCSHCTqIkSo4Se4TwkhIlRwk9wjhJCRKjhJDhJ7gkSo4SQ4adOwSMlHCT3Bwkh
IlRwkhw06dgCVHCT3Bwk9XUEiVBNJ7gNtPcAlRw09wnhJ7hEiVINtJBwk9wkSo4ST+QDbSAl
Rwkhwk9wgSo4SQ4aQJlQbaSLsAmk9wSRKjhJ17A4aevqEkyo4adOwOEnXsAjJRwk9wcJIiRk
o4SQ4adOwJEqfsgiJLR6d4DivxMV3zH/2Q==
--------------060708020103050401060503-.
250 <45D997EE01267F19> Mail accepted
QUIT
221 smtp-out2.libero.it QUIT
Notiamo che quando, come in questo caso, l'intestazione Content-Disposition (RFC
2183) assume il valore inline, il client di posta ricevente è istruito a visualizzare l'immagine
subito di seguito alla prima parte testuale. Viceversa, una intestazione
Content-Disposition: Attachment avrebbe determinato l'attesa di una esplicita decisione
umana su cosa fare. Di seguito all'intestazione Content-Disposition possono essere presenti
diversi parametri, come ad esempio il nome del file, da usare come suggerimento qualora si
voglia salvare la parte su disco, ma anche eventualmente, data di creazione e di modifica, e
dimensione.
91
Insiemi di caratteri
Posta elettronica
Insiemi di caratteri
Il concetto che ad un byte corrisponda univocamente un carattere stampabile, e viceversa, non
è nientaffatto corretto. Dai tempi in cui venne definito il primo insieme di caratteri per
telecomunicazioni (il codice Morse del 1840), l'associazione tra codici numerici e simboli
linguistici si è via via estesa, fino alla definizione di un insieme (Universal Caracter Set, o UCS, o
Unicode) che possa rappresentare in modo congiunto i simboli previsti da tutte le lingue del
mondo, in modo da poter essere utilizzato per i contenuti da scambiare a livello planetario,
come avviene in Internet. Ma andiamo con ordine.
ASCII
L'insieme di caratteri più universalmente noto è il codice ASCII, standardizzato come
X3.4-1986 da ANSI, come ISO 646 da ISO, e come US-ASCII da IANA, che definisce una tabella di
corrispondenza tra i codici numerici 0-127 (e dunque rappresentabili con 7 bit) ed i caratteri
stampabili. Questi codici rappresentano, per le prime 32 posizioni, i cosiddetti caratteri di
controllo, e sono una eredità dell'epoca delle telescriventi. I restanti codici, sono invece
associati ai cosidetti caratteri stampabili. Tra questi però, non compaiono ad esempio le lettere
accentate, cosicchè ci fu un periodo in cui vennero definite a tale scopo, diverse mappature dei
restanti 128 caratteri ancora disponibili, settando ad 1 il bit più significativo di un byte.
Codepage
Una Codepage è una tabella che stabilisce una corrispondenza i codici a 8 bit aventi il bit più
significativo posto ad uno (che non rientrano nella tabella ASCII), con i simboli di un
certo alfabeto, e con dei caratteri semi-grafici (mediante i quali si poteva produrre una qualche
forma di disegno sullo schermo dei terminali di allora).
Una codepage di largo uso in Europa, è stata la numero 850, indicata come Multilingual
(Latin-1), poi sostituita con windows-1252, e quindi con la sua evoluzione ISO 8859-1, detto
anche alfabeto Latin-1, definito da ISO e IEC, e mostrato nella tabella sottostante, in cui
notiamo che i codici 00–1F, 7F, e 80–9F non sono assegnati a caratteri.
ISO/IEC 8859-1
x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x
1x
2x SP !
3x 0 1
4x @ A
5x P Q
6x ` a
7x p q
8x
9x
Ax NBSP ¡
Bx ° ±
Cx À Á
Dx Ð Ñ
Ex à á
Fx ð ñ
unused
"
2
B
R
b
r
#
3
C
S
c
s
$
4
D
T
d
t
%
5
E
U
e
u
&
6
F
V
f
v
'
7
G
W
g
w
(
8
H
X
h
x
)
9
I
Y
i
y
*
:
J
Z
j
z
+
;
K
[
k
{
,
<
L
\
l
|
=
M
]
m
}
.
>
N
^
n
~
/
?
O
_
o
ª
º
Ê
Ú
ê
ú
«
»
Ë
Û
ë
û
¬
¼
Ì
Ü
ì
ü
SHY ®
¯
¿
Ï
ß
ï
ÿ
unused
¢
²
Â
Ò
â
ò
£
³
Ã
Ó
ã
ó
¤
´
Ä
Ô
ä
ô
¥
µ
Å
Õ
å
õ
¦
¶
Æ
Ö
æ
ö
§
·
Ç
×
ç
÷
92
¨
¸
È
Ø
è
ø
©
¹
É
Ù
é
ù
½
Í
Ý
í
ý
¾
Î
Þ
î
þ
Lo strato applicativo di Internet
Alessandro Falaschi
Questa, è divenuta la codifica di default anche per le pagine distribuite
dai server Web, e supporta Africano, Basco, Catalano, Danese, Olandese, Inglese, Faeroese,
Finlandese, Francese, Galizio, Tedesco, Islandese, Irlandese, Italiano, Norvegese, Portoguese,
Scozzese, Spagnolo, e Svedese. Successivamente, l'ISO 8859-1 si è ancora evoluto in ISO 8859-15,
o Latin-9, che sostituisce ad alcuni simboli molto poco usati (¤, ¦, ¨, ´, ¸, ¼, ½, and ¾) alcuni
rari caratteri francesi e finlandesi, e il simbolo di valuta dell'euro €.
In tutti gli alfabeti ISO 8859-x, la codifica dei primi 127 caratteri (non di controllo) è la stessa di
quella dell'US-ASCII, quindi i files scritti con il secondo alfabeto, sono automaticamente validi
anche nel primo.
Unicode
Nel 2004, il gruppo di lavoro di ISO/IEC responsabile della manutenzione delle codifiche di
carattere ad 8 bit si è sciolto, e tutti gli sforzi si sono indirizzati verso lo Universal Character
Set del consorzio Unicode, noto anche come ISO/IEC 10646, che contiene centinaia di migliaia di
caratteri di quasi tutte le lingue del mondo, ognuno identificato in modo non ambiguo da un
nome, e da un numero chiamato il suo Code Point.
Ogni carattere Unicode viene rappresentato con la sequenza "U+", seguita da un numero
esadecimale che indica il codepoint del carattere. I primi 256 caratteri, indicati come il blocco
latin-script, coincidono con quelli dell'alfabeto ISO 8859-1, e ne condividono l'ordinamento, e
quindi la rappresentazione numerica.
Piani
Sono definiti 17 piani di caratteri, ognuno comprendente 65,536 (= 216) possibili code points,
ognuno dei quali può quindi in principio essere rappresentato da 21 bits. Ma come vedremo
subito, sono definite della regole di trasformazione allo scopo di usare un numero variabile di
bits, in modo da rendere la dimensione del testo comparabile a quella "classica" che usava 1 byte
per carattere.
Basic Multilingual Plane
I CodePoints da U+0000 a U+FFFF costituiscono il piano 0, noto anche come Basic Multilingual
Plane (BMP), e contiene la maggior parte delle assegnazioni eseguite finora, come risulta dalla
mappa riportata qui sotto, in cui sono evidenziati gli utilizzi per tutti i singoli blocchi da 256
codepoints.
93
Insiemi di caratteri
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Posta elettronica
Black = Latin scripts and symbols
Light Blue = Linguistic scripts
Blue = Other European scripts
Orange = Middle Eastern and SW Asian scripts
Light Orange = African scripts
Green = South Asian scripts
Purple = Southeast Asian scripts
Red = East Asian scripts
Light Red = Unified CJK Han
Yellow = Canadian Aboriginal scripts
Magenta = Symbols
Dark Grey = Diacritics
Light Grey = UTF-16 surrogates and private use
Cyan = Miscellaneous characters
White = Unused
Unicode Transformation Format
Consiste in un insieme di regole per rappresentare i caratteri definiti dalle sequenze numeriche
identificate dai codepoint, in un numero variabile di byte, allo scopo di minimizzare
l'occupazione di memoria necessaria, e massimizzare la compatibilità con i testi preesistenti. Lo
standard de facto è indicato come UTF-8, che usa da uno a quattro bytes per rappresentare
un carattere Unicode. Altri formati di trasformazione, sono l'UTF-16, anch'esso a lunghezza
variabile, a multipli di 16 bit, e l'UTF-32, con lunghezza fissa pari a 32 bit. Dato che l'SMTP, come
più volte ricordato, si basa su caratteri a 7 bit (a meno che il server non supporti l'estensione
8BITMIME), le trasformazioni fin qui citate, se utilizzate come valore del parametro charset
della intestazione MIME Content-Type, devono subire un ulteriore processo di trasformazione,
indicando un Content-Transfer-Encoding di tipo quoted-printable oppure base64. Per
questo, è stato definito un ulteriore formato di trasformazione, l'UTF-7, che rappresenta il testo
Unicode come una stringa di caratteri ASCII.
UTF-8
Questo formato di trasformazione per l'Unicode, definito nella RFC 3629, è del tutto consistente
con l'alfabeto US-ASCII, in quanto i codepoint da U+0000 a U+007F sono rappresentati da un unico
byte, in cui i sette bit diversi da zero rappresentano esattamente gli stessi simboli dell'alfabeto
ASCII. Pertanto, tutti i files di testo ASCII sono del tutto validi anche se interpretati come UTF-8.
Per le lettere accentate ed i caratteri Latin-1, associati all'intervallo da U+0080 a U+07FF,
occorrono due bytes, mentre ne occorrono tre per il resto del Basic Multilingual Plane (da
U+0800 to U+FFFF); per caratteri appartenenti a qualunque altro piano di Unicode, occorrono 4
bytes. Lo schema di codifica, è il seguente:
Per i primi 127 codepoints, UTF-8 utilizza un solo byte, con il bit più significativo posto a zero.
Altrimenti, se occorre utilizzare N bytes per uno stesso codepoint, il primo byte ha il bit più
significativo posto ad uno, seguito da N bits posti anche essi ad uno, seguiti da uno zero (alla
N+2-esima posizione), seguiti dai bit più significativi del codepoint. I bytes successivi, hanno una
coppia di bit pari a 10 nella posizione più significativa, seguiti da 6 bit presi in sequenza dalla
rappresentazione binaria del codepoint. Lo schema è riassunto nella tabella seguente, in cui la
lettera x indica i bit disponibili per codificare il codepoint:
94
Lo strato applicativo di Internet
Alessandro Falaschi
Char. number range | n. of | UTF-8 octet sequence
(hexadecimal) | bits | (binary)
--------------------+--------------------------------------------0000 0000-0000 007F |
7 | 0xxxxxxx
0000 0080-0000 07FF |
11 | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF |
16 | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF |
21 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
La RFC 3629 riporta alcuni esempi di codifica. Proviamo qui ora ad individuare la codifica per la
parola cioè. Le prime tre lettere, che appartengono all'alfabeto ascii, producono un byte
ciascuna, pari a 0x63 0x69 0x6F. Alla lettera è compete un codepoint pari a U+00E8, uguale a
ciò che risulta in ISO 8859-1, e che in binario si rappresenta come 11101000. In accordo alla
seconda riga della tabella soprastante, questo si riscrive come 110(00011) 10(101000), ossia
0xC3 0xA8. Pertanto, il risultato finale in UTF-8, è 0x63 0x69 0x6F 0xC3 0xA8.
Sicurezza
Questo concetto si applica a diverse fasi dell'invio delle email, e cioè
1.
2.
3.
4.
5.
6.
7.
autenticazione di colui che invia, presso il server di partenza
propagazione della informazione di autenticazione verso il server di arrivo
notifica al destinatario, se il mittente è autenticato o meno
autenticazione del destinatario della email
crittografia del contenuto del messaggio (confidenzialità)
garanzia a riguardo che il messaggio ricevuto è proprio quello trasmesso (integrità)
firma digitale dell'autore del messaggio (autenticità) (non repudiabilità)
Ognuno dei passi elencati può essere svolto in accordo ad uno o più protocolli, che si basano su
concetti e algoritmi che sono discussi in una sezione apposita. Nel seguito, illustriamo
direttamente le soluzioni adottate, rimandando a quella sezione per gli approfondimenti.
Autenticazione
Osserviamo subito, che verificare l'autenticità di qualcuno/qualcosa, è diverso dall'accordare
allo stesso soggetto il potere di fare qualcosa, ovverosia, autorizzarlo. Ma in ciò che segue, i due
concetti si fondono, in quanto lo scopo dell'autenticazione è ristretto alle necessità della
applicazione che la richiede, e quindi l'autenticazione implica il permesso ad operare. Ma in
generale, si può dire soltanto il viceversa, e cioè che un processo di autorizzazione, sottintende
un prerequisito di autenticazione. Wikipedia dedica una categoria a parte, sull'argomento
della autenticazione delle email.
SASL
Il supporto dei meccanismi offerti da SASL può essere aggiunto, a fini di autenticazione, sia nel
momento dell'invio della email (punto 1), abilitatandolo presso il server SMTP del proprio ISP, sia
nel momento della ricezione della stessa (punto 4), abilitandolo presso il server POP3 o IMAP
dell'ISP del destinatario. Nel primo caso, ci si avvale della estensione SMTP-AUTH, e può essere
aggiunto un header che dichiara l'avvenuta autenticazione. Nel secondo, si ricade nella
definizione standard del protocollo di prelievo email. Una variante di questo caso, si ha quando
la lettura della email avviene mediante una interfaccia di tipo Webmail: in questo caso, l'utente
viene autenticato dalla applicazione web, che poi opera in veste di agente, usando le credenziali
dell'utente per autenticarsi come lui, ed accedere alle email giacenti presso un server IMAP,
impersonando l'utente.
95
Sicurezza
Posta elettronica
SMTP-AUTH
La RFC 2554 definisce una estensione di SMTP, indicata come SMTP-AUTH, che permette di
ottemperare ai primi tre punti espressi nella tabella di cui sopra. Infatti, consente di
condizionare l'accettazione di un nuovo messaggio, al buon esito di un passo supplementare di
autenticazione, in cui il server di partenza, si accerta della reale identità del soggetto che invia
il messaggio. Ciò permette agli utenti abilitati di usare questo server SMTP anche quando si
collegano (in roaming) da una postazione esterna alla rete del proprio provider; al tempo stesso,
però, si introduce un rischio di sicurezza, perchè un attaccante, indovinando (ad esempio,
mediante un metodo di forza bruta) la password di un utente autorizzato, potrebbe poi usare il
server SMTP per inoltrare SPAM. Inoltre, sebbene mediante SMTP-AUTH il server SMTP di
partenza potrebbe informare quello di arrivo che il mittente è stato correttamente autenticato,
in generale non esiste un rapporto di fiducia tra i due server, e così il destinatario, non sarà mai
rassicurato con certezza in tal senso. Per questi motivi, l'estensione SMTP-AUTH non è molto
usata.
Ad ogni modo, esaminiamo come appare una sessione che fa uso di questa estensione:
S: 220 smtp.example.com ESMTP server ready
C: EHLO jgm.example.com
S: 250-smtp.example.com
S: 250 AUTH CRAM-MD5 DIGEST-MD5
C: AUTH FOOBAR
S: 504 Unrecognized authentication type.
C: AUTH CRAM-MD5
S: 334 PENCeUxFREJoU0NnbmhNWitOMjNGNndAZWx3b29kLmlubm9zb2Z0LmNvbT4=
C: ZnJlZCA5ZTk1YWVlMDljNDBhZjJiODRhMGMyYjNiYmFlNzg2ZQ==
S: 235 Authentication successful.
Dopo che il server ESMTP ha annunciato la disponibilità della estensione AUTH, assieme ad una
lista dei meccanismi SASL supportati (nell'esempio, CRAM-MD5 e DIGEST-MD5), il client manifesta
l'intenzione di usarne uno. Il CRAM-MD5 è tra quelli supportati, ed il server risponde inviando lo
challenge, che viene però (reversibilmente) codificato come base64. Il client da parte sua, dopo
aver calcolato l'HMAC-MD5 concatenando lo challenge alla password dell'utente, ed
avere prefisso il risultato con l'identificativo dell'utente stesso, codifica la stringa risultante
in base64, e reinvia il tutto al server. La trasformazione via base64 viene prescritta dalla RFC
4422 (SASL), in modo che se challenge e/o password contengono caratteri non ASCII, per questi
venga usata la codifica Unicode, con trasformazione UTF-8, e quindi poi il tutto sia rappresentato
con caratteri a 7 bit, appunto mediante codifica base64.
Confidenzialità, integrità e autenticità
Gli ultimi tre punti della tabella posso essere soddisfatti appieno solo se le trasformazioni
crittografiche avvengono da estremo ad estremo del collegamento, adottando uno degli standard
noti come PGP ed S/MIME. Tuttavia, esiste la possibilità di effettuare ogni singolo trasferimento
dal mittente al primo server SMTP, e poi tra server SMTP intermedi fino a quello di destinazione,
su collegamenti resi sicuri mediante TLS, come permesso in base alla estensione STARTTLS
dell'SMTP.
StartTLS
Il Transport Layer Security (TLS) è definito nella RFC 4346, ed offre alle applicazioni una
modalità di comunicazione sicura. L'estensione STARTTLS di SMTP, descritta nella RFC 3207,
permette ad un client SMTP di negoziare con il server i servizi di crittografia ottenibili via
TLS, tali da impedire la lettura (da parte di un intercettatore) dei contenuti in transito,
ottemperando quindi ai requisiti di confidenzialità. Questo però avviene solo di tratta in tratta,
96
Lo strato applicativo di Internet
Alessandro Falaschi
sempre che tutte le tratte lo permettano, e scelgano di usarlo: questa variabilità ne vanifica in
parte gli scopi, per quanto rimane comunque un valido meccanismo di protezione nella
comunicazione tra il client, ed il server SMTP del proprio provider. Inoltre, dato che l'attivazione
di TLS precede l'autenticazione basata su SASL (vedi esercitazioni), l'uso di TLS si dimostra una
soluzione valida, per utilizzare il meccanismo plaintext, dato che la password non viene inviata
in chiaro, ma crittografata dal TLS.
Ricezione dell'email
Una volta che l'email è giunta presso il computer indicato dal RR MX associato al dominio di
destinazione, questa può essere letta dal destinatario (la cui autenticazione stavolta è
obbligatoria) sia in locale, se ha accesso fisico al computer di destinazione, sia da remoto,
utilizzando una applicazione come ad es. Outlook, Thunderbird, Evolution, Opera, Eudora, KMail,
Pine, Mutt (vedi confronto). In questo secondo caso, si utilizza uno di due procolli, POP3 od
IMAP, entrambi di tipo client-server, le cui differenze sostanziali sono illustrate nella figura che
segue.
POP3
Il Post Office Protocol, definito nella RFC 1939, essenzialemente è nato per permettere di
scaricare sul proprio computer le email ricevute, ed anche se è prevista una opzione del
tipo lascia sul server, questa è molto inefficiente nel caso di utilizzo di tipo nomadico. In origine,
permetteva solo l'invio della password in chiaro, mentre le successive estensioni, permettono
l'uso dei metodi SASL, e di TLS.
IMAP
L'Internet Message Access Protocol è definito dalla RFC 3501, ed offre diversi vantaggi rispetto
all'uso del POP, come
• la connessione con il server resta attiva per tutto il tempo che è aperto il programma di
posta, risparmiando sui tempi di inizializzazione;
• un stessa mailbox può essere acceduta in contemporanea da parte di più client differenti;
• le diverse parti di un messaggio MIME possono essere scaricate (o meno) in modo
indipendente le une dalle altre, permettendo ad esempio di rimandare la ricezione di
un allegato voluminoso;
97
Altre architetture di telecomunicazione testuale
Posta elettronica
• i messaggi lasciati sul server possono essere etichettati con attibuti tali da permettere
di riconoscere, ad esempio, i messaggi letti, e quelli a cui si è risposto;
• si possono creare cartelle presso il server, in cui ordinare i propri messaggi,
eventualmente condividendoli con altri;
• un client può richiedere al server di fare ricerche specifiche, senza dover scaricare i
messaggi;
• un server può annunciare la disponibilità di particolari estensioni, che possono essere
usate dai client che pure le supportano;
• tra queste estensioni c'è il supporto a SASL ed a TLS, che permette di aggiungere servizi di
sicurezza;
Webmail
E' la contrazione di Web-based email, e consiste in un portale web da cui si può accedere alla
propria casella di posta elettronica, in modo da poterla leggere anche da una postazione
occasionale, tipicamente pubblica, permettendo inoltre di spedire posta. In questo caso, l'unico
protocollo che sembrerebbe essere in gioco, è il dialogo HTTP che si svolge tra il nostro browser,
ed il server web che ci mostra le pagine del portale. In effetti però, le pagine sono generate da
un CGI, ossia un programma in esecuzione presso il computer che ospita il server web, e che a
sua volta opera in modalità client nei confronti dei procolli email, ossia SMTP pe spedire, ed
IMAP per ricevere.
Altre architetture di telecomunicazione testuale
Prima della definizione del World Wide Web, il mondo di Internet funzionava principalmente in
formato testo, ed anche così, molte persone scoprivano un mondo del tutto nuovo, e delle
formidabili potenzialità di telecomunicazione con gli altri individui in rete. Probabilmente a quei
tempi, gli individui che si affacciavano ad Internet erano effettivamente i più progressisti ed
aperti ai cambiamenti, oppure era solo un effetto generato dalla curiosità per la novità e la cosa
che sta crescendo, ma fatto sta che la comunicazione era più ricca ed entusiasta. Citiamo nel
seguito, quattro architetture di comunicazione testuale, di gruppo (e non): Mailing list,
Newsgroup, Internet Relay Chat, e Instant Messenger.
Mailing List
Le mailing list non sono altro che liste di indirizzi email, usate in congiunzione ad un
meccanismo, tale che uno stesso messaggio email venga distribuito automaticamente a tutti gli
indirizzi che compaiono nella lista. Questo può avvenire in modo molto banale, configurando
staticamente un server SMTP in modo da associare un singolo nome di utente fittizio (detto alias,
o riflettore) alla lista, facendo si che le email dirette all'alias vengano in realtà ricevute da tutti.
Il problema in questo caso, è che se nella lista si verificano avvicendamenti frequenti, diventa
oltremodo noioso modificare a mano la lista dei componenti.
Automazione
Per questo, sono sviluppati dei programmi appositi, detti anche mail robot, o mailbot, che
vengono eseguiti a seguito della ricezione di una email diretta a speciali indirizzi di gestione,
grazie alla modifica del file aliases, in modo da redirigire il contenuto delle email, verso lo
standard input dei mailbot. Se nella email sono individuati comandi particolari, come ad esempio
la richiesta di iscrizione, o il desiderio di visionare l'elenco degli iscritti, questi comandi sono
eseguiti dal mailbot.
98
Lo strato applicativo di Internet
Alessandro Falaschi
Gestori
Un esempio celebre di questo genere di meccanismo, è majordomo, così chiamato inspirandosi al
latino major domus, ossia maestro della casa. Ora che Internet è quasi sinonimo di Web, diventa
poco sensato amministrare una mailing list via email, e l'applicazione in assoluto più diffusa per
la gestione delle mailing list, è Mailman, scritta in Python, e che permette una personalizzazione
molto spinta sia da parte dei singoli iscritti, che da parte dell'amministratore della lista. E' il
gestore di mailing list usato anche per questo corso. E' appena il caso di menzionare il fatto, che
tutto il lavoro di preparatorio di discussione per quanto riguarda lo sviluppo degli standard
Internet da parte di IETF, avviene per mezzo di mailing lists.
Archiviazione
E' possibile archiviare la mailing list, in modo che i messaggi che vi transitano siano accessibili
tramite interfaccia web. Ciò è realizzato o dallo stesso programma che gestisce la ML (come in
effetti fa Mailman), oppure utilizzando un servizio di terze parti. Se poi l'interfaccia web
all'archivio permette anche a chi legge, di scrivere, allora si ottiene un risultato simile a quello
del Newsgroup, a partecipazione aperta. Esempi di questo approccio sono Gmane, MARC, Nabble,
Google Groups, Yahoo Groups.
Netiquette
E' una parola derivata dalla contrazione del vocabolo inglese net (rete) e quello di lingua
francese étiquette (buona educazione), e descrive un insieme di regole di buona condotta, che
dovrebbero disciplinare il comportamento di un utente di Internet nel rapportarsi agli altri,
mediante meccanismi quali newsgroup, mailing list, forum, e-mail, o in genere, mediante
qualunque tipo di comunicazione scritta. In questo contensto, assume significato l'uso degli
emoticon, (compresi quelli in stile asiatico) per veicolare in modo esplicito il proprio stato
d'animo, e disambiguare le circostanze in cui il lettore può equivocare che una frase scherzosa,
debba invece doversi ritenere offensiva.
Newsgroup
Anzichè discutere mediante lo strumento delle mailing list, permettendo solo agli aderenti di
partecipare, perché non permettere anche a terze persone di visionare ciò che è descritto dagli
altri, e prendere parte alla discussione? Probabilmente per soddisfare questo desiderio, fu
definito il protocollo NTTP (Network News Transfer Protocol, RFC 3977, che aggiorna la RFC 977),
che ha dato vita al servizio indicato come Usenet, a significare il possesso della rete da parte
degli utenti: in effetti, partecipare a Usenet è l'equivalente virtuale dello scendere in piazza e
discutere liberamente con gli altri dei fatti e dei temi che si desidera, e ciò rappresenta
inequivocabilmente un elemento di democrazia.
Tecnicamente, i diversi server NNTP comunicano tra loro secondo il principio di mantenere
sincronizzate le basi di messaggi, che ognuno di questi riceve da parte degli utenti che vi si
connettono. Presso i server sono definiti i diversi argomenti di discussione, detti newsgroup,
organizzati in gerarchie che categorizzano gli argomenti stessi in sotto-argomenti, e sotto-sotto
argomenti. Considerando che Usenet ha una propagazione mondiale, e che ogni popolo ha pur
sempre il diritto di discutere nella propria lingua, possiamo restringere il campo alla gerarchia in
lingua italiana.
Per partecipare ad Usenet, la maggior parte dei lettori email offre la possibilità di definire un
nuovo account news (anzichè email), configurando il newsserver a cui ci si desidera collegare,
che in generale, corrisponde a quello ospitato presso il proprio provider. Infatti, come avviene
99
Altre architetture di telecomunicazione testuale
Posta elettronica
per i server SMTP, anche i server NNTP negano l'accesso ai client esterni alla propria rete. In
alternativa, esistono svariate iniziative che, in analogia al servizio di webmail, offrono una
interfaccia web ai newsgroup, come a esempio Google, Mailgate, nntp.it. Anche se l'utilizzo dei
newsgroup mediante client personale è più completo, e privo della pubblicità inserita dal
portale, l'accesso web ha il vantaggio di non dipendere dalla conoscenza del proprio server NNTP,
e può aiutare a farsi una idea.
BBS
I Bullettin Board Services si sono sviluppati parallelamente ai Newsgruop, e sono ormai quasi del
tutto tecnologicamente superati, ma rappresentato tuttora un ottimo esempio di comunicazione
assolutamente autogestita. Si tratta infatti, ancora una volta, di una rete di computer che
mantengono sincronizzate le rispettive basi di messaggi, ma i collegamenti tra computer non si
avvalevano della rete Internet, ma del modem su rete telefonica commutata, rimuovendo
qualunque forma di dipendenza da fornitori di connettività dati. Attualmente, molte BBS oltre a
fornire ai propri utenti un accesso via modem, sono altresì accessibili (per ironia) via Internet,
che spesso usano anche per sincronizzarsi con gli altri nodi. Sebbene diverse BBS si possano
accordare per mettersi in rete tra di loro in modo del tutto autonomo, esiste una rete mondiale
di BBS che cooperano a mantenere viva una distribuzione globale alternativa, chiamata FidoNet.
Internet Relay Chat
Le chat offerte da siti web e da applicazioni di Instant Messaging sono tutte evoluzioni delle chat
con cui chi si collegava via modem ad una BBS, poteva dialogare con il gestore (sysop) della BBS
stessa. Queste ultime forme di comunicazione, hanno a loro volta tratto ispirazione dal comando
talk, in cui lo schermo del terminale viene suddiviso in due zone, ed i caratteri immessi
dall'interlocutore, appaiono uno alla volta.
L'IRC è la standardizzazione Internet dello stesso concetto, ed è basato su di un network di
server chat, interconnessi a formare uno spanning tree, in modo da propagare in modo
efficiente i messaggi che ogni server ricevere dai utenti connessi allo stesso. La formalizzazione
IETF del protocollo di IRC è la RFC 1459, a cui sono da affiancare le successive evoluzioni, anche
se le diverse implementazioni del server IRC tendono sempre a divergere un pò. Ad esempio, fin
dall'inizio non si è previsto alcun supporto per i caratteri non-ASCII, con il risultato che possono
coesistere clients che usano contemporaneamente codifiche diverse ed incompatibili (ad es. ISO
8859-1 e UTF-8).
La comunicazione su IRC avviene nell'ambito dei cosiddetti canali, che possono essere locali ad
uno stesso server, oppure propagati a tutti i server che fanno parte delle rete IRC. Di reti IRC, al
mondo ne esistono migliaia, e quella italiana più diffusa, è Azzurra, mentre quella con più utenti
è IRCnet, a distribuzione mondiale; infine, Freenode offre principalmente supporto ai progetti
OpenSource. Ci si collega, con una vasta scelta di client.
Instant Messaging
Le applicazioni di Messaggistica istantanea hanno guadagnato una grande popolarità in virtù della
visibilità di cui godono i service provider a cui fanno riferimento i rispettivi programmi client, ed
i cui maggiori esponenti sono
• AIM - America On Line Instant Messenger - interopera con ICQ
• ICQ - gioco di parole con I seek You (ti sto cercando) - Creato da Mirabilis, venne
acquista da AOL, poi fusasi con Time Warner
100
Lo strato applicativo di Internet
Alessandro Falaschi
• Windows Live Messenger - indissolubilmente legato a Microsoft, è l'evoluzione del Windows
Messenger
• Yahoo! Messenger - interopera con MSN
• Gtalk - Contrazione di Google talk ed integrato con Gmail, adotta standard aperti come
XMPP
• C6 - l'unico pienamente Italiano - interopera con XMPP
• QQ - più di 160 millioni le persone lo usano in Cina
Ognuna di queste applicazioni, consta di una popolazione di utenti, che tutti assieme individuano
una community di utilizzatori, la cui numerosità stimata complessiva, ammonta a diverse
centinaia di milioni di individui.
Topologia e interlavoro
La maggior parte di queste applicazioni, opera
con una modalità client-server, in cui ogni
client, fa capo ad unico server centralizzato,
che implementa il protocollo di comunicazione
con tutti i client. Inoltre, la politica più
diffusa, è quella di ostacolare lo sviluppo di
prodotti di terze parti che si possano
connettere a queste reti, tentando di
fidelizzare i propri utenti, all'uso del proprio
client, tramite il quale si possono più
facilmente introdurre estensioni e nuove caratteristiche. Solo da poco, alcuni di questi provider
stanno seguendo un approccio di "apertura" reciproca (come Yahoo e MSN, oppure AIM e ICQ),
comunque sempre dettati da motivazioni commerciali.
Client multiprotocollo
Cionostante, vi sono applicazioni tipicamente dell'Open Source,
come ad esempio
• Trillian - shareware ma dal sorgente chiuso
• Pidgin - precedentemente noto come Gaim, funziona
anche su piattaforme non-Microsoft
• Kopete - permette l'uso di una webcam con gli utenti MSN
e Yahoo
• Miranda - solo per Win
• Adium - solo per Mac
che a seguito di una operazione di reverse engineering, permettono il
collegamento contemporaneo su diverse di queste reti.
Standard aperti
In contrapposizione alle reti proprietarie sopra descritte, i servizi di messaggistica possono essere
realizzati anche in accordo a specifiche pubbliche.
101
Altre architetture di telecomunicazione testuale
Posta elettronica
Jabber - XMPP
Lo IETF ha pubblicato come RFC 3920, 21, 22 e
23, le specifiche dell'Extensible Messaging and
Presence Protocol (XMPP), alla base del
funzionamento della piattaforma Jabber, e
che offre una gamma veramente molto vasta
di estensioni, sia stabili, che in via di sviluppo,
che allo stadio di proposte.
Architettura
La rete Jabber non prevede un unico server centralizzato, ma ogni utente è individuato da una
URI del tipo di quelle previste per l'email, ed i messaggi che gli sono diretti, transitano per il
server associato alla parte dominio della proprio indirizzo, proprio come avviene per le e-mail.
Interoperabilità
La architettura XMPP
prevede l'esistenza di
Gateway che interfacciano la
rete Jabber con quelle
basate sui diversi protocolli
di Messagging, come ad es.
MSN o ICQ, permettendo ad
un client Jabber, di
comunicare con tutti gli
altri. Una volta che un client
Jabber si connette ad un server che implementa il gateway verso la rete di messaggistica
desiderata, deve comunicare al server jabber l'identità e le credenziali con le quali può accedere
all'altra rete; a quel punto, il server Jabber si connetterà alla diversa rete impersonando
l'identità del client, comportandosi come un proxy, e convertendo le primitive del protocollo di
un lato del gateway, in quelle del protocollo dell'altro versante.
SIMPLE
Il WG IETF SIMPLE (SIP for Instant Messaging and Presence Leveraging Extensions) definisce come
il protocollo SIP, progettato per il VoIP, possa offrire il supporto alle funzioni di Presenza e
Messaggistica Istantanea, a loro volta definite nella RFC 2778. In particolare, nelle RFC 3265
e 3856, viene descritto il supporto a queste funzioni, mentre in un recente Draft, si riassume
l'intreccio delle specifiche di cui tenere conto. Piuttosto che addentrarci in dettagli, esponiamo i
concetti base coinvolti.
Presence
La funzione di Presenza è definibile come la gestione di una informazione di stato, relativa ad
una entità definibile come Presentity, che viene resa nota ad un insieme di altre entità, definibili
come Watchers.
102
Lo strato applicativo di Internet
Alessandro Falaschi
+---------------------------+
|
PRESENCE SERVICE
|
|
|
+---------------------------+
^
|
|
|
|
v
+------------+
+------------+
| PRESENTITY |
| WATCHER
|
+------------+
+------------+
Tipicamente una Presentity, di propria volontà, mentiene informato il gestore del servizio di
presenza a riguardo dei propri cambiamenti di stato, mentre un Watcher può interrogare
periodicamente il servizio di presenza, oppure (preferibilmente) sottoscrivere (Subscribe) il
servizio, e ricevere delle notifiche (Notify) ogni qualvolta l'informazione sia cambiata.
La derivazione di queste definizioni, a partire dal tradizionale comportamento di una
applicazione di messaggistica, in grado di mostrarci lo stato dei nostri contatti, è più che
evidente. La possibilità di trasmettere a distanza, oltre ai propri scritti, oltra alla propria voce
e/o immagine, anche la propria propensione alla comunicazione, apre un nuovo modo di
intendere le telecomunicazioni, che meriterebbe senz'altro una approfondita analisi
psico-sociale.
Rimanendo invece sul piano tecnico, notiamo come la formalizzazione delle funzioni di Presenza
e Messaggistica Istantanea espressa nel contesto della RFC 2778, ha consentito di definire nella
RFC 3859 un Common Profile for Presence (CPP), in modo tale che le applicazioni che aderiscono
al CPP, abbiano buone possibilità di poter interoperare, e scambiarsi questo tipo di
informazione.
Open Mobile Alliance
Effettivamente, il lavoro sviluppato del WG SIMPLE aderisce al CPP, così come vi aderiscono le
specifiche emesse dall'Open Mobile Alliance (OPA), che definisce standard aperti per l'industria
della telefonia mobile. Vi aderiscono tutti i maggiori produttori di telefonini e loro derivati,
operatori mobili, e produttori di software, ed intrattiene relazioni con le altre organizzazioni di
standardizzazione, come 3GPP, 3GPP2, IETF, W3C. E cosa dire, allora, di Open Handset Alliance?
(video)
Funzioni Telemediali
Senza dover necessariamente ricorrere a tutti i costi al telefonino, le stesse applicazioni di
messaging supportano funzioni audio-video del tutto equivalenti, se non superiori, a quelle
offerte dagli operatori telefonici, ad un costo assai inferiore, al punto che i telefonini stessi,
sono in procinto di saltare sul carro dell'accesso WiFi ad Internet. Infatti, oltre alle applicazioni
storicamente ed esplicitamente nate per il Voice over IP (VoIP) come H.323, SIP o Skype, anche i
messenger nati per il solo supporto alla comunicazione testuale, si stanno via dotando di
funzionalità di comunicazione audio e video, al punto da coniare per questi, il termine di Voice
over Instant Messaging (VoIM), mentre qualcuno, prova ad usare il termine di
CoIP-Communication over IP (video), a rimarcare la funzione di collante tra test, voce e dati,
svolta dalle applicazioni di messaggistica.
Mentre MSN, Yahoo, AIM e ICQ, al solito, adottano soluzioni proprietarie, Gtalk adotta libjingle,
una estensione di XMPP. Inoltre, è da segnalare l'iniziativa di Gtalk2VoIP, che offre un gateway
per le chiamate audio tra le reti MSN, Yahoo, AIM, ICQ, Gtalk, SIP e PSTN.
103
Altre architetture di telecomunicazione testuale
Realizzato con
Posta elettronica
da Alessandro Falaschi - ultimo aggiornamento Dicembre 2007
104
Lo strato applicativo di Internet
Sicurezza
Questa sezione fornisce una panoramica sugli agli aspetti di sicurezza che intervengono nelle
architetture di telecomunicazione Internet, senza per questo affrontare tutti gli aspetti della
sicurezza informatica.
• Quadro di riferimento
•
•
•
•
Attacchi
Servizi
Meccanismi
Localizzazione
• Crittografia convenzionale
• Chiavi di sessione
• Autenticazione del messaggio
•
•
•
•
•
•
Message Authentication Code
Funzioni Hash
Hash e segreto condiviso
Hash e crittografia convenzionale
Hash e crittografia a chiave pubblica
HMAC
• Crittografia a chiave pubblica
• Utilizzi della crittografia asimmetrica
• Confidenzialità
• Autenticazione
• Scambio di chiavi
• Algoritmi a chiave pubblica
• RSA
• Diffie-Hellman
•
•
•
•
•
•
Generazione delle chiavi
Il segreto condiviso
Lo scambio di Diffie-Hellman
La chiave di sessione
Attacco MITM
Autenticazione dello scambio
• DSS
• Gestione delle chiavi
• Certificati digitali
• Distibuzione di chiavi di sessione mediante crittografia asimmetrica
• PKI
• X.509
• Catena delle Autorità di Certificazione
• Formato
• Fingerprint
Quadro di riferimento
•
•
•
•
Sicurezza
Richiesta e rilascio dei certificati
Codifica
Revoca dei certificati
Certificati autofirmati
• Web of trust
• Strati di sicurezza
• IPSEC
• TLS
• Record Protocol
• Handshake Protocol
• API di sicurezza
• SASL
• CRAM-MD5
• PGP e GPG
• S/MIME
• Riferimenti
Quadro di riferimento
Prima di tutto, forniamo alcune definizioni dei concetti inerenti gli aspetti di sicurezza, come i
tipi di attacchi alla sicurezza, i servizi che la sicurezza può offrire, i meccanismi con cui si attua,
e la localizzazione di questi servizi.
Attacchi
Il normale flusso
dell'informazione, da sorgente a
destinazione, può essere
alterato fraudolentemente,
secondo uno dei quattro casi
illustrati in figura:
• interruzione: quando si
rende inutilizzabile il
mezzo di comunicazione,
ed il messaggio non
raggiunge più il
destinatario; è un attacco
alla disponibilità;
• intercettazione: quando
pur raggiungendo il
destinatario, il messaggio
è spiato all'insaputa delle
parti in comunicazione. E'
un attacco alla confidenzialità;
• modifica: un "uomo nel mezzo" (man in the middle, o MITM) si appropria del messaggio e
lo altera, che così raggiunge il destinatario in forma distorta. E' un attacco alla integrità;
• contraffazione: il destinatario riceve un messaggio che non è stato prodotto dal mittente
che crede. E' un attacco alla autenticità.
106
Lo strato applicativo di Internet
Alessandro Falaschi
Questi attacchi possono essere condotti in forma passiva, come nel caso della intercettazione, o
della analisi del traffico, oppure in forma attiva, secondo le categorie
• impersonificazione (masquerade): qualcuno o qualcosa, si spaccia per qualcun altro, ed
esempio, esibendo credenziali intercettate, e ri-utilizzate successivamente;
• replica (replay): dopo una intercettazione passiva, il messaggio viene re-inviato per
ottenere un effetto indesiderato;
• modifica - è il caso tipico del man in the middle;
• negazione del servizio (Denial of Service, o DoS): si ostacola od impedisce il normale
utilizzo del sistema/servizio di comunicazione. Spesso, questo si ottiene sovraccaricando
la risorsa, ad esempio inviando ad un server un numero esagerato di richieste.
Servizi
Per prevenire e/o ostacolare gli attacchi di sicurezza, vengono messi in opera un serie di
espedienti, che realizzano una o più delle seguenti funzioni, o servizi di sicurezza:
• confidenzialità: è la protezione contro gli attacchi passivi come le intercettazioni, e viene
realizzato mediante tecniche di crittografia dei singoli messaggi in transito, oppure di
tutto il traffico tra nodi di rete;
• autenticazione: è la protezione contro l'impersonificazione, ed in linea generale,
garantisce alla destinazione di un messaggio, che la sorgente sia veramente quella che
dice di essere. Può anche servire ad accertare l'identità del destinatario (come quando ad
esempio, ci colleghiamo ad un sito di commercio elettronico), garantendo di trasmettere
l'informazione esattamente al soggetto a cui pensiamo di rivolgerci;
• integrità: protegge contro attacchi di intercettazione, modifica e replay, e come per la
confidenzialità, si realizza crittografando il singolo messaggio, o l'intero traffico.
• non repudiabilità: impedisce al mittente od al destinatario, di negare la trasmissione o la
ricezione di un messaggio. Ha molti aspetti in comune, con l'autenticazione
• controllo di accesso: nel caso in cui l'identità del soggetto che intende usufruire di una
risorsa sia accertata mediante autenticazione, si può procedere ad un passo successivo, in
cui si verificano i diritti di accesso che tali individuo vanta nei confronti della risorsa in
oggetto.
Meccanismi
Non esiste un singolo
meccanismo, od
algoritmo, capace di
fornire in un colpo solo
tutti i servizi di
sicurezza elencati, ma
si tratta sempre e
comunque di ricorrere
a funzioni sviluppate
nel campo della
crittografia, e
utilizzate in modo da
cooperare alla
realizzazione di un
modello di architettura
di sicurezza, molto
sommariamente
descritta dalla figura a lato.
Una terza parte fidata, si occupa di distribuire alle parti principali in comunicazione, una
107
Crittografia convenzionale
Sicurezza
informazione segreta, usata per operare una trasformazione di sicurezza, tale proteggere il
canale di comunicazione dall'intervento di un opponente, intenzionato ad portare un attacco.
Localizzazione
Le
trasformazioni
di sicurezza
possono aver
luogo sia agli
estremi
(ellissi nere)
delle due
parti in
comunicazione, tipicamente ad opera dello strato applicativo in esecuzione presso gli stessi,
come ad esempio nel caso di TLS, S/MIME, PGP.
Viceversa, le trasformazioni di sicurezza possono essere localizzate presso gli estremi dei singoli
collegamenti (ellissi grigie) che vengono attraversati dalla comunicazione, come viene ad
esempio definito dalla collezione di protocolli IPSec.
Crittografia convenzionale
Si basa sull'esistenza di un segreto condiviso, noto alle due parti in comunicazione, e che
funziona come seme per una algoritmo crittografico, tale da rendere molto difficile risalire alla
chiave, anche venendo in possesso del testo in chiaro, oltre che della sua versione crittografata.
Gli algoritmi crittografici in uso sono denominati:
• DES - Data Encryption Standard: definito nel 1977 dal NIST, e denominato anche Data
Encryption Algoritm (DEA). Opera su blocchi di testo di 64 bit, elaborati mediante una
108
Lo strato applicativo di Internet
•
•
•
•
•
Alessandro Falaschi
chiave di 56 bit. Con il progredire della potenza di calcolo, nel 1998, Electronic Frontier
Foundation (EFF) annunciò di essere riuscita a "aprire" il codice, dimostrando di essere
stata in grado di risalire alla chiave, a partire dalla conoscenza di plaintext e ciphertext.
Ma l'uso di chiavi più lunghe, come ad esempio di 128 bit, rende l'algoritmo ancora molto
robusto.
Triple DEA (TDEA): opera applicando per tre volte l'algoritmo DES, con tre chiavi distinte,
portando così a 56*3=168 bit la lunghezza della chiave, rendendo il metodo virtualmente
inespugnabile.
Advanced Encryption Standard (AES): è il risultato di un bando lanciato da NIST nel 1997,
per definire un successore del DES. Opera su blocchi di testo di 128 bit, con una chiave a
scelta tra 128, 192 o 256 bit, in funzione del livello di protezione desiderato, e si basa su
sequenze di operazioni più facilmente realizzabili in software rispetto al DES.
International Data Encryption Algorithm (IDEA): opera con una chiave di 128 bit, è coperto
da brevetto, ma ne esiste una versione liberamente utilizzabile per fini non commerciali.
E' stato descritto per la prima volta nel 1991 come una alternativa a DES, e non essendo
ancora stato "aperto", è ritenuto molto affidabile.
Blowfish opera su blocchi di 64 bit mediante una chiave di lunghezza variabile, da 32 a 448
bit. E' molto efficiente sia da un punto di vista computazionale che di occupazione di
memoria, e molto robusto. Per questi motivi, e per l'assenza di brevetti, è largamente
impiegato.
RC5 è brevettato, e definito nella RFC 2040. Opera su blocchi di lunghezza variabile, con
chiavi lunghe fino a 2048 bits.
Chiavi di sessione
Nella
crittografia
convenzionale, i rischi di sicurezza aumentano, quanto più materiale viene crittografato usando
sempre la medesima chiave, rendendo sempre meno complicato per un intercettatore, tentare di
scoprire la chiave usata. La soluzione più usata contro questo problema, passa dall'utilizzo di una
chiave di sessione, che ha una validità che si protrae per la sola durata di una sessione, e viene
poi distrutta, in modo da non dare il tempo ad un intercettatore, di forzare il codice. Nella
figura a lato, è illustrato uno schema di principio, in cui si postula l'esistenza di una entità di
distribuzione, che viene contattata dall'entità che intende generare il messaggio, e che fornisce
la chiave di sessione, trasmettendola in forma crittografata mediante una chiave permanente,
nota sia al distributore che alle altre entità. La stessa chiave di sessione, è fornita anche al
destinatario, sempre in forma crittografata, e lo mette in grado di decrittare il messaggio in
arrivo. La chiave di sessione non deve essere necessariamente distribuita da una entità separata,
ma può anche essere generata da una delle due parti in comunicazione, come vedremo appresso.
109
Autenticazione del messaggio
Sicurezza
Autenticazione del messaggio
Mentre la crittografia in generale, protegge dagli attacchi di tipo passivo (ad es,
l'intercettazione), la garanzia che il messaggio ricevuto è autentico, sia nel contenuto (integrità)
che nel mittente, ricade nei compiti delle procedure di autenticazione. In linea di principio,
impiegando tecniche di crittografia convenzionale, in cui mittente e destinatario condividono la
stessa chiave segreta (una per ogni coppia di soggetti), la corretta decrittazione di un messaggio
ricevuto, oltre a garantirne l'integrità, garantirebbe anche a riguardo della sua provenienza, e
quindi, si potrebbe fare così.
Viceversa, sussistono dei buoni motivi per lasciare il messaggio in chiaro, tralasciando quindi la
confidenzialità, e ottemperare ai requisiti di integrità e autenticità mediante la spedizione,
assieme al messaggio, di un Message Authentication Code (MAC). Come buoni motivi, citiamo i
casi in cui
• il messaggio ha destinazioni multiple, e solo una entità ha il compito di eseguire
l'autenticazione
• si risparmia la complessità della crittografia dell'intero messaggio
• il messaggio consiste in dati da fornire ad un programma, e lo si può memorizzare in
chiaro, senza doverlo decrittare ogni volta, mantenendo la possibilità di verificarne
l'autenticità
• il messaggio è in realtà un programma, che può essere eseguito senza doverlo prima
decrittare
Message Authentication Code
Un algoritmo MAC accetta in ingresso un messaggio da autenticare, ed una chiave segreta K, e
produce in uscita una etichetta (detta appunto, MAC) che dipende dai due ingressi, e che viene
allegata al messaggio. Il ricevitore del messaggio, se conosce la stessa chiave segreta, può
effettuare lo stesso calcolo a partire dal messaggio ricevuto, e se il MAC risulta identico a quello
ricevuto, vuol dire che il mittente è in possesso della stessa chiave usata in ricezione, e che il
messaggio ricevuto non è stato modificato; per quest'ultimo motivo, l'etichetta risultante viene
anche chiamata Message Integrity Code (MIC), anche se questo termine si riferisce ad un
controllo svolto in modo lievemente diverso. Non è necessario che il processo descritto sia
reversibile. In particolare, l'algoritmo MAC può essere basato su di una delle funzioni
crittografiche esaminate prima.
110
Lo strato applicativo di Internet
Alessandro Falaschi
Funzioni Hash
Si tratta di una trasformazione in grado di
generare, in modo semplice, una breve
etichetta identificativa a partire da un
generico messaggio, anche molto più lungo.
Un suo utilizzo è attinente alla costruzione di
tabelle hash per l'accesso rapido ad una
raccolta di dati, ma quello è un altro discorso.
Per i nostri fini, ci basta dire che una funzione
Hash produce una uscita H(M) di lunghezza
fissa a partire da una stringa M di lunghezza
variabile di ingresso, ed il valore di uscita è
chiamato valore di hash, checksum
crittografico o message digest. Le proprietà di
questa funzione si possono riassumere in
•
•
•
•
•
funziona per messaggi di qualunque dimensione
il risultato è di lunghezza fissa
è semplice da calcolare
la sua inversione è computazionalmente infattibile
individuare un diverso ingresso che produce la stessa uscita di un altro è
computazionalmente infattibile
Alcune funzioni hash usate nelle applicazioni di sicurezza sono
• Secure Hash Function (SHA-1): pubblicata nel 1995, elabora l'ingresso in blocchi di 512 bit
e produce un risultato di 160 bit. Ha la proprietà che ogni bit di uscita, dipende da ogni
bit di ingresso.
• Message Digest Algorithm (MD5): sviluppato da Ronald Rivest nel 1991. Nel 1995 sono state
scoperte delle debolezze, delle altre nel 2004, ed altre ancora nel 2007, tanto da
metterne in dubbio la validità. Elabora l'ingresso in blocchi di 512 bit e produce un
111
Autenticazione del messaggio
Sicurezza
risultato di 128 bit, tipicamente espressi come una stringa di 32 caratteri esadecimali. E'
descritto nella RFC 1321.
Dato che diverse stringhe di ingresso, possono produrre lo stesso digest, la trasformazione non è
reversible. Inoltre, a differenza del MAC, la funzione hash non usa una chiave segreta. Per
questo, una funzione hash, da sola, si presta ad applicazioni del tipo
• memorizzazione di una password non in chiaro - ad esempio nei sistemi Unix, il file /etc/
password (o meglio, /etc/shadow) contiene il risultato della applicazione di una
funzione hash alle password associate agli utenti del sistema. Quando un utente immette
la sua password, su questa viene applicata la stessa funzione hash, ed il risultato è
confrontato con la versione memorizzata. In questo modo, anche qualora il file di
password venisse violato da un attaccante, sarebbe comunque impossibile risalire alla
conoscenza delle password originarie - se non conducendo un attacco a forza bruta;
• generazione di un checksum in grado di garantire l'integrità di un messaggio trasmesso,
come ad esempio per verificare se si siano verificati o meno errori di trasmissione, ma
senza offrire supporto di sicurezza, in quanto un attaccante che sostituisse al messaggio
originario il proprio, potrebbe senza difficoltà generare un hash corretto per il messaggio
contraffatto.
Per il motivo illustrato nel secondo esempio, il calcolo di un MAC può far uso di una funzione
hash, purchè la si associ all'uso di un segreto condiviso, alla crittografia convenzionale, od
alla crittografia a chiave pubblica, secondo uno dei seguenti schemi.
Hash e segreto condiviso
Il messaggio da autenticare, viene concatenato con un segreto condiviso tra le due parti in
comunicazione, e l'hash calcolato su entrambi. Il segreto non viene trasmesso, mentre al
messaggio, si concatena l'hash ottenuto come descritto. Il ricevitore a sua volta, concatena lo
stesso segreto, con la sola parte di messaggio ricevuto, e confronta il risultato, con Il MAC
ricevuto. Il segreto usato viene a volte indicato con il termine di sale (salt), o seme (seed), o
vettore di inizializzazione (IV).
Il vantaggio principale di questa tecnica, è che non viene usata nessuna funzione crittografica,
riducendo il carico computazionale dei dispositivi. Inoltre, le funzioni crittografiche sono spesso
ottimizzate per lunghi testi, mentre questa soluzione di presta bene anche nel caso
di messaggi particolarmente brevi. Una variazione di questa tecnica è nota con il nome di HMAC.
Hash e crittografia convenzionale
In questo caso, il valore dell'hash viene calcolato a partire dal solo messaggio da trasmettere, e
da questo viene generato un MAC mediante crittografia convenzionale, usando una chiave nota
anche al destinatario. Il MAC viene quindi concatenato al messaggio, e trasmesso. Il ricevente,
usando la stessa chiave, decritta il MAC, in modo da poterlo confrontare con l'hash che a sua
112
Lo strato applicativo di Internet
Alessandro Falaschi
volta ha calcolato, a partire dalla conoscenza del messaggio.
Hash e crittografia a chiave pubblica
Quest'ultimo caso è simile al precedente, tranne per l'uso della crittografia asimmetica, in cui il
mittente usa la propria chiave privata per crittografare l'hash e generare il MAC, e chi riceve usa
la chiave pubblica del mittente per effettuare la decrittazione.
HMAC
Il metodo di generare un MAC a partire da una funzione hash e da un segreto condiviso, ha dato
origine ad una tecnica particolare di autenticazione, detta HMAC, in cui una funzione hash
(SHA-1 o MD5) è usata congiuntamente ad una chiave (la cui conoscenza è nota al destinatario),
per generare una etichetta MAC. Se la stessa operazione eseguita a destinazione, fornisce lo
stesso risultato, il destinatario ritiene che il messaggio sia autentico, perchè ha verificato la
conoscenza della chiave da parte del mittente. Il metodo non fa uso di funzioni crittografiche, e
quindi presenta un basso carico computazionale. La tecnica è utilizzata in IPsec, in TLS, e in
tecniche di autenticazione client-server come ad esempio CRAM-MD5.
Crittografia a chiave pubblica
Questa metodologia, detta anche crittografia asimmetrica, e proposta da Diffie e Hellman nel
1976, è stato il primo vero rivoluzionario progresso dopo millenni. Ora non occorre più che le due
parti si trovino d'accordo nell'usare una medesima chiave per crittografare, e recuperare la
versione in chiaro del testo. Infatti:
• ogni entità (A, B, C...) può generare con facilità una coppia di chiavi, di cui una privata
(XA) che viene mantenuta segreta, ed una pubblica (YA) che viene comunicata a tutti i
propri corrispondenti;
113
Crittografia a chiave pubblica
Sicurezza
• esistono due coppie di algoritmi crittografici semplici, che permettono rispettivamente
• di utilizzare una chiave pubblica per recuperare un testo crittografato con una
chiave privata, come nel caso della autenticazione, ovvero
• di usare una chiave privata per recuperare un testo crittografato con una chiave
pubblica, come nel caso del recupero di un messaggio confidenziale;
• risulta essere computazionalmente infattibile tentare di risalire alla chiave segreta, a
partire dalla conoscenza di quella pubblica;
• risulta essere computazionalmente infattibile tentare di risalire al messaggio in chiaro, a
partire dalla conoscenza di quello crittografato, e della chiave pubblica.
L'esistenza di due diverse chiavi, di cui una pubblica, evita il problema della crittografia
convenzionale, di dover trovare il modo di comunicare anche il segreto condiviso.
Utilizzi della crittografia asimmetrica
Illustriamo ora come un sistema di crittografia a chiave pubblica possa essere usato per offrire
un servizio di confidenzialità, di autenticazione, o di scambio di chiavi.
Confidenzialità
Una simpatica analogia, è quella di pensare alla chiave pubblica come ad una specie di
lucchetto, di cui solo il proprietario possiede la chiave (privata). Quindi, se Bob intende spedire
un messaggio ad Alice, prima di tutto, si fa spedire da Alice un suo lucchetto aperto. Quindi, usa
la chiave pubblica (il lucchetto) di Alice, e con quella crittografa (sigilla) il messaggio, che solo
Alice, con la sua chiave privata, potrà aprire. A volte, si usa il simbolismo del portachiavi
(keyring), per indicare il meccanismo con cui vengono conservate e recuperate le chiavi
pubbliche dei nostri corrispondenti.
Autenticazione
Questo è il caso in cui Bob vuole che chiunque sia in grado di verificare che un suo messaggio è
autentico, e prodotto proprio da lui. Stavolta quindi, Bob esegue l'algoritmo crittografico usando
la propria chiave privata, di cui è l'unico possessore, mentre chiunque (e quindi anche Alice)
potrà usare la chiave pubblica di Bob, per aprire il messaggio. Dato che, se il messaggio si apre
con la chiave pubblica di Bob, vuol dire che è stato chiuso usando la rispettiva chiave privata
114
Lo strato applicativo di Internet
Alessandro Falaschi
(sempre di Bob), e che Bob ne è l'unico possessore, allora il messaggio, è sicuramente di Bob.
Spesso, si preferisce non crittografare l'intero messaggio, ma solamente un hash dello stesso,
ottenendo un MAC (chiamato in questo caso firma digitale) che ognuno potrà verificare essere
stato generato da Bob.
Scambio di chiavi
Anche se la crittografia a chiave pubblica può essere usata a scopi di confidenzialità, spesso,
come abbiamo visto prima, può essere preferibile generare una chiave di sessione, con validità
molto limitata nel tempo. Questo permette ad esempio di usare la chiave di sessione nell'ambito
di un algoritmo crittografico convenzionale, eventualmente più debole, o più veloce, e
crittografare con quello il messaggio; la chiave di sessione, ad esempio, viene trasmessa assieme
al messaggio, crittografata con una algoritmo a chiave pubblica, più robusto
e/o computazionalmente più oneroso.
Un diverso aspetto, riguarda la modalità con cui vengono generate le coppie di chiavi pubblica e
privata, che spesso vengono calcolate a partire da un numero casuale. Per alcuni algoritmi, (ad
esempio, Diffie-Hellman) se entrambe le parti conoscono, oltre alla chiave pubblica del
corrispondente, anche il numero casuale di partenza, è possibile che entrambe le parti calcolino
(indipendentemente) anche il medesimo segreto condiviso, da usare poi nell'ambito di uno
scambio basato sulla crittografia convenzionale, evitando così il problema della comunicazione
del segreto condiviso.
Algoritmi a chiave pubblica
La seguente tabella indica gli usi più idonei per quattro algoritmi di crittografia a chiave pubblica
algoritmo
confidenzialità firma digitale scambio chiavi
RSA
si
si
si
Diffie-Hellman
no
no
si
DSS
no
si
no
Curve Ellittiche
si
si
si
115
Crittografia a chiave pubblica
Sicurezza
RSA
Questo acronimo non ha un significato particolare, se non di essere formato dalle iniziali dei suoi
tre autori, ossia Ron Rivest, Adi Shamir e Len Adleman del MIT, che lo hanno formalizzato nel
1977. Al di là dei dettagli tecnici del suo funzionamento, a fronte della sua discreta complessità
computazionale, l'algoritmo si presta ad essere usato per scambiarsi una chiave di sessione
crittografata con RSA, e poi proseguire la trasmissione sicura utilizzando quella, mediante un
algoritmo di crittografia simmetrica.
Diffie-Hellman
Pubblicato per la prima volta nel 1996, permettere a due entità di scambiarsi in modo sicuro le
reciproche chiavi pubbliche, e quindi proseguire con quelle.
Generazione delle chiavi
Il metodo funziona a partire dalla conoscenza comune di due numeri, q che è un numero primo, e
alfa che è una radice primitiva di q. Alice può allora scegliere un intero qualunque XA<q, e
calcolare YA = alfaXA mod q, che costituiscono rispettivamente le sue chiavi privata (XA) e
pubblica (YA). Allo stesso modo Bob, partendo dalla conoscenza degli stessi due numeri alfa e q,
calcola la sua chiave privata (XB) e pubblica (YB), scegliendo casualmente XB<q, e calcolando YB
= alfaXB mod q. In linea di principio, non è necessario che i due numeri di partenza, q e alfa,
siano gli stessi per le due entità, e dopo che le chiavi pubbliche ottenute sono state scambiate, si
può procedere ed utilizzarle ai fini della crittografia e della autenticazione basate sugli algoritmi
a chiave pubblica.
Il segreto condiviso
Se invece le due parti calcolano le chiavi a partire dagli stessi numeri iniziali q ed alfa, è
possibile calcolare, da entrambi i lati, un medesimo segreto K, che potrebbe essere poi utilizzato
come chiave di sessione, nell'ambito di un contesto di crittografia simmetrica. Si può infatti
dimostrare che se Alice effettua il calcolo di K = (YB)XA mod q, utilizzando la sua chiave
privata XA e quella pubblica YB di Bob, quest'ultimo può pervenire allo stesso
risultato calcolando K = (YA)XB mod q, ovvero utilizzando la sua chiave privata XB, e quella
pubblica YA di Alice. Infatti, semplificando un pò, osserviamo che (YA)XB = ( alfaXA )XB è uguale a
(YB)XA =(alfaXB)XA.
Lo scambio di
Diffie-Hellman
La figura di lato,
riassume i passi
dello scambio di
Diffie-Hellman: le
due entità Alece e
Bob, a partire dalla
comune conoscenza
di q e di alfa,
calcolano le proprie
coppie di chiavi
pubblica e privata. Quindi, scambiandosi le chiavi pubbliche, mettono l'altra parte in grado di
calcolare il medesimo segreto K. In assenza di un accordo a priori, i valori di q ed alfa
possono essere definiti da Alice, e comunicati a Bob assieme alla propria chiave pubblica Y A.
116
Lo strato applicativo di Internet
Alessandro Falaschi
La chiave di sessione
Resta ora il fatto, che il segreto condiviso K potrebbe non essere idoneo ad essere usato in un
algoritmo di crittografia simmetrica. Per questo, anziché usare direttamente K come chiave di
sessione, una delle due parti (in genere Alice, che ha iniziato lo scambio) sceglie una differente
chiave di sessione (indichiamola con M), ed usa quindi K per crittografare M mediante un
algoritmo simmetrico. La chiave di sessione M così crittografata viene ora trasmessa a Bob, che a
sua volta usa K per recuperarla, e da quel punto in poi, proseguire la comunicazione mediante
crittografia simmetrica, basata su M.
Attacco MITM
Un eventuale Man in the Middle (Eva) che assiste al primo scambio tra Alice e Bob, anche
venendo a conoscenza di q, alfa e YA, ma non essendo a conoscenza della scelta fatta da Bob a
riguardo di XB, né della chiave privata XA di Alice, non sa come calcolare K. Però, dato che la
trasmissione dei numeri iniziali e delle chiavi pubbliche non è autenticata (e per questo, il
metodo ora illustrato è detto anonimo), Eva potrebbe modificare i valori q, alfa e YA, inviati da
Alice a Bob, con altri valori da lei impostati, e sostituirsi a Bob nel completare lo scambio di
Diffie-Hellman con Alice. Quindi, Eva inizia un nuovo scambio con Bob, stavolta fingendosi Alice.
Infine, intercetta tutti i messaggi tra le parti, transcrittografandoli durante il transito.
Autenticazione dello scambio
L'attacco MITM può essere evitato, se durante lo scambio di q, alfa, YA, e YB, le due parti
possono autenticarsi vicendevolmente, mettendo Eva fuori gioco. Perché ciò sia possibile, ci sono
due alternative:
• esiste una PKI in grado di certificare l'autenticità delle parti, ovvero le parti applicano una
firma digitale ai dati scambiati, e questa firma può essere verificata come autentica da
una parte, utilizzando la chiave pubblica che compare in un certificato digitale dell'altra
parte, e firmato da una CA di fiducia, oppure
• esiste un altro segreto condiviso a priori tra le parti, come ad esempio una password,
mediante la quale aggiungere sale ai messaggi scambiati.
DSS
Il Digital Signature Standard è stato proposta nel 1991 da una agenzia governativa statunitense
(NIST), per offrire dei servizi di firma digitale sulla base del Digital Signature Algorithm (DSA),
che utilizza SHA-1. L'ultima revisione è avvenuta nel 2000. Non viene invece usato per fornire
servizi di crittografia e scambio di chiavi.
Gestione delle chiavi
Alcuni aspetti di già accennati nella discussione dello scambio di Diffie-Hellman rientrano
esattamente in questa definizione, che riguarda i problemi di:
• come ottenere la chiave pubblica di un'altra entità in modo fidato
• come scambiarsi il valore di una chiave di sessione temporanea
La soluzione più generale, in buona analogia con i casi della vita reale, passa per la presenza di
una terza parte, con cui le due parti in comunicazione hanno un rapporto di fiducia.
117
Gestione delle chiavi
Sicurezza
Certificati digitali
Nella crittografia
asimmetrica, sussiste il
problema di come
ottenere la chiave
pubblica di un altro
utente, in modo fidato.
Infatti se durante la
trasmissione della
chiave pubblica di Alice
a Bob, un man in the
middle (Eva)
intercettasse il
messaggio e lo
sostituisse con un altro,
contenente la propria
chiave pubblica, Eva
potrebbe poi spacciarsi
per Alice, e leggere i
messaggi destinati a lei.
Per risolvere questo
problema, si ricorre
all'esistenza di una
terza parte, una sorta di
garante, detta
Certification Autority
(CA), e di cui è possibile
procurarsi con un elevato grado di affidabilità la chiave pubblica, ad esempio, per averla
ricevuta di persona. Una entità che desidera che la propria identità sia certificata dalla CA, gli
consegna a sua volta la propria chiave pubblica, in modo affidabile, come ad esempio
affidandogliela di persona, e mostrando un documento di identità.
La CA associa quindi alla chiave pubblica dei singoli individui, l'identità del legittimo
proprietario, mediante l'emissione di un Certificato Digitale, che viene firmato utilizzando la
propria chiave privata come mostrato in figura, ovvero
• si calcola un hash del certificato non firmato
• si crittografa l'hash con la chiave privata della CA
• si concatena l'hash crittografato al certificato, che risulta così firmato dalla CA
Chi riceve il certificato firmato può verificare l'autenticità dello stesso, e quindi fidarsi che la
chiave pubblica presente nel certificato sia veramente quella dell'individuo a cui il certificato è
intestato, svolgendo le operazioni previste per l'autenticazione mediante funzioni Hash associate
alla crittografia a chiave pubblica, ovvero
• chi vuole verificare il certificato deve disporre della chiave pubblica della CA, scritta ad
esempio in un diverso certificato intestato alla CA, ed essere certo che questa chiave
pubblica sia veramente della CA;
• viene calcolato l'hash del certificato non firmato;
• si confronta il risultato, con quello ottenuto decifrando l'hash cifrato ricevuto, mediante la
chiave pubblica della CA.
118
Lo strato applicativo di Internet
Alessandro Falaschi
Distibuzione di chiavi di sessione mediante crittografia asimmetrica
Poco sopra abbiamo illustrato come lo scambio di Diffie-Hellman consente a due parti il calcolo
di uno stesso segreto condiviso, senza la necessità che lo stesso venga trasmesso, ma è esposto
ad attacchi di tipo MITM, che possono essere sventati ricorrendo ad una Certification Authority.
Infatti, se Alice possiede un certificato firmato da una CA, che ne attesta il possesso di
una chiave pubblica a lungo termine, può usare la chiave privata associata, per firmare i dati
iniziali dello scambio, trasmettendo assieme a questi anche il certificato, in modo che Bob, dopo
aver verificato l'autenticità del certificato usando la chiave pubblica della CA, possa ritenere il
mittente autentico.
Ma, nel caso in cui esista una CA la cui chiave pubblica è distribuita in modo affidabile alle parti
in comunicazione, le quali hanno altresì provveduto a certificarsi presso al CA, decade la
necessità di effettuare uno scambio di Diffie-Hellman completo. Infatti, è possibile crittografare
il messaggio da inviare con un algoritmo simmetrico, e spedirlo assieme alla chiave necessaria ad
aprirlo, crittografando quest'ultima con la chiave pubblica del destinatario, così come risulta
scritta nel certificato firmato relativo del destinario, e noto al mittente; in questo modo, il
ricevente può decrittare la chiave dell'algoritmo simmetrico, facendo uso della propria chiave
privata.
PKI
Una Infrastruttura a Chiave Pubblica (Public Key Infrastructure) permette ad individui ed utenti
di asserire la propria identità, verificare quella degli altri, e si basa sulla accessibilità di
certificati digitali firmati da una Certificate Authority, abilitando in tal modo le entità a
procedere allo sviluppo di una comunicazione sicura facente uso di tecniche crittografiche
qualsiasi.
X.509
E' uno standard ITU-T che definisce, fra le altre cose, formati standard per i certificati a chiave
pubblica, i loro meccanismi di revoca, e la gerarchia delle CA. Nasce nel 1988 in
associazione servizio di directory X.500, ed assume l'esistenza di una rigida organizzazione
gerarchica delle CA, tale da prevedere per ognuna di esse la firma del relativo certificato da
parte di una CA più importante, su su fino ad una unica CA radice. Viene definita una
architettura in cui le CA hanno il solo compito di firmare i certificati, mentre l'emissione degli
stessi è delegata ad una diversa entità, indicata come Registration Autority (RA), e la loro
conservazione è attuata da un Certificate Repository (CR). Anche dopo diverse revisioni, questa
architettura non si è mai realizzata, mentre il servizio di directory X.500 si è evoluto nel
Lightweight Directory Access Protocol (LDAP). Attualmente per certificato X.509 si intende
quello definito nell'ambito del profilo formalizzato nella RFC 3280 prodotta dal gruppo di lavoro
IETF PKIX, che sta per Public Key Infrastructure (X.509).
Catena delle autorità di certificazione
Perché il certificato di Alice, emesso da CA1, sia di di qualche utilità per Bob, questi deve
conoscere con certezza la chiave pubblica di CA1, in modo da poter verificare la sua firma. In
caso negativo, se Bob conosce invece la chiave pubblica di una diversa autorità, ad esempio di
CA2, può tentare di trovare un certificato di CA1 che sia firmato da CA2, perché in tal caso può
usare la chiave pubblica di CA2 per verificare l'autenticità della chiave pubblica di CA1, e quindi
finalmente usare questa, per verificare il certificato di Alice. Nel caso in cui CA1 e CA2 non si
siano certificati a vicenda, lo stesso processo può essere ripetuto attraversando un numero
qualunque di CA.
119
PKI
Sicurezza
Formato
Un certificato X.509 contiene le informazioni
riportate in figura, ossia
• versione: può essere 1, 2 o 3, in accordo
alle specifiche emesse in tempi successivi;
• numero di serie: deciso dalla CA;
• algoritmo di firma: ripetuto in fondo, nella
firma stessa, specifica come decrittarla;
• emittente: identifica la CA che ha apposto
la firma, e (come anche il Subject name) è
espresso con una sintassi X.500 e nota
come Distinguished Name (DN), composta
da una serie di campi in cui compaiono
coppie sigla-valore, in accordo al modello
gerarchico originario, in cui le
sigle dovrebbero individuare la catena delle
CA coinvolte, ed individuare univocamente
il soggetto, come:
•
•
•
•
•
•
Country C
State or province SP
Locality L
Organisation O
Organisational unit OU
Common name CN
ad esempio: C=US/L=Area 51/O=Hanger 18/OU=X.500 Standards
Designers/CN=John Doe.
• periodo di validità: oltre il quale il certificato è da ritenersi scaduto;
• chiave pubblica del soggetto: è proprio l'oggetto del certificato!
• identificatori unici: per disambibuare il caso in cui lo stesso DN sia stato usato per
soggetti diversi;
• estensioni: nella versione v3 dello standard, si è intordott la possibilità di aggiungere un
numero variabile di informaziioni, come ad esempio un indirizzo email, od un dominio
Internet; o delle condizioni (policy) di utilizzo del certificato;
• firma: apposta dalla CA, utilizzando la sua chiave privata, in base ad un algoritmo a
chiave pubblica.
Per avere una idea del risultato finale, possiamo osservare alcuni esempi di certificati, oppure
scoprire i certificati delle root CA che troviamo preinstallati nel nostro browser.
Fingerprint
Può capitare di frequente, che ci si ritrovi per le mani un certificato, senza avere a disposizione
la chiave pubblica di chi l'ha firmato, oppure, un certificato auto-firmato, e si abbia la necessità
di usare la chiave pubblica che vi compare, senza però voler correre il rischio di rimanere vittima
di una impersonificazione frudolenta. Allora, la cosa più semplice che si può fare, è quella di
tentare di contattare la persona/entità a cui è intestato il certificato, e chiedergli se la chiave
pubblica del certificato, è veramente la sua. Dato però che una chiave pubblica può essere molto
lunga, si è diffuso il costume di calcolare un HMAC della versione binaria (ad es DER) del
certificato, in genere di lunghezza ridotta (ad es, 32 cifre esadecimali), e di chiamarlo
120
Lo strato applicativo di Internet
Alessandro Falaschi
fingerprint (impronta digitale) del certificato. In questo modo, la fingerprint può ad esempio,
essere facilmente letta a voce al telefono, o facilmente verificata perché scritta su di un sito
web, e può essere presa con sufficiente affidabilità come la prova che il certificato in proprio
possesso, è conforme a quello in possesso di chi l'ha emesso.
Richiesta e rilascio dei certificati
Per ottenere un proprio certificato, occorre generare una propria coppia di chiavi, compilare una
richiesta di firma certificato in cui compaiono gli elementi che concorono a formare il proprio
Distinguished Name, allegare alla richiesta la propria chiave pubblica, e firmare la richiesta
utilizzando la propria chiave privata, che d'ora in poi dovrà essere custodita con la massima cura.
Se vogliamo utilizzare il certificato per autenticarci verso altre entità, con cui non abbiamo
nessun rapporto preesistente, dobbiamo sottoporre la richiesta ad una CA la cui chiave pubblica
è già ampiamente distribuita, come ad esempio quelle preinstallate con il browser. In questo
caso la CA (o, più correttamente, la RA) può (e deve) svolgere alcune verifiche formali, come ad
esempio accertarsi (mediante il comando whois e/o host) che il richiedente corrisponda
all'intestatario del dominio citato nella registrazione, e/o che il richiedente abbia fornito una
email che gli è nota. Pertanto, la visita con successo di un sito web sicuro, ci garantisce
unicamente che esiste un qualche rapporto tra lo sviluppatore del sito, e il manutentore del
dominio che compare nella URI del sito.
Codifica
Una volta che la CA ha usato la richiesta di certificato per generarne uno, intestato al
richiedente, e firmato dalla CA, il risultato di queste operazioni viene salvato in un file, che può
essere consegnato al richiedente, e/o a quanti potranno richiederlo. La consegna avviene
secondo una tra una serie di possibili modalità di codifica, associate al tipo di estensione usato
per salvare il file, tra cui elenchiamo
• TXT - la rappresentazione testuale, idonea ad essere visualizzata da un utente, ma inutile
ai fini della autenticazione automatica;
• DER - Distinguished Encoding Rules, costituisce una sintassi di trasferimento per dati la cui
struttura è descritta mediante la notazione ASN.1, come appunto è il caso dei certificati
X.509, allo scopo di permetterne la distribuzione verso sistemi con meccanismi di
rappresentazione diversi. Il risultato è una sequenza di byte che rappresenta gli elementi
della struttura dati di partenza, come triplette costituite da tipo-lunghezza-valore (TLV),
in cui le etichette sono le stesse valide per la sintassi di trasferimento BER, come
illustrato in questo esempio;
• PEM - la rappresentazione base64 di una rappresentazione DER, a volte usato anche per
trasmettere la chiave privata, debitamente crittografata;
• P12 - indica il formato PKCS#12, ovvero il 12-esimo in un gruppo di Public Key
Cryptography Standards sviluppati e pubblicati da RSA Security; in particolare, il #12
prende il nome di Personal Information Exchange Syntax Standard e definisce un formato
contenitore per memorizzare oggetti multipli, come più certificati, e chiavi private
associate, generalmente protetti e crittati con un algoritmo crittografico simmetrico
basato su password. Ad esempio, nelle smartcard e derivati (bancomat, SIM) sono
conservati assieme il certificato di identità, e la chiave privata usabile per firmare,
protetta con un algoritimo simmetrico, la cui chiave è il PIN.
Revoca dei certificati
Ad ogni certificato è associato un periodo di validità, e prima che questo scada, deve essere
rinnovato, e prodotta una nuova copia. Ma anche se il certificato non è ancora scaduto,
può essere revocato in anticipo, perché ad esempio la chiave privata del proprietario è stata
121
Strati di sicurezza
Sicurezza
compromessa, il proprietario non è più certificato, o si pensa che il certificato sia stato
compromesso. Ogni CA mantiene quindi una lista (CRL, Certificate Revocation List), firmata,
contenente l'elenco dei certificati emessi, ancora nominalmente validi, ma revocati. Quando si
riceve un certificato, sarebbe bene richiedere alla CA che l'ha emesso, l'invio della CRL, in modo
da poter verificare se questo non sia stato revocato. A fronte della evidente complicazione di
questo modo di operare, nella RCF 2560 è stato definito un Online Certificate Status Protocol
(OCSP) che opera tramite messaggi codificati in ASN.1 e trasmessi via HTTP, e che permette
le verifiche di revoca di certificato in modo molto più veloce dello scaricamento ed elaborazione
delle CRL.
I browser web sono distribuiti con preinstallati i certificati autofirmati di diverse CA, con cui i
produttori del browser hanno stretto un accordo, in modo da semplificare la verifica di
autenticità dei siti che inviano un loro proprio certificato.
Certificati autofirmati
Come illustrato, chiedendo il rilascio del proprio certificato ad una CA la cui chiave pubblica è
preinstallata nel browser, consente di avere il proprio certificato immediatamente riconosciuto
come valido; dato però che queste CA sono tutte root, i loro certificati risulteranno auto-firmati.
In alternativa, ci si può rivolgere ad esempio a CaCert, che offre certificati gratuiti, ed il cui
certificato autofirmato può essere importato in modo facile dal browser. Oppure, se non ci vuol
rivolgere ad una CA esterna, è sempre possibile assolvere a tale funzione in proprio, ad esempio
usando gli strumenti offerti dal progetto OpenSSL. Una volta creato il certificato autofirmato
dalla propria auto-CA, questo deve essere esportato presso i clients che poi lo useranno per
verificare i certificati che firmeremo. L'esportazione può avvenire sia mediante un diverso canale
fisico (consegna fisica di un dischetto, un CD), oppure creando in proprio una distribuzione Linux
installabile da CD, e contenente il certificato, oppure ancora via rete mediante una email sicura,
una rete WiFi sicura, una pagina web, descrivendo il certificato mediante un header
MIME Content-Type: application/x-x509-ca-cert.
L'uso di certificati autofirmati, espone chi li accetta per la prima volta al rischio di un attacco di
tipo man-in-the-middle, perché un attaccante potrebbe sostituire il suo certificato a quello
legittimo, e poi continuare ad impersonare l'interlocutore. Ma se il certificato è corretto, ed è
salvato dal client, gli scambi successivi avvengono senza ulteriori rischi di sicurezza.
Web of trust
Una web of trust (rete di fiducia) è un concetto utilizzato da PGP, GnuPG, e altri sistemi
compatibili con OpenPGP, per stabilire l'autenticità dell'associazione chiave
pubblica-utente, alternativa all'uso delle Certificate Authority. In questo caso, i certificati sono
firmati direttamente da altre persone, in occasione di incontri fisici. Un singolo certificato più
presentare diverse firme, apposte direttamente da altre persone. Ognuno può impostare
l'affidabilità da attribuire ai diversi firmatari dei certificati in suo possesso, considerando
massimamente fidate le firme di persone (chiamiamoli amici) che ci hanno consegnato la chiave
privata di persona, e via via meno fidate, le firme apposte da persone che sono solo amici di
amici (il cui certificato è firmato da amici), o amici di amici di amici (di amici di amici...). A
partire dalla versione 3, anche X.509 ha previsto la possibilità di costruire una rete di fiducia, ma
orientata solamente a far firmare alle CA, i certificati di altre CA.
Strati di sicurezza
In accordo al paradigma della stratificazione dei servizi, le funzioni di sicurezza che offrono
servizi aggiuntivi di questa natura alle applicazioni Internet, vengono realizzate in forma di strati
122
Lo strato applicativo di Internet
Alessandro Falaschi
funzionali addizionali che offrono i propri servizi a quelli superiori, in accordo al seguente
schema
IPSEC
IPsec è l'abbreviazione di IP Security ed è uno standard (RFC 4301) per ottenere connessioni
basate su reti IP sicure. La sicurezza viene raggiunta attraverso la cifratura e l'autenticazione dei
pacchetti IP, e quindi a livello di rete, rendendo la trasformazione trasparente alle applicazioni,
che non devono essere modificate. IPsec definisce
• protocolli che forniscono la cifratura del flusso di dati, attuata mediante due protocolli:
• Authentication Header (AH), che garantisce l'autenticazione e l'integrità del
messaggio, ma non offre la confidenzialità, e
• Encapsulating Security Payload (ESP) che fornisce autenticazione, confidenzialità e
controllo di integrità del messaggio, e per questo motivo ESP è molto più usato di
AH;
• protocolli che implementano lo scambio delle chiavi per realizzare il flusso crittografato:
Attualmente esiste un solo protocollo per questo fine, l'Internet Key Exchange (IKE).
Stabisce uno shared session secret, utilizzando l'algoritmo di Diffie-Hellman. E' definito in
RFC 4306, ed utilizza UDP sulla porta 500.
Mediante IPSec/ESP si può realizzare una Virtual Private Network (VPN), configurandolo sulle
interfacce esterne dei router che interconnettono, mediante un collegamento ad internet, le
sedi distaccate di una stessa organizzazione.
TLS
Il Transport Layer Security è definito nella RFC 4346, e rappresenta la formalizzazione da parte
IETF del Secure Socket Layer definito da Netscape, ed ha lo scopo di realizzare comunicazioni
sicure su Internet per applicazioni come il browsing Web e l'email, in modo da evitare
intercettazioni (eavesdropping), sabotaggi (tampering) e flasificazioni (forgery). Tra SSL e TLS
sussistono differenze minime.
L'uso di una connessione resa sicura via SSL/TLS, può avvenire sia su iniziativa del protocollo
soprastante, come nel caso di STARTTLS, oppure può avvenire fin dall'inizio della connessione,
riservando una porta diversa da quella standard (ad esempio, l'HTTP sicuro prende il nome di
HTTPS, e risponde sulla porta 443 anziché la 80).
Un ulteriore uso di TLS, è quello di creare dei tunnel sicuri nella infrastruttura Internet pubblica,
realizzando delle Virtual Private Network (VPN), come ad esempio avviene con OpenVPN, senza
necessità di intervenire sui singoli dispositivi di rete, come invece nel caso di IPSec.
123
Strati di sicurezza
Sicurezza
Record Protocol
Il Record Protocol offre i servizi di
sicurezza allo strato applicativo, così come
a tre protocolli ausiliari (Handshake,
Change Chiper e Alert) necessari alla
gestione della connessioni che fanno uso di
TLS. L'handshake protocol si occupa di
creare una sessione TLS, ossia un insieme
di parametri crittografici, da utilizzare nel
corso di una o più connessioni, evitando di
negoziare ogni volta gli stessi parametri.
Tra questi, menzioniamo
• l'identificatore di sessione, una
sequenza di byte arbitraria scelta dal server, per identificare uno stato di sessione attiva o
risvegliabile
• il certificato del peer, di tipo X.509, che può non esserci
• il tipo di compressione, ossia l'algoritmo usato per ridurre il volume dei bytes scambiati
• il cifrario, ossia l'algoritmo crittografico per la riservatezza, e l'algoritmo hash per il
calcolo del MAC
• il segreto condiviso tra client e server
• se è risvegliabile, ossia se la sessione può essere usata per creare nuove connessioni.
Lo stato di connessione è invece identificato da
•
•
•
•
random di client e server: scelti a caso dalle due entità per ogni connessione
segreti MAC: le chiavi usate da client e server per calcolare i MAC dei messaggi in uscita
chiavi di scrittura: la chiave di crittografia simmetrica usata dal client e dal server
vettori di inizializzazione: rappresenta lo stato interno per un codificatore a blocchi in
modalità CBC
• numeri di sequenza: aggiornati da entrambe le parti, per i messaggi inviati e ricevuti in
una stessa connessione.
Il Record protocol offre confidenzialità, autenticazione e (opzionalmente) compressione, in
accordo alle modalità operative mostrate nella figura che segue
124
Lo strato applicativo di Internet
Alessandro Falaschi
Il MAC è generato mediante funzione hash SHA-1 oppure MD5, ed usando come sale il segreto
MAC, in modo del tutto simile all'HMAC. La crittatura può usare uno tra gli algoritmi IDEA, RC2,
DES, 3DES, RC4, ed opera anche sul MAC già calcolato.
L'aggiunta finale di una intestazione, dà
luogo al formato mostrato al lato. Il campo
Content Type (8 bits) codifica il protocollo
di strato superiore, ed i numeri di versione
permettono di tener traccia delle
evoluzioni delle specifiche. Infine, viene
inserito un campo che descrive la
dimensione del pacchetto risultante.
Il Record Protocol, anziché incapsulare
informazioni provenienti dallo strato
applicativo, può trasportare informazioni
prodotte da uno dei tre protocolli specifici
del TLS, come mostrato dalla figura
seguente, in cui si confrontano i diversi tipi
di payload del Record Protocol
• Change Cipher occupa un solo byte, che se c'è, vale uno. Ha il solo scopo di far si che le
informazioni relative allo stato in attesa siano copiate nello stato corrente, aggiornando la
cipher suite da usare per questa connessione.
• Alert Protocol occupa due byte, e può inoltrare informazioni di allarme verso l'altra parte
in comunicazione. Il primo byte classifica l'allarme come warning o fatal, nel cui caso la
connessione è interrotta; il secondo byte specifica di che tipo di problema si tratti.
Handshake Protocol
Permette a client e server di autenticarsi vicendevolmente, di negoziare un algoritmo di
crittografia, un algoritmo per il calcolo del MAC, e le chiavi crittografiche da usare. Tutti i
messaggi scambiati mediante l'handshake protocol, precedenti alla trasmissione di qualsiasi altro
dato, hanno il formato mostra sopra, con i campi:
• tipo: specifica uno tra 10 diversi messaggio, come ad esempio hello di client e server,
catena di certificati X.509, parametri per lo scambio di chiavi, richiesta di certificato,
verifica della firma, scambio delle chiavi....
125
Strati di sicurezza
Sicurezza
• lunghezza: del campo successivo
• contenuto: i parametri associati con il tipo di messaggio descritto nel campo tipo.
Nel suo
funzionamento, l'handshake protocol può pensarsi come suddiviso in una successione di 4 fasi.
La prima, è iniziata dal client, che invia il messaggio client_hello, con associati i parametri
mostrati in figura. La risposta server_hello, costituisce la negoziazione dei parametri, e contiene
un numero di sessione valido, e la scelta della cipher suite. Il primo elemento di quest'ultima,
codifica il metodo di scambio chiave, tra cui
• RSA: la chiave segreta è crittografata con quella privata del mittente, e per leggere quella
segreta, occorre prima procurarsi un certificato dove si possa leggere la chiave pubblica dl
mittente
• Diffie-Hellman in versione "fissa", effimera o anonima.
La cipher suite prosegue quindi con lo specificare, tra l'altro, l'algoritmo crittografico simmetrico
scelto, l'algoritmo hash per il calcolo del MAC, e la sua dimensione.
Inizia quindi una seconda fase, in cui (se necessario) il server invia il proprio certificato X.509 e
126
Lo strato applicativo di Internet
Alessandro Falaschi
la propria chiave (inviando i parametri di Diffie-Hellman, oppure adottando RSA). Nel calcolo
dell'hash necessario a generare la firma di autenticazione, oltre ai parametri del server,
sono utilizzati anche i nonce di client e server, inviati con i messaggi di hello, a protezione di
attacchi replay.
Nella terza fase, il client può verificare l'autenticità del certificato ricevuto, utilizzando la
chiave pubblica della CA che ha firmato il cerificato del server; se questo ha buon esito, procede
con l'inviare un PreMasterSecret crittografato con la chiave pubblica del server, oppure i
parametri di Diffie-Hellman. La chiave segreta vera e propria verrà poi calcolata da entrambe le
parti, a partire dalla versione Pre-, e da entrambi i nonce.
Infine nella quarta fase, il messaggio change_chiper-spec segna l'inizio della crittografia di ciò
che segue.
API di sicurezza
Anziché inframmezzare le funzioni di sicurezza tra due strati funzionali preesistenti, a volte si
preferisce isolare queste primitive all'interno di librerie richiamabili dai programmi applicativi
che le linkano, e contenenti entry points di subroutines che implementano i diversi servizi
crittografici di cui l'applicazione può avere bisogno.
SASL
Il Simple
Authentication
and Security
Layer (SASL) è
definito
dalla RFC 4422
come una
infrastruttura
capace di offrire
alle applicazioni
basate su TCP,
servizi di
autenticazione
e di sicurezza
dati, e
fornisce uno
strato di astrazione che, per mezzo di una interfaccia strutturata, permette a diversi protocolli
di far uso di meccanismi crittografici sviluppati indipendentemente.
Presso lo IANA è pubblicato un registro che elenca i protocolli applicativi che prevedono modalità
di interazione con SASL, e fornisce i riferimenti alle specifiche che definiscono questi aspetti. Tra
i procolli che utilizzano SASL, troviamo IMAP, LDAP, POP, SMTP, FTP, NFS, NNTP, e XMPP.
SMTP
\
LDAP
XMPP
Other protocols ...
|
|
/
\
|
|
/
SASL abstraction layer
/
|
|
\
127
API di sicurezza
Sicurezza
/
EXTERNAL
|
GSSAPI
|
PLAIN
\
Other mechanisms ...
I meccanismi supportati anch'essi registrati presso lo IANA, e tra questi troviamo
GSSAPI - Generic Security Service Application Program Interface, Kerberos
RFC4752
EXTERNAL - l'autenticazione è ottenuta con altri meccanismi (es. TLS)
RFC4422
ANONYMOUS - accesso non autenticato, come ospite
RFC4505
OTP - One Time Password
RFC2444
PLAIN - usa una password di tipo cleartext
RFC4616
DIGEST-MD5 - Integrazione dell'HTTP Digest Access in SALS
RFC2831
CRAM-MD5 - Challenge-Response Authentication Mechanism basato su HMAC MD5 RFC2195, draft
Esistono implementazioni libere di librerie che offrono il supporto a SASL, come ad esempio
quelle di Cyrus e GNU. Una fonte di informazioni, si trova presso l'autore delle RFC, SASL e
Sendmail, Technoids.org
CRAM-MD5
Questo acronimo sta per Challenge-Response Authentication Mechanism ed è definito dalla RFC
2195. Si basa sull'algoritmo HMAC-MD5 che calcola un Message Authentication Code (MAC)
utilizzando una funzione crittografica hash in combinazione con una chiave segreta. La funzione
Hash utilizzata è il Message-Digest algorithm 5 (MD5), standardizzato nella RFC 1321, e qui
utilizzato nella variante keyed illustrata in RFC 2104, e che usa una password nota sia al client
che al server come chiave per generare un digest di 16 bytes, rappresentato da 32 caratteri
esadecimali.
Nel CRAM-MD5 il server invia al client, con una codifica di trasferimento base64, una sfida
(challenge) generata ex-novo per l'occasione, e che tipicamente consiste in una stringa di tipo
msg-id, come ad esempio <[email protected]>, e che
contiene un timestamp sempre diverso.
Il client, dopo aver
decodificato lo challenge
dalla sua
rappresentazione
base64, ne calcola un
digest HMAC applicando
l'algoritmo MD5, ossia
usa lo challenge come
messaggio, ed una password segreta associata all'utente che intende autenticarsi, e nota anche
al server, come chiave. I 16 bytes del digest vengono quindi rappresentati come 32 caratteri
esadecimali, e dato che ogni diverso utente possiede una diversa password, il nome dell'utente
che desidera autenticarsi viene prefisso al digest, separato da questo da uno spazio. Quest'ultimo
risultato viene quindi trasformato base64, e finalmente inviato come response al server, il quale
dopo aver recuperato la password associata all'utente, calcola anch'esso il digest, e lo confronta
con quello contenuto nella risposta ricevuta. Un esempio di scambio reale, può essere trovato
nella sezione relativa alle esercitazioni.
L'utilizzo di MD5-keyed per il calcolo del digest, permette di non memorizzare la password in
chiaro presso il server, ma solo una sua versione già crittografata, che compare come calcolo
intermedio in MD5, e indicata come contesto. Il protocollo di sfida difende da attacchi di tipo
128
Lo strato applicativo di Internet
Alessandro Falaschi
replay, dato che anche se intercettato, il messaggio di risposta alla sfida non può essere riusato
successivamente, perché nel frattempo è cambiata la parola di sfida. Dato che ogni sfida è
diversa, questa viene a volte indicata con il termine di nonce, ossia di nome utilizzato una sola
volta.
PGP e GPG
La Pretty Good Privacy è una iniziativa imputabile ad una unica persona, Phil Zimmermann, e
deve molta della sua popolarità all'approccio del tutto aperto con cui è stato impostato il lavoro,
che può essere definito come l'applicazione di crittografia più diffusa al mondo, e che è
formalizzato come standard IETF nella RFC 4880. Nella figura che segue riportiamo uno schema
di firma e crittografia di un messaggio, ad esempio di una email.
Osserviamo che innanzitutto viene calcolato un hash del messaggio, il quale viene crittografato
(asimmetricamente) con la chiave privata del mittente, ed il risultato (ossia la firma del
messaggio) viene concatenato al messaggio stesso. La chiave privata usata, è stata prelevata
(selezionandola in base alla sua identità IDA) da un keyring di chiavi private, dov'era conservata
in forma crittografata (PGP consente agli individui, di possedere più coppie di chiavi pubblica/
privata). Questa chiave privata viene decrittata usando una passphrase, che viene chiesta ogni
volta all'utente, mentre la sua identità è anch'essa concatenata a messaggio + firma. Il risultato
complessivo, viene crittografato usando un algoritmo simmetrico, e che opera in base alla chiave
prodotta da un generatore di numeri casuali (RNG), la quale chiave viene pure trasmessa
concatenata al messaggio, dopo averla crittografata (asimmetricamente) usando la chiave
pubblica associata ad una privata del destinatario, la cui identità (IDB) viene pure concatenata al
messaggio uscente. Con l'ausilio della figura seguente, descriviamo ora il precesso di ricezione.
129
API di sicurezza
Sicurezza
L'identità della chiave privata del ricevitore viene usata per individuarla, in forma crittografata,
all'interno del keyring privato del ricevitore, che quindi chiede all'utente la passphrase, in modo
da poterla decrittare. A questo punto, siamo in grado di decrittare (asimmetricamente) la chiave
di sessione, grazie alla quale possiamo decrittare il messaggio ricevuto. Quindi, l'identificativo
della chiave privata del mittente permette di recuperare, dal keyring pubblico, la chiave
pubblica del mittente stesso, e con questa, decrittare l'hash del messaggio, e verificare così la
firma digitale apposta appunto dal mittente.
Il PGP attribuisce un grado di fiducia alle chiavi pubbliche altrui in accordo alla soluzione basata
sul Web of Trust, spesso coadiuvato dalla esistenza di alcuni key server che mentengo un
deposito di chiavi pubbliche firmate da altri utenti. Per il PGP esistono applicazioni
sia commerciali, che libere, descritte nella apposita sezione delle esercitazioni.
S/MIME
Lo standard S/MIME non offre nulla di più o di meglio del PGP, ossia dei servizi crittografici
di sicurezza per le applicazioni di messaggistica elettronica: autenticazione, integrità e
non-repudiazione, mediante firme digitali, e confidenzialità usando la crittografia. E' stato
prima sviluppato presso RSA come PKCS #7, e quindi il controllo della definizione dello standard
è passato a IETF, che attualmente lo supporta come Cryptographic Message Syntax definito nella
RFC 3852, nell'ambito del WG S/MIME di IETF. I messaggi elaborati in accordo a tali specifiche,
sono identificati da un header MIME-Type: application/pkcs7-mime (o "enveloped-data").
La differenza più sostanziale tra PGP e S/MIME risiede nel formato dei certificati e nella loro
codifica, che rende i due sistemi tra loro incompatibili. S/MIME infatti, esige che i suoi
utilizzatori usino certificati X.509, rilasciati da una qualche CA, di cui il client possieda in modo
sicuro, la rispettiva chiave pubblica.
130
Lo strato applicativo di Internet
Alessandro Falaschi
Riferimenti
Gran parte delle illustrazioni utilizzate in questa sezione sono tratte (in modo non autorizzato)
dal testo "Network Security Essentials: Applications and Standards, 3/E" di William Stallings,
Ed. Prentice Hall, di cui consiglio a tutti la lettura, in virtù della sua estrema chiarezza.
Tuttavia, solo ora mi avvedo che tali figure (ed altro interessantissimo materiale) sono comunque
già disponibili in rete, in formato pdf, presso il sito mantenuto dall'autore. Inoltre, mi sento di
segnalare i seguenti riferimenti
•
•
•
•
•
•
•
•
Diffie-Hellman Key Exchange – A Non-Mathematician’s Explanation
Distributed Security - Microsoft TechNet
Godzilla crypto tutorial - di Peter Gutmann
Recommendation X.509 (03/00) - ITU
The Open–source PKI Book - di Symeon (Simos) Xenitellis
SSL/TLS Strong Encryption: An Introduction - Apache Foundation
OpenSSL Documentation - di Jeremy Mates
IPsec HOWTO - in italiano
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Febbraio 2008
131
Lo strato applicativo di Internet
World Wide Web
L'aspetto di Internet, per come è noto ai più, si basa essenzialmente sulla navigazione del World
Wide Web (trad. lett. ragnatela mondiale), fondata su tre meccanismi per rendere le
informazioni prontamente disponibili:
• lo schema di denominazione individuare le risorse, ossia gli URL;
• il protocollo per accedere alle risorse giacenti sul Web, ossia l'HTTP;
• il formalismo di rappresentazione ipertestuale, ossia HTML.
A questo semplice trittico, si sono via via aggiunte sempre più tecnologie (CGI, CMS, Web
Services, Web Semantico), a cui in questa sezione tenteremo di dare un ordinamento.
• Storia
• W3C
• Markup Language
• SGML, XML
• HTML
• Elementi
• CSS
• Selettori e regole
• Proprietà
• Caricare le pagine sul server
• FTP, SFTP, NFS, SMB, IMAP
• URL, URI, URN
• HTTP
• ABNF
• Da estremo a estremo
• Richiesta
• Metodi
• Intestazioni di richiesta
• Risposta
• Codici di risposta
• Intestazioni di risposta
• Caching
• Intercepting e Reverse Proxy
• Redirezione
• Negoziazione dei contenuti
• Connessioni persistenti
• Pipeline
• Header Connection
• Compressione e Transfer-Encoding
Lo strato applicativo di Internet
Alessandro Falaschi
• Chunked transfer encoding
• Sicurezza
• Autenticazione
• Basic Access Authentication
• Digest Access Authentication
• SSL/TLS
• Header Upgrade
• Dal lato del browser
• Gestione dei Mime-Type ed embedding
• Plugin
• Protocolli registrati
• Configurazione di Firefox
• Esecuzione codice
• Java
• JME
• Javascript
• AJAX
• Flash
• Riempimento moduli
• Action
• Parametri di chiamata
• Esempio di form
• Dal lato del server
• Common Gateway Interface
•
•
•
•
Metodo GET e QUERY_STRING
Metodo POST
Media Type application/x-www-form-urlencoded
Parsing della query e invio file
• Linguaggi di scripting
• Perl, PHP, Python, Java servlet, ASP
• Uso dei database, SQL
• Ruby
• Stato della sessione
• Cookie
• Variabili nascoste
• Server Virtuali
• Log e Statistiche
• Content Managment Systems
• Blog
• Wiki
• Feed RSS e Atom
• Podcast
• Content Delivery Network
• Mirror e Geolocation
133
Storia
World Wide Web
• Gli elementi di una CDN
• Approccio basato sul DNS
• Approccio basato sul livello applicativo
• Multicast, una soluzione mancata
• Overlay Networks
• Reti Peer to peer
• Web Service
• Elaborazione distribuita
• RPC, CORBA, RMI, DCOM, ActiveX e .Net
• SOAP
• XML-RPC
• Mashup
• Web Semantico
• Riferimenti
Storia
Nel 1991 Tim Berners-Lee, durante il suo lavoro al CERN di Ginevra, affrontò il problema di
visualizzare congiuntamente i grafici e le tabelle prodotti come risultati di esperimenti
scientifici, condotti su macchine diverse ed in laboratori differenti. Per questo, realizzò (assieme
ad un suo collega Robert Cailliau) un meccanismo di condivisione delle documentazione
scientifica in formato elettronico, tale da renderla accessibile in modo indipendente dal
particolare tipo di computer dell'utente. Successivamente, accettò l'offerta di trasferirsi al
Massachusetts Institute of Technology (MIT) di Boston, presso cui nel 1994 fondò il World Wide
Web Consortium (W3C).
Il linguaggio con cui si definisce il contenuto della presentazione è l'HTML, contenuto in pagine
definite statiche, e visualizzabili mediante una applicazione browser, detta anche User Agent.
Queste pagine sono richieste ad un sistema remoto presso cui è in esecuzione uno Web Server,
mediante il protocollo HTTP. La URL è un indirizzo di livello applicativo, che consente di
individuare contemporaneamente sia il protocollo, che il computer che ospita il web server, che
la specifica pagina richiesta.
W3C
Il World Wide Web Consortium (W3C), è il consorzio nato allo scopo di studiare, migliorare e
definire nuove tecnologie relative al WWW, con il fine di conseguire il massimo delle potenzialità
offerte da questo mezzo. Non è un ente di standardizzazione, ed i suoi documenti sono delle
raccomandazioni a cui i produttori di sofware sono invitati ad attenersi. D'altra parte, tra i
membri del W3C compaiono gli stessi produttori a cui le raccomandazioni sono indirizzate, oltre
ad aziende telefoniche, istituzioni di ricerca, e società strategicamente interessate alla crescita
del Web. In particolare, mette a disposizione una serie di validatori della sintassi usata nella
redazione delle pagine web.
Markup Language
Un linguaggio di marcatura (markup) ha lo scopo di indicare il modo in cui alcune parti di un
testo devono essere visualizzate, mediante l'uso di descrittori appositi detti TAG, o Elementi.
134
Lo strato applicativo di Internet
Alessandro Falaschi
Mentre i linguaggi di tipo procedurale contengono le istruzioni da eseguire per la visualizzazione
desiderata, i linguaggi descrittivi lasciano al visualizzatore il compito di stabilite il risultato
finale effettivo, e danno solo delle indicazioni di tipo semantico sulla natura delle singole parti di
testo. In questa seconda categoria, troviamo SGML, XML, HTML.
SGML
Lo Standard Generalized Markup Language (SGML) è un metalinguaggio standardizzato (ISO 8879),
discendente dal Generalized Markup Language (GML) sviluppato in IBM, ed è basato sul concetto
di definizione del tipo di documento o Document Type Definition (DTD), che a sua volta definisce
quali sono i TAG permessi in un determinato documento SGML, in modo che questo possa essere
verificato formalmente, prima di procedere alla sua visualizzazione, in accordo al markup.
XML
L'eXtensible Markup Language (XML) è una semplificazione e adattamento dell'SGML, da cui è
nato, e permette di definire la grammatica di diversi linguaggi specifici derivati. Il suo scopo
primario è quello dello scambio di dati strutturati, come ad esempio quelli prelevati da un
database, che potrebbero essere descritti nel seguente modo:
<?xml version="1.0" encoding="ISO-8859-1"?>
<utenti>
<utente>
<nome>Luca</nome>
<cognome>Ruggiero</cognome>
</utente>
<utente>
<nome>Max</nome>
<cognome>Rossi</cognome>
</utente>
</utenti>
Nella prima riga, detta prologo, si indica la versione, la codifica dei caratteri, e se esiste, il DTD
che ne definisce i tag (anche se per questo scopo, si preferisce fare uso di XML Schema Definition
- XSD). Ogni tag può essere corredato da attributi, e lo spezzone di file contenuto tra un tag di
apertura ed uno di chiusura, prende il nome di nodo; il nodo più esterno, che racchiude tutti gli
altri, prende il nome di Elemento Radice. Un file XML può essere visualizzato da parte di un
browser così come si trova, oppure in associazione con un foglio di stile (CSS o XSL) che ne
definisce l'aspetto. In particolare, l'XHTML è un file XML che usa un insieme ridotto dei tag di
HTML, ed una sintassi più rigida, e che può essere visualizzato da un browser web, solo se
accompagnato da un foglio di stile CSS.
HTML
L'Hyper Text Mark-Up Language è stato sviluppato alla fine degli anni '80 da Tim Berners-Lee,
come semplificazione dell'SGML, e la cui sintassi, definita dal W3C, è praticamente ferma dal
1999 alla versione 4.01, resa pubblica nel 1999, e non più modificata, perché in un qualche
futuro, verrà soppiantato da XHTML e XML. Un file HTML è composto di elementi racchiusi tra
tag, uno di apertura ed uno di chiusura, e quest'ultimo, per certi elementi, è opzionale. Ad
esempio, l'elemento <b>testo testo testo</b> verrà visualizzato in grassetto, come testo
testo testo.
Molto spesso, nel tag di apertura di un elemento, vengono anche specificati uno o più attributi,
con lo scopo di arricchire e/o specializzare la semantica standard del tag, assegnando ad una o
più proprietà, dei valori definiti in modo esplicito. Per questo, il formato di un elemento HTML
135
Markup Language
World Wide Web
avrà un aspetto del tipo
<tag attr1=valore1 attr2=valore2 ... >testo al quale si applica la semantica del tag</tag>
Si può inoltre dire, che un file HTML, è un file SGML che adotta il DTD di HTML. La prima riga di
un documento HTML contiene infatti l'indicazione della DTD adottata, la quale specifica al
browser quali sono le specifiche HTML che stiamo utilizzando. Il documento HTML vero e proprio,
è quindi racchiuso tra i tag <html> e </html>, all'interno de quali, troviamo due sezioni:
• quella racchiusa tra i tag <head> e </head>, dove trovano posto le informazioni generali
riguardanti l'intero documento, che non vengono visualizzate dal browser;
• quella racchiusa tra i tag <body> e </body> contiene invece il testo (ed il markup
associato) che verrà mostrato dal browser
Ad esempio, il listato seguente raffigura come si presenta il sorgente della pagina che stiamo
leggendo, che usa il DTD 4.01 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="it">
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
<title>World Wide Web</title>
<link rel="stylesheet" type="text/css" href="../corso.css">
<meta content="Alessandro Falaschi" name="author">
</head>
<body>
<a href="../laboratorio.html">Laboratorio di Software per le Telecomunicazioni</a>
<br>
.
.
.
</body>
</html>
Sebbene inizialmente l'HTML fosse stato pensato per essere scritto a mano, attualmente è
abbastanza comune ricorrere a strumenti wysiswyg, come ad esempio
(video)
(ora divenuto Kompozer) con cui sono realizzate queste pagine; ciononostante, può accadere di
dover modificare manualmente una pagina preesistente, e conoscere qualcosa dei possibili
elementi può essere molto utile.
Elementi
Questo corso non ha nessuna pretesa di prevedere, tra le altre cose, un corso di HTML. Ma chi
volesse approfondire l'argomento, può prendere come ottimo punto di partenza, questo sito con
le traduzioni italiane del sito di W3C, e che presenta diverso materiale utile, come un tutorial di
HTML e CSS, la raccomandazione HTML 4.01, e la tabella degli elementi da questa definiti, che è
riportata qui sotto.
Legenda: Facoltativo, Proibito, Vuoto, Disapprovato, DTD Transitoria, DTD Frameset
Nome
Marcatore iniziale Marcatore finale Vuoto Disap. DTD Descrizione
A
ancora
ABBR
forma abbreviata (es., WWW, HTTP, ecc.)
136
Lo strato applicativo di Internet
Alessandro Falaschi
ACRONYM
ADDRESS
informazioni sull'autore
APPLET
D
AREA
P
V
BASE
P
V
BASEFONT
P
V
T
applet Java
area di una mappa immagine lato-cliente
B
stile di testo grassetto
URI di base del documento
D
T
dimensione di base dei caratteri
BDO
sovrascrive l'algoritmo bidirezionale
BIG
stile di testo ingrandito
BLOCKQUOTE
BODY
citazione lunga
F
BR
F
P
corpo del documento
V
interruzione di riga forzata
BUTTON
pulsante
CAPTION
didascalia di tabella
CENTER
D
T
CITE
abbreviazione per DIV align=center
citazione
CODE
frammento di codice
COL
P
V
colonna di tabella
COLGROUP
F
gruppo di colonne di tabella
DD
F
definizione di un termine
DEL
testo cancellato
DFN
racchiude una definizione
DIR
D
T
DIV
elenco di directory
contenitore generico di lingua/stile
DL
elenco di definizioni
DT
F
termine definito
EM
enfasi
FIELDSET
gruppo di controlli di un modulo
FONT
D
T
FORM
cambiamento locale di carattere
modulo interattivo
FRAME
P
V
FRAMESET
F
sottofinestra
F
suddivisione della finestra
H1
titolo
H2
titolo
H3
titolo
H4
titolo
H5
titolo
H6
HEAD
titolo
F
HR
HTML
F
P
F
intestazione del documento
V
riga orizzontale
F
elemento radice del documento
I
stile italico del testo
IFRAME
T
sottofinestra a livello di riga
IMG
P
V
immagine incorporata
INPUT
P
V
controllo di modulo
P
V
INS
ISINDEX
testo aggiunto
D
T
campo di immissione a riga singola
KBD
testo che deve essere inserito dall'utente
LABEL
etichetta di un campo modulo
LEGEND
didascalia di un gruppo di campi modulo
LI
F
LINK
P
elemento di un elenco
V
un collegamento indipendente dal mezzo
MAP
mappa immagine sul lato cliente
MENU
META
NOFRAMES
D
P
T
V
elenco di menu
metainformazioni generiche
F
contenitore di contenuto alternativo per la riproduzione non basata sui frame
NOSCRIPT
contenitore di contenuto alternativo per la riproduzione non basata su script
OBJECT
oggetto generico incorporato
137
Markup Language
World Wide Web
OL
elenco ordinato
OPTGROUP
gruppo di opzioni
OPTION
F
P
F
PARAM
P
opzione selezionabile
paragrafo
V
valore di proprietà denominata
PRE
testo preformattato
Q
breve citazione in riga
S
D
T
stile per il testo cancellato
SAMP
esempio tipico di listato di programma, script, ecc.
SCRIPT
dichiarazioni di script
SELECT
selettore di scelte
SMALL
stile di testo rimpicciolito
SPAN
generico contenitore di lingua/stile
STRIKE
D
T
testo cancellato
STRONG
forte enfasi
STYLE
informazioni di stile
SUB
pedice
SUP
apice
TABLE
TBODY
F
TD
F
corpo della tabella
F
cella di dati di una tabella
TEXTAREA
campo di testo su più righe
TFOOT
F
piede della tabella
TH
F
cella d'intestazione di una tabella
THEAD
F
intestazione di tabella
TITLE
TR
titolo del documento
F
riga di tabella
TT
stile di testo di telescrivente o a spaziatura fissa
U
D
T
stile di testo sottolineato
UL
elenco non ordinato
VAR
instanza di una variabile o argomento di un programma
Nella precedente tabella, per ogni elemento, si possono individuare gli attributi supportati.
Questi ultimi, hanno lo scopo di modificare e/o specificare meglio la funzione dell'elemento,
come ad es. href e target, usati con l'elemento <a>, che specificano rispettivamente il link da
seguire, e dove aprire la nuova pagina:
<p>Avete visto le nostre <a href="../gabbie/uccelli.gif" target="_top">gabbie per uccelli</a>?</p>
che produrrà il risultato:
Avete visto le nostre gabbie per uccelli?
Gli elementi che si usano più di frequente, sono
•
•
•
•
•
•
•
•
<a></a> per inserire un iperlink,
<p></p> per separare un paragrafo,
<b></b> e <i></i> per il grassetto ed il corsivo,
<h1>..<h6> per i titoli,
<ul> ed <ol> per le liste con i pallini o con i numeri,
<li> per gli elementi delle liste,
<table> per le tabelle, assieme a <tr> e <td> per definire righe e colonne, e
<form> per i campi di inserimento.
Un elenco un pò più dettagliato, è presente presso Wikipedia.
138
Lo strato applicativo di Internet
Alessandro Falaschi
CSS
I fogli di stile a cascata (CSS = Cascading Style Sheets) contengono le dichiarazioni necessarie a
definire lo stile (per es. tipo di carattere, colori e spaziature) da applicare ai documenti HTML e
XHTML, e la definizione di queste regole è ancora una volta emanata dal W3C. In questo modo, è
possibile sviluppare in modo indipendente i contenuti e la formattazione delle pagine,
rendendole più omogenee. Ad esempio, non occorre ripetere una specifica di colore per tutti gli
elementi simili, con il rischio che qualora si desideri cambiarla, occorra ripetere ovunque la
stessa operazione: al contrario, la specifica del colore viene eseguita una sola volta, nel foglio di
stile.
Sebbene il W3C abbia pubblicato nel 2006 la versione 2.01 delle specifiche CSS, e che si stia
lavorando alla versione 3.0, la traduzione italiana che riportiamo è quella della versione 2.0 del
1998, che pure è molto diffusa. Il foglio di stile viene associato alla pagina HTML nella sua
sezione <head>, essenzialmente in uno dei modi seguenti: usando un file separato,
eventualmente ri-usabile a partire da pagine HTML differenti
<html>
<head>
<title>Esempio</title>
<link rel="stylesheet" type="text/css" href="foglio_di_stile.css">
</head>
.
.
oppure in-linea nella stessa pagina per la quale se ne desidera l'applicazione
<html>
<head>
<title>Esempio</title>
<style type="text/css">
codice css
</style>
</head>
.
.
Selettori e regole
Il codice CSS consiste in una serie di regole, strutturate secondo il seguente schema, in cui il
selettore individua quando applicare la regola, che consiste nell'attribuire un certo valore, ad
una determinata proprietà:
selettore {
proprietà1 : valore1;
proprietà2 : valore2, valore3;
}
Il selettore può corrispondere a
• un elemento HTML (es h1, p, li..), indicato come selettore di tipo, che indica come
le regole si applichino a tutte le istanze di quell'elemento,
• una classe (es. selettore = elemento.nome_classe), indicando che le regole si
applicano a quegli specifici elementi, per quali è stato dichiarato un attibuto
class=nome_classe, ovvero
139
Markup Language
•
World Wide Web
una classe generica (es. selettore = *.nome_classe, o selettore =
.nome_classe), e che indica come le regole si applichino a qualunque elemento
per il quale è definito un attributo class=nome_classe;
• un identificatore (es. selettore = #nome_identificatore), indicando che le regole si
applicano al solo elemento per il quale è definito un attributo
id=nome_identificatore. Solo un elemento in tutta la pagina, può avere l'attributo
id pari ad un certo valore;
• altri casi come pseudo-elementi e pseudo-classi (es selettore = elemento:pseudo), che
permettono di individuare ad es. la prima riga di un paragrafo, o la prima lettera, oppure
di identificare condizioni particolari, come il passaggio del mouse.
Alcuni esempi di uso dei selettori, possono essere trovati presso HTML.it; qui notiamo invece,
che le pagine di questo corso usano un CSS specifico, allo scopo di non ripetere i comandi relativi
al colore dello sfondo, ed alla dimensione dei caratteri, per tutti i riquadri di codice. Ciò è
ottenuto realizzando i riquadri come una tabella ad una sola cella, ed usando per gli elementi
<table> e <td>, un attributo class=pre, al quale sono associati i seguenti selettori nel file
corso.css utilizzato:
table.pre {
border: 1pt solid rgb(253, 152, 253);
width: auto;
background-color: rgb(244, 255, 252);
}
td.pre {
font-weight: normal;
font-size: small;
font-family: monospace,Courier New,Courier;
}
Proprietà
Nell'esempio su riportato, la proprietà border è utilizzata per impostare il bordo della tabella
(qualora all'elemento table sia assegnato un attibuto di valore pre) che delimita il riquadro, ad
uno spessore di un pixel, a linea continua, e di colore viola, mentre per lo sfondo è scelto il
colore celeste, e la larghezza del riquadro dipenderà da quella del contenuto. Quindi, il selettore
td.pre determina l'applicazione delle proprietà sui caratteri contenuti all'interno della colonna,
stabilendone il peso, la dimensione, ed il tipo di carattere. Pertanto, un riquadro (vuoto!) sarà
realizzato mediante un codice HTML pari a
<table class="pre" border="0" cellpadding="10" cellspacing="0">
<tbody>
<tr>
<td class="pre">
--- inserire qui il contentuto del riquadro! --</td>
</tr>
</tbody>
</table>
Un elenco delle proprietà esistenti, assieme ai loro possibili valori, ed a degli esempio di utilizzo,
è fornita assieme alla raccomandazione di W3C, ed è replicata su diversi siti in rete. Tra i
riferimenti, elenchiamo alcuni siti dove scegliere liberamente un template di stile da usare per
dare un aspetto gradevole alle proprie pagine.
140
Lo strato applicativo di Internet
Alessandro Falaschi
Caricare le pagine sul server
Ora che abbiamo preparato le pagine che il server web dovrà fornire, su richiesta, al browser,
resta il problema di come depositarle presso il server. A questo scopo esistono tutta una serie di
possibilità, che elenchiamo.
FTP
Il File Transfert Protocol è uno tra i protocolli più anziani di Internet, specificato nella RFC 959,
e permette ad un programma client di colloquiare con un server in ascolto sulla porta TCP 21, al
fine di leggere/scrivere/navigare tra i files del suo filesystem. Può essere invocato da linea di
comando, impartendo manualmente i comandi di cui dispone, oppure può essere utilizzata una
interfaccia grafica, ormai incorporata nelle stesse applicazioni genericamente usate per navigare
nel filesystem locale (ossia, del proprio computer), permettendo in questo caso, operazioni di
tipo drag and drop.
In una prima fase del collegamento, l'utente che
sta usando il client si autentica presso il server,
trasmettendo la password in chiaro, e questa
circostanza è uno dei principali motivi per cui l'uso
dell'FTP è sconsigliato/scoraggiato. E' da notare,
tuttavia, che esiste anche una modalità anonima
di collegamento, in cui il client usa con nome
utente anonymous, e come password tipicamente
invia il proprio indirizzo email. Vedi, come
esempio, questo file di capture. Quando ancora il
web non esisteva, questo era il modo in cui
venivano messi pubblicamente a disposizione dati e
programmi, ed è tuttora in uso, ad esempio
come meccanismo di default utilizzato dai browser
web, per accedere una URI il cui schema è ftp:.
Due ulteriori possibilità, sono quelle relative ad un
collegamento attivo o passivo. La differenza nasce
dal fatto che l'FTP utilizza in effetti due diverse
connessioni TCP, la prima detta di controllo, su cui
avviene l'autenticazione, e dove poi sono inviati
i comandi di sessione, ed una seconda connessione,
instaurata sotto il controllo della prima, su cui
avviene il trasferimento dati vero e proprio.
Nel caso della modalità attiva, è il server a
chiamare il client, un pò per meglio gestire le
richieste di servizio nel caso di elevato traffico, ed
un pò per essere sicuro di stare parlando con chi si
è presentato con l'IP sorgente. In questo caso, il
server usa la porta 20 come sorgente del
canale dati, e contatta il client sul numero di porta
da esso usato in uscita, incrementato di uno.
L'ultima delle figure a fianco, prelevate da un
articolo pubblicato su qcipc, mostra il risultato
finale di un setup attivo. Questa tecnica però dà luogo a problemi, ogni volta in cui tra client
server sia interposto un dispostivo NAT, ovvero quando il client posside un indirizzo IP privato, ed
141
Caricare le pagine sul server
World Wide Web
il server uno pubblico. Infatti in questo caso, il server non è in grado di aprire una connessione
verso il client, e il trasferimento non può avere luogo.
Nel caso specificato (presenza di un NAT), si ricorre allora alla modalità di FTP passivo, mostrata
nella figura seguente. In questo caso la connessione dati viene aperta su iniziativa del client, e
nella prima fase, il server comunica al client un nuovo numero di porta effimera, su cui aprire la
connessione dati. Quindi nel caso passivo, è sempre il client ad aprire entrambi i canali (di
controllo e dati), e non si presenta nessun problema, anche in presenza di NAT.
A volte, per garantire una maggiore sicurezza e confidenzialità, il client si trova ad operare in
una modalità cosiddetta chrooted, cioè a dire, come se sul server fosse stato eseguito il comando
chroot, abbreviazione di change root. In tal caso, il client non può navigare per tutto il
filesystem del server, ma solo a partire (e poi, in giù) da quella che sarebbe stata la sua home
directory, se si fosse collegato come terminale, sullo stesso computer che ospita il server FTP.
Esistono molte implementazioni di client e server FTP.
SFTP
Lo SSH File Transfer Protocol non è ancora uno standard Internet (l'ultimo Draft è scaduto), ma è
utilizzato estensivamente come un vero e proprio protocollo di accesso remoto ad un filesystem.
Non consiste nella esecuzione di FTP su di una connessione resa sicura via SSH, ma è un
protocollo sviluppato ex-novo, che sfrutta i meccanismi di sicurezza offerti da uno strato che
assicura tale funzione, ma l'accoppiata con SSH è particolamente diffusa e utilizzata.
NFS
Il Network File system venne inizialmente sviluppato nel 1984 da Sun Microsystem, e da allora ha
subito diverse evoluzioni, fino alla ultima versione normativa definita dalla RFC 3530. Prevede
che un computer -server NFS- offra parte del suo filesystem, per essere montato da altri
computer -client NFS-, i quali da quel momento in poi, accedono al disco remoto come se fosse il
proprio. E' utilizzato in special modo per realizzare delle stazioni di lavoro diskless, oppure per
condividere dati e programmi su più macchine, senza doverli replicare.
SMB
Il Server Message Block è il protocollo usato dai prodotti Microsoft per condividere in rete files,
stampanti, porte seriali e comunicazioni di varia natura, e include un meccanismo di
comunicazione autenticata tra processi. Nato per essere usato principalmente su rete locale in
associazione al NetBIOS, funziona anche su TCP/IP. Come per il caso precedente, sebbene possa
ben essere usato per salvare le pagine web sul disco del server, ha degli scopi più articolati.
142
Lo strato applicativo di Internet
Alessandro Falaschi
IMAP
L'Internet Message Acces Protocol, sebbe nato per la gestione dell'email, può altrettanto bene
essere usato per trasferire file da/verso il proprio computer locale ed un computer remoto !
URL, URI, URN
Un indirizzo di livello applicativo che identifica una risorsa accessibile mediante HTTP è
chiamata URI (Uniform Resource Identifier), come definito nella RFC 2396, ed estende i concetti
di URL (Uniform Resource Locator, utilizzato per indicare anche dove trovare la risorsa, e come
utilizzarla) ed URN (Uniform Resource Name, utilizzato esclusivamente per dare un nome univoco
alla risorsa) precedentemente usati. La generica sintassi di una URI
<scheme>:<scheme-specific-part>
ne permette l'uso per identificare non solo un indirizzo web, ma anche (ad es.) un indirizzo
email, un identificativo VoIP, un codice ISBN, o tante altre cose, in base al tipo di schema che vi
compare, in accordo a quelli registrati presso lo IANA. Lo schema è indicativo del namespace
sotto cui ricade la risorsa, e la sintassi della parte scheme-specific-part dipende dallo schema
usato, ma per parecchi di questi, ci si può riferire a questo generico esempio relativo ad una URL
HTTP:
in cui
• protocol è un caso particolare di nome di schema, che identifica effettivamente il nome
del protocollo applicativo usato;
• la coppia user:password, se presente, può essere usata al servizio, come ad es. per
accedere ad un server FTP (se il protocol, è ftp:);
• il gruppo user:password@domain:port è anche indicato come authority, ed indica
dove si trova la risorsa, e come accedervi;
• la porta indica l'indirizzo di trasporto da utilizzare per accedere al servizio che supporta
il protocollo indicato, e se assente, è posta pari a quella registrata per lo stesso presso lo
IANA;
• il path identifica una particolare risorsa sotto il controllo della authority, e può essere
assente;
• la query è presente in associazione con meccanismi di tipo CGI che fanno uso del metodo
GET, e dopo il punto interrogativo, presenta una serie di coppie <chiave>=<valore>,
separate da &, e che rappresentano altrettanti parametri formali;
• l'anchor identifica una sottoparte specifica nell'ambito di una unica risorsa indivisible,
come un punto particolare nell'ambito di una pagina web.
Quando una URI compare come valore di un attributo href di un elemento anchor in una pagina
HTML, il browser tenta di dereferenziare l'indirizzo, intraprendendo una azione legata allo
schema che compare nella URI. Se ad esempio si tratta di un'altra pagina web, ne farà richiesta
al server che la ospita, e visualizzerà il body della risposta, mentre se ad esempio si tratta di uno
schema mailto (es. mailto:[email protected]), manderà in esecuzione
l'applicazione-client email predefinita, impostando il destinatario a quello che compare nella
URI.
143
HTTP
World Wide Web
HTTP
L'Hyper Text Transfer Protocol è definito nella sua versione attuale (1.1) dalla RFC 2616, di cui è
in corso una attività di revisione documentata in un Draft. La definizione della sintassi dei suoi
messaggi è descritta per mezzo di un formalismo chiamato forma aumentata di Backus-Naur
(ABNF).
ABNF
Un breve parentesi, per illustrare come la ABNF è una sintassi formale orientata alla descrizione
di grammatiche context-free, e che funziona mediante l'applicazione ripetuta di regole di
produzione del tipo
simbolo ::= espressione
che indicano come dei simboli non terminali possono essere riscritti in termini di sequenze di
altri (terminali o meno). Partendo da un simbolo non terminale, si applicano ripetutamente le
regole, finché non restano solo simboli terminali, per i quali non esistono regole di riscrittura, ed
il risultato forma una frase appartenente al linguaggio che si sa descrivendo. L'espressione può
indicare il semplice concatenamento di altre regole e terminali, oppure l'alternativa tra essi
terno ::= numero numero numero / ambo numero
ambo
::= numero numero
numero ::= 1 / 2 / 3 / 4 / 5 / 6 / 7 / 8 / 9 / 0
mentre altre notazioni hanno altri significati, come ad esempio un [elemento] tra parentesi
quadre è opzionale, un asterisco come in *ALPHA indica la ripetizione di un numero qualsiasi di
ALPHA.
E' abbastanza usata per descrivere i linguaggi di programmazione, e i formati dei protocoli
Internet, e per questo, è documentata nella RFC 4234, ed è stata ulteriormente riassunta, nello
stesso documento che descrive l'HTTP.
144
Lo strato applicativo di Internet
Alessandro Falaschi
Da estremo
a estremo
La figura di
lato mostra il
meccanismo di
richiesta/
risposta
(client/
server), a
partire da un
click su di una
pagina, al
prelievo dei
files dal sever
web, ed alla
comparsa del
risultato sullo
schermo. Lo
User Agent
(browser) nel
ruolo di client,
invia una
richiesta HTTP su di una connessione TCP aperta verso l'indirizzo di trasporto corrispondente alla
porta 80, ed il server restituisce sulla stessa connessione la risposta. Vi sono quindi due tipi di
messaggi HTTP: di richiesta e di risposta. Tanto che la ABNF per l'HTTP, inizia così:
generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line
= Request-Line | Status-Line
Nelle prime versioni del protocollo, la connessione veniva chiusa immediatamente dopo che una
richiesta era stata soddisfatta, in accordo alla natura senza stato (stateless) del protocollo: il
server non mantiene memoria delle richieste precedenti, anche se provenienti dallo stesso
client, ma le tratta tutte in modo indipendente l'una dall'altra. D'altra parte, nel caso in cui nella
pagina ricevuta siano presenti elementi HTML (come ad es. di tipo <img>), che referenziano
oggetti (immagini) da inserire nella pagina da visualizzare, queste vengono allora richieste subito
di seguito alla pagina ricevuta.
Una buona parte dei siti che visitiamo correntemente, estende questo paradigma, oltre che al
prelievo di files, anche all'esecuzione di codice dal lato server, che in quel caso, prende il nome
di Application server. Per riassumere, un video.
Richiesta
In accordo allo schema su riportato, un messaggio di richiesa HTML è composto da tre parti:
• riga di richiesta
• sezione header, contenente informazioni aggiuntive, separata dalla seguente da una linea
vuota
• body, o corpo del messaggio, che nelle richeste è quasi sempre assente
145
HTTP
World Wide Web
La riga di richiesta ha l'aspetto generico descritto dalla ABNF, a cui è affiancato un esempio reale
Request-Line
es.
= Method SP Request-URI SP
HTTP-Version CRLF
GET
/wiki/Pagina_principale HTTP/1.1
ed è composta dal metodo (qui, GET), dal nome della risorsa oggetto della richiesta (/wiki/
Pagina_principale) così come compare nella URL che ha prodotto la richiesta stessa, e dal
nome del protocollo con la sua versione. In generale, la risposta viene generata interpretando la
risorsa come il nome di un file, completo di path relativo, che giace sul disco del computer che
ospita il server, sotto una apposita directory.
Metodi
Dei metodi possibili descritti dalla RFC, i più frequentemente usati sono
• GET - in assoluto il più frequente, serve a chiedere una pagina od una risorsa
• POST - oltre a referenziare una risorsa, invia i dati che sono stati raccolti mediante un
modulo di inserimento (form) collocandoli nel body. Anche con GET si possono inviare dei
dati, ma sotto forma di parametri aggiuntivi nella stessa stringa che identifica la risorsa,
collocandoli dopo un punto interrogativo, come ad
es. name=ferret&colour=pink in http://example.com/over/
there?name=ferret&colour=pink. La differenza fondamentale, è che con GET si
potrebbe generare una stringa di parametri troppo lunga, mentre con POST, tutte le
coppie nome=valore che con il GET sono separate da &, vengono invece scritte nel
BODY, una per linea
• HEAD - produce una risposta identica a quella che si otterrebbe con GET, ma senza
ricevere il body associato alla risposta. E' utile per ricevere le meta-informazioni presenti
negli header, senza scaricare l'intero contenuto.
• OPTIONS - richiede di conoscere i metodi HTTP supportati dal server.
Intestazioni di Richiesta
Il formato delle intestazioni segue quello specificato per il caso delle email, ossia il nome
dell'header, seguito da due punti, e poi una stringa che ne specifica il valore. Mentre nelle email,
però, gli header sono a prevalente beneficio del ricevente, nell'HTTP sono realmente funzionali
al protocollo, e sono presenti sia nelle richieste, che nelle risposte. L'insieme completo dei
Request Header che possono comparire nelle richieste è specificato nella RFC. A partire da un
esempio concreto, possiamo discutere di
• Host: tools.ietf.org - la parte della URI relativa al computer ed alla porta dove si
trova la risorsa richiesta;
• User-Agent: Mozilla/5.0 etc etc - il tipo di browser che utilizziamo: il server
potrebbe fornire pagine differenti in base al client;
• Accept: text/xml,application/xml,application/xhtml+xml,text/
html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 - indica i tipi di media (nei
termini della classificazione MIME) che il browser è disposto ad accettare, usando il
parametro q per indicare un grado di preferenza;
• Accept-Language: it,en;q=0.7,en-us;q=0.3 - indica la preferenza per la lingua
della risorsa che stiamo richiedendo, nel caso in cui il borwser ne abbia diverse traduzioni;
• Accept-Encoding: gzip,deflate - il nostro browser accetta i contenuti compressi;
• Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 - indica i character encodig
che si è disposti a ricevere, e la rispettiva preferenza;
146
Lo strato applicativo di Internet
Alessandro Falaschi
• Connection: keep-alive - indica che si desidera mantenere la connessione aperta
anche dopo la ricezione della risorsa, in modo che se si continua ad interrogare lo stesso
server, non si deve eseguire nuovamente il three-way-handshake;
• Keep-Alive: 300 - specifica di voler mantenere la connessione aperta per 300 secondi
(5 minuti)
• Referer: http://en.wikipedia.org/wiki/URI_scheme - indica la pagina che il
browser stava visualizzando, quando è partita questa richiesta
Risposta
E' composta di tre parti:
• Status Line di risposta
• sezione header
• body, separato con uno spazio dagli header
Il body è presente nel caso in cui il codice di risposta indica un successo, ed è posto di seguito
alla sezione degli header, separato da questi da una linea vuota, come per l'email.
Codici di risposta
La prima riga della risposta ha un aspetto del tipo
HTTP/1.1 200 OK
ed il codice di risposta segue le convenzioni già viste per l'email, in cui la prima cifra dà una
indicazione relativa all'esito della richiesta, in accordo allo schemaLa descrizione dei casi d'uso
dei diversi codici è contenuta nella RFC 2616, e wikipedia ne presenta un elenco sintetico. Alcuni
codici di risposta particolarmente significativi sono
• 200 OK - la richiesta ha avuto successo;
• 301 Moved Permanently - la risorsa che abbiamo richiesto non è raggiungibile perché è
stata spostata in modo permanente, e la sua nuova URI è indicata nell'header Location. Di
norma i browser eseguono la richiesta del nuovo URI in modo automatico, senza
interazione dell'utente;
• 302 Found - la risorsa è stata temporaneamente spostata presso un'altro URI, anche qui
indicato da Location;
• 304 Not Modified - usato a seguito di una richiesta condizionata, nel caso in cui la
copia della risorsa che risiede nella cache del client sia allineata con quella disponibile
presso il server;
• 400 Bad Request - la risorsa richiesta non è comprensibile al server;
• 401 Unauthorized - simile a 403/Forbidden, ma usato quando è
richiesta autenticazione, e questa è fallita;
• 403 Forbidden - la risorsa referenziata esiste, ma i privilegi non sono sufficienti;
• 404 Not Found - la risorsa richiesta non è stata trovata, e non se ne conosce
l'ubicazione. Di solito si verifica quando l'URI è stato indicato in modo incorretto, oppure il
contenuto è stato rimosso dal server;
• 500 Internal Server Error - il server non è in grado di rispondere alla richiesta per
un suo problema interno.
• 505 HTTP Version Not Supported - la versione di HTTP non è supportata.
147
HTTP
World Wide Web
Intestazioni di risposta
Commentiamo assieme il capture relativo al referenziamento ripetuto della
URI http://infocom.uniroma1.it/alef/tesi/.
• Date: Tue, 29 May 2007 21:31:20 GMT - è la data in cui viene servita la pagina
• Server: Apache/2.0.46 (Red Hat) - il tipo di server web che ha trasmesso la
risposta
• Last-Modified: Fri, 09 Dec 2005 16:43:23 GMT - la data in cui è avvenuta
l'ultima modifica alla pagina
• ETag: "808071-1bd-156520c0" - una etichetta (Tag) della Entità richiesta, che il
server usa per identificare la versione della risorsa inviata, e che verrà utilizzata
successivamente, nell'ambito dei meccanismi di caching. Ad esempio, il server web
Apache, di default, calcola l'ETag in base agli attributi associati al file corrispondente alla
risorsa richiesta, come data di modifica, dimensione, iNode
• Accept-Ranges: bytes - indica che il server è disposto ad accettare richieste parziali
delle risorse, specificate mediante l'header di richiesta Range, indicando l'intervallo di
bytes desiderato
• Content-Length: 445 - la dimensione in bytes del body
• Connection: close - il tipo di connessione offerta dal server. In questo caso, alla fine
di ogni risposta, viene chiusa la connessione TCP utilizzata
• Content-Type: text/html - specifica il Media Type (coincidente con quelli definiti da
MIME) della risorsa contenuta nel body
Caching
Nella navigazione web
sono presenti una o più
cache intermedie, che
hanno lo scopo di
alleggerire il carico
dei server. Una prima
cache è interna al
browser, ma in rete
possono esserne
dislocate altre, che
prendono il nome di
Proxy, a cui il client
indirizza tutte le
richieste (dovunque dirette), e che si fa carico di effettuare le richieste per suo conto, e di
fornire la risposta.
Se le risorse richieste giacciono già nella cache (del proxy, o del browser), queste possono essere
restituite direttamente, senza recuperarle nuovamente dal server di origine, che quindi riduce
l'occupazione di banda di uscita. Se diversi client usano lo stesso proxy, e referenziano le stesse
pagine, il risparmio di banda può diventare considerevole, e può convenire dislocare un proxy
interno ad una sottorete, da far condividere a tutti i client di quella sottorete.
Il meccanismo con cui si tenta di accedere direttamente alle repliche presenti in cache, è quello
di validazione, ottenuto rendendo i metodi di richiesta condizionali, mediante l'inserimento degli
header
• If-Modified-Since - viene citata la data che era presente nel Last-Modified
ricevuto
148
Lo strato applicativo di Internet
Alessandro Falaschi
• If-Match - viene citato il valore di Etag che era stato associato alla risorsa ricevuta
In questo modo, se il server verifica che l'oggetto è sempre uguale (ossia, la data è la stessa, e/o
l'Etag coincide), risponde con un codice 304 Not Modified, ed il browser (il proxy) visualizza
(invia) il contenuto della propria cache. Un esempio di tale comportamento, può essere
riscontrato nel file di capture già utilizzato.
Un secondo meccanismo di gestione delle cache si basa invece su di una logica di obsolescenza
(expiration), fondata sull'uso di alcuni header specifici, come
• Expires - fornito nelle risposte, indica fino a quando (si presume) che l'oggetto abbia
validità
• Age - è inserito tipicamente da un proxy intermedio quando accede alla sua cache, ed
esprime l'anzianità (in secondi) dell'oggetto restituito
• Cache-Control - può assumere uno tra diversi valori, ed essere presente sia nelle
richieste (no-cache, no-store, max-age) che nelle risposte (no-cache, no-store,
max-age, must-revalidate)
Quando un client sta per effettuare una richiesta di un oggetto che ha in cache, ma che non è
ancora spirato, può scegliere di rinunciare ad effettuare la richiesta, e visualizzare la sua copia
locale. Al contrario, un server può impedire che un oggetto da esso inviato venga memorizzato
nelle cache, usando i valori no-cache, no-store, must-revalidate, come ad esempio
avviene nel caso di pagine dinamiche ottenute mediante l'esecuzione di CGI.
Intercepting e Reverse Proxy
Mentre tutti i browser hanno la
possibilità di configurare
volontariamente un proxy a cui
inoltrare le richieste, può
succedere che i router della
LAN o del provider provvedano
di loro iniziativa a reinstradare
i pacchetti IP associati a
comunicazioni HTTP, in modo
che attraversino un Proxy.
Questa funzionalità prende il
nome di Intecepting Proxy.
Un Reverse Proxy al contrario,
invece di essere usato per
uscire, è usato per smistare il
traffico in ingresso ad una lan, verso una pluralità di web server interni, ognuno che serve pagine
per un diverso dominio, e potenzialmente configurati con un IP privato. Questo ha lo scopo di
migliorare la sicurezza, di permettere il bilanciamento del carico, oltre naturalmente a
realizzare il caching delle pagine in uscita.
Redirezione
Le risorse associate agli URI presenti su determinate pagine web, possono essere trasferite su
computer differenti, e cambiare dominio, oppure possono essere ri-nominate, e pur rimanendo
sullo stesso server (e dominio), prendere un URI diverso. In tal caso, le richieste che citano il
vecchio indirizzo, si vedrebbero restituire una risposta del tipo 404 Not Found, producendo
disappunto e frustrazione. La soluzione offerta da HTTP si basa su di un meccanismo di
redirezione, che usa i codici di risposta 301-303 e 307, e comunica il nuovo indirizzo come valore
149
HTTP
World Wide Web
associato all'header Location presente nella risposta. La differenza tra i codici di risposta, risiede
nelle possibilità che il nuovo indirizzo sia temporaneo o permanente (nel qual caso, i
collegamenti preferiti dovrebbero aggiornarsi automaticamente), e nella possibilità che il
browser segua automaticamente il nuovo indirizzo, oppure chieda prima conferma all'operatore
umano.
Affinché il server verso cui sono dirette le richieste per risorse che non ci sono più, risponda con
un codice di tipo 3xx Moved anziché 404 Not Found, il server stesso deve essere debitamente
configurato in tal senso.
Negoziazione dei contenuti
L'HTTP permette la negoziazione dei contenuti, consentendo allo User Agent di esprimere le
proprie preferenze a riguardo delle diverse possibili versioni degli oggetti richiesti, ed al Server
di decidere. Oppure, al contrario, si consente al Server di offrire una scelta di possibilità, ed allo
UA di decidere quale utilizzare. Queste preferenze vengono espresse mediante l'uso di appositi
header nella richiesta, come Accept, Accept-Charset, Accept-Encoding, Accept-Language, e
User-Agent. Il server quindi, utilizza l'header di risposta Vary per specificare su quali dimensioni
si è effettuata la scelta del tipo di contentenuto da inviare. Per una descrizione dei metodi usati
per gestire la fase di negoziazione dei contenuti, ci si può riferire alla documentazione relativa
al server Web Apache.
150
Lo strato applicativo di Internet
Alessandro Falaschi
Connessioni Persistenti
Quando uno UA invia più
richieste consecutive verso
uno stesso server, come nel
caso, ad esempio, in cui si
vogliano scaricare tutte le
immagini contenute in una
determinata pagina appena
ricevuta, è molto più
sensato ri-utilizzare sempre
la stessa connessione TCP,
piuttosto che aprirne una
diversa, per ogni diverso
oggetto richiesto. In tal
modo, oltre a risparmiare
sui tempi necessari al
Round Trip Time necessario
per l'apertura e la chiusura
delle connessioni, si riduce
l'occupazione di memoria
necessaria ai buffer del
TCP, e la gestione del
controllo di congestione
attuata dal TCP, può
evolvere su di un intervallo
temporale più ampio.
Pipeline
Un client può inviare le
richieste in pipeline, ossia
una di seguito all'altra,
senza attendere la fine della risposta alla richiesta precedente; in tutti i modi, è prescritto che il
server invii le risposte nello stesso ordine con cui sono pervenute le richieste.
Header Connection
Nella versione 1.1 di HTTP, le connessioni persistenti sono il funzionamento di default, che può
essere sovvertito qualora il client (il server), invii assieme alla richiesta (risposta) l'header
Connection: Close. Viceversa, per compatibilità con versioni precedenti del protocollo, il
desiderio esplicito di usare connessioni persistenti può essere segnalato mediante l'header
Connection: KeepAlive.
Un esempio di utilizzo delle conessioni persistenti, è dato dal file di capture relativo alla
richiesta della URI http://www.ubuntu-it.org/index.php?page=Filosofia.
Compressione e Transfer-Encoding
Qualora la richiesta lo permetta (dichiarando tramite l'header Accept-Encoding della
richiesta, uno o più algoritmi scelti tra gzip, compress, e deflate), il body della risposta
HTTP può contenere un oggetto che è memorizzato, e trasmesso, in forma compressa, ed in tal
151
HTTP
World Wide Web
caso l'header Content-Encoding esprimerà quale sia stato l'algoritmo di compressione scelto.
Viceversa, l'oggetto richiesto può essere memorizzato presso il server in formato nativo, e
compresso solo al momento della trasmissione: questa circostanza, viene segnalata per mezzo
dell'header Transfer-Encoding, che oltre ai valori prima elencati, prevede anche la codifica
chunked.
Chunked transfer encoding
Più codifiche di trasferimento, possono essere applicate in cascata, ma chunked deve essere
applicata per ultima, perchè questa anziché realizzare una compressione, segmenta il messaggio
in blocchi (chunks). Questa tecnica è usata quando il server non conosce a priori la dimensione
dell'oggetto inviato, perché questo è il risultato di un calcolo ancora in corso, oppure perché si
tratta di un contenuto audio/video generato in tempo reale. Al fine di evitare il calcolo della
dimensione totale dell'oggetto, questo viene inviato chunked, con ogni chunk che all'inizio
contiene la dichiarazoine della lunghezza del chunk.
Sicurezza
Nei termini definiti al capitolo precedente, la sicurezza in http può essere intesa come
• restrizione dell'accesso a determinati contenuti, ai soli utenti autenticati;
• autenticazione del server nei confronti dello UA, in modo da verificare l'autenticità della
fonte;
• riservatezza dei dati trasmessi, che potrebbero contenere dati sensibili e/o monetari e/o
ulteriori credenziali di sicurezza.
Mentre per i secondi due punti, si ricorre essenzialmente alla attivazione del TLS, il primo punto,
anche se potenzialmente gestibile con meccanismi appositamente definiti per l'HTTP, viene
generalmente implementato a cura di uno strato applicativo ancora superiore all'HTTP, mediante
le tecniche dei CGI, dei cookie, o del javascript. Ma iniziamo, comunque, dal primo punto.
Autenticazione
Il meccanismo di autenticazione previsto da HTTP si basa su di uno schema challenge-response,
in cui il server dopo aver ricevuto la richiesta di un oggetto per il quale è stato ristretto
l'accesso, anziché inviare la risposta contenente l'oggetto, emette una risposta con la quale
lo sfida ad autenticarsi; il client quindi sottomette una nuova richiesta, a cui allega le proprie
credenziali. Sono previste due modalità di autenticazione, dette Basic e Digest, descritte nella
RFC 2617, entrambe basate sulla conoscenza di un segreto (password) condiviso tra client e
server.
Basic Access Authentication
Questo schema è da considerare assolutamente insicuro, e da usare solo in un ambito del tutto
fidato, in quanto la password è inviata in chiaro, seppur con codifica base64. La prima risposta
(di sfida) del server, che riporta un codice 401 Unauthorized, contiene un header
WWW-Authenticate: Basic realm="Laboratorio di Cisterna"
Il browser allora, presenta all'utente una finestra in cui cita il valore del Realm (in modo che
l'utente possa ricordare quali credenziali usare), e richiede l'immissione di una coppia
utente-password. Ad esempio, l'identità dell'utente "Aladdin" con password "open sesame"
saranno combinati assieme com "Aladdin:open sesame", e quindi trasmessi con codifica
152
Lo strato applicativo di Internet
Alessandro Falaschi
base64, come QWxhZGRpbjpvcGVuIHNlc2FtZQ== (verifica). Pertanto, dopo l'immissione di
utente e password, il browser reitera la richiesta precedente, aggiungendo alla stessa una
intestazione
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
che questa volta produce nel server l'invio della pagina protetta. Un esempio del comportamento
descritto, si può ottenere visitando questa pagina protetta, (username/password = labsoftel/
cisternalab) a cui corrisponde questo file di capture.
Digest Access Authentication
Dal punto di vista dell'utente, il funzionamento di questo schema è del tutto identico al
precedente; al contrario di quello, però, la password viene inviata in una forma
crittograficamente sicura. Anche ora il server risponde alla prima richiesta, con una risposta che
riporta il codice 401 Unauthorized, ma che stavolta contiene un header di sfida del tipo
WWW-Authenticate: Digest realm="[email protected]",
qop="auth,auth-int",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41
Mentre il realm ha come prima lo scopo di essere mostrato all'utente, il nonce viene usato
assieme al nome utente, alla password, al realm, al metodo, all'URI della risorsa, ad un
contatore di richiesta (nc), al codice di quality of protection (qop) prescelto, e ad un nonce del
client (cnonce), per calcolare (mediante il calcolo ripetuto di un hash MD5), il valore di risposta
da inserire nell'header da restituire al server:
Authorization: Digest username="Mufasa",
realm="[email protected]",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
uri="/dir/index.html",
qop=auth,
nc=00000001,
cnonce="0a4f113b",
response="6629fae49393a05397450978507c4ef1",
opaque="5ccc069c403ebaf9f0171e9517f40e41"
Il server usa la stessa password (o meglio, una sua versione crittografata) per effettuare lo stesso
calcolo, ed autenticare l'utente.
SSL/TLS
Qualora si desideri un livello di sicurezza maggiore di quello offerto dal semplice uso della
autenticazione HHTP, si può ricorrere al Secure Sockets Layer (SSL), definito da Netscape, e che
ha costituito la base per la definizione del TLS. In tal caso, la URI presenta una schema di tipo
https, che causa l'apertura di una connessione TCP verso la porta 443 anziché la 80. A quel
punto, un messaggio di Client_Hello (capture) determina l'inizio dell'handshake protocol, al
termine del quale l'applicazione prosegue come se si trattasse di una normale connessione HTTP
su TCP, mentre invece tutto il traffico si svolge in modalità crittografata, come descritto nella
RFC 2818.
153
Dal lato del browser
World Wide Web
Header Upgrade
Anzichè usare una diversa porta come per il caso dell'https, la RFC 2817 descrive l'uso di un
codice di risposta, 426 Upgrade Required, e dell'header Upgrade, tali da permettere ad una
connessione HTTP normale, di passare in una modalità protetta da TLS, sempre usando la stessa
porta 80. Questo, oltre che permette di risparmiare un indirizzo di trasporto, permette di
ospitare dei server virtuali su di un medesimo computer, senza necessità di assegnare allo stesso
molteplici indirizzi IP.
Dal lato del browser
Dopo aver illustrato molti dettagli dell'HTTP, svolgiamo un approfondimento di ciò che accade ai
due estremi della navigazione web, iniziando da quando una risposta giunge al browser, e
come possano essere intraprese azioni differenti dalla semplice visualizzazione della pagina
ricevuta. Quindi, illustriamo come possono essere gestiti gli schemi diversi da http. Infine,
discutiamo come si possano inviare, assieme ad una richiesta HTTP, anche alcuni dati
intenzionalmente immessi dall'operatore umano.
Gestione dei Mime-Type ed embedding
La risposta HTTP contiene, tra gli altri, l'header Content-Type, che identifica il documento
trasportato nel body, come aderente ad uno dei tipi registrati presso IANA. Alcuni di questi sono
direttamente visualizzabili dal browser, mentre per altri, il browser invoca una Helper
Application, posta in corrispondenza al tipo di file dal sistema operativo stesso, oppure
memorizzata a seguito di una domanda a riguardo, posta all'utente. Ma non sempre un server
web invia un header Content-Type (perchè ciò avvenga, deve essere opportunamente
configurato), e così a volte il browser deve tentare di assegnare per suo conto un Mime Type al
file ricevuto, in base all'estensione del file, oppure analizzando l'inizio dello stesso. Se tutti i
tentativi falliscono, il file viene trattato come application/octet-stream, e viene suggerito
di salvarlo su disco.
Plugin
Un volta determinato con successo il Mime-Type dell'oggetto ricevuto, e individuata
l'applicazione Helper idonea a visualizzare/riprodurre lo stesso, questa può essere eseguita in
modo indipendente, o esterno, al browser, oppure direttamente all'interno della finestra del
browser. In questo secondo caso, il programma Helper prende il nome di plugin, in quanto non
può essere eseguito in modo indipendente, dipendendo dai servizi offerti dal browser stesso,
come ad esempio l'interfaccia grafica. A volte invece, un plugin ha il solo scopo di far eseguire
una applicazione preesistente, che altrimenti verrebbe eseguita esternamente al browser,
all'interno dello stesso. La configurazione attuale dei plugin del browser Firefox, ad esempio,
può essere visualizzata immettendo l'indirizzo about:plugins nella barra degli indirizzi dello
stesso.
Protocolli registrati
A volte il programma da usare per visualizzare/riprodurre un oggetto richiesto mediante web,
non è determinato al momento dell'arrivo della risposta, bensì al momento in cui viene cliccata
la URI presente in una pagina web. Se la URI fa riferimento ad uno schema che non è http,
allora il browser non invierà nessuna richiesta http, ed invocherà invece un programma
apposito, passandogli la URI come argomento, delegando a questo il compito di procedere, in
accordo al protocollo associato alla URI.
154
Lo strato applicativo di Internet
Alessandro Falaschi
Configurazione di Firefox
In Firefox, le preferenze per quanto riguarda le modalità di navigazione e di gestione delle
informazioni ricevute possono essere impostate inserendo l'indirizzo about:config nella barra
degli indirizzi; il risultato, oltre a visualizzare i valori impostati agendo sul menù delle
preferenze, ne visualizza anche molti altri, definiti in accordo a queste regole di configurazione.
In particolare,
• le preferenze della serie network. protocol-handler.* sono quelle che permettono di
specificare il comportamento del browser in corrispondenza dei protocolli (schemi) che
vengono referenziati nelle pagine web, dopo che per questi è stata registrata
l'applicazione che li gestisce;
• la preferenza network.http.pipelining e collegate, permette di definire il comportamento
per ciò che riguarda le connessioni persistenti;
• la preferenza network.dns.disableIPv6 consente di disabilitare le query al DNS per indirizzi
IPv6, che in pratica sono quasi per nulla diffusi, velocizzando così la navigazione.
Esecuzione codice
A volte la risposta HTTP, anziché contenere un oggetto (come ad es. una pagina HTML, una
immagine, od un contenuto multimediale) che deve essere semplicemente mostrato dal browser
(o da un plugin, o da una helper application), consegna allo UA del vero e proprio codice
eseguibile, rendendo così il web, un meccanismo di distribuzione di applicazioni, o application
server. Fin qui nulla di straodinario, tranne per il fatto che il codice ricevuto deve essere
eseguito indipendentemente dal S.O. presente sul computer presso il quale è utilizzato il
browser, ed a questo fine, sono state sviluppate le soluzioni proposte con Java, Javascript e
Flash, brevissimamente descritte appresso.
Java
Il linguaggio Java è stato definito da Sun Microsystem, che recentemente l'ha
rilasciato con licenza GPL, ma che fin dal 1998 ha adottato un modello di sviluppo
aperto indicato come Java Community Process. Java è basato su oggetti, e
presenta una sintassi abbastanza simile al c++ (video corso in italiano).
La compilazione del codice sorgente Java produce un eseguibile detto bytecode
che, anziché essere legato ad un particolare tipo di ambiente hardware/software,
deve essere eseguito da un altro programma, denominato Java Virtual Machine
(JVM), che costituisce lo strato software che effettivamente interagisce con il
computer ospite. Pertanto, se il bytecode è uno, di macchine virtuali ce ne sono
tante, quante sono le architetture alternative. Il nutrito insieme di librerie di classi disponibili
per Java, permette di scrivere applicazioni (dette anche applet) di ogni tipo, anche con accesso
alla rete, e che una volta ricevute tramite web, sono eseguite in una sandbox, in modo da
restringere i diritti di uso ed accesso alle risorse del computer ospite.
Le versioni di JVM più recenti prevedono un ulteriore passo di elaborazione del bytecode, detto
compilazione Just In Time (JIT), e che produce il codice macchina relativo alla architettura
ospite, direttamente al momento della esecuzione. In una pagina HTML possono essere presenti
diverse applet java, inserite nella stessa mediante l'elemento HTML <object>, e che vengono
eseguite in una sandbox che ne impedisce l'accesso ad altre risorse del computer.
155
Dal lato del browser
World Wide Web
JME
La Java Micro Edition è la specifica di un sottoinsieme della piattaforma Java, idoneo per lo
sviluppo di applicazioni da utilizzare nell'ambito di dispositivi con prestazioni ridotte, come ad
es. i telefoni cellulari, ed il cui codice sorgente è stato rilasciato sotto licenza GPL con il nome di
PhoneMe; dato che l'ambiente può essere emultato su computer, lo sviluppo di nuove
applicazioni mobili è particolarmente facilitato.
Le funzionalità di cui una applicazione JME può usufruire, sono descritte dalla applicazione di un
particolare profilo, alla configurazione della JME di cui è equipaggiato il dispositivo su cui
l'applicazione dovrà essere eseguita. Ad esempio, la Connected Limited Device Configuration
(CLDC) contiene un sotto-insieme minimo di librerie di classi Java, e quando accoppiata
alla Mobile Information Device Profile (MIDP), viene definito un ambiente dotato di una API alla
interfaccia grafica (GUI), e di una API orientata alla esecuzione di giochi bi-dimensionali: le
applicazioni scritte per questo profilo, sono dette MIDlets.
Javascript
Mentre per Java, il bytecode ricevuto deve essere eseguito da una JVM (che non è detto sia
installata), il codice Javascript è inviato in forma di sorgente, è molto semplificato rispetto a
Java (con cui non ha neanche molto a vedere, se è per quello), e viene eseguito direttamente dal
browser. Il sorgente viene così interpretato riga per riga dallo UA stesso; per mantenere
compatibilità tra questi, Javascript è stato sottoposto ad un processo di standardizzazione da
parte di ECMA, riconosciuto anche da ISO, che gli ha portato il secondo nome di ECMAscript.
Ciononostante, le implementazioni di Javascript su browser diversi sono parzialmente
incompatibili, ed il codice Javascript deve fare del suo meglio per tentare di capire dove si
trova, ed evitare d eseguire istruzioni che potrebbero essere interpretate per il verso sbagliato.
L'uso principale di Javascript è stato quello di produrre particolari effetti grafici non ottenibili
con il solo HTML, ma che attualmente sono possibili utilizzando il CSS. Javascript viene altresì
usato per modificare al volo una pagina HTML ricevuta, prima che questa venga visualizzata,
intervenendo direttamente su di una sua rappresentazione interna al Browser, nota con il nome
di Document Object Model (DOM).
Presso la sezione dei riferimenti, alcuni interessanti links a siti che consentono di sperimentare
la programmazione Javascript modificando direttamente degli esempi già pronti.
AJAX
Rappresenta l'acronimo di Asynchronous JavaScript and XML, e consiste nell'utilizzo congiunto di
diverse tecnologie per realizzare pagine web interattive che si comportano in maniera
sensibilmente più pronta di quelle tradizionali, in quanto il ciclo richiesta-risposta non avviene
più solo ad opera dell'utente, ma è il browser stesso a condurre una dialogo asincrono con il
Server, mentre l'utente interagisce con la rappresentazione dei dati mostrata dal browser. Ad
esempio, nel caso in cui si richieda un diverso ordinamento di una tabella dati, anziché chiedere
una nuova pagina al server, con i dati ordinati in modo diverso, i dati sono riordinati
direttamente dal browser.
156
Lo strato applicativo di Internet
Alessandro Falaschi
Flash
Nel 1995 viene distributo FutureSplash, come un plugin capace di produrre grafica vettoriale
animata all'interno del browser. La ditta originaria viene acquisita nel '96 da
Macromedia, sviluppatrice del concorrente Shockwave, e i due prodotti vengono fusi in
Macromedia Flash; e dal 2005, i diritti sulla tecnologia sono acquisiti da Adobe Systems.
Il plugin Flash viene prodotto per architetture Windows, Macintosh e Linux, e rappresenta una
sorta di browser nel browser. Le animazioni Flash vengono definite per mezzo del linguaggio
interpretato ActionScript, molto simile al Javascript, e che viene eseguito da una Actionscript
Virtual Machine, che nella sua realizzazione più recente dispone anche di un compilatore Just In
Time.
La grande diffusione di Flash in moltissimi siti web ne ha favorito la crescita, ed attualmente è la
tecnologia in assoluto più usata per la diffusione di contenuti multimediali via web.
Riempimento moduli
In HTML è definito l'elemento <form> (modulo o modello), tra i cui tag di apertura e chiusura,
oltre ad altri elementi HTML qualsiasi, si possono inserire elementi particolari detti controlli, che
vengono visualizzati dal browser come campi di inserimento all'interno di moduli.
157
Dal lato del browser
World Wide Web
Action
L'elemento <form> possiede un attributo particolare, denominato action, che identifica una
URI da invocare quando l'utente aziona un pulsante di inoltro, e verso cui viene inviata una
richiesta, usando come metodo per inviarla, quello definito dall'attributo (sempre di form)
method.
Parametri di chiamata
La particolarità della URI che compare nell'attributo action, è che anziché rappresentare una
risorsa statica, individua un programma, invocato con argomenti impostati in base ai contenuti
presenti nei campi di inserimento: per ogni campo (controllo) della form, è specificato infatti un
attributo name, che rappresenta un nome di variabile, a cui viene associato il valore immesso
dall'utente in corrispondenza di quel campo.
Esempio di form
Per sperimentare l'effetto della esecuzione di questo e dei prossimi esempi, occorre installare sul
proprio computer il server Apache e configurarlo come indicato nella esercitazione collegata a
questo capitolo, e quindi installare nella propria directory public_html gli esempi forniti. Il
codice HTML
<form method="get" action="http://127.0.0.1/labsoftel/primocgi.cgi">
<table style="width: 85%" border="0" cellpadding="4" cellspacing="2">
<caption>
<i>Esempio di Inserimento</i>
</caption>
<tbody>
<tr>
<td style="text-align: right;">email:</td>
<td><input maxlength="50" name="email"></td>
</tr>
<tr>
<td style="text-align: right;"><input name="ok" value="ok" type="submit"></td>
<td style="text-align: left;"><input name="reset" value="reset" type="reset"></td>
</tr>
<tr>
<table style="text-align: left;" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td><input name="ordine" value="pizza" type="radio"> pizza</td>
</tr>
<tr>
<td><input checked="checked" name="ordine" value="lasagna" type="radio"> lasagna</td>
</tr>
<tr>
<td><input name="ordine" value="tiramisu" type="radio"> tiramisu</td>
</tr>
<tr>
<td><input name="ordine" value="pinta" type="radio"> pinta</td>
</tr>
</tbody>
</table>
</tr>
</tbody>
</table>
</form>
produce la visualizzazione seguente
Esempio di Inserimento
email:
158
Lo strato applicativo di Internet
Alessandro Falaschi
pizza
• lasagna
ordine:
tiramisu
pinta
ok
reset
e quando viene premuto il tasto ok, il browser effettua una richiesta HTTP con il metodo GET,
verso la URI http://127.0.0.1/labsoftel/primocgi.cgi indicata nell'attributo action
dell'elemento form. Come anticipato, l'oggetto referenziato dalla action in realtà è un
programma, detto CGI, che verrà eseguito sul server, e che produrrà come risultato una pagina
html, che il server web ci invierà come risposta.
Dal lato del Server
Siamo ora in grado di approfondire lo studio di ciò che avviene dal lato server dell'HTTP, e di
come la tecnologia web si sia man mano arricchita di funzionalità in grado di offrire servizi
sempre più evoluti, mediante una interfaccia di presentazione sempre più universale.
Common Gateway Interface
Il CGI è una modalità di eseguire un programma residente presso un server web (chiamato
anch'esso CGI), il cui nome è presente nel path di una richiesta HTTP, e di visualizzare come
risposta una pagina web, il cui contenuto è prodotto dal programma stesso. Pertanto, la pagina
visualizzata non esiste in forma fisica, ma è stata generata dinamicamente per l'occasione. La
realizzazione di programmi CGI scritti utilizzando linguaggi di scripting, ed abbinati a
database, ha reso possibile lo sviluppo dei Content Managment Systems.
Il meccanismo di comunicazione tra utente, server web, e programma CGI, merita qualche
commento:
• il CGI è un programma che può essere eseguito anche da finestra terminale, e che
• può accedere al contentuto delle variabili di ambiente definite da chi lo manda in
esecuzione,
• può ricevere dei dati mediante il canale di standard input
• può comunicare i risultati della sua elaborazione mediante operazioni di stampa
dirette verso standard output
• il browser presso l'utente funge da interfaccia di immissione e di visualizzazione dei
risultati, ovvero
• i valori immessi nella form posso essere codificati direttamente nella sezione query
della URL di richiesta, oppure essere inseriti nel body della richiesta stessa
• la pagina HTML che viene visualizzata a seguito della richiesta, e contenuta nel
body della risposta HTTP, è generata direttamente dal CGI, in base al risultato delle
sue elaborazioni
• il server web che fa da intermediario comunica con il cgi ed il broswer
• scrivendo i contenuti della URI e intestazioni della richiesta HTTP, nelle variabili di
ambiente che possono essere lette dal CGI
• ridirigendo il contenuto del body della richiesta, verso lo standard input del CGI
159
Dal lato del Server
World Wide Web
• ridirigendo lo standard output del CGI, verso il body della risposta HTTP
La definizione formale di questa metodologia risale al 1993, e fu definita nell'ambito delle
discussioni svolte tramite la mailng list a cui erano iscritti gli sviluppatori web di allora,
e pubblicata presso il sito dell'NCSA, che a quei tempi offriva la prima implementazione (a cura
di Rob McCool) di server web universalmente diffusa. Da allora, solo nel 2004 si è arrivati ad una
formalizzazione ufficiale della interfaccia CGI/1.1, con la RFC 3875.
Nella figura precedente, tratta da questo testo on-line, si mostra la sequenza delle operazioni
descritte. Il termine CGI quindi, oltre che a rifersi alla interfaccia tra server web ed
applicazione, esprime bene il concetto che questa applicazione-CGI può costituire una sorta di
porta (comune) verso altri universi: una delle prime applicazioni della tecnica fu infatti quella di
utilizzare il CGI come mezzo di interrogazione di un DataBase, formattando i risultati in una
modo facilmente accessibile, e idoneo a generare ulteriori interrogazioni al database, in un modo
semplice.
Metodo GET e QUERY_STRING
Come anticipato, il server web comunica al CGI i parametri che gli giungono da parte del client
mediante l'uso di variabili di ambiente, che il CGI può leggere, ed usare per i suoi scopi. Un
esempio è fornito nelle esercitazioni, dove è mostrato lo script perl che viene invocato dalla
form precedente, e che ci mostra le variabili di ambiente ricevute a seguito dell'invocazione del
pulsante di inoltro.
In particolare, la variabile QUERY_STRING riporta la parte di URI successiva al simbolo ?, ossia
la sequenza di coppie variabile=valore associate ai campi della form, separate dal simbolo
&. Inoltre, la variabile REQUEST_METHOD indica il metodo indicato nell'attributo method
dell'elemento HTML <form>, che può assumere i valori GET e POST.
Metodo POST
Mentre nel caso precedente (metodo GET) i campi della form sono trasmessi come parte della
URI, con il metodo POST questi sono invece passati nel body della richiesta HTTP, ed il server
web a sua volta, li passa al CGI mediante il canale di standard input.
Per fare un esempio, replichiamo la form soprastante, utilizzando questa volta il metodo POST,
ed invocando una diversa action, modificando quindi, rispetto alla form precedente, solo la
prima linea, che diventa
<form method="post" action="http://127.0.0.1/labsoftel/secondocgi.cgi">
160
Lo strato applicativo di Internet
Alessandro Falaschi
dando così luogo al modulo seguente
Uso del metodo POST
email:
pizza
• lasagna
ordine:
tiramisu
pinta
ok
reset
Come possiamo apprezzare dalla pagina di risposta inviata dallo script invocato nella action, i
parametri della chiamata questa volta sono stati inviati nel body del messaggio di richiesta HTTP.
Media Type application/x-www-form-urlencoded
Se nel campo email delle form precedenti, immettiamo parole separate da spazi, o contenenti
lettere accentate, possiamo osservare come questi caratteri siano sostituiti, dal lato del CGI che
li riceve, dal carattere + (per lo spazio) oppure da codifiche esadecimali. Questa trasformazione
è quella di default, che può essere resa esplicita aggiungendo nel tag dell'elemento form, un
attributo enctype con valore application/x-www-form-urlencoded.
Parsing della query e invio file
Osserviamo ora che, sebbene il body possa essere di lunghezza qualsiasi, e si possa pensare di
aver risolto così il problema di avere strighe di opzioni troppo lunghe, restano ancora due
questioni:
• come fare per interpretare la stringa delle coppie variabile=valore ? Questo, in linea
di principio, non è un problema, come mostrato dall'output prodotto da terzocgi, invocato
mediante il bottone seguente, che realizza una form con dei controlli nascosti:
<form method="post" action="http://127.0.0.1/labsoftel/terzocgi.cgi">
<input name="ok" value="ordina in segreto" type="submit">
<input name="ordine" value="amatriciana" type="hidden">
<input name="email" value="[email protected]" type="hidden">
</form>
•
ordina in segreto
• nel caso in cui si voglia inviare, mediante la form, un intero file (usando un controllo di
tipo, appunto, file), è probabile che la tecnica attuata nel terzocgi fallisca. Allora, al
posto del valore di default x-www-form-urlencoded, si preferisce specificare nella
action un attibuto enctype="multipart/form-data", definito nella RFC 2388.
Questo fa sì che ogni diverso campo della form, venga trasmesso in una diversa sezione del
body della richiesta HTTP, ed ogni sezione suddivisa in modo multipart, come previsto
dalle specifiche MIME. Sperimentiamo anche questa tecnica, invocando ora secondocgi,
che ci mostra il body così come è stato ricevuto:
161
Dal lato del Server
World Wide Web
<form enctype="multipart/form-data" method="post" action="http://127.0.0.1/labsoftel/
secondocgi.cgi">
<input name="ok" value="ordina multipart" type="submit">
<input name="ordine" value="pastiera" type="hidden">
<input name="email" value="[email protected]" type="hidden">
</form>
•
ordina multipart
Linguaggi di scripting
Il termine script, tradotto in italiano come linguaggio interpretato, tra origine dall'uso del
termine script nel campo delle arti drammatiche, dove con questo termine, si intende il copione
che deve poi essere (appunto) interpretato da un attore. La programmazione degli script, nasce
dall'esigenza di abbreviare il ciclo di sviluppo del codice, che ne prevede l'edit, la compilazione,
il linkaggio, il debug, e l'esecuzione. Omettendo la fase di compilazione e link, si può verificare
immediatamente l'effetto di piccole modifiche apportate, integrando il debug con le fasi di edit
e di esecuzione. L'uso dei linguaggi di scripting si è quindi affermato per lo sviluppo
dei programmi CGI, che anche se possono essere scritti in qualunque linguaggio, compreso c e
c++, beneficiano della adattabilità intrinseca derivante dall'uso degli script. Nel corso della storia
del web, si sono accumulate notevoli quantità di librerie di codice già pronto per l'uso, rendendo
possibile il rapido sviluppo sia di applicazioni CGI per compiti specifici, che di applicazioni più
generali che ricadono nella categoria dei CMS, dei Blog e dei Wiki.
Perl
Acronimo di Practical Extraction and Report Language (anche se in effetti, è un retronimo), perl
nasce nel 1987 su iniziativa di Larry Wall, ed oggi dispone di una miriade di moduli già pronti per
l'uso. In particolare, la sezione dedicata alle applicazioni web ed allo sviluppo di applicazioni è
particolamente nutrita e pronta a soddisfare quasi ogni esigenza. Allo stesso tempo, esiste un
modulo opzionale di Apache, che incorpora in Apache il compilatore-interprete perl, offrendo
prestazioni superiori. Anche se in origine è nato come un linguaggio interpretato, attualmente
l'esecuzione di un programma Perl prevede una prima fase, in qui viene prodotto un bytecode ed
un grafo di flusso, che sono poi eseguiti da una virtual machine in stile java.
La sintassi di Perl può ricordare un pò quella del c, anche se subisce l'influenza di molti altri
linguaggi, anche orientati agli oggetti. Può invocare in modo diretto la valutazione di espressioni
regolari. Effettua automaticamente la conversione di tipo delle variabili (es indirizzo/intero/
stringa/) in funzione del contesto in cui vengono usate, ed usa il primo carattere delle stesse per
identificarne la dimensionalità, come ad esempioRFC
PHP
Nasce nel 1994 come un insieme di CGI scritti in c, per rimpiazzare degli script perl usati
dall'autore per mantenere le proprie pagine personali. Da allora ha ricevuto i contributi di
parecchi sviluppatori, ed ora è un potente linguaggio di alto livello, con una sintassi che ricorda
il c, un buon supporto del paradigma di programmazione ad oggetti, e l'accesso diretto ai
parametri ricevuti mediante l'uso dei controlli delle form. Il solo nucleo di base prevede più di
3000 funzioni, ed offre il supporto alla interrogazione di parecchi diversi tipi di DataBase, così
come svariati wrapper verso altri linguaggi/applicazioni/protocolli/tecnologie, che sono raccolti
in un deposito denominato PEAR. E' alla base dello sviluppo di diversi applicativi wiki o cms,
come MediaWiki, su cui è basata Wikipedia. L'uso congiunto di Linux, Apache, MySQL e PHP (e/o
Perl e/o Python), viene denominato server LAMP, e rappresenta la configurazione preferita per
162
Lo strato applicativo di Internet
Alessandro Falaschi
lo sviluppo di siti dinamici, costituendo un stack applicativo tutto Open Source, molto
competitivo rispetto alle soluzioni commerciali.
Python
Nasce alla fine degli anni 80, e quindi, a differenza di PHP, non per risolvere problematiche
legate ai CGI. E' particolarmente sensibile alle esigenze di leggibilità del codice, consentendo di
affrontare serenamente anche la stesura di progetti complessi. Permette di adottare altrettanto
bene paradigmi di programmazione orientata agli oggetti, oppure strutturata, o funzionale.
Java servelet
Sebbene Java sia nato allo scopo di distribuire codice eseguibile su qualunque tipo di macchina
client, in questo particolare caso è invece usato per realizzare codice da eseguire dal lato
server, al punto che il termine originario applet si trasforma, in questo caso, in servlet. Le
particolarità di Java hanno fatto si che, anziché adattarsi ad un server web preesistente, si sia
preferito lo sviluppo di server scritti apposta, e denominati Servlet container.
ASP
Le Active Server Pages sono l'approccio di Microsoft allo sviluppo di applicazioni server-side,
scritte in VB.NET, C# e J#, ed ha subito una graduale evoluzione fino alla attuale versione
ASP.NET, che è integrata con la architettura .NET, nata a sua volta, in risposta a Java.
Uso dei database, SQL
Come anticipato, una delle applicazioni principali dell'approccio-CGI, è stato l'accesso ai dati
mantenuti in un DBMS, ed alla presentazione dei risultati in pagine web scritte in modo da
facilitare ulteriori richieste correlate alla prima. Mentre per DataBase si può intendere una
semplice organizzazione indicizzata dei dati, tale da permetterne un accesso velocizzato rispetto
alla ricerca sequenziale, un DBMS è una applicazione server che permette l'accesso, la modifica a
la manutenzione degli indici dei dati, da parte di più applicazioni client che operano in modo
concorrente. In buona sostanza, le applicazioni che fanno uso di un DBMS, di fatto sostituiscono
alle proprie variabili e strutture dati, quelle presenti nel database che viene usato, che
rappresenta in tal senso una sorta di memoria a lungo termine dell'applicazione.
Lo Structured Query Language è un linguaggio definito appositamente per realizzare delle
interrogazioni ai database relazionali (RDBMS), ed affonda le sue radici a cavallo tra gli anni 70
ed 80. I database relazionali organizzano i dati in tabelle, le cui righe rappresentano dei record
che mettono in relazione tra loro i contenuti che compaiono nelle colonne, ed alcune colonne
possono svolgere il ruolo di mettere in relazione tra loro i record presenti in tabelle differenti.
Nonostante sia ANSI che ISO abbiano partecipato ad un processo di standardizzazione di SQL, gli
sviluppatori di DBMS non vi hanno mai aderito pienamente, cosicchè un programma scritto in uno
dei linguaggi fin qui discussi, deve in genere usare una diversa libreria di funzioni per ogni
diverso RDBMS che intende usare. Ma nonostante ciò, le operazioni di base che è possibile
eseguire hanno gli stessi nomi nei diversi casi, come ad esempio Select, Insert, Update, Delete.
Per un confronto tra diversi RDBMS, si veda la tabella presso Wikipedia.
163
Dal lato del Server
World Wide Web
Ruby
Anche Ruby è un linguaggio di scripting, di tipo interpretato, nato nel 1993 per opera di Yukihiro
Matsumoto, che segue un paradigma ad oggetti. Viene citato ora, anzichè nella sezione
precedente, perchè il motivo della sua popolarità è legato allo sviluppo (2004) di un ambiente
noto come Ruby on Rails, che consente lo sviluppo rapido di applicazioni Web basate su RDBMS.
La rapidità si basa su di una filosofia di progetto che tende ad evitare la ripetizione di definizioni
altrimenti deducibili, e la necessità di specificare solo ciò che si discosta delle convenzioni.
Questo tipo di approccio è stato definito come scaffholding (impalcatura, o ponteggio) che
consiste nell'usare la struttura delle tabelle già definita nel database che si intende usare, ed i
nomi li definiti, per i nomi delle variabili di programmazione. In definitiva, questo paradigma si
traduce nella generazione automatica della interfaccia di programmazione, a partire dalla
struttura del database soggiacente, e quindi nel suo utilizzo da parte della applicazione che si
sta realizzando.
Stato della sessione
Abbiamo affermato fin dall'inizio, che un server HTTP tratta tutte le richieste come indipendenti
le une dalle altre, evitando accuratamente di memorizzare informazioni di stato, relative alla
evoluzione della sessione che si sta svolgendo con un client che invii richieste ripetute. In tal
modo, si permette l'attuazione di tecniche di bilanciamento del carico, come ad esempio nel
caso in cui la richiesta HTTP sia inoltrata ad uno tra diversi server in batteria, che condividono
gli stessi documenti da inviare, ma non l'informazione di stato relativa al client.
Per ovviare a questa situazione, e permettere ad esempio lo sviluppo di servizi di commercio
elettronico, dove chi naviga mette nel carrello diversi acquisti, oppure per permettere la
personalizzazione dell'aspetto di un sito, discutiamo di due soluzioni possibili.
Cookie
Anche se letteralmente questo termine significa biscottino, ha il senso di un gettone, del tutto
simile alla contromarca che ci viene consegnata dall'inserviente di un guardaroba, e che
riconsegnamo per ri-ottenere il nostro cappotto. In origine, questo termine è stato usato per
autenticare gli utenti di sessioni video remote su macchine Unix. L'applicazione di questo
concetto alla navigazione web è stato introdotto da un impiegato di Netscape, e poi è stato
ri-definito formalmente nella RFC 2965. Il funzionamento si basa sulla presenza, nella risposta
inviata da un server web, di una intestazione Set-Cookie, che specifica una stringa che
codifica una serie di attributi, come
•
•
•
•
•
una coppia nome-valore;
una data di rimozione, trascorsa la quale, il cookie viene distrutto;
un dominio;
un percorso;
se il cookie deve essere re-inviato solo su connessioni sicure.
Nelle successive richieste da parte del client, in cui la URI corrisponde al dominio ed al percorso
citati nel cookie, questo viene accluso alla richiesta, associandolo alla intestazione Cookie. Il
valore del cookie, contiene una codifica (eventualmente ottenuta con metodi crittografici) dello
stato della sessione all'atto della richiesta che ha generato la risposta che ha prodotto la prima
istanza del cookie, ed allegando tale codice anche nelle successive richieste, si ottiene che
• il server è in grado di condizionare la nuova risposta al valore di tale stato;
• il cookie può essere modificato mediante una nuova intestazione Set-Cookie contenuta
nella nuova risposta.
164
Lo strato applicativo di Internet
Alessandro Falaschi
I propositi di questa tecnica sono molteplici: oltre al caso già citato del commercio elettronico, è
ad esempio possibile
• autenticare un utente (mendiante un form), ed evitare che debba, in seguito, farlo di
nuovo (se seduto allo stesso computer);
• personalizzare l'aspetto di un sito, usando l'attestazione di avvenuta autenticazione, come
chiave per il recupero del template di formattazione preferito dall'utente;
• tracciare i comportamenti individuali. In pagine servite da siti diversi, possono essere
presenti banner od altre piccole immagini, prelevate da un server diverso da quello della
pagina richiesta, assieme al quale ci viene consegnato anche un cookie che ci identifica
(indipendentemente dall'indirizzo IP che usiamo in quel momento). In tal modo, il
fornitore del banner (e del coockie) può tenere traccia della sequenza di navigazione tra
tutti i siti che ospitano il banner, e provare ad indovinare le nostre preferenze, in modo da
poter poi realizzare delle campagne di marketing mirate.
Nonostante una serie di controindicazioni all'uso dei cookie, l'attuale navigazione web non
sembra poterne fare a meno.
Variabili nascoste
Una delle più valide alternative ai cookie, applicabile nel caso in cui le pagine di risposta siano
sempre generate da un CGI, è quella di inserire nelle stesse, dei moduli (form) contenenti dei
controlli nascosti, i cui valori rappresentano le informazioni di stato relative alla navigazione
svolta fino al momento della generazione della pagina contenente i controlli nascosti. Inoltre,
nel caso in cui la navigazione prosegua utilizzando il metodo POST, questi valori non compaiono
nella URI, ottenendo prestazioni del tutto equivalenti a quelle dei cookie, al prezzo di
ri-generare ogni volta la pagina di risposta.
La differenza sostanziale tra l'uso dei cookie e quello delle variabili nascoste, è che mentre i
primi sopravvivono fino alla loro data di scadenza, permettendo di conservare l'informazione di
stato anche tra visite distanti nel tempo, le variabili nascoste possono invece accumulare
informazioni di stato, solo nel caso in cui si continui a visitare sempre lo stesso sito, in modo che
le variabili presenti nella nuova pagina, dipendano dalle scelte operate alla pagina precedente.
Server Virtuali
Si tratta della possibilità di ospitare su di un medesimo server web, più siti corrispondenti ognuno
ad un diverso dominio, ed un diverso intestatario. Questo, può essere ottenuto in due modi. Il
primo, consiste nel dotare il computer che ospita il sito web, di più indirizzi IP (indicati con il
termine multihoming), ognuno corrispondente ad un diverso dominio, e discriminare le richieste
in base all'IP di destinazione del socket. Il secondo metodo, consiste nell'utilizzo di un unico IP,
su cui il DNS risolve tutti i domini associati ai siti (che sono quindi alias di un unico CNAME), e nel
differenziare le richieste in base alla intestazione Host presente nella richiesta, che appunto
riferisce a riguardo del dominio che compare nella URI di richiesta.
Log e Statistiche
I file di log del server web contengono molte informazioni relative alle pagine che sono richieste,
all'orario, al codice di risposta, allo user agent, al referente alla pagina visitata, e sono
tipicamente esaminati una volta al giorno, da parte di programmi appositi, allo scopo di generare
dei report (accessibili via web) che caratterizzano le modalità di fruizione dei contenuti del sito.
L'interesse per questi report può essere di semplice curiosità, o rivestire un fine più concreto,
come il monitoraggio dell'esito di una campagna di marketing. Due di queste applicazioni open
source, sono Webalizer e Awstats, il primo scritto in c, ed il secondo in perl.
165
Content Managment Systems
World Wide Web
Una diversa tecnica di analisi di basa sul page tagging, e consiste nell'inserire nelle pagine un
riferimento ad un oggetto, oppure del codice javascript, tale da produrre un accesso ad
un server remoto (tipicamente, di terza parte) che effetturà l'analisi, e che altrettanto
tipicamente, consegnerà al visitatore un cookie per riconoscerlo le volte successive. In questo
blog troviamo un confronto di diverse metodologie di analisi. Un servizio molto diffuso, forse
anche perché gratuito, è quello offerto da Google Analytics (video).
Content Managment Systems
La filosofia del CMS nasce al difuori del web, come una metodologia di lavoro collaborativo
basato sullo scambio e sulla redazione partecipata di documenti. Un approcio simile si è quindi
naturalmente fuso con le possibilità offerte dal web, non ultima quella del telelavoro; inoltre,
mettere un CMS su web significa anche rendere i propri risultati editoriali direttamente
disponibili alla fruizione del grande pubblico. Si può pensare che il CMS sia una delle pietre
angolari di ciò che viene denominato come Web 2.0 (video).
Un CMS web è tipicamente realizzato come una applicazione CGI abbastanza articolata, che
consente l'editing dei contenuti senza richiedere la conoscenza di HTML, CSS, SQL, e dei
linguaggi di scripting, la cui presenza viene nascosta da una funzione di interfaccia utente
realizzata sempre via web. L'aspetto di un CMS-web risulta in genere omogeneo, mentre i
contenuti sono coerenti anche se presentati sotto viste differenti, questo grazie alla adozione di
fogli di stile in comune alle diverse sezioni, ed alla generazione dinamica delle diverse pagine a
partire dalle informazioni memorizzate in unico database. Per contro, la manutenzione di un
CMS-web necessita la definizione di ruoli editoriali precisi, attribuendo ai singoli individui la
gestione di singoli aspetti e/o componenti, nonché dei ruoli di supervisione ed editoriali rispetto
ai contenuti che possono essere incorporati anche da fonti esterne. Nella sezione specifica dei
riferimenti, possiamo trovare i link ai principali CMS esistenti, ed ai siti che li mettono a
confronto. Tra questi, i più diffusi/famosi, sono joomla, mambo, plone, drupal.
A partire dal concetto generale di CMS e dai principi su cui si fonda, nel tempo si sono sviluppate
applicazioni particolari della tecnologia, orientate alla gestione di problemi specifici, e
che offrono supporto ad esigenze particolari. Vediamone alcune.
Blog
Il termine Blog è una contrazione di web log, a sua volta parafrasi di travel log, o libro di bordo.
Infatti, un blog è un CMS, in cui un singolo individuo espone pensieri, riflessioni, punti di vista e
sensazioni, accludendo nel sito contenuti di vario genere, link ad altri siti, e permettendo in
genere ai visitatori, di arricchire l'esperienza di interazione collettiva, mediante l'inserimento di
commenti individuali, trasformando ogni editoriale immesso, nello spunto di discussione di un
forum telematico, con il risultato di misurare il polso dei frequentatori del sito.
Chi voglia dar vita al proprio blog, può rivolgersi a fornitori di questo servizio specifico, che
ospitano siti-blog gratuitamente, oppure installare presso un provider che offre hosting, o su di
una propria macchina in rete, un applicativo apposito, come ad esempio Wordpress, di cui
abbiamo anche un video.
166
Lo strato applicativo di Internet
Alessandro Falaschi
Wiki
Il termine è un a parola
polinesiana che significa veloce,
e chi lo usò per la prima volta
per descrivere una modalità di
editing di pagine web, attuata
mediante il web stesso, lo fece
in seguito al fascino che su di
lui ebbe l'autobus dell'areoporto
di Honolulu, che per l'appunto
per la sua velocità, era
chiamato wiki-wiki.
Sebbene un wiki potrebbe esser
fatto ricadere sotto la categoria
più generale dei CMS, possiede
alcune caratteristiche
particolari, che lo differenziano
in modo unico.
• editing via web - i contenuti possono essere modificati intervenendo direttamente tramite
il browser, dovunque ci si trovi, a partire da un qualunque computer. Può essere presente
una unica password per tutto il wiki, oppure possono essere definiti degli utenti,
eventualmente con privilegi ristretti a solo alcune sotto-sezioni
• metalinguaggio semplificato - le pagine del wiki, pur se visualizzate inviando codice HTML
al browser, sono scritte usando un linguaggio di markup molto semplificato rispetto
all'HTML, consentendo di dedicare più attenzione ai contenuti, che non al markup. La
trasformazione dal markup del wiki all'HTML del browser, avviene per opera del CGI che
implementa il wiki stesso.
• facile creazione di nuove pagine - in ogni pagina creata, possono essere inseriti links a
pagine non ancora esistenti, che sono successivamente visualizzate nel wiki come links ad
una pagina di edit vuota, in modo da poter procedere con lo sviluppo dei contenuti,
rimandando il completamento degli argomenti correlati, ed invogliando a realizzare
pagine corte e dedicate ad un aspetto per volta. Un modo celebre per indicare che una
parola è da intendersi come un link ad una nuova pagina, è il cosiddetto CamelCase,
chiamato così per via della presenza di due lettere maiuscole, che ricordano la sagoma di
un cammello: la sequenza in CamelCase costituirà quindi il nome della nuova pagina. Dato
che questo modo di procedere può divenire una limitazione, esistono modi diversi per
indicare un hyperlink interno al wiki, come ad esempio, racchiudere il nome della pagina
tra parentesi quadre doppie, come ad esempio fa MediaWiki, il motore di Wikipedia.
• reversibilità delle modifiche - se da un lato l'apertura del wiki ad accogliere contributi
provenienti da diverse fonti, migliora la qualità finale dei suoi contenuti, da un'altra
parte, espone il sito ad accogliere informazioni errate, oppure peggio ancora, a subire atti
di sabotaggio e/o vandalismo. Per questo, un wiki mantiene memoria di tutte le modifiche
effettuate ad ogni sua pagina, permettendo di evidenziare la sola parte modificata, per
meglio valutarne la congruità. Allo stesso tempo, le modifiche possono essere annullate, e
la pagina riportata allo stato in cui appariva prima dell'ultima (la penultima, etc etc)
modifica.
• ricerca nel sito - quasi sempre, in un wiki esiste la possibilità di immettere una parola
chiave, e localizzare le pagine dove questa compare.
A queste caratteristiche se ne aggiungono altre, come
• i wiki adottano fogli di stile che rendono l'aspetto della pagine uniformi tra loro,
riducendo ancora di più il tempo da dedicare agli aspetti estetici,
167
Content Managment Systems
World Wide Web
• spesso i motori wiki sono corredati da una serie di estensioni che ne potenziano le
funzioni, integrando anche caratteristiche più propriamente legate ai CMS propriamente
detti, ai blog, ai forum, ai repository, alla documentazione, ai feed RSS,
al punto che, al di là dell'approccio collaborativo, le caratteristiche esposte sono ben utili anche
nel caso in cui il sito sia mantenuto da una persona sola, oppure da un gruppo di persone che
sono coinvolte in un progetto comune, come ad esempio lo sviluppo di un sofware open source
(es con trac), per il quale non valga la pena di progettare un nuovo sito ad-hoc.
Anche in questo caso, chi voglia sviluppare il proprio wiki, può rivolgersi ad una wiki farm (es:
wikia) che offre ospitalità, oppure installare in proprio uno dei motori esistenti.
Feed RSS e Atom
Attualmente (nella versione 2.0) RSS è l'acronimo di Really Simple Syndacation, anche se in tempi
non troppo lontani, ha avuto anche il significato di Rich Site Summary (ver 0.91) e RDF Site
Summary (ver 0.9 ed 1.0). Consiste in un dialetto dell'XML, orientato alla descrizione dei
contenuti di un sito web, e da questo punto di vista deve molto alle sue origini, legate alle
definizione di metadata e RDF. Un esempio di RSS 2.0 è fornito da wikipedia, ed è riportato
appresso:
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>Liftoff News</title>
<link>http://liftoff.msfc.nasa.gov/</link>
<description>Liftoff to Space Exploration.</description>
<language>en-us</language>
<pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate>
<lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>Weblog Editor 2.0</generator>
<managingEditor>[email protected]</managingEditor>
<webMaster>[email protected]</webMaster>
<item>
<title>Star City</title>
<link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>
<description>How do Americans get ready to work with Russians aboard the
International Space Station? They take a crash course in culture, language
and protocol at Russia's Star City.</description>
<pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
</item>
<item>
<title>Space Exploration</title>
<link>http://liftoff.msfc.nasa.gov/</link>
<description>Sky watchers in Europe, Asia, and parts of Alaska and Canada
will experience a partial eclipse of the Sun on Saturday, May 31st.</description>
<pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>
</item>
<item>
<title>The Engine That Does More</title>
<link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
<description>Before man travels to Mars, NASA hopes to design new engines
that will let us fly through the Solar System more quickly. The proposed
VASIMR engine would do that.</description>
<pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/2003/05/27.html#item571</guid>
</item>
<item>
<title>Astronauts' Dirty Laundry</title>
<link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link>
<description>Compared to earlier spacecraft, the International Space
168
Lo strato applicativo di Internet
Alessandro Falaschi
Station has many luxuries, but laundry facilities are not one of them.
Instead, astronauts have other options.</description>
<pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>
<guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid>
</item>
</channel>
</rss>
Come si vede, l'XML di un RSS è strutturato in modo da racchiudere, nel contesto di un
<channel>, caratterizzato da un insieme di elementi validi per tutti i diversi contentuti di un
canale, le descrizioni associate a diversi <item>, fornendo per ciascuno di essi, un'altra serie di
elementi che permettono sia di accedere alla pagina web dove è effettivamente esposto
l'argomento, sia di descrivere il contenuto in forma sintetica, in modo da permettere a chi legge,
di valutare il suo interesse.
I documenti XML che descrivono un feed RSS sono prelevabili (con Mime-Type
application/rss+xml) da siti web (es Repubblica, Punto Informatico) che
espongono il logo mostrato a lato, da parte di programmi detti feed reader (anche se i
moderni browsers e client email sono egualmente all'altezza), che consentono di
tenere sott'occhio (prelevandoli dalle rispettive fonti) in modo uniforme i feed RSS di diversa
provenienza (video). Un approccio simile ma diverso, è quello degli aggregatori, che pure
raccolgono i feed RSS provenienti da fonti diverse, ma li compongono a formare una nuova
pagina web, i cui contenuti hanno origine a partire dai diversi feed a cui l'aggregatore è iscritto.
La pagina web contenente l'aggregatore, può essere personalizzata in associazione all'identità di
un utente autenticato del sito web, come ad esempio accade con Bloglines, MyYahoo,
YourLiveWire, Google Reader, ovvero quelli riportati da newsonfeed.
Un diverso formato dei feed è denominato Atom, che gode del riconoscimento ufficiale della RFC
4287 di IETF, e che nasce a seguito dell'insoddisfazione relativa ai diversi formati incompatibili
esistenti per RSS. Una ulteriore RFC 5023 definisce poi l'Atom Publishing Protocol, basato su
HTTP, che stabilisce le modalità di pubblicazione e recupero degli oggetti Atom.
Podcast
Questo termine nasce dalla contrazione (o dalla sinergia?) tra l'iPod di Apple, ed il broadcasting,
anche se ha ben poco a vedere con entrambi. Si tratta della ricezione in differita di contenuti
multimediali (audio, video) preregistrati, ed annunciati per mezzo di feed RSS o Atom. Chi si
iscrive al feed, lascia che il suo podcast-reader (come iTunes) verifichi se ci sono novità, ed in tal
caso le scarichi, permettendo di ascoltare/vedere i nuovi contenuti in un secondo tempo.
In RSS 2.0 il podcast è abilitato dalla definizione dell'elemento <enclosure>, che consente di
specificare la URI del contenuto multimediale, la sua dimensione in byte, ed il MIME-Type
associato al file. In Atom, viene usato allo stesso scopo il termine enclosure, come possibile
valore dell'attributo rel (che sta per relazione) dell'elemento link.
Content Delivery Network
Questo termine può essere tradotto come rete di consegna dei contenuti, e descrive una filosofia
che si discosta dal tradizionale approccio client-server, e utilizza la rete Internet come una
infrastruttura globale su cui edificare una rete sovrapposta di elementi di replica, in grado di
offrire gli stessi contenuti disponibili su di un server specifico. In questo modo, il client potrà
recuperare la copia dell'oggetto richiesto, direttamente presso l'elemento di replica a lui più
prossimo, evitando di sovraccaricare la rete internazionale di transito con richieste spesso uguali,
169
Content Delivery Network
World Wide Web
e provenienti da client topologicamente vicini tra loro.
Sebbene questa illustrata possa sembrare la classica funzione da far svolgere ad un elemento
proxy, in questo caso i contenuti da replicare in prossimità del client non sono qualsiasi, ma sono
solo quelli per i quali è previsto il servizio. Questa esigenza è particolarmente sentita nel caso di
contenuti per i quali si può sviluppare un volume di richieste molto elevata, concentrata in un
periodo di tempo molto breve, come nel caso, ad esempio, di un lancio pubblicitario televisivo,
oppure per contenuti audio-video erogati in diretta.
Mirror e Geolocation
Un esempio di CDN è la rete di mirror che sono proposti come siti alternativi da cui scaricare un
determinato contenuto, e predisposti da organizzazioni come sourceforge. Nella sua forma più
basilare, al client che richiede il download di un contenuto viene visualizzata una pagina, in cui
si offre di scegliere tra un elenco di siti alternativi per il download. Attualmente, si tende ad
evitare che il client bebba scegliere di sua iniziativa, proponendo direttamente una scelta
determinata dall'esito di servizi di geolocalizzazione basati su di una mappatura approssimata
associata all'indirizzo da cui proviene la richiesta, come ad esempio quelli offerti da Maxmind.
Gli elementi di una CDN
Come già fatto notare, delegare la consegna all'utente finale dell'oggetto richiesto a dei
dispositivi di replica, è molto simile a quello ottenibile mediante dei proxy, che intercetta la
richiesta originaria perché si trova sul suo stesso percorso, oppure che è esplicitamente
designato dal client a svolgere il rulo di proxy. In una CDN invece, si tenta di instradare la
richiesta stessa del client, verso l'elemento di replica più idoneo (ossia più prossimo al client),
che si occuperà quindi di servirla.
Presso wikipedia troviamo una breve panoramica della problematica, la RFC 3568 illustra alcuni
metodi comunemente in uso, e presso globule troviamo una trattazione assai più approfondita.
Ma in linea di massima, il funzionamento di una CDN può essere decomposto nelle seguenti parti:
• i dispositivi di consegna dei contenuti: l'insieme degli elementi di replica, detti surrogati,
in grado di consegnare copie dei contenuti, ad insiemi di utenti;
• una infrastruttura di distribuzione: è il meccanismo che sposta i contenuti dal server di
origine ai surrogati, e deve essere specificato in termini di
• advertising - ogni surrogato deve comunicare alla infrastruttua di instradamento
della richiesta, informazioni relative al suo stato, e chi intende servire
• replica - il modo con cui i contenuti si propagano tra surrogati;
• segnalazione - la consegna da nodo a nodo deve essere coordinata a seguito della
decisione presa dalla funzione di instradamento della richiesta
• un sistema di instradamento della richiesta: si tratta del meccanismo che guida il client
verso un appuntamento con il server di replica. Sussistono almeno due approcci
diversi, quello basato sulla infrastruttura di rete, come la redirezione DNS e gli switch a
livello applicativo, e quello basato su soluzioni a livello applicativo, come nel caso
discusso tra breve. Oltre a chi fa cosa, occorre però definire anche come lo fa, ovvero, in
base a quale metrica viene deciso il miglior server da utilizzare, e come calcolare questa
metrica.
Approccio basato sul DNS
E' il sistema di instradamento della richiesta adottato (più o meno) da Akamai, che gestisce
un folto insieme di surrogati, dispegati per i quattro angoli del pianeta, e che rivende l'uso del
170
Lo strato applicativo di Internet
Alessandro Falaschi
servizio a chi intende farne uso. Il suo utilizzo si basa nell'identificare l'indirizzo applicativo
dell'ogetto da distribure con un nome a dominio appartenete al domioni di cui Akamai è
autorevole. Quando un client ne farà richiesta, il DNS autorevole di Akamai risolve l'indirizzo
applicativo dell'oggetto, con l'indirizzo IP associato all'elemento di replica più prossimo al client,
in base alla conoscenza dell'indirizzo IP del DNS a cui il client ha inoltrato la richiesta di
risoluzione originaria. Ognuo dei surrogati, quindi, dovrà identificare la copia dell'oggetto
mediante la medesima sezione path della URI che lo identifica.
Approccio basato sul livello applicativo
In questo caso, l'instradamento della richiesta è attuato dal portale a cui si rivolge il client, in
base all'indirizzo IP del client stesso, noto al portale al momento della ricezione della richiesta.
Dopo aver inoltrato questa informazione alla entità di gestione della CDN, in modo che questa
individui il nodo di replica più idoneo per quel client, il portale risponde alla richiesta, indicando
la URI relativa alla copia dell'oggetto localizzata presso il surrogato indicato dall'entità di
controllo.
171
Content Delivery Network
World Wide Web
Multicast, una soluzione mancata
Un esempio in cui la
realizzazione di un
servizio non può
prescindere
dalla esistenza di una
adeguata CDN
progettata allo
scopo, è quello della
distribuzione su scala
globale (a più
centinaia di miloni di
fruitori) di un
contenuto multimediale mediante Live Streaming, ossia dell'equivalente di una diretta TV, per il
quale è materialmente impossibile replicare il contenuto, che viene generato in tempo reale a
partire da una sorgente multimediale.
In tal caso infatti, se ci fosse solo un unico server ad erogare i contenuti verso tutti i player,
questo dopo qualche migliaio di connessioni, inevitabilmente saturerebbe a la propria banda di
uscita, rendendo matematicamente impossibile raggiungere bacini di audience dell'ordine dei
milioni di persone, come è invece possibile con le trasmissioni radio.
Una soluzione a questo problema in realtà esisterebbe, ed è quella basata sulla modalità di
istradamento multicast, che è in grado di individuare un albero di distribuzione dei contenuti,
basato sulla replica da parte dei router di Internet dei pacchetti in arrivo, verso ognuna delle
diverse destinazioni (reti) in uscita, presso le quali è noto che ci siano ricevitori attivi.
Alcune considerazioni, hanno ostacolato l'interconnessione dei protocolli di routing multicast
tra ISP differenti, e reso non percorribile questo approccio.
Volendo illustrare in due parole (superficiali, approssimate) il funzionamento del multicast, si
172
Lo strato applicativo di Internet
Alessandro Falaschi
può dire che si basa sull'uso di un particolare gruppo di indirizzi IP (contenuti nel prefisso
224.0.0./8) non assegnabili a singoli computer. Invece, una applicazione può aprire un socket in
ascolto su di un indirizzo multicast (ora chiamato gruppo), provocando l'effetto che il kernel usi
l'IGMP per contattare il default gateway, notificandogli l'intenzione di ricevere i pacchetti IP
destinati a quel gruppo. Quindi, un protocollo di routing (se abilitato) provvede a propagare tra i
router di Internet l'informazione che qualcuno è in ascolto per quel gruppo, in modo che questi
memorizzino, per ogni gruppo, su quali interfacce si è manifestato interesse per la ricezione. A
questo punto, se un computer inizia a trasmettere pacchetti che hanno il gruppo come
destinazione, questi vengono inviati dal suo default gateway (se partecipante al
routing multicast) verso le interfacce di uscita dalle quali è arrivata la notizia che più giù
qualcuno li vuole: lo stesso avviene anche per gli altri ruoter, e voilà! si realizza così un diverso
albero di distribuzione, per ogni sorgente attiva. Notiamo ora due cose:
• la distribuzione multicast così definita, è bidirezionale, ed un host può decidere se
ricevere, inviare, od entrambe le cose, e
• il protocollo di trasporto deve necessariamente essere UDP, non potendo la sorgente
gestire i riscontri prevenienti da tutti i destinatari.
Overlay networks
Dato che i nodi
replica di una CDN
sono sparsi in giro
per Internet, e che i
contenuti possono
essere distribuiti tra
gli stessi, quel che si
ottiene è una sorta
di rete sovrapposta
(Overlay Network),
che sfrutta i
collegamenti di
Internet per
permettere lo
scambio dei
contenuti tra i nodi
dell'Overlay. Dato
che il risultato
finale, più o meno,
può permette di realizzare ciò che il multicast ha promesso ma non mantenuto, questa
architettura viene spesso indicata come Application Level Multicast, od Overlay Multicast.
La differenza tra questi ultimi due termini, risiede nel fatto che con ALM si indica il caso in cui i
nodi dell'Overlay sono realizzati dagli stessi computer situati presso gli utenti finali: per questo
motivo, un ALM viene anche indicato come End Sytems Multicast. Il risultato, è che la
distribuzione ottenibile è caratterizzata da una topologia spesso molto lontana dal caso ideale;
inoltre, anche con le attuali conessioni ADSL a banda larga, la velocità dell'UpLink è in generale
molto ridotta, al punto da porre un serio limite al numero di flussi uscenti da uno stesso nodo. Al
contrario, il termine Overlay Multicast è usato per identificare il caso in cui i nodi dell'overlay
sono disposti direttamente nella core network, dunque sotto il coordinamento degli stessi ISP,
permettendo di realizzare un albero di distribuzione molto più efficente, e con fan-out di uscita
per ogni nodo, in grado di limitare di molto la profondità dell'albero di distribuzione.
Data l'importanza dell'argomento per lo sviluppo di internet in campo telemediale, si è formato
173
Web Service
World Wide Web
un gruppo di lavoro IRTF, SAMRG (Scalable Adaptive Multicast Research Group), nei cui atti del
66o meeting IETF, troviamo una interessante survey sull'argomento.
Reti Peer to peer
Un caso particolare di Overlay Network, è quello realizzato da molte applicazioni di file sharing
cosiddette peer-to-peer, denominate così perché mettono tutti i partecipanti su di uno stesso
piano (video). Durante l'anno accademico 2006-2007, alcuni studenti di questo corso si sono
impegnati nello svolgere delle tesine al riguardo; probabilmente però, può essere più utile
approfondire gli aspetti delle diverse architetture, leggendo direttamente i riferimenti più o
meno ufficiali, raggiungibili a partire da una tabella comparativa di protocolli ed
applicazioniesistenti. In termini molto generali, le reti p2p sono caratterizzate dalla adozione di
un metodo di indirizzamento di strato applicativo autonomo, indipendente dal DNS, e si
distinguono tra loro in base ai metodi utilizzati per risolvere una serie di problemi:
• come identificare i contenuti disponibili e desiderati;
• come pubblicare la disponibilità dei propri contenuti;
• come effettuare la ricerca dei contenuti desiderati: in questo caso, possiamo distinguere
in base a
• meccanismi per così dire ciechi, in cui le richieste si propagano per inondazione
(flooding);
• meccanismi basati su criteri metrici e/o di indicizzazione, come per le distributed
hash table (DHT);
• come organizzare la collaborazione tra i nodi che possono offrire il contenuto;
• come effettuare il recupero di un contenuto.
Inoltre, le reti peer to peer possono essere classificate in base alla loro topologia, come
• reti pure, in cui non esistono nodi di controllo centralizzato, come Gnutella, Freenet, Kad,
CAN;
• reti centralizzate, in cui pur se i contenuti sono scambiati direttamente tra i peer, esiste
un nodo speciale che svolge la funzione di directory, come Napster, eDonkey, BitTorrent;
• reti ibride, in cui pur non essendoci un unico server centrale, alcuni nodi detti supernodi
assumono un ruolo privilegiato rispetto ad altri, come ad es. FastTrack (usato da Kazaa),
JXTA.
Web Service
E' il nome dato ad una metodologia di esecuzione di applicazioni remote, che fa uso di HTTP
come strato di trasporto per il recapito delle invocazioni, per il passaggio dei parametri, e per la
ricezione dei risultati. Benchè l'invocazione di applicazioni remote non contenga assolutamente
nulla di nuovo, rispetto alle preesistenti metodologie di elaborazione distribuita, i Web
Service hanno dalla loro la possibilità di far tesoro delle esperienze preesistenti, possiedono una
minore cripticità dovuta al formato testuale delle comunicazioni, e godono di una universalità di
accesso, legata all'uso della porta 80, riuscendo in tal modo a scavalcare i problemi legati ai
firewall. Per certi versi, si tratta di una evoluzione della logica dei CGI, a cui è stata aggiunta
una formalizzazione più stringente per quanto riguarda il meccanismo di passaggio dei parametri,
e dei meccanismi di auto-documentazione dei servizi offerti. Inoltre, mentre i CGI sono pensati
per essere invocati da parte di un interattore umano che opera dietro la finestra di un browser
web, i Web Service sono pensati per essere utilizzati da parte di procedure software.
174
Lo strato applicativo di Internet
Alessandro Falaschi
Elaborazione distribuita
Come accennato, il desiderio di definire un metodo che permetta a programmi in esecuzione su
computer differenti, con sistemi operativi differenti, di cooperare, ripartendosi il carico
computazionale, ed offrendo ognuno la propria tipologia particolare di servizi, nasce assieme ai
computer ed alle reti dati.
In linea generale, l'elaborazione distribuita è realizzata dopo aver definito un protocollo di
comunicazione tra chi usa e chi offre il servizio, con una sua propria sintassi, una sua macchina a
stati, una porta ben definita su cui comunicare, un metodo di codifica dei dati indipendente
dalla architettura delle entità coinvolte... tutte problematiche analizzate e discusse,
praticamente fin dall'inizio del corso. La differenza maggiore è che, mentre le soluzione discusse
fin'ora miravano ognuna a risolvere un particolare problema, una architettura di elaborazione
distribuita vuole permettere l'invocazione di programmi qualunque.
Le soluzioni a questo problema, sono a volte indicate con il temine di middleware, intendendo
dire che si tratta di sofware che giace tra il livello applicativo, e quello di rete. Nel corso della
storia precedente e/o parallela al web, si sono succedute diverse iniziative in tal senso, tra cui
possiamo citare:
RPC
Il termine Remote Procedure Call rende bene l'idea di ciò che si vorrebbe ottenere, ed il suo
primo uso risale al 1976, quando fu menzionato nella RFC 707. L'implementazione più celebre
di RPC è stata quella della Sun, chiamata ONC RPC: è basata sullo scambio di messaggi, serializza
i dati mediante XDR, utilizza sia UDP che TCP, ed è alla base del metodo di condivisione files
NFS. L'accesso ai servizi offerti via RPC è attuato attraverso un demone port mapper, che si pone
in ascolto sulla porta ben nota 111 (TCP e UDP), e svolge il ruolo di multiplare le richieste di
esecuzione remota, mediante un numero di programma, che è contenuto nella invocazione
remota per identificare il servizio richiesto, e per il quale (numero), il programma (es. NFS) che
intende offrire quel servizio, si registra. L'uso di RPC ed NFS è tuttora molto diffuso,
prevalentemente in ambito di rete locale.
CORBA
La Common Object Request Broker Architecture è definita dall'Object Management Group come
un metodo che abilita alcuni componenti software scritti in linguaggi diversi, in esecuzione su
computer diversi, a lavorare assieme. Si basa sul concetto di interface definition language (IDL),
che specifica le interfacce che gli oggetti presentano al mondo, mentre CORBA
specifica un mapping da IDL ai diversi specifici linguaggi di programmazione. Nonostante la sua
definizione risalga ai primi anni '90, a tutt'oggi non è riuscito ad affermarsi, ed alcune critiche
alla sua impostazione non hanno trovato risposta.
RMI
La Remote Method Invocation pone l'accento sulla filosofia ad oggetti (in opposizione a quella di
chiamata a procedura di RPC), che determina l'interazione con oggetti remoti mediante
l'invocazione di metodi. La RMI consente ad un codice Java (a cui è indissolubilmente legata) di
invocare l'esecuzione di un metodo offerto da un oggetto remoto, quasi come se fosse locale.
175
Web Service
World Wide Web
DCOM
Una implementazione alternativa ad RPC, è stata il Network Computing System (NCS) da parte di
Apollo Computer, che venne successivamente usato come la base per il DCE/RPC nel Distributed
Computing Environment di OSF. Un decennio più tardi, Microsoft adotta DCE/RPC come base per
il suo MSRPC, su cui fonda DCOM. Quest'ultima, è stata la risposta di Microsoft a CORBA, anche se
attualmente, gli stessi scopi sono invece perseguiti con l'architettura .NET.
ActiveX e .NET
Sono le due tecnologie con cui Microsoft risponde alle esigenze di elaborazione distribuita,
tranne che... non sono aperte ad architetture differenti!
SOAP
Il Simple Object Access Protocol è un framework che permette l'invocazione di procedure remote
mediante lo scambio di messaggi in formato XML, trasportati tipicamente su connessioni HTTP.
La struttura dei messaggi segue il paradigma Head-Body, in cui gli Header
contengono meta-informazioni riguardanti il routing, la sicurezza e le transazioni, mentre il Body
trasporta il contenuto informativo.
I protocolli degli Web Sevices, oltre a prevedere SOAP come
meccanismo per inviare i messaggi di esecuzione remota,
prevedono l'esistenza di altri protocolli, come il Web
Services Description Language (WSDL), che descrive come
interagire con un determinato servizio, indicando i metodi
messi a disposizione, i suoi vincoli (protocollo, formato dei
parametri di ingresso e delle risposte), ed il suo punto di
accesso, ovvero l'URI del Web Service. Come mostrato in
figura, il fornitore del servizio pubblica presso un Service
Broker (strutturato in accordo a UDDI) la descrizione della
propria offerta, in modo che questo possa
essere successivamente interrogato da un potenziale
richiedente, che individua così chi offre il servizio di cui ha
bisogno, e quindi lo istanzia per mezzo di messaggi SOAP. Presso wikipedia, è mostrato un
semplice esempio di transazione SOAP.
XML-RPC
Prima che venisse definito SOAP, WSDL e UDDI, un certo Dave Winer (sì, lo stesso che ha definto
l'RSS 2.0) aveva già completato la definizione di una specifica, chiamata XML-RPC, per svolgere
né più né meno la funzione di invocare l'esecuzione remota di una applicazione, incapsulando la
richiesta in HTPP, inviare parametri comunque complessi mediante una rappresentazione XML,
e ricevere in risposta strutture dati egualmente complesse. In effetti, fu proprio questa
specifica, che poi diede il via ai lavori di definizione di SOAP.
176
Lo strato applicativo di Internet
Alessandro Falaschi
Nel caso in cui,
molto
semplicemente,
sussista
unicamente
l'esigenza di
invocare
delle procedure
remote, e non
ci si voglia stare
a preoccupare
molto di
definire un
nuovo
protocollo per
gestire il
passaggio dei parametri, la soluzione di utilizzare una delle tante librerie che si occupano della
serializzazione dei dati in XML, del loro invio in HTTP, e della formattazione inversa dall'altro
lato del collegamento, sembra essere quella meno impegnativa.
Presso wikipedia, possiamo trovare una tabella riassuntiva della formattazione necessaria ai
diversi tipi di dato, assieme ad alcuni esempi di transazione XML-RPC.
Mashup
Mentre questo termine, nella musica hip-hop, individua un brano realizzato ri-mixando assieme
diversi brani preesistenti, nel Web un Mashup è una applicazione distribuita che utilizza
informazioni raccolte da siti diversi, per combinarle assieme e realizzare così un nuovo servizio
(video). Le informazioni possono essere raccolte ad es. mediante feed RSS, Web Services, API
pubbliche. Il codice software che realizza il mashup viene tipicamente distribuito tramite il sito
che ospita il servizio, ed eseguito presso il browser dell'utente, come ad esempio è il caso di
Twittervision, che usa le API di Twitter e Google Maps, per localizzare in diretta la provenienza
degli inserimenti su Twitter.
Web Semantico
Il Web tradizionale non prende in considerazione la struttura ed il significato del contenuto delle
pagine servite: ad esempio, per un qualsiasi motore di ricerca, non esistono differenze tra il
termine Rossi nel contesto Il Sig. Rossi ed il termine Rossi nel contesto Capelli Rossi. Per
strutturare meglio i contenuti, sono allora stati definiti alcuni linguaggi, quali Resource
Description Framework (RDF) e Web Ontology Language (OWL), entrambi basati su XML, che
consentono di esprimere le relazioni tra le informazioni rifacendosi alla logica dei predicati
mutuata dall'intelligenza artificiale.
•
•
•
•
•
Web Semantico - su Wikipedia
semedia - presso DEIT, Dipartimento Università Politecnica delle Marche
web:semantico - a cura dell'Osservatorio sulla Comunicazione
L'architettura del Semantic Web di Paolo Ceravolo
Video
• Ben Hammersly (2004)
• Sir Tim Berners-Lee (2007)
• Knowledge Representation and the Semantic Web (2006)
177
Riferimenti
World Wide Web
Riferimenti
• Guide di HTML.it
• HTML di Wolfgang Cecchin
• XML di Andrea Chiarelli
• XHTML di Cesare Lamanna
• CSS
• Aggiungere un tocco di stile di Dave Raggett
• CSS di base di Cesare Lamanna
• tabelle di riferimento per le proprietà CSS
• presso w3school
• presso tizag
• presso stylegala
• Template di stile
• WebShapes - una risorsa a contribuzione libera, con sezioni orientate a Drupal,
Wordpress e menù css
• Open Source Web Design - una collezione di progetti web donati al pubblico
• Open Web Design - una comunità di progettisti di siti che condividono i loro
template.
• Esecuzione lato client
•
•
•
•
•
Guida JavaScript di base - di Ilario Valdelli
Guida JavaScript per esempi - di Wolfgang Cecchin
Esempi Javascript presso w3schools
OpenAJAX white paper (in italiano)
Guida AJAX - di Andrea Giammarchi
• CGI
• CGI Resource Index
• Ovid's CGI Course
• HTML Writers Guild
• CMS e wiki
•
•
•
•
OpensourceCMS - permette di sperimentare diversi CMS senza installarli
AllScriptsDemo.com - come sopra
elenco di CMS - su wikipedia ci sono tutti i links ai CMS esistenti, free e commerciali
CMS Matrix - permette di confrontare testa-a-testa le caratteristiche offerte da
svariati CMS
• elenco dei wiki - Sempre su wikipedia, sono confrontati anche i wiki
• WikiMatrix - confronto testa-a-testa dei diversi motori wiki
• RSS e Podcast
•
•
•
•
•
Introduzione a RSS di Cesare Lamanna
Guida podcasting di Mirko Corli
Making a podcast - da Apple.com
Feedvalidator.org
RDS Morning Show
• Corso di Applicazioni Telematiche - Prof. Roberto Canonico, Università di Napoli
• Sistemi peer-to-peer di Leonardo Querzoni, connesso al corso di Sistemi Distribuiti e (1, 2)
e seminari
178
Lo strato applicativo di Internet
Realizzato con
Alessandro Falaschi
da Alessandro Falaschi - ultimo aggiornamento: Febbraio 2008
179
Lo strato applicativo di Internet
Voice over IP
All'inizio di questo corso, si è fatto notare come la trasmissione a pacchetto dei dati,
caratteristica della rete Internet, si pone in diretta contrapposizione con le reti a commutazione
di circuito, tipiche delle reti telefoniche nate per la trasmissione vocale. Ciononostante, a
seguito dello sviluppo di Internet, della banda disponibile, e della velocità dei nodi di
commutazione, la trasmissione vocale è divenuta possibile (e di fatto, estensivamente praticata)
anche su reti a pacchetto, e che nel caso di reti IP, prende il nome di Voice over IP (VoIP).
• Evoluzione storica
• Elementi architetturali
•
•
•
•
•
User Agent
Registrar
Proxy
Gateway
Servizi aggiuntivi
• Session Initiation Protocol
• Messaggi
• Sintassi
• Trasporto
• Macchina a stati
•
•
•
•
Richieste
Metodi
Status Line
Intestazioni
• Stratificazione di SIP
• Sessione, dialogo e transazione
• Transazione
• Dialogo
• Sessione
• Autenticazione
• Federazione
• Instradamento
• Route Set
• Loose routing
• Procedure
• Registrazione, service discovery, e autenticazione
• Invito, creazione del dialogo e route set
• Session Description Protocol
•
•
•
•
Contesti di utilizzo
Sintassi e sezioni
Elementi
Offerta e risposta
Lo strato applicativo di Internet
Alessandro Falaschi
• Creazione della risposta
• Ricezione della risposta
• Modifica della sessione
• Esempio
• Real Time Protocol
• Qualità, ritardo, jitter e buffer di riproduzione
• Unità dati applicative
• Pacchettizzazione
• Sincronizzazione
• Intestazioni
• Audio Video Profile
• Payload statici e dinamici
• Real Time Control Protocol
• Attraversamento NAT e Firewall
• Firewall
• NAT
• Tipi di NAT
• UDP Hole Punching
• SIP Keep Alive
• RTP simmetrico
• Uso di dispositivi esterni
• Session Border Controller o B2BUA
• STUN
• TURN e ICE
• Riferimenti
Evoluzione storica
Per molti, le telefonate Internet sono automaticamente associate all'uso di Skype, che gode di un
particolare successo di diffusione e di immagine, ma i cui protocolli operativi sono proprietari e
quasi sconosciuti. D'altra parte, la possibilità di usare le reti per dati anche a scopi di
trasmissione vocale, è stata a lungo inseguita dagli operatori telefonici tradizionali, prima
offrendo un accesso numerico con ISDN, poi integrando la trasmissione di voce e dati su di una
stessa rete ATM. Al punto che in sede ITU fu standardizzata una famiglia di protocolli aperti ed
interoperabili, l'H.323, orientata ad offrire servizi multimediali su reti a pacchetto, facilitando
allo stesso tempo l'interoperabilità con le reti a circuito preesistenti. Nel frattempo, il WG
MMUSIC di IETF stava procedendo a investigare le modalità di realizzazione di servizi
multimediali (come videoconferenze e streaming) su rete Internet, definendo
• il controllo di una sorgente multimediale mediante il Real Time Streaming Protocol
(RTSP),
• la sintassi di descrizione delle modalità di codifica e trasmissione per dati multimediali,
mediante il Session Description Protocol (SDP), e
• il formato di pacchettizzazione per la trasmissione dei dati multimediali, mediante il Real
Time Protocol (RTP).
Da un lato, l'ITU adottò e fece proprie alcune scelte di IETF, incorporando il trasporto RTP in
H.323; da un altro canto lo scenario preconizzato da IETF, che prevedeva la diffusione globale
dell'instradamento multicast, venne in parte a decadere. Allo stesso tempo, i meccanismi previsti
dall'H.323 si rivelarono piuttosto macchinosi, a causa del tentativo di replicare su Internet i
181
Voice over IP
meccanismi di segnalazione SS7 preesistenti sulle reti a circuito. Fu a questo punto, che venne
definito in sede IETF un nuovo protocollo di segnalazione, il Session Initiation Protocol (SIP), in
grado di declinare le funzioni di controllo chiamata adottando messaggi testuali in stile SMTP e
HTTP, e di integrarsi armonicamente con le funzioni già assolte da SDP e RTP.
Al giorno d'oggi, mentre sono tuttora in uso dispositivi (MCU) di videoconferenza basati su H.323,
praticamente ogni operatore che intende offrire un servizio VoIP si basa sulla adozione di SIP, al
punto che questo è anche alla base dello sviluppo dell'IP Multimedia Subsystem (IMS) che
costituisce l'architettura per la fornitura dei servizi multimediali offerti dagli operatori di
telefonia mobile di terza generazione (3G).
Elementi architetturali
La tecnologia VoIP SIP si basa sulla
definizione di una serie di elementi
User Agent
Abbreviato come UA, è il dispositivo
mediante il quale gli umani possono
comunicare: in questo senso, è l'analogo
del tradizionale telefono, con la
differenza che mentre un telefono è
associato ad un determinato numero,
legato alla presa telefonica od alla SIM
del cellulare, uno UA viene configurato per corrispondere ad una URI simile a quella di una
email, come ad esempio sip:[email protected], che è proprieta dell'utente, dovunque egli la
usi, permettendone la mobilità.
La parte di URI nome_utente@dominio_voip viene indicata come Address of Record (AoR),
e rappresenta l'identità di una persona fisica, immutabile e indipendente dalla posizione
effettiva dell'individuo nella rete, e dal dispositivo usato per collegarsi. Uno UA può essere
realizzato mediante
• una applicazione eseguita su di un computer (softphone), oppure
• un dispositivo del tutto simile ad un telefono fisso (telefono VoIP), ma connesso ad
Internet (eventualmente, anche in modalità Wireless, come nel cordless VoIP) anziché alla
PSTN, oppure
• una applicazione in eseguita su di un telefono mobile capace di connessione dati (GPRS o
UMTS);
Dato che una chiamata che ha
origine da uno UA, viene
terminata su di un altro UA,
questo può pensarsi scomposto in
due componenti:
• uno User Agent Client
(UAC), che si attiva per
l'invio di messaggi di uscita,
come ad esempio nel caso
di una chiamata uscente, e
riceve le relative risposte;
182
Lo strato applicativo di Internet
Alessandro Falaschi
• uno User Agent Server (UAS), che rimane in ascolto dei messaggi in ingresso, come nel
caso di una chiamata entrante, ed invia le relative risposte.
Per questo motivo, il VoIP non viene classificato come un protocollo Client-Server, ma Peer to
Peer;
Registrar
E' l'elemento a cui uno UA comunica (registra) l'indirizzo IP (indicato anche come Contact
Address) da associare all'AoR, e che memorizza questa informazione presso un entità di
memorizzazione indicata come Location Server. Il Registrar viene amministrato dal fornitore di
servizio (provider) VoIP che ha rilasciato l'AoR all'utente, e che amministra il DNS autorevole per
il nome a dominio che compare nell'AoR.
Un Registrar è l'analogo di un server SMTP di destinazione, con la differenza che mentre le email
in arrivo si fermano lì, quando una chiamata VoIP entrante raggiunge il Registrar, questa viene
immediatamente inoltrata verso il Contact Address che è stato registrato in corrispondenza
dell'AoR, supportando così la mobilità dell'utente, e l'uso di indirizzi IP dinamici, come nel caso di
una connessione on-demand. Spesso, l'entità che ospita il Registrar è la stessa che ospita anche
un elemento Proxy.
Diversi UA possono
registrare diversi
Contact Address per
uno stesso AoR, ed in
questo caso la
chiamata entrante per
un AoR, viene inoltrata
a tutti i Contact
Address associati,
provocando il forking
del controllo, in modo
da far squillare tutti gli
UA presso cui può
trovarsi il chiamato.
Proxy
E' un elemento che ha
la capacità di inoltrare i messaggi SIP, ed in questo senso, si può pensare al suo ruolo, come per
certi versi simile a quello di un router di livello applicativo. Un classico esempio di utilizzo, è
quello in cui uno User Agent gli consegna la propria chiamata (uscente), facendogli assumere un
ruolo analogo a quello di un server SMTP di uscita: in questo caso, il proxy prende il nome di
Outbound Proxy.
Tra le prerogative di un Proxy, possiamo elencare quelle di
• gestione di diversi tipi di politiche (policy), come
•
•
•
•
•
di autenticazione e autorizzazione,
controllo di accesso,
tariffazione,
instradamento
controllo della qualità del servizio;
• possibilità di inoltrare la chiamata, anziché al Registrar di destinazione, verso un ulteriore
Proxy di Transito, o verso un Gateway;
183
Elementi architetturali
Voice over IP
• capacità di deviare la chiamata, comportandosi come un Redirect Proxy, rispondendo con
un messaggio in cui viene specificato un diverso Proxy a cui inoltrarla;
• funzionamento in modalità stateless, ossia senza conservare traccia dei messaggi già
inoltrati, oppure statefull, in modo da poter ricombinare assieme messaggi relativi alla
stessa comunicazione, ad esempio ai fini di tariffazione del servizio.
Gateway
La sua funzione è quella di
interfacciare il VoIP SIP con
altre reti multimediali, come
nel caso in cui la rete di
destinazione/provenienza della
chiamata, è quella telefonica
(PSTN), H.323, di telefonia
mobile (GSM o IMS-3G), una
rete VoIM, o associata ad altro
protocollo VoIP.
La presenza di un Gateway
verso PSTN consente di
raggiungere anche gli utenti di
telefonia fissa, usando Internet
per trasportare la chiamata il
più vicino possibile alla località
del numero chiamato, e quindi
(lì) attraversare un Gateway, rendendo la chiamata equivalente ad una locale.
La funzione del Gateway può essere ulteriormente scomposta in
• un Media Gateway, che provvede alla transcodifica dei dati che trasportano il segnale
multimediale, e
• un Media Gateway Controller, che termina i messaggi e le componenti di segnalazione
proprie dei due lati del gateway.
Al fine di incentivare l'interoperabilità tra apparati, la comunicazione tra MG e MGC può
avvenire mediante un ulteriore protocollo pubblico, noto come Media Gateway Control Protocol,
la cui implementazione è formalizzata ulteriormente dalla raccomandazione H.248. Inoltre, un
Gateway che abbia la funzione di interconnettere direttamente dei telefoni (tradizionali o VoIP)
di una stessa organizzazione, così come avviene nel caso di un centralino, è a volte indicato
come un SoftSwitch (ad es., Asterisk), e può usare interfacce più o meno intelligenti.
184
Lo strato applicativo di Internet
Alessandro Falaschi
Servizi aggiuntivi
Alcuni elementi della architettura SIP offrono funzionalità aggiuntive, che ne arricchiscono le
potenzialità:
• il Conference Server che interconnette tra loro diverse chiamate, realizzando una
funzione di regia automatica:
• un server di conferenza di capacità ridotte, può essere realizzato direttamente
presso uno UA;
• il Back to Back User Agent (B2BUA) che può modificare completamente i messaggi in
transito:
• questa è la modalità di realizzazione di Application Level Gateway (ALG), Security
Gateway (SEG), o Session Border Controlled (SBC) presso i punti di Ingresso/Uscita
dalla rete di un Provider VoIP, ovvero un meccanismo che può essere usato per
realizzare funzioni di Third Party Call Control;
• il Presence Server, che detiene delle informazioni di stato:
• le informazioni possono essere relative allo stato di registrazione degli UA, agli
utenti connessi in conferenza, allo stato di libero/occupato di uno UA;
• queste informazioni sono notificate agli UA che abbiano sottoscritto l'interesse a
esserne mantenuti aggiornati.
Di questi elementi, gli unici due obbligatori sono i primi due, consentendo anche ad uno UA non
registrato, di effettuare una chiamata diretta verso la URI di un secondo UA, registrato presso il
registrar corrispondente al dominio della URI. D'altra parte, sono proprio gli altri elementi che
rendono il VoIP interessante e competitivo rispetto alle modalità di comunicazione alternative,
come PSTN e VoIM.
Session Initiation Protocol
Il Session Initiation Protocol (SIP) è un protocollo di segnalazione definito nella RFC 3261, e il suo
sviluppo coinvolge praticamente tutti i gruppi di lavoro IETF che fanno parte dell'area Real-time
Applications and Infrastructure. Sebbene l'architettura VoIP definita sia basata su di un modello
peer to peer, SIP opera sulla base di messaggi che utilizzano un modello di comunicazione di tipo
client-server. Inoltre, nessuno degli elementi su esposti è strettamente indispensabile, a parte
ovviamente gli UA: infatti, è possibile per uno UA, inviare una chiamata direttamente verso
la URI di un secondo UA, a patto ovviamente che il nome a dominio che compare nell'AoR
chiamato, si risolva effettivamente nell'indirizzo IP del computer presso il quale lo UA chiamato è
185
Session Initiation Protocol
Voice over IP
in esecuzione.
SIP non si occupa né di negoziare il tipo di formato multimediale da usare nella comunicazione,
né di trasportare il segnale digitalizzato: questi due compiti, sono svolti rispettivamente da SDP
e RTP. Al contrario, SIP si occupa di mettere in contatto le parti coinvolte nella comunicazione,
in modo da definire una sessione in comune tra loro, e di permettergli di utilizzare i servizi
offerti da altre entità. Ciò consente di declinare i principi della Service Creation in accordo al
paradigma Internet, secondo cui l'intelligenza è posta ai bordi della rete, in contrapposizione al
punto di vista degli operatori di telecomunicazioni, che invece accentrano i servizi all'interno
delle reti, relegando i dispositivi di accesso ad un ruolo assolutamente passivo.
Messaggi
Affrontiamo ora la descrizione dei tipi e dei formati dei messaggi SIP. Sebbene ciò possa risultare
tedioso e oltremodo formale, gli esempi forniti di seguito sono un ottimo modo di verificare
strada facendo la semantica delle diverse componenti dei messaggi. Pertanto si consiglia di
alternare l'esame dei capture forniti, con la descrizione formale delle sintassi incontrate.
Sintassi
I messaggi possono essere di due tipi, richieste o risposte, e aderiscono alla sintassi definita da
una ABNF del tutto simile a quella già vista nel caso dell'HTTP e SMTP, ossia sono composti da
• una prima linea in cui viene indicato il Metodo (per le richieste) od una Status Line (per le
risposte);
• un numero variabile di linee contenenti svariati header che caratterizzano il messaggio;
• un body che contiene le informazioni aggiuntive, come ad esempio, una descrizione SDP.
Trasporto
I messaggi SIP sono generati dallo strato applicativo, e tipicamente incapsulati su UDP con porta
di destinazione ben nota 5060, in modo da velocizzare al massimo il loro recapito. In alternativa,
i messaggi di richiesta-risposta tra due entità SIP possono essere trasportati su TCP, sempre verso
la porta 5060; la decisione di usare TCP anziché UDP viene presa dallo UAC, quando ad esempio
la dimensione del messaggio è tale da non entrare in un singolo pacchetto UDP, oppure la
comunicazione è ritenuta a priori inaffidabile. Infine, lo strato di trasporto può essere reso sicuro
mediante l'uso di una connessione TLS, indirizzata questa volta verso la porta ben nota 5061. In
quest'ultimo caso, la URI di destinazione userà lo schema sips anziché sip come ad es.
sips:[email protected].
Macchina a stati
Nel caso del trasporto UDP, SIP fa uso di una macchina a stati che definisce i parametri della
seguente modalità di ri-trasmissione. Se lo UAC non riceve risposta ad un suo messaggio entro un
tempo T1 (posto a 500 msec), lo re-invia di nuovo, e raddoppia il valore del timer T1. Al nuovo
scadere di T1, ripete ancora l'invio del messaggio, e raddoppia di nuovo T1, e così via
(ritrasmette e raddoppia il timer) finché
• non riceve una risposta valida, oppure
• è trascorso più di 1 minuto dal primo invio, oppure
• viene ricevuto un errore di tipo ICMP
In questo modo, mentre si sfruttano i vantaggi di velocità connessi all'uso di UDP, si aggiunge una
funzione di affidabilità al trasporto, per gestire il caso dei messaggi persi.
186
Lo strato applicativo di Internet
Alessandro Falaschi
Richieste
La prima riga di una richiesta SIP presenta il formato
Method SP Request-URI SP SIP-Version CRLF
in cui Method individua la semantica del messaggio, e Request-URI indica il destinatario del
messaggio, nella forma del tipo sip:[email protected],
Metodi
I seguenti metodi compaiono nei messaggi SIP inviati (se non indicato diversamente) da uno UAC.
Metodo Commento
RFC Esempio
REGISTER
inviato al Registrar relativo al Dominio di un AoR, per associare l'AoR con
un Contact Address
INVITE
inviato verso il proprio Outbound Proxy, oppure verso il Registrar
autorevole per l'AoR del chiamato, allo scopo di instaurare una sessione.
Dato che, tipicamente, lo UA chiamato inizierà a squillare, e si dovrà
attendere che qualcuno risponda, viene subito inviata una risposta provvisoria, e
solo successivamente, una risposta definitiva (positiva o negativa)
"
si-2
ACK
inviato dallo UA chiamante, verso lo UA chiamato, per confermare la
ricezione di una risposta definitiva ad un INVITE. L'INVITE è l'unico
metodo che attua questa forma di tree way handshake, inviando una risposta alla
risposta.
"
si-2
OPTIONS
inviato ad un altro UA od un Proxy, per chiedere le funzionalità
disponibili all'altro estremo
BYE
inviato da uno UA coinvolto in una sessione con uno o più altri UA, per
manifestare l'intenzione di abbandonare la sessione, e che viene inoltrato
agli altri UA in sessione. Non può essere usato per annullare un INVITE che
non ha ricevuto ancora una risposta definitiva
CANCEL
inviato per annullare una richiesta INVITE anche se non è ancora stata
ricevuta una risposta definitiva, e può essere emesso oltre che da uno UA,
anche da un proxy intermedio
INFO
usato per inviare ad uno UA con cui si è già instaurata una sessione, delle
informazioni relative ad eventi che avvengono dall'altro lato, come ad
esempio, la pressione dei tasti del telefono. Questi vengono quindi
trasmessi nel body di un messaggio INFO, descritto da un apposito header
Content-Type: application/dtmf-relay
2976
REFER
viene tipicamente usato tra due parti che sono già in comunicazione,
mettendo in grado chi lo riceve di eseguire una nuova chiamata, verso una
destinazione indicata da chi lo invia mediante l'header Refer-to. Lo UA che
riceve il REFER, dopo aver chiesto conferma all'umano che lo gestisce, di
eseguire la nuova chiamata, emette un nuovo INVITE verso la URI indicata,
mentre il mittente del REFER viene notificato (mediante il metodo NOTIFY)
dell'esito dell'operazione.
3515
SUBSCRIBE
consente a chi lo invia, di manifestare l'interesse a ricevere delle
notifiche (mediante messaggi NOTIFY) della evoluzione di alcune variabili
di stato, indicate mediante l'intestazione Event, in cui si fa riferimento
ad un event package
3265
NOTIFY
tiene uno UA al corrente della evoluzione di alcune variabili di stato, può
esere inviato anche senza aver prima ricevuto un SUBSCRIBE
"
MESSAGE
permette l'invio di messaggi istantanei, ospitati nel body e descritti da
una intestazione Content-Type, convertendo lo UA in un messenger.
3428
PRACK
un messaggio di richiesta di Provisional Response ACK (PRACK) viene inviato da un
UAC che vuole riscontrare la ricezione di risposte temporanee ad un INVITE già
inviato. Infatti, mentre le risposte definitive sono riscontrate dall'ACK,
quelle temporanee no, e lo UAS che le invia, resta nel dubbio se sia
arrivate. Alla ricezione del PRACK (che è una richiesta), lo UAS invia una
risposta 200 OK (che non è quello dell'INVITE, ma del PRACK), e lo UAC
cessa di inviare PRACK
3262
187
3261
(s10)
si-1
3261
(s11)
"
3261
(s9)
si-2
Session Initiation Protocol
Voice over IP
UPDATE
3311
Status Line
In analogia a SMTP e HTTP, anche per SIP la prima linea dei messaggi di risposta ha un aspetto
del tipo
SIP-Version SP Status-Code SP Reason-Phrase CRLF
in cui la prima cifra dello Status-Code identifica la categoria della risposta in una delle
seguenti classi:
• 1xx: risposta provvisoria: indica il progresso delle operazioni, come ad esempio lo squillo
del telefono remoto, ma l'impossibilità di determinare il tempo necessario al loro
completamento;
• 2xx: successo, la richiesta è stata accettata;
• 3xx: redirezione: sono necessarie ulteriori azioni per completare la richiesta;
• 4xx: errore del client: la richiesta non può essere soddisfatta perché contiene qualche
errore sintattico;
• 5xx: errore del server: la richiesta appare valida, ma non può essere soddisfatta per un
problema interno del server
• 6xx: errore generale: la richiesta non può essere accettata da parte di nessun server.
La RFC 3261 contiene una sezione in cui si descrivono una serie di possibili messaggi.
Intestazioni
Anche le intestazioni SIP hanno un aspetto del tutto simile a quelle già incontrate per l'SMTP e
l'HTTP, sia pure con qualche differenza. Per uno stesso header, infatti possono essere presenti
più valori, separati da virgole:
header = "header-name" HCOLON header-value *(COMMA header-value)
mentre per ogni valore, possono essere specificati dei parametri aggiuntivi, ognuno con il proprio
valore, e separati da punto e virgola, in modo da arricchire il loro potere espressivo, e
permettere lo sviluppo di nuove estensioni
header-value: value *(;parameter-name=parameter-value)
Un esempio di questa sintassi, può essere osservato in corrispondenza dell'header Contact del
pacchetto n. 10 presente nel capture dell'esempio di registrazione.
La RFC 3261 contiene una sezione che elenca una grande quantità di header, assieme ad un
tabella che ne specifica l'applicabilità nei contesti delle metodi delle richieste e dei codici
di risposta, del tipo di entità che li può inserire, rimuovere e modificare. In particolare, molte
intestazioni sono semplicemente copiate nei pacchetti di risposta, a partire da quelle presenti
nei pacchetti di richiesta. Per alcune intestazioni, è utile indicarne ora l'utilizzo:
Intestazione Commento
To
RFC Esempio
la URI del destinatario della richiesta
188
3261
Lo strato applicativo di Internet
Alessandro Falaschi
From
rappresenta la URI di chi invia la richiesta; nelle risposte, sia From
che To restano invariati
"
Call-ID
Un identificatore semi-casuale, che resta uguale per tutti i messaggi di
uno stesso dialogo, ovvero è univocamente associato ad un INVITE
iniziale
"
CSeq
è costituito da un numero seguito dal nome del metodo che ha dato inizio
alla transazione. Il numero si incrementa di uno ad ogni nuova transazione di
uno stesso dialogo, e resta uguale per tutti i messaggi della stessa
transazione.
"
Via
inserita da ogni UAC che invia (o inoltra) una richiesta SIP, in cui
indica il proprio indirizzo, porta, trasporto, ed un parametro branch
utile per distinguere le diramazioni di un messaggio forkato. Ogni
elemento di transito che deve inoltrare la risposta, rimuove
l'intestazioone da lui inserita, ed usa quella in cima per determinare a
chi inviarla. In questo modo non occorre consultare il DNS, ed è
sufficiente un Proxy Stateless
"
Max-Forwards
utile per limitare il numero di volte che un messaggio è inoltrato
"
Contact
contiene uno o più URI presso le quali il mittente di una richiesta
desidera essere ricontattato
"
Allow
annuncia i metodi supportati da una entità
Supported
Record-Route
es-via
elenca le estensioni supportate, tra quelle elencate presso IANA
specifica la volontà di un Proxy, di essere mantenuto nel path dei futuri
messaggi del dialogo
Stratificazione di SIP
Per la definizione di SIP si è fatto ricorso alla suddivisione delle sue funzioni in termini
stratificati, distinguendo, dal basso verso l'alto
• uno strato sintattico e di codifica, che provvede alla formattazione
ed interpretazione degli elementi dei messaggi;
• uno strato di trasporto, che definisce come UAC e UAS si scambiano
richieste e risposte, ovvero decide se usare TCP o UDP;
• uno strato di transazione, che non esiste nei proxy stateless, e che
gestisce le ritrasmissioni in accordo alle macchine a stati finiti che
descrivono il comportamento per transazioni iniziate con un INVITE o
meno, associa le risposte alle relative richieste, e gestisce i timeout;
• uno strato Transaction User (TU), assente nei proxy stateless, che caratterizza il tipo di
entità SIP, e che utilizza i servizi offerti dallo strato di trasporto SIP per interagire con le
altre entità. Il TU rappresenta il nucleo della entità SIP, identificata dai metodi che è in
grado di gestire, e mentre per le entità UA valgono le considerazioni svolte nelle sezioni
da 8 a 15 della RFC 3261, le particolarità dei Proxy sono descritte alla sezione 16.
Sessione, dialogo e transazione
Per quanto appena discusso, osserviamo che mentre lo strato di transazione si prende carico
dell'effettivo scambio di tutti i messaggi che intercorrono tra UAC e UAS, necessari allo
svolgimento di una funzione elementare di SIP, i pacchetti effettivamente scambiati a questo
fine, sono visti dal TU come una unica Transazione.
189
Session Initiation Protocol
Voice over IP
Transazione
La RFC 3261 distingue i comportamenti associati a transazioni iniziate con un INVITE o meno. Nel
primo caso, se la risposta definitiva è 200 OK, la trasmissione dell'ACK non viene considerata
parte della transazione, ed è effettuata a cura del TU dello UAC. Dal lato del chiamato, è il TU
dello UAS che si prende carico di ritrasmettere il 200 OK, finché non riceve il corrispettivo ACK.
Se invece la risposta appartiene alle classi 3xx-6xx, questa viene assorbita dallo strato di
transazione dello UAC, che provvede a generare per suo conto l'ACK, mentre lo strato di
transazione dello UAS provvede a ritrasmettere le risposte, finché non sono riscontrate dall'ACK.
Nel caso, invece, di transazioni non legate ad una richiesta INVITE, lo strato di transazione dello
UAC continua autonomamente a reinviare la richiesta, finché non riceve una risposta, mentre è
lo strato di transazione dello UAS a re-inviare le risposte, per ogni richiesta ricevuta.
Quando un UAC riceve una risposta, deve ricombinarla assieme alla richiesta orginaria. Per
questo, devono corrispondere due cose:
• il parametro branch associato al primo header Via nella risposta, è lo stesso di quello
nella richiesta, e
• il numero associato all'header CSeq, ed il parametro method ad esso associato, sono gli
stessi che appaiono nella richiesta.
Dialogo
Tutti i messaggi scambiati tra due UA tra l'inizio di una comunicazione e la sua conclusione,
vanno a costituire un dialogo, che è individuato presso ogni UA in base al valore della
intestazione Call-ID, al tag locale, ed al tag remoto. Questi ultimi due, sono stringhe inserite
dagli UA, e si scambiano di ruolo: presso il chiamante, il tag remoto è espresso come parametro
del From, e quello locale viene letto dal paramentro tag associato al To, al momento della
ricezione della risposta. Presso il chiamato invece, il tag locale è assocato al To, e quello remoto
al From. La tripla di valori Call-ID, from-tag e to-tag inizia ad esistere su entrambi gli UA, a
190
Lo strato applicativo di Internet
Alessandro Falaschi
seguito della ricezione da parte dello UA chiamante della risposta definitiva 200 OK, e cessa di
esistere a seguito della ricezione di una richiesta di BYE, e della relativa risposta.
Durante il dialogo, la tripla che lo individua è presente in tutti i messaggi che vi fanno parte,
permettendone la contestualizzazione di chi li riceve, in base alla esistenza di uno stato
condiviso rappresentato dagli altri parametri del dialogo, come i valori dei CSeq delle due parti
(che si incrementano ad ogni transazione del dialogo, ma restano costanti per i diversi messaggi
della stessa transazione), le URI locale e remota, i parametri usati dalle estensioni, e la lista dei
Proxy che deve essere attraversata dagli altri messaggi del dialogo.
Per un esempio, possiamo fare riferimento al capture della procedura di INVITE.
Sessione
Una Sessione viene creata a seguito dell'invio di un messaggio iniziale di INVITE, mediante il
quale avviene la negoziazione dei parametri necessari alla trasmissione multimediale, basata su
di un paradigma offerta-risposta.
L'offerta può essere formalizzata
• mediante l'inserimento nel body della richiesta INVITE di una descrizione SDP, oppure
• la richiesta può non contenere offerte, formalizzate invece mediante l'inserimento della
descrizione SDP nel body del primo messaggio di risposta definitiva (il 200 OK), come ad
esempio nel caso in cui l'invito deve attraversare un Gateway verso reti per le quali la
formulazione di una offerta è demandata al chiamato.
La risposta all'offerta consiste in una scelta tra le possibilità offerte, e viene veicolata nei due
casi, rispettivamente, mediante l'inserimento di una descrizione SDP nel body del primo
messaggio di risposta definitiva, ovvero nel body del messaggio di ACK.
Nel caso in cui pervengano più risposte definitive per lo stesso INVITE, come nel caso in cui
questo sia stato forkato, oppure inviato in multicast, ognuna di queste determina la creazione di
un diverso dialogo, e tutti i dialoghi vengono a far pare della medesima sessione.
Una sessione può essere modificata durante la sua esistenza mediante l'invio di un nuovo INVITE
(detto re-INVITE), da parte di una delle parti che aderiscono alla sessione, ossia anche su
iniziativa del chiamato. La modifica può riguardare, ad esempio, l'aggiunta di un nuovo media
(ad esempio, video) alla sessione, e consistere quindi nell'inizio di un nuovo ciclo di
offerta-risposta, attuato come già illustrato. A differenza dell'INVITE originario,, un re-INVITE
non può essere forkato, in quanto diretto alle parti già in comunicazione.
Una sessione può essere terminata mediante l'invio di un BYE di una delle due parti dell'unico
dialogo della sessione, mentre se la sessione è condivisa tra più parti, il BYE termina unicamente
il dialogo corrispondente. Alternativamente, la sessione viene terminata a seguito della ricezione
di una risposta definitiva di tipo diverso da 2xx, Infine, la sessione può essere terminata a seguito
della ricezione di una richiesta CANCEL.
Autenticazione
L'associazione di un Contact Address con un AoR, ad opera di uno UA che contatta un Registrar, è
una operazione che, se eseguita senza nessuna verifica di autorizzazione, permetterebbe a
chiunque di ricevere le telefonate SIP in realtà dirette a qualcun altro. Pertanto, qualunque
provider VoIP minimamente serio, intraprende una procedura di verifica del possesso di
credenziali di accesso, da parte dello UA che richiede la registrazione. In linea con il resto delle
specifiche, anche l'autenticazione SIP ricalca i metodi già visti per l'HTTP, in quanto consiste in
191
Session Initiation Protocol
Voice over IP
una sfida che il Registrar invia allo UA, contenuta nella intestazione WWW-Authenticate
presente in una risposta 401 Unauthorized, e basata sul metodo Digest. Così il VoIP provider
che gestisce il Registrar, e rilascia l'AoR all'utente dello UA, concorda con quest'ultimo anche un
segreto condiviso, o password, da usare in associazione alla parte user dell'AoR, per verificare
l'autorizzazione all'uso del Registrar.
Allo stesso modo, anche i messaggi inviati da uno UA al proprio Outbound Proxy devono essere
autenticati, in modo da impedire al Proxy di comportarsi come un OpenRelay, ed inoltrare
richieste provenienti da chiamanti sconosciuti. Nel caso (come è spesso) in cui Registrar e
Outbound Proxy coincidano, viene ovviamente usata la stessa password stabilita in precedenza;
altrimenti, occorre far riferimento da parte di entrambi, ad uno stesso autentication server.
Federazione
Resta aperta la questione, di come procedere alla autenticazione tra l'Outbound Proxy di
partenza, ed il Registrar di destinazione, senza contare la presenza di eventuali altri Proxy
intermedi: infatti, mentre tra UA, Registrar, e Outbound Proxy, i rapporti sono diretti, e mediati
da uno stesso soggetto VoIP provider, non invece è pensabile di poter stabilire un segreto
condiviso tra tutte le coppie di Proxy presenti in Intenet. La soluzione attualmente più
percorribile, sembra essere quella allo studio da parte del WG SPEERMINT di IETF, e che consiste
nella definizione di Federazioni SIP, a cui i singoli provider VoIP possono aderire, e che svolgono
la funzione di una Certification Authority comune per firmare i certificati digitali dei provider
aderenti, da usare nell'ambito delle connessioni TLS che le coppie di Proxy federati devono
usare, quando coinvolti dall'attraversamento della segnalazione SIP.
Instradamento
Ogni entità che invia (o inoltra) una richiesta, aggiunge una intestazione Via al messaggio, in
cima a quelle già presenti, in cui sono indicati l'indirizzo IP, il trasporto, e la porta usati dallo
UAC, più un parametro branch che contiene una stringa creata semi-casualmente per
l'occasione, e che viene citata nelle risposte, allo scopo di distinguere tra loro le diverse risposte
che possono provenire da UAS situati su rami diversi di un fork. Lo UAS che riceve la richiesta, è
in grado di correggere l'intestazione Via, nel caso in cui l'indirizzo IP e/o la porta citati
dal mittente, siano differenti da quelli effettivamente osservati dal socket su cui la richiesta è
pervenuta, ad es. perché il richiedente è NATtato: in questo caso, viene aggiunto al Via un
parametro received= in cui si indicano i dati corretti e/o mancanti, come nell'esempio
seguente.
Quando una richiesta raggiunge lo UAS di destinazione, e questo genera una risposta,
non inserisce nessuna nuova intestazione Via, ma usa quella in cima a tutte, per determinare a
chi inviare la risposta, in cui include anche tutte le altre intestazioni Via. Se la risposta è
ricevuta da un Proxy intermedio, questo dopo aver rimosso l'intestazione Via che lui stesso
aveva inserito, usa a sua volta il Via in cima alla pila, per individuare a chi restituire la risposta,
e così via, fino allo UAC originario.
Route Set
Quando un Proxy inoltra una richiesta che determina la creazione di un dialogo (tipicamente, un
INVITE), può richiedere di rimanere nel path dei successivi messaggi appartenenti allo stesso
dialogo. Per questo, prima di inoltrare il messaggio, vi inserisce un header Record-Routein cui
dichiara la propria URI. Se anche altri Proxy lungo il tragitto della richiesta di inizio dialogo
vogliono restare nel path, aggiungono a loro volta una intestazione Record-Route in testa alle
altre. Quando la richiesta arriva allo UA di destinazione, questo memorizza gli indirizzi trovati
192
Lo strato applicativo di Internet
Alessandro Falaschi
nelle intestazioni Record-Route in un route set, che entrerà a far parte del contesto da
applicare agli altri messaggi del dialogo, non appena la sua creazione verrà confermata dal
messaggio di ACK.
La risposta che ora lo UA chiamato invia verso il chiamante, utilizza la catena dei Via per
ritrovare la strada verso il chiamante, e contiene inalterata la lista dei Record-Route costruita
nel viaggio di andata, dato che i Proxy aggiungono i Record-Route nelle richieste, e non nelle
risposte. Quando la risposta arriva allo UA chiamante, se questa è di successo, il route set viene
memorizzato anche da questo lato.
Da questo momento in poi, quando uno UA invia una richiesta appartenente ad un dialogo, vi
inserisce un header Route, in cui copia il route set associato al dialogo; quindi, aggiunge un Via
con il proprio indirizzo, ed usa il primo elemento del route set, per determinare a chi inviare la
richiesta, indipendentemente dal valore della intestazione To, e della request-URI. Nel caso
in cui si sia configurato un Outbound Proxy, questo comparirà come primo elemento del route
set. Il Proxy che riceve questa richiesta, rimuove il proprio indirizzo dall'elenco che compare nel
Route, ed usa l'indirizzo successivo, per inoltrare a sua volta la richiesta.
Loose routing
Con questo termine, i Proxy SIP annunciano la propria conformità alla RFC 3261, in
contrapposizione a quelli il cui comportamento è definito dalla precedente RFC 2543, detti Stric
Routers. Un Proxy annuncia il proprio comportamento da loose router aggiungendo nelle
intestazioni che modifica, il parametro ;lr, oppure ;lr=on.
Procedure
Registrazione, service discovery, e autenticazione
Nella procedura di registrazione, uno UA invia al proprio Registrar una richiesta mediante la
quale si richiede di associare il proprio AoR con con metodo REGISTER, che se andata a buon
fine, determina il messaggio di risposta 200 OK. Come risultato, il Registrar ha memorizzato la
corrispondenza AoR-Contact in un Location Database, che verrà interrogato in seguito, nel caso
di chiamate entranti, per localizzare l'utente.
In questo file di capture, relativo alla procedura di registrazione per l'AoR
193
Session Initiation Protocol
Voice over IP
[email protected], possiamo apprezzare il formato dei messaggi, e svolgere una serie di
interessanti osservazioni.
• il nome a dominio del Registrar è ing.uniroma1.it, e prima di inviare il messaggio SIP,
viene interrogato due volte il DNS:
• viene prima eseguita una query per il RR di tipo SRV, allo scopo di individuare il
Proxy SIP del dominio, e la porta su cui risponde;
• quindi, avviene la risoluzione dal nome a dominio del Proxy, al suo indirizzo IP
• nel caso in cui la query del RR di tipo SRV fosse fallita, la richiesta sarebbe
stata direttamente inoltrata al nome a dominio corrispondente all'AoR;
• le intestazioni From e To del REGISTER risultano uguali (a meno dei parametri tag),
indicando che il chiamato è la stessa URI di colui che sta effettuando la registrazione (il
chiamante);
• l'intestazione Via presente nel pacchetto 5 è priva del numero di porta, e pubblica un
indirizzo IP privato (e quindi irraggiungibile), ma queste informazioni vengono corrette
dallo UAS fin dalla risposta temporanea del pacchetto 6, in cui troviamo
Via: SIP/2.0/UDP 192.168.1.100;rport=1024;branch=z9hG4bKscwclcls;received=151.49.83.143
• la prima richiesta REGISTER sip:ing.uniroma1.it SIP/2.0 presente al pacchetto 5
viene respinta con una risposta SIP/2.0 401 Unauthorized, in quanto non erano
presenti credenziali di autenticazione, e mediante l'header WWW-Authenticate viene
indicato il realm="ing.uniroma1.it" ed il nonce della sfida per procedere;
• la richiesta viene reiterata al pacchetto 8 inserendo questa volta
l'intestazione Authorization, che contiene la risposta alla sfida, e che stavolta viene
accettata al pacchetto 10;
• l'intestazione Contact della risposta contiene due diversi indirizzi, ovvero
Contact:
<sip:[email protected];transport=UDP>;expires=2590;received="sip:151.49.83.143:5060",
<sip:[email protected]>;expires=3600;received="sip:151.49.83.143:1024"
• il primo è relativo ad una precedente registrazione per lo stesso AoR, effettuato da
un diverso UA, mentre il secondo è relativo alla registrazione corrente;
• per entrambi i valori di Contact compare un indirizzo IP privato, mentre nel
parametro received il Registrar ha annotato l'IP pubblico del router casalingo, ed i
numeri di porta usati dagli UAC;
• quando, al pacchetto 20, viene inviato un messaggio con l'intenzione di annullare la
registrazione, l'intestazione Contact contiene il parametro expires=0, che indica
appunto il desiderio di rimuovere l'associazione memorizzata nel Location Database
194
Lo strato applicativo di Internet
Alessandro Falaschi
Invito, creazione del dialogo e route set
Nella procedura di invito, è pratica
comune che la richiesta INVITE, prima di
raggiungere lo UAS chiamato, attraversi
almeno due proxy: l'Outbound Proxy del
chiamante, e il Proxy/Registrar del
chiamato. Questa forma di
instradamento prende il nome di
trapezoide SIP, in base al particolare
modo di raffigurare l'instradamento,
riportato a fianco.
Notiamo che nell'esempio riportato, la
richiesta BYE che termina la
comunicazione viene inviata direttamente, senza attraversare i due proxy. Questo può avvenire
per il verificarsi di due condizioni:
• i due telefoni VoIP hanno appreso, leggendo l'intestazione Contact inserita dal lato
remoto, i rispettivi indirizzi IP, e
• i due Proxy non hanno richiesto di rimane nel percorso di instradamento.
Qui sotto, osserviamo un nuovo disegno un pò più dettagliato, che mette in evidenza la fase di
richiesta al DNS necessaria a scoprire il proxy server di destinazione. Ciò che invece non è
mostrato, è l'interrogazione del Proxy di destinazione al Location Database mantenuto aggiornato
dal Registrar di b.com.
195
Session Initiation Protocol
Voice over IP
Nel diagramma di flusso è riportato un esempio in cui l'Outbound Proxy ed il Registrar vengono a
coincidere, e viene posta in evidenza la sequenza dei messaggi che vengono scambiati tra UAC
del chiamante e lo UAS del Proxy, e quindi tra lo UAC del Proxy e lo UAS del chiamato. Come si
vede, il Proxy invia immediatamente una risposta temporanea di tipo 100 Trying, allo scopo di
riscontrare lo UAC della avvenuta ricezione della richiesta INVITE, ed arrestare il re-invio della
richiesta. Quindi,
• l'INVITE è inoltrato a destinazione;
• il chiamato lo riscontra immediatamente con 100 Trying;
• il chiamato inizia ad inviare una sequenza di risposte temporanee 180 Ringing, che sono
immediatamente re-instradate dal Proxy verso il chiamante, mediante l'esame dell'header
Via posto in cima agli altri;
• quando la persona fisica chiamata risponde, lo UAS chiamato invia la risposta definitiva
200 OK, immediatamente inoltrata;
• il chiamante completa il ciclo del three way handshake inviando un ACK direttamente al
chiamato (lo può fare, perché ne conosce il Contact Address, ed il Proxy non ha richiesto
di restare nel path)
• finalmente, le due parti sono in comunicazione vocale, trasportata da pacchetti RTP
instradati direttamente tra le parti.
Siamo ora pronti ad esaminare il risultato di un Capture di traffico reale, relativo alla chiamata
che [email protected] esegue verso [email protected], utilizzando
come Outbound Proxy il nome a dominio ing.uniroma1.it, così come si ottiene eseguendo il
capture presso il chiamante. Possiamo osservare che:
• nei pacchetti 1-4 avviene la risoluzione DNS, che individua in smile.ing.uniroma1.it
il server SIP delegato dal nome a dominio dell'Outbound Proxy, che viene quindi risolto
nell'indirizzo 151.100.122.144;
• al pacchetto 5 si inizializza il local tag della sessione, e sono definiti il Call-ID ed il
CSeq:
From: "alef" <sip:[email protected]>;tag=xglhe
Call-ID: [email protected]
CSeq: 986 INVITE
• al pacchetto 8 sia il local tag che il Call-ID sono ri-usati, mentre il Cseq è incrementato
di uno; oltre alla aggiunta di una intestazione Proxy-Authorization, contenente le
credenziali di autenticazione, notiamo la presenza delle intestazioni
196
Lo strato applicativo di Internet
Alessandro Falaschi
Content-Type: application/sdp
Allow: INVITE,ACK,BYE,CANCEL,OPTIONS,PRACK,REFER,NOTIFY,SUBSCRIBE,INFO
Supported: replaces,norefersub,100rel
che indicano la presenza di una offerta SDP, ed i metodi e le estensioni supportate
• al pacchetto 11 viene ricevuta la risposta definitiva 200 OK, in cui troviamo
Record-Route:
<sip:198.65.166.131;ftag=xglhe;lr;transport=UDP>,<sip:[email protected]:5060;nat=yes;ftag=xglhe;lr=on>
To: "[email protected]" <sip:[email protected]>;tag=n448pds8f6igkkn3gt0ehij2
Contact: <sip:[email protected]:5060;transport=UDP;nat=yes>
Allow: INVITE,ACK,BYE,CANCEL,REFER,NOTIFY,OPTIONS,PRACK
e quindi osserviamo come con il parametro tag di To, sia ora definito il remote tag
dell'altra parte in comunicazione, mentre in Record-Route siano indicati gli indirizzi
dell'Outbound Proxy, e di in proxy del dominio del chiamato; inoltre, notiamo come
entrambi si dichiarino dei loose routers. Inoltre, nel body del messaggio possiamo trovare
l'SDP di risposta;
• al pacchetto 12 viene inviato l'ACK, in cui osserviamo che nella Request-URI compare il
Contact appena ricevuto, ma il messaggio viene comunque inviato al proprio Outbound
Proxy 151.100.122.144, in virtù della presenza di questo indirizzo come ultimo valore
dell'header Record-Route osservato nel 200 OK. Inoltre, il route-set dichiarato mediante
l'header Route, ricalca quello dichiarato nel Record-Route ricevuto, ma con ordine
invertito. Infine, notiamo come il To ora sia corredato del remote tag appreso con il 200
OK, e come il CSeq contenga ancora lo stesso numero, ma un metodo diverso, in modo da
individuare una transazione differente.
ACK sip:[email protected]:5060;transport=UDP;nat=yes SIP/2.0
Route:
<sip:[email protected]:5060;nat=yes;ftag=xglhe;lr=on>,<sip:198.65.166.131;ftag=xglhe;lr;transport=UDP>
To: "[email protected]" <sip:[email protected]>;tag=n448pds8f6igkkn3gt0ehij2
CSeq: 986 ACK
• al pacchetto 13 viene subito inviato un SDES RTP, e quindi inizia la trasmissione dell'RTP.
Dopo circa 170 msec, inizia ad arrivare il flusso RTP proveniente dall'altro lato.
Terminazione
Redirezione
Session Description Protocol
Il Session Description Protocol (SDP) non definisce un insieme di messaggi che possono essere
scambiati tra dispositivi in rete, bensì costituisce una sintassi in grado di descrivere i parametri
che caratterizzano una trasmissione multimediale Internet.
Contesti di utilizzo
SDP è descritto dalla RFC 4566 del 2006, ma la sua definizione iniziale risale al 1998, come
meccanismo per distribuire gli annunci di sessione relativi alle conferenze multicast di Mbone, in
modo da indicare il tipo di codifica audio-video mediante i quali sono distribuiti i media, e gli
indirizzi IP multicast e di trasporto, presso i quali gli aderenti si devono sintonizzare.
197
Session Description Protocol
Voice over IP
Oltre all'uso originale, una descrizione SDP può essere distribuita mediante una URI HTTP, oppure
come parte MIME di una email, utilizzando un header Content-Type: application/sdp. In
questo caso, l'SDP può ancora essere usato per ricevere una sessione multicast, ammesso che
l'instradamento multicast raggiunga il potenziale partecipante. D'altra parte, non
necessariamente una sessione multimediale deve rappresentare una conferenza tra più parti,
bidirezionale, ed in tempo reale: più banalmente, può essere unidirezionale, e/o relativa ad un
evento registrato. Per questo, è stato definito l'RTSP, mediante il quale dei player unicast
possono richiedere la ricezione di un contentuto multimediale, e che pure usa l'SDP come sintassi
di descrizione dei contenuti, mentre alcuni aspetti della negoziazione dei parametri di
trasmissione, sono gestiti dall'RTSP.
La particolarità dell'uso di SDP nel contesto di SIP, è quello di consentire l'attuazione di un
meccanismo di offerta/risposta (descritto nella RFC 3264), tale da permettere a due entità di
accordarsi su modalità comuni di trasmissione multimediale.
Sintassi e sezioni
Analizziamo gli elementi di una descrizione SDP, a partire da quella contenuta nel pacchetto
numero 8 del capture relativo all'esempio dell'INVITE, a cui per chiarezza sono stati aggiunti dei
commenti:
v=0
o=alef 326810211 397034952 IN IP4 192.168.1.101
s=c=IN IP4 192.168.1.101
t=0 0
m=audio 8000 RTP/AVP 98 97 8 0 3 101
a=rtpmap:98 speex/16000
a=rtpmap:97 speex/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:3 GSM/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=ptime:20
#
#
#
#
#
#
#
version
origin
session name
contact
tempo di inizio e fine
media description
attributo sottotipo del PT 98
# formato per il PT 101
# intervallo tra pacchetti di 20 msec
Un SDP è composto da una serie di linee, il cui primo carattere individua un elemento sintattico,
il cui tipo determina la semantica di ciò che segue il segno di uguale. La prima linea v= indica la
versione dell'SDP (per ora, esiste solo la versione 0), e contrassegna la sezione di SDP comune a
tutta la sessione. Ogni linea che inizia per m=, indica l'inizio della sezione specifica di un media.
Gli elementi comuni mostrati nell'esempio sono solo quelli obbligatori, mentre la RFC 4566 ne
prevede diversi altri opzionali.
Elementi
L'elemento s= indica il session name, utile nel caso di conferenze Multicast, mentre per l'uso con
SIP è irrilevante, e quindi sostituito da un segno meno; un discorso analogo vale per l'elemento
time t=.
L'elemento Origin o= ha una sintassi
o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
e, a parte per il campo <sess-version>, costituisce un identificativo della sessione
globalmente unico, mentre <sess-version> permette di distinguere tra versioni successive
198
Lo strato applicativo di Internet
Alessandro Falaschi
della stessa sessione. Il campo <unicast-address> indica il computer presso il quale la
sessione è state definita.
L'elemento contact c= può comparire solo nella sezione generale, oppure in ogni sezione
specifica di un media, e indica l'indirizzo del computer che eroga i (il) media, oppure il gruppo
multicast verso cui viene trasmessa; in quest'ultimo caso, occorre specificare anche un TTL (Time
To Live).
L'elemento media description m=, ha un formato
m=<media> <port> <proto> <fmt> ...
in cui
• media può tipicamente assumere i valori audio e video (ma non solo),
• port indica un numero di porta di trasporto, che
• per le sessioni multicast, è quello su cui si deve mettere in ascolto chi vuol
ricevere, e quindi anche quello verso cui si deve trasmettere, mentre
• per le sessioni unicast, è quello su cui la stessa entità che invia l'SDP, si mette in
ascolto,
• in entrambi i casi, il numero di porta indicato sarà un numero pari, ed il fusso RTCP
associato, utilizzerà il numero di porta (dispari) immediatamente successivo;
• proto ha quasi sempre ha il valore RTP/AVP, che indica una pacchettizzazione RTP su
UDP, con parametri definiti dall'RTP Profile for Audio and Video Conferences,
• fmt rappresenta il media format description, e se <proto> è pari a RTP/AVP, è costituito
da una serie di interi detti di Payload Type (PT).
Gli elementi attribute a= sono il meccanismo con cui è possibile estendere l'espressività di SDP,
per mezzo della definizione di nuovi nomi. Possono comparire sia nella sezione generale,
tipicamente per meglio caratterizzare una sessione multicast, ad esempio descrivendola in
termini di parole chiave, o categorie gerarchiche, oppure ancora, indicare il verso della
comunicazione, come nel caso di a=recvonly, a=sendonly, a=sendrecv, (che è il default,
se non specificato). Quando invece gli elementi a= compaiono nella sezione specifica per un
media, possono veicolare informazioni relative alla temporizzazione, alla qualità, a parametri
del codec, ma l'uso più diffuso è quello di associare a ciascuno dei PT dichiarati
dall'elemento m=, e non completamente descritti dall'AVP, il corrispettivo codec, frequenza di
campionamento, ed eventuali altri parametri, in accordo alla sintassi
a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
in cui encoding name è scelto in modo che, combinandolo assieme al nome del media che
compare nell'elemento m= relativo, si ottenga il nome di un MIME Media Type costruito come
media/encoding name, del tipo di quelli registrati presso IANA.
Così, tornando ad esaminare l'esempio fornito, osserviamo che chi invia l'SDP comunica
l'intenzione di ricevere il media audio sulla porta 8000, pacchettizzato in RTP su UDP, e dichiara
di essere in grado di ricevere 6 diversi PT, i primi cinque dei quali sono relativi a codec audio, di
cui il primo wideband (campionato a 16 KHz), mentre il sesto PT rappresenta la pressione di un
tasto del telefono, usando quindi dell'elemento a= per specificare un formato specifico del
media (a=fmtp:101 0-15 individua uno dei sedici DTMF). Infine, con a=ptime:20 viene
specificato che ogni pacchetto RTP, corrisponde a 20 msec di segnale.
199
Session Description Protocol
Voice over IP
Offerta e risposta
La RFC 3264 descrive le modalità secondo cui SDP può essere usato, assieme a SIP, per negoziare
i parametri di una trasmissione mutimediale. In questo modo, chi invia l'offerta compila una lista
di media e di Payload Type (PT) che è in grado di gestire, in ordine di preferenza, e permette a
chi invia la risposta di esprimere la sua scelta, allegando un diverso SDP, creato sulla base di
quello ricevuto, ed in cui sono indicati i PT disponibili tra quelli indicati.
Creazione della risposta
La risposta conterrà una diversa linea o=, indicativa di chi risponde, una linea t= uguale a quella
dell'offerta, ed un numero di sezioni media pari al numero di sezioni presenti
nell'offerta, disposte secondo lo stesso ordine. Il numero di porta indicato nelle linee m= indica
ora la porta su cui chi risponde intende ricevere il media, e per rifiutare in toto un determinato
media, viene indicato un numero di porta pari a zero. Nel caso di sessioni unidirezionali, anche
chi trasmette solamente dovrà indicare un numero di porta diverso da zero, consentendo
comunque la ricezione del canale RTCP. Accettando l'offerta per un media classificato come
sendonly o receiveonly, nella risposta si indicherà per lo stesso una
modalità rispettivamente receiveonly o sendonly. Chi risponde, può specificare un intervallo
di pachettizzazione (con a=ptime:xx) diverso da quello dell'offerta.
Ricezione della risposta
Una volta inviata la risposta, chi risponde deve essere pronto a ricevere i media per i quali ha
individuato dei codec opportuni, usando i parametri indicati nella risposta, e può iniziare a
trasmettere, in accordo ai parametri contenuti nell'offerta. Una volta ricevuta la risposta,
l'offerente deve iniziare a ricevere sulla porta indicata nell'offerta, ed a trasmettere verso la
porta indicata nella risposta. Per ogni media e per ognuna delle due parti, la trasmissione
avviene usando uno dei PT presenti in entrambi gli SDP scambiati, con l'ordine di preferenza
indicato. Durante la sessione, una delle due parti può cambiare il codec usato per la
trasmissione, e usarne un altro scelto tra quelli negoziati, per attuare ad esempio una codifca a
bassa velocità nei periodi di silienzio, oppure per inviare dei DTMF via RTP.
Modifica della sessione
Durante la conversazione, una delle due parti può iniziare un nuovo ciclo di offerta-risposta, alla
scopo di modificare i parametri della sessione multimediale, Può essere proposto un nuovo
insieme di PT per gli stessi media (ad esempio, a causa di una variazione di
potenza computazionale, in base a considerazioni di rispamio energetico, oppure a mutate
condizioni di qualità del collegamento), oppure possono essere aggiunti e/o rimossi nuovi media
(ad es., video), e/o modificati indirizzo e porta del collegamento, oppure l'altra parte può essere
messa in attesa.
Esempio
Ritornando ad esaminare il capture relativo all'esempio dell'INVITE, ecco di seguito l'SDP di
risposta contenuto al pacchetto numero 11:
v=0
o=Nokia-SIPUA 326810212 397034953 IN IP4 151.49.97.148
s=c=IN IP4 198.65.166.131
t=0 0
200
Lo strato applicativo di Internet
Alessandro Falaschi
m=audio 40822 RTP/AVP 8 101
a=ptime:20
a=maxptime:200
a=fmtp:101 0-15
a=rtpmap:8 PCMA/8000/1
a=rtpmap:101 telephone-event/8000/1
a=nortpproxy:yes
Questo SDP è generato da uno UA codless VoIP, come risulta dalla linea o=, dove compare l'IP
pubblico del router WiFi da cui ottiene la connettività Internet. Ciononostante, nella linea c= è
riportato l'indirizzo IP di un elemento RTP proxy inserito nel path dei media, dal provider VoIP.
Per quanto riguarda il media audio, la risposta presenta un unico valore di PT, il pcm legge A.
Oltre a confermare (a=ptime:20) un intervallo tra pacchetti di 20 msec, l'SDP avverte che
questo può crescere fino a 200 msec (a=maxptime:200). Infine, l'attributo non-standard
a=nortpproxy:yes segnala che non occorre provvedere all'inserimento di altri elementi di
attraversamento NAT.
Real Time Protocol
L'RTP è attualmente formalizzato dalla RFC 3550 del 2003, ma il suo primo draft risale al 1993.
Rappresenta la modalità con cui lo strato applicativo incapsula i dati multimediali, prima di
consegnarli ad un trasporto basato su UDP, in accordo allo schema riportato appresso, assieme al
quale è indicato il calcolo della quantità minima totale delle informazioni di overhead; notiamo
inoltre che il carico utile, ossia i dati multimediali trasportati, è indicato come payload.
protocollo
byte
ethernet 14
IP
20
UDP
8
RTP
12
totale
54
I motivi per cui si preferisce usare UDP piuttosto che TCP, possono riassumersi in
• una ridotta dimensione della intestazione;
• la possibilità offerta allo strato applicativo di segmentare i dati da trasmettere in modo
coerente con la loro pacchettizzazione;
• l'inutilità pratica della affidabilità garantita dal TCP, preferendo omettere la riproduzione
dei dati mancanti, piuttosto che chiederne la ritrasmissione
201
Real Time Protocol
Voice over IP
D'altra parte, l'assenza totale di
funzionalità di controllo (di flusso, di
errore e di congestione) da parte
dell'UDP, viene sanata dall'uso
congiunto del Real Time Control
Protocol (RTCP), che anzichè
trasportare dati, invia all'indietro (ad
una velocità molto ridotta)
informazioni di controllo come
numero di pacchetti persi, ritardo e
jitter. Inoltre, RTCP viene inviato
anche nella stessa direzione dell'RTP,
per trasportare informazioni aggiuntive sul media contenuto nell'RTP. Contrariamente a molti
altri casi discussi finora, l'RTP non usa un numero di porta ben nota, e l'unica convenzione
adottata è di inviarlo su di un numero di porta pari, mentre sul numero di porta dispari
immediatamente successivo, viene inviato l'RTCP.
Inoltre, le particolarità che i dati multimediali trasportati impongono all'RTP sono descritte da un
profilo di utilizzo dell'RTP stesso, ovvero di un documento addizionale che
specifica l'interpretazione da dare ad alcuni campi dell'RTP che sono specificatamente previsti
per la descrizione della natura del payload, e degli elementi informativi che RTP prevede per
quel payload. In particolare, la quasi totalità della applicazioni aderiscono all'Audio Video
Profile, o AVP, descritto nel seguito.
Infine, una applicazione che voglia trasmettere/riprodurre dati multimediali trasportati su RTP,
necessita di una ulteriore specifica, ovvero la definizione dei formati di codifica, che descrivono
come una particolare rappresentazione dei dati (codec) determini la modalità di interpretazione
dei dati contenuti nel payload, e come questi dati siano segmentati e pacchettizzati.
Prima di descrivere il formato delle intestazioni RTP, che concretizzano gli aspetti ora introdotti,
svolgiamo alcune considerazioni più generali, relative alla problematica della trasmissione
multimediale su IP.
Qualità, ritardo, jitter e buffer di riproduzione
Mentre nella trasmissione dati è inammissibile che alcuni pacchetti vadano persi, nelle
trasmissioni multimediali le eventuali discontinuità nella trasmissione vengono interpolate
cognitivamente, e non costituiscono un reale impedimento alla comunicazione (ovviamente,
entro certi limiti). Invece, un elemento determinante relativo alla usabilità della comunicazione
interattiva, è legato al ritardo di Round Trip Time percepito, che dovrebbe essere mantenuto al
disotto dei 200 msec, in modo da preservare la piena interattività dell'interloquio. Infine, occorre
tenere conto che il ritardo di attraversamenteo della rete può variare, e la sua quantificazione è
indicata con il termine di Jitter, anche se questo termine nasce per indicare solo le irregolarità
statistiche di un dispositivo di temporizzazione (ad esempio, nell'audio HiFi). Le cause
dell'insorgenza del Jitter in Internet sono le più disparate, ma l'effetto è che, prima di procedere
alla riproduzione del segnale ricevuto, questo deve essere accodato in un buffer in modo da
assorbire le variazioni di ritardo.
202
Lo strato applicativo di Internet
Alessandro Falaschi
La figura a lato ci aiuta a definire il
criterio di dimensionamento del buffer
di riproduzione. Sulle ordinate è
riportata la percentuale di pacchetti
che pervengono con entro un
determinato intevallo temporale, di
durata pari alla durata del segnale che è
codificato entro il pacchetto, e pari
quindi al tempo necessario per
riprodurre quel segnale.
L'estensione del playout buffer size viene quindi determinata in modo tale che la percentuale di
pacchetti pervenuti in tempo utile (per poter riprodurre il segnale che trasportano) sia sufficente
elevata, in modo da non penalizzare troppo la qualità dell'ascolto; allo stesso tempo, il ritardo
introdotto deve essere mantenuto basso, in modo da non pregiudicare l'interattività della
conversazione.
Dato che la distribuzione dei ritardi deve essere valutata in base alle condizioni di rete effettive,
ed al fine di individuare una soluzione di compromesso tra le due esigenze contrastanti, le
soluzioni migliori sono quelle che effettuano un dimensionamento adattativo del buffer di
riproduzione, tipicamete riducendone la dimensione nei momenti di inattività vocale, e
aumentandola se la percentuale di pacchetti scartati tende ad aumentare.
Osserviamo infine che nel caso in cui la quantità di dati (bit) trasportati sia uguale per ogni
pacchetto, la dimensione così individuata corrisponde ad una estensione di memoria fisica,
mentre se la quantità di bit è variabile, rappresenta unicamente il numero di pacchetti da
accodare nel buffer.
Unità dati applicative
Un codificatore di segnale, opera tipicamente su intervalli temporali costanti, e suoi multipli
naturali, e produce in uscita delle unità dati che, essendo generate a livello applicativo, vengono
indicate come Application Data Unit (ADU). Ad esempio, un codificatore vocale basato su di un
modello di sorgente vocale opera su intervalli di 10-40 msec (pari a 80-320 campioni, se il
segnale è campionato a 8 KHz), mentre un codificatore video con frame rate (ad es) di 16
quadri/sec, produce ADU distanziate di 62,5 msec.
Pacchettizzazione
Il numero effettivo di bit di cui ogni ADU è composta, dipenderà dal tipo di codificatore in uso; in
linea generale, le ADU devono essere ricevute (correttamente) per intero, pena l'impossibilità di
procedere alla loro riproduzione. Quest'ultima considerazione è un ulteriore motivo fondante
della trasmissione via UDP, perché a differenza del TCP, delega allo strato applicativo (in cui è in
esecuzione il codificatore) la suddivisione delle ADU nei pacchetti da trasmettere.
203
Real Time Protocol
Voice over IP
A questo punto, si possono presentare le seguenti scelte:
• un pacchetto può contenere più di una ADU: è il caso del segnale vocale, ed il
raggruppamento può migliorare l'efficienza della trasmissione (riducendo l'incidenza dei
byte di intestazione rispetto a quelli di dati), ma può peggiorare il ritardo, e la
degradazione associata alla perdita di un pacchetto;
• una ADU deve essere suddivisa in più pacchetti: è il caso del segnale video, e per evitare il
problema mostrato in figura, è sconsigliabile creare pacchetti che contengono frammenti
appartenenti a ADU divese. Inoltre, dopo un pacchetto perso, quello ricevuto
correttamente può iniziare con un frammento di ADU intermedio, e quindi occorre che i
pacchetti contengano dei marker tali da consentire la ri-sincronizzazione del flusso
multimediale.
Sincronizzazione
Dal lato della riproduzione, una volta che le ADU sono state ricomposte, il jitter è stato assorbito
dal buffer di riproduzione, ed il processo di codifica attuato in partenza è stato invertito,
occorre ristabilire l'esatto ordinamento temporale, in modo che gli intervalli di segnale usati in
partenza, vengano riprodotti con la medesima cadenza. Per questo, il processo di
pacchettizzazione RTP inserisce delle informazioni temporali, tali da mettere in grado il lato
ricevente di svolgere questo compito. Nel caso in cui la trasmissione consista in due o più media
mutuamente sincronizzati prodotti da una medesima sorgente, (come ad esempio un video, ed il
relativo audio), dal lato ricevente occore prevedere l'esistenza di un agente di sincronizzazione,
in grado di usare i riferimenti temporali presenti nei due flussi per controllare entrambi i ritardi
di riproduzione, ristabilendo la corretta sincronizzazione congiunta.
204
Lo strato applicativo di Internet
Alessandro Falaschi
Intestazioni
I campi della intestazione RTP sono stati definiti allo scopo di permettere la soluzione delle
problematiche fin qui accennate, e sono organizzati in tre (o più) gruppi di quattro byte, in
accordo allo schema seguente:
2
3
4
V
P
X
8
CSRC
count
9
M
16bit
Payload type
32bit
Sequence number
Timestamp
Synchronization source (SSRC)
Contributing source (CSRC: variable 0 - 15 items, 2 octets each)
i cui campi sono descritti come
• V (2 bit) indica la versione, che per la RFC 3550 è 2;
• P (1 bit) sta per padding, e se vale 1, indica che nella parte finale del payload sono
presenti dei bytes che non fanno parte del payload stesso;
• X (1 bit) sta per extension, e se vale 1 indica che dopo l'SSRC e gli eventuali CSRC, sono
presenti delle informazioni addizionali a disposizione per il progetto di eventuali
estensioni al protocollo;
• CSRC count o CC (4 bit): il numero di gruppi di 4 bytes identificativi della Contributing
Sources eventualmente presenti;
• M (1 bit) è un Marker, ed è a disposizione della applicazione, per segnalare eventi che per
il PT in uso rivestono una particolare rilevanza sintattica. Ad esempio, è usato per
segnalare l'ultimo dei pacchetti in cui è stata frammentata una ADU relativa ad un frame
video, in modo da riassemblarlo e passarlo al decodificatore, oppure per segnalare l'inizio
di un talkspurt audio, dopo una sospensione dell'invio, associata all'evento di detezione del
silenzio;
• Payload Type o PT (7 bit), identifica il formato del payload mediante un codice numerico,
in accordo a quanto definito da un apposito profilo, come l'AVP, ovvero a codici che
indicano un payload dinamico, a sua volta associato ad un formato specifico mediante un
meccanismo non-RTP, come l'SDP. Qualora RTP sia usato in accordo ad un profilo diverso
da AVP, il byte contenente PT ed M può essere ridefinito con una nuova semantica;
• Sequence number (16 bit), è un contatore monotonicamente crescente che si incrementa
di uno ad ogni paccehtto inviato, e che consente al ricevitore di ristabilire l'ordinamento
originariio, e di rilevare la perdita di pacchetti;
• Timestamp (32 bit), è il numero di campione corrispondente all'inizio dell'ADU contenuta
nel pacchetto. Ad esempio, per un segnale audio campionato 8000 Hz e pacchettizzato
ogni 20 msec, ogni pacchetto contiene 160 campioni, ed il timestamp di pacchetti
successivi si incrementerà di 160. Nel caso in cui qualche pacchetto non venisse
trasmesso, ad esempio in corrispondenza di pause del parlatore, il timestamp subirà una
discontinuità proporzionale al numero di pacchetti soppressi (mentre il sequence number
si incrementerà di uno) Nel caso, ad esempio, di un frame video suddiviso tra più
pacchetti, questi avranno tutti lo stesso timestamp. Due flussi multimediali (ad es. audio
e video) emessi da una medesima sorgente, ma con diversa frequenza di campionamento,
205
Real Time Protocol
Voice over IP
possono essere messi in sincronismo mediante il calcolo, per ognuna di esse, dell'istante di
tempo relativo ai timestamp;
• Synchronization source o SSRC (32 bit), è un numero scelto in modo da identificare
in modo sperabilmente univoco la sorgente che emette i pacchetti relativi ad una
medesima sessione, ed è lo stesso per i diversi flussi emessi da una medesima sorgente.
• Contributing source o CSRC (32 bit) contiene una lista di fino a 15 diverse sorgenti,
ognuna indicata dal proprio SSRC, che prendono parte ad una operazione di missaggio,
come mostrato nella figura seguente. Nel caso in cui un flusso attraversi unicamente un
elemento di transcodifica (o translator), la SSRC di uscita è la stessa di quella di ingresso.
Audio Video Profile
La RFC 3551 descrive un profilo chiamato RTP/AVP, che definisce un insieme di corrispondenze di
default tra i codici dei Payload Type RTP ed i formati di codifica del segnale. Inoltre, lo stesso
documento descrive anche un insieme di formati di codifica audio e video, ossia la sintassi con la
quale il segnale codificato è rappresentato, e contiene riferimenti alle implementazioni di
riferimento dei codificatori. Come anticipato nella discussione sull'SDP, il payload RTP può essere
messo in corrispondenza con un MIME Type mediante gli elementi m= ed a=rtpmap: le RFC 4855
e 4856 specificano le procedure per registrare nuovi formati di payload RTP, e presso IANA è
accessibile un registro dei parametri RTP che sono stati definiti.
Payload statici e dinamici
Un intervallo di codici di Payload Type viene riservato per la descrizione di formati di codifica
statici, ovvero i cui parametri sono pienamente descritti dalla RFC 3551, e per i quali l'elemento
a=rtpmap può essere omesso nell'SDP che descrive la sessione. Ma dato che l'uso di
corrispondenze statiche tra i codici dei PT, ed i formati di codifica, potrebbe determinare il
rapido esaurimento dei codici disponibili, i codici da 96 a 127 sono riservati per poter dichiarare
fino a 32 payload dinamici per una stessa sessione, ovvero associazioni tra un codice di PT ed un
formato di codifica valido solo par la durata della sessione, e identificate in base alla
corrispondenza tra il codice del PT, e l'elemento a=rtpmap ad esso corrispondente, e presente
nell'SDP che definisce la sessione di cui il media fa parte.
Real Time Control Protocol
Come già accennato, l'RTP è affiancato da un protocollo di controllo, l'RTCP, che non trasporta
dati multimediali, utilizza la porta UDP dispari immediatamente superiore a quella (pari)
utilizzata dal flusso RTP a cui è associato, e viene inviato sia dai ricevitori che dai trasmettitori.
Il formato di pacchetto è simile a quello dell'RTP, ed i primi 8 byte hanno la struttura
2
3
8
16bit
32bit
206
Lo strato applicativo di Internet
V
P
count
Alessandro Falaschi
Packet Type
Length
SSRC or CSRC
in cui viene utilizzato il campo PT per indicare un particolare tipo di pacchetto:
• Sender Report o SR (PT 200) ha le stesse informazioni fornite dai RR, ma in più contiene 20
byte di Sender Information, che descrivono
• NTP timestamp: 64 bits, che rappresentano l'ora NTP (espressa in secondi) presso la
sorgente;
• RTP timestamp: 32 bits, è lo stesso valore usato per l'RTP, corrispondente all'ora
NTP;
• sender's packet count: 32 bits, dall'inizio della trasmissione;
• sender's octet count: 32 bits, dall'inizio della trasmissione;
• Receiver Report o RR (PT 201) contiene count elementi di tipo Reception Report, presenti
anche nei SR, che descrive
•
•
•
•
•
il SSRC a cui si riferisce
fraction lost è la percentuale di pacchetti persi dall'ultimo report
cumulative number of packets lost a partire dall'inizio trasmissione
extended highest sequence number received
interarrival jitter è una stima della deviazione standard del tempo di interarrivo
tra pacchetti
• Source Description o SDES (PT 202) contiene count sezioni, per ognuna della quali viene
citato il SSRC o CSRC a cui si riferisce, e sono presentate informazioni ad esso relative,
come CNAME, NAME, EMAIL, PHONE, LOC, TOOL, NOTE, PRIV;
• BYE (PT 203) segnala che una o più sorgenti non sono più attive;
• APP (PT 204) può essere usato per sperimentare estensioni al protocollo.
In uno stesso pacchetto RTCP si può trovare più di una delle sezioni descritte sopra, come ad
esempio il caso in cui un RR viaggia assieme ad una SDES.
Attraversamento NAT e Firewall
I problemi del VoIP con i Firewall ed i NAT sono molteplici, e si può dire, che esistono fin dalle
origini di entrambi.
Firewall
Per quanto riguarda i Firewall, questi sono dispostivi Router (eventualmente realizzati in
Software come applicazioni eseguite presso lo stesso computer sorgente/destinazione del
traffico) che applicano una politica che permette l'ingresso solo del traffico diretto verso un
numero ristretto di porte ben note. Se si è a conoscenza dell'intervallo di porte che RTP userà
per ricevere, possiamo tentare di includerle nella access list del Firewall; altrimenti, questo
dovrebbe essere dotato di un Application Level Gateway in grado di esaminare i messaggi SIP,
rilevare le porte RTP annunciate mediante l'offerta/risposta SDP, ed aprirle. Oppure, lasciare le
porte aperte. Ma allora, che firewall sarebbe?
207
Attraversamento NAT e Firewall
Voice over IP
NAT
Per quanto riguarda i
NAT, anche questi sono
dei router, usati come
Default Gateway
per interconnettere
una LAN (ai cui
computer
corrispondono indirizzi IP privati) con il resto di Internet, ovvero con dispositivi dotati di IP
pubblici. Il Source NAT (SNAT) sostituisce alla coppia (IP, porta)LAN del mittente dei pacchetti
uscita dalla LAN, una coppia (IP, porta)NAT in cui compare il proprio IP pubblico, ed un numero di
porta scelto a caso. Quindi, crea uno stato della connessione, memorizzando questa
associazione.
Nel caso di una connessione TCP uscente, i pacchetti di ritorno sono diretti verso (IP, porta)NAT,
ed il NAT provvede a re-impostare la coppia (IP, porta)LAN originaria. Nel caso dell'UDP usato per
l'RTP, e per SIP, questo meccanismo in generale non funziona, perché
• se l'RTP entrante si presenta al NAT senza un traffico uscente associato, il NAT non sa a
chi mandarlo;
• l'RTCP dovrebbe viaggiare su di un numero di porta pari a quello dell'RTP più uno, mentre
il NAT lo mappa su di un numero di porta qualsiasi;
• l'indirizzo IP che compare nell'elemento Contact dell'SDP presenta un IP privato, che non
viene instradato dai router, e che quinid non pò essere raggiunto dal resto di Internet;
• quando una richiesta SIP su UDP arriva sulla porta 5060 di un NAT, e diretto ad uno UA con
IP privato, il NAT non sa a chi consegnarla.
Certo, se nell'SDP ci fosse scritto l'indirizzo IP pubblico del proprio NAT, anziché quello privato
dello UA, le richieste potrebbero essere istradate dai router di Internet. Inoltre, se l'RTP usasse
lo stesso numero di porta sia per inviare che per ricevere, allora l'RTP uscente abiliterebbe anche
quello entrante, ed i pacchetti potrebbero arrivare. Infine, se le richieste SIP entranti usassero
una porta diversa, per ogni UA raggiungibile, il NAT potrebbe distinguerli l'uno dall'altro. In
estrema sintesi, abbiamo descritto ciò che viene realizzato con le tecniche che andiamo ad
esporre.
Tipi di NAT
Intanto, prendiamo atto che non tutti i NAT sono uguali, e possiamo distinguerli in
208
Lo strato applicativo di Internet
Alessandro Falaschi
• full cone - tutto il traffico entrante verso
(IP, porta)NAT, di qualunque provenienza,
viene diretto verso un unico computer
interno, che può così ospitare un server (ad
es http, smtp, ftp);
• restricted cone - il traffico viene accettato
solo se proveniente da un IP pubblico verso
il quale è già stato inviato traffico uscente,
in tal caso, il trffico entrante è inoltrato al
computer interno che ha generato quello uscente. E' il caso tipico dei router casalinghi;
• port restricted cone - come sopra, con l'ulteriore restrizione che la porta di origine del
traffico entrante, deve corrispondere a quella di destinazione del traffico uscente;
• simmetrici - come sopra, con l'ulteriore restrizione che ogni volta che un IP privato
contatta un nuovo IP pubblico, anche se usa porte sorgente e destinazione già usate, il
NAT sceglie una nuova porta come indirizzo sorgente del traffico uscente. Questo è il caso
tipico per i NAT aziendali.
UDP Hole Punching
Letteralmente, si tratta di bucare il NAT, e consiste nella generazione preventiva di traffico UDP
uscente, per poter poi ricevere quello entrante. Di fatto, questo metodo funziona a patto che
solo uno dei due dispositivi in comunicazione sia NATtato.
SIP Keep Alive
Quando uno UA si registra, invia un pacchetto UDP verso la porta 5060 del Registrar, ed in questo
modo, genera nel NAT la corrispondenza necessaria a ricevere la risposta. Il Registrar osserva la
coppia (IP, porta)NAT da cui proviene la richiesta, ed la usa come Contact Addressdello UA.
Quando successivamente il Registrar riceve un INVITE destinato allo UA, usa questo Contact
Address, e l'INVITE viene felicemente inoltrato dal NAT verso lo UA corretto. Sempre a patto
che.... non sia scaduto il tempo per il quale viene mantenuta l'informazione di stato! Infatti, allo
scopo di poter ri-usare le porte impegnate, dopo che è trascorso un tempo (dai 30 ai 180 secondi)
senza osservare traffico uscente, il NAT dimentica questa corrispondenza. La soluzione a questo
problema, consiste nel continuare a generare traffico uscente, detto keep alive, ad esempio
mediante messaggi SIP di rinnovo registrazione, oppure usando il metodo OPTION, oppure
semplicemente inviando pacchetti UDP vuoti diretti al Registrar.
RTP simmetrico
Mentre per SIP è previsto di usare lo stesso numero di porta UDP sia come sorgente che come
destinazione del traffico, non c'è nulla che prescriva la stessa cosa per l'RTP. D'altra parte, la
possibilità di forare il NAT, consentita dall'uso (presso una entità NATata) della stessa porta
come sorgente e destinazione, ha determinato la formalizzazione (RFC 4961) di questa pratica,
che prescrive per l'entità NATtata, di iniziare a generare traffico in uscita il prima possibile,
usando come numero di porta sorgente, lo stesso numero su cui si desidera ricevere il traffico
entrante, annunciato nell'SDP. A differenza del SIP, nel caso dell'RTP simmetrico, l'entità
corrispondente (non NATtata) può non utilizzare l'RTP simmetrico, e se lo adotta, non è
necessario che usi le stesse porte dell'entità NATtata. Restano comunque ancora aperti
il problemi:
• come fare per rendere nota all'altra entità, la coppia (IP, porta)NAT che userà il proprio
NAT?
• come gestire il fatto che la porta dell'RTCP non viene mappata come quella dell'RTP, più
uno?
209
Attraversamento NAT e Firewall
Voice over IP
Uso di dispositivi esterni
Mentre per SIP, è praticamente certo che il path di segnalazione attraversi un Registrar/Proxy
dotato di IP pubblico, grazie al quale attivare il pinhole del NAT, per l'RTP invece questa
soluzione di fatto non funziona, dato che è molto probabile che entrambi gli UA in
comunicazione siano NATtati. In questo caso, si aprono due alternative:
• fare uso di UA ignari del problema NAT, e delegarne la soluzione ad un elemento
aggiuntivo, situato su di un IP pubblico, con la funzione di proxy RTP, oppure
• utilizzare degli UA che con l'ausilio di elementi esterni, riescono ad inserire nel Contact
Address dell'SDP la coppia (IP, porta)NAT che verrà usata dal proprio NAT.
Session Border Controller o B2BUA
In questo caso, lo UA è completamente ignaro di risiedere dietro un NAT, e deve adottare la
modalità di trasmissione via RTP simmetrico. In queste ipotesi, lo UA può comunicare anche se
anche l'altro UA è NATtato, a patto che un elemento di transito (il Registrar, l'Outbound Proxy,
od un ALG che si trova nel path) ospiti un elemento B2BUA, e modifichi gli indirizzi presenti
nell'SDP in modo da riferire all'entità remota, anziché quelli forniti dall'altro UA, quelli messi a
disposizione da una entità (RTPproxy) attraverso la quale verrà triangolato il traffico RTP. In
particolare:
• nell'SDP di offerta
presente nella
richiesta INVITE,
viene
specificato come
Contact, l'IP
pubblico
dell'RTPproxy, e
come porte usate
dai diversi media,
quelle scelte dall'RTPproxy stesso.
• nell'SDP di risposta presente nella risposta SIP, è nuovamente specificato come Contatto,
quello valido per raggiungere l'RTPproxy
A questo punto, entrambi gli UA, pur credendo di inviare l'RTP direttamente al corrispondente, lo
inviano invece all'RTPproxy. Quest'ultimo, non appena riceve dei pacchetti RTP da uno degli UA,
prende nota dell'IP e della porta mittente, che evidentemente corrispondono al NAT dello UA, in
modo da inoltrare verso di esse, l'RTP proveniente dall'altro UA. Dato che in questo modo,
nessuno UA può ricevere, se prima non ha iniziato a trasmettere, sia per aprire il pinhole nel
NAT, sia per rendere palese l'associazione tra la propria (IP, porta)NAT ed il traffico proveniente
dall'altro estremo, entrambi gli UA iniziano ad inviare l'RTP il prima possibile. L'elemento
RTPproxy può essere co-residente con il B2BUA, oppure essere scelto da quest'ultimo, tra una
serie di alternative possibili, in modo da ridurre al minimo l'aumento di latenza legato al maggior
percorso del traffico RTP.
Nonostante questa tecnica funzioni benissimo, viene criticata in quanto prefigura un vero e
proprio attacco MITM, rendendo problematico un controllo di integrità sui messaggi SIP.
STUN
Simple Traversal of UDP Through NAT (STUN) è l'acronimo della metodologia descritta nella RFC
3489, che utilizza un server STUN presente sulla Internet pubblica, per permettere ad uno UA
NATtato di scoprire il tipo di NAT (o Firewall) presente, qual'é il suo IP pubblico, e quale porta
esterna viene scelta, in corrispondenza alla porta interna utilizzzata dalla UA.
210
Lo strato applicativo di Internet
Alessandro Falaschi
STUN permette la comunicazione
anche tra UA entrambi NATtati,
usando l'RTP simmetrico, ma non
funziona se uno UA è dietro ad un NAT
simmetrico. Gli altri tipi di NAT
infatti, mantengono una specifica
coppia (IP, porta)NAT associata con continuità alla stessa coppia (IP, porta)LAN, per tutto il
periodo di validità. Pertanto lo UA, prima di effettuare una chiamata, contatta il server STUN
usando la stessa (IP, porta)LAN, che userà per l'RTP successivo, in modo che il server STUN gli
comunichi la coppia (IP, porta)NAT corrispondente. Quindi, lo UA userà questi ultimi valori, per
costruire il proprio SDP.
TURN e ICE
Per risolvere il
problema dei NAT
simmetrici, una
proposta IETF
denominata Traversal
Using Relay NAT
(TURN) prevede
ancora che lo UA,
prima di iniziare una
comunicazione,
contatti un server
situato presso
l'Internet pubblica (il server TURN), che stavolta offre anche un servizio di RTPproxy. Il server
TURN comunica quindi allo UA una coppia (IP, porta)TURN che l'RTPproxy ha riservato per gestire
il traffico destinato a quello UA: tutti i pacchetti che l'RTPproxy riceverà su (IP, porta)TURN,
verranno re-inviati alla (IP, porta)NAT associata, permettendo al NAT di consegnarli alla
(IP, porta)LAN corrispondente. A questo punto, lo UA userà la coppia (IP, porta)TURN per costruire
l'SDP da allegare alle chiamate uscenti, come fosse un proprio fermo posta.
A differenza della soluzione realizzata mediante il B2BUA, stavolta è lo UA a decidere cosa fare.
Dato che l'RTPproxy viene a costituire un punto critico della architettura, con potenziali
problemi di scalabilità, e che il suo uso è necessario solo nel caso di un NAT simmetrico, allora è
preferibile usare un server STUN ogni volta che è possibile, e solo in caso di fallimento, usare il
server TURN. Questo è proprio l'approccio seguito dalla proposta IETF detta Interactive
Connectivity Establishment (ICE).
Riferimenti
• Trasmissione multimedia via Internet - RTP, SDP, RTSP, Multicast e Routing, Alessandro
Falaschi 2002, seminario Info-Com
• Video e voce in rete - H.323 & SIP - Alessandro Falaschi 2002, Workshop AICA
• Teledidattica nell'era di SIP - Mbone, OpenMash & SIP - Alessandro Falaschi 2002,
WorkShop Garr @ CNR - Bologna
• voip.html.it
• Applications and Services in Internet, SIP - Jouni Mäenpää
• Henning Schulzrinne - pagina personale
211
Riferimenti
Voice over IP
• Mark Handley - pagina personale
• VoIP: Ready for prime time - video di Madhu Yarlagadda, Director of Engineering, Yahoo!
• Componenti per il VoIP - Presso il Laboratorio di Applicazioni Telematiche
• Componenti per il VoIP: i CODEC
• Architectural Considerations for a New Generation of Protocols - David D. Clark, David L.
Tennenhouse
• Terena IP Telephony Cookbook
• Sippy B2BUA
• Mobile & Wireless Computing
• Telefonia Aziendale e VoIP : studio di soluzioni e realizzazione
• SIP - Call Transfer Enhancements Using the Refer Method - by CISCO
• MediaProxy - by AG Projects
• Security in IP Telephony: selected topics di Saverio Niccolini
• NAT traversal for the SIP protocol by Diana Cionoiu
•
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Marzo 2008
212
Lo strato applicativo di Internet
Streaming
Questo capitolo è un abbozzo. Prossimamente, i suoi contenuti saranno approfonditi ed estesi.
Ciononostante, si desidera inserire fin d'ora qualche accenno e riferimento alla questione.
Introduzione
Per Streaming si intende la trasmissione e la fruizione di contenuti multimediali (audio e/o
video) via Internet in modalità unidirezionale, ossia da una unica sorgente verso uno o più
destinatari, senza che questi ultimi possano (debbano, vogliano) a loro volta inviare contenuti
multimediali indietro al mittente. D'altra parte, sono fatte salve alcune funzionalità che
potremmo definire tipiche di video-registratori e riproduttori di CD, MP3 e DVD, come la messa in
pausa, il riavvolgimento e il fast forward, e l'accesso diretto ad un determinato istante
temporale. Ma anche se l'unidirezionalità di base rende quasi ovvia una impostazione di tipo
client-server della architettura, vi sono molti altri aspetti, come
•
•
•
•
•
•
•
•
•
erogazione di contenuti Live o On-Demand
trasporto basato su UDP o TCP
instradamento unicast o multicast
eventuale coinvolgimento di una CDN o di una distribuzione Peer to peer
compatibiità con altri sistemi di telecomunicazione, come TV analogica o digitale, e
telefonia cellulare
compatibilità con altri sistemi di immagazzinamento multimediale digitale, come il CD,
l'MP3 ed il DVD
scelta dei codec, della banda, della qualità di servizio
indicizzazione e catalogazione dei contenuti
presenza o meno di un sistema di gestione dei diritti (DRM)
che determinano importanti alternative realizzative, così variegate, da causare di fatto un
rallentamento della affermazione della tecnologia. Dal punto di vista delle applicazioni di
erogazione e fruizione dei contenuti, il principale spartiacque può identificarsi nelle alternative
tra soluzioni aderenti a standard pubblici e soluzioni proprietarie.
Le soluzioni aderenti a standard pubblici sono conformi alle indicazioni contenute in documenti
normativi come quelli emessi da IETF, ed hanno l'obbiettivo di favorire l'interoperabilità di
apparati ed applicazioni di fornitori diversi, ma accomunati dal supporto a protocolli comuni
come quello per il controllo (l'RTSP) dell'interazione tra client e server, quelli comuni al VoIP
(l'SDP, l'RTP) per la descrizione ed il trasporto dei contenuti, ed a formati di codifica e
pacchettizzazione descritti da standard pubblici.
Le soluzioni proprietarie tendono invece ad offrire soluzioni integrate, fornendo ad esempio sia i
componenti server che i client, adottando protocolli e codec coperti da brevetto, applicando
sistemi di protezione che impediscono la fruizione non autorizzata.
RTSP
Il Real Time Streaming Protocol è descritto nella RFC 2326, e da allora, soggetto a revisione. E'
un protocollo strettamente Client-Server, e si occupa solo del controllo della riproduzione
(inizio, pausa, posizionamento, arresto), delegando a SDP ed RTP i compiti di descrivere il
RTSP
Streaming
contenuto, e di trasportare i dati multimediali. Sotto molti aspetti somiglia all'HTTP, ma a
differenza di questo è stateful, in quanto la possibilità per il client di mettere in pausa la
riproduzione, obbliga il server a ricordare per la durata della sessione, le informazioni relative ai
suoi client. Svolgiamo un rapidissimo esempio del suo funzionamento, discutendo il seguente
capture, in cui i messaggi inviati dal client sono indicati in rosso:
1 OPTIONS rtsp://labtel.ing.uniroma1.it/spider-man2.mp4 RTSP/1.0
2 CSeq: 9
3 User-Agent: VLC media player (LIVE555 Streaming Media v2007.02.20)
4
5 RTSP/1.0 200 OK
6 Server: DSS/5.5.4 (Build/489.13; Platform/Linux; Release/Darwin; )
7 Cseq: 9
8 Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, OPTIONS, ANNOUNCE, RECORD
9
10 DESCRIBE rtsp://labtel.ing.uniroma1.it/spider-man2.mp4 RTSP/1.0
11 CSeq: 10
12 Accept: application/sdp
13 User-Agent: VLC media player (LIVE555 Streaming Media v2007.02.20)
14
15 RTSP/1.0 200 OK
16 Server: DSS/5.5.4 (Build/489.13; Platform/Linux; Release/Darwin; )
17 Cseq: 10
18 Last-Modified: Fri, 13 Aug 2004 03:20:55 GMT
19 Cache-Control: must-revalidate
20 Content-length: 1223
21 Date: Tue, 08 Apr 2008 04:48:00 GMT
22 Expires: Tue, 08 Apr 2008 04:48:00 GMT
23 Content-Type: application/sdp
24 x-Accept-Retransmit: our-retransmit
25 x-Accept-Dynamic-Rate: 1
26 Content-Base: rtsp://labtel.ing.uniroma1.it/spider-man2.mp4/
27
28 v=0
29 o=StreamingServer 3416618880 1092367255000 IN IP4 151.100.122.171
30 s=/spider-man2.mp4
31 u=http:///
32 e=admin@
33 c=IN IP4 0.0.0.0
34 t=0 0
35 a=control:*
36 a=isma-compliance:1,1.0,1
37 a=mpeg4-iod: "data:application/mpeg4-iod;base64,AoCAgxsAT///DwP/
A4CAghgACUD0ZGF0YTphcHBsaWNhdGlvbi9tcGVnNC1vZC1hdTtiYXNlNjQsQVlDQWdSVUJnSUNBT1FLZkE0Q0FnRElBQVFBRWdJQ0FGVUFWQUFFVEFBQ
38 a=range:npt=0- 126.45500
39 m=audio 0 RTP/AVP 96
40 a=control:trackID=5
41 a=rtpmap:96 mpeg4-generic/22050/2
42 a=mpeg4-esid:1
43 a=fmtp:96 streamtype=5; profile-level-id=15; mode=AAC-hbr; config=139000; SizeLength=13; IndexLength=3; IndexDel
44 m=video 0 RTP/AVP 97
45 a=control:trackID=8
46 a=rtpmap:97 MP4V-ES/6003
47 a=mpeg4-esid:2
48 a=fmtp:97 profile-level-id=1; config=000001b003000001b509000001000000012000845d4c283c2080a31f;
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
SETUP rtsp://labtel.ing.uniroma1.it/spider-man2.mp4/trackID=5 RTSP/1.0
CSeq: 11
Transport: RTP/AVP;unicast;client_port=32906-32907
User-Agent: VLC media player (LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK
Server: DSS/5.5.4 (Build/489.13; Platform/Linux; Release/Darwin; )
Cseq: 11
Last-Modified: Fri, 13 Aug 2004 03:20:55 GMT
Cache-Control: must-revalidate
Session: 6519445514613088315
Date: Tue, 08 Apr 2008 04:48:00 GMT
Expires: Tue, 08 Apr 2008 04:48:00 GMT
Transport: RTP/AVP;unicast;source=151.100.122.171;client_port=32906-32907;server_port=6970-6971;ssrc=3C06B58A
SETUP rtsp://labtel.ing.uniroma1.it/spider-man2.mp4/trackID=8 RTSP/1.0
CSeq: 12
Transport: RTP/AVP;unicast;client_port=32910-32911
Session: 6519445514613088315
214
Lo strato applicativo di Internet
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
Alessandro Falaschi
User-Agent: VLC media player (LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK
Server: DSS/5.5.4 (Build/489.13; Platform/Linux; Release/Darwin; )
Cseq: 12
Session: 6519445514613088315
Last-Modified: Fri, 13 Aug 2004 03:20:55 GMT
Cache-Control: must-revalidate
Date: Tue, 08 Apr 2008 04:48:00 GMT
Expires: Tue, 08 Apr 2008 04:48:00 GMT
Transport: RTP/AVP;unicast;source=151.100.122.171;client_port=32910-32911;server_port=6970-6971;ssrc=0E4A8A71
PLAY rtsp://labtel.ing.uniroma1.it/spider-man2.mp4/ RTSP/1.0
CSeq: 13
Session: 6519445514613088315
Range: npt=0.000User-Agent: VLC media player (LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK
Server: DSS/5.5.4 (Build/489.13; Platform/Linux; Release/Darwin; )
Cseq: 13
Session: 6519445514613088315
Range: npt=0.00000-126.45500
RTP-Info: url=rtsp://labtel.ing.uniroma1.it/spider-man2.mp4/trackID=5;seq=1461;rtptime=700028915,url=rtsp://labt
TEARDOWN rtsp://labtel.ing.uniroma1.it/spider-man2.mp4/ RTSP/1.0
CSeq: 14
Session: 6519445514613088315
User-Agent: VLC media player (LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK
Server: DSS/5.5.4 (Build/489.13; Platform/Linux; Release/Darwin; )
Cseq: 14
Session: 6519445514613088315
Connection: Close
Il client inizia il dialogo interrogando il server a riguardo dei metodi disponibili, mediante il
metodo OPTIONS. Come si vede, anche in questo caso i messaggi convogliano
informazioni semantiche mediante l'uso di intestazioni, come Cseq, che si incrementa di uno ad
ogni nuovo messaggoi del client, ed è citato uguale nella relativa risposta.
Alla riga 5 il sever risponde con una sintassi ormai nota, formata da una prima linea contenente
un codice numerico di successo, ed alla riga 10 il client passa a chiedere la descrizione di una URI
di cui si desidera la riproduzione. Questa descrizione è fornita nella risposta di riga 15, mediante
un elemento SDP contenuto nel body della risposta stessa. Notiamo che negli header di questa
risposta sono presenti elementi indicanti la data del contenuto originario, la data attuale,
intestazioni dedicate ai proxy ed al controllo cache, ed intestazioni più propriamente dedicare
allo streaming. Per quanto riguarda l'SDP, notiamo una serie di linee a= (righe 36-38) mediante le
quali si asserisce l'adesione alle specifiche ISMA, un Initial Object Descriptor di mpeg4, e la
durata in secondi dell'intero clip. Quindi, alla linea 39 troviamo la linea a= relativa all'audio,
associato al payload type dinamico 96, e per il quale non è ancora stata negoziata una porta. Le
linee 40-43 indicano che l'audio è associato alla traccia 5 (il file da cui si parte, contiene audio e
video del clip multiplati assieme nello stesso file, ma suddivisi in differenti tracce), e che il PT
96 corrisponde ad un audio mpeg4, campionato a 22050 Hz, stereo, più altre indicazioni
specifiche. Le righe 44-48 descrivono invece il media video, associato al PT dinamico 97,
corrispondente ad un MP4, presente sulla traccia 8 del file originale.
Il server RTSP dovrà demultiplare i flussi audio e video presenti nel file originale, e generare per
ognuno di essi un diverso flusso RTP, mantenendo per questi la possibilità di rimanere
sincronizzati.
Alla riga 49 il client inizia a predisporre il server alla trasmissione, comunicando (riga 51) le
porte su cui intende ricevere RTP ed RTCP per quanto rigurda l'audio, che sono riscontrate dal
215
Soluzioni Proprietarie
Streaming
server alla riga 62; inoltre alla riga 59 il server assegna alla richiesta un identificativo di
sessione. Questo identificativo è citato alla riga 67, assieme alla richiesta di SETUP pe il media
video (riga 64), che viene a sua volta riscontrato dal server con la risposta che inizia alla riga 70.
Finalmente, alla riga 80 il client richiede il PLAY dei media associati alla sessione appena
definita, riscontrato dal sever alla riga 86. Infine, la riga 93 rappresenta la richiesta del client di
arrestare la riproduzione.
Soluzioni Proprietarie
Real
Real Networks è il fornitore di una architettura di streaming composta da server (Helix, versione
di valutazione), client (RealPlayer), encoder (RealProducer), e codec (RealAudio, RealVideo).
Può essere ritenuta la prima soluzione commerciale per la distribuzione multimediale su
Internet. Mentre la componente di controllo è attuata in accordo all'RTSP, il trasporto usa
(preferenzialmente) un protocollo proprietario (RDT), così come anche il codec non segue gli
standard pubblici. Viene inoltre definito un formato di descrizione indicato come Real Audio
Metadata (.ram), ed un linguaggio di sincronizzazione tra contenuti multimediali e presentazioni
testuali, il Synchronized Multimedia Integration Language (.smil). Infine, il player è in grado di
riprodurre anche altri formati e contenitori, e gran parte del codice sorgente alla base della
soluzione di Real, è stato rilasciato con licenza OpenSource.
Windows Media
Vedi Wikipedia
Quicktime
Vedi Wikipedia
Flash
Il plugin Flash di Adobe risulta installato nel 99% dei browser web, ed anche se la riproduzione
video risulta penalizzata rispetto ad applicazioni client indipendenti, la sua estrema diffusione è
la ragione principale della sua adozione quasi universale. Per diverso tempo questo plugin si è
limitato a riprodurre files ShockWaveFlash (con estensione .swf), un formato proprietario di
grafica vettoriale, che si è poi evoluto a formato contenitore di codifiche multimediali.
Successivamente, si è definito un ulteriore formato detto Flash Video (con estensione .flv), che
può essere riprodotto anche da un player esterno al browser. Un file flv può essere ricevuto
come singolo oggetto per una successiva riproduzione, oppure visionato durante la ricezione in
forma di download progressivo HTTP, o in streaming RTMP. Nonostante la licenza proprietaria
neghi il diritto di sviluppare un Player diverso, ne esistono diverse realizzazioni indipendenti.
Riferimenti
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Aprile 2008
216
Lo strato applicativo di Internet
Alessandro Falaschi
217
Lo strato applicativo di Internet
Mondo Linux
In questa sezione (senza pretese), riportiamo descrizioni,
commenti e riferimenti per l'uso di base di Linux come
strumento di studio, di lavoro e di sviluppo
• Diritti e privilegi
•
•
•
•
Diritti degli utenti e permessi dei file
Diritti dei programmi
Diritti di apertura dei socket
Sudo
• Comandi da tastiera
•
•
•
•
•
Wildcard
Il filesystem
La shell
Tasti utili
Variabili di ambiente
• Genealogia
• Variabili famose
• Processi
•
•
•
•
•
•
Redirezione
Pipe
Process ID
Background e terminazione
Chiamate di sistema
Script di Init
• Riferimenti
Diritti e privilegi
Svolgiamo qui una breve digressione a riguardo del sistema degli utenti offerto da Linux, e di
come questo si riallacci alle questioni inerenti il lancio di processi server.
Diritti degli utenti e permessi dei file
Ad ogni file presente sul disco, sono associati degli attributi, mostrati eseguendo il comando ls
con l'opzione -l:
[alef@localhost ~]$ ls -l
totale 436
drwxrwxr-x 2 alef alef
4096
-rw------- 1 alef alef 96703
drwxrwxr-x 2 alef alef
4096
drwxrwxr-x 2 alef alef
4096
-rw-r--r-- 1 root root 129142
drwxrwxr-x 3 alef alef
4096
drwxrwxr-x 12 alef alef
4096
drwxrwxr-x 4 alef alef
4096
22
19
18
12
13
31
25
24
gen
gen
gen
dic
dic
ott
gen
gen
16:04
16:06
09:37
17:09
14:38
18:37
00:17
23:34
autosave
autosave.xmi
bin
citta_utopia
enum+39069090611.cap
images
infocom
t
Lo strato applicativo di Internet
Alessandro Falaschi
Il primo carattere indica in qualche modo il tipo i file, e nel caso di una directory, prende il
valore d, mentre per un file regolare, si ha un trattino -. Seguono 3 gruppi di tre caratteri del
tipo rwx, in cui una o più lettere posono essere sostituite da -. Ogni gruppo è una
rappresentazione leggibile di tre bit, che rappresentano rispettivamente la possibilità per il file
di essere letto (read), scritto (write) ed eseguito (executed), per il proprietario del file, per chi
appartiene al gruppo a cui è assegnato al file, e per il resto del mondo. La differenza tra i tre
gruppi di lettere sarà chiara dopo aver descritto l'organizzazione degli utenti in Linux.
Il creatore del file, è quello il cui nome compare nella terza colonna; in Linux, ogni utente può
appartenere ad uno o più gruppi, mentre i files possono appartenere ad un solo gruppo, descritto
dal nome che compare nella quarta colonna. Se un utente vuole operare su di un suo file, si
applicano i diritti descritti dal primo gruppo di lettere; se invece il file non è suo, ci sono due
possibilità:
• o uno dei gruppi di cui l'utente fa parte, è proprio il gruppo a cui è associato il file, ed in
tal caso per l'utente valgono i privilegi descritti dal secondo gruppo di lettere, oppure
• il file è assegnato ad un diverso gruppo di cui l'utente non fa parte, ed allora valgono i
privilegi del terzo gruppo di lettere.
Per impostare il proprietario e il gruppo del file prova.txt si può usare il comando chown (change
owner)
chown utente.gruppo prova.txt
mentre per modificare i tre gruppi di permessi, si usa il comando chmod
chmod ABC prova.txt
in cui ABC rappresenta un numero di tre cifre ottali, ognuna delle quali codifica i tre bit dei
permessi rwx, dando alla r peso 4, alla w peso 2 ed alla x peso 1, in accordo allo schema
219
Mondo Linux
Permessi
ABC
Descrizione
rw-r--r--
644
L'utente proprietario può accedervi in lettura e scrittura (4+2=6), mentre sia gli
appartenenti al gruppo, sia gli altri utenti, possono solo accedervi in lettura.
rwxr-x---
750
L'utente proprietario può accedervi in lettura, scrittura ed esecuzione (4+2+1=7);
gli utenti appartenenti al gruppo possono accedervi in lettura e in esecuzione
(4+1=5); gli altri utenti non possono accedervi in alcun modo.
rw-------
600
L'utente proprietario può accedervi in lettura e scrittura (4+2=6), mentre tutti gli
altri non possono accedervi affatto.
Diritti dei programmi
Per eseguire un programma, non è sufficiente che il suo codice eseguibile sia contenuto in un
file, ma occorre che il file sia anche dichiarato eseguibile, e che l'utente che intende eseguirlo,
sia in possesso dei diritti di esecuzione. Quando un programma viene eseguito, eredita l'identità
ed il gruppo dell'utente che lo ha lanciato; in particolare, il programma potrà eseguire solo le
operazioni che sono possibili per l'utente stesso: potrà cioè leggere/scrivere solo in directory che
sono a loro volta leggibili/scrivibili da tale utente. Quindi, anche se un programma appartiene a
root (che è il super utente di amministrazione, che può fare qualunque cosa, senza rispetto per
i permessi vigenti), quando questo viene lanciato da un "utente normale", i diritti del programma
sono gli stessi dell'utente che lo ha lanciato.
Diritti di apertura dei socket
Le porte ben note su cui si pongono in ascolto i demoni di un server, con un indirizzo di trasporto
(porta) inferiore a 1024, per essere eseguiti, devono possedere i privilegi di root. Il motivo di
questa scelta risiede nella considerazione che, essendo tali programmi in grado di rispondere a
richieste di servizio esterne, devono essere sotto il diretto controllo dell'amministratore del
computer. Ciò non toglie che sia possibile, per root, di delegare ad un utente qualunque la
possibilità di lanciare il programma: ciò è possibile, agendo su di un ulteriore attributo del file, il
bit suid (Set User IDentity), che quando è settato, permette al programa di girare con i privilegi
del proprietario del programma, anzichè con quelli di chi l'ha lanciato. Un programma lanciato in
questo modo, in genere, dopo aver completato le operazioni per le quali sono necessari i privilegi
di root, come ad esempio aprire socket su porte ben note ed i files di log, cede i propri privilegi,
e torna ad assumere quelli di un utente non privilegiato, invocando la system call setuid(). In
questo modo, se durante la sua esecuzione si dovesse verificare una qualche situazione non
prevista, che potesse portare il programma ad effettuare operazioni che potrebbero
compromettere la sicurezza del sistema, il programma stesso non potrà arrecare danni a nessuna
configurazione critica, proprio in virtù dei bassi privilegi di cui gode. Quanto esposto, è una delle
ragioni della scarsa attaccabilità di un sistema Unix, rispetto ad altri.
Sudo
Quando un utente non privilegiato ha necessità di accedere a delle risorse concesse solo a root,
oppure di eseguire un programma come root, deve diventare root mediante il comando
su -
ed inserire la password di root; l'opzione meno (-) provoca l'esecuzione del .bashrc di root, e
quindi la definizione delle variabili di ambiente previste per root. Al termine delle operazioni,
l'utente può tornare in sè con la combinazione di tasti Control-d. Nel caso si dimentichi di
farlo, continuerà a lavorare come root, con il rischio di modificare inavvertitamente files
220
Lo strato applicativo di Internet
Alessandro Falaschi
importanti, o di creare files che poi come utente non privilegiato, non riuscirà più a modificare.
Questa rigida suddivisione di ruoli tra super-utente e utenti non privilegiati, oltre che offrire
una maggiore sicurezza, affonda le sue radici nel tempo in cui un unico computer era usato allo
stesso tempo da utenti diversi, ed era amministrato da una terza persona. Attualmente, è molto
più probabile che il computer sia usato da una unica persona, contemporaneamente utente ed
amministratore; oppure, che chi possiede la password di root non desideri "darla in giro" così
facilmente, e nemmeno dover ogni volta andare ad immetterla di persona. Inoltre, l'utente root
potrebbe voler esplicitamente delegare a qualche utente non privilegiato, l'esecuzione di alcuni
compiti particolari. Per questi motivi, si è nel tempo affermato il meccanismo previsto dal
comando sudo (Super User DO), che permette ad un utente non privilegiato di assumere
l'identità di root per il tempo strettamente necessario alla esecuzione di un comando,
immettendo
sudo comando
seguito dalla propria (di utente non privilegiato) password; infatti, in questo caso occorre
solamente sincerarsi che l'utente sia proprio lui, in quanto abilitato ad eseguire quel comando
con i privilegi di root, e non qualcun altro che per caso passa davanti al computer lasciato
incustodito da chi aveva acceduto inizialmente. Al termine della esecuzione del comando,
l'utente riprende automaticamente la propria identità. L'utente root può, editando il file /etc/
sudoers, abilitare i diversi utenti, ad eseguire uno o più comandi con i privilegi di root; una sua
configurazione particolarmente permissiva, permette di far fare tutto a tutti.
Comandi da tastiera
Benché anche con un sistema Linux, si possa fare praticamente tutto senza togliere la mano dal
mouse, l'uso dei comandi da tastiera permette da un lato di comprendere meglio ciò che
succede, e dall'altro costituisce spesso il modo più rapido di eseguire un comando,
indipendentemente dall'interfaccia grafica, a partire dalla memoria della sua sintassi. In rete
esistono diversi tutorial relativi a questi aspetti, come MPL, AIL, ML, UFI, IGL, a cui è
sicuramente opportuno far riferimento per una trattazione un minimo più dettagliata, rispetto a
quella che brevissimamente riassumiamo qui. Si tenga comunque presente che è prassi comune,
in caso di dubbio, invocare i comandi con l'opzione -h oppure --help, per avere un breve
riassunto della modalità di chiamata.
comando
utilizzo
man comando
visualizza la manpage del comando, che ne spiega la funzione, e le opzioni possibili
apropos chiave
visualizza i comandi per i quali chiave compare nella rispettiva manpage
which comando
mostra in quale directory (tra quelle elencate in $PATH) si trova il comando
echo $VAR
mostra il valore della variabile di ambiente VAR, che può essere assegnato mediante
il comando set VAR=valore
ls
lista i contenuti di una directory
pwd
print working directory - dice dove ci si trova
cd path
change directory - per spostarsi, in modo assoluto (sui path che iniziano per /) oppure
relativo (path iniziano con il nome di sotto-directory, oppure ../ per specificare la
directory padre)
cp file1 file2
copy - copia file1 in file2
mv file1 file2
move - rinomina file1 in file2
rm file
remove - cancella (irreversibilmente!) un file
mkdir dir
make directory - crea una directory
rmdir dir
remove directory - rimuove una directory (se è vuota)
221
Mondo Linux
tar
tape archive - comprime/scomprime un archivio con estensione .tar o .tar.gz o .tgz (ma esiste
anche zip/unzip)
ln -s file1 file2
link - crea un collegamento simbolico file2 che punta al file esistente file1
cat file
concatenate - stampa a schermo il contenuto di un file di testo. Se invocato con più
argomenti, li stampa uno dopo l'altro, e se stdout è rediretto su di un file, si
ottiene il risultato di concatenarli tra loro (da cui, il nome del comando)
tail file
visualizza le ultime 10 linee di file, molto utile l'opzione -f che non ritorna, e dopo
le ultime 10 linee, visualizza anche le aggiunte che qualche altro programma fa al
file
less file
visualizza un file di testo, e permette di navigarci all'interno mediante le frecce
della tastiera, Pgup/Pgdown, Home/End. Per cercare una stringa dentro il file, inserire
/stringa
sort
ordina stdin e scrive il risultato su sdtout, molto utile se messo in pipe con altri
comandi, o se si fa uso della redirezione di ingresso/uscita
df
disk full - mostra l'occupazione del disco, mentre du (disk usage) mostra le dimensioni di
files/directory
chmod modo file
change mode - modifica i peremssi associati al file
chown gruppo.utente change owner -
modifica i proprietario di un file, settando utente e gruppo (facoltativo)
passwd
permette di cambiare la propria password
su utente
permette di diventare un altro utente, fornendo la sua password. Se l'utente non è
specificato, si può divenire root; se viene inserita l'opzione - (meno) verrano usate
le variabili di ambiente di quell'utente
lpq
line printer queue - mostra la coda dei lavori da stampare
lprm numero
line printer remove - rimuove una stampa dalla coda. Utile qualora per sbaglio si prenotano
stampe per errore, e ci si ripensi
kill -segnale pid invia un segnale al processo pid
ps ax
processes - visualizza un elenco dei processi in esecuzione sul computer. Sono a volte
utili anche le opzioni u per conoscere gli utenti, f per capire chi è figlio di chi, w
per mostrare il comando per intero e non troncarlo alla larghezza della finestra
grep stringa file
cerca in file l'occorrenza di stringa. Molto utile se messo in pipe con l'uscita di un
altro comando, ad esempio ps, nel qual caso non occorre specificare file, dato che viene
usato stdin. Se per file si specifica *, la stringa è cercata in tutti i file della
directory, mentre specificando l'opzione -nr, la ricerca avviene in modo recursivo
anche in tutte le sotto-directory, e vengono stampati i numeri di linea in cui si è
trovata l'occorrenza di stringa.
top
mostra interattivamente i processi correnti, dando la possibilità di ordinarli in base
ad esempio all'uso di CPU, di memoria o di durata
Inoltre, la comunità Debian ha prodotto una simpatica Quick Reference Card, da stampare su di
un solo foglio.
Wildcard
Diversi dei comandi riportati, possono accettare come argomento, più di un singolo nome di file.
In tal caso, può essere utile descrivere un insieme di files dai nomi simili, per mezzo di caratteri
jolly, in grado di corrispondere a caratteri qualunque: in particolare, il simbolo * (asterisco)
corrisponde ad una stringa qualunque, mentre il simbolo ? (punto interrogativo) corrisponde ad
un carattere singolo qualunque. Quindi ad esempio, possiamo scrivere
cat *
cat fi*
cat fi?e
# concatena tutti i files presenti
# concatena tutti i files presenti, che iniziano per "fi"
# concatena tutti i files con nome ad es pari a file, fice, fide, fine, fife...
222
Lo strato applicativo di Internet
Alessandro Falaschi
Il filesystem
Ogni file è contenuto dentro una directory, che a sua volta può contenere altre sotto-directory.
Il termine directory, ad un certo punto della storia, è stato tradotto in italiano come "cartella". Il
filesystem rappresenta l'ordinamento gerarchico di tutte le directory presenti sul disco. Possiamo
spostarci da una directory all'altra mediante il comando cd (change directory). Tra le directory,
notiamo
•
•
•
•
•
la directory / è quella (root o radice) entro cui sono contenute tutte le altre;
./ indica la directory corrente;
../ indica la directory (genitore) entro cui è ospitata la directory in cui ci troviamo;
pwd (print working directory) è un comando che ci informa in quale directory ci troviamo;
la directory /home/utente è la casa di utente, a volte indicata come ~ (il simbolo ~ si
ottiene come AltGr+ì), ed infatti ci si può arrivare immettendo cd ~. Quando utente
effettua il login, si trova nella sua home, che usualmente contiene files su cui utente ha
pieni diritti;
• per referenziare un file
• presente nella directory in cui ci troviamo, lo indichiamo come file
• presente nella directory genitore, lo indichiamo come ../file
• presente da tutta una altra parte, lo indichiamo come /dir1/dir2/file.
Questo si chiama path (percorso), che può essere
• assoluto, se inizia con /, oppure
• relativo, se non inizia con / . Ad es.:
• se inizia con ../ saliamo di un livello, con ../../ di due livelli, per
poi eventualmente ri-scendere
• se inizia con dir1/, ci stiamo riferendo ad una nostra sotto-directory
• i files il cui nome inizia con un punto (es ~/.bashrc) sono chiamati files nascosti, e non
vengono mostrati con il normale comando ls (ma compaiono con ls -a). In generale,
sono usati per memorizzare le informazioni di configurazione dei programmi utilizzati, e
non vengono mostrati, per non creare confusione inutile.
Nel mondo Linux e Unix, si è sviluppata una iniziativa per rendere la struttura gerarchica delle
directory il più possibile simile tra sistemi diversi, in modo da favorire l'interoperabilità delle
piattaforme. Questo ha portato ad una specializzazione delle diverse directory, in accordo a
questa tabella:
Directory
Utilizzo
/bin
qui risiedono molti dei files eseguibili
/etc
contiene tutti i files di configurazione, spesso suddivisi directory individuali per i
diversi programmi
/lib
ospita le librerie, spesso in forma di shared object (estensione .so), ed i links alle
versioni specifiche delle stesse
/home
contiene le sottodirectory associate alle case dei diversi utenti
/proc
rappresenta un filesystem virtuale, che non esiste fisicamente, ma i cui files sono creati
al volo dal kernel quando vengono visitati. Costituisce una modalità di comunicazione tra
user-space e kernel
/sbin
ospita files eseguibili solo da root
/var
contiene files e sotto-directory i cui contenuti possono variare di molto, come ad esempio
/var/log per i files di registro, e /var/spool per l'email e le code di stampa
223
Mondo Linux
Directory
Utilizzo
/usr
acronimo di Unix System Resources, è stata definita per ospitare dati condivisi tra diversi
computer, e non dovrebbe contenere configurazione specifiche
A volte, parte di questa struttura viene ripetuta ricorsivamente, così ad esempio all'interno della
/usr, è possibile trovare /usr/bin, /usr/etc, /usr/lib... ma anche cose più specifiche,
come /usr/src per i files sorgente, /usr/include per i .h, /usr/share/doc con la
documentazione dei pacchetti installati. Infine, in /usr/local trovano spesso posto dei files
creati dall'utente, od importati in forma di sorgente.
La shell
Vuol dire conchiglia, ed è il programma che interpreta ed esegue i comandi immessi dall'utente,
e viene eseguito automaticamente dal sistema quando un utente effettua il login. I comandi,
oltre che poter essere immessi da tastiera, possono anche essere contenuti in un file che, pur
essendo di solo testo, è classificato come eseguibile; questo file viene chiamato file di comandi o
script, e contiene una sequenza di comandi ed istruzioni dello stesso tipo di quelle che
potremmo immettere da tastiera, assieme ad instruzioni di controllo, come quelle di loop (es.
for) e diramazione (es if).
Esistono diverse shell sotto Unix, ma la più diffusa con Linux è bash, o Bourne Again Shell. Come
un qualunque linguaggio di programmazione che si rispetti, anche la shell ha le sue variabili, che
prendono il nome di variabili di ambiente.
Quando viene impartito un comando mediante un terminale, questo viene prima analizzato dalla
shell, per vedere se si tratti di un comando che può eseguire autonomamente. Un elenco di
questi comandi può essere scoperto invocando help. Se il comando non è un comando interno,
allora viene effettuata una ricerca all'interno delle directory specificate dalla variable di
ambiente PATH, per trovare un eseguibile denominato come il comando invocato. Se invece il
comando inizia per ./, allora deve corrispondere ad un file presente nella directory corrente, con
il bit di esecuzione settato, contenente un programma compilato, oppure ad uno script.
Tasti utili
La shell, ed alcuni programmi, attribuiscono a tasti particolari, funzioni particolarmente utili.
Mentre dialoghiamo con la shell
• il tasto freccia in su permette di ritrovare i comandi immessi per ultimi, in modo che se li
dobbiamo re-impartire di nuovo, non serva di digitarli daccapo;
• la combinazione Shift+PageUp (o PageDown) permette di scrollare l'output video più
recente, in modo da poter leggere di nuovo le informazioni ormai passate;
• il tasto Tab permette l'auto-completamento dei comandi: se ad esempio, dobbiamo
immettere un comando particolarmete lungo, o di cui non ricordiamo esattamente
l'ortografia, digitando solamente le prime lettere, seguite dal tasto Tab, la shell ci
propone una serie di alternative, composta da tutti i comandi che condividono la stessa
sotto-stringa iniziale. Aggiungendo di volta in volta lettere alla nostra abbreviazione,
arriviamo al momento in cui c'è un solo comando con quel prefisso, che ci viene proposto
per intero, ed a quel punto, è sufficiente premere Return per eseguirlo;
• la combinazione Ctrl+c interrompe il programma in corso;
• la combinazione Ctrl+d interrompe una sequenza di input. Esempio: immettiamo il
comando sort, che accetta l'insieme di righe da ordinare da standard input. Inseriamo
una serie di parole da ordinare, separate dal tasto Retrun (o Invio), e per finire, usiamo la
sequenza Ctrl+d.
224
Lo strato applicativo di Internet
Alessandro Falaschi
Durante l'osservazione del risultato ottenuto con il comando less:
• i tasti > e < portano rispettivamente a fine ed inizio del file
• i tasti freccia su e freccia giù scrollano di una riga, PageUp e PageDown di una
pagina
• mentre sull'ultima riga compaiono i due punti (:), sono possibili comandi e combinazioni di
tasti, possibili anche durante la lettura delle pagine di manuale con man, e durante
l'editing di un file con vi:
• la sequenza /stringa ricerca l'occorrenza di stringa all'interno dell'output di
less
• il tasto q (quit) consente l'uscita da less
Variabili di ambiente
Le variabili di ambiente prendono questo nome per il fatto che esistono al difuori di un
determinato programma, e costituiscono in tal senso una sorta di "ambiente" in cui il programma
viene eseguito. Nell'ambiente definito da una finestra terminale, e quindi delimitato da una shell
interattiva, possiamo assegnargli un valore mediante la classica sintassi in cui compare il segno
di uguale (senza spazi). Per accedere invece al loro valore, occorre farle precedere dal segno $.
Ad esempio
~$ SEDE=Cisterna
~$ echo $SEDE
Cisterna
# assegnamo un valore alla variabile SEDE
# chiediamo la stampa del suo valore
# il valore è stampato
Due programmi eseguiti in sequenza possono passarsi dei valori mediante le variabili di
ambiente, se il primo le setta, ed il secondo le legge. Attribuendo loro un valore mediante la
sintassi
~$ export SEDE=Cisterna
ne definiamo l'ereditarietà, ovvero estendiamo l'ambiente in cui sono definite, permettendone la
lettura anche da parte dei processi figli. Alcuni esempi di variabili di ambiente, possono essere
ottenuti con il comando man environ; mentre la lista di quelle attualmente definite, con il
comando env.
Genealogia
Dopo aver chiuso la shell entro la quale abbiamo definito delle nuove variabili di ambiente,
queste cessano di esistere. Ci chiediamo allora: da dove hanno origine quelle che osserviamo già
esistenti, quando apriamo una nuova finestra terminale ? Hanno due origini:
• alcune sono definite dallo script .bashrc presente nella home directory, che viene
eseguito da bash al suo avvio. Il suffisso rc è comune a molti files di inizializzazione, e sta
per run commands.
• altre sono ereditate a partire da processi genitori (od anche nonni) sopra la nostra shell; in
particolare, il processo init che parte per primo, è il genitore di tutti, e definisce
l'ambiente comune a tutti gli altri processi
225
Mondo Linux
Variabili famose
Una variabile d'ambiente particolarmente importante, è PATH, che contiene una serie di path
separati da due punti, che indicano in quali directory cercare, per tentare di eseguire un
comando immesso da tastiera. Le directory vengono esaminate nell'ordine con cui compaiono,
per cui possono esistere due eseguibili con lo stesso nome, in due diverse directory, ma verrà
sempre eseguito quello ospitato nella directory esaminata per prima.
Se vogliamo eseguire un comando presente nella directory in cui ci troviamo, occorre lanciarlo
come ./programma. Non è consigliabile inserire ./ nel PATH, perchè potremmo
inavvertitamente mascherare un programma dallo stesso nome.
Altre variabili famose, sono $HOME, $LD_LIBRARY_PATH, $DISPLAY...
Processi
Redirezione
Ogni programma al momento della sua esecuzione, ha tre file già aperti, denominati standard
input, standard output e standard error (stdin, stdout, stderr) che di default, sono collegati
all'input da tastiera, all'output su schermo, ed all'output dove scrivere gli errori (sempre lo
schermo). E' molto facile redirigere l'uscita, anzichè sullo schermo, dentro un file, così come
redirigere il contentuto di un file, come se fosse immesso da tastiera, mediante i simboli < e >
(minore e maggiore).
Pipe
Le pipe (tubature) permettono di costruire comandi più complessi a partire da quelli a
disposizione, redirigento l'uscita di uno verso l'ingresso dell'altro, semplicemente immettendo i
due comendi sulla stessa riga, separati dal simbolo di barra (es comando1 | comando2).
Ad esempio, possiamo provare ad immettere
~$ cd /
~$ ls -R
<control>-c
~$ ls -R | less
~$ ls | sort
#
#
#
#
#
#
#
ci portiamo alla root del file system
scopriamo tutti i files nel nostro computer
interrompiamo lo scroll
l'uscita di ls viene diretta in ingresso a less,
che ne effettua la paginazione
l'uscita di ls viene diretta in ingresso a sort,
che ne effettua l'ordinamento
Process ID
Ad ogni processo in esecuzione, viene assegnato un numero chiamato PID, che lo identifica
univocamente, e he permette di interagire con lo stesso, ad esempio inviandogli segnali o
terminandolo. Ad ognuno di questi, corrisponde una directory nel flesystem virtuale /proc.
Per conoscere il PID dei processi in esecuzione si utilizza il comando ps, che senza altre opzioni,
indica solamente i processi lanciati a partire dalla shell corrente. Un gruppo di opzioni
comunemente usate, è ps auxf, che (a) li mostra tutti, indicandone (u) l'utente che li ha
lanciati, comprendendo anche (x) quelli lanciati da un altro processo non-shell, e nostra chi è
figlio di chi. Oltre al PID, ps mostra in una serie di colonne, diversi altri parametri associati ai
226
Lo strato applicativo di Internet
Alessandro Falaschi
processi.
Un diverso modo per valutare l'attività del sistema, è di eseguire il comando top, disponibile
assieme alle utilities del packacage procps. Mediante top, si ha una schermata in real-time in
cui i processi sono ordinati in base all'ammontare di risorse impiegate, come ad esempio la CPU,
o la memoria. Mentre top è in esecuzione, si può (con il tasto k) inviare un segnale ad un
processo, indicandone il numero, ad esempio per terminarlo. Attualmente, esistono applicazioni
grafiche che svolgono la stessa funzione, come ad es. il gnome system monitor.
Il comando designato ad inviare segnali ad un processo è kill, che con l'opzione -9 causa la
terminazione del processo.
Background e terminazione
Un processo può essere lanciato sullo sfondo (in background) se viene invocato con una & alla
fine del comando: in tal modo, si ri-ottiene il prompt dei comandi, e si può eseguire qualche
altro comando. Ovviamente, la cosa ha un senso purché il programma mandato in backgound,
non richieda un input da tastiera ! Per riportate il programa sotto il controllo della tastiera, si
può eseguire il comando fg (foreground). Si può mandare un comando già lanciato in
background, prima interrompendolo (premendo control-z), e quindi digitando bg. Infine, si
può interrompere un programma che è eseguito in foreground, con la combinazione di tasti
control-c. Per terminare un programma in background senza riportarlo in foreground, si può
verificare il suo pid mediante il comando ps ax, e quindi usare il comando kill pid, oppure
kill -9 pid, se il programma non termina.
Chiamate di sistema
Un programa di utente, oltre alle istruzioni prodotte dalle proprie linee di codice, può eseguire
codice contenuto in librerie, e codice che viene eseguito all'interno del kernel del sistema
operativo, come ad esempio per accedere a delle risorse fisiche, all'hardware, od alla rete.
L'invocazione di questo codice esterno, è indicata come system call, che spesso in realtà non
esegue direttamente una funzione offerta dal kernel, ma invoca una funzione di libreria che
risiede nello spazio di utente, e che a sua volta invoca la fuzionalità del kernel, come per la
glibc.
L'invocazione delle system call da parte di un programma di utente, non può avvenire senza che
quest'ultimo non includa nella parte iniziale, i riferimenti ai files .h (gli header files) che
contengono le definizioni di tipo di dato, ed i prototipi delle chiamate a funzione, in modo che il
compilatore possa verificare la corettzza formale delle chiamate, e produrre un codice oggetto
che potrà linkarsi con successo alle funzioni esterne.
Per osservare le chiamate di sistema che vengono effettuate da un processo, Linux offre il
comando strace, con cui lanciare il programma. In alternativa, si può attaccare strace ad un
programma già in esecuzione, utilizzando l'opzione -p.
Script di Init
Quando un computer Linux viene avviato, dopo una serie di operazioni necessarie a caricare il
kernel dalla partizione di disco corretta, il primo programma ad essere eseguito è init, che
nella impostazione classica di Unix SystemV, determina il dafarsi in base all'esame del file /etc/
inittab. Nel file inittab viene definito, tra le altre cose, il runlevel inziale del sistema, che
consiste in un numero tra zero e sei, e che determina quali servizi/processi debbano essere
227
Mondo Linux
attivati, e quali arrestati. Ad ogni processo che può essere avviato, corrisponde uno script
presente nella directory /etc/init.d, che può essere invocato con le opzioni start, stop,
restart, status, ed altre.
Per ogni runlevel, esiste una directory /etc/rcN.d, che contiene una serie di link simbolici agli
script presenti in /etc/init.d: i link non esistono per tutti i file, ma solo per quelli rilevanti
per quel runlevel. Questi link simbolici, prendono lo stesso nome dello script target, prefisso con
una lettera ed un numero. La lettera può essere una S oppure una K, significando Kill o Start di
quel servizio, mentre il numero serve a stabilire un ordine temporale per la partenza/uccisione
dei diversi servizi. Gli script presenti in /etc/init.d possono essere invocati in qualunque
momento, anche dopo il boot, per avviare o terminare i servizi in modo pulito.
Una particolarità di questa modalità di avvio, è che i servizi partono uno dopo l'altro, provocando
un lentezza intrinseca del processo. Recentemente sono state proposte delle alternative, come
Initng, oppure Upstart, che è usato da Ubuntu, e che ha il vantaggio di essere compatibile con gli
script di SystemV.
Strumenti per la configurazione degli script di init, che permettono di lanciare/arrestare i
servizi, ovvero fare in modo che questi partano (o meno) al momento del boot, sono quelli
descritti nel wiki di Ubuntu.
Sottosistema Cron
Sottosistema dei Log
Configurazione della Rete
Riferimenti
[GAB] - Guida avanzata di scripting Bash di Mendel Cooper
Guida Linux di Edoardo Valsesia
Master in Tecnologia del Software Libero e Open Source - Stefano Zacchiroli
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Novembre 2007
228
Lo strato applicativo di Internet
Cattura del traffico, compilazione, e
socket
In questa attività, si tenta di acquisire una visione congiunta dei tre aspetti della
programmazione, delle interfacce utente, e dell'analisi di protocollo.
• Strumenti di Cattura e di analisi delle intestazioni
•
•
•
•
•
Configurazione delle opzioni di cattura
Menù principale e cattura
Menù di Analisi
Menù statistiche
Esercitazione
• A tu per tu con il codice
•
•
•
•
I comandi della shell
Compilazione
File di comandi
Makefile
• Dipendenze e target
• Macro e regole
• Esecuzione
•
•
•
•
•
•
Errori di compilazione
Server parallelo TCP
Connessioni UDP
Diagrammi temporali, UML
Select
Broadcast
• Riferimenti
Strumenti di Cattura e di analisi delle intestazioni
Sebbene si possa visualizzare il traffico in transito sulle
interfacce di rete (operazione in gergo chiamata sniffing) anche
mediante strumenti testuali come tcpdump o iptraf,
il programma più diffuso e ricco è sempre stato Ethereal, che di
recente ha cambiato nome in Wireshark. Mentre tcpdump e
wireshark fanno entrambi uso della libreria libpcap, iptraf
accede all'interfaccia di rete tramite chiamate dirette al
kernel.
Dopo aver lanciato wireshark in modalità privilegiata (digando quindi il comando sudo
wireshark, ed immettendo la nostra password di utente non privilegiato), cliccare sull'icona
che permette di vedere le interfacce disponibili, in modo da osservare la finestra sottostante,
che elenca le interfacce di cattura, e già mostra su quali di queste si sta osservando traffico.
Strumenti di Cattura e di analisi delle intestazioni
Cattura del traffico, compilazione, e socket
Configurazione delle opzioni di cattura
Nel caso in cui si desideri osservare il traffico diretto verso localhost, si scelga l'interfaccia lo;
se invece si opera verso un computer remoto. si scelga eth0, o se in dubbio, any (che le cattura
entrambe). Si può iniziare subito la cattura, premendo Start, oppure modificare le opzioni,
giungendo ad una seconda finestra.
230
Lo strato applicativo di Internet
Alessandro Falaschi
• la cattura in modo promiscuo significa che osserveremo tutti i pacchetti in transito per la
sezione di rete a cui siamo collegati direttamente, e non solo quelli da/verso il nostro
computer, e ciò è possibile solo eseguendo WireShark da root;
• è possibile specificare un capture filter, seguendo la sintassi di tcpdump (si veda la
sezione Esempi della pagina man), in modo da limitare i pacchetti catturati a quelli
desiderati, ad esempio filtrando alcune porte, o specificando solo alcuni indirizzi IP. Il
capture filter è utile per ridurre la quantità di dati osservati, come quando sul segmento
di rete a cui siamo affacciati, si verifica un traffico molto intenso a cui non siamo
interessati. Alcuni esempi di filtri di cattura:
• host 192.168.120.40: cattura solo il traffico diretto da e verso questo indirizzo
IP (che nell'esempio, è il nostro);
• port 80: cattura solo il traffico diretto da e verso la porta 80;
• arp: solo il traffico di arp (possiamo specificare un altro nome di protocollo, come
ad esempio smtp, dns, etc);
• ip: solo il traffico IP, e quindi non, ad esempio, il traffico ARP, che non possiede
una intestazione IP;
• la User Guide di wireshark espone una breve introduzione alla sintassi del filtro di
cattura, mentre presso il suo Wiki sono presentati degli esempi al riguardo;
231
Strumenti di Cattura e di analisi delle intestazioni
Cattura del traffico, compilazione, e socket
• cliccando sul bottone
si apre una finestra di dialogo, che
permette di definire un filtro, e di salvarlo con un nome, per un uso futuro
• dal riquadro Capture File(s) di sinistra, osserviamo che si può dirigere il risultato
direttamente in un file;
• dal riquadro Stop Capture, si può temporizzare la fine della cattura in base al tempo
trascorso, oppure al numero di pacchetti, od al volume di traffico;
• nelle Display Options, a destra, possiamo scegliere di vedere subito il risultato della
cattura, anziché aspettare il termine della stessa, ed anche, vedere i pacchetti catturati
scrollare immediatamente. Sebbene questo sia visivamente molto immediato, nel caso di
una elevata intensità di traffico, è invece preferibile catturare senza vedere, in modo da
non sovraccaricare il computer con compiti grafici, ed eventualmente perdere qualche
pacchetto per questo motivo;
• sotto Name Resolution infine, si può richiedere che venga mostrata la risoluzione per
• gli indirizzi MAC (la parte iniziale dell'indirizzo Ethernet determina il costruttore
della scheda di rete);
• i nomi dei servizi in ascolto sulle porte ben note degli indirizzi di trasporto;
• i nomi di Host associati agli indirizzi IP di rete (quest'ultima opzione è sconsigliata
in caso di Live Capture, dato che implica una fase di richiesta al DNS, che rallenta
le operazioni).
Menù principale e cattura
Possiamo ora eseguire un live capture, oppure caricare (File/Open..) in Wireshark questo file
ottenuto presso un computer di ingegneria, durante la visita su wikipedia della pagina dell'8
Marzo, della festa della donna, e della mimosa. D'altra parte, il wiki di wireshark contiene molti
esempi di file catturati.
Nella barra principale troviamo molte utili scorciatoie, tra cui evidenziamo
•
abilita/disabilta la colorazione dei pacchetti,
•
modificano la dimensione dei fonts e dell'incolonnamento
Menù di Analisi
Questo menù presenta delle opzioni che possono spesso essere richiamate anche con il tasto
destro del mouse, dopo aver evidenziato nella finestra superiore un particolare pacchetto,
oppure una particolare intestazione di un pacchetto, od un particolare campo. Citiamo:
• il filtro di display apre una finestra di dialogo accessibile anche dal bottone posto sotto la
barra principale
, del tutto simile a quella del filtro di cattura, mediante la
quale definire e salvare per un uso successivo, un filtro di visualizzazione, che modifica
quanto già catturato. Dato però che la sintassi di questo filtro, è differente da quella del
filtro di cattura, è spesso molto più conveniente definire il filtro di visualizzazione
interattivamente, seguendo la procedura spiegata appresso;
• possono essere disabilitati alcuni protocolli, oppure si può specificare di forzare il traffico
da/verso una certa porta, ad essere decodificato in un modo particolare; è questo il caso,
ad esempio, dell'RTP nel VoIP;
• Follow TCP stream ci consente, a partire da un pacchetto, di genereare un display filter
che mostra solo i pacchetti associati alla medesima connessione: per esempio, possiamo
scegliere il pacchetto 14, contenente il SYN di apertura del TCP. Nella finestra risultante,
232
Lo strato applicativo di Internet
Alessandro Falaschi
osserviamo, ricomposto, tutto il traffico della connessione, potendo (in basso) scegliere
come visualizzare il risultato, e di escludere (o selezionare) solo questo;
• lo stesso risultato, si ottiene con il tasto destro;
• per rimuovere l'effetto del filtro, si può cliccare sull'icona
nella barra dei filtri;
• per modificare ulteriormente il filtro ottenuto:
• possiamo agire sull'icona
nella barra principale, o su
in quella
dei filtri
• oppure
possiamo di
nuovo
operare con
il tasto
destro, dopo
aver
evidenziato,
un
pacchetto,
una
intestazione, od un campo. Selezionando Apply as Filter, e scegliendo ... and
Selected, si mette in and la condizione precedente, con il filtro attuale.
Quest'ultimo, realizza la condizione mostrata in basso nella finestra di
Wireshark.
Possiamo ora sperimentare ad eliminare via via i diversi protocolli presenti, fino a focalizzarci
solo sul traffico effettivamente pertinente alla navigazine web di cui all'esempio.
Menù statistiche
Sotto questo pop-down sono presenti molte utilissime funzioni. Mentre il sommario presenta dei
dati riassuntivi, la gerarchia dei protocolli, le conversazioni e gli endpoints mostrano in dettaglio
le entità presenti, e le loro relazioni.
• Con I/O Graph possiamo studiare la velocità di picco del traffico, potendo eventualmente
inserire dei filtri di visualizzazione, al fine di evidenziare eventuali situazioni di
sincronizzazione tra diversi tipi di traffico;
• Destinations ci mostra, per ogni destinazione, i diversi protocolli di trasporto e le diverse
porte sorgente;
• Flow Graph crea un diagramma temporale dei pacchetti visualizzati (eventualmente, a
seguito della applicazione di un Display Filter), permettendo di navigare nel file di
capture, e di analizzare nei dettagli ciò che viene mostrato come valore dei singoli campi
delle intestazioni
• HTTP crea una statistica dettagliata per il traffico web, così come SIP, RTP e VoIP
mostrano risultati attinenti alla telefonia Internet (provare con questo capture relativo ad
una chiamata SIP)
233
A tu per tu con il codice
Cattura del traffico, compilazione, e socket
• Packet Length mostra una interessante statistica, a riguardo della ripartizione del traffico
su diverse lunghezze di pacchetto
Esercitazione
Dopo aver caricato il file di traffico catturato, eseguire le analisi indicate ai punti 9-18 della
prima prova di questa esercitazione. Quindi, sempre a partire dallo stesso file di cattura,
eseguire le analisi indicate ai punti 12-16 e 18-20 della seconda prova della stessa esercitazione.
A tu per tu con il codice
Per sperimentare l'uso di Wireshark, ed analizzare il traffico prodotto utilizzando i programmi la
cattura dei pacchetti prodotti utilizzando mettere in pratica i concetti illustrati in questo
capitolo, procediamo alla compilazione del codice di cui si è discusso, e strada facendo,
aggiungiamo varianti e particolarità.
I comandi della shell
Benché anche con un sistema Linux si possa fare praticamente tutto senza togliere la mano dal
mouse, l'uso dei comandi da tastiera permette da un lato di meglio comprendere ciò che
succede, e dall'altro costituisce spesso il modo più rapido di eseguire un comando,
indipendentemente dall'interfaccia grafica, a partire dalla memoria della sua sintassi. In rete
esistono diversi tutorial relativi a questi aspetti, come MPL, AIL, ML, UFI,
Compilazione
Apriamo innanzitutto una finestra terminale, dove è possibile impartire comandi con la tastiera.
Creiamo quindi una directory di lavoro:
$
$
$
$
cd ~
pwd
mkdir codice
cd codice
Rechiamoci quindi sulla directory contenente il codice, e scarichiamo nella directory codice
tutti i files ivi presenti, oppure scarichiamo l'unico archivio compresso, e decomprimiamolo
presso il nostro computer. Il file compila è uno script shell, ossia un file contenente gli stessi
comandi che è possibile impartire in una finestra terminale, e nel caso non lo sia già (ls -l
compila), deve essere reso eseguibile con il comando chmod 755 compila. Quindi
eseguiamolo, scrivendo ./compila (il ./ è necessario, altrimenti potrebbe esistere un
programma con lo stesso nome in una delle directory mostrate con echo $PATH, e verrebbe
eseguito quello al suo posto). Risolviamo i possibili errori. Osserviamo il risultato dell'operazione,
ed i nuovi files presenti nella directory.
Il comando che serve per compilare un generico programma C di nome pippo.c, e che viene
eseguito da compila, è
$ cc -o eseguibile pippo.c
in cui l'opzione -o provvede a dare un nome all'eseguibile (nell'esempio, il nome è eseguibile)
234
Lo strato applicativo di Internet
Alessandro Falaschi
che altrimenti, prenderebbe il nome di default a.out.
File di comandi
Come possiamo osservare, il file compila iniza in un modo un pò particolare, chiamato shebang
(o hashbang). In assenza di questa linea, il file potrebbe essere passato come argomento
all'interprete dei comandi (eseguendo bash compila), che eseguirebbe tutte le direttive che vi
trova. Mandandolo direttamente in esecuzione invece, è sempre l'interprete bash che deve
decidere il da farsi. Se si tratta di un vero programma, gli cede il controllo; se invece localizza in
testa ai caratteri #!, lancia il programma che è scritto subito appresso (nella fattispecie, un'altra
istanza di se stesso), passandogli lo script come argomento, e termina. A questo punto,
sembrerebbe che ci siamo cacciati in un loop senza fine, ed invece, quando il secondo bash si
accorge di essere stato lanciato da un altro bash, inizia tutto contento ed eseguire i comandi
che si trovano nel file, ignorando questa volta la prima linea, anche perché.. il simbolo # è
quello che si usa per scrivere i commenti !
Makefile
Ora che abbiamo imparato le basi dei file di comandi, ci rendiamo però conto che compilare ogni
volta tutto quanto anche se si modifica un solo file (come suggerito nel seguito), potrebbe essere
uno spreco di risorse, non tanto ora che i programmi sono piccolini, ma più in generale, qualora
si abbia a che fare con progetti di dimensioni considerevoli. In nostro aiuto ci soccorre il
comando make, che usa le informazioni presenti in un file chiamato, per l'appunto, Makefile
(con l'iniziale maiuscola), che rappresenta una sorta di linguaggio di programmazione
dichiarativo, in quanto specifica cosa deve fare make (e non come). In rete sono presenti alcuni
buoni tutorial a riguardo, citiamo quello di AIL, di LUPG, o quello (ottimo) presso il CEH.
Dipendenze e target
Il vantaggio di usare il make, è che nel Makefile sono definite una serie di dipendenze,
dichiarando quale file dipende da quale altro. Così, quando un file di un gruppo è modificato, è
possibile ri-generare solo i files che dipendono da quest'ultimo, unicamente osservando se la loro
data di creazione è precedente o successiva a quella dei files da cui dipendono. Un primo
esempio di Makefile funzionante è
default: all
all: tcp udp
tcp:
udp:
server client selectserver
listener talker broadcaster
server:
server.o
client:
client.o
listener: listener.o
talker:
talker.o
selectserver: selectserver.o
broadcaster: broadcaster.o
server.o:
server.c
client.o:
client.c
listener.o: listener.c
talker.o:
talker.c
selectserver.o: selectserver.c
broadcaster.o: broadcaster.c
235
A tu per tu con il codice
Cattura del traffico, compilazione, e socket
In questo esempio, alla sinistra dei due punti sono presenti i cosidetti target, che possono essere
citati su di una linea di comando come make target, intendendo con questo richiedere la
generazione del target richiesto. A sua volta un target può dipendere da un altro target, e così si
definisce come all dipenda da tcp e udp, mentre tcp dipende da server, client e
selectserver. A sua volta, sever dipende da server.o, che a sua volta ancora, dipende da
server.c. In questo modo, è possibile invocare
make all
make tcp
make
make listener
#
#
#
#
compila tutto
compila server e client
prende all come target di default
compila solamente listener
Macro e regole
Allo scopo di rendere un Makefile più compatto esistono alcune particolarità. Le istruzioni
macro consentono di associare una serie di stringhe ad un unico oggetto OBJ, che può essere
ri-espanso successivamente, citandolo con la notazione $(OBJ). Inoltre, le estensioni dei singoli
nomi in cui $(OBJ) si espande, possono essere ulteriormente trasformate al volo: ad esempio,
se poniamo OBJ = pippo.c, citando $(OBJ:.c=.o), otteniamo l'espansione in pippo.o.
Le regole consentono di abbinare ad un target, la sequenza di comandi che permette di risolvere
la dipendenza espressa dal target. La sintassi di questo costrutto è esprimibile come
target: nome(i) file di ingresso
azioni
in cui, che dopo la linea che esprime una dipendenza, è posta una seconda linea (che inizia con
un TAB) che esprime una (o più) azione(i), da applicare perché sia soddisfatta. In base a queste
nuove nozioni, al Makefile precedente possono essere aggiunte in testa ed in coda le istruzioni
OBJS = server.o client.o listener.o talker.o selectserver.o broadcaster.o
.
.
.
clean:
-rm -f $(OBJS) $(OBJS:.o=) *~
rebuild: clean all
che definiscono la macro OBJS come uguale a tutti i codici oggetto, ed i target clean e
rebuild, tali che
• al target clean è associata l'azione -rm -f $(OBJS) $(OBJS:.o=) *~ , che esegue il
comando di cancellazione rm, applicato a tutti i codici oggetto definiti dalla macro
OBJS, a tutti i codici eseguibili ottenuti rimovendo le estensioni .o, ed alle le copie di
backup dell'editor, che terminano con ~, riportando la directory nello stato iniziale;
• il target rebuild prima esegue clean, e quindi ricompila tutto daccapo.
L'uso della espansione di una macro, ci evita di dover scrivere parecchie linee di codice uguali,
cosicché invece di dover scrivere una regola che specifica come passare da un .c ad un .o, ossia
server.o:
server.c
cc -c server.c
236
Lo strato applicativo di Internet
Alessandro Falaschi
per ognuno dei codici oggetto da generare, possiamo scrivere
CC = gcc
# utilizziamo gcc anziché cc
OBJS = server.o client.o listener.o talker.o selectserver.o broadcaster.o
obj: $(OBJS)
%.o: %.c
$(CC) -c $<
in modo che, invocando make obj, si ottiene la compilazione di tutti i sorgenti in codice
oggetto, in base alla semantica delle seguenti macro predefinte:
la macro si espande in
%.c
qualunque file con estensione .c presente nella directory
%.o
un file con estensione .o, e con lo stesso nome della dipendenza della regola, e che
compare come dipendenza di un'altra regola
$(CC)
cc, il compilatore standard, o quale altro compilatore definito in una macro cc =
$<
l'elemento che compare dal lato dipendenza della regola
$@
il nome del target
Questa logica è poi ulteriormente potenziata dalla esistenza delle regole deduttive, che
permettono a make di stabilire autonomamente quale sia l'azione necessaria a soddisfare una
determinata dipendenza, cosicché ad esempio, per ottenere un file eseguibile, make prova a
likare un codice oggetto dallo stesso nome. Così, anche se dovremmo scrivere
%.o: %.c
$(CC) -c -o $@ $<
per generare i .o a partire dai .c, e
%: %.o
$(CC) -o $@ $<
per generare gli eseguibili, il Makefile definitivo riporta queste istruzioni commentate.
Esecuzione
Ora che abbiamo gli eseguibili, possiamo verificare il funzionamento dei server parallelo e seriale
studiati. Poniamoci nella directory con i files scompattati, ed impartiamo il camando make.
Errori di compilazione
Come dite? Il comando make (e/o compila) risponde con una serie di errori, il primo dei quali
dice "error: stdio.h: nessun file o directory" ?.... aaahhh si, dovete scaricare con
Synaptic, il pacchetto build-essential, che permette di scaricare gli header di sistema!
237
A tu per tu con il codice
Cattura del traffico, compilazione, e socket
Server parallelo TCP
Nella finestra terminale aperta, lanciamo ./server ed in una nuova finestra, ./client
127.0.0.1: constatiamo che il risultato è quello atteso. Ora, proviamo a fare questi
esperimenti:
• 1. osserviamo il traffico on wireshark, impostiamo
un filtro di visualizzazione che mostri solo il
traffico relativo al nostro esperimento, salviamo il
risultato della cattura nel file server.pcap
• 2. chiudiamo il server con control-c, e
rilanciamo il client. Cosa dice ? Catturando il
traffico con Wireshark, quali sono le differenze
rispetto al caso precedente ? Salviamo anche
stavolta il risultato nel file noserver.pcap
copiamo tutti i files in una nuova directory, che
chiamiamo test. Modifichiamo il codice del server, in
modo che
• 3. anzichè il messaggio Hello, word! scriva
qualcosa di originale, ad esempio il vostro nome
ed un augurio. Ricompilatelo con make,
rilanciatelo, collegatevi con il client e notate che
succede. Avete modificato il terzo parametro di
send, con il numero di caratteri più uno ??
• 4. comunicate il vostro IP ai vicini di postazione, scrivetevi il loro, e contattatevi a
vicenda.
• 5. salvate ora il codice di server.c in un nuovo file, servermod.c, e modificatelo in modo
che esegua il bind ma non il listen, oppure il listen ma non l'accept.
• Suggerimento: si usi l'istruzione sleep(secondi) e qualche stampa su schermo,
che faccia capire cosa accade
• Scorciatoia: se modificare il codice richiede troppo tempo, si usi questa
versione già modificata. Per capire cosa è cambiato, si usi il programma
kompare. Se non l'avete intallato, cercatelo con Synaptic.
• Il messaggio del client è cambiato? Catturiamo il traffico per capire cosa accade, e
salviamo il risultato in noaccept.pcap
• Risposta: mentre nel caso di noserver.pcap, a seguito del SYN di apertura
della connessione TCP, il kernel risponde immediatamente con un pacchetto
di ReSeT, nel caso di noaccept.pcap invece, il kernel porta regolamente a
temine il three-way handshake; però, finché non viene eseguita la
accept(), il processo non prosegue.
• 6. modifichiamo nuovamente il server, in modo che non venga armato l'handler del
SIGCHLD. Dopo ogni invocazione del client, verifichiamo lo stato dei processi con ps ax
(si esegua ps ax | grep server). Cosa notiamo ? Usiamo il comando kill, per
eliminare i processi zombie. Funziona ? E se uccido il padre ?
• Risposta: in assenza del gestore di SIGCHLD, i processi figli continuano a risiedere
in memoria, in uno stato di <defunct>. Non rispondono al kill, e per farli sparire,
occorre terminare il processo padre.
238
Lo strato applicativo di Internet
Alessandro Falaschi
Connessioni UDP
Ora, proviamo a lanciare la coppia di programi che fanno uso di connessioni UDP, ossia
listener e talker:
• 7. anche in questo caso, verifichiamo che tutto si svolga come previsto, e catturiamo il
traffico con Wireshark. Che differenze notiamo ? salviamo il risultato in listener.pcap.
• 8. chiudiamo ora il processo listener, eseguiamo nuovamente talker, e salviamo il
risultato della cattura in nolistener.pcap. Che accade ? Anche se talker non è cosciente
che le sue parole cadono nel vuoto, di cosa ci possiamo accorgere dalla cattura ?
• Risposta: nel caso in cui listener non sia attivo, il kernel invia un pacchetto ICMP
Port Unreachable, per segnalare appunto che non c'é nessun processo in ascolto
sulla porta del listener
Diagrammi temporali, UML
Lo scambio di pacchetti può essere visualizato con Wireshark in forma di Diagramma Temporale,
selezionando Statistics/FlowGraph, e scegliendo quindi una modalità di visualizzazione.Un modo
più formale di ottenere lo stesso risultato, è quello di costruire un vero e proprio Diagramma di
Sequenza così come definito da UML, ad esempio mediante l'uso di uno strumento apposito
(UMbreLlo), con cui editare un modello, e quindi produrre diagrammi temporali come quello
mostrato sopra.
Select
E' ora la volta di sperimentare il funzionamento di selectserver. Il server di chat viene
lanciato su di un unico computer, di cui ti annoti l'indirizzo, e su cui è in esecuzione etherape.
Quindi, sia tu che tutti gli altri, iniziate a catturare il traffico, eseguite su di una finestra
terminale in comando telnet indirizzo-del-server 9034, ed iniziate a chattare. Ad un
certo punto, il server viene chiuso.
• 9. durante il funzionamento, teniamo d'occhio l'aspetto di etherape
• 10. osserviamo il comportamento del TCP in conseguenza della chiusura del server.
Osserviamo i flag usati nei pacchetti TCP. Salviamo il capture con il nome chat.pcap.
• 11. modifichiamo selectserver in modo che i messaggi ricevuti dai terminali via telnet,
siano del tipo ip mittente: messaggio.
Telnet
Il comando telnet implementa il lato client del protocollo telnet, e consente di collegare lo
standard input (la tastiera) ad un socket TCP remoto, stampando su standard output (lo
schermo) ciò che la applicazione remota invia, sempre mediante la stessa connessione TCP. Per
questo motivo, viene spesso usato per dialogare con applicazioni server che adottano protocolli
testuali (come, ad esempio SMTP, HTTP, SIP). Dato che ogni carattere immesso da tastiera, viene
trasmesso all'altro estremo della comunicazione, si pone il problema di come terminare la
comunicazione, usando la tastiera. In questo caso, infatti, il normale control-c non ha effetto. La
soluzione, ci viene però indicata al momento della partenza della connessione:
239
Riferimenti
Cattura del traffico, compilazione, e socket
alef@alef-laptop:~$ telnet 151.100.122.122 80
Trying 151.100.122.122...
Connected to 151.100.122.122.
Escape character is '^]'.
Sapendo che il carattere ^ è usato per indicare la pressione del tasto Control, capiamo che per
terminare il telnet, e riottenere il prompt dei comandi, occorre digitare la sequenza di escape,
ossia la combinazione Control+parentesi_quadra_chiusa. Quest'ultima, sulla tastiera italiana si
realizza premendo assieme AltGr e ], e quindi in definitiva, occorre premere tre tasti in
contemporanea. Quindi, premere il tasto Invio. A questo punto il nostro programma telnet, ci
presenta il suo prompt telnet>, ed in questa fase, possiamo impartirgli dei comandi locali,
come ad esempio, help. Per uscire, si può invece impartire close, oppure anche solo il tasto q.
Broadcast
Ora è il momento, di sperimentare il programma broadcaster.
• 12. modifichiamo il programma listener, in modo che quando riceve un pacchetto non
esca, ma cicli indefinitivamente. Inoltre, quando stampa il contenuto di un pacchetto
ricevuto, facciamo entrare tutto su di una unica linea;
• 13. ognuno lanci il suo listener, in modo da ricevere il broadcast di tutti, e in una altra
finestra terminale, provi innanzitutto a lanciare talker, chiedendo di trasmettere verso
l'indirizzo broadcast 192.168.0.255. Verifichiamo il codice d'errore, legato alla
mancanza dell'opzione SO_BROADCAST del socket.
• 14. Lanciamo quindi una istanza di broadcaster, con il quale si inviano prima messaggi al
nostro proprio indirizzo, quindi all'indirizzo di qualcun altro, ed infine all'indirizzo
broadcast 192.168.0.255, in modo da inviare messaggi a tutti, e di nuovo, realizzare
una specie di chat.
• 15. Percepiamo la differenza tra la chat eseguita collegandosi in telnet con selectserver, e
questa in cui ognuno ha il suo proprio listener indipendente.
• 16. si tenga d'occhio Etherape. Si noteranno i computer della rete che comunicano verso
l'indirizzo broacast, oppure delle comunicazioni dirette, se effettuiamo comunicazioni
unicast.
• 17. Catturiamo il traffico con Wireshark, comprendendo sia traffico unicast (generato e/o
ricevuto), che broadcast. Determiniamo i display filter tali da limitare il traffico
mostrato alla sola nostra applicazione, e
•
•
•
•
mostrare
mostrare
mostrare
mostrare
solo
solo
solo
solo
il
il
il
il
traffico
traffico
traffico
traffico
unicast entrante
unicast uscente
broadcast entrante
broadcast uscente
Riferimenti
[AIL] - Appunti di Informatica Libera di Daniele Giacomini
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Novembre 2007
240
Lo strato applicativo di Internet
Investigazioni di Rete
Trattiamo ora di alcuni strumenti utili per verificare la corretta configurazione degli host
sia nella nostra rete, che remoti, e che possono aiutare di molto il compito di diagnosticare
malfuzionamenti e problemi, investigare sulle possibili soluzioni, e svelare chi contattare.
• Arrivo fin lì? Tu ci sei? Pronto?
• Controllo delle intrusioni
• Su quali porte stanno ascoltando, i miei servizi?
• Quale programa sta ascoltando su questa porta?
• Nmap
•
•
•
•
Tipo di scan
Intervallo delle porte
Indicazione del target
Stato delle porte
• Esperimenti
• Il percorso dei nostri pacchetti
• Chi è chi?
• Whois
• Riferimenti
Arrivo fin lì? Tu ci sei? Pronto?
Quando in un computer, abbiamo configurato
•
•
•
•
l'indirizzo IP,
la network mask,
il default gateway, e
il DNS,
non ci resta che verificare se possiamo collegarci o meno. Per questo possiamo fare uso del
programma ping (man page), che invia dei pacchetti ICMP echo, ne riceve la risposta, e ci
informa del ritardo intercorso. Può essere usato per
• verificare il corretto funzionamento della nostra interfaccia di rete, dirigendo il ping verso
noi stessi;
• verificare la connessione alla rete locale, dirigendo il ping verso un computer con uguale
prefisso di sottorete;
• verificare il corretto instradamento verso il default gateway, dirigendo il ping verso un
computer esterno alla LAN;
• verificare la corretta configurazione del DNS, dirigendo il ping verso un nome di dominio.
Analizzando questo capture, possiamo verificare il traffico prodotto durante l'esecuzione di un
ping.
Ora, sperimentiamo gli strumenti per la scoperta dei servizi attivi su uno o più computer della
nostra rete.
Controllo delle intrusioni
Investigazioni di Rete
Controllo delle intrusioni
L'intrusion detection è un aspetto di Network Security spesso trascurato dagli amministratori di
rete (ammesso che, nelle piccole realtà, ce ne siano), almeno finchè non si è oggetto di un serio
attacco informatico. L'approfondimento della questione non è tra gli scopi di questo corso; ci
limitiamo quindi ad indicare in Nessus uno degli applicativi più usati a questo scopo. Analizziamo
invece ora una serie di strumenti più di base, ma potremmo definire indispensabili.
Su quali porte stanno ascoltando, i miei servizi?
Sebbene con il comando ps possiamo scoprire quali programmi sono in esecuzione presso il nostro
computer, il comando
netstat -n --udp --tcp -p -l
ci mostra su quali numeri di porta (-n) udp e tcp ci sono programmi in ascolto (-l), indicando il
PID ed il nome del programma (-p) che ha aperto il socket. Per lo stesso comando, sono possibili
diverse combinazioni di opzioni, in grado di mostrare anche i socket non in ascolto (omettendo
-l), mostrando il relativo stato, o di mostrare i socket unix, oppure ancora di mostrare le
informazioni di instradamento (netstat -r)
Quale programa sta ascoltando su questa porta?
L'opzione -p di netstat, che ci mostra PID e nome del programma connesso al socket, è di
introduzione recente, per la sola architettura Linux; altrimenti, una volta noto un numero di
porta, si può ricorrere al comando
fuser -n tcp -v numero_di_porta
che ci mostra il nome del programma che sta usando il numero di porta specificato. Anche in
questo caso, le opzioni della chiamata possono variare, permettendo di interrogare il namespace
udp, o quello dei descrittori di file.
Nmap
Dopo aver investigato il proprio computer, può venire la voglia di curiosare in quello degli altri, e
questo può essere fatto, analizzando il tipo di risposta che il kernel invia, nel caso in cui presso
una certa porta, ci sia un programma in ascolto o meno. Si badi che questo tipo di analisi, non
necessariamente rappresenta una azione di attacco, anzi, al contrario, permette ad un
amministratore di verificare lo stato di salute (o di compromissione) delle macchine della propria
rete, come se ad esempio, un virus abbia infettato un computer, e sia in esecuzione, mettendosi
in ascolto su di una porta non prevista, permettendo ad un attaccante di conettercisi,
ed eseguire azioni da remoto. Inoltre, un amministratore che voglia proteggere le proprie
macchine da sguardi indiscreti, provvederà senz'altro a configurare un firewall che ne impedisca
la raggiungibilità.
Un modo semplice di svolgere questo tipo di analisi, ci viene offerto dal programma nmap (sito,
HowTo italiano, man in italiano), che è eseguibile anche per mezzo del suo front-end grafico
nmapfe, che ha l'aspetto mostrato sotto, e che all'ultima riga, mostra le opzioni da referenziare
sulla linea di comando, equivalenti alle scelte espresse in modo grafico.
242
Lo strato applicativo di Internet
Alessandro Falaschi
.
Tipo di scan
La scelta di un Scan Type permette di effettuare operazioni diverse, come ad esempio
• Ping Sweep - ha un effetto equivalente al ping, e utilizza ICMP;
• Connect Scan - tenta di eseguire il three way handshake in modo completo, e può essere
eseguito anche da utenti non-root;
• Syn-Scan - si limita ad inviare solo il primo pacchetto dell'handshake, evitando di essere
registrto nei files di log del computer target
• UDP Scan - per scoprire i servizi offerti via UDP
Intervallo delle porte
A parte per caso di Ping Sweep, per gli scan orientati alla scoperta dei servizi, occorre
specificare l'intervallo delle porte da esaminare, potendo scegliere tra
• default - un insieme di 1695 porte, che comprende le prime 1024, ed indicato nel file
nmap-services
• all - tutte le 65530 porte
• most important - un insieme ridotto di 1245 porte
• un insieme esplicito (es. 25,80,110)
• un intervallo (es. 20-200)
Indicazione del target
Possiamo specificare
243
Esperimenti
Investigazioni di Rete
• un indirizzo IP singolo
• un intervallo (es. 192.168.0.64-128)
• una intera sottorete (es.192.168.0.0/24)
e nel secondo e terzo caso, lo scan sarà ripetuto per tutti gli host indicati.
Stato delle porte
In funzione della presenza o meno di un programa sulle porta esplorata, e della presenza o meno
di un firewall tra i due computer, lo stato della porta può essere classificato come
• open - la porta è aperta, c'è un programma in ascolto:
• ad es, il TCP-SYN produce un SYN-ACK di risposta, oppure un UDP non produce nulla
• closed - la porta è chiusa, non c'è nessun socket in ascolto:
• ad es, TCP-SYN produce un RST, ed un UDP produce un ICMP port unreachable
• filtered - la porta non esibisce il comportamento atteso per uno dei due casi precedenti, e
questo è da imputare alla presenza di un firewall
Esperimenti
Proviamo a verificare l'uso di nmapfe, lasciando aperti sui nostri computer i server (server,
listener e selectserver) che ricordiamo, sono rispettivamente in ascolto sulle porte TCP
3490, UDP 4950 e TCP 9034. Per questo, utilizziamo il programma nmap e/o nmapfe (sito,
HowTo italiano, man in italiano)
1. Proviamo a dirigere un SYN Stealth Scan (il SYN clandestino) verso le porte 0-10000 di
127.0.0.1, ed impostando l'opzione Ordered Ports. Riusciamo ad individuare i servizi
attivi ? ne troviamo aperti altri ?
2. Durante lo scan, teniamo aperto Wireshark. Cosa accade ?
1. Avendo ordinato lo scan con porte ordinate, ci è facile individuare che al pacchetto
5700 si trova il SYN diretto verso la porta 3490, dove è in ascolto server, che a
differenza delle altre porte, risponde SYN, ACK anziché RST, ACK, dopodicheè nmap
interrompe la connessione con un RST.
2. per scoprire i servizi offerti in UDP, selezioniamo UDP Port Scan
3. mediante wireshark, etherape, tcpdump o iptraf, scopriamo qualche computer linux nella
nostra stessa rete, scegliamone uno, e ripetiamo lo scan. Quali sono i servizi che troviamo
attivi ?? Un altro modo per scoprire tutti i computer nella nostra rete, è quello di
effettuare un Ping Sweep con target 192.168.0.0/24. Mediante Wireshark, notiamo
qual'è la tecnica usata da nmap.
4. effettuiamo ora uno scan verso un computer fuori della nostra rete, ad esempio
151.100.122.122. Notiamo nuovi messaggi ? cosa vuol dire filtered ports ? (verifichiamolo
con Wireshark).
5. per apprezzare la ricchezza delle operazioni possibili, diamo una occhiata alla manpage di
nmap, che funziona egualmente bene se invocato da linea di comando, offrendo
l'opportunità di una piena configurazione.
Il percorso dei nostri pacchetti
Abbiamo parlato di come l'ICMP può essere usato dal programma traceroute per scoprire,
utilizzando dei time to live via via crescenti, la sequenza dei router attraversati pe raggiungere
una determinata destinazione. Questo capture, riporta il traffico prodotto durante l'esecuzione
244
Lo strato applicativo di Internet
Alessandro Falaschi
di un traceroute indirizzato verso www.fasthit.net, un service provider australiano.
Presso traceroute.org è possibile eseguire un traceroute che parte da svariate località del
mondo, verso il nostro computer. Partiamo ad esempio dalla Universidad Tecnica Federico Santa
Maria che si trova in Cile, e
1. contiamo quanti salti è possibile visualizzare;
2. notiamo i nomi delle macchine attraversate. Notiamo che per alcuni hop, sono elencati
più router, in alternativa tra loro;
3. facciamo caso ai tempi che sono mostrati.
4. Osserviamo infine, qual'é l'ultimo router che riusciamo a raggiungere, e l'IP ad esso
associato, differente dal nostro. Perché ?
5. proviamo ora a fare il tragitto inverso, eseguendo traceroute a partire dal nostro
computer. Facciamo lo stesso percorso ?
6. mentre proviamo il traceroute che parte dal nostro computer, possiamo tenere aperto
Wireshark, ed esaminare cosa avviene
1. una alternativa a traceroute è tracepath, che realizza anche la funzione di
path MTU discovery
2. da notare anche xtraceroute, che offre una visione tridimensionale del globo, e
tenta di localizzarvi i router incontrati per la strada
Qualora ci si trovi dietro un firewall che blocca i pacchetti UDP, oppure se gli operatori di rete
che gestiscono i router intermedi non generano, o bloccano, le risposte icmp time to live
exceeded, possiamo provare ad usare
• tcptraceroute, che analogamente a quanto fatto da nmap, usa la tecnica di tentare di
aprire una connessione TCP, sempre incapsulandola in una intestazione IP con un valore
di TTL via via crescente, oppure
• mtr, che riporta su schermo, in modo continuativo, le statistiche sui ritardi medi, minimi
e massimi, e la deviazione standard
7. finalmente, possiamo confrontare il percorso per il Cile, con quello dal Cile verso
di noi.
8. catturando con Wireshark il traffico generato da tcptraceroute e mtr, possiamo
studiarne il funzionamento.
• nel corso di questa verifica, ci siamo trovati nel caso in cui sia traceroute che
tcptraceroute non funzionavano, mentre invece mtr si. A quanto pare, l'ISP utilizzato,
filtra i pacchetti ICMP di tipo icmp time to live exceeded. A seguito della verifica
fatta con wireshark, possiamo notare che mentre mtr opera inviando dei veri e propri
pacchetti icmp echo request, tcptraceroute invia invece un TCP SYN, sempre con
un campo TTL IP troppo basso. In entrambi i casi, i router di transito, nel generare la
risposta ICMP, vi inseriscono come PDU l'inizio del pacchetto scartato, dando modo ai
router sulla strada di ritorno, di investigare il tipo di traffico che ha prodotto l'icmp.
Quindi, evidentemente, il nostro ISP decide di non bloccare l'ICMP prodotto dal ping, e di
bloccare invece quello prodotto dal TCP, in quanto in questo secondo caso, non è esplicita
l'intenzione del mittente originario, di effettuare una investigazione di rete.
Presso cybergeography si trova una interessante rassegna di links a siti e strumenti che svolgono
un compito simile, di cui alcuni sviluppati in java, alcuni non più raggiungibili, ed altri che
integrano ancora altre funzionalità, come la ricerca whois. Un altro sito (Morgan) offre (oltre a
diverse altre cose utili) un servizio di traceroute da loro verso di noi, senza mappatura
geografica, ma con la visualizzazione del dove si generano i maggiori ritardi.
245
Chi è chi?
Investigazioni di Rete
Chi è chi?
Whois
E' un comando che si immette da tastiera sui sistemi Unix, che implementa il protocollo descritto
dalla RFC 3912 operante via TCP su porta 43, e che permette di risalire alle informazioni
riguardanti gli intestatari dei domini, degli indirizzi IP, e dei sistemi autonomi. Per quanto
riguarda gli indirizzi IP ed i numeri di sistema autonomo, questi sono registrati presso i Registri
Internet regionali (RIR): ce ne sono 5 nel mondo, dislocati nei continenti. Gli Internet Service
Provider (ISP), a loro volta, si rivolgono ai RIR per vedersi assegnate risorse di queto tipo.
• eseguire il comando whois 151.100.70.22: si scopre che viene interrogato il server
whois.ripe.net, del RIR RIPE, che risponde che questo indirizzo, fa parte del lotto
151.100.0.0 - 151.100.255.255 assegnato all'Università la Sapienza, e vengono mostrati i
riferimenti al DNS autorevole per il mapping inverso, al contatto tecnico, ed al sistema
autonomo di riferimento (AS137)
• eseguire il comando whois AS137: viene interrogato il server whois.arin.net, e fornita la
risposta che gli indirizzi sono stati ulteriormente ri-assegnati, e di consultare
http://www.ripe.net/whois
• si consulti http://www.ripe.net/whois, immettendo la richiesta AS137, oppure si esegua
whois -h whois.ripe.net AS137, che dirige la richiesta verso il server di RIPE: si
scoprirà che il numero di sistema autonomo è gestito dal GARR
• si vada sul sito del GARR: potremo osservare la topologia della rete, e di li (weathermap/
RomaTizii/LaSapienza) l'andamento del traffico giornaliero, mensile e annuale. Notiamo la
crescita costante del traffico sul link da 1 Gbit, che si riscontra anche bene ad es. sul link
da 2 Gbit del MIX (Peering Internet/Mix). I grafici sono prodotti con MRTG, che basa il
funzionamento su di un programma eseguito ad intervalli regolari come un cron job, e che
interroga via SNMP gli oggetti reperibili presso i MIB dei router, acquisendo così le
informazioni sui byte in transito, che vengono salvate in un file, e da cui i derivano le
informazioni differenziali. Quindi, sono invocati i servizi offerti da una libreria in grado di
generare i grafici che osserviamo.
• Presso il sito del MIX (che è un IXP (lista), dove gli ISP fanno peering) troviamo
l'elenco degli afferenti alla struttura, la documentazione ed i costi, oltre ad una
sezione sulle statistiche ad accesso riservato, a beneficio degli aderenti. Altre
interconnessioni internazionali di ricerca, avvengono tramite la rete GEANT (o
meglio, Geant2)
Ma il comando whois effettua anche ricerche sui domini:
• eseguire il comando whois uniroma1.it: viene interrogato il server whois.nic.it, e si
ottiene di nuovo l'informazione di assegnazione all'Università Sapienza, con i contatti, ed il
DNS autorevole per i nomi di dominio.
Riferimenti
•
•
•
•
•
Home Network Security - presso CERT® Coordination Center
Top 100 Network Security Tools - presso insecure.org
mappe della rete
Exploring Autonomous System Numbers
Robtex - swiss army knife internet tool
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Novembre 2007
246
Lo strato applicativo di Internet
Alessandro Falaschi
247
Lo strato applicativo di Internet
Domain Name System
• Cercando tra i nomi
• Un DNS tutto nostro
• La zona locale
• Ospitare un proprio server SMTP
• DHCP e DDNS
• Dnsmasq
• Zeroconf
Cercando tra i nomi
Esistono diversi strumenti che effettuano ricerca tra i DNS. Il più comune e semplice è il
comando host, che offre una buona scelta di opzioni, con cui svolgere le query più diverse, e
che permette la risoluzione sia diretta che inversa:
Usage: host [-aCdlriTwv] [-c class] [-N ndots] [-t type] [-W time]
[-R number] hostname [server]
-a is equivalent to -v -t *
-c specifies query class for non-IN data
-C compares SOA records on authoritative nameservers
-l lists all hosts in a domain, using AXFR
-r disables recursive processing
-R specifies number of retries for UDP packets
-t specifies the query type
-T enables TCP/IP mode
-v enables verbose output
-w specifies to wait forever for a reply
-W specifies how long to wait for a reply
• mentre si cattura il traffico con Wireshark, eseguire il comando host -r
infocom.uniroma.it. Si osservi l'assenza di risposta dovuta alla assenza di recursione
• si esegua ora host -a infocom.uniroma.it, e si noti la risposta. Si osservi come nel
protocollo, la risposta contenga di nuovo i campi di domanda, oltre che le risposte. Si
osservi che l'opzione -a effettua una query type ANY (provare -t CNAME, ad esempio).
• eseguire di nuovo host -r infocom.uniroma.it, e verificare che ora la risoluzione ha
successo: il risultato è stato salvato nella cache.
• indirizzare ora la richiesta verso un DNS diverso dal proprio (ad es. 151.100.4.2,
151.100.8.33, 195.210.91.100) e confrontare i risultati
Un elenco delle possibili opzioni è piuttosto lungo, ma può valere la pena verificarlo.
Altri comandi per esplorare il DNS sono dig, nslookup, e dnstracer.
Un DNS tutto nostro
Passiamo a sperimentare la configurazione ed il funzionamento del DNS, con riferimento alla
distribuzione Ubuntu Linux che stiamo usando:
1. installiamo il pacchetto bind9;
Lo strato applicativo di Internet
Alessandro Falaschi
2. editare (con sudo gedit) il file /etc/bind/named.conf.local, in modo da
riprodurre la situazione illustrata a lezione;
3. creiamo nella directory /etc/bind i tre files 192.168, dg e brot.dg, con i contenuti
citati nell'esempio, oppure,
1. scaricare ed installare questo archivio (scomprimelo in una propria directory, e poi
copiarlo con sudo cd nella dir /etc/bind);
2. il DNS locale può quindi essere mandato in esecuzione mediante il comando sudo /etc/
init.d/bind9 start, oppure
1. /etc/init.d/bind9 reload, nel caso in cui stia già girando;
2. verifichiamo che nel file di log non siano evidenziati errori, ovvero
1. impartiamo il comando less /var/log/daemon.log ed andiamo in fondo al file
con il tasto freccia ->, o con Shift+>, o con PageDown, oppure
1. teniamo continuamente sott'occhio il file di log, impartendo (da un'altra
console) il comando tail -f /var/log/daemon.log;
Ora, sarà possibile investigare tra le informazioni immesse, eseguendo ad es. il comando host
-a www.brot.dg 127.0.0.1.
La zona locale
Anzichè avere ognuno il proprio DNS, ha più senso mantenerne uno solo per tutto il laboratorio,
delegando a questo, anche il compito di risolvere i loro nomi, con gli indirizzi IP privati di cui
dispongono: indirizzi del tipo 192.168.0.aaa, dove aaa è il numero (da 150 in su) che compare
nel prompt dei comandi, oppure digitando il comando hostname. Per poter contattare i computer
del laboratorio per nome, occorre quindi
1. designare un computer (ad es il 192.168.0.152) ad ospitare il DNS autorevole per il
laboratorio;
2. installare e configurare BIND9;
3. decidere il nome di dominio da adottare -> usiamo softel
4. decidere un nuovo nome per i singoli computer, e
1. modificare in accordo il nuovo nome del computer, sostituendolo
1. nel file /etc/hostname
2. nel filie /etc/hosts
2. creare i files di zona diretto (/etc/bind/softel) e modificare quello inverso (/etc/
bind/192.168), in modo coerente ai nomi decisi;
3. eseguire /etc/init.d/bind9 reload per causare la rilettura della configurazione;
4. verificarne il funzionamento mediante il comando host;
5. modificare i files /etc/resolv.conf dei computer del laboratorio, in modo da usare il
DNS interno come DNS, ed usare il nuovo dominio come suffisso di default
1. i passi 4. e 8. possono essere attuati mediante lo strumento grafico Sistema/
Amministrazione/Rete, modificando le linguette General/Hostname e General/
Domain, DNS Servers, Search Domains, e Hosts, come illustrato appresso.
2. una volta modificati i parametri del resolver, salviamo la configurazione, come
postazione softel.
249
Un DNS tutto nostro
Domain Name System
I parametri di rete IP non devono essere modificati
Queste impostazioni alterano il file /etc/
hostname ed /etc/resolv.conf
Queste impostazioni alterano /etc/resolv.conf
queste impostazioni alterano /etc/hosts
Facciamolo assieme. Il risultato, sono questi files. Nelle prossime lezioni, ricordiamo di tenere
acceso questo DNS.
Ospitare un proprio server SMTP
Per poter sperimentare appieno la configurazione di un server SMTP, occorre predisporre il file di
zona softel, perché le email indirizzate verso un computer della rete locale (ad es., verso
[email protected]), siano effettivamente consegnate al proprio computer. Come
250
Lo strato applicativo di Internet
Alessandro Falaschi
illustrato, questo corrisponde a configurare, per ogni computer, un RR di tipo MX che referenzi il
computer stesso. Il risultato, si trova in questo nuovo file di zona.
DHCP e DDNS
Proviamo a catturare il traffico osservato dal nostro computer, per scoprire gli eventuali
messaggi DHCP di Discovery e Request. Quindi, proviamo a suscitarli noi stessi, mediante
l'interfaccia di configurazione della rete (sudo network-admin), configurando una connessione
via cavo che faccia uso di un server DHCP, e salvando poi la configurazione così ottenuta.
Dnsmasq
Si tratta di un serverino molto intelligente (sito, man page, guida alla configurazione 1, 2), che
implementa un forwarder DNS, associato ad un server DHCP, il tutto incorporato in unico
programma. In tal modo, si è in grado di risolvere gli IP dei computer della propria rete, in base
al nome che questi hanno comunicato nella DHCP Discovery, ed in base all'IP affittato loro.
Sperimentiamo ora questa nuova soluzione, in modo da confrontarla con la configurazione statica
del file di zona, intrapresa precedentemente.
Sul computer con IP 192.168.0.152:
• editiamo il file di configurazione di dnsmasq, con sudo gedit /etc/dnsmasq.conf, in
modo che in fondo allo stesso, appaiano le direttive
dhcp-range=192.168.0.151,192.168.0.170,12h
dhcp-option=option:router,192.168.0.3
selfmx
domain=softel
di host
•
•
•
•
#
#
#
#
L'intervallo degli indirizzi da assegnare
Il default gateway da comunicare ai clients
Aggiunge un record MX ad ogni IP
il suffisso di domiono da aggiungere ai nomi
seguiamo l'evolversi degli eventi, con tail -f /var/log/daemon.log
disattiviamo il DNS BIND, con il comando sudo /etc/init.d/bind9 stop
mettiamoci in ascolto con wireshark
lanciamo dnsmask, con sudo /etc/init.d/dnsmask start
Sugli altri computer del laboratorio, invece, lanciamo di nuovo lo strumento grafico Sistema/
Amministrazione/Rete, clicchiamo sulle Proprietà della connessione via cavo, e scegliamo la
Configurazione automatica (DHCP). Dovremmo aver ricevuto un nuovo IP, diverso dal
precedente. Verifichiamo:
•
•
•
•
il nostro nuovo IP, con il comando ip addr
le informazioni di routing, con il comando ip route
l'impostazione del DNS, con il comando cat /etc/resolv.conf
che la risoluzione funzioni ancora, con il comando host mionome
• nella sperimentazione, avviamo verificato che dnsmask utilizza come DNS a cui
inoltrare le richieste per i domini esterni, quello che trova scritto in /etc/
resolv.conf. Per questo, prima di lanciare dnsmask, è bene verificare che lì sia
scritto qualcosa di sensato
Il risultato dello svolgimento della procedura indicata, è riportata in questo file di cattura,
ottenuto presso lo stesso computer in cui viene eseguito dnsmask.
251
Zeroconf
Domain Name System
Zeroconf
L'implementazione di Zeroconf per Linux è quella fornita da Avahi, e che prevede di installare i
pacchetti
• avahi-daemon, che realizza le funzioni di mDNS e DNS-SD
• avahi-discover, che offre una applicazione grafica in grado di scoprire i servizi
zeroconf presenti in rete
• avahi-utils, che comprendono una serie di programmi, che permettono ad esempio di
interrogare il mDSN, ovvero di pubblicare un nuovo servizio
• libnss-mdns, che offre il supporto mDSN alla resolver library
• Un browser web che supporta l'mDNS per la risoluzione dei nomi *.local, è Epiphany
A questo punto, abbiamo tutto ciò che occorre per procedere nella nostra sperimentazione.
Mantenendo aperto il capture di Wireshark
• attivare l'mDNS del proprio host, eseguendo il comando sudo avahi-daemon
• osservare che a seguito del lancio dell'mDNS, dopo un primo messaggio IGMP che segna
l'iscrizione dell'host al gruppo multicast, seguono delle query in cui nel campo
Authoritative si annunciano i dati dell'host, e quindi, in assenza di contese sullo stesso
Link Locale, viene generata una risposta. Poi, altre tre query che annunciano il servizio di
workstation, ed ancora risposte.
• per scoprire i servizi offerti dagli host presenti nella propria LAN, eseguire il comando
avahi-discover
• per abilitare l'uso di mDNS da parte del resolver, modificare il file /etc/nsswitch.conf
come indicato presso /usr/share/doc/libnss-mdns/README.html
• provare ora a lanciare Epiphany, e referenziare l'indirizo
http://nomedelvostrocomputer.local (sempre che abbiate installato il web sever,
apache va benissimo!)
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Dicembre 2007
252
Lo strato applicativo di Internet
Posta elettronica: SMTP, IMAP, e
autenticazione
Nella esercitazione precedente abbiamo configurato un DNS presso 192.168.0.152, e lo abbiamo
reso autorevole per la zona di TLD softel, i cui nomi a dominio di secondo livello sono stati fatti
corrispondere con i nomi e gli IP privati dei computer del laboratorio. Quindi per ogni
computer, è stato aggiunto nel DNS un RR di tipo MX, che definisce ogni computer, come il Mail
eXchanger di se stesso. Ora, ci aggingiamo a configurare per ogni computer un server SMTP, in
modo che si possano inviare e ricevere email da un computer all'altro, senza dover transitare
dall'esterno, come codificato da header del tipo
From: alice <[email protected]>
To:
bruno <[email protected]>
In questo esempio, alice è seduta davanti a alice.softel, e vi sta lavorando con login
labsoftel. Per inviare una email al suo collega bruno, loggato come labsoftel su
bruno.softel, lo User Agent di posta elettronica di alice utilizza
• come identità, alice <[email protected]>, e
• come server SMTP di uscita, quello residente sul proprio stesso computer.
Il proprio SMTP server quindi, interrogando il DNS residente su alef.softel, invia a sua volta
l'email al server SMTP residente su bruno.softel.
Se al contrario, alice vuole inviare una email ad un indirizzo email domiciliato presso un nome
a dominio associato ad un IP pubblico, allora dovrà usare
• una identità presso la quale possa ottenere una risposta, come ad esempio alice
<[email protected]>, ed
• un server SMTP di uscita (detto outbound) che inoltri l'email sulla Internet pubblica
Stabiliamo dunque di configurare l'SMTP presente su smtp.softelin modo che questo, anzichè
tentare di contattare direttamente il server di posta indicato dal RR MX del dominio di
destinazione (che molto probabilmente rifiuterebbe di accettarla, come difesa dallo spam), invii
tutta la posta in uscita ad un suo smarthost fisso, residente sulla Internet pubblica, in modo che
sia questo, a consegnare l'email a destinazione. Qualora il destinatario della email di alice (ad
es bruno <[email protected]>) scelga di rispondere ad alice.delmar,
quest'ultima troverà la risposta presso il dominio gmail.com.
Configurazione di un server SMTP - Postfix
Posta elettronica: SMTP, IMAP, e autenticazione
• Configurazione di un server SMTP - Postfix
• Invio interno al dominio locale
• Ricezione locale
• Analisi del traffico email
•
•
•
•
•
il capture
i file di log
MIME
encoded word
transfer encoding
• Prelievo email con server IMAP - Dovecot
• Architettura del server
• Protocollo di accesso
• Autenticazione
• formato delle password
• Ricezione ed autenticazione
• SASL
• CRAM-MD5
• Abilitazione di TLS
• Uso di certificati differenti
• Sicurezza per l'SMTP
• Risoluzione Problemi
Configurazione di un server SMTP - Postfix
La distribuzione Ubuntu 7.10 installata al laboratorio, prevede l'utilizzo del server SMTP Postfix.
Ci sono tre diversi modi di configurarlo:
1. usando Synaptic per scaricarlo, viene eseguita automaticamente una procedura di
configurazione guidata in modalità grafica;
2. seguendo le istruzioni riportate nella documentazione di Ubuntu, dopo l'installazione, si
può eseguire il comando
sudo dpkg-reconfigure postfix, che determina l'esecuzione di una procedura di
configurazione guidata in modalità testuale;
254
Lo strato applicativo di Internet
Alessandro Falaschi
3. modificando direttamente il file di configurazione del demone, eseguendo sudo gedit
/etc/postfix/main.cf
Dato che la prima modalità parte da sola all'atto dello scaricamento, illustriamo cosa rispondere
alle domande, tenendo però presente che se questa modalità non dovesse andare a buon fine,
possiamo ricorrere ad una delle altre due. Usando Synaptic, dopo aver cercato, selezionato e
scaricato Postfix, ci compare una finestra di configurazione, in cui per ogni domanda, possiamo
chiedere l'aiuto, che ci chiarifica il senso delle scelte da effettuare. Vediamo ora quindi, le
risposte da fornire nei due casi individuati, ossia l'installazione del proprio server, e del server di
Outbound:
• Profilo generale: rispondiamo Sito Internet. Significa che il computer tenterà di
recapitare la posta in uscita direttamente al destinatario finale, e verrà abilitato a
riceverla, ovviamente, solo dai client interni alla rete locale.
• nel caso invece della configurazione dell'outbound SMTP, rispondiamo Sito internet
con smarthost, che significherà che il computer non tenterà di di consegnare
direttamente l'email al destinatario, ma la invierà tutta ad un ulteriore sever SMTP,
ospitato sulla Internet pubblica, che realizza una funzione di relay (ponte);
• Nome del sistema: inserire (se non è già suggerito) il nome che compare come risposta al
comando shell hostname (tipicamente, quello che si è inserito alla esercitazione
precedente, e che dovrebbe essere pari a mionome.softel). Questa informazione è
necessaria al server SMTP per riconoscersi come il destinatario finale delle email a lui
dirette, nel qual caso, tenterà di consegnarle nella inbox dell'utente locale, se esiste. Per
domini diversi, invece, tenterà di contattare direttamente l'SMTP di destinazione;
• l'outbound SMTP invece, quando riceve una email destinata ad un indirizzo diverso
dal proprio nome, tenta di inoltrarla al suo smarthost;
• SMTP relay host: questa impostazione viene richiesta solo nel caso dell'outbound SMTP, ed
è il nome del computer prima indicato come smarthost. Inseriamo qui il nome del server
SMTP del provider che ci offre la connettività.
Il risultato della configurazione è visualizzabile nel file /etc/postfix/main.cf, la cui lista
completa dei parametri di configurazione è ottenibile come man 5 postconf. Nel nostro caso,
avremo il risultato:
myhostname = mionome.softel
mydestination = mionome.softel, localhost.softel, localhost
relayhost =
mynetworks = 127.0.0.0/8
mentre per l'outbound SMTP, occorre aggiungere a mynetworks la rete locale 192.168.0.0/24,
istruendolo così a permetterne l'uso come Relay da parte degli altri computer della LAN, come
illustrato dalla documentazione. Inoltre, l'outbound SMTP deve inserire, alla riga relayhost,
quello designato per inoltrare le email sulla Internet pubblica.
Invio interno al dominio locale
Per sperimentare l'invio delle email, utilizziamo un client di posta, ad esempio possiamo usare
Evolution. Se è la prima volta che lo apriamo, la configurazione di un nuovo account partirà da
sola, altrimenti, ci possiamo arrivare dal menù modifica/preferenze. Chiamiamo questo nuovo
account [email protected], che corrisponderà anche all'indirizzo email, ed
impostiamo per la posta in uscita, il server SMTP residente sul nostro stesso computer ed appena
installato, ossia ancora mionome.softel; per ora, non richiediamo nessuna opzione di
sicurezza. Quindi, usciamo da Evolution, e rientriamo. Monitorando il file di log di Postfix
mediante il comando tail -f /var/log/mail.log, ed eventualmente tenendo aperto
255
Configurazione di un server SMTP - Postfix
Posta elettronica: SMTP, IMAP, e autenticazione
wireshark con filtro di cattura port 25, proviamo a spedire una email verso l'indirizzo di un
nostro collega, come [email protected].
Che succede ? Non parte ? Che messaggio di errore osserviamo ? Proviamo a capire cosa è
successo, dall'analisi del nostro file di log, ed eventualmente, anche di quello del nostro collega.
Ad esempio, potreste avere impostato male myhostname, nel qual caso il mittente si vedrà
tornare indietro l'email, con il motivo che "il destinatario ha problemi di loop".
Dopo aver eventualmente modificato il file di configurazione, dobbiamo fare in modo che Postfix
lo rilegga: impartiamo allora il comando sudo /etc/init.d/postfix restart. Verificare
che nel file di log, il processo si riavvii.
Ricezione locale
Ora che siamo in grado di scrivere ai computer di softel, cerchiamo anche di leggere la posta
ricevuta. Dato che siamo seduti davanti allo stesso computer su cui è in esecuzione l'SMTP
ricevente, possiamo verificare che l'email che un nostro collega ci ha scritto, si è effettivamente
parcheggiata in un file di sistema, immettendo il comando cat /var/mail/labsoftel. In
modo più comodo, potremmo accedervi mediante un client di posta testuale, come ad esempio
mutt.
Per potervi accedere dal client di email, dobbiamo ri-aprire Modifica/preferenze, ed editare
l'account, specificando sulla linguetta Ricezione email, di usare un File spool mbox standard
Unix, ed indicando il percorso /var/mail/alef.
Analisi del traffico email
Modifichiamo ora la configurazione dello User Agent Evolution, scegliendo il nostro account in
Modifica/preferenze, e nelle preferenze di composizione, indichiamo Formato messaggi in HTML
come Comportamento predefinito. Quindi
• creiamo ora una nuova email, nuovamente indirizzata al nostro
[email protected] (accertandoci che lui faccia lo stesso), contenente
• un Subject con (almeno) una lettera accentata
• una frase con qualche lettera accentata
• il nostro nome evidenziato come Header1 (usando il secondo selettore sotto
l'oggetto)
• usando la voce del menù in alto Inserisci:
• una faccina
• una immagine (ad esempio, /home/labsoftel/Examples/
logo-Ubuntu.png)
• e quindi allegare un'altra email, trascinandone (con il mouse) il sommario, dentro
alla finestra di composizione
• prima di inviare l'email
• aspettiamo che anche il nostro collega l'abbia compilata
• lanciamo Wireshark, ed assicuriamoci che anche il collega l'abbia lanciato
• su una altra finestra terminale, eseguiamo il comando tail -f /var/log/
mail.log
• finalmente, spediamo l'email, e poi, fermiamo wireshark.
256
Lo strato applicativo di Internet
Alessandro Falaschi
Il capture
Ora che nel capture il traffico è incrociato, con gli stessi due IP che si scambiano il ruolo di
mittente e destinatario, come facciamo a separare il traffico delle due comunicazioni?
Ovviamente, vale sempre il filtro creato con "follow TCP stream"... ma più in generale, i due
Client useranno due diverse porte effimere, dunque sarà così, che potremo distinguere i due tipi
di traffico.
I file di log
Se apriamo l'email ricevuta, e scegliamo di visualizzarne il sorgente, ad esempio digitando
control-u, possiamo
• verificare che il message-id che compare nel file di log del nostro collega, in
corrispondenza alla accettazione del messaggio da parte del suo SMTP server, corrisponde
a quello associato all'Header MIME omonimo;
• osservando il traffico catturato, potremmo verificare se questo Header fosse già
presente nel messaggio, oppure sia stato inserito dall'SMTP ricevente;
• verificare come l'id presente nel primo Header Received, corrisponda a quello indicato nel
nostro file di log;
• apprezzare la struttura annidata prevista dallo standard MIME.
MIME
Meglio ancora, salviamo il messaggio come un file, e poi apriamolo con il solito editor gedit, in
modo da ritrovarci nella stessa situazione ottenibile osservando ad esempio questo messaggio
salvato. Osserviamo come
• il boundary =-tD+3pVv/anrIvtyoTefF separa l'email vera e propria, dall'allegato
(l'altro messaggio)
• il boundary =-G0oO6HRE7BjAXqVLfRx3 separa il testo della email, dalla
immagine inclusa
• il boundary =-OGyz4VI0kdx5dq1STkyx separa la versione del messaggio in
text/plain, da quella in HTML
Notiamo ora, come nella parte HTML, l'immagine sia referenziata citando il Content-ID:
<1197403030.18175.2.camel@alef-laptop> definito nella parte MIME che la rappresenta.
Verifichiamo come l'immagine sia rappresentata con una codifica di trasferimento di tipo Base64.
Encoded Word
Osserviamo come la parola Perù presente nel Subject, sia stata trasformata nella stringa
=?ISO-8859-1?Q?Per=F9?=, in accordo al metodo indicato come Encoded Word, utilizzando
perdipiù un charset di riferimento (ISO-8859-1) diverso da quello usato nel body della email.
Transfer Encoding
Facciamo ora caso alla modalità di rappresentazione delle lettere accentate. Nella parte HTML,
benchè sia dichiarato l'uso del charset UTF-8, si adotta un Transfer-Encoding a 7bit, dato che non
sono presenti caratteri diversi dall'insieme US-ASCII. Infatti, le lettere accentate (e non solo),
sono rappresentate per mezzo di Numeric Character Reference, un metodo precedente alla
definizione dell'Unicode, e che rappresenta un carattere mediante la sequenza &#nnn; in cui
257
Prelievo email con server IMAP - Dovecot
Posta elettronica: SMTP, IMAP, e autenticazione
nnn sono due o più cifre numeriche che individuano il codepoint del carattere rappresentato,
nell'ambito del charset dichiarato per il documento.
Per quanto riguarda la parte in text/plain invece, l'effettiva codifica UTF-8 ad 8 bit, usata per
rappresentare i caratteri non-ASCII, può essere apprezzata al meglio, utilizzando un editor
binario: adoperiamoci quindi per scaricare il buon khexedit impartendo il comando sudo
apt-get install khexedit. Quindi, possiamo aprire il file contenente il testo della email
salvata, e verificare come per le lettere accentate, vengano effettivamente usati due bytes. Con
un pò di pazienza, potremmo anche verificare come risalire effettivamente, ai codepoints
rappresentati.
Prelievo email con server IMAP - Dovecot
Come illustrato nella guida di ubuntu, la distribuzione è armonizzata con il server Dovecot, che
scarichiamo mediante Synaptic, selezionando dovecot-imapd.
Architettura del server
Dovecot si compone di diversi processi, ed i principali sono
• processo Master (dovecot) - legge i files di configurazione, scrive i file di log, lancia gli
altri processi e li ri-lancia in caso di errore;
• processi di Login (imap-login, pop3-login) - accettano la connessione di un nuovo client,
rispondono alle richieste di opzioni, gestiscono l'attivazione di TLS/SSl se richiesto, e
quindi comunicano con il processo di autenticazione, dopodiché (in caso di successo)
cedono il controllo al processo mail vero e proprio;
• processo di Authentication (dovecot-auth) - gestisce tutti i passi relativi alla
autenticazione, ossia i meccanismi SASL, la verifica delle password, e le informazioni di
utente. Comunica sia con i processi di login, che con il processo master, tenendo memoria
se il PID associato al singolo client è stato autenticato o meno;
• processo Mail (imap, pop3) - gestisce l'accesso alle email associate all'utente che ha
effettuato con successo il login, in accordo al protocollo selezionato.
Protocollo di accesso
Scegliamo di accedere all'email mediante lo user agent Evolution, adottando il protocollo IMAP.
Per questo:
• editare /etc/dovecot/dovecot.conf, e decommentare la linea protocols = imap
imaps, commentando invece protocols = none
• ri-lanciare il server dovecot con il comando sudo /etc/init.d/dovecot restart
• in Evolution, configurare come imap server il nome del proprio computer mionome.softel,
e come nome utente, labsoftel
• mantenere aperto wireshark, e sniffare sulla interfaccia any:
ora, cliccando sulla cartella inbox (o in arrivo), sarà chiesta la password per l'utente indicato, e
sarà possibile leggere le email spedite in locale. Verificare con Wireshark, cosa è successo (sulla
porta 143).
* OK Dovecot ready.
A00000 CAPABILITY
* CAPABILITY IMAP4rev1 SASL-IR SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN
NAMESPACE LOGIN-REFERRALS STARTTLS AUTH=PLAIN
A00000 OK Capability completed.
258
Lo strato applicativo di Internet
Alessandro Falaschi
A00001 LOGIN alef password-in-chiaro
A00001 OK Logged in.
A00002 NAMESPACE
* NAMESPACE (("" "/")) NIL NIL
A00002 OK Namespace completed.
A00003 LIST "" {1+}
.
.... etc etc etc
In rosso, sono indicati i messaggi inviati dal client: come si vede, la password viene trasmessa in
chiaro. Proviamo ora a configurare tutti quanti lo stesso server IMAP, corrispondente
a alef.softel, e verifichiamo la possibilità per IMAP, di avere più connessioni contemporanee, alla
stessa mailbox. Possiamo ora facilmente trasformare anche questo esperimento, in una nuova
forma di chat. Ma... non ci permette di entrare! Sniffando, osservo
* OK Dovecot ready.
A00000 CAPABILITY
* CAPABILITY IMAP4rev1 SASL-IR SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN
NAMESPACE LOGIN-REFERRALS STARTTLS LOGINDISABLED
A00000 OK Capability completed.
A00001 LOGIN labsoftel password-in-chiaro
* BAD [ALERT] Plaintext authentication is disabled, but your client sent password in plaintext
anyway. If anyone was listening, the password was exposed.
A00001 NO Plaintext authentication disallowed on non-secure connections.
A00002 LOGOUT
* BYE Logging out
A00002 OK Logout completed.
Questo comportamento è dettato dalla direttiva di configurazione disable_plaintext_auth
= yes, presente nel file /etc/dovecot/dovecot.conf, e attiva di default. In questo caso il
Dovecot in escecuzione su alef.softel, accorgendosi che l'IP di provenienza è differente dal
proprio, ci mette in guardia dei rischi di sicurezza, a meno che questo non sia previsto,
modificando la direttiva di compilazione. Anziché seguire questa strada, valutiamo le possibilità
di mettere in sicurezza la ricezione delle email.
Autenticazione
L'abilitazione alla autenticazione del ricevente, ci mette in grado di assolvere al punto 4) dei
requisiti di sicurezza per la posta elettronica. Se chiediamo a Evolution il tipo di autenticazione
supportato dal server IMAP (Modifica/Preferenze, e poi Modifica del profilo email creato, e
quindi Ricezione email, e poi Controlla tipi supportati), il capture di Ethereal mostra lo scambio
* OK Dovecot ready.
A00000 CAPABILITY
* CAPABILITY IMAP4rev1 SASL-IR SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN
NAMESPACE LOGIN-REFERRALS STARTTLS LOGINDISABLED
A00000 OK Capability completed.
in cui osserviamo come il protocollo IMAP permetta al client di
investigare sulle Capability del server: quelle che ci interessano, in
questa fase, sono SASL e STARTTLS. Dato che per Evolution la
risposta ottenuta determina la cancellazione dei tipi di
autenticazione diversi dalla password, ed avendo capito che per
password, si intende in chiaro, ciò significa che per procedere,
occorre abilitare le funzioni crittografiche previste dal server
Dovecot, ossia il Simple Authentication and Security Layer (SASL) ed il TLS. Ma prima, conviene
svolgere qualche considerazione relativa al formato con cui sono memorizzate le password presso
il server.
259
Prelievo email con server IMAP - Dovecot
Posta elettronica: SMTP, IMAP, e autenticazione
Formato delle password
Se le password memorizzate presso il server sono salvate in chiaro, queste possono essere
utilizzatate congiuntamente ad un qualunque meccanismo di autenticazione, perché una volta
che il server riceve una password su cui è stata operata una traformazione crittografica, non
deve far altro che applicare la medesima trasformazione sulla propria copia della password, e
verificare se i risultati corrispondono.
D'altra parte, nel caso in cui il server venga compromesso, e venisse trafugato il file con le
password in chiaro di tutti gli utenti, avremmo combinato un bel casino. Per questo motivo, si
preferisce memorizzare (almeno presso il server) le password in forma crittografata. Infatti, se la
password ci viene inviata in chiaro, non dobbiamo far altro che ripetere su questa, la
trasformazione crittografica utilizzata nella fase di salvataggio, e procedere al confronto. Se
invece la password ci arriva già crittografata, allora... in generale, il meccanismo di crittografia
usato per memorizzare le password sul server, deve essere legato al meccanismo di crittografia
adottato dal meccanismo di autenticazione. Come risultato, se si consente agli utenti di scegliere
uno tra diversi meccanismi crittografici, si hanno due possibilità:
• mantenere presso il server diversi formati crittografici per lo stesso insieme di password,
uno per ogni meccanismo di autenticazione possibile, oppure
• tornare al caso della memorizzare di una unica copia delle password in chiaro, da
trasformare di volta in volta, in accordo al meccanismo crittografico scelto dall'utente.
Infine, nel caso in cui la trasmissione si avvalga dei servizi crittografici offerti da uno strato
inferiore, in grado di garantire la riservatezza della comunicazione, come nel caso di IPSec/ESP o
di TLS, allora si può tornare ad effettuare l'invio della password in chiaro, e mantenere le
password presso il server in un formato crittografico unico.
SASL
Come illustrato nella parte di teoria, (SASL) è una libreria che offre ai protocolli applicativi, l'uso
di meccanimsi crittografici a scelta. Tra i vari possibili meccanismi di autenticazione utilizzabili
da Dovecot, scegliamo di attivare CRAM-MD5.
CRAM-MD5
Per questo, editiamo (come root) il file /etc/dovecot/dovecot.conf, localizzando la linea
che elenca i meccanismi, e modificandola come
mechanisms = plain cram-md5
Seguendo le indicazioni di un howto, scegliamo di memorizzare una password criptata con uno
schema compatibile con CRAM-MD5, da associare all'utente labsoftel che effettivamente esiste
sul computer, in un database di password corrispondente ad un semplice file in formato passwd,
che salviamo in /etc/dovecot/cram-md5.pwd. Per fare questo,
• invochiamo il comando dovecotpw a cui forniamo il valore di password che intendiamo
usare, e prendiamo nota del suo valore crittografato. Ad esempio, scegliendo come
password labsoftel, si ottiene
{HMAC-MD5}57038d3507ea76f510597155a39f6bf172bcc436e76c43e669f53c98b9a81afe
• creiamo un nuovo file con gedit (lanciato come root), in cui inseriamo la linea
labsoftel:{HMAC-MD5}57038d3507ea76f510597155a39f6bf172bcc436e76c43e669f53c98b9
• salviamo il file con nome /etc/dovecot/cram-md5.pwd;
260
Lo strato applicativo di Internet
Alessandro Falaschi
• modifichiamo i permessi del nuovo file con sudo chmod 0600 /etc/dovecot/
cram-md5.pwd;
• aggiungiamo in /etc/dovecot/dovecot.conf la direttiva
passdb passwd-file {
args = /etc/dovecot/cram-md5.pwd
}
• ri-lanciamo il server dovecot con il comando sudo /etc/init.d/dovecot restart;
Se ora eseguiamo di nuovo la richiesta del tipo di autenticazione supportata, osserviamo che ora
CRAM-MD5 non è cancellato, e lo possiamo selezionare. Quindi, sniffando con Wireshark il
traffico corrispondente ad una richiesta di Send/Receive, otteniamo il capture
* OK Dovecot ready.
A00000 CAPABILITY
* CAPABILITY IMAP4rev1 SASL-IR SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN
NAMESPACE LOGIN-REFERRALS STARTTLS LOGINDISABLED AUTH=CRAM-MD5
A00000 OK Capability completed.
A00001 AUTHENTICATE CRAM-MD5
+ PDE4NDk0MzMxMjQzNjI0ODMuMTIwMTcwODQzMUBhbGVmPg==
bGFic29mdGVsIDU1ZWIzNDYyMDdmMDE4NzEyODVkYjJmMTUxYWY4M2Zl
A00001 OK Logged in.
A00002 NAMESPACE
* NAMESPACE (("" "/")) NIL NIL
A00002 OK Namespace completed.
.
... etc etc etc
in cui osserviamo appunto, l'offerta AUTH=CRAM-MD5, la sua scelta, l'invio della sfida, e la
risposta, contenente la codifica base64 del nome dell'utente, e l'HMAC-MD5 calcolato a partire
da challenge e password. Utilizzando uno strumento on-line di co-decodifica base64, possiamo
verificare che il contenuto di challenge e response, corrisponde a quanto illustrato a lezione.
Abilitazione di TLS
L'uso di un servizio di sicurezza a livello di trasporto, svincola lo strato applicativo dal doversi
preoccupare di possibili attacchi di sicurezza, e permette l'invio di password in chiaro. In questo
caso, mentre l'utente si autentica presso il server inviando la propria password, anche il server si
autentica presso l'utente, mediante l'invio di un proprio certificato. Perché ciò sia possibile,
occorre editare di nuovo il file /etc/dovecot/dovecot.conf, e decommentare le linee
ssl_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
ssl_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
che contengono i riferimenti ad una chiave privata (.key), ed al certificato X.509 autofirmato
(.pem), relativo alla rispettiva chiave pubblica, che sono preinstallati su linux. A questo punto
ri-configuriamo Evolution, chiedendo di abilitare TLS, come previsto dalla RFC 2595, passando
ancora da Modifica/Preferenze, scegliendo l'account/Modifica, Ricezione enail/usa connessione
sicura/TLS. Dopo aver richiuso e ri-lanciato Evolution, questo ci mostra una finestra in cui chiede
se accettare o meno il certificato autofirmato ricevuto, rilasciato da un fantomatico Office for
Complication of Otherwise Simple Affairs, e con
fingerprint 12:cf:98:70:fc:81:a7:1f:d2:c7:3c:8f:62:9f:a7:75.
Stavolta il capture di Wireshark appare come segue:
261
Sicurezza per l'SMTP
Posta elettronica: SMTP, IMAP, e autenticazione
* OK Dovecot ready.
A00000 CAPABILITY
* CAPABILITY IMAP4rev1 SASL-IR SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN
NAMESPACE LOGIN-REFERRALS STARTTLS LOGINDISABLED AUTH=CRAM-MD5
A00000 OK Capability completed.
A00001 STARTTLS
A00001 OK Begin TLS negotiation now.
.^....E......9..8..5..f..3..2......../...........
.
... etc etc etc
e dopo la richiesta (confermata) di utilizzare il TLS, il dissettore di IMAP non è più in grado di
decodificare il traffico. Invece, qualora in Evolution si richieda l'SSL anzichè il TLS, si può ancora
vedere qualcosa, come mostrato in questo capture.
Uso di certificati differenti
Nelle esercitazioni sugli aspetti di sicurezza, si illustra come generare ed utilizzare un certificato
differente.
Sicurezza per l'SMTP
Torniamo ora al server SMTP di uscita. Anche per questo, possiamo abilitare le opzioni di
sicurezza, agendo sul file di configurazione. Postfix non offre un supporto alla sicurezza in modo
diretto, ma utilizza invece i servizi offerti da altri componenti software. In particolare, può
utilizzare il componente di autenticazione SASL offerto da Dovecot, che abbiamo già configurato
correttamente, e quindi sarà proprio quello che useremo. Seguendo le indicazioni fornite in nella
documentazione di Postfix e relativa a SASL e TLS, operiamo come segue:
• apriamo con sudo gedit /etc/postfix/main.cf il file di configurazione di Postfix
• decommentiamo le linee che indicano il certificato e la chiave privata da usare, abilitano
il supporto a TLS, e definiscono la memoria cache
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${queue_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${queue_directory}/smtp_scache
• inseriamo delle linee che abilitano l'uso di SASL, stabiliscono le restrizioni per
l'accettazione delle email in uscita, e forzano l'aggiunta di un header che attesta
l'avvenuta autenticazione
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject
smtpd_sasl_authenticated_header = yes
• aggiungiamo le due linee che indicano di usare il supporto SASL offerto da Dovecot, e
definiscono il path di comunicazione tra Postfix e Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
• e salviamo il file così modificato.
Ora, apriamo il file di configurazione di Dovecot con sudo gedit /etc/dovecot/
dovecot.conf e, come indicato nella documentazione di Postfix, aggiungiamo nella sezione
auth default {} il nome ed i privilegi per il socket Unix di comunicazione tra Dovecot e
262
Lo strato applicativo di Internet
Alessandro Falaschi
Postfix:
auth default {
socket listen {
client {
path = /var/spool/postfix/private/auth
mode = 0660
user = postfix
group = postfix
}
}
}
A questo punto, possiamo far ripartire entrambi i server con i comandi
sudo /etc/init.d/postfix restart
sudo /etc/init.d/dovecot restart
e provare a spedire email con Evolution. Innanzitutto, chiediamo (Edit/Preferences,
selezioniamo il profilo, Edit, Sending Email) di usare una connessione TLS. Scriviamo un
messaggio in uscita, e verifichiamo che il capture prodotto con Wireshark sia simile a questo
220 alef-laptop ESMTP Postfix (Ubuntu)
EHLO [127.0.0.1]
250-alef-laptop
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN CRAM-MD5
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
STARTTLS
220 2.0.0 Ready to start TLS
....]...Y...%U.o.`yy.........4.Z..r....q..# ...\W|(.x...D.>...M..j3. K...b.........
dove appunto, notiamo la presenza della estensione AUTH PLAIN CRAM-MD5, identica a come
l'avevamo configurata per Dovecot, mentre a seguito della negoziazione TLS, il contenuto diventa
indecifrabile. Quindi, riconfiguriamo nuovamente Evolution, rimuovendo la richiesta del TLS, ed
inserendo invece quella per l'autenticazione CRAM-MD5. Sniffando di nuovo, notiamo che il
messaggio ora viaggia in chiaro, ma prima della sua accettazione, il client si è autenticato:
...
250 DSN
AUTH CRAM-MD5
334 PDE3MjU2NDQxMDYyNDYyNjkuMTE3OTI2ODYyNEBhbGVmLWxhcHRvcD4=
YWxlZiAyMmQzMjI0MmY4Mjg1MGViZTk5YWNmZDIxMDNlMjc1Nw==
235 2.0.0 Authentication successful
MAIL FROM:<[email protected]>
250 2.1.0 Ok
...
Inoltre, se andiamo ad aprire gli header del messaggio che è arrivato a destinazione remota,
possiamo trovare la traccia della avvenuta autenticazione, nel primo Received:
Received: from [127.0.0.1] (alef-laptop [127.0.0.1]) (Authenticated sender:
alef) by alef-laptop (Postfix) with ESMTP id CC520186128 for
<[email protected]>; Wed, 16 May 2007 00:36:10 +0200 (CEST)
263
Risoluzione problemi
Posta elettronica: SMTP, IMAP, e autenticazione
Pertanto, possiamo concludere che, abilitando l'autenticazione SMTP, siamo riusciti a conseguire
i punti 1) e 3) dei requisiti di sicurezza per la posta elettronica, mentre per il 2), questo non può
essere garantito, in quanto sarebbe necessaria l'esistenza di un rapprto di fiducia tra tutte le
coppie di server SMTP di trandito possibili.
Infine, se riconfiguriamo ancora una volta Evolution, per utilizzare sia l'autenticazione CRAM-MD5
che il TLS, in ricezione possiamo ancora osservare l'header che dichiara l'avvenuta
autenticazione, mentre osservando il capture, verifichiamo che questa ha luogo dopo che si è
attivato il TLS, e questo è il motivo per cui con il TLS, l'autenticazione può anche essere basata
semplicemente su plaintext.
Risoluzione problemi
Nel corso della esercitazione, le cose possono non andare così lisce come previsto, ma spesso è
sufficiente tenere d'occhio i file /var/log/messages e /var/log/mail.log (o .warn, o
.err) per scoprire la natura del problema. Tenerli d'occhio vuol dire leggerli mediante il
comando less (per andare ad inizio/fine file, si usino i simboli < e >), oppure (meglio ancora) in
una altra finestra terminale, si inserisca il comando
tail -f /var/log/mail.log
che visualizzerà le righe del file, men mano che queste vengono aggiunte dal demone SMTP.
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Febbraio 2007
264
Lo strato applicativo di Internet
Aspetti di Sicurezza delle
Telecomunicazoni Internet
In questa sezione svolgiamo alcune esperienze di applicazione degli aspetti di sicurezza alle
telecomunicazioni Internet
• SSH
•
•
•
•
Autenticazione del server
Confidenzialità
Autenticazione del client
Grafica remota
• TLS
• Openssl
•
•
•
•
Creazione di una Certification Autority
Richiesta di un nuovo certificato firmato
Firma del certificato
Interfacce grafiche
• Gnu Privacy Guard
• Seahorse
SSH
Fin dagli albori di Internet, si è potuti entrare su di un altro computer, usando il comando Telnet
per collegare standard input ed ouput locali, ad una sessione terminale remota. Questa modalità
operativa però, soffre di alcune ingenuità legate al fatto che ai tempi in cui fu definito Telnet,
Internet era confinata al mondo accademico e della ricerca, per cui
• nella la fase di autenticazione iniziale la password viene trasmessa in chiaro
• non è previsto un modo per crittografare la comunicazione
A partire dal 1995, si è lavorato ad un diverso metodo di connessione remota, crittograficamente
sicuro, ed il risultato, noto come Secure SHell, è stato formalizzato in una serie di documenti
emessi dal gruppo di lavoro SECSH di IETF, brevissimamente riassunti qui. L'implementazione più
diffusa sui sistemi Unix, è quella offerta dal progetto OpenSSH, e prevede l'esecuzione di un
applicativo server (sshd) in ascolto in TCP, sulla porta ben nota 22, e di un programma client
(ssh), da invocare da parte di chi vuol connettersi. Per funzionare, non pretende l'esistenza di
una PKI, ma si basa sulla autenticazione a chiave pubblica delle due parti in comunicazione, e
sulla generazione estemporanea di chiavi simmetriche di sessione.
In effetti, lo scopo di ssh non si limita al solo accesso ad una shell remota, ed una delle sue
caratteristiche più interessanti, consiste nella possibilità di realizzare dei tunnel sicuri tra
computer, ridirezionando servizi basati su socket, da uno all'altro.
SSH
Aspetti di Sicurezza delle Telecomunicazoni Internet
Autenticazione del server
Questo aspetto è per così dire simmetrico a quello della autenticazione del client: se infatti il
client fornisse le sue credenziali, anziché al server a cui si rivolge, ad un man in the middle
impostore, oltre che non riceverere il servizio richiesto, il client avrebbe anche svelato la sua
identità, e la sua password. Per questo, occorre stabilire un modo per permettere al server di
dimostrare la sua identità.
Quando ci si collega in ssh ad un computer remoto per la prima volta, ci viene chiesto se
accettare o meno la chiave pubblica del server, identificata da una fingerprint. In linea di
principio, si dovrebbe contattare in modo sicuro (ad es, per telefono) l'amministratore del server
e leggergli la fingerprint, chiedendogli se questa corrisponde effettivamente a quella della
chiave pubblica del suo computer.
alef@alef-laptop:~$ ssh 151.100.122.171
The authenticity of host '151.100.122.171 (151.100.122.171)' can't be established.
RSA key fingerprint is 5a:f9:f2:33:68:d7:6f:45:ec:b4:35:d0:cf:00:e3:b9.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '151.100.122.171' (RSA) to the list of known hosts.
[email protected]'s password: *******
[alef@labtel alef]$
Nel caso in cui si decida di fidarci della chiave pubblica, questa viene memorizzata, assieme al
nome del computer, nel file ~/.ssh/known_hosts.
Le volte successive che ci colleghiamo, se il server continua a fornire la stessa chiave pubblica, e
che ora corrisponde alla versione memorizzata dal lato client, non ci verrà più chiesto se
accettare o meno l'autenticità della parte remota. Viceversa, se la chiave pubblica del server
fosse cambiata, ci verrà impedito di collegarci, nel dubbio che qualcun altro stia impersonando il
server remoto. Se siamo sicuri che il server sia proprio lui, e che la nuova chiave sia anch'essa
autentica, allora la cosa più semplice e rapida da fare per poter entrare, sarà quella di
cancellare il file ~/.ssh/known_hosts.
Confidenzialità
Come risulta da questo file di cattura, prima ancora che venga svolto il dialogo relativo alla
chiave del server, il protocollo ha già provveduto ad instaurare una connessione sicura, mediante
uno scambio di Diffie-Hellman. Osserviamo che il ritardo di 8 secondi, che intercorre tra il
pacchetto 17 ed il pacchetto 18, corrisponde al tempo impiegato per rispondere alla domanda se
continuare la connessione o meno. Quindi, tutto quel che segue risulta protetto da una chiave di
sessione simmetrica.
Autenticazione del client
Avendo conseguito la confidenzialità della comunicazione, la trasmissione della password
dell'utente verso il sistema remoto viene effettuata in forma crittografata dalla strato di
sicurezza di SSH. Alternativamente, la richiesta della password può essere evitata, qualora la
chiave pubblica del client venga memorizzata presso il server, in modo che quest'ultimo possa
verificare autonomamente l'identità del client.
Grafica remota
Una opzione molto simpatica di ssh, è quella (opzione -Y) che consente di visualizzare sul
proprio computer, la finestra di esecuzione di una applicazione lanciata sul computer su cui ci si
266
Lo strato applicativo di Internet
Alessandro Falaschi
è collegati. Inoltre, si può specificare (opzione -l) di presentarsi sul computer remoto, con una
UserID differente da quella impersonata sul proprio computer. Queste due opzioni, combinate
assieme, producono il comando generico
ssh -Y -l utenteremoto computerremoto
che ci permette appunto, di eseguire programmi presso computerremoto, con l'identità di
utenteremoto, e di visualizzare la relativa finestra sul nostro schermo. La cosa ancora più
divertente, è che in questo caso funziona anche il copia e incolla, tra le finestre del computer
remoto, e quelle del computer locale, dato che entrambe sono visualizzate dallo stesso desktop.
TLS
Come illustrato a lezione, il TLS è uno strato frapposto tra l'applicazione ed il TCP, che permette
di autenticare l'altra parte mediante certificati X.509 e relativa fingerprint, e di negoziare
dinamicamente una chiave di sessione a crittografia simmetrica, in modo da garantire la
confidenzialità della comunicazione. Riprendendo l'esempio svolto in merito alla attivazione del
TLS nel contesto di una connessione IMAP, proviamo ad analizzare più in dettaglio il risultato del
capture ottenuto.
Osserviamo che dopo che nei pacchetti 9-10 il client ed il server IMAP si sono accordati per
utilizzare il TLS, il capture non è più in grado di decodificare correttamente quanto accade. E'
però possibile istruire Wireshark, affinché tenti di interpretare i pacchetti come la fase iniziale
di una comunicazione TLS. Per ottenere questo, occorre posizionarsi con il mouse su di un
pacchetto TLS, cliccare con il tasto destro, e scegliere l'opzione decode as; quindi, specificare
che le due porte utilizzate agli estremi della comunicazione (in questo caso, la 143 che è la porta
ben nota di IMAP, e 45238, che è una porta effimera) identificano pacchetti SSL (il predecessore
del TLS).
A questo punto, l'aspetto del capture cambia completamente, e si possono apprezzare i passaggi
previsti dall'handshake protocol. Inoltre, possiamo notare ad esempio come, nel pacchetto TCP
12, trovano posto 4 diverse PDU del TLS.
No.
No.
Time
Source
Destination
Protocol Info
11 0.015362
192.168.0.213
192.168.0.152
SSLv2
Client Hello
SSLv2 Record Layer: Client Hello
No. 12 0.031612
192.168.0.152
192.168.0.213
TLSv1
Server Hello, Certificate,
Server Key Exchange, Server Hello Done
TLSv1 Record Layer: Handshake Protocol: Server Hello
TLSv1 Record Layer: Handshake Protocol: Certificate
TLSv1 Record Layer: Handshake Protocol: Server Key Exchange
267
Openssl
Aspetti di Sicurezza delle Telecomunicazoni Internet
TLSv1 Record Layer: Handshake Protocol: Server Hello Done
No. 14 4.695011
192.168.0.213
192.168.0.152
TLSv1
Cipher Spec, Encrypted Handshake Message
TLSv1 Record Layer: Handshake Protocol: Client Key Exchange
TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message
No. 15 4.728238
192.168.0.152
192.168.0.213
TLSv1
Encrypted Handshake Message
TLSv1 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
TLSv1 Record Layer: Handshake Protocol: Encrypted Handshake Message
Client Key Exchange, Change
Change Cipher Spec,
Ulteriori dettagli possono essere apprezzati, espandendo ulteriormente i contenuti delle PDU
TLS.
Openssl
Si tratta di un toolkit OpenSource, cresciuto sulle fondamenta gettate da un altro, che oltre ad
implementare gli strati di sicurezza SSL e TLS, offre una potente libreria crittografica che
implementa praticamente tutti gli algoritmi di cui si può aver bisogno, e e che viene usata da un
gran numero di applicazioni crittografiche. Inoltre, è disponibile il comando openssl, che
permette l'esecuzione di quasi tutti i comandi e le operazioni crittografiche, a partire da una
finestra terminale. Un progetto del tutto analogo, ma sviluppato in accordo ad una licenza più
liberale, è GnuTLS.
Dato che il comando openssl, per la ricchezza delle sue possibilità, può richiedere un pò troppa
pazienza prima di individuare cosa occorre fare per svolgere delle operazioni ben precise, alcune
sue funzionalità posso essere accedute per mezzo di interfacce grafiche e web. In particolare, le
operazioni relative alla gestione di una Certification Authority, posso essere svolte per mezzo
dello script perlCA.pl, come descritto in questo HowTo, ripreso appresso.
Creazione di una Certification Autority
Lo script CA.pl non si trova nel path, e quindi per generare la nostra CA, eseguiamo
labsoftel@alef:~$ /usr/lib/ssl/misc/CA.pl -newca
CA certificate filename (or enter to create)
Making CA certificate ...
Generating a 1024 bit RSA private key
..........++++++
...++++++
writing new private key to './demoCA/private/cakey.pem'
Enter PEM pass phrase: <non la dico a nessuno>
Verifying - Enter PEM pass phrase: <non la dico a nessuno>
----You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
----Country Name (2 letter code) [AU]:IT
State or Province Name (full name) [Some-State]:Italy
Locality Name (eg, city) []:Cisterna di Latina
Organization Name (eg, company) [Internet Widgits Pty Ltd]:La Sapienza - sede di Latina
Organizational Unit Name (eg, section) []:Palazzo Caetani
Common Name (eg, YOUR name) []:labsoftel
Email Address []:[email protected]
Please enter the following 'extra' attributes
to be sent with your certificate request
268
Lo strato applicativo di Internet
Alessandro Falaschi
A challenge password []:
An optional company name []:
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem: <non la dico a nessuno>
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number:
b7:43:24:f0:9e:f4:b4:53
Validity
Not Before: Feb 1 12:56:54 2008 GMT
Not After : Jan 31 12:56:54 2011 GMT
Subject:
countryName
= IT
stateOrProvinceName
= Italy
organizationName
= La Sapienza - sede di Latina
organizationalUnitName
= Palazzo Caetani
commonName
= labsoftel
emailAddress
= [email protected]
X509v3 extensions:
X509v3 Subject Key Identifier:
D9:B5:FA:BE:7B:10:D7:D9:93:8F:B8:13:7D:E6:82:2E:F8:89:3C:A4
X509v3 Authority Key Identifier:
keyid:D9:B5:FA:BE:7B:10:D7:D9:93:8F:B8:13:7D:E6:82:2E:F8:89:3C:A4
DirName:/C=IT/ST=Italy/O=La Sapienza - sede di Latina/OU=Palazzo Caetani/
CN=labsoftel/[email protected]
serial:B7:43:24:F0:9E:F4:B4:53
X509v3 Basic Constraints:
CA:TRUE
Certificate is to be certified until Jan 31 12:56:54 2011 GMT (1095 days)
Write out database with 1 new entries
Data Base Updated
e possiamo verificare ora l'esistenza di una directory demoCA nella nostra home, con il frutto del
nostro lavoro. Possiamo già ora, provare ad utilizzare questo certificato auto-firmato per
Dovecot, al posto di quello di snakeoil. Per questo, copiamo il certificato e la chiave privata
nella directory che viene letta da Dovecot, con
sudo cp demoCA/cacert.pem /etc/ssl/certs/softelcert.pem
sudo cp demoCA/private/cakey.pem /etc/ssl/private/softelkey.pem
e modifichiamo /etc/dovecot/dovecot.conf in modo che utilizzi i nuovi files
ssl_cert_file = /etc/ssl/certs/softelcert.pem
ssl_key_file = /etc/ssl/private/softelkey.pem
ssl_key_password = <non la dico a nessuno>
Se ora ci ri-colleghiamo con Evolution, vediamo comparire il nuovo certificato. Se controlliamo il
file di log, troviamo
~$ tail -f /var/log/mail.log
Feb 1 00:51:56 alef dovecot: Dovecot v1.0.5 starting up
Feb 1 01:02:02 alef dovecot: imap-login: Login: user=<labsoftel>, method=PLAIN, rip=192.168.0.213,
lip=192.168.0.152, TLS
269
Openssl
Aspetti di Sicurezza delle Telecomunicazoni Internet
Richiesta di un nuovo certificato firmato
Ora, passiamo a compilare una Richiesta di Certificato di Utente, con il comando /usr/lib/
ssl/misc/CA.pl -newreq. Essendo un certificato individuale, ognuno potrà inserire i propri
dati, ottenendo come risultato, due files:
labsoftelf@alef:~$ /usr/lib/ssl/misc/CA.pl -newreq
Generating a 1024 bit RSA private key
...++++++
...
... etc etc etc...
...
Request is in newreq.pem, private key is in newkey.pem
che risiedono entrambi nella nostra home directory.
Firma del certificato
Possiamo scegliere di far emettere il certificato per il quale abbiamo generato la richiesta,
alla nostra stessa CA, oppure di farlo firmare da una stessa CA centralizzata, che firmerà anche
quelli dei nostri colleghi, e che provvederà a distribuire la propria chiave pubblica in modo
fidato. Ad ogni modo, il comando per firmare una richiesta di certificato da parte di una CA, è
~$ /usr/lib/ssl/misc/CA.pl -sign
# usa come input, il file newreq.pem nella dir corrente
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem: <la passphrase usata alla creazione della CA>
Check that the request matches the signature
Signature ok
Certificate Details:
...
... etc etc etc...
...
Certificate is to be certified until Jan 31 00:13:43 2009 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Signed certificate is in newcert.pem
Come affermato, il certificato si trova in ~/newcert.pem, dove troviamo anche la sua
corrispettiva chiave privata newkey.pem (se abbiamo usato la nostra stessa CA). Inoltre, il
nuovo certificato si trova anche nella directory ~/demoCA/newcerts, dove è conservato
assieme agli altri che verranno emessi, ed a quello emesso per la CA stessa; i certificati, sono
contrassegnati da un numero seriale crescente, e che corrisponde a quello presente all'interno
del certificato stesso. La chiave privata invece, si trova ancora in ~/newkey.pem, dove è stata
generata dal comando precedente.
Interfacce grafiche
Anziché eseguire dei comandi da terminale, le operazioni associate ad una CA possono esere
svolte utilizzando degli strumenti grafici, come ad esempio quelli di TinyCA, e gnoMint. Inoltre,
le operazioni di richiesta e di ritiro di un nuovo certificato, possono anche essere svolte
interagendo con una CA remota, come nel caso dell'utilizzo di una interfaccia web, ad esempio
quella offerta da PyCA e OpenCA.
270
Lo strato applicativo di Internet
Alessandro Falaschi
Gnu Privacy Guard
La GNU Privacy Guard, è una implementazione Open dello standard OpenPGP descritto nella RFC
4880, e che offre servizi di crittografia per la trasmissione sicura delle email, in grado di
ottemperare ai requisiti 5), 6) e 7) elencati nella lista descritta precedentemente. Di base, offre
uno strumento usabile da linea di comando, ma presso il sito di GPG, sono documentate le
estensioni disponibili, sia per la sua gestione grafica, che per la sua integrazione con altre
applicazioni, come i client di email.
Seahorse
Questa è probabilmente la migliore interfaccia grafica di GPG, che permette in modo molto
semplice di
•
•
•
•
•
•
•
generare una o più coppie di chiavi da usare con PGP
esportare la propria chiave pubblica in modo da poterla inviare a terze parti
attribuire un grado di fiducia alle chiavi pubbliche ricevute, e firmarle
condividere le proprie chiavi sia via rete locale, che per il tramite di un keyserver
firmare e cifrare, sia le email che i file, direttamente da Evolution e da Nautilus
gestire anche le chiavi utilizzate con SSH
eseguire il back di tutto il portachiavi
Dopo l'installazione di Seahorse con Synaptics, l'applicazione risulta accessibile tramite il menù
Applicazioni, sotto Accessori/Password e chiavi di cifratura. Nella mia sperimentazione, ho
notato una forma di instabilità in corrispondenza della fase di sincronizzazione delle chiavi con il
keyserver, dunque consiglio di selezionare subito Modifica/Preferenze, poi la linguetta server di
chiavi, e quindi de-selezionare le voci Recuperare e Sincronizzare.
Possiamo quindi iniziare con il generare un nuova coppia di chiavi PGP, da associare al nostro
nome e cognome, ed alla nostra email. L'email indicata, dovrà essere esattamente quella che
useremo poi nel seguito, idonea anche alla ricezione; scegliamo allora quella nella forma
[email protected], che funziona all'interno del laboratorio: altre email, associate ad altre
chiavi, potranno essere definite in un secondo momento. Ci viene quindi chiesto di inserire una
passphrase, con la quale verrà crittografata la nostra chiave privata, e che ci sarà chiesta di
nuovo, ogni volta che quest'ultima dovrà essere usata - a meno di non chiedere, che venga
memorizzata per la durata della sessione.
La chiave così generata, si ritrova ora come chiave privata, e mediante il tasto destro del mouse,
possiamo investigarne le proprietà, ed esportare la parte pubblica in un file, che potremo inviare
in allegato. Infatti, aprendo ora Evolution, ed scegliendo l'account che usa il nostro stesso
computer come SMTP ed IMAP, scriviamo delle email ai nostri colleghi, e prima di spedirle,
stabiliamo di firmarla, (dalla voce Sicurezza/firma PGP), ed alleghiamo il file in cui abbiamo
salvato la chiave pubblica. Alla ricezione di queste email, notiamo in basso la dicitura La firma
esiste, ma è necessaria la chiave pubblica, . Clicchiamo allora (con il tasto destro) sull'allegato
contenente la chiave pubblica, e scegliamo Apri in importa chiave, e... la chiave appare, come
per magia, in Seahorse, tra le chiavi collezionate. A questo punto, se siamo certi della identità
del mittente, non ci resta che attribuirgli fiducia (tasto desto, Proprietà, Fiducia), e quindi
firmare la chiave, indicando il nostro grado di certezza sulla identità, ed inserendo la passphrase
per poter apporre la firma. Potremo quindi verificare che ora il messaggio ricevuto appare come
correttamente firmato.
Dopo aver ricevuto le chiavi private dei nostri colleghi, potremo quindi inizare a crittografare i
messaggi indirizzati loro, utilizzando la chiave pubblica del destinatario. Proviamo quindi ad
inoltrare come allegato una email crittografata e diretta a noi, verso una terza persona, e
verifichiamo come quest'ultima, non sia assolutamente in grado di leggere il messaggio.
271
Gnu Privacy Guard
Aspetti di Sicurezza delle Telecomunicazoni Internet
Per verificare il risultato delle nostre operazioni, possiamo usare la combinazione di tasti
control-U per visionare il sorgente delle email firmata e/o crittografata, osservando come, nel
caso di una email firmata, sia presente l'intestazione
Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="=-/
uPEKZ6Vb6K2qdfequMJ"
e poi, nella parte che contiene la firma, questa sia identificata come
Content-Disposition: attachment; filename=pippo.asc
Content-Type: application/pgp-keys; name=pippo.asc
Content-Transfer-Encoding: base64
mentre invece, un messaggio crittografato è identificato da una serie di direttive del tipo
Date: Tue, 05 Feb 2008 23:30:13 +0100
Message-Id: <1202250613.7965.0.camel@alef-laptop>
Mime-Version: 1.0
Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";
boundary="=-P4aCM6gPf7ob7XiDhP3P"
--=-P4aCM6gPf7ob7XiDhP3P
Content-Type: application/pgp-encrypted
Content-Transfer-Encoding: 7bit
Version: 1
--=-P4aCM6gPf7ob7XiDhP3P
Content-Type: application/octet-stream; name=encrypted.asc
Content-Description: Questa =?ISO-8859-1?Q?=E8?= una parte del messaggio
cifrata digitalmente
Content-Transfer-Encoding: 7bit
-----BEGIN PGP MESSAGE----Version: GnuPG v1.4.6 (GNU/Linux)
hQIOA4XIA4bLol0LEAf+KfcJ1BnmzHZAjWPtU6hfKTyPVHeQXCG2ZeCfaZtV1vZN
7sr9YajLqbBUke73FO/OmaMUrj+trkZ2xN7BpY7hk11Ew5+O+gEvu4Z9H63KhIRD
OD7twpkd7qzwBqUOq6ErivEFDTvhhl7Nct9I.....
.
.
Infine, osserviamo come dal file manager Nautils, cliccando con il tasto destro sopra di un file,
ora viene anche offerta la possibilità di cifrare e/o firmare un file.
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Febbraio 2007
272
Lo strato applicativo di Internet
HTML e CSS
• Esempi già fatti
• Le estensioni dal web developer
• Aardvark
• Firebug
• Kompozer
• Modifica di una pagina esistente
• Salvataggio sul server web e visualizzazione
• Collegamento in FTP
• Visualizzazione
Esempi già fatti
Sperimentiamo con la sintassi dell'HTML e dei fogli di stile. La cosa più semplice che possiamo
fare, è quella di partire da una pagina già pronta, come quelle che troviamo presso uno dei siti di
template free. Prendiamo, ad esempio, metamorph_sunset, quasi completamente privo di
tabelle; scarichiamolo, scomprimiamolo, e salviamolo in una directory locale, come ad esempio
questa. Possiamo individuare una directory contenente le immagini utilizzate nella pagina, e
possiamo visualizzare direttamente il foglio di stile CSS che la pagina stessa utilizza.
Le estensioni dal web developer
Una delle cose più antipatiche, nella redazione di pagine web che usano i CSS, specialmente di
quelle prodotte da altri, è l'individuazione dei selettori, classi, ed identificatori CSS, le cui regole
determinano l'aspetto finale dei componenti di quell'elemento. Una delle cose più simpatiche, è
che questo problema può essere felicemente risolto, facendo uso di strumenti appositamete
sviluppati.
Innanzitutto, proviamo ad installare alcune estensioni per il browser Firefox, tali da rendere più
facile il mestiere del web developer: tra queste, possono tornare molto utili Aardvark, Firebug, e
WebDeveloper. Una volta installati, questi producono la comparse di due nuove voci nel menù
Strumenti, così come pure nel menù che si ottiene cliccando con il tasto destro all'interno della
pagina.
Aardvark
Il suo funzionamento è molto semplice, ancorché geniale: si attiva dal menù strumenti, oppure
con il tasto destro, e passando con il mouse sopra gli elementi che compaiono nella pagina, un
rettangolo rosso evidenzia l'ambito grafico su cui si estendono gli elementi HTML, ne viene
visualizzato il nome, e se presenti, anche i selettori CSS in quel momento attivi per
quell'elemento. Premendo il tasto h (help), compare un menù che ci ricorda le altre funzioni
ottenibili mediante la pressione di altri tasti. Possiamo a questo punto, modificare decisamente
l'aspetto della pagina, e poi.... richiedendo di ricaricarla, torna tutto come prima.
Kompozer
HTML e CSS
Firebug
Nel caso in cui vogliamo modificare l'aspetto di una pagina, ma non sappiamo dove mettere le
mani, possiamo posizionarci in quel punto con il mouse, cliccare con il tasto desto, e selezionare
inspect element: nella parte inferiore della finestra di Firefox, ci compare (a sinistra) il codice
HTML associato, e (a destra) le regole CSS che hanno effetto su quell'elemento, mettendo anche
in evidenza quelle regole che non sono applicate, perché rimpiazzate da altre più specifiche. A
destra, inoltre, possiamo apprezzare il layout risultante dalla impostazione dei valori per i
margini. Ma la cosa più divertente.. è che possiamo modificare la nostra pagine, sia per quanto
riguarda l'HTML, che il CSS!! Così, una volta individuati i valori che producono l'effetto
desiderato, possiamo riportarli nei files effettivamente presenti su disco, ed ottenere la nostra
pagina, così come desidriamo che appaia.
Kompozer
Mentre le due estensioni ora descritte, ci aiutano nella analisi (ed eventuale modifica) di pagine
preesistenti, un editor come Kompozer ci aiuta nella creazione di pagine ex-novo.
Modifica di una pagina esistente
A questo punto, partendo dal template che abbiamo scaricato, proviamo ad apportare alcune
modifiche, come ad esempio:
1.
2.
3.
4.
sostituire al link in alto friends, il link a questa pagina del corso
sostituire al testo Design by Metamorphosis Design, il vostro nome e cognome
allargare la pagina, e la colonna di destra
sostituire alla immagine della testata, una diversa immagine (della stessa altezza, ma con
la nuova larghezza!) ottenuta catturando una altra immagine di vostro gradimento,
eventualmente ritagliandola con the gimp
5. aumentare la dimensioni dei titoli (come Welcome To Our Website e METAMORPHOSIS
DESIGN)
Ma procediamo con ordine.
1. Aprendo il file index.html (che viene visualizzato di default, se ci limitiamo a
referenziare la directory in cui si trova) con kompozer, possiamo aprire una finestra di
dialogo con un doppio click sopra al link "friends", ed immettere, al posto del simbolo #,
l'indirizzo di questa pagina, http://infocom.uniroma1.it/alef/cisterna/
esercitazioni/html.html.
2. ancora utilizzando kompozer, possiamo scrivere direttamente il nostro nome e cognome
nel posto indicato, ma... facendolo, ci accorgiamo che le lettere compaiono tutte
minuscole. Come mai?
• visualizzando la pagina con Firefox, posizioniamoci sopra il nostro nome che abbiamo
appena scritto, e dopo aver cliccato con il tasto destro, scegliamo Inspect element,
attivando così Firebu, che nella parte inferiore della finestra, ci fa vedere il codice HTML
corrispondente, e le regole CSS che vi si applicano.
• notiamo allora che alla riga 101 di styles.css, è presente un selettore #logo a, che
sia applica a quegli elementi HTML con tag <a>, che compaiono all'interno di un altro
elemento, per il quale è stato definito l'attributo id=logo. E infatti, id=logo è proprio
l'identificatore del tag div, che influsce su tutta la zona in cui compare l'immagine del
tramonto. Nella colonna di destra, tra le regole del seletore #logo a, troviamo la regola
text-transform:lowercase; che è appunto quella che determina la scomparsa delle
maiuscole.
274
Lo strato applicativo di Internet
Alessandro Falaschi
• per allargare la pagina, usiamo ancora Firebug, e cliccando su Inspect, ci posizioniamo sulla
parte bianca in basso a sinistra, in modo da far comparire un rettangolo blu che racchiude tutta
la pagina, e clicchiamo. Dalle finestre inferiori, osserviamo di aver inviduato l'elemento <div
id=content>, che appunto ha influenza sull'intera pagina, ed il cui selettore CSS #content
attiva, tra le altre, la regola width:786px;
• modifichiamo allora questo valore in kompozer, portandolo ad esempio, a 900px; per fare
questo:
•
•
•
•
apriamo la finestra dell'editor CSS, ad es con il tasto F11,
individuiamo il selettore #content,
modifichiamo il valore width sotto la linguetta box;
chiudiamo con ok, ed ammiriamo il risultato.
• tocca ora alla larghezza della colonna di destra: usando ancora la funzione inspect di
firebug, troviamo che la colonna è controllata dal selettore #right, che contiene le
regole float:right; e width:500px;, mentre la prima regola indica di allineare la
colonna a destra, la seconda è quella da modificare; dato che il precedente incremento di
larghezza è stato di 900-786=114 pixel, possiamo portare width a 614px; per fare
questo:
•
•
•
•
utilizziamo ancora l'editor CSS di kompozer,
individuiamo il selettore #right,
modifichiamo il valore width sotto la linguetta box;
chiudiamo con ok, ed ammiriamo il risultato.
• rimane da allargare anche la prima riga della pagina, quella con i link in alto, ma come
fare questo, lo trovate da soli... basta ricordare che la nuova larghezza, dovrà ancora
incrementarsi di 114 pixel, ovvero arrivare a 892 pixel.
• la dimensione originale dell'immagine può essere rilevata
• usando ancora Firebug, e cliccando su Inspect, le due finestre inferiori ci mostrano che
questa è contenuta nel tag <div id=logo>, a cui corrisponde il selettore #logo, che
come prima regola asserisce background:#FFFFFF url(images/big_pic.jpg)
no-repeat scroll 0%; mentre rimandiamo altrove per una descrizione dell'insieme dei
valori associabili alla proprietà background, possiamo notare che passando con il mouse
sopra la linea del css, ci viene mostrata una versione ridotta dell'immagine, assieme alla
sua dimensione in pixel: 778x226. Pertando, occore ora produrre una immagine di 892x226
pixel.
• possiamo sceglierne una, ad esempio, da flickr: ad esempio scegliendo questa, nella
versione più grande, occorre salvarla su disco, e quindi aprirla con Gimp;
• ridimensiono l'immagine alla larghezza desiderata (tasto destro, immagine, scala);
• usando lo strumento di selezione rettangolare, ritaglio l'altezza alla dimensione
desiderata;
• eseguo modifica/copia, e quindi modifica/incolla come/nuova immagine;
• salvo il risultato nella directory delle immagini, con lo stesso nome della
precedente;
• nell'edito css di composer, modifico la proprietà width del selettore #logo, al
nuovo valore di 892;
• mi godo il risultato.. uhmm c'è un rettangolo bianco a destra.. si aggiusta, portando
a 4 il valore della proprietà padding-left: del selettore #logo.... però ancora non
va, così si è spiaccicato a sinistra il logo... si corregge aggiungnedo la proprietà
padding-left = 40px; nel selettore #logo a
• per ingrandire Welcome To Our Website, ci accorgiamo che su di esso fa effetto il seletore
#right h2, e quindi aggiungiamo a questo la regola font-size:xx-large;
275
Salvataggio sul server web e visualizzazione
HTML e CSS
• per ingrandire METAMORPHOSIS DESIGN, possiamo intervenire sul selettore #right h4,
impostandolo come font-size:large;
L'effetto finale, è quello visibile qui.
Salvataggio sul server web e visualizzazione
Ora che abbiamo presisposto la nostra bella pagina, preoccupiamoci di salvarla presso il nostro
server web. Per questo scopo, useremo il computer alef.softel, già presisposto sia come server
web che come server ftp. Infatti, sono stati creati diversi utenti, con nome pari ai nomi dati ai
computer del laboratorio. A tutti questi utenti, è stata assegnata la stessa password. Il server ftp
è configurato in modo tale che quando gli utenti si connettono, possono accedere alla sola
porzione di filesystem è limitata agli oggetti radicati a partire dalla propria home directory.
Collegamento in FTP
A questo scopo, abbiamo due possibilità:
• usiamo il programma gftp,
• se non lo abbiamo già installato, possiamo scaricarlo con synaptic;
• quindi, lo lanciamo da Applicazioni/Internet;
• poi, inseriamo nel campo host il nome alef.softel, nel campo utente il nostro nome,
e per password, sempre la stessa;
• se tutto è andato bene, dovremmo trovarci nella directory remota /home/
nomeutente del computer remoto;
• per copiare i files da un computer all'altro, si fa uso delle freccette poste tra le due
colonne della finestra.
• usiamo il client ftp integrato in Nautilus:
• lanciamo Risorse/Connetti al server;
• inseriamo come Tipo di servizio: FTP con login, nome del server, e nome utente (il
vostro), connetti;
• il nome del computer ci appare sotto il menù Risorse; cliccandolo ci viene chiesta la
password, e quindi possiamo entrare
• se apriamo un altro Nautilus, possiamo copiare i files dal nostro a quello
Visualizzazione
Affinché le pagine che carichiamo sul server, siano poi visibili, dobbiamo metterle in una
directory con un nome particolare, public_html, che creiamo (visto che da sé, non esiste). I
files che carichiamo lì, sono visibili a partire dall'indirizzo http://alef.softel/~nomeutente
(suggerimento: il carattere ~ si ottiene, sulla tastiera Linux, con la combinazione di tasti AltGr
e ì).
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento: Febbraio 2008
276
Lo strato applicativo di Internet
Alessandro Falaschi
277
Lo strato applicativo di Internet
Server Apache
Utilizzeremo il server HTTP Apache, il più diffuso in assoluto.
• Apache, questo sconosciuto
• Installazione
• La mia prima pagina
• Studiamo il log
• I permessi dei files da mostrare
• Personalizzazione del Log
• Il sito principale
• Virtual Host
• La documentazione
• I file di configurazione
• Informazioni sul server
• Mappare le URI sui files
• Autenticazione
• Digest Authentication
• Fornitori
• Oscuramento
• Gestione dei Mime Type
• Il mio primo CGI
• Metodo POST
• Interpretazione della richiesta
•
•
•
•
Un ristorante virtuale
Tutto il codice prodotto
HTTPS e VirtualHost
Riferimenti
Lo strato applicativo di Internet
Alessandro Falaschi
Apache, questo sconosciuto
Si narra che il nome
Apache derivi da una
contrazione di a patchy
server, dato che
inizialmente, non era
costituito da nient'altro
che una seie di patch
(pezze) al preesistente
server di NCSA.
Il suo funzionamento
prevede il pre-fork di
alcuni processi figli, in
modo che le nuove
richieste HTTP non
vengano rallentate
nell'attesa della
creazione di un nuovo
processo figlio. Oppure,
si può ricorrere ad un
modulo orientato al
multi-threading
come worker.
In ogni modo, l'architettura di Apache prevede di delegare molti tipi di elaborazioni possibili, ad
un insieme di diversi moduli che implementano ognuno una diversa funzionalità. In questo modo,
si rende indipendente lo sviluppo dei moduli, e delle funzionalità associate, da quello del nucleo
del server web.
Ogni modulo può necessitare della definizione di sue particolari variabili e direttive di
configurazione, che sono dichiarate in files separati, e tenuti assieme mediante una direttiva di
include. Infatti, nel file di configurazione principale (/etc/apache2/apache2.conf),
sono presenti le direttive
Include /etc/apache2/mods-enabled/*.load
Include /etc/apache2/mods-enabled/*.conf
che attivano il caricamento (.load) e la configurazione (.conf) dei moduli con nome uguale a
quello di questi files. Se investighiamo sul contenuto della directory /etc/apache2/
mods-enabled però, vi troviamo una serie di collegamenti simbolici a files dallo stesso nome,
ma che si trovano in /etc/apache2/mods-available. Per abilitare un modulo quindi, occorre
creare il link simbolico dalla seconda directory alla prima, per i due files di configurazione dello
stesso. Per semplificare questa operazione, sono disponibili i comandi a2enmod e a2dismod,
rispettivamente per abilitare e disabilitare un modulo, come ad esempio
sudo a2dismod info
sudo a2enmod info
# disabilita il modulo info
# ri-abilita il modulo info
279
Installazione
Server Apache
Installazione
Con Synaptic, scarichiamo ed installiamo apache2, apache2-doc e apache2-utils,
Impartendo il comando ps axf | grep apache, verifichiamo se è già in esecuzione, ed in
caso contrario, lanciamo il server web con il comando sudo /etc/init.d/apache2 start.
Apriamo il Browser web, e visitiamo la URI http://127.0.0.1. Si aprirà una pagina, in cui è
mostrata una sola directory, apache2-default/, cliccando la quale, si giunge alla pagina che ci
conferma il successo dell'operazione.
La mia prima pagina
Come già fatto in una precedente esercitazione, proviamo a pubblicare una pagina sotto la
nostra directory di utente. Prima di tutto, dobbiamo abilitare il modulo userdir, che consente
l'uso delle directory di utente. Per questo, eseguiamo i comandi
sudo a2enmod userdir
sudo /etc/init.d/apache2 force-reload
Creiamo quindi la directory public_html in /home/labsoftel, scriviamo al suo interno un
file di test (es prova.txt) contenente una frase simpatica, e proviamo a visualizzare il file,
referenziando la URI http://127.0.0.1/~labsoftel/prova.txt. Come dite? Compare un
messaggio Forbidden ??
Studiamo il log
Per verificare l'esito delle operazioni in corso, possiamo andare a leggere le informazioni salvate
nei file di log, ossia /var/log/apache2/access.log che documenta gli accessi, e /var/
log/apache2/error.log, che documenta le circostanze di errore. Quest'ultimo, contiene
l'informazione che cercavamo, ossia il messaggio
[Wed May 30 08:32:02 2007] [error] [client 127.0.0.1] (13): file permissions deny server
access: /home/labsoftel/public_html/prova.txt, referer: http://127.0.0.1/~labsoftel/
I permessi dei files da mostrare
Infatti, il file che abbiamo creato va reso leggibile dall'utente con i cui privilegi è in esecuzione il
server web. Per modificare i permessi del file, si può agire mediante una applicazione di file
manager grafico, oppure impartire il comando chmod 644 /home/labsoftel/public_html/
prova.txt. Fatto ciò, possiamo riprovare a visualizzare il nostro file !
Tenere d'occhio il log, può essere un buon modo per accellerare lo sviluppo di un sito: a tal fine,
può essere molto utile impartire il comando tail -f /var/log/apache2/error.log, che
ha l'effetto di mantenere la schermata agganciata allo stato corrente del file, scollando quando
vi vengono aggiunte nuove linee.
280
Lo strato applicativo di Internet
Alessandro Falaschi
Personalizzazione del Log
Le informazioni che compaiono nei file di log, come access.log, possono essere personalizzate
mediante le direttive LogFormat and CustomLog anche allo scopo di particolarizzare il tipo di
report generato dagli appositi programmi di analisi giornaliera.
Il sito principale
Ma, oltre alle directory degli utenti, come si fa ad usare direttamente il FQDN del sito, con una
URL del tipo http://localhost/pagina.html ? Le definizioni legate a questa possibilità, si trovano
nel file /etc/apache2/sites-enabled/000-default, in cui si dichiara, tra le altre cose,
che la DocumentRoot del web server, corrisponde alla directory /var/www/, e quindi è lì che
dobbiamo salvare i files che vogliamo compaiano direttamente dopo il nome del computer.
Virtual Host
Abbiamo parlato di sito principale, perché presso lo stesso computer, possono essere ospitati siti
diversi, corrispondenti a nomi di dominio diversi, ma relativi (mediante dei RR del DNS di tipo
CNAME) allo stesso indirizzo IP. Questa tecnica prende il nome di Virtual Host, e si basa sul fatto
che il nome a dominio che compare nella URL di richiesta, è comunque indicato nell'header Host
della stessa. In virtù di questo fatto, Apache usa uno dei file di configurazione presenti in /etc/
apache2/sites-enabled/, per mappare la richiesta su diverse parti del filesytem.
La documentazione
Il package di documentazione che abbiamo installato, installa sullo stesso server web le pagine
accessibii a partire da http://127.0.0.1/manual/, che sono copie conformi di quanto compare
presso il sito della fondazione Apache. Per seguire ciò che ha consentito la comparsa della nostra
pagina on-line, possiamo leggere l'How-to corrispondente a Per-user Web Directories
(public_html), che ci guida nel primo impatto con la configurazione di Apache.
I file di configurazione
Il primo impatto con le direttive, i moduli, i contesti, che definiscono il comportamento di
apache, può scoraggiare chi è abituato alle interfacce di configurazione grafica: d'altra parte,
affrontando un problema alla volta, dopo qualche tempo si apprezza l'elevato grado di
configurabilità ottenibile. Dei moduli abbiamo già parlato; per quanto riguarda le direttive (ad
es userdir), la documentazione relativa utilizza una terminologia il cui significato è documentato
a parte. In particolare, le direttive sono attivabile all'interno di specifici contesti, come ad
esempio <Directory> o <Location>, che individuano il loro campo di applicablità. Per esempio, in
userdir.conf troviamo
UserDir public_html
UserDir disabled root
# la dir di utente da rendere accessibile
# l'utente root non è accessibile
<Directory /home/*/public_html>
AllowOverride FileInfo AuthConfig Limit
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
</Directory>
che indica come, a seguito della attivazione del modulo userdir, le direttive AllowOverride
etc etc, si applichino a tutte le directory di utente /home/*/public_html. Questo tipo di
281
Autenticazione
Server Apache
meccanismo, permette di limitare l'effetto delle direttive di configurazione, solo a particolari
sezioni del sito.
Ma oltre ai files presenti in /etc/apache2/mods-enabled, la configurazione complessiva può
essere dichiarata anche mediante dei file .htaccess, dislocati nelle stesse directory in cui si
trovano i documenti da servire, in modo da permettere agli utenti stessi di impostare le loro
preferenze.
Informazioni sul server
Apache offre due URI mediante le quali ci mostra i dettagli sullo stato delle connessioni che sta
servendo, e l'effetto delle diverse direttive di configurazione:
• lo stato delle connessioni è visualizzato visitando http://127.0.0.1/server-status, ed il suo
funzionamento si abilita, dopo essersi accertati della presenza di /etc/apache2/
mods-enabled/status.conf (in caso contrario, eseguire a2enmod), modificando in
questo file, la direttiva Allow in (ad es.) Allow from 127.0.0.1;
• l'effetto delle direttive di configurazione è visualizzato visitando http://127.0.0.1/
server-info/, ed il suo funzionamento si abilitata verificando che il modulo info sia
attivo, e modificando come indicato sopra il file info.conf, oppure usando localhost
nella URI di richiesta. Notiamo come nella pagina visualizzata, si possano verificare tutte
le impostazioni di configurazione impartite al server, e si possa anche visualizzare
della auto-documentazione pubblicata da parte dei moduli attivi.
Mappare le URI sui files
Sicuramente un indirizzo in cui compare una tilde (~) non è dei più belli da dare in giro, e per
costruire un indirizzo più leggibile, possiamo ricorrere ad una tra due direttive che ci vengono in
soccorso: Alias e Redirect, in cui la prima serve per mettere in corrispondenza la parte path
della URI, con un percorso nel filesystem locale, mentre la seconda serve per inviare risposte di
tipo 30x Redirect, anche verso siti esterni, in corrispondenza di URI particolari. Mentre
l'argomento nel suo complesso, è ben trattato nella documentazione, indichiamo qui la direttiva
da inserire nel nostro apache2.conf (o, meglio, alias.conf), per far corrispondere
all'indirizzo http://127.0.0.1/~labsoftel, un più leggibile http://127.0.0.1/
labsoftel:
Alias /labsoftel "/home/labsoftel/public_html"
Autenticazione
Anche se la nostra prima pagina non è un granché, possiamo comunque proteggerla da sguardi
indiscreti. Nella documentazione di Apache troviamo le indicazioni su come procedere, e
seguendo quei consigli, possiamo fare così:
• creiamo un file di password, contenente la password per l'utente labsoftel, presso la
nostra home directory
htpasswd -c /home/labsoftel/passwords labsoftel
e quando ci viene chiesta, inseriamo la password che vogliamo ci venga richiesta. Proviamo
a guardare ora, cosa contiene quel file ?
282
Lo strato applicativo di Internet
Alessandro Falaschi
• creiamo nella directory dove si trova la nostra pagina, il file .htaccess che serve ad
apache per capire che la directory è protetta, dove trovare le password, e quali utenti
sono ammessi
AuthType Basic
AuthName "Laboratorio di Cisterna"
AuthUserFile /home/labsoftel/passwords
Require user labsoftel
in cui AuthName definisce il realm che verrà indicato nella fiinestra di richiesta del
browser, la direttiva AuthUserFile definisce il file di password che consente
l'autenticazione dell'utente, e Require definisce le restrizioni di accesso (autorizzazione)
successive alla fase di autenticazione.
• apriamo wireshark, e mentre visitiamo di nuovo la nostra pagina, e rispondiamo alla
richiesta di password, osserviamo i pacchetti in transito
Notiamo che non è stato necessario ri-lanciare il server apache perché le modifiche avessero
effetto: questo vuol dire che i file .htaccess vengono ri-letti ad ogni nuova richiesta, e questo
può essere un elemento di inefficienza all'aumentare del carico, per cui se si ha la possibilità di
intervenire sui files di configurazione di sistema, è preferible modificare quelli.
Digest Authentication
Nel caso si scelga questo tipo più sicuro di autenticazione, la versione delle password residente
presso il server dovà essere generata mediante l'utility htdigest anziché htpasswd, dato il
diverso meccanismo utilizzato, ed usata anche la direttiva AuthDigestDomain.
Fornitori
Nell'esempio svolto, le credenziali degli utenti presso il server sono memorizzate su di un
semplice file piatto. All'aumentare delle dimensioni di questo, e della sua frequenza di utilizzo,
questo metodo può divenire inefficiente. Esiste allora la possibilità di accedere alle credenziali
da verificare mediante un file indicizzato (modulo authn_dbm), un DBMS (modulo authn_dbd), od
un sever LDAP (modulo authnz_ldap).
Oscuramento
Può succedere, che si voglia interdire l'accesso ad una pagina, od una directory, nei riguardi
delle richieste che giungono da un certo computer, o da un gruppo di computer. Le regole
generali, prevedono l'uso delle direttive Allow, Deny e Order, ma per una sperimentazione
semplice semplice, ci si può limitare ad inserire nel file /home/labsoftel/public_html/
.htaccess la direttiva
Deny from All
e quindi, provando ad accedere di nuovo alla nostra pagina, possiamo verificare come ora
l'accesso sia divenuto proibito. Una volta fatta la prova, commentiamo la direttiva, anteponendo
un #.
283
Gestione dei Mime Type
Server Apache
Gestione dei Mime Type
Nel file /etc/apache2/mods-enabled/mime.conf, compare la direttiva
TypesConfig /etc/mime.types
che individua in che file sono dichiarate le corrispondenze tra le estensioni dei nomi di file ed i
Mime-Type. Questa corrispondenza sarà quindi usata per determinare il Mime-Type da usare
come argomento dell'Header Content-Type nella risposta inviata ad un browser che avesse
richiesto un file con una delle estensioni presenti. Nel caso in cui si desideri erogare un
contenuto con una estensione che non rientra tra quelle elencate in /etc/mime.types, si
possono definire delle ulteriori associazioni, inserendo in mime.conf una o più direttive del tipo
AddType MIME-type extension [extension]
Il mio primo CGI
Seguendo (più o meno) i suggerimenti riportati nell'How-To fornito con Apache, per sperimentare
l'esecuzione di codice da parte di un server web, possiamo modificare il file di configurazione
relativo alle directory degli utenti (sudo gedit /etc/apache2/mods-enabled/
userdir.conf) in modo che appaia come segue:
<IfModule mod_userdir.c>
UserDir public_html
UserDir disabled root
<Directory /home/*/public_html>
AllowOverride FileInfo AuthConfig Limit
Options ExecCGI MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
AddHandler cgi-script .cgi
</Directory>
</IfModule>
In particolare, la direttiva Options ExecCGI è quella che abilita l'esecuzione di codice nelle
directory degli utenti, mentre AddHandler istruisce Apache a trattare i files con estensione
.cgi come programmi eseguibili, eseguirli, e tentare di inviare lo standard output risultante, al
browser che aveva referenziato tale programma. Quindi, non tutti i programmi presenti in
/home/labsoftel/public_html saranno eseguiti, ma solo quelli con estensione .cgi.
Creiamo ora il nostro CGI (gedit primocgi.cgi), in modo che appaia come segue:
#!/usr/bin/perl
print "Content-type: text/plain\n\n";
print "Salute a tutti.\n\n";
print "State osservano lo standard output prodotto da $0.\n";
print "I files presenti in questa directory sono:\n\n";
system "ls -l";
print "\n o o o o o o o o o o o o o o o o o o o o \n\n";
print "Qui sotto, mostriamo i valori associati alle variabili di ambiente che apache rende
accessibili a questo script:\n\n";
foreach $key (keys %ENV) {
print "$key --> $ENV{$key}\n";
}
284
Lo strato applicativo di Internet
Alessandro Falaschi
e quindi, ricordiamoci di rendere eseguibile il programma, anche da parte di Apache: chmod
755 primocgi.cgi. Infine, verifichiamo il corretto funzionamento, referenziando la URI
http://127.0.0.1/labsoftel/primocgi.cgi. Eventualmente, qui troviamo un esempio del risutato
che si dovrebbe ottenere. Notiamo che:
• lo script usa il linguaggio perl, e prima di eseguirlo come CGI, è consigliabile verificarne il
funzionamento, tentandone l'esecuzione da linea di comandi, con ./primocgi.cgi;
• la specifica di un header Content-Type: text/plain fa si che il browser visualizzi il
risultato con un font monospaced;
• la presenza di una linea vuota dopo il Content-Type, separa la fine degli header
dall'inizio del body, e se è assente, il cgi non funziona (provare per credere);
• il comando system permette a perl di eseguire comandi come se fossero immessi dalla
shell in cui è eseguito;
• il ciclo foreach accede ad un array assocativo (%ENV) in cui si trovano i valori delle
variabili di ambiente a cui lo script ha accesso, e l'accesso avviene usando i nomi delle
variabili stesse, come chiavi; questi nomi sono a loro volta ottenuti scandendo la
loro lista, creata con l'espressione keys %ENV.
Metodo POST
Come illustrato nella parte di teoria, utilizzando il metodo POST, i campi della form sono passati
nel body. Questo secondo esempio, che chiameremo secondocgi.cgi (ispirato da questo
corso), ha appunto lo scopo di mostrare l'effetto di una tale chiamata.
#!/usr/bin/perl
use strict;
print
print
print
print
"Content-type: text/plain\n\n";
"Salute a tutti.\n\n";
"State osservando lo standard output prodotto da $0.\n";
"\n o o o o o o o o o o o o o o o o o o o o \n\n";
print "Qui sotto, lo standard input ricevuto dal server web\n\n";
my $buffer;
read (STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
print $buffer;
print "\n\ned ora, alcune delle variabili di ambiente ricevute:\n\n";
my $key;
foreach $key ('REQUEST_METHOD', 'QUERY_STRING', 'REQUEST_URI', 'CONTENT_LENGTH') {
print "$key --> $ENV{$key}\n";
}
Una form che invoca questo script è visibile nella parte di teoria, mentre qui possiamo osservare
il risultato della invocazione.
Interpretazione della richiesta
A prima vista, quella stringa del tipo nome1=valore1&nome2=valore2& etc etc ... non
sembra molto masticabile da un programma, ma non è poi così difficile, cavarne qualcosa di
buono, come viene fatto con questo che chiameremo terzocgi.cgi, che funziona sia con il
metodo GET che con il POST, e... si limita a farci vedere ciò che sa fare.
#!/usr/bin/perl
use strict;
print "Content-type: text/plain\n\n";
285
Un ristorante virtuale
Server Apache
print "Salute a tutti.\n\n";
print "State osservando lo standard output prodotto da $0.\n";
print "\n o o o o o o o o o o o o o o o o o o o o \n\n";
print "Qui sotto, lo standard input ricevuto dal server web\n\n";
my $buffer;
read (STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
print $buffer;
print "\n\nPoi, alcune delle variabili di ambiente ricevute:\n\n";
my $key;
foreach $key ('REQUEST_METHOD', 'QUERY_STRING', 'CONTENT_LENGTH', 'REQUEST_URI') {
print "$key --> $ENV{$key}\n";
}
print "\n\nInfine, la decodifica dei campi ricevuti\n\n";
my @data;
if ( $ENV{ 'REQUEST_METHOD' } eq "GET" ) {
# suddivide le coppie name/value tra loro
@data = split /&/, $ENV{ 'QUERY_STRING' };
} elsif ( $ENV{ 'REQUEST_METHOD' } eq "POST" ) {
@data = split /&/, $buffer;
} else {
print "Sono permessi solo i metodi GET e POST!";
exit;
}
my (%data, $value, $item);
foreach $item ( @data ) {
# suddivide le coppie e traduce i + in spazi
($key, $value) = split /=/, $item;
$key
=~ tr/\+/ /;
# Converte %XX da numeri hex ad alfanumerico
$key
=~ s/%([\da-f][\da-f])/pack("c",hex($1))/gei;
$value =~ tr/\+/ /;
$value =~ s/%([\da-f][\da-f])/pack("c",hex($1))/gei;
$data{$key} = $value;
}
foreach $key (keys %data) {
print "$key ==>> $data{$key}\n";
}
La form che invoca terzocgi.cgi è mostrata nella parte di teoria, e qui è mostrato il risultato
della invocazione.
Un ristorante virtuale
A partire dagli esempi forniti fin qui, ed usando il modulo Perl Email::Send, scriviamo un CGI in
grado di recapitare per email l'ordine ricevuto. Il sapore non sarà un gran che, però farà un gran
bell'effetto :-)
Per prima cosa, scarichiamo ed installiamo il modulo con le sue dipendenze (Email::Simple,
Module::Pluggable, Email::Address, Return::Value): per ognuno di questi, eseguire le
seguente sequenza di operazioni:
• scaricare e compattare l'archivio .tar.gz
• porsi nella directory dove si è scompattato l'archivio
• eseguire il comando perl Makefile.PL che crea il Makefile per la verifica e
l'installazione del modulo
• eseguire il comando make che, a partire dal Makefile, verifica il contenuto del modulo e
le sue dipendenze, e predispone i files alla installazione. Se in questa fase si notano
errori, ri-eseguirla dopo aver installato le altre dipendenze
• eseguire il comando sudo make install, che installa i files del modulo nelle directory
di sistema
286
Lo strato applicativo di Internet
Alessandro Falaschi
Alternativamente: eseguire cpan Email::Send.
Quindi, inseriamo in una pagina HTML, il codice della form che invoca il nuovo cgi, che
chiamiamo vristo.cgi
Il mio primo ristorante virtuale
email:
pizza
• lasagna
ordine:
tiramisu
pinta
ok
reset
Infine, editiamo il nostro nuovo cgi, vristo.cgi, a partire dal codice già incontrato in terzocgi,
di cui abbiamo corretto un errore nella espressione regolare, ed il cui codice è riportato sotto.
Dopo aver salvato vristo.cgi nella directory public_html ed aver correttamente configurato
i permessi, possiamo provare ad immettere un ordine nella form soprastante, e verificare se
l'email ci arriva! Ad ogni modo, anche stavolta riportiamo l'esito della esecuzione.
#!/usr/bin/perl
use strict;
use Email::Send;
# impostare qui, quello che sarà il mittente dell'email
my $from = '[email protected]';
print
print
print
print
"Content-type: text/plain\n\n";
"Salute a tutti.\n\n";
"State osservando lo standard output prodotto da $0.\n";
"\n o o o o o o o o o o o o o o o o o o o o \n\n";
# Leggiamo lo standard input ricevuto dal server web\n\n";
my $buffer;
read (STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
my @data;
if ( $ENV{ 'REQUEST_METHOD' } eq "GET" ) {
# suddivide le coppie name/value tra loro
@data = split /&/, $ENV{ 'QUERY_STRING' };
} elsif ( $ENV{ 'REQUEST_METHOD' } eq "POST" ) {
@data = split /&/, $buffer;
} else {
print "Sono permessi solo i metodi GET e POST!\n";
exit;
}
my (%data, $value, $item, $key, $message, $sender, $result);
foreach $item ( @data ) {
# suddivide le coppie e traduce i + in spazi
($key, $value) = split /=/, $item;
$key
=~ tr/\+/ /;
# Converte %XX da numeri hex ad alfanumerico
$key
=~ s/%([\da-f][\da-f])/pack("c",hex($1))/gei;
$value =~ tr/\+/ /;
$value =~ s/%([\da-f][\da-f])/pack("c",hex($1))/gei;
# Nell'esempio originale non c'erano le parentesi tonde dopo il %
$data{$key} = $value;
}
$message = "To: $data{'email'}\nFrom: $from\nSubject: Buon Appetito!\n\nIl CGI $0 ha ricevuto
un ordine per te, eccoti servito: $data{'ordine'}!\n";
287
Tutto il codice prodotto
Server Apache
$sender = Email::Send->new({ mailer => 'SMTP',
mailer_args => [ Host => '127.0.0.1']});
print "Ecco il messaggio che intendiamo spedire:\n\n$message\n";
$result = $sender->send($message) ;
print ("L'invio ha avuto esito: $result\n");
Tutto il codice prodotto
Nell'archivio cgi.tar.gz si può trovare il codice discusso in questa pagina. Per far funzionare gli
esempi che invocano i cgi, scomprimere l'archivio nella directory public_html del proprio
computer, a meno che non ne sia stata configurata una diversa, ed assicurarsi di aver
impostato correttamente i permessi di accesso al file.
HTTPS e VirtualHost
Non resta ora che da configurare il nostro server web in modo da offrire la possibilità di
collegarsi in modo crittograficamente sicuro, come previsto da HTTP su TLS (HTTPS), ovvero
• consentire l'autenticazione del server;
• creare una chiave crittografica di sessione;
• cifrare i successivi messaggi in transito sulla connessione.
Lo scenario generale della infrastruttura di sicurezza web è particolarmente ben riassunto nella
documentazione di Apache, che offre questi servizi mediante il modulo ssl. Inoltre, usare lo
stesso server Apache per offrire contemporaneamente sia l'HTTP su porta 80, che l'HTTPS su
porta 443, richiede la configurazione di due diversi Virtual Host, di cui il primo è quello (default)
utilizzato finora, ed il secondo è quello che ci accingiamo a definire nel file /etc/apache2/
sites-available/secure. Pertanto, impartiamo ora i comandi
sudo
sudo
sudo
sudo
a2enmod ssl
cp /etc/apache2/sites-available/default /etc/apache2/sites-available/secure
a2ensite secure
gedit /etc/apache2/sites-enabled/secure
che abilitano sia il modulo ssl che il sito secure, il cui file di configurazione è ottenuto a partire
da una copia di quello di default. L'ultimo comando della serie, ci consente di editare la
configurazione del file che definisce il funzionamento del server HTTPS. Innanzitutto,
modifichiamo le prime due linee, in modo da dichiarare esplicitamente l'uso della porta 443, e
quindi abilitiamo l'uso di SSL su questa porta, mediante la direttiva SSLEngine, in modo che ora
l'inizio del file secure appaia come segue:
NameVirtualHost *:443
<VirtualHost *:443>
SSLEngine on
Se ora proviamo a rilanciare Apache (sudo /etc/init.d/apache2 restart), questo si
rifiuta di andare in esecuzione, notificando nel file di log il messaggio: Server should be
SSL-aware but has no certificate configured [Hint: SSLCertificateFile].
Infatti, occorre specificare il certificato e la chiave da usare, inserendo di seguito alla direttiva
SSLEngine, le direttive
288
Lo strato applicativo di Internet
Alessandro Falaschi
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
Stavolta Apache accetta di partire, ed invocando una delle URI servite (es
https://localhost), la pagina arriva, e il campo di inserimento indirizzo si colora di giallo, e
si arricchisce del disegno di un lucchetto, a segnalare la sicurezza della navigazione. Ma... prima
di arrivare a questo bel risultato, nel file di log abbiamo ossevato il messaggio
RSA server certificate CommonName (CN) `terranova' does NOT match server name!?
ed infatti, il certificato che abbiamo utilizzato non è rilasciato al nome a dominio che viene
servito da Apache. Questo fatto comporta che anche il browser, prima di visualizzare la pagina
richiesta, notifica alcune finestre di avvertimento, mediante le quali dichiara
• l'impossibilità di verificare il sito come affidabile, e si specifica che
• il nome a dominio del sito, è differente dal nome dell'intestatario del certificato,
ipotizzando che potrebbe esserci una terza parte che sta tentando di impersonare il server
stesso.
Mentre il primo fatto è evidentemente legato alla assenza (presso il browser) del certificato della
CA che ha firmato il certificato del server, il secondo è risolvibile avendo l'accortezza di
richiedere un certificato per il quale il Common Name corrisponda esattamente al nome a
domino per cui si intenderà usarlo. Per questo, possiamo generare una richiesta di certificato e
firmarla, usando lo strumento TinyCA, ed utilizzando per la firma la chiave privata
di labsoftelCA, che importiamo in TinyCA. Una volta esportati certificato e chiave privata
intestati al CN uguale al nostro dominio, sostituiamo (nel path dichiarato mediante la direttiva
SSLCertificateFile presente nel file secure) questi nuovi valori, a quelli relativi a
ssl-cert-snakeoil, e ri-lanciamo Apache. Sullo schermo, si sviluppa il dialogo
alef@alef-laptop:~$ sudo /etc/init.d/apache2 restart
* Starting web server apache2
Apache/2.2.4 mod_ssl/2.2.4 (Pass Phrase Dialog)
Some of your private key files are encrypted for security reasons.
In order to read them you have to provide the pass phrases.
Server alef-laptop.softel:443 (RSA)
Enter pass phrase:
OK: Pass Phrase Dialog successful.
[ OK ]
alef@alef-laptop:~$
che rappresenta la richiesta, da parte di Apache, di conoscere la passphrase con cui è
crittografata la chiave privata associata al nuovo cerificato usato, che nell'esempio precedente
era invece lasciata in chiaro.
Finalmente ora, immettendo (nel caso di chi scrive) la URI https://alef-laptop.softel, non si
ottiene più l'avvertimento relativo al dominio sbagliato! Ora, non resta che importare nel
browser, il certificato della CA che ha firmato il certificato con cui abbiamo configurato Apache.
Cliccando sul link del certificato appena fornito, il certificato stesso viene visualizzato dal
Browser, ma non importato dallo stesso. Pertanto, occorre prima salvarlo su file, e quindi
importarlo in modo esplicito, ossia (in firefox)
• cliccare su modifica/preferenze
• cliccare su avanzate/cifratura/mostra certificati
• cliccare su autorità/importa, e quindi selezionare il file di certificato non appena
scaricato
289
Riferimenti
Server Apache
Alernativamente, si può configurare Apache affinchè cliccando sul link del certificato, questo
venga automaticamente importato dal browser, senza necessità dei passi ora illustrati. A questo
scopo, occorre modificare il file /etc/apache2/apache2.conf, inserendo la direttiva
AddType application/x-x509-ca-cert pem
in modo che il file con estensione .pem sia inviato con il MIME-Type corretto.
Riferimenti
• Guida Apache - di Edoardo Valsesia
• I servizi web - di Simone Piccardi
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Febbraio 2008
290
Lo strato applicativo di Internet
OpenSER e Twinkle
Svolgiamo alcuni esperimenti relativi al VoIP SIP. Per concentrarci sulla segnalazione SIP e RTP,
scegliamo di non utilizzare componenti di autenticazione, né di sfruttare il supporto offerto dal
DNS.
• Scelta dello UA
• Chiamata diretta
• Servizi agguntivi
•
•
•
•
•
Messa in attesa
Chiamata su altra linea
Conferenza a tre
Trasferimento di chiamata
Invio di DTMF
• Registrazione su di un hub
• Configuriamo un Outbound Proxy
• Trapezisti!
• Riferimenti
Scelta dello UA
Presso il Wiki del progetto Sapientel, è stata stilata una tabella di comparazione dei softphone
SIP disponibili in forma libera, e tra quelli, scegliamo di usare Twinkle, che scarichiamo mediante
Synaptics. La scelta di Twinke è dettata dalla sua implementazione diretta degli standard, senza
mascherarli troppo dietro interfacce utente oltremodo semplificate. Inoltre, sembra offrire
caratteristiche interessanti, come la conferenza a tre, svariate funzioni di controllo
chiamata, confidenzialità del media, e possibilità di eseguire degli script in corrispondenza alla
ricezione della chiamata.
Chiamata diretta
Per provare subito se funziona, sperimentiamo una chiamata diretta, che non faccia uso di Proxy
intermedi. Per questo, creiamo un profilo di utente che potremmo chiamare locale, in cui
indichiamo un Address of Record con nome labsoftel, e con dominio quello del nostro
computer (mionome.softel). In corrispondenza di queso profilo (menù File/change user/
locale/Edit/Sip Server), disabilitiamo l'interruttore Register at startup.
Ora, possiamo provare a chiamare i nostri colleghi, con AoR [email protected]. Se
catturiamo il traffico, possiamo verificare come viene comunque fatto il tentativo di interrogare
il DNS, ma non trovando nessun RR di tipo SRV, lo UA Twinkle rinuncia al tentativo di usare un
Registrar, e procede ad inviare la chiamata direttamente al dominio di destinazione. Per
abbattere la chiamata, usiamo il tasto
.
Servizi agguntivi
OpenSER e Twinkle
Servizi agguntivi
Sperimentiamo alcune funzioni di Twinkle, contraddistinte dalle icone riportate di seguito, e cioè
• Messa in attesa
• Chiamata su altra linea
• Conferenza a tre
• Trasferimento di chiamata
• Invio di DTMF
I capture forniti, sono per il caso in cui alice@dock chiama bruno@dock, e sono prodotti
presso lo UA di alice. Nella sezione dei Riferimenti, troviamo una nutrita casistica di servizi
aggiuntivi realizzabili con SIP
Messa in attesa
In questo caso (hold), viene eseguito un re-INVITE da parte di alice, nel cui nel nuovo SDP la
sessione viene dichiarata sendonly, e che quando accettato da bruno, produce un SDP di
risposta che dichiara (dal suo punto di vista) la sessione receiveonly. Lo sviluppo attuale di
Twinkle non sembra (ancora) prevedere l'invio di una musica di attesa, però ci starebbe bene...
Chiamata su altra linea
Mentre alice e bruno sono in conversazione, alice decide di chiamare una amica, e clicca
sulla seconda linea. Il capture svela che anche in questo caso, bruno è stato messo on hold con
la stessa tecnica di prima.
Conferenza a tre
L'amica chiamata da alice, in realtà è l'annuncio preregistrato ascoltabile
presso sip:[email protected]... beh poco male, proviamo a creare una conferenza a tre
tra alice, bruno, e l'annuncio. La tecnica svelata dal capture è sempre la stessa, bruno viene
messo on hold, parte l'INVITE verso test, e poi, quando si attiva la conferenza a tre... bruno è
re-invitato per la terza volta, e viene riaperto il flusso RTP verso di lui, che ora è mixato assieme
a quello di test.
Trasferimento di chiamata
In questo caso alice, dopo aver chiamato bruno, decide di trasferire la chiamata verso
sip:[email protected]. In questo caso il capture svela dei particolari interessanti: dopo
aver messo, come al solito, bruno on hold, alice clicca sul trasferimento di chiamata, e sceglie
di voler effettuare un blind transfer, indicando la nuova URI di destinazione: il risultato è che
bruno riceve un REFER, che nella intestazione refer-to, indica la nuova URI. Lo UA di bruno
risponde al REFER con un 202 Accepted, e dopo un pò, bruno (l'umano) risponde
affermativamente alla finestra di notifica che gli propone il trasferimento, causando l'emissione
di un INVITE verso la nuova URI. Per alice, l'invio del REFER sottindente la sottoscrizione alle
notifiche relative allo stato della nuova chiamata, ed infatti bruno inizia a tenere informata
292
Lo strato applicativo di Internet
Alessandro Falaschi
alice della evoluzione della nuova chiamata, per mezzo di messaggi NOTIFY, nel cui body sono
contenute le risposte che bruno riceve per la nuova chiamata. Finché bruno, non termina il
dialogo con alice, con un BYE.
Invio di DTMF
Nel caso ci si trovi a dover interagire con un IVR, può capitare di dover immettere dei toni da
tastiera. In questo caso, il capture ci mostra come questo corrisponda ad inviare, nei pacchetti
RTP, un diverso payload type, che contiene la rappresentazione letterale del tasto premuto.
Registrazione su di un hub
Ora, possiamo creare un nuovo profilo utente, che potremmo chiamare hub, che usa come nome,
il vostronome, e come dominio, alef.softel; Tenendo aperto wireshark, proviamo a
1. registrarci/deregistrarci mediante la quarta voce del menù in alto
2. interrogare le nostre registrazioni mediante l'icona-stellina
all'estrema destra del
nome del profilo
Possiamo verificare come, anche senza aver specificato un Register, viene per default utilizzato
quello corrispondente al proprio dominio. Nel primo caso, l'intestazione Contact contiene un
parametro, expires, pari rispettivamente a 3600, ed a zero. Nel secondo caso, invece, la
richiesta non contiene nessuna intestazione Contact, e viene quindi usata per recuperare del
Register le registrazioni attive.
Proviamo ora, sempre con wireshark attivo, a chiamare un nostro collega, alla URI
sip:[email protected]. In base alle intestazioni Server e UserAgent, determiniamo
quali risposte ci vengono inviate dal Registrar, e quali dallo UA chiamato.
Configuriamo un Outbound Proxy
Il proxy SIP che possiamo scaricare con Synaptic, è OpenSER. Dopo averlo fatto, dobbiamo
abilitarne il funzionamento, editando il file /etc/default/openser (con sudo gedit), e
modificando una delle prima linee come
RUN_OPENSER=yes
Quindi, correggiamo un piccolo bug nell'init-script, immettendo sudo gedit /etc/init.d/
openser, e modificando la linea 99 come
if [ ! -d $HOMEDIR ]; then
Infine, editiamo il file di configurazione vero e proprio di OpenSER, immettendo sudo gedit
/etc/openser/openser.cfg, inserendo la direttiva
mhomed=yes
Ora possiamo lanciare OpenSER, con il consueto sudo /etc/init.d/openser start, e
controllare l'esito dell'operazione, tenendo sott'occhio il file di log, con tail -f /var/log/
293
Riferimenti
OpenSER e Twinkle
daemon.log. Osserviamo il messaggio ERROR: udp_init: bind(5, 0x813a7fc, 16) on
127.0.0.1: Address already in use ? Come al solito, ha ragione lui: la porta 5060 è già
occupata da Twinkle, ed OpenSER non può aprire il suo socket. Per rimediare, riconfiguriamo
Twinkle: con la voce di menù Edit/System settings/Network, scegliamo una diversa porta per il
SIP, e quindi
• chiudiamo e riapriamo Twinkle;
• impostiamo Registrar e Outbound Proxy mediante la voce di menù di Twinkle Edit/User
profile/SIP server, selezionando
• il Registrar alef.softel
• la casella use outbound proxy, specificando il nome proprionome.softel;
• rilanciamo OpenSER, e verifichiamo dal suo file di log, che sia attivo;
• registriamo Twinkle.
Trapezisti!
Ora, possiamo sperimentare l'evoluzione delle intestazioni di segnalazione, sniffando
contemporaneamente sul proprio computer, e (tramite ssh) presso alef.softel. Come
esempio, ecco due capture, ottenuti rispettivamente presso l'outbound proxy colocato con lo UA
chiamante, e presso il Register, per una chiamata da sip:[email protected], verso
sip:[email protected].
Riferimenti
• Session Initiation Protocol (SIP) Basic Call Flow Examples - RFC 3665
• Best Current Practices for Third Party Call Control (3pcc) in the Session Initiation Protocol
(SIP) - RFC 3725
• A Call Control and Multi-party usage framework for the Session Initiation Protocol (SIP) draft IETF 2007
• Session Initiation Protocol Service Examples - draft IETF 2008
Realizzato con
da Alessandro Falaschi - ultimo aggiornamento Marzo 2008
294
Lo strato applicativo di Internet
Alessandro Falaschi
295

Documenti analoghi

presentazione in formato pdf

presentazione in formato pdf configurate, possono presentare vulnerabilità che permettono il VLAN hopping, ovvero la possibilità di far passare traffico da una VLAN ad un'altra, e vanno pertanto prese tutte le necessarie preca...

Dettagli