仙石浩明の日記

システム構築・運用

2006年4月17日

オープンソースにこだわる

多くの会社と同様、KLab (および KLabセキュリティ) でも、 出来る限りオープンソースを利用するようにしています。 我々がDSASと呼んでいる システムインフラは、完全にオープンソースベースとなっており、例えば 「ファイアウォール兼負荷分散器兼ルータマシン」も Linux ベースとなっております。

なぜオープンソースにこだわるのか?

佐野氏のコラムに、 オープンソースにこだわる人の理由って正しい?:

    > オープンソースにこだわる人に理由を聞くと普通
    >
    >  1.無料だから
    >  2.大勢の人が使っているからバグが少ないと思われる
    >  3.ソースコードが公開されているから安心
    >
    > という答えが返ってきます。1と2はまあその通りだと思います。
    > しかし3は個人的にちょっと疑問です。
    > オープンソースにこだわっている人で、オープンソースソフトウェアの
    > ソースコードを実際に分析したことがある人って
    > どのくらいいるのでしょうか。
      ……
    > なのでオープンソースにこだわる理由を聞かれたらかっこいいこと
    > 言わずに素直に「無料だし機能に不満もないから」くらいにしておくのが
    > よいのではないでしょうか。

という問いかけがありました。さすが佐野さん、的を射た厳しいご意見ですね。 正直な話、KLab もオープンソースを利用しているといっても、 スミからスミまで分析しているわけではありませんし、 「無料だし機能に不満もないから」という面もあることは否定しません。 しかし、お客様にサービスを提供するという立場としては、 もう少し積極的な理由も持ちたいところです。

責任あるシステム運用を実現するためのオープンソース

システムにベンダ任せのブラックスボックスな部分があると、 その部分が原因の障害への対応は遅くなりがちですし、 原因究明を完全に行なうことができなければ、 再発防止策も対症療法的なものになりがちです。 これでは自信を持ってお客様にサービスを提供することができません。

KLab も以前は箱モノの負荷分散機を利用していたのですが、 クリティカルなバグに散々悩まされました。 この箱モノは L2処理に問題があり、 通信不良が発生するケースがあったのです。 もちろんベンダへは症状を報告していたのですが、 完全な対策には至らず、なんとか運用でカバーしていました。

これでは、いつ症状が再発するか分からず 精神衛生上もよろしくありません。 そこで、LVS (Linux Virtual Server) を使って Linux ベースの負荷分散機を 構築することにしました。 むろん、LVS のソースコードの全てを完全に把握しつくし、 LVS プロジェクトに貢献できるようになるまでには、 まだまだ道程が遠いのですが、 再現可能な障害であれば問題の所在を見つけ出せる程度の レベルには達することができていると思っています。 しかも、実はこうやって自前で構築した負荷分散機の方が、 それまで使っていた箱モノよりずっと安定して運用できてしまったのです。

ベンダの都合に振り回されないためのオープンソース

プロプライエタリなソフトウェアを使っている場合は、 ベンダがサポートを停止するリスクというのも考えておかねばなりません。 ベンダがサポートを止めたことを理由に、 弊社のお客様に対するサービス提供を止める、というやり方も 無いわけではありませんが、 技術会社を標榜する KLab としては、 あまりそういう言い訳はしたくありません。

すると、 ベンダがサポートを止めたときのことまで考えておく必要がありますが、 あいにくソフトウェアの使用許諾というのは一般に不平等契約で、 ソフトウェアを使用する側には打つ手がないことが多いようです。 ベンダの都合に振り回されるよりは、 いざとなったら自前で解決できるよう、 ソースがオープンになっているソフトウェアを選ぶ方が 結果的に楽といえるのではないでしょうか。

なんかプロプライエタリって馬鹿みたいだな」 (ここギコ!) で、

    > プロプライエタリなソフトの方がよっぽどリスクだらけちゃうの?
    > わざわざクソ高い金払うのに、と思えてくる。

という意見も出ているように、 ベンダのサポートがアテになるケースばかりとは限りません。

自由なシステム構築を実現するためのオープンソース

どんなに柔軟性が高いソフトウェアでも、 カスタマイズで可能な範囲というのはタカが知れています。 ソースを改変することによって得られる自由とは雲泥の差でしょう。

KLab としては、 他社では行なっていないような方法で、 耐故障性を向上させたり、 性能を向上させたり、 より低コストな運用を実現したり することによって、 差別化をはかっていきたいわけで、 そうなるとベンダの製品を使うよりは、 オープンソースを使うべき、という選択になります。

実際にどのようにオープンソースを活用しているかは、 DSAS開発者の部屋などで 紹介していきたいと思っておりますし、 オープンソースを活用していく過程で我々のレベルが上がって、 オープンソース界に貢献できるようになれれば、 それは我々にとって望外の幸であり、 それを目指して研鑽を積んでいく所存です。

Filed under: システム構築・運用,技術と経営 — hiroaki_sengoku @ 06:19
2006年4月15日

VPN-Warp 入門編 (2)

前回は、ssh のポートフォワーダには次の二点の欠点がある、 というお話をしました。

  1. リモートホストにログインアカウントが必要
  2. リモートホストへアクセスできることが必要

すなわち、ssh でポートフォワードを行なう場合、例えば

ssh -L 8080:intra:10080 remote "sleep 1d"

といった感じで実行しますが、ssh ログイン先である remote の セキュリティレベルを下げる要因となってしまう、という欠点です。

欠点 (1) を VPN-Warp ではどのように解決しているか

VPN-Warpでは、リモートマシンにログインアカウントは必要ありません。 リモートマシンに必要なのは、リレーエージェントと呼ばれるプログラムを 走らせることだけで、Linux 上でも Windows 上でも走らせることができますし、 Windows 版は、NT サービスとして実行することも可能です。

VPN-Warp ではユーザ管理をリレーサーバ上の DB で行なっていますので、 100万人規模のユーザに対しても余裕でサービスできます。 リモートマシンではユーザ管理を行なう必要がないので、 リレーエージェントを走らせるために必要な設定は、 ポートフォワード先 (上述の例だと intra:10080) の設定だけです。

リレーエージェントが行なうのは、 ポートフォワードに限定されているので、 セキュリティリスクを最小限に抑えることができます。

欠点 (2) を VPN-Warp ではどのように解決しているか

VPN-Warpでは、リモートマシンに直接アクセスする代わりに、 中継専門のリレーサーバを用います。 リモートマシン上で走らせるリレーエージェントが、 リレーサーバへアクセスしてリレーサーバと連係動作することによって、 ローカルホストがアクセスする対象はリモートマシンではなく リレーサーバになります。 ssh と VPN-Warpの違いを図で書くと次のような感じになります:

