X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=sockctrl.tex;h=5ef2c7cc0ab160165a4d742fd3661294aba778c6;hp=ea6981590c872f0e6fdbc5bd0586e3af8d3625d5;hb=d450a86ffcd4c7ef3265f950994cba25345881ed;hpb=276ae7fb9a1e43b6d5e5944071848094c8cc2c3b diff --git a/sockctrl.tex b/sockctrl.tex index ea69815..5ef2c7c 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -227,14 +227,16 @@ un altro server ancora. In realtà un server DNS è in grado di fare 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 +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. Oggigiorno i dati mantenuti nei server DNS sono -sostanzialmente relativi soltanto ad indirizzi internet, per cui in pratica -c'è soltanto una classe di indirizzi utilizzata, i dati invece possono essere -di vario tipo, uno dei quali è appunto la corrispondenza fra nome a dominio e -numero IP. +di questi ultimi.\footnote{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, rispetto a quelle relative alla semplice @@ -257,22 +259,24 @@ 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 \texttt{LOCALDOMAIN}). In genere è necessario eseguire questa -funzione direttamente in quanto viene automaticamente chiamata la prima che si -esegue una delle altre. - -Le impostazioni del resolver e lo stato del sistema vengono mantenute in una -serie di variabili contenute in una apposita struttura interna che viene -definita in \file{resolv.h} ed è utilizzata come variabile globale, così che -anche un programma vi può accedure una volta che essa sia stata opportunamente -dichiarata come: \includecodesnip{listati/resolv_option.c} +ambiente \texttt{LOCALDOMAIN}). In genere non è necessario eseguire questa +funzione direttamente in quanto viene automaticamente chiamata la prima volta +che si esegue una delle altre. + +Le impostazioni e lo stato del \textit{resolver} vengono mantenuti in una +serie di variabili raggruppate nei campi di una apposita struttura \var{\_res} +usata da tutte queste funzioni. Essa viene definita in \file{resolv.h} ed è +utilizzata internamente alle funzioni essendo definita come variabile globale; +questo consente anche di accedervi direttamente all'interno di un qualunque +programma, una volta che la sia opportunamente dichiarata come: +\includecodesnip{listati/resolv_option.c} Tutti i campi della struttura sono ad uso interno, e vengono usualmente inizializzati da \func{res\_init} 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}, una maschera binaria che contiene una serie di bit di opzione che permettono di controllare il -comportamento del resolver. +comportamento del \textit{resolver}. \begin{table}[htb] \centering @@ -378,10 +382,10 @@ lunghezza \param{anslen} puntato da \param{answer} che si sar allocato in precedenza. -Una seconda funzione di ricerca, analoga a \func{res\_query}, e che prende gli -stessi argomenti, ma esegue l'interrogazione con le funzionalità addizionali -previste dalle due opzioni \const{RES\_DEFNAMES} e \const{RES\_DNSRCH}, è -\funcd{res\_search}, il cui prototipo è: +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}, il cui prototipo è: \begin{functions} \headdecl{netinet/in.h} \headdecl{arpa/nameser.h} @@ -397,19 +401,19 @@ previste dalle due opzioni \const{RES\_DEFNAMES} e \const{RES\_DNSRCH}, \end{functions} In sostanza la funzione ripete una serie di chiamate a \func{res\_query} -aggiungendo opportunamente il dominio di default da cercare nella stinga -\param{dname}, fermandosi non appena trova un risultato. Il risultato di +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 capitolo 14 di -\cite{DNSbind}. +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 solo quella degli indirizzi internet; le -costanti che identificano dette classi come valore per l'argomento -\param{class} sono riportate 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}.\footnote{esisteva in realtà anche una classe \const{C\_CSNET} per la omonima rete, ma è stata dichiarata obsoleta.} @@ -434,15 +438,22 @@ tab.~\ref{tab:DNS_address_class}.\footnote{esisteva in realt \label{tab:DNS_address_class} \end{table} -Come accennato le tipologie di dati che sono mantenibili su un DNS sono -diverse, ed a ciascuna di essa corriponde ad un diverso tipo di -\textit{resource record}; l'elenco dei valori possibili\footnote{come - ottenibile dai file di dichiarazione \file{arpa/nameser.h} e - \file{arpa/nameser_compat.h}.} che si possono indicare per l'argomento -\param{type} è riportato in tab.~\ref{tab:DNS_record_type}; le costanti (tolto -il \texttt{T\_} iniziale) usano gli stessi valori usati per identificare i -record nei file di zona di BIND, e che normalmente sono anche usati come -\textsl{nomi} per indicare i record. +Come accennato le tipologie di dati che sono mantenibili su un server DNS sono +diverse, ed a ciascuna di essa corriponde un diverso tipo di \textit{resource + record}. L'elenco delle costanti\footnote{ripreso dai file di dichiarazione + \file{arpa/nameser.h} e \file{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 rifererimento; 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 @@ -489,9 +500,9 @@ record nei file di zona di BIND, e che normalmente sono anche usati come \const{T\_NAPTR} & puntatore ad una \textit{naming authority} .\\ \const{T\_TSIG} & firma di transazione.\\ \const{T\_IXFR} & trasferimento di zona incrementale.\\ - \const{T\_AXFR} & trasferimenzo di zona di autorità.\\ + \const{T\_AXFR} & trasferimento di zona di autorità.\\ \const{T\_MAILB} & trasferimento di record di caselle di posta.\\ - \const{T\_MAILA} & trasferimetno di record di server di posta.\\ + \const{T\_MAILA} & trasferimento di record di server di posta.\\ \const{T\_ANY} & valore generico.\\ \hline \end{tabular} @@ -505,45 +516,46 @@ L'elenco di tab.~\ref{tab:DNS_record_type} \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, pertanto non entreremo nei dettagli del -significato di tutti quanti, ma solo di quelli usati dalle funzioni del -\textit{resolver}, che sono sostanzialmente i seguenti: +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}] per indicare 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}] 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 provvedere la mappatura inversa fra un indirizzo IP ed - un nome a dominio si utilizza questo tipo di record (il cui nome sta per - \textit{pointer}). +\item[\texttt{A}] viene usato per indicare 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}] 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 corripondenza 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}, o \texttt{sources.truelite.it}, che fanno sempre riferimento a \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}). + \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, a -differenza delle funzioni viste finora, 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, e può non avere -nessun significato nell'indicare quale parte del procedimento di risoluzione è +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 all'interno del resolver è stata definita una apposita -variabile di errore, \var{h\_errno} che viene utilizzata dalle funzioni del -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: +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 sono riportati in tab.~\ref{tab:h_errno_values}. - +ed i valori che può assumere, con il relativo significato, sono riportati in +tab.~\ref{tab:h_errno_values}. \begin{table}[!htb] \centering @@ -571,11 +583,10 @@ ed i valori che pu \label{tab:h_errno_values} \end{table} - Insieme alla nuova variabile vengono definite anche due nuove funzioni per -stampare l'errore a video, analoghe a quelle di sez.~\ref{sec:sys_strerror}, -ma che usano il valore di \var{h\_errno}; la prima è \funcd{herror} ed il suo -prototipo è: +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 è: \begin{functions} \headdecl{netdb.h} \funcdecl{void herror(const char *string)} @@ -593,15 +604,15 @@ funzione Restituisce una stringa corripondente ad un errore di risoluzione. \end{functions} -\noindent e come per l'analoga \func{strerror} restituise una stringa con un -messaggio di errore già formattato corrispondente al codice passato come +\noindent che, come l'analoga \func{strerror}, restituise una stringa con un +messaggio di errore già formattato, corrispondente al codice passato come argomento (che si presume sia dato da \var{h\_errno}). \subsection{La risoluzione dei nomi a dominio} -\label{sec:sock_gethostbyname} +\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 @@ -614,8 +625,8 @@ una stazione noto il suo nome a dominio, il suo prototipo 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.} + struttura di tipo \struct{hostent} contenente i dati associati al nome a + dominio, o un puntatore nullo in caso di errore.} \end{prototype} La funzione prende come argomento una stringa \param{name} contenente il nome @@ -656,12 +667,39 @@ diretto al primo indirizzo della lista. 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}. 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 indirizzara con +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} normalmente 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 resolver; dato che questo non è molto comodo è stata +definita\footnote{questa è una estensione fornita dalle \acr{glibc}, + disponibile anche in altri sistemi unix-like.} un'altra funzione, +\funcd{gethostbyname2}, il cui prototipo è: +\begin{functions} + \headdecl{netdb.h} + \headdecl{sys/socket.h} + \funcdecl{struct hostent *gethostbyname2(const char *name, int af)} + +Determina l'indirizzo di tipo \param{af} associato al nome a dominio +\param{name}. + +\bodydesc{La funzione restituisce in caso di successo il puntatore ad una + struttura di tipo \struct{hostent} contenente i dati associati al nome a + dominio, o un puntatore nullo in caso di errore.} +\end{functions} + +In questo caso la funzione prende un secondo argomento \param{af} che indica +(i soli valori consentiti sono \const{AF\_INET} o \const{AF\_INET6}, per +questo è necessario l'uso di \texttt{sys/socket.h}) la famiglia di indirizzi +che dovrà essere utilizzata nei risultati restituiti dalla funzione. Per tutto +il resto la funzione è identica a \func{gethostbyname}, ed identici sono i +suoi risultati. \begin{figure}[!htb] \footnotesize \centering @@ -673,36 +711,388 @@ corrispondente struttura \var{in\_addr} da indirizzara con \label{fig:myhost_example} \end{figure} -Vediamo allora un primo esempio dell'uso di queste funzioni, in +Vediamo allora un primo esempio dell'uso delle funzioni di risoluzione, in fig.~\ref{fig:myhost_example} è riportato un estratto del codice di un -programma che esegue una semplice interrogazione al resolver usando -\func{gethostbyname} e stampa a video i risultati. Al solito il sorgente -completo, he comprende il trattamento delle opzioni ed una funzione per -stampare un messaggio di aiuto, è nel file \texttt{myhost.c} dei sorgenti +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, he comprende il trattamento delle opzioni ed una funzione +per stampare un messaggio di aiuto, è nel file \texttt{myhost.c} dei sorgenti allegati alla guida. +Il programma richiede un solo argomento che specifichi il nome da cercare, +senza il quale (\texttt{\small 12--15}) esce con un errore. Dopo di che +(\texttt{\small 16}) si limita a chiamare \func{gethostbyname}, ricendo il +risultato nel puntatore \var{data}. Questo (\texttt{\small 17--20}) 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 21}) +con lo stampare il nome canonico, dopo di che (\texttt{\small 22--26}) si +stampano eventuali altri nomi. Per questo prima (\texttt{\small 22}) si prende +il puntatore alla cima della lista che contiene i nomi e poi (\texttt{\small + 23--26}) si esegue un ciclo che sarà ripetuto fin tanto che nella lista si +troveranno dei puntatori validi\footnote{si ricordi che la lista viene + terminata da un puntatore nullo.} per le stringhe dei nomi; prima +(\texttt{\small 24}) si stamperà la stringa e poi (\texttt{\small 25}) 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 27--34}) è 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 35--40}) si stamperanno i valori degli indirizzi, di +nuovo (\texttt{\small 35}) 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 37}) ad 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 38}) 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: utilizzando una area di +memoria interna per allocare i contenuti della struttura \struct{hostent} non +possono essere rientranti. Questo 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 +\index{\textit{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 sottostrutture con altri + puntatori) e copiare anche i dati da questi referenziati.} + +Per ovviare a questi problemi nelle \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{functions} + \headdecl{netdb.h} + \headdecl{sys/socket.h} + \funcdecl{int gethostbyname\_r(const char *name, struct hostent *ret, + char *buf, size\_t buflen, struct hostent **result, int *h\_errnop)} + \funcdecl{int gethostbyname2\_r(const char *name, int af, + struct hostent *ret, char *buf, size\_t buflen, + struct hostent **result, int *h\_errnop)} + + Versioni rientranti delle funzioni \func{gethostbyname} e + \func{gethostbyname2}. + + \bodydesc{Le funzioni restituiscono 0 in caso di successo ed un valore + negativo in caso di errore.} +\end{functions} + +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 \index{\textit{value~result~argument}}\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 +puntatatore che si userà per accedere i dati con \param{result}. + +In caso di successo entrambe le funzioni restituiscono un valore nullo, +altrimenti restituiscono un codice di errore negativo 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\footnote{si potrebbero impostare direttamente le opzioni di + \var{\_\_res.options}, ma queste funzioni permettono di semplificare la + procedura.} sono previste delle funzioni apposite; la prima è +\funcd{sethostent}, il cui prototipo è: +\begin{prototype}{netdb.h} +{void sethostent(int stayopen)} +Richiede l'uso di connessioni per le interrogazioni ad un server DNS. -Con l'uso di \func{gethostbyname} normalmente 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 chiamare -\func{res\_init} (vedi sez.~\ref{sec:sock_resolver_functions}) per modificare -le opzioni del resolver; dato che questo non è molto comodo è stata definita -un'altra funzione, \funcd{gethostbyname2}, il cui prototipo è: +\bodydesc{La funzione non restituisce nulla.} +\end{prototype} + +La funzione 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 pari a 1 (o diverso da zero), che indica una condizione vera in C, +attiva la funzionalità. Come si attiva l'uso delle connessioni TCP lo si può +disattivare con la funzione \funcd{endhostent}; il suo prototipo è: \begin{prototype}{netdb.h} -{struct hostent *gethostbyname2(const char *name, int af)} +{void endhostent(void)} -Determina l'indirizzo di tipo \param{af} associato al nome a dominio -\param{name}. +Disattiva l'uso di connessioni per le interrogazioni ad un server DNS. -\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.} +\bodydesc{La funzione non restituisce nulla.} \end{prototype} +\noindent e come si può vedere la funzione è estremamente semplice, non +richiedendo nessun argomento. -In questo caso la funzione prende un secondo argomento \param{af} che indica -la famiglia di indirizzi da usare come +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{functions} + \headdecl{netdb.h} + \headdecl{sys/socket.h} + \funcdecl{struct hostent *gethostbyaddr(const char *addr, int len, int type)} + + Richiede la risoluzione inversa di un indirizzo IP. + + \bodydesc{La funzione restituisce l'indirizzo ad una struttura + \struct{hostent} in caso di successo ed \const{NULL} in caso di errore.} +\end{functions} + +In questo caso l'argomento \param{addr} dovrà essere il puntatore ad una +appropriata struttura contentente il valore dell'indirizzo IP (o IPv6) che si +vuole risolvere. L'uso del tipo \type{char *} per questo argomento è storico, +il dato dovrà essere fornito in una struttura \struct{in\_addr}\footnote{si + ricordi che, come illustrato in fig.~\ref{fig:sock_sa_ipv4_struct}, questo + in realtà corrisponde ad un numero intero, da esprimere comunque in + \textit{network order}, non altrettanto avviene però per \var{in6\_addr}, + pertanto è sempre opportuno inizializzare questi indirizzi con + \func{inet\_pton} (vedi sez.~\ref{sec:sock_conv_func_gen}).} per un +indirizzo IPv4 ed una struttura \struct{in6\_addr} per un indirizzo IPv6, +mentre in \param{len} se ne dovrà specificare la dimensione (rispettivamente 4 +o 16), infine l'argomento \param{type} indica 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 funziona comunque inizializza anche il primo campo della lista +\var{h\_addr\_list} col valore dell'indirizzo passato come argomento. + +Per risolvere il problema dell'uso da parte delle due funzioni +\func{gethostbyname} e \func{gethostbyaddr} di memoria statica che può essere +socrascritta 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}), vennero introdotte due nuove funzioni di +risoluzione,\footnote{le funzioni sono presenti nelle \acr{glibc} versione + 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{functions} + \headdecl{netdb.h} + \headdecl{sys/types.h} + \headdecl{sys/socket.h} + + \funcdecl{struct hostent *getipnodebyname(const char *name, int af, int + flags, int *error\_num)} + + \funcdecl{struct hostent *getipnodebyaddr(const void *addr, size\_t len, + int af, int *error\_num)} + + Richiedono rispettivamente la risoluzione e la risoluzione inversa di un + indirizzo IP. + + \bodydesc{Entrambe le funzioni restituiscono l'indirizzo ad una struttura + \struct{hostent} in caso di successo ed \const{NULL} in caso di errore.} +\end{functions} + +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 +(identico 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{10cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \const{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.\\ + \const{AI\_ALL} & usato con \const{AI\_V4MAPPED}; richiede sia + indirizzi IPv4 che IPv6, e gli indirizzi IPv4 + saranno rimappati in IPv6.\\ + \const{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.\\ + \const{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} +allocata dinamicamente che contiene i risultati della ricerca, e per questo +non soffrono dei problemi dovuti all'uso di una sezione statica di memoria +presenti con le precedenti \func{gethostbyname} e \func{gethostbyaddr}. +Questo però comporta la necessità di deallocare esplicitamente la memoria +occupata dai risultati una volta che questi non siano più necessari, onde +evitare perdite di memoria; a tale scopo viene fornita la funzione +\funcd{freehostent}, il cui prototipo è: +\begin{functions} + \headdecl{netdb.h} + \headdecl{sys/types.h} + \headdecl{sys/socket.h} + + \funcdecl{void freehostent(struct hostent *ip)} + + Disalloca una struttura \var{hostent}. + + \bodydesc{La funzione non ritorna nulla.} +\end{functions} + +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. + +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{getXXXbyname} e \texttt{getXXXbyaddr} 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 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&\file{/etc/hosts}&\struct{hostent}&\func{gethostbyname}& + \func{gethostbyaddr}\\ + servizio &\file{/etc/services}&\struct{servent}&\func{getservbyname}& + \func{getservbyaddr}\\ + rete &\file{/etc/networks}&\struct{netent}&\func{getnetbyname}& + \func{getnetbyaddr}\\ + protocollo&\file{/etc/protocols}&\struct{protoent}&\func{getprotobyname}& + \func{getprotobyaddr}\\ + \hline + \end{tabular} + \caption{Funzioni di risoluzione dei nomi per i vari servizi del + \textit{Name Service Switch}.} + \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 NSS a parte, +si fa sempre riferimento ai dati mantenuti nei rispettivi file. + +Consideriamo allora una ricerca sui nomi dei servizi, le due funzioni in +questione sono \funcd{getservbyname} e \funcd{getservbyaddr} i cui prototopi +sono: +\begin{functions} + \headdecl{netdb.h} + \funcdecl{struct servent *getservbyname(const char *name, const char *proto)} + \funcdecl{struct servent *getservbyport(int port, const char *proto)} + + Disalloca una struttura \var{hostent}. + + \bodydesc{La funzione non ritorna nulla.} +\end{functions} + + + +Oltre alle precedenti funzioni di ricerca sono definite anche delle ulteriori +funzioni generiche che permettono di accedere direttamente al contenuto dei +file contenenti le informazioni; come le precedenti esse sono tutte nella +forma \texttt{setXXXent}, \texttt{getXXXent} ed \texttt{endXXXent}, e sono +analoghe a quelle viste in sez.~\ref{sec:sys_user_group} per la lettura delle +informazioni relative ai dati degli utenti e dei gruppi (vedi +tab.~\ref{tab:sys_passwd_func}) che pure sono mantenute tremite il +\textit{Name Service Switch}. + + + + + + +\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 +questi inconvenienti, non c'è comunque una interfaccia sufficientemente +generica + + +Per questo motivo lo standard Posix 1003.1-2001 indicava come deprecate le +varie \func{gethostbyaddr}, \func{gethostbyname}, \var{getipnodebyname} e +\var{getipnodebyaddr} per introdurre una interfaccia + + + +rimane comunque il problema generico che si deve sapere +in anticipo quale tipo di indirizzi devo