X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=sockctrl.tex;h=9d5279e6ab62856b34ff617697608b440c23c03e;hp=82f1c66be27ed36530bc48faae6990891af43821;hb=fa15a3f1ecd64efd8440e46d398fd9976abc3d25;hpb=042a4b9aecb49ccf46e506e30a130e8c592d010e diff --git a/sockctrl.tex b/sockctrl.tex index 82f1c66..9d5279e 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -1,6 +1,6 @@ %% sockctrl.tex %% -%% Copyright (C) 2004 Simone Piccardi. Permission is granted to +%% Copyright (C) 2004-2019 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Prefazione", @@ -8,12 +8,13 @@ %% license is included in the section entitled "GNU Free Documentation %% License". %% + \chapter{La gestione dei socket} \label{cha:sock_generic_management} -Esamineremo in questo capitolo una serie di funzionalità aggiuntive relative +Esamineremo in questo capitolo una serie di funzionalità aggiuntive relative alla gestione dei socket, come la gestione della risoluzione di nomi e -indirizzi, le impostazioni delle varie proprietà ed opzioni relative ai +indirizzi, le impostazioni delle varie proprietà ed opzioni relative ai socket, e le funzioni di controllo che permettono di modificarne il comportamento. @@ -22,228 +23,5126 @@ comportamento. \label{sec:sock_name_resolution} Negli esempi dei capitoli precedenti abbiamo sempre identificato le singole -macchine attraverso indirizzi numerici, sfruttando al più le funzioni di +macchine attraverso indirizzi numerici, sfruttando al più le funzioni di conversione elementare illustrate in sez.~\ref{sec:sock_addr_func} che -permettono di passare da un indirizzo espresso in forma dotted decimal ad un -numero. Vedremo in questa sezione le funzioni utilizzate per poter utilizzare -dei nomi simbolici al posto dei valori numerici, e viceversa quelle che -permettono di ottenere i nomi simbolici associati ad indirizzi, porte o altre -proprietà del sistema. +permettono di passare da un indirizzo espresso in forma \textit{dotted + decimal} ad un numero. Vedremo in questa sezione le funzioni utilizzate per +poter utilizzare dei nomi simbolici al posto dei valori numerici, e viceversa +quelle che permettono di ottenere i nomi simbolici associati ad indirizzi, +porte o altre proprietà del sistema. \subsection{La struttura del \textit{resolver}} \label{sec:sock_resolver} -La risoluzione dei nomi è associata tradizionalmente al servizio del -\textit{Domain Name Service} che permette di identificare le macchine su -internet invece che per numero IP attraverso il relativo \textsl{nome a - dominio}. In realtà per DNS si intendono spesso i server che forniscono su -internet questo servizio, mentre nel nostro caso affronteremo la problematica -dal lato client, di un qualunque programma che necessita di compiere questa -operazione. +\itindbeg{resolver} La risoluzione dei nomi è associata tradizionalmente al +servizio del \itindex{Domain~Name~Service~(DNS)} \textit{Domain Name Service} +che permette di identificare le macchine su internet invece che per numero IP +attraverso il relativo \textsl{nome a dominio}.\footnote{non staremo ad + entrare nei dettagli della definizione di cosa è un nome a dominio, dandolo + per noto, una introduzione alla problematica si trova in \cite{AGL} (cap.~9) + mentre per una trattazione approfondita di tutte le problematiche relative + al DNS si può fare riferimento a \cite{DNSbind}.} In realtà per DNS si +intendono spesso i server che forniscono su internet questo servizio, mentre +nel nostro caso affronteremo la problematica dal lato client, di un qualunque +programma che necessita di compiere questa operazione. -\begin{figure}[htb] - \centering - \includegraphics[width=10cm]{img/resolver} - \caption{Schema di funzionamento delle routine del \textit{resolver}.} +\begin{figure}[!htb] + \centering \includegraphics[width=11cm]{img/resolver} + \caption{Schema di funzionamento delle funzioni del \textit{resolver}.} \label{fig:sock_resolver_schema} \end{figure} -Inoltre quella fra nomi a dominio e indirizzi IP non è l'unica corrispondenza +Inoltre quella fra nomi a dominio e indirizzi IP non è l'unica corrispondenza possibile fra nomi simbolici e valori numerici, come abbiamo visto anche in sez.~\ref{sec:sys_user_group} per le corrispondenze fra nomi di utenti e -gruppi e relativi identificatori numerici; per quanto riguarda però tutti i +gruppi e relativi identificatori numerici; per quanto riguarda però tutti i nomi associati a identificativi o servizi relativi alla rete il servizio di -risoluzione è gestito in maniera unificata da un insieme di routine fornite +risoluzione è gestito in maniera unificata da un insieme di funzioni fornite con le librerie del C, detto appunto \textit{resolver}. -Lo schema di funzionamento del \textit{resolver} è illustrato in +Lo schema di funzionamento del \textit{resolver} è illustrato in fig.~\ref{fig:sock_resolver_schema}; in sostanza i programmi hanno a disposizione un insieme di funzioni di libreria con cui chiamano il -\textit{resolver}, indicate con le freccie nere. Ricevuta la richiesta è +\textit{resolver}, indicate con le frecce nere. Ricevuta la richiesta è quest'ultimo che, sulla base della sua configurazione, esegue le operazioni necessarie a fornire la risposta, che possono essere la lettura delle informazioni mantenute nei relativi dei file statici presenti sulla macchina, una interrogazione ad un DNS (che a sua volta, per il funzionamento del -protocollo può interrogarene altri) o la richiesta ad altri server per i quali -sia fornito il supporto, come LDAP. +protocollo, può interrogarne altri) o la richiesta ad altri server per i quali +sia fornito il supporto, come LDAP.\footnote{la sigla LDAP fa riferimento ad + un protocollo, il \textit{Lightweight Directory Access Protocol}, che + prevede un meccanismo per la gestione di \textsl{elenchi} di informazioni + via rete; il contenuto di un elenco può essere assolutamente generico, e + questo permette il mantenimento dei più vari tipi di informazioni su una + infrastruttura di questo tipo.} -La configurazione del resolver attiene più alla amministrazione di sistema che -alla programmazione, ciò non di meno, prima di trattare le varie funzioni che -vale la pena farne una panoramica. Originariamente la configurazione +La configurazione del \textit{resolver} attiene più alla amministrazione di +sistema che alla programmazione, ciò non di meno, prima di trattare le varie +funzioni di librerie utilizzate dai programmi, vale la pena fare una +panoramica generale. Originariamente la configurazione del \textit{resolver} riguardava esclusivamente le questioni relative alla gestione dei nomi a dominio, e prevedeva solo l'utilizzo del DNS e del file statico -\file{/etc/hosts}. +\conffile{/etc/hosts}. -In questo caso il file di configurazione principale è \file{/etc/resolv.conf} -che contiene in sostanza l'elenco dei server DNS da contattare, a cui si -affianca il file \file{/etc/host.conf} il cui scopo principale è indicare +Per questo aspetto il file di configurazione principale del sistema è +\conffile{/etc/resolv.conf} che contiene in sostanza l'elenco degli indirizzi +IP dei server DNS da contattare; a questo si affiancava (fino alla \acr{glibc} +2.4) il file \conffile{/etc/host.conf} il cui scopo principale era indicare l'ordine in cui eseguire la risoluzione dei nomi (se usare prima i valori di -\file{/etc/hosts} o il DNS); tralasciamo i dettagli relativi alle varie -direttive che possono essere usate in questi file, che si trovano nelle -relative pagine di manuale. - -Con il tempo però è divenuto possibile fornire diversi sostituti per -l'utilizzo delle associazione statiche in \file{/etc/hosts}, inoltre oltre all -risoluzione dei nomi a dominio si sono aggiunti altri nomi da risolvere, come -quelli associati alle reti ed ai gruppi di macchine definiti dal servizio NIS, -o quelli dei protocolli e dei servizi mantenuti nei file statici -\file{/etc/protocols} e \file{/etc/services}, tutte informazioni che -normalmente non si trovano su un DNS, ma che in un ambiente distribuito -possono essere centralizzate su opportuni server (ad esempio su LDAP) in grado -di mantenerle. - -Questo ha portato alla creazione di un sistema di risoluzione più ampio, il -\textit{Name Service Switch} di cui il \textit{resolver} viene a costituire un -sottoinsieme. Questo sistema, che si applica anche alla risoluzioni fra nomi -di utenti e gruppi e relativi identificatori, permette di definire in maniera -generica (attraverso una serie di librerie dinamiche) sia i supporti su cui -mantenere i dati di corrispondenza fra nomi e valori numerici, sia l'ordine in -cui effettuare le ricerche sui vari supporti disponibili. Il sistema è -controllato dal file \file{/etc/nsswitch.conf}, ed anche per questo si può -fare riferimento alle pagine di manuale ed al relativo capitolo nel manuale -\cite{glibc} delle \textsl{glibc}. - -In ogni caso, qualunque sia la modalità con cui ricevono i dati o il supporto -su cui vengono mantenuti, dal punto di vista di un programma che deve -effettuare la risoluzione di un nome, tutto quello che conta sono le funzioni -che il \textit{resolver} mette a disposizione, e sono queste quelle che -tratteremo nelle sezioni successive. - - - -\subsection{La risoluzione dei nomi a dominio} -\label{sec:sock_gethostbyname} - -Dato che la principale funzionalità del \textit{resolver} resta quella di -risolvere i nomi a dominio in indirizzi IP, vedremo per prime le funzioni a -questo dedicate. La prima funzione è \funcd{gethostbyname} il cui scopo è -ottenere l'indirizzo di una stazione noto il suo nome a dominio, il suo -prototipo è: -\begin{prototype}{netdb.h} -{struct hostent *gethostbyname(const char *name)} - -Determina l'indirizzo associato al nome a dominio \param{name}. - -\bodydesc{La funzione restituisce in caso di successo il puntatore ad una - struttura di tipo \struct{hostent} contente i dati associati al nome a - dominio o un puntatore nullo in caso di errore.} -\end{prototype} +\conffile{/etc/hosts} o quelli del DNS). Tralasciamo i dettagli relativi alle +varie direttive che possono essere usate in questi file, che si trovano nelle +rispettive pagine di manuale. + +Con il tempo però è divenuto possibile fornire diversi sostituti per +l'utilizzo delle associazione statiche in \conffile{/etc/hosts}, inoltre oltre +alla risoluzione dei nomi a dominio ci sono anche altri nomi da risolvere, +come quelli che possono essere associati ad una rete (invece che ad una +singola macchina) o ai gruppi di macchine definiti dal servizio +NIS,\footnote{il \textit{Network Information Service} è un servizio, creato da + Sun, e poi diffuso su tutte le piattaforme unix-like, che permette di + raggruppare all'interno di una rete (in quelli che appunto vengono chiamati + \textit{netgroup}) varie macchine, centralizzando i servizi di definizione + di utenti e gruppi e di autenticazione, oggi è sempre più spesso sostituito + da LDAP.} o come quelli dei protocolli e dei servizi che sono mantenuti nei +file statici \conffile{/etc/protocols} e \conffile{/etc/services}. + +Molte di queste informazioni non si trovano su un DNS, ma in una rete locale +può essere molto utile centralizzare il mantenimento di alcune di esse su +opportuni server. Inoltre l'uso di diversi supporti possibili per le stesse +informazioni (ad esempio il nome delle macchine può essere mantenuto sia +tramite \conffile{/etc/hosts}, che con il DNS, che con NIS) comporta il +problema dell'ordine in cui questi vengono interrogati. Con le implementazioni +classiche i vari supporti erano introdotti modificando direttamente le +funzioni di libreria, prevedendo un ordine di interrogazione predefinito e non +modificabile (a meno di una ricompilazione delle librerie stesse). + +\itindbeg{Name~Service~Switch~(NSS)} + +Per risolvere questa serie di problemi la risoluzione dei nomi a dominio +eseguità dal \textit{resolver} è stata inclusa all'interno di un meccanismo +generico per la risoluzione di corrispondenze fra nomi ed informazioni ad essi +associate chiamato \textit{Name Service Switch}, cui abbiamo accennato anche in +sez.~\ref{sec:sys_user_group} per quanto riguarda la gestione dei dati +associati a utenti e gruppi. Il sistema è stato introdotto la prima volta +nella libreria standard di Solaris e la \acr{glibc} ha ripreso lo stesso +schema; si tenga presente che questo sistema non esiste per altre librerie +standard come la \acr{libc5} o la \acr{uClib}. + +Il \textit{Name Service Switch} (cui spesso si fa riferimento con l'acronimo +NSS) è un sistema di librerie dinamiche che permette di definire in maniera +generica sia i supporti su cui mantenere i dati di corrispondenza fra nomi e +valori numerici, sia l'ordine in cui effettuare le ricerche sui vari supporti +disponibili. Il sistema prevede una serie di possibili classi di +corrispondenza, quelle attualmente definite sono riportate in +tab.~\ref{tab:sys_NSS_classes}. + +\begin{table}[htb] + \footnotesize + \centering + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Classe} & \textbf{Tipo di corrispondenza}\\ + \hline + \hline + \texttt{passwd} & Corrispondenze fra nome dell'utente e relative + proprietà (\ids{UID}, gruppo principale, ecc.).\\ + \texttt{shadow} & Corrispondenze fra username e password dell'utente + (e altre informazioni relative alle password).\\ + \texttt{group} & Corrispondenze fra nome del gruppo e proprietà dello + stesso.\\ + \texttt{aliases} & Alias per la posta elettronica.\\ + \texttt{ethers} & Corrispondenze fra numero IP e MAC address della + scheda di rete.\\ + \texttt{hosts} & Corrispondenze fra nome a dominio e numero IP.\\ + \texttt{netgroup} & Corrispondenze fra gruppo di rete e macchine che lo + compongono.\\ + \texttt{networks} & Corrispondenze fra nome di una rete e suo indirizzo + IP.\\ + \texttt{protocols}& Corrispondenze fra nome di un protocollo e relativo + numero identificativo.\\ + \texttt{rpc} & Corrispondenze fra nome di un servizio RPC e relativo + numero identificativo.\\ + \texttt{publickey}& Chiavi pubbliche e private usate per gli RFC sicuri, + utilizzate da NFS e NIS+. \\ + \texttt{services} & Corrispondenze fra nome di un servizio e numero di + porta. \\ + \hline + \end{tabular} + \caption{Le diverse classi di corrispondenze definite + all'interno del \textit{Name Service Switch}.} + \label{tab:sys_NSS_classes} +\end{table} + +% TODO rivedere meglio la tabella + +Il sistema del \textit{Name Service Switch} è controllato dal contenuto del +file \conffile{/etc/nsswitch.conf}; questo contiene una riga di configurazione +per ciascuna di queste classi, che viene inizia col nome di +tab.~\ref{tab:sys_NSS_classes} seguito da un carattere ``\texttt{:}'' e +prosegue con la lista dei \textsl{servizi} su cui le relative informazioni +sono raggiungibili, scritti nell'ordine in cui si vuole siano interrogati. +Pertanto nelle versioni recenti delle librerie è questo file e non +\conffile{/etc/host.conf} a indicare l'ordine con cui si esegue la +risoluzione dei nomi. + +Ogni servizio è specificato a sua volta da un nome, come \texttt{file}, +\texttt{dns}, \texttt{db}, ecc. che identifica la libreria dinamica che +realizza l'interfaccia con esso. Per ciascun servizio se \texttt{NAME} è il +nome utilizzato dentro \conffile{/etc/nsswitch.conf}, dovrà essere presente +(usualmente in \file{/lib}) una libreria \texttt{libnss\_NAME} che ne +implementa le funzioni. + +In ogni caso, qualunque sia la modalità con cui ricevono i dati o il supporto +su cui vengono mantenuti, e che si usino o meno funzionalità aggiuntive +fornite dal sistema del \textit{Name Service Switch}, dal punto di vista di un +programma che deve effettuare la risoluzione di un nome a dominio, tutto +quello che conta sono le funzioni classiche che il \textit{resolver} mette a +disposizione (è cura della \acr{glibc} tenere conto della presenza del +\textit{Name Service Switch}) e sono queste quelle che tratteremo nelle +sezioni successive. + +\itindend{Name~Service~Switch~(NSS)} + + +\subsection{Le funzioni di interrogazione del DNS} +\label{sec:sock_resolver_functions} + +Prima di trattare le funzioni usate normalmente nella risoluzione dei nomi a +dominio conviene trattare in maniera più dettagliata il servizio DNS. Come +accennato questo, benché esso in teoria sia solo uno dei possibili supporti su +cui mantenere le informazioni, in pratica costituisce il meccanismo principale +con cui vengono risolti i nomi a dominio. Inolte esso può fornire anche +ulteriori informazioni oltre relative alla risoluzione dei nomi a dominio. +Per questo motivo esistono una serie di funzioni di libreria che servono +specificamente ad eseguire delle interrogazioni verso un server DNS, funzioni +che poi vengono utilizzate anche per realizzare le funzioni generiche di +libreria usate dal sistema del \textit{resolver}. + +Il sistema del DNS è in sostanza di un database distribuito organizzato in +maniera gerarchica, i dati vengono mantenuti in tanti server distinti ciascuno +dei quali si occupa della risoluzione del proprio \textsl{dominio}; i nomi a +dominio sono organizzati in una struttura ad albero analoga a quella +dell'albero dei file, con domini di primo livello (come i \texttt{.org}), +secondo livello (come \texttt{.truelite.it}), ecc. In questo caso le +separazioni sono fra i vari livelli sono definite dal carattere ``\texttt{.}'' +ed i nomi devono essere risolti da destra verso sinistra.\footnote{per chi si + stia chiedendo quale sia la radice di questo albero, cioè l'equivalente di + ``\texttt{/}'', la risposta è il dominio speciale ``\texttt{.}'', che in + genere non viene mai scritto esplicitamente, ma che, come chiunque abbia + configurato un server DNS sa bene, esiste ed è gestito dai cosiddetti + \textit{root DNS} che risolvono i domini di primo livello.} Il meccanismo +funziona con il criterio della \textsl{delegazione}, un server responsabile +per un dominio di primo livello può delegare la risoluzione degli indirizzi +per un suo dominio di secondo livello ad un altro server, il quale a sua volta +potrà delegare la risoluzione di un eventuale sotto-dominio di terzo livello ad +un altro server ancora. + +Come accennato un server DNS è in grado di fare molto altro rispetto alla +risoluzione di un nome a dominio in un indirizzo IP: ciascuna voce nel +database viene chiamata \textit{resource record}, e può contenere diverse +informazioni. In genere i \textit{resource record} vengono classificati per la +\textsl{classe di indirizzi} cui i dati contenuti fanno riferimento, e per il +\textsl{tipo} di questi ultimi (ritroveremo classi di indirizzi e tipi di +record più avanti in tab.~\ref{tab:DNS_address_class} e +tab.~\ref{tab:DNS_record_type}). Oggigiorno i dati mantenuti nei server DNS +sono quasi esclusivamente relativi ad indirizzi internet, per cui in pratica +viene utilizzata soltanto una classe di indirizzi; invece le corrispondenze +fra un nome a dominio ed un indirizzo IP sono solo uno fra i vari tipi di +informazione che un server DNS fornisce normalmente. + +L'esistenza di vari tipi di informazioni è un altro dei motivi per cui il +\textit{resolver} prevede, oltre a quelle relative alla semplice risoluzione +dei nomi, un insieme di funzioni specifiche dedicate all'interrogazione di un +server DNS, tutte nella forma \texttt{res\_}\textsl{\texttt{nome}}. La prima +di queste funzioni è \funcd{res\_init}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{netinet/in.h} +\fhead{arpa/nameser.h} +\fhead{resolv.h} +\fdecl{int res\_init(void)} +\fdesc{Inizializza il sistema del \textit{resolver}.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore. +} +\end{funcproto} + +La funzione legge il contenuto dei file di configurazione per impostare il +dominio di default, gli indirizzi dei server DNS da contattare e l'ordine +delle ricerche; se non sono specificati server verrà utilizzato l'indirizzo +locale, e se non è definito un dominio di default sarà usato quello associato +con l'indirizzo locale (ma questo può essere sovrascritto con l'uso della +variabile di ambiente \envvar{LOCALDOMAIN}). In genere non è necessario +eseguire questa funzione esplicitamente, in quanto viene automaticamente +chiamata la prima volta che si esegue una qualunque delle altre. + +Le impostazioni e lo stato del \textit{resolver} inizializzati da +\func{res\_init} vengono mantenuti in una serie di variabili raggruppate nei +campi di una apposita struttura. Questa struttura viene definita in +\headfiled{resolv.h} e mantenuta nella variabile globale \var{\_res}, che +viene utilizzata internamente da tutte le funzioni dell'interfaccia. Questo +consente anche di accedere direttamente al contenuto della variabile +all'interno di un qualunque programma, una volta che la sia opportunamente +dichiarata con: +\includecodesnip{listati/resolv_option.c} + +Dato che l'uso di una variabile globale rende tutte le funzioni +dell'interfaccia classica non rientranti, queste sono state deprecate in +favore di una nuova interfaccia in cui esse sono state sostituite da +altrettante nuove funzioni, il cui nome è ottenuto apponendo una +``\texttt{n}'' al nome di quella tradizionale (cioè nella forma +\texttt{res\_n\textsl{nome}}). Tutte le nuove funzioni sono identiche alle +precedenti, ma hanno un primo argomento aggiuntivo, \param{statep}, puntatore +ad una struttura dello stesso tipo di \var{\_res}. Questo consente di usare +una variabile locale per mantenere lo stato del \textit{resolver}, rendendo le +nuove funzioni rientranti. In questo caso per poter utilizzare il nuovo +argomento occorrerà una opportuna dichiarazione del relativo tipo di dato con: +\includecodesnip{listati/resolv_newoption.c} + +Così la nuova funzione utilizzata per inizializzare il \textit{resolver} (che +come la precedente viene chiamata automaticamente da tutte altre funzioni) è +\funcd{res\_ninit}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{netinet/in.h} +\fhead{arpa/nameser.h} +\fhead{resolv.h} +\fdecl{int res\_ninit(res\_state statep)} +\fdesc{Inizializza il sistema del \textit{resolver}.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore. +} +\end{funcproto} + +Indipendentemente da quale versione delle funzioni si usino, tutti i campi +della struttura (\var{\_res} o la variabile puntata da \param{statep}) sono ad +uso interno, e vengono usualmente inizializzate da \func{res\_init} o +\func{res\_ninit} in base al contenuto dei file di configurazione e ad una +serie di valori di default. L'unico campo che può essere utile modificare è +\var{\_res.options} (o l'equivalente della variabile puntata +da\param{statep}), una maschera binaria che contiene una serie di bit che +esprimono le opzioni che permettono di controllare il comportamento del +\textit{resolver}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \constd{RES\_INIT} & Viene attivato se è stata chiamata + \func{res\_init}. \\ + \constd{RES\_DEBUG} & Stampa dei messaggi di debug.\\ + \constd{RES\_AAONLY} & Accetta solo risposte autoritative.\\ + \constd{RES\_USEVC} & Usa connessioni TCP per contattare i server + invece che l'usuale UDP.\\ + \constd{RES\_PRIMARY} & Interroga soltanto server DNS primari.\\ + \constd{RES\_IGNTC} & Ignora gli errori di troncamento, non ritenta la + richiesta con una connessione TCP.\\ + \constd{RES\_RECURSE} & Imposta il bit che indica che si desidera + eseguire una interrogazione ricorsiva.\\ + \constd{RES\_DEFNAMES} & Se attivo \func{res\_search} aggiunge il nome + del dominio di default ai nomi singoli (che non + contengono cioè un ``\texttt{.}'').\\ + \constd{RES\_STAYOPEN} & Usato con \const{RES\_USEVC} per mantenere + aperte le connessioni TCP fra interrogazioni + diverse.\\ + \constd{RES\_DNSRCH} & Se attivo \func{res\_search} esegue le ricerche + di nomi di macchine nel dominio corrente o nei + domini ad esso sovrastanti.\\ + \constd{RES\_INSECURE1} & Blocca i controlli di sicurezza di tipo 1.\\ + \constd{RES\_INSECURE2} & Blocca i controlli di sicurezza di tipo 2.\\ + \constd{RES\_NOALIASES} & Blocca l'uso della variabile di ambiente + \envvar{HOSTALIASES}.\\ + \constd{RES\_USE\_INET6} & Restituisce indirizzi IPv6 con + \func{gethostbyname}. \\ + \constd{RES\_ROTATE} & Ruota la lista dei server DNS dopo ogni + interrogazione.\\ + \constd{RES\_NOCHECKNAME}& Non controlla i nomi per verificarne la + correttezza sintattica. \\ + \constd{RES\_KEEPTSIG} & Non elimina i record di tipo \texttt{TSIG}.\\ + \constd{RES\_BLAST} & Effettua un ``\textit{blast}'' inviando + simultaneamente le richieste a tutti i server; + non ancora implementata. \\ + \constd{RES\_DEFAULT} & Combinazione di \const{RES\_RECURSE}, + \const{RES\_DEFNAMES} e \const{RES\_DNSRCH}.\\ + \hline + \end{tabular} + \caption{Costanti utilizzabili come valori per \var{\_res.options}.} + \label{tab:resolver_option} +\end{table} + +Per utilizzare questa funzionalità per modificare le impostazioni direttamente +da programma occorrerà impostare un opportuno valore per questo campo ed +invocare esplicitamente \func{res\_init} o \func{res\_ninit}, dopo di che le +altre funzioni prenderanno le nuove impostazioni. Le costanti che definiscono +i vari bit di questo campo, ed il relativo significato sono illustrate in +tab.~\ref{tab:resolver_option}; trattandosi di una maschera binaria un valore +deve essere espresso con un opportuno OR aritmetico di dette costanti; ad +esempio il valore di default delle opzioni, espresso dalla costante +\const{RES\_DEFAULT}, è definito come: +\includecodesnip{listati/resolv_option_def.c} + +Non tratteremo il significato degli altri campi non essendovi necessità di +modificarli direttamente; gran parte di essi sono infatti impostati dal +contenuto dei file di configurazione, mentre le funzionalità controllate da +alcuni di esse possono essere modificate con l'uso delle opportune variabili +di ambiente come abbiamo visto per \envvar{LOCALDOMAIN}. In particolare con +\envvar{RES\_RETRY} si soprassiede il valore del campo \var{retry} che +controlla quante volte viene ripetuto il tentativo di connettersi ad un server +DNS prima di dichiarare fallimento; il valore di default è 4, un valore nullo +significa bloccare l'uso del DNS. Infine con \envvar{RES\_TIMEOUT} si +soprassiede il valore del campo \var{retrans} (preimpostato al valore della +omonima costante \const{RES\_TIMEOUT} di \headfile{resolv.h}) che è il valore +preso come base (in numero di secondi) per definire la scadenza di una +richiesta, ciascun tentativo di richiesta fallito viene ripetuto raddoppiando +il tempo di scadenza per il numero massimo di volte stabilito da +\texttt{RES\_RETRY}. + +La funzione di interrogazione principale è \funcd{res\_query} +(\funcd{res\_nquery} per la nuova interfaccia), che serve ad eseguire una +richiesta ad un server DNS per un nome a dominio \textsl{completamente + specificato} (quello che si chiama +\itindex{Fully~Qualified~Domain~Name~(FQDN)} FQDN, \textit{Fully Qualified + Domain Name}); il loro prototipo è: + +\begin{funcproto}{ +\fhead{netinet/in.h} +\fhead{arpa/nameser.h} +\fhead{resolv.h} +\fdecl{int res\_query(const char *dname, int class, int type, + unsigned char *answer, int anslen)} +\fdecl{int res\_nquery(res\_state statep, const char *dname, int class, int + type, \\ + \phantom{int res\_nquery(}unsigned char *answer, int anslen)} +\fdesc{Esegue una interrogazione al DNS.} +} +{Le funzioni ritornano un valore positivo pari alla lunghezza dei dati scritti + nel buffer \param{answer} in caso di successo e $-1$ per un errore. +} +\end{funcproto} + +Le funzioni eseguono una interrogazione ad un server DNS relativa al nome da +risolvere passato nella stringa indirizzata da \param{dname}, inoltre deve +essere specificata la classe di indirizzi in cui eseguire la ricerca con +\param{class}, ed il tipo di \textit{resource record} che si vuole ottenere +con \param{type}. Il risultato della ricerca verrà scritto nel buffer di +lunghezza \param{anslen} puntato da \param{answer} che si sarà opportunamente +allocato in precedenza. + +Una seconda funzione di ricerca analoga a \func{res\_query}, che prende gli +stessi argomenti ma che esegue l'interrogazione con le funzionalità +addizionali previste dalle due opzioni \const{RES\_DEFNAMES} e +\const{RES\_DNSRCH}, è \funcd{res\_search} (\funcd{res\_nsearch} per la nuova +interfaccia), il cui prototipo è: + +\begin{funcproto}{ +\fhead{netinet/in.h} +\fhead{arpa/nameser.h} +\fhead{resolv.h} +\fdecl{int res\_search(const char *dname, int class, int type, + unsigned char *answer, \\ + \phantom{int res\_search}int anslen)} +\fdecl{int res\_nsearch(res\_state statep, const char *dname, int class, + int type, \\ + \phantom{int res\_nsearch(}unsigned char *answer, int anslen)} +\fdesc{Esegue una interrogazione al DNS.} +} +{Le funzioni ritornano un valore positivo pari alla lunghezza dei dati scritti + nel buffer \param{answer} in caso di successo e $-1$ per un errore. +} +\end{funcproto} + +In sostanza la funzione ripete una serie di chiamate a \func{res\_query} +(\func{res\_nquery}) aggiungendo al nome contenuto nella stringa \param{dname} +il dominio di default da cercare, fermandosi non appena trova un risultato. +Il risultato di entrambe le funzioni viene scritto nel formato opportuno (che +sarà diverso a seconda del tipo di record richiesto) nel buffer di ritorno; +sarà compito del programma (o di altre funzioni) estrarre i relativi dati, +esistono una serie di funzioni interne usate per la scansione di questi dati, +per chi fosse interessato una trattazione dettagliata è riportata nel +quattordicesimo capitolo di \cite{DNSbind}. + +Le classi di indirizzi supportate da un server DNS sono tre, ma di queste in +pratica oggi viene utilizzata soltanto quella degli indirizzi internet; le +costanti che identificano dette classi, da usare come valore per l'argomento +\param{class} delle precedenti funzioni, sono riportate in +tab.~\ref{tab:DNS_address_class} (esisteva in realtà anche una classe +\constd{C\_CSNET} per la omonima rete, ma è stata dichiarata obsoleta). + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \constd{C\_IN} & Indirizzi internet, in pratica i soli utilizzati oggi.\\ + \constd{C\_HS} & Indirizzi \textit{Hesiod}, utilizzati solo al MIT, oggi + completamente estinti. \\ + \constd{C\_CHAOS}& Indirizzi per la rete \textit{Chaosnet}, un'altra rete + sperimentale nata al MIT. \\ + \constd{C\_ANY} & Indica un indirizzo di classe qualunque.\\ + \hline + \end{tabular} + \caption{Costanti identificative delle classi di indirizzi per l'argomento + \param{class} di \func{res\_query}.} + \label{tab:DNS_address_class} +\end{table} + +Come accennato le tipologie di dati che sono mantenibili su un server DNS sono +diverse, ed a ciascuna di essa corrisponde un diverso tipo di \textit{resource + record}. L'elenco delle costanti, ripreso dai file di dichiarazione +\headfiled{arpa/nameser.h} e \headfiled{arpa/nameser\_compat.h}, che +definiscono i valori che si possono usare per l'argomento \param{type} per +specificare il tipo di \textit{resource record} da richiedere è riportato in +tab.~\ref{tab:DNS_record_type}; le costanti (tolto il \texttt{T\_} iniziale) +hanno gli stessi nomi usati per identificare i record nei file di zona di +BIND,\footnote{BIND, acronimo di \textit{Berkley Internet Name Domain}, è una + implementazione di un server DNS, ed, essendo utilizzata nella stragrande + maggioranza dei casi, fa da riferimento; i dati relativi ad un certo dominio + (cioè i suoi \textit{resource record} vengono mantenuti in quelli che sono + usualmente chiamati \textsl{file di zona}, e in essi ciascun tipo di dominio + è identificato da un nome che è appunto identico a quello delle costanti di + tab.~\ref{tab:DNS_record_type} senza il \texttt{T\_} iniziale.} e che +normalmente sono anche usati come nomi per indicare i record. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \constd{T\_A} & Indirizzo di una stazione.\\ + \constd{T\_NS} & Server DNS autoritativo per il dominio richiesto.\\ + \constd{T\_MD} & Destinazione per la posta elettronica.\\ + \constd{T\_MF} & Redistributore per la posta elettronica.\\ + \constd{T\_CNAME} & Nome canonico.\\ + \constd{T\_SOA} & Inizio di una zona di autorità.\\ + \constd{T\_MB} & Nome a dominio di una casella di posta.\\ + \constd{T\_MG} & Nome di un membro di un gruppo di posta.\\ + \constd{T\_MR} & Nome di un cambiamento di nome per la posta.\\ + \constd{T\_NULL} & Record nullo.\\ + \constd{T\_WKS} & Servizio noto.\\ + \constd{T\_PTR} & Risoluzione inversa di un indirizzo numerico.\\ + \constd{T\_HINFO} & Informazione sulla stazione.\\ + \constd{T\_MINFO} & Informazione sulla casella di posta.\\ + \constd{T\_MX} & Server cui instradare la posta per il dominio.\\ + \constd{T\_TXT} & Stringhe di testo (libere).\\ + \constd{T\_RP} & Nome di un responsabile (\textit{responsible person}).\\ + \constd{T\_AFSDB} & Database per una cella AFS.\\ + \constd{T\_X25} & Indirizzo di chiamata per X.25.\\ + \constd{T\_ISDN} & Indirizzo di chiamata per ISDN.\\ + \constd{T\_RT} & Router.\\ + \constd{T\_NSAP} & Indirizzo NSAP.\\ + \constd{T\_NSAP\_PTR}& Risoluzione inversa per NSAP (deprecato).\\ + \constd{T\_SIG} & Firma digitale di sicurezza.\\ + \constd{T\_KEY} & Chiave per firma.\\ + \constd{T\_PX} & Corrispondenza per la posta X.400.\\ + \constd{T\_GPOS} & Posizione geografica.\\ + \constd{T\_AAAA} & Indirizzo IPv6.\\ + \constd{T\_LOC} & Informazione di collocazione.\\ + \constd{T\_NXT} & Dominio successivo.\\ + \constd{T\_EID} & Identificatore di punto conclusivo.\\ + \constd{T\_NIMLOC}& Posizionatore \textit{nimrod}.\\ + \constd{T\_SRV} & Servizio.\\ + \constd{T\_ATMA} & Indirizzo ATM.\\ + \constd{T\_NAPTR} & Puntatore ad una \textit{naming authority}.\\ + \constd{T\_TSIG} & Firma di transazione.\\ + \constd{T\_IXFR} & Trasferimento di zona incrementale.\\ + \constd{T\_AXFR} & Trasferimento di zona di autorità.\\ + \constd{T\_MAILB} & Trasferimento di record di caselle di posta.\\ + \constd{T\_MAILA} & Trasferimento di record di server di posta.\\ + \constd{T\_ANY} & Valore generico.\\ + \hline + \end{tabular} + \caption{Costanti identificative del tipo di record per l'argomento + \param{type} di \func{res\_query}.} + \label{tab:DNS_record_type} +\end{table} + + +L'elenco di tab.~\ref{tab:DNS_record_type} è quello di \textsl{tutti} i +\textit{resource record} definiti, con una breve descrizione del relativo +significato. Di tutti questi però viene impiegato correntemente solo un +piccolo sottoinsieme, alcuni sono obsoleti ed altri fanno riferimento a dati +applicativi che non ci interessano non avendo nulla a che fare con la +risoluzione degli indirizzi IP, pertanto non entreremo nei dettagli del +significato di tutti i \textit{resource record}, ma solo di quelli usati dalle +funzioni del \textit{resolver}. Questi sono sostanzialmente i seguenti (per +indicarli si è usata la notazione dei file di zona di BIND): +\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}} +\item[\texttt{A}] viene usato per indicare la corrispondenza fra un nome a + dominio ed un indirizzo IPv4; ad esempio la corrispondenza fra + \texttt{jojo.truelite.it} e l'indirizzo IP \texttt{62.48.34.25}. +\item[\texttt{AAAA}] viene usato per indicare la corrispondenza fra un nome a + dominio ed un indirizzo IPv6; è chiamato in questo modo dato che la + dimensione di un indirizzo IPv6 è quattro volte quella di un indirizzo IPv4. +\item[\texttt{PTR}] per fornire la corrispondenza inversa fra un indirizzo IP + ed un nome a dominio ad esso associato si utilizza questo tipo di record (il + cui nome sta per \textit{pointer}). +\item[\texttt{CNAME}] qualora si abbiamo più nomi che corrispondono allo + stesso indirizzo (come ad esempio \texttt{www.truelite.it} e + \texttt{sources.truelite.it}, che fanno entrambi riferimento alla stessa + macchina (nel caso \texttt{dodds.truelite.it}) si può usare questo tipo di + record per creare degli \textit{alias} in modo da associare un qualunque + altro nome al \textsl{nome canonico} della macchina (si chiama così quello + associato al record \texttt{A}). +\end{basedescript} + +Come accennato in caso di successo le due funzioni di richiesta restituiscono +il risultato della interrogazione al server, in caso di insuccesso l'errore +invece viene segnalato da un valore di ritorno pari a $-1$, ma in questo caso, +non può essere utilizzata la variabile \var{errno} per riportare un codice di +errore, in quanto questo viene impostato per ciascuna delle chiamate al +sistema utilizzate dalle funzioni del \textit{resolver}, non avrà alcun +significato nell'indicare quale parte del procedimento di risoluzione è +fallita. + +Per questo motivo è stata definita una variabile di errore separata, +\var{h\_errno}, che viene utilizzata dalle funzioni del \textit{resolver} per +indicare quale problema ha causato il fallimento della risoluzione del nome. +Ad essa si può accedere una volta che la si dichiara con: +\includecodesnip{listati/herrno.c} +ed i valori che può assumere, con il relativo significato, sono riportati in +tab.~\ref{tab:h_errno_values}. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{9cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \constd{HOST\_NOT\_FOUND}& L'indirizzo richiesto non è valido e la + macchina indicata è sconosciuta.\\ + \constd{NO\_ADDRESS} & Il nome a dominio richiesto è valido, ma non ha + un indirizzo associato ad esso + (alternativamente può essere indicato come + \constd{NO\_DATA}).\\ + \constd{NO\_RECOVERY} & Si è avuto un errore non recuperabile + nell'interrogazione di un server DNS.\\ + \constd{TRY\_AGAIN} & Si è avuto un errore temporaneo + nell'interrogazione di un server DNS, si può + ritentare l'interrogazione in un secondo + tempo.\\ + \hline + \end{tabular} + \caption{Valori possibili della variabile \var{h\_errno}.} + \label{tab:h_errno_values} +\end{table} + +Insieme alla nuova variabile vengono definite anche delle nuove funzioni per +stampare l'errore a video, analoghe a quelle di sez.~\ref{sec:sys_strerror} +per \var{errno}, ma che usano il valore di \var{h\_errno}; la prima è +\funcd{herror} ed il suo prototipo è: + +{\centering +\vspace{3pt} +\begin{funcbox}{ +\fhead{netdb.h} +\fdecl{void herror(const char *string)} +\fdesc{Stampa un errore di risoluzione.} +} +\end{funcbox}} + +La funzione è l'analoga di \func{perror} e stampa sullo \textit{standard error} un +messaggio di errore corrispondente al valore corrente di \var{h\_errno}, a cui +viene anteposta la stringa \param{string} passata come argomento. La seconda +funzione è \funcd{hstrerror} ed il suo prototipo è: + +{\centering +\vspace{3pt} +\begin{funcbox}{ +\fhead{netdb.h} +\fdecl{const char *hstrerror(int err)} +\fdesc{Restituisce una stringa corrispondente ad un errore di risoluzione.} +} +\end{funcbox}} + +\noindent che, come l'analoga \func{strerror}, restituisce una stringa con un +messaggio di errore già formattato, corrispondente al codice passato come +argomento (che si presume sia dato da \var{h\_errno}). + +\itindend{resolver} + + +\subsection{La vecchia interfaccia per la risoluzione dei nomi a dominio} +\label{sec:sock_name_services} + +La principale funzionalità del \textit{resolver} resta quella di risolvere i +nomi a dominio in indirizzi IP, per cui non ci dedicheremo oltre alle funzioni +per effetture delle richieste generiche al DNS ed esamineremo invece le +funzioni del \textit{resolver} dedicate specificamente a questo. Tratteremo in +questa sezione l'interfaccia tradizionale, che ormai è deprecata, mentre +vedremo nella sezione seguente la nuova interfaccia. + +La prima funzione dell'interfaccia tradizionale è \funcd{gethostbyname} il cui +scopo è ottenere l'indirizzo di una stazione noto il suo nome a dominio, il +suo prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{struct hostent *gethostbyname(const char *name)} +\fdesc{Determina l'indirizzo associato ad un nome a dominio.} +} + +{La funzione ritorna il puntatore ad una + struttura di tipo \struct{hostent} contenente i dati associati al nome a + dominio in caso di successo o un puntatore nullo per un errore.} +\end{funcproto} La funzione prende come argomento una stringa \param{name} contenente il nome a dominio che si vuole risolvere, in caso di successo i dati ad esso relativi vengono memorizzati in una opportuna struttura \struct{hostent} la cui -definizione è riportata in fig.~\ref{fig:sock_hostent_struct}. In caso di -insuccesso l'errore viene segnalato da un valore nullo del puntatore, ma in -questo caso, a differenza delle funzioni viste finora, non viene utilizzata la -variabile \var{errno} per riportare un codice di errore, in quanto questo è -dipende solo dalle sottostanti chiamate al sistema e non avere nessun -significato nell'indicare quale parte del procedimento di risoluzione è -fallita. +definizione è riportata in fig.~\ref{fig:sock_hostent_struct}. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{15cm} + \begin{minipage}[c]{0.80\textwidth} \includestruct{listati/hostent.h} \end{minipage} - \caption{La struttura \structd{hostent} .} + \caption{La struttura \structd{hostent} per la risoluzione dei nomi a + dominio e degli indirizzi IP.} \label{fig:sock_hostent_struct} \end{figure} -Per questo motivo all'interno del resolver è stata definita una apposita -variabile di errore, \var{h\_errno} che viene utilizzata dalle funzioni di -libreria per indicare quale problema ha causato il fallimento della -risoluzione. Ad essa si può accedere una volta che la si dichiara con: -\includecodesnip{listati/herrno.c} -ed i valori che può assumere sono i seguenti: -\begin{basedescript}{\desclabelwidth{3cm}\desclabelstyle{\nextlinelabel}} -\item[\const{HOST\_NOT\_FOUND}] l'indirizzo richiesto non è valido e la - macchina indicata è sconosciuta. -\item[\const{NO\_ADDRESS}] il nome a dominio richiesto è valido, ma non ha un - indirizzo associato ad esso. -\item[\const{NO\_RECOVERY}] si è avuto un errore non recuperabile - nell'interrogazione di un server DNS. -\item[\const{TRY\_AGAIN}] si è avuto un errore temporaneo nell'interrogazione - di un server DNS, si può ritentare l'interrogazione in un secondo tempo. -\end{basedescript} +Quando un programma chiama \func{gethostbyname} e questa usa il DNS per +effettuare la risoluzione del nome, è con i valori contenuti nei relativi +record che vengono riempite le varie parti della struttura \struct{hostent}. +Il primo campo della struttura, \var{h\_name} contiene sempre il \textsl{nome + canonico}, che nel caso del DNS è appunto il nome associato ad un record +\texttt{A}. Il secondo campo della struttura, \var{h\_aliases}, invece è un +puntatore ad vettore di puntatori, terminato da un puntatore nullo. Ciascun +puntatore del vettore punta ad una stringa contenente uno degli altri +possibili nomi associati allo stesso \textsl{nome canonico} (quelli che nel +DNS vengono inseriti come record di tipo \texttt{CNAME}). +Il terzo campo della struttura, \var{h\_addrtype}, indica il tipo di indirizzo +che è stato restituito, e può assumere soltanto i valori \const{AF\_INET} o +\const{AF\_INET6}, mentre il quarto campo, \var{h\_length}, indica la +lunghezza dell'indirizzo stesso in byte. -Per capire meglio il contenuto della struttura \struct{hostent} conviene -spendere alcune parole sul funzionamento del DNS. Questo in sostanza è un -database distribuito organizzato in maniera gerarchica, interrogando il quale -si possono avere una serie di informazioni la principale delle quali è la -corrispondenza fra un nome (a dominio) ed indirizzo IP. Un server DNS -contiene comunque una serie di altre informazioni; ciascuna voce nel database -viene chiamata \textit{resource record} e vi è associato un certo -\textsl{tipo}, identificato da una sigla. Per quanto ci interessa i tipi di -\textit{resource record} che vengono utilizzati dal \textit{resolver} sono -sostanzialmente i seguenti: -\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}} -\item[\texttt{A}] indica la corripondenza fra un nome a dominio ed un - indirizzo IPv4, ad esempio la corrispondenza fra \texttt{dodds.truelite.it} - e l'indirizzo IP \texttt{62.48.34.25}. -\item[\texttt{AAAA}] chiamato in questo modo dato che la dimensione è quattro - volte quella di un indirizzo IPv4, questo record contiene la corrispondenza - fra un nome a dominio ed un indirizzo IPv6. -\item[\texttt{PTR}] per provvedere la mappatura inversa fra un indirizzo IP ed - un nome a dominio si utilizza invece questo tipo di record (il cui nome sta - per \textit{pointer}). -\item[\texttt{CNAME}] qualora si abbiamo più nomi con i quali si voglia - indicare lo stesso indirizzo (ad esempio \texttt{www.truelite.it}, o - \texttt{sources.truelite.it}, che comunque fanno sempre riferimento alla - macchina \texttt{dodds.truelite.it}) si può usare questo tipo di record per - creare degli \textit{alias} in modo da associare un qualunque altro nome al - \textsl{nome canonico} della macchina (quello associato al record - \texttt{A}). -\end{basedescript} +Infine il campo \var{h\_addr\_list} è il puntatore ad un vettore di puntatori +ai singoli indirizzi; il vettore è terminato da un puntatore nullo. Inoltre, +come illustrato in fig.~\ref{fig:sock_hostent_struct}, viene definito il campo +\var{h\_addr} come sinonimo di \code{h\_addr\_list[0]}, cioè un riferimento +diretto al primo indirizzo della lista. -Quando un programma chiama \func{gethostbyname} e questa usa il DNS per -effettuare la risoluzione del nome, è con i valori di questi record che -vengono riempite le varie parti della struttura \struct{hostent}. Il primo -campo della struttura, \var{h\_name} contiene sempre il \textsl{nome - canonico}, che nel caso del DNS è appunto il nome associato ad un record -\texttt{A}. Il secondo campo della struttura invece è un puntatore ad vettore -di puntatori, terminato da un puntatore nullo. Ciascun puntatore del vettore -fa riferimento ad una delle stringhe che contengono tutti i possibili altri -nomi associati allo stesso indirzzo (quelli che nel DNS sarebbero record -\texttt{CNAME}). +Oltre ai normali nomi a dominio la funzione accetta come argomento +\param{name} anche indirizzi numerici, in formato dotted decimal per IPv4 o +con la notazione illustrata in sez.~\ref{sec:IP_ipv6_notation} per IPv6. In +tal caso \func{gethostbyname} non eseguirà nessuna interrogazione remota, ma +si limiterà a copiare la stringa nel campo \var{h\_name} ed a creare la +corrispondente struttura \var{in\_addr} da indirizzare con +\code{h\_addr\_list[0]}. + +Con l'uso di \func{gethostbyname} si ottengono solo gli indirizzi IPv4, se si +vogliono ottenere degli indirizzi IPv6 occorrerà prima impostare l'opzione +\const{RES\_USE\_INET6} nel campo \texttt{\_res.options} e poi chiamare +\func{res\_init} (vedi sez.~\ref{sec:sock_resolver_functions}) per modificare +le opzioni del \textit{resolver}; dato che questo non è molto comodo è stata +definita (è una estensione fornita dalla \acr{glibc}, disponibile anche in +altri sistemi unix-like) un'altra funzione, \funcd{gethostbyname2}, il cui +prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/socket.h} +\fdecl{struct hostent *gethostbyname2(const char *name, int af)} +\fdesc{Determina l'indirizzo del tipo scelto associato ad un nome a dominio.} +} + +{La funzione ritorna il puntatore ad una + struttura di tipo \struct{hostent} contenente i dati associati al nome a + dominio in caso di successo e un puntatore nullo per un errore.} +\end{funcproto} + +In questo caso la funzione prende un secondo argomento \param{af} che indica +quale famiglia di indirizzi è quella che dovrà essere utilizzata per +selezionare i risultati restituiti dalla funzione; i soli valori consentiti +sono \const{AF\_INET} o \const{AF\_INET6} per indicare rispettivamente IPv4 e +IPv6 (per questo è necessario l'uso di \headfile{sys/socket.h}). Per tutto il +resto la funzione è identica a \func{gethostbyname}, ed identici sono i suoi +risultati. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/mygethost.c} + \end{minipage} + \normalsize + \caption{Esempio di codice per la risoluzione di un indirizzo.} + \label{fig:mygethost_example} +\end{figure} + +Vediamo allora un primo esempio dell'uso delle funzioni di risoluzione, in +fig.~\ref{fig:mygethost_example} è riportato un estratto del codice di un +programma che esegue una semplice interrogazione al \textit{resolver} usando +\func{gethostbyname} e poi ne stampa a video i risultati. Al solito il +sorgente completo, che comprende il trattamento delle opzioni ed una funzione +per stampare un messaggio di aiuto, è nel file \texttt{mygethost.c} dei +sorgenti allegati alla guida. + +Il programma richiede un solo argomento che specifichi il nome da cercare, +senza il quale (\texttt{\small 15--18}) esce con un errore. Dopo di che +(\texttt{\small 20}) si limita a chiamare \func{gethostbyname}, ricevendo il +risultato nel puntatore \var{data}. Questo (\texttt{\small 21--24}) viene +controllato per rilevare eventuali errori, nel qual caso il programma esce +dopo aver stampato un messaggio con \func{herror}. + +Se invece la risoluzione è andata a buon fine si inizia (\texttt{\small 25}) +con lo stampare il nome canonico, dopo di che (\texttt{\small 26--30}) si +stampano eventuali altri nomi. Per questo prima (\texttt{\small 26}) si prende +il puntatore alla cima della lista che contiene i nomi e poi (\texttt{\small + 27--30}) si esegue un ciclo che sarà ripetuto fin tanto che nella lista si +troveranno dei puntatori validi per le stringhe dei nomi (si ricordi che la +lista viene terminata da un puntatore nullo); prima (\texttt{\small 28}) si +stamperà la stringa e poi (\texttt{\small 29}) si provvederà ad incrementare +il puntatore per passare al successivo elemento della lista. + +Una volta stampati i nomi si passerà a stampare gli indirizzi, il primo passo +(\texttt{\small 31--38}) è allora quello di riconoscere il tipo di indirizzo +sulla base del valore del campo \var{h\_addrtype}, stampandolo a video. Si è +anche previsto di stampare un errore nel caso (che non dovrebbe mai accadere) +di un indirizzo non valido. + +Infine (\texttt{\small 39--44}) si stamperanno i valori degli indirizzi, di +nuovo (\texttt{\small 39}) si inizializzerà un puntatore alla cima della lista +e si eseguirà un ciclo fintanto che questo punterà ad indirizzi validi in +maniera analoga a quanto fatto in precedenza per i nomi a dominio. Si noti +come, essendo il campo \var{h\_addr\_list} un puntatore ad strutture di +indirizzi generiche, questo sia ancora di tipo \texttt{char **} e si possa +riutilizzare lo stesso puntatore usato per i nomi. + +Per ciascun indirizzo valido si provvederà (\texttt{\small 41}) a una +conversione con la funzione \func{inet\_ntop} (vedi +sez.~\ref{sec:sock_addr_func}) passandole gli opportuni argomenti, questa +restituirà la stringa da stampare (\texttt{\small 42}) con il valore +dell'indirizzo in \var{buffer}, che si è avuto la cura di dichiarare +inizialmente (\texttt{\small 10}) con dimensioni adeguate; dato che la +funzione è in grado di tenere conto automaticamente del tipo di indirizzo non +ci sono precauzioni particolari da prendere.\footnote{volendo essere pignoli + si dovrebbe controllarne lo stato di uscita, lo si è tralasciato per non + appesantire il codice, dato che in caso di indirizzi non validi si sarebbe + avuto un errore con \func{gethostbyname}, ma si ricordi che la sicurezza non + è mai troppa.} + +Le funzioni illustrate finora hanno un difetto: utilizzano tutte una area di +memoria interna per allocare i contenuti della struttura \struct{hostent} e +per questo non possono essere rientranti. L'uso della memoria interna inoltre +comporta anche che in due successive chiamate i dati potranno essere +sovrascritti. + +Si tenga presente poi che copiare il contenuto della sola struttura non è +sufficiente per salvare tutti i dati, in quanto questa contiene puntatori ad +altri dati, che pure possono essere sovrascritti; per questo motivo, se si +vuole salvare il risultato di una chiamata, occorrerà eseguire quella che si +chiama una \itindex{deep~copy} \textit{deep copy}.\footnote{si chiama così + quella tecnica per cui, quando si deve copiare il contenuto di una struttura + complessa (con puntatori che puntano ad altri dati, che a loro volta possono + essere puntatori ad altri dati) si deve copiare non solo il contenuto della + struttura, ma eseguire una scansione per risolvere anche tutti i puntatori + contenuti in essa (e così via se vi sono altre sotto-strutture con altri + puntatori) e copiare anche i dati da questi referenziati.} + +Per ovviare a questi problemi nella \acr{glibc} sono definite anche delle +versioni rientranti delle precedenti funzioni, al solito queste sono +caratterizzate dall'avere un suffisso \texttt{\_r}, pertanto avremo le due +funzioni \funcd{gethostbyname\_r} e \funcd{gethostbyname2\_r} i cui prototipi +sono: + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/socket.h} +\fdecl{int gethostbyname\_r(const char *name, struct hostent *ret, + char *buf, size\_t buflen,\\ +\phantom{int gethostbyname\_r(}struct hostent **result, int *h\_errnop)} +\fdecl{int gethostbyname2\_r(const char *name, int af, + struct hostent *ret, char *buf,\\ +\phantom{int gethostbyname2\_r(}size\_t buflen, struct hostent **result, int *h\_errnop)} + +\fdesc{Versioni rientranti delle funzioni \func{gethostbyname} e + \func{gethostbyname2}.} +} + +{Le funzioni ritornano $0$ in caso di successo ed un valore diverso da zero per + un errore.} +\end{funcproto} + +Gli argomenti \param{name} (e \param{af} per \func{gethostbyname2\_r}) hanno +lo stesso significato visto in precedenza. Tutti gli altri argomenti hanno lo +stesso significato per entrambe le funzioni. Per evitare l'uso di variabili +globali si dovrà allocare preventivamente una struttura \struct{hostent} in +cui ricevere il risultato, passandone l'indirizzo alla funzione nell'argomento +\param{ret}. Inoltre, dato che \struct{hostent} contiene dei puntatori, dovrà +essere allocato anche un buffer in cui le funzioni possano scrivere tutti i +dati del risultato dell'interrogazione da questi puntati; l'indirizzo e la +lunghezza di questo buffer devono essere indicati con gli argomenti +\param{buf} e \param{buflen}. + +Gli ultimi due argomenti vengono utilizzati per avere indietro i risultati +come \textit{value result argument}, si deve specificare l'indirizzo della +variabile su cui la funzione dovrà salvare il codice di errore +con \param{h\_errnop} e quello su cui dovrà salvare il puntatore che si userà +per accedere i dati con \param{result}. + +In caso di successo entrambe le funzioni restituiscono un valore nullo, +altrimenti restituiscono un valore non nulla e all'indirizzo puntato +da \param{result} sarà salvato un puntatore nullo, mentre a quello puntato da +\param{h\_errnop} sarà salvato il valore del codice di errore, dato che per +essere rientrante la funzione non può la variabile globale \var{h\_errno}. In +questo caso il codice di errore, oltre ai valori di +tab.~\ref{tab:h_errno_values}, può avere anche quello di \errcode{ERANGE} +qualora il buffer allocato su \param{buf} non sia sufficiente a contenere i +dati, in tal caso si dovrà semplicemente ripetere l'esecuzione della funzione +con un buffer di dimensione maggiore. + +Una delle caratteristiche delle interrogazioni al servizio DNS è che queste +sono normalmente eseguite con il protocollo UDP, ci sono casi in cui si +preferisce che vengano usate connessioni permanenti con il protocollo TCP. Per +ottenere questo sono previste delle funzioni apposite (si potrebbero impostare +direttamente le opzioni di \var{\_\_res.options}, ma queste funzioni +permettono di semplificare la procedura); la prime sono \funcd{sethostent} e +\func{endhostent}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{void sethostent(int stayopen)} +\fdesc{Richiede l'uso di connessioni TCP per le interrogazioni ad un server DNS.} +\fdecl{void endhostent(void)} +\fdesc{Disattiva l'uso di connessioni TCP per le interrogazioni ad un server DNS.} +} + +{Le funzioni non restituiscono nulla, e non danno errori.} +\end{funcproto} + +La funzione \func{sethostent} permette di richiedere l'uso di connessioni TCP +per la richiesta dei dati, e che queste restino aperte per successive +richieste; il valore dell'argomento \param{stayopen} indica se attivare questa +funzionalità, un valore diverso da zero, che indica una condizione vera in C, +attiva la funzionalità. Per disattivare l'uso delle connessioni TCP si può +invece usare \func{endhostent}, e come si vede la funzione è estremamente +semplice, non richiedendo nessun argomento. + +Infine si può richiedere la risoluzione inversa di un indirizzo IP od IPv6, +per ottenerne il nome a dominio ad esso associato, per fare questo si può +usare la funzione \funcd{gethostbyaddr}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/socket.h} +\fdecl{struct hostent *gethostbyaddr(const char *addr, int len, int type)} +\fdesc{Richiede la risoluzione inversa di un indirizzo IP.} +} + +{La funzione ritorna l'indirizzo ad una struttura \struct{hostent} in caso di + successo e \val{NULL} per un errore.} +\end{funcproto} + +In questo caso l'argomento \param{addr} dovrà essere il puntatore ad una +appropriata struttura contenente il valore dell'indirizzo IP (o IPv6) che si +vuole risolvere. L'uso del tipo \texttt{char *} per questo argomento è +storico, il dato dovrà essere fornito in una struttura \struct{in\_addr} per +un indirizzo IPv4 ed una struttura \struct{in6\_addr} per un indirizzo IPv6. + +Si ricordi inoltre, come illustrato in fig.~\ref{fig:sock_sa_ipv4_struct}, che +mentre \struct{in\_addr} corrisponde in realtà ad un oridinario numero intero +a 32 bit (da esprimere comunque in \textit{network order}) non altrettanto +avviene per \struct{in6\_addr}, pertanto è sempre opportuno inizializzare +questi indirizzi con \func{inet\_pton} (vedi +sez.~\ref{sec:sock_conv_func_gen}). + +Nell'argomento \param{len} se ne dovrà poi specificare la dimensione +(rispettivamente 4 o 16), infine l'argomento +\param{type} deve indicare il tipo di indirizzo, e dovrà essere o +\const{AF\_INET} o \const{AF\_INET6}. + +La funzione restituisce, in caso di successo, un puntatore ad una struttura +\struct{hostent}, solo che in questo caso la ricerca viene eseguita +richiedendo al DNS un record di tipo \texttt{PTR} corrispondente all'indirizzo +specificato. In caso di errore al solito viene usata la variabile +\var{h\_errno} per restituire un opportuno codice. In questo caso l'unico +campo del risultato che interessa è \var{h\_name} che conterrà il nome a +dominio, la funzione comunque inizializza anche il primo campo della lista +\var{h\_addr\_list} col valore dell'indirizzo passato come argomento. + +Dato che \func{gethostbyaddr} usa un buffer statico, anche di questa funzione +esiste una versione rientrante \funcd{gethostbyaddr\_r} fornita come +estensione dalla \acr{glibc}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/socket.h} +\fdecl{struct hostent *gethostbyaddr\_r(const void *addr, socklen\_t len, int type,\\ +\phantom{struct hostent *gethostbyaddr\_r(}struct hostent *ret, char *buf, size\_t buflen,\\ +\phantom{struct hostent *gethostbyaddr\_r(}struct hostent **result, int *h\_errnop);} +\fdesc{Richiede la risoluzione inversa di un indirizzo IP.} +} + +{La funzione ritorna $0$ in caso di successo e un valore non nullo per un errore.} +\end{funcproto} + +La funzione prende per gli argomenti \param{addr}, \param{len} e \param{type} +gli stessi valori di \func{gethostbyaddr} con lo stesso significato, gli +argomenti successivi vengono utilizzati per restituire i dati, sono identici a +quelli già illustrati in per \func{gethostbyname\_r} e +\func{gethostbyname2\_r} e devono essere usati allo stesso modo. + +Infine lo standard POSIX prevede la presenza della funzione +\funcd{gethostent}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{struct hostent *gethostent(void)} +\fdesc{Ottiene la voce successiva nel database dei nomi a dominio.} +} + +{La funzione ritorna l'indirizzo ad una struttura \struct{hostent} in caso di + successo e \val{NULL} per un errore.} +\end{funcproto} + +La funzione dovrebbe ritornare (come puntatore alla solita struttura +\struct{hostent} allocata internamente) la voce successiva nel database dei +nomi a dominio, ma questo ha un significato soltato quando è relativo alla +lettura dei dati da un file come \conffile{/etc/hosts} e non per i risultati +del DNS. Nel caso della \acr{glibc} questa viene usata allora solo per la +lettura delle voci presenti in quest'ultimo, come avviene anche in altri +sistemi unix-like, ed inoltre ignora le voci relative ad indirizzi IPv6. + +Della stessa funzione la \acr{glibc} fornisce anche una versione rientrante +\funcd{gethostent\_r}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{struct hostent *gethostent\_r(struct hostent *ret, char *buf, size\_t buflen,\\ +\phantom{struct hostent *gethostent\_r(}struct hostent **result, int *h\_errnop);} +\fdesc{Ottiene la voce successiva nel database dei nomi a dominio.} +} + +{La funzione ritorna $0$ in caso di successo e un valore non nullo per un errore.} +\end{funcproto} + +La funzione ha lo stesso effetto di \func{gethostent}; gli argomenti servono a +restituire i risultati in maniera rientrante e vanno usati secondo le modalità +già illustrate per \func{gethostbyname\_r} e \func{gethostbyname2\_r}. + +Dati i limiti delle funzioni \func{gethostbyname} e \func{gethostbyaddr} con +l'uso di memoria statica che può essere sovrascritta fra due chiamate +successive, e per avere sempre la possibilità di indicare esplicitamente il +tipo di indirizzi voluto (cosa che non è possibile con \func{gethostbyname}), +è stata successivamente proposta, +nell'\href{http://www.ietf.org/rfc/rfc2553.txt}{RFC~2553} un diversa +interfaccia con l'introduzione due nuove funzioni di +risoluzione,\footnote{dette funzioni sono presenti nella \acr{glibc} 2.1.96, + ma essendo considerate deprecate (vedi + sez.~\ref{sec:sock_advanced_name_services}) sono state rimosse nelle + versioni successive.} \funcd{getipnodebyname} e \funcd{getipnodebyaddr}, i +cui prototipi sono: + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/types.h} +\fhead{sys/socket.h} +\fdecl{struct hostent *getipnodebyname(const char *name, int af, int + flags, int *error\_num)} +\fdesc{Richiede la risoluzione di un nome a dominio.} +\fdecl{struct hostent *getipnodebyaddr(const void *addr, size\_t len, + int af, int *error\_num)} +\fdesc{Richiede la risoluzione inversa di un indirizzo IP.} +} + +{Le funzioni ritornano l'indirizzo ad una struttura \struct{hostent} in caso + di successo e \val{NULL} per un errore.} +\end{funcproto} + +Entrambe le funzioni supportano esplicitamente la scelta di una famiglia di +indirizzi con l'argomento \param{af} (che può assumere i valori +\const{AF\_INET} o \const{AF\_INET6}), e restituiscono un codice di errore +(con valori identici a quelli precedentemente illustrati in +tab.~\ref{tab:h_errno_values}) nella variabile puntata da \param{error\_num}. +La funzione \func{getipnodebyaddr} richiede poi che si specifichi l'indirizzo +come per \func{gethostbyaddr} passando anche la lunghezza dello stesso +nell'argomento \param{len}. + +La funzione \func{getipnodebyname} prende come primo argomento il nome da +risolvere, inoltre prevede un apposito argomento \param{flags}, da usare come +maschera binaria, che permette di specificarne il comportamento nella +risoluzione dei diversi tipi di indirizzi (IPv4 e IPv6); ciascun bit +dell'argomento esprime una diversa opzione, e queste possono essere specificate +con un OR aritmetico delle costanti riportate in +tab.~\ref{tab:sock_getipnodebyname_flags}. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \constd{AI\_V4MAPPED} & Usato con \const{AF\_INET6} per richiedere una + ricerca su un indirizzo IPv4 invece che IPv6; gli + eventuali risultati saranno rimappati su indirizzi + IPv6.\\ + \constd{AI\_ALL} & Usato con \const{AI\_V4MAPPED}; richiede sia + indirizzi IPv4 che IPv6, e gli indirizzi IPv4 + saranno rimappati in IPv6.\\ + \constd{AI\_ADDRCONFIG}& Richiede che una richiesta IPv4 o IPv6 venga + eseguita solo se almeno una interfaccia del + sistema è associata ad un indirizzo di tale tipo.\\ + \constd{AI\_DEFAULT} & Il valore di default, è equivalente alla + combinazione di \const{AI\_ADDRCONFIG} e di + \const{AI\_V4MAPPED}.\\ + \hline + \end{tabular} + \caption{Valori possibili per i bit dell'argomento \param{flags} della + funzione \func{getipnodebyname}.} + \label{tab:sock_getipnodebyname_flags} +\end{table} + +Entrambe le funzioni restituiscono un puntatore ad una struttura \var{hostent} +che contiene i risultati della ricerca, che viene allocata dinamicamente +insieme a tutto lo spazio necessario a contenere i dati in essa referenziati; +per questo motivo queste funzioni non soffrono dei problemi dovuti all'uso di +una sezione statica di memoria presenti con le precedenti \func{gethostbyname} +e \func{gethostbyaddr}. L'uso di una allocazione dinamica però comporta anche +la necessità di disallocare esplicitamente la memoria occupata dai risultati +una volta che questi non siano più necessari; a tale scopo viene fornita la +funzione \funcd{freehostent}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/types.h} +\fhead{sys/socket.h} +\fdecl{void freehostent(struct hostent *ip)} +\fdesc{Disalloca una struttura \var{hostent}.} +} + +{La funzione non ritorna nulla, e non da errori.} +\end{funcproto} -Il terzo campo, \var{h\_addrtype}, indica il tipo di indirizzo che è stato -restituito, e può essere solo \const{AF\_INET} o \const{AF\_INET6}, mentre il -quarto campo, \var{h\_length}, indica la lunghezza dell'indirizzo stesso in -byte. Infine il campo \var{h\_addr\_list} è il puntatore ad un vettore di -puntatori ai singoli indirizzi; il vettore è terminato da un puntatore nullo. -Inoltre, come illustrato in fig.~\ref{fig:sock_hostent_struct}, viene definito -per compatibilità il campo \var{h\_addr} corrispondente al puntatore al primo -indirizzo della lista. +La funzione permette di disallocare una struttura \var{hostent} +precedentemente allocata in una chiamata di \func{getipnodebyname} o +\func{getipnodebyaddr}, e prende come argomento l'indirizzo restituito da una +di queste funzioni. -In sostanza +Infine per concludere la nostra panoramica sulle funzioni di risoluzione dei +nomi dobbiamo citare le funzioni che permettono di interrogare gli altri +servizi di risoluzione dei nomi illustrati in sez.~\ref{sec:sock_resolver}; in +generale infatti ci sono una serie di funzioni nella forma +\texttt{get\textsl{XXX}byname} e \texttt{get\textsl{XXX}byaddr} (dove +\texttt{\textsl{XXX}} indica il servizio) per ciascuna delle informazioni di +rete mantenute dal \textit{Name Service Switch} che permettono rispettivamente +di trovare una corrispondenza cercando per nome o per numero. +L'elenco di queste funzioni è riportato nelle colonne finali di +tab.~\ref{tab:name_resolution_functions}, dove le si sono suddivise rispetto +al tipo di informazione che forniscono (riportato in prima colonna). Nella +tabella si è anche riportato il file su cui vengono ordinariamente mantenute +queste informazioni, che però può essere sostituito da un qualunque supporto +interno al \textit{Name Service Switch} (anche se usualmente questo avviene +solo per la risoluzione degli indirizzi). Ciascuna funzione fa riferimento ad +una sua apposita struttura che contiene i relativi dati, riportata in terza +colonna. +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|l|l|l|} + \hline + \textbf{Informazione}&\textbf{File}&\textbf{Struttura}& + \multicolumn{2}{|c|}{\textbf{Funzioni}}\\ + \hline + \hline + indirizzo &\conffile{/etc/hosts}&\struct{hostent}&\func{gethostbyname}& + \func{gethostbyaddr}\\ + servizio &\conffile{/etc/services}&\struct{servent}&\func{getservbyname}& + \func{getservbyport}\\ + rete &\conffile{/etc/networks}&\struct{netent}&\funcm{getnetbyname}& + \funcm{getnetbyaddr}\\ + protocollo&\conffile{/etc/protocols}&\struct{protoent}& + \funcm{getprotobyname}&\funcm{getprotobyaddr}\\ + \hline + \end{tabular} + \caption{Funzioni di risoluzione dei nomi per i vari servizi del + \textit{Name Service Switch} riguardanti la rete.} + \label{tab:name_resolution_functions} +\end{table} + +Delle funzioni di tab.~\ref{tab:name_resolution_functions} abbiamo trattato +finora soltanto quelle relative alla risoluzione dei nomi, dato che sono le +più usate, e prevedono praticamente da sempre la necessità di rivolgersi ad +una entità esterna; per le altre invece, estensioni fornite dal \textit{Name + Service Switch} a parte, si fa sempre riferimento ai dati mantenuti nei +rispettivi file. + +Dopo la risoluzione dei nomi a dominio una delle ricerche più comuni è quella +sui nomi dei servizi di rete più comuni (cioè \texttt{http}, \texttt{smtp}, +ecc.) da associare alle rispettive porte. Le due funzioni da utilizzare per +questo sono \funcd{getservbyname} e \funcd{getservbyport}, che permettono +rispettivamente di ottenere il numero di porta associato ad un servizio dato +il nome e viceversa; i loro prototipi sono: + + + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{struct servent *getservbyname(const char *name, const char *proto)} +\fdecl{struct servent *getservbyport(int port, const char *proto)} +\fdesc{Risolvono il nome di un servizio nel rispettivo numero di porta e viceversa.} +} + +{Le funzioni ritornano il puntatore ad una struttura \struct{servent} con i + risultati in caso di successo e \val{NULL} per un errore.} +\end{funcproto} + +Entrambe le funzioni prendono come ultimo argomento una stringa \param{proto} +che indica il protocollo per il quale si intende effettuare la ricerca (le +informazioni mantenute in \conffile{/etc/services} infatti sono relative sia +alle porte usate su UDP che su TCP, occorre quindi specificare a quale dei due +protocolli si fa riferimento) che nel caso di IP può avere come valori +possibili solo \texttt{udp} o \texttt{tcp};\footnote{in teoria si potrebbe + avere un qualunque protocollo fra quelli citati in + \conffile{/etc/protocols}, posto che lo stesso supporti il concetto di + \textsl{porta}, in pratica questi due sono gli unici presenti.} se si +specifica un puntatore nullo la ricerca sarà eseguita su un protocollo +qualsiasi. + +Il primo argomento è il nome del servizio per \func{getservbyname}, +specificato tramite la stringa \param{name}, mentre \func{getservbyport} +richiede il numero di porta in \param{port}. Entrambe le funzioni eseguono una +ricerca sul file \conffile{/etc/services}\footnote{il \textit{Name Service + Switch} astrae il concetto a qualunque supporto su cui si possano + mantenere i suddetti dati.} ed estraggono i dati dalla prima riga che +corrisponde agli argomenti specificati; se la risoluzione ha successo viene +restituito un puntatore ad una apposita struttura \struct{servent} contenente +tutti i risultati, altrimenti viene restituito un puntatore nullo. Si tenga +presente che anche in questo caso i dati vengono mantenuti in una area di +memoria statica e che quindi la funzione non è rientrante. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/servent.h} + \end{minipage} + \caption{La struttura \structd{servent} per la risoluzione dei nomi dei + servizi e dei numeri di porta.} + \label{fig:sock_servent_struct} +\end{figure} + +La definizione della struttura \struct{servent} è riportata in +fig.~\ref{fig:sock_servent_struct}, il primo campo, \var{s\_name} contiene +sempre il nome canonico del servizio, mentre \var{s\_aliases} è un puntatore +ad un vettore di stringhe contenenti gli eventuali nomi alternativi +utilizzabili per identificare lo stesso servizio. Infine \var{s\_port} +contiene il numero di porta e \var{s\_proto} il nome del protocollo. + +Come riportato in tab.~\ref{tab:name_resolution_functions} ci sono analoghe +funzioni per la risoluzione del nome dei protocolli e delle reti; non staremo +a descriverle nei dettagli, in quanto il loro uso è molto limitato, esse +comunque utilizzano una loro struttura dedicata del tutto analoga alle +precedenti: tutti i dettagli relativi al loro funzionamento possono essere +trovati nelle rispettive pagine di manuale. + +Oltre alle funzioni di ricerca esistono delle ulteriori funzioni che prevedono +una lettura sequenziale delle informazioni mantenute nel \textit{Name Service + Switch} (in sostanza permettono di leggere i file contenenti le informazioni +riga per riga), che sono analoghe a quelle elencate in +tab.~\ref{tab:sys_passwd_func} per le informazioni relative ai dati degli +utenti e dei gruppi. Nel caso specifico dei servizi avremo allora le tre +funzioni \funcd{setservent}, \funcd{getservent} e \funcd{endservent} i cui +prototipi sono: + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{struct servent *getservent(void)} +\fdesc{Legge la voce successiva nel file \conffile{/etc/services}.} +\fdecl{void setservent(int stayopen)} +\fdesc{Apre il file \conffile{/etc/services} e si posiziona al suo inizio.} +\fdecl{void endservent(void)} +\fdesc{Chiude il file \conffile{/etc/services}.} +} + +{Le due funzioni \func{setservent} e \func{endservent} non ritornano nulla, + \func{getservent} restituisce il puntatore ad una struttura \struct{servent} + in caso di successo e \val{NULL} per un errore o fine del file.} +\end{funcproto} + +La prima funzione, \func{getservent}, legge una singola voce a partire dalla +posizione corrente in \conffile{/etc/services}, pertanto si può eseguire una +lettura sequenziale dello stesso invocandola più volte. Se il file non è +aperto provvede automaticamente ad aprirlo, nel qual caso leggerà la prima +voce. La seconda funzione, \func{setservent}, permette di aprire il file +\conffile{/etc/services} per una successiva lettura, ma se il file è già stato +aperto riporta la posizione di lettura alla prima voce del file, in questo +modo si può far ricominciare da capo una lettura sequenziale. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|l|l|} + \hline + \textbf{Informazione}&\multicolumn{3}{|c|}{\textbf{Funzioni}}\\ + \hline + \hline + indirizzo &\func{sethostent} &\func{gethostent} &\func{endhostent} \\ + servizio &\func{setservent} &\func{getservent} &\func{endservent}\\ + rete &\funcm{setnetent} &\funcm{getnetent} &\funcm{endnetent}\\ + protocollo&\funcm{setprotoent}&\funcm{getprotoent}&\funcm{endprotoent}\\ + \hline + \end{tabular} + \caption{Funzioni lettura sequenziale dei dati del + \textit{Name Service Switch}.} + \label{tab:name_sequential_read} +\end{table} + +L'argomento \param{stayopen} di \func{setservent}, se diverso da zero, fa sì +che il file resti aperto anche fra diverse chiamate a \func{getservbyname} e +\func{getservbyport}; di default dopo una chiamata a queste funzioni il file +viene chiuso, cosicché una successiva chiamata a \func{getservent} riparte +dall'inizio. La terza funzione, \func{endservent}, provvede semplicemente a +chiudere il file. + +Queste tre funzioni per la lettura sequenziale di nuovo sono presenti per +ciascuno dei vari tipi di informazione relative alle reti di +tab.~\ref{tab:name_resolution_functions}; questo significa che esistono +altrettante funzioni nella forma \texttt{setXXXent}, \texttt{getXXXent} e +\texttt{endXXXent}, analoghe alle precedenti per la risoluzione dei servizi, +che abbiamo riportato in tab.~\ref{tab:name_sequential_read}. Essendo, a +parte il tipo di informazione che viene trattato, sostanzialmente identiche +nel funzionamento e di scarso utilizzo, non staremo a trattarle una per una, +rimandando alle rispettive pagine di manuale. + + +\subsection{Le funzioni avanzate per la risoluzione dei nomi} +\label{sec:sock_advanced_name_services} + +Quelle illustrate nella sezione precedente sono le funzioni classiche per la +risoluzione di nomi ed indirizzi IP, ma abbiamo già visto come esse soffrano +di vari inconvenienti come il fatto che usano informazioni statiche, e non +prevedono la possibilità di avere diverse classi di indirizzi. Anche se sono +state create delle estensioni o metodi diversi che permettono di risolvere +alcuni di questi inconvenienti, comunque esse non forniscono una interfaccia +sufficientemente generica.\footnote{rimane ad esempio il problema generico che + si deve sapere in anticipo quale tipo di indirizzi IP (IPv4 o IPv6) + corrispondono ad un certo nome a dominio.} + +Inoltre in genere quando si ha a che fare con i socket non esiste soltanto il +problema della risoluzione del nome che identifica la macchina, ma anche +quello del servizio a cui ci si vuole rivolgere. Per questo motivo con lo +standard POSIX 1003.1-2001 sono state indicate come deprecate le varie +funzioni \func{gethostbyaddr}, \func{gethostbyname}, \var{getipnodebyname} e +\var{getipnodebyaddr} ed è stata introdotta una interfaccia completamente +nuova. + +La prima funzione di questa interfaccia è \funcd{getaddrinfo}, che combina le +funzionalità delle precedenti \func{getipnodebyname}, \func{getipnodebyaddr}, +\func{getservbyname} e \func{getservbyport}, consentendo di ottenere +contemporaneamente sia la risoluzione di un indirizzo simbolico che del nome +di un servizio; la funzione è stata introdotta, insieme a \func{getnameinfo} +che vedremo più avanti, +nell'\href{http://www.ietf.org/rfc/rfc2553.txt}{RFC~2553} ed il suo prototipo è: + + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/socket.h} +\fdecl{int getaddrinfo(const char *node, const char *service, const + struct addrinfo *hints, \\ +\phantom{int getaddrinfo(}struct addrinfo **res)} +\fdesc{Esegue una risoluzione di un nome a dominio e di un nome di servizio.} +} + +{La funzione ritorna $0$ in caso di successo e un codice di errore diverso da + zero per un errore.} +\end{funcproto} + +La funzione prende come primo argomento il nome della macchina che si vuole +risolvere, specificato tramite la stringa \param{node}. Questo argomento, +oltre ad un comune nome a dominio, può indicare anche un indirizzo numerico in +forma \textit{dotted-decimal} per IPv4 o in formato esadecimale per IPv6. Si +può anche specificare il nome di una rete invece che di una singola macchina. +Il secondo argomento, \param{service}, specifica invece il nome del servizio +che si intende risolvere. Per uno dei due argomenti si può anche usare il +valore \val{NULL}, nel qual caso la risoluzione verrà effettuata soltanto +sulla base del valore dell'altro. + +Il terzo argomento, \param{hints}, deve essere invece un puntatore ad una +struttura \struct{addrinfo} usata per dare dei \textsl{suggerimenti} al +procedimento di risoluzione riguardo al protocollo o del tipo di socket che si +intenderà utilizzare; \func{getaddrinfo} infatti permette di effettuare +ricerche generiche sugli indirizzi, usando sia IPv4 che IPv6, e richiedere +risoluzioni sui nomi dei servizi indipendentemente dal protocollo (ad esempio +TCP o UDP) che questi possono utilizzare. + +Come ultimo argomento in \param{res} deve essere passato un puntatore ad una +variabile (di tipo puntatore ad una struttura \struct{addrinfo}) che verrà +utilizzata dalla funzione per riportare (come \textit{value result argument}) +i propri risultati. La funzione infatti è rientrante, ed alloca autonomamente +tutta la memoria necessaria in cui verranno riportati i risultati della +risoluzione. La funzione scriverà all'indirizzo puntato da \param{res} il +puntatore iniziale ad una \textit{linked list} di strutture di tipo +\struct{addrinfo} contenenti tutte le informazioni ottenute. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.90\textwidth} + \includestruct{listati/addrinfo.h} + \end{minipage} + \caption{La struttura \structd{addrinfo} usata nella nuova interfaccia POSIX + per la risoluzione di nomi a dominio e servizi.} + \label{fig:sock_addrinfo_struct} +\end{figure} + +Come illustrato la struttura \struct{addrinfo}, la cui definizione è riportata +in fig.~\ref{fig:sock_addrinfo_struct}, viene usata sia in ingresso, per +passare dei valori di controllo alla funzione, che in uscita, per ricevere i +risultati. La definizione è ripresa direttamente dal file \headfiled{netdb.h} +in cui questa struttura viene dichiarata, la pagina di manuale riporta +\type{size\_t} come tipo di dato per il campo \var{ai\_addrlen}, qui viene +usata quanto previsto dallo standard POSIX, in cui viene utilizzato +\type{socklen\_t}; i due tipi di dati sono comunque equivalenti. + +Il primo campo, \var{ai\_flags}, è una maschera binaria di bit che +permettono di controllare le varie modalità di risoluzione degli indirizzi, +che viene usato soltanto in ingresso. I tre campi successivi \var{ai\_family}, +\var{ai\_socktype}, e \var{ai\_protocol} contengono rispettivamente la +famiglia di indirizzi, il tipo di socket e il protocollo, in ingresso vengono +usati per impostare una selezione (impostandone il valore nella struttura +puntata da \param{hints}), mentre in uscita indicano il tipo di risultato +contenuto nella struttura. + +Tutti i campi seguenti vengono usati soltanto in uscita e devono essere nulli +o \val{NULL} in ingresso; il campo \var{ai\_addrlen} indica la dimensione +della struttura degli indirizzi ottenuta come risultato, il cui contenuto sarà +memorizzato nella struttura \struct{sockaddr} posta all'indirizzo puntato dal +campo \var{ai\_addr}. Il campo \var{ai\_canonname} è un puntatore alla stringa +contenente il nome canonico della macchina, ed infine, quando la funzione +restituisce più di un risultato, \var{ai\_next} è un puntatore alla successiva +struttura \struct{addrinfo} della lista. + +Ovviamente non è necessario dare dei suggerimenti in ingresso, ed usando +\val{NULL} come valore per l'argomento \param{hints} si possono compiere +ricerche generiche. Se però si specifica un valore non nullo questo deve +puntare ad una struttura \struct{addrinfo} precedentemente allocata nella +quale siano stati opportunamente impostati i valori dei campi +\var{ai\_family}, \var{ai\_socktype}, \var{ai\_protocol} ed \var{ai\_flags}. + +I due campi \var{ai\_family} e \var{ai\_socktype} prendono gli stessi valori +degli analoghi argomenti della funzione \func{socket}; in particolare per +\var{ai\_family} si possono usare i valori di tab.~\ref{tab:net_pf_names} ma +sono presi in considerazione solo \const{AF\_INET} e \const{AF\_INET6}, mentre +se non si vuole specificare nessuna famiglia di indirizzi si può usare il +valore \const{AF\_UNSPEC}. Allo stesso modo per \var{ai\_socktype} si possono +usare i valori illustrati in sez.~\ref{sec:sock_type} per indicare per quale +tipo di socket si vuole risolvere il servizio indicato, anche se i soli +significativi sono \const{SOCK\_STREAM} e \const{SOCK\_DGRAM}; in questo caso, +se non si vuole effettuare nessuna risoluzione specifica, si potrà usare un +valore nullo. + +Il campo \var{ai\_protocol} permette invece di effettuare la selezione dei +risultati per il nome del servizio usando il numero identificativo del +rispettivo protocollo di trasporto (i cui valori possibili sono riportati in +\conffile{/etc/protocols}); di nuovo i due soli valori utilizzabili sono quelli +relativi a UDP e TCP, o il valore nullo che indica di ignorare questo campo +nella selezione. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \const{AI\_ADDRCONFIG} & Stesso significato dell'analoga di + tab.~\ref{tab:sock_getipnodebyname_flags}.\\ + \const{AI\_ALL} & Stesso significato dell'analoga di + tab.~\ref{tab:sock_getipnodebyname_flags}.\\ + \constd{AI\_CANONNAME} & Richiede la restituzione del nome canonico della + macchina, che verrà salvato in una stringa il cui + indirizzo sarà restituito nel campo + \var{ai\_canonname} della prima struttura + \struct{addrinfo} dei risultati. Se il nome + canonico non è disponibile al suo posto + viene restituita una copia di \param{node}. \\ + \constd{AI\_NUMERICHOST}& Se impostato il nome della macchina specificato + con \param{node} deve essere espresso in forma + numerica, altrimenti sarà restituito un errore + \const{EAI\_NONAME} (vedi + tab.~\ref{tab:addrinfo_error_code}), in questo + modo si evita ogni chiamata alle funzioni di + risoluzione.\\ + \constd{AI\_NUMERICSERVICE}& Analogo di \const{AI\_NUMERICHOST} per la + risoluzione di un servizio, con + \param{service} che deve essere espresso in forma + numerica.\\ + \constd{AI\_PASSIVE} & Viene utilizzato per ottenere un indirizzo in + formato adatto per una successiva chiamata a + \func{bind}. Se specificato quando si è usato + \val{NULL} come valore per \param{node} gli + indirizzi restituiti saranno inizializzati al + valore generico (\const{INADDR\_ANY} per IPv4 e + \const{IN6ADDR\_ANY\_INIT} per IPv6), altrimenti + verrà usato l'indirizzo dell'interfaccia di + \textit{loopback}. Se invece non è impostato gli + indirizzi verranno restituiti in formato adatto ad + una chiamata a \func{connect} o \func{sendto}.\\ + \const{AI\_V4MAPPED} & Stesso significato dell'analoga di + tab.~\ref{tab:sock_getipnodebyname_flags}.\\ + \hline + \const{AI\_CANONIDN} & Se il nome canonico richiesto con + \const{AI\_CANONNAME} è codificato con questo + flag la codifica viene convertita in forma + leggibile nella localizzazione corrente.\\ + \const{AI\_IDN} & Se specificato il nome viene convertito, se + necessario, nella codifica IDN, usando la + localizzazione corrente.\\ + \const{AI\_IDN\_ALLOW\_UNASSIGNED} & attiva il controllo + \texttt{IDNA\_ALLOW\_UNASSIGNED}.\\ + \const{AI\_AI\_IDN\_USE\_STD3\_ASCII\_RULES} & attiva il controllo + \texttt{IDNA\_USE\_STD3\_ASCII\_RULES}\\ + \hline + \end{tabular} + \caption{Costanti associate ai bit del campo \var{ai\_flags} della struttura + \struct{addrinfo}.} + \label{tab:ai_flags_values} +\end{table} + +% TODO mettere riferimento a IDNA_ALLOW_UNASSIGNED e IDNA_USE_STD3_ASCII_RULES + +Infine gli ultimi dettagli si controllano con il campo \var{ai\_flags}; che +deve essere impostato come una maschera binaria; i bit di questa variabile +infatti vengono usati per dare delle indicazioni sul tipo di risoluzione +voluta, ed hanno valori analoghi a quelli visti in +sez.~\ref{sec:sock_name_services} per \func{getipnodebyname}; il valore di +\var{ai\_flags} può essere impostata con un OR aritmetico delle costanti di +tab.~\ref{tab:ai_flags_values}, ciascuna delle quali identifica un bit della +maschera. + +Nella seconda parte della tabella si sono riportati i valori delle costanti +aggiunte a partire dalla \acr{glibc} 2.3.4 per gestire la +internazionalizazione dei nomi a dominio (IDN o \textit{Internationalized + Domain Names}) secondo quanto specificato +nell'\href{http://www.ietf.org/rfc/rfc3490.txt}{RFC~3490} (potendo cioè usare +codifiche di caratteri che consentono l'espressione di nomi a dominio in +qualunque lingua). + +Come accennato passando un valore \val{NULL} per l'argomento \param{hints} si +effettua una risuluzione generica, equivalente ad aver impostato un valore +nullo per \var{ai\_family} e \var{ai\_socktype}, un valore \const{AF\_UNSPEC} +per \var{ai\_family} e il valore \code{(AI\_V4MAPPED|AI\_ADDRCONFIG)} per +\var{ai\_flags}. + +La funzione restituisce un valore nullo in caso di successo, o un codice in +caso di errore. I valori usati come codice di errore sono riportati in +tab.~\ref{tab:addrinfo_error_code}; dato che la funzione utilizza altre +funzioni e chiamate al sistema per ottenere il suo risultato in generale il +valore di \var{errno} non è significativo, eccetto il caso in cui si sia +ricevuto un errore di \const{EAI\_SYSTEM}, nel qual caso l'errore +corrispondente è riportato tramite \var{errno}. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{10cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \constd{EAI\_ADDRFAMILY}& La richiesta non ha nessun indirizzo di rete + per la famiglia di indirizzi specificata. \\ + \constd{EAI\_AGAIN} & Il DNS ha restituito un errore di risoluzione + temporaneo, si può ritentare in seguito. \\ + \constd{EAI\_BADFLAGS}& Il campo \var{ai\_flags} contiene dei valori non + validi per i flag o si è richiesto + \const{AI\_CANONNAME} con \param{name} nullo. \\ + \constd{EAI\_FAIL} & Il DNS ha restituito un errore di risoluzione + permanente. \\ + \constd{EAI\_FAMILY} & La famiglia di indirizzi richiesta non è + supportata. \\ + \constd{EAI\_MEMORY} & È stato impossibile allocare la memoria necessaria + alle operazioni. \\ + \constd{EAI\_NODATA} & La macchina specificata esiste, ma non ha nessun + indirizzo di rete definito. \\ + \constd{EAI\_NONAME} & Il nome a dominio o il servizio non sono noti, + viene usato questo errore anche quando si specifica + il valore \val{NULL} per entrambi gli argomenti + \param{node} e \param{service}. \\ + \constd{EAI\_SERVICE} & Il servizio richiesto non è disponibile per il tipo + di socket richiesto, anche se può esistere per + altri tipi di socket. \\ + \constd{EAI\_SOCKTYPE}& Il tipo di socket richiesto non è supportato. \\ + \constd{EAI\_SYSTEM} & C'è stato un errore di sistema, si può controllare + \var{errno} per i dettagli. \\ +% \hline +% TODO estensioni GNU, trovarne la documentazione +% \constd{EAI\_INPROGRESS}& Richiesta in corso. \\ +% \constd{EAI\_CANCELED}& La richiesta è stata cancellata.\\ +% \constd{EAI\_NOTCANCELED}& La richiesta non è stata cancellata. \\ +% \constd{EAI\_ALLDONE} & Tutte le richieste sono complete. \\ +% \constd{EAI\_INTR} & Richiesta interrotta. \\ + \hline + \end{tabular} + \caption{Costanti associate ai valori dei codici di errore della funzione + \func{getaddrinfo}.} + \label{tab:addrinfo_error_code} +\end{table} + +Come per i codici di errore di \func{gethostbyname} anche in questo caso è +fornita una apposita funzione, simile a \func{strerror}, che consente di +utilizzare direttamente il codice restituito dalla funzione per stampare a +video un messaggio esplicativo; la funzione è \funcd{gai\_strerror} ed il suo +prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{const char *gai\_strerror(int errcode)} +\fdesc{Fornisce il messaggio corrispondente ad un errore di \func{getaddrinfo}.} +} + +{La funzione ritorna il puntatore alla stringa contenente il messaggio di + errore.} +\end{funcproto} + +La funzione restituisce un puntatore alla stringa contenente il messaggio +corrispondente dal codice di errore \param{errcode} ottenuto come valore di +ritorno di \func{getaddrinfo}. La stringa è allocata staticamente, ma essendo +costante ed accessibile in sola lettura, la funzione è rientrante. + +Dato che ad un certo nome a dominio possono corrispondere più indirizzi IP +(sia IPv4 che IPv6), e che un certo servizio può essere fornito su protocolli +e tipi di socket diversi, in generale, a meno di non aver eseguito una +selezione specifica attraverso l'uso di \param{hints}, si otterrà una diversa +struttura \struct{addrinfo} per ciascuna possibilità. + +Ad esempio se si richiede la risoluzione del servizio \textit{echo} per +l'indirizzo \texttt{www.truelite.it}, e si imposta \const{AI\_CANONNAME} per +avere anche la risoluzione del nome canonico, si avrà come risposta della +funzione la lista illustrata in fig.~\ref{fig:sock_addrinfo_list}. + +\begin{figure}[!htb] + \centering + \includegraphics[width=10cm]{img/addrinfo_list} + \caption{La \textit{linked list} delle strutture \struct{addrinfo} + restituite da \func{getaddrinfo}.} + \label{fig:sock_addrinfo_list} +\end{figure} + +Come primo esempio di uso di \func{getaddrinfo} vediamo un programma +elementare di interrogazione del \textit{resolver} basato questa funzione, il +cui corpo principale è riportato in fig.~\ref{fig:mygetaddr_example}. Il +codice completo del programma, compresa la gestione delle opzioni in cui è +gestita l'eventuale inizializzazione dell'argomento \var{hints} per +restringere le ricerche su protocolli, tipi di socket o famiglie di indirizzi, +è disponibile nel file \texttt{mygetaddr.c} dei sorgenti allegati alla guida. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/mygetaddr.c} + \end{minipage} + \normalsize + \caption{Esempio di codice per la risoluzione di un indirizzo.} + \label{fig:mygetaddr_example} +\end{figure} + +Il corpo principale inizia controllando (\texttt{\small 1--5}) il numero di +argomenti passati, che devono essere sempre due, e corrispondere +rispettivamente all'indirizzo ed al nome del servizio da risolvere. A questo +segue la chiamata (\texttt{\small 7}) alla funzione \func{getaddrinfo}, ed il +successivo controllo (\texttt{\small 8--11}) del suo corretto funzionamento, +senza il quale si esce immediatamente stampando il relativo codice di errore. + +Se la funzione ha restituito un valore nullo il programma prosegue +inizializzando (\texttt{\small 12}) il puntatore \var{ptr} che sarà usato nel +successivo ciclo (\texttt{\small 14--35}) di scansione della lista delle +strutture \struct{addrinfo} restituite dalla funzione. Prima di eseguire +questa scansione (\texttt{\small 12}) viene stampato il valore del nome +canonico che è presente solo nella prima struttura. + +La scansione viene ripetuta (\texttt{\small 14}) fintanto che si ha un +puntatore valido. La selezione principale è fatta sul campo \var{ai\_family}, +che stabilisce a quale famiglia di indirizzi fa riferimento la struttura in +esame. Le possibilità sono due, un indirizzo IPv4 o IPv6, se nessuna delle due +si verifica si provvede (\texttt{\small 27--30}) a stampare un messaggio di +errore ed uscire (questa eventualità non dovrebbe comunque mai verificarsi, +almeno fintanto che la funzione \func{getaddrinfo} lavora correttamente). + +Per ciascuno delle due possibili famiglie di indirizzi si estraggono le +informazioni che poi verranno stampate alla fine del ciclo (\texttt{\small + 31--34}). Il primo caso esaminato (\texttt{\small 15--21}) è quello degli +indirizzi IPv4, nel qual caso prima se ne stampa l'identificazione +(\texttt{\small 16}) poi si provvede a ricavare la struttura degli indirizzi +(\texttt{\small 17}) indirizzata dal campo \var{ai\_addr}, eseguendo un +opportuno casting del puntatore per poter estrarre da questa la porta +(\texttt{\small 18}) e poi l'indirizzo (\texttt{\small 19}) che verrà +convertito con una chiamata ad \func{inet\_ntop}. + +La stessa operazione (\texttt{\small 21--27}) viene ripetuta per gli indirizzi +IPv6, usando la rispettiva struttura degli indirizzi. Si noti anche come in +entrambi i casi per la chiamata a \func{inet\_ntop} si sia dovuto passare il +puntatore al campo contenente l'indirizzo IP nella struttura puntata dal campo +\var{ai\_addr}.\footnote{il meccanismo è complesso a causa del fatto che al + contrario di IPv4, in cui l'indirizzo IP può essere espresso con un semplice + numero intero, in IPv6 questo deve essere necessariamente fornito come + struttura, e pertanto anche se nella struttura puntata da \var{ai\_addr} + sono presenti direttamente i valori finali, per l'uso con \func{inet\_ntop} + occorre comunque passare un puntatore agli stessi (ed il costrutto + \code{\&addr6->sin6\_addr} è corretto in quanto l'operatore \texttt{->} ha + in questo caso precedenza su \texttt{\&}).} + +Una volta estratte dalla struttura \struct{addrinfo} tutte le informazioni +relative alla risoluzione richiesta e stampati i relativi valori, l'ultimo +passo (\texttt{\small 34}) è di estrarre da \var{ai\_next} l'indirizzo della +eventuale successiva struttura presente nella lista e ripetere il ciclo, fin +tanto che, completata la scansione, questo avrà un valore nullo e si potrà +terminare (\texttt{\small 36}) il programma. + +Si tenga presente che \func{getaddrinfo} non garantisce nessun particolare +ordinamento della lista delle strutture \struct{addrinfo} restituite, anche se +usualmente i vari indirizzi IP (se ne è presente più di uno) sono forniti +nello stesso ordine in cui vengono inviati dal server DNS. In particolare +nulla garantisce che vengano forniti prima i dati relativi ai servizi di un +determinato protocollo o tipo di socket, se ne sono presenti di diversi. Se +allora utilizziamo il nostro programma potremo verificare il risultato: +\begin{Console} +[piccardi@gont sources]$ \textbf{./mygetaddr -c gapil.truelite.it echo} +Canonical name sources2.truelite.it +IPv4 address: + Indirizzo 62.48.34.25 + Protocollo 6 + Porta 7 +IPv4 address: + Indirizzo 62.48.34.25 + Protocollo 17 + Porta 7 +\end{Console} +%$ + +Una volta estratti i risultati dalla \textit{linked list} puntata +da \param{res} se questa non viene più utilizzata si dovrà avere cura di +disallocare opportunamente tutta la memoria, per questo viene fornita +l'apposita funzione \funcd{freeaddrinfo}, il cui prototipo è: + + +\begin{funcproto}{ +\fhead{netdb.h} +\fdecl{void freeaddrinfo(struct addrinfo *res)} +\fdesc{Libera la memoria allocata da una precedente chiamata a \func{getaddrinfo}.} +} + +{La funzione non restituisce nessun codice di errore.} +\end{funcproto} + +La funzione prende come unico argomento il puntatore \param{res}, ottenuto da +una precedente chiamata a \func{getaddrinfo}, e scandisce la lista delle +strutture per liberare tutta la memoria allocata. Dato che la funzione non ha +valori di ritorno deve essere posta molta cura nel passare un valore valido +per \param{res} ed usare un indirizzo non valido o già liberato può avere +conseguenze non prevedibili. + +Si tenga presente infine che se si copiano i risultati da una delle strutture +\struct{addrinfo} restituite nella lista indicizzata da \param{res}, occorre +avere cura di eseguire una \textit{deep copy} in cui si copiano anche tutti i +dati presenti agli indirizzi contenuti nella struttura \struct{addrinfo}, +perché una volta disallocati i dati con \func{freeaddrinfo} questi non +sarebbero più disponibili. + +Anche la nuova interfaccia definita da POSIX prevede una nuova funzione per +eseguire la risoluzione inversa e determinare nomi di servizi e di dominio +dati i rispettivi valori numerici. La funzione che sostituisce le varie +\func{gethostbyname}, \func{getipnodebyname} e \func{getservbyname} è +\funcd{getnameinfo}, ed il suo prototipo è: + +\begin{funcproto}{ +\fhead{netdb.h} +\fhead{sys/socket.h} +\fdecl{int getnameinfo(const struct sockaddr *sa, socklen\_t salen, \\ +\phantom{int getnameinfo(}char *host, size\_t hostlen, char *serv, size\_t +servlen, int flags)} +\fdesc{Effettua una risoluzione di un indirizzo di rete in maniera + indipendente dal protocollo.} +} + +{La funzione ritorna $0$ in caso di successo e un codice di errore diverso da + zero per un errore.} +\end{funcproto} + +La principale caratteristica di \func{getnameinfo} è che la funzione è in +grado di eseguire una risoluzione inversa in maniera indipendente dal +protocollo; il suo primo argomento \param{sa} infatti è il puntatore ad una +struttura degli indirizzi generica, che può contenere sia indirizzi IPv4 che +IPv6, la cui dimensione deve comunque essere specificata con l'argomento +\param{salen}. + +I risultati della funzione saranno restituiti nelle due stringhe puntate da +\param{host} e \param{serv}, che dovranno essere state precedentemente +allocate per una lunghezza massima che deve essere specificata con gli altri +due argomenti \param{hostlen} e \param{servlen}. Quando non si è +interessati ad uno dei due, si può passare il valore \val{NULL} come argomento, +così che la corrispondente informazione non venga richiesta. Infine l'ultimo +argomento \param{flags} è una maschera binaria i cui bit consentono di +impostare le modalità con cui viene eseguita la ricerca, e deve essere +specificato attraverso l'OR aritmetico dei valori illustrati in +tab.~\ref{tab:getnameinfo_flags}, nella seconda parte della tabella si sono +aggiunti i valori introdotto con la \acr{glibc} 2.3.4 per gestire la +internazionalizzione dei nomi a dominio. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \constd{NI\_DGRAM} & Richiede che venga restituito il nome del + servizio su UDP invece che quello su TCP per quei + pichi servizi (porte 512-214) che soni diversi + nei due protocolli.\\ + \constd{NI\_NOFQDN} & Richiede che venga restituita solo il nome della + macchina all'interno del dominio al posto del + nome completo (FQDN).\\ + \constd{NI\_NAMEREQD} & Richiede la restituzione di un errore se il nome + non può essere risolto.\\ + \constd{NI\_NUMERICHOST}& Richiede che venga restituita la forma numerica + dell'indirizzo (questo succede sempre se il nome + non può essere ottenuto).\\ + \constd{NI\_NUMERICSERV}& Richiede che il servizio venga restituito in + forma numerica (attraverso il numero di + porta).\\ + \hline + \const{NI\_IDN} & Se specificato il nome restituito viene convertito usando la + localizzazione corrente, se necessario, nella + codifica IDN.\\ + \const{NI\_IDN\_ALLOW\_UNASSIGNED} & attiva il controllo + \texttt{IDNA\_ALLOW\_UNASSIGNED}.\\ + \const{NI\_AI\_IDN\_USE\_STD3\_ASCII\_RULES} & attiva il controllo + \texttt{IDNA\_USE\_STD3\_ASCII\_RULES}\\ + \hline + \end{tabular} + \caption{Costanti associate ai bit dell'argomento \param{flags} della + funzione \func{getnameinfo}.} + \label{tab:getnameinfo_flags} +\end{table} + +La funzione ritorna zero in caso di successo, e scrive i propri risultati agli +indirizzi indicati dagli argomenti \param{host} e \param{serv} come stringhe +terminate dal carattere NUL, a meno che queste non debbano essere troncate +qualora la loro dimensione ecceda quelle specificate dagli argomenti +\param{hostlen} e \param{servlen}. Sono comunque definite le due costanti +\constd{NI\_MAXHOST} e \constd{NI\_MAXSERV}\footnote{in Linux le due costanti + sono definite in \headfile{netdb.h} ed hanno rispettivamente il valore 1024 + e 12.} che possono essere utilizzate come limiti massimi. In caso di +errore viene restituito invece un codice che assume gli stessi valori +illustrati in tab.~\ref{tab:addrinfo_error_code}. + +A questo punto possiamo fornire degli esempi di utilizzo della nuova +interfaccia, adottandola per le precedenti implementazioni del client e del +server per il servizio \textit{echo}; dato che l'uso delle funzioni appena +illustrate (in particolare di \func{getaddrinfo}) è piuttosto complesso, +essendo necessaria anche una impostazione diretta dei campi dell'argomento +\param{hints}, provvederemo una interfaccia semplificata per i due casi visti +finora, quello in cui si specifica nel client un indirizzo remoto per la +connessione al server, e quello in cui si specifica nel server un indirizzo +locale su cui porsi in ascolto. + +La prima funzione della nostra interfaccia semplificata è \texttt{sockconn} +che permette di ottenere un socket, connesso all'indirizzo ed al servizio +specificati. Il corpo della funzione è riportato in +fig.~\ref{fig:sockconn_code}, il codice completo è nel file \file{SockUtil.c} +dei sorgenti allegati alla guida, che contiene varie funzioni di utilità per +l'uso dei socket. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/sockconn.c} + \end{minipage} + \normalsize + \caption{Il codice della funzione \texttt{sockconn}.} + \label{fig:sockconn_code} +\end{figure} + +La funzione prende quattro argomenti, i primi due sono le stringhe che +indicano il nome della macchina a cui collegarsi ed il relativo servizio su +cui sarà effettuata la risoluzione; seguono il protocollo da usare (da +specificare con il valore numerico di \conffile{/etc/protocols}) ed il tipo di +socket (al solito specificato con i valori illustrati in +sez.~\ref{sec:sock_type}). La funzione ritorna il valore del file descriptor +associato al socket (un numero positivo) in caso di successo, o $-1$ in caso +di errore. + +Per risolvere il problema di non poter passare indietro i valori di ritorno di +\func{getaddrinfo} contenenti i relativi codici di errore si sono stampati i +messaggi d'errore direttamente nella funzione; infatti non si può avere +nessuna certezza che detti valori siano negativi e per cui stampare subito +l'errore diventa necessario per evitare ogni possibile ambiguità nei confronti +del valore di ritorno in caso di successo. + +Una volta definite le variabili occorrenti (\texttt{\small 3--5}) la funzione +prima (\texttt{\small 6}) azzera il contenuto della struttura \var{hint} e poi +provvede (\texttt{\small 7--9}) ad inizializzarne i valori necessari per la +chiamata (\texttt{\small 10}) a \func{getaddrinfo}. Di quest'ultima si +controlla (\texttt{\small 12--16}) il codice di ritorno, in modo da stampare +un avviso di errore, azzerare \var{errno} ed uscire in caso di errore. + +Dato che ad una macchina possono corrispondere più indirizzi IP, e di tipo +diverso (sia IPv4 che IPv6), mentre il servizio può essere in ascolto soltanto +su uno solo di questi, si provvede a tentare la connessione per ciascun +indirizzo restituito all'interno di un ciclo (\texttt{\small 18--40}) di +scansione della lista restituita da \func{getaddrinfo}, ma prima +(\texttt{\small 17}) si salva il valore del puntatore per poterlo riutilizzare +alla fine per disallocare la lista. + +Il ciclo viene ripetuto (\texttt{\small 18}) fintanto che si hanno indirizzi +validi, ed inizia (\texttt{\small 19}) con l'apertura del socket; se questa +fallisce si controlla (\texttt{\small 20}) se sono disponibili altri +indirizzi, nel qual caso si passa al successivo (\texttt{\small 21}) e si +riprende (\texttt{\small 22}) il ciclo da capo; se non ve ne sono si stampa +l'errore ritornando immediatamente (\texttt{\small 24--27}). + +Quando la creazione del socket ha avuto successo si procede (\texttt{\small + 29}) direttamente con la connessione, di nuovo in caso di fallimento viene +ripetuto (\texttt{\small 30--38}) il controllo se vi sono o no altri indirizzi +da provare nella stessa modalità fatta in precedenza, aggiungendovi però in +entrambi i casi (\texttt{\small 32} e (\texttt{\small 36}) la chiusura del +socket precedentemente aperto, che non è più utilizzabile. + +Se la connessione ha avuto successo invece si termina (\texttt{\small 39}) +direttamente il ciclo, e prima di ritornare (\texttt{\small 31}) il valore del +file descriptor del socket si provvede (\texttt{\small 30}) a liberare le +strutture \struct{addrinfo} allocate da \func{getaddrinfo} utilizzando il +valore del relativo puntatore precedentemente (\texttt{\small 17}) salvato. +Si noti come per la funzione sia del tutto irrilevante se la struttura +ritornata contiene indirizzi IPv6 o IPv4, in quanto si fa uso direttamente dei +dati relativi alle strutture degli indirizzi di \struct{addrinfo} che sono +opachi rispetto all'uso della funzione \func{connect}. + +Per usare questa funzione possiamo allora modificare ulteriormente il nostro +programma client per il servizio \textit{echo}; in questo caso rispetto al +codice usato finora per collegarsi (vedi fig.~\ref{fig:TCP_echo_client_1}) +avremo una semplificazione per cui il corpo principale del nostro client +diventerà quello illustrato in fig.~\ref{fig:TCP_echo_fifth}, in cui le +chiamate a \func{socket}, \func{inet\_pton} e \func{connect} sono sostituite +da una singola chiamata a \texttt{sockconn}. Inoltre il nuovo client (il cui +codice completo è nel file \file{TCP\_echo\_fifth.c} dei sorgenti allegati) +consente di utilizzare come argomento del programma un nome a dominio al posto +dell'indirizzo numerico, e può utilizzare sia indirizzi IPv4 che IPv6. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/TCP_echo_fifth.c} + \end{minipage} + \normalsize + \caption{Il nuovo codice per la connessione del client \textit{echo}.} + \label{fig:TCP_echo_fifth} +\end{figure} +La seconda funzione di ausilio che abbiamo creato è \texttt{sockbind}, il cui +corpo principale è riportato in fig.~\ref{fig:sockbind_code} (al solito il +sorgente completo è nel file \file{sockbind.c} dei sorgenti allegati alla +guida). Come si può notare la funzione è del tutto analoga alla precedente +\texttt{sockconn}, e prende gli stessi argomenti, però invece di eseguire una +connessione con \func{connect} si limita a chiamare \func{bind} per collegare +il socket ad una porta. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/sockbind.c} + \end{minipage} + \normalsize + \caption{Il codice della funzione \texttt{sockbind}.} + \label{fig:sockbind_code} +\end{figure} + +Dato che la funzione è pensata per essere utilizzata da un server ci si può +chiedere a quale scopo mantenere l'argomento \param{host} quando l'indirizzo +di questo è usualmente noto. Si ricordi però quanto detto in +sez.~\ref{sec:TCP_func_bind}, relativamente al significato della scelta di un +indirizzo specifico come argomento di \func{bind}, che consente di porre il +server in ascolto su uno solo dei possibili diversi indirizzi presenti su di +una macchina. Se non si vuole che la funzione esegua \func{bind} su un +indirizzo specifico, ma utilizzi l'indirizzo generico, occorrerà avere cura di +passare un valore \val{NULL} come valore per l'argomento \var{host}; l'uso +del valore \const{AI\_PASSIVE} serve ad ottenere il valore generico nella +rispettiva struttura degli indirizzi. + +Come già detto la funzione è analoga a \texttt{sockconn} ed inizia azzerando +ed inizializzando (\texttt{\small 6--11}) opportunamente la struttura +\var{hint} con i valori ricevuti come argomenti, soltanto che in questo caso +si è usata (\texttt{\small 8}) una impostazione specifica dei flag di +\var{hint} usando \const{AI\_PASSIVE} per indicare che il socket sarà usato +per una apertura passiva. Per il resto la chiamata (\texttt{\small 12--18}) a +\func{getaddrinfo} e ed il ciclo principale (\texttt{\small 20--42}) sono +identici, solo che si è sostituita (\texttt{\small 31}) la chiamata a +\func{connect} con una chiamata a \func{bind}. Anche la conclusione +(\texttt{\small 43--44}) della funzione è identica. + +Si noti come anche in questo caso si siano inserite le stampe degli errori +sullo \textit{standard error}, nonostante la funzione possa essere invocata da +un demone. Nel nostro caso questo non è un problema in quanto se la funzione +non ha successo il programma deve uscire immediatamente prima di essere posto +in background, e può quindi scrivere gli errori direttamente sullo +\textit{standard error}. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/TCP_echod_third.c} + \end{minipage} + \normalsize + \caption{Nuovo codice per l'apertura passiva del server \textit{echo}.} + \label{fig:TCP_echod_third} +\end{figure} +Con l'uso di questa funzione si può modificare anche il codice del nostro +server \textit{echo}, che rispetto a quanto illustrato nella versione iniziale +di fig.~\ref{fig:TCP_echo_server_first_code} viene modificato nella forma +riportata in fig.~\ref{fig:TCP_echod_third}. In questo caso il socket su cui +porsi in ascolto viene ottenuto (\texttt{\small 15--18}) da \texttt{sockbind} +che si cura anche della eventuale risoluzione di un indirizzo specifico sul +quale si voglia far ascoltare il server. \section{Le opzioni dei socket} -\label{sec:TCP_sock_options} +\label{sec:sock_options} -Finora abbiamo trattato i socket nel loro comportamento più comune, è però -possibile attivare alcune modalità diverse di funzionamento degli stessi +Benché dal punto di vista del loro uso come canali di trasmissione di dati i +socket vengano trattati allo stesso modo dei file, acceduti tramite i file +descriptor, e gestiti con le ordinarie funzioni di lettura e scrittura dei +file, l'interfaccia standard usata per la gestione dei file generici non è +comunque sufficiente a controllare la moltitudine di caratteristiche +specifiche che li contraddistinguono, considerato tra l'altro che queste +possono essere completamente diverse fra loro a seconda del tipo di socket e +della relativa forma di comunicazione sottostante. -Dato che la maggior parte delle opzioni dei socket sono relative ai socket -TCP, ed hanno poi significato analogo quando usate con altri socket, abbiamo -preferito trattare l'argomento in generale in questa sezione piuttosto che nel -capitolo dedicato alla trattazione generica dei socket. +In questa sezione vedremo allora quali sono le funzioni dedicate alla gestione +delle caratteristiche specifiche dei vari tipi di socket, che vengono +raggruppate sotto il nome generico di ``\textit{socket options}'', ma +soprattutto analizzaremo quali sono queste opzioni e quali caretteristiche e +comportamenti dei socket permettono di controllare. -\section{Altre funzioni di controllo} -\label{sec:TCP_sock_ctrl} +\subsection{Le funzioni di gestione delle opzioni dei socket} +\label{sec:sock_setsockopt} +La modalità principale con cui si possono gestire le caratteristiche dei +socket (ne vedremo delle ulteriori nelle prossime sezioni) è quella che passa +attraverso l'uso di due funzioni di sistema generiche che permettono +rispettivamente di impostarle e di recuperarne il valore corrente. La prima di +queste due funzioni, quella usata per impostare le \textit{socket options}, è +\funcd{setsockopt}, ed il suo prototipo è: +\begin{funcproto}{ +\fhead{sys/socket.h} +\fhead{sys/types.h} +\fdecl{int setsockopt(int sock, int level, int optname, const void + *optval, socklen\_t optlen)} +\fdesc{Imposta le opzioni di un socket.} +} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EBADF}] il file descriptor \param{sock} non è valido. + \item[\errcode{EFAULT}] l'indirizzo \param{optval} non è valido. + \item[\errcode{EINVAL}] il valore di \param{optlen} non è valido. + \item[\errcode{ENOPROTOOPT}] l'opzione scelta non esiste per il livello + indicato. + \item[\errcode{ENOTSOCK}] il file descriptor \param{sock} non corrisponde ad + un socket. + \end{errlist} +} +\end{funcproto} + +Il primo argomento della funzione, \param{sock}, indica il socket su cui si +intende operare; per indicare l'opzione da impostare si devono usare i due +argomenti successivi, \param{level} e \param{optname}. Come abbiamo visto in +sez.~\ref{sec:net_protocols} i protocolli di rete sono strutturati su vari +livelli, ed l'interfaccia dei socket può usarne più di uno. Si avranno allora +funzionalità e caratteristiche diverse per ciascun protocollo usato da un +socket, e quindi saranno anche diverse le opzioni che si potranno impostare +per ciascun socket, a seconda del \textsl{livello} (trasporto, rete, ecc.) su +cui si vuole andare ad operare. + +Il valore di \param{level} seleziona allora il protocollo su cui vuole +intervenire, mentre \param{optname} permette di scegliere su quale delle +opzioni che sono definite per quel protocollo si vuole operare. In sostanza la +selezione di una specifica opzione viene fatta attraverso una coppia di valori +\param{level} e \param{optname} e chiaramente la funzione avrà successo +soltanto se il protocollo in questione prevede quella opzione ed è utilizzato +dal socket. Infine \param{level} prevede anche il valore speciale +\const{SOL\_SOCKET} usato per le opzioni generiche che sono disponibili per +qualunque tipo di socket. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Livello} & \textbf{Significato} \\ + \hline + \hline + \constd{SOL\_SOCKET}& Opzioni generiche dei socket.\\ + \constd{SOL\_IP} & Opzioni specifiche per i socket che usano IPv4.\\ + \constd{SOL\_TCP} & Opzioni per i socket che usano TCP.\\ + \constd{SOL\_IPV6} & Opzioni specifiche per i socket che usano IPv6.\\ + \constd{SOL\_ICMPV6}& Opzioni specifiche per i socket che usano ICMPv6.\\ + \hline + \end{tabular} + \caption{Possibili valori dell'argomento \param{level} delle + funzioni \func{setsockopt} e \func{getsockopt}.} + \label{tab:sock_option_levels} +\end{table} + +I valori usati per \param{level}, corrispondenti ad un dato protocollo usato +da un socket, sono quelli corrispondenti al valore numerico che identifica il +suddetto protocollo in \conffile{/etc/protocols}; dato che la leggibilità di un +programma non trarrebbe certo beneficio dall'uso diretto dei valori numerici, +più comunemente si indica il protocollo tramite le apposite costanti +\texttt{SOL\_*} riportate in tab.~\ref{tab:sock_option_levels}, dove si sono +riassunti i valori che possono essere usati per l'argomento +\param{level}. + +La notazione in questo caso è, purtroppo, abbastanza confusa: infatti in Linux +il valore si può impostare sia usando le costanti \texttt{SOL\_*}, che le +analoghe \texttt{IPPROTO\_*} (citate anche da Stevens in \cite{UNP1}); +entrambe hanno gli stessi valori che sono equivalenti ai numeri di protocollo +di \conffile{/etc/protocols}, con una eccezione specifica, che è quella del +protocollo ICMP, per la quale non esiste una costante, il che è comprensibile +dato che il suo valore, 1, è quello che viene assegnato a \const{SOL\_SOCKET}. + +Il quarto argomento, \param{optval} è un puntatore ad una zona di memoria che +contiene i dati che specificano il valore dell'opzione che si vuole passare al +socket, mentre l'ultimo argomento \param{optlen},\footnote{questo argomento è + in realtà sempre di tipo \ctyp{int}, come era nelle \acr{libc4} e + \acr{libc5}; l'uso di \type{socklen\_t} è stato introdotto da POSIX (valgono + le stesse considerazioni per l'uso di questo tipo di dato fatte in + sez.~\ref{sec:TCP_func_accept}) ed adottato dalla \acr{glibc}.} è la +dimensione in byte dei dati presenti all'indirizzo indicato da \param{optval}. +Dato che il tipo di dati varia a seconda dell'opzione scelta, occorrerà +individuare qual è quello che deve essere usato, ed utilizzare le opportune +variabili. + +La gran parte delle opzioni utilizzano per \param{optval} un valore intero, se +poi l'opzione esprime una condizione logica, il valore è sempre un intero, ma +si dovrà usare un valore non nullo per abilitarla ed un valore nullo per +disabilitarla. Se invece l'opzione non prevede di dover ricevere nessun tipo +di valore si deve impostare \param{optval} a \val{NULL}. Un piccolo numero +di opzioni però usano dei tipi di dati peculiari, è questo il motivo per cui +\param{optval} è stato definito come puntatore generico. + +La seconda funzione usata per controllare le proprietà dei socket è +\funcd{getsockopt}, che serve a leggere i valori delle opzioni dei socket ed a +farsi restituire i dati relativi al loro funzionamento; il suo prototipo è: + + +\begin{funcproto}{ +\fhead{sys/socket.h} +\fhead{sys/types.h} +\fdecl{int getsockopt(int s, int level, int optname, void *optval, + socklen\_t *optlen)} +\fdesc{Legge le opzioni di un socket.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EBADF}] il file descriptor \param{sock} non è valido. + \item[\errcode{EFAULT}] l'indirizzo \param{optval} o quello di + \param{optlen} non è valido. + \item[\errcode{ENOPROTOOPT}] l'opzione scelta non esiste per il livello + indicato. + \item[\errcode{ENOTSOCK}] il file descriptor \param{sock} non corrisponde ad + un socket. + \end{errlist} +} +\end{funcproto} + +I primi tre argomenti sono identici ed hanno lo stesso significato di quelli +di \func{setsockopt}, anche se non è detto che tutte le opzioni siano definite +per entrambe le funzioni. In questo caso \param{optval} viene usato per +ricevere le informazioni ed indica l'indirizzo a cui andranno scritti i dati +letti dal socket, infine \param{optlen} diventa un puntatore ad una variabile +che viene usata come \textit{value result argument} per indicare, prima della +chiamata della funzione, la lunghezza del buffer allocato per \param{optval} e +per ricevere indietro, dopo la chiamata della funzione, la dimensione +effettiva dei dati scritti su di esso. Se la dimensione del buffer allocato +per \param{optval} non è sufficiente si avrà un errore. + + + +\subsection{Le opzioni generiche} +\label{sec:sock_generic_options} + +Come accennato esiste un insieme generico di opzioni dei socket che possono +applicarsi a qualunque tipo di socket, indipendentemente da quale protocollo +venga poi utilizzato. Una descrizione di queste opzioni è generalmente +disponibile nella settima sezione delle pagine di manuale; nel caso specifico +la si può consultare con \texttt{man 7 socket}. Se si vuole operare su queste +opzioni generiche il livello da utilizzare è \const{SOL\_SOCKET}; si è +riportato un elenco di queste opzioni in tab.~\ref{tab:sock_opt_socklevel}. + + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|c|c|l|l|} + \hline + \textbf{Opzione}&\texttt{get}&\texttt{set}&\textbf{flag}&\textbf{Tipo}& + \textbf{Descrizione}\\ + \hline + \hline + \const{SO\_ACCEPTCONN}&$\bullet$& & &\texttt{int}& + Indica se il socket è in ascolto.\\ + \const{SO\_ATTACH\_FILTER}& &$\bullet$& &\texttt{sock\_fprog}& + Aggancia un filtro BPF al socket.\\ + \const{SO\_BINDTODEVICE}&$\bullet$&$\bullet$& &\texttt{char *}& + Lega il socket ad un dispositivo.\\ + \const{SO\_BROADCAST}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Attiva o disattiva il \textit{broadcast}.\\ + \const{SO\_BSDCOMPAT}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita la compatibilità con BSD.\\ + \const{SO\_BUSY\_POLL}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Attiva il ``\textit{busy poll}'' sul socket.\\ + \const{SO\_DEBUG} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita il debugging sul socket.\\ + \const{SO\_DETACH\_FILTER}& &$\bullet$&$\bullet$&\texttt{int}& + Rimuove il filtro BPF agganciato al socket.\\ + \const{SO\_DOMAIN} &$\bullet$& & &\texttt{int}& + Legge il tipo di socket.\\ + \const{SO\_DONTROUTE}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Non invia attraverso un gateway.\\ + \const{SO\_ERROR} &$\bullet$& & &\texttt{int}& + Riceve e cancella gli errori pendenti.\\ + \const{SO\_KEEPALIVE}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Controlla l'attività della connessione.\\ + \const{SO\_LINGER} &$\bullet$&$\bullet$& &\texttt{linger}& + Indugia nella chiusura con dati da spedire.\\ + \const{SO\_LOCK\_FILTER}& &$\bullet$&$\bullet$&\texttt{int}& + Blocca il filtro BPF agganciato al socket.\\ + \const{SO\_MARK} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta un ``\textit{firewall mark}'' sul socket.\\ + \const{SO\_OOBINLINE}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Lascia in linea i dati \textit{out-of-band}.\\ + \const{SO\_PASSCRED} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita la ricezione di credenziali.\\ + \const{SO\_PEEK\_OFF} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Imposta il valore del ``\textit{peek offset}''.\\ + \const{SO\_PEERCRED} &$\bullet$& & &\texttt{ucred}& + Restituisce le credenziali del processo remoto.\\ + \const{SO\_PRIORITY} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta la priorità del socket.\\ + \const{SO\_PROTOCOL} &$\bullet$& & &\texttt{int}& + Ottiene il protocollo usato dal socket.\\ + \const{SO\_RCVBUF} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta dimensione del buffer di ricezione.\\ + \const{SO\_RCVBUFFORCE}&$\bullet$&$\bullet$& &\texttt{int}& + Forza dimensione del buffer di ricezione.\\ + \const{SO\_RCVLOWAT} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Basso livello sul buffer di ricezione.\\ + \const{SO\_RCVTIMEO} &$\bullet$&$\bullet$& &\texttt{timeval}& + Timeout in ricezione.\\ + \const{SO\_REUSEADDR}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Consente il riutilizzo di un indirizzo locale.\\ + \const{SO\_REUSEPORT}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Consente il riutilizzo di una porta.\\ + \const{SO\_RXQ\_OVFL} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Richiede messaggio ancillare con pacchetti persi.\\ + \const{SO\_SNDBUF} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta dimensione del buffer di trasmissione.\\ + \const{SO\_SNDBUFFORCE}&$\bullet$&$\bullet$& &\texttt{int}& + Forza dimensione del buffer di trasmissione.\\ + \const{SO\_SNDLOWAT} &$\bullet$&$\bullet$& &\texttt{int}& + Basso livello sul buffer di trasmissione.\\ + \const{SO\_SNDTIMEO} &$\bullet$&$\bullet$& &\texttt{timeval}& + Timeout in trasmissione.\\ + \const{SO\_TIMESTAMP}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita/disabilita la ricezione dei \textit{timestamp}.\\ + \const{SO\_TYPE} &$\bullet$& & &\texttt{int}& + Restituisce il tipo di socket.\\ + \hline + \end{tabular} + \caption{Le opzioni disponibili al livello \const{SOL\_SOCKET}.} + \label{tab:sock_opt_socklevel} +\end{table} + +% TODO aggiungere e documentare SO_ATTACH_BPF, introdotta con il kernel 3.19, +% vedi http://lwn.net/Articles/625224/ +% TODO aggiungere e documentare SO_INCOMING_CPU, introdotta con il kernel 3.19, +% TODO documentare SO_PEERGROUPS introdotta con il kernel 4.13, citata +% in https://lwn.net/Articles/727385/ +% TODO documentare SO_ZEROCOPY, vedi https://lwn.net/Articles/726917/ (e il +% resto pure) introdotta con il kernel 4.14 + +La tabella elenca le costanti che identificano le singole opzioni da usare +come valore per \param{optname}; le due colonne seguenti indicano per quali +delle due funzioni (\func{getsockopt} o \func{setsockopt}) l'opzione è +disponibile, mentre la colonna successiva indica, quando si ha a che fare con +un valore di \param{optval} intero, se l'opzione è da considerare un numero o +un valore logico. Si è inoltre riportato sulla quinta colonna il tipo di dato +usato per \param{optval} ed una breve descrizione del significato delle +singole opzioni sulla sesta. + +Le descrizioni delle opzioni presenti in tab.~\ref{tab:sock_opt_socklevel} +sono estremamente sommarie, è perciò necessario fornire un po' più di +informazioni. Alcune opzioni inoltre hanno una notevole rilevanza nella +gestione dei socket, e pertanto il loro utilizzo sarà approfondito +separatamente in sez.~\ref{sec:sock_options_main}. Quello che segue è quindi +soltanto un elenco più dettagliato della breve descrizione di +tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: + +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} +\item[\constd{SO\_ACCEPTCONN}] questa opzione permette di rilevare se il socket + su cui opera è stato posto in modalità di ricezione di eventuali connessioni + con una chiamata a \func{listen}. L'opzione può essere usata soltanto con + \func{getsockopt} ed utilizza per \param{optval} un intero in cui viene + restituito 1 se il socket è in ascolto e 0 altrimenti. + +\item[\constd{SO\_ATTACH\_FILTER}] questa opzione permette di agganciare ad un + socket un filtro di selezione dei pacchetti con la stessa sintassi del BPF + (\textit{Berkley Packet Filter}) di BSD, che consente di selezionare, fra + tutti quelli ricevuti, verranno letti. Può essere usata solo con + \func{setsockopt} ed utilizza per \param{optval} un puntatore ad una + struttura \struct{sock\_fprog} (definita in + \headfile{linux/filter.h}). Questa opzione viene usata principalmente con i + socket di tipo \const{AF\_PACKET} (torneremo su questo in + sez.~\ref{sec:packet_socket}) dalla libreria \texttt{libpcap} per + implementare programmi di cattura dei pacchetti, e per questo tipo di + applicazione è opportuno usare sempre quest'ultima.\footnote{la trattazione + del BPF va al di là dell'argomento di questa sezione per la documentazione + si consulti il file \texttt{networking/filter.txt} nella documentazione + del kernel.} + +\item[\constd{SO\_BINDTODEVICE}] questa opzione permette di \textsl{legare} il + socket ad una particolare interfaccia, in modo che esso possa ricevere ed + inviare pacchetti solo su quella. L'opzione richiede per \param{optval} il + puntatore ad una stringa contenente il nome dell'interfaccia (ad esempio + \texttt{eth0}); utilizzando una stringa nulla o un valore nullo per + \param{optlen} si può rimuovere un precedente collegamento. + + Il nome della interfaccia deve essere specificato con una stringa terminata + da uno zero e di lunghezza massima pari a \constd{IFNAMSIZ}; l'opzione è + effettiva solo per alcuni tipi di socket, ed in particolare per quelli della + famiglia \const{AF\_INET}; non è invece supportata per i \textit{packet + socket} (vedi sez.~\ref{sec:socket_raw}). + +\item[\constd{SO\_BROADCAST}] questa opzione abilita il \textit{broadcast}: + quando abilitata i socket di tipo \const{SOCK\_DGRAM} riceveranno i + pacchetti inviati all'indirizzo di \textit{broadcast} e potranno scrivere + pacchetti su tale indirizzo. Prende per \param{optval} un intero usato come + valore logico. L'opzione non ha effetti su un socket di tipo + \const{SOCK\_STREAM}. + +\item[\constd{SO\_BSDCOMPAT}] questa opzione abilita la compatibilità con il + comportamento di BSD (in particolare ne riproduce alcuni bug). Attualmente + è una opzione usata solo per il protocollo UDP e ne è prevista la rimozione. + L'opzione utilizza per \param{optval} un intero usato come valore logico. + + Quando viene abilitata gli errori riportati da messaggi ICMP per un socket + UDP non vengono passati al programma in \textit{user space}. Con le versioni + 2.0.x del kernel erano anche abilitate altre opzioni di compatibilità per i + socket raw (modifiche casuali agli header, perdita del flag di + \textit{broadcast}) che sono state rimosse con il passaggio al 2.2; è + consigliato correggere i programmi piuttosto che usare questa funzione. Dal + kernel 2.4 viene ignorata, e dal 2.6 genera un messaggio di log del kernel. + +\item[\constd{SO\_BUSY\_POLL}] questa opzione, presente dal kernel 3.11, + imposta un tempo approssimato in microsecondi, per cui in caso di ricezione + bloccante verrà eseguito un \itindex{busy~poll} ``\textit{busy + poll}'',\footnote{con \textit{busy poll} si fa riferimento al + \textit{polling} su una risorsa occupata; si continuerà cioè a tentare di + leggere anche quando non ci sono dati senza portare il processo stato di + \textit{sleep}, in alcuni casi, quando ci si aspetta che i dati arrivino a + breve, questa tecnica può dare un miglioramento delle prestazioni.} da + indicare in \param{optval} con un valore intero. Si tratta di una opzione + utilizzabile solo con socket che ricevono dati da un dispositivo di rete che + la supporti, e che consente di ridurre la latenza per alcune applicazioni, + ma che comporta un maggiore utilizzo della CPU (e quindi di energia); per + questo il valore può essere aumentato solo da processi con i privilegi di + amministratore (in particolare con la \textit{capability} + \const{CAP\_NET\_ADMIN}). Il valore di default viene controllato dal file + \sysctlrelfile{net/core}{busy\_read} per le funzioni di lettura mentre il + file \sysctlrelfile{net/core}{busy\_poll} controlla il ``\textit{busy + poll}'' per \func{select} e \func{poll}. + +\item[\constd{SO\_DEBUG}] questa opzione abilita il debugging delle operazioni + dei socket; l'opzione utilizza per \param{optval} un intero usato come + valore logico, e può essere utilizzata solo da un processo con i privilegi + di amministratore (in particolare con la \textit{capability} + \const{CAP\_NET\_ADMIN}). L'opzione necessita inoltre dell'opportuno + supporto nel kernel;\footnote{deve cioè essere definita la macro di + preprocessore \macrod{SOCK\_DEBUGGING} nel file \file{include/net/sock.h} + dei sorgenti del kernel, questo è sempre vero nei kernel delle serie + superiori alla 2.3, per i kernel delle serie precedenti invece è + necessario aggiungere a mano detta definizione; è inoltre possibile + abilitare anche il tracciamento degli stati del TCP definendo la macro + \macrod{STATE\_TRACE} in \file{include/net/tcp.h}.} quando viene + abilitata una serie di messaggi con le informazioni di debug vengono inviati + direttamente al sistema del kernel log.\footnote{si tenga presente che il + comportamento è diverso da quanto avviene con BSD, dove l'opzione opera + solo sui socket TCP, causando la scrittura di tutti i pacchetti inviati + sulla rete su un buffer circolare che viene letto da un apposito + programma, \cmd{trpt}.} + +\item[\constd{SO\_DETACH\_FILTER}] consente di distaccare un filtro + precedentemente aggiunto ad un socket con l'opzione + \const{SO\_ATTACH\_FILTER}, in genere non viene usata direttamente in quanto + i filtri BPF vengono automaticamente rimossi alla chiusura del socket, il + suo utilizzo è pertanto limitato ai rari casi in cui si vuole rimuovere un + precedente filtro per inserirne uno diverso. Come \const{SO\_ATTACH\_FILTER} + può essere usato solo \func{setsockopt} e prende per \param{optval} un + intero usato come valore logico. + +\item[\constd{SO\_DOMAIN}] questa opzione, presente dal kernel 2.6.32, legge + il ``\textsl{dominio}'' (la famiglia di indirizzi) del socket. +. Funziona solo con \func{getsockopt}, ed + utilizza per \param{optval} un intero in cui verrà restituito il valore + numerico che lo identifica (ad esempio \texttt{AF\_INET}). + +\item[\constd{SO\_DONTROUTE}] questa opzione richiede che l'invio dei + pacchetti del socket sia eseguito soltanto verso una destinazione + direttamente connessa, impedendo l'uso di un \textit{gateway} e saltando + ogni processo relativo all'uso della tabella di routing del kernel. Prende + per \param{optval} un intero usato come valore logico. È equivalente all'uso + del flag \const{MSG\_DONTROUTE} su una \func{send} (vedi + sez.~\ref{sec:net_send_recv}). + +\item[\constd{SO\_ERROR}] questa opzione riceve un errore presente sul socket; + può essere utilizzata soltanto con \func{getsockopt} e prende per + \param{optval} un valore intero, nel quale viene restituito il codice di + errore, e la condizione di errore sul socket viene cancellata. Viene + usualmente utilizzata per ricevere il codice di errore, come accennato in + sez.~\ref{sec:TCP_sock_select}, quando si sta osservando il socket con una + \func{select} che ritorna a causa dello stesso. + +\item[\const{SO\_KEEPALIVE}] questa opzione abilita un meccanismo di verifica + della persistenza di una connessione associata al socket; è pertanto + effettiva solo sui socket che supportano le connessioni, ed è usata + principalmente con il TCP. L'opzione utilizza per \param{optval} un intero + usato come valore logico. Maggiori dettagli sul suo funzionamento sono + forniti in sez.~\ref{sec:sock_options_main}. + +\item[\const{SO\_LINGER}] questa opzione controlla le modalità con cui viene + chiuso un socket quando si utilizza un protocollo che supporta le + connessioni (è pertanto usata con i socket TCP ed ignorata per UDP) e + modifica il comportamento delle funzioni \func{close} e \func{shutdown}. + L'opzione richiede che l'argomento \param{optval} sia una struttura di tipo + \struct{linger}, definita in \headfile{sys/socket.h} ed illustrata in + fig.~\ref{fig:sock_linger_struct}. Maggiori dettagli sul suo funzionamento + sono forniti in sez.~\ref{sec:sock_options_main}. + +\item[\constd{SO\_LOCK\_FILTER}] consente di bloccare un filtro + precedentemente aggiunto ad un socket con l'opzione + \const{SO\_ATTACH\_FILTER}, in modo che non possa essere né rimosso né + modificato, questo consente di impostare un filtro su un socket, bloccarlo e + poi cedere i privilegi con la sicurezza che il filtro permarrà fino alla + chiusura del socket. Come \const{SO\_ATTACH\_FILTER} può essere usato solo + \func{setsockopt} e prende per \param{optval} un intero usato come valore + logico. + +\item[\constd{SO\_MARK}] questa opzione, presente dal kernel 2.6.25, imposta + un valore di marcatura sui pacchetti del socket. Questa è una funzionalità + specifica di Linux, ottenibile anche con l'uso del target \texttt{MARK} + del comando \texttt{iptables} (l'argomento è trattato in sez.~3.3.5 di + \cite{SGL}). Il valore di marcatura viene mantenuto all'interno dello stack + di rete del kernel e può essere usato sia dal \itindex{netfilter} + \textit{netfilter}\footnote{il \textit{netfilter} è l'infrastruttura usata + per il filtraggio dei pacchetti del kernel, per maggiori dettagli si + consulti il cap.~2 di \cite{FwGL}.} di Linux che per impostare politiche + di routing avanzato. Il valore deve essere specificato in \param{optval} + come un intero. L'opzione richiede i privilegi di amministratore con la + \textit{capability} \const{CAP\_NET\_ADMIN}. + +\item[\constd{SO\_OOBINLINE}] se questa opzione viene abilitata i dati + \textit{out-of-band} vengono inviati direttamente nel flusso di dati del + socket (e sono quindi letti con una normale \func{read}) invece che restare + disponibili solo per l'accesso con l'uso del flag \const{MSG\_OOB} di + \func{recvmsg}. L'argomento è trattato in dettaglio in + sez.~\ref{sec:TCP_urgent_data}. L'opzione funziona soltanto con socket che + supportino i dati \textit{out-of-band} (non ha senso per socket UDP ad + esempio), ed utilizza per \param{optval} un intero usato come valore logico. + +\item[\constd{SO\_PASSCRED}] questa opzione abilita sui socket unix-domain + (vedi sez.~\ref{sec:unix_socket}) la ricezione dei messaggi di controllo di + tipo \const{SCM\_CREDENTIALS}. Prende come \param{optval} un intero usato + come valore logico. + +\item[\constd{SO\_PEEK\_OFF}] questa opzione, disponibile a partire dal kernel + 3.4, imposta un ``\textit{peek offset}'' sul socket (attualmente disponibile + solo per i socket unix-domain (vedi sez.~\ref{sec:unix_socket}). La funzione + serve come ausilio per l'uso del flag \const{MSG\_PEEK} di \func{recv} che + consente di ``\textsl{sbirciare}'' nei dati di un socket, cioè di leggerli + senza rimuoverli dalla coda in cui sono mantenuti, così che vengano + restituiti anche da una successiva lettura ordinaria. + + Un valore negativo (il default è $-1$) riporta alla situazione ordinaria in + cui si ``\textsl{sbircia}'' a partire dalla testa della coda, un valore + positivo consente di leggere a partire dalla posizione indicata nella coda e + tutte le volte che si sbirciano dei dati il valore dell'offset viene + automaticamente aumentato della quantità di dati sbirciati, in modo che si + possa proseguire da dove si era arrivati. Il valore deve essere specificato + in \param{optval} come intero. + +\item[\constd{SO\_PEERCRED}] questa opzione restituisce le credenziali del + processo remoto connesso al socket; l'opzione è disponibile solo per socket + unix-domain di tipo \textit{stream} e anche per quelli di tipo + \textit{datagram} quando se ne crea una coppia con \func{socketpair}, e può + essere usata solo con \func{getsockopt}. Utilizza per + \param{optval} una apposita struttura \struct{ucred} (vedi + sez.~\ref{sec:unix_socket}). + +\item[\constd{SO\_PRIORITY}] questa opzione permette di impostare le priorità + per tutti i pacchetti che sono inviati sul socket, prende per \param{optval} + un valore intero. Con questa opzione il kernel usa il valore per ordinare le + priorità sulle code di rete,\footnote{questo richiede che sia abilitato il + sistema di \textit{Quality of Service} disponibile con le opzioni di + routing avanzato.} i pacchetti con priorità più alta vengono processati + per primi, in modalità che dipendono dalla disciplina di gestione della + coda. Nel caso di protocollo IP questa opzione permette anche di impostare i + valori del campo \textit{type of service} (noto come TOS, vedi + sez.~\ref{sec:IP_header}) per i pacchetti uscenti. Per impostare una + priorità al di fuori dell'intervallo di valori fra 0 e 6 sono richiesti i + privilegi di amministratore con la \textit{capability} + \const{CAP\_NET\_ADMIN}. + +\item[\constd{SO\_PROTOCOL}] questa opzione, presente dal kernel 2.6.32, legge + il protocollo usato dal socket. Funziona solo con \func{getsockopt}, ed + utilizza per \param{optval} un intero in cui verrà restituito il valore + numerico che lo identifica (ad esempio \texttt{IPPROTO\_TCP}). + +\item[\constd{SO\_RCVBUF}] questa opzione imposta la dimensione del buffer di + ricezione del socket. Prende per \param{optval} un intero indicante il + numero di byte. Il valore di default ed il valore massimo che si può + specificare come argomento per questa opzione sono impostabili tramiti gli + opportuni valori di \func{sysctl} (vedi sez.~\ref{sec:sock_sysctl}). + + Si tenga presente che nel caso di socket TCP il kernel alloca effettivamente + una quantità di memoria doppia rispetto a quanto richiesto con + \func{setsockopt} per entrambe le opzioni \const{SO\_RCVBUF} e + \const{SO\_SNDBUF}. Questo comporta che una successiva lettura con + \func{getsockopt} riporterà un valore diverso da quello impostato con + \func{setsockopt}. Questo avviene perché TCP necessita dello spazio in più + per mantenere dati amministrativi e strutture interne, e solo una parte + viene usata come buffer per i dati, mentre il valore letto da + \func{getsockopt} e quello riportato nei vari parametri di + \textit{sysctl}\footnote{cioè \sysctlrelfile{net/core}{wmem\_max} e + \sysctlrelfile{net/core}{rmem\_max} in \texttt{/proc/sys/net/core} e + \sysctlrelfile{net/ipv4}{tcp\_wmem} e \sysctlrelfile{net/ipv4}{tcp\_rmem} + in \texttt{/proc/sys/net/ipv4}, vedi sez.~\ref{sec:sock_sysctl}.} indica + la memoria effettivamente impiegata. Si tenga presente inoltre che le + modifiche alle dimensioni dei buffer di ricezione e trasmissione, per poter + essere effettive, devono essere impostate prima della chiamata alle funzioni + \func{listen} o \func{connect}. + +\item[\constd{SO\_RCVBUFFORCE}] questa opzione, presente dal kernel 2.6.14, è + identica a \const{SO\_RCVBUF} ma consente ad un processo con i privilegi di + amministratore (per la precisione con la \textit{capability} + \const{CAP\_NET\_ADMIN}) di impostare in valore maggiore del limite di + \sysctlrelfile{net/core}{rmem\_max}. + +\item[\constd{SO\_RCVLOWAT}] questa opzione imposta il valore che indica il + numero minimo di byte che devono essere presenti nel buffer di ricezione + perché il kernel passi i dati all'utente, restituendoli ad una \func{read} o + segnalando ad una \func{select} (vedi sez.~\ref{sec:TCP_sock_select}) che ci + sono dati in ingresso. L'opzione utilizza per \param{optval} un intero che + specifica il numero di byte; con Linux questo valore è sempre 1 e può essere + cambiato solo con i kernel a partire dal 2.4. Si tenga presente però che per + i kernel prima del 2.6.28 sia \func{poll} che \func{select} non supportano + questa funzionalità e ritornano comunque, indicando il socket come + leggibile, non appena almeno un byte è presente, con una successiva lettura + con \func{read} che si blocca fintanto che non diventa disponibile la + quantità di byte indicati. Con \func{getsockopt} si può leggere questo + valore mentre \func{setsockopt} darà un errore di \errcode{ENOPROTOOPT} + quando il cambiamento non è supportato. + +\item[\constd{SO\_RCVTIMEO}] l'opzione permette di impostare un tempo massimo + sulle operazioni di lettura da un socket, e prende per \param{optval} una + struttura di tipo \struct{timeval} (vedi fig.~\ref{fig:sys_timeval_struct}) + identica a quella usata con \func{select}. Con \func{getsockopt} si può + leggere il valore attuale, mentre con \func{setsockopt} si imposta il tempo + voluto, usando un valore nullo per \struct{timeval} il timeout viene + rimosso. + + Se l'opzione viene attivata tutte le volte che una delle funzioni di lettura + (\func{read}, \func{readv}, \func{recv}, \func{recvfrom} e \func{recvmsg}) + si blocca in attesa di dati per un tempo maggiore di quello impostato, essa + ritornerà un valore -1 e la variabile \var{errno} sarà impostata con un + errore di \errcode{EAGAIN} e \errcode{EWOULDBLOCK}, così come sarebbe + avvenuto se si fosse aperto il socket in modalità non bloccante.\footnote{in + teoria, se il numero di byte presenti nel buffer di ricezione fosse + inferiore a quello specificato da \const{SO\_RCVLOWAT}, l'effetto potrebbe + essere semplicemente quello di provocare l'uscita delle funzioni di + lettura restituendo il numero di byte fino ad allora ricevuti.} + + In genere questa opzione non è molto utilizzata se si ha a che fare con la + lettura dei dati, in quanto è sempre possibile usare una \func{select} che + consente di specificare un \textit{timeout}; l'uso di \func{select} non + consente però di impostare il timeout per l'uso di \func{connect}, per avere + il quale si può ricorrere a questa opzione (nel qual caso il raggiungimento + del \textit{timeout} restituisce l'errore \errcode{EINPROGRESS}). + +\item[\const{SO\_REUSEADDR}] questa opzione permette di eseguire la funzione + \func{bind} su indirizzi locali che siano già in uso da altri socket; + l'opzione utilizza per \param{optval} un intero usato come valore logico. + Questa opzione modifica il comportamento normale dell'interfaccia dei socket + che fa fallire l'esecuzione della funzione \func{bind} con un errore di + \errcode{EADDRINUSE} quando l'indirizzo locale (più propriamente il + controllo viene eseguito sulla porta) è già in uso da parte di un altro + socket. Maggiori dettagli sul suo funzionamento sono forniti in + sez.~\ref{sec:sock_options_main}. + +\item[\const{SO\_REUSEPORT}] questa opzione, presente a partire dal kernel + 3.9, permette di far usare a più socket di tipo \const{AF\_INET} o + \const{AF\_INET6} lo stesso indirizzo locale, e costituisce una estensione + della precedente \const{SO\_REUSEADDR}. Maggiori dettagli sul suo + funzionamento sono forniti in sez.~\ref{sec:sock_options_main}. + +\item[\constd{SO\_RXQ\_OVFL}] questa opzione, presente dal kernel 2.6.33, + permette di abilitare o disabilitare sul socket la ricezione di un messaggio + ancillare (tratteremo l'argomento in sez.~\ref{sec:net_ancillary_data}) + contenente un intero senza segno a 32 bit che indica il numero di pacchetti + scartati sul socket fra l'ultimo pacchetto ricevuto e questo. L'opzione + utilizza per \param{optval} un intero usato come valore logico. + +% TODO documentare SO_RXQ_OVFL, vedi https://lwn.net/Articles/626150/ capire +% che significa 'questo' + +\item[\constd{SO\_SNDLOWAT}] questa opzione imposta il valore che indica il + numero minimo di byte che devono essere presenti nel buffer di trasmissione + perché il kernel li invii al protocollo successivo, consentendo ad una + \func{write} di ritornare o segnalando ad una \func{select} (vedi + sez.~\ref{sec:TCP_sock_select}) che è possibile eseguire una scrittura. + L'opzione utilizza per \param{optval} un intero che specifica il numero di + byte; con Linux questo valore è sempre 1 e non può essere cambiato; + \func{getsockopt} leggerà questo valore mentre \func{setsockopt} darà un + errore di \errcode{ENOPROTOOPT}. + +\item[\constd{SO\_SNDBUF}] questa opzione imposta la dimensione del buffer di + trasmissione del socket. Prende per \param{optval} un intero indicante il + numero di byte. Il valore di default ed il valore massimo che si possono + specificare come argomento per questa opzione sono impostabili + rispettivamente tramite gli opportuni valori di \func{sysctl} (vedi + sez.~\ref{sec:sock_sysctl}). + +\item[\constd{SO\_SNDBUFFORCE}] questa opzione, presente dal kernel 2.6.14, è + identica a \const{SO\_SNDBUF} ma consente ad un processo con i privilegi di + amministratore (per la precisione con la \textit{capability} + \const{CAP\_NET\_ADMIN}) di impostare in valore maggiore del limite di + \sysctlrelfile{net/core}{wmem\_max}. + +% TODO verificare il timeout con un programma di test + +\item[\constd{SO\_SNDTIMEO}] l'opzione permette di impostare un tempo massimo + sulle operazioni di scrittura su un socket, ed usa gli stessi valori di + \const{SO\_RCVTIMEO}. In questo caso però si avrà un errore di + \errcode{EAGAIN} o \errcode{EWOULDBLOCK} per le funzioni di scrittura + \func{write}, \func{writev}, \func{send}, \func{sendto} e \func{sendmsg} + qualora queste restino bloccate per un tempo maggiore di quello specificato. + +\item[\constd{SO\_TIMESTAMP}] questa opzione, presente dal kernel 2.6.30, + permette di abilitare o disabilitare sul socket la ricezione di un messaggio + ancillare di tipo \const{SO\_TIMESTAMP}. Il messaggio viene inviato con + livello \const{SOL\_SOCKET} ed nel campo \var{cmsg\_data} (per i dettagli si + veda sez.~\ref{sec:net_ancillary_data}) viene impostata una struttura + \struct{timeval} che indica il tempo di ricezione dell'ultimo pacchetto + passato all'utente. L'opzione utilizza per \param{optval} un intero usato + come valore logico. + +% TODO capire meglio la tempistica di questi messaggi ancillari +% TODO documentare SO_TIMESTAMP e le altre opzioni di timestamping dei +% pacchetti, introdotte nel 2.6.30, vedi nei sorgenti del kernel: +% Documentation/networking/timestamping.txt + +\item[\constd{SO\_TYPE}] questa opzione permette di leggere il tipo di socket + su cui si opera; funziona solo con \func{getsockopt}, ed utilizza per + \param{optval} un intero in cui verrà restituito il valore numerico che lo + identifica (ad esempio \const{SOCK\_STREAM}). + + +\end{basedescript} + + +\subsection{L'uso delle principali opzioni dei socket} +\label{sec:sock_options_main} + +La descrizione sintetica del significato delle opzioni generiche dei socket, +riportata nell'elenco in sez.~\ref{sec:sock_generic_options}, è +necessariamente sintetica, alcune di queste però possono essere utilizzate +per controllare delle funzionalità che hanno una notevole rilevanza nella +programmazione dei socket. Per questo motivo faremo in questa sezione un +approfondimento sul significato delle opzioni generiche più importanti. + + +\constbeg{SO\_KEEPALIVE} +\subsubsection{L'opzione \const{SO\_KEEPALIVE}} + +La prima opzione da approfondire è \const{SO\_KEEPALIVE} che permette di +tenere sotto controllo lo stato di una connessione. Una connessione infatti +resta attiva anche quando non viene effettuato alcun traffico su di essa; è +allora possibile, in caso di una interruzione completa della rete, che la +caduta della connessione non venga rilevata, dato che sulla stessa non passa +comunque alcun traffico. + +Se si imposta questa opzione, è invece cura del kernel inviare degli appositi +messaggi sulla rete, detti appunto \textit{keep-alive}, per verificare se la +connessione è attiva. L'opzione funziona soltanto con i socket che supportano +le connessioni (non ha senso per socket UDP ad esempio) e si applica +principalmente ai socket TCP. + +Con le impostazioni di default (che sono riprese da BSD) Linux emette un +messaggio di \textit{keep-alive} (in sostanza un segmento ACK vuoto, cui sarà +risposto con un altro segmento ACK vuoto) verso l'altro capo della connessione +se questa è rimasta senza traffico per più di due ore. Se è tutto a posto il +messaggio viene ricevuto e verrà emesso un segmento ACK di risposta, alla cui +ricezione ripartirà un altro ciclo di attesa per altre due ore di inattività; +il tutto avviene all'interno del kernel e le applicazioni non riceveranno +nessun dato. + +Qualora ci siano dei problemi di rete si possono invece verificare i due casi +di terminazione precoce del server già illustrati in +sez.~\ref{sec:TCP_conn_crash}. Il primo è quello in cui la macchina remota ha +avuto un crollo del sistema ed è stata riavviata, per cui dopo il riavvio la +connessione non esiste più.\footnote{si ricordi che un normale riavvio o il + crollo dell'applicazione non ha questo effetto, in quanto in tal caso si + passa sempre per la chiusura del processo, e questo, come illustrato in + sez.~\ref{sec:file_open_close}, comporta anche la regolare chiusura del + socket con l'invio di un segmento FIN all'altro capo della connessione.} In +questo caso all'invio del messaggio di \textit{keep-alive} si otterrà come +risposta un segmento RST che indica che l'altro capo non riconosce più +l'esistenza della connessione ed il socket verrà chiuso riportando un errore +di \errcode{ECONNRESET}. + +Se invece non viene ricevuta nessuna risposta (indice che la macchina non è +più raggiungibile) l'emissione dei messaggi viene ripetuta ad intervalli di 75 +secondi per un massimo di 9 volte\footnote{entrambi questi valori possono + essere modificati a livello di sistema (cioè per tutti i socket) con gli + opportuni parametri illustrati in sez.~\ref{sec:sock_sysctl} ed a livello di + singolo socket con le opzioni \texttt{TCP\_KEEP*} di + sez.~\ref{sec:sock_tcp_udp_options}.} (per un totale di 11 minuti e 15 +secondi) dopo di che, se non si è ricevuta nessuna risposta, il socket viene +chiuso dopo aver impostato un errore di \errcode{ETIMEDOUT}. Qualora la +connessione si sia ristabilita e si riceva un successivo messaggio di risposta +il ciclo riparte come se niente fosse avvenuto. Infine se si riceve come +risposta un pacchetto ICMP di destinazione irraggiungibile (vedi +sez.~\ref{sec:ICMP_protocol}), verrà restituito l'errore corrispondente. + +In generale questa opzione serve per individuare una caduta della connessione +anche quando non si sta facendo traffico su di essa. Viene usata +principalmente sui server per evitare di mantenere impegnate le risorse che +verrebbero dedicate a trattare delle connessioni che in realtà sono già +terminate (quelle che vengono anche chiamate connessioni +\textsl{semi-aperte}); in tutti quei casi cioè in cui il server si trova in +attesa di dati in ingresso su una connessione che non arriveranno mai o perché +il client sull'altro capo non è più attivo o perché non è più in grado di +comunicare con il server via rete. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/TCP_echod_fourth.c} + \end{minipage} + \normalsize + \caption{La sezione della nuova versione del server del servizio + \textit{echo} che prevede l'attivazione del \textit{keepalive} sui + socket.} + \label{fig:echod_keepalive_code} +\end{figure} + +Abilitandola dopo un certo tempo le connessioni effettivamente terminate +verranno comunque chiuse per cui, utilizzando ad esempio una \func{select}, se +ne potrà rilevare la conclusione e ricevere il relativo errore. Si tenga +presente però che non può avere la certezza assoluta che un errore di +\errcode{ETIMEDOUT} ottenuto dopo aver abilitato questa opzione corrisponda +necessariamente ad una reale conclusione della connessione, il problema +potrebbe anche essere dovuto ad un problema di routing che perduri per un +tempo maggiore di quello impiegato nei vari tentativi di ritrasmissione del +\textit{keep-alive} (anche se questa non è una condizione molto probabile). + +Come esempio dell'utilizzo di questa opzione introduciamo all'interno del +nostro server per il servizio \textit{echo} la nuova opzione \texttt{-k} che +permette di attivare il \textit{keep-alive} sui socket; tralasciando la parte +relativa alla gestione di detta opzione (che si limita ad assegnare ad 1 la +variabile \var{keepalive}) tutte le modifiche al server sono riportate in +fig.~\ref{fig:echod_keepalive_code}. Al solito il codice completo è contenuto +nel file \texttt{TCP\_echod\_fourth.c} dei sorgenti allegati alla guida. + +Come si può notare la variabile \var{keepalive} è preimpostata (\texttt{\small + 8}) ad un valore nullo; essa viene utilizzata sia come variabile logica per +la condizione (\texttt{\small 14}) che controlla l'attivazione del +\textit{keep-alive} che come valore dell'argomento \param{optval} della +chiamata a \func{setsockopt} (\texttt{\small 16}). A seconda del suo valore +tutte le volte che un processo figlio viene eseguito in risposta ad una +connessione verrà pertanto eseguita o meno la sezione (\texttt{\small 14--17}) +che esegue l'impostazione di \const{SO\_KEEPALIVE} sul socket connesso, +attivando il relativo comportamento. +\constend{SO\_KEEPALIVE} + + + +\constbeg{SO\_REUSEADDR} +\subsubsection{Le opzioni \const{SO\_REUSEADDR} e \const{SO\_REUSEPORT}} + +La seconda opzione da approfondire è \constd{SO\_REUSEADDR}, che consente di +eseguire \func{bind} su un socket anche quando la porta specificata è già in +uso da parte di un altro socket. Si ricordi infatti che, come accennato in +sez.~\ref{sec:TCP_func_bind}, normalmente la funzione \func{bind} fallisce con +un errore di \errcode{EADDRINUSE} se la porta scelta è già utilizzata da un +altro socket, proprio per evitare che possano essere lanciati due server sullo +stesso indirizzo e la stessa porta, che verrebbero a contendersi i pacchetti +aventi quella destinazione. + +Esistono però situazioni ed esigenze particolari in cui non si vuole che +questo comportamento di salvaguardia accada, ed allora si può fare ricorso a +questa opzione. La questione è comunque abbastanza complessa in quanto, come +sottolinea Stevens in \cite{UNP1}, si distinguono ben quattro casi diversi in +cui è prevista la possibilità di un utilizzo di questa opzione, il che la +rende una delle più difficili da capire. + +Il primo caso in cui si fa ricorso a \const{SO\_REUSEADDR}, che è anche il più +comune, è quello in cui un server è terminato ma esistono ancora dei processi +figli che mantengono attiva almeno una connessione remota che utilizza +l'indirizzo locale, mantenendo occupata la porta. Quando si riesegue il server +allora questo riceve un errore sulla chiamata a \func{bind} dato che la porta +è ancora utilizzata in una connessione esistente.\footnote{questa è una delle + domande più frequenti relative allo sviluppo, in quanto è piuttosto comune + trovarsi in questa situazione quando si sta sviluppando un server che si + ferma e si riavvia in continuazione dopo aver fatto modifiche.} Inoltre se +si usa il protocollo TCP questo può avvenire anche dopo tutti i processi figli +sono terminati, dato che una connessione può restare attiva anche dopo la +chiusura del socket, mantenendosi nello stato \texttt{TIME\_WAIT} (vedi +sez.~\ref{sec:TCP_time_wait}). + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/sockbindopt.c} + \end{minipage} + \normalsize + \caption{Le sezioni della funzione \texttt{sockbindopt} modificate rispetto al + codice della precedente \texttt{sockbind}.} + \label{fig:sockbindopt_code} +\end{figure} + +Usando \const{SO\_REUSEADDR} fra la chiamata a \func{socket} e quella a +\func{bind} si consente a quest'ultima di avere comunque successo anche se la +connessione è attiva (o nello stato \texttt{TIME\_WAIT}). È bene però +ricordare (si riveda quanto detto in sez.~\ref{sec:TCP_time_wait}) che la +presenza dello stato \texttt{TIME\_WAIT} ha una ragione, ed infatti se si usa +questa opzione esiste sempre una probabilità, anche se estremamente +remota,\footnote{perché ciò avvenga infatti non solo devono coincidere gli + indirizzi IP e le porte degli estremi della nuova connessione, ma anche i + numeri di sequenza dei pacchetti, e questo è estremamente improbabile.} che +eventuali pacchetti rimasti intrappolati in una precedente connessione possano +finire fra quelli di una nuova. + +Come esempio di uso di questa connessione abbiamo predisposto una nuova +versione della funzione \texttt{sockbind} (vedi fig.~\ref{fig:sockbind_code}) +che consenta l'impostazione di questa opzione. La nuova funzione è +\texttt{sockbindopt}, e le principali differenze rispetto alla precedente sono +illustrate in fig.~\ref{fig:sockbindopt_code}, dove si sono riportate le +sezioni di codice modificate rispetto alla versione precedente. Il codice +completo della funzione si trova, insieme alle altre funzioni di servizio dei +socket, all'interno del file \texttt{SockUtils.c} dei sorgenti allegati alla +guida. + +In realtà tutto quello che si è fatto è stato introdurre nella nuova funzione +(\texttt{\small 1}) un nuovo argomento intero, \param{reuse}, che conterrà il +valore logico da usare nella successiva chiamata (\texttt{\small 14}) a +\func{setsockopt}. Si è poi aggiunta una sezione (\texttt{\small 13--17}) che +esegue l'impostazione dell'opzione fra la chiamata a \func{socket} e quella a +\func{bind}. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/TCP_echod_fifth.c} + \end{minipage} + \normalsize + \caption{Il nuovo codice per l'apertura passiva del server \textit{echo} che + usa la nuova funzione \texttt{sockbindopt}.} + \label{fig:TCP_echod_fifth} +\end{figure} + +A questo punto basterà modificare il server per utilizzare la nuova +funzione; in fig.~\ref{fig:TCP_echod_fifth} abbiamo riportato le sezioni +modificate rispetto alla precedente versione di +fig.~\ref{fig:TCP_echod_third}. Al solito il codice completo è coi sorgenti +allegati alla guida, nel file \texttt{TCP\_echod\_fifth.c}. + +Anche in questo caso si è introdotta (\texttt{\small 8}) una nuova variabile +\var{reuse} che consente di controllare l'uso dell'opzione e che poi sarà +usata (\texttt{\small 14}) come ultimo argomento di \func{setsockopt}. Il +valore di default di questa variabile è nullo, ma usando l'opzione \texttt{-r} +nell'invocazione del server (al solito la gestione delle opzioni non è +riportata in fig.~\ref{fig:TCP_echod_fifth}) se ne potrà impostare ad 1 il +valore, per cui in tal caso la successiva chiamata (\texttt{\small 13--17}) a +\func{setsockopt} attiverà l'opzione \const{SO\_REUSEADDR}. + +Il secondo caso in cui viene usata \const{SO\_REUSEADDR} è quando si ha una +macchina cui sono assegnati diversi indirizzi IP (o come suol dirsi +\textit{multi-homed}) e si vuole porre in ascolto sulla stessa porta un +programma diverso (o una istanza diversa dello stesso programma) per indirizzi +IP diversi. Si ricordi infatti che è sempre possibile indicare a \func{bind} +di collegarsi solo su di un indirizzo specifico; in tal caso se un altro +programma cerca di riutilizzare la stessa porta (anche specificando un +indirizzo diverso) otterrà un errore, a meno di non aver preventivamente +impostato \const{SO\_REUSEADDR}. + +Usando questa opzione diventa anche possibile eseguire \func{bind} +sull'indirizzo generico, e questo permetterà il collegamento per tutti gli +indirizzi (di quelli presenti) per i quali la porta non risulti occupata da +una precedente chiamata più specifica. Si tenga presente infatti che con il +protocollo TCP non è in genere possibile far partire più server che eseguano +\func{bind} sullo stesso indirizzo e la stessa porta se su di esso c'è già un +socket in ascolto, cioè ottenere quello che viene chiamato un +\itindex{completely~duplicate~binding} \textit{completely duplicate binding} +(per questo è stata introdotta \const{SO\_REUSEPORT}). + +Il terzo impiego è simile al precedente e prevede l'uso di \func{bind} +all'interno dello stesso programma per associare indirizzi locali diversi a +socket diversi. In genere questo viene fatto per i socket UDP quando è +necessario ottenere l'indirizzo a cui sono rivolte le richieste del client ed +il sistema non supporta l'opzione \constd{IP\_RECVDSTADDR};\footnote{nel caso + di Linux questa opzione è stata supportata per in certo periodo nello + sviluppo del kernel 2.1.x, ma è in seguito stata soppiantata dall'uso di + \const{IP\_PKTINFO} (vedi sez.~\ref{sec:sock_ipv4_options}).} in tale modo +si può sapere a quale socket corrisponde un certo indirizzo. Non ha senso +fare questa operazione per un socket TCP dato che su di essi si può sempre +invocare \func{getsockname} una volta che si è completata la connessione. + +Infine il quarto caso è quello in cui si vuole effettivamente ottenere un +\textit{completely duplicate binding}, quando cioè si vuole eseguire +\func{bind} su un indirizzo ed una porta che sono già ``\textsl{legati}'' ad +un altro socket. Come accennato questo con TCP non è possibile, ed ha anche +poco senso pensare di mettere in ascolto due server sulla stessa porta. Se +però si prende in considerazione il traffico in \textit{multicast}, diventa +assolutamente normale che i pacchetti provenienti dal traffico in +\textit{multicast} possano essere ricevuti da più applicazioni o da diverse +istanze della stessa applicazione sulla stessa porte di un indirizzo di +\textit{multicast}. + +Un esempio classico è quello di uno streaming di dati (audio, video, ecc.) in +cui l'uso del \textit{multicast} consente di trasmettere un solo pacchetto da +recapitare a tutti i possibili destinatari (invece di inviarne un duplicato a +ciascuno); in questo caso è perfettamente logico aspettarsi che sulla stessa +macchina più utenti possano lanciare un programma che permetta loro di +ricevere gli stessi dati, e quindi effettuare un \textit{completely duplicate + binding}. + +In questo caso utilizzando \const{SO\_REUSEADDR} si può consentire ad una +applicazione eseguire \func{bind} sulla stessa porta ed indirizzo usata da +un'altra, così che anche essa possa ricevere gli stessi pacchetti. Come detto +la cosa non è possibile con i socket TCP (per i quali il \textit{multicast} +comunque non è applicabile), ma lo è per quelli UDP che è il protocollo +normalmente in uso da parte di queste applicazioni. La regola è che quando si +hanno più applicazioni che hanno eseguito \func{bind} sulla stessa porta, di +tutti pacchetti destinati ad un indirizzo di \textit{broadcast} o di +\textit{multicast} viene inviata una copia a ciascuna applicazione. Non è +definito invece cosa accade qualora il pacchetto sia destinato ad un indirizzo +normale (\textit{unicast}). + +% TODO documentare SO_REUSEPORT, vedi https://lwn.net/Articles/542260/ + +\constbeg{SO\_REUSEPORT} + +Esistono però dei casi, in particolare per l'uso di programmi +\textit{multithreaded}, in cui può servire un \textit{completely duplicate + binding} anche per delle ordinarie connessioni TCP. Per supportare queste +esigenze a partire dal kernel 3.9 è stata introdotta un'altra opzione, +\const{SO\_REUSEPORT} (già presente in altri sistemi come BSD), che consente +di eseguire il \textit{completely duplicate binding}, fintanto che essa venga +specificata per tutti i socket interessati. Come per \const{SO\_REUSEADDR} +sarà possibile usare l'opzione su un socket legato allo stesso indirizzo e +porta solo se il programma che ha eseguito il primo \func{bind} ha impostato +questa opzione. + +Nel caso di \const{SO\_REUSEPORT} oltre al fatto che l'opzione deve essere +attivata sul socket prima di chiamare \func{bind} ed attiva su tutti i socket +con \textit{completely duplicate binding}, è richiesto pure che tutti i +processi che si mettono in ascolto sullo stesso indirizzo e porta abbiano lo +stesso \ids{UID} effettivo, per evitare che un altro utente possa ottenere il +relativo traffico (eseguendo quello che viene definito \textit{port hijacking} +o \textit{port stealing}). L'opzione utilizza per \param{optval} un intero +usato come valore logico. + +L'opzione si usa sia per socket TCP che UDP, nel primo caso consente un uso +distribuito di \func{accept} in una applicazione \textit{multithreaded} +passando un diverso \textit{listening socket} ad ogni thread, cosa che +migliora le prestazioni rispetto all'approccio tradizionale di usare un thread +per usare \func{accept} e distribuire le connessioni agli altri o avere più +thread che competono per usare \func{accept} sul socket. Nel caso di UDP +l'opzione consente di distribuire meglio i pacchetti su più processi o thread, +rispetto all'approccio tradizionale di far competere gli stessi per l'accesso +in ricezione al socket. + +% TODO documentare SO_REUSEPORT introdotta con il kernel 3.9, vedi +% http://git.kernel.org/linus/c617f398edd4db2b8567a28e899a88f8f574798d TODO: +% in cosa differisce da REUSEADDR? + +\constend{SO\_REUSEPORT} +\constend{SO\_REUSEADDR} + + +\constbeg{SO\_LINGER} +\subsubsection{L'opzione \const{SO\_LINGER}} + +La terza opzione da approfondire è \const{SO\_LINGER}; essa, come il nome +suggerisce, consente di ``\textsl{indugiare}'' nella chiusura di un socket. Il +comportamento standard sia di \func{close} che \func{shutdown} è infatti +quello di terminare immediatamente dopo la chiamata, mentre il procedimento di +chiusura della connessione (o di un lato di essa) ed il rispettivo invio sulla +rete di tutti i dati ancora presenti nei buffer, viene gestito in sottofondo +dal kernel. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/linger.h} + \end{minipage} + \caption{La struttura \structd{linger} richiesta come valore dell'argomento + \param{optval} per l'impostazione dell'opzione dei socket + \const{SO\_LINGER}.} + \label{fig:sock_linger_struct} +\end{figure} + +L'uso di \const{SO\_LINGER} con \func{setsockopt} permette di modificare (ed +eventualmente ripristinare) questo comportamento in base ai valori passati nei +campi della struttura \struct{linger}, illustrata in +fig.~\ref{fig:sock_linger_struct}. Fintanto che il valore del campo +\var{l\_onoff} di \struct{linger} è nullo la modalità che viene impostata +(qualunque sia il valore di \var{l\_linger}) è quella standard appena +illustrata; questa combinazione viene utilizzata per riportarsi al +comportamento normale qualora esso sia stato cambiato da una precedente +chiamata. + +Se si utilizza un valore di \var{l\_onoff} diverso da zero, il comportamento +alla chiusura viene a dipendere dal valore specificato per il campo +\var{l\_linger}; se quest'ultimo è nullo l'uso delle funzioni \func{close} e +\func{shutdown} provoca la terminazione immediata della connessione: nel caso +di TCP cioè non viene eseguito il procedimento di chiusura illustrato in +sez.~\ref{sec:TCP_conn_term}, ma tutti i dati ancora presenti nel buffer +vengono immediatamente scartati e sulla rete viene inviato un segmento di RST +che termina immediatamente la connessione. + +Un esempio di questo comportamento si può abilitare nel nostro client del +servizio \textit{echo} utilizzando l'opzione \texttt{-r}; riportiamo in +fig.~\ref{fig:TCP_echo_sixth} la sezione di codice che permette di introdurre +questa funzionalità; al solito il codice completo è disponibile nei sorgenti +allegati. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/TCP_echo_sixth.c} + \end{minipage} + \normalsize + \caption{La sezione del codice del client \textit{echo} che imposta la + terminazione immediata della connessione in caso di chiusura.} + \label{fig:TCP_echo_sixth} +\end{figure} + +La sezione indicata viene eseguita dopo aver effettuato la connessione e prima +di chiamare la funzione di gestione, cioè fra le righe (\texttt{\small 12}) e +(\texttt{\small 13}) del precedente esempio di fig.~\ref{fig:TCP_echo_fifth}. +Il codice si limita semplicemente a controllare (\texttt{\small 3}) il +valore della variabile \var{reset} che assegnata nella gestione delle opzioni +in corrispondenza all'uso di \texttt{-r} nella chiamata del client. Nel caso +questa sia diversa da zero vengono impostati (\texttt{\small 5--6}) i valori +della struttura \var{ling} che permettono una terminazione immediata della +connessione. Questa viene poi usata nella successiva (\texttt{\small 7}) +chiamata a \func{setsockopt}. Al solito si controlla (\texttt{\small 7--10}) +il valore di ritorno e si termina il programma in caso di errore, stampandone +il valore. + +Infine l'ultima possibilità, quella in cui si utilizza effettivamente +\const{SO\_LINGER} per \textsl{indugiare} nella chiusura, è quella in cui sia +\var{l\_onoff} che \var{l\_linger} hanno un valore diverso da zero. Se si +esegue l'impostazione con questi valori sia \func{close} che \func{shutdown} +si bloccano, nel frattempo viene eseguita la normale procedura di conclusione +della connessione (quella di sez.~\ref{sec:TCP_conn_term}) ma entrambe le +funzioni non ritornano fintanto che non si sia concluso il procedimento di +chiusura della connessione, o non sia passato un numero di +secondi\footnote{questa è l'unità di misura indicata da POSIX ed adottata da + Linux, altri kernel possono usare unità di misura diverse, oppure usare il + campo \var{l\_linger} come valore logico (ignorandone il valore) per rendere + (quando diverso da zero) \func{close} e \func{shutdown} bloccanti fino al + completamento della trasmissione dei dati sul buffer.} pari al valore +specificato in \var{l\_linger}. + +\constend{SO\_LINGER} + + + +\subsection{Le opzioni per il protocollo IPv4} +\label{sec:sock_ipv4_options} + +Il secondo insieme di opzioni dei socket che tratteremo è quello relativo ai +socket che usano il protocollo IPv4; come per le precedenti opzioni generiche +una descrizione di esse è disponibile nella settima sezione delle pagine di +manuale, nel caso specifico la documentazione si può consultare con +\texttt{man 7 ip}. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|c|c|l|p{4.8cm}|} + \hline + \textbf{Opzione}&\texttt{get}&\texttt{set}&\textbf{flag}&\textbf{Tipo}& + \textbf{Descrizione}\\ + \hline + \hline + \const{IP\_ADD\_MEMBERSHIP} & &$\bullet$& &\struct{ip\_mreqn}& + Si unisce a un gruppo di \textit{multicast}.\\ + \const{IP\_ADD\_SOURCE\_MEMBERSHIP} & &$\bullet$& &\struct{ip\_mreq\_source}& + Si unisce a un gruppo di \textit{multicast} per una sorgente.\\ + \const{IP\_BLOCK\_SOURCE} & &$\bullet$& &\struct{ip\_mreq\_source}& + Smette di ricevere dati di \textit{multicast} per una sorgente.\\ + \const{IP\_DROP\_MEMBERSHIP}& &$\bullet$& &\struct{ip\_mreqn}& + Si sgancia da un gruppo di \textit{multicast}.\\ + \const{IP\_DROP\_SOURCE\_MEMBERSHIP}& &$\bullet$& &\struct{ip\_mreq\_source}& + Si sgancia da un gruppo di \textit{multicast} per una sorgente.\\ + \const{IP\_FREEBIND} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita il \textit{binding} a un indirizzo IP non locale ancora non assegnato.\\ + \const{IP\_HDRINCL} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Passa l'intestazione di IP nei dati.\\ + \const{IP\_MINTTL} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta il valore minimo del TTL per i pacchetti accettati.\\ + \const{IP\_MSFILTER} &$\bullet$&$\bullet$& &\struct{ip\_msfilter}& + Accesso completo all'interfaccia per il filtraggio delle sorgenti + \textit{multicast}.\\ + \const{IP\_MTU} &$\bullet$& & &\texttt{int}& + Legge il valore attuale della MTU.\\ + \const{IP\_MTU\_DISCOVER} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta il \textit{Path MTU Discovery}.\\ + \const{IP\_MULTICAST\_ALL} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Imposta l'interfaccia locale di un socket \textit{multicast}.\\ + \const{IP\_MULTICAST\_IF} & &$\bullet$& &\struct{ip\_mreqn}& + Imposta l'interfaccia locale di un socket \textit{multicast}.\\ + \const{IP\_MULTICAST\_LOOP} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Controlla il reinvio a se stessi dei dati di \textit{multicast}.\\ + \const{IP\_MULTICAST\_TTL} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta il TTL per i pacchetti \textit{multicast}.\\ + \const{IP\_NODEFRAG} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Disabilita il riassemblaggio di pacchetti frammentati.\\ + \const{IP\_OPTIONS} &$\bullet$&$\bullet$&&\texttt{void *}& %??? + Imposta o riceve le opzioni di IP.\\ + \const{IP\_PKTINFO} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita i messaggi di informazione.\\ + \const{IP\_RECVERR} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita i messaggi di errore affidabili.\\ + \const{IP\_RECVOPTS} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Passa un messaggio con le opzioni IP.\\ + \const{IP\_RECVORIGSTADDR} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita i messaggi con l'indirizzo di destinazione originale.\\ + \const{IP\_RECVTOS} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Passa un messaggio col campo TOS.\\ + \const{IP\_RECVTTL} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita i messaggi col campo TTL.\\ + \const{IP\_RETOPTS} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita i messaggi con le opzioni IP non trattate.\\ + \const{IP\_ROUTER\_ALERT} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Imposta l'opzione \textit{IP router alert} sui pacchetti.\\ + \const{IP\_TOS} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta il valore del campo TOS.\\ + \const{IP\_TRANSPARENT} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita un \textit{proxing} trasparente sul socket.\\ + \const{IP\_TTL} &$\bullet$&$\bullet$& &\texttt{int}& + Imposta il valore del campo TTL.\\ + \const{IP\_UNBLOCK\_SOURCE} & &$\bullet$& &\struct{ip\_mreq\_source}& + Ricomincia a ricevere dati di \textit{multicast} per una sorgente.\\ + \hline + \end{tabular} + \caption{Le opzioni disponibili al livello \const{IPPROTO\_IP}.} + \label{tab:sock_opt_iplevel} +\end{table} + +Se si vuole operare su queste opzioni generiche il livello da utilizzare è +\constd{IPPROTO\_IP} (o l'equivalente \const{SOL\_IP}); si è riportato un +elenco di queste opzioni in tab.~\ref{tab:sock_opt_iplevel}. Le costanti +indicanti le opzioni, e tutte le altre costanti ad esse collegate, sono +definite in \headfiled{netinet/ip.h}, ed accessibili includendo detto file. + +Le descrizioni riportate in tab.~\ref{tab:sock_opt_iplevel} sono estremamente +succinte, una maggiore quantità di dettagli sulle varie opzioni è fornita nel +seguente elenco: +\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}} +\item[\constd{IP\_ADD\_MEMBERSHIP}] L'opzione consente di unirsi ad gruppo di + \textit{multicast}, e può essere usata solo con \func{setsockopt}. + L'argomento \param{optval} in questo caso deve essere una struttura di tipo + \struct{ip\_mreqn}, illustrata in fig.~\ref{fig:ip_mreqn_struct}, che + permette di indicare, con il campo \var{imr\_multiaddr} l'indirizzo del + gruppo di \textit{multicast} a cui ci si vuole unire, con il campo + \var{imr\_address} l'indirizzo dell'interfaccia locale con cui unirsi al + gruppo di \textit{multicast} e con \var{imr\_ifindex} l'indice + dell'interfaccia da utilizzare (un valore nullo indica una interfaccia + qualunque). + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.90\textwidth} + \includestruct{listati/ip_mreqn.h} + \end{minipage} + \caption{La struttura \structd{ip\_mreqn} utilizzata per unirsi a un gruppo di + \textit{multicast}.} + \label{fig:ip_mreqn_struct} +\end{figure} + +Questa struttura è presente a partire dal kernel 2.2, per compatibilità è +possibile utilizzare anche un argomento di tipo \struct{ip\_mreq}, presente +fino dal kernel 1.2, che differisce da essa soltanto per l'assenza del campo +\var{imr\_ifindex}; il kernel riconosce il tipo di struttura in base alla +differente dimensione passata in \param{optlen}. + +\item[\constd{IP\_ADD\_SOURCE\_MEMBERSHIP}] L'opzione consente di unirsi ad + gruppo di \textit{multicast}, ricevendo i dati solo da una sorgente + specifica; come \const{IP\_ADD\_MEMBERSHIP} può essere usata solo con + \func{setsockopt}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.90\textwidth} + \includestruct{listati/ip_mreq_source.h} + \end{minipage} + \caption{La struttura \structd{ip\_mreqn} utilizzata per unirsi a un gruppo di + \textit{multicast} per una specifica sorgente.} + \label{fig:ip_mreq_source_struct} +\end{figure} + +L'argomento \param{optval} in questo caso è una struttura +\struct{ip\_mreq\_source} illustrata in fig.~\ref{fig:ip_mreq_source_struct}, +dove il campo \var{imr\_multiaddr} è l'indirizzo del gruppo di +\textit{multicast}, il campo \var{imr\_interface} l'indirizzo dell'interfaccia +locale che deve essere usata per aggiungersi al gruppo di \textit{multicast} e +il campo \var{imr\_sourceaddr} l'indirizzo della sorgente da cui +l'applicazione vuole ricevere i dati. L'opzione può essere ripetuta più volte +per collegarsi a diverse sorgenti. + +\item[\constd{IP\_BLOCK\_SOURCE}] Questa opzione, disponibile dal kernel + 2.4.22, consente di smettere di ricevere dati di \textit{multicast} dalla + sorgente (e relativo gruppo) specificati dalla struttura + \struct{ip\_mreq\_source} (vedi fig.~\ref{fig:ip_mreq_source_struct}) + passata come argomento \param{optval}. L'opzione è utilizzabile solo se si è + già registrati nel gruppo di \textit{multicast} indicato con un precedente + utilizzo di \const{IP\_ADD\_MEMBERSHIP} o + \const{IP\_ADD\_SOURCE\_MEMBERSHIP}. + +\item[\constd{IP\_DROP\_MEMBERSHIP}] Lascia un gruppo di \textit{multicast}, + prende per \param{optval} la stessa struttura \struct{ip\_mreqn} (o + \struct{ip\_mreq}) usata per \const{IP\_ADD\_MEMBERSHIP} (vedi + fig.~\ref{fig:ip_mreqn_struct}). + +\item[\constd{IP\_DROP\_SOURCE\_MEMBERSHIP}] Lascia un gruppo di + \textit{multicast} per una specifica sorgente, prende per \param{optval} la + stessa struttura \struct{ip\_mreq\_source} usata per + \const{IP\_ADD\_SOURCE\_MEMBERSHIP} (vedi + fig.~\ref{fig:ip_mreq_source_struct}). Se ci si è registrati per più + sorgenti nello stesso gruppo, si continuerà a ricevere dati sulle altre. Per + smettere di ricevere dati da tutte le sorgenti occorre usare l'opzione + \const{IP\_LEAVE\_GROUP}. + +\item[\constd{IP\_FREEBIND}] Se abilitata questa opzione, disponibile dal + kernel 2.4, consente di usare \func{bind} anche su un indirizzo IP non + locale o che ancora non è stato assegnato. Questo permette ad una + applicazione di mettersi in ascolto su un socket prima che l'interfaccia + sottostante o l'indirizzo che questa deve usare sia stato configurato. È + l'equivalente a livello di singolo socket dell'uso della \textit{sysctl} + \texttt{ip\_nonlocal\_bind} che vedremo in + sez.~\ref{sec:sock_ipv4_sysctl}. Prende per + \param{optval} un intero usato come valore logico. + +\item[\constd{IP\_HDRINCL}] Se viene abilitata questa opzione, presente dal + kernel 2.0, l'utente deve fornire lui stesso l'intestazione del protocollo + IP in testa ai propri dati. L'opzione è valida soltanto per socket di tipo + \const{SOCK\_RAW}, e quando utilizzata eventuali valori impostati con + \const{IP\_OPTIONS}, \const{IP\_TOS} o \const{IP\_TTL} sono ignorati. In + ogni caso prima della spedizione alcuni campi dell'intestazione vengono + comunque modificati dal kernel, torneremo sull'argomento in + sez.~\ref{sec:socket_raw}. Prende per \param{optval} un intero usato come + valore logico. + +\item[\constd{IP\_MSFILTER}] L'opzione, introdotta con il kernel 2.4.22, + fornisce accesso completo all'interfaccia per il filtraggio delle sorgenti + di \textit{multicast} (il cosiddetto \textit{multicast source filtering}, + definito dall'\href{http://www.ietf.org/rfc/rfc3376.txt}{RFC~3376}). + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.90\textwidth} + \includestruct{listati/ip_msfilter.h} + \end{minipage} + \caption{La struttura \structd{ip\_msfilter} utilizzata per il + \textit{multicast source filtering}.} + \label{fig:ip_msfilter_struct} +\end{figure} + +L'argomento \param{optval} deve essere una struttura di tipo +\struct{ip\_msfilter} (illustrata in fig.~\ref{fig:ip_msfilter_struct}); il +campo \var{imsf\_multiaddr} indica l'indirizzo del gruppo di +\textit{multicast}, il campo \var{imsf\_interface} l'indirizzo +dell'interfaccia locale, il campo \var{imsf\_mode} indica la modalità di +filtraggio e con i campi \var{imsf\_numsrc} e \var{imsf\_slist} +rispettivamente la lunghezza della lista, e la lista stessa, degli indirizzi +sorgente. + +Come ausilio all'uso di questa opzione sono disponibili le macro +\macro{MCAST\_INCLUDE} e \macro{MCAST\_EXCLUDE} che si possono usare per +\var{imsf\_mode}. Inoltre si può usare la macro +\macro{IP\_MSFILTER\_SIZE}\texttt{(\textsf{n})} per determinare il valore +di \param{optlen} con una struttura \struct{ip\_msfilter} contenente +\texttt{\textsf{n}} sorgenti in \var{imsf\_slist}. + +\item[\constd{IP\_MINTTL}] L'opzione, introdotta con il kernel 2.6.34, imposta + un valore minimo per il campo \textit{Time to Live} dei pacchetti associati + al socket su cui è attivata, che se non rispettato ne causa lo scarto + automatico. L'opzione è nata per implementare + l'\href{http://www.ietf.org/rfc/rfc5082.txt}{RFC~5082} che la prevede come + forma di protezione per i router che usano il protocollo BGP poiché questi, + essendo in genere adiacenti, possono, impostando un valore di 255, scartare + automaticamente tutti gli eventuali pacchetti falsi creati da un attacco a + questo protocollo, senza doversi curare di verificarne la + validità.\footnote{l'attacco viene in genere portato per causare un + \textit{Denial of Service} aumentando il consumo di CPU del router nella + verifica dell'autenticità di un gran numero di pacchetti falsi; questi, + arrivando da sorgenti diverse da un router adiacente, non potrebbero più + avere un TTL di 255 anche qualora questo fosse stato il valore di + partenza, e l'impostazione dell'opzione consente di scartarli senza carico + aggiuntivo sulla CPU (che altrimenti dovrebbe calcolare una checksum).} + +\itindbeg{Path~MTU} +\item[\constd{IP\_MTU}] Permette di leggere il valore della \textit{Path MTU} + del socket. L'opzione richiede per \param{optval} un intero che conterrà il + valore della \textit{Path MTU} in byte. Questa è una opzione introdotta con + i kernel della serie 2.2.x, ed è specifica di Linux. + + È tramite questa opzione che un programma può leggere, quando si è avuto un + errore di \errval{EMSGSIZE}, il valore della MTU corrente del socket. Si + tenga presente che per poter usare questa opzione, oltre ad avere abilitato + la scoperta della \textit{Path MTU}, occorre che il socket sia stato + esplicitamente connesso con \func{connect}. + + Ad esempio con i socket UDP si può ottenere una stima iniziale della + \textit{Path MTU} eseguendo prima una \func{connect} verso la destinazione, + e poi usando \func{getsockopt} con questa opzione. Si può anche avviare + esplicitamente il procedimento di scoperta inviando un pacchetto di grosse + dimensioni (che verrà scartato) e ripetendo l'invio coi dati aggiornati. Si + tenga infine conto che durante il procedimento i pacchetti iniziali possono + essere perduti, ed è compito dell'applicazione gestirne una eventuale + ritrasmissione. + +\item[\constd{IP\_MTU\_DISCOVER}] Questa è una opzione introdotta con i kernel + della serie 2.2.x, ed è specifica di Linux. L'opzione permette di scrivere + o leggere le impostazioni della modalità usata per la determinazione della + \textit{Path MTU} (vedi sez.~\ref{sec:net_lim_dim}) del + socket. L'opzione prende per \param{optval} un valore intero che indica la + modalità usata, da specificare con una delle costanti riportate in + tab.~\ref{tab:sock_ip_mtu_discover}. + + \begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|r|p{7cm}|} + \hline + \multicolumn{2}{|c|}{\textbf{Valore}}&\textbf{Significato} \\ + \hline + \hline + \constd{IP\_PMTUDISC\_DONT}&0& Non effettua la ricerca dalla \textit{Path + MTU}.\\ + \constd{IP\_PMTUDISC\_WANT}&1& Utilizza il valore impostato per la rotta + utilizzata dai pacchetti (dal comando + \texttt{route}).\\ + \constd{IP\_PMTUDISC\_DO} &2& Esegue la procedura di determinazione + della \textit{Path MTU} come richiesto + dall'\href{http://www.ietf.org/rfc/rfc1191.txt}{RFC~1191}.\\ + \constd{IP\_PMTUDISC\_PROBE}&?& .\\ + \hline + \end{tabular} + \caption{Valori possibili per l'argomento \param{optval} di + \const{IP\_MTU\_DISCOVER}.} + \label{tab:sock_ip_mtu_discover} + \end{table} + + Il valore di default applicato ai socket di tipo \const{SOCK\_STREAM} è + determinato dal parametro \texttt{ip\_no\_pmtu\_disc} (vedi + sez.~\ref{sec:sock_sysctl}), mentre per tutti gli altri socket di default la + ricerca è disabilitata ed è responsabilità del programma creare pacchetti di + dimensioni appropriate e ritrasmettere eventuali pacchetti persi. Se + l'opzione viene abilitata, il kernel si incaricherà di tenere traccia + automaticamente della \textit{Path MTU} verso ciascuna destinazione, e + rifiuterà immediatamente la trasmissione di pacchetti di dimensioni maggiori + della MTU con un errore di \errval{EMSGSIZE}.\footnote{in caso contrario la + trasmissione del pacchetto sarebbe effettuata, ottenendo o un fallimento + successivo della trasmissione, o la frammentazione dello stesso.} +\itindend{Path~MTU} + +\item[\constd{IP\_MULTICAST\_IF}] Imposta l'interfaccia locale per l'utilizzo + del \textit{multicast}, ed utilizza come \param{optval} le stesse strutture + \struct{ip\_mreqn} o \struct{ip\_mreq} delle due precedenti opzioni. + +\item[\constd{IP\_MULTICAST\_LOOP}] L'opzione consente di decidere se i dati + che si inviano su un socket usato con il \textit{multicast} vengano ricevuti + anche sulla stessa macchina da cui li si stanno inviando. Prende per + \param{optval} un intero usato come valore logico. + + In generale se si vuole che eventuali client possano ricevere i dati che si + inviano occorre che questa funzionalità sia abilitata (come avviene di + default). Qualora però non si voglia generare traffico per dati che già sono + disponibili in locale l'uso di questa opzione permette di disabilitare + questo tipo di traffico. + +\item[\constd{IP\_MULTICAST\_TTL}] L'opzione permette di impostare o leggere il + valore del campo TTL per i pacchetti \textit{multicast} in uscita associati + al socket. È importante che questo valore sia il più basso possibile, ed il + default è 1, che significa che i pacchetti non potranno uscire dalla rete + locale. Questa opzione consente ai programmi che lo richiedono di superare + questo limite. L'opzione richiede per + \param{optval} un intero che conterrà il valore del TTL. +% TODO chiarire quale è la struttura \struct{ip\_mreq} + +\item[\constd{IP\_OPTIONS}] l'opzione permette di impostare o leggere le + opzioni del protocollo IP (si veda sez.~\ref{sec:IP_options}). L'opzione + prende come valore dell'argomento \param{optval} un puntatore ad un buffer + dove sono mantenute le opzioni, mentre \param{optlen} indica la dimensione + di quest'ultimo. Quando la si usa con \func{getsockopt} vengono lette le + opzioni IP utilizzate per la spedizione, quando la si usa con + \func{setsockopt} vengono impostate le opzioni specificate. L'uso di questa + opzione richiede una profonda conoscenza del funzionamento del protocollo, + torneremo in parte sull'argomento in sez.~\ref{sec:sock_IP_options}. + +\item[\constd{IP\_PKTINFO}] Quando abilitata l'opzione permette di ricevere + insieme ai pacchetti un messaggio ancillare (vedi + sez.~\ref{sec:net_ancillary_data}) di tipo \const{IP\_PKTINFO} contenente + una struttura \struct{pktinfo} (vedi fig.~\ref{fig:sock_pktinfo_struct}) che + mantiene una serie di informazioni riguardo i pacchetti in arrivo. In + particolare è possibile conoscere l'interfaccia su cui è stato ricevuto un + pacchetto (nel campo \var{ipi\_ifindex}),\footnote{in questo campo viene + restituito il valore numerico dell'indice dell'interfaccia, + sez.~\ref{sec:sock_ioctl_netdevice}.} l'indirizzo locale da esso + utilizzato (nel campo \var{ipi\_spec\_dst}) e l'indirizzo remoto dello + stesso (nel campo \var{ipi\_addr}). + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/pktinfo.h} + \end{minipage} + \caption{La struttura \structd{pktinfo} usata dall'opzione + \const{IP\_PKTINFO} per ricavare informazioni sui pacchetti di un socket + di tipo \const{SOCK\_DGRAM}.} + \label{fig:sock_pktinfo_struct} +\end{figure} + + +L'opzione è utilizzabile solo per socket di tipo \const{SOCK\_DGRAM}. Questa è +una opzione introdotta con i kernel della serie 2.2.x, ed è specifica di +Linux;\footnote{non dovrebbe pertanto essere utilizzata se si ha a cuore la + portabilità.} essa permette di sostituire le opzioni \const{IP\_RECVDSTADDR} +e \const{IP\_RECVIF} presenti in altri Unix (la relativa informazione è quella +ottenibile rispettivamente dai campi \var{ipi\_addr} e \var{ipi\_ifindex} di +\struct{pktinfo}). + +L'opzione prende per \param{optval} un intero usato come valore logico, che +specifica soltanto se insieme al pacchetto deve anche essere inviato o +ricevuto il messaggio \const{IP\_PKTINFO} (vedi +sez.~\ref{sec:net_ancillary_data}); il messaggio stesso dovrà poi essere +letto o scritto direttamente con \func{recvmsg} e \func{sendmsg} (vedi +sez.~\ref{sec:net_sendmsg}). + +\item[\constd{IP\_RECVERR}] Questa è una opzione introdotta con i kernel della + serie 2.2.x, ed è specifica di Linux. Essa permette di usufruire di un + meccanismo affidabile per ottenere un maggior numero di informazioni in caso + di errori. Se l'opzione è abilitata tutti gli errori generati su un socket + vengono memorizzati su una coda, dalla quale poi possono essere letti con + \func{recvmsg} (vedi sez.~\ref{sec:net_sendmsg}) come messaggi ancillari + (torneremo su questo in sez.~\ref{sec:net_ancillary_data}) di tipo + \const{IP\_RECVERR}. L'opzione richiede per \param{optval} un intero usato + come valore logico e non è applicabile a socket di tipo + \const{SOCK\_STREAM}. + +\item[\constd{IP\_RECVOPTS}] Quando abilitata l'opzione permette di ricevere + insieme ai pacchetti un messaggio ancillare (vedi + sez.~\ref{sec:net_ancillary_data}) di tipo \const{IP\_OPTIONS}, contenente + le opzioni IP del protocollo (vedi sez.~\ref{sec:IP_options}). Le + intestazioni di instradamento e le altre opzioni sono già riempite con i + dati locali. L'opzione richiede per \param{optval} un intero usato come + valore logico. L'opzione non è supportata per socket di tipo + \const{SOCK\_STREAM}. + +\item[\constd{IP\_RECVTOS}] Quando abilitata l'opzione permette di ricevere + insieme ai pacchetti un messaggio ancillare (vedi + sez.~\ref{sec:net_ancillary_data}) di tipo \const{IP\_TOS}, che contiene un + byte con il valore del campo \textit{Type of Service} dell'intestazione IP + del pacchetto stesso (vedi sez.~\ref{sec:IP_header}). Prende per + \param{optval} un intero usato come valore logico. + +\item[\constd{IP\_RECVTTL}] Quando abilitata l'opzione permette di ricevere + insieme ai pacchetti un messaggio ancillare (vedi + sez.~\ref{sec:net_ancillary_data}) di tipo \const{IP\_RECVTTL}, contenente + un byte con il valore del campo \textit{Time to Live} dell'intestazione IP + (vedi sez.~\ref{sec:IP_header}). L'opzione richiede per \param{optval} un + intero usato come valore logico. L'opzione non è supportata per socket di + tipo \const{SOCK\_STREAM}. + +\item[\constd{IP\_RETOPTS}] Identica alla precedente \const{IP\_RECVOPTS}, ma + in questo caso restituisce i dati grezzi delle opzioni, senza che siano + riempiti i capi di instradamento e le marche temporali. L'opzione richiede + per \param{optval} un intero usato come valore logico. L'opzione non è + supportata per socket di tipo \const{SOCK\_STREAM}. + +\item[\constd{IP\_ROUTER\_ALERT}] Questa è una opzione introdotta con i + kernel della serie 2.2.x, ed è specifica di Linux. Prende per + \param{optval} un intero usato come valore logico. Se abilitata + passa tutti i pacchetti con l'opzione \textit{IP Router Alert} (vedi + sez.~\ref{sec:IP_options}) che devono essere inoltrati al socket + corrente. Può essere usata soltanto per socket di tipo raw. + +\item[\constd{IP\_TOS}] L'opzione consente di leggere o impostare il campo + \textit{Type of Service} dell'intestazione IP (per una trattazione più + dettagliata, che riporta anche i valori possibili e le relative costanti di + definizione si veda sez.~\ref{sec:IP_header}) che permette di indicare le + priorità dei pacchetti. Se impostato il valore verrà mantenuto per tutti i + pacchetti del socket; alcuni valori (quelli che aumentano la priorità) + richiedono i privilegi di amministrazione con la \textit{capability} + \const{CAP\_NET\_ADMIN}. + + Il campo TOS è di 8 bit e l'opzione richiede per \param{optval} un intero + che ne contenga il valore. Sono definite anche alcune costanti che + definiscono alcuni valori standardizzati per il \textit{Type of Service}, + riportate in tab.~\ref{tab:IP_TOS_values}, il valore di default usato da + Linux è \const{IPTOS\_LOWDELAY}, ma esso può essere modificato con le + funzionalità del cosiddetto \textit{Advanced Routing}. Si ricordi che la + priorità dei pacchetti può essere impostata anche in maniera indipendente + dal protocollo utilizzando l'opzione \const{SO\_PRIORITY} illustrata in + sez.~\ref{sec:sock_generic_options}. + +\item[\constd{IP\_TTL}] L'opzione consente di leggere o impostare per tutti i + pacchetti associati al socket il campo \textit{Time to Live} + dell'intestazione IP che indica il numero massimo di \textit{hop} (passaggi + da un router ad un altro) restanti al paccheto (per una trattazione più + estesa si veda sez.~\ref{sec:IP_header}). Il campo TTL è di 8 bit e + l'opzione richiede che \param{optval} sia un intero, che ne conterrà il + valore. +\end{basedescript} + + + +\subsection{Le opzioni per i protocolli TCP e UDP} +\label{sec:sock_tcp_udp_options} + +In questa sezione tratteremo le varie opzioni disponibili per i socket che +usano i due principali protocolli di comunicazione del livello di trasporto; +UDP e TCP.\footnote{come per le precedenti, una descrizione di queste opzioni + è disponibile nella settima sezione delle pagine di manuale, che si può + consultare rispettivamente con \texttt{man 7 tcp} e \texttt{man 7 udp}; le + pagine di manuale però, alla stesura di questa sezione (Agosto 2006) sono + alquanto incomplete.} Dato che questi due protocolli sono entrambi +trasportati su IP,\footnote{qui si sottintende IPv4, ma le opzioni per TCP e + UDP sono le stesse anche quando si usa IPv6.} oltre alle opzioni generiche +di sez.~\ref{sec:sock_generic_options} saranno comunque disponibili anche le +precedenti opzioni di sez.~\ref{sec:sock_ipv4_options}.\footnote{in realtà in + sez.~\ref{sec:sock_ipv4_options} si sono riportate le opzioni per IPv4, al + solito, qualora si stesse utilizzando IPv6, si potrebbero utilizzare le + opzioni di quest'ultimo.} + +Il protocollo che supporta il maggior numero di opzioni è TCP; per poterle +utilizzare occorre specificare \const{SOL\_TCP} (o l'equivalente +\constd{IPPROTO\_TCP}) come valore per l'argomento \param{level}. Si sono +riportate le varie opzioni disponibili in tab.~\ref{tab:sock_opt_tcplevel}, +dove sono elencate le rispettive costanti da utilizzare come valore per +l'argomento \param{optname}. Dette costanti e tutte le altre costanti e +strutture collegate all'uso delle opzioni TCP sono definite in +\headfiled{netinet/tcp.h}, ed accessibili includendo detto file.\footnote{in + realtà questo è il file usato dalle librerie; la definizione delle opzioni + effettivamente supportate da Linux si trova nel file + \texttt{include/linux/tcp.h} dei sorgenti del kernel, dal quale si sono + estratte le costanti di tab.~\ref{tab:sock_opt_tcplevel}.} + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|c|c|l|l|} + \hline + \textbf{Opzione}&\texttt{get}&\texttt{set}&\textbf{flag}&\textbf{Tipo}& + \textbf{Descrizione}\\ + \hline + \hline + \const{TCP\_NODELAY} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Spedisce immediatamente i dati in segmenti singoli.\\ + \const{TCP\_MAXSEG} &$\bullet$&$\bullet$& &\texttt{int}& + Valore della MSS per i segmenti in uscita.\\ + \const{TCP\_CORK} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Accumula i dati in un unico segmento.\\ + \const{TCP\_KEEPIDLE} &$\bullet$&$\bullet$& &\texttt{int}& + Tempo in secondi prima di inviare un \textit{keepalive}.\\ + \const{TCP\_KEEPINTVL} &$\bullet$&$\bullet$& &\texttt{int}& + Tempo in secondi prima fra \textit{keepalive} successivi.\\ + \const{TCP\_KEEPCNT} &$\bullet$&$\bullet$& &\texttt{int}& + Numero massimo di \textit{keepalive} inviati.\\ + \const{TCP\_SYNCNT} &$\bullet$&$\bullet$& &\texttt{int}& + Numero massimo di ritrasmissioni di un SYN.\\ + \const{TCP\_LINGER2} &$\bullet$&$\bullet$& &\texttt{int}& + Tempo di vita in stato \texttt{FIN\_WAIT2}.\\ + \const{TCP\_DEFER\_ACCEPT}&$\bullet$&$\bullet$& &\texttt{int}& + Ritorna da \func{accept} solo in presenza di dati.\\ + \const{TCP\_WINDOW\_CLAMP}&$\bullet$&$\bullet$& &\texttt{int}& + Valore della \textit{advertised window}.\\ + \const{TCP\_INFO} &$\bullet$& & &\struct{tcp\_info}& + Restituisce informazioni sul socket.\\ + \const{TCP\_QUICKACK} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& + Abilita la modalità \textit{quickack}.\\ + \const{TCP\_CONGESTION} &$\bullet$&$\bullet$& &\texttt{char *}& + Imposta l'algoritmo per il controllo della congestione.\\ + \hline + \end{tabular} + \caption{Le opzioni per i socket TCP disponibili al livello + \const{SOL\_TCP}.} + \label{tab:sock_opt_tcplevel} +\end{table} + +Le descrizioni delle varie opzioni riportate in +tab.~\ref{tab:sock_opt_tcplevel} sono estremamente sintetiche ed indicative, +la spiegazione del funzionamento delle singole opzioni con una maggiore +quantità di dettagli è fornita nel seguente elenco: +\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}} + +\item[\constd{TCP\_NODELAY}] il protocollo TCP utilizza un meccanismo di + bufferizzazione dei dati uscenti, per evitare la trasmissione di tanti + piccoli segmenti con un utilizzo non ottimale della banda + disponibile.\footnote{il problema è chiamato anche + \itindex{silly~window~syndrome} \textit{silly window syndrome}, per averne + un'idea si pensi al risultato che si ottiene quando un programma di + terminale invia un segmento TCP per ogni tasto premuto, 40 byte di + intestazione di protocollo con 1 byte di dati trasmessi; per evitare + situazioni del genere è stato introdotto \index{algoritmo~di~Nagle} + l'\textsl{algoritmo di Nagle}.} Questo meccanismo è controllato da un + apposito algoritmo (detto \textsl{algoritmo di Nagle}, vedi + sez.~\ref{sec:tcp_protocol_xxx}). Il comportamento normale del protocollo + prevede che i dati siano accumulati fintanto che non si raggiunge una + quantità considerata adeguata per eseguire la trasmissione di un singolo + segmento. + + Ci sono però delle situazioni in cui questo comportamento può non essere + desiderabile, ad esempio quando si sa in anticipo che l'applicazione invierà + soltanto un piccolo quantitativo di dati;\footnote{è il caso classico di una + richiesta HTTP.} in tal caso l'attesa introdotta dall'algoritmo di + bufferizzazione non soltanto è inutile, ma peggiora le prestazioni + introducendo un ritardo. Impostando questa opzione si disabilita l'uso + dell'\textsl{algoritmo di Nagle} ed i dati vengono inviati immediatamente in + singoli segmenti, qualunque sia la loro dimensione. Ovviamente l'uso di + questa opzione è dedicato a chi ha esigenze particolari come quella + illustrata, che possono essere stabilite solo per la singola applicazione. + + Si tenga conto che questa opzione viene sovrascritta dall'eventuale + impostazione dell'opzione \const{TCP\_CORK} (il cui scopo è sostanzialmente + l'opposto) che blocca l'invio immediato. Tuttavia quando la si abilita viene + sempre forzato lo scaricamento della coda di invio (con conseguente + trasmissione di tutti i dati pendenti), anche qualora si fosse già abilitata + \const{TCP\_CORK}.\footnote{si tenga presente però che \const{TCP\_CORK} può + essere specificata insieme a \const{TCP\_NODELAY} soltanto a partire dal + kernel 2.5.71.} + +\item[\constd{TCP\_MAXSEG}] con questa opzione si legge o si imposta il valore + della MSS (\textit{Maximum Segment Size}, vedi sez.~\ref{sec:net_lim_dim} e + sez.~\ref{sec:tcp_protocol_xxx}) dei segmenti TCP uscenti. Se l'opzione è + impostata prima di stabilire la connessione, si cambia anche il valore della + MSS annunciata all'altro capo della connessione. Se si specificano valori + maggiori della MTU questi verranno ignorati, inoltre TCP imporrà anche i + suoi limiti massimo e minimo per questo valore. + +\item[\constd{TCP\_CORK}] questa opzione è il complemento naturale di + \const{TCP\_NODELAY} e serve a gestire a livello applicativo la situazione + opposta, cioè quella in cui si sa fin dal principio che si dovranno inviare + grosse quantità di dati. Anche in questo caso l'\textsl{algoritmo di Nagle} + tenderà a suddividerli in dimensioni da lui ritenute + opportune,\footnote{l'algoritmo cerca di tenere conto di queste situazioni, + ma essendo un algoritmo generico tenderà comunque ad introdurre delle + suddivisioni in segmenti diversi, anche quando potrebbero non essere + necessarie, con conseguente spreco di banda.} ma sapendo fin dall'inizio + quale è la dimensione dei dati si potranno di nuovo ottenere delle migliori + prestazioni disabilitandolo, e gestendo direttamente l'invio del nostro + blocco di dati in soluzione unica. + + Quando questa opzione viene abilitata non vengono inviati segmenti di dati + fintanto che essa non venga disabilitata; a quel punto tutti i dati rimasti + in coda saranno inviati in un solo segmento TCP. In sostanza con questa + opzione si può controllare il flusso dei dati mettendo una sorta di + ``\textsl{tappo}'' (da cui il nome in inglese) al flusso di uscita, in modo + ottimizzare a mano l'uso della banda. Si tenga presente che per l'effettivo + funzionamento ci si deve ricordare di disattivare l'opzione al termine + dell'invio del blocco dei dati. + + Si usa molto spesso \const{TCP\_CORK} quando si effettua il trasferimento + diretto di un blocco di dati da un file ad un socket con \func{sendfile} + (vedi sez.~\ref{sec:file_sendfile_splice}), per inserire una intestazione + prima della chiamata a questa funzione; senza di essa l'intestazione + potrebbe venire spedita in un segmento a parte, che a seconda delle + condizioni potrebbe richiedere anche una risposta di ACK, portando ad una + notevole penalizzazione delle prestazioni. + + Si tenga presente che l'implementazione corrente di \const{TCP\_CORK} non + consente di bloccare l'invio dei dati per più di 200 millisecondi, passati i + quali i dati accumulati in coda sanno inviati comunque. Questa opzione è + tipica di Linux\footnote{l'opzione è stata introdotta con i kernel della + serie 2.4.x.} e non è disponibile su tutti i kernel unix-like, pertanto + deve essere evitata se si vuole scrivere codice portabile. + +\item[\constd{TCP\_KEEPIDLE}] con questa opzione si legge o si imposta + l'intervallo di tempo, in secondi, che deve trascorrere senza traffico sul + socket prima che vengano inviati, qualora si sia attivata su di esso + l'opzione \const{SO\_KEEPALIVE}, i messaggi di \textit{keep-alive} (si veda + la trattazione relativa al \textit{keep-alive} in + sez.~\ref{sec:sock_options_main}). Anche questa opzione non è disponibile + su tutti i kernel unix-like e deve essere evitata se si vuole scrivere + codice portabile. + +\item[\constd{TCP\_KEEPINTVL}] con questa opzione si legge o si imposta + l'intervallo di tempo, in secondi, fra due messaggi di \textit{keep-alive} + successivi (si veda sempre quanto illustrato in + sez.~\ref{sec:sock_options_main}). Come la precedente non è disponibile su + tutti i kernel unix-like e deve essere evitata se si vuole scrivere codice + portabile. + +\item[\constd{TCP\_KEEPCNT}] con questa opzione si legge o si imposta il numero + totale di messaggi di \textit{keep-alive} da inviare prima di concludere che + la connessione è caduta per assenza di risposte ad un messaggio di + \textit{keep-alive} (di nuovo vedi sez.~\ref{sec:sock_options_main}). Come + la precedente non è disponibile su tutti i kernel unix-like e deve essere + evitata se si vuole scrivere codice portabile. + +\item[\constd{TCP\_SYNCNT}] con questa opzione si legge o si imposta il numero + di tentativi di ritrasmissione dei segmenti SYN usati nel \textit{three way + handshake} prima che il tentativo di connessione venga abortito (si + ricordi quanto accennato in sez.~\ref{sec:TCP_func_connect}). Sovrascrive + per il singolo socket il valore globale impostato con la \textit{sysctl} + \texttt{tcp\_syn\_retries} (vedi sez.~\ref{sec:sock_ipv4_sysctl}). Non + vengono accettati valori maggiori di 255; anche questa opzione non è + standard e deve essere evitata se si vuole scrivere codice portabile. + +\item[\constd{TCP\_LINGER2}] con questa opzione si legge o si imposta, in + numero di secondi, il tempo di sussistenza dei socket terminati nello stato + \texttt{FIN\_WAIT2} (si ricordi quanto visto in + sez.~\ref{sec:TCP_conn_term}).\footnote{si tenga ben presente che questa + opzione non ha nulla a che fare con l'opzione \const{SO\_LINGER} che + abbiamo visto in sez.~\ref{sec:sock_options_main}.} Questa opzione + consente di sovrascrivere per il singolo socket il valore globale impostato + con la \textit{sysctl} \texttt{tcp\_fin\_timeout} (vedi + sez.~\ref{sec:sock_ipv4_sysctl}). Anche questa opzione è da evitare se si + ha a cuore la portabilità del codice. + +\item[\constd{TCP\_DEFER\_ACCEPT}] questa opzione consente di modificare il + comportamento standard del protocollo TCP nello stabilirsi di una + connessione; se ricordiamo il meccanismo del \textit{three way handshake} + illustrato in fig.~\ref{fig:TCP_TWH} possiamo vedere che in genere un client + inizierà ad inviare i dati ad un server solo dopo l'emissione dell'ultimo + segmento di ACK. + + Di nuovo esistono situazioni (e la più tipica è quella di una richiesta + HTTP) in cui sarebbe utile inviare immediatamente la richiesta all'interno + del segmento con l'ultimo ACK del \textit{three way handshake}; si potrebbe + così risparmiare l'invio di un segmento successivo per la richiesta e il + ritardo sul server fra la ricezione dell'ACK e quello della richiesta. + + Se si invoca \const{TCP\_DEFER\_ACCEPT} su un socket dal lato client (cioè + dal lato da cui si invoca \func{connect}) si istruisce il kernel a non + inviare immediatamente l'ACK finale del \textit{three way handshake}, + attendendo per un po' di tempo la prima scrittura, in modo da inviare i dati + di questa insieme col segmento ACK. Chiaramente la correttezza di questo + comportamento dipende in maniera diretta dal tipo di applicazione che usa il + socket; con HTTP, che invia una breve richiesta, permette di risparmiare un + segmento, con FTP, in cui invece si attende la ricezione del prompt del + server, introduce un inutile ritardo. + + Allo stesso tempo il protocollo TCP prevede che sul lato del server la + funzione \func{accept} ritorni dopo la ricezione dell'ACK finale, in tal + caso quello che si fa usualmente è lanciare un nuovo processo per leggere i + successivi dati, che si bloccherà su una \func{read} se questi non sono + disponibili; in questo modo si saranno impiegate delle risorse (per la + creazione del nuovo processo) che non vengono usate immediatamente. L'uso + di \const{TCP\_DEFER\_ACCEPT} consente di intervenire anche in questa + situazione; quando la si invoca sul lato server (vale a dire su un socket in + ascolto) l'opzione fa sì che \func{accept} ritorni soltanto quando sono + presenti dei dati sul socket, e non alla ricezione dell'ACK conclusivo del + \textit{three way handshake}. + + L'opzione prende un valore intero che indica il numero massimo di secondi + per cui mantenere il ritardo, sia per quanto riguarda il ritorno di + \func{accept} su un server, che per l'invio dell'ACK finale insieme ai dati + su un client. L'opzione è specifica di Linux non deve essere utilizzata in + codice che vuole essere portabile.\footnote{su FreeBSD è presente una + opzione \texttt{SO\_ACCEPTFILTER} che consente di ottenere lo stesso + comportamento di \const{TCP\_DEFER\_ACCEPT} per quanto riguarda il lato + server.} + +\item[\constd{TCP\_WINDOW\_CLAMP}] con questa opzione si legge o si imposta + alla dimensione specificata, in byte, il valore dichiarato della + \textit{advertised window} (vedi sez.~\ref{sec:tcp_protocol_xxx}). Il kernel + impone comunque una dimensione minima pari a \texttt{SOCK\_MIN\_RCVBUF/2}. + Questa opzione non deve essere utilizzata in codice che vuole essere + portabile. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/tcp_info.h} + \end{minipage} + \caption{La struttura \structd{tcp\_info} contenente le informazioni sul + socket restituita dall'opzione \const{TCP\_INFO}.} + \label{fig:tcp_info_struct} +\end{figure} + +\item[\constd{TCP\_INFO}] questa opzione, specifica di Linux, ma introdotta + anche in altri kernel (ad esempio FreeBSD) permette di controllare lo stato + interno di un socket TCP direttamente da un programma in \textit{user space}. + L'opzione restituisce in una speciale struttura \struct{tcp\_info}, la cui + definizione è riportata in fig.~\ref{fig:tcp_info_struct}, tutta una serie + di dati che il kernel mantiene, relativi al socket. Anche questa opzione + deve essere evitata se si vuole scrivere codice portabile. + + Con questa opzione diventa possibile ricevere una serie di informazioni + relative ad un socket TCP così da poter effettuare dei controlli senza dover + passare attraverso delle operazioni di lettura. Ad esempio si può verificare + se un socket è stato chiuso usando una funzione analoga a quella illustrata + in fig.~\ref{fig:is_closing}, in cui si utilizza il valore del campo + \var{tcpi\_state} di \struct{tcp\_info} per controllare lo stato del socket. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/is_closing.c} + \end{minipage} + \caption{Codice della funzione \texttt{is\_closing.c}, che controlla lo stato + di un socket TCP per verificare se si sta chiudendo.} + \label{fig:is_closing} +\end{figure} + +%Si noti come nell'esempio si sia ( + + +\item[\constd{TCP\_QUICKACK}] con questa opzione è possibile eseguire una forma + di controllo sull'invio dei segmenti ACK all'interno di in flusso di dati su + TCP. In genere questo invio viene gestito direttamente dal kernel, il + comportamento standard, corrispondente la valore logico di vero (in genere + 1) per questa opzione, è quello di inviare immediatamente i segmenti ACK, in + quanto normalmente questo significa che si è ricevuto un blocco di dati e si + può passare all'elaborazione del blocco successivo. + + Qualora però la nostra applicazione sappia in anticipo che alla ricezione di + un blocco di dati seguirà immediatamente l'invio di un altro + blocco,\footnote{caso tipico ad esempio delle risposte alle richieste HTTP.} + poter accorpare quest'ultimo al segmento ACK permette di risparmiare sia in + termini di dati inviati che di velocità di risposta. Per far questo si può + utilizzare \const{TCP\_QUICKACK} impostando un valore logico falso (cioè 0), + in questo modo il kernel attenderà così da inviare il prossimo segmento di + ACK insieme ai primi dati disponibili. + + Si tenga presente che l'opzione non è permanente, vale a dire che una volta + che la si sia impostata a 0 il kernel la riporterà al valore di default dopo + il suo primo utilizzo. Sul lato server la si può impostare anche una volta + sola su un socket in ascolto, ed essa verrà ereditata da tutti i socket che + si otterranno da esso al ritorno di \func{accept}. + +% TODO trattare con gli esempi di apache + +\item[\constd{TCP\_CONGESTION}] questa opzione permette di impostare quale + algoritmo per il controllo della congestione\footnote{il controllo della + congestione è un meccanismo previsto dal protocollo TCP (vedi + sez.~\ref{sec:tcp_protocol_xxx}) per evitare di trasmettere inutilmente + dati quando una connessione è congestionata; un buon algoritmo è + fondamentale per il funzionamento del protocollo, dato che i pacchetti + persi andrebbero ritrasmessi, per cui inviare un pacchetto su una linea + congestionata potrebbe causare facilmente un peggioramento della + situazione.} utilizzare per il singolo socket. L'opzione è stata + introdotta con il kernel 2.6.13,\footnote{alla data di stesura di queste + note (Set. 2006) è pure scarsamente documentata, tanto che non è neanche + definita nelle intestazioni della \acr{glibc} per cui occorre definirla a + mano al suo valore che è 13.} e prende come per \param{optval} il + puntatore ad un buffer contenente il nome dell'algoritmo di controllo che + si vuole usare. + + L'uso di un nome anziché di un valore numerico è dovuto al fatto che gli + algoritmi di controllo della congestione sono realizzati attraverso + altrettanti moduli del kernel, e possono pertanto essere attivati a + richiesta; il nome consente di caricare il rispettivo modulo e di introdurre + moduli aggiuntivi che implementino altri meccanismi. + + Per poter disporre di questa funzionalità occorre aver compilato il kernel + attivando l'opzione di configurazione generale + \texttt{TCP\_CONG\_ADVANCED},\footnote{disponibile come \textit{TCP: + advanced congestion control} nel menù \textit{Network->Networking + options}, che a sua volta renderà disponibile un ulteriore menù con gli + algoritmi presenti.} e poi abilitare i singoli moduli voluti con le varie + \texttt{TCP\_CONG\_*} presenti per i vari algoritmi disponibili; un elenco + di quelli attualmente supportati nella versione ufficiale del kernel è + riportato in tab.~\ref{tab:sock_tcp_congestion_algo}.\footnote{la lista è + presa dalla versione 2.6.17.} + + + Si tenga presente che prima della implementazione modulare alcuni di questi + algoritmi erano disponibili soltanto come caratteristiche generali del + sistema, attivabili per tutti i socket, questo è ancora possibile con la + \textit{sysctl} \texttt{tcp\_congestion\_control} (vedi + sez.~\ref{sec:sock_ipv4_sysctl}) che ha sostituito le precedenti + \textit{sysctl}.\footnote{riportate anche, alla data di stesura di queste + pagine (Set. 2006) nelle pagine di manuale, ma non più presenti.} + + \begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|l|} + \hline + \textbf{Nome}&\textbf{Configurazione}&\textbf{Riferimento} \\ + \hline + \hline + reno& -- &Algoritmo tradizionale, usato in caso di assenza degli altri.\\ + \texttt{bic} &\texttt{TCP\_CONG\_BIC} & + \url{http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/index.htm}.\\ + \texttt{cubic} &\texttt{TCP\_CONG\_CUBIC} & + \url{http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/index.htm}.\\ + \texttt{highspeed}&\texttt{TCP\_CONG\_HSTCP} & + \url{http://www.icir.org/floyd/hstcp.html}.\\ + \texttt{htcp} &\texttt{TCP\_CONG\_HTCP} & + \url{http://www.hamilton.ie/net/htcp/}.\\ + \texttt{hybla} &\texttt{TCP\_CONG\_HYBLA} & + \url{http://www.danielinux.net/projects.html}.\\ + \texttt{scalable}&\texttt{TCP\_CONG\_SCALABLE}& + \url{http://www.deneholme.net/tom/scalable/}.\\ + \texttt{vegas} &\texttt{TCP\_CONG\_VEGAS} & + \url{http://www.cs.arizona.edu/protocols/}.\\ + \texttt{westwood}&\texttt{TCP\_CONG\_WESTWOOD}& + \url{http://www.cs.ucla.edu/NRL/hpi/tcpw/}.\\ +% \texttt{}&\texttt{}& .\\ + \hline + \end{tabular} + \caption{Gli algoritmi per il controllo della congestione disponibili con + Linux con le relative opzioni di configurazione da attivare.} + \label{tab:sock_tcp_congestion_algo} + \end{table} + +\end{basedescript} + + +Il protocollo UDP, anche per la sua maggiore semplicità, supporta un numero +ridotto di opzioni, riportate in tab.~\ref{tab:sock_opt_udplevel}; anche in +questo caso per poterle utilizzare occorrerà impostare l'opportuno valore per +l'argomento \param{level}, che è \const{SOL\_UDP} (o l'equivalente +\constd{IPPROTO\_UDP}). Le costanti che identificano dette opzioni sono +definite in \headfiled{netinet/udp.h}, ed accessibili includendo detto +file.\footnote{come per TCP, la definizione delle opzioni effettivamente + supportate dal kernel si trova in realtà nel file + \texttt{include/linux/udp.h}, dal quale si sono estratte le costanti di + tab.~\ref{tab:sock_opt_udplevel}.} + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|c|c|c|l|l|} + \hline + \textbf{Opzione}&\texttt{get}&\texttt{set}&\textbf{flag}&\textbf{Tipo}& + \textbf{Descrizione}\\ + \hline + \hline + \constd{UDP\_CORK} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& %??? + Accumula tutti i dati su un unico pacchetto.\\ + \constd{UDP\_ENCAP} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& %??? + Non documentata.\\ + \hline + \end{tabular} + \caption{Le opzioni per i socket UDP disponibili al livello + \const{SOL\_UDP}.} + \label{tab:sock_opt_udplevel} +\end{table} + +% TODO documentare \const{UDP\_ENCAP} + +Ancora una volta le descrizioni contenute tab.~\ref{tab:sock_opt_udplevel} +sono un semplice riferimento, una maggiore quantità di dettagli sulle +caratteristiche delle opzioni citate è quello dell'elenco seguente: +\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}} + +\item[\constd{UDP\_CORK}] questa opzione ha l'identico effetto dell'analoga + \const{TCP\_CORK} vista in precedenza per il protocollo TCP, e quando + abilitata consente di accumulare i dati in uscita su un solo pacchetto che + verrà inviato una volta che la si disabiliti. L'opzione è stata introdotta + con il kernel 2.5.44, e non deve essere utilizzata in codice che vuole + essere portabile. + +\item[\constd{UDP\_ENCAP}] Questa opzione permette di gestire l'incapsulazione + dei dati nel protocollo UDP. L'opzione è stata introdotta con il kernel + 2.5.67, e non è documentata. Come la precedente è specifica di Linux e non + deve essere utilizzata in codice portabile. + +\end{basedescript} + + + + +\section{La gestione attraverso le funzioni di controllo} +\label{sec:sock_ctrl_func} + +Benché la maggior parte delle caratteristiche dei socket sia gestibile con le +funzioni \func{setsockopt} e \func{getsockopt}, alcune proprietà possono +essere impostate attraverso le funzioni \func{fcntl} e \func{ioctl} già +trattate in sez.~\ref{sec:file_fcntl_ioctl}; in quell'occasione abbiamo +parlato di queste funzioni esclusivamente nell'ambito della loro applicazione +a file descriptor associati a dei file normali; qui tratteremo invece i +dettagli del loro utilizzo con file descriptor associati a dei socket. + + +\subsection{L'uso di \func{ioctl} e \func{fcntl} per i socket generici} +\label{sec:sock_ioctl} + +Tratteremo in questa sezione le caratteristiche specifiche delle funzioni +\func{ioctl} e \func{fcntl} quando esse vengono utilizzate con dei socket +generici. Quanto già detto in precedenza sez.~\ref{sec:file_fcntl_ioctl} +continua a valere; quello che tratteremo qui sono le operazioni ed i comandi +che sono validi, o che hanno significati peculiari, quando queste funzioni +vengono applicate a dei socket generici. + +Nell'elenco seguente si riportano i valori specifici che può assumere il +secondo argomento della funzione \func{ioctl} (\param{request}, che indica il +tipo di operazione da effettuare) quando essa viene applicata ad un socket +generico. Nell'elenco si illustrerà anche, per ciascuna operazione, il tipo di +dato usato come terzo argomento della funzione ed il significato che esso +viene ad assumere. Dato che in caso di lettura questi dati vengono restituiti +come \textit{value result argument}, con queste operazioni il terzo argomento +deve sempre essere passato come puntatore ad una variabile (o struttura) +precedentemente allocata. Le costanti che identificano le operazioni sono le +seguenti: +\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}} +\item[\constd{SIOCGSTAMP}] restituisce il contenuto di una struttura + \struct{timeval} con la marca temporale dell'ultimo pacchetto ricevuto sul + socket, questa operazione può essere utilizzata per effettuare delle + misurazioni precise del tempo di andata e ritorno\footnote{il \textit{Round + Trip Time} cui abbiamo già accennato in sez.~\ref{sec:net_tcp}.} dei + pacchetti sulla rete. + +\item[\constd{SIOCSPGRP}] imposta il processo o il \textit{process group} a + cui inviare i segnali \signal{SIGIO} e \signal{SIGURG} quando viene + completata una operazione di I/O asincrono o arrivano dei dati urgenti + (\texttt{out-of-band}). Il terzo argomento deve essere un puntatore ad una + variabile di tipo \type{pid\_t}; un valore positivo indica direttamente il + \ids{PID} del processo, mentre un valore negativo indica (col valore + assoluto) il \textit{process group}. Senza privilegi di amministratore o la + \textit{capability} \const{CAP\_KILL} si può impostare solo se stessi o il + proprio \textit{process group}. + +\item[\constd{SIOCGPGRP}] legge le impostazioni presenti sul socket + relativamente all'eventuale processo o \textit{process group} cui devono + essere inviati i segnali \signal{SIGIO} e \signal{SIGURG}. Come per + \const{SIOCSPGRP} l'argomento passato deve un puntatore ad una variabile di + tipo \type{pid\_t}, con lo stesso significato. Qualora non sia presente + nessuna impostazione verrà restituito un valore nullo. + +\item[\const{FIOASYNC}] Abilita o disabilita la modalità di I/O asincrono sul + socket. Questo significa (vedi sez.~\ref{sec:signal_driven_io}) che verrà + inviato il segnale di \signal{SIGIO} (o quanto impostato con + \const{F\_SETSIG}, vedi sez.~\ref{sec:file_fcntl_ioctl}) in caso di eventi + di I/O sul socket. +\end{basedescript} + +Nel caso dei socket generici anche \func{fcntl} prevede un paio di comandi +specifici; in questo caso il secondo argomento (\param{cmd}, che indica il +comando) può assumere i due valori \const{FIOGETOWN} e \const{FIOSETOWN}, +mentre il terzo argomento dovrà essere un puntatore ad una variabile di tipo +\type{pid\_t}. Questi due comandi sono una modalità alternativa di eseguire le +stesse operazioni (lettura o impostazione del processo o del gruppo di +processo che riceve i segnali) che si effettuano chiamando \func{ioctl} con +\const{SIOCGPGRP} e \const{SIOCSPGRP}. + + +\subsection{L'uso di \func{ioctl} per l'accesso ai dispositivi di rete} +\label{sec:sock_ioctl_netdevice} + +Benché non strettamente attinenti alla gestione dei socket, vale la pena di +trattare qui l'interfaccia di accesso a basso livello ai dispositivi di rete +che viene appunto fornita attraverso la funzione \texttt{ioctl}. Questa non è +attinente a caratteristiche specifiche di un qualche protocollo, ma si applica +a tutti i socket, indipendentemente da tipo e famiglia degli stessi, e +permette di impostare e rilevare le funzionalità delle interfacce di rete. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/ifreq.h} + \end{minipage} + \caption{La struttura \structd{ifreq} utilizzata dalle \func{ioctl} per le + operazioni di controllo sui dispositivi di rete.} + \label{fig:netdevice_ifreq_struct} +\end{figure} + +Tutte le operazioni di questo tipo utilizzano come terzo argomento di +\func{ioctl} il puntatore ad una struttura \struct{ifreq}, la cui definizione +è illustrata in fig.~\ref{fig:netdevice_ifreq_struct}. Normalmente si utilizza +il primo campo della struttura, \var{ifr\_name} per specificare il nome +dell'interfaccia su cui si vuole operare (ad esempio \texttt{eth0}, +\texttt{ppp0}, ecc.), e si inseriscono (o ricevono) i valori relativi alle +diversa caratteristiche e funzionalità nel secondo campo, che come si può +notare è definito come una \dirct{union} proprio in quanto il suo significato +varia a secondo dell'operazione scelta. + +Si tenga inoltre presente che alcune di queste operazioni (in particolare +quelle che modificano le caratteristiche dell'interfaccia) sono privilegiate e +richiedono i privilegi di amministratore o la \textit{capability} +\const{CAP\_NET\_ADMIN}, altrimenti si otterrà un errore di \errval{EPERM}. +Le costanti che identificano le operazioni disponibili sono le seguenti: +\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}} +\item[\constd{SIOCGIFNAME}] questa è l'unica operazione che usa il campo + \var{ifr\_name} per restituire un risultato, tutte le altre lo utilizzano + per indicare l'interfaccia sulla quale operare. L'operazione richiede che si + indichi nel campo \var{ifr\_ifindex} il valore numerico dell'\textsl{indice} + dell'interfaccia, e restituisce il relativo nome in \var{ifr\_name}. + + Il kernel infatti assegna ad ogni interfaccia un numero progressivo, detto + appunto \itindex{interface~index} \textit{interface index}, che è quello che + effettivamente la identifica nelle operazioni a basso livello, il nome + dell'interfaccia è soltanto una etichetta associata a detto \textsl{indice}, + che permette di rendere più comprensibile l'indicazione dell'interfaccia + all'interno dei comandi. Una modalità per ottenere questo valore è usare il + comando \cmd{ip link}, che fornisce un elenco delle interfacce presenti + ordinato in base a tale valore (riportato come primo campo). + + +\item[\constd{SIOCGIFINDEX}] restituisce nel campo \var{ifr\_ifindex} il valore + numerico dell'indice dell'interfaccia specificata con \var{ifr\_name}, è in + sostanza l'operazione inversa di \const{SIOCGIFNAME}. + +\item[\constd{SIOCGIFFLAGS}] permette di ottenere nel campo \var{ifr\_flags} il + valore corrente dei flag dell'interfaccia specificata (con \var{ifr\_name}). + Il valore restituito è una maschera binaria i cui bit sono identificabili + attraverso le varie costanti di tab.~\ref{tab:netdevice_iface_flag}. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{8cm}|} + \hline + \textbf{Flag} & \textbf{Significato} \\ + \hline + \hline + \constd{IFF\_UP} & L'interfaccia è attiva.\\ + \constd{IFF\_BROADCAST} & L'interfaccia ha impostato un indirizzo di + \textit{broadcast} valido.\\ + \constd{IFF\_DEBUG} & È attivo il flag interno di debug.\\ + \constd{IFF\_LOOPBACK} & L'interfaccia è una interfaccia di + \textit{loopback}.\\ + \constd{IFF\_POINTOPOINT}&L'interfaccia è associata ad un collegamento + \textsl{punto-punto}.\\ + \constd{IFF\_RUNNING} & L'interfaccia ha delle risorse allocate (non può + quindi essere disattivata).\\ + \constd{IFF\_NOARP} & L'interfaccia ha il protocollo ARP disabilitato o + l'indirizzo del livello di rete non è impostato.\\ + \constd{IFF\_PROMISC} & L'interfaccia è nel cosiddetto + \index{modo~promiscuo} \textsl{modo promiscuo}, + riceve cioè tutti i pacchetti che vede passare, + compresi quelli non direttamente indirizzati a + lei.\\ + \constd{IFF\_NOTRAILERS}& Evita l'uso di \textit{trailer} nei pacchetti.\\ + \constd{IFF\_ALLMULTI} & Riceve tutti i pacchetti di \textit{multicast}.\\ + \constd{IFF\_MASTER} & L'interfaccia è il master di un bundle per il + bilanciamento di carico.\\ + \constd{IFF\_SLAVE} & L'interfaccia è uno slave di un bundle per il + bilanciamento di carico.\\ + \constd{IFF\_MULTICAST} & L'interfaccia ha il supporto per il + \textit{multicast} attivo.\\ + \constd{IFF\_PORTSEL} & L'interfaccia può impostare i suoi parametri + hardware (con l'uso di \struct{ifmap}).\\ + \constd{IFF\_AUTOMEDIA} & L'interfaccia è in grado di selezionare + automaticamente il tipo di collegamento.\\ + \constd{IFF\_DYNAMIC} & Gli indirizzi assegnati all'interfaccia vengono + persi quando questa viene disattivata.\\ +% \const{IFF\_} & .\\ + \hline + \end{tabular} + \caption{Le costanti che identificano i vari bit della maschera binaria + \var{ifr\_flags} che esprime i flag di una interfaccia di rete.} + \label{tab:netdevice_iface_flag} +\end{table} + + +\item[\constd{SIOCSIFFLAGS}] permette di impostare il valore dei flag + dell'interfaccia specificata (sempre con \var{ifr\_name}, non staremo a + ripeterlo oltre) attraverso il valore della maschera binaria da passare nel + campo \var{ifr\_flags}, che può essere ottenuta con l'OR aritmetico delle + costanti di tab.~\ref{tab:netdevice_iface_flag}; questa operazione è + privilegiata. + +\item[\constd{SIOCGIFMETRIC}] permette di leggere il valore della metrica del + dispositivo associato all'interfaccia specificata nel campo + \var{ifr\_metric}. Attualmente non è implementato, e l'operazione + restituisce sempre un valore nullo. + +\item[\constd{SIOCSIFMETRIC}] permette di impostare il valore della metrica del + dispositivo al valore specificato nel campo \var{ifr\_metric}, attualmente + non ancora implementato, restituisce un errore di \errval{EOPNOTSUPP}. + +\item[\constd{SIOCGIFMTU}] permette di leggere il valore della \textit{Maximum + Transfer Unit} del dispositivo nel campo \var{ifr\_mtu}. + +\item[\constd{SIOCSIFMTU}] permette di impostare il valore della + \textit{Maximum Transfer Unit} del dispositivo al valore specificato campo + \var{ifr\_mtu}. L'operazione è privilegiata, e si tenga presente che + impostare un valore troppo basso può causare un blocco del kernel. + +\item[\constd{SIOCGIFHWADDR}] permette di leggere il valore dell'indirizzo + hardware del dispositivo associato all'interfaccia nel campo + \var{ifr\_hwaddr}; questo viene restituito come struttura \struct{sockaddr} + in cui il campo \var{sa\_family} contiene un valore \texttt{ARPHRD\_*} + indicante il tipo di indirizzo ed il campo \var{sa\_data} il valore binario + dell'indirizzo hardware a partire dal byte 0. + +\item[\constd{SIOCSIFHWADDR}] permette di impostare il valore dell'indirizzo + hardware del dispositivo associato all'interfaccia attraverso il valore + della struttura \struct{sockaddr} (con lo stesso formato illustrato per + \const{SIOCGIFHWADDR}) passata nel campo \var{ifr\_hwaddr}. L'operazione è + privilegiata. + +\item[\constd{SIOCSIFHWBROADCAST}] imposta l'indirizzo \textit{broadcast} + hardware dell'interfaccia al valore specificato dal campo + \var{ifr\_hwaddr}. L'operazione è privilegiata. + +\item[\constd{SIOCGIFMAP}] legge alcuni parametri hardware (memoria, interrupt, + canali di DMA) del driver dell'interfaccia specificata, restituendo i + relativi valori nel campo \var{ifr\_map}; quest'ultimo contiene una + struttura di tipo \struct{ifmap}, la cui definizione è illustrata in + fig.~\ref{fig:netdevice_ifmap_struct}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/ifmap.h} + \end{minipage} + \caption{La struttura \structd{ifmap} utilizzata per leggere ed impostare i + valori dei parametri hardware di un driver di una interfaccia.} + \label{fig:netdevice_ifmap_struct} +\end{figure} + +\item[\constd{SIOCSIFMAP}] imposta i parametri hardware del driver + dell'interfaccia specificata, restituendo i relativi valori nel campo + \var{ifr\_map}. Come per \const{SIOCGIFMAP} questo deve essere passato come + struttura \struct{ifmap}, secondo la definizione di + fig.~\ref{fig:netdevice_ifmap_struct}. + +\item[\constd{SIOCADDMULTI}] aggiunge un indirizzo di \textit{multicast} ai + filtri del livello di collegamento associati dell'interfaccia. Si deve usare + un indirizzo hardware da specificare attraverso il campo \var{ifr\_hwaddr}, + che conterrà l'opportuna struttura \struct{sockaddr}; l'operazione è + privilegiata. Per una modalità alternativa per eseguire la stessa operazione + si possono usare i \textit{packet socket}, vedi + sez.~\ref{sec:packet_socket}. + +\item[\constd{SIOCDELMULTI}] rimuove un indirizzo di \textit{multicast} ai + filtri del livello di collegamento dell'interfaccia, vuole un indirizzo + hardware specificato come per \const{SIOCADDMULTI}. Anche questa operazione + è privilegiata e può essere eseguita in forma alternativa con i + \textit{packet socket}. + +\item[\constd{SIOCGIFTXQLEN}] permette di leggere la lunghezza della coda di + trasmissione del dispositivo associato all'interfaccia specificata nel campo + \var{ifr\_qlen}. + +\item[\constd{SIOCSIFTXQLEN}] permette di impostare il valore della lunghezza + della coda di trasmissione del dispositivo associato all'interfaccia, questo + deve essere specificato nel campo \var{ifr\_qlen}. L'operazione è + privilegiata. + +\item[\constd{SIOCSIFNAME}] consente di cambiare il nome dell'interfaccia + indicata da \var{ifr\_name} utilizzando il nuovo nome specificato nel campo + \var{ifr\_rename}. + +\end{basedescript} + + +% TODO aggiunta con il kernel 3.14 SIOCGHWTSTAMP per ottenere il timestamp +% hardware senza modificarlo + +Una ulteriore operazione, che consente di ricavare le caratteristiche delle +interfacce di rete, è \constd{SIOCGIFCONF}; però per ragioni di compatibilità +questa operazione è disponibile soltanto per i socket della famiglia +\const{AF\_INET} (vale ad dire per socket IPv4). In questo caso l'utente dovrà +passare come argomento una struttura \struct{ifconf}, definita in +fig.~\ref{fig:netdevice_ifconf_struct}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/ifconf.h} + \end{minipage} + \caption{La struttura \structd{ifconf}.} + \label{fig:netdevice_ifconf_struct} +\end{figure} + +Per eseguire questa operazione occorrerà allocare preventivamente un buffer di +contenente un vettore di strutture \struct{ifreq}. La dimensione (in byte) di +questo buffer deve essere specificata nel campo \var{ifc\_len} di +\struct{ifconf}, mentre il suo indirizzo andrà specificato nel campo +\var{ifc\_req}. Qualora il buffer sia stato allocato come una stringa, il suo +indirizzo potrà essere fornito usando il campo \var{ifc\_buf}.\footnote{si + noti che l'indirizzo del buffer è definito in \struct{ifconf} con una + \dirct{union}, questo consente di utilizzare una delle due forme a piacere.} + +La funzione restituisce nel buffer indicato una serie di strutture +\struct{ifreq} contenenti nel campo \var{ifr\_name} il nome dell'interfaccia e +nel campo \var{ifr\_addr} il relativo indirizzo IP. Se lo spazio allocato nel +buffer è sufficiente il kernel scriverà una struttura \struct{ifreq} per +ciascuna interfaccia attiva, restituendo nel campo \var{ifc\_len} il totale +dei byte effettivamente scritti. Il valore di ritorno è 0 se l'operazione ha +avuto successo e negativo in caso contrario. + +Si tenga presente che il kernel non scriverà mai sul buffer di uscita dati +eccedenti numero di byte specificato col valore di \var{ifc\_len} impostato +alla chiamata della funzione, troncando il risultato se questi non dovessero +essere sufficienti. Questa condizione non viene segnalata come errore per cui +occorre controllare il valore di \var{ifc\_len} all'uscita della funzione, e +verificare che esso sia inferiore a quello di ingresso. In caso contrario si è +probabilmente\footnote{probabilmente perché si potrebbe essere nella + condizione in cui sono stati usati esattamente quel numero di byte.} avuta +una situazione di troncamento dei dati. + +\begin{figure}[!htbp] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/iflist.c} + \end{minipage} + \caption{Il corpo principale del programma \texttt{iflist.c}.} + \label{fig:netdevice_iflist} +\end{figure} + +Come esempio dell'uso di queste funzioni si è riportato in +fig.~\ref{fig:netdevice_iflist} il corpo principale del programma +\texttt{iflist} in cui si utilizza l'operazione \const{SIOCGIFCONF} per +ottenere una lista delle interfacce attive e dei relativi indirizzi. Al solito +il codice completo è fornito nei sorgenti allegati alla guida. + +Il programma inizia (\texttt{\small 7--11}) con la creazione del socket +necessario ad eseguire l'operazione, dopo di che si inizializzano +opportunamente (\texttt{\small 13--14}) i valori della struttura +\struct{ifconf} indicando la dimensione del buffer ed il suo +indirizzo;\footnote{si noti come in questo caso si sia specificato l'indirizzo + usando il campo \var{ifc\_buf}, mentre nel seguito del programma si accederà + ai valori contenuti nel buffer usando \var{ifc\_req}.} si esegue poi +l'operazione invocando \func{ioctl}, controllando come sempre la corretta +esecuzione, ed uscendo in caso di errore (\texttt{\small 15--19}). + +Si esegue poi un controllo sulla quantità di dati restituiti segnalando un +eventuale overflow del buffer (\texttt{\small 21--23}); se invece è tutto a +posto (\texttt{\small 24--27}) si calcola e si stampa a video il numero di +interfacce attive trovate. L'ultima parte del programma (\texttt{\small + 28--33}) è il ciclo sul contenuto delle varie strutture \struct{ifreq} +restituite in cui si estrae (\texttt{\small 30}) l'indirizzo ad esse +assegnato\footnote{si è definito \var{access} come puntatore ad una struttura + di tipo \struct{sockaddr\_in} per poter eseguire un \textit{casting} + dell'indirizzo del valore restituito nei vari campi \var{ifr\_addr}, così + poi da poterlo poi usare come argomento di \func{inet\_ntoa}.} e lo si +stampa (\texttt{\small 31--32}) insieme al nome dell'interfaccia. + + + +\subsection{L'uso di \func{ioctl} per i socket TCP e UDP} +\label{sec:sock_ioctl_IP} + +Non esistono operazioni specifiche per i socket IP in quanto tali,\footnote{a + parte forse \const{SIOCGIFCONF}, che però resta attinente alle proprietà + delle interfacce di rete, per cui l'abbiamo trattata in + sez.~\ref{sec:sock_ioctl_netdevice} insieme alle altre che comunque si + applicano anche ai socket IP.} mentre per i pacchetti di altri protocolli +trasportati su IP, qualora li si gestisca attraverso dei socket, si dovrà fare +riferimento direttamente all'eventuale supporto presente per il tipo di socket +usato: ad esempio si possono ricevere pacchetti ICMP con socket di tipo +\texttt{raw}, nel qual caso si dovrà fare riferimento alle operazioni di +quest'ultimo. + +Tuttavia la gran parte dei socket utilizzati nella programmazione di rete +utilizza proprio il protocollo IP, e quello che succede è che in realtà la +funzione \func{ioctl} consente di effettuare alcune operazioni specifiche per +i socket che usano questo protocollo, ma queste vendono eseguite, invece che a +livello di IP, al successivo livello di trasporto, vale a dire in maniera +specifica per i socket TCP e UDP. + +Le operazioni di controllo disponibili per i socket TCP sono illustrate dalla +relativa pagina di manuale, accessibile con \texttt{man 7 tcp}, e prevedono +come possibile valore per il secondo argomento della funzione le costanti +illustrate nell'elenco seguente; il terzo argomento della funzione, gestito +come \textit{value result argument}, deve essere sempre il puntatore ad una +variabile di tipo \ctyp{int}: +\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}} +\item[\constd{SIOCINQ}] restituisce la quantità di dati non ancora letti + presenti nel buffer di ricezione; il socket non deve essere in stato + \texttt{LISTEN}, altrimenti si avrà un errore di \errval{EINVAL}. +\item[\constd{SIOCATMARK}] ritorna un intero non nullo, da intendere come + valore logico, se il flusso di dati letti sul socket è arrivato sulla + posizione (detta anche \textit{urgent mark}) in cui sono stati ricevuti dati + urgenti (vedi sez.~\ref{sec:TCP_urgent_data}). Una operazione di lettura da + un socket non attraversa mai questa posizione, per cui è possibile + controllare se la si è raggiunta o meno con questa operazione. + + Questo è utile quando si attiva l'opzione \const{SO\_OOBINLINE} (vedi + sez.~\ref{sec:sock_generic_options}) per ricevere i dati urgenti all'interno + del flusso dei dati ordinari del socket;\footnote{vedremo in + sez.~\ref{sec:TCP_urgent_data} che in genere i dati urgenti presenti su un + socket si leggono \textit{out-of-band} usando un opportuno flag per + \func{recvmsg}.} in tal caso quando \const{SIOCATMARK} restituisce un + valore non nullo si saprà che la successiva lettura dal socket restituirà i + dati urgenti e non il normale traffico; torneremo su questo in maggior + dettaglio in sez.~\ref{sec:TCP_urgent_data}. + +\item[\constd{SIOCOUTQ}] restituisce la quantità di dati non ancora inviati + presenti nel buffer di spedizione; come per \const{SIOCINQ} il socket non + deve essere in stato \texttt{LISTEN}, altrimenti si avrà un errore di + \errval{EINVAL}. +\end{basedescript} + +Le operazioni di controllo disponibili per i socket UDP, anch'esse illustrate +dalla relativa pagina di manuale accessibile con \texttt{man 7 udp}, sono +quelle indicate dalle costanti del seguente elenco; come per i socket TCP il +terzo argomento viene gestito come \textit{value result argument} e deve +essere un puntatore ad una variabile di tipo \ctyp{int}: +\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}} +\item[\const{FIONREAD}] restituisce la dimensione in byte del primo pacchetto + in attesa di ricezione, o 0 qualora non ci sia nessun pacchetto. +\item[\const{TIOCOUTQ}] restituisce il numero di byte presenti nella coda di + invio locale; questa opzione è supportata soltanto a partire dal kernel 2.4 +\end{basedescript} + + + +\section{La gestione con \func{sysctl} ed il filesystem \texttt{/proc}} +\label{sec:sock_sysctl_proc} + +Come ultimo argomento di questo capitolo tratteremo l'uso della funzione +\func{sysctl} (che è stata introdotta nelle sue funzionalità generiche in +sez.~\ref{sec:sys_sysctl}) per quanto riguarda le sue capacità di effettuare +impostazioni relative alle proprietà dei socket. Dato che le stesse +funzionalità sono controllabili direttamente attraverso il filesystem +\texttt{/proc}, le tratteremo attraverso i file presenti in quest'ultimo. + + +\subsection{L'uso di \func{sysctl} e \texttt{/proc} per le proprietà della + rete} +\label{sec:sock_sysctl} + +La differenza nell'uso di \func{sysctl} e del filesystem \texttt{/proc} +rispetto a quello delle funzioni \func{ioctl} e \func{fcntl} visto in +sez.~\ref{sec:sock_ctrl_func} o all'uso di \func{getsockopt} e +\func{setsockopt} è che queste funzioni consentono di controllare le proprietà +di un singolo socket, mentre con \func{sysctl} e con \texttt{/proc} si +impostano proprietà (o valori di default) validi a livello dell'intero +sistema, e cioè per tutti i socket. + +Le opzioni disponibili per le proprietà della rete, nella gerarchia dei valori +impostabili con \func{sysctl}, sono riportate sotto il nodo \texttt{net}, o, +se acceduti tramite l'interfaccia del filesystem \texttt{/proc}, sotto +\texttt{/proc/sys/net}. In genere sotto questa directory compaiono le +sottodirectory (corrispondenti ad altrettanti sotto-nodi per \func{sysctl}) +relative ai vari protocolli e tipi di interfacce su cui è possibile +intervenire per effettuare impostazioni; un contenuto tipico di questa +directory è il seguente: +\begin{verbatim} +/proc/sys/net/ +|-- core +|-- ethernet +|-- ipv4 +|-- ipv6 +|-- irda +|-- token-ring +`-- unix +\end{verbatim} +e sono presenti varie centinaia di parametri, molti dei quali non sono neanche +documentati; nel nostro caso ci limiteremo ad illustrare quelli più +significativi. + +Si tenga presente infine che se è sempre possibile utilizzare il filesystem +\texttt{/proc} come sostituto di \func{sysctl}, dato che i valori di nodi e +sotto-nodi di quest'ultima sono mappati come file e directory sotto +\texttt{/proc/sys/}, non è vero il contrario, ed in particolare Linux consente +di impostare alcuni parametri o leggere lo stato della rete a livello di +sistema sotto \texttt{/proc/net}, dove sono presenti dei file che non +corrispondono a nessun nodo di \func{sysctl}. + + +\subsection{I valori di controllo per i socket generici} +\label{sec:sock_gen_sysctl} + +Nella directory \texttt{/proc/sys/net/core/} sono presenti i file +corrispondenti ai parametri generici di \textit{sysctl} validi per tutti i +socket. Quelli descritti anche nella pagina di manuale, accessibile con +\texttt{man 7 socket} sono i seguenti: + +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} +\item[\sysctlrelfiled{net/core}{rmem\_default}] imposta la dimensione + di default del buffer di ricezione (cioè per i dati in ingresso) dei socket. +\item[\sysctlrelfiled{net/core}{rmem\_max}] imposta la dimensione + massima che si può assegnare al buffer di ricezione dei socket attraverso + l'uso dell'opzione \const{SO\_RCVBUF}. +\item[\sysctlrelfiled{net/core}{wmem\_default}] imposta la dimensione + di default del buffer di trasmissione (cioè per i dati in uscita) dei + socket. +\item[\sysctlrelfiled{net/core}{wmem\_max}] imposta la dimensione + massima che si può assegnare al buffer di trasmissione dei socket attraverso + l'uso dell'opzione \const{SO\_SNDBUF}. +\item[\sysctlrelfiled{net/core}{message\_cost}, + \sysctlrelfiled{net/core}{message\_burst}] contengono le impostazioni del + \textit{bucket filter} che controlla l'emissione di + messaggi di avviso da parte del kernel per eventi relativi a problemi sulla + rete, imponendo un limite che consente di prevenire eventuali attacchi di + \textit{Denial of Service} usando i log.\footnote{senza questo limite un + attaccante potrebbe inviare ad arte un traffico che generi + intenzionalmente messaggi di errore, per saturare il sistema dei log.} + + \itindbeg{bucket~filter} + + Il \textit{bucket filter} è un algoritmo generico che permette di impostare + dei limiti di flusso su una quantità\footnote{uno analogo viene usato per + imporre dei limiti sul flusso dei pacchetti nel \textit{netfilter} di + Linux.} senza dovere eseguire medie temporali, che verrebbero a dipendere + in misura non controllabile dalla dimensione dell'intervallo su cui si media + e dalla distribuzione degli eventi;\footnote{in caso di un picco di flusso + (il cosiddetto \textit{burst}) il flusso medio verrebbe a dipendere in + maniera esclusiva dalla dimensione dell'intervallo di tempo su cui calcola + la media.} in questo caso si definisce la dimensione di un + ``\textsl{bidone}'' (il \textit{bucket}) e del flusso che da esso può + uscire, la presenza di una dimensione iniziale consente di assorbire + eventuali picchi di emissione, l'aver fissato un flusso di uscita garantisce + che a regime questo sarà il valore medio del flusso ottenibile dal + \textit{bucket}. + + \itindend{bucket~filter} + + I due valori indicano rispettivamente il flusso a regime (non sarà inviato + più di un messaggio per il numero di secondi specificato da + \texttt{message\_cost}) e la dimensione iniziale per in caso di picco di + emissione (verranno accettati inizialmente fino ad un massimo di + \texttt{message\_cost/message\_burst} messaggi). + +\item[\sysctlrelfiled{net/core}{netdev\_max\_backlog}] numero massimo + di pacchetti che possono essere contenuti nella coda di ingresso generale. + +\item[\sysctlrelfiled{net/core}{optmem\_max}] lunghezza massima dei + dati ancillari e di controllo (vedi sez.~\ref{sec:net_ancillary_data}). +\end{basedescript} + +Oltre a questi, nella directory \texttt{/proc/sys/net/core} si trovano diversi +altri file, la cui documentazione, come per gli altri, dovrebbe essere +mantenuta nei sorgenti del kernel nel file +\texttt{Documentation/networking/ip-sysctl.txt}; la maggior parte di questi +però non è documentato: +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} +\item[\sysctlrelfiled{net/core}{dev\_weight}] blocco di lavoro (\textit{work + quantum}) dello \textit{scheduler} di processo dei pacchetti. + +% TODO da documentare meglio + +\item[\sysctlrelfiled{net/core}{lo\_cong}] valore per l'occupazione + della coda di ricezione sotto la quale si considera di avere una bassa + congestione. + +\item[\sysctlrelfiled{net/core}{mod\_cong}] valore per l'occupazione della + coda di ricezione sotto la quale si considera di avere una congestione + moderata. + +\item[\sysctlrelfiled{net/core}{no\_cong}] valore per l'occupazione della coda + di ricezione sotto la quale si considera di non avere congestione. + +\item[\sysctlrelfiled{net/core}{no\_cong\_thresh}] valore minimo (\textit{low + water mark}) per il riavvio dei dispositivi congestionati. + + % \item[\sysctlrelfiled{net/core}{netdev\_fastroute}] è presente + % soltanto quando si è compilato il kernel con l'apposita opzione di + % ottimizzazione per l'uso come router. + +\item[\sysctlrelfiled{net/core}{somaxconn}] imposta la dimensione massima + utilizzabile per il \textit{backlog} della funzione \func{listen} (vedi + sez.~\ref{sec:TCP_func_listen}), e corrisponde al valore della costante + \constd{SOMAXCONN}; il suo valore di default è 128. + +\end{basedescript} + + +\subsection{I valori di controllo per il protocollo IPv4} +\label{sec:sock_ipv4_sysctl} + +Nella directory \texttt{/proc/sys/net/ipv4} sono presenti i file che +corrispondono ai parametri dei socket che usano il protocollo IPv4, relativi +quindi sia alle caratteristiche di IP, che a quelle degli altri protocolli che +vengono usati all'interno di quest'ultimo (come ICMP, TCP e UDP) o a fianco +dello stesso (come ARP). + +I file che consentono di controllare le caratteristiche specifiche del +protocollo IP in quanto tale, che sono descritti anche nella relativa pagina +di manuale accessibile con \texttt{man 7 ip}, sono i seguenti: +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} + +\item[\sysctlrelfiled{net/ipv4}{ip\_default\_ttl}] imposta il valore di + default per il campo TTL (vedi sez.~\ref{sec:IP_header}) di tutti i + pacchetti uscenti, stabilendo così il numero massimo di router che i + pacchetti possono attraversare. Il valore può essere modificato anche per il + singolo socket con l'opzione \const{IP\_TTL}. Prende un valore intero, ma + dato che il campo citato è di 8 bit hanno senso solo valori fra 0 e 255. Il + valore di default è 64, e normalmente non c'è nessuna necessità di + modificarlo.\footnote{l'unico motivo sarebbe per raggiungere macchine + estremamente ``{lontane}'' in termini di \textit{hop}, ma è praticamente + impossibile trovarne.} Aumentare il valore è una pratica poco gentile, in + quanto in caso di problemi di routing si allunga inutilmente il numero di + ritrasmissioni. + +\item[\sysctlrelfiled{net/ipv4}{ip\_forward}] abilita l'inoltro dei + pacchetti da una interfaccia ad un altra, e può essere impostato anche per + la singola interfaccia. Prende un valore logico (0 disabilita, diverso da + zero abilita), di default è disabilitato. + +\item[\sysctlrelfiled{net/ipv4}{ip\_dynaddr}] abilita la riscrittura + automatica degli indirizzi associati ad un socket quando una interfaccia + cambia indirizzo. Viene usato per le interfacce usate nei collegamenti in + dial-up, il cui indirizzo IP viene assegnato dinamicamente dal provider, e + può essere modificato. Prende un valore intero, con 0 si disabilita la + funzionalità, con 1 la si abilita, con 2 (o con qualunque altro valore + diverso dai precedenti) la si abilità in modalità \textsl{prolissa}; di + default la funzionalità è disabilitata. + +\item[\sysctlrelfiled{net/ipv4}{ip\_autoconfig}] specifica se + l'indirizzo IP è stato configurato automaticamente dal kernel all'avvio + attraverso DHCP, BOOTP o RARP. Riporta un valore logico (0 falso, 1 vero) + accessibile solo in lettura, è inutilizzato nei kernel recenti ed eliminato + a partire dal kernel 2.6.18. + +\item[\sysctlrelfiled{net/ipv4}{ip\_local\_port\_range}] imposta l'intervallo + dei valori usati per l'assegnazione delle porte effimere, permette cioè di + modificare i valori illustrati in fig.~\ref{fig:TCP_port_alloc}; prende due + valori interi separati da spazi, che indicano gli estremi + dell'intervallo. Si abbia cura di non definire un intervallo che si + sovrappone a quello delle porte usate per il \textit{masquerading}, il + kernel può gestire la sovrapposizione, ma si avrà una perdita di + prestazioni. Si imposti sempre un valore iniziale maggiore di 1024 (o meglio + ancora di 4096) per evitare conflitti con le porte usate dai servizi noti. + +\item[\sysctlrelfiled{net/ipv4}{ip\_no\_pmtu\_disc}] permette di disabilitare + per i socket \const{SOCK\_STREAM} la ricerca automatica della \textit{Path + MTU} (vedi sez.~\ref{sec:net_lim_dim} e + sez.~\ref{sec:sock_ipv4_options}). Prende un valore logico, e di default è + disabilitato (cioè la ricerca viene eseguita). + + In genere si abilita questo parametro quando per qualche motivo il + procedimento del \textit{Path MTU discovery} fallisce; dato che questo può + avvenire a causa di router\footnote{ad esempio se si scartano tutti i + pacchetti ICMP, il problema è affrontato anche in sez.~3.4.4 di + \cite{SGL}.} o interfacce\footnote{ad esempio se i due capi di un + collegamento \textit{point-to-point} non si accordano sulla stessa MTU.} + mal configurati è opportuno correggere le configurazioni, perché + disabilitare globalmente il procedimento con questo parametro ha pesanti + ripercussioni in termini di prestazioni di rete. + +\item[\sysctlrelfiled{net/ipv4}{ip\_always\_defrag}] fa sì che tutti i + pacchetti IP frammentati siano riassemblati, anche in caso in successivo + immediato inoltro.\footnote{introdotto con il kernel 2.2.13, nelle versioni + precedenti questo comportamento poteva essere solo stabilito un volta per + tutte in fase di compilazione del kernel con l'opzione + \texttt{CONFIG\_IP\_ALWAYS\_DEFRAG}.} Prende un valore logico e di default + è disabilitato. Con i kernel dalla serie 2.4 in poi la deframmentazione + viene attivata automaticamente quando si utilizza il sistema del + \textit{netfilter}, e questo parametro non è più presente. + +\item[\sysctlrelfiled{net/ipv4}{ipfrag\_high\_thresh}] indica il limite + massimo (espresso in numero di byte) sui pacchetti IP frammentati presenti + in coda; quando questo valore viene raggiunto la coda viene ripulita fino al + valore \texttt{ipfrag\_low\_thresh}. Prende un valore intero. + +\item[\sysctlrelfiled{net/ipv4}{ipfrag\_low\_thresh}] indica la dimensione + (specificata in byte) della soglia inferiore a cui viene riportata la coda + dei pacchetti IP frammentati quando si raggiunge il valore massimo dato da + \texttt{ipfrag\_high\_thresh}. Prende un valore intero. + +\item[\sysctlrelfiled{net/ipv4}{ip\_nonlocal\_bind}] se abilitato rende + possibile ad una applicazione eseguire \func{bind} anche su un indirizzo che + non è presente su nessuna interfaccia locale. Prende un valore logico e di + default è disabilitato. La funzionalità può essere abilitata a livello di + singolo socket con l'opzione \const{IP\_FREEBIND} illustrata in + sez.~\ref{sec:sock_ipv4_options}. + + Questo può risultare utile per applicazioni particolari (come gli + \textit{sniffer}) che hanno la necessità di ricevere pacchetti anche non + diretti agli indirizzi presenti sulla macchina, ad esempio per intercettare + il traffico per uno specifico indirizzo che si vuole tenere sotto + controllo. Il suo uso però può creare problemi ad alcune applicazioni. + +% \item[\texttt{neigh/*}] La directory contiene i valori +% TODO trattare neigh/* nella parte su arp, da capire dove sarà. + +\end{basedescript} + +I file di \texttt{/proc/sys/net/ipv4} che invece fanno riferimento alle +caratteristiche specifiche del protocollo TCP, elencati anche nella rispettiva +pagina di manuale (accessibile con \texttt{man 7 tcp}), sono i seguenti: +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} + +\item[\sysctlrelfiled{net/ipv4}{tcp\_abort\_on\_overflow}] indica al + kernel di azzerare le connessioni quando il programma che le riceve è troppo + lento ed incapace di accettarle. Prende un valore logico ed è disabilitato + di default. Questo consente di recuperare le connessioni se si è avuto un + eccesso dovuto ad un qualche picco di traffico, ma ovviamente va a discapito + dei client che interrogano il server. Pertanto è da abilitare soltanto + quando si è sicuri che non è possibile ottimizzare il server in modo che sia + in grado di accettare connessioni più rapidamente. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_adv\_win\_scale}] indica al kernel quale + frazione del buffer associato ad un socket\footnote{quello impostato con + \sysctlrelfile{net/ipv4}{tcp\_rmem}.} deve essere utilizzata per la + finestra del protocollo TCP\footnote{in sostanza il valore che costituisce + la \textit{advertised window} annunciata all'altro capo del socket.} e + quale come buffer applicativo per isolare la rete dalle latenze + dell'applicazione. Prende un valore intero che determina la suddetta + frazione secondo la formula + $\texttt{buffer}/2^\texttt{tcp\_adv\_win\_scale}$ se positivo o con + $\texttt{buffer}-\texttt{buffer}/2^\texttt{tcp\_adv\_win\_scale}$ se + negativo. Il default è 2 che significa che al buffer dell'applicazione + viene riservato un quarto del totale. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_app\_win}] indica la frazione della + finestra TCP che viene riservata per gestire l'overhaed dovuto alla + bufferizzazione. Prende un valore intero che consente di calcolare la + dimensione in byte come il massimo fra la MSS e + $\texttt{window}/2^\texttt{tcp\_app\_win}$. Un valore nullo significa che + non viene riservato nessuno spazio; il valore di default è 31. + +% vecchi, presumibilmente usati quando gli algoritmi di congestione non erano +% modularizzabili +% \item[\texttt{tcp\_bic}] +% \item[\texttt{tcp\_bic\_low\_window}] +% \item[\texttt{tcp\_bic\_fast\_convergence}] + +\item[\sysctlrelfiled{net/ipv4}{tcp\_dsack}] abilita il supporto, + definito nell'\href{http://www.ietf.org/rfc/rfc2884.txt}{RFC~2884}, per il + cosiddetto \textit{Duplicate SACK}.\footnote{si indica con SACK + (\textit{Selective Acknowledgement}) un'opzione TCP, definita + nell'\href{http://www.ietf.org/rfc/rfc2018.txt}{RFC~2018}, usata per dare + un \textit{acknowledgement} unico su blocchi di pacchetti non contigui, + che consente di diminuire il numero di pacchetti scambiati.} Prende un + valore logico e di default è abilitato. +% TODO documentare o descrivere che cos'è il Duplicate SACK o +% mettere riferimento nelle appendici + + +\item[\sysctlrelfiled{net/ipv4}{tcp\_ecn}] abilita il meccanismo della + \textit{Explicit Congestion Notification} (in breve ECN) nelle connessioni + TCP. Prende valore logico che di default è disabilitato. La \textit{Explicit + Congestion Notification} \itindex{Explicit~Congestion~Notification~(ECN)} + è un meccanismo che consente di notificare quando una rotta o una rete è + congestionata da un eccesso di traffico,\footnote{il meccanismo è descritto + in dettaglio nell'\href{http://www.ietf.org/rfc/rfc3168.txt}{RFC~3168} + mentre gli effetti sulle prestazioni del suo utilizzo sono documentate + nell'\href{http://www.ietf.org/rfc/rfc2884.txt}{RFC~2884}.} si può così + essere avvisati e cercare rotte alternative oppure diminuire l'emissione di + pacchetti (in modo da non aumentare la congestione). + + Si tenga presente che se si abilita questa opzione si possono avere dei + malfunzionamenti apparentemente casuali dipendenti dalla destinazione, + dovuti al fatto che alcuni vecchi router non supportano il meccanismo ed + alla sua attivazione scartano i relativi pacchetti, bloccando completamente + il traffico. +% TODO documentare o descrivere che cos'è l'Explicit Congestion Notification o +% mettere riferimento nelle appendici + + +\item[\sysctlrelfiled{net/ipv4}{tcp\_fack}] abilita il supporto per il + \textit{TCP Forward Acknowledgement}, un algoritmo per il controllo della + congestione del traffico. Prende un valore logico e di default è abilitato. + +% TODO documentare o descrivere che cos'è il TCP Forward Acknowledgement o +% mettere riferimento nelle appendici + +\item[\sysctlrelfiled{net/ipv4}{tcp\_fin\_timeout}] specifica il numero di + secondi da passare in stato \texttt{FIN\_WAIT2} nell'attesa delle ricezione + del pacchetto FIN conclusivo, passati quali il socket viene comunque chiuso + forzatamente. Prende un valore intero che indica i secondi e di default è + 60.\footnote{nei kernel della serie 2.2.x era il valore utilizzato era + invece di 120 secondi.} L'uso di questa opzione realizza quella che in + sostanza è una violazione delle specifiche del protocollo TCP, ma è utile + per fronteggiare alcuni attacchi di \textit{Denial of Service}. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_frto}] abilita il supporto per + l'algoritmo F-RTO, un algoritmo usato per la ritrasmissione dei timeout del + protocollo TCP, che diventa molto utile per le reti wireless dove la perdita + di pacchetti è usualmente dovuta a delle interferenze radio, piuttosto che + alla congestione dei router. Prende un valore logico e di default è + disabilitato. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_keepalive\_intvl}] indica il + numero di secondi che deve trascorrere fra l'emissione di due successivi + pacchetti di test quando è abilitata la funzionalità del \textit{keepalive} + (vedi sez.~\ref{sec:sock_options_main}). Prende un valore intero che di + default è 75. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_keepalive\_probes}] indica il + massimo numero pacchetti di \textit{keepalive} (vedi + sez.~\ref{sec:sock_options_main}) che devono essere inviati senza ricevere + risposta prima che il kernel decida che la connessione è caduta e la + termini. Prende un valore intero che di default è 9. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_keepalive\_time}] indica il numero di + secondi che devono passare senza traffico sulla connessione prima che il + kernel inizi ad inviare pacchetti di \textit{keepalive}.\footnote{ha effetto + solo per i socket per cui si è impostata l'opzione \const{SO\_KEEPALIVE} + (vedi sez.~\ref{sec:sock_options_main}.} Prende un valore intero che di + default è 7200, pari a due ore. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_low\_latency}] indica allo stack + TCP del kernel di ottimizzare il comportamento per ottenere tempi di latenza + più bassi a scapito di valori più alti per l'utilizzo della banda. Prende un + valore logico che di default è disabilitato in quanto un maggior utilizzo + della banda è preferito, ma esistono applicazioni particolari in cui la + riduzione della latenza è più importante (ad esempio per i cluster di + calcolo parallelo) nelle quali lo si può abilitare. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_max\_orphans}] indica il numero + massimo di socket TCP ``\textsl{orfani}'' (vale a dire non associati a + nessun file descriptor) consentito nel sistema.\footnote{trattasi in genere + delle connessioni relative a socket chiusi che non hanno completato il + processo di chiusura.} Quando il limite viene ecceduto la connessione + orfana viene resettata e viene stampato un avvertimento. Questo limite viene + usato per contrastare alcuni elementari attacchi di \textit{denial of + service}. Diminuire il valore non è mai raccomandato, in certe condizioni + di rete può essere opportuno aumentarlo, ma si deve tenere conto del fatto + che ciascuna connessione orfana può consumare fino a 64K di memoria del + kernel. Prende un valore intero, il valore di default viene impostato + inizialmente al valore del parametro del kernel \texttt{NR\_FILE}, e viene + aggiustato a seconda della memoria disponibile. + +% TODO verificare la spiegazione di connessione orfana. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_max\_syn\_backlog}] indica la lunghezza + della coda delle connessioni incomplete, cioè delle connessioni per le quali + si è ricevuto un SYN di richiesta ma non l'ACK finale del \textit{three way + handshake} (si riveda quanto illustrato in + sez.~\ref{sec:TCP_func_listen}). + + Quando questo valore è superato il kernel scarterà immediatamente ogni + ulteriore richiesta di connessione. Prende un valore intero; il default, che + è 256, viene automaticamente portato a 1024 qualora nel sistema ci sia + sufficiente memoria (se maggiore di 128Mb) e ridotto a 128 qualora la + memoria sia poca (inferiore a 32Mb).\footnote{si raccomanda, qualora si + voglia aumentare il valore oltre 1024, di seguire la procedura citata + nella pagina di manuale di TCP, e modificare il valore della costante + \texttt{TCP\_SYNQ\_HSIZE} nel file \texttt{include/net/tcp.h} dei sorgenti + del kernel, in modo che sia $\mathtt{tcp\_max\_syn\_backlog} \ge + \mathtt{16*TCP\_SYNQ\_HSIZE}$, per poi ricompilare il kernel.} + +\item[\sysctlrelfiled{net/ipv4}{tcp\_max\_tw\_buckets}] indica il + numero massimo di socket in stato \texttt{TIME\_WAIT} consentito nel + sistema. Prende un valore intero di default è impostato al doppio del valore + del parametro \texttt{NR\_FILE}, ma che viene aggiustato automaticamente a + seconda della memoria presente. Se il valore viene superato il socket viene + chiuso con la stampa di un avviso; l'uso di questa funzionalità consente di + prevenire alcuni semplici attacchi di \textit{denial of service}. + + +\item[\sysctlrelfiled{net/ipv4}{tcp\_mem}] viene usato dallo stack TCP + per gestire le modalità con cui esso utilizzerà la memoria. Prende una + tripletta di valori interi, che indicano un numero di pagine: + + \begin{itemize*} + \item il primo valore, chiamato \textit{low} nelle pagine di manuale, indica + il numero di pagine allocate sotto il quale non viene usato nessun + meccanismo di regolazione dell'uso della memoria. + + \item il secondo valore, chiamato \textit{pressure} indica il numero di + pagine allocate passato il quale lo stack TCP inizia a moderare il suo + consumo di memoria; si esce da questo stato di \textsl{pressione} sulla + memoria quando il numero di pagine scende sotto il precedente valore + \textit{low}. + + \item il terzo valore, chiamato \textit{high} indica il numero massimo di + pagine che possono essere utilizzate dallo stack TCP/IP, e soprassiede + ogni altro valore specificato dagli altri limiti del kernel. + \end{itemize*} + +\item[\sysctlrelfiled{net/ipv4}{tcp\_orphan\_retries}] indica il numero + massimo di volte che si esegue un tentativo di controllo sull'altro capo di + una connessione che è stata già chiusa dalla nostra parte. Prende un valore + intero che di default è 8. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_reordering}] indica il numero + massimo di volte che un pacchetto può essere riordinato nel flusso di dati, + prima che lo stack TCP assuma che è andato perso e si ponga nello stato di + \textit{slow start} (si veda sez.~\ref{sec:tcp_protocol_xxx}) viene usata + questa metrica di riconoscimento dei riordinamenti per evitare inutili + ritrasmissioni provocate dal riordinamento. Prende un valore intero che di + default che è 3, e che non è opportuno modificare. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_retrans\_collapse}] in caso di + pacchetti persi durante una connessione, per ottimizzare l'uso della banda + il kernel cerca di eseguire la ritrasmissione inviando pacchetti della + massima dimensione possibile; in sostanza dati che in precedenza erano stati + trasmessi su pacchetti diversi possono essere ritrasmessi riuniti su un solo + pacchetto (o su un numero minore di pacchetti di dimensione + maggiore). Prende un valore logico e di default è abilitato. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_retries1}] imposta il massimo + numero di volte che protocollo tenterà la ritrasmissione si un pacchetto su + una connessione stabilita prima di fare ricorso ad ulteriori sforzi che + coinvolgano anche il livello di rete. Passato questo numero di + ritrasmissioni verrà fatto eseguire al livello di rete un tentativo di + aggiornamento della rotta verso la destinazione prima di eseguire ogni + successiva ritrasmissione. Prende un valore intero che di default è 3. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_retries2}] imposta il numero di + tentativi di ritrasmissione di un pacchetto inviato su una connessione già + stabilita per il quale non si sia ricevuto una risposta di ACK (si veda + anche quanto illustrato in sez.~\ref{sec:TCP_server_crash}). Prende un + valore intero che di default è 15, il che comporta un tempo variabile fra 13 + e 30 minuti; questo non corrisponde a quanto richiesto + nell'\href{http://www.ietf.org/rfc/rfc1122.txt}{RFC~1122} dove è indicato un + massimo di 100 secondi, che però è un valore considerato troppo basso. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_rfc1337}] indica al kernel di + abilitare il comportamento richiesto + nell'\href{http://www.ietf.org/rfc/rfc1337.txt}{RFC~1337}. Prende un valore + logico e di default è disabilitato, il che significa che alla ricezione di + un segmento RST in stato \texttt{TIME\_WAIT} il socket viene chiuso + immediatamente senza attendere la conclusione del periodo di + \texttt{TIME\_WAIT}. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_rmem}] viene usato dallo stack TCP + per controllare dinamicamente le dimensioni dei propri buffer di ricezione, + anche in rapporto alla memoria disponibile. Prende una tripletta di valori + interi separati da spazi che indicano delle dimensioni in byte: + + \begin{itemize} + \item il primo valore, chiamato \textit{min} nelle pagine di manuale, indica + la dimensione minima in byte del buffer di ricezione; il default è 4Kb, ma + in sistemi con poca memoria viene automaticamente ridotto a + \const{PAGE\_SIZE}. Questo valore viene usato per assicurare che anche in + situazioni di pressione sulla memoria (vedi quanto detto per + \sysctlrelfile{net/ipv4}{tcp\_rmem}) le allocazioni al di sotto di + questo limite abbiamo comunque successo. Questo valore non viene comunque + ad incidere sulla dimensione del buffer di ricezione di un singolo socket + dichiarata con l'opzione \const{SO\_RCVBUF}. + + \item il secondo valore, denominato \textit{default} nelle pagine di + manuale, indica la dimensione di default, in byte, del buffer di ricezione + di un socket TCP. Questo valore sovrascrive il default iniziale impostato + per tutti i socket con \sysctlfile{net/core/mem\_default} che vale per + qualunque protocollo. Il default è 87380 byte, ridotto a 43689 per sistemi + con poca memoria. Se si desiderano dimensioni più ampie per tutti i socket + si può aumentare questo valore, ma se si vuole che in corrispondenza + aumentino anche le dimensioni usate per la finestra TCP si deve abilitare + il \textit{TCP window scaling} (di default è abilitato, vedi più avanti + \sysctlrelfile{net/ipv4}{tcp\_window\_scaling}). + + \item il terzo valore, denominato \textit{max} nelle pagine di manuale, + indica la dimensione massima in byte del buffer di ricezione di un socket + TCP; il default è 174760 byte, che viene ridotto automaticamente a 87380 + per sistemi con poca memoria. Il valore non può comunque eccedere il + limite generale per tutti i socket posto con + \sysctlfile{net/core/rmem\_max}. Questo valore non viene ad + incidere sulla dimensione del buffer di ricezione di un singolo socket + dichiarata con l'opzione \const{SO\_RCVBUF}. + \end{itemize} + +\item[\sysctlrelfiled{net/ipv4}{tcp\_sack}] indica al kernel di + utilizzare il meccanismo del \textit{TCP selective acknowledgement} definito + nell'\href{http://www.ietf.org/rfc/rfc2018.txt}{RFC~2018}. Prende un valore + logico e di default è abilitato. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_stdurg}] indica al kernel di + utilizzare l'interpretazione che viene data + dall'\href{http://www.ietf.org/rfc/rfc1122.txt}{RFC~1122} del puntatore dei + \textit{dati urgenti} (vedi sez.~\ref{sec:TCP_urgent_data}) in cui questo + punta all'ultimo byte degli stessi; se disabilitato viene usata + l'interpretazione usata da BSD per cui esso punta al primo byte successivo. + Prende un valore logico e di default è disabilitato, perché abilitarlo può + dar luogo a problemi di interoperabilità. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_synack\_retries}] indica il numero + massimo di volte che verrà ritrasmesso il segmento SYN/ACK nella creazione di + una connessione (vedi sez.~\ref{sec:TCP_conn_cre}). Prende un valore intero + ed il valore di default è 5; non si deve superare il valore massimo di 255. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_syncookies}] abilita i \textit{TCP + syncookies}.\footnote{per poter usare questa funzionalità è necessario + avere abilitato l'opzione \texttt{CONFIG\_SYN\_COOKIES} nella compilazione + del kernel.} Prende un valore logico, e di default è disabilitato. Questa + funzionalità serve a fornire una protezione in caso di un attacco di tipo + \textit{SYN flood}, e deve essere utilizzato come ultima risorsa dato che + costituisce una violazione del protocollo TCP e confligge con altre + funzionalità come le estensioni e può causare problemi per i client ed il + reinoltro dei pacchetti. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_syn\_retries}] imposta il numero di + tentativi di ritrasmissione dei pacchetti SYN di inizio connessione del + \textit{three way handshake} (si ricordi quanto illustrato in + sez.~\ref{sec:TCP_func_connect}). Prende un valore intero che di default è + 5; non si deve superare il valore massimo di 255. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_timestamps}] abilita l'uso dei + \textit{TCP timestamps}, come definiti + nell'\href{http://www.ietf.org/rfc/rfc1323.txt}{RFC~1323}. Prende un valore + logico e di default è abilitato. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_tw\_recycle}] abilita il riutilizzo + rapido dei socket in stato \texttt{TIME\_WAIT}. Prende un valore logico e di + default è disabilitato. Non è opportuno abilitare questa opzione che può + causare problemi con il NAT.\footnote{la + \itindex{Network~Address~Translation~(NAT)} \textit{Network Address + Translation} (abbreviato in NAT) è una tecnica, impiegata nei firewall e + nei router, che consente di modificare al volo gli indirizzi dei pacchetti + che transitano per una macchina, Linux la supporta con il + \textit{netfilter}.} + +\item[\sysctlrelfiled{net/ipv4}{tcp\_tw\_reuse}] abilita il riutilizzo + dello stato \texttt{TIME\_WAIT} quando questo è sicuro dal punto di vista + del protocollo. Prende un valore logico e di default è disabilitato. + +\item[\sysctlrelfiled{net/ipv4}{tcp\_window\_scaling}] un valore + logico, attivo di default, che abilita la funzionalità del + \itindex{TCP~window~scaling} \textit{TCP window scaling} definita + dall'\href{http://www.ietf.org/rfc/rfc1323.txt}{RFC~1323}. Prende un valore + logico e di default è abilitato. Come accennato in + sez.~\ref{sec:TCP_TCP_opt} i 16 bit della finestra TCP comportano un limite + massimo di dimensione di 64Kb, ma esiste una opportuna opzione del + protocollo che permette di applicare un fattore di scale che consente di + aumentarne le dimensioni. Questa è pienamente supportata dallo stack TCP di + Linux, ma se lo si disabilita la negoziazione del + \itindex{TCP~window~scaling} \textit{TCP window scaling} con l'altro capo + della connessione non viene effettuata. + +%\item[\sysctlrelfiled{net/ipv4}{tcp\_vegas\_cong\_avoid}] +% TODO: controllare su internet + +%\item[\sysctlrelfiled{net/ipv4}{tcp\_westwood}] +% TODO: controllare su internet + +\item[\sysctlrelfiled{net/ipv4}{tcp\_wmem}] viene usato dallo stack TCP + per controllare dinamicamente le dimensioni dei propri buffer di spedizione, + adeguandole in rapporto alla memoria disponibile. Prende una tripletta di + valori interi separati da spazi che indicano delle dimensioni in byte: + + \begin{itemize} + \item il primo valore, chiamato \textit{min}, indica la dimensione minima in + byte del buffer di spedizione; il default è 4Kb. Come per l'analogo di + \sysctlrelfile{net/ipv4}{tcp\_rmem}) viene usato per assicurare + che anche in situazioni di pressione sulla memoria (vedi + \sysctlrelfile{net/ipv4}{tcp\_mem}) le allocazioni al di sotto di + questo limite abbiamo comunque successo. Di nuovo questo valore non viene + ad incidere sulla dimensione del buffer di trasmissione di un singolo + socket dichiarata con l'opzione \const{SO\_SNDBUF}. + + \item il secondo valore, denominato \textit{default}, indica la dimensione + di default in byte del buffer di spedizione di un socket TCP. Questo + valore sovrascrive il default iniziale impostato per tutti i tipi di + socket sul file \sysctlfile{net/core/wmem\_default}. Il default è 87380 + byte, ridotto a 43689 per sistemi con poca memoria. Si può aumentare + questo valore quando si desiderano dimensioni più ampie del buffer di + trasmissione per i socket TCP, ma come per il precedente + \sysctlrelfile{net/ipv4}{tcp\_rmem}) se si vuole che in corrispondenza + aumentino anche le dimensioni usate per la finestra TCP si deve abilitare + il \textit{TCP window scaling} con + \sysctlrelfile{net/ipv4}{tcp\_window\_scaling}. + + \item il terzo valore, denominato \textit{max}, indica la dimensione massima + in byte del buffer di spedizione di un socket TCP; il default è 128Kb, che + viene ridotto automaticamente a 64Kb per sistemi con poca memoria. Il + valore non può comunque eccedere il limite generale per tutti i socket + posto con \sysctlfile{net/core/wmem\_max}. Questo valore non viene + ad incidere sulla dimensione del buffer di trasmissione di un singolo + socket dichiarata con l'opzione \const{SO\_SNDBUF}. + \end{itemize} + +\end{basedescript} + + + +% LocalWords: socket sez dotted decimal resolver Domain Name Service cap DNS +% LocalWords: client fig LDAP Lightweight Access Protocol NIS Information Sun +% LocalWords: like netgroup Switch Solaris glibc libc uclib NSS tab shadow uid +% LocalWords: username group aliases ethers MAC address hosts networks rpc RPC +% LocalWords: protocols services dns db lib libnss org truelite it root res HS +% LocalWords: resource init netinet resolv int void conf host LOCALDOMAIN TCP +% LocalWords: options DEBUG debug AAONLY USEVC UDP PRIMARY IGNTC RECURSE INET +% LocalWords: DEFNAMES search STAYOPEN DNSRCH INSECURE NOALIASES HOSTALIASES +% LocalWords: IPv gethostbyname NOCHECKNAME KEEPTSIG TSIG BLAST RETRY retry NS +% LocalWords: retrans query FQDN Fully Qualified const char dname class type +% LocalWords: unsigned answer anslen CSNET Hesiod MIT CHAOS Chaosnet ANY BIND +% LocalWords: nameser compat Berkley MF CNAME SOA MB MR NULL WKS PTR HINFO TXT +% LocalWords: MINFO RP responsible person AFSDB AFS RT router NSAP SIG KEY PX +% LocalWords: GPOS AAAA LOC NXT EID NIMLOC nimrod SRV ATMA ATM NAPTR naming AF +% LocalWords: authority IXFR AXFR MAILB MAILA errno NOT FOUND RECOVERY TRY err +% LocalWords: AGAIN herror netdb string perror error hstrerror strerror struct +% LocalWords: hostent name addrtype length addr list sys af mygethost inet ret +% LocalWords: ntop deep copy buf size buflen result errnop value argument len +% LocalWords: ERANGE sethostent stayopen endhostent gethostbyaddr order pton +% LocalWords: getipnodebyname getipnodebyaddr flags num MAPPED ALL ADDRCONFIG +% LocalWords: freehostent ip getXXXbyname getXXXbyaddr servent getservbyname +% LocalWords: netent getnetbyname getnetbyaddr protoent smtp udp +% LocalWords: getprotobyname getprotobyaddr getservbyport port tcp setservent +% LocalWords: getservent endservent setXXXent getXXXent endXXXent gethostent +% LocalWords: setnetent getnetent endnetent setprotoent getprotoent POSIX RFC +% LocalWords: endprotoent getaddrinfo getnameinfo nell' node service addrinfo +% LocalWords: hints linked addrlen socklen family socktype protocol sockaddr +% LocalWords: canonname next PF UNSPEC SOCK STREAM DGRAM bind INADDR loopback +% LocalWords: connect sendto NUMERICHOST EAI NONAME SYSTEM BADFLAGS ADDRFAMILY +% LocalWords: NODATA MEMORY FAIL errcode echo mygetaddr ptr casting Canonical +% LocalWords: freeaddrinfo getservname salen hostlen serv servlen l'OR NI NUL +% LocalWords: NOFQDN NAMEREQD NUMERICSERV MAXHOST MAXSERV sockconn SockUtil of +% LocalWords: descriptor hint fifth sockbind setsockopt getsockopt sock level +% LocalWords: optname optval optlen EBADF EFAULT EINVAL ENOPROTOOPT ENOTSOCK +% LocalWords: IPPROTO Stevens ICMP ICMPV ICMPv get KEEPALIVE OOBINLINE timeval +% LocalWords: RCVLOWAT SNDLOWAT RCVTIMEO SNDTIMEO BSDCOMPAT BSD PASSCRED ucred +% LocalWords: PEERCRED BINDTODEVICE REUSEADDR ACCEPTCONN DONTROUTE gateway MSG +% LocalWords: BROADCAST broadcast SNDBUF RCVBUF LINGER linger PRIORITY read IF +% LocalWords: OOB recvmsg kernel select write readv recv recvfrom EAGAIN send +% LocalWords: EWOULDBLOCK writev sendmsg raw domain SCM CREDENTIALS eth packet +% LocalWords: IFNAMSIZ capabilities capability ADMIN log trpt EADDRINUSE close +% LocalWords: listen routing sysctl shutdown Quality TOS keep alive ACK RST to +% LocalWords: ECONNRESET ETIMEDOUT keepalive echod fourth newsgroup WAIT reuse +% LocalWords: sockbindopt SockUtils homed completely binding RECVDSTADDR onoff +% LocalWords: PKTINFO getsockname multicast streaming unicast REUSEPORT reset +% LocalWords: stealing ling RECVTOS RECVTTL TTL RECVOPTS RETOPTS HDRINCL MTU +% LocalWords: RECVERR DISCOVER Path Discovery ALERT alert ADD MEMBERSHIP mreqn +% LocalWords: pktinfo ipi ifindex spec dst RECVIF Live IPTOS LOWDELAY Advanced +% LocalWords: Transfer Unit PMTUDISC DONT WANT route dall' pmtu EMSGSIZE imr +% LocalWords: multiaddr mreq fcntl ioctl request SIOCGSTAMP trip SIOCSPGRP pid +% LocalWords: process SIGIO SIGURG KILL FIOASYNC SIOCGPGRP filesystem proc ttl +% LocalWords: rmem wmem message cost burst bucket filter netdev backlog optmem +% LocalWords: forward dynaddr dial autoconfig local masquerading ipfrag high +% LocalWords: thresh low always defrag CONFIG SETSIG cmd FIOGETOWN FIOSETOWN +% LocalWords: quest'ultime neigh dev weight cong mod somaxconn Di SIOCINQ DoS +% LocalWords: Documentation SIOCATMARK SIOCOUTQ FIONREAD TIOCOUTQ Denial work +% LocalWords: netfilter scheduler mark ARP DHCP BOOTP RARP nonlocal sniffer is +% LocalWords: linux NODELAY MAXSEG CORK KEEPIDLE KEEPINTVL KEEPCNT SYNCNT INFO +% LocalWords: DEFER ACCEPT WINDOW CLAMP QUICKACK CONGESTION ENCAP urgent MSS +% LocalWords: Segment SYN accept advertised window info quickack Nagle ifreq +% LocalWords: ifr ppp union EPERM SIOCGIFNAME dell' interface index IFF NOARP +% LocalWords: SIOCGIFINDEX SIOCGIFFLAGS POINTOPOINT RUNNING PROMISC NOTRAILERS +% LocalWords: ALLMULTI bundle PORTSEL ifmap AUTOMEDIA DYNAMIC SIOCSIFFLAGS way +% LocalWords: SIOCGIFMETRIC SIOCSIFMETRIC SIOCGIFMTU SIOCSIFMTU SIOCGIFHWADDR +% LocalWords: SIOCSIFHWADDR SIOCSIFHWBROADCAST SIOCGIFMAP SIOCSIFMAP sendfile +% LocalWords: SIOCADDMULTI SIOCDELMULTI SIOCGIFTXQLEN SIOCSIFTXQLEN three syn +% LocalWords: SIOCSIFNAME SIOCGIFCONF handshake retries MIN FreeBSD closing Mb +% LocalWords: abort overflow adv win app bic convergence dsack ecn fack frto +% LocalWords: intvl probes latency orphans l'ACK SYNQ HSIZE tw buckets mem rfc +% LocalWords: orphan reordering collapse sack stdurg synack syncookies recycle +% LocalWords: timestamps scaling vegas avoid westwood tcpi l'incapsulazione NR +% LocalWords: metric EOPNOTSUPP mtu hwaddr ARPHRD interrupt DMA map qlen silly +% LocalWords: rename ifconf syndrome dell'ACK FTP ACCEPTFILTER advanced reno +% LocalWords: congestion control Networking cubic CUBIC highspeed HSTCP htcp +% LocalWords: HTCP hybla HYBLA scalable SCALABLE ifc req iflist access ntoa Kb +% LocalWords: hop Selective acknowledgement Explicit RTO stack firewall passwd +% LocalWords: Notification wireless denial pressure ATTACH DETACH publickey +% LocalWords: libpcap discovery point l'overhaed min PAGE flood NFS blast +% LocalWords: selective COOKIES NAT Translation + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: -%%% Local Variables: -%%% mode: latex -%%% TeX-master: "gapil" -%%% End: