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
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...