inetd の IPv6 対応FreeBSD は 4.0-RELEASE から標準で IPv6 が使えるようになっており、 inetd も IPv6 に対応しています。 inetd の IPv6 対応は、TCP の場合、以下のような仕様になってます。
一般に AF_INET6 のソケットを生成し、そのアドレスを in6addr_any (ANY アドレス) として bind(2), listen(2) した場合、 指定したポート番号に対するコネクション確立要求は、IPv6 のみではなく、 IPv4 のものも受け付けることが出来ます。 inetd.conf、にて ``tcp46'' と定義した場合の動作がこれにあたります。 クライアント側アプリケーションが IPv4 にて接続してきた場合は、 prefix が ::ffff: となった IPv4 mapped IPv6 address として、 アプリケーションに通知されます(accept(2) や getpeername(2) にて取得できるアドレス)。 inetd.conf にて ``tcp'' と定義した場合は、AF_INET のソケットを生成しますので、 IPv4 での接続要求しか受け付けることが出来ません。 では、どのようにして inetd は ``tcp6'' と ``tcp46'' の動作を切り分けているのか、 確認してみます。 inetd のソースは /usr/src/usr.sbin/inetd/inetd.c です。 getconfigent() が inetd.conf のエントリを読み込む処理で、 以下の辺りがポイントになります。
inetd.conf のプロトコル名文字列が sp->se_proto に格納されており、 その末尾の文字が数字の場合に、末尾の文字を消しながら処理をループしています。 ソースを読めばわかる通り、``tcp4'' と定義されていた場合は v4bind が 1 となり、``tcp6'' と定義されいた場合は v6bind が 1 となります。 ``tcp46'' の場合は v4bind, v6bind ともに 1 が設定されます。 この状態でループを抜け、1738 行目の if 文に進みます。 定義が ``tcp6'' となっていた場合は、v6bind == 1, v4bind == 0 なので、 1741 行目の処理が実行され、sep->se_nomapped に 1 が格納されます。 sep->se_nomapped は IPv4 mapped IPv6 address は扱わない、 というフラグになります。この機能を実現するのが、IPV6_V6ONLY というソケットオプション (IPv6 レベルのオプション) です。 inetd は setup() にて inetd.conf のエントリに応じたソケットを生成した後、 sep->se_nomapped の値に応じて IPV6_V6ONLY オプションに関する setsockopt(2) を実行します。
上記の通り sep->se_nomapped が 1 であれば、 IPV6_V6ONLY オプションをを有効にします。 IPV6_V6ONLY オプションは Draft-ietf-ipngwg-rfc2553bis-03.txt にて提唱されている、新しいオプションです。 以下のように記述されています。
5.3 IPV6_V6ONLY option for AF_INET6 Sockets
This socket option restricts AF_INET6 sockets to IPv6 communications
only. As stated in section <3.7 Compatibility with IPv4 Nodes>,
AF_INET6 sockets may be used for both IPv4 and IPv6 communications. Some
applications may want to restrict their use of an AF_INET6 socket to
IPv6 communications only. For these applications the IPV6_V6ONLY socket
option is defined. When this option is turned on, the socket can be
used to send and receive IPv6 packets only. This is an IPPROTO_IPV6
level option. This option takes an int value. This is a boolean
option. By default this option is turned off.
Here is an example of setting this option:
int on = 1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&on, sizeof(on)) == -1)
perror("setsockopt IPV6_V6ONLY");
else
printf("IPV6_V6ONLY set0);
Note - This option has no effect on the use of IPv4 Mapped addresses
which enter a node as a valid IPv6 addresses for IPv6 communications as
defined by Stateless IP/ICMP Translation Algorithm (SIIT) [8].
冒頭でも述べた通り、通常 AF_INET6 のソケットには、 IPv4 のパケットも通知されます。しかし、IPV6_V6ONLY オプションを有効にすれば、 IPv6 のパケットのみしか通知されなくなります。 FreeBSD の inetd は、このオプションの動作を利用して、 ``tcp46'' と ``tcp6'' を使い分けているわけです。 FreeBSD では 4.4-RELEASE から、この IPV6_V6ONLY オプションをサポートしています。 新しい標準化機能を貪欲に取り込んでいますね。 TetsuoSTREAMS > FreeBSD > inetd の IPv6 対応 |