9
I semestre 03/04 Università degli studi di Salerno Laurea in Informatica Prof. Vincenzo Auletta [email protected] http://www.dia.unisa.it/professori/auletta/ Conversioni di Nomi ed Indirizzi 1 1 Interazione con il DNS Il DNS consente di convertire dinamicamente nomi di dominio in indirizzi IP e viceversa L’interazione con il name server avviene tramite l’API resolver l’applicazione interagisce con il name server utilizzando le funzioni dell’API il funzionamento delle funzioni è modificabile tramite file di configurazione /etc/resolv.conf /etc/hosts, /etc/services, ecc. Il resolver è utilizzato in generale per calcolare corrispondenze tra nomi ed indirizzi nomi di servizio e numeri di porta 2 2 Funzioni del resolver #include <netdb.h> struct hostent* gethostbyname(const char* hostname); struct hostent* gethostbyaddr(const char* addr, size_t len, int family); Restituisce NULL se errore puntatore diverso da NULL se OK Permettono di interrogare il resolver per effettuare conversioni da nomi ad indirizzi gethostbyname: nome indirizzo gethostbyaddr: indirizzo nome 3 3 Struttura hostent Le funzioni gethostbyname e gethostbyaddr restituiscono puntatori ad oggetti hostent allocati staticamente struct hostent { char* h_name; /* nome canonico */ char** h_aliases; /* elenco di alias */ int h_addrtype; /* tipo di indirizzo */ int h_length; /* lunghezza dell’indirizzo */ char** h_addr_list; /* elenco indirizzi */ }; #define h_addr h_addr_list[0] h_aliases e h_addr_list sono array di stringhe terminati da una stringa nulla

Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

I semestre 03/04

Università degli studi di SalernoLaurea in Informatica

Prof. Vincenzo [email protected]

http://www.dia.unisa.it/professori/auletta/

Conversioni di Nomi ed Indirizzi

11

Interazione con il DNSIl DNS consente di convertire dinamicamente nomi di dominio in indirizzi IP e viceversaL’interazione con il name server avviene tramite l’API resolver

l’applicazione interagisce con il name server utilizzando le funzioni dell’APIil funzionamento delle funzioni è modificabile tramite file di configurazione

/etc/resolv.conf/etc/hosts, /etc/services, ecc.

Il resolver è utilizzato in generale per calcolare corrispondenze tra nomi ed indirizzi

nomi di servizio e numeri di porta

22

Funzioni del resolver#include <netdb.h>struct hostent* gethostbyname(const char* hostname);

struct hostent* gethostbyaddr(const char* addr, size_t len, int family);

RestituisceNULL se errorepuntatore diverso da NULL se OK

Permettono di interrogare il resolver per effettuare conversioni da nomi ad indirizzi

gethostbyname: nome indirizzogethostbyaddr: indirizzo nome

33

Struttura hostentLe funzioni gethostbyname e gethostbyaddrrestituiscono puntatori ad oggetti hostent allocati staticamente

struct hostent {char* h_name; /* nome canonico */char** h_aliases; /* elenco di alias */int h_addrtype; /* tipo di indirizzo */int h_length; /* lunghezza dell’indirizzo */char** h_addr_list; /* elenco indirizzi */

};#define h_addr h_addr_list[0]

h_aliases e h_addr_list sono array di stringhe terminati da una stringa nulla

Page 2: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

44

Esempiooggetto restituito da gethostbyname per il nome koala

un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi IP 4 (140.252.1.11, 140.252.3.54, 140.252.4.54)

h_nameh_aliasesh_addrtypeh_lengthh_addr_list

bsdi

koalapandaNULL

AF_INET4

140.252.1.11140.252.3.54140.252.4.54NULL 55

Funzionamento del ResolverIl resolver può operare sia localmente che interagendo con il DNS

il file /etc/resolv.conf contiene gli indirizzi dei name server da contattare e le regole di espansioneil file /etc/hosts contiene un elenco delle corrispondenze nome/indirizzo

il file di configurazione (/etc/resolv.conf) stabilisce le regole di funzionamento del resolver

per default contatta prima i name server e poi legge il file locale

66

ErroriIn caso di errore le funzioni del resolverscrivono un codice nella variabile h_errno

la funzione hstrerror() legge il valore di h_errno e restituisce un messaggio di errore appropriatoi valori che può assumere h_errno sono definiti in <netdb.h>

HOST_NOT_FOUND Il nome specificato è sconosciutoTRY_AGAIN Un errore temporaneo si è verificato su un name serverNO_RECOVERY Un errore irrimediabile si è verificato su un name serverNO_ADDRESS (NO_DATA) Il nome specificato è valido ma non ha un indirizzo IP

77

Conversioni Servizi/Porte#include <netdb.h>struct servent* getservbyname(const char* servname, const char*protoname);

struct servent* getservbyaddr(int port, const char* protoname);

Permettono di interrogare il resolver per effettuare conversioni nomi di servizi/numeri di porta

getservbyname: nome portagetservbyaddr: porta nome

Il resolver non interagisce con il DNS ma legge soltanto il contenuto di un file locale (/etc/services)

Page 3: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

88

Struttura serventLe funzioni getservbyname e getservbyaddrrestituiscono puntatori ad oggetti servent allocati staticamente

struct servent {char* s_name; /* nome ufficiale del servizio */char** s_aliases; /* elenco di alias */int s_port; /* numero di porta */char* s_proto; /* protocollo da utilizzare */

};

99

Altri Tipi di Interrogazioni#include <netdb.h>struct netent* getnetbyname(const char* netname);

struct netent* getnetbyaddr(long net, int type);

struct protoent* getprotobyname(const char* protoname);

struct protoent* getprotobynumber(int proto);

consentono di assegnare dei nomi a reti e protocolli

funzioni poco utilizzateIl resolver legge i file locali (/etc/networks e/etc/protocols)

1010

Altre Funzioni#include <netdb.h>void sethostent(int flag);

void endhostent(void);

#include <unistd.h>#include <sys/utsname.h>int gethostname(char* name, size_t len); /* name contiene il risultato */

sethostent(true) consente di utilizzare TCP per interrrogare il DNSendhostent() ripristina l’uso di UDPgethostname() restituisce il nome dell’host corrente

stesso risultato ottenuto con uname()1111

Client daytime con resolver – 1 1.legge da

linea di comando il nome del server e del servizio

2.recupera l’elenco di indirizzi IP del server

3.recupera il numero di porta ed il tipo di protocollo

int main(int argc, char **argv) {int sockd, n;char recvline[MAXLINE + 1], str[MAXLINE];struct sockaddr_in servaddr;struct in_addr **elenco_addr;struct hostent *hp;struct servent *sp;

if (argc != 3) (1)err_quit("utilizzo: dtime_client <nome dell'host> <nome del

servizio>");if ( (hp = gethostbyname(argv[1])) == NULL) (2)

err_quit("errore nella gethostbyname per l'host %s: %s",argv[1], hstrerror(h_errno));

if ( (sp = getservbyname(argv[2], "tcp")) == NULL)(3)err_quit("errore nella getservbyname per il servizio %s",

argv[2]);elenco_addr = (struct in_addr **) hp->h_addr_list;

Page 4: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

1212

Client daytime con resolver – 2 4. prova a

connettersi a tutti gli indirizzi forniti dal resolver

5. crea il socket6. riempie

servaddr7. tenta di

connettersi e se ci riesce esce dal ciclo

8. altrimenti chiude il socket

for ( ; *elenco_addr != NULL; elenco_addr++) { (4)if( (sockd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )

err_sys("errore nella socket"); (5)bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET; (6)servaddr.sin_port = sp->s_port;memcpy(&servaddr.sin_addr, *elenco_addr, sizeof(struct

in_addr));if (connect(sockd, (SA *) &servaddr, sizeof(servaddr)) == 0)

(7)break;

err_ret("connessione non riuscita con %s:%d", inet_ntop(hp->h_addrtype, *elenco_addr, str,

sizeof(str)), ntohs(sp->s_port));close(sockd); (8)

}1313

Client daytime con resolver – 3

9. se è uscito dal ciclo senza essere riuscito a stabilire la connessione esce

10.legge la data e la stampa

if (*elenco_addr == NULL) (9)err_quit("impossibile stabiliree una connessione");

while ( (n = read(sockd, recvline, MAXLINE)) > 0) { (10)recvline[n] = 0;if( fputs(recvline, stdout) == EOF )

err_sys("errore in fputs");}exit(0);

}

1414

Server daytime con resolver – 1 int main(int argc, char **argv) {

pid_t pid;int listend, connd;struct sockaddr_in servaddr;char buff[MAXLINE];time_t ticks;struct servent *sp;

if( (listend = socket(AF_INET, SOCK_STREAM, 0)) < 0)err_sys("errore in socket");

if( (sp = getservbyname("daytime", "tcp")) == NULL ) {fprintf(stderr, "errore nella getservbyame perr il servizio %s", argv[2]);exit(-1);

}/* riempie la struttura servaddr */servaddr.sin_port = sp->s_port;if( (bind(listend, (SA *) &servaddr, sizeof(servaddr))) < 0)

err_sys("errore in bind"); 1515

Server daytime con resolver – 2 if( listen(listend, 5) < 0 )

err_sys("errore in listen");for ( ; ; ) {

if( (connd = accept(listend, (struct sockaddr *) NULL, NULL)) < 0)err_sys("errore in accept");

if( (pid = fork()) == 0 ) {/* il figlio chiude il socket di ascolto */ticks = time(NULL);snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));if( write(connd, buff, strlen(buff)) != strlen(buff) )

err_sys("errore in write");/* il figlio chiude il socket di connessione */exit(0);

}/* il padre chiude il socket di connessione */

}}

Page 5: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

1616

Funzioni Indipendenti dal Protocollo

Le funzioni gethostbyname e gethostbyaddrdipendono dal tipo di indirizzi utilizzati e sono obsolete

Per utilizzare l’indirizzo restituito da gethostbynamedobbiamo sapere a che famiglia appartiene per copiarlo nel campo opportuno di struct sockaddr

Lo standard POSIX 1.g ha introdotto due nuove funzioni per interfacciarsi con il resolver

Sono indipendenti dal tipo di indirizziRestituiscono informazioni immediatamente utilizzabili dall’applicazione

L’applicazione non deve sapere nulla di indirizzi, protocolli, ecc. 1717

Funzione getaddrinfo#include <netdb.h>int getaddrinfo(const char* host, const char* serv,

const struct addrinfo *hints, struct addrinfo **result);

RestituisceDiverso da 0 se errore0 se OK

Consente di fare interrogazioni sia per nomi di host che di servizi contemporaneamente

Legge dalla struttura puntata da hints il tipo di informazioni richiesterestituisce il risultato nella lista puntata da result

1818

Struttura addrinfostruct addrinfo {

int ai_flags; /* nome canonico */int ai_family; /* famiglia di indirizzi */int ai_socktype; /* tipo di socket */int ai_protocol; /* tipo di protocollo */size_t ai_addrlength; /* lunghezza di ai_addr */

char* ai_canonname; /* puntatore al nome ufficiale */struct sockaddr *ai_addr; /* puntatore all’indirizzostruct addrinfo *ai_next; /* puntatore al nodo succ */

};

Tutti i puntatori indirizzano memoria allocata dinamicamente

L’applicazione deve preoccuparsi di rilasciare la memoriaLa funzione freeaddrinfo() rilascia tutta la memoria associata ad un oggetto addrinfo

1919

Esempio Richiediamo informazioni sul servizio daytime e l’host koala

Specifichiamo che vogliamo indirizzi IP 4 e trasporto TCP

ai_flagai_familyai_socktypeai_protocolai_addrlen

AF_INET

0

AI_CANONNAME

SOCK_STREAM

ai_canonnameai_addrai_next

0NULLNULLNULL

HINTS

bsdi.xyz.com

ai_flagai_familyai_socktypeai_protocolai_addrlen

AF_INET

0

0

SOCK_STREAM

ai_canonnameai_addrai_next

16

140.252.1.11AF_INET 7

prossimo nodo

RESULTS

Page 6: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

2020

ErroriIn caso di errore la funzione getaddrinfo() restituisce un intero nonnegativo

la funzione gai_strerror() legge il valore restituito dalla funzione e restituisce un messaggio di errore appropriato

EAI_ADDRFAMILY tipo di indirizzo non supportato per nameEAI_AGAIN un errore temporaneo si è verificato su un name serverEAI_FAIL un errore irrecuperabile si è verificato su un name serverEAI_BADFLAGS valore non corretto di ai_flagsEAI_FAMILY valore di ai_family non supportatoEAI_MEMORY errore di allocazione della memoriaEAI_NODATA nessun indirizzo associato a nameEAI_NONAME name o service non conosciutoEAI_SERVICE service non supportato per ai_socktypeEAI_SOCKTYPE ai_socktype non supportatoEAI_SYSTEM errore di sistema restituito in errno 2121

Funzione getnameinfo#include <netdb.h>int getaddrinfo(const struct sockaddr* sockaddr, socklen_t addrlen,

char* host, size_t hostlen,char* serv, size_t servlen, int flags);

Restituisce-1 se errore0 se OK

Consente di trasformare l’indirizzo del socket contenuto in sockaddr in due stringhe

host contiene il nome dell’host e serv contiene il nome del serviziohostlen e servlen sono le lunghezze allocate per le stringheflags consente di modificare il comportamento di default della funzione

2222

Utilizzo di getaddrinfo()E’ possibile costruire delle funzioni che nascondono all’applicazione tutti i dettagli relativi alla gestione del socket

L’applicazione usa solo i nomi dell’host e del servizioLe funzioni utilizzano le informazioni restituite da getaddrinfo() per invocare le funzioni sul socket

Useremo le seguenti funzionitcp_connect() (client TCP)tcp_listen() (server TCP)udp_client() (client UDP non connesso)udp_connect() (client UDP connesso)udp_server() (server UDP)

2323

Schema BaseTutte le funzioni adotteranno il seguente schema

Leggono da linea di comando nome dell’host e del servizio

È possibile anche specificare l’indirizzo IP o il numero di porta

Invocano getaddrinfo()Scorrono la lista di risultati e provano ad utilizzare ognuno degli indirizzi

Appena ne trovano uno funzionante esconoSe nessuno funziona escono con un errore

Page 7: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

2424

Tcp_connect() – 1

1.Riempie i campi di hints2.Invoca getaddrinfo

Risultato restituito nella lista puntata da risp

int tcp_connect(const char *host, const char *serv) {int sockd, n;struct addrinfo hints, *risp, *backup;char buff[MAXLINE];

bzero(&hints, sizeof(struct addrinfo));hints.ai_family = AF_UNSPEC; (1)hints.ai_socktype = SOCK_STREAM;if ( (n = getaddrinfo(host, serv, &hints, &risp)) != 0) (2)

err_quit("errore in tcp_connect per %s:%s: %s", host, serv, gai_strerror(n));backup = risp;

2525

Tcp_connect() – 2

3. Cicla su tutti gli indirizzi di rispProva ad eseguire prima socket() e poi connect() ed esce se ha stabilito la connessione

4. Dealloca la memoria dinamica

do { (3)sockd = socket(risp->ai_family, risp->ai_socktype, risp->ai_protocol);if (sockd < 0)

continue;if (connect(sockd, risp->ai_addr, risp->ai_addrlen) < 0)

/* ignora questo indirizzo e chiude il socket */break;

} while ( (risp = risp->ai_next) != NULL);if (risp == NULL)

err_sys("errore in tcp_connect per %s:%s", host, serv);freeaddrinfo(backup); (4)return(sockd);

}

2626

Tcp_listen() – 1

1.Richiede socket passivo2.Invoca getaddrinfo

