getaddrinfo - getaddrinfo
Cele Funcțiile getaddrinfo () și getnameinfo () conversia nume de domenii , nume de gazde și adresele IP între reprezentări de text care poate fi citit-umane și formate binare structurate pentru sistemul de operare e API - ul de rețea. Ambele funcții sunt conținute în interfața de programare a aplicației standard (API) POSIX .
getaddrinfo și getnameinfo sunt funcții inverse una de cealaltă. Sunt protocoale de rețea agnostice și acceptă atât IPv4 cât și IPv6 . Este interfața recomandată pentru rezolvarea numelor în construirea aplicațiilor independente de protocol și pentru tranziția codului IPv4 moștenit la Internetul IPv6.
Pe plan intern, funcțiile efectuează rezoluții folosind sistemul de nume de domeniu (DNS) apelând alte funcții de nivel inferior, cum ar fi numele gethostbyname () .
Pe 16 februarie 2016, a fost anunțată o eroare de securitate în implementarea glibc a getaddrinfo (), folosind o tehnică de revărsare tampon , care poate permite executarea codului arbitrar de către atacator.
cuprins
struct addrinfo
Structura de date C utilizată pentru a reprezenta adrese și nume de gazdă în API-ul de rețea este următoarea:
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr* ai_addr;
char* ai_canonname; /* canonical name */
struct addrinfo* ai_next; /* this struct can form a linked list */
};
În unele sisteme mai vechi de tipul de ai_addrlen este size_t în loc de socklen_t . Cele mai multe funcții, cum ar fi socket accept () și getpeername () , necesită parametrul pentru a avea tipul socklen_t * și programatori trec de multe ori adresa la ai_addrlen element al addrinfo structurii. Dacă tipurile sunt incompatibile, de exemplu, pe un sistem Solaris 9 pe 64 de biți unde size_t este de 8 octeți și socklen_t este de 4 octeți, atunci pot rezulta erori în timp de execuție.
Structura conține structuri ai_family și sockaddr cu propriul câmp sa_family . Acestea sunt setate la aceeași valoare atunci când structura este creată cu funcția getaddrinfo în unele implementări.
getaddrinfo ()
getaddrinfo () convertește șiruri de text care pot fi citite de oameni reprezentând nume de gazdă sau adrese IP într-o listă legată dinamic de structuri addrinfo struct. Prototipurile funcțiilor pentru aceste funcții sunt specificate după cum urmează:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char* hostname,
const char* service,
const struct addrinfo* hints,
struct addrinfo** res);
- nume de gazdă
- poate fi fie un nume de domeniu, cum ar fi „exemplu.com”, un șir de adrese, cum ar fi „127.0.0.1”, sau NULL, caz în care adresa 0.0.0.0 sau 127.0.0.1 este atribuită în funcție de indicatoarele indicii.
- serviciu
- poate fi un număr de port transmis ca șir, cum ar fi „80”, sau un nume de serviciu, de exemplu „ecou”. În ultimul caz, o implementare tipică folosește getervbyname () pentru a interoga fișierul / etc / services pentru a rezolva serviciul la un număr de port.
- sugestii
- poate fi NULL sau o structură addrinfo cu tipul de serviciu solicitat.
- res
- este un indicator care indică o nouă structură addrinfo cu informațiile solicitate după finalizarea cu succes a funcției. Funcția returnează 0 după succes și valoarea de eroare non-zero dacă eșuează.
Deși implementările variază în funcție de platforme, funcția încearcă mai întâi să obțină un număr de port, de obicei, prin ramificare la service . Dacă valoarea șirului este un număr, o transformă într-un număr întreg și apelează la htons () . Dacă este un nume de serviciu, cum ar fi www , serviciul este de căutare cu getervbyname () , folosind protocolul derivat din indicii-> ai_socktype ca al doilea parametru pentru funcția respectivă. Apoi, dacă este dat un nume de gazdă (nu NULL), un apel către gethostbyname () îl rezolvă, sau altfel se folosește adresa 0.0.0.0 , dacă indicii-> ai_flags este setat pe AI_PASSIVE și 127.0.0.1 în caz contrar. A alocat o nouă structură addrinfo completată cu sockaddr_in corespunzătoare într-una din aceste condiții și, de asemenea, adaugă portul preluat la început. În cele din urmă, parametrul ** res este dereferențiat pentru a face punctul către o structură addrinfo nou alocată . În unele implementări, cum ar fi versiunea Unix pentru Mac OS, indicii-> ai_protocol înlocuiesc indicii-> ai_socktype în timp ce, în altele, este opus, deci ambele trebuie definite cu valori echivalente pentru ca codul să funcționeze pe mai multe platforme.
getnameinfo ()
getnameinfo () convertește reprezentarea internă binară a unei adrese IP sub forma unui pointer struct sockaddr în șiruri de text constând din numele de gazdă sau, dacă adresa nu poate fi rezolvată într-un nume, o reprezentare textuală a adresei IP, precum și serviciul numele sau numărul portului. Prototipul funcției este specificat după cum urmează:
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr* sa, socklen_t salen,
char* host, size_t hostlen,
char* serv, size_t servlen,
int flags);
freeaddrinfo ()
Această funcție eliberează memoria alocată de funcția getaddrinfo () . Deoarece rezultatul din urmă este o listă legată de structuri addrinfo , freeaddrinfo () se bucle pe listă și le eliberează pe rând.
#include <sys/socket.h>
#include <netdb.h>
void freeaddrinfo(struct addrinfo *ai);
- ai este capul listei addrinfo
Exemplu
Următorul exemplu utilizează getaddrinfo () pentru a rezolva numele de domeniu www.example.com în lista sa de adrese și apoi apelează la getnameinfo () pe fiecare rezultat pentru a returna numele canonic pentru adresă. În general, aceasta produce numele de gazdă original , cu excepția cazului în care adresa particulară are mai multe nume, caz în care numele canonic este returnat. În acest exemplu, numele de domeniu este tipărit de trei ori, o dată pentru fiecare dintre cele trei rezultate obținute.
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif
int main(void)
{
struct addrinfo* result;
struct addrinfo* res;
int error;
/* resolve the domain name into a list of addresses */
error = getaddrinfo("www.example.com", NULL, NULL, &result);
if (error != 0) {
if (error == EAI_SYSTEM) {
perror("getaddrinfo");
} else {
fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
}
exit(EXIT_FAILURE);
}
/* loop over all returned results and do inverse lookup */
for (res = result; res != NULL; res = res->ai_next) {
char hostname[NI_MAXHOST];
error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
if (error != 0) {
fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
continue;
}
if (*hostname != '\0')
printf("hostname: %s\n", hostname);
}
freeaddrinfo(result);
return 0;
}
Vezi si
Referințe
linkuri externe
- RFC 3493 , Extensii de bază pentru interfață de soclu pentru IPv6