getaddrinfo - getaddrinfo

Tyto funkce getaddrinfo () a getnameinfo () konvertovat doménová jména , názvy hostitelů a adresy IP mezi lidskými čitelných textových reprezentací a strukturovaných binárních formátů pro operační systém s síťové rozhraní API. Obě funkce jsou obsaženy ve standardním aplikačním programovacím rozhraní (API) POSIX .

getaddrinfo a getnameinfo jsou vzájemně inverzní funkce. Jsou agnostické pro síťový protokol a podporují IPv4 i IPv6 . Je doporučeným rozhraním pro překlad názvů při vytváření aplikací nezávislých na protokolu a pro přechod staršího kódu IPv4 na internet IPv6.

Funkce interně provádějí řešení pomocí systému DNS ( Domain Name System ) voláním dalších funkcí nižší úrovně, například gethostbyname () .

16. února 2016 byla oznámena chyba zabezpečení v implementaci glibc metody getaddrinfo () pomocí techniky přetečení vyrovnávací paměti , která může útočníkovi umožnit spuštění libovolného kódu.

struct addrinfo

C Datová struktura pro reprezentaci adresy a názvy hostitelů v rámci síťové API je následující:

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 */
};

V některých starších systémech typu ai_addrlen je size_t místo socklen_t . Většina zásuvka funkce, jako je přijmout () a getpeername () , vyžaduje parametr, který má mít typ socklen_t * a programátoři často předat adresu do ai_addrlen prvku addrinfo struktury. Pokud jsou typy nekompatibilní, např. Na 64bitovém systému Solaris 9 , kde size_t je 8 bajtů a socklen_t je 4 bajty, může dojít k chybám za běhu.

Struktura obsahuje struktury ai_family a sockaddr s vlastním polem sa_family . Jsou nastaveny na stejnou hodnotu, když je struktura vytvořena pomocí funkce getaddrinfo v některých implementacích.

getaddrinfo ()

getaddrinfo () převádí textem čitelné textové řetězce představující názvy hostitelů nebo adresy IP na dynamicky přidělený propojený seznam struktur struktury addrinfo. Prototypy funkcí pro tyto funkce jsou specifikovány následovně:

#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);
název hostitele
může to být buď název domény, například „example.com“, řetězec adresy, například „127.0.0.1“, nebo NULL, v takovém případě je adresa 0.0.0.0 nebo 127.0.0.1 přiřazena podle příznaků nápovědy.
servis
může být číslo portu předané jako řetězec, například „80“, nebo název služby, např. „echo“. V druhém případě typická implementace používá getervbyname () k dotazu na soubor / etc / services k vyřešení služby na číslo portu.
rady
může být buď NULL, nebo struktura addrinfo s požadovaným typem služby.
res
je ukazatel, který ukazuje na novou strukturu addrinfo s informacemi požadovanými po úspěšném dokončení funkce. Funkce vrátí 0 při úspěchu a nenulovou chybovou hodnotu, pokud selže.

Ačkoli se implementace mezi platformami liší, funkce se nejprve pokusí získat číslo portu obvykle větvením ve službě . Pokud je řetězcovou hodnotou číslo, převede jej na celé číslo a zavolá htons () . Pokud se jedná o název služby, například www , je služba vyhledána pomocí metody getervbyname () pomocí protokolu odvozeného od hints-> ai_socktype jako druhého parametru této funkce. Pak, pokud je uveden název hostitele (ne NULL), volání gethostbyname () jej vyřeší, nebo je jinak použita adresa 0.0.0.0 , pokud je hints-> ai_flags nastavena na AI_PASSIVE a jinak 127.0.0.1 . Přidělila novou strukturu addrinfo naplněnou příslušným sockaddr_in v jedné z těchto podmínek a také k ní přidá načtený port na začátku. Nakonec je dereferencován parametr ** res, aby odkazoval na nově přidělenou strukturu addrinfo . V některých implementacích, jako například verze Unix pro Mac OS je rady-> ai_protocol Přepíše rady-> ai_socktype hodnoty, zatímco v jiných je to naopak, tak jak je třeba definovat s ekvivalentní hodnoty pro kód za práci přes násobek platformy.

getnameinfo ()

getnameinfo () převádí interní binární reprezentaci adresy IP ve formě ukazatele struktury sockaddr na textové řetězce skládající se z názvu hostitele nebo, pokud adresu nelze přeložit na název, textovou reprezentaci adresy IP a také službu název nebo číslo portu. Prototyp funkce je specifikován následovně:

#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 ()

Tato funkce uvolní paměť přidělenou funkcí getaddrinfo () . Výsledkem posledně jmenovaného je propojený seznam struktur addrinfo, prochází seznamem freeaddrinfo () a postupně uvolňuje každou z nich.

#include <sys/socket.h>
#include <netdb.h>

void freeaddrinfo(struct addrinfo *ai);
  • ai je vedoucím seznamu addrinfo

Příklad

Následující příklad používá getaddrinfo () k rozlišení názvu domény www.example.com do seznamu adres a poté volá getnameinfo () u každého výsledku, aby vrátil kanonický název adresy. Obecně se vytvoří původní název hostitele , pokud konkrétní adresa nemá více jmen, v takovém případě se vrátí kanonický název. V tomto příkladu je název domény vytištěn třikrát, jednou pro každý ze tří získaných výsledků.

#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;
}

Viz také

Reference

externí odkazy

  • RFC 3493 , Basic Socket Interface Extensions for IPv6