ラベル ipv6 の投稿を表示しています。 すべての投稿を表示
ラベル ipv6 の投稿を表示しています。 すべての投稿を表示

2012/04/21

さくらVPS 2GでのIPv6接続

さくらのVPSが受付を再開したのでメモリ2GBのプランを申し込んでみました。

レスポンスはお名前.comのVPSが良いように感じますが、お名前.comのVPSはIPv6環境としては実用レベルの環境にする事は難しいと感じたので、さくらのVPSはIPv6を中心にみていく事にします。

カスタムOSへの変更

以前と環境を合わせるために、Debian6 amd64版をまずインストールしました。 その上で6rdでのIPv6環境を構築するために、パッケージをstableからtestingに変更しています。

/etc/apt/sources.listの内容

## for 6rd kernel
deb http://ftp.jp.debian.org/debian testing main contrib non-free
deb-src http://ftp.jp.debian.org/debian testing main contrib non-free
#

6rdのガイドに従ってカーネルを更新すると、関連した周辺パッケージも導入されるので、最終的には全体をtestingパッケージに合わせる事になると思います。

 # apt-get update
 # apt-get dist-upgrade

ping6による速度計測

まずは比較用に標準でIPv6をサポートしているDTI VPSまでのping6結果です。

比較用:自宅からDTI ServersMan@VPSまでのping6結果

PING 2001:2e8:601:0:3:1:0:bc(2001:2e8:601:0:3:1:0:bc) 56 data bytes
64 bytes from 2001:2e8:601:0:3:1:0:bc: icmp_seq=1 ttl=56 time=20.6 ms
64 bytes from 2001:2e8:601:0:3:1:0:bc: icmp_seq=2 ttl=56 time=21.0 ms
64 bytes from 2001:2e8:601:0:3:1:0:bc: icmp_seq=3 ttl=56 time=19.7 ms

次に6rdでIPv6アドレスを振ったさくらVPS 2Gまでのping6結果です。

自宅からさくらVPSまでのping6結果

PING 2001:e41:31d4:87d4::1(2001:e41:31d4:87d4::1) 56 data bytes
64 bytes from 2001:e41:31d4:87d4::1: icmp_seq=1 ttl=48 time=31.4 ms
64 bytes from 2001:e41:31d4:87d4::1: icmp_seq=2 ttl=48 time=31.6 ms
64 bytes from 2001:e41:31d4:87d4::1: icmp_seq=3 ttl=48 time=31.5 ms

まとめ

ping6の結果はTokyo6to4でIPv6化したお名前.comと比べると、だいたい10倍くらい早くなっています。ちなみにさくらVPSからwww.iij.ad.jpへのping6の結果をみると、前述の30ms台というのは自宅側に問題があって、さくらのVPSとDTIのVPSにレイテンシについては20ms前後で、違いはほとんどないようです。

体感的なパフォーマンスやIPv6を除いた全体的な印象では、お名前.comがお勧めです。 さくらのVPSでは、6rdが期限延長されたとはいえ、代替案なしにIPv6サポートとがなくなるリスクはありますが、IPv6が必要な方には、現時点でのベストチョイスの一つでしょう。

もちろんIPv6についていえばDTIのServersMan@VPSでも問題はないと思います。 私自身はIPv6対応DNSサーバーが必要なのでServersMan@VPSは現状のまま維持するとは思いますが、ip6tablesに対する不満は強く持っています。

DTIが現状のままであれば、将来さくらのVPSがIPv6を公式にサポートすれば完全に移行するでしょう。 そんな風に感じた数日間でした。

2012/04/17

お名前.comのVPS(KVM)でのIPv6接続

お名前.comのサーバーを少し使ってみて、パフォーマンスには驚くばかりです。 これが1ヶ月単位の契約でも1300円ちょっとというのは、言葉になりません。

さて自宅の中も外もIPv6環境を整えているので、サーバーとして使うにはなにかしらIPv6リーチャブルでないと困ってしまいます。

今回はTokyo6to4を使って、IPv6環境を設定してみました。

6to4を使う前提

Ipv6に対応する手段として6to4はお手軽で強力な方法ですが、Ipv4の固定アドレスが必要になります。 いわゆるVPSと呼ばれるものは、固定IPv4アドレスを持っているので、問題になることはないでしょう。

自宅のサーバーなんかを6to4に接続する場合には、固定IPv4アドレスの契約をしている事と、ホームルーター(ブロードバンドルーター)を自作するのがお勧めです。

Tokyo6to4設定方法

設定情報はTokyo6to4が「6to4の利用方法」としてまとめています。

何も難しくないというか、固定IPv4アドレスからグローバルアドレスを計算する方法ぐらいしか間違えそうな要素がありません。

手動でIPv6アドレスを計算していたので、この部分については、次のようなコマンドでも自動化できると思います。

 $ env LANG=C ip -4 -o addr | awk '!/127.0./ {sub("...$","",$4);split($4,list,"."); printf "2002:%02x%02x:%02x%02x::1\n",list[1],list[2],list[3],list[4];}'

さすがに、これはない。これなら固定IPv4を素直に人間が分解して、ガイドの通りprintfコマンドに渡した方が簡単ですね。

これでガイドの通りの設定を加えるとinterfacesファイル全体は次のようになります。

$ cat /etc/network/interfaces の出力結果


# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
iface eth0 inet dhcp

auto tun6to4
iface tun6to4 inet6 v4tunnel
        address 2002:cbbd:60af::1
        netmask 16
        gateway ::192.88.99.1
        local 203.189.96.175
        endpoint any
        ttl 64
設定の有効化

サービス開始前ならちゃんと再起動して確認した方がいいと思いますが、とりあえず設定を確認するのに再起動を繰り返すのは時間が無駄なので、次のコマンドで確認します。

$ sudo ifup tun6to4

設定を再度試すには$ sudo ifdown tun6to4で一度設定を戻してから試します。

うまくいけば再起動時にも判定されるか、reboot(shutdown -r now)して試しましょう。

各種アプリケーションからのIPv6アドレス指定方法

DNSにAAAAレコードを追加するまではIPアドレスを直接してして試すしかありません。

Tokyo6to4の設定確認方法にも載っているping6コマンドは、直接2002から始まるIPv6アドレスを渡します。

$ ping6 2002:cbbd:60af::1

しかし、firefoxなどのURLでは[]で括って渡してあげます。

http://[2002:cbbd:60af::1]/
$ wget 'http://[2002:cbbd:60af::1]/'

sshクライアントではping6と同じように2002で始まるアドレスを渡します。

$ ssh 2002:cbbd:60af::1

ここら辺がちょっと判りづらいところですよね。

本番運用する時の考慮点

とりあえずIPv4によるバックアップがあるので、IPv6へのサービス提供、サービスアクセスが常に必要でなければ6to4で十分な場合が多いと思います。固有なサービスを作りたいのであれば、避けるべきだと思います。

レイテンシについて6to4は早いとはいえず、IPv6に対応しているServersman@VPSが良いのは間違いありません。 とはいえIPv6に対応しているServersman@VPSのサーバー自身の可用性がいまいち信頼できないので、安定して稼働して欲しいなぁとは思っています。最近は調子が良いですけどね。

6to4サービスのレイテンシ

ping6の結果はだいたい15倍ぐらいの開きがあって、これが6to4サービスをサーバー側で使うことのネックになるでしょう。TCPのセッションを確立するだけで、だいたい1秒くらいかかる事になります。

$ ping6 2001:2e8:601:0:3:1:0:bc


PING 2001:2e8:601:0:3:1:0:bc(2001:2e8:601:0:3:1:0:bc) 56 data bytes
64 bytes from 2001:2e8:601:0:3:1:0:bc: icmp_seq=1 ttl=56 time=20.2 ms
64 bytes from 2001:2e8:601:0:3:1:0:bc: icmp_seq=2 ttl=56 time=20.2 ms

$ ping6 2002:cbbd:60af::1

$ ping6 2002:cbbd:60af::1
PING 2002:cbbd:60af::1(2002:cbbd:60af::1) 56 data bytes
64 bytes from 2002:cbbd:60af::1: icmp_seq=1 ttl=52 time=323 ms
64 bytes from 2002:cbbd:60af::1: icmp_seq=2 ttl=52 time=319 ms

ただ2002で始まるアドレスを使う6to4には逆引きDNSサービスが受けられます。 AAAAレコードを登録できるDNSサーバを持つ事が前提ですけれど、とりあえずはセカンダリDNSサービスに紛れる事にします。

2010/10/11

IPv6は脆弱なのか

プライバシーに対する懸念をやたら増幅して活動する人たちがいますが、それでもプライバシーは重要だと思います。

ただプライバシーは企業活動上の危機管理などと直交する問題を含んでいるため、一般的な仕様に含まれると少し面倒なことになりそうです。

プライバシーの懸念

IPv6はIPv4にはない機能が実装されています。 特にネットワークに簡単に接続できるように、IPv4では後付けだった仕組みが、IPv6では標準仕様に含まれています。

現状(IPv4)との違いについてセキュリティの観点から「 情報セキュリティ技術動向調査(2009 年下期) 4.IPv6セキュリティ」にまとめられています。

この中でプライバシーについて RFC3041RFC4941に触れて、MACアドレスを元にIPアドレスを設定した場合にネットワークを変えても機器が特定される可能性、解決策と関連する課題についてまとめられています。

IPv6アドレスのバーゲンセール

プライバシーの懸念が広がっていくと、より多くのランダム化されたIPv6アドレスを端末機器が要求し、湯水のようにIPv6アドレスが単一の物理ポートに割り当てられる時代がくるかもしれません。

