Internet Engineering Task Force R.E. Gilligan (FreeGate) INTERNET-DRAFT S. Thomson (Bellcore) Obsoletes draft-ietf-ipngwg-bsd-api-new-03.txt Jim Bound (Compaq) W. R. Stevens (Consultant) November 3, 1998 Basic Socket Interface Extensions for IPv6 Status of this Memo This document is a submission by the Internet Protocol IPv6 Working Group of the Internet Engineering Task Force (IETF). Comments should be submitted to the ipng@sunroof.eng.sun.com mailing list. This document is an Internet-Draft. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF), its areas, and its working groups. Note that other groups may also distribute working documents as Internet-Drafts. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet- Drafts as reference material or to cite them other than as "work in progress." To view the entire list of current Internet-Drafts, please check the "1id-abstracts.txt" listing contained in the Internet-Drafts Shadow Directories on ftp.is.co.za (Africa), ftp.nordu.net (Europe), munnari.oz.au (Pacific Rim), ftp.ietf.org (US East Coast), or ftp.isi.edu (US West Coast). Distribution of this memo is unlimited. 要約 TCP/IP アプリケーションのための事実上の標準アプリケーションプログラム インターフェイス (API) は、"ソケット" インターフェイスである。この API は 1980 年代はじめに UNIX 用に開発されたが、数多くの非 UNIX システム上でも 実装されている。ソケット API を使って書かれた TCP/IP アプリケーションは 高度な移植性を経験した。そして我々は、IPv6 アプリケーションでも同じような 移植性を好むだろう。しかし、ソケット API に IPv6 をサポートさせるには 変更が要求されるので、このメモはそれらの変更について記述する。それらは、 IPv6アドレスを運ぶための新しいソケットアドレス構造体、新しいアドレス変換 関数と、いくつかの新しいソケットオプションを含んでいる。これらの拡張は、 TCPと UDP アプリケーションによって要求されたマルチキャストを含む基本的な IPv6 の特徴へのアクセスを与えるために設計された。その上これらの拡張は、 システムへの変更を最小にし、今ある IPv4 アプリケーションとの完全な互換性を 提供する。高度な IPv6 の特徴に対する付加的な拡張 (生のソケットと IPv6 拡張ヘッダに対するアクセス) は別の文書 [4] で定義されている。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 1] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 Table of Contents: 1. 導入.........................................................3 2. 設計上の留意点...............................................3 2.1 変更される必要のあるもの....................................3 2.2 データ型....................................................5 2.3 ヘッダ......................................................5 2.4 構造体......................................................5 3. ソケットインタフェース.......................................5 3.1 IPv6 アドレスファミリとプロトコルファミリ...................5 3.2 IPv6 アドレス構造体.........................................6 3.3 4.3BSD系システムのためのソケットアドレス構造体..............6 3.4 4.4BSD系システムのためのソケットアドレス構造体..............7 3.5 ソケット関数................................................8 3.6 IPv4 アプリケーションとの互換性.............................9 3.7 IPv4 ノードとの互換性.......................................9 3.8 IPv6 ワイルドカードアドレス................................10 3.9 IPv6 ループバックアドレス..................................11 3.10 移植性の追加..............................................11 4. インタフェース識別..........................................13 4.1 名前からインデックス.......................................14 4.2 インデックスから名前.......................................14 4.3 全インタフェース名とインデックスの返却.....................15 4.4 メモリ解放.................................................15 5. ソケットオプション..........................................15 5.1 ユニキャスト中継点限界数...................................16 5.2 マルチキャストパケットの送受信.............................16 6. ライブラリ関数..............................................18 6.1 ノード名からアドレス変換...................................18 6.2 アドレスからノード名変換...................................21 6.3 getipnodebynameおよびgetipnodebyaddr用メモリ解放...........22 6.4 プロトコル非依存なノード名およびサービス名変換.............22 6.5 ソケットアドレス構造体からノード名およびサービス名.........25 6.6 アドレス変換関数...........................................26 6.7 アドレス試験マクロ.........................................27 7. 新しい定義のまとめ..........................................27 8. セキュリティ考察............................................29 9. 2000年考察..................................................29 RFC 2133 からの変更............................................29 謝辞...........................................................32 参考文献.......................................................32 著者のアドレス.................................................33 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 2] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 1. はじめに IPv4 アドレスは、32ビットの長さであるが、IPv6 のインターフェイスは 128 ビットのアドレスで識別される。ソケットインターフェイスは、明らかに アプリケーションに対して IP アドレスのサイズを作る。事実、BSD 系システム のすべての TCP/IP アプリケーションは IP アドレスのサイズに対する知識を 持っている。アドレスをさらしている API の部分は、より大きいIPv6の アドレスのサイズに対応するために変更されなければならない。IPv6 はまた 新しい特徴(例えばフローラベルと優先度)を導入した。そのいくつかは明らか に API を通してアプリケーションのために作られなければならない。このメモ はソケットインターフェイスに大きいアドレスサイズと IPv6 の新しい特徴を サポートさせるための拡張の集合を定義する。 2. 設計上の留意点 このよく使われた API の変更を設計する上でのいくつかの重要な考察である。 - API の変更は、元の API で書かれたプログラムのソースとバイナリの 両方について互換性を提供するべきである。すなわち、既存のプログラムの バイナリは、新しい API をサポートしたシステムが稼働した時にも動き 続けるべきである。それに加えて、再コンパイルされ、新 API をサポート したシステムの上で走る現存のアプリケーションは動き続けるべきである。 簡単にいうと、IPv6 のための API の変更は既存のプログラムを破壊 すべきではない。実装がこれを証明するための追加機構は、新しい シンボルが IEEE Std 1003.1 で記述される機能試験マクロによって 保護されることを証明する(このような機能試験マクロはこのRFCでは 定義されない)。 - 既存の IPv4 アプリケーションを IPv6 用に変える仕事を簡素化するために、 API の変更点は可能な限り少なくあるべきである。 - もしも可能ならば、アプリケーションは IPv6 と IPv4の両方のホストで このAPIを使えるべきである。アプリケーションは、通信している相手が どちらのタイプのホストか知る必要はない。 - データ構造体の中で運ばれる IPv6 アドレスは、64ビット境界で整列 されるべきである。これは、64 ビットマシンアーキテクチャにおいて 最適なパフォーマンスを得るために必要である。 API に IPv4 との互換性を与えることは重要なので、これらの拡張は、IPv4 とIPv6 の両方が完全にサポートされているマシンの上で使用するために 明示的に設計された。この API の下位集合は、IPv6 しかサポートしていない システムで使用するために多分設計されている。しかしこれはこの文書では 特定されていない。 2.1 変更される必要のあるもの ソケットインターフェイス API は、いくつかの異なった要素からなる。 - 中心的ソケット関数 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 3] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 - アドレスデータ構造 - 名前からアドレス変換関数 - アドレス変換関数 中心的なソケット関数 -- TCP コネクションの開設・解放や、UDP パケットの 送受信の処理を行なうこれらの関数 -- は、自由に運ぶために設計されている。 プロトコルアドレスが関数の引数として通過する場所では、不透明なポインタに よって運ばれる。プロトコル独自のアドレスデータ構造は、ソケット関数が サポートしている各プロトコルごとに定義されている。アプリケーションが ソケット関数を使う時、これらのプロトコル独自のアドレス構造体へのポインタ を一般的な "sockaddr" アドレス構造体へのポインタにキャストしなければ ならない。これらの関数は、IPv6 用の変更を必要としないが、IPv6 独自の アドレスデータ構造は必要である。 sockaddr_in 構造体は、IPv4 のプロトコル独自のデータ構造体である。この データ構造体は、実は8オクテットの未使用の領域を含んでいて、sockaddr_in 構造体を IPv6 に適用するために、このスペースを使うことを試してみたくなる。 不運にも、sockaddr_in 構造体は、必要な他の情報 (アドレスファミリやポート 番号) はもちろん 16 オクテットの IPv6 アドレスさえも保持するのに十分な 大きさではない。従って、新しいアドレス構造体が IPv6 用に定義された。 IPv6 アドレスは [2] で書かれているようにスコープされていて、リンクローカル、 サイト、組織、グローバルや今はまだ定義されていないスコープが可能である。 特定のスコープのためのインターフェイス集合の識別をしたいアプリケーションを サポートするためにIPv6 の sockaddr_in 構造体は、IPv6 アドレスのスコープを 識別するインターフェイスの集合を識別するための実装に使われるフィールドを サポートしなければならない。 ソケットインターフェイスの名前-アドレス変換関数は、gethostbyname() と gethostbyaddr() である。これらはそれとして残り、新しい関数が IPv4 と IPv6 をサポートするために定義された。それに加えて、POSIX 1003.g ドラフト [5] は、プロトコルに依存しない新しいノード名-アドレス変換関数を明確に 述べた。この関数は IPv4 でも IPv6 でも使うことが出来る。 アドレス変換関数 -- inet_ntoa() と inet_addr() -- は、バイナリ形式と 印字可能形式の IPv4 アドレスを変換する。これらの関数は完全に 32 ビットの IPv4 アドレスに特有の物である。我々は、IPv4 と IPv6 アドレスとの両方で 変換する二つの類似している関数を設計した。そして、それはアドレスタイプ パラメータを運んでいるので、同様に別のプロトコルファミリに対応させる ことができる。 最後に、IPv6 をサポートするにはいくつかの雑多な機能が必要とされている。 IPv6 のフローラベル、優先度、そして中継点限界数ヘッダフィールドをサポート するために新しいインターフェイスが必要とされる。IPv6 のマルチキャスト パケットの送受信を制御するために新しいソケットオプションが必要である。 ソケットインターフェイスは、近い将来、別のIPv6の機能へのアクセスを与える ために拡張されるだろう。これらの拡張は [4] に記述されている。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 4] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 2.2 データ型 この文書で与えられる構造体の要素のデータタイプは、例のつもりであって 絶対的な要求ではない。可能なら、POSIX 1003.1g のドラフト 6.6 (1997年3月)の データタイプが使われる。uintN_t はちょうど N ビットの符号無し整数(例えば uint16_t)を意味する。我々はまた、可能なら 1003.1g による引数のデータ タイプとみなす (例えば setsockopt() の最後の引数は size_t の値である)。 バッファサイズが指定された時は POSIX 1003.1 size_t データタイプが使われる (例えば getnameinfo() の二つの長さの引数)。 2.3 ヘッダ 関数のプロトタイプや構造体が出現する時、我々は、項目が定義されるために #include されなければならないヘッダを示す。 2.4 構造体 構造体が記述中、メンバとして出現したメンバは実装に現れなければならない。 それに加え、実装によっては非標準のメンバも定義されるかも知れない。更に 用心のために、非標準のメンバは IEEE Std 1003.1 で記述される機能試験 マクロによって確かめられるだろう(このような機能試験マクロはこのRFCでは 定義されない)。 構造体のメンバは、マルチバイトメンバの境界を考慮して推奨される順序で 示されているが、実装はメンバを異なる順序で並べてもよい。 3. ソケットインタフェース この章では、IPv6 用ソケットインターフェイスの変更点を述べる。 3.1 IPv6 のアドレスファミリとプロトコルファミリ 新しいアドレスファミリ名 AF_INET6 は で定義されている。 この AF_INET6 の定義は、オリジナルの sockaddr_in アドレスデータ構造体と 新しい sockaddr_in6 データ構造体を区別する。 新しいプロトコルファミリ名 PF_INET6 は で定義されている。 他の多くのプロトコルファミリ名と同じように、これも通常アドレスファミリ名と 同じ値が定義されている。 #define PF_INET6 AF_INET6 PF_INET6 は、IPv6 ソケットが作られることを示すために socket() 関数の 最初の引数に使われる。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 5] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 3.2 IPv6 アドレス構造体 新しい in6_addr 構造体は、一つの IPv6 アドレスを保持し、 をインクルードした結果定義される。 struct in6_addr { uint8_t s6_addr[16]; /* IPv6 address */ }; このデータ構造体は、8ビットの要素16個からなる配列を含んでおり、それが 128 ビットの IPv6 アドレスを作っている。IPv6 アドレスはネットワーク バイトオーダで格納される。 上の構造体 in6_addr は、普通 struct in_addr の BSD の実装と同じ風習の 境界をもったフィールドの共用体として実装される。 次に例を示す。 struct in6_addr { union { uint8_t _S6_u8[16]; uint32_t _S6_u32[4]; uint64_t _S6_u64[2]; } _S6_un; }; #define s6_addr _S6_un._S6_u8 3.3 4.3BSD 系システム用のソケットアドレス構造体 ソケットインターフェイスの中で、異なったプロトコル独自のデータ構造体が、 それぞれのプロトコル用のアドレスを運ぶために定義されている。各プロトコル 独自のデータ構造体は、プロトコル非依存のデータ構造体--"sockaddr"構造体--に キャストできるように設計されている。それぞれが、sockaddr データ構造体の "sa_family" を上塗りする "family" フィールドを持っている。このフィールドが データ構造体のタイプを識別する。 sockaddr_in 構造体は、IPv4 プロトコル独自のアドレスデータ構造体である。 それは、ソケット関数の中でアプリケーションとシステムとの間でアドレスを 伝えるのに使われている。次の sockaddr_in6 構造体は、IPv6 アドレスを保持 していて、 ヘッダをインクルードした結果定義される。 struct sockaddr_in6 { sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* トランスポート層のポート番号 */ uint32_t sin6_flowinfo; /* IPv6 トラヒッククラスとフロー情報 */ struct in6_addr sin6_addr; /* IPv6 アドレス */ uint32_t sin6_scope_id; /* スコープのためのインタフェース集合 */ }; この構造体は、4.3BSD release で使われている sockaddr データ構造体と 互換性があるように設計されている。 sin6_family フィールドは、これが sockaddr_in6 構造体であるということを draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 6] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 識別する。このフィールドは、バッファが sockaddr データ構造体にキャスト された時、sa_family フィールドを上塗りする。このフィールドの値は、AF_INET6 でなければならない。 sin6_port フィールドは、16 ビットの UDP か TCP のポート番号を持っている。 このフィールドは、sockaddr_in 構造体の sin_port フィールドと同じ方法で 使われる。ポート番号はネットワークバイトオーダで格納される。 sin6_flowinfo フィールドは、トラフィッククラスとフローラベルの二つの 情報を持った32ビットのフィールドである。そのメンバの内容と解釈は[1]で 記されている。sin6_flowinfo フィールドは、受信操作の時にアプリケーションに よって sockaddr_in6 構造体が使われるより前に実装によって0がセットされて いるべきである。 sin6_addr フィールドは、(前章で定義された)一つの in6_addr 構造体である。 このフィールドは 128 ビットの IPv6 アドレスを保持している。このアドレスは ネットワークバイトオーダで格納される。 この構造体の中の要素の並び方は明示的に設計されたので、sin6_addrフィールドが 64ビット境界で整列される時この構造体の先頭も64ビット境界で整列されている だろう。これは64ビットアーキテクチャ上で最適なパフォーマンスを得る。 sin6_scope_id フィールドは sin6_addr フィールドが運んでいるアドレスの スコープのための適当なインターフェイスの集合を識別する32ビット整数である。 リンクスコープの sin6_addr では sin6_scope_id はインターフェイス インデックスになるだろう。サイトスコープの sin6_addrでは sin6_scope_id はサイト識別子になるだろう。sin6_scope_id のインターフェイスやその集合 へのマッピングは実装と将来の仕様に任されている。 sockaddr_in6 構造体は、通常一般的な sockaddr 構造体よりも大きくなる ことに注意せよ。多くの現存の実装では、sizeof(struct sockaddr_in) は sizeof(struct sockaddr) に等しく、どちらも 16 バイトである。こう仮定 しているいくつかの現存のコードを IPv6 用に変更する時は、注意深く試験 される必要がある。 3.4 4.4BSD 系システムのソケットアドレス構造体 4.4BSD release は、ソケットインターフェイスに対して小さいが互換性のない 変更を含んでいる。sockaddr データ構造体の "sa_family" フィールドは、16 ビット値から8ビット値に変更された。そして、空いた領域は "sa_len" という 名前で長さのフィールドを保持するために使われる。前章で与えられた sockaddr_in6 データ構造体は、新しい sockaddr データ構造体に正しくキャスト することができない。この理由から、4.4BSD 系のシステムでは次の代替 IPv6 アドレスデータ構造体が用意されている。これは ヘッダを インクルードした結果定義される。 struct sockaddr_in6 { uint8_t sin6_len; /* この構造体の長さ */ sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* トランスポート層のポート番号 */ uint32_t sin6_flowinfo; /* IPv6 フロー情報 */ struct in6_addr sin6_addr; /* IPv6 アドレス */ uint32_t sin6_scope_id; /* スコープのためのインタフェース集合 */ }; draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 7] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 このデータ構造体と 4.3BSD のそれとの違いは、長さのフィールドを含み、 ファミリフィールドが 8ビットデータタイプに変更になったことだけである。 他の全てのフィールドの宣言は、前章で定義した構造体を同様である。 このバージョンの sockaddr_in6 データ構造体を提供しているシステムでは、 ヘッダをインクルードした結果として SIN6_LEN も宣言 しなければならない。このマクロは、アプリケーションが 4.3BSD のデータ 構造体をサポートしているシステムの上で動くか、4.4BSD のそれの上で動くか どうかを決めることができる。 3.5 ソケット関数 アプリケーションは、通信のエンドポイントの代理をするソケットディスクリプタ を生成するために socket() 関数を呼ぶ。socket() 関数への引き数は、どの プロトコルを使うかとその後の関数でどの型のアドレス構造体が使われるのかを システムに知らせる。例えば、IPv4/TCP ソケットを生成したいならアプリ ケーションは次のようにする: s = socket(PF_INET, SOCK_STREAM, 0); IPv4/UDP ソケットを生成したいなら、アプリケーションは次のようにする: s = socket(PF_INET, SOCK_DGRAM, 0); アプリケーションは、最初の引数の PF_INET の代わりに単に定数 PF_INET6 を 使うだけで、IPv6/TCP や IPv6/UDP のソケットを生成できる。例えば、 IPv6/TCP ソケットを生成したいならアプリケーションは次のようにする: s = socket(PF_INET6, SOCK_STREAM, 0); IPv6/UDP ソケットを生成したいならアプリケーションは次のようにする: s = socket(PF_INET6, SOCK_DGRAM, 0); 一旦アプリケーションが PF_INET6 ソケットを生成したら、システムに アドレスを伝える時には sockaddr_in6 アドレス構造体を使わなければならない。 アプリケーションがシステムにアドレスを伝えるために使う関数は: bind() connect() sendmsg() sendto() システムは、PF_INET6 ソケットを使っているアプリケーションにアドレスを 返すために sockaddr_in6 アドレス構造体を使うだろう。システムから アプリケーションにアドレスを返す関数は: accept() recvfrom() recvmsg() getpeername() getsockname() 全ての"アドレスを運んでいる"関数は、不透明なアドレスポインタを使用して draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 8] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 いて、関数の引数としてアドレスの長さを運んでいるので、IPv6 をサポート するために、ソケット関数の文法に変更は必要ない。 3.6 IPv4 アプリケーションとの互換性 元の API を使ったアプリケーションの大きな基盤をサポートする目的で、 システムの実装は、元のAPIとのソースとバイナリでの完全な互換性を提供 しなければならない。これは、システムが PF_INET ソケットと sockaddr_in アドレス構造体のサポートを続けなければならないことを意味する。 アプリケーションは、前章で述べられたように socket() 関数で PF_INET 定数を用いて IPv4/TCP と IPv4/UDP ソケットを生成できなければならない。 アプリケーションは、同じプロセスの中で同時に IPv4/TCP、IPv4/UDP、 IPv6/TCP そして IPv6/UDP ソケットを保持できるべきである。 元の API を使っているアプリケーションは、IPv4 しかサポートしていない システム上でしていたように動作し続けるべきである。すなわち、それらは IPv4 ノードでも動作し続けるべきである。 3.7 IPv4 ノードとの互換性 API は、IPv6 アプリケーションが IPv4 アプリケーションとともに相互動作 する能力という違ったタイプの互換性を提供する。この特徴は、IPv6 アドレス アーキテクチャ仕様書[2] で定義された IPv4 射影 IPv6 アドレス形式を使って いる。このアドレス形式は、IPv4 ノードの IPv4 アドレスに対して、IPv6 アドレスの代理をすることを許している。Ipv4 アドレスは、IPv6 アドレスの 下位 32 ビットに置かれ、上位 96 ビットは固定プレフィックス 0:0:0:0:0:FFFF を持つ。IPv4 射影アドレスは次のように書かれる。 ::FFFF: これらのアドレスは、IPv4 アドレスしか持たないホストを指定した時に gethostbyname() 関数によって自動的に生成される(6.1 に記述されている)。 アプリケーションは、単に終点の IPv4 アドレスをIPv4 射影 IPv6 アドレスと してエンコードして、connect() や sendto() コールの中で sockaddr_in6 構造体 の中でそのアドレスを通すことによって、IPv4 ノードに TCP コネクションを オープンするためやIPv4 ノードに UDP パケットを送るために PF_INET6 ソケットを使うだろう。アプリケーションが IPv4 ノードからの TCP コネクションを accept するためや IPv4 ノードからの UDP パケットを受け 取るために PF_INET6 を使う時、システムは accept(), recvfrom() や getpeername() コールにおいてこの方法でエンコードされた sockaddr_in6 を 用いて peer アドレスをアプリケーションに返す。 いくつかのアプリケーションは、多分相互動作しているノードがどのタイプか 知る必要があるだろう。しかし、それを知りたいそれらのアプリケーションに 対して、6.6 節で定義される IN6_IS_ADDR_V4MAPPED() マクロが用意されている。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 9] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 3.8 ワイルドカードアドレス bind() 関数は、アプリケーションが UDP パケットや TCP コネクションの 始点 IP アドレスを選ぶことを許している。アプリケーションはシステムに彼ら の始点アドレスを選ばせたがる。IPv4 では、bind() コールや単に bind() 全て を省略すると、一つのアドレスが、(ワイルドカードアドレスと呼ばれる) シンボル定数 INADDR_ANY として明確にされていた。 IPv6 アドレスタイプは構造体 (struct in6_addr) なので、シンボル定数は IPv6 アドレス変数を初期化に使うことはできたが、割り当てに使うことは出来ない。 それゆえにシステムは二つの形式で IPv6 ワイルドカードアドレスを提供する。 最初のバージョンは、in6_addr 構造体の "in6addr_any" という名前の グローバル変数である。この変数の外部宣言は で定義されている: extern const struct in6_addr in6addr_any; アプリケーションは、IPv4 で INADDR_ANY を使うのと同じ方法で in6addr_any を使う。例えば、始点アドレスをシステムに選ばせて、ポート番号23にソケットを バインドしたい場合は、アプリケーションは以下のコードを使うことができる: struct sockaddr_in6 sin6; . . . sin6.sin6_family = AF_INET6; sin6.sin6_flowinfo = 0; sin6.sin6_port = htons(23); sin6.sin6_addr = in6addr_any; /* 構造体の代入 */ . . . if (bind(s, (struct sockaddr *) &sin6, sizeof(sin6)) == -1) . . . 別のバージョンは、IN6ADDR_ANY_INIT という名前のシンボル定数で、 で定義されている。この定数は、in6_addr 構造体の初期化に 使うことができる: struct in6_addr anyaddr = IN6ADDR_ANY_INIT; この定数は、宣言時に*しか*使うことが出来ないことに注意せよ。これは、 既に宣言された in6_addr 構造体に対して割り当てることはできない。 例えば、次のコードは動かないだろう: /* これは未指定アドレスを代入する*誤った*方法である */ struct sockaddr_in6 sin6; . . . sin6.sin6_addr = IN6ADDR_ANY_INIT; /* コンパイル*できない*だろう */ IPv4 の INADDR_xxx 定数は全てホストバイトオーダで定義されていたが、 IPv6 の IN6ADDR_xxx 定数と IPv6 の in6addr_xxx 外部宣言は、ネットワーク バイトオーダで定義されていることに注意せよ。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 10] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 3.9 IPv6 ループバックアドレス アプリケーションは、ローカルノードに備わっているサービスに UDP パケット を送ったり、TCP コネクションを張ったりする必要があるだろう。IPv4 では、 connect(), sendto() や sendmsg() コール中で IPv4 アドレス定数 INADDR_LOOPBACK を使うことで、これをしてきた。 IPv6 にもローカルの TCP や UDP サービスにコンタクトするためのループ バックアドレスが用意されている。未指定アドレスのように IPv6 ループバック アドレスは二つの形式が用意されており、それらはグローバル変数とシンボル 定数である。 グローバル変数は、"in6addr_loopback" という名前の in6_addr 構造体である。 この変数の外部宣言は で定義されている: extern const struct in6_addr in6addr_loopback; アプリケーションは、IPv4 で INADDR_LOOPBACK を使っていたように in6addr_loopback を使う(しかし、前節の終わりで述べたバイトオーダの違いに 注意せよ)。例えば、ローカルの telnet サーバに TCP コネクションを張るため に、アプリケーションは以下のコードを使うことが出来る: struct sockaddr_in6 sin6; . . . sin6.sin6_family = AF_INET6; sin6.sin6_flowinfo = 0; sin6.sin6_port = htons(23); sin6.sin6_addr = in6addr_loopback; /* 構造体の代入 */ . . . if (connect(s, (struct sockaddr *) &sin6, sizeof(sin6)) == -1) . . . シンボル定数は、IN6ADDR_LOOPBACK_INIT という名前で、 で 定義されている。これは、宣言時*しか*使うことができない。例えば: struct in6_addr loopbackaddr = IN6ADDR_LOOPBACK_INIT; IN6ADDR_ANY_INIT のように、この定数は前に宣言された IPv6 アドレス変数への 割り当てでは使うことが出来ない。 3.10 移植性の追加 アプリケーション制作者を助けるためのソケット API への簡単な追加は、 struct sockaddr_storage である。この構造体で複数のアドレスファミリや プラットフォーム間で移植性のあるコードを書くことができる。この構造体は 次のような目的で設計された。 - 要求されたプロトコルに固有のソケットアドレス構造体を格納するのに 十分な実装固有の最大サイズを持っている?。特に、少なくとも sockaddr_in と sockaddr_in6 と他のプロトコル特有のソケットアドレスへの適応には十分な 大きさである。 - 適当な境界で整列されているので、プロトコル特有のソケットアドレス 構造体へのポインタはそれにキャストすることができ、境界を問題にする ことなくアクセスすることができる。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 11] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 - これは、使われているプロトコルの由来を決定するために使われうる、 実装における "struct sockaddr" データ構造のフィールドと同形の初期的 フィールドをもつ。 これらの初期的フィールドは、ほとんどの実装では "sa_family_t" 型の 一つのフィールド(sa_family フィールドと同形、16ビット)か、 それぞれ uint8_t と sa_family_t 型の2つのフィールド(sa_len と sa_family_t と同形、それぞれ8ビット)だろう。 これらのデータ構造体の実装案の例は次のようになるだろう。 /* * 最大長と整列に望まれる設計 */ #define _SS_MAXSIZE 128 /* 実装依存な最大長 */ #define _SS_ALIGNSIZE (sizeof (int64_t)) /* 実装依存で要求された境界 */ /* * sockaddr_storage 構造体のパディング設計に使われる定義 */ #define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (sa_family_t)) #define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (sa_family_t)+ _SS_PAD1SIZE + _SS_ALIGNSIZE)) struct sockaddr_storage { sa_family_t __ss_family; /* アドレスファミリ */ /* 次のフィールドは実装固有 */ char __ss_pad1[_SS_PAD1SIZE]; /* 6 バイトパッド, これはデータ構造中明示的に続く */ /* パッドまでの実装依存なパッドを作るためである */ int64_t __ss_align; /* 保持構造に望まれる境界を強制するための */ /* フィールド */ char __ss_pad2[_SS_PAD2SIZE]; /* 望まれるサイズまでの 112 バイトのパッド */ /* _SS_MAXSIZE 値 引く ss_family のサイズ, */ /* __ss_pad1, __ss_align フィールドは 112 */ }; sockaddrデータ構造体に "sa_len" を含む実装では、そのデータ構造体の フィールドは次のようになるだろう。 /* * 最大長と整列に望まれる設計 */ #define _SS_MAXSIZE 128 /* 実装依存な最大長 */ #define _SS_ALIGNSIZE (sizeof (int64_t)) /* 実装依存で要求された境界 */ /* * sockaddr_storage 構造体のパディング設計に使われる定義 */ #define _SS_PAD1SIZE (_SS_ALIGNSIZE - (sizeof (uint8_t) + sizeof (sa_family_t)) #define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (sa_family_t)+ _SS_PAD1SIZE + _SS_ALIGNSIZE)) struct sockaddr_storage { uint8_t __ss_len /* アドレス長 */ sa_family_t __ss_family; /* アドレスファミリ */ /* 次のフィールドは実装固有 */ char __ss_pad1[_SS_PAD1SIZE]; /* 6 バイトパッド, これはデータ構造中明示的に続く */ /* パッドまでの実装依存なパッドを作るためである */ int64_t __ss_align; /* 保持構造に望まれる境界を強制するための */ draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 12] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 /* フィールド */ char __ss_pad2[_SS_PAD2SIZE]; /* 望まれるサイズまでの 112 バイトのパッド */ /* _SS_MAXSIZE 値 引く ss_len, ss_family, */ /* __ss_pad1, __ss_align フィールドのサイズは 112 */ }; 上の例は64ビット境界で整列するデータ構造体を示している。実装固有な フィールド "__ss_pad1" に続く "__ss_align" は、sockaddr_in6 (IPv6) や sockaddr_in (IPv4) アドレスデータ構造に十分適切な 64 ビット境界を 強制するために用いられている。パディングフィールド __ss_pad1 の 大きさは選ばれた整列境界に依存する。パディングフィールド __ss_pad2 の 大きさは、この構造体の全体の大きさとして選ばれた全部の大きさに依存する。 この大きさと整列は上の例では実装固有の(必須でない)定数 _SS_MAXSIZE (選定値 128) と _SS_ALIGNMENT (選定値 8)として示されている。定数 _SS_PAD1SIZE (計算値 6)と _SS_PAD2SIZE (計算値 112) もまた図示のためで あり、必須ではない。上でアンダースコアで始まる実装固有の定義と構造体 フィールド名は実装だけの名前空間であることを示す。移植可能なコードは それらのフィールドや定数にアクセスしたり参照したりすることは期待されて いない。 sockaddr_storage 構造体は、どのようなファミリのソケットアドレス構造体を 格納するにしても十分大きく整列されている格納用自動変数を宣言する際の 問題を解決する。例えば、ファイルディスクリプタだけあってアドレス ファミリの文脈のないコードが、getpeername() のような呼び出しでソケット アドレス構造体へのポインタが期待されているところでこの変数へのポインタを 渡し、呼出し後、得られた内容にアクセスすることでアドレスファミリを決定 することができる。 sockaddr_storage は、いくつものアドレスファミリでの使用が必要とされる かもしれない十分に大きく整列した一般的なソケットアドレスのところの いくつかの他のインタフェース有用で、適用されるかもしれない。それらの インタフェースについての議論はこの文書の範囲外である。 また、多くの既存のコードがどんなソケットアドレス構造も一般の sockaddr 構造におさまるとみなしている。これは IPv4 ソケット構造体には正しかったが、 Unix ドメインソケットに対してはいつも正しくなかった(ただし実際問題として これは問題にはなってこなかった)し、IPv6 ソケットアドレス構造体でも 正しくない(これは問題になりうる)。 というわけで、ついにアプリケーションは次のようにできる: struct sockaddr_storage __ss; struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *) &__ss; 4. インターフェイス識別子 この API は、マルチキャストグループに加えられているローカルインタフェースを 識別するためにインターフェイスインデックス (小さな正の整数値)を使う(5.3節)。 それに加えて、高度な API [4] は同じインターフェイスインデックスを、データ グラムが受け取られたインターフェイスを識別するためや、データグラムが送られる draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 13] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 インターフェイスを指定するために使う。 インターフェイスは普通 "le0", "sl1", "ppp2" などのような名前で知られて いる。バークレイ派の実装では、インターフェイスがシステムに知らされた時、 カーネルが、そのインターフェイスに対して (インターフェイスインデックスと 呼ばれる) ユニークな正の整数値を割り当てる。それらは1から始まる小さな正の 整数値である。(0はインターフェイスインデックスには決して使われないことに 注意。)特定の正のインデックスに対して現在のインタフェースがないために それは間があくかもしれない。 この API は、インターフェイス名とインデックスとの間をマップする二つの 関数、全てのインターフェイス名とインデックスを返す三つ目の関数、それを 動的に確保されたメモリで返す四つ目の関数を定義している。どのようにして これらの関数が実装されるかは、実装による(?)。 4.4BSD の実装は、存在している sysctl() 関数に NET_RT_IFLIST コマンドを | 使ってこれらの関数を実装できる。他の実装は、この方法のために ioctl() を 使うことを望むかも知れない。 4.1 名前からインデックス 最初の関数は、インターフェイス名をそれに一致するインデックスに写像する。 #include unsigned int if_nametoindex(const char *ifname); もし指定されたインターフェイスが存在しなければ、戻り値は 0 で、errnoには ENXIOがセットされる。もし(実行時のメモリ不足のような)システムエラーなら、 戻り値0でerrnoには適当な値がセットされる(例えばENOMEM)。 4.2 インデックスから名前 二つ目の関数は、インターフェイスインデックスをそれに一致する名前に写像する。 #include char *if_indextoname(unsigned int ifindex, char *ifname); ifname 引数は、指定されたインデックスに一致するインターフェイス名が返 されるための少なくとも IF_NAMESIZE バイトのバッファを指していなければなら ない。(IF_NAMESIZE も で定義されていて、その内容はインターフェ イス名の最後がヌルバイトで終わっている)。 このポインタは関数の戻り値で もある。指定されたインデックスに一致するインターフェイスがなければ、 NULL が返される。そして、もし(実行時メモリ不足のような)システムエラー ならerrnoにはENXIOがセットされる。if_indextoname はNULLを返し、errnoに は適当な値(例えばENOMEM)がセットされるだろう。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 14] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 4.3 全てのインターフェイス名とインデックスの返却 if_nameindex 構造体は、一つのインターフェイスについての情報を持っており、 それは ヘッダをインクルードした結果定義される。 struct if_nameindex { unsigned int if_index; /* 1, 2, ... */ char *if_name; /* null 終端名: "le0", ... */ }; 最後の関数は、if_nameindex 構造体の配列を返す。一つのインターフェイスに つき、一つの構造体である。 struct if_nameindex *if_nameindex(void); 構造体の配列の最後は、if_index が 0 で if_name が NULL の構造体によって 示される。エラーが起きるとNULLポインタを返し、errnoには適当な値がセット されるだろう。 if_nameメンバによって指されるインターフェイス名と一緒にこの構造体の配列に よって使われるメモリは、動的に確保されている。このメモリは次の関数によって 解放される。 4.4 メモリ解放 次の関数は if_nameindex() で確保した動的メモリを解放する。 #include void if_freenameindex(struct if_nameindex *ptr); この関数への引数は if_nameindex() で返されるポインタでなければならない。 現在のところ、net/if.hには関数のプロトタイプ宣言はないが、if_nameindex{} 構造体と同様、これらの宣言はnet/if.hで宣言されることが推奨される。 5. ソケットオプション いくつかの新しいソケットオプションが IPv6 用に定義された。これらの 全ての新しいオプションは IPPROTO_IPV6 レベルである。すなわち、これらの オプションが使われる時の getsockopt() と setsockopt() コールの "レベル" パラメータは IPPROTO_IPV6 である。定数名プレフィックス IPV6_ は全ての 新しいソケットオプションで使われる。これは IPv6 に適用するときに 明らかにこれらのオプションを識別するのに役立つ(?)。 この章で定義されている IPPROTO_IPV6 の宣言、新しい IPv6 ソケット オプションと、関係する定数は、 ヘッダをインクルードする ことによって得られる。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 15] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 5.1 ユニキャスト中継点限界数 新しい setsockopt() オプションは、出ていくユニキャスト IPv6 パケットに 使われている中継点限界数を制御する。このオプションの名前は IPV6_UNICAST_HOPS で、IPPROTO_IPV6 層で使われる。次の例は使い方を 示している: int hoplimit = 10; if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &hoplimit, sizeof(hoplimit)) == -1) perror("setsockopt IPV6_UNICAST_HOPS"); setsockopt() で IPV6_UNICAST_HOPS オプションがセットされると、与えられた オプションの値は、ソケットを通して送られるその後の全てのユニキャスト パケットの中継点限界数として使われる。もしオプションがセットされなければ、 システムはデフォルト値を選ぶ。整数の中継点限界数(ここでは x) は次のよう に解釈される: x < -1: エラーEINVALを返す x == -1: カーネル既定値を使用 0 <= x <= 255: xを使用 x >= 256: エラーEINVALを返す IPV6_UNICAST_HOPS オプションは getsockopt() で、その後のソケットを 通して送られるユニキャストパケットの中継点限界数をシステムが決定する のに使われるだろう。例えば: int hoplimit; size_t len = sizeof(hoplimit); if (getsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &hoplimit, &len) == -1) perror("getsockopt IPV6_UNICAST_HOPS"); else printf("Using %d for hop limit.\n", hoplimit); 5.2 マルチキャストパケットの送受信 IPv6 アプリケーションは、sendto() 関数のアドレス引数にIPv6 マルチ キャストアドレスを指定するだけで、UDP マルチキャストパケットを送るだろう。 IPPROTO_IPV6 層の三つのソケットオプションは、マルチキャストパケットを 送る際のいくつかのパラメータを制御する。これらのオプションを設定すること は要求されていない。アプリケーションはこれらのオプションを使わずにマルチ キャストパケットを送ってもよい。マルチキャストパケットの送信を制御する setsockopt() のオプションは、以下で要約されている。これら三つのオプション | は getsockopt() でも使うことが出来る。 IPV6_MULTICAST_IF マルチキャストパケットが出ていくようにインターフェイスを設定する。 引数は、使うインターフェイスのインデックスである。 引数の型: unsigned int draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 16] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 IPV6_MULTICAST_HOPS 出ていくマルチキャストパケットの中継点限界数を設定する (別の オプション - IPV6_UNICAST_HOPS - が出ていくユニキャストパケットの 中継点限界数を設定するために用意されていることに注意せよ)。引数の 解釈は、IPV6_UNICAST_HOPS オプションと同様である。 x < -1: エラーEINVALを返す x == -1: カーネル既定値を使用 0 <= x <= 255: xを使用 x >= 256: エラーEINVALを返す If IPV6_MULTICAST_HOPS がセットされなかったら、既定値は 1 (今の IPv4 と同様)。 引数の型: int IPV6_MULTICAST_LOOP マルチキャストデータグラムが、それを送ったホスト自身が加わって いるグループに送られた時、もしこのオプションが1にセットされて いれば、そのデータグラムのコピーはローカル配送のためにIP層によって ループバックされる。もし、このオプションが0にセットされれば、 コピーはループバックしない。他のオプション値はEINVALのエラーを 返す。 もし、IPV6_MULTICAST_LOOPがセットされてなければ、デフォルトは1 (ループバック; 現在のIPv4と同じ)である。 引数の型: unsigned int マルチキャストパケットの受信は、以下で要約される二つの setsockopt() の オプションで制御される。getsockopt() でこれら二つのオプションが 使用されると EOPNOTSUPP のエラーが返される。 IPV6_JOIN_GROUP 指定したローカルインターフェイスでマルチキャストグループに参加する。 もしインターフェイス識別子に0が指定されると、カーネルはローカル インターフェイスを選ぶ。例えばいくつかのカーネルは、通常のIPv6 経路制御表の中からマルチキャストグループを探し、その結果のインタ フェースを使う。 引数の型: struct ipv6_mreq IPV6_LEAVE_GROUP 指定されたインターフェイスのマルチキャストグループから離脱する。 Argument type: struct ipv6_mreq これらのオプションの両方の引数型は ipv6_mreq 構造体であり、 ヘッダのインクルードの結果定義される: struct ipv6_mreq { struct in6_addr ipv6mr_multiaddr; /* IPv6 マルチキャストアドレス */ draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 17] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 unsigned int ipv6mr_interface; /* インタフェース番号 */ }; プロセスは、マルチキャストデータグラムを受け取るために、マルチキャスト グループに加わり、データグラムが送られるであろう UDP ポートにバインド する必要がある。いくつかのプロセスはまた、ソケットの同じポートに届けら れた他のデータグラムを受け取るのを防ぐために、ポートに加えてマルチ キャストグループアドレスにもソケットをバインドする。 6. ライブラリ関数 IPv6 アドレスの各種操作をするために、新しいライブラリ関数が必要である。 関数は、ドメインネームシステム(DNS) で IPv6 アドレスを検索するのに必要で ある。正引き (ノード名からアドレスへの変換)と逆引き(アドレスからノード名 への変換) の両方がサポートされる必要がある。関数はまた、バイナリと テキスト形式との間で IPv6 アドレスを変換する必要がある。 我々は二つの関数 gethostbyname() と gethostbyaddr() がそのまま残る ことに注意しなければならない。IPv4 と IPv6 の両方のアドレスを扱うために 新しい関数が定義された。 6.1 ノード名からアドレス変換 共通に使われてきた関数 gethostbyname() は、多くのアプリケーションに とって不十分である。一つ目の理由は、呼び出し側が要求するアドレスタイプ について指定する方法が用意されていないこと (IPv4 だけ、IPv6 だけ、IPv4 射影 IPv6 なら OK など)。そして二つ目は、この関数の多くの実装は、thread safeではない。RFC2133 は、gethostbyname2() という名前の関数を定義したが、 この関数も不十分である。その一つ目の理由は、IPv6 アドレスが要求された時、 グローバルオプション(RES_USE_INET6) の設定が要求されること。二つ目は、 必要とされるアドレスの型を越えた制御を呼出側で行なうためのフラグ引数が 必要とされていることである。 次の関数は新しい。そして、thread safe でなければならない。 #include #include struct hostent *getipnodebyname(const char *name, int af, int flags int *error_num); name 引き数は、ノード名か数字のアドレス文字(即ちドット表記の10進数 IPv4 アドレスや IPv6 の16進数アドレス) のどちらかを取ることができる。 af 引き数は、AF_INET か AF_INET6 かどちらかのアドレスファミリを指定する。 error_numの値は、thread safeなエラーコード返却をサポートするために、 適当なエラーコードがポインタを通じて呼び出し元に返される。error_numには 次の値のうちの一つがセットされるだろう。 HOST_NOT_FOUND そのようはホストは知らない。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 18] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 NO_ADDRESS サーバは要求と名前を認識したが、アドレスがない。このドメインの サーバに対する他の型の要求は答が返ってくるかもしれない。 NO_RECOVERY 予期せぬ回復不可能な失敗が発生した。 TRY_AGAIN サーバの応答が失敗した等のたぶん一時的なエラーが起きた。 flags 引き数は、検索され、また、返されるるアドレスのタイプを示す。 我々は、(以下で定義される) AI_DEFAULT という特殊な flags の値が 多くのアプリケーションで操作されるべきであることに注意する。 即ち、IPv6 を使うための簡単なアプリケーションの移植は hptr = gethostbyname(name); という呼出を hptr = getipnodebyname(name, AF_INET6, AI_DEFAULT, &error_num); で置き換え、関連するエラー診断コードを、h_errno といった外部宣言変数の かわりに error_num に置換することである。 検索される、また返されるアドレス型を通じてよりよい制御を必要とする アプリケーションは、別の flags 引き数の組合せを指定することができる。 flags における 0 は、af 引き数の厳密な解釈を意味する。 - もし flags が 0 で af が AF_INET なら、呼び出し元は IPv4 アドレス だけを求めている。問い合わせは A レコードに対して行なわれる。もし 成功すれば、IPv4 アドレスが返され、hostent 構造体の h_length メンバは 4 になるだろう。そうでなければ、関数は NULL ポインタを返す。 - もし、flags が 0 で、af が AF_INET6 なら、呼び出し元は、IPv6 アドレスだけを求めている。問い合わせは AAAA レコードに対して 行なわれる。もし成功すれば、IPv6 アドレスが返され、hostent 構造体の h_length メンバは 16 になるだろう。そうでなければ、関数は NULL を返す。 他の定数は、関数の振る舞いを修正するために、flags 引き数に OR(論理和)を とることが出来る。 - もし、AF_INET6 の af に AI_V4MAPPED フラグが指定されたら、呼び出し 元は、IPv4 射影 IPv6 アドレスを受け入れるだろう。即ち、もしAAAA レコードが見つからなければ、問い合わせは A レコードで行なわれ、 見つかれば IPv4 射影 IPv6 アドレスで返される(h_length は 16 になる だろう)。AI_V4MAPPED フラグは、af がAF_INET6 でない限り無視される。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 19] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 - AI_ALL フラグは AI_V4MAPPED フラグと連結して使われる。そしてそれは IPv6アドレスファミリでのみ使われる。AI_ALL が AI_V4MAPPED フラグとの 論理和をとられると、呼び出し元はIPv6とIPv4射影IPv6アドレスの全ての アドレスを要求している。問い合わせは最初AAAAレコードで行なわれ、 成功すればIPv6アドレスが返される。それから他の問い合わせがAレコードで 行なわれ、見つかればIPv4射影IPv6アドレスで返される。h_length は 16 となる。この両方の問い合わせが失敗した時だけ関数はNULLポインタを 返す。このフラグはafが AF_INET6 でないかぎり無視される。 - AI_ADDRCONFIG フラグは、もしノードが少なくとも一つの設定されたIPv6 始点アドレスを持っていれば AAAA レコードで問い合わせるべきであり、 もしノードが少なくとも一つの設定された IPv4 始点アドレスを持って いれば A レコードで問い合わせるべきである、ということを指定する。 例えば、ノードが設定された IPv6 始点アドレスを持っていなくて、 af が AF_INET6 に等しく、そして、ノード名は AAAA と A レコードの 両方で探されるようになっているなら、 (a) もし AI_ADDRCONFIGだけが指定されれば、関数はNULLポインタを返し、 (b) もし AI_ADDRCONFIG | AI_V4MAPPED が指定されれば、Aレコードが IPv4射影IPv6アドレスとして返される 特別なフラグ値 AI_DEFAULT が次のように定義される #define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG) 我々は、getnodebyname() 関数が name 引き数にノード名かリテラルなアドレス 文字(即ちドット表記の10進数 IPv4 アドレスやIPv6 の16進数アドレス)を 許さなければならないことに注意している。これにより、アプリケーションは アドレス文字を処理するために inet_pton() を呼ぶ必要がなくなる。 アドレス文字のタイプと af 引き数の値によって4つのシナリオがある。 2つの簡単な場合は: name がドット表記のIPv4アドレスで af が AF_INET であるか、name が IPv6 16進数 アドレスで af が AF_INET6 である時である。返される hostent 構造体のメンバは 次の通りである。h_name は name 引き数のコピーを指し、h_aliases は NULL ポインタである。h_addrtype は af 引き数のコピーであり、h_length は 4 (AF_INET) か 16(AF_INET6) かのどちらかである。h_addr_list[0] は、4バイトか 16バイトのバイナリアドレスへのポインタで、h_addr_list[1] は NULL ポインタで ある。 name 引き数が、ドット表記の10進数 IPv4 アドレスで、af が AF_INET6 で flags が AI_V4MAPPEDであるなら、IPv4 射影 IPv6 アドレスが返される。h_name はIPv4射影 IPv6アドレスを含んだ IPv6 16進数アドレスを指し、h_aliases は NULL ポインタで ある。h_addrtype は AF_INET6 であり、h_length は 16、h_addr_list[0]は、 16バイトのバイナリアドレスへのポインタで、h_addr_list[1] は NULLポインタで ある。もし(AI_ALLに関係なく) AI_V4MAPPED がセットされていれば、IPv4射影IPv6 アドレスが、さもなくば NULL が返る。 name が IPv6 16進数アドレスで af が AF_INET であるならエラーになる。この 関数の戻り値は、NULL ポインタで、h_errno は HOST_NOT_FOUND になる。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 20] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 6.2 アドレスからノード名変換 次の関数は、今ある gethostbyaddr() 関数と同じ引数を持つが、エラー番号が 加わっている。 #include #include struct hostent *getipnodebyaddr(const void *src, size_t len, int af, int *error_num); getipnodebyname() と同様、getipnodebyaddr() は thread safe でなければ ならない。thread safeなエラーコード返却をサポートするために、error_num の 値は適当なエラーコードを持って呼出元に返される。error_num によって次の エラーの状況が返されるかも知れない: HOST_NOT_FOUND そのようはホストは知らない。 NO_ADDRESS サーバは要求と名前を認識したが、アドレスがない。このドメインの サーバに対する他の型の要求は答が返ってくるかもしれない。 NO_RECOVERY 予期せぬ回復不可能な失敗が発生した。 TRY_AGAIN サーバの応答が失敗した等のたぶん一時的なエラーが起きた。 混乱の元になりそうなのが、IPv4射影IPv6アドレスとIPv4互換IPv6アドレスの扱い であるが、次の論理が適用されるべきである。 1. もし af が AF_INET6 で、len が 16 で、IPv6 アドレスが IPv4射影 IPv6 アドレスか IPv4互換IPv6 アドレスであるなら、IPv6 アドレスの最初の 12バイトをスキップし、af に AF_INET を、len に 4 をセットする。 2. もし af が AF_INET なら、与えられた IPv4 アドレスに対する名前を検索 する(例えば、in-addr.apra ドメインの PTR レコードに対する問い合わせ)。 3. もし af が AF_INET6 なら、与えられた IPv6 アドレスに対する名前を検索 する(例えば、ip6.int ドメインの PTR レコードに対する問い合わせ)。 4. もし関数が成功を返すときは、返される hostent 構造体に一つだけ 含まれるアドレスは、この関数への引数としてわたされたアドレスファミリ と同一のアドレスファミリを伴う、最初の引数としてとして渡された アドレスのコピーである。 リストした4つ全てのステップは、順番に実行される。IPv6の16進数アドレス "::" と "::1" はIPv4互換IPv6アドレスとして扱われてはならならず、もし、アドレスが draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 21] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 "::" なら、HOST_NOT_FOUNDが返され、このアドレスの問い合わせは実行されない ことに注意せよ。 6.7節のマクロ IN6_IS_ADDR_V4COMPAT もまた "::" と "::1" に対して失敗を 返さなければならない。 6.3 Freeing memory for getipnodebyname and getipnodebyaddr hostent構造体は今ある定義から変更されていない。この構造体とこの構造体に よって示される情報は、getipnodebyname と getipnodebyaddr によって動的に 確保される。次の関数はこのメモリを解放する: #include void freehostent(struct hostent *ptr); 6.4 プロトコル非依存のノード名からサービス名変換 ノード名-アドレス変換は、電気電子技術者協会 (IEEE) POSIX 1003.1g (プロトコル非依存インターフェイス) ドラフト仕様書 [3] で選ばれた getaddrinfo() 関数を使ったプロトコル非依存の方法で行なわれる。 この関数についての公式の仕様が、次の付加的な要求を伴い、最新の POSIX 標準となるだろう: - (次の節で記される getnameinfo() 関数に従って) getaddrinfo() は thread safe でなければならない。 - AI_NUMERICHOST はこの文書で新しい。 - getaddrinfo() で返されるソケットアドレス構造体の明白な引き数によって 埋められていない全てのフィールド (例えば sin6_flowinfo と sin_zero) は、0 に設定されなければならない。(これは、ソケットアドレス構造体の 比較を容易にする。) - getaddrinfo() は、ソケットアドレス構造体の長さのフィールド(例えば sin6_len) をサポートしているシステム上では、これを埋めなければなら ない。 (IETF文書と同様)POSIX 標準が自由に入手できないので、我々は関数の独立な 記述を用意する。 #include #include int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); addrinfo 構造体は、 ヘッダをインクルードした結果として定義される。 struct addrinfo { draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 22] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 または IPv4又はIPv6には IPPROTO_xxx */ size_t ai_addrlen; /* ai_addr の長さ */ char *ai_canonname; /* nodename の規準名 */ struct sockaddr *ai_addr; /* バイナリアドレス */ struct addrinfo *ai_next; /* リンクリスト中の次構造体 */ }; この関数からの戻り値は 0 が成功で、非 0 がエラーコードである。次の名前 は getaddrinfo() からの非ゼロのエラーコードで で定義されている: EAI_ADDRFAMILY nodename のアドレスファミリはサポートされていない EAI_AGAIN 名前解決中の一時的失敗 EAI_BADFLAGS 不正な ai_flags 値 EAI_FAIL 名前解決中の回復不可能な失敗 EAI_FAMILY サポートされていない ai_family EAI_MEMORY メモリ確保失敗 EAI_NODATA nodename に関係するアドレスがない EAI_NONAME nodename も servname 与えられていないか、わからない EAI_SERVICE servname が ai_socktype に対してサポートされていない EAI_SOCKTYPE ai_socktype はサポートされていない EAI_SYSTEM システムエラーが errno に返された nodename と servname 引き数は、ヌルで終端する文字列か NULL へのポインタで ある。これら二つの引き数のうち一つか両方かは、非 NULL ポインタでなければ ならない。普通のクライアントの筋書きでは nodename と servname の両方が 指定される。普通のサーバの筋書きでは、 servname だけが指定される。NULL で ない nodename の文字列は、ノード名か数字のホストアドレス文字列 (即ち ドット表記の10進数 IPv4 アドレスかIPv6 16進数アドレス)である。NULL でない servname の文字列は、サービス名か10進数のポート番号のどちらかに できる。 呼び出し元は、呼び出し元がサポートしているソケットタイプに関係する hints を 提供するために3つ目の引き数によって指される addrinfo 構造体を自由に通過 させることが出来る?。この hints 構造体の ai_flags, ai_family, ai_socktype そして ai_protocol 以外のメンバは、ゼロもしくは NULL ポインタでなければ ならない。ai_family の PF_UNSPEC の値は、呼び出し元がどのようなプロトコル ファミリも受け入れることを意味する。ai_socktype の値が 0 というのは、呼び 出し元がどのようなソケットタイプも受け入れることを意味する。ai_protocol の値が 0 というのは、呼び出し元がどのようなプロトコルも受け入れることを 意味する。例えば、もし呼び出し元が TCP だけ処理して UDP を処理しないなら、 getaddrinfo() が呼ばれる時 hints 構造体の ai_socktype メンバは、 SOCK_STREAM に設定されるべきである。もし呼び出し元が IPv4 だけ処理して IPv6 を処理しないなら、hints 構造体の ai_family メンバは、getaddrinfo() が呼ばれる時、PF_INET に設定されるべきである。もし getaddrinfo() への3つ 目の引き数が NULL ポインタなら、ai_family を PF_UNSPEC にセットして addrinfo 構造体をゼロで初期化するのと同じである。 成功すると、一つかそれ以上の addrinfo 構造体のリンクリストへのポインタが、 最後の引き数によって返される。呼び出し元は、NULL ポインタに出会うまで ai_next ポインタを辿ることで、このリストのそれぞれの addrinfo 構造体を 処理できる。それぞれの返された addrinfo 構造体の ai_family、ai_socktype そして、ai_protocol は socket() 関数の呼び出すのに一致した引き数である。 それぞれの addrinfo 構造体の ai_addr メンバは、長さが ai_addrlen メンバに draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 23] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 よって示されているソケットアドレス構造体を指し示す。 もし hints 構造体の ai_flags メンバの AI_PASSIVE ビットが立っているなら、 呼び出し元は、返されるソケットアドレス構造体を bind() コールに使う計画を 立てている。この場合、もし nodename 引数が NULL ポインタなら、ソケット アドレス構造体の IP アドレスの部分は、IPv4 アドレスなら INADDR_ANY、IPv6 アドレスなら IN6ADDR_ANY_INIT がセットされるだろう。 もし hints 構造体の ai_flags メンバの AI_PASSIVE ビットが立っていない なら、返されたソケットアドレス構造体は connect() (コネクション指向 プロトコル) か、connect()、sendto()、sendmsg() のどれか (コネクション レスプロトコル) をコールする用意が出来ているだろう。この場合、nodename 引数が NULL ポインタであるなら、ソケットアドレス構造体の IP アドレスの 部分はループバックアドレスがセットされるだろう。 もし hints 構造体の ai_flags メンバの AI_CANONNAME ビットが立って いたら、リンクリストの最初の addrinfo 構造体の ai_canonname メンバの 成功した戻り値は、指定された nodename の正式な名前をもつヌルで終端する 文字列を指すだろう。 もし hints 構造体の ai_flags メンバの AI_NUMERICHOST ビットが立って いたら、NULL でない nodename 文字列は、数値のホストアドレス文字列で なければならない。そうでなければ、 EAI_NONAME エラーが返される。この フラグは、あらゆる名前検索サービス(例えばDNS)が呼ばれるのを防ぐ。 addrinfo 構造体、addrinfo 構造体から示されるソケットアドレス構造体や 正式なノード名文字列などの getaddrinfo() で返される全ての情報は、動的に 確保されている。システムにこの情報を返すために、関数 freeaddrinfo() が 呼ばれる: #include #include void freeaddrinfo(struct addrinfo *ai); ai 引数によって示される addrinfo 構造体とその構造体によって示される全ての 動的な記憶は、解放される。この操作は、NULL の ai_next ポインタに出会うまで 繰り返される。 getaddrinfo() によって返される EAI_xxx コードを基にしたエラーメッセージを アプリケーションが表示するのを助けるために、次の関数が定義された。 #include #include char *gai_strerror(int ecode); 引数は、前に定義された EAI_xxx のうちの一つで、戻り値は、エラーが記述 されている文字列を指し示している。もし、引数が EAI_xxx のうちの一つで ないなら、関数は未知のエラーを示す文字列を指すポインタを返す。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 24] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 6.5 ソケットアドレス構造体からノード名とサービス名 POSIX 1003.1g 仕様書は、getaddrinfo() の逆変換を行なう関数を含んで いない。バイナリアドレスとポートが与えられてノード名とサービス名を検索 する関数である。それゆえ、我々は次の関数を定義する: #include #include int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); この関数は、DNS やシステム特有のデータベースの呼び出し元によって用意 される IP アドレスとポート番号を検索する。そして、呼び出し元によって用意 されるバッファにテキスト文字列を返す。この関数は、戻り値 0 によって正常 終了したことを示し、非0 の戻り値が失敗を示す。 最初の引数 sa は IP アドレスとポート番号を持つ sockaddr_in 構造体 (IPv4用)か sockaddr_in6 構造体(IPv6用)かのどちからへのポインタである。 salen 引数は、sockaddr_in か sockaddr_in6 構造体の長さを与える。 関数は、host 引数で示されるバッファに IP アドレスで関連づけたノード名 を返す。呼び出し元は、hostlen 引数を通じてこのバッファのサイズを提供する。 ポート番号で関連付けされるサービス名は、serv で示されるバッファに返され、 servlen 引数は、このバッファの長さを与える。呼び出し元は、hostlen や servlen に0を与えることによってどちらかの文字列を返さないように指定する。 一方で、呼び出し元は、ノード名やサービス名を終端のヌル文字を含めて保持 するのに十分な大きさのバッファを用意しなければならない。 不幸にも多くのシステムは、完全なドメイン名やサービス名の最大サイズを 指定する定数を用意していない。それゆえ、アプリケーションがこれら二つの 返される文字列のためにバッファを確保するのを助けるために、次の定数が で定義された。 #define NI_MAXHOST 1025 #define NI_MAXSERV 32 最初の値は、実は最近のバージョンの BIND の ヘッダ (BIND の古いバージョンではこの定数は 256 として定義されていた)の中で MAXDNAME 定数として定義されていた。そして二つ目は、現在の Assigned Numbers RFC の中のサービスリストを元に推測されている。 最後の引数は、この関数のデフォルトの動作を変更するフラグである。 デフォルトでは、ホストの完全なドメイン名 (FQDN) は DNS で検索されて 返される。もしフラグの NI_NOFQDN ビットがセットされると、FQDN の ノード名の部分は、ローカルホストが返される。 もしフラグの NI_NUMERICHOST ビットがセットされるか、ホスト名が DNS に 存在しなかった場合は、名前の代わりとしてホストアドレスの数字表記が返される (例えば、getipnodebyaddr() の代わりに inet_ntop() が呼ばれる)。 もしフラグのNI_NAMEREQD ビットがセットされると、ホスト名が DNS に draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 25] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 存在しなかった場合はエラーが返される。 もしフラグの NI_NUMERICSERV ビットがセットされると、サービスアドレスの 数値形式が、その名前の代わりに返される(例えばそのポート番号)。二つの NI_NUMERICxxx フラグは、多くのコマンドで用意されている -n フラグを サポートすることが要求される。 5番目のフラグビット NI_DGRAM は、サービスがデータグラムサービスである ことを指定し、getservbyport() に二つ目の引数のデフォルトの "tcp" の代わり に "udp" でコールさせる。これは UDP と TCP でサービスが異なるいくつかの ポート(512-514)で要求される。 AI_xxx フラグはすでに getaddrinfo() のために定義されているのに加えて、 これらの NI_xxx フラグは の中で定義されている。 6.6 アドレス変換関数 2つの関数 inet_addr() と inet_ntoa() が IPv4 アドレスをバイナリと テキスト形式との間で変換する。IPv6 アプリケーションも同様の関数を 必要である。次の2つの関数は IPv6 と IPv4 アドレスを変換する: #include #include int inet_pton(int af, const char *src, void *dst); const char *inet_ntop(int af, const void *src, char *dst, size_t size); inet_pton() 関数は、アドレスを標準テキスト形式から、数値のバイナリ形式 に変換する。af 引数はアドレスファミリを指定する。現在では AF_INET と AF_INET6 アドレスファミリがサポートされている。src 引数は、通過させる 文字列を指し示している。dst 引数は、関数が数字のアドレスを格納するための バッファを指し示している。アドレスはネットワークバイトオーダで返される。 inet_pton() は変換に成功すれば 1 を返し、入力が正しい IPv4 ドット表記の 文字列か正しい IPv6 アドレス文字列でなかった場合は 0 を返す。また af 引数が未知のものなら EAFNOSUPPORT を errno にセットし -1 を返す。これを コールしたアプリケーションは、dst によって参照されるバッファが数字の アドレスを保持するのに十分な大きさ (AF_INET なら4バイト、AF_INET6 なら 16 バイト) であることを保証しなければならない。 もし af 引数が AF_INET なら、関数は、標準の IPv4 ドット表記の形式の 文字列を受け入れる: ddd.ddd.ddd.ddd ここで ddd は、一つの3桁の10進数で 0 から 255 までである。今ある多くの 実装の inet_addr() と inet_aton() 関数は、8進数や16進数、4つの数字より 少ないものといった標準でない入力を受け入れることに注意せよ。inet_pton() はこれらの形式を受け入れない。 もし af 引数が AF_INET6 なら、関数は アドレスアーキテクチャ仕様書[2] の 2.2 節で定義された IPv6 の標準テキスト形式のうちの一つの文字列を 受け入れる。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 26] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 inet_ntop() 関数は、数値のアドレスをその状態にふさわしいテキスト文字列 に変換する。af 引数はアドレスファミリを指定する。これは AF_INET か AF_INET6 のどちらかを取ることができる。src 引数は、af 引数が AF_INET の時は IPv4 アドレスを、af 引数が AF_INET6 の時は IPv6 アドレスを保持 するアドレスを指し示す。dst 引数は、関数が結果のテキスト文字列を格納する であろうバッファを指し示す。size 引数は、このバッファのサイズを指定する。 アプリケーションは、NULL でない dst 引数を指定しなければならない。IPv6 アドレスに対しては、バッファは少なくとも 46 オクテットでなければならない。 IPv4 アドレスに対しては、バッファは少なくとも 16 オクテットでなければ ならない。文字列形式の IPv4 や IPv6 アドレスを格納するのにふさわしい サイズのバッファをアプリケーションが簡単に宣言できるように、次の二つの 定数が で定義された。 #define INET_ADDRSTRLEN 16 #define INET6_ADDRSTRLEN 46 inet_ntop() 関数は、変換に成功すれば、テキスト文字列を含んだバッファへ のポインタを返し、それ以外では NULL を返す。失敗した場合は、af 引数が不正 なら errno に EAFNOSUPPORT が、結果のバッファサイズが不十分なら ENOSPEC がセットされる。 6.7 アドレス試験マクロ 以下のマクロが特殊な IPv6 アドレスの試験に使うことができる。 #include int IN6_IS_ADDR_UNSPECIFIED (const struct in6_addr *); int IN6_IS_ADDR_LOOPBACK (const struct in6_addr *); int IN6_IS_ADDR_MULTICAST (const struct in6_addr *); int IN6_IS_ADDR_LINKLOCAL (const struct in6_addr *); int IN6_IS_ADDR_SITELOCAL (const struct in6_addr *); int IN6_IS_ADDR_V4MAPPED (const struct in6_addr *); int IN6_IS_ADDR_V4COMPAT (const struct in6_addr *); int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *); int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *); int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *); int IN6_IS_ADDR_MC_ORGLOCAL (const struct in6_addr *); int IN6_IS_ADDR_MC_GLOBAL (const struct in6_addr *); 最初の7つのマクロは、アドレスが指定されたタイプなら真を返し、そうで なければ偽を返す。最後の5つは、マルチキャストアドレスのスコープをテストし、 アドレスが指定されたスコープのマルチキャストアドレスなら真、アドレスが マルチキャストアドレスでないか指定されたスコープでないなら偽を返す。 IN6_IS_ADDR_LINKLOCAL と IN6_IS_ADDR_SITELOCAL は、二つのローカルで 使用される IPv6 ユニキャストアドレスである時のみ真を返すことに注意せよ。 これら二つのマクロは、リンクローカルスコープかサイトローカルスコープの どちらかの IPv6 マルチキャストアドレスには真を返さない。 7. 新しい定義の概要 次のリストは、この文書で議論された定数、構造体、外部定義をヘッダごとに ソートして要約したものである。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 27] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 IF_NAMESIZE struct if_nameindex{}; AI_ADDRCONFIG AI_ALL AI_CANONNAME AI_NUMERICHOST AI_PASSIVE AI_V4MAPPED EAI_ADDRFAMILY EAI_AGAIN EAI_BADFLAGS EAI_FAIL EAI_FAMILY EAI_MEMORY EAI_NODATA EAI_NONAME EAI_SERVICE EAI_SOCKTYPE EAI_SYSTEM NI_DGRAM NI_MAXHOST NI_MAXSERV NI_NAMEREQD NI_NOFQDN NI_NUMERICHOST NI_NUMERICSERV struct addrinfo{}; IN6ADDR_ANY_INIT IN6ADDR_LOOPBACK_INIT INET6_ADDRSTRLEN INET_ADDRSTRLEN IPPROTO_IPV6 IPV6_JOIN_GROUP IPV6_LEAVE_GROUP IPV6_MULTICAST_HOPS IPV6_MULTICAST_IF IPV6_MULTICAST_LOOP IPV6_UNICAST_HOPS SIN6_LEN extern const struct in6_addr in6addr_any; extern const struct in6_addr in6addr_loopback; struct in6_addr{}; struct ipv6_mreq{}; struct sockaddr_in6{}; AF_INET6 PF_INET6 union sockaddr_storage; 次のリストは、この文書で議論された関数やマクロのプロトタイプをヘッダ ごとにソートして要約したものである。 int inet_pton(int, const char *, void *); const char *inet_ntop(int, const void *, char *, size_t); draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 28] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 char *if_indextoname(unsigned int, char *); unsigned int if_nametoindex(const char *); void if_freenameindex(struct if_nameindex *); struct if_nameindex *if_nameindex(void); int getaddrinfo(const char *, const char *, const struct addrinfo *, struct addrinfo **); int getnameinfo(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int); void freeaddrinfo(struct addrinfo *); char *gai_strerror(int); struct hostent *getipnodebyname(const char *, int, int, int *); struct hostent *getipnodebyaddr(const void *, size_t, int, int *); void freehostent(struct hostent *); int IN6_IS_ADDR_LINKLOCAL(const struct in6_addr *); int IN6_IS_ADDR_LOOPBACK(const struct in6_addr *); int IN6_IS_ADDR_MC_GLOBAL(const struct in6_addr *); int IN6_IS_ADDR_MC_LINKLOCAL(const struct in6_addr *); int IN6_IS_ADDR_MC_NODELOCAL(const struct in6_addr *); int IN6_IS_ADDR_MC_ORGLOCAL(const struct in6_addr *); int IN6_IS_ADDR_MC_SITELOCAL(const struct in6_addr *); int IN6_IS_ADDR_MULTICAST(const struct in6_addr *); int IN6_IS_ADDR_SITELOCAL(const struct in6_addr *); int IN6_IS_ADDR_UNSPECIFIED(const struct in6_addr *); int IN6_IS_ADDR_V4COMPAT(const struct in6_addr *); int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *); 8. セキュリティ考察 IPv6 はいくつかの新しいセキュリティ機構を用意していて、その多くは アプリケーションからアクセス出来る必要がある。IPv6 セキュリティを サポートするためのソケットインターフェイスの拡張について詳述している もう一方のメモが執筆中である。 9. 西暦2000年についての考察 日付の使用に関して、西暦2000年問題については、このドラフトに問題はない。 RFC 2133 からの変更点 1998年3月版(-01 draft)での変更点: 他の IPv6 文書との一貫性のために 全ての "ホスト名" が "ノード名"に 変更された。 3.3節: sin6_flowinfo に対するコメントを "トラフィッククラスとフロー 情報" に変更し、関係する文章をこれら二つのフィールドの現在の定義に draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 29] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 合致するように更新した 3.10節: ("移植性の追加") は新しい。 6章: 今ある gethostbyname() と gethostbyaddr() は変更されていないと いうことを繰り返す文節が加えられた。 6.1節: gethostbyname3() を getnodebyname() に変更した。多くの アプリケーションを処理するために AI_DEFAULT を加えた。 AI_V6ADDRCONFIG が AI_ADDRCONFIG という名前に変更され、Aレコード用と IPv4 アドレス用にそれが定義された。getnodebyname() の name 引数が 数字のアドレス文字列である時、getnodebyname() が返さなければならない ものを正確に定義した。 6.2節: gethostbyaddr() を getnodebyaddr() に変更した。どのタイプの DNS query を発行するかを指定する代わりに与えられたアドレスに対する "名前を引くため" の IPv4射影アドレスとIPv6互換アドレスをどうやって 処理するかの記述の中の2と3の項を言い換えた。 6.3節: getaddrinfo() にもう2つ要求を加えた。 7章: のリストに AI_ADDRCONFIG, AI_ALL, AI_V4MAPPED の定数を 加えた。 のリストに sockaddr_union 共用体と SA_LEN を 加えた。 参考文献の更新。 1997年11月版(-00 draft)での変更点: データ型が Posix 1003.1g 標準のドラフト 6.6 に従って変更された。 3.2節: s6_addr のデータ型が "uint8_t" に変更された。 3.3節: sin6_family のデータ型が "sa_family_t" に変更された。 sin6_port のデータ型は "in_port_t" に変更され、sin6_flowinfo の データ型は "uint32_t" に変更された。 3.4節: 3.3節と同様、そしてsin6_len のデータ型が "uint8_t" に 変更された。 6.2節: gethostbyaddr() の最初の引数が "const char *" から "const void *" に、二つ目の引数が "int" から "size_t" に変更された。 6.4節: getnameinfo() の二つ目の引数が "size_t" から "socklen_t" に 変更された。 構造体を宣言するのにどのヘッダが読み込まれなければならないかをより 明確にするために、新しい構造体を宣言する際のいい回しを変更した: 3.2節 (in6_addr{}), 3.3節 (sockaddr_in6{}), 3.4節 (sockaddr_in6{}), 4.3節 (if_nameindex{}), 5.3節 (ipv6_mreq{}), および 6.3節 (addrinfo{}). 4章: NET_RT_LIST を NET_RT_IFLIST に変更。 5.1節: IPV6_ADDRFORM ソケットオプションを削除。 draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 30] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 5.3節: IPV6_MULTICAST_LOOP への0か1以外のオプション値はエラーを返す という注意を追加。IPV6_MULTICAST_IF, IPV6_MULTICAST_HOPS および IPV6_MULTICAST_LOOPは getsockopt() で使うことができるが、 IPV6_ADD_MEMBERSHIP と IPV6_DROP_MEMBERSHIP は getsockopt() で使う ことができないという注意が加えられた。 6.1節: gethostbyname2() とそれに関連する RES_USE_INET6 オプション の記述が削除され、gethostbyname3() で置き換えられた。 6.2節: gethostbyaddr() は thread safe であるという要求を加えた。 RES_USE_INET6 オプションを無効にするようにステップ4を言い換えた。 6.3節: getaddrinfo() と getnameinfo() は thread safe である という要求を加えた。AI_NUMBERICHOST フラグを加えた。 6.6節: IN6_IS_ADDR_LINKLOCAL と IN6_IS_ADDR_SITELOCAL マクロを明確化 した。 98年9月版(ドラフト-01規格)での変更点 仕様の中のトラフィッククラスの優先度を変えた。 2.1節で、スコープ識別子の必要性を加えた。 3.3と3.4節で、struct sockaddr_in6 に sin6_scope_id を加えた。 3.10節で、IPv6アドレスを保持するのにstorage構造体(?)を使う ようにした。SA_LENマクロを削除した。 4.1と4.2節で、インターフェイス識別子の無効な入力パラメータと システム的な失敗を区別した。 5.2節で、マルチキャスト操作にデフォールトを加えた。 IPv6の用語と矛盾しないように名前をADDからJOINに、DROPから LEAVEに変えた。 getnodebynameをgetipnodebynameに、getnodebyaddrを getipnodebyaddrに変えた。6章で、関数のパラメータに MT safe な エラーコードを加えた。 freehostentを今の節から getipnodebyaddr の後ろの6.3節に 移動した(よって6章の残りの節は後ろにずれた)。 AF パラメータに依存する AI_ALL と AI_V4MAPPED の使用法を 明確にし、6.1節で論理和として使用しなければならないとした。 6.1節で、フラグ引数と一緒に使われなかったリテラルアドレスの 制限を削除した。 西暦2000年問題の章をドラフトに追加した。 IDディレクトリから削除され、期限が切れたので以下への参照を 削除した。しかし、前述のドラフトのロジックは未だ適用されるので 6.2節の3つ目のパラグラフの後の項目は保持されている。 [7] P. Vixie, "Reverse Name Lookups of Encapsulated IPv4 Addresses in IPv6", Internet-Draft, , May 1996. draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 31] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 以下は、もはや参照されなくなったので削除された。 そしてこのドラフトは期限が切れた。 [3] D. McDonald, "A Simple IP Security API Extension to BSD Sockets", Internet-Draft, , March 1997. 以下は、もはや参照されなくなったので削除された。 [4] C. Metz, "Network Security API for Sockets", Internet-Draft, , January 1998. 現状にあわせて参考文献を更新した。 in6_addr と sin6_addr で境界についての注意を加えた。 AI_V4MAPPED は、getipnodebyname() でアドレスファミリが AF_INET6の時に ドット表記の IPv4 アドレスと一緒に使用されなければならないことをさらに 明確にした。 getipnodebyaddr() で使われた "::" と "::1" を明確にする文章を加えた。 謝辞 この文書に対すして提案とフィードバックを寄せてくれた、次の諸氏を含む 多くの人々に感謝する: Werner Almesberger, Ran Atkinson, Fred Baker, Dave Borman, Andrew Cherenson, Alex Conta, Alan Cox, Steve Deering, Richard Draves, Francis Dupont, Robert Elz, Marc Hasson, Tom Herbert, Bob Hinden, Wan-Yen Hsu, Christian Huitema, Koji Imada, Markus Jork, Ron Lee, Alan Lloyd, Charles Lynn, Dan McDonald, Dave Mitton, Thomas Narten, Josh Osborne, Craig Partridge, Jean-Luc Richier, Erik Scoredos, Keith Sklower, Matt Thomas, Harvey Thompson, Dean D. Throop, Karen Tracey, Glenn Trewitt, Paul Vixie, David Waitzman, Carl Williams, および山本和彦. getaddrinfo() と getnameinfo() 関数は、Keith Sklower による、先のインター ネットドラフトから採用された。ドラフトに記述されたように、William Durst, Steven Wise, Michael Karels, および Eric Allman が、プロトコル非依存な 名前関数について数多くの有益な議論を提供し、Keith Sklower のもとの 提案の初期の版について再考した。Eric Allman が getaddrinfo() の最初の プロタイプを実装した。 名前とサービスの組の指定がプロトコル独立なサービス接続に十分である、 という知見は、X/Open の "Uniform Network Interface" に対する Marshall Rose による提案によってなされた。 Craig Metz, Jack McCann, Erik Nordmark, Tim Hartrick, および Mukesh Kacker がこの文書に多大な貢献をした。Ramesh Govindan はこのメモの旧版について 数多くの貢献をし、共同執筆した。 参考文献 [1] S. Deering, R. Hinden, "Internet Protocol, Version 6 (IPv6) Specification", Internet Draft, draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 32] INTERNET-DRAFT draft-ietf-ipngwg-bsd-api-new-04.txt October 1998 , November 1997. [2] R. Hinden, S. Deering, "IP Version 6 Addressing Architecture", RFC 2373, July 1998 Draft Standard. [3] IEEE, "Protocol Independent Interfaces", IEEE Std 1003.1g, DRAFT 6.6, March 1997. [4] W. Stevens, M. Thomas, "Advanced Sockets API for IPv6", RFC 2292, February 1998. Authors' Addresses Robert E. Gilligan FreeGate Corporation 1208 E. Arques Ave. Sunnyvale, CA 94086 Phone: +1 408 617 1004 Email: gilligan@freegate.net Susan Thomson Bell Communications Research MRE 2P-343, 445 South Street Morristown, NJ 07960 Telephone: +1 201 829 4514 Email: set@thumper.bellcore.com Jim Bound Compaq Computer Corporation 110 Spitbrook Road ZK3-3/U14 Nashua, NH 03062-2698 Phone: +1 603 884 0400 Email: bound@zk3.dec.com W. Richard Stevens 1202 E. Paseo del Zorro Tucson, AZ 85718-2826 Phone: +1 520 297 9416 Email: rstevens@kohala.com draft-ietf-ipng-bsd-api-new-04.txt Expires April 1999 [Page 33] 原訳: 補遺: 吉藤英明