[Mew-dist 11468] Re: im-133

Kazu Yamamoto ( 山本和彦 ) kazu at example.com
1999年 11月 25日 (木) 19:34:40 JST


From: Hajimu UMEMOTO (梅本 肇) <ume at example.com>
Subject: [Mew-dist 11466] Re: im-133 

>   うーん、話が見えない。v6 の方で話が進んでるのかな? ;_;

すいません。v6 at example.com に流れたのは、imput のバグの性で、事故です。
#mew-dist だけでも itojun は飛び出してきます。:-)

>   でも、実際のところ、gethostbyname() が AAAA RR を持っていたら AAAA
> RR しか返さない。つまり、折角ループで回して使えるホストを探すのに、
> AAAA RR を持っているホストで POP3 なりのサーバが上がっていたら、お話でき
> ないわけです。local には、IPv6 Perl なら gethostbyname2() を AF_INET と 
> AF_INET6 と 2 回呼び出して対処するというコードを持ってたりします。

つまり、getaddrinfo() でしょう?

> # IPv6 Perl を使うと、いきなり AAAA RR を見てくれるので、あとのロジック
> # が IPv6 対応してないと、ある日突然サーバが IPv6 対応になったりなんかす
> # ると、悲しい思いをします。ftpmirror を IPv6 化しなきゃと思ったのは、ま
> # さにこの理由によります。

ええ、だから protocol independent なプログラミングをしましょうと言って
います。以下に iij.news に執筆した原稿を付けておきます。少なくとも 
v6 at example.com の人には有益なはず。ちょっと長いです。ごめんなさい。

そのうち web に貼ります。(iijlab の web 更新をサボっている問題とも言う。)

--かず
-------------- next part --------------
「IPv6 ことはじめ」

第4回 ホスト名とアドレス

-- IPv6 とアプリケーション

前回は IPv6 のプラグ&プレイ
機能についてお話しました。
IPv6 を喋るコンピュータは、
たとえば Ethernet につないだ
瞬間から、インターネットに接
続されたコンピュータと通信を
開始できます。

実際ユーザはアプリケーション
をどうやって利用するのでしょ
うか? 答えは簡単で、IPv4 の
ときとなんら変わりありません。
あまり変わらないのが IPv6 の
いいところだとも言えます。

たとえば、ftp を使って、IPv6 
対応の ftp.kame.net に明日ア
クセスするには次のようにしま
す。

   % ftp ftp.kame.net

何も変わらないので拍子抜けさ
れたかもしれませんね。という
訳で、ユーザはアプリケーショ
ンを使う際に何も考える必要は
ありません。これで今回のアプ
リケーションの使い方は終りで
す...

--- ":" のジレンマ

と言ったら怒られそうなので、
もう少しホスト名と IPv6 アド
レスの関係について説明したい
と思います。お勧めの方法では
ないので恐縮ですが、ここでは
まず IPv6 アドレスを直接アプ
リケーションに指定することを
考えてみましょう。例えばこん
な感じになります。

   % ftp 3ffe:501:4819:2000:5254:ff:fedc:50d2

IPv6 アドレスを直接指定でき
ることは、打ち込みたくないぐ
らい長いことを除けば、IPv4 
の時となんら変わりないように
思います。しかし、IPv6 に区
切り文字に選択された ":" が
くせものなのです。

たとえば、SSH(Secure Shell) 
の scp を利用する場面を想像
してみて下さい。こんな感じに
なります。

   % scp 3ffe:501:4819:2000:5254:ff:fedc:50d2:foo.txt .

scp では、コンピュータの識別
子(ホスト名やアドレス)とファ
イル名の区切り文字に ":" を
利用します。この例から明らか
なように、どこがコンピュータ
の識別子でどこがファイル名な
のか分からなくなります。

「scp が特殊なんでしょう」と
思う人には、rcp、X Window サー
バの DIPLAY 環境変数、URL な
どの例を挙げて問題の深刻さを
分かって頂くことにします。特
に URL は頻繁に使われるので、
困りものです。

IPv6 アドレスを URL に埋め込
むために、"[" と "]" で囲む
方法が現在提案されています。
たとえば、こうなります。

	http://[3ffe:501:4819:2000:5254:ff:fedc:50d2]/~kazu/

こうすれば URL の ":" と 
IPv6 アドレスの ":" が区別が
付くようになります。この方法
を他のアプリケーションに適用
したら問題解決ですね。めでた
しめでたし...

しかし、そうは問屋が下しませ
ん。scp の例にたち返ってみま
しょう。"[" と "]" を使うと
次のようになります。

   % scp [3ffe:501:4819:2000:5254:ff:fedc:50d2]:foo.txt .

"[" と "]" は UNIX の一般的
なシェルでは特殊な意味を持っ
ているので、ユーザの意図とは
異なって解釈されてしまいます。
結局、"'" で囲むしかなくなり
ます。

   % scp '[3ffe:501:4819:2000:5254:ff:fedc:50d2]:foo.txt' .

とっても面倒ですね。結局選択
肢としては、

   - IPv6 の区切りを別の文字に変える
   - 極力ホスト名を使うようにする

しかありません。僕は今年の 4 
月 1 日に ":" を止めて "=" 
にしようという冗談の RFC を
書こうとしました。しかし、周
りの人から「洒落にならないの
で止めた方がいい」となだめら
れ思い留まりました。:p

IPv6 のアドレスは長く打ちに
くいこと、区切り文字 ":" は
いろいろなアプリケーションと
相性が悪いことなどを考えれば、
極力ホスト名を使うという案が
妥当なのかもしれません。

-- DNS

それではホスト名をアプリケー
ションに指定したときに、何が
起こるのか考えてみましょう。
ホスト名は、DNS(Domain Name
System)を使ってアドレスに変
換されます。

IPv4 の際は、A レコードを使っ
てホスト名に対し IPv4 アドレ
スを登録していました。以下に
例を挙げます。

    www.kame.net A 203.178.141.212

一方 IPv6 では、IPv4 よりも
アドレスの長さが 4 倍になっ
たということで、AAAA レコー
ドを使って IPv6 アドレスを登
録します。AAAA は、quad A と
発音されることがあります。
こんな感じになります。

    www.kame.net AAAA 3ffe:501:4819:2000:5254:ff:fedc:50d2

ホスト名に複数の IPv4 アドレ
スが登録されていた場合、どう
いう順番でその IPv4 アドレス
並べられて返されてくるのか決
まりはありませんでした。

同様に、あるホスト名に対して 
IPv4 アドレスと IPv6 アドレ
スが登録されていた場合、どち
らのアドレスが先に返って来る
のか分かりません。IPv4 アド
レスが先に返って来れば、IPv4 
で通信が開始されますし、逆も
また真なりです。

ここで注意して頂きたいのは、
DNS への問い合わせに関する通
信とアプリケーションの通信と
で、同じ IP バージョンが使わ
れなくてもよいことです。たと
えば、DNS へは IPv4 で問い合
わせ、返って来た答えが IPv6 
アドレスだったので、アプリケー
ションは IPv6 で通信するとい
うこともありえます。

このように、「IPv6 対応」と
いった場合は、コンテンツを対
応させたのか、トランスポート
を対応させたのか区別しないと
いけません。たとえば、
「whois データベースをIPv6 
に対応させました」という台詞
だけでは、IPv6 アドレスをデー
タとして登録できるようになっ
たのか、whois データベースを
IPv6 で検索できるようになっ
たのか分からないのです。

余談になりますが、IPv6 アド
レスの逆引きは 16 進数の桁の
境界で分割し逆にして、
"IP6.INT" の下に PTR レコー
ドとして登録します。以下に 
IPv4 と一緒に IPv6 の逆引き
の例を示します。登録作業が大
変なのは想像に難くないでしょ
う。:-)

   $ORIGIN 141.178.203.IN-ADDR.ARPA.
   212 PTR www.kame.net.
   $ORIGIN 0.0.0.2.9.1.8.4.1.0.5.0.e.f.f.3.IP6.INT.
   2.d.0.5.c.d.e.f.f.f.0.0.4.5.2.5 PTR www.kame.net.