つまりDHCPやらRAやらが割り当てた以外のアドレスをエンドユーザが要求するということですが、FirewallやらN-IDSやらの通信記録を元に端末を特定したいニーズは危機管理上、確実に存在しています。

機器毎にユニークなMACアドレスランダム化されたり、されなかったりするIPv6アドレス との対応を記録する仕組みは今でも必要ですが、今後はより重要になりそうな気がしています。

それもよく管理されている場所ではなくて、不特定多数が利用するような場所においてより必要に思えます。

保険としてのログの重要性

ネットカフェやらネットワーク管理者が存在しない中小企業など、ランダム化されたIPv6アドレスを使われたくないと思っていても、それは無理でしょう。

MACアドレスベースのフィルタをかけているつもりでも、元々IPv6は通信を許す方向で設計されていますから、DHCPからの割り当てが行なわれないだけでRAベースでは重複しないアドレスを割り当てるかもしれません。

何はなくともログを記録して残す仕組みがブロードバンドルータやら、ネットワーク機器ではより重要になりそうに思えます。

IPv6にするとより安全なのか

IPAの文書では総当たりのネットワーク探索や機器の特定といった点についてIPv4ネットワークとの違いに触れられていますが、現状よりも時間や投資のコストが違うというだけで、エンドユーザが考慮しなければいけない(プライバシーや侵入といった)脅威のレベルに違いはないと感じました。

現状の課題はIPv6でも引き続き

IPv6では機能が増える分だけ安全ではないようにみえますが、現状でもMACアドレスを詐称することが可能ですから、できることはいろいろあります。

ネットワークに接続する端末の選択

不正なブロードキャスト通信やMACアドレスの詐称に対応するためには、IEEE 802.1x認証だけが現状の解決策ではないでしょうか。

これからはMACアドレスフィルタと組み合せて、IEEE 802.1x認証を、ID/Passwordをキーボードから入力するという以外の、より一般的な形で普及することが必要そうに思えます。

例えばコーヒーメーカーをネットワークに接続する時の手順はどうなるでしょう。

  • 手元のAndroidやiPhone端末にコーヒーメーカーの管理アプリをダウンロードする
  • コーヒーメーカーと手元のスマートフォンをbluetoothで接続する
  • 設置責任者が持つ認証に必要な情報(ID/Password)を入力する
  • 構内WiFi網を経由して管理アプリは、コーヒーメーカーのMACアドレスをサーバに登録する
  • コーヒーメーカーをLANに接続する

bluetoothだけで良いんじゃない 、というのは置いておいて、このケースだとID/Passwordに相当する情報の漏洩が心配です。

その作業を行なう人と情報の組み合せが一致している事が必要です。

それなら接続に必要な情報は文字列としてのID/Passwordである必要ないわけで、スマートフォンに登録してボタン一つで送信すれば良いんじゃないかという感じがします。

漏洩を考えると公開鍵暗号の仕組みを取り入れるのが一番でしょうね。それも使い易い形で。

そもそもLAN内部からどうやってこのコーヒーメーカーサーバに接続するのかを考えれば、LAN内部のアプリケーションレベルでは サービスの発見能力 が問われそうです。

IPv6の長いアドレスを直接入力するような状況は避けたいですが、それを全部DNSで管理するというのは情報の信頼性を下げてしまいそうで、間違ったアプローチのように思えるからです。

さいごに

MACアドレスについては、下位層の話しですし、あまり議論されないんですよね。

現状のIPv4ネットワークでは機器を特定するためにMACアドレスを利用していたり、DHCPがIPを割り振る際に登録された機器かどうかみていたりします。

でもMACアドレスの偽造は簡単だし、ノートPCの裏側などに印字されている場合も多くて、産業スパイ等外部からその企業内部の秘密を守るというよりは、 社員がプライベートなPCを持ち込む事を防ぐ程度の役割 しかありません。

IPv6になっても、そういう状況に変化はないわけで、IPv4が枯渇するという理由以外にIPv6を導入する理由をみつけるのは難しいでしょうね。

それでもNATを使わずに機器が直接(Firewallを経由して)、外部のサーバと通信をするのは本格的でワクワクすると思うのは私だけでしょうか。

2010/02/28

racoonによるIPsec環境の構築

freeradiusを触った時に経路の暗号化をしないと潜在的なリスクがあると思ったので、IPsecをtransport modeで試してみる事にしました。

今回の鍵作成の作業はApache2用にSSLキーを作成した時と同じで、Ubuntu 8.04 LTSで行なっています。作成する鍵ファイルは次の3種類です。

  • newreq.pem - リクエストファイル。秘密鍵ファイルを作成するために使用
  • newkey.pem - 秘密鍵ファイル。newreq.pemを元にCAが署名し、生成される
  • newcert.pem - 公開鍵ファイル。newkey.pemと対になる

opensslやCA.plを使った鍵作成の手順を説明したサイトはいくつかありますが、独自のファイル名を使うため鍵ファイルの用途がわかりずらいと感じました。 この記事ではCA.plが作成するファイル名を踏襲しました。

今回の作業全体の流れは7.3.3.2 公開鍵を使った方法にある流れに従っています。 ただ、これだけでは不十分だったので、より正確な情報をIPsec HowtoThe PKIX certificate with racoon、それにipsec-tools.sourceforge.netからのリンク先にあるAutomatic keyingから補完しました。

なおIPsecが稼働するサーバはAlixとWRAPで稼働するDebian lennyです。

鍵ファイルの作成

CAとしてはApacheサーバ用にSSL用鍵ファイルを作成した時に使ったdemoCAをずっと使っていますが、手を広げ過ぎたので鍵ファイルの管理が煩雑になってきました。

そこで今回はIPsec用に中間CAを作成するところから始めました。 必要がなければ飛して既にあるdemoCAディレクトリを使えば良いと思います。

中間CA用demoCAの作成

まずは/usr/lib/ssl/misc/CA.plを使って、土台となるdemoCAディレクトリを準備します。 いま親CAのdemoCAディレクトリがみえるディレクトリにいるとして、中間CA用にサブディレクトリを作成する事にします。

$ mkdir demoCA.ipseq_ca
$ cd demoCA.ipseq_ca
$ /usr/lib/ssl/misc/CA.pl -newca

入力項目は任意なのでパスワードだけ忘れないようにしておきます。 この作業が終るとカレントディレクトリにdemoCAディレクトリが作成されています。

親CAによる中間CA用reqファイルの署名

いまはdemoCA.ipseq_caディレクトリ直下にいて、そこには"demoCA"ディレクトリだけが存在している状態を仮定します。

このディレクトリの中で単独のCAとして必要なものは揃っていますが、中間CAとなるために親CAに署名をしてもらう必要があります。 通常CAを作成するときに使うCA.pl -newcaコマンドでは、リクエストファイルを作成して、リクエストファイルへの署名をdemoCA内にある自身の秘密鍵で行なっています。

今回はその署名作業を親CAに行なってもらう必要があるので、いちど作成したcacert.pemを捨てて、改めてcareq.pemファイルを親CAに署名してもらいます。

$ cp demoCA/careq.pem ../newreq.pem
$ cd ..
$ /usr/lib/ssl/misc/CA.pl -signCA

ここまでの作業で"newreq.pem"ファイルが新たに作成されました。 これを中間CAのdemoCAディレクトリにコピーします。

$ cd demoCA.ipseq_ca
$ rm demoCA/cacert.pem 
$ mv ../newcert.pem demoCA/cacert.pem

ここでcacert.pemを削除せずに上書きしても良いのですが、作業内容をはっきりとさせるために削除するようにしています。

作業が終ったらnewreq.pemファイルは削除しておきます。

$ rm ../newreq.pem

これで中間CAを作成する作業は完了です。

IPsec用の鍵ファイルの作成

中間CAはできたので、IPsecで2点間の通信を暗号化するための鍵ファイルを作成します。 ここでは最終的に"newkey.pem", "newcert.pem"の2つのファイルを1セットとして作成します。 サーバ2台でテストをするために、合計で4ファイル、2セットを作成する事になります。

$ /usr/lib/ssl/misc/CA.pl -newreq
$ /usr/lib/ssl/misc/CA.pl -sign
$ mkdir server1
$ mv new* server1/

作業ではCommon Name(CN)をサーバのFQDNにしておきます。 作業の結果作成された"newkey.pem", "newcert.pem"ファイルをサーバ毎のディレクトリに分けておき、必要に応じて使う事にします。

続けて"server1"を"server2"と読み替えて、もう一度、この手順を繰り返します。

最後にserver1ディレクトリにserver2のnewcert.pemファイルをコピー(server2.newcert.pem)し、server2ディレクトリにも同様にserver1のnewcert.pemファイルをコピー(server1.newcert.pem)します。

ここまででserver1, server2ディレクトリにそれぞれ"newkey.pem"と"newcert.pem"ファイルと相手のnewcert.pemファイルが存在しているはずです。 treeコマンドを使うと、次のようなディレクトリ構造になっているはずです。

treeコマンド出力