ssh のポートフォワードの場合:

ローカルホスト                          リモートホスト
    ssh ─────────────────→ sshd  ─→ intra
  8080番ポート …………………………………………………→ 10080番ポート

VPN-Warpの場合:

ローカルホスト         リレー           リモートホスト
    stone ─────→ サーバ ←──── relayagent─→ intra
  8080番ポート …………………………………………………→ 10080番ポート

図中 relayagent というのがリレーエージェントです。 VPN-Warpの場合、リモートホストへは外部からアクセスする必要が ないことに注意して下さい。 代わりに外部からのアクセスを受け付けるのは「リレーサーバ」です。

ssh の場合はリモートホストが外部からの攻撃に晒されるリスクがあるわけですが、 VPN-Warpの場合は、外部からの攻撃に晒されるのはリレーサーバだけです。

そしてリレーサーバは、KLab など VPN-Warp 提供側が運営するので、 VPN-Warp ユーザは外部からの攻撃を気にする必要がありません。

また、リレーサーバ自体は単にデータを右から左へデータを流すだけで、 ssh ログインアカウントのような侵入の足掛かりになるようなものは 何もありません。 もちろんリレーサーバは、専用のディレクトリへ chroot してから、 リレーサーバ専用のユーザ権限で実行するようにしています。

Filed under: システム構築・運用 — hiroaki_sengoku @ 07:01
2006年4月14日

DB サーバのセキュリティ向上策 (6)

DB サーバのセキュリティ向上策 (3)」では、 どのユーザが UNIX ドメインソケットにアクセスしたか特定するために、 ユーザごとにソケットを作成しました。 しかし Linux などの OS では、UNIX ドメインソケットに限り アクセス元のユーザを getsockopt(2) で調べることができるので、 ソケット一つだけでどのユーザからのアクセスか区別することができます。

例えば以下のように getsockopt の引数に SO_PEERCRED を指定することにより、 ucred 構造体にアクセス元のユーザの情報が格納されます:

struct ucred cr;
int len = sizeof(cr);
int ret = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (ret == 0) {
    struct passwd *passwd = getpwuid(cr.uid);

    ...

}

したがって、UNIX ドメインソケットを listen し、 そのソケットへ接続があったら、 それを DB サーバへ通信を監視しつつ中継するプログラム dbrelay において、 上記のように getsockopt(2) を使ってアクセス元ユーザを特定し、 通信の監視によって得られた DB ユーザ名と一致したら中継を継続し、 一致しなかったら通信を遮断する、ということが可能になります。

もちろん、各ユーザが直接 DB サーバへアクセスしないよう、 dbrelay からのアクセス以外は OUTPUT チェインで通信を却下します。

このような仕掛けを、ラック内の全サーバに仕込むことにより、 各ユーザは同名の DB ユーザでのみ DB サーバへ、 UNIX ドメインソケット経由でアクセスできます。

通信の監視をクライアント側でなく、 DB サーバ側で行ないたい場合は、 クライアント側の dbrelay では アクセス元のユーザ名をサーバ側へ伝えるだけにして、 通信の監視および通信の遮断はサーバ側で行なわせることもできます。

最新版 の stone には アクセス元のユーザ名をサーバ側へ伝える機能があるので、 例えばクライアント側で次のように stone を実行します。

stone dbserver:12345/http /tmp/db.sock '\U'

「/http」の指定と「'\U'」が、ユーザ名をサーバ (dbserver:12345) へ 伝える設定です。例えばユーザ sengoku が UNIX ドメインソケット /tmp/db.sock にアクセスすると、stone はまず

Apr 14 07:54:36.809789 16384 3 5>6 73 65 6e 67 6f 6b 75 0d  sengoku.
Apr 14 07:54:36.809828 16384 3 5>6 0a 0d 0a                 ...

を dbserver:12345 へ送信し、その後は /tmp/db.sock から dbserver:12345 への 中継が行なわれます。 したがってサーバ側ではまず最初に送られてきたユーザ名を受け取り、 その後は通信を監視しつつ 12345 番ポートから DB サーバへの中継を行なえばよいわけです。

Filed under: stone 開発日記,システム構築・運用 — hiroaki_sengoku @ 08:13
2006年4月13日

VPN-Warp 入門編

CTO日記のほうで 「VPN-Warp入門編」を始めた。 VPN-Warpというのは、port forwarder で、「relay agent」プログラムを動かしているマシンへ、「リレーサーバ」経由で TCP トンネルを掘ることができる。 つまり、イントラの中だろうが固定IPがついてない NAT の中だろうが、ダイアルアップするノートPCだろうが、インターネットへアクセスすることさえできるならば、relay agent を動かすだけで外部からアクセスできるトンネルが設置可能。

ssh の -R オプションと、-L オプションを組み合わせて同様のことが実現可能であるが、大きな違いは、ssh とちがってアカウントを作る必要がないこと。SSLクライアント証明書を発行するだけなので、異なるセキュリティポリシーのトンネルを何本でも手軽に設置できる。実際、KLab のインフラの各所で活用している。

Filed under: システム構築・運用 — hiroaki_sengoku @ 11:46
2006年4月13日

VPN-Warp 入門編 (1)

KLabセキュリティ(株)の製品に VPN-Warp という SSL VPN ソリューションがあります。 この製品は、最初のプロトタイプを私が開発し、 社内インフラ構築で長年 (といっても KLab(株) が設立からまだ 6年なので、 せいぜいそのくらいですが) 使い倒すことによって信頼性があがってきたものを、 商品化したものです。 私自身が最初に開発した、という愛着もあるので、 「仙石浩明CTO の日記」という場を利用して、 VPN-Warp を内部構造も含めて解説していきたいと思います。

VPN-Warp は、ふつうの SSL VPN に比べ、以下の特徴があります:

  1. サーバ側の設定が簡単
    特殊な設定の必要がありません。 イントラネット上の Web サーバに専用ソフトウェアをインストールするだけです。
  2. 既存のイントラネット環境を利用
    ファイアウォールの設定を変える必要がありません。
  3. PC、携帯電話、PDA などから利用可能
    主要端末に対応しています。
  4. ファイアウォール内部の情報を完璧に保護
    SSL により暗号化・認証 (クライアント・サーバ間の相互認証) で 高度なセキュリティを実現します。
  5. クライアント側への簡単な導入
    特別なソフトが必要なく SSL 証明書のインポートだけで使えます。
  6. 安定したシステム
    定評ある KLab のデータセンタを利用するため安心です。

VPN-Warp って何?

一言で言うと、ポートフォワーダです。 ssh のポートフォワードを使ったことがある人は多いと思うのですが、 基本はアレと同じです。 ssh だと、ローカルホスト (例えば自分の PC) 上で

