X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=tcpsock.tex;h=7261246389bdf1e8ac4b3f8fb13b51d263fdfa93;hb=b52f6b91fcc6e0bc4a1522462f61f5f62e684bfe;hp=d3d1f559c4ffa3fd66f861fb83d2a993e4bb2ae0;hpb=d7db23a35bbd9c7465780719188709ca06e99eaf;p=gapil.git diff --git a/tcpsock.tex b/tcpsock.tex index d3d1f55..7261246 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -125,38 +125,46 @@ varr \subsection{Le opzioni TCP.} \label{sec:TCP_TCP_opt} -Ciascun segmento SYN contiene in genere delle opzioni per il protocollo TCP -(le cosiddette \textit{TCP options}, che vengono inserite fra l'header e i -dati) che servono a comunicare all'altro capo una serie di parametri utili a -regolare la connessione. Normalmente vengono usate le seguenti opzioni: +Ciascun segmento SYN contiene in genere delle opzioni per il protocollo TCP, +le cosiddette \textit{TCP options},\footnote{da non confondere con le opzioni + dei socket TCP che tratteremo in sez.~\ref{sec:sock_tcp_udp_options}, in + questo caso si tratta delle opzioni che vengono trasmesse come parte di un + pacchetto TCP, non delle funzioni che consentono di impostare i relativi + valori.} che vengono inserite fra l'header e i dati, e che servono a +comunicare all'altro capo una serie di parametri utili a regolare la +connessione. Normalmente vengono usate le seguenti opzioni: \begin{itemize} -\item \textit{MSS option}, dove MMS sta per \textit{maximum segment size}, con - questa opzione ciascun capo della connessione annuncia all'altro il massimo - ammontare di dati che vorrebbe accettare per ciascun segmento nella - connessione corrente. È possibile leggere e scrivere questo valore - attraverso l'opzione del socket \const{TCP\_MAXSEG}. +\item \textit{MSS option}, dove MMS sta per \itindex{Maximum~Segment~Size} + \textit{Maximum Segment Size}, con questa opzione ciascun capo della + connessione annuncia all'altro il massimo ammontare di dati che vorrebbe + accettare per ciascun segmento nella connessione corrente. È possibile + leggere e scrivere questo valore attraverso l'opzione del socket + \const{TCP\_MAXSEG} (vedi sez.~\ref{sec:sock_tcp_udp_options}}). -\item \textit{window scale - option}, %come spiegato in sez.~\ref{sec:tcp_protocol} - il protocollo TCP implementa il controllo di flusso attraverso una - \textsl{finestra annunciata} (\textit{advertized window}) con la quale - ciascun capo della comunicazione dichiara quanto spazio disponibile ha in - memoria per i dati. Questo è un numero a 16 bit dell'header, che così può - indicare un massimo di 65535 byte;\footnote{ Linux usa come massimo 32767 - per evitare problemi con alcune implementazioni che usano l'aritmetica con - segno per implementare lo stack TCP.} ma alcuni tipi di connessione come - quelle ad alta velocità (sopra i 45Mbit/sec) e quelle che hanno grandi - ritardi nel cammino dei pacchetti (come i satelliti) richiedono una finestra - più grande per poter ottenere il massimo dalla trasmissione, per questo - esiste questa opzione che indica un fattore di scala da applicare al valore - della finestra annunciata\footnote{essendo una nuova opzione per garantire - la compatibilità con delle vecchie implementazioni del protocollo la - procedura che la attiva prevede come negoziazione che l'altro capo della - connessione riconosca esplicitamente l'opzione inserendola anche lui nel - suo SYN di risposta dell'apertura della connessione.} per la connessione - corrente (espresso come numero di bit cui spostare a sinistra il valore - della finestra annunciata inserito nel pacchetto). +\item \textit{window scale option}, il protocollo TCP implementa il controllo + di flusso attraverso una \itindex{advertised~window} \textit{advertised + window} (la ``\textsl{finestra annunciata}'', vedi + sez.~\ref{sec:tcp_protocol_xxx}) con la quale ciascun capo della + comunicazione dichiara quanto spazio disponibile ha in memoria per i dati. + Questo è un numero a 16 bit dell'header, che così può indicare un massimo di + 65535 byte;\footnote{Linux usa come massimo 32767 per evitare problemi con + alcune implementazioni che usano l'aritmetica con segno per implementare + lo stack TCP.} ma alcuni tipi di connessione come quelle ad alta velocità + (sopra i 45Mbit/sec) e quelle che hanno grandi ritardi nel cammino dei + pacchetti (come i satelliti) richiedono una finestra più grande per poter + ottenere il massimo dalla trasmissione, per questo esiste questa opzione che + indica un fattore di scala da applicare al valore della + \itindex{advertised~window} finestra annunciata\footnote{essendo una nuova + opzione per garantire la compatibilità con delle vecchie implementazioni + del protocollo la procedura che la attiva prevede come negoziazione che + l'altro capo della connessione riconosca esplicitamente l'opzione + inserendola anche lui nel suo SYN di risposta dell'apertura della + connessione.} per la connessione corrente (espresso come numero di bit cui + spostare a sinistra il valore della finestra annunciata inserito nel + pacchetto). Con Linux è possibile impostare questo valore a livello di + sistema con una opportuna \textit{sysctl} (vedi + sez.~\ref{sec:sock_ipv4_sysctl}). \item \textit{timestamp option}, è anche questa una nuova opzione necessaria per le connessioni ad alta velocità per evitare possibili corruzioni di dati @@ -165,8 +173,8 @@ regolare la connessione. Normalmente vengono usate le seguenti opzioni: \end{itemize} -La MSS è generalmente supportata da quasi tutte le implementazioni del -protocollo, le ultime due opzioni (trattate +La MSS \itindex{Maximum~Segment~Size} è generalmente supportata da quasi tutte +le implementazioni del protocollo, le ultime due opzioni (trattate nell'\href{http://www.ietf.org/rfc/rfc1323.txt}{RFC~1323}) sono meno comuni; vengono anche dette \textit{long fat pipe options} dato che questo è il nome che viene dato alle connessioni caratterizzate da alta velocità o da ritardi @@ -290,9 +298,10 @@ che il protocollo viene ad assumere per i due lati, server e client. \label{fig:TCP_conn_example} \end{figure} -La connessione viene iniziata dal client che annuncia un MSS di 1460, un -valore tipico con Linux per IPv4 su Ethernet, il server risponde con lo stesso -valore (ma potrebbe essere anche un valore diverso). +La connessione viene iniziata dal client che annuncia una MSS +\itindex{Maximum~Segment~Size} di 1460, un valore tipico con Linux per IPv4 su +Ethernet, il server risponde con lo stesso valore (ma potrebbe essere anche un +valore diverso). Una volta che la connessione è stabilita il client scrive al server una richiesta (che assumiamo stare in un singolo segmento, cioè essere minore dei @@ -757,7 +766,6 @@ indicare l'indirizzo di \textit{loopback}, che a sua volta viene inizializzata staticamente a \const{IN6ADRR\_LOOPBACK\_INIT}. - \subsection{La funzione \func{connect}} \label{sec:TCP_func_connect} @@ -820,15 +828,18 @@ sopra), quelle che per o problemi nella chiamata della funzione sono le seguenti: \begin{enumerate} \item Il client non riceve risposta al SYN: l'errore restituito è - \errcode{ETIMEDOUT}. Stevens riporta che BSD invia un primo SYN alla chiamata - di \func{connect}, un altro dopo 6 secondi, un terzo dopo 24 secondi, se - dopo 75 secondi non ha ricevuto risposta viene ritornato l'errore. Linux - invece ripete l'emissione del SYN ad intervalli di 30 secondi per un numero - di volte che può essere stabilito dall'utente sia con una opportuna - \func{sysctl} che attraverso il filesystem \file{/proc} scrivendo il valore - voluto in \file{/proc/sys/net/ipv4/tcp\_syn\_retries}. Il valore predefinito - per la ripetizione dell'invio è di 5 volte, che comporta un timeout dopo - circa 180 secondi. + \errcode{ETIMEDOUT}. Stevens riporta che BSD invia un primo SYN alla + chiamata di \func{connect}, un altro dopo 6 secondi, un terzo dopo 24 + secondi, se dopo 75 secondi non ha ricevuto risposta viene ritornato + l'errore. Linux invece ripete l'emissione del SYN ad intervalli di 30 + secondi per un numero di volte che può essere stabilito dall'utente. Questo + può essere fatto a livello globale con una opportuna + \func{sysctl},\footnote{o più semplicemente scrivendo il valore voluto in + \file{/proc/sys/net/ipv4/tcp\_syn\_retries}, vedi + sez.~\ref{sec:sock_ipv4_sysctl}.} e a livello di singolo socket con + l'opzione \const{TCP\_SYNCNT} (vedi sez.~\ref{sec:sock_tcp_udp_options}). Il + valore predefinito per la ripetizione dell'invio è di 5 volte, che comporta + un timeout dopo circa 180 secondi. \item Il client riceve come risposta al SYN un RST significa che non c'è nessun programma in ascolto per la connessione sulla porta specificata (il @@ -908,11 +919,11 @@ con cui il kernel tratta le connessioni in arrivo. Per ogni socket in ascolto infatti vengono mantenute due code: \begin{enumerate} \item La coda delle connessioni incomplete (\textit{incomplete connection - queue} che contiene un riferimento per ciascun socket per il quale è - arrivato un SYN ma il \itindex{three~way~handshake}\textit{three way + queue}) che contiene un riferimento per ciascun socket per il quale è + arrivato un SYN ma il \itindex{three~way~handshake} \textit{three way handshake} non si è ancora concluso. Questi socket sono tutti nello stato \texttt{SYN\_RECV}. -\item La coda delle connessioni complete (\textit{complete connection queue} +\item La coda delle connessioni complete (\textit{complete connection queue}) che contiene un ingresso per ciascun socket per il quale il \itindex{three~way~handshake} \textit{three way handshake} è stato completato ma ancora \func{accept} non è ritornata. Questi socket sono @@ -2385,13 +2396,13 @@ si aveva il SYN flag attivo. Si noti come a partire dal secondo pacchetto sia sempre attivo il campo \texttt{ack}, seguito dal numero di sequenza per il quale si da il ricevuto; quest'ultimo, a partire dal terzo pacchetto, viene espresso in forma relativa per maggiore compattezza. Il campo \texttt{win} in -ogni riga indica la \textit{advertising window} di cui parlavamo in -sez.~\ref{sec:TCP_TCP_opt}. Allora si può verificare dall'output del comando -come venga appunto realizzata la sequenza di pacchetti descritta in -sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal client un primo pacchetto -con il SYN che inizia la connessione, a cui il server risponde dando il -ricevuto con un secondo pacchetto, che a sua volta porta un SYN, cui il client -risponde con un il terzo pacchetto di ricevuto. +ogni riga indica la \itindex{advertised~window} \textit{advertised window} di +cui parlavamo in sez.~\ref{sec:TCP_TCP_opt}. Allora si può verificare +dall'output del comando come venga appunto realizzata la sequenza di pacchetti +descritta in sez.~\ref{sec:TCP_conn_cre}: prima viene inviato dal client un +primo pacchetto con il SYN che inizia la connessione, a cui il server risponde +dando il ricevuto con un secondo pacchetto, che a sua volta porta un SYN, cui +il client risponde con un il terzo pacchetto di ricevuto. Ritorniamo allora alla nostra sessione con il servizio echo: dopo le tre righe del \textit{three way handshake} \itindex{three~way~handshake} non avremo nulla @@ -2605,9 +2616,9 @@ Il risultato finale qui dipende dall'implementazione dello stack TCP, e nel caso di Linux anche dall'impostazione di alcuni dei parametri di sistema che si trovano in \file{/proc/sys/net/ipv4}, che ne controllano il comportamento: in questo caso in particolare da \file{tcp\_retries2} (vedi -sez.~\ref{sec:sock_sysctl}). Questo parametro infatti specifica il numero di -volte che deve essere ritentata la ritrasmissione di un pacchetto nel mezzo di -una connessione prima di riportare un errore di timeout. Il valore +sez.~\ref{sec:sock_ipv4_sysctl}). Questo parametro infatti specifica il numero +di volte che deve essere ritentata la ritrasmissione di un pacchetto nel mezzo +di una connessione prima di riportare un errore di timeout. Il valore preimpostato è pari a 15, il che comporterebbe 15 tentativi di ritrasmissione, ma nel nostro caso le cose sono andate diversamente, dato che le ritrasmissioni registrate da \cmd{tcpdump} sono solo 8; inoltre l'errore @@ -2842,7 +2853,7 @@ niente fintanto che non pu possono utilizzare questi valori per far si che \func{select} ritorni solo quando c'è la certezza di avere dati a sufficienza.\footnote{questo tipo di controllo è utile di norma solo per la lettura, in quanto in genere le - operazioni di scrittura sono già controllate dall'applicazione, che sà + operazioni di scrittura sono già controllate dall'applicazione, che sa sempre quanti dati invia, mentre non è detto possa conoscere la quantità di dati in ricezione; per cui, nella situazione in cui si conosce almeno un valore minimo, per evitare la penalizzazione dovuta alla ripetizione delle @@ -3391,17 +3402,18 @@ successiva \func{select} ritorner disponibilità. Il nostro server comunque soffre di una vulnerabilità per un attacco di tipo -\textit{Denial of Service}. Il problema è che in caso di blocco di una -qualunque delle funzioni di I/O, non avendo usato processi separati, tutto il -server si ferma e non risponde più a nessuna richiesta. Abbiamo scongiurato -questa evenienza per l'I/O in ingresso con l'uso di \func{select}, ma non vale -altrettanto per l'I/O in uscita. Il problema pertanto può sorgere qualora una -delle chiamate a \func{write} effettuate da \func{FullWrite} si blocchi. Con -il funzionamento normale questo non accade in quanto il server si limita a -scrivere quanto riceve in ingresso, ma qualora venga utilizzato un client -malevolo che esegua solo scritture e non legga mai indietro l'\textsl{eco} del -server, si potrebbe giungere alla saturazione del buffer di scrittura, ed al -conseguente blocco del server su di una \func{write}. +\itindex{Denial~of~Service~(DoS)} \textit{Denial of Service}. Il problema è +che in caso di blocco di una qualunque delle funzioni di I/O, non avendo usato +processi separati, tutto il server si ferma e non risponde più a nessuna +richiesta. Abbiamo scongiurato questa evenienza per l'I/O in ingresso con +l'uso di \func{select}, ma non vale altrettanto per l'I/O in uscita. Il +problema pertanto può sorgere qualora una delle chiamate a \func{write} +effettuate da \func{FullWrite} si blocchi. Con il funzionamento normale questo +non accade in quanto il server si limita a scrivere quanto riceve in ingresso, +ma qualora venga utilizzato un client malevolo che esegua solo scritture e non +legga mai indietro l'\textsl{eco} del server, si potrebbe giungere alla +saturazione del buffer di scrittura, ed al conseguente blocco del server su di +una \func{write}. Le possibili soluzioni in questo caso sono quelle di ritornare ad eseguire il ciclo di risposta alle richieste all'interno di processi separati, utilizzare @@ -3600,7 +3612,7 @@ questo server le considerazioni finali di sez.~\ref{sec:TCP_serv_select}. % LocalWords: SNDLOWAT third fset maxfd fileno ISSET closed how SHUT RD WR eof % LocalWords: RDWR fifo Trip ping fourth CLR sull'I SETSIZE nread break Denial % LocalWords: Service poll POLLIN POLLRDNORM POLLPRI POLLRDBAND POLLOUT events -% LocalWords: POLLHUP POLLERR revents pollfd +% LocalWords: POLLHUP POLLERR revents pollfd Di %%% Local Variables: %%% mode: latex