Interazione con il DNS Conversioni di Nomi ed Indirizzi



Documenti analoghi
Server Iterativi. Server TCP Ricorsivi. Fork. Server Ricorsivi. un server iterativo gestisce una connessione alla volta. Prof.

Socket TCP. seconda parte

Esempio 1: stampa locale di file remoto

Progettazione di un client TCP. Progettazione di un server TCP. Esempio: daytime TCP. Client TCP daytime

Una semplice applicazione client/server 1

Laboratorio di Sistemi Operativi Cognome Nome Mat.

INTERNET DOMAIN SOCKETS (Cap.59)

Comunicazione Connectionless o Datagram

(VHUFLWD]LRQLGLEDVHVXOOH6RFNHWLQ&

SERVER CLIENT. Struttura di un Applicazione UDP. Socket UDP. Parametri di sendto. Funzioni di Input/Output. Prof. Vincenzo Auletta

Esercitazione [6] Client/Server con Socket

Laboratorio di Reti di Calcolatori

Esercitazione Laboratorio di Sistemi Operativi Cognome Nome Mat.

Sviluppo di Applicazioni su Rete. Introduzione all API socket di Berkeley. Interazione tra Processi. Modello Client-Server

Socket TCP. prima parte

I/O su Socket TCP: read()

Laboratorio di Reti di Calcolatori

COMUNICAZIONE TRA PROCESSI REMOTI IN UNIX

Esempio 1: stampa locale di file remoto

LABORATORIO di Reti di Calcolatori

I Socket. Laboratorio Software M. Grotto R. Farina

Progettazione di Applicazioni Robuste. Applicazione Echo. Schema Generale di un Server TCP Ricorsivo 1. Applicazione echo

*HVWLRQHDYDQ]DWDGHOOH6RFNHWLQ& ODSULPLWLYDVHOHFW

Programmazione di Rete

Inizializzazione degli Host. BOOTP e DHCP

request reply richiesta client processo di servizio processo server principale From - Valeria Cardellini, Corso Sist. Distr. A.A.

rsystem Maximiliano Marchesi

Socket. Nei sistemi operativi moderni i servizi disponibili in rete si basano principalmente sul modello client/server.

Cenni di programmazione distribuita in C++ Mauro Piccolo

10.1. Un indirizzo IP viene rappresentato in Java come un'istanza della classe InetAddress.

Timeout. Socket Avanzati. Funzione alarm() Client echo UDP con alarm

Server Ricorsivii i. Dott. Delfina Malandrino.

Problema. I/O Multiplexing. Struttura delle Operazioni di Lettura. Modelli di I/O. Prof. Vincenzo Auletta

5 Esercitazione (svolta):

Sono definiti per vari protocolli

Esempi di Client e Server

Laboratorio Reti di Calcolatori (A.A ) Delfina Malandrino.

Corso di Reti di Calcolatori T

Elementi di programmazione con interfaccia Socket

Laboratorio di Reti di Calcolatori

Scrittura dei programmi applicativi di rete

Funzioni bloccanti e soluzioni

I puntatori e l allocazione dinamica di memoria

Esercitazione [7] Client/Server con Socket

unsigned long inet_addr(cp) char *cp;

SERVER CLIENT. Letteralmente significa presa (di corrente) È l astrazione di un canale di comunicazione fra due computer connessi da una rete

Interazione (TCP) Client-Server con le socket

IPC Inter Process Communication

Opzioni del Socket. Socket Options. Opzioni di Livello Socket. Livello delle Opzioni

Programmazione di applicazioni di rete con socket - parte 1

Creare una applicazione Winsock di base

Socket. Nei sistemi operativi moderni i servizi disponibili in rete si basano principalmente sul modello client/server.

Allocazione dinamica della memoria - riepilogo

RETI DI CALCOLATORI. Prof. PIER LUCA MONTESSORO Ing. DAVIDE PIERATTONI. Facoltà di Ingegneria Università degli Studi di Udine

Applicazione ECHO. Dott. Delfina Malandrino. p//ssd s / d

Domain Name Service. Mapping nomi/indirizzi con Socket API in C

Reti (già Reti di Calcolatori )

HTTP adaptation layer per generico protocollo di scambio dati

INGEGNERIA DEL WEB. VinX

P2-11: BOOTP e DHCP (Capitolo 23)

Inizializzazione, Assegnamento e Distruzione di Classi

Introduzione ai socket

Funzioni bloccanti e soluzioni. Funzioni bloccanti e soluzioni (2) Parametri della funzione select() Funzione select()

Esercizio 2. Client e server comunicano attraverso socket TCP

Funzioni in C. Violetta Lonati

AXO. Operativo. Architetture dei Calcolatori e Sistema. programmazione di sistema

DATAGRAM SOCKET. Angelastro Sergio Diomede Antonio Viterbo Tommaso

Introduzione alla programmazione in C

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli

Program m azione di Sistem a 6

Laboratorio reti AA 2008/2009. Dott. Matteo Roffilli Ricevimento in ufficio dopo la lezione

Guida all' uso dei sockets nella programmazione in C

Esercitazione [8] Pipe e FIFO

Programmazione socket. Queste slide sono distribuite con licenza Creative Commons Attribuzione-Non commerciale-condividi allo stesso modo 2.

Fondamenti di Informatica 2

Scrittura dei programmi applicativi di rete

Architetture dei Calcolatori e Sistemi Operativi

Esercitazione sulle libpq - libreria C per PostgreSQL

SCUOLA DI INGEGNERIA DELL INFORMAZIONE. Corso di Piattaforme Software per la rete MODULO 2 Anno Accademico Prof. William FORNACIARI

Corso di Reti di Calcolatori T

Corso di Reti di Calcolatori L-A

IPC System V. Code di messaggi

funzione fork() La funzione fork è usata per duplicare un processo. #include <unistd.h> pid_t fork (void);

Le funzioni in C. I programmi C sono costituiti da definizioni di variabili e funzioni.

Laboratorio di. Reti Informatiche. Corso di Laurea Triennale in Ingegneria Informatica A.A. 2016/2017. Ing. Niccolò Iardella

appunti delle lezioni Architetture client/server: applicazioni client

LABORATORIO di Reti di Calcolatori

Esercitazione di Lab. di Sistemi Operativi 1 a.a. 2011/ Comunicazione Tra Processi (IPC) Parte -

Gli array. Gli array. Gli array. Classi di memorizzazione per array. Inizializzazione esplicita degli array. Array e puntatori

CORSO DI SISTEMI OPERATIVI A - ESERCITAZIONE 6

Laboratorio di. Reti Informatiche. Corso di Laurea Triennale in Ingegneria Informatica A.A. 2016/2017. Ing. Niccolò Iardella

Laboratorio di Programmazione in rete

Introduzione al Linguaggio C

Socket per TCP: Fondamenti

Paradigma client-server

Introduzione alle applicazioni di rete

costruttori e distruttori

Transcript:

a.a. 2003/04 Interazione con il DNS Conversioni di Nomi ed Indirizzi Prof. Vincenzo Auletta auletta@dia.unisa.it http://www.dia.unisa.it/professori/auletta/ Università degli studi di Salerno Laurea in Informatica 1 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 e numeri di porta 2 Funzioni del resolver 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 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

Esempio Funzionamento del Resolver 4 oggetto 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_name h_aliases h_addrtype h_length h_addr_list AF_INET 4 bsdi koala panda NULL 140.252.1.11 140.252.3.54 140.252.4.54 NULL 5 Il 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 espansione il 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 Errori In caso di errore le funzioni del resolver scrivono un codice nella variabile h_errno la funzione hstrerror() legge il valore di h_errno e restituisce un messaggio di errore appropriato i valori che può assumere h_errno sono definiti in <netdb.h> HOST_NOT_FOUND TRY_AGAIN NO_RECOVERY NO_ADDRESS (NO_DATA) 6 Il nome specificato è sconosciuto Un errore temporaneo si è verificato su un name server Un errore irrimediabile si è verificato su un name server Il nome specificato è valido ma non ha un indirizzo IP 7 Conversioni Servizi/Porte 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 porta getservbyaddr: porta nome Il resolver non interagisce con il DNS ma legge soltanto il contenuto di un file locale (/etc/services)

Struttura servent Altri Tipi di Interrogazioni 8 Le funzioni getservbyname e getservbyaddr restituiscono puntatori ad oggetti servent allocati staticamente struct servent { char* s_name; /* nome ufficiale del */ char** s_aliases; /* elenco di alias */ int s_port; /* numero di porta */ char* s_proto; /* protocollo da utilizzare */ ; 9 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 utilizzate Il resolver legge i file locali (/etc/networks e /etc/protocols) 10 Altre Funzioni 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 DNS endhostent() ripristina l uso di UDP gethostname() restituisce il nome dell host corrente stesso risultato ottenuto con uname() 11 Client daytime con resolver 1 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 >"); 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 %s", argv[2]); elenco_addr = (struct in_addr **) hp->h_addr_list; 1.legge da linea di comando il nome del server e del 2.recupera l elenco di indirizzi IP del server 3.recupera il numero di porta ed il tipo di protocollo

12 Client daytime con resolver 2 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) 4. prova a connettersi a tutti gli indirizzi forniti dal resolver 5. crea il socket 6. riempie servaddr 7. tenta di connettersi e se ci riesce esce dal ciclo 8. altrimenti chiude il socket 13 Client daytime con resolver 3 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); 9. se è uscito dal ciclo senza essere riuscito a stabilire la connessione esce 10.legge la data e la stampa 14 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 %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"); 15 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 */