ssh -L 8080:intra:10080 remote "sleep 1d"

などと実行することにより、 ローカルホストの 8080 番ポートを (remote から見て) intra:10080 番ポートへフォワードできます。 intra:10080 に、イントラへアクセス可能な http proxy が動いていれば、 ローカルホストの 8080 番ポートをイントラの http proxy として 使うことができるわけですね。

じゃ、ssh でいいんじゃない? なんで VPN-Warp を使うの?

ssh のポートフォワーダには大きく分けて二つの欠点があります:

  1. リモートホスト (この例では remote) にログインアカウントが必要
    ポートフォワードするためだけに、 ssh でログインできる権限を与える というのは、いかにも牛刀ですよね? また、サーバのアカウントというのは滅多矢鱈に増やせるものでもないので、 例えば数千人を超えるユーザにサービスする方法としては現実的ではありません。
  2. 外部からリモートホストへアクセスできることが必要
    この例の remote はイントラ内へアクセスできることが必要です。 イントラ内へアクセスできるサーバを 外部からアクセスできるセグメント (例えば DMZ) に置くのは 現実的ではありませんから、普通はいったん外部からアクセス可能な サーバ (例えばファイアウォール) の 適当なポート (例えば 10022 番ポート) で受けて、 それをイントラ内へフォワードするように設定しておくことになります。 DMZ に置くよりはマシであるものの、 外部から直接ログインできてしまうことにかわりはありません。

この二つの欠点は、どちらも「リモートホスト」の セキュリティレベルを下げる要因になります。 単刀直入に言えば、外部の第三者が「リモートホスト」にログインして フルコントロール権限を奪うリスクが高まっている、ということです。

次回は、VPN-Warp が上記欠点をどのように解決しているか説明します。

Filed under: システム構築・運用 — hiroaki_sengoku @ 08:06
2006年4月12日

ネットが切れる不安

ネットが切れる不安という日記を見つけた。

引っ越し先には光ファイバーが入っていないのだ(汗) 明日、ADSLが大丈夫かどうか確認して、なるべく間隔があかないように手続きをしないと。 今の時代、一日でもネットに接続できないと、なんだか不安になってしまう。

私も 6年前に引越したのだが、 ネットが切れる不安におそわれた。 なんとか間隔があかないように苦労したのを覚えている。 顛末は日経Linuxの連載の枕 (PDF版) に書いた。

引っ越し作業中も社宅でサーバーを動かし続ける必要があるわけですが,部屋中に電話線やらEthernetケーブルが張り巡らせてある状態で引っ越し作業ができるはずはないので,サーバー,ルーター,TA(Terminal Adapter),電話等のネットワーク関係を部屋の片隅の半畳程度の部分に再構築し,作業中絶対にこの部分には近付かないよう*3 引っ越し業者の方にお願いすることにしました

当時はまだ ADSL のサービスが始まっていなかったので、OCN エコノミーを利用していた。だから TA。

Filed under: システム構築・運用 — hiroaki_sengoku @ 20:01
2006年4月7日

adsl-stop

今朝未明、bフレッツのメンテナンス工事があって、 GCDの対外線が切れた。 切れたこと自体は事前に NTT からアナウンスがあったことだし 問題はないのだが、

bフレッツが切れたことにより PPPoE を行っている pppd が終了すると、 /etc/ppp/adsl-lost が実行される。 GCD の adsl-lost は次のようになっている:

#!/bin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
. /etc/rc.d/hostname
MASTER_FILE="/var/run/keepalived_vrrp.MASTER"
if [ -f $MASTER_FILE -a "$1" = "/etc/ppp/pppoe.conf" ]; then
    rm -f $MASTER_FILE
    ERROR_FILE="/var/run/keepalived_vrrp.ERROR"
    echo 2 >> $ERROR_FILE
    /command/svc -t /service/keepalived/
fi

つまり、/var/run/keepalived_vrrp.MASTER を削除したうえで keepalived を再起動する。 すると、keepalived は BACKUP 状態に移行する。 すると、

/etc/rc.d/vrrp_notify INSTANCE VI BACKUP

実行されて、vrrp_notify が adsl-stop を呼び出す。

そして、adsl-stop が adsl-connect が強制終了する。 こうして完全な BACKUP 状態になるはずだった。

ところが

今朝起きて見てみると、 ゲートウェイが両方とも BACKUP 状態になっていた。(*_*)

片方のゲートウェイは PPPoE がつながっていて、 インターネットに正常に接続しているのだが、 あいにく BACKUP 状態なので、 GCD LAN のデフォルトゲートウェイアドレスである 192.168.1.1 を 持っておらず、 GCD LAN の他のマシンからインターネットへ接続できない状態に 陥っていた。

どうしてこんな事態になってしまったのか考えるより、 まずは復旧が優先ということで、 PPPoE がつながっているのに BACKUP 状態となっている 中途半端なゲートウェイ上で adsl-connect プロセスを殺し、 keepalived を再起動させて、 完全な BACKUP 状態へ移行させた。

すると、もう片方のゲートウェイが自動的に MASTER へ昇格して、 無事正常な状態に戻った。

その後、原因を調べていると、 前述したように adsl-stop が adsl-connect を強制終了させることが できずに adsl-connect が走り続けていたことが原因と判明。 つまり、adsl-connect が走り続けたために、 BACKUP 状態であるにもかかわらず PPPoE のリトライを行っていた。 そして bフレッツのメンテナンス工事の終了にともなって PPPoE が成功、 BACKUP 状態なのに PPPoE でつながっている、という状態が発生した。 この状態では、正常にインターネットにつながっているために、 MASTER に昇格することはなく、BACKUP 状態が継続する。

一方、もう片方のゲートウェイは、MASTER に昇格しようとして PPPoE を試みても失敗してしまう。 つまり MASTER へ昇格できない。 したがって、両方のゲートウェイが BACKUP 状態のままになる。

というわけで問題は adsl-stop が adsl-connect を 終了させることができない点にありそうだと推測。 あらためて adsl-stop を読みなおすと...

    # Kill pppd, which should in turn kill pppoe
    if [ -r "$PPPD_PIDFILE" ] ; then
        PPPD_PID=`cat "$PPPD_PIDFILE"`
        $LOGGER -p daemon.notice "Killing pppd"
        echo "Killing pppd ($PPPD_PID)"
        kill $PPPD_PID > /dev/null 2>&1 || exit 1
    fi
    ....
    # Kill adsl-connect
    $LOGGER -p daemon.notice "Killing adsl-connect"
    echo "Killing adsl-connect ($PID)"
    kill $PID > /dev/null 2>&1

