RFC 3484 の呪い

昔、DNS ラウンドロビンが当てにならなくなってきたのは RFC 3484 の影響、という事を書きました。

IPv6 と RFC3484 - JULYの日記

この RFC は 6724 で更新されています。

RFC 6724 - Default Address Selection for Internet Protocol Version 6 (IPv6)

この RFC は、割り当てられた複数のアドレスから、どのアドレスを使って相手との通信を行うか、というもので、それを実装すると、名前解決の結果がソートされ、結果、DNS ラウンドロビンを期待して複数の A レコードを設定している場合、片方にアクセスが寄ってしまう、という現象がありました*1

RFC 3484、6724 自体は、IPv6 上でより近い経路になるアドレスを選択するためのもので、DNS ラウンドロビンの問題は、その結果の巻き添えを食った感じですが、今度は、本当にこの RFC にまつわる問題に遭遇しました。

ソースアドレスの選択

RFC 6724 のポイントの一つに、どのアドレスを発信元のアドレスとして選択するのか、というのがあります。これまでの試行錯誤の結果、

  • グローバルアドレス(MAC アドレスからの生成)
  • グローバル一時アドレス
  • ULA

の3つのアドレスがホストに割り当てられている状態になっています。この状態で実際に通信を行う時に、このアドレスのどれを発信元とするか、というルールを決める必要があります。そのルールが RFC 6724 の「5. Source Address Selection」にある、Rule 1 〜 8 です。

このルールを一つ一つ、確認してみます。

Rule 1: 宛先とアドレスと同じアドレスを優先する。

自分自身へ接続する場合には、宛先アドレスと同じ発信元アドレスを使う、ということになります。

Rule 2: 適切なスコープを選択する。

ざっくり言うとグローバルアドレス相手にはグローバルアドレスを、リンクローカルアドレス相手にはリンクローカルアドレスを、ということのようです。

Rule 3: 非推奨アドレスを避ける。

自動構成のアドレスの有効期限が近づいているアドレスが非推奨アドレスです。自動構成アドレスは時間とともに「優先(Preferred)」「非推奨(Deprecated)」「無効(Invalid)」というようにステータスが変化します。新たな通信を開始する時には、非推奨アドレスを利用せず、非推奨アドレスをつかった既存の通信が無くなるのを待つ、という形で、スムーズなアドレスの更新を実現します。

Rule 4: ホームアドレスを優先する。

ホームアドレスは、Mobaile IPで使われるアドレスです。

Rule 5: 宛先に向かうインタフェース上にあるアドレスを優先する。

複数のインタフェースがあって、宛先アドレスからルーティングテーブルにしたがってパケットを送出するインタフェースが決まると、そのインタフェースに割り当てられているアドレスを優先する、という話です。一見、当たり前ですが、例えば、ルータ自身が LAN 側のホストへ繋ごうとする際に、WAN 側のアドレスを使わない、という話になります。

Rule 5.5: Next-hop 側のインタフェース上にあるアドレスを優先する。

基本的には 5. と同じ話で、宛先がさらに別のゲートウェイの向こうになる場合、一番近いゲートウェイへ向かうインタフェース上のアドレスを優先する、という話です。

Rule 6: ラベルが一致する物を優先する。

NGN 閉域網の問題*2の時に話題になったポリシーテーブルで割り当てられるラベルが一致しているアドレスを優先します。

Rule 7: 一時アドレスを優先する。

一時アドレスがある場合には一時アドレスを優先して使います。

Rule 8: アドレスのプレフィックスを比較して、一致している長さが長いものを優先する。

IPv6 アドレスのネットワーク部であるプレフィクスを比較して、先頭ビットから何ビット一致しているかをチェックし、一致しているビット数の多い方を優先することで、ルーティング経路の有利なアドレスを選択する、という意図があります。

ULA のスコープ

RFC 6724 のルールを見ていくと、Rule 2 を除く 1 〜 5.5 に関しては、割と当たり前のルールです。Rule 4 は Mobile IP を使っている場合のケースで、かなり特殊で縁がない感じで、あとは、「まぁ、そうだよなぁ」という話です。

問題は、Rule 2 です。

IPv6 アドレスのスコープは、

  • グローバル
  • サイトローカル
  • リンクローカル

と言われていました。しかし、サイトローカルアドレスは廃止*3され、その代わりに ULA が作られました。

ULA のスコープがサイトローカルとして定義されていれば分かりやすかったのですが、実は、ULA のスコープはグローバルです。そのことが ULA を定義している RFC 4193 に書かれています。

http://tools.ietf.org/html/rfc4193

3.3 Scope Definition
By default, the scope of these addresses is global.

という事は、本当にグローバルなアドレスだろうが、ULA だろうが、Rule 2 では優先順位に差がない、ということになります。

最長一致より一時アドレス

前回までで、

  • グローバルなアドレスは、MAC アドレスを元にした自動構成アドレスと一時アドレス
  • ULA は DHCPv6 で割り当てられたアドレス

という3つのアドレスを持つ構成になっています。この状態で同じ ULA を持つおうちサーバに繋ごうとすると、Rule 6 より前のルールでは決着が付きません。

Rule 6 はポリシーテーブルで割り当てられるラベルで、デフォルトのポリシーテーブル*4では3つのアドレスに差はありません。

次に Rule 7 で評価されると、3つのアドレスのうち、グローバルな一時アドレスが優先される事が決定します。

つまり、これまで苦労して3つのアドレスが割り当てられるようにした結果、おうちサーバに繋ぐ時に選択されるアドレスは、グローバルなアドレスの一時アドレス、という事になってしまいます。Rule 8 にたどり着けば、プレフィックスの最長一致で、当然、ULA が選択されます。しかし、たとえ相手と同一プレフィックスを持っていても、つまり、相手が同一セグメントにあっても、別のプレフィックスを持つ一時アドレスが選択され、わざわざルータ経由で通信することになります。

屈辱のポリシーテーブル

RFC 3484 が 6724 で更新されたポイントの中に、3484 以降に制定された ULA に対する記述*5と聞いていたのですが、それがどこかというと「10.6. Configuring ULA Preference」で、そこで書かれているのは単に「ポリシーテーブルで ULA の優先順位を上げてね」という話*6で、少なくともデフォルトポリシーテーブルでは、ULA はグローバルアドレスと同じ扱いになってしまいます。

一時アドレスを一切使わない、ということであれば、今回のケースは Rule 8 のプレフィックス最長一致で救われることになりますが、一時アドレスの有無をプレフィックスによって変えると、たとえ全く同じプレフィックスを持つ、隣のホストに対するアクセスでも、一時アドレスを利用してルータ越しの通信を行うことになります。

ということで、結局、ポリシーテーブルを設定する以外に解決策がない、ということになりました。

Windows でのポリシーテーブルの設定方法に関しては、「netsh prefixpolicies」あたりで検索すれば、「IPv4 を優先させる」という文脈でたくさん見つかるでしょう。

手元の Windows 7 でのデフォルトでは下記のようになっています。

優先順位   ラベル  プレフィックス
----------  -----  --------------------------------
        50      0  ::1/128
        40      1  ::/0
        30      2  2002::/16
        20      3  ::/96
        10      4  ::ffff:0:0/96
         5      5  2001::/32

今回のケースだと、宛先アドレスの IPv6 アドレスは ULA のみ*7なので、Rule 6 で宛先とラベルが一致さえしてしまえば、発信元のアドレスとして ULA が選択されることになります。

なので、ULA のプレフィックスのラベルを定義し、優先順位は通常の IPv6 アドレスと同じ 40 で設定しました*8

優先順位   ラベル  プレフィックス
----------  -----  --------------------------------
        50      0  ::1/128
        40      6  fd00::/8
        40      1  ::/0
        30      2  2002::/16
        20      3  ::/96
        10      4  ::ffff:0:0/96
         5      5  2001::/32

こうすることで、ULA を持つおうちサーバに対して、ULA のアドレスを使ってアクセスするようになりました*9

そして、手動設定が残った...

このポリシーテーブルをクライアントへ配信する方法は、Active Directory を使って、参加しているホストに適用する事は出来るみたいですが、そもそも、ドメインコントローラに繋ぐ時に、一時アドレスが選択されたらどうなるのか? という疑問があります。

DHCPv6 で stateful な「管理された自動構成」を実現するなら、このポリシーテーブルも DHCPv6 で配布できないか、と思うのですが、どうも、そういったオプションは無さそうです*10

ポリシーテーブルの設定という手動設定が残る、という屈辱の結果になってしまいました。ULA のプレフィックスがデフォルトのポリシーとして設定されるようになるか、RFC 6724 が更新されて、ULA の宛先の時に、グローバルの一時アドレスより ULA が優先されるようなルールになって欲しいと思うのですが...。

*1:複数の A レコードで、アドレスの上位ビットがある程度等しいと、「行き先のネットワークは同じだろう」ということで、ソートされずに済むケースがあるみたいです。

*2:参照: NTT IPv6閉域網フォールバック問題:Geekなぺーじ

*3:RFC 3879 に廃止する理由などが書かれています

*4:RFC 6724 の「2.1. Policy Table」にデフォルトがあります

*5:RFC6724: Default Address Selection for Internet Protocol Version 6 (IPv6):Geekなぺーじ

*6:RFC 6724 「10.6. Configuring ULA Preference」にある例は、発信元、宛先ともにグローバルと ULA の2つのアドレスを持っている時に、ULA が優先されない、という文脈なので、今回のケースとはちょっと違ってます。

*7:もし、おうちサーバの名前解決の結果にグローバルなアドレスが含まれるのであれば、ULA の優先順位を上げた方が良いでしょう。

*8:実際に設定するときに、netsh の interface ipv6 add prefixpolicies で、デフォルトのポリシーテーブルに追加したつもりでいて、再起動して確認すると、自分が追加したポリシーだけが入っている状態になりました。なので、一度、デフォルトのポリシーを削除し、自分が追加したいポリシーと一緒に、元のデフォルトポリシーも追加してやる必要があるみたいです。

*9:「fd00::/8」よりも「fc00::/7」の方が正しいかもしれませんが、とりあえず「fd00::/8」で実際に利用可能な状態にある ULA をカバーしていることになるはず。

*10:2014-4-28 追記: RFC 7078 で、DHCPv6 を使った配布方法が定義されたようです。但し、発行したのが今年の1月。一般的に実装されるのは、まだ先の話ですね。

Stateless と Stateful の狭間

IPv6 アドレスの stateless な自動設定に関する RFC は 2014 年 4 月現在、4862 です。

RFC 4862 - IPv6 Stateless Address Autoconfiguration

ところが、RFC の中に明示的に stateful な自動設定に関して記述しているものは見つかりませんでした。強いていうと、DHCPv6 は 3315 です。

http://tools.ietf.org/html/rfc3315

RFC 4862 のタイトルは明確に「IPv6 Stateless Address Autoconfiguration」と言っているのとは対照的です。しかし、RFC 4862 をよく読むと、こう書かれています。

Major clarifications:

(中略)

Avoided the wording of "stateful configuration", which is known to be quite confusing, and simply used "DHCPv6" wherever appropriate.

「"stateful な設定"という言葉は、ちょっと混乱を招くので、"DHCPv6" に置き換えた」ということのようです。あれこれ調べ回っていると、下記の記事では、自動設定の形式として「Stateless Configuration」「Stateful Configuration」「Both Configurations」の3つがある、という書き方をしています。

How to configure IPv6 address in Windows

どうも、単純に stateless、stateful の2つに分割できる話じゃなさそうです。

autonomous address-configuration flag

今の目標は、

  • グローバルなアドレスは、RA による自動構成まかせ。
  • ULA は、DHCPv6 からのアドレスのみで、一時アドレスを作らないようにする。

です。DHCPv6 を使うときの RA の設定で、M フラグや O フラグは RA 全体に対するフラグで、プレフィックス毎に設定する物ではありません。

じゃぁ、プレフィックス毎に何か設定できる事はないか、と思い、かつて、おうちサーバで動かしていた radvd の設定ファイルを眺めていると、「AdvAutonomous」という設定項目がありました。

radvd.conf(5) - Linux man page