16 Funzioni Indipendenti dal Protocollo Le funzioni gethostbyname e gethostbyaddr dipendono dal tipo di indirizzi utilizzati e sono obsolete Per utilizzare l indirizzo restituito da gethostbyname dobbiamo sapere a che famiglia appartiene per copiarlo nel campo opportuno di struct sockaddr Restituisce Lo standard POSIX 1.g ha introdotto due nuove funzioni per interfacciarsi con il resolver Sono indipendenti dal tipo di indirizzi Restituiscono informazioni immediatamente utilizzabili dall applicazione L applicazione non deve sapere nulla di indirizzi, protocolli, ecc. 17 Funzione getaddrinfo int getaddrinfo(const char* host, const char* serv, const struct addrinfo *hints, struct addrinfo **result); Diverso da 0 se errore 0 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 richieste restituisce il risultato nella lista puntata da result Struttura addrinfo Esempio 18 struct 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 indirizzo struct addrinfo *ai_next; /* puntatore al nodo succ */ ; Tutti i puntatori indirizzano memoria allocata dinamicamente L applicazione deve preoccuparsi di rilasciare la memoria La funzione freeaddrinfo() rilascia tutta la memoria associata ad un oggetto addrinfo 19 Richiediamo informazioni sul daytime e l host koala Specifichiamo che vogliamo indirizzi IP 4 e trasporto TCP HINTS ai_flag AI_CANONNAME ai_family AF_INET ai_socktype SOCK_STREAM ai_protocol 0 ai_addrlen 0 ai_canonname NULL ai_addr NULL ai_next NULL RESULTS ai_flag 0 ai_family AF_INET ai_socktype SOCK_STREAM ai_protocol 0 ai_addrlen 16 ai_canonname bsdi.xyz.com ai_addr 140.252.1.11 ai_next AF_INET 7 prossimo nodo

20 Errori In 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 EAI_AGAIN EAI_FAIL EAI_BADFLAGS EAI_FAMILY EAI_MEMORY EAI_NODATA EAI_NONAME EAI_SERVICE EAI_SOCKTYPE EAI_SYSTEM tipo di indirizzo non supportato per name un errore temporaneo si è verificato su un name server un errore irrecuperabile si è verificato su un name server valore non corretto di ai_flags valore di ai_family non supportato errore di allocazione della memoria nessun indirizzo associato a name name o service non conosciuto service non supportato per ai_socktype ai_socktype non supportato errore di sistema restituito in errno 21 Funzione getnameinfo int getaddrinfo(const struct sockaddr* sockaddr, socklen_t addrlen, char* host, size_t hostlen, char* serv, size_t servlen, int flags); Restituisce -1 se errore 0 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 hostlen e servlen sono le lunghezze allocate per le stringhe flags consente di modificare il comportamento di default della funzione Utilizzo di getaddrinfo() Schema Base 22 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 Le funzioni utilizzano le informazioni restituite da getaddrinfo() per invocare le funzioni sul socket Useremo le seguenti funzioni tcp_connect() (client TCP) tcp_listen() (server TCP) udp_client() (client UDP non connesso) udp_connect() (client UDP connesso) udp_server() (server UDP) 23 Tutte le funzioni adotteranno il seguente schema Leggono da linea di comando nome dell host e del È 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 escono Se nessuno funziona escono con un errore

24 Tcp_connect() 1 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; 1.Riempie i campi di hints 2.Invoca getaddrinfo Risultato restituito nella lista puntata da risp 25 Tcp_connect() 2 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); 3. Cicla su tutti gli indirizzi di risp Prova ad eseguire prima socket() e poi connect() ed esce se ha stabilito la connessione 4. Dealloca la memoria dinamica Tcp_listen() 1 Tcp_listen() 2 26 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; 1.Richiede socket passivo 2.Invoca getaddrinfo 27 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 occupata 4. Se socket() e bind() riescono chiama la listen() 5. Restituisce in addrlenp un puntatore alla lunghezza dell indirizzo assegnato al socket 6. Dealloca la memoria dinamica

28 Client daytime con tcp_connect() 1 int main(int argc, char **argv) { int sockd, n; char recvline[maxline + 1]; socklen_t len; struct sockaddr *sa; 1.legge da linea di comando il nome del server e del 2.recupera l elenco di indirizzi IP del server 3.recupera il numero di porta ed il tipo di protocollo if (argc!= 3) (1) err_quit("utilizzo: dtime_name_client <nome dell'host> <nome del >"); 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 29 Client daytime con tcp_connect 2 while ( (n = read(sockd, recvline, MAXLINE)) > 0) { (10) recvline[n] = 0; if( fputs(recvline, stdout) == EOF ) err_sys("errore in fputs"); exit(0); 9. se è uscito dal ciclo senza essere riuscito a stabilire la connessione esce 10.legge la data e la stampa 30 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>] < 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 2. Alloca la memoria per contenere l indirizzo del client 31 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 */

Client e Server UDP Dal 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 32