-- アプリケーションの改良

今まで出てきたアプリケーショ
ンは IPv4 にも IPv6 にも対応
していると暗黙に仮定して説明
してきました。現実問題として、
これまでのアプリケーションは 
IPv4 しかサポートしていない
ので、IPv6 にも対応させる必
要があります。

これは IPv6 プログラマの仕事
であり、みなさんが実際に作業
することはほとんどないでしょ
う。しかし、技術的に面白いの
で、典型的な変更例を紹介する
ことします。

ここでは、クライアントの場合
を考えます。IPv4 のクライア
ントは、ホスト名を IPv4 アド
レスに変更するために 
gethostbyname() という関数を
使います。IPv4 のクライアン
トのソースを見れば、以下のよ
うなコードを発見できるはずで
す。

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
int i, s;
struct hostent *hp;
struct servent *sp;
struct sockaddr_in sin;

s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
hp = gethostbyname("www.kame.net");
sp = getservbyname("http", "tcp");
for (i = 0; hp->h_addr_list[i]; i++) {
   memset(&sin, 0, sizeof(sin));
   sin.sin_family = AF_INET;
   sin.sin_len = sizeof(sin);
   sin.sin_port = htons(sp->s_port);
   memcpy(&sin.sin_addr, hp->h_addr_list[i], hp->h_length);
   if (connect(s, &sin, sizeof(sin)) < 0)
      continue;
   break;
}
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

まず、socket() 関数を使って
ソケット開いています。ここで
注目すべきは、AF_INET つまり 
IPv4 であることを明示的に指
定していることです。次に、
gethostbyname() 関数を使って、
ホスト名を IPv4 アドレスに変
換してます。また、
getservbyname() 関数を読んで、
サービス名をポート番号に直し
ます。

次に得られた複数の IPv4 アド
レスに対し、次々に connect() 
を試みます。コネクションを張
れる IPv4 アドレスを発見でき
た時点でこのループを終了しま
す。

ループの中で注目して欲しいの
は、struct sockaddr_in とい
う IPv4 アドレス用の構造体で
す。プログラマは明らかに 
IPv4 を意識してコードを書い
ていることが分かります。

このアプリケーションを IPv6 
に対応させるには、IPv4 に加
えて IPv6 も意識しないといけ
ないのでしょうか? そうでは
ありません。getaddrinfo() と
いう魔法の関数を利用すると、
以下のようにすっきりしたプロ
グラムになります。

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
int s;
struct addrinfo hints, *res, *res0;

memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("www.kame.net", "http", &hints, &res0);
for (res = res0; res; res = res->ai_next) {
   s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
   if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
      close(s);
      continue;
   }
   break;
}
freeaddrinfo(res0);
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

注目して頂きたいのは、
AF_INET といった IP バージョ
ンを明示的に指定していないこ
とです。その代わりに、
PF_UNSPEC を使っています。
PF_UNSPEC とは、どちらのバー
ジョンでも OK だということを
意味しています。ループの中で
ソケットを動的に開いているの
で、アドレスが DNS からどう
いう順番で返されても平気です。

さらに言えば、ホスト名をアド
レスに変換すると同時に、サー
ビス名もポート番号に変換して
くれるので便利です。

サーバだともう少し込み入って
きますが、基本的には同じよう
な作業で済みます。データの中
にアドレスを直接埋め込むよう
なお行儀の悪いアプリケーショ
ンの場合は、こう簡単にはいき
ません。しかし、素直なアプリ
ケーションであれば、IPv6 に
も対応させることはそんなに大
変ではないとお分かり頂ければ
幸いです。

;;; 14 x 153 x 2 
;;;Local variables: 
;;;fill-column: 28
;;;End:


Mew-dist メーリングリストの案内