C言語では、 関数と関数は、ドメイン名、ホスト名、IPアドレスを、人間が読めるテキスト表現と、オペレーティングシステムのネットワークAPI用の構造化されたバイナリ形式の間で 変換します。これらの関数は両方ともPOSIX標準アプリケーションプログラミングインターフェース(API)に含まれています。 [ 1 ]getaddrinfo()getnameinfo()
getaddrinfoとgetnameinfoは互いに逆関数の関係にあります。これらはネットワークプロトコルに依存せず、IPv4とIPv6の両方をサポートしています。プロトコルに依存しないアプリケーションの構築時や、既存のIPv4コードをIPv6インターネットに移行する際に、名前解決のための推奨インターフェースとして使用されます。
内部的には、これらの関数はドメインネームシステム(DNS)に限定されないさまざまな解決方法を使用する可能性があります。ネームサービススイッチは、Unix ライクなシステムで一般的に使用されており、 BSD ソケット時代の前身と同様に、このペアのほとんどの実装に影響を与えます。[ 2 ]
ネットワーク API で使用するアドレス情報クエリの結果を表すために使用される C データ構造は、メンバーの順序が異なったり、メンバーが追加されたりする可能性があるが、次のように定義される可能性がある。[ 3 ] [注1 ]
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 ; struct addrinfo * ai_next ; };この構造体には、メンバーと、独自のフィールドを持つオブジェクトを指すai_familyメンバーが含まれています。一部の実装では、関数を使用して構造体を作成する際に、これらのメンバーは同じ値に設定されます。ai_addrstruct sockaddrsa_familygetaddrinfo()
getaddrinfo()ホスト名またはIP アドレスを表す人間が読めるテキスト文字列をstruct addrinfo 構造体のリストに変換します。関数プロトタイプは次のとおりです。[ 1 ]
int getaddrinfo ( const char * restrict hostname , const char * restrict service , const struct addrinfo * restrict hints , struct addrinfo ** restrict res );NULLアドレス0.0.0.0または127.0.0.1が割り当てられる、のいずれかになります。getservbyname()NULLである場合もある。addrinfoaddrinfofreeaddrinfo()この関数は成功した場合は 0 を返し、失敗した場合は 0 以外のエラー値を返して、[ 1 ]それを[ 6 ]を使用して人間が読める文字列にマッピングできます。gai_strerror()
実装方法はプラットフォームによって異なりますが、多くの場合、ホスト名がDNSにない場合はDNSでホスト名を検索し、既知のサービスデータベースからサービスを検索します。ホスト名とサービス解決のために照会されるソースの正確なセットは、多くの場合、システムのネームサービススイッチの設定によって制御されます。
この関数は、freeaddrinfo()関数によって割り当てられたメモリを解放します。関数によって生成された、aiから始まるオブジェクトgetaddrinfo()のリンクリストが与えられた場合、そのリスト内のすべてのオブジェクトを解放します。struct addrinfogetaddrinfo(..., &ai)freeaddrinfo(ai)struct addrinfo
void freeaddrinfo ( struct addrinfo * ai );この関数はgetnameinfo()、ポインタの形式で表されるIPアドレスの内部バイナリ表現を、struct sockaddrホスト名、またはアドレスが名前に解決できない場合はテキスト形式のIPアドレス表現、およびサービスポート名または番号からなるテキスト文字列に変換します。関数プロトタイプは次のように指定されます。
int getnameinfo ( const struct sockaddr * restrict sa , socklen_t salen , char * restrict host , socklen_t hostlen , char * restrict service , socklen_t servicelen , int flags );次の例では、getaddrinfo()ドメイン名www.example.com をアドレスのリストに解決し、各結果に対して を呼び出して、そのアドレスの正規名を返します。通常、特定のアドレスに複数の名前がない限り、これは元のホスト名を生成します。複数の名前がある場合は、正規名が返されます。この例では、ドメイン名が 3 回出力されます。これは、取得した 3 つの結果それぞれに対して 1 回ずつです。getnameinfo()
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h>#include <netdb.h> #include <netinet/in.h> #include <sys/socket.h>#ifndef NI_MAXHOST #define NI_MAXHOST 1025 #endifint main ( void ) { const char query_host [] = "www.example.com" ; struct addrinfo * result ;struct addrinfo hints = { . ai_family = AF_UNSPEC , . ai_socktype = SOCK_STREAM };// ドメイン名をアドレスのリストに解決するint gai_rc = getaddrinfo ( query_host , NULL , & hints , & result ); switch ( gai_rc ) { case 0 : break ; case EAI_SYSTEM : fprintf ( stderr , "Failed to resolve server address '%s': system error %s \n " , query_host , strerror ( errno )); return EXIT_FAILURE ; default : fprintf ( stderr , "Failed to resolve server address '%s': %s \n " , query_host , gai_strerror ( gai_rc )); return EXIT_FAILURE ; }// 解決されたアドレスごとに逆引き DNS ルックアップを実行しますfor ( const struct addrinfo * ai = result ; ai != NULL ; ai = ai -> ai_next ) { char hostname [ NI_MAXHOST ]; char addr [ NI_MAXHOST ];int gni_rc = getnameinfo ( ai- > ai_addr , ai- > ai_addrlen , addr , sizeof ( addr ), NULL , 0 , NI_NUMERICHOST ); if ( gni_rc != 0 ) { fprintf ( stderr , "アドレスのフォーマットに失敗しました: %s \n " , gai_strerror ( gni_rc )); continue ; }gni_rc = getnameinfo ( ai- > ai_addr , ai- > ai_addrlen , hostname , sizeof ( hostname ), NULL , 0 , 0 ); switch ( gni_rc ) { case 0 : printf ( "ホスト名 %s: %s \n " , addr , hostname ); break ; case EAI_SYSTEM : fprintf ( stderr , "逆引き DNS ルックアップ %s: システム エラー %s \n " , addr , strerror ( errno )); break ; default : fprintf ( stderr , "逆引き DNS ルックアップ %s: %s \n " , addr , gai_strerror ( gni_rc )); } }freeaddrinfo ( result ); return 0 ; }