Int tcp_listen(const char *host, const char *serv, socklen_t *addrlenp) {int listend, n;const int on = 1;struct addrinfo hints, *risp, *backup;

bzero(&hints, sizeof(struct addrinfo));hints.ai_flags = AI_PASSIVE;hints.ai_family = AF_UNSPEC;hints.ai_socktype = SOCK_STREAM;if ( (n = getaddrinfo(host, serv, &hints, &risp)) != 0)

err_quit("errore in tcp_listen per %s:%s: %s", host, serv, gai_strerror(n));backup = risp;

2727

Tcp_listen() – 2 do {

listend = socket(risp->ai_family, risp->ai_socktype, risp->ai_protocol);if (listend < 0) continue;if( setsockopt(listend, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) (3)

err_sys("errore in setsockopt");if (bind(listend, risp->ai_addr, risp->ai_addrlen) < 0)

/* ignora questo indirizzo e chiude il descrittore. */break;

} while ( (risp = risp->ai_next) != NULL);if (risp == NULL) err_quit("errore in tcp_listen per %s:%s", host, serv);if( listen(listend, LISTENQ) < 0 ) err_sys("errore in listen"); (4)if (addrlenp) *addrlenp = risp->ai_addrlen; (5)freeaddrinfo(backup); (6)return(listend);

}

3. Setta il socket per poter utilizzare una porta occupata4. Se socket() e bind() riescono chiama la listen()5. Restituisce in addrlenp un puntatore alla lunghezza dell’indirizzo

assegnato al socket6. Dealloca la memoria dinamica

Page 8: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

2828

Client daytime con tcp_connect() –1

1. legge da linea di comando il nome del server e del servizio

2.recupera l’elenco di indirizzi IP del server

3.recupera il numero di porta ed il tipo di protocollo

int main(int argc, char **argv) {int sockd, n;char recvline[MAXLINE + 1];socklen_t len;struct sockaddr *sa;

if (argc != 3) (1)err_quit("utilizzo: dtime_name_client <nome dell'host>

<nome del servizio>");sockd = tcp_connect(argv[1], argv[2]);if( (sa = malloc(MAXSOCKADDR) == NULL )

err_sys(“errore in malloc”);len = MAXSOCKADDR;if( getpeername(sockd, sa, &len) < 0 )

err_sys(“errore in getpeername”);printf 2929

Client daytime con tcp_connect –2

9. se è uscito dal ciclo senza essere riuscito a stabilire la connessione esce

10.legge la data e la stampa

while ( (n = read(sockd, recvline, MAXLINE)) > 0) { (10)recvline[n] = 0;if( fputs(recvline, stdout) == EOF )

err_sys("errore in fputs");}exit(0);

}

3030

Server daytime con tcp_listen – 1

int main(int argc, char **argv) {pid_t pid;int listend, connd;struct sockaddr *cliaddr;socklen_taddrlen, len;struct linger ling;char buff[MAXLINE];time_t ticks;

switch(argc) { (1)case 2:

listend = tcp_listen(NULL, argv[1], &addrlen); break;case 3:

listend = tcp_listen(argv[1], argv[2], &addrlen); break;default:

err_quit("utilizzo: dtime_name_server [<host>] <servizio o porta>");}if( (cliaddr = malloc(addrlen)) == NULL ) err_sys("errore in malloc"); (2)

1. legge da linea di comando il nome del server e del servizio

2. Alloca la memoria per contenere l’indirizzo del client

3131

Server daytime con tcp_listen – 2 for ( ; ; ) {

len = addrlen;if( (connd = accept(listend, cliaddr, &len)) < 0) err_sys("errore in accept");ling.l_onoff = 1;ling.l_linger = 0;if( setsockopt(connd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) < 0 )

err_sys("errore in setsockopt");if( (pid = fork()) == 0 ) {

/* il processo figlio chiude il socket di ascolto */ticks = time(NULL);snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));if( write(connd, buff, strlen(buff)) != strlen(buff) )

err_sys("errore in write");/* il processo figlio chiude il socket di connessione */exit(0);

}/* il processo padre chiude il socket di connessione */

}

Page 9: Conversioni di Nomi ed Il DNS consente di convertire ...4 Esempio oggetto restituito da gethostbyname per il nome koala un nome canonico (bsdi), due alias (koala e panda) e tre indirizzi

3232

Client e Server UDPDal sito è possibile scaricare

il codice delle funzioni udp_client(), udp_server() e udp_connect()

logica simile a tcp_connect() e tcp_listen()

Il codice di un client ed un server UDP indipendenti dal protocollo