以前このスクリプトを読んだときは見落としていたのだが、 「kill $PPPD_PID」の後に「|| exit 1」がついている! なんだこれは!?

つまり、pppd プロセスが動いていなければ exit してしまうので、 adsl-connect を終了させないではないか! 誰だ、こんな頭悪いコードを書いた奴は。

adsl-connect は pppd が失敗すると、 リトライするまえに 5秒 sleep する。 つまりこの 5秒間は pppd プロセスが無い。 だから、運悪く sleep 中に adsl-stop を実行すると、 adsl-connect が強制終了されずに残ってしまう。

速攻で adsl-stop から「|| exit 1」の部分を削除した。 これで安心 (だといいな)。

Filed under: システム構築・運用 — hiroaki_sengoku @ 11:56
2006年4月7日

DB サーバのセキュリティ向上策 (5)

前々回(3)前回(4) と、 他人の DB パスワードを知ったユーザが、 その人になりすまして DB にログインしようとしても DBサーバへの通信を遮断する仕掛けについて説明しました。 (3) はクライアント側で、(4) はサーバ側で、 それぞれ DBサーバへの通信を監視し、 UNIX ユーザ名と、DB ユーザ名が一致しない場合は通信を遮断します。

DB サーバへの通信から DB ユーザ名を抽出する方法は、 DB サーバの種類によって異なるので、 専用のものを実装することになるのですが、 今回はその一例として MySQL 4.0.x の場合について説明しましょう。

MySQL の場合は、ソースが公開されていますし、 開発者向けにはプロトコル仕様書もあるようなので、 クライアント-サーバ間通信を完全に解析することも可能なのですが、 DBユーザ名を取り出す程度なら通信内容をダンプするだけでも 取り出し方が推測できます。

まずは手始めに通信内容をダンプしてみましょう。 どんなツールを使ってもよいのですが、 ここでは拙作 stone を使ってみます。 適当なポートで listen し、 それを MySQL サーバへ中継しつつ、 通信内容をダンプするように stone を実行します。 例えば、12345番ポートで listen し、 「-ppp」オプションを指定することによって通信内容をダンプさせ、 ホスト「dbserver」の 3306番ポートへ中継させるためには、 次のように stone を実行します。

stone -ppp dbserver:3306 12345

そして、MySQL のクライアントである mysql コマンドを実行します。 MySQL サーバに接続する代わりに、 stone が listen する 12345番ポートに接続させましょう。

mysql -P12345 -h127.0.0.1 -usengoku -pabcdefg

DB ユーザ名「sengoku」、パスワード「abcdefg」で接続します。 この時、stone の出力は次のようになります:

% stone -ppp dbserver:3306 12345
Apr  7 07:04:45.525293 16384 start (2.3a) [19635]
Apr  7 07:04:45.530733 16384 stone 3: senri.gcd.org:3306 <- 0.0.0.0:12345
Apr  7 07:05:03.405877 16384 stone 3: accepted TCP 5 from 127.0.0.1:37758 mode=3

Apr  7 07:05:03.417693 16384 3 5<6 34 00 00 00 0a 34 2e 30  4....4.0
Apr  7 07:05:03.417785 16384 3 5<6 2e 32 35 2d 73 74 61 6e  .xx-stan
Apr  7 07:05:03.417802 16384 3 5<6 64 61 72 64 2d 6c 6f 67  dard-log
Apr  7 07:05:03.417813 16384 3 5<6 00 e8 7e 00 00 2d 3a 79  ..~..-:y
Apr  7 07:05:03.417823 16384 3 5<6 75 5e 58 7e 31 00 2c 20  u^X~1.,
Apr  7 07:05:03.417833 16384 3 5<6 0c 02 00 00 00 00 00 00  ........
Apr  7 07:05:03.417844 16384 3 5<6 00 00 00 00 00 00 00 00  ........
Apr  7 07:05:03.418337 16384 3 5>6 15 00 00 01 85 24 00 00  .....$..
Apr  7 07:05:03.418374 16384 3 5>6 00 73 65 6e 67 6f 6b 75  .sengoku
Apr  7 07:05:03.418385 16384 3 5>6 00 53 4d 5c 4a 55 53 49  .SM\JUSI
Apr  7 07:05:03.418393 16384 3 5>6 57                       W
Apr  7 07:05:03.418643 16384 3 5<6 05 00 00 02 00 00 00 02  ........
Apr  7 07:05:03.418671 16384 3 5<6 00                       .

各行始めの「Apr 7 07:04:45.525293」は時刻で、マイクロ秒単位で表示しています (マイクロ秒単位まで表示するようになったのは stone 2.3a からです)。 次の「16384」はスレッドID ですが、今回は無視してもらって構いません。 最初の三行は stone のログなので無視するとして、 次の部分が MySQL サーバからクライアントへ送られた通信内容です。 「5<6」が、サーバ→クライアント方向の通信であることを示します。

Apr  7 07:05:03.417693 16384 3 5<6 34 00 00 00 0a 34 2e 30  4....4.0
Apr  7 07:05:03.417785 16384 3 5<6 2e 32 35 2d 73 74 61 6e  .xx-stan
Apr  7 07:05:03.417802 16384 3 5<6 64 61 72 64 2d 6c 6f 67  dard-log
Apr  7 07:05:03.417813 16384 3 5<6 00 e8 7e 00 00 2d 3a 79  ..~..-:y
Apr  7 07:05:03.417823 16384 3 5<6 75 5e 58 7e 31 00 2c 20  u^X~1.,
Apr  7 07:05:03.417833 16384 3 5<6 0c 02 00 00 00 00 00 00  ........
Apr  7 07:05:03.417844 16384 3 5<6 00 00 00 00 00 00 00 00  ........

MySQL のバージョン番号らしきものが送られている様子が分かります。 ここでの目的は DB ユーザ名を抽出することであり、 DB ユーザ名は、クライアント→サーバ方向に送られるはずなので、 サーバ→クライアント方向の通信は無視してしまっても構わないのですが、 先頭の「34 00」には注目しておいた方がよいでしょう。 この手のクライアント-サーバ間プロトコルでは、 先頭にこれから送るデータの長さを送信することが一般的だからです。 実際、「34 00」は十進数で言うと 52 ですが、 クライアントへ送られたデータは 56 バイトなので、 先頭 2 バイトがデータ長、次の 2 バイト「00 00」がデータの種別、 残りの 52 バイトがデータだろう、と推測できます。

続く部分が、クライアントからサーバへ送られた通信内容です。 「5>6」が、クライアント→サーバ方向の通信であることを示します。

