Posted on Mon Aug 11 23:44:00 +0900 2008 by nabeken
自宅のネットワークでは、NTT東からの RA と自分のネットワーク用(OCN IPv6経由)のRAを流しています。普段は問題なく外部と通信できていたのですが(OCN IPv6で貰ったアドレスがソースになっている)、とあるホストが 6to4 だったため、NTT東で貰ったアドレスがソースになり、通信できなくる問題に遭遇しました。
最初、相手側が悪いのではと思い(移行期なので、ほとんどがトンネリングなため不通なのが少なくないから)、連絡したところ、問題ないという返事が来ました。そこで、ようやく traceroute6 を行ない、ようやく問題の原因がわかりました。
原因はソースアドレスがNTT東のものになっていたためでした。このため、応答(正確には要求に対するリプライが届かない)がなかったというわけです。
Linuxでは複数のルーティングテーブルを持つことができます。この機能を Advanced Routing と呼んでおり、カーネルの設定で有効にする必要があります。
さらに、 kernel configration では Source Address based routing と Router Preference/Information(RFC 4191) Support があります。前者を有効にしないと/sbin/ip -6 rule add が失敗します。
iproute2パッケージの ip コマンドでどのように判断されるかを確認することができます。http://ornellas.apanela.com/dokuwiki/pub:firewall_and_adv_routing がわかり易いと思います。
# /sbin/ip -6 route get 2001:dc2:1000:2000::80 2001:dc2:1000:2000::80 via fe80::20c:29ff:fe8a:819 dev eth0 proto kernel src 2001:c90:78d:4908:20f:eaff:fe5a:5e5 metric 1024 expires 30110sec mtu 1500 advmss 1440 hoplimit 64
2001:dc2:1000:2000::80 は www.nic.ad.jp の AAAA です。この宛先にパケットを送る際、カーネルは上のように判断しているようです。この場合、ソースアドレスは src である 2001:c90:78d:4908:20f:eaff:fe5a:5e5 を使用し、 パケットは fe80::20c:29ff:fe8a:819 へ eth0 を通して投げるようです。このゲートウェイは OCN IPv6 と接続しているため、このソースアドレスは誤りです。
# /sbin/ip -6 route get 2001:200:0:8002:203:47ff:fea5:3085 2001:200:0:8002:203:47ff:fea5:3085 via fe80::20c:29ff:fe8a:819 dev eth0 proto kernel src 2001:380:e03:61:20f:eaff:fe5a:5e5 metric 1024 expires 30517sec mtu 1500 advmss 1440 hoplimit 64
2001:200:0:8002:203:47ff:fea5:3085 は www.kame.net の AAAA です。この場合は正しいソースアドレスが選択されています。が、これは偶然に過ぎないことは上の結果からもわかります。というわけで、以下のポリシを適用することにします。
ルーティングテーブルでデフォルトゲートウェイを指定します。これにより、適切なゲートウェイが選択されます。まず、現状のルーティングテーブルがどのようになっているかを確認します。デフォルトでは、 local, main の2つが用意されています。
# /sbin/ip -6 rule 0: from all lookup local 32766: from all lookup main # /sbin/ip -6 route list table local local ::1 via :: dev lo proto none metric 0 mtu 16436 advmss 16376 hoplimit 4294967295 local 2001:380:e03:61:20f:eaff:fe5a:5e5 via :: dev lo proto none metric 0 mtu 16436 advmss 16376 hoplimit 4294967295 local 2001:c90:78d:4908:20f:eaff:fe5a:5e5 via :: dev lo proto none metric 0 mtu 16436 advmss 16376 hoplimit 4294967295 local fe80::20f:eaff:fe5a:5e5 via :: dev lo proto none metric 0 mtu 16436 advmss 16376 hoplimit 4294967295 # /sbin/ip -6 route list table main 2001:380:e03:61::/64 dev eth0 proto kernel metric 256 expires 2592005sec mtu 1500 advmss 1440 hoplimit 4294967295 2001:c90:78d:4908::/64 dev eth0 proto kernel metric 256 expires 2592047sec mtu 1500 advmss 1440 hoplimit 4294967295 fe80::/64 dev eth0 metric 256 expires 21329445sec mtu 1500 advmss 1440 hoplimit 4294967295 ff00::/8 dev eth0 metric 256 expires 21329445sec mtu 1500 advmss 1440 hoplimit 4294967295 default via fe80::20c:29ff:fe8a:819 dev eth0 proto kernel metric 1024 expires 30372sec mtu 1500 advmss 1440 hoplimit 64 default via fe80::217:dfff:fe6e:f01a dev eth0 proto kernel metric 1024 expires 1685sec mtu 1500 advmss 1440 hoplimit 64
実は可変ソースアドレッシングポリシは Linux では最新版で実装されています。2.6.25 らしいので、gitから持ってこないとダメっぽいです。cf. http://member.wide.ad.jp/tr/wide-tr-usagi-addrpol-01.txt
というわけで、仕切り直して、上の USAGI プロジェクトの文章を参考に最新カーネルを用いて動作を確認してみます。テスト環境は VMware-server 上の Debian GNU/Linux ('etch') 上で linux-2.6.25-rc6 を自前でビルドしたものです。iproute2は以下の手順で git からcoしたものを使用しました。
UPDATE: 08/08/11 現在の Debian GNU/linux testing/sid では、 2.6.25 + iproute2-20080725 なため、自前ビルドせずに動きます。
# git clone git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git # aptitude install bison flex libdb3-dev # cd iproute2 # make
準備ができました。
# ip/ip addrlabel prefix ::1/128 label 0 prefix ::/96 label 3 prefix ::ffff:0.0.0.0/96 label 4 prefix 2001::/32 label 6 prefix 2002::/16 label 2 prefix fc00::/7 label 5 prefix ::/0 label 1 # ip/ip addrlabel help Usage: ip addrlabel [ list | add | del | flush ] prefix PREFIX [ dev DEV ] [ label LABEL ]
ちゃんと動いてます。このコマンドにより、RFC3484 (参考: http://www5d.biglobe.ne.jp/~stssk/rfc/rfc3484j.html#72) のソースアドレス選択の Rule6 を制御することができます。
同一インターフェースに
inet6 addr: 2001:c90:78d:4908:20f:eaff:fe5a:5e5/64 Scope:Global (SA) inet6 addr: 2001:380:e03:61:20f:eaff:fe5a:5e5/64 Scope:Global (SB)
がRAでついたとします。前者をアドレスSA、後者をSBと呼ぶとします。
宛先アドレスをDと呼ぶとします。
Rule1~5はともに等しい。Rule6も SA = SB = D = label 1 となるため、これも等しい。Rule7も同様。したがって、最後の最長一致となるため、これも等しくなります。したがって、集合の一番最初である SA が使用されます。
さて、ここで次のコマンドを使い、ラベリングを行います。
# ip/ip -6 addrlabel add prefix 2001:c90::/32 label 10
これは 2001:c90::/32 というプレフィクスを持つアドレスに `10' というラベルを貼ります。したがって、上の例での Rule6 が変わってきます。Rule6では、 SAのラベルは 10, SBのラベルは1、そして宛先のラベルは1、したがって、 SB = D となり、SBが優先となります。したがって、この時のソースアドレスはSBが選択されます。
最後にポリシーベースルーティングをすることで、適切なゲートウェイに転送できます。
# ip/ip -6 rule add to 2001:c90::/32 priority 100 table 100 # ip/ip -6 route add default via NTT東 table 100
以上によって、 2001:c90::/32 宛(フレッツスクエア)は通常のルーティングテーブルより前に評価され、デフォルトゲートェイを通過します。その時のソースアドレスは先程の Rule8 により、SAが優先されます(=2001:c90::/32以外の宛先については SB が優先される)。
6to4の扱いを検証する際にこの記事の誤りに気づきました。まず、prefixの表現方法の解釈を間違っていました。(参考: http://www.7key.jp/rfc/1884/rfc1884_22.html#text_rep_addresses)
prefixの先頭にある :: はそのままゼロを省略しているので、 ::/96 というのは、後ろ32ビットだけのIPv6アドレスです。また、2001::/32 というprefixは 2001:0000::/32 の省略であるため、 2001:380::/32 にはマッチしません。
さて、これらを踏まえて 2002::/16 ですが、この状況では 2001:c90::/32 だけ特別扱いできればいいので、ずばり 2002::/16 のラベルは削除することにしました。これで最後の ::/0 のデフォルトにマッチします。
次はBSD系での動作を確認してみようと思います。