|-- demoCA ## 親CA
|   |-- cacert.pem
.   .
.   .
.   `-- careq.pem
.   
`-- demoCA.ipsec_ca ## 中間CA
    |-- demoCA
    .
    .
    |-- server1/
    |   |-- newcert.pem
    |   |-- server2.newcert.pem
    |   `-- newkey.pem
    `-- server2/
       |-- newcert.pem
       |-- server1.newcert.pem
       `-- newkey.pem

実際のところはnewcert.pemとnewkey.pemが2組作れていれば良いので、この構造は参考に留めておいてください。 いろいろな鍵ファイルを作る手順をみていると、どこまでがMUSTで、どこからがSHOULDなのか判らないですよね…。

公開鍵方式を使ったIPsec接続

今回はracoonを使った鍵交換を行なうため、双方のシステムにracoonをインストールしておきます。

$ sudo apt-get install racoon
鍵ファイルの配置

サーバにserver1, server2ディレクトリをそれぞれコピーし、作成した鍵ファイルを/etc/racoon/certsディレクトリにコピーしておきます。 なお本当の環境では、サーバの秘密鍵"newkey.pem"はネットワークを経由する事はありません。相手側に渡さないように注意しましょう。

$ sudo mkdir /etc/racoon/certs
$ sudo cd server1
$ sudo cp newkey.pem newcert.pem server2.newcert.pem /etc/racoon/certs/

他方のserver2サーバにログインして、同様にファイルを配置します。

racoon.confファイルの作成

ファイルの設定方法は本家サイトのドキュメントが信頼性が高そうです。 この他のドキュメントはKAMEの流れを組む*BSD用だったり、少し古いとそのまま使えないものもありました。

exchange_mode main;を使う場合には、IPアドレスでの指定だけが使えるため、IPv6とIPv4の設定を分けていますが、内容は同じです。

server2側の/etc/racoon/racoon.confファイル

path certificate "/etc/racoon/certs";
remote 192.168.1.xx {
        exchange_mode main;
        my_identifier asn1dn;
        peers_identifier asn1dn;

        certificate_type x509 "newcert.pem" "newkey.pem";
	peers_certfile x509 "server1.newcert.pem";
	verify_cert on;
        proposal {
                encryption_algorithm aes;
                hash_algorithm sha1;
                authentication_method rsasig;
                dh_group modp1024;
        }
        generate_policy on;
	passive off;
}
remote 2001:03xx:xxxx:1::xxxx {
        exchange_mode main;
        my_identifier asn1dn;
        peers_identifier asn1dn;

        certificate_type x509 "newcert.pem" "newkey.pem";
        peers_certfile x509 "server1.newcert.pem";
	verify_cert on;
        proposal {
                encryption_algorithm aes;
                hash_algorithm sha1;
                authentication_method rsasig;
                dh_group modp1024;
        }
        generate_policy on;
        passive off;
}

sainfo anonymous {
        pfs_group modp768;
        encryption_algorithm rijndael, 3des;
        authentication_algorithm hmac_sha1, hmac_md5;
        compression_algorithm deflate;
}
CRLファイルの取り扱いについて

いまのところは、CRLやcacert.pemファイルの取り扱いについて、ちゃんとしたドキュメントをみつけられていません。 racoon.confのオプションには関連しそうなca_typeパラメータがありますが、使い方について明確な指示はみつけられませんでした。verify_certは相手方から送られてくるDNと手元のcertファイルのDNを比較するもののようで関係なさそうでした。

コードを少し追った限りではCRLのチェックはしているようにみえました。 しかしrevokeしたnewcert.pemファイルはpeers_certfileに指定した状態で、CRLファイルを配置してもhashファイルへのリンクを作成しても通信が拒否される事ありませんでした。

ハッシュファイルへのシンボリックリンクはc_rehashコマンドで行なうことができます。

$ sudo c_rehash /etc/racoon/certs

ここら辺の動きについてはもう少し確認が必要そうです。

/etc/racconディレクトリの内容

treeコマンドを使うと、現在の/etc/racoonディレクトリの構造は次のようになっています。

tree /etc/racoonの実行結果

/etc/racoon/
|-- certs
|   |-- server2.newcert.pem
|   |-- newcert.pem
|   `-- newkey.pem
`-- racoon.conf
ipsec-tools.confファイルの編集

少し古いドキュメントには/etc/setkey.confを編集する手順が載っていますが、Debian Lennyでは/etc/ipsec-tools.confファイルを編集します。 起動時に/etc/init.d/setkeyスクリプトが、/etc/rc2.d/S??setkey経由で実行されて、ipsec-tools.confの内容が反映されることになります。

/etc/ipsec-tools.confファイル

#!/usr/sbin/setkey -f
#
flush;
spdflush;

## out rule (local -> remote)
## IPv4
spdadd 192.168.10.xx 192.168.1.yy any -P out ipsec
           esp/transport//require;
## IPv6
spdadd 2001:03xx:xxxx:10::xxxx 2001:03xx:xxxx:1::yyyy any -P out ipsec
           esp/transport//require;

## in rule (remote -> local)
## IPv4
spdadd 192.168.1.yy 192.168.10.xx any -P in ipsec
           esp/transport//require;
## IPv6
spdadd 2001:03xx:xxxx:1::yyyy 2001:03xx:xxxx:10::xxxx any -P in ipsec
           esp/transport//require;
稼働確認

両方のサーバで次のようにプロセスを再起動する事で設定が完了します。

$ /etc/init.d/setkey restart
$ /etc/init.d/racoon restart

さいごに

IPsecを使ってみて気になったことをまとめておきます。

煩雑な設定

相手方を指定するところでは個別にpeers_certfileなどを指定する必要があるため、サイト全体に拡張しようとするとかなり煩雑になりそうです。 ファイルを互いに交換する仕組みだと鍵交換がn*(n-1)回必要になるので公開鍵方式の利点を殺したような状態になっています。

まぁネットワーク層レベルの仕組みですから、何を信頼するかという議論もあると思うんですけどね。

とはいえracoon.confファイルはincludeで、外部ファイルを読み込む事ができるので、他で検証した設定ファイルとpemファイル一式を展開してあげれば、だいたい安全に自動化ができそうな気配です。

しかしpeers_certfileはdnssecを引数に取るので、これが使えるかもしれないと思っています。 時間をみつけて検証していこうと思います。

おかしな挙動

試したdebian lenny同士の接続では、ipsec-tools.confでAHを有効(ah/transport//require;付き)にした状態で、しばらく使っていると反応がなくなりハングアップしてしまいました。

うまく動かなかったipsec-tools.conf設定

...
## IPv6
spdadd 2001:03xx:xxxx:10::xxxx 2001:03xx:xxxx:1::yyyy any -P out ipsec
    esp/transport//require
    ah/transport//require;
...

これはpmtu関連のメッセージが大量にでていて、どうやら途中の経路にあるルータのMTUが1500よりも低いことが原因のようでした。 このルータをはさまないようにスイッチングハブのみを経由して互いを接続したところ、この問題は発生しませんでした。

ただIPv4は無事に接続できたのですが、IPv6だけはエラーになってしまいました。

racoonのエラーメッセージ

...
Mar  1 08:59:26 localhost racoon: ERROR: phase1 negotiation failed due to time up. ac92e25b5eb92084:0000000000000000
Mar  1 08:59:37 localhost racoon: ERROR: phase2 negotiation failed due to time up waiting for phase1. ESP 2001:3e0:a31:10:20d:b9ff:fe12:f284[500]->2001:3e0:a31:10:20d:b9ff:fe03:4154[500]
...

これはracoonが正常に動いていないようにみえるのですが、ともかく設定を再び行ないます。

$ sudo /etc/init.d/racoon stop
$ sudo /usr/sbin/setkey -F
$ sudo /usr/sbin/setkey -FP

2,3分ほどしたら再び起動します。

$ sudo /etc/init.d/racoon start

両方のサーバでracoonが起動した事を確認します。 次にsetkeyでSPDを更新します。

$ sudo /etc/init.d/setkey restart

これで無事にIPv4, IPv6ともにtransport modeでIPsecを動かす事ができました。 たぶん/etc/ipsec-tools.confでAHを有効したり、無効にしたり編集している間におかしくなったんだと思います。

それにしても元々の問題はpmtuが正常に動けば問題ないはずなのですが、この直結に近い状態でもmtuの高い側から低い側へ接続すると比較的データ量の多そうな通信の応答がなくなってしまいます。 これはVMWare上でも同様の動きをしています。 tcpdumpでみるとARPやらICMPv6 Neighbor Discoveryには正常に反応しているので、接続は切れずにこのまま画面が固まり続けるんでしょうね。

試しにこの状態で$ sudo setkey -F$ sudo setkey -FPを実行すると、反応は戻ってきました。 /etc/init.d/setkeyをリスタートしてみると、やはりまた元に戻ってしまいます…。 う〜ん、困ったなぁ…。

racoonプロセスの稼働状況

sshで相手方に接続している最中にどちらかのracoonプロセスを再起動すると、次のログのようにSADが再構成されるため、その間は通信ができなくなります。 切断はしませんでしたが、入力した文字はバッファに入ったまま応答がなくなってしまうので、使い方によってはクリティカルかもしれません。

/var/log/daemon.logから抜粋

...
Feb 28 13:38:16 localhost racoon: INFO: respond new phase 2 negotiation: 192.168.10.yy[500]<=>192.168.1.xx[500]
Feb 28 13:38:16 localhost racoon: INFO: Update the generated policy : 192.168.1.xx/32[500] 192.168.10.yy/32[500] proto=any dir=in
Feb 28 13:38:16 localhost racoon: INFO: IPsec-SA established: ESP/Transport 192.168.1.xx[0]->192.168.10.yy[0] spi=250681865(0xef11a09)
Feb 28 13:38:16 localhost racoon: INFO: IPsec-SA established: ESP/Transport 192.168.10.yy[500]->192.168.1.xx[500] spi=221824184(0xd38c4b8)
Feb 28 13:38:16 localhost racoon: ERROR: such policy does not already exist: "192.168.1.xx/32[500] 192.168.10.yy/32[500] proto=any dir=in"
Feb 28 13:38:16 localhost racoon: ERROR: such policy does not already exist: "192.168.10.yy/32[500] 192.168.1.xx/32[500] proto=any dir=out"
...

2010/02/12

AlixでのIPv6接続の自動化を試してみる

Alixで作成したブロードバンドルータを再起動した時に、自動でfeel6へ接続しIPv6通信ができるようにしました。 単純にいくつかのスクリプトを作成して、組み合せただけですけどね。

修正 & 作成したスクリプトについて

今回作成したスクリプトは次の通りです。

  • /usr/local/sbin/yadtcpc.pl
  • /usr/local/sbin/ipv6_up.sh
  • /usr/local/sbin/ipv6_down.sh

起動時に呼ばれるスクリプトは"ipv6_up.sh"で、"ipv6_down.sh"は停止時、及び、メンテナンス用のスクリプト。 yadtcpc.plは"ipv6_up.sh"が内部的に呼び出すため、明示的に実行する必要はありません。

/usr/local/sbin/yadtcpc.pl

前回の投稿で紹介したNet::POP3モジュールを使ったDTCPクライアントです。少し変更して、DTCP接続時に渡された情報を標準出力ではなくファイルに出力するようにしました。 接続時には、このファイルから必要な情報を読み取るようにしています。

/var/run/yadtcpc.infoファイル

local=219.xxx.xxx.xxx,remote=43.244.xxx.xx,prefix=2001:03xx:xxxx::,mask=48

また内部では適当なwaitを入れてループしていますが、"/var/run/yadtcpc.control"ファイルから停止の指示があるとquit()により接続を切って全体の処理を中断します。 停止したい場合には$ echo exit | sudo tee /var/run/yadtcpc.controlのようなコマンドを実行します。

前回作成したpackage YADtcpc;はそのまま使い、後ろにあるmain処理全体を次のようなコードで置き換えています。

差し替え個所

...
################
## main class ##
################
package Main;

sub new {
  my ($class) = @_;
  my $self = {
    dtcpc => undef,
    local => undef,
    remote => undef,
    prefix => undef,
    mask => undef,
  
    feel6_remote => "dtcp.feel6.jp",
    feel6_port => 20200,
    feel6_id => undef,
    feel6_password => undef,
  };

  bless $self, $class;
  return $self;
}

sub connect {
  my ($self) = @_;

  if($self->{dtcpc}) {
    $self->{dtcpc}->quit();
    $self->{dtcpc} = undef;
  }
  $self->{dtcpc} = YADtcpc->new($self->{feel6_remote}, Port=>$self->{feel6_port});
  ($self->{local}, $self->{remote}, $self->{prefix},$self->{mask}) = $self->{dtcpc}->dtcp($self->{feel6_id}, $self->{feel6_password});

  $self;
}

sub write_log {
  my ($self, $log_file) = @_;
  if(open(LOG, ">$log_file")) {
    printf LOG "local=%s,remote=%s,prefix=%s,mask=%s\n", $self->{local}, $self->{remote}, $self->{prefix},$self->{mask};
    close(LOG);
  }

  $self;
}

## for debug purpose only
sub print_log {
  my ($self) = @_;
  printf "local=%s,remote=%s,prefix=%s,mask=%s\n", $self->{local}, $self->{remote}, $self->{prefix},$self->{mask};
  $self;
}
sub ping_pong {
  my ($self, $check_file) = @_;
  while ($self->{dtcpc}->ping() =~ /pong/i) {
    if(open(CHECK, $check_file)) {
      my $check = <CHECK>;
      if($check =~ /exit/i) {
        $self->{dtcpc}->quit();
        exit;
      }
      close(CHECK);
    }
    sleep 210; ## essential to send 'ping' within five minutes intervales.
  }

  $self;
}

##########
## main ##
##########
my $main = Main->new();
$main->{feel6_remote} = "dtcp.feel6.jp";
$main->{feel6_port} = 20200;
$main->{feel6_id} = "xxxxxxxx";
$main->{feel6_password} = "xxxxxxxx";

my $info_file = "/var/run/yadtcpc.info";
my $control_file = "/var/run/yadtcpc.control";
do {
  $main->connect();
  $main->write_log($info_file);
  $main->ping_pong($control_file);
  sleep 1;
} while(1);

__END__

あとはPIDを"/var/run/yadtcpc.pid"辺りに書き出して、コマンドの起動時に重複起動のチェックをしようかなと思っています。

/usr/local/sbin/ipv6_up.sh

内部では次のような処理を行なっています。

  • DTCPクライアント(yadtcpc.pl)の起動
  • /var/run/yadtcpc.infoファイルの読み込み
  • デフォルトルートの設定
  • eth1, eth2へのユニキャストアドレスの設定、及びルーティング
  • RAサーバ(radvd)の起動

/usr/local/sbin/ipv6_up.shファイル

#!/bin/bash

umask 022
PATH=/sbin:/usr/sbin:/bin:/usr/bin
LANG=C
export PATH LANG

function ipv4to6addr {
  ## main process
  ipv4_1="$(echo $1 | cut -d'.' -f1)"
  ipv4_2="$(echo $1 | cut -d'.' -f2)"
  ipv4_3="$(echo $1 | cut -d'.' -f3)"
  ipv4_4="$(echo $1 | cut -d'.' -f4)"

  printf "%02x%02x:%02x%02x\n" "${ipv4_1}" "${ipv4_2}" "${ipv4_3}" "${ipv4_4}"
}

## start the my DTCP client
## - first remove the control file
YADTCPC_FILE=/var/run/yadtcpc.control
test -f ${YADTCPC_FILE} && rm ${YADTCPC_FILE}
## - start the client
/usr/local/sbin/yadtcpc.pl &
## - waiting to finish the DTCP configuration
sleep 5

YADTCPC_FILE=/var/run/yadtcpc.info
if test -f ${YADTCPC_FILE}; then
  IPV6_LOCAL="$(cat ${YADTCPC_FILE}|cut -d, -f1|cut -d= -f2)"
  IPV6_REMOTE="$(cat ${YADTCPC_FILE}|cut -d, -f2|cut -d= -f2)"
  IPV6_PREFIX="$(cat ${YADTCPC_FILE}|cut -d, -f3|cut -d= -f2)"
  IPV6_MASK="$(cat ${YADTCPC_FILE}|cut -d, -f4|cut -d= -f2)"
else
  exit 1
fi

## setup sit device
ifconfig sit0 up tunnel ::${IPV6_REMOTE} mtu 1454
route -A inet6 del ::/0 dev eth0
DEV_NAME="$(ifconfig | grep ^sit | grep -v sit0 | head -1 | cut -d' ' -f1)"
test "${DEV_NAME}" && route -A inet6 add ::/0 dev "${DEV_NAME}"

## setup network address
DEV1_IP="$(ip -f inet addr show eth1 | tail -1 | awk '{print $2}' | cut -d/ -f1)"
DEV1_NET="$(echo ${IPV6_PREFIX}|sed -e 's/::/:/')1"
ip -f inet6 addr add ${DEV1_NET}::$(ipv4to6addr ${DEV1_IP})/64 dev eth1
ip -f inet6 route add ${DEV1_NET}::/64 dev eth1

DEV2_IP="$(ip -f inet addr show eth2 | tail -1 | awk '{print $2}' | cut -d/ -f1)"
DEV2_NET="$(echo ${IPV6_PREFIX}|sed -e 's/::/:/')10"
ip -f inet6 addr add ${DEV2_NET}::$(ipv4to6addr ${DEV2_IP})/64 dev eth2
ip -f inet6 route add ${DEV2_NET}::/64 dev eth2

## start radvd
INIT_RADVD=/etc/init.d/radvd
if test -f ${INIT_RADVD}; then
  ${INIT_RADVD} start
fi

/usr/local/sbin/ipv6_down.sh

内部の処理は、ほぼ起動時の処理の逆ですが、既にLAN内部でIPv6を使った接続済みのセッションを切断しないようにデバイスのIPv6アドレス、及び、ルーティング情報は削除していません。

/usr/local/sbin/ipv6_down.shファイル

#!/bin/bash

umask 022
LANG=C
PATH=/sbin:/bin:/usr/bin/:/usr/sbin
export LANG PATH

if test -f /var/run/yadtcpc.info; then
  IPV6_LOCAL="$(cat /var/run/yadtcpc.info|cut -d, -f1|cut -d= -f2)"
  IPV6_REMOTE="$(cat /var/run/yadtcpc.info|cut -d, -f2|cut -d= -f2)"
  IPV6_PREFIX="$(cat /var/run/yadtcpc.info|cut -d, -f3|cut -d= -f2)"
  IPV6_MASK="$(cat /var/run/yadtcpc.info|cut -d, -f4|cut -d= -f2)"
fi

## stop the my DTCP client
echo exit > /var/run/yadtcpc.control

## list up sit+ devices other than sit0
DEV_LIST="$(ifconfig | grep ^sit | grep -v sit0 | cut -d' ' -f1)"

## stop radvd
INIT_RADVD=/etc/init.d/radvd
if test -f ${INIT_RADVD}; then
  ${INIT_RADVD} stop
fi

## down devices
for sit_dev in ${DEV_LIST}
do
  route -A inet6 del ::/0 dev ${sit_dev}
  ip link set ${sit_dev} down
  ip tunnel del ${sit_dev}
done

/etc/network/interfacesファイルの修正

ファイルを配置してから、interfacesファイルを編集します。 再起動の後で$ ping6 www.kame.netが成功する事を確認しています。

interfacesファイル変更後

auto dsl-provider
iface dsl-provider inet ppp
  pre-up /sbin/ifconfig eth0 up # line maintained by pppoeconf
  provider dsl-provider
  post-up /usr/local/sbin/config_iptables.sh
  post-up /usr/local/sbin/config_ip6tables.sh
  post-up /usr/local/sbin/ipv6_up.sh
  pre-down /usr/local/sbin/ipv6_down.sh

2010/02/11

IPv6 + TCP Wrapperでのnetmaskの取り扱いについて

LAN内部での事ですが、DNSにAAAAレコードを追加し、Ipv6を使ってサーバに接続するようになりました。 しかしAlixで作成したゲートウェイにIPv6経由でSSH接続したときだけ、タイムアウトをしているかのような動きになったので原因を追ってみました。

エラーの内容::クライアント編

サーバ側に出力されたログでは、原因が直感的にはわかりませんでした。 一般的にサーバ側は誰かに管理されていて、ログをみたり設定の変更ができる事は少ないですよね。 そんなわけでsshで困った時にはクライアント側で-vオプションを使うのがお勧めです。

$ ssh -v 2001:03xx:xxxx:1::c0a8:0101

出力されたエラーの内容

OpenSSH_4.7p1 Debian-8ubuntu1.2, OpenSSL 0.9.8g 19 Oct 2007
debug1: Reading configuration data /home/yasu/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to 2001:03xx:xxxx:1::c0a8:0a01 [2001:03xx:xxxx:1::c0a8:0a01] port 22.
debug1: Connection established.
debug1: identity file /home/yasu/.ssh/identity type 0
debug1: identity file /home/yasu/.ssh/id_rsa type -1
debug1: identity file /home/yasu/.ssh/id_dsa type 2
ssh_exchange_identification: Connection closed by remote host

エラーの内容::サーバ編

ちなみにサーバ側では次のようなログでした。

サーバ側の/var/log/auth.logファイル抜粋

Feb 11 18:07:56 xxxxxxxx sshd[5424]: refused connect from 2001:03xx:xxxx:1::xxxx (2001:03xx:xxxx:1::xxxx)

サーバ側で接続を拒否しているかのような動きですが、すぐには原因が思いつきませんでした。

解決編

結局のところ原因は、/etc/hosts.allowにIPv4用のTCP Wrapper(libwrap)の設定を書いていたことでした。

原因がわかればなんてこともないのですけどね。 修正内容はhosts.allowにIPv6用の設定を追加しただけなのですが、ネットマスクを使ったルールの書式が少し判りずらいかなと感じました。

追加した/etc/hosts.allowファイル

ALL: 192.168.1.0/24 192.168.10.0/24 [2001:03xx:xxxx::]/48

ブランケットの中に/48を入れてしまうとうまく動きません。

今回はiptablesの保険として設定しておいたTCP Wrapperがちゃんと仕事をしてくれた事でトラブルになってしまいました。 まぁIPv6用の設定方法もわかったし、良しとしましょう。

2010/02/07

IPv6への移行は円滑に進むのか

ここはブログというよりも最近はメモ帳になっています。 今回はさっき投稿したip6tablesについてまとめている途中で書いていた文章をベースにしています。 少しぐちっぽいかもしれません。

IPv6への対応状況

実際にIPv6へ接続し、利用してみると、それなりに思うことがでてきます。

エンドユーザーの状況

端末からIPv6ネットワークへの接続自体はPHS以外にも各ISPが積極的にサービスを提供しています。 いってみればエンドユーザは、既にIPv6への接続準備が終りつつあるのが現状だと思います。

もちろんエンドユーザ側でのルータの新規購入とか、そういうコスト負担は必要です。 しかし、極端な話し、Internetを使いたいならそのコストを負担するべし、という事になり従うだけでしょう。 とはいえ、市販されているブロードバンドルータのIPv6対応があまり進んでいない事がかなり心配です。 まぁ「IPv6家庭用ルータガイドライン」も2009年6月にver. 1.0が出たぐらいですから、これから本格的に進むのでしょう。

サーバ側の状況

しかしサービスのIPv6対応はあまり進んでいない印象です。 IPv6普及・高度化推進協議会は「IPv4サーバ環境へのIPv6導入ガイドライン」を公開していますが、Web関連したサービスを提供する事業者に限定した文書になっています。

お名前.comのようなレジストリが提供しているDNSサービスで、IPv6のAAAAレコードを登録できると表明しているところを見つける事はできませんでした。 IIJなど登録できるDNSサーバがないわけじゃないですけれど、使えないところが圧倒的に多い印象です。 普段IPv4で使っているところが使えないことは、ごくごく普通に起こっていることです。

趣味でIPv6を使えるようにしてDNSがおまけで使えればおもしろいと思うんですよね。

エンドユーザからみれば、IPv4 or IPv6を意識する必要はないですが、水面下ではサーバ側(サービス)の対応が大きな問題になるように思えます。

サービスのIPv6移行

アドレスが枯渇するとはいっても、エンドユーザはCATVが導入している悪名高いキャリアグレードNATによりIPv4を使い続けることができます。

しかしサーバ側は固定IPv4アドレスを消費するため、将来的には市場から高価なIPv4アドレスを買い上げるという事が起こるでしょう。 その割り当ても効率的に行なえているわけではないですが、市場原理が働けばエンドユーザのIPv4アドレスは取り上げられISPによって企業向けに売られる事になるでしょう。

Webサーバの状況

サーバの中でもWebサーバは比較的対応が進んでいるのではないでしょうか。 その背景にはその多くが独立して稼働しているという事情も影響しているかもしれません。 Webサーバがクラスタ化されていても、実際にはフロントエンドのProxyサーバがIPv6に対応すればバックエンドはIPv4のプライベートアドレスのままで済むからです。

またWebサーバは組織の中になく、レンタルサーバを借りているだけという状況もあるでしょう。

SMTPサーバの状況

しかしSMTPサーバは通常は組織の内部に配置されています。 よく使うMLのMXレコードなど限られた範囲を調べた限りでは、ほとんどIPv6へは対応していないようです。 そもそもサーバ間の連携が必要なメールシステムでは一方だけがIPv6をしゃべれても意味がないでしょう。 それぞれIPv4とIPv6だけに対応しているSMTPサーバ間の通信をどうやって解決するのか興味深いところです。

また組織内部に配置されたSMTPサーバのトポロジを注意深く設計しないと、部分的にIPv6を導入したとたんにメールが届かないという状況も生まれそうです。

相手のいるサービスは頑張らないとIPv6に対応できない

まぁSMTPサーバだけがIPv4とIPv6アドレス両方を持たないといけないとか、そんな事は許されないでしょう。 かといってゲートウェイを経由するとなるとパフォーマンスやセキュリティの観点から、望ましい状況ではないですね。 ゲートウェイの前後をタッピングすればメールの内容がみえちゃいますから。 いまもそうですが、狙うところがより明確になるのが嫌です。

有名どころの大学をざっとみたところだと学術系でもサーバのIPv6対応は少ないようです。 IPv6対応がIPv6に特化したネットワークや基幹系ルータなどに留まっているように見えるのは少し先行きが心配です。

エンドユーザはISPが頑張ってIPv6アドレスを押し付けたり、OSがデュアルスタックを裏側で準備して何事もなくIPv6ネットワークに接続されるでしょう。 しかしサーバは、そう簡単に行きそうにありません。

サーバ/ネットワーク管理の状況

私自身はIPv4の経験はそれなりにありますが、IPv6については趣味で家庭のLANを接続するぐらいで、企業の基幹システムレベルのIPv6網を触った経験はありません。 ただそこにIPv6ネットワークが容易に構築されるとは到底思えません。

いきなりIPv6へ移行するわけではなく、部分的であっても最低数年間はIPv4とIPv6の両方のネットワークを管理する必要があるからです。

既存インフラへのIPv6ネットワークの追加

IPv4で稼働している対外的なサーバにIPv6を割り振る作業自体は簡単だと思います。

問題はバックエンドのシステムのIPv6対応をどうするかでしょう。 フロントエンドがIPv6に対応すればバックエンドはIPv4のままで良いという状況もありそうです。

オフィスエリアからの通信はIPv6になって、ゲートウェイを経由しないとIPv4なバックエンドサーバにアクセスできないというのは、冗談ですが、ある意味セキュアかもしれません。

普通はIPv4アドレスの割り振りの手続きが組織毎に決められているでしょうし、重複するような方法でさらに長いIPv6アドレスも管理するとなると、やってられないという心理的な抵抗はありそうです。

管理者のマインドは、しばらくIPv4アドレスでサーバを管理するという状況から抜けないように思います。 いきなりIPv6で全部を考えることはできないでしょうし、メリットもなさそうです。

IPv6に対応したエンドユーザが利用する範囲をIPv6に対応させていく、そういう状況が想像できます。 新規の環境は少なくともIPv4/IPv6のデュアルスタックになって、IPv4を捨てる日はそう近くならないでしょう。

インフラ管理者がIPv4、IPv6両対応のコストを払うのでしょう

しばらくは(実際は相当な長期間)IPv4アドレスでイントラネットが設計され続けるでしょうし、IPv6をバックエンドサーバの接続で使うことはないのかもしれません。

さきほど冗談で書いたIPv4の方が、むしろセキュアだとか屁理屈をつけてIPv4に留まろうと不毛な努力をするのかもしれません。 いずれにしても、そんなカオスな状況にあるインフラのIPv6移行へのコストは管理者が払うのでしょうね。

IPv4の資産を継承しないと決めた上位の決定は、結局のところ最終的に下位のインフラ管理者のところに、そのコストを転嫁しただけといえるのかもしれません。 技術的には理解できる決定ですし、正しいとは思います。 けれどコスト負担の構図は全員が正しく理解する必要があるでしょう。

現場が苦労して、それを利益を教授する人が意識もしないというのは、現代文明の性ですが寂しいところです。

さいごに

IPv6の導入のような大規模な変更こそ、既存の環境に加える形で、小さく導入して大きくしていく戦略が有効に思えます。 しかし、使わない or いつ使うかわからないIPv6のために、稼働確認の予算追加が認められるわけもないし、きっとどこかで困らないと進まないんでしょうね。

日本はIPv6の必要性を十分に認識していると思います。 しかし先を見通して先手を打てない状況は、(日本に限った事ではないですが)現代の日本が抱えているいろいろな問題の根本原因にもつながる体質のように思えます。

ネットワークが経済に与える影響を考えれば、サーバ側のIPv6対応はエンドユーザのIPv6対応以上に真剣に検討されなければいけないでしょう。

サービス(URL)にアクセス可能なサーバと不可なサーバが生まれれば、SOAなんていう単語が笑い飛ばされてしまうでしょうね。 実際、そういう状況に向いつつあると思います。 いきなりIPv6へ移行するのではなく、もっとゆるやかで長期的なプランを描いて、早く実行しておくべきだったんでしょうか。この事から何を学ぶべきなんでしょう。

2010/02/06

IPv6 - ip6tablesによるFirewall設定

IPv6用の設定にはip6tablesコマンドを使用します。 今回のスクリプトの中はだいたい、次の図のような流れになっています。

The ip6tables Process Flow

基本的な構成について

Feel6を使ったIPv6接続は、まだ手動で接続しています。 アドレス空間が膨大でDNSサーバに登録していないとはいってもポートスキャンの脅威がないわけではないですからね。接続の自動化よりもFirewallの設定を先にする事にしました。

設定したFirewallルールの確認

外出用にPHSカードは持っていて、IPv4のFirewallチェックにも使いました。 PRINはIPv6用のトンネルインタフェースも提供しているので、何も考えなくともPHSモデム経由でIPv6で接続する事ができるようになっています。

PRINのIPv6提供は実験的サービスのようですが、これが使えて助かりました。

PHSが使えると気がつくまでは、稼働の確認にSubnetOnline.comONLINE PING IPV6とONLINE PORT SCANNER IPV6も使いました。 IPv4向けにはいろいろなサービスがあるんですけどね、IPv6に対応した接続確認サービスを提供しているところは案外少ない印象です。

スクリプトの作成方針

まだ十分にIPv6の構造について勉強が進んでいるわけではないのですが、 とりあえず現行のIPv4用のiptables設定をベースにしています。

TCPヘッダのフラグチェックは同様に必要だよね、UDPも動きに変更ないよね、とか思いながら設定を削ったり付け加えたりしています。 ICMPはICMPv6になり機能は増え、考え方は変っていませんが、ARPの代替機能を持ったりしています。

ICMPv6は基本的に制限を加えない事にしました。 その代りログに出力をさせて将来必要なものと不要なものを振り分けるルールを追加しようとしています。 もし制限を加えるのであれば、後ろ向きですがecho-replyのように不要なものを個別に設定するのが良さそうです。

ログの取り方

使用頻度が低そうなところではログを取るようにしています。 必要に応じてACCEPT⇔logaccept、DROP⇔logdropを変更して使っています。

config_ip6tables.shスクリプト

次のようなスクリプトを/usr/local/sbinに配置して、interfacesファイルの中でpost-upに指定しています。

/etc/network/interfacesファイルの設定抜粋

auto dsl-provider
iface dsl-provider inet ppp
  pre-up /sbin/ifconfig eth0 up # line maintained by pppoeconf
  provider dsl-provider
  post-up /usr/local/sbin/config_iptables.sh
  post-up /usr/local/sbin/config_ip6tables.sh

ここで指定しているconfig_ip6tables.shの全体は次のとおりです。

config_ip6tables.shスクリプト

#!/bin/bash

## Initialize Script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

#######################
## Initialize Chains ##
#######################
ip6tables -F
ip6tables -X
ip6tables -Z

ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
ip6tables -P FORWARD DROP

########################
## Creating new rules ##
########################
ip6tables -N insit  ## from internet to home-lan
ip6tables -N outsit ## from home-lan to internet
ip6tables -N logdrop        ## logging rule
ip6tables -N logaccept      ## logging rule
ip6tables -N dumpdrop       ## for un-expectation connections
ip6tables -N deny_ip_flags  ## for ip flag check
ip6tables -N deny_localaddr ## for local ip address group

## [logdrop] Prepare the logging interface
IP6TABLES_OPTS="-m limit --limit 5/minute -j LOG"
ip6tables -A logdrop ${IP6TABLES_OPTS} --log-level warn --log-prefix "netfilter6 drop "
ip6tables -A logdrop -j DROP

## [logaccept] Prepare the logging interface
ip6tables -A logaccept ${IP6TABLES_OPTS} --log-level debug --log-prefix "netfilter6 accept "
ip6tables -A logaccept -j ACCEPT

## [dumpdrop] Prepare the logging interface
ip6tables -A dumpdrop ${IP6TABLES_OPTS} --log-level warn --log-prefix "netfilter6 dumpdrop "
ip6tables -A dumpdrop -j DROP

## [deny_ip_flags] Prepare the logging interface
ip6tables -A deny_ip_flags ${IP6TABLES_OPTS} --log-level error --log-prefix "netfilter6 ipflagcheck "
ip6tables -A deny_ip_flags -j DROP

## [deny_localaddr] Prepare the logging interface
ip6tables -A deny_localaddr $IP6TABLES_OPTS} --log-level error --log-prefix "netfilter6 deny_localaddr "
ip6tables -A deny_localaddr -j DROP

##############################
## prepare the lo interface ##
##############################
ip6tables -A INPUT -i lo -j logaccept
ip6tables -A OUTPUT -o lo -j logaccept

##########################################
## prepare sit+ interfaces without sit0 ##
##########################################
## [insit] Default Chain Policy from outside attackers.
ip6tables -A INPUT   -i sit+ -j insit
ip6tables -A FORWARD -i sit+ -j insit
## [outsit] Default Chain Policy to stop leaking private connection.
ip6tables -A OUTPUT  -o sit+ -j outsit ## manage from localhost, so may be useless.
ip6tables -A FORWARD -o sit+ -j outsit ## manage from home-lan clients, so it's essential.

## [insit] check tcp flags before default rules
ip6tables -A insit -p tcp --tcp-flags ACK,FIN FIN -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags ACK,PSH PSH -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags ACK,URG URG -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags FIN,RST FIN,RST -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags SYN,FIN SYN,FIN -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags SYN,RST SYN,RST -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags ALL ALL -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags ALL NONE -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags ALL FIN,PSH,URG -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j deny_ip_flags
ip6tables -A insit -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j deny_ip_flags

## [insit/outsit] Adding Deny Rules for local,
##   private reserved and broadcast addresses from outside.
ip6tables -A insit -s fe80::/8       -j deny_localaddr
ip6tables -A outsit -d fe80::/8     -j deny_localaddr

########################
## Default sit+ rules ##
########################
## - allow already used connections
ip6tables -A insit -m state --state ESTABLISHED,RELATED -p tcp -j ACCEPT
ip6tables -A insit -m state --state ESTABLISHED,RELATED -p udp -j ACCEPT
ip6tables -A insit -m state --state ESTABLISHED,RELATED -p icmpv6 -j ACCEPT
##
## - allow outbound connections
ip6tables -A outsit -m state --state ESTABLISHED,RELATED -p tcp -j logaccept
ip6tables -A outsit -m state --state ESTABLISHED,RELATED -p udp -j logaccept
ip6tables -A outsit -m state --state ESTABLISHED,RELATED -p icmpv6 -j logaccept
ip6tables -A outsit -m state --state NEW -p tcp -j ACCEPT
ip6tables -A outsit -m state --state NEW -p udp -j ACCEPT
ip6tables -A outsit -m state --state NEW -p icmpv6 -j ACCEPT

################################
## Define other special rules ##
################################
## for ICMPv6
ip6tables -A insit -p icmpv6 -j logaccept
ip6tables -A outsit -p icmpv6 -j logaccept
## for SSH connection
ip6tables -A insit -p tcp --dport 22 -j logaccept

##################################
## Adding Deny Rules as default ##
##################################
ip6tables -A insit -j dumpdrop 
ip6tables -A outsit -j dumpdrop

################################
## End of Processing for sit+ ##
################################


################################
## Default rules for eth[012] ##
################################
ip6tables -A INPUT -i eth+ -j ACCEPT
ip6tables -A FORWARD -i eth+ -j ACCEPT
ip6tables -A OUTPUT -o eth+ -j ACCEPT
ip6tables -A FORWARD -o eth+ -j ACCEPT

###################################
## Drop all packets with logging ##
###################################
ip6tables -A FORWARD -j dumpdrop
ip6tables -A INPUT -j dumpdrop
ip6tables -A OUTPUT -j dumpdrop

############
## Fin... ##
############
exit 0

2010/02/10追記:
輻輳を防ぐためにローカルに存在しないアドレスへの問い合せが外部に流れないように、フィルターでプリフィックス宛てのパケットをブロックします。
ついでに外部からプリフィックスを発信元とする不正なパケットの流入も禁止します。

fe80::/8の後ろに新たに追加した設定内容

...
ip6tables -A insit  -s 200x:xxx:xxx::/48 -j deny_localaddr
ip6tables -A outsit -d 200x:xxx:xxx::/48 -j deny_localaddr
...

さいごに

このスクリプトはとりあえずでっち上げたものなので、2、3日すると構造は変わると思います。 このまま使う事をお勧めするものではないので、ログをこまめに取るなどご注意ください。

2010/02/05

IPv6接続用DTCPクライアントをNet::POP3をベースに作ってみた

IPv6でのDTCP接続をする時に参考にさせて頂いたsetup-dtcp.plはNet::POP3の関数を呼び出すように設計されています。 自分で使うのに手を入れずらかったので、実験を兼ねてNet::POP3を継承したDTCPクライアントを作成してみました。

実際に使っているものは、もう少し手を加えていますが、最低限の機能を実現するバージョンを載せておきます。

Perlでの差分プログラミング

Net::POP3はpackageを使ったPerlクラスとして設計されています。 そこでAPOPのコードをベースにDTCP用のコードを追加してみました。

結果として、この範囲の機能だとかなり冗長な感じになってしまいました。 ただ自分で使う分には見通しが良くなったので、もう少し手を加えて使っています。

スクリプトの内容

 #!/usr/bin/perl

package YADtcpc;
use vars qw(@ISA $VERSION $debug);
use Net::POP3;
use Net::Cmd;
use Carp;
@ISA = qw(Net::POP3);

sub logit {
    my ($self, $msg) = @_;
    printf(STDERR "debug: %s\n", $msg);
}

## based on the 'sub apop'
sub _DTCP { shift->command('tunnel', @_)->response() == CMD_OK; }
sub dtcp {
    @_ >= 1 && @_ <= 3 or croak 'usage: $dtcp->dtcp( USER, PASS )';
    my($me,$user,$pass) = @_;
    my $banner;
    my $md;

    if (eval { local $SIG{__DIE__}; require Digest::MD5 }) {
	$md = Digest::MD5->new();
    } elsif (eval { local $SIG{__DIE__}; require MD5 }) {
	$md = MD5->new();
    } else {
	carp "You need to install Digest::MD5 or MD5 to use the DTCP command";
	return undef;
    }

    my $msg = ${*$me}{'net_pop3_banner'};
    return undef
	unless ( $banner = (${*$me}{'net_pop3_banner'} =~ /^([0-9A-z]+)\s+/)[0] );

    if (@_ <= 2) {
	($user, $pass) = $me->_lookup_credentials($user);
    }

    $md->add($user,$banner,$pass);

    $me->_DTCP($user, $md->hexdigest, 'network');

    $me->get_remote_link_addr();
}
sub get_remote_link_addr {
    my ($self) = @_;

    if ($self->message =~ /^(\d+[\.\d]+)\s+(\d+[\.\d]+)\s+([\d\:a-f]+)\/(\d+)/i) {
	return ($1, $2, $3, $4);
    } else {
	$self->logit("I couldn't get the correct response, then aborting now...");
	$self->quit();
	exit 1;
    }
}
sub _PING { shift->command('PING')->response() == CMD_OK }
sub ping {
    @_ == 1 or croak 'usage: $dtcp->ping()';
    my $me = shift;

    return () unless $me->_PING() && $me->message =~ /^([0-9A-z]+)/i;
    ($1 || 0);
}

##########
## main ##
##########
my $host = "dtcp.feel6.jp";
my $port = 20200;
my $user = "xxxxxx";
my $pass = "xxxxxx";

my $dtcpc = YADtcpc->new($host, Port=>$port);
my ($local,$remote,$prefix,$mask) = $dtcpc->dtcp($user, $pass);
printf("local=%s,remote=%s,prefix=%s,mask=%s\n", $local, $remote, $prefix, $mask);

while ($dtcpc->ping() =~ /pong/i) {
    printf("send ping message\n");
    sleep 60;
}

$dtcpc->logit("exit from while(1) loop because we ditn't receive the 'pong' message.");
$dtcpc->quit();

__END__
応用について

一応モジュールなので## main ##行より前半部分はYADtcp.pmとして使う事もできます。ただ、ここで分割する利点はないので一つの.plファイルとしてまとめています。

コード内部にパスワードを書くのは良いマナーとはいえないので、実際には別ファイルに分割していましょう。

バックグラウンドで動かすためには$ sudo -b ./yadtcpc.plみたいに動かす事ができますが、prefixなどの情報をファイルに書き出すようにしないとですね。 それに数回コネクションが切断してしまう経験もしたので、再接続のループは追加した方が良いでしょう。

だいたいこんな感じでしょうか。

2010/02/04

AlixのブロードバンドルータでIPv6

以前作成したalixなブロードバンドルータをフリービットのFeel6接続サービスを使ってIPv6に対応させてみました。

この手の作業は同じlinuxでもディストリビューションや環境に左右されるので、まず今回の環境をまとめておきます。

  • インターネット接続:NTT東日本 Bフレッツ + 固定IP
  • ブロードバンドルータHW:Alix 2C3
  • ブロードバンドルータSW:Debian lenny (eth0:Global ipv4 addr, eth1:192.168.1.1, eth2:192.168.10.1)
  • DTCPクライアント:自作Perlスクリプト
  • RAサーバ:debian lenny付属のradvdパッケージ from http://v6web.litech.org/radvd/dist/
  • クライアント1:Ubuntu 8.04 x86_64 (192.168.1.x)
  • クライアント2:Mac OS X 10.6.2 (192.168.1.x)

Feel6接続サービスへの登録

IPv6なネットワークに接続する方法はいくつかありますが、今回はフリービットのサービスを使う事にしました。 固定IPを使っているので静的にトンネルを作ってもらっても良かったのですが、将来プロバイダを変更するかもしれないですしね。

登録はFeel6のトップページから必要事項を送信するだけです。

DTCP接続を試してみる

Feel6のサーバにIPv6ネットワークへのトンネルを作ってもらうわけですが、その情報のやりとりはDTCPというプロトコルを使用するようです。 ここら辺の解説は「Linux 上で DTCP を使って IPv6 over IP トンネルを張る」がとても参考になりました。

検索してみるとDTCPの使い方としては、次のような方法がありました。

  • DTCPクライアントを自作する方法
  • USAGIプロジェクトが配布しているdtcpcコマンドを使用する方法

Linux 上で DTCP を使って IPv6 over IP トンネルを張る」にある"setup-dtcp"スクリプトやUSAGIプロジェクトのdtcpcを使ってみました。しかし内部で呼び出しているコマンドの実行に失敗するなど簡単にはできなかったため"setup-dtcp"の元になったスクリプトをベースに手作業でコマンドを実行していきました。

DTCPクライアントの自作

最終的には作り直したのですが、まずは参考にしたPerlスクリプトでトンネル状態を維持する事にしました。 参考にしたページにあるスクリプトでは変数定義が抜けているのと、Feel6から貰ったIPv6アドレスがわからないので出力ようにして、だいたい次のようなコードを追加しています。

#!/usr/bin/perl

my $host = "dtcp.feel6.jp";
my $port = 20200;
my $user = "xxxxxx";
my $pass = "xxxxxx";
...
    ($local, $remote, $prefix, $nbits) = ($1, $2, $3, $4);
    printf(STDERR "local=%s,remote=%s,prefix=%s,nbits=%s\n", $1, $2, $3, $4);
} else {
...

ここで$user$passには、Feel6登録時に入力したものを記入します。 実行に成功すると4つの文字列が手に入ります。

DTCPクライアントは接続を維持するために毎分PINGメッセージを送信しています。 そのためIPv6を使う間はずっと起動しておく必要があります。

AlixをIpv6ルータとして構成する

ここからはDTCPクライアントが裏側で動いている前提で書いています。

Feel6とは関係なしにBフレッツを使っているとNTTからIPv6アドレスが付与されます。 ただしこれは/64なプリフィックスなので、サブネット用に番号を加える事ができません。 また他の方のブログなどをみるとオプションを申し込まないと、NTTが準備したコンテンツ以外にアクセスする事は難しいようです。

Alixで確認すると、NTTから自動的に割り当てられるこのアドレスは以前Alixをルータにする投稿の中で、Bフレッツとの接続に使ったeth0に割り当てられています。

Bフレッツで自動的に割り当てられるIPv6アドレス

eth0      Link encap:イーサネット  ハードウェアアドレス 00:0d:xx:xx:xx:xx
          inet6アドレス: 2001:c90:489e:xxxx:xxxx:xxxx:xxxx:xxxx/64 範囲:グローバル
          inet6アドレス: fe80::xxxx:xxxx:xxxx:xxxx/64 範囲:リンク
...

Feel6から付与されるプリフィックスは/48ですから、前半64bitの残り16bit(0xffff分)を使ってネットワークを分割する事が可能になります。IPv4ではeth1, eth2でネットワークを分けているので、それにならってIPv6でもeth1, eth2でサブネットを設定する事にしました。

IPv6ルータになるための設定項目

Bフレッツ用のIPv6アドレスが割り当てられていた理由は、lennyのデフォルトとしてRouter Advertisement(RA)を受け付けるようになっている事に起因します。 ルータ自身がRAに反応しては困るらしくsysctlの設定を変更します。

Fee6を使う場合はRAを有効にしても大丈夫なんじゃないかという気はしつつ、先達に習うことにしました。 その他のアイデアとしてはeth0ではRAを受信してNTTのアドレスを構成しつつ、eth1, eth2はRAを無視して自分でアサインする、という構成も考えられましたが今回は試していません。

/etc/sysctl.confファイルの追加内容

...
net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.all.accept_redirects=0
net.ipv6.conf.all.forwarding=1
...

また直接は関係ないですが、この他にsysctl.confではipv6関連の設定を2つ行なっています。

net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_source_route = 0
proc経由での設定変更について

sysctl.conf周りの設定は/procファイルシステムを通しても可能で、IPv6を説明した多くのサイトで$ echo 1 > /proc/sys/net/ipv6/conf/all/accept_raのようなコードが書かれています。 しかし恒久的な変更には/etc/sysctl.confファイルを使いましょう。

procに"0"や"1"を書き出したいが、sudoを使わないとという場合にはteeコマンドを使いましょう。

$ echo 1 | sudo tee /proc/sys/net/ipv6/conf/all/accept_ra

DTCPの出力からAlixにIPv6アドレスを付与する

DTCPクライアントの出力から次のような情報が得られています。

  • local - 自分のGlobal IPアドレス:219.117.xxx.xxx
  • remote - Feel6への接続用IPアドレス:43.244.xxx.xx
  • prefix - IPv6接続に使用するプリフィックス:2001:03xx:xxxx::/48
Alixの各インタフェースに割り当てる情報を決めていく

prefixは最後の2byte(16bit)が空いているので、ここを埋めてeth1, eth2にどのようなサブネットを設定するか考えます。 何でも良いのですが、IPv4に合わせて最後は0001,0010としました。

  • eth1 prefix - 2001:03xx:xxxx:1::/64
  • eth2 prefix - 2001:03xx:xxxx:10::/64

ここまでを踏まえてそれぞれのIPv6アドレスを決めました。 アドレスは何でも良いですが、"192.168.1.1", "192.168.10.1"を16進数に変換した"c0a8:0101", "c0a8:a101"を使う事にしました。

  • eth1 ipv6 addr - 2001:03xx:xxxx:1::c0a8:0101/64
  • eth2 ipv6 addr - 2001:03xx:xxxx:10::c0a8:0a01/64

ただしalixから外部に通信する必要がなければサイトローカルユニキャストアドレス(fe80::/64)で十分なはずで、必要だとしても2つも追加する必要はなかったりします。 まぁどちらかのデバイスをダウンさせる事もあるかもしれないので、こういう設定にしてみました。

実際にIPv6環境を構築していく

情報は決まったのでコマンドをパチパチ打っていきます。

トンネルの構築

remoteアドレスをベースにsit0, sit1インタフェースを構成します。

$ sudo /sbin/ifconfig sit0 up tunnel ::43.244.xxx.xx

Alixではiptablesを構成しているので、通常の構成ではカプセル化したパケットが出ていきません。 dropしたパケットのログをみると次のようになっています。

iptablesでdropしたパケットの情報

...
[135368.059979] netfilter drop IN= OUT=ppp0 SRC=219.117.xxx.xxx DST=43.244.xxx.xx LEN=124 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=41
...
[136225.974684] netfilter drop IN=ppp0 OUT= MAC= SRC=43.244.xxx.xx DST=219.117.xxx.xxx LEN=124 TOS=0x00 PREC=0x00 TTL=246 ID=16480 PROTO=41
...

このproto=41を通すためにiptablesに設定を追加します。

iptables -A inppp -s 43.244.xxx.xx --proto 41 -j ACCEPT
iptables -A outppp -d 43.244.xxx.xx --proto 41 -j ACCEPT
ルーティング情報の設定

eth0にはBフレッツから割り当てられたアドレスが付いています。 当然デフォルトゲートウェイはeth0に向いているので、このルーティングを削除しつつ、Feel6に変更する設定を行ないます。

$ sudo /sbin/route -A inet6 del ::/0 dev eth0
$ sudo /sbin/route -A inet6 add ::/0 dev sit1
eth1, eth2にIPv6アドレスを付与する

外部との通信に使用するために、IPv6でいうところのグローバルユニキャストアドレスを追加します。

$ sudo /sbin/ip -f inet6 addr add 2001:03xx:xxxx:1::c0a8:0101/64 dev eth1
$ sudo /sbin/ip -f inet6 addr add 2001:03xx:xxxx:10::c0a8:a101/64 dev eth2
ここまでの稼働確認

おそらくping6は既にインストールされていると思うので、これを使って接続が確立しているか確認します。

$ ping6 www.kame.net
$ ping6 2001:200:0:8002:203:47ff:fea5:3085

ping6 www.kame.netの出力

PING www.kame.net(orange.kame.net) 56 data bytes
64 bytes from orange.kame.net: icmp_seq=1 ttl=54 time=14.2 ms
64 bytes from orange.kame.net: icmp_seq=2 ttl=54 time=13.3 ms

ping6 2001:200:0:8002:203:47ff:fea5:3085の出力

PING 2001:200:0:8002:203:47ff:fea5:3085(2001:200:0:8002:203:47ff:fea5:3085) 56 data bytes
64 bytes from 2001:200:0:8002:203:47ff:fea5:3085: icmp_seq=1 ttl=54 time=14.6 ms
64 bytes from 2001:200:0:8002:203:47ff:fea5:3085: icmp_seq=2 ttl=54 time=13.5 ms

生のIPv6アドレスはwww.kame.netのものです。 将来的に変更されているかもしれないので、nslookupでアドレスを確認してからping6に渡してください。

$ nslookup -type=AAAA www.kame.net

nslookup -type=AAAA出力例

$ nslookup -type=AAAA www.kame.net
Server:		192.168.1.x
Address:	192.168.1.x#53

Non-authoritative answer:
www.kame.net	has AAAA address 2001:200:0:8002:203:47ff:fea5:3085
....

もしping6がインストールされていなければ、iputils-pingパッケージを導入してください。 nslookupはdnsutilsパッケージに含まれています。

$ sudo apt-get install iputils-ping

ここまでうまく行けば、radvdクライアントを動かすか、クライアント側を適切に設定すればIPv6ネットワークに接続する事ができるようになります。

トラブルシュート

もしping6の実行に失敗してデバイスを指定する次のようなコマンドが成功するとしたら、ルーティング情報が間違っているはずです。

$ ping6 -I sit1 2001:200:0:8002:203:47ff:fea5:3085

またping6実行時にping: sendmsg: Operation not permittedメッセージが出力されているとすれば、iptablesの設定に失敗しているか、ip6tablesが設定されているのが原因でしょう。

いまはIPv6用のfirewallは素通しの状態になっているはずで、次のコマンドでデフォルトが"(policy ACCEPT)"になっている事を確認します。

sudo /sbin/ip6tables -L

期待する出力

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

radvdクライアントの起動

Alixではパッケージで配布されているradvdコマンドを使用します。

$ sudo apt-get install radvd

今回は次のような設定ファイルを準備しました。

/etc/radvd.confファイル

interface eth1
{
        AdvSendAdvert on;

        MinRtrAdvInterval 3;
        MaxRtrAdvInterval 10;

        prefix 2001:03xx:xxxx:1::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
        };
};

interface eth2
{
        AdvSendAdvert on;

        MinRtrAdvInterval 3;
        MaxRtrAdvInterval 10;

        prefix 2001:03xx:xxxx:10::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
        };
};

最後にradvdを起動して終りです。

$ sudo /etc/init.d/radvd start
radvdの初期設定について

パッケージに含まれる通常の構成だとAlixの再起動時に自動的にradvdが起動します。 これが悪いとはいいませんが、トンネルの構成をまだ自動化していないので意図しないタイミングでradvdが起動してしまうかもしれません。

今回はradvdを制御する目的で明示的に/etc/init.d/radvdスクリプトを実行する事にして、自動起動は停止する事にしました。

$ sudo mv /etc/rc2.d/S50radvd /etc/rc2.d/K50radvd

クライアントの接続確認

本当は手動でルーティングをしていたのですが、radvdを使う方法を書く事にしたのでクライアント側でする事はあまりありません。 Ubuntu 8.04 x86_64以外にMac 10.6でもブラウザをいくつか立ち上げて確認をしています。

Ubuntu 8.04での稼働確認

accept_raは有効になっているので、基本的にIPアドレスはすでに割り当てられていました。 しかしufwを有効にしているせいかip6tablesのデフォルトポリシーがDROPになっていたためping6の実行に失敗しました。

ip6tablesの構成は後でする事にして、いまは全部の通信を許可しています。

$ sudo /sbin/ip6tables -P INPUT ACCEPT
$ sudo /sbin/ip6tables -P OUTPUT ACCEPT
$ sudo /sbin/ip6tables -P FORWARD ACCEPT

とりあえずWebブラウザだけを使って、keme.netの亀が踊るかどうか確認します。

http://www.kame.net/

Mozilla Firefox 3.0.17, Google Chromium 5.0.315.0 (37939) Ubuntu, Opera 10.10で確認しました。 結果としてOperaだけがIPv4で接続していました。

OperaはIPv6周りののバグ対策として、とりあえずIPv6を使えなくしたようですね。 一時的とはいえ後ろ向きな感じがしなくてはない対応ですが、フレームワークの問題で抜本的な対策が難しかったのかなぁ…。

Mac 10.6での稼働確認

Ubuntu同様に自動的にグローバルアドレスを受信しているので、Safariなどで何も考えなくても亀が踊っています。Opera 10.10を試してみたところやはりIPv6では接続できませんでした。

さいごに

Bフレッツのアドレスを使えるのであれば、eth0とbound0を組んでradvdだけ起動してしまえば使えそうな気もします。 それにサブネットを分ける必要性があるのか、という気もします。 まぁせっかくalixにはNICが3つも付いているので、これもまた良いでしょう。

しかし、一応動いているとはいえ頭の中が完全にIPv4のネットワークのマナーに染まっているので、IPv6的な考え方がまったくできていないと実感しています。 ここに書いた対応も成功事例ではありますが、本当のベストプラクティスとはいえないところがあるだろうと思います。まぁしばらくIPv6で遊んでみるつもりです。

この後の残作業はFirewall周りの他に、基本的なところでDTCPクライアントからeth1, eth2にサブネットワークを構成して、そのアドレスを反映したradvd.confを作成するところまでを自動化する必要があります。

まっさらなところからの自動化自体は簡単ですが、途中からのやり直しなんかを考えると、各作業の粒度を考えて個別のスクリプトにしないと安定しそうにありません。これも少し時間を考えて試行錯誤したいと思います。

とりあえずは次のステップはfirewallの設定ですかね。