Apr  7 07:05:03.418337 16384 3 5>6 15 00 00 01 85 24 00 00  .....$..
Apr  7 07:05:03.418374 16384 3 5>6 00 73 65 6e 67 6f 6b 75  .sengoku
Apr  7 07:05:03.418385 16384 3 5>6 00 53 4d 5c 4a 55 53 49  .SM\JUSI
Apr  7 07:05:03.418393 16384 3 5>6 57                       W

先頭 2 バイト「15 00」がデータ長であると仮定してみます。 十進数で言うと 21 で、 データ種別と推測される 2 バイトデータ「00 01」の後に 21 バイトのデータが続いています。 そして、データの中に明らかに DB ユーザ名と思われる文字列「sengoku」と そのデリミタと思われる「00」があります。 続く 8 バイトはパスワードと推測できます。 DB ユーザ名の前の 5 バイトのデータ「85 24 00 00 00」は、 固定長のデータと推測できるので、 DBユーザ名を抽出するには、 クライアント→サーバ方向のデータのうち、 最初から 10 バイト目から「00」までを取り出せば良さそうです。

もちろん実際に運用する際は、MySQL のソースないしプロトコル仕様書を 参照して確実を期するべきですが、 プロトコル仕様が公式には公開されていない DB サーバの場合でも、

  • DB ユーザ名が取り出せなかった場合は、ログに出力した上で通信を容認
  • DB ユーザ名が取り出せたが、その DB ユーザ名が DB に存在しない場合は、 ログに出力した上で通信を容認
  • DB ユーザ名が取り出せて、かつその DB ユーザ名が存在する場合は、 取り出した DB ユーザ名が正しいものとして扱い、通信の許可/遮断を行なう

などと、DB ユーザ名を正しく取り出せなかったと思われるときは とりあえず通信を容認しておいて、 後ほど DB ユーザ名の抽出方法を改訂する、という運用が可能でしょう。

なお、MySQL の場合は前述したように公式なプロトコル仕様書もありますし、 Ian Redfern 氏がソースを解析して作成したプロトコルの解説が 以下のページで公開されています。

MySQL Protocol (MySQL 3.22 ~ 4.0)
http://www.redferni.uklinux.net/mysql/MySQL-323.html
MySQL Protocol (MySQL 4.1)
http://www.redferni.uklinux.net/mysql/MySQL-Protocol.html
Filed under: stone 開発日記,システム構築・運用 — hiroaki_sengoku @ 09:35
2006年4月6日

GCDバックアップ回線の監視(3)

GCDバックアップ回線用のフレッツADSL では、 バックアップ回線ということで固定IPアドレスにはしていない。 どのくらい安定してつながっているか過去 10日間の統計を取ってみた。

毎分 ssh のテストログイン 14400回(=10*24*60)の結果:

エラー回数 112回
IPアドレスの切換回数 114回
IPアドレス平均持続時間 123.6分
持続時間の標準偏差(σ) 201.2分
持続時間の中央値 39分
最短持続時間 1分
最長持続時間 1385分

思ったより IPアドレスの切換が激しい。 一時間も持続しないIPアドレスが半数以上にのぼる。 10時間以上安定していたのは 4例だけ。

Filed under: システム構築・運用 — hiroaki_sengoku @ 19:48
2006年4月6日

DB サーバのセキュリティ向上策 (4)

前回は、 DB サーバへの通信を監視して、 UNIX でのユーザ権限と DB ユーザ名が一致する時に限り 通信を許可する方法について説明しました。

アクセス元となるクライアント側のマシンならば、 どのユーザがアクセスしているか容易に調べられるので、 通信の監視もアクセス元で行なった方が簡単です。

しかしながらこの方法では、 データセンタ内の全てのサーバで通信の監視を行わなければならず、 やや繁雑です。 また、UNIX でのユーザ権限ごとのアクセスコントロールを 実現する方法として、 前回は各ユーザごとに専用の UNIX ドメインソケットを用意し、 そのパーミッション設定でコントロールする方法を紹介しましたが、 当然のことながら DB アクセスを行うクライアントプログラムが UNIX ドメインソケットをサポートしていなければなりません。

DB サーバへの通信の監視をアクセス先、 つまり DB サーバー側で行うことができれば、 クライアント側は監視が行われていることを意識する必要がなくなります。 つまり前回説明した「入口規制」によるアクセス制限ですね。 クライアント側から見れば、 普通に DBサーバへ TCP 接続するだけなので、 どのようなクライアントプログラムでも利用可能でしょう。

この入口規制を実現するには、 どのユーザ権限でクライアントプログラムが動いているのか、 DB サーバ側から調べる必要があります。 しかしながら、TCP 接続ではサーバ側は送られてきた パケットを受け取るだけなので、 そのパケットを誰が送信したかまでは関知しません。 そこで、通信相手が誰なのか調べる方法を定めたのが、 RFC1413 で提案された IDENT プロトコルです。 IDENT プロトコルは、 受け取った TCP パケットに記録されている 送信元の IP アドレスとポート番号を手がかりに、 相手が誰かクライアント側へ問い合わせます。

IDENT プロトコルは、あまり使われなくなって久しいので、 まず簡単に紹介しましょう。

ホスト CLIENT からホスト SERVER の 12345番ポートへアクセスした 場合について考えます。 その接続状況は次のように netstat コマンドなどで確認できて、

SERVER % netstat
Proto Recv-Q Send-Q  Local Address  Foreign Address  State
tcp        0      0  SERVER:12345   CLIENT:45486     ESTABLISHED

この場合だと、CLIENT の 45486番ポートから SERVER の 12345番ポートへの TCP 接続が確立している (ESTABLISHED) ことが分かります。

このとき、SERVER は CLIENT に IDENT 問合せをすることによって、 CLIENT のどのユーザが TCP 接続の相手か調べることができます。

SERVER % telnet CLIENT 113
Connected to CLIENT.
45486,12345                                 … (1)
45486 , 12345 : USERID : OTHER :sengoku     … (2)
Connection closed by foreign host.

(1) が SERVER から CLIENT への問合せで、 送受信双方のポート番号の対を送信しています。 これに対し、(2) が CLIENT から SERVER への応答で、 TCP 接続の相手が「sengoku」であることが分かりました。

このように、通信相手が誰か手軽に確認できる便利なプロトコルなのですが、 相手ホストが信用できなければ当然 IDENT 応答も信じることはできません。 不特定多数のホストからの通信を受け付ける場合は、 IDENT 問合せを行なっても「正直な」応答が返ってくるとは期待できないわけで、 少なくともインターネット上ではあまり使われなくなったようです。

しかし データセンタのラック内のサーバであれば、 当然管理者が決まっているでしょうから、 全てのサーバで正しく IDENT 応答を返すように徹底することは容易です。 したがって、 IDENT プロトコルを使った入口規制を実施することができます。

