~nabeken/diary/

Gentoo Linux(6年くらい)とFreeBSD(1年くらい)とOpenBSD(新参者)を使う日々。


IHANet BGP peering overview

Linux でのソースアドレス選択

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 です。この場合は正しいソースアドレスが選択されています。が、これは偶然に過ぎないことは上の結果からもわかります。というわけで、以下のポリシを適用することにします。

  • 2001:c90::/32 宛のパケットは routing table `100' を見る
    • このルーティングテーブルでは default をNTT東へ倒す
  • それ以外は routing table `main' を見る

ルーティングテーブルでデフォルトゲートウェイを指定します。これにより、適切なゲートウェイが選択されます。まず、現状のルーティングテーブルがどのようになっているかを確認します。デフォルトでは、 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

Linuxにおける可変ポリシ

というわけで、仕切り直して、上の 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 なため、自前ビルドせずに動きます。

iproute2 の準備

 # 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と呼ぶとします。

dest: 2001:dc2:1000:2000::80 (D) の場合

宛先アドレスを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 (2002::/16) の扱い

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系での動作を確認してみようと思います。

更新履歴

  • グーグルに引っかかりやすいように、見出しを更新、最近のDebianについて言及 (Mon, 11 Aug 2008 23:44:00 +0900)
  • 手動の更新記録を削除 (Wed, 14 May 2008 15:54:29 +0900)
  • 更新記録を自動生成 (Wed, 14 May 2008 15:53:34 +0900)
  • ヘッダとボディの分離 (Tue, 22 Apr 2008 12:54:18 +0900)
  • 更新履歴を更新 (Sat, 22 Mar 2008 06:10:35 +0900)
  • 更新履歴の順番を逆にした (Sat, 22 Mar 2008 06:06:42 +0900)
  • RFC1884を参考に修正 (Sat, 22 Mar 2008 06:05:30 +0900)
  • rule6じゃなくてrule8 (Fri, 21 Mar 2008 04:24:18 +0900)
  • 最後の一文を修正 (Fri, 21 Mar 2008 04:22:57 +0900)
  • ラベル名が間違ってたので修正 (Fri, 21 Mar 2008 04:20:34 +0900)
  • rebuildworld (Fri, 21 Mar 2008 04:11:55 +0900)
  • ブロック要素を字下げ (Fri, 21 Mar 2008 04:06:13 +0900)
  • RFC 3484を参考にルールの適用具合を書いた (Fri, 21 Mar 2008 04:03:44 +0900)
  • 初稿: source-address-selection-on-linux (Tue, 18 Mar 2008 16:42:47 +0900)
  • ip addrlabel を追試 (Tue, 18 Mar 2008 16:21:36 +0900)
  • source-address-selection と内容が被るので移動 (Tue, 18 Mar 2008 04:28:37 +0900)
  • ポリシを追加 (Sat, 15 Mar 2008 18:19:31 +0900)
  • 2.6.25以降に可変ソースアドレッシングが実装される (Sat, 15 Mar 2008 05:55:32 +0900)