X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=sockctrl.tex;h=8f6e63426e0d2b8315e55254a127d735e033e96b;hp=62989d4a2deaa2922461f33ff4c9e966f0a82500;hb=4c6bdffb5a1a4746b241d8323faaf3a49a4633a9;hpb=9f5fac5abf66c3a2fe782ecc17d63b62af2485ef diff --git a/sockctrl.tex b/sockctrl.tex index 62989d4..8f6e634 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -24,11 +24,11 @@ comportamento. Negli esempi dei capitoli precedenti abbiamo sempre identificato le singole 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}} @@ -64,17 +64,17 @@ con le librerie del C, detto appunto \textit{resolver}. 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 +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 manenimento dei più vari tipi di informazioni su una + questo permette il mantenimento dei più vari tipi di informazioni su una infrastruttura di questo tipo.} La configurazione del \textit{resolver} attiene più alla amministrazione di @@ -86,12 +86,13 @@ dominio, e prevedeva solo l'utilizzo del DNS e del file statico \file{/etc/hosts}. Per questo aspetto il file di configurazione principale del sistema è -\file{/etc/resolv.conf} che contiene in sostanza l'elenco dei server DNS da -contattare; a questo si affianca il file \file{/etc/host.conf} il cui scopo -principale è indicare l'ordine in cui eseguire la risoluzione dei nomi (se -usare prima i valori di \file{/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. +\file{/etc/resolv.conf} che contiene in sostanza l'elenco degli indirizzi IP +dei server DNS da contattare; a questo si affianca il file +\file{/etc/host.conf} il cui scopo principale è indicare l'ordine in cui +eseguire la risoluzione dei nomi (se usare prima i valori di \file{/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 \file{/etc/hosts}, inoltre oltre @@ -105,19 +106,19 @@ NIS,\footnote{il \textit{Network Information Service} 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 \file{/etc/protocols} e \file{/etc/services}. Molte di queste -informazioni non si trovano su un DNS, e poi in un ambiente distribuito può -essere molto utile centralizzare il mentenimento 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 \file{/etc/hosts}, che con il DNS, che con NIS) comporta il problema +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 +\file{/etc/hosts}, che con il DNS, che con NIS) comporta il problema dell'ordine in cui questi vengono interrogati.\footnote{con le implementazioni classiche i vari supporti erano introdotti modificando direttamente le - funzioni di liberia, prevedendo un ordine di interrogazione predefinito e + funzioni di libreria, prevedendo un ordine di interrogazione predefinito e non modificabile (a meno di una ricompilazione delle librerie stesse).} Per risolvere questa serie di problemi la risoluzione dei nomi a dominio -eseguira dal \textit{resolver} è stata inclusa all'interno di un meccanismo -generico per la risoluzione di corripondenze fra nomi ed informazioni ad essi +eseguirà 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}\footnote{il sistema è stato introdotto la prima volta nelle librerie standard di Solaris, le \acr{glibc} hanno ripreso lo stesso schema, si tenga presente che questo sistema non @@ -201,43 +202,50 @@ da esse utilizzato e cio benché 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. Per questo motivo esistono una serie di funzioni di -libreria che servono specificamente ad esseguire delle interrogazioni verso un +libreria che servono specificamente ad eseguire delle interrogazioni verso un server DNS, funzioni che poi vengono utilizzate per realizzare le funzioni generiche di libreria usate anche dal sistema del \textit{resolver}. Il sistema del DNS è in sostanza di un database distribuito organizzato in -maniera gerarchica, la manutenzione dei dati è mantenuta in tanti server -distinti ciascuno dei quali si occupa della risoluzione del proprio -\textsl{dominio}; i nomi a dominio sono poi organizzati in una struttura ad -albero analoga a quella dell'albero dei file in un sistema unix-like, 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. 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 sottodominio di terzo livello ad un altro server ancora. - -In realtà un server DNS contiene comunque una serie di altre informazioni; -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. 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. - -L'esistenza di vari tipi di informazioni ottenibili da un server DNS è -un'altro dei motivi per cui il \textit{resolver} prevede un insieme di -funzioni dedicato rispetto a quelle della semplice risoluzione dei nomi; la -prima di queste è \funcd{res\_init}, il cui prototipo è: +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 sottodominio di terzo livello ad +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 +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.\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 +risoluzione dei nomi, un insieme di funzioni specifiche dedicate +all'interrogazione di un server DNS; la prima di queste funzioni è +\funcd{res\_init}, il cui prototipo è: \begin{functions} -\headdecl{netinet/in.h} -\headdecl{arpa/nameser.h} -\headdecl{resolv.h} -\funcdecl{int res\_init(void)} + \headdecl{netinet/in.h} \headdecl{arpa/nameser.h} \headdecl{resolv.h} + \funcdecl{int res\_init(void)} Inizializza il sistema del \textit{resolver}. @@ -245,29 +253,30 @@ Inizializza il sistema del \textit{resolver}. errore.} \end{functions} -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. In genere si deve eseguire questa funzione prima di -chiamare tutte le altre. - -Le impostazioni del resolver e lo stato del sistema vengono mantenute in una -serie di variabili globali contenuti in una apposita struttura interna, -definita in \file{resolv.h}, che può essere acceduta una volta che la si -dichiara con: +La funzione legge il contenuto dei file di configurazione (i già citati +\file{resolv.conf} e \file{host.conf}) 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 \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, l'unico che può essere -utile modificare è il campo \var{\_res.options}, che è una maschera binaria -che permette di controllare il comportamento del resolver, modificandone -alcune impostazioni direttamente da programma prima di invocare -\func{res\_init}. Le costanti che definiscono i vari bit di questo campo, con -il relativo significato sono illustrate in tab.~\ref{tab:resolver_option}, un -valore deve essere espresso con un opportuno OR aritmetico di dette costanti; -ad esempio il valore di default dato dalla costante \const{RES\_DEFAULT} è -definito come: -\includecodesnip{listati/resolv_option_def.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 \textit{resolver}. \begin{table}[htb] \centering @@ -293,7 +302,7 @@ definito come: del dominio di default ai nomi singoli (che non contengono cioè un ``\texttt{.}'').\\ \const{RES\_STAYOPEN} & usato con \const{RES\_USEVC} per mantenere - aperte le connesioni TCP fra interrogazioni + aperte le connessioni TCP fra interrogazioni diverse. \\ \const{RES\_DNSRCH} & se attivo \func{res\_search} esegue le ricerche di nomi di macchine nel dominio corrente o nei @@ -318,10 +327,37 @@ definito come: \label{tab:resolver_option} \end{table} -La funzione di richiesta principale è \funcd{res\_query}, che serve ad -eseguire una richiesta ad un server DNS per un nome a dominio completamente -specificato (quello che si chiama FQDN, \textit{Fully Qualified Domain Name}); -il suo prototipo è: +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}, 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 \texttt{LOCALDOMAIN}. In particolare con +\texttt{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 \texttt{RES\_TIMEOUT} si +soprassiede il valore del campo \var{retrans},\footnote{preimpostato al valore + della omonima costante \const{RES\_TIMEOUT} di \file{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}, che serve ad +eseguire una richiesta ad un server DNS per un nome a dominio +\textsl{completamente specificato} (quello che si chiama FQDN, \textit{Fully + Qualified Domain Name}); il suo prototipo è: \begin{functions} \headdecl{netinet/in.h} @@ -332,106 +368,286 @@ il suo prototipo Esegue una interrogazione al DNS. -\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore.} +\bodydesc{La funzione restituisce un valore positivo pari alla lunghezza dei + dati scritti nel buffer \param{answer} in caso di successo e -1 in caso di + errore.} \end{functions} +La funzione esegue 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}, il cui prototipo è: +\begin{functions} +\headdecl{netinet/in.h} +\headdecl{arpa/nameser.h} +\headdecl{resolv.h} +\funcdecl{int res\_search(const char *dname, int class, int type, + unsigned char *answer, int anslen)} + + Esegue una interrogazione al DNS. + + \bodydesc{La funzione restituisce un valore positivo pari alla lunghezza dei + dati scritti nel buffer \param{answer} in caso di successo e -1 in caso di + errore.} +\end{functions} + +In sostanza la funzione ripete una serie di chiamate a \func{res\_query} +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}.\footnote{esisteva in realtà anche una classe + \const{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 + \const{C\_IN} & indirizzi internet, in pratica i soli utilizzati oggi.\\ + \const{C\_HS} & indirizzi \textit{Hesiod}, utilizzati solo al MIT, oggi + completamente estinti. \\ + \const{C\_CHAOS}& indizzi per la rete \textit{Chaosnet}, un'altra rete + sperimentale nata al MIT. \\ + \const{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\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 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 + \const{T\_A} & indirizzo di una stazione.\\ + \const{T\_NS} & server DNS autoritativo per il dominio richiesto.\\ + \const{T\_MD} & destinazione per la posta elettronica.\\ + \const{T\_MF} & redistributore per la posta elettronica.\\ + \const{T\_CNAME} & nome canonico.\\ + \const{T\_SOA} & inizio di una zona di autorità.\\ + \const{T\_MB} & nome a dominio di una casella di posta.\\ + \const{T\_MG} & nome di un membro di un gruppo di posta.\\ + \const{T\_MR} & nome di un cambiamento di nome per la posta.\\ + \const{T\_NULL} & record nullo.\\ + \const{T\_WKS} & servizio noto.\\ + \const{T\_PTR} & risoluzione inversa di un indirizzo numerico.\\ + \const{T\_HINFO} & informazione sulla stazione.\\ + \const{T\_MINFO} & informazione sulla casella di posta.\\ + \const{T\_MX} & server cui instradare la posta per il dominio.\\ + \const{T\_TXT} & stringhe di testo (libere).\\ + \const{T\_RP} & nome di un responsabile (\textit{responsible person}).\\ + \const{T\_AFSDB} & database per una cella AFS.\\ + \const{T\_X25} & indirizzo di chiamata per X.25.\\ + \const{T\_ISDN} & indirizzo di chiamata per ISDN.\\ + \const{T\_RT} & router.\\ + \const{T\_NSAP} & indirizzo NSAP.\\ + \const{T\_NSAP\_PTR}& risoluzione inversa per NSAP (deprecato).\\ + \const{T\_SIG} & firma digitale di sicurezza.\\ + \const{T\_KEY} & chiave per firma.\\ + \const{T\_PX} & corrispondenza per la posta X.400.\\ + \const{T\_GPOS} & posizione geografica.\\ + \const{T\_AAAA} & indirizzo IPv6.\\ + \const{T\_LOC} & informazione di collocazione.\\ + \const{T\_NXT} & dominio successivo.\\ + \const{T\_EID} & identificatore di punto conclusivo.\\ + \const{T\_NIMLOC}& posizionatore \textit{nimrod}.\\ + \const{T\_SRV} & servizio.\\ + \const{T\_ATMA} & indirizzo ATM.\\ + \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} & trasferimento di zona di autorità.\\ + \const{T\_MAILB} & trasferimento di record di caselle di posta.\\ + \const{T\_MAILA} & trasferimento di record di server di posta.\\ + \const{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} -Per quanto ci interessa i tipi di \textit{resource record} che vengono -utilizzati dal \textit{resolver} sono sostanzialmente i seguenti: + +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}] 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}). +\item[\texttt{A}] viene usato per indicare la corrispondenza 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 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}, 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 (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{10cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \const{HOST\_NOT\_FOUND} & l'indirizzo richiesto non è valido e la + macchina indicata è sconosciuta. \\ + \const{NO\_ADDRESS} & il nome a dominio richiesto è valido, ma non ha + un indirizzo associato ad esso + (alternativamente può essere indicato come + \const{NO\_DATA}). \\ + \const{NO\_RECOVERY} & si è avuto un errore non recuperabile + nell'interrogazione di un server DNS. \\ + \const{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 due 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 è: +\begin{functions} +\headdecl{netdb.h} +\funcdecl{void herror(const char *string)} +Stampa un errore di risoluzione. +\end{functions} +La funzione è l'analoga di \func{perror} e stampa sullo 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 è: +\begin{functions} +\headdecl{netdb.h} +\funcdecl{const char *hstrerror(int err)} +Restituisce una stringa corrispondente ad un errore di risoluzione. +\end{functions} +\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}). -Per questo motivo il \textit{resolver} prevede delle funzioni che permettono -sia di eseguire direttamente delle interrogazione ad un server DNS, che di -controllare le modalità con cui queste vengono eseguite; diventa così -possibile modificare da programma buona parte dei parametri controllati da -\file{/etc/resolv.conf}. \subsection{La risoluzione dei nomi a dominio} -\label{sec:sock_gethostbyname} +\label{sec:sock_name_services} -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 è: +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 +di richiesta generica ed esamineremo invece 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.} + 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 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 può 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} \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 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 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 (alternativamente può essere indicato come - \const{NO\_DATA}). -\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 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 +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 @@ -442,8 +658,7 @@ 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. La funzione ritorna sempre una -struttura +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, @@ -453,14 +668,831 @@ 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 + \begin{minipage}[c]{15cm} + \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 12--15}) esce con un errore. Dopo di che +(\texttt{\small 16}) si limita a chiamare \func{gethostbyname}, ricevendo 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 +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 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. + +\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} +{void endhostent(void)} + +Disattiva l'uso di connessioni per le interrogazioni ad un server DNS. +\bodydesc{La funzione non restituisce nulla.} +\end{prototype} +\noindent e come si può vedere 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{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 contenente 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 +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}), 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 +(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{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} +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 deallocare 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{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 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&\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. + +Dopo la risoluzione dei nomi a dominio una delle ricerche più comuni è quella +sui nomi dei servizi noti (cioè \texttt{http}, \texttt{smtp}, ecc.) da +associare alle rispettive porte, le due funzioni da utilizzare per questo sono +\funcd{getservbyname} e \funcd{getservbyaddr}, che permettono rispettivamente +di ottenere il numero di porta associato ad un servizio dato il nome e +viceversa; i loro prototipi 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)} + + Risolvono il nome di un servizio nel rispettivo numero di porta e viceversa. + + \bodydesc{Ritornano il puntatore ad una struttura \struct{servent} con i + risultati in caso di successo, o \const{NULL} in caso di errore.} +\end{functions} + +Entrambe le funzioni prendono come ultimo argomento una stringa \param{proto} +che indica il protocollo per il quale si intende effettuare la +ricerca,\footnote{le informazioni mantenute in \file{/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 si +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 \file{/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 \file{/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]{15cm} + \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 hanno una struttura del tutto analoga alle precedenti, e 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{functions} + \headdecl{netdb.h} + \funcdecl{void setservent(int stayopen)} + Apre il file \file{/etc/services} e si posiziona al suo inizio. + + \funcdecl{struct servent *getservent(void)} + Legge la voce successiva nel file \file{/etc/services}. + + \funcdecl{void endservent(void)} + Chiude il file \file{/etc/services}. + + \bodydesc{Le due funzioni \func{setservent} e \func{endservent} non + restituiscono nulla, \func{getservent} restituisce il puntatore ad una + struttura \struct{servent} in caso di successo e \const{NULL} in caso di + errore o fine del file.} +\end{functions} + +La prima funzione, \func{getservent}, legge una singola voce a partire dalla +posizione corrente in \file{/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 +\file{/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. L'argomento +\param{stayopen}, se diverso da zero, fa sì che il file resti aperto anche fra +diverse chiamate a \func{getservbyname} e \func{getservbyaddr}.\footnote{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, \funcd{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. + +\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 &cd te\func{setservent}&\func{getservent}&\func{endservent}\\ + rete &\func{setnetent}&\func{getnetent}&\func{endnetent}\\ + protocollo&\func{setprotoent}&\func{getprotoent}&\func{endprotoent}\\ + \hline + \end{tabular} + \caption{Funzioni lettura sequenziale dei dati del \textit{Name Service + Switch}.} + \label{tab:name_sequential_read} +\end{table} + + + + + +\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,\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.} comunque esse non +forniscono una interfaccia sufficientemente generica. + +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 +un servizio; il suo prototipo è: +\begin{functions} + \headdecl{netdb.h} + \headdecl{sys/socket.h} + \headdecl{netdb.h} + + \funcdecl{int getaddrinfo(const char *node, const char *service, const + struct addrinfo *hints, struct addrinfo **res)} + + Esegue una risoluzione di un nome a dominio e di un nome di servizio. + + \bodydesc{La funzione restituisce 0 in caso di successo o un codice di + errore diverso da zero in caso di fallimento.} +\end{functions} + +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 \const{NULL}, nel qual caso la risoluzione verrà effettuata utilizzando +soltantoo 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; la funzione 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. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \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} + +La struttura \struct{addrinfo}, la cui definizione\footnote{la definizione è + ripresa direttamente dal file \texttt{netdb.h} in 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.} è 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. 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; 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} è il puntatore alla stringa contenente il nome +canonico della macchina, ed infine, quando la funzione restituisce più di un +risultato, \var{ai\_next} è il puntatore alla struttura \struct{addrinfo} +successiva della lista. + +Ovviamente non è necessario dare dei suggerimenti in ingresso, ed usando +\const{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{PF\_INET} e \const{PF\_INET6}, mentre +se non si vuole specificare questo nessuna famiglia di indirizzi si può usare +il valore \const{PF\_UNSPEC}. Allo stesso modo per \var{ai\_socktype} si +possono usare i valori illustrati 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 +\file{/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. + +Infine l'ultimo 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. + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{10cm}|} + \hline + \textbf{Costante} & \textbf{Significato} \\ + \hline + \hline + \const{AI\_PASSIVE} & viene utilizzato per ottenere un indirizzo in + formato adatto per una successiva chiamata a + \func{bind}. Se specificato quando si è usato + \const{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 verrano restituiti in formato adatto ad + una chiamata a \func{connect} o \func{sendto}.\\ + \const{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}. \\ + \const{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.\\ + \const{AI\_V4MAPPED} & 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}.\\ + \const{AI\_ADDRCONFIG} & stesso significato dell'analoga di + tab.~\ref{tab:sock_getipnodebyname_flags}.\\ + \hline + \end{tabular} + \caption{Costanti associate ai bit del campo \var{ai\_flags} della struttura + \struct{addrinfo}.} + \label{tab:ai_flags_values} +\end{table} + +Come ultimo argomento di \func{getaddrinfo} deve essere passato un puntatore +ad una variabile (di tipo puntatore ad una struttura \struct{addrinfo}) che +verrà utilizzata dalla funzione per restituire (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 restituisce in \param{res} il +puntatore alla prima di una \textit{linked list} di strutture di tipo +\struct{addrinfo} contenenti tutte le informazioni ottenute. + +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 + \const{EAI\_FAMILY} & la famiglia di indirizzi richiesta non è + supportata. \\ + \const{EAI\_SOCKTYPE}& il tipo di socket richiesto non è supportato. \\ + \const{EAI\_BADFLAGS}& il campo \var{ai\_flags} contiene dei valori non + validi. \\ + \const{EAI\_NONAME} & il nome a dominio o il servizio non sono noti, + viene usato questo errore anche quando si specifica + il valore \const{NULL} per entrambi gli argomenti + \param{node} e \param{service}. \\ + \const{EAI\_SERVICE} & il servizio richiesto non è disponibile per il tipo + di socket richiesto, anche se può esistere per + altri tipi di socket. \\ + \const{EAI\_ADDRFAMILY}& la rete richiesta non ha nessun indirizzo di rete + per la famiglia di indirizzi specificata. \\ + \const{EAI\_NODATA} & la . \\ + \const{EAI\_MEMORY} & è stato impossibile allocare la memoria necessaria + alle operazioni. \\ + \const{EAI\_FAIL} & il DNS ha restituito un errore di risoluzione + permanente. \\ + \const{EAI\_AGAIN} & il DNS ha restituito un errore di risoluzione + temporaneo, si può ritentare in seguito. \\ + \const{EAI\_SYSTEM} & c'è stato un errore di sistema, si può controllare + \var{errno} per i dettagli. \\ +% \hline +% estensioni GNU, trovarne la documentazione +% \const{EAI\_INPROGRESS}& richiesta in corso. \\ +% \const{EAI\_CANCELED}& la richiesta è stata cancellata.\\ +% \const{EAI\_NOTCANCELED}& la richiesta non è stata cancellata. \\ +% \const{EAI\_ALLDONE} & tutte le richieste sono complete. \\ +% \const{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, analoga di \func{strerror}, che consente di +utilizzarli direttamente per stampare a video un messaggio esplicativo; la +funzione è \func{gai\_strerror} ed il suo prototipo è: +\begin{functions} + \headdecl{netdb.h} + + \funcdecl{const char *gai\_strerror(int errcode)} + + Fornisce il messaggio corrispondente ad un errore di \func{getaddrinfo}. + + \bodydesc{La funzione restituisce il puntatore alla stringa contenente il + messaggio di errore.} +\end{functions} + +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, questo non comporta nessun problema +di rientranza della funzione. + +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} si avrà come risposta 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 resolver, basato questa funzione, il cui +corpo principale è riportato in fig.. Il codice +del programma è nel file \texttt{mygetaddr.c}, dei sorgenti allegati alla +guida. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/mygetaddr.c} + \end{minipage} + \normalsize + \caption{Esempio di codice per la risoluzione di un indirizzo.} + \label{fig:mygethost_example} +\end{figure} + + + +Una volta estratti i risultati dalla \textit{linked list} puntata da +\param{res} si dovrà avere cura di disallocare opportunamente tutta la +memoria, per questo viene fornita l'apposita funzione \funcd{freeaddrinfo}, il +cui prototipo è: +\begin{functions} + \headdecl{netdb.h} + + \funcdecl{void freeaddrinfo(struct addrinfo *res)} + + Libera la memoria allocata da una precedente chiamata a \func{getaddrinfo}. + + \bodydesc{La funzione non restituisce nessun codice di errore.} +\end{functions} +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}.