まず DB サーバを、UNIX ドメインソケットでのみアクセスを受け付ける ように設定します。 このソケットは、local ユーザが勝手にアクセスしたりしないよう、 DB サーバを実行するユーザ権限でのみ読み書きできるように 設定しておくとよいでしょう。

次に、特定のポートで listen し、接続を受け付けたら この UNIX ドメインソケットへ中継するプログラムを、 DB サーバを実行するユーザと同じユーザ権限で走らせます。 この中継プログラムは、 中継する際に接続元ホストに対して IDENT 問合せを行ない、 IDENT 応答で得たユーザ名と、 通信を監視することによって得られた DB ユーザ名が 一致しない場合は通信を遮断するというわけです。

このような仕掛けにより、 クライアント側のユーザは、 仕掛けを意識することなく DB サーバにアクセスすることができます。 そして、 何かのはずみに別の DBユーザのパスワードを知り、 その DBユーザになりすましてアクセスしようとしても 通信は遮断されます。

Filed under: システム構築・運用 — hiroaki_sengoku @ 12:25
2006年4月5日

DB サーバのセキュリティ向上策 (3)

一般に、マシン C からマシン S へのアクセスを制限するには、

(IN) マシン S でアクセスを受け付けるところで制限する「入口規制」
(OUT) マシン C でアクセスを出すところで制限する「出口規制」

の2通りの方法があります。一般にアクセス制限というと (IN) の入口規制を用いることが多いのですが、 これはアクセスを出すマシンが特定できないか、 あるいは特定はできるのだけどマシンの数ないし種類が多過ぎるためです。

例えば、マシン S へのログインを制限したい場合を考えてみましょう。 一般的にはアクセス元となりうるマシンは特定できないか、 特定できたとしても数が多いでしょうし、 そのマシンで動く OS の種類も多種多様でしょう。 アクセス元となりうるマシンの全てで、 アクセスを出すことを制限しようとするのは非現実的です。 なので普通はアクセスを受け付ける側のマシン S で クライアントの認証を行なってアクセス制限をします。

例えば ssh の場合ならどこのマシンからのアクセスであっても、 秘密鍵を持っていることを証明できるならアクセスを許可し、 そうでなければ却下します。 アクセスを出す側のマシンでは何の出口規制もなく、 アクセスを受け付ける側のマシンでの入口規制だけですね。

ところが、データセンタのラック内のマシンに限定すれば、 事情は変わってきます。 ラック内に入れてあるマシンの数は高々有限 ;) ですし、 多くの場合全てのマシンで同じ OS が動いているでしょうし、 管理の都合からいえば全てのマシンを同じチームが管理すべきでしょう。

このような特殊な環境下では、 (OUT) の出口規制も現実的な方法となります。 例えば DB サーバへのアクセスを考えると、 DB サーバは通常のサーバ認証のみであっても、 クライアント側でアクセスを出すのを制限する出口規制を設けることによって、 セキュリティを向上させることができます。

クライアント側の OS が Linux であれば、 出口規制の方法として iptables の OUTPUT チェインを使うことができます。 例えば DB サーバが 12345番ポートでアクセスを受け付けているならば、 ラック内の全マシンにおいて

iptables -N dbaccess 2>/dev/null || iptables -F dbaccess
iptables -A dbaccess -j ACCEPT -m owner --uid-owner dbuser  …(2)
iptables -A dbaccess -j DROP                                …(3)

iptables -A OUTPUT -j dbaccess -p tcp --dport 12345 --syn   …(1)

を実行しておきます。

DB サーバへアクセスを出そうとして、 DB サーバが動いているマシンの 12345番ポートへの接続しようとすると、 まず OUTPUT チェインの (1) のルールによって dbaccess チェインへジャンプします。 アクセスを出そうとしたユーザが dbuser であれば、 dbaccess チェインの (2) のルールによって通信が許可されますが、 dbuser 以外のユーザであれば、 (3) のルールによって通信が却下されます。

つまり、dbuser 以外のユーザは、たとえ DB のパスワードを知っていても、 DB にアクセスできない、というわけです。

DB にアクセスしたいユーザが増えてくると、 そのたびに iptables の設定を変更するのは面倒ですので、 DB サーバへ接続できるユーザは一つだけ (例えば dbuser) にしておいて、 そのユーザ権限で中継プログラムを動かすようにすると便利でしょう。

例えば、DB にアクセスしたいユーザ user1, user2, user3, user4 が あるとします。 まず、DB 上に同名のユーザアカウントを作ります。 次に、ラック内の全サーバにおいて、 ユーザ毎に UNIX ドメインソケットを listen し、 そのソケットへ接続があったら、 それを DB サーバへ中継するプログラム (ここでは dbrelay と呼ぶことにしましょう) を動かします。 例えば次のようなソケットをオープンすることになるでしょう。

/home/user1/socket
/home/user2/socket
/home/user3/socket
/home/user4/socket

各ソケット (あるいはソケットを置いてあるディレクトリ) は、 自分以外のユーザは読み書きできないように パーミッションを設定します。 つまり dbrelay は root 権限で起動する必要があります。 さらに、前述したように DB サーバへアクセスするには dbuser ユーザ権限で実行する必要がありますから、 各ソケットをオープンした後は、 dbuser ユーザ権限に setuid する必要があります。

そして、ここが肝なのですが、 dbrelay は DB サーバへの通信を監視し、 接続を受け付けたソケットのユーザ名と、 DB へのアクセスを行なう DB ユーザ名が一致しない場合は 通信を遮断します。

以上のような仕掛けにより、 例えばユーザ user1 は、 /home/user1/socket へ接続することによって DB サーバへアクセスできるが、 そのとき使用できる DB ユーザ名は user1 だけで、 それ以外のユーザ名で DB へアクセスしようとしても dbrelay によって 通信を遮断されることになります。 しかも /home/user1/socket は user1 以外は読み書きできません。 つまり、各ユーザは自身のユーザ名以外では (仮に他の DB ユーザのパスワードを知っていたとしても) DB へアクセスできない ということになります。

Filed under: システム構築・運用 — hiroaki_sengoku @ 08:39
2006年4月4日

DB サーバのセキュリティ向上策 (2)

KLab で採用している DB サーバのセキュリティ向上策を説明する前に、 DB アクセスの際に SSL クライアント認証を行なう方法について説明します。

DB サーバへのアクセスにおいて SSL クライアント認証を必須とし、

(a) 開発者が (デバッグ目的等で) DB アクセスを行なう時は、 その開発者個人が管理する SSL 秘密鍵を用いてアクセスするようにし、

(b) プログラムが DB アクセスを行なう時は、 そのプログラムの実行権限でのみアクセスできる SSL 秘密鍵を 用いるようにすれば、

普通のパスワード認証よりはセキュリティを向上させることができます。 SSL クライアント認証をサポートしている DB サーバであれば、 その機能を有効にするだけで良いので、とても手軽な方法です。

ここで注意したいのは、 普通に SSL を使う (つまり SSL による暗号化のみを行なう、 あるいは暗号化に加えて SSL サーバ認証のみ行なう) ことは、 あまり意味がない、ということです。

データセンタのラック内の通信の盗聴を心配しても仕方がないわけで、 通信路を暗号化すること自体には意味はないでしょう。 また、サーバ認証は接続先が意図したサーバか確認するための手段ですが、 これもラック内で、通信相手が意図通りのサーバでないか心配しても 仕方がないですね。

SSL クライアント認証をサポートしていない DB サーバでも、 拙作 stone を使えば、手軽に SSL クライアント認証を付け加えることができます。

例えば DB サーバへのアクセスを unix ドメインソケット /path/to/socket でのみ 受け付けている場合、このソケットへのアクセス権限を DB サーバの実行ユーザ (ここでは uid が 1001 番とします) 権限に限定して、 local ユーザがアクセスできないようにしておいて、 stone を次のように実行します。

stone -o 1001 -z verify \
      -z CApath=/usr/local/ssl/certs \
      -z key=/usr/local/ssl/private/db.pem \
      /path/to/socket 12345/ssl

「-z verify」が SSL クライアント認証を必須とするためのオプションです。 「-z CApath=/usr/local/ssl/certs」オプションで、 CA の証明書を置いてあるパスを指定します。

すると、その CA が署名した SSL 証明書に対応する秘密鍵を 持っているクライアントが、その SSL 証明書を提示して ポート 12345 番に SSL 接続してきた時のみ、 stone はそれを /path/to/socket へ中継します。

CA が署名した SSL 証明書ならなんでも OK とするのではなく、 特定の CA の特定の証明書のみを受け付ける場合は、

stone -o 1001 -z verify \
      -z CApath=/usr/local/ssl/certs \
      -z key=/usr/local/ssl/private/db.pem \
      -z depth=1 \
      -z re1='/CN=KLAB Root CA[/$]' \
      -z re0='/CN=dbuser[0-9]*[/$]' \
      /path/to/socket 12345/ssl

などのように、SSL証明書の発行対象の名称 (CN) を特定するための 正規表現 (この例では「/CN=dbuser[0-9]*[/$]」) を指定します。

なお、ここでいう証明書は、いわゆる「オレオレ証明書」で構いません。 つまり DB サーバの管理者が必要に応じて何枚でも独自に発行できます。

「オレオレ証明書」が問題となるのは、認証する側が認めていない CA が 証明書を発行する場合です。 例えばサーバ認証を行なう場合は、認証する側は WWW ブラウザなどになります。 WWW ブラウザのユーザが認めていない CA を勝手に立てて証明書を発行し、 ユーザにきちんと説明することなくその証明書を受け入れることを 強要すべきではありません。これがいわゆる「オレオレ証明書」です。

一方、クライアント認証の場合は、認証を行なうのはサーバ側であるので、 サーバの管理者が認める CA ならばなんでも構いません。 もちろんサーバの管理者が独自に立てた CA で OK です。

上記の例では、KLab で立てた「KLAB Root CA」が発行した証明書で、 かつその発行対象の名称 (CN) が「dbuser」+ 0桁以上の数字 の場合 のみ接続を受け付けます。

DB へアクセスする必要がある開発者と、DB へアクセスするプログラム それぞれに別々の証明書を発行すれば、DB 側で 誰からのアクセスか特定することが可能になります。

しかしながら、

(1) プログラム用の秘密鍵を誰が管理するのか?

(2) SSL クライアント認証にともなう負荷増大

という問題が残ります。(2) はコストを度外視すれば済むので、 高いパフォーマンスが要求されない場合は問題とならないかも知れません。 が、(1) はなかなかやっかいです。

プログラムの開発者は、プログラムの実行権限で読むことができるファイルは 何でも読めます。例えば、秘密鍵を読んで特定の場所へコピーするよう プログラムを改変することは至って簡単でしょう。 したがって、プログラム専用の秘密鍵というのは実は 開発者全員で共同管理している秘密鍵と大差ありません。

プログラムの開発者なら誰でも DB にアクセスできる、 という状況を許容するなら、わざわざクライアント認証のような 負荷の高い方法を選択しなくても、と思うのが人情です。

ではどういう方法がよいでしょうか?

(続きは次回に)

Filed under: stone 開発日記,システム構築・運用 — hiroaki_sengoku @ 08:03
2006年4月3日

DB サーバのセキュリティ向上策 (1)

KLab が運用しているコンテンツで使用している DB サーバは、
パスワードを知っているだけではアクセスできません。
どういう仕掛けになっているかの説明は後のお楽しみ、ということで
まずは前振りから...

パスワードというのは知る人が多くなればなるほど漏れるものですし、
ひとたび漏れてしまえば、どこまで漏れるかコントロール不能です。
したがって DB に限らず、KLab ではパスワードへの依存を
できる限り減らしています。

例えば、サーバへのログインは、必ず ssh の RSA 認証を使うことを必須とし、
コンテンツ管理のためのページでは SSL クライアント認証を行なっています。
つまり、秘密鍵を持っている人のみがアクセスできるようにしておいて、
秘密鍵自体は各人の責任において管理してもらう、という方式です。
万一、サーバへ不正なアクセスが行なわれたら、
誰の秘密鍵によってアクセスされたかログが残りますから、
誰の責任か明確になるわけです。

ところが、プログラムが DB サーバなどへアクセスする場合は事情が
変わってきます。まず、

(1) プログラムには責任を負わせることができない ;-)

そのプログラムを開発したり運用したりする人が、
秘密鍵を管理するしかありませんが、
秘密鍵というのはあくまで一人の個人が管理するからこそ
責任を負わせられるのであって、
共同管理ということにしてしまっては、
万一漏れた時に、どこから漏れたのか調べようがなくなります。

かといって、そのプログラムが動作する時に用いる鍵の管理を、
一人の個人が管理するルールにしてしまうと、
運用がとても大変になります。
障害が起きた時に、その人がいなければ原因究明もままなりません。

二番目の問題として、

(2) DB アクセスには高いパフォーマンスが要求される

人がサーバ等へログインするときは、所詮は人間のスピードですから、
大したレスポンススピードは必要ありません。
秘密鍵による認証を行なう余裕は充分にあります。
一方、Web アプリケーション等のプログラムが DB サーバへアクセスする場合は、
ページのヒット数が高ければ高いほど、高いパフォーマンスが要求されます。

コネクションをプールするなどの手法によって、
認証コストを下げることは可能であるものの、
プログラム-DBサーバ間の通信路の暗号化などを行なっていては、
暗号化処理のぶんだけサーバ負荷が余計にかかります。
つまり DB サーバへのアクセスに SSL クライアント認証を行なう、
などの方法は、なるべくなら避けたいところです。

ではどうすればいいでしょうか?
(続きは次回に)

Filed under: システム構築・運用 — hiroaki_sengoku @ 11:20
2006年4月3日

IPv6 (2) hatena_b

IPv6ブリッジ機能付きルーター (ブルータ) を使えば、 NAT 内の LAN でそのまま IPv6 を使えるわけで、 IPv6 の敷居は一気に下がる。

つまり、ほとんどの OS がすでに IPv6 をサポートしているので、 ルータが IPv6 を素通し (ブリッジ) しさえすれば、 LAN 内で IPv6 を意識せずに使える。

今まで通り IP を (NAT 経由したプライベートアドレスで) 使いながら、IPv6 のオイシイところ (end-to-end 通信ができる) だけを ツマミ食いできるわけで、 今度こそ (^^;) IPv6 が普及するのではないかと...

Linux でブルータを実現するには、 まずブリッジ機能をカーネルに組み込んでおく。

# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.00022Axxxxxx       no              eth0
                                                        eth1

このままだと IP までブリッジしてしまうので、 IP に対してはルータとして機能し、 IPv6 に対してだけブリッジさせるために、ebtables を使う。

# ebtables -t broute -L
Bridge table: broute

Bridge chain: BROUTING, entries: 3, policy: DROP      …… (3)
-j mark --set-mark 0x0 --mark-target CONTINUE         …… (0)
-p IPv6 -i eth0 -j mark --set-mark 0x600              …… (1)
-p IPv6 -i eth1 -j mark --set-mark 0x601              …… (2)

上記設定の意味は、

(0) まず全パケットに対し 0x0 のマークをつける。
    で、
(1) eth0 から入ってきた (LAN内から外へ出ていく)
    IPv6 パケットは、0x600 のマークをつけてブリッジする。
(2) 逆に eth1 から入ってきた (外から入ってきた)
    IPv6 パケットは、0x601 のマークをつけてブリッジする。
(3) それ以外 (IP パケットや PPPoE パケット) はブリッジしない (DROP)
    つまり IP に対してはルータとして機能する

さらに ip6tables を使ってフィルタリングする。

ip6tables -P FORWARD DROP                                       …… (*)
ip6tables -I FORWARD -j incoming -m mark --mark 0x601/0xffff    …… (2)
ip6tables -I FORWARD -j ACCEPT -m mark --mark 0x600/0xffff      …… (1)
(1) 0x600 のマークがついているパケットは、素通し (ACCEPT) する。
(2) 0x601 のマークがついているパケットは、incoming チェインへ渡す。

incoming チェインで ACCEPT されなかったパケットは、
(*) FORWARD チェインのポリシーに従って、DROP される。

ebtables でマーク付して ip6tables でそのマークに基づいて フィルタリングするという、 まわりくどい方法をとっているのは、 ebtables はあくまで L2 のフィルタなので IPv6 アドレスに基づいたフィルタリングができず、 逆に ip6tables は L3 のフィルタなので eth0/eth1 はまとめてブリッジインタフェース br0 としてしか見えず、 どちらの物理インタフェースから入ってきたパケットか 判別できないため。

ちなみに iptables だと、 L3 フィルタといいながら physdev モジュールがあるので、 ブリッジのどちら側から入ってきたか判別できたりする。 ip6tables の機能拡張に期待したいところ。

Filed under: IPv6,システム構築・運用 — hiroaki_sengoku @ 07:20
2006年3月31日

ネイティブ IPv6

昨日に引き続き、これも tech ML で流した IPv6 ネタですが...

KLab のイントラのサーバである kamiya で、

ping6 -I eth0 ff02::1

を実行してみると、20台程度のマシンが反応します。うち、半分くらいは、 私が IPv6 をインストールしたマシンだったりします。 Linux や WindowsXP は標準で IPv6 をサポートしてますし、 Windows2000 も IPv6 Technology Preview を使えば IPv6 が使えます。興味がある人は試してみては? 今まで鳴かず飛ばずだった IPv6 ですが、なんとなく いろいろ使えそうな予感がします。 いろいろな仕掛けを IPv6 へ移行中...

# ついでに言うと stone も、IPv6 をサポートしています

六本木LAN の kamiya からフツーに IP で、私の自宅サーバ asao.gcd.org へ ping を打って、

kamiya:/home/sengoku % ping -t 64 asao.gcd.org
PING asao.gcd.org (60.32.85.216) from 10.10.0.2 : 56(84) bytes of data.
64 bytes from gcd.org (60.32.85.216): icmp_seq=1 ttl=50 time=6.55 ms

asao.gcd.org 側で見ると、

asao.gcd.org:/root # tcpdump -v -i ppp0 icmp
tcpdump: listening on ppp0, link-type LINUX_SLL (Linux cooked), capture size 96 bytes
09:34:55.115600 IP (tos 0x0, ttl  50, id 0, offset 0, flags [DF], length: 84) 161.90.128.210.bf.2iij.net > asaogw.gcd.org: icmp 64: echo request seq 256

64 に設定した ttl が 50 まで減っています。つまり 14 hop あるということ ですね。ping パケットは

六本木LAN → PPPoE (IPv6網) → IIJ (6 hop) ─┐
                                             ↓
                                           MFEED
                                             │
  自宅LAN ← PPPoE (IPv6網) ← OCN (7 hop) ←┘

と延々と旅をしてますし、しかも IPv6網は PPPoE でトンネリングして しまっているので、IPv6網での物理的な hop 数はカウントされていません。 実質的には合計で 20 ~ 22 hop 程度はあると考えるべきでしょう。

一方 IPv6 で asao.gcd.org へ ping を打つと、

asao.gcd.org:/root # tcpdump -v -i br0 icmp6
tcpdump: WARNING: br0: no IPv4 address assigned
tcpdump: listening on br0, link-type EN10MB (Ethernet), capture size 96 bytes
09:37:10.664278 kamiya.v6.klab.org > asao.v6.gcd.org: icmp6: echo request seq 256 (len 64, hlim 60)

hlim が 60 までしか減ってません。つまりわずか 4 hop ですね。

六本木LAN → IPv6網 → 自宅LAN

しかも途中に PPPoE のような邪魔なものは入っていないので、 mtu は 1500 のままです。

Filed under: IPv6,システム構築・運用 — hiroaki_sengoku @ 08:38
« Newer PostsOlder Posts »