GnomixLand




INDICE

1      INTRODUZIONE

2      LO STACK TCP/IP
2.1    L'architettura di rete

3      I PROTOCOLLI DI RETE
3.1    I protocolli del livello di trasporto
3.1.1   Il protocollo TCP
3.1.2   Il protocollo UDP
3.2    I protocolli del livello internet
3.2.1   Il protocollo IP
3.2.2   Il protocollo di controllo ICMP
3.2.3   Il protocollo di controllo IGMP
3.2.4   Il protocollo ARP

4      IL LIVELLO DELLE APPLICAZIONI: I SOCKET
4.1    Le applicazioni socket 
4.1.2   Definizioni
4.1.3   Storia del socket
4.2    Elementi costitutivi 
4.2.1 Tipi di socket
4.2.2 Altri tipi di socket
4.3 Funzionamento del socket
4.3.1 Definizioni del linguaggio C/C++
4.4 Le chiamate alle funzioni
4.5 Comunicazione di rete orientata alla connessione
4.5.1 Funzione socket()
4.5.2 Funzione connect()
4.5.3 Funzione bind()
4.5.4 Funzione listen()
4.5.5 Funzione accept()
4.6 Comunicazione di rete non orientata alla con	connessione
4.7 Riepilogo
4.8 Il winsock

5       CONCLUSIONE


1 INTRODUZIONE



Quando leggo gli articoli di BFI provo contemporaneamente meraviglia e 
sgomento. Lo sgomento nasce dal fatto che, in quella e-zine,  spesso mi
mancano le informazioni per poter capire quella massa di dati forniti con
estrema disinvoltura. 
Lo stesso è avvenuto per l'articolo "Guida newbie all'IP spoofing" che altro 
non era che la seconda parte del progetto "0N0S3NDAi" elucubrata dal pur 
ottimo FuSyS. Lì per i veri newbie c'era ben poco da spolpare. 
Al momento non avevo sottomano la prima parte del progetto e così 
scartabellai libri, manuali, ezines, e quant'altro mi potesse fornire la 
conoscenza per avvicinarmi al livello richiesto da FuSyS. Letture disordinate, 
sul letto o in cucina, nei ritagli di tempo che a volte, invece, arrivavano 
ad inglobare buona parte della giornata. 
Quindi le ho organizzate in piccoli appunti, collegandoli tra loro come 
chiazze d'olio nell'acqua. 
Ma ecco quello che ne è uscito.


2) LO STACK TCP-IP 

Esiste un'ampia letteratura sui modelli di organizzazione della rete e sulla
descrizione dei protocolli utilizzati per la trasmissione dei dati. I principali
modelli prevedono la suddivisione della rete in livelli, ad ognuno dei quali
sono associati determinati protocolli di comunicazione. I due modelli di
suddivisione od organizzazione della rete più noti sono il modello ISO-OSI
ed il modello di rete TCP-IP. 


2.1 L'architettura di rete

Il  modello di organizzazione ISO-OSI suddivide la rete in sette livelli o 
strati (stack). Nato tra il 1977 e il 1984 ad opera dell'organismo 
internazionale ISO (International Standard Organization), questo modello si 
basa su un procedimento standardizzato per il collegamento dei sistemi, 
chiamato modello standard di riferimento OSI (Open Systems Interconnection). 
La descrizione di questa architettura venne poi chiamata modello di 
organizzazione ISO-OSI. 
Invece, secondo il modello di rete TCP-IP, la rete viene suddivisa in quattro
strati: lo strato dell'Applicazione (dove opera il software applicativo), 
lo strato del Trasporto, lo strato Internet e lo strato della Rete.  

Il termine protocollo viene usato per indicare un procedimento di 
trasmissione standardizzato dei dati tra le applicazioni di rete. 
I vari protocolli sono caratterizzati dal tipo di dati trasmessi e dalla 
modalità di trasmissione. 
I dati vengono trasmessi in segmenti di byte, chiamati pacchetti. 
Nella manualistica sulle comunicazioni di rete è frequente trovare ancora il 
termine ottetto al posto di byte. L'ottetto, che ha il significato di 
insieme di otto bit, sostituiva la parola byte perché al momento della 
progettazione del protocollo TCP esistevano sistemi con byte formati da nove
bit. Oggi, pur con la quasi totalità dei sistemi che utilizzano byte di otto 
bit, questo termine viene ancora  utilizzato anche se è anacronistico.
L'organizzazione del modello di rete TCP/IP prevede che i diversi protocolli
operino nello strato del trasporto, nello strato internet e nello strato 
della rete. Nel livello dell'applicazione, i programmi di rete trasmettono 
i dati al livello del trasporto o di internet utilizzando determinate 
interfacce software, chiamate API socket.



3 I PROTOCOLLI DI RETE

A livello dello strato del trasporto operano due protocolli: TCP e UDP.
Il protocollo TCP (Transport Control Protocol), esegue il trasporto di una 
sequenza di dati a livello dello strato del trasporto utilizzando un flusso 
byte-stream (la spiegazione di byte stream è più avanti). Nello stesso strato
opera il protocollo UDP, che trasmette i dati mediante l'invio di datagrammi.
Ad un livello più basso, nello strato della rete operano tre protocolli 
diversi: il protocollo IP, che si occupa di frammentare i dati e di 
trasportare i datagrammi attraverso la rete ed i protocolli ICMP e IGMP, che 
vengono chiamati protocolli di controllo in quanto servono ad inviare dati di
controllo della connessione. 
Questi protocolli saranno l'oggetto della presente trattazione.  

Come abbiamo già detto, nello strato dell'applicazione operano i programmi di
rete. Verranno descritte le modalità in cui questi programmi inviano e
ricevono i dati, interagendo con lo strato del trasporto e utilizzando
dei programmi di interfaccia (API) che permettono la creazione di una
connessione tra due host in rete (socket). Saranno definiti i vari tipi di
socket e le chiamate alle varie funzioni che i programmi effettuano
durante l'instaurarsi della comunicazione.


3.1 protocolli del livello di trasporto

3.1.1 Il protocollo TCP 

RFC 793
In una sessione TCP, tra i due host si stabilisce una connessione
full-duplex, cioè un trasferimento di dati bidirezionale, in cui l'host 
destinatario conferma il ricevimento dei pacchetti di dati all'host mittente. 
Ma come avviene, in pratica, la connessione con il protocollo TCP? L'host  
client comunica al proprio sistema operativo che intende aprire una sessione 
con l'host server, e pertanto si fa assegnare una porta. L'assegnazione  
viene effettuata dinamicamente dal s.o., con porte  casuali i cui numeri 
assumono un valore minimo di 1024 fino a 65.535.

Per chi non lo sapesse, le porte da 1 a 256 sono definite porte ben note e 
vengono associate ad applicazioni o servizi distinti. 
La descrizione delle porte si trova sotto win nel file C:windowsservices, 
mentre su linux in /etc/services.

A questo punto, l'host mittente si connette all'indirizzo IP dell'host 
server, specificando il numero di porta dell'applicazione con la quale 
intende comunicare. Ora l'host server, ricevuta la richiesta di apertura 
della sessione, comunica al proprio s.o. che si deve stabilire un'apertura 
passiva della porta, la quale si dice che è in stato d'ascolto. A questo 
punto si è aperta una sessione di comunicazione punto-punto tra i due host. 
Tale sessione viene anche definita circuito virtuale. L'indirizzo IP del 
server, unitamente al protocollo usato per il trasporto ed il numero della 
porta al quale il protocollo si connette, costituisce l'indirizzo socket.

Prima avevamo detto che TCP invia e riceve i dati utilizzando un flusso 
byte-stream. Ma che significa? Significa che il protocollo trasmette tutti i 
dati come un'unica sequenza di byte, come se le informazioni facessero parte 
di un unico flusso seriale. La trasmissione byte-stream (anche definita a 
flusso di dati), utilizzata da TCP si differenzia dalla trasmissione dei 
protocolli UDP e IP, che segmentano i dati in datagrammi, unità di 
informazioni indipendenti trasmesse non sequenzialmente. 

Il flusso dei dati TCP può essere di due tipi: flusso di massa (ftp, news)
e flusso interattivo (telnet, rlogin).
Il meccanismo di trasmissione byte-stream adottato da TCP appare a prima
vista più farraginoso ed è più lento di quello usato da UDP, ma ha il
vantaggio di essere estremamente affidabile perché, a differenza di
quest'ultimo, TCP si assicura che i dati giungano effettivamente
all'applicazione ricevente, nella sequenza corretta. Inoltre, TCP ha anche
il compito di ottimizzare l'ampiezza di banda della rete, controllando
che il flusso di dati trasmesso non sia eccessivo e non mandi in overflow
il buffer di dati nell'host di destinazione. In questo caso TCP induce
l'host mittente a ridurre la velocità di trasmissione.