AdvAutonomous on|off
When set, indicates that this prefix can be used for autonomous address configuration as specified in RFC 4862.
Default: on

「セットされていれば、このプレフィクスが RFC 4862 で定義されている自立的なアドレス設定に利用できる事を意味する」とあります。

RFC 4862 を読み返すと、「4. Protocol Overview」にこのような記述があります。

One Prefix Information option field, the "autonomous address-configuration flag", indicates whether or not the option even applies to stateless autoconfiguration

プレフィックスが stateless な自動構成を適用するかどうかを表すオプションだと言っています。また、「5.5 Creation of Global Addresses」の「5.5.3 Router Advertisement Processing」では、

a) If the Autonomous flag is not set, silently ignore the Prefix Information option.

autonomous フラグがセットされていなかったら、そのプレフィックス情報は黙って無視する(つまり、アドレスを作らない)と書かれています。

どうも、このフラグが肝となりそうです。このフラグが off なら、stateless な自動構成アドレスの対象から外され、その結果、一時アドレス(stateless な自動構成アドレスの一種)も作られないのではないか。

NVR500 だと、「ipv6 prefix」にある「a_flag」が該当するので、

ipv6 prefix 2 fdfe:dcba:9876:5432::/64 a_flag=off

としてみます*1

すると、見事に

  • グローバルなアドレスは、MAC アドレスから生成されたアドレスと一時アドレスの2つ。
  • ULA は DHCPv6 から払い出されたアドレスの1つ。

という構成になりました。

stateless の本当の意味

RFC 4862 は stateless なアドレスの自動構成に関して書いています。で、RA のプレフィックス情報に含まれる "autonomous address-configuration flag" が on でないと、そもそも自動構成の対象とせずに無視される、という事が書かれています。

という事は、stateless なアドレスの自動構成は、

  • RA の M フラグが off
  • RA のプレフィックス情報で "autonomous address-configuration flag" が on

という、2つの条件を満たす必要がある、という事になります。この2つのフラグはともにデフォルトで、自動構成が行われる値(M フラグは off、"autonomous address-configuration flag" は on)なので、結果的に「RA だけがある状態なら stateless」ということになります。

ところが...

割り当てられるアドレスは狙ったとおりになりました。しかし、おうちサーバへの接続には、まだ問題が...。ということで、まだ話は続きます。

*1:引き続き、ULA のプレフィックスを fdfe:dcba:9876:5432::/64 としています。

DHCPv6 登場

IPv6 アドレスの自動割り当ては、

  • RA による stateless
  • DHCPv6 による statesful

の2つがあるのは、IPv6 の解説には必ず登場する有名な話です。で、DHCPv6 を使って stateful な IPv6 アドレスの割り当てをする場合、RA の M フラグと O フラグを設定する事も、様々な解説で登場します。ちなみに M フラグ、O フラグのそれぞれの意味は、

M フラグ
Management の M で、アドレスを管理(Management)する事を意味する。
O フラグ
Other の O で、アドレス以外の情報(DNS サーバのアドレス等)を提供する事を意味する。

で、実際にアドレスを管理したり、アドレス以外の情報を提供するのが DHCPv6 サーバ、という事になります。RA を受信したホストは、受信した RA の情報で M フラグが on になっていたら、DHCPv6 サーバからアドレスの割り当てを受ける、O フラグが on だったら、DHCPv6 から DNS サーバのアドレス等を取得する、という挙動をすることになります*1

で、このときにふと気になったのは、前回の段階では、ルータの RA にグローバルなアドレスのプレフィックスと ULA のプレフィックスを広告する様に設定していますが、問題になったのは、

  • グローバルなアドレスは一時アドレスを使う。
  • ULA は一時アドレスを使わない。

と、2つのプレフィックスで違うポリシーでアドレスを割り当てたい、ということでした。で、グローバルなアドレスは今まで通りでよく、ULA のプレフィックスだけ、DHCPv6 でコントロールできないか、という発想だったのですが、ルータのマニュアルをどう読んでも、先の M フラグ、O フラグをプレフィックス毎に設定できません。

実際に、RA のパケットをキャプチャしてみると、一つの RA の中に2つのプレフィックス情報があり、M フラグ、O フラグは、そのプレフィックス情報の外側にあるので、RA の仕様として、プレフィックス毎にこれらのフラグを使い分ける事ができないことが分かりました。

で、しょうがないので、

  • M フラグ、O フラグを on にする。
  • だけど、広告する2つのプレフィックスのうち、DHCPv6 サーバが提供しているのは片方(当然、ULA のプレフィックス)。
  • 結果、ULA の方は DHCPv6 から割り当てられるけど、グローバルな方は、仕方なく、自動構成アドレスになる。

という挙動を期待するしかありません。

実際に設定してみる

実際に、M フラグ、O フラグを on にした NVR500 の設定は、こんな感じになります*2

ipv6 prefix 1 dhcp-prefix@lan2::/64
ipv6 prefix 2 fdfe:dcba:9876:5432::/64
ipv6 lan1 address dhcp-prefix@lan2::1/64
ipv6 lan1 address fdfe:dcba:9876:5432::1/64
ipv6 lan1 rtadv send 1 2 m_flag=on o_flag=on

前回との違いは「m_flag=on o_flag=on」が付いている部分です。

DHCPv6 サーバの方は、おうちサーバの CentOS で動かしました。/etc/dhcp/dhcpd6.conf の主な内容は下記の通りです。

# T2, the delay before Rebind (if Renews failed)
#  (default is 3/4 preferred lifetime)
#  (set to 2 hours)
option dhcp-rebinding-time 7200;

# Enable RFC 5007 support (same than for DHCPv4)
allow leasequery;

# Global definitions for name server address(es) and domain search list
option dhcp6.name-servers fdfe:dcba:9876:5432::35;
option dhcp6.domain-search "july.example.com";

# Set preference to 255 (maximum) in order to avoid waiting for
# additional servers when there is only one
##option dhcp6.preference 255;

# Server side command to enable rapid-commit (2 packet exchange)
##option dhcp6.rapid-commit;

# The delay before information-request refresh
#  (minimum is 10 minutes, maximum one day, default is to not refresh)
#  (set to 6 hours)
option dhcp6.info-refresh-time 21600;

# The path of the lease file
dhcpv6-lease-file-name "/var/lib/dhcpd/dhcpd6.leases";

# The subnet where the server is attached
#  (i.e., the server has an address in this subnet)
subnet6 fdfe:dcba:9876:5432::/64 {
        # Two addresses available to clients
        #  (the third client should get NoAddrsAvail)
        range6 fdfe:dcba:9876:5432::1:1 fdfe:dcba:9876:5432::1:ffff;
}

CentOS Ver 6.5 に含まれる dhcp パッケージでは、/usr/share/doc/dhcp-4.1.1/dhcpd6.conf.sample というサンプルファイル*3があるので、これを参考にして /etc/dhcp/dhcpd6.conf を作成しました。

ポイントになるのは、まず、

  • option dhcp6.name-servers
  • option dhcp6.domain-search

で、これで DHCPv6 で渡す DNS サーバとドメイン名を定義しています。RA で O フラグを on にした時に、クライアントに渡される情報です。

あとは、

  • subnet6 fdfe:dcba:9876:5432::/64 { 〜

の部分で、ここで、DHCPv6 で割り当てるアドレスの範囲を指定します。RA で M フラグ on にしていると、subnet6 で指定されているプレフィックスと RA が広告するプレフィックスで一致する物があれば、DHCPv6 からアドレスが割り当てられることになるはずです。

結果は、あと一歩

この状態で PC を起動すると、

  • グローバルなアドレスは、RA による自動構成アドレス。
  • ULA のアドレスは、DHCPv6 サーバが割り当てるアドレス。

となる事が確認できました。ところが、予定外の事が一つありました。

グローバルなアドレスに関しては狙ったとおり、RA だけの時と何ら変わりありません。ところが、ULA は、

の2つのアドレスが割り当てられました。前回見つかった問題は、

  • 一時アドレスは、ダイナミック DNS の対象外
  • ソースアドレスとして一時アドレスが使われると、DNS 上には存在しないホストからの接続になる。
  • WindowsLinux の Kerberos 認証を使っていると、host プリンシパルの問題があるので、これでは都合が悪い。

という問題です。DHCPv6 を使っても、ULA の一時アドレスが使われるのであれば、問題は解決しません。

調べると、Windows で「そもそも、IPv6 の一時アドレスを使わない」という方法を推奨している記事を見かけます。

固定IPv6ができない?

上記の Technet フォーラムでの話は Windows 8 での話ですが、Windows 7 だと netsh コマンドで設定できるようです。

http://www.ipnet-lab.jp/post/2012/04/12/ipv6-ra-privacyaddress-disable.aspx

しかし、これだとグローバルなアドレスでも一時アドレスが付かなくなってしまいます。

先の Technet フォーラムでの回答には

Windows Vista / Windows Server 2008 以降の OS は、ステートレス RA 環境に置かれると、IPv6 アドレスを自動構成がデフォルト ON になっていますので、手動で IPv6 アドレスを設定しても、RA で自動構成された IPv6 アドレスも付いてしまいます。

とあります。DHCPv6 でアドレスが払い出されるプレフィックスは stateful ではないのか? と思うのですが、実際には一時アドレスが付いてしまいます。

う〜ん、どうしたものか... ということで次回に続きます。

*1:O フラグだけ on であれば、アドレス自体は RA に含まれるプレフィックスから自動構成で、DNS サーバのアドレス等は DHCPv6 サーバから受け取る、ということになります。その逆(アドレスは DHCPv6 だけど、DNS サーバ等は手動設定するとか、IPv4 まかせ)にするケースは、ほとんど無いかな。

*2:前回から引き続き、ULA のプレフィックスを fdfe:dcba:9876:5432::/64 としています

*3:このサンプルファイル。おそらく、ISC のオリジナルパッケージに含まれている物をそのまま収録したものだと思いますが、RHEL / CentOSSELinux を有効にしている場合、dhcpv6-lease-file-name の指定をサンプルから変更しないと、リース状態を出力するファイルの書き込みに失敗するはずです。/var/lib/dhcpd の下に設定すれば、SELinux 有効で問題ありません。

IPv6 でアドレスの手動設定はイヤ

IPv6 では、ルータが送信する RA(Router Advirtisement:ルータ広告)の情報に含まれるプレフィックスから、自動的にアドレスが決定される、という話は有名です。実際、個人向け IPv6 で、ご家庭用ブローバンドルータを使った時に、端末側に振られる IPv6 アドレスは、まさにこの仕組みによるものです。

前回、おうちサーバには、IPv4 のプライベートアドレスに該当する ULA を手動で、グローバルなアドレスに関しては RA を受信した上で自動構成する、としました。

同じ事は、クライアント側にも当てはまります。

グローバルなアドレスは、ルータが広告する RA によって自動構成アドレスが付与されます。サーバと同様に ULA を手動で設定する、という事も可能ですが、はっきり言って、128 bit のアドレスを手入力するのは拷問です。まぁ、一度設定すれば変える事はないかもしれませんが、例えばノート PC のように、自宅外のネットワークにつなぐ事を考えた時、自動でアドレスが割り当てられるようにしていた方がベターです*1

IPv4 で自動的にアドレスを割り当てるのは DHCP の役目ですが、IPv6 では基本的に RA の役目です。ところが、RA が IPv4 での DHCP の役割を置き換える事ができるかというと、

  • あくまでも、RA が通知しているのは「ネットワークアドレスはこれですよ」と「デフォルトゲートウェイはこれですよ」だけ。
  • 故に DNS サーバやドメイン名は範囲外。
  • 特定のホストに、毎度、同じアドレスを付与するようなまねはできない。

といった具合に、完全に力不足です。DNS に関して言えば、IPv4DHCP で付与すれば、それでも OK ですが、IPv6 の話をしている時に、DNSIPv4 で、というのもちょっとどうかなぁ、と。IPv4 が全く使われない、という時代は遥か先*2なので、実用上はこれでも OK なのですが、そんなところで妥協するぐらいなら、ULA を付けてまで、おうちネットワークを IPv6 化する意味がない!

ということで、DHCPv6 の登場です。

DHCPv6 は単独では生きられない

正直、IPv4DHCP のように、DHCP サーバを正しく設定しておけば OK、という方が楽です。が、なぜか、DHCPv6 は、単独では意味を成しません。DHCPv6 はあくまで RA を補佐する役割であって、RA がすでに広告されている事が大前提です。

という事は、ULA で IPv4 での DHCP のような環境を作ろうとしたら、まずは、ULA のプレフィックスを RA で広告する必要があります。

実は、IPv6 のインターネット接続環境がやってくる前に、おうちサーバで RA と DHCPv6 をやらせていました。もっとも、おうちネットワークの外に IPv6 の経路が無いのに広告している、というイリーガルな状態でしたが、DHCPv6 でのアドレス配信はできていました。

IPv6 のインターネット接続環境がやってきた、ということは、RA を送出するのはルータの役目でなので、まずは、ルータに ULA のアドレスを認識させて、RA で広告するプレフィックスに ULA のプレフィックスを追加する、という必要があります。

RA に ULA プレフィックスを追加

具体的な手順は、ルータによって様々だと思います。実際は分かりませんが、LAN 側にルータの IPv6 アドレスを手動で追加すると、そのプレフィックスを自動的に広告してくれるかもしれません。

我が家のルータは Yamaha の NVR500 ですが、Web インタフェースからの設定方法が分からず、結局、テキストベースで config を投入することになりました。

ipv6 prefix 1 dhcp-prefix@lan2::/64
ipv6 prefix 2 fdfe:dcba:9876:5432::/64
ipv6 lan1 address dhcp-prefix@lan2::1/64
ipv6 lan1 address fdfe:dcba:9876:5432::1/64
ipv6 lan1 rtadv send 1 2

1行目、3行目は、lan2、すなわち、WAN 側から与えられたアドレスに関するもので、フレッツ光ネクストひかり電話を使いつつ、IPoE で IPv6 を使えるように設定すれば入っている設定です*3

2行目で ULA のプレフィックスを定義し、4行目でルータ自身の LAN 側の IPv6 アドレスに、ULA のアドレスを手動設定(ULA のプレフィックスで、末尾が 1 のアドレス)しています。

5行目が、RA を送信するための設定で、ULA を追加する前は「ipv6 lan1 rtadv send 1」となるところに、2行目で追加したプレフィックスも送信するように設定しています。

ひとまず、ここまでやれば、RA による自動構成アドレスがクライアントに付与される格好になります。

実は、ここまでで、いったん満足してました。とりあえず、ULA のアドレスが自動的に付与されるようになったし、これで、DNS を除けば、おうちのネットワーク IPv6 だし、と。

ところが、「ダメだ。やっぱり DHCPv6 が必要だ!」という事が発覚します。

きっかけは、おうちサーバで運用している Kerberos の認証で不具合が発生したことでした。

シングルサインオンの快感 - JULYの日記

自分で書いておいて、すっかり忘れていたのですが、MIT の Kfw を使わずに、Windows のネイティブの機能で非 Active Directory の Kerberos に対応させようとすると、Windows がクライアントのホストプリンシパルを要求する関係で、事実上、Dynamic DNS 必須になります。

RA で ULA を配信するようになると、ULA のプレフィックスを持つ IPv6 アドレスが2つ作られます。一つは MAC アドレスから生成される EUI-64 を使ったアドレス。もう一つは、一時アドレス(もしくは、匿名アドレス、プライバシーアドレス)と呼ばれる、都度、変化するアドレスです。

IPv6 の一時アドレス

もともと、IPv6 で「DHCP サーバを用意しなくても、自動的に IP アドレスが設定されます。」というのは、RA のプレフィックス情報と EUI-64 の組み合わせで生成する、というものでした。

EUI-64【イーユーアイ・ロクジュウヨン】 | 日経 xTECH(クロステック)

EUI-64 がどういう物かは上記ページに詳しく書かれていますが、ポイントは、MAC アドレスから生成される点で、MAC アドレスから生成されるということは、IPv6 アドレスの下位 64 bit を見れば、同じ PC から接続されている事が分かる*4ことになります。自宅から繋ごうが、ホテルから繋ごうが、公共のネットワークから繋ごうが、IPv6 アドレスの下位 64 bit が同じならば、同じ PC から繋いでると考えられます。

で、これはプライバシー上問題だ、ということで、一時アドレスと呼ばれるアドレスが作られます。こっちはランダムに割り当てられるので、どこへ行っても下位 64 bit が同じ、という事はありません。

で、この一時アドレスは、Dynamic DNS による DNS サーバへの登録から除外されます。

Windows ツールを使用して IPv6 構成情報を取得する

通常、一時的 IPv6 アドレスは、Web ブラウザなどの通信を開始するときにクライアント アプリケーションによって使用され、DNS に登録されません。

ということは、クライアント側が一時アドレスを送信元のアドレスとして選択してサーバへ接続すると、その IPv6 アドレスは DNS 上、存在しないことになり、前述の Kerberos の問題が発生します。

これ、おうちネットワークで問題が発生するのは私のところぐらいかもしれませんが、普通に企業内ネットワークを IPv6 で作った時に、一時アドレスが送信元では都合が悪い、という事は結構、ありそうです。

一時アドレスを一切使わない、という手段はあるようですが、目指すところは、

  • グローバルなアドレスは一時アドレスを使う。
  • ULA は一時アドレスを使わない。

です。で、手動でアドレスを設定すれば、この条件を満たせるのは分かるのですが、IPv6 で手動設定は、出だしにも書きましたが「拷問」です。

ということで、おうちネットワークで IPv6 アドレスを自動で割り当てたかったら、単に ULA を RA に乗せるだけでは事が足りない事が分かりました。

で、実際にどうするかは、次回へ*5

*1:といっても、ULA のアドレス割り当てを自動にする明確なメリットは、せいぜい、「アドレス入力の間違いを無くせる」ぐらいですが。

*2:少なくとも、私が生きている間には、そんな時代は来ないかな、と。

*3:http://jp.yamaha.com/products/network/solution/flets/next/flets-next-ipv6_ipoe-nvr500/

*4:厳密には、同じ NIC から接続されていることが分かる。なので、例えば、同じ PC からでも有線と無線では違う。

*5:途中、「ということで、DHCPv6 の登場です。」と書いておいて、RA の話で終わってしまった...

IPv6 に NAT が無いことの影響

我が家に IPv6 環境がやってきました。フレッツ光ネクストの回線にして、ISP 側に申し込んで、IPoE(いわゆるネイティブ方式)で IPv6 のインターネットにつながりました。

おそらく、多くの一般家庭であれば、今時のルータさえ用意すれば、特段、意識することなく、IPv6 につながる環境になると思います。おうちサーバがあっても、「自宅内は IPv4 で十分」と考えれば、何も問題はありません。

が、一応、北の大地で技術系サラリーマンの端くれとして生活の糧を得ている身としては、おうち LAN でも IPv6 を使わないでどうする、と、無駄な努力をするのでした(^^;

IPv6 とは

なんて話はどうでもよいですね。立派な専門家の方々がたくさん解説を書いています。

NAT が無い

これも割と有名な話だと思います。そもそも、NAT によってグローバルアドレスを延命する、というアイデアが出る前に、「次世代の IP を作らなければ、アドレスが枯渇する」と言われてました*1

故に、かどうかは分かりませんが、IPv6 には NAT がありません。という事はどういう事かというと、「インターネットに繋ぎたければ、末端の端末、一つ一つに、グローバルアドレスを持つべし」という事になります。

実際、IPv6 に対応したご家庭用ブロードバンドルータで、IPv6 でつながる環境になると、IPv6 のアドレスの自動構成によって、おうちの中の PC にグローバルな IPv6 アドレスが付与されます。その状態で、例えば Google に繋ぐと、どこにも NAT が入らず、グローバルな IPv6 アドレスでつながっています。

個人向けの接続サービスだと、IPv4 アドレスがルータの WAN 側に一個、割り当てられるのが普通ですが、IPv6 の場合は、プレフィックス、つまり、アドレスのネットワーク部が割り当てられます。128 bit の IPv6 アドレスのうち、上位 64 bit のアドレスが ISP から割り当てられ、下位 64 bit は「勝手に付けてよし」という状態です*2

プライベートアドレス

NAT が無く、普通にグローバルアドレスが PC に割り当てられているのだから、IPv4 のプライベートアドレスのような物は必要ないか、というと、そういうわけでもありません。例えば、サーバのアドレスは固定したい訳ですが、もし、個人向けの安い契約で済ませようとすれば、割り当てられるプレフィックスが変わるたびに、サーバのアドレスを変更する必要があります。固定の契約を結んでも、ISP を変えたら、サーバのアドレスを変更しなければいけません。インターネット側からアクセスするためのサーバならしかたないですが、内部だけで使うサーバもこれではたまりません。

当初は、「NAT は悪だ! だからプライベートアドレスなんて不要だ!」みたいな雰囲気があったのですが、結局、上記のような事を考えると、プライベートアドレスに該当する物が必要、ということで、IPv6 では ULA と呼ばれるアドレス帯が用意されました。

ULA は「fd」で始まるアドレスで、組織統合などがあった場合にも衝突しないように、計算方法を提示されています。また、実際に計算するための Web ページが、BSD 系 OS の IPv6 を実装した Kame プロジェクトにあります。

http://www.kame.net/~suz/gen-ula.html

自分が持っている PC や機器の MAC アドレスを入れれば、48bit のプレフィックスを生成してくれます。これで、IPv4 でのプライベートアドレスを使う事ができ、内部サーバに固定の IPv6 アドレスを割り当てる事ができます。

再び、NAT が無い

IPv4 のプライベートアドレスで内部のネットワークを作り、それでインターネットに接続できたのは、NAT のおかげです。しかし、IPv6 では NAT がありません。このままだと、

  • グローバルのアドレスが割り当てられた物は、インターネットにはつながるけど、ULA を付けた内部のサーバに、直接はつながらない*3
  • ULA を付けたものは、内部のサーバにはアクセスできるが、インターネットにはつながらない。

ということになります。そもそも、内部のサーバは ULA を付ける訳ですから、じゃぁ、このサーバのアップデートとかはどうするんだ? という事になります。

で、どうするかというと、「どっちのアドレスも付ける」という事になります。IPv6 が「複数のアドレスを持つのが普通」と言う時、通常使うアドレスとリンクローカルアドレスの事を指して解説している事が多いのですが、ULA を使う場合には、「ULA とグローバルの両方のアドレスを持つ」という事になります。IPv4 だと内部のネットワークがプライベートアドレスだけで済んでいたのと、大きな違いになります*4

Windows 上で、ipconfig で見ると、こんな感じになります。

   自動構成有効. . . . . . . . . . . : はい
   IPv6 アドレス . . . . . . . . . . . : 240b:1234:5678:9abc:def0:1234:5678:9abc(優先)
   IPv6 アドレス . . . . . . . . . . . : fdfe:dcba:9876:5432::beef(優先)
   一時 IPv6 アドレス. . . . . . . . . : 240b:1234:5678:9abc:fedc:ba09:8765:4321(優先)
   リンクローカル IPv6 アドレス. . . . : fe80::123:4567:890a:bcde%11(優先)

上記の例では、プレフィックスは 64 bit で、

  • グローバルなアドレスは、「240b:1234:5678:9abc:def0:1234:5678:9abc」と「240b:1234:5678:9abc:fedc:ba09:8765:4321」
  • ULA は「fdfe:dcba:9876:5432::beef」
  • リンクローカルアドレスは「fe80::123:4567:890a:bcde」

になります。

おうちサーバにグローバルな IPv6 と ULA を付ける

ということで、おうちサーバを IPv6 対応にするには、グローバルなアドレスと ULA の両方を持つように設定する必要があります。

が、ここで落とし穴が。

私のおうちサーバは CentOS なのですが、CentOS で普通に GUI でアドレス設定をしようとすると、

  • 手動で設定すれば、自動構成のアドレスは生成されない。
  • 自動構成のアドレスが生成されるようにすると、手動でアドレスを設定できない。

という状態になります。サーバなので、ULA のアドレスを手動で設定したいのですが、そうすると、自動構成で割り当てられるはずのグローバルなアドレスは付与されない、という状態になります。企業のように、グローバルのプレフィックスが固定の場合は問題ないですが、おうちサーバだと、プレフィックスが変わる可能性があるので、グローバルのアドレスを手動で設定する訳にはいきません。

IPv6 の自動構成アドレスは、ルータが送信する RA(Router Advertisement:ルータ広告)のメッセージを受信し、そのメッセージに含まれるプレフィックスの情報を使って、自分のアドレスを決定します。RA を受信して自動構成アドレスを生成しつつ、固定で ULA を付けたい。IPv4 で例えれば「DHCP と手動設定の両方のアドレスを付けたい」といった感じです。

いろいろ嗅ぎまわったところ、「/proc/sys/net/ipv6/conf/eth0/accept_ra」が 0 な事が分かりました。おそらく、これを 1 にする必要があるだろうと思って、

# echo 1 >/proc/sys/net/ipv6/conf/eth0/accept_ra

として「service network restart」としてみると、0 に戻ってしまいます。

# find /etc/sysconfig/network-scripts/ -type f -exec grep -Hn accept_ra {} \;

とすると、確かに、この値を書き換えているところが見つかります。

これを追いかけると、どうやら IPV6_AUTOCONF が yes なら accept_ra が 1 になるようです。GUI から IPv6 アドレスを手動すると、/etc/sysconfig/network-scripts/ifcfg-eth0 に IPV6_AUTOCONF が no に設定されます。これを yes にすれば良いのですが、今度は NetworkManager が上書きしてしまいます。

ということで、

  • NetworkManager を無効にする。もしくは、インタフェースを NetworkManager の管理外にする*5
  • /etc/sysconfig/network-scripts/ifcfg-インタフェース名 のファイルで「IPV6_AUTOCONF=yes」とする。

とした上で、ULA の固定アドレスを設定すると、両方のアドレスが割り当てられるようになります。ifcfg-インタフェース名で IPv6 に必要な設定内容はこんな感じになります。

IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6ADDR=fdfe:dcba:9876:5432::1234/64

NetworkManager が残念

NetworkManager が動いていると、あるとき、意図しない設定になっている目に遭って、「サーバだから、そんな物は必要ない」みたいな事を言う人は多いのですが、とはいえ、無線 LAN や VPN のように、ユーザのデマンドで接続する場合には、NetworkManager がある方が便利だし、慣れていない人でも、それなりに設定できるので、個人的には「なら、手なずけてやる」と思って使ってきたのですが、NetworkManager を止めざるを得なかったのは、KVM のホストでブリッジを作った時と合わせて2度目。う〜ん、ちょっと残念。

*1:その頃は IPng (IP next generation) と言われていました

*2:フレッツ光ネクストのネイティブ接続で個人契約の場合。サービスメニューによって変わる可能性が無いわけではないですが、基本、64 bit のプレフィックスと思っていて間違いないと思います。

*3:ルータを介してルーティングすれば接続可能。ルータは割り当てを受けているプレフィックスを持つホストが、内部にいる事を知っているので、ルータの LAN 側に ULA のアドレスを付けるれば、基本的には OK

*4:まぁ、インターネットへの接続は全部、Proxy 経由、という構成もあり得ますが、その Proxy は少なくとも、グローバルなアドレスと ULA の両方を持つ必要があります。

*5:/etc/sysconfig/network-scripts/ifcfg-インタフェース名のファイルで NM_CONTROLLED=no とします。

「パスワードを保存する」ということ

Chrome のパスワード管理で、平文のパスワードが見えると大騒ぎになっているようです。

Chromeでは自動保存のパスワードが丸見え。サーッと血の気が引いたわ | ギズモード・ジャパン

これ、2つの論点が混ざっていて、

  • 平文のパスワードが表示できる。
  • 平文のパスワードが表示できることに、なんら警告がない。

という話になります。

で、前者は原理的には驚くことはなにもありません。パスワードをユーザの代わりに送信しようとするソフトウェアは、平文のパスワードを知らないと「ユーザの代わり」はできません。私はKeePass というオープンソースのソフトを使っていますが、これでも表示することはできます*1

ただ、その平文のパスワードをどうやって保存するか、という事に関しては千差万別です。

最も、ユーザの手を煩わさない方法は、ソフトウェアが他の秘密情報無しに復元できる形で保存する方法で、一番単純なのは、そのままの形でファイルに保存する方法で、ちょっと気を利かせるなら暗号化もどきをした上で保存します。ここで大切なのは、しょせんもどきなことです。

暗号化もどきは、プログラムにハードコーディングされているアルゴリズム、情報さえ分かってしまえば、誰でも複合化できます。これが問題になった典型的なケースは Gumblar というマルウェアで、FFFTP で保存したパスワードが抜き取られた事件です。

Gumblar - Wikipedia

当時の FFFTP では「簡易的な暗号化」と呼ばれる処理で、一見、元のパスワードが分からないように処理してから保存していたのですが、FFFTP が行っている処理をそっくりまねれば、元のパスワードは誰でも復元できます。Gumblar は FFFTP が保存している「簡易的な暗号化」したパスワードを見つけると、それを復号化する仕組みをもっていたため、ここから FTP 用のアカウント情報を収集し、Web サイトの書き換えを行いました。

FFFTP はその後、マスターパスワードを使うように修正されました。

ウイルス感染したPCにおける保存パスワードの窃取問題へ対策した「FFFTP」v1.97 - 窓の杜

スターパスワードを使って、AES で暗号化する、といった対策が取られましたが、これだと、マルウェア等が自動的にパスワードを復元する事は不可能になります。これは、AES で暗号化したからではなく、マスターパスワードを鍵として*2暗号化しているからです。

今時の暗号化の大前提は、暗号化処理のアルゴリズム自体は既知であり、その暗号化処理の鍵を秘密にする、というものです*3FFFTP が行った対策は、AES という既知のアルゴリズムで暗号化しているのですが、鍵をマスターパスワードという形でユーザに入力させることで、自動的には復号化できないようにしました。

逆に、マスターパスワードに該当する入力を必要としない場合には、マルウェア等が自動的にパスワードを復元できる可能性があります。

例えば、暗号化処理に AES を使っていたとしても、その鍵が、レジストリのどこかに保存されている、ということであれば、ユーザはマスターパスワードのような物を入力する必要はありませんが、同時に、その鍵のありかさえ分かれば、自動的にパスワードを復元できることになります。

元記事に戻ると、そもそも Safari から Chrome にパスワードを引き継げた、という事は、Safari で保存していたパスワードも自動的に復元できる、ということですから、その点では SafariChrome も同じです*4

Google 側の言い分としては、Chrome を実行しているアカウントが第三者に盗られた時点でアウトなんだから、しょうがないだろう、というものです。

これはこれで「アリ」だとは思います。Windows Vista 以降であれば、管理者権限を持ったアカウントであっても、UAC が有効であれば、プログラムがアクセス、コントロールできる範囲は狭くなっているので、マルウェアが好き勝手できない状態にはなります。ただ、アカウント情報を盗もうとするのであれば、特に管理者権限も必要なく、通常のユーザの権限で動くマルウェアで十分です。

という事を考えると、最初の方に書いた論点の後者「平文のパスワードが表示できることに、なんら警告がない」という点に関しては不満が残ります。また、マスターパスワードの設定のような、保存されたパスワードを保護するための機能が無い、という点では、Firefox よりも劣っていることにはなります。

どうも元記事を読んでると、「パスワードが見えた!」という事に反応してしまって、本来、取り上げるべき

  • ユーザに対する警告が無い。
  • スターパスワードのような保護機構が用意されていない。

という点に焦点があまり当たっていない感じがします。それは、

UPDATE:FireFoxも見れますね…ご指摘ありがとうございます。「Are you sure you wish to show your passwords?(本当に表示していいですか?)」の警告は出ますけど、そこでYESを押すと一括表示です。

というところに現れています。Firefox は警告もしているし、マスターパスワードも設定できます。

個人的には、マスターパスワードに該当するものがないパスワードの保存、というのは、基本的にあまり信用してません。マルウェアに感染したら抜かれる情報だ、という認識でいます。抜かれてもクリティカルではなく、利便性が向上するならかまわないと思いますが、「パスワードの保存」というのはそれに該当することはないでしょう。

*1:KeePass の場合は、ブラウザに限らない汎用にパスワード管理ソフトで、パスワードを確認して手入力することも想定しているので、表示できないと困ります。

*2:通常、パスワードの文字列は鍵そのものではなく、その文字列から一方向関数などで鍵を生成させて使います。

*3:もちろん、そのアルゴリズムに弱点がないことを、世界中の数学者がよってたかって研究して、大丈夫であることが確認されている、という事も重要です。

*4:Safari のパスワード保存でマスターパスワードが設定できるのであれば、Chrome よりもマシですが、設定していなければ同じです。

自転車の交通事故

自転車通行可の標識を減らしているそうです。

http://www3.nhk.or.jp/news/html/20130525/k10014839591000.html

自転車乗りの端くれとして、この「自転車は車道を走れ」は悲しい物があるものの、明らかに酷い走り方をしている人がいるのは事実だし、個人的にはそういった、我が物顔で歩行者の脇をすり抜けていく人に怒りを感じます。車道を走る時には車の交通状況を常に気にした上で車道走り、車の通行の妨げになると思った場合には、十分に歩行者との間隔を空けた上で、いつでも危険を回避できるように気を配って走っていている人までも、そういったマナーの悪い人たちと同じように見られるのはつらいです。

で、気になったのは、上記のニュースのこの部分です。

警察庁によりますと、自転車が歩行者に接触する事故は去年、全国で2625件と、10年連続で2000件を超え、死亡事故も5件起きるなど深刻な状態が続いています。

警察庁によると、

  • 10 年連続で 2000 件を超えている。
  • うち、死亡事故が 5 件ある。

という事は「深刻な事態である」として、自転車専用道の整備もできていない現状で、自転車を車道へ追い出している点です。

「じゃぁ、自転車と自動車の間の事故は、これよりも深刻ではないの?」と疑問に思いました。

警察庁」「自転車」「自動車」「事故」でググって見つかったのが下記の資料です。

自転車関連事故の状況(PDF)

この資料は、平成 13 〜 23 年の統計で、前述の報道で言われている資料より一年古いものだと思いますが、平成 23 年の事故は、

  • 自転車と自動車の事故件数: 121,004 件(うち死亡事故 556 件)
  • 自転車と歩行者の事故件数: 2,801 件(うち死亡事故 6 件)

とあります。少なくとも、「点」の数字としては、自転車と自動車の事故の方が圧倒的に多いし、事故全体に占める死亡事故の割合も、

  • 自転車と自動車: 556 / 121,004 = 0.46%
  • 自転車と歩行者: 6 / 2,801 = 0.21%

と、自動車との事故の方が高くなります。ちょっと単純すぎる比較*1ですが、自転車に乗る者にとって車道の方が危険である事には違いないでしょう。

ただ、トレンドとしては自動車と自転車の事故件数はこの 10 年あまりで 15 % 程度減少し、死亡事故に関しては 40% 近く減っているのに対し、歩行者との事故は 50 % 以上増加していて、死亡事故も 4〜6 人で推移している、ということから、自転車と歩行者の事故を減らすための対策が必要、という事に異論はありません。

自転車の信号無視の取り締まりをやっているニュース映像を見たことがありますが、こういった取り締まりの強化には賛成します。自転車の飲酒運転とか、夜間無灯火とか、傘を差したままの運転とか、明らかに危険な行為に対して、もっと厳しくて良いと思います。

ただ、歩行者との事故を減らすために「車道を走れ」というのは、自転車を乗る人に対して、より危険な選択を迫っていることになります。

「車道が原則」である事は分かりますが、そのために、より危険な方へ追い込むのは本末転倒な気が...

*1:例えば、そもそも交差点のように、自転車も歩行者も車道を通行する区間での事故の場合、自転車が通行していたのが、歩道とも車道とも言えない、とか。ただ、車両相互の追突事故だけでも 1,853 件あり、このケースの多くは車道走行中と思われる。