Ma come fa il protocollo a garantire la ricezione dei pacchetti di dati TCP? 
Per capirlo dobbiamo esaminare com'è fatto un segmento TCP.
Un segmento di dati TCP può essere diviso in 18 campi.

1) Porta di origine: tale campo, a 16 bit, definisce la porta di protocollo 
   usata dall'applicazione trasmittente.
2) Porta di destinazione: campo a 16 bit che identifica la porta di 
   protocollo dell'applicazione ricevente.
3) SEQ o numero di sequenza: campo a 32 bit che indica l'ordine di 
   riassemblaggio dei segmenti.
4) Numero di acknowledgment (numero della conferma): campo a 32 bit che 
   specifica il numero successivo nella sequenza che l'host ricevente si
   aspetta di ricevere.
5) Offset dei dati: campo a 4 bit che specifica la lunghezza 
   dell'intestazione TCP in parole a 32 bit.
6) Reserved: è un campo a 6 bit riservato, che verrà utilizzato in impieghi
   futuri; il valore deve essere impostato su 0.
7) Flag URG (bit del controllo urgente): campo di un bit che, se ha il valore
   impostato a 1, significa che il campo "puntatore urgente" punta a dati 
   urgenti.
8) Flag ACK (Acknowledgment Control Bit o bit del controllo delle conferme): 
   campo di un bit che, se ha il valore impostato a 1, significa che il 
   numero di acknowledgement è valido e deve essere letto.
9) Flag PSH (Push Control Bit o bit del controllo di lancio): campo di un 
   bit che, se impostato ad 1, il segmento chiede di essere inviato 
   immediatamente, senza attendere che l'applicazione riempia il proprio 
   buffer di trasmissione.
10) Flag RST (Reset Control Bit o bit del controllo del reset): campo di un 
    bit che, se impostato ad 1, il segmento richiede che la connessione TCP 
    sia reinizializzata.
11) Flag SYN (Syncronize Control Bit o bit del controllo della sintonia): 
    campo di un bit che, allo stabilirsi di una sessione TCP, imposta il suo 
    valore a 1 e chiede al modulo TCP ricevente di sincronizzare i numeri di 
    sequenza.           
12) Flag FIN (Finish Control Bit o bit del controllo di fine invio): campo di
    un bit che, se impostato ad 1, l'host mittente comunica che non vi sono 
    più dati da trasmettere.
13) Dimensione Finestra: campo a 16 bit che indica il numero di ottetti di 
    dati che l'host mittente accetterà. Questo numero definisce la grandezza 
    delle finestre scorrevoli.      
14) Checksum (somma di controllo): campo a 16 bit che permette al modulo TCP 
    ricevente di rilevare eventuali alterazioni sui dati; l'operazione di 
    controllo è calcolata tramite una tecnica definita "complemento ad uno".
15) Puntatore urgente: campo a 16 bit che punta all'ultimo byte di dati 
    urgenti nell'area dati TCP.
16) Opzioni: campo di lunghezza di bit variabile, che può contenere tre 
    opzioni diverse anche contemporaneamente; queste sono End of Option 
    List=0, No Operation=1, Maximum segment size=2.
17) Padding (riempitivo): campo che, riempito da una serie di 0,  assicura 
    che l'intestazione TCP termini al limite dei 32 bit.
18) Data: i dati reali inclusi nel segmento.

L'instaurazione di una sessione TCP, detta anche handshacking a tre vie, 
si attiva con l'host mittente che invia il primo segmento con il flag SYN 
impostato ad 1, unitamente ad un numero sequenziale a 32 bit, SEQ, scelto a 
caso. E' da sottolineare, tuttavia, che il numero di sequenza identifica un
byte nel flusso di dati e rappresenta un valore di spostamento (offset)
rispetto al primo segmento inviato, come se fosse un contatore. Quindi,
i successivi SEQ  sono aumentati dell'esatto numero di byte inviati.

L'host ricevente, se accetta la connessione, invia due segmenti. Il primo è 
in risposta al segmento ricevuto e contiene il flag ACK impostato a 1, 
oltre al numero di acknowledgement. Questo numero viene impostato su prossimo
valore di SEQ che il server si aspetta di ricevere. Tale conferma instaura una 
connessione TCP in una direzione. 

A sua volta, l'host ricevente trasmette un segmento di dati con il flag SYN 
impostato a 1, e con il proprio numero sequenziale, anche in questo caso 
scelto casualmente. L'host trasmittente trasmetterà a sua volta un
messaggio di acknowledgement, con il flag ACK impostato a 1 e il numero
di acknowledgement uguale al SEQ del server aumentato di 1. Ciò crea la
comunicazione anche nell'altro senso. 
Questa connessione  viene definita full-duplex. I dati che scorrono in una 
direzione sono indipendenti da quelli che scorrono nell'altra.

Es. di handsnake a tre vie tra l'host client A e l'host server B:

A-----> SYN 1, SEQ 2616666351 -----> B  A invia la richiesta di connessione
B-----> ACK 1, SEQ 2616666352 -----> A  B conferma ricezione dati
B-----> SYN 1, SEQ 6465455251 -----> A  B stabilisce connessione altro senso
A-----> ACK 1, SEQ 6465455252 -----> B  A si sincronizza con B 
A-----> SYN 1, SEQ 2616666352 -----> B  A invia il secondo pacchetto dati

 
Nell'instaurarsi della sessione avviene un altro fatto: l'host mittente 
imposta le dimensioni della finestra di trasmissione e lo comunica all'host 
ricevente, che imposta la finestra di ricezione sulle stesse dimensioni. 
Ma cosa indica la dimensione di queste finestre? Essa indica il numero 
massimo di segmenti che si possono inviare ogni volta. In pratica, quando 
l'applicazione posta al livello superiore passa i dati al protocollo TCP, 
questo li suddivide in pacchetti o segmenti. Allo stabilirsi della sessione, 
l'host mittente invia contemporaneamente  tanti segmenti quanti ne può 
contenere la finestra di trasmissione.

Mettiamo che l'host mittente debba inviare 20 segmenti ed imposti la propria
finestra di trasmissione in modo da inviare quattro segmenti per volta. 
L'host mittente invia i segmenti SYN1, SYN2, SYN3 e SYN4. L'host ricevente, 
per qualche problema della rete, riceverà solo i pacchetti 1, 2  e 4. 
La risposta dell'host ricevente sarà che ha ricevuto solo i segmenti 1 e 2 e 
trasmetterà i segmenti ACK1 e ACK2. L'host mittente, ricevuta l'informazione 
ritrasmetterà i segmenti SYN3 e SYN4, ma contemporaneamente trasmetterà i 
segmenti SYN5 e SYN6, riempiendo così la finestra di trasmissione. 
E così via. Questo tipo di trasmissione viene chiamato metodo delle finestre 
scorrevoli o sliding windows. In questo modo, l'host ricevente può inviare 
una sola risposta di conferma per una ricezione di più segmenti 
contemporaneamente.

Ma come fa l'host mittente a sapere con esattezza quali pacchetti sono giunti 
a destinazione? Inserendo un temporizzatore di ritrasmissione in ogni 
segmento trasmesso. Quando il temporizzatore raggiunge il valore di 0, 
l'host mittente invia nuovamente il segmento, impostando il temporizzatore 
ad una durata doppia di prima. Questo metodo viene usato in quanto l'host 
ricevente può comunicare solo l'avvenuta ricezione dei segmenti e non anche 
il contrario.

La connessione termina mediante un handsnake a due sensi. In pratica, sia
il client che il server, possono decidere di terminare la comunicazione,
inviando il flag FIN impostato a 1. L'host che invia il flag FIN effettua
la chiusura attiva della connessione, mentre l'altro host effettua la
chiusura passiva della connessione TCP.  Mettiamo che il client invii FIN.
Il server risponderà con un flag ACK, che starà ad indicare di avere
ricevuto la richiesta di termine della connessione e, generalmente,
invierà a sua volta un flag FIN, effettuando la chiusura passiva. Ma
che cosa succede se il server non invia il flag FIN? In questo stato
viene ancora mantenuta la connessione nell'altro senso. Questo stato di
chiusura intermedia viene chiamato Half-Close. E' un evento che avviene
raramente perché pochissime applicazioni TCP hanno bisogno di utilizzare
questo tipo di chiusura.

Una sessione TCP, pertanto, si può trovare in diverse condizioni, a seconda 
che la sessione stia per iniziare, sia iniziata o terminata. Durante una 
connessione, con il comando netstat -na si possono visualizzare tutti gli 
stati della sessione TCP. Ecco gli stati possibili:

- LISTEN: l'host attende una richiesta di connessione da parte di qualsiasi 
  host remoto;
- SYN-SENT: l'host che si trova in questo stato, ha inviato una richiesta di 
  connessione ad un host ricevente e sta aspettando la richiesta di ritorno 
  per instaurare  la connessione full-duplex;
- SYN-RECEIVED: è lo stato dell'host ricevente che ha ricevuto ed inviato a 
  sua volta una richiesta di conferma per la connessione e sta aspettando la 
  conferma;
- ESTABLISHED: significa che la connessione tra i due host è aperta;
- FIN-WAIT1: è lo stato di attesa di una richesta di termine della sessione o
  di una conferma di una richiesta di termine della sessione precedente;
- FIN-WAIT2: è lo stato di attesa per una richiesta di termine della sessione
  dall'host remoto;
- CLOSE-WAIT; stato che rappresenta il lasso di tempo in cui la connessione 
  TCP attende la richiesta di termine della sessione da parte 
  dell'applicazione posta nel livello superiore dello stack TCP-IP;
- CLOSING; è lo stato dell'attesa della conferma della richiesta  di termine 
  della connessione da parte dell'host remoto;
- LAST-ACK: è lo stato dell'attesa della conferma della richesta di termine 
  della connessione che l'host ha inviato all'host remoto;
- TIME-WAIT: l'host è in attesa di chiudere la connessione, dopo l'invio 
  della conferma della sua richiesta di termine della connessione;
- CLOSED: la connessione tra i due host è terminata.



3.1.2 Il protocollo UDP

RFC 768
E' un protocollo che  permette una consegna non garantita, ma più veloce dei
dati, trasmessi mediante l'invio di datagrammi. Una seconda caratteristica
di tale protocollo è che l'host mittente, durante la trasmissione dei dati,
non deve aprire una sessione con l'host di destinazione. Infatti si parla
di di comunicazione senza connessione, per distinguerla dalla comunicazione
con connessione del protocollo TCP. In questo caso il client effettuerà
un'apertura attiva della porta, mentre il server effettuerà un'apertura
passiva, ricevendo i dati senza comunicare l'avvenuta ricezione. La
mancanza di questo meccanismo di controllo rende meno affidabile, ma
sicuramente più veloce, la trasmissione dei dati. 

Pertanto, ogni applicazione che voglia utilizzare questo protocollo,
come ad  es. le applicazioni Realaudio, deve occuparsi di ritrasmettere
i dati smarriti e di effettuare direttamente il controllo del flusso dei
dati con un apposito buffer, evitando eventuali congestioni del flusso.
Inoltre essa dovrà provvedere alla frammentazione e riassemblggio dei
dati voluminosi. 
Con UDP è comunque possibile una verifica dell'integrità dei dati
trasmessi e viene permesso l'invio dei dati in broadcasting e in
multicasting, cosa non permessa al protocollo TCP. 

Ma come è fatto il datagramma UDP? Esso è composto da un header di 4
byte, contenente quattro campi, e un'area dati. I primi due campi
indicano la porta sorgente e la porta destinazione del protocollo.
Il terzo campo è il message lenght ed indica la lunghezza in byte del
datagramma. Il campo di checksum o somma di controllo, utilizza la
tecnica del complemento ad uno sull'header e sui dati per la verifica
dell'integrità delle informazioni. L'area dati è di lunghezza variabile
e contiene i dati che provengono dall'applicazione posta nel livello
superiore. 

Nella trasmissione dei dati, l'host mittente non stabilisce una
connessione con l'host ricevente, ma invia i datagrammi UDP dopo
averli incapsulati in un datagramma IP. L'host ricevente, se avrà
una porta in listening, accetterà il pacchetto eliminando
l'incapsulazione IP. L'analisi del datagramma UDP permetterà all'host
ricevente di verificare le informazioni del datagramma.
Poiché il volume dei dati inviati tramite il protocollo UDP può
essere elevata, i datagrammi UDP tendono ad essere frammentati in
più pacchetti. Un controllo della velocità può essere effettuato
con la produzione da parte dell'host server di datagrammi denominati
"source quench", che non sono altro che ICMP di tipo 4; generalmente,
la trasmissione dei dati inizia lentamente, per aumentare sempre più
finchè il server non risponde con un messaggio soure quench.



3.2 I protocolli del Livello Internet


3.2.1 Il protocollo IP

RFC  791
L'Internet Protocol (IP) è il principale protocollo utilizzato per
la trasmissione dei dati in rete. Tutti i protocolli provenienti dal
livello superiore dello stack, come TCP ed UDP, o provenienti dallo
stesso livello, come i protocolli di controllo ICMP e IGMP, vengono
incapsulati nei datagrammi IP e inviati nel livello inferiore, chiamato
link layer, pronti per il successivo invio nella rete.

Il pacchetto IP viene chiamato datagramma. Che cosa significa questo
termine? Significa unità di dati autocontenente e, solitamente,
specifica il tipo di consegna dei dati, per distinguerlo dalla trasmissione
dei dati byte-stream. Pertanto, si può comprendere che  il datagramma
IP, pur utilizzando lo stesso metodo di trasmissione, è diverso dal
datagramma UDP.
Il datagramma IP contiene uno header e l'area dati. Quest'ultima, a
sua volta consiste nel pacchetto incapsulato. L'header IP ha la
lunghezza fissa di 20 byte. Ma ecco, di seguito, i campi dell'header.

- Version number (VERS): campo di 4 bit che identifica la versione
dell'IP usata per creare il datagramma.
- Header lengh (HLEN): campo di 4 bit che specifica la lunghezza
dell'header IP in parole di 32 bit.
- Type of service (TOS): campo di 8 bit che specifica la priorità
di consegna dei dati e le decisioni progettuali. Tuttavia, il TOS
non viene supportato da parecchi host e router. Questo campo è a
sua volta suddiviso in 5 sottocampi. Il primo sottocampo (precedence)
viene utilizzato dalle applicazioni o dai protocolli per specificare
l'importanza dei loro dati, mediante un valore che va da 0 a 7.
Sebbene sia utile nel controllo delle congestioni in rete, viene
scarsamente utilizzato. Il secondo sottocampo (delay), così come
gli altri tre, definisce una priorità non generale come il primo,
ma dipendente dalle applicazioni. Delay indica che si vogliono
minimizzare i ritardi. Il terzo sottocampo (throughput) indica che
si vuole massimizzare il throughput. Il quarto sottocampo (reliability) 
indica che si vuole massimizzare l'affidabilità. L'ultimo sottocampo
(cost) indica che si vuole massimizzare il costo.
- Packet length: campo di 16 bit che specifica la lunghezza totale
dell'intero pacchetto IP.
- Identification: campo di 16 bit, utilizzato per l'identificazione
del datagramma IP quando questo viene frammentato.
- Flags: campo di 3 bit utilizzato per il controllo della frammentazione.
Se l'applicazione intende prevenire la frammentazione del datagramma,
essa attiva il primo bit del campo. Tuttavia questo metodo viene
scarsamente utilizzato poiché in caso di una sua attivazione che sia
in contrasto con il MTU il pacchetto viene distrutto. L'ultimo bit
del campo indica "altri frammenti". Questo bit viene attivato da IP
in tutti i frammenti creati, eccetto l'ultimo frammento, che avrà
valore uguale a 0.
- Fragment offset: campo di 13 bit che indica la distanza o punto
di rottura dall'inizio del datagramma in caso di frammentazione.
Questo valore verrà utilizzato da IP per la ricostruzione dei
frammenti.    Dato che la lunghezza massima di un datagramma è
di 65535, questo campo deve poter puntare in qualsiasi punto del
pacchetto e deve poter contenere valori che vanno da 1 a 65535.
- Time-to-Live (TTL): campo di 8 bit che indica quanto tempo potrà
vivere il pacchetto durante il suo viaggio nella rete. Questo
campo viene decrementato di un'unità ad ogni passaggio in un router.
Il router che riceva un pacchetto scaduto prima del suo arrivo a
destinazione, lo distruggerà ed invierà un pacchetto ICMP di
avvertimento all'host mittente.
- Protocol: campo di 8 bit che indica quale protocollo ha creato
il pacchetto trasportato da IP. A titolo di esempio, il protocollo
ICMP ha valore 1, l'IGMP 2, il TCP 6, mentre UDP 17.
- Header checksum: campo di 16 bit utilizzato per la verifica
dell'integrità dell'header IP. La checksum non comprende l'area
dati, il cui controllo di integrità viene gestito dal protocollo
che ha creato il pacchetto.
- Indirizzi IP di partenza e di arrivo: source IP address è un
campo di 32 bit che contiene l'indirizzo IP dell'host mittente. 
Destination IP address è un campo di 32 bit che contiene
l'indirizzo IP dell'host ricevente.
- IP options: campo di 8 bit utilizzato per testare e correggere
le applicazioni di rete. Questo campo è suddiviso in tre sottocampi:
copia, classe opzione e numero opzione. Non tutti i router ed host
supportano l'IP options.

In rete si indica per MTU il valore di unità massima di
trasferimento del pacchetto che si vuol trasferire. Quando un
programma di rete cerca di inviare un pacchetto più grande della
MTU di quella rete, esso viene frammentato in più parti. La
frammentazione può avvenire anche durante il tragitto, se il
router ha una MTU di rete più piccola di quella della rete da
dove è partito il pacchetto.  
Come si è già detto, il riassemblaggio dei pacchetti avviene per
mezzo dei tre campi Identification, Flags e Fragment Offset.





3.2.2 Il protocollo di controllo ICMP 

RFC 792
L'internet Control Message Protocol viene definito protocollo di basso 
livello, in quanto opera nello strato della rete, unitamente al protocollo 
IP. Tuttavia, pur operando nello stesso livello, anche ICMP si affida al 
protocollo IP per la trasmissione in rete dei propri pacchetti. 
Tutti i programmi che utilizzano l'ICMP devono creare un'interfaccia software
particolarmente rudimentale, chiamata socket raw. 

Ma di cosa si occupa questo protocollo? L'ICMP svolge essenzialmente due 
compiti: il primo è  di trasportare i messaggi d'errore della rete; il 
secondo è di trasportare i messaggi di richiesta, i quali contengono sia 
richieste di informazione che risposte, relative sia alla rete che all'host. 
La progettazione di ICMP fu resa necessaria dal fatto che il protocollo IP 
non contemplava la possibilità di fornire notifiche di errori nel trasporto
dei dati. I progettatori decisero di semplificare l'attività di IP e di 
affidare questo compito al nuovo protocollo ICMP, con alcuni limiti.
Infatti ICMP non è in grado di risolvere i problemi scaturiti durante
il trasporto dei dati, e non può comunicare il verificarsi di un
errore ai router intermedi, ma solo all'host che ha generato il
pacchetto. Una particolarità che è utile menzionare è che un messaggio
di errore non può  generare altri messaggi di errore. Ciò evita la
produzione di messaggi a catena, che provocherebbero le cosiddette
"tempeste broadcast).

Ma ecco la descrizione del pacchetto ICMP. 
L'header ICMP è formato da tre campi, di cui due a 8 bit e il terzo a
16 bit, per un totale di 32 bit. Il pacchetto che contiene ICMP
comprende inoltre l'header IP con i primi 8 byte di dati del
datagramma che ha generato l'errore (se si tratta di messaggi
di errore) o con i dati contenenti il messaggio di richiesta.
Ciò avviene perché il pacchetto del protocollo ICMP, per il
trasporto nella rete, viene incapsulato in un datagramma IP.

Il primo campo contiene il valore Type ed è di 8 bit. Questo valore
indica i 15 tipi diversi di messaggio ICMP.
Il secondo campo contiene il valore Code ed è anch'esso di un byte 
(1 byte= 8 bit). Questo valore contiene i codici o le categorie esistenti
per ogni messaggio. Ad esempio, l'ICMP di tipo 3 è un messaggio di errore che
significa destinazione irraggiungibile. Questo messaggio comprende a sua 
volta 16 diverse categorie che contemplano i vari tipi di errore per una 
destinazione irraggiungibile.
Il terzo campo da 2 byte, contiene il valore Checksum.

Ma ecco una tabella riassuntiva.

Tipo 0  messaggio di richiesta      descrizione: risposta echo
Tipo 3  messaggio di errore         descrizione: destinazione irraggiungibile
Tipo 4  messaggio di errore         descrizione: estinzione della fonte
Tipo 5  messaggio di errore         descrizione: reindirizzamento
Tipo 8  messaggio di richiesta      descrizione: echo
Tipo 9  messaggio di richiesta      descrizione: annuncio al router
Tipo 10 messaggio di richiesta      descrizione: sollecito al router
Tipo 11 messaggio di errore         descrizione: tempo superato
Tipo 12 messaggio di errore         descrizione: problema dei parametri
Tipo 13 messaggio di richiesta      descrizione: richiesta di un timestamp
Tipo 14 messaggio di richiesta      descrizione: invio di un timestamp
Tipo 15 messaggio di richiesta      descrizione: rich. informazioni (obsoleto)
Tipo 16 messaggio di richiesta      deccrizione: invio informazioni (obsoleto)
Tipo 17 messaggio di richiesta      descrizione: rich. maschera d'indirizzo
Tipo 18 messaggio di richiesta      descrizione: invio maschera d'indirizzo

Come si può vedere, ICMP comprende 5 messaggi di errore e 10 messaggi di 
richiesta. Specifichiamo i vari messaggi.

 
- MESSAGGI DI ERRORE

1) errori di destinazione irraggiungibile  (tipo 3)

Lo scopo principale del protocollo ICMP è proprio il messaggio di
errore del tipo 3, cioè destinazione irraggiungibile. Questa peculiarità
di ICMP serve per ovviare al fatto che il protocollo IP non garantisce
la consegna dei datagrammi. Questo messaggio di errore viene prodotto
dal router ed inviato all'host sorgente ogni volta che non gli è
possibile consegnare il pacchetto dei dati. L'impossibilità di consegna
dei dati può dipendere da un problema nel trasferimento dei dati o da
un  problema di routing. Nel primo caso il codice di errore è di host
irraggiungibile, mentre nel secondo caso viene prodotto un codice di
errore di rete irraggiungibile.
I codici di errore per l'ICMP di tipo 3 sono 16:

codice 0: rete irraggiungibile
codice 1: host irraggiungibile
codice 2: protocollo irraggiungibile
codice 3: porta irraggiungibile
codice 4: necessaria frammentazione e disattivazione del bit "don't fragment"
codice 5: tragitto di origine fallito
codice 6: rete di destinazione sconosciuta
codice 7: host di destinazione sconosciuto
codice 8: host di origine isolato (non più usato)
codice 9: rete di destinazione vietata dall'amministrazione
codice 10: host di destinazione vietato dall'amministrazione
codice 11: rete irraggiungibile per il tipo di servizio (TOS)
codice 12: host irraggiungibile per il tipo di servizio (TOS)
codice 13: comunicazione proibita dall'amministrazione tramite filtri
codice 14: violazione della precedenza da parte dell'host
codice 15: scorciatoia in vigore


2) Errori di indirizzamento (tipo 5)

Essi vengono prodotti dai router. Ogni router di una rete fisica ha
il compito di indirizzare i pacchetti verso l'hop successivo del
percorso, seguendo la via più breve. Esso ha una propria tabella
di routing in cui vengono memorizzate le informazioni sui percorsi
ottimali verso una rete di destinazione. La tabella di routing
viene costantemente aggiornata mediante un continuo scambio di
informazioni tra i router. Quando un computer host invia dei dati
in rete utilizzando un percorso non ottimale, il router che è
situato nel primo nodo dove inizia il percorso non ottimale informa
l'host di ciò con un messaggio di errore di indirizzamento del tipo
5. Questi messaggi di reindirizzamento possono essere inviati solo
dai router. I codici di errore per gli ICMP di tipo 5 sono  4:

codice 0: reindirizzamento per rete
codice 1: reindirizzamento per host
codice 2: reindirizzamento per tipo di servizio (TOS) e rete
codice 3: reindirizzamento per tipo di servizio (TOS) e host  

3) Errori di superamento del tempo   (tipo 11)

Gli header dei datagrammi IP contengono un campo che definisce la
vita del pacchetto. Questo campo è chiamato "time to live" (TTL).
Se il TTL raggiunge lo zero, il software di rete  scarta il
pacchetto ed invia all'host sorgente un messaggio di errore.
Esistono due codici di errore per questo tiipo di messaggio.
Il codice 0 indica che il TTL ha raggiunto lo 0 durante il
passaggio. In genere ciò è dovuto ad un errore nelle tabelle
di routing che produce un ciclo di routing, cioè un ciclo di
loop continui tra due router che si scambiano lo stesso pacchetto,
aspettandosi che l'altro router si incarichi dell'hop. 
Il codice 1, invece, indica che il timer di riassemblaggio dei
frammenti di un host ha raggiunto il suo limite prima che tutti
i frammenti fossero giunti. Infatti, quando l'host client invia
un datagramma contenente il flag "More Fragment" settato,
l'host di destinazione innesca un timer per il riassemblaggio,
entro il quale tutti i frammenti devono giungere, pena lo scarto
dei frammenti.

4) errori relativi a problemi dei parametri  (tipo 12)

Questo tipo di errore può essere generato dall'host ogni qualvolta
ci sia una condizione di errore sconosciuta o quando un datagramma
non contiene tutte le informazioni richieste dal protocollo
 Nel primo caso l'ICMP di tipo 12 avrà il codice 0 ( cattivo
header IP), mentre nel secondo caso avrà il codice 1 (opzione
richiesta mancante)

5) errori di estinzione della fonte   (tipo 4)

I protocolli orientati alla connessione come TCP contengono un
controllo del flusso dei dati, per impedire l'intasamento del buffer
dell'host server. Un protocollo non orientato alla connessione,
come IP, è privo di questo controllo del flusso. Poiché i router
utilizzano datagrammi IP, senza un adeguato controllo del flusso
dei dati, essi si potrebbero intasare, congestionando a sua volta
il traffico di rete. Quando si crea una congestione, i router
iniziano a scartare i pacchetti ed inviano questo tipo di messaggio
di errore, informando l'host mittente che è necessario rallentare
la velocità del flusso. Questo tipo di ICMP contiene un solo codice,
settato a 0.

     MESSAGGI ICMP DI RICHIESTA


1) Richieste ai router   (tipi 9 e 10)

Come specificato nella RFC 1256, il protocollo ICMP effettua due
tipi di richiesta al router: il messaggio di sollecito al router
(tipo 10) e il messaggio di annuncio del router (tipo 9). 
Innanzi tutto è bene ricordare che lo smistamento dei pacchetti
si chiama routing. Gli host preposti allo smistamento di questi
pacchetti si chiamano router (o anche gateway). Il routing può
essere diretto od indiretto: nel primo caso il routing avviene
tra due host connessi direttamente alla stessa rete o sottorete;
nel secondo caso, i dati vengono trasmessi ad almeno un router,
cioè un host che si occupa del successivo smistamento ad un altro
router o all'host ricevente. Ogni router ha una sua tabella di
routing, che non è altro che una tabella, contenente tra le altre
cose, una serie di indirizzi di destinazioni successive, con a
fianco un valore numerico (metrica) che indica la qualità della
destinazione. La tabella di routing può essere statica e descritta
in un file o dinamica. Ora possiamo tornare ai messaggi ICMP di
richiesta al router. 
Il messaggio di sollecito viene prodotto dall'host al suo avvio,
e la risposta del router viene chiamato messaggio di annuncio.
Il messaggio di annuncio viene utilizzato dall'host per
inizializzare dinamicamente la propria tabella di routing,
in modo da non dover utilizzare un file statico come tabella.
La particolarità del messaggio di annuncio è che il router può
inserire nel pacchetto ICMP più di un indirizzo di router. Ogni
indirizzo di router è corredato di un campo, chiamato Preference
Level, che indica all'host ricevente quale router utilizzare per
primo o con maggior frequenza. Questo pacchetto contiene anche
il campo Timelife, che indica il numero di secondi per cui
l'indirizzo rimane valido, che di norma è di 1800 secondi.  

2) Richieste di timestamp  (tipi 13 e 14)

Questi tipi di richieste permettono di misurare il tempo impiegato
dai pacchetti nel passare da un host a un altro. Questo datagramma
contiene due campi particolari: il campo identificatore ed il numero
di sequenza. Questi campi vengono utilizzati per distinguerli tra
le varie richieste di timestamp che, generalmente, vengono utilizzate
per analisi statistiche del tempo di trasferimento.


3) Richieste di maschera di indirizzo   (17 e 18)
La richiesta di maschera di indirizzo viene generalmente
utilizzata da una workstation senza disco per poter ottenere
la propria maschera di sottorete. La richiesta viene effettuata
in broadcast e gli host in rete risponderanno con un datagramma
contenente l'invio della maschera di indirizzo. I campi del
datagramma ICMP di tipo 17 e 18 sono gli stessi del datagramma
timestamp.


4) Messaggi  di richiesta e risposta echo  (tipi 0 e 8)

Questo tipo di messaggio ICMP viene utilizzato da programmi come
ping (packet internet grouper) per verificare se l'host di
destinazione è raggiungibile e per misurare il tempo che la richiesta
di echo impiega a tornare. L'ICMP di tipo 0 viene inviato
dall'applicazione verso l'host di destinazione e questi risponde
con un messaggio di tipo 8. L'utilizzo di questo tipo di ICMP è
utile per la verifica della connettività. 
Per la conferma che i protocolli TCP/IP sono stati installati
correttamente, generalmente si effettua un ping al proprio host,
mediante l'utilizzo dell'indirizzo di riciclo o loopback, che è
127.0.0.1. Se il pacchetto torna indietro, i protocolli sono
installati correttamente.
Un ping all'indirizzo IP assegnato al proprio host, invece, ci
permette di verificare la corretta configurazione di questo IP sul
proprio host.
Un ping all'indirizzo IP di gateway predefinito della propria rete,
ci permette di verificare la corretta configurazione della maschera
di sottorete.
E' evidente che in una buona configurazione dei firewall a filtro
di pacchetti, deve essere permessa la ricezione di pacchetti ICMP
di errore di tipo 3, mentre è utile bloccare gli ICMP di tipo 0 e 8.


3.2.3 Il protocollo IGMP

RFC 1112
Una piccola premessa per ricordare che gli indirizzi IP si distinguono
in unicast, broadcast e multicast. Gli indirizzi di classe A, B e C
si dicono indirizzi unicast, in quanto sono assegnati ad un singolo host.
L'Internet Network Information Center (InterNIC) ha il compito di
garantire che ogni rete abbia un identificatore univoco. Questo ente
utilizza gli indirizzi di classe D per indirizzi di tipo multicast. 

Quando i pacchetti inviati da un host mittente devono raggiungere
più host destinatari, si possono utilizare due  metodi di trasmissione:
la trasmissione broadcasting, e la trasmissione multicasting. 

Il metodo broadcasting comporta che il pacchetto di dati venga
analizzato da tutti gli host della rete, i quali verificheranno
che esso non sia destinato a loro. Il problema è che diversi
router sono configurati per non inoltrare i pacchetti con la
modalità broadcasting. 

Il metodo di trasmissione multicasting, invece, permette di
specificare come destinazione uno specifico gruppo di host,
evitando che i pacchetti debbano essere analizzati da tutti i
router della rete. 
I dati multicast vengono trasmessi mediante datagrammi UDP. 
Gli host  possono entrare od uscire dinamicamente da questi gruppi
multicast. Quando ne fanno parte, assumono degli indirizzi IP di
classe D, che vanno da 224.0.0.1 a 239.255.255.255. Se viene
indicato come destinazione l'indirizzo IP 224.0.0.1, significa
che il gruppo broadcast è formato da tutti gli host e i router
che partecipano a un multicasting IP su una sezione della rete.
Il pacchetto IGMP è formato da cinque campi.

- Version: campo che indica la versione del protocollo utilizzato.
Con IGMP è settato sul valore di 1
- Type: può avere due valori; il valore 1 significa che il messaggio
IGMP è il prodotto di un'interrogazione di un router multicast; il
valore impostato a 2 significa che il pacchetto origina da una
risposta di un host IP
- Checksum: campo che contiene un valore numerico corrispondente
alla somma di controllo, per la verifica dell'integrità del dato.
- Group address: campo che contiene l'IP del gruppo di host multicast.

Questo tipo di protocollo viene utilizzato generalmente da
applicazioni interattive, che permettono di fare arrivare le
informazioni a più host.
L'Internet Assigned Number Autority (IANA) assegna alcuni indirizzi
multicast come indirizzi noti, i quali rappresentano gruppi di host
permanenti.

A causa di un bug nello stack TCP/IP nelle piattaforme win95/98,
i pacchetti IGMP frammentati  possono essere utilizzati per
effettuare attacchi D.o.S.
Recentemente è stata rilasciata dalla Microsoft una patch che
risolve il problema.


3.2.4  Il protocollo ARP

RFC 826
L'Address Resolution Protocol è un protocollo che viene utilizzato
per risolvere un indirizzo IP di un host client nel relativo indirizzo
MAC. No, nulla a che vedere con la gloriosa casa  Apple. Il MAC
(media access control) è l'indirizzo fisico dell'host, detto anche
indirizzo hardware della scheda di rete. 

Il processo in cui opera tale protocollo è il seguente: innanzi tutto
il client verificherà se il server fa parte della stessa rete o di
una rete remota; l'indirizzo IP del server sarà confrontato con la
maschera di sottorete del client mediante il processo di messa in
AND. Gli indirizzi IP dell'origine e della destinazione sono
confrontati con la maschera di sottorete dell'origine. Se il server
si trova nella stessa rete avverrà qwuanto segue: l'host client,
prima di inviare i dati al server, controlla nella propria cache ARP se
vi sia l'indirizzo del server. In caso negativo, il client invia un
pacchetto ARP al server, con il quale chiede l'indirizzo MAC di
quest'ultimo. Nel pacchetto, il client inserisce il proprio IP e 
indirizzo MAC, che andranno nella cache ARP del server. Il pacchetto
è inviato all'indirizzo broadcast e, quindi, a tutti gli host del
segmento i quali esamineranno il pacchetto. Gli host a cui non è
diretto il pacchetto, lo ignoreranno dopo averlo esaminato. L'host
a cui è destinato il pacchetto, inserirà le informazioni nella propria
cache ARP ed invierà il proprio indirizzo MAC all''host mittente.
Dopo questo passaggio, può avere inizio la comunicazione tra il client
ed il server.

Quando il server si trova in una rete remota, il client controllerà
nella propria cache ARP se ha l'indirizzo MAC del router predefinito.
In caso negativo, esso invierà un pacchetto ARP contenente il proprio
indirizzo IP e indirizzo MAC, con il quale richiederà l'indirizzo MAC
del router. Quindi invierà il pacchetto al router. Il processo è
identico, da router a router, fino al server.

Il pacchetto ARP si compone di 9 campi.

- Hardware type: campo che indica il tipo di hardware usato nella rete
- Protocol type: campo che indica il tipo di indirizzo di protocollo
- Hardware address lenght: campo che indica la lunghezza in bit
dell'indirizzo hardware
- Protocol Address Lenght: campo che indica la lunghezza dell'indirizzo
di protocollo
- Op code: campo che indica se il pacchetto è una richiesta od una
risposta ARP
- Sender's hardware Address: campo che indica l'indirizzo hardware
dell'host mittente
- Sender's Protocol Address: campo che indica l'indirizzo IP
dell'host mittente
- Target's Hardware Address: campo che indica l'indirizzo hardware
dell'host destinatario
- Target's Protocol Addres: campo che indica l'indirizzo hardware
dellìhost destinatario



4 Il livello delle applicazioni e i socket

4.1   Le applicazioni socket

Immediatamente soprastante a tale livello, nello strato dell'applicazione 
lavorano le applicazioni che si possono suddividere in due categorie:
 
- applicazioni socket
- applicazioni netbios

Le applicazioni socket sono dei programmi di rete (ftp, telnet ecc.) che 
utilizzano le API socket.
Le applicazioni NetBios utilizzano altri tipi di API per comunicare e 
condividere i dati tra due host remoti. Questa nota è improntata alla 
descrizione delle applicazioni socket, e quindi non parlerò del NetBios.


4.1.2  Definizioni

Socket: quando due host si scambiano dati sulla rete, i due capi in cui 
avviene la comunicazione si dicono punti di arrivo; i socket  sono i punti 
di arrivo tra due computer che comunicano in rete. Secondo una convenzione, 
definita  modello client-server, i programmi che comunicano in rete, a 
seconda che inviino o ricevino i dati, si distinguono rispettivamente in 
programmi client e programmi server. Pertanto in una comunicazione ci saranno
due socket, uno nel lato client e uno nel lato server. 
Tecnicamente su usa pure dire che un socket è una rappresentazione astratta 
di un punto di arrivo. 

Le API (Application Program Interface), sono un gruppo di funzioni o 
interfacce software utilizzate dai programmatori per sviluppare applicazioni
in determinati ambienti. 
L'API socket quindi si può definire come un'interfaccia tra le applicazioni
che comunicano in rete e lo stack di protocolli TCP-IP. 


4.1.3 Storia del socket

Ed ora, consentitemi una piccola digressione sull'interfaccia socket.
Negli anni '80, sull'onda del rapido sviluppo di internet, su richiesta 
dell'ARPA, gli uomini dei laboratori dell'università di Berkeley,  
svilupparono un software particolare che interfacciava  tutte le applicazioni
di rete  che giravano sul sistema operativo Unix, con i protocolli TCP-IP. 
Essi progettarono un programma d'interfaccia, denominato API  socket, 
chiamato anche socket Berkeley, che si implementava con i protocolli TCP-IP 
su macchine Unix. 

Anche win ha le sue API sockets, chiamate windows sockets o anche winsock. 
Le funzioni del winsock sono praticamente le stesse di quelle dei socket
Berkeley, ma implementano una  serie di funzioni specifiche per l'utilizzo 
sotto windows. Si dice che il winsock è progettato come un componente WOSA 
(Windows Open Service Architecture). 

Nel 1991 nacque il Winsock Group, una società formata da produttori e 
sviluppatori di applicazioni per le reti e di software per sistemi operativi
windows. Nel 1993 fu prodotto WinSock versione 1.1,  che permetteva 
l'utilizzo di applicazioni a 16 bit. Dopo il rilascio di windows 95,  sono 
state pubblicate le specifiche delle Windows Sockets versione 2.0, a 32 bit, 
con nuove funzionalità. Oggi siamo alle 2.2. 
Diversamente dalla versione 1.1, che era focalizzata interamente progettato
sul TCP/IP, la nuova API è indipendente dal protocollo di trasporto. 
Il winsock32.dll consiste di due interfacce standard , una tra il
winsock stesso e le  Application Programming Interface (API), l'altra tra il
WinSock e i service providers, Service Providers Interface (SPI).
All'interno delle Windows Sockets 2 sono inseriti TCP/IP, IPX/SPX, OSI e 
altri protocolli minori. 



4.2  Elementi costitutivi


4.2.1 Tipi di socket

Il funzionamento del socket non è particolarmente complesso, ma per capirlo 
ci sono alcuni termini che dovrete memorizzare. 
Ogni socket  host è costituito da cinque elementi informativi: il protocollo
utilizzato, l'indirizzo IP dell'host locale o client, l'indirizzo IP 
dell'host remoto o server, una porta di protocollo per il processo client e 
una porta di protocollo per il processo server. Il protocollo utilizzato, 
permette di distinguere i programmi client o server orientati alla 
connessione o programmi client o server non orientati alla connessione. 
I client o server orientati alla connessione utilizzano un protocollo di 
trasmissione affidabile, come il Tcp, mentre quelli non orientati alla 
connessione si servono di protocolli la cui trasmissione non è garantita, 
come IP e UDP. 

Quanto abbiamo detto sopra, ci permette di distinguere i tipi di 
comunicazione che vengono definiti in tutto dall'interfaccia socket.

-   Comunicazione di rete orientata alla connessione:

I dati viaggiano in un unico flusso di byte (byte-stream); nel linguaggio
di programmazione, si dice che l'interfaccia (API) socket utilizza la
costante simbolica SOCK_STREAM ed si avvale del protocollo TCP.


-   Comunicazione senza connessione:

I dati viaggiano in pacchi ben distinti (datagrammi). L'API socket utilizza,
in questo caso, la costante simbolica SOCK_DGRAM e usa il protocollo UDP.


Oltre ai due tipi di comunicazione sopra descritti, esistono altri tre
tipi di comunicazione dell'API socket.


-   Comunicazione raw socket:

Il terzo tipo,  più rudimentale, viene chiamato "raw socket", da raw=grezzo. 
L'API socket utilizza la costante simbolica SOCK_RAW. 
Un raw socket viene normalmente utilizzato dal programma per poter adottare
protocolli diversi da TCP e UDP. 
Nel modello dello stack dei protocollo TCP-IP, è come dire che il raw socket
mette in comunicazione direttamente il livello delle applicazioni con il 
livello di rete, saltando il livello del trasporto. 
Un esempio di tale tipo di comunicazione è quando un'applicazione crea un 
socket raw per gestire l'ICMP, un  protocollo di controllo di basso livello,
che opera nello strato della rete, come IP e IGMP. 

Per chi si vuole dilettare nella creazione dei pacchetti, è opportuno 
ricordare che i winsock inferiori alla versione 2.0 non contemplano la 
comunicazione raw socket, mentre le versioni  successive la supportano con 
diverse limitazioni. Questa limitazione non esiste, invece, per i socket unix
che utilizzano normalmente i raw socket. Sotto win, un uso meno limitato 
della comunicazione socket raw puo' essere effettuato utilizzando un winsock 
diverso da quello di default fornito dalla Microsoft, ad esempio usando il 
Trumpet  Winsock, versione 3.0d che però, a detta di alcuni esperti, rende il
sistema instabile in alcune situazioni.


4.2.2   Altri tipi di socket 

Gli ultimi due tipi di socket, sono:

- socket di pacchetto in sequenza: SOCK_SEQPACKET

- socket di messaggio consegnato affidabilmente (non implementato): SOCK_RDM.

Dei due tipi di socket, solo il primo viene utilizzato raramente, mentre
il secondo non è implementato, e vengono qui citati solo per completezza
di esposizione.


4.3  Funzionamento del socket

Ora passiamo ad una breve descrizione tecnica di ciò che avviene quando un 
programma comunica con un altro in rete. Credo che ciò sia utile anche per 
chi non si intende di programmazione, se non altro perchè potrà fornirgli
l'input a sviluppare i concetti qui espressi. 
Per costoro, è utile almeno riassumere quanto segue.


4.3.1 Definizioni del linguaggio C/C++

Nel codice sorgente di un programma possono esistere delle sezioni di codice 
distinte, che sono chiamate funzioni. Le funzioni hanno un nome, un valore o 
argomento e un tipo di restituzione.
Le funzioni possono essere chiamanti o chiamate. Le funzioni chiamanti 
sospendono l'esecuzione della sezione di codice in esse contenuto in seguito
ad una chiamata di funzione. Ciò permetterà l'esecuzione della sezione di 
codice della funzione chiamata. Per fare un esempio, un nome di una funzione 
che vedremo più avanti è "socket". I valori (cioè argomenti o chiamati anche 
parametri) della funzione sono facoltativi, e sono indicati all'interno di 
una coppia di parentesi tonde, poste dopo il nome della funzione. 

Nel caso di una chiamata ad una funzione che, ad esempio, ha nome 
"che_palle()", con le parentesi prive di contenuto, avremmo una funzione 
priva di argomenti. Il tipo di restituzione dice al compilatore (programma 
che traduce il sorgente in codice macchina) che tipo di dati la funzione 
chiamata restituisce alla funzione chiamante. 
Variabile: è la rappresentazione che il linguaggio di programmazione usa per
definire dei dati, che possono essere numeri o stringhe di caratteri. Quando 
ad una variabile non è stato assegnato un valore, si dice che la variabile 
non è stata inizializzata. Ad una stessa variabile possono essere assegnati 
valori diversi.

Header file o file d'intestazione: è un file che contiene delle definizioni 
d'interfaccia di classe e/o dichiarazioni di funzione. Ha estensione .h. Un 
esempio è il file iostream.h che, tra le altre cose, dice al compilatore come 
utilizzare i comandi di imput ed output (<< >>). Quando nel sorgente l'header
è compreso in due parentesi acute () significa che il file si 
trova nella directory predefinita dal compilatore. Se invece l'header è 
compreso in due doppi apici ("vector.h"), significa che esso si trova nella 
stessa directory del file sorgente. 

Puff, pant. Se volete un corso di C alla Bignami avete sbagliato tutorial ma,
soprattutto, avete riposto troppa fiducia nell'autore.


4.4  Le chiamate alle funzioni

Ora veniamo ai dettagli. Se utilizziamo un programma di rete (browser web, 
ftp), questo viene definito come programma client. 
Quando un programma client vuole comunicare con un programma server in rete,
il client si limita a creare un'interfaccia socket, chiamando la funzione 
"socket()", con tre  parametri: int socket( int famiglia, int tipo, int 
protocollo ).

A questo punto, l'applicazione, prima di poter utilizzare il socket creato, 
deve prima configurarlo nella giusta maniera. Se ricordate ciò che abbiamo 
detto più sopra, possiamo raggruppare i socket in  due tipi principali: 
quelli connessi e quelli non connessi. Il metodo di configurazione, pertanto,
varia a seconda del tipo di socket.


4.5  Comunicazione di rete orientata alla connessione

Se il programma client utilizza il protocollo TCP si dice che è orientato 
alla connessione. L'applicazione crea inizialmente un socket, con la chiamata
alla omonima funzione. Per la configurazione del socket, il programma
chiama una seconda funzione, definita "connect()". Ma procediamo con ordine
e vediamo come sono strutturate le funzioni chiamate.

4.5.1    Funzione Socket()

La funzione socket contiene i parametri che specificano la famiglia di 
protocolli (protocol_family), il tipo di socket (socket_type) e il protocollo
utilizzato (protocol_type).

Definiamo i tre parametri.

Protocol_family: l'interfaccia socket puo effettuare comunicazioni su più 
tipi di reti e, quindi, può utilizzare diversi protocolli come TCP/IP, XNS 
ed i protocolli interni di unix. XNS è uno stack di protocolli simile a 
TCP/IP, sviluppato dai laboratori Xerox, che viene implementato nelle reti 
Netware di Nowell e VINES di Banyan. Questo parametro comprende quindi delle 
costanti simboliche per definire la famiglia di protocolli supportata. 
Quella utilizzata per le comunicazioni internet è la costante simbolica 
PF_INET, che identifica lo stack TCP/IP. PF_UNIX identifica la famiglia di 
protocolli interni di unix, i quali vengono utilizzati per le comunicazioni 
interne tra i vari processi del s.o.;  PF_NS identifica la famiglia di 
protocolli XEROX. Quando il parametro identifica non le famiglie di 
protocolli, ma le famiglie di indirizzi, i quali variano da rete a rete, esso
utilizza le stesse costanti simboliche con il prefisso AF_ al posto di PF. 
Pertanto avremo AF_INET, AF_UNIX e AF_NS. 

Socket_type: come abbiamo già visto esistono cinque tipi di socket, dei quali
solo tre sono comunemente implementati: SOCK_STREAM, che indica che verrà 
utilizzato la comunicazione byte stream; SOCK_DGRAM che indica che verrà 
utilizzata la comunicazione con invio di datagrammi; SOCK_RAW, che indica che
verrà utilizzato un protocollo di basso livello, come ICMP e IGMP.

Protocol_type: la costante simbolica viene specificata con un prefisso 
IPPROTO_ seguita dal tipo di protocollo: ad es. IPPROTO_UDP, IPPROTO_TCP ecc.





4.5.2   Funzione connect()

Questa funzione contiene tre parametri: socket_handle, remote_socket_address 
e address_lenght.
Come si può notare, anche intuitivamente, dai nomi dei parametri, è' la 
funzione connect a memorizzare le informazioni del punto di arrivo locale e 
di quello remoto.
In questo caso, il protocollo utilizzato permette una connessione diretta 
con il server, attraverso l'invio di dati byte-stream.


Anche il programma server, dopo un procedimento analogo di creazione del 
socket, chiama alcune funzioni:

4.5.3.   Funzione bind()

La prima, relativa alla configurazione delle informazioni 
locali, è chiamata funzione "bind()"; il socket del server viene informato
su quale porta deve stare in ascolto da questa funzione. 
Una piccola digressione sulla funzione bind(). La chiamata a bind può essere 
utilizzata in 3 modi diversi:
1. I server registrano il loro indirizzo, ben noto, nel sistema. 
In pratica dicono al sistema: "Questo è il mio indirizzo e qualsiasi 
messaggio ricevuto ad esso indirizzato deve essere consegnato a me!". 
Questa procedura deve essere fatta prima di accettare richieste da un client 
sia dai server orientati alla connessione sia da quelli che non lo sono. 
2. Un client può registrare un indirizzo specifico per se stesso, in modo che 
il server risponda alle richieste su quel indirizzo. 
3. Un client senza connessione deve accertarsi che il sistema assegni un 
certo indirizzo unico, affinchè l'altra estremità abbia un indirizzo di 
ritorno valido su cui inviare le risposte. 
Terminata la digressione, definiamo i parametri.
I parametri sono: ( int sockfd, struct sockaddr*mioindir, int lunghindr).
1. sockfd: descrittore di socket precedentemente creato con la chiamata di 
sistema socket. 
2. mioindr: è un puntatore all'indirizzo specifico della struttura del 
protocollo. 
3. lunghdir: dimensione della struttura del protocollo. 

Come? Ah, c'è qualcuno che non conosce le definizioni descrittore e 
puntatore? 

Puntatore: è un indirizzo di memoria associato ad un tipo di dato, dove 
l'associazione viene indicata con il simbolo *. Es: Tipo_di_dato*puntatore

Descrittore: E' un tipo particolare di puntatore. In C, uno dei modi per 
manipolare il contenuto di un file consiste nell'aprire uno stream, cioè un
"canale di flusso" col file stesso mediante un'apposita funzione, che 
restituisce il puntatore ad una struttura i cui campi sono utilizzati poi da 
altre funzioni, per compiere operazioni sul file stesso. Tale puntatore è 
detto "descrittore" del file. 
Se qualcuno non ha capito nulla,  ecco un altro esempio di ripasso: 
(Borland C++ 3 ed. Apogeo, lire 64 mila)*puntatore.


Le altre due chiamate, relative alle  informazioni remote sono le funzioni 
"listen()" e "accept()".


4.5.4  Funzione listen()

Questa chiamata di sistema è usata da un server orientato alla connessione 
per indicare che è disposto a ricevere le connessioni, cioè si trova in stato 
di attesa. 
Solitamente è eseguita dopo le chiamate di sistema socket e bind ed 
immediatamente prima della chiamata accept. Quando arrivano più richieste di 
connessione, il server usa la funzione listen() per gestire le richieste 
multiple e simultanee per il socket.
I parametri sono: int listen( int sockfd, int backlog );
1. sockfd: descrittore di socket precedentemente creato con la chiamata di 
sistema socket. 
2. backlog: specifica il numero di richieste di connessione che possono 
essere accodate dal sistema mentre è in attesa che il server esegua la 
chiamata accept. 


4.5.5   Funzione accept()

Dopo che un server orientato alla connessione ha eseguito 
la chiamata di sistema listen, si pone in attesa di una eventuale connessione 
da parte di un processo client.
La chiamata accept prende in esame la richiesta di connessione che si ha in 
testa alla coda specificata dalla listen e crea un altro socket con le stesse
propietà di socketfd.
Se non ci sono richieste di connessione in sospeso, questa chiamata blocca 
il chiamante finche non ne arriva una.
Le funzioni sono: int accept( int sockfd, struct sockaddr *pari, 
int lunghindir); 
1. sockfd: Descrittore di socket fd.
2. lunghindr:Contiene la lunghezza della struttura dell'indirizzo del 
processo connesso (client). Il lunghindir viene prima posto uguale alla 
dimensione della struttura e succesivamente prende il valore della dimensione
della struttura effetivamente occupata dal client connesso.


Il programma client, per instaurare la classica trasmissione handsnake a tre 
vie, a sua volta chiamerà  la funzione "write()" per trasmettere i dati e la 
funzione "read()" per ricevere i dati di risposta a una porta specifica che 
verranno inviati dal server. 
A questo punto, il server chiamerà anch'esso le funzioni read() e write(), 
rispettivamente per ricevere e rispondere.



4.6  Comunicazione di rete non orientata alla connessione
  
Se il programma client non è orientato alla connessione,  per configurare le 
informazioni locali esso chiama la funzione "bind" e la funzione "sendto"
per la configurazione delle informazioni remote. Dato che il socket è senza
connessione, non viene effettuata la chiamata alla funzione connect.
A sua volta, il programma server senza connessione ascolterà passivamente
i dati che giungeranno dalla porta di protocollo e chiamerà la funzione 
"bind" per le informazioni locali e la funzione "recvfrom" per le 
informazioni remote. Quando giungeranno i dati dal client, il server 
trasmetterà dati in risposta con la stessa funzione sendto ed il client
riceverà tali dati utilizzando la chiamata alla funzione recvfrom (invece di
recv o read), esattamente come avviene nel server. 
In questo tipo di comunicazione, il protocollo utilizzato non permette una
connessione diretta tra il programma client ed il programma server, cioè una
connessione detta point-to-point tra due punti di arrivo.
Come abbiamo già visto, i dati vengono trasmessi mediante l'uso dei 
datagrammi.

4.7    Riepilogo

Ricapitolando, terminata la fase della configurazione, durante la 
trasmissione dei dati l'API del socket chiamerà cinque diverse funzioni: 
send, write, writev, sendto e sendmsg.

Le prime tre funzioni sono utilizzate solo da socket orientati alla 
connessione. 
In particolare, la funzione send contiene quattro parametri e contiene alcuni
flag particolari usati per controllare il socket (socket_handle, 
message_buffer, buffer_lenght e special_flags). La funzione write trasmette
i dati utilizzando un semplice buffer e contiene generalmente tre funzioni
(socket_handle, message_buffer e buffer_lenght). La funzione writev trasmette
i dati utilizzando memoria non contigua come buffer per i dati e contiene tre
funzioni (socket_handle, io_vector e vector_lenght).

Le ultime due funzioni vengono usate dall'API del socket non connesso.
In particolare, la funzione sendto utilizza un semplice buffer per i messaggi
e contiene sei parametri (socket_handle, message_buffer, buffer_lenght,
special_flags, socket_address_structure e address_structure_lenght).
La funzione sendmsg trasmette i dati utilizzando una struttura dei messaggi
flessibile come buffer dei dati e contiene tre parametri (socket_handle,
message_structure e special_flags).


Ecco uno specchietto con le corrispondenze tra le funzioni di trasmissione e 
le funzioni di ricezione nell'API socket:

   funzione di trasmissione / funzione di ricezione
-  send                       recv
-  write                      read
-  writev                     readv
-  sendto                     recvfrom
-  sendmsg                    recvmsg


Ed ecco pure uno specchietto delle varie chiamate dei due tipi di socket:

-  socket con protocollo orientato alla connessione

 Server=socket-bind-listen-accept--read-write
                                    |     |
             Client=socket-connect-write-read

-  socket con protocollo non orientato alla connessione

  Server=socket-bind-recvfrom--sendto
                        |        |
  Client=socket-bind-sendto-recvfrom

A tutte le funzioni sopra espresse, bisogna aggiungere un'ultima funzione:

Select(): è solitamente usata dai programmi server o da programmi client 
particolarmente sofisticati e permette ad un singolo progesso di verificare 
lo stato di più socket. Richiede cinque parametri e sono: 
select(number_sockets, readable_sockets, writeable_sockets, error_sockets,
max_time).



4.8      Il winsock


Non ci sono grandi differenze di caratteristiche tra il socket Berkeley e il
Winsock. Le principali sono:

1. Il socket windows implementa l'API del socket in una libreria con
   estensione dll, chiamata winsock.dll.
2. Winsock, oltre alle funzioni già definite con il socket Berkeley, 
   richiede sempre la chiamata a due funzioni specifiche: WSAStartup e 
   WSACleanup. WSAStartup() è una funzione chiamata dal programma durante una
   negoziazione tra il programma stesso e winsock.dll. Il programma specifica
   le caratteristiche minime richieste al winsock ed il winsock risponde 
   specificando le proprie funzionalità. In pratica questa funzione serve al 
   programma per specificare quale versione dell'API winsock necessita. 
   WSAStartup può essere chiamata diverse volte durante l'attività del 
   programma, ad esempio per fornire le caratteristiche dell'implementazione.
   A ogni chiamata viene incrementato un contatore delle chiamate.    
   WSACleanup() è una funzione che viene chiamata dal programma per 
   decrementare il contatore delle chiamate alla funzione WSAStartup. 
3. In un errore nel socket, l'API Berkeley utilizza la funzione errno() con 
   il valore a -1, mentre il winsock definisce una nuova costante, chiamata 
   Socket_Error, il cui valore è -1; il programma chiamerà quindi la funzione
   WSAGetLastError, che verificherà la causa che ha provocato l'errore nel 
   winsock.
4. A differenza di quanto avviene con i programmi unix, che necessitano di 
   più file header, nei programmi per Windows l'unico file da includere per 
   il supporto dei  socket e' winsock.h sia per la versione a 16 che per 
   quella a 32 bit. L'header winsock.h include automaticamente windows.h e, 
   pertanto, non sarà necessario inserirlo. In  fase di  compilazione si 
   scegliera' (automaticamente o manualmente) la dll da usare.



5     CONCLUSIONE

Ora è ovvio che chi non conosce l'arte della programmazione, più in là non 
può andare. Memorizzare le varie funzioni chiamate da un programma durante lo
stabilimento di una connessione non serve a molto se non si smanetta in C o 
VB.  Lo sforzo di imparare un linguaggio verrà ricompensato dalla capacità di
poter capire e commentare, ad esempio, un programma per creare pacchetti TCP,
leggendo il sorgente o magari di poterlo modificare per una diversa utilità.
Le e-zine tecniche come BFI partono da questo presupposto. Adesso tocca a voi.


©  GnomixLand
http://www.gnomixland.com/