仙石浩明の日記

システム構築・運用

2006年3月30日

glibc 2.3 での IPv6

一年以上前に tech ML で取り上げたネタなのですが、現在よく使われている Linux ディストリビューションでも glibc 2.3.2 あたりが使われることもある ようなので紹介します。


KLab のイントラのサーバには、IPv6 なアドレスも割り当ててあります。 例えば、

% host kamiya.v6.klab.org
kamiya.v6.klab.org has IPv6 address 2001:c90:c1c:100e:2e0:81ff:feab:cdef

% host 2001:c90:c1c:100e:2e0:81ff:feab:cdef
f.e.d.c.b.a.e.f.f.f.1.8.0.e.2.0.e.0.0.1.c.1.c.0.0.9.c.0.1.0.0.2.ip6.arpa domain name pointer kamiya.v6.klab.org.

のような感じ。kamiya というホスト名は KLab が六本木ヒルズへ移転してくる 前は、神谷町にオフィスがあったことにちなんでいます。イントラのサーバ群に は地名がつけられているマシンが多く、もちろん roppongi というホスト名の マシンもあります。

で、当時は Linux サーバの多くは glibc 2.2 を使っていたのですが、一部の マシンは glibc 2.3 にバージョンアップしていました。ところが、glibc 2.3 な マシンから ping6 を打ってみると異様に遅い...

% time ping6 -c 3 kamiya.v6.klab.org
PING kamiya.v6.klab.org(kamiya.v6.klab.org) 56 data bytes
64 bytes from kamiya.v6.klab.org: icmp_seq=1 ttl=64 time=1.10 ms
64 bytes from kamiya.v6.klab.org: icmp_seq=2 ttl=64 time=0.563 ms
64 bytes from kamiya.v6.klab.org: icmp_seq=3 ttl=64 time=0.363 ms

--- kamiya.v6.klab.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 20022ms
rtt min/avg/max/mdev = 0.338/0.475/0.569/0.102 ms
0.006u 0.004s 0:40.04 0.0%      0+0k 0+0io 0pf+0w

3 発 ping を打つだけなのに 40 秒もかかっています。-n オプションを 指定して、逆引きを抑制すると、

% time ping6 -nc 3 kamiya.v6.klab.org
PING kamiya.v6.klab.org(2001:c90:c1c:100e:2e0:81ff:feab:cdef) 56 data bytes
64 bytes from 2001:c90:c1c:100e:2e0:81ff:feab:cdef: icmp_seq=1 ttl=64 time=0.981 ms
64 bytes from 2001:c90:c1c:100e:2e0:81ff:feab:cdef: icmp_seq=2 ttl=64 time=0.354 ms
64 bytes from 2001:c90:c1c:100e:2e0:81ff:feab:cdef: icmp_seq=3 ttl=64 time=0.273 ms

--- kamiya.v6.klab.org ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 0.273/0.536/0.981/0.316 ms
0.003u 0.004s 0:02.02 0.0%      0+0k 0+0io 0pf+0w

などとフツーに 2 秒程度で終わるので、DNS の逆引きに問題があることが 分かります。一回の逆引きに 10 秒ほどかかっているようです。 てっきりネームサーバの設定の問題かと思ったのですが、host コマンドや dnsqr コマンドを使う限り、このような遅れは生じません。ping6 をはじめ、 glibc の getnameinfo(3) を使う場合だけ遅延が発生します。

後で気づいたのですが、この問題が起きるのは glibc 2.3 だけで glibc 2.2 では起きません (つまり kamiya とかでは正常に ping6 できる)。また、 当然ながら glibc 2.3 でも IP の逆引きは正常で、問題なのは IPv6 の逆引き だけです。

# 後述するように問題があるのは glibc 2.3.3 までで 2.3.4 は問題ありません こーいうときは tcpdump が基本だよね、つーことでパケットダンプしてみると、 getnameinfo(3) の場合は、

\[x20010c900c1c100e02e081fffeabcdef/128].ip6.arpa.

というクエリがまず飛び、10 秒ほどたってタイムアウトした後に

f.e.d.c.b.a.e.f.f.f.1.8.0.e.2.0.e.0.0.1.c.1.c.0.0.9.c.0.1.0.0.2.ip6.arpa.

というクエリが飛ぶことが分かりました。前者は見慣れない形式だったのですが、 「Binary Label」ないし「Bit-String」などと呼ばれる形式のようです (ちなみ に後者は nibble 形式)。「Binary Label」は、ドメイン名の一形式として RFC1035 で規定され、DNS での使い方が RFC2673 で決められたにもかかわらず、 ネームサーバでサポートされなかったために、RFC3363 で IPv6 の逆引きの方法 としては、使うのを断念されてしまった不幸な形式のようです。

とはいえ、「DNS で、どーして上位バイトが先にくるんだ~ 実装のこと何も 考えてないな~」と脊髄反射的に拒否したくなる、頭悪い (brain damaged) 形式なので、断念されて幸い、ということもできますね。

2002年8月に RFC3363 で正式に断念された形式なら、そのまま人々の記憶から 忘れ去られて欲しかったのですが、何を血迷ったか、glibc 2.3 は IPv6 の 逆引きで、まず「Bit-String」クエリを試し、タイムアウトしたら「nibble」 クエリを送信するという実装になっています (glibc の resolv は BIND 由来 だから?)。

少なくとも 2004年8月3日に公開された glibc 2.3.3 では Bit-String が デフォルトのままですね。一刻も早く Bit-String が使われなくなることを 願ってやみません。

願ってるだけではアレ (^^;) なので、ソースを見てみると、 glibc-2.3.3/resolv/nss_dns/dns-host.c (2003年10月26日) では

case AF_INET6:
  /* XXX Maybe we need an option to select whether to use the nibble
     or the bitfield form.  The RFC requires the bitfield form so
     we use it.  */

って書いてありますね (Maybe って書くくらいならオプション指定できるように しろよ...)。これが glibc-2.3.4/resolv/nss_dns/dns-host.c (2004年10月25日) だと

case AF_INET6:
  /* Only lookup with the byte string format if the user wants it.  */
  if (__builtin_expect (_res.options & RES_USEBSTRING, 0))
    {
      qp = stpcpy (qbuf, "\\[x");
      ...

に修正されています! つまりデフォルトでは nibble 形式に変更されたんです ね。めでたしめでたし。さっさと glibc 2.3.4 (2005年1月26日) に上げよっと。

...と書いてる間に自宅マシンで 2.3.4 を make して install してみました。 無事、getnameinfo(3) が遅延なく IPv6 の逆引きができるようになりました。 メール書いているうちに自己完結してしまったわけですが、まあ何かの参考に なるかも知れないし、IPv6 に興味を持ってくれる人が増えるといいな、 ということで tech に投げておきます。

#12237                                                          仙石 浩明
https://www.gcd.org/sengoku/             Hiroaki Sengoku <sengoku@gcd.org>
2006年3月30日

IPv6 (1)

バックボーンには導入が進むものの、 一般ユーザには一向に普及する兆しのない IPv6。 可能性があるとすれば、安価なブルータの普及が鍵だろうと思う。

ADSL や FTTH によって安価にインターネットへ常時接続できるようになり、 また一家に複数の PC を持つことが普通になってルータも普及してきた。 このルータに、IPv6 ブリッジ機能が標準で搭載されるようになれば、 IPv6 への移行は格段に容易になるに違いない。 つまりユーザが意識しなくても NAT の内側の LAN 上の PC で IPv6 が使えるようになる。

実際、NTT東日本のフレッツドットネット対応を謳って、 IPv6 ブリッジ機能を持つ安価なルータが多数販売されている。

IPv6対応(フレッツドットネット対応=IPv6ブリッジ機能付き) ルータ一覧

IPv6 が IP に比べて優れた点があるとは思わないが、 IP の「やり直し」という意味はあるだろう。 IP アドレスの割当問題しかり、 無防備な PC の氾濫しかり。

IP が提案された当時、現在のような普及状況は誰も予測していなかったわけで、 今、やり直すことができるのなら、もっと効率的なアドレス割当ができるだろう。

IP スタックが OS に標準搭載されるのが一般的になり始めた頃、 現在のようなウィルス蔓延の可能性を、 アプリケーション開発者の大半が意識できていなかったわけで、 今、やり直すことができるのなら、IP 通信を受付けることの危険性を 認識した上での開発ができるだろう。

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

OS

OS って何だろう。

言うまでもなく OS といえば、 コンピュータのリソースを管理するものであり、 またハードウェアの仕様の差を吸収して、 異なるハードウェア上で同一のプログラムを 走らせることができるようにするソフトウェアである。

ただ、OS といっても、 ほとんどカーネルと呼んだほうがいいような場合もあるし、 ミドルウェアの機能をまで含んで、 アプリケーションの操作性を統一するようなものまである。 さらには Windows における Internet Explorer のように、 従来はアプリケーションと思われていたものまで OS としてしまう場合すらある。

わたしが初めて使った OS (と呼べるかどうかは微妙だが) は、 CP/M だった。自作 PC (今風に言う自作 PC ではなく、 回路の設計から半田付けまですべて自分で作る PC である。 CPUなどはもちろん LSI を使うが、 ほかは汎用 TTL でロジックをくみ上げているので、 今風に言うチップセットは存在しない) 用の BIOS を スクラッチから開発して、市販されていた CP/M を移植した。

低機能な OS をハードウェアレベルから くみ上げるところから始めたということもあって、 OS というとわたしはカーネルに近いレベルを想定してしまう。一方、

システム管理コラム集 実践してみてわかったことシリーズその1

などを読むと、 あらためて人によって OS という言葉から思い浮かべるものが 異なるものだと実感する。 私にとっては Linux の各ディストリビューションごとの差異など あまり気にしなかったりするのだが、 最近の人にとっては、ディストリビューションが違うと、 異なる OS ととらえることもあるのだろう。

ちなみに、私の自宅サーバは、 10年以上前にインストールした Slackware をベースにしている。 ベースにしているといっても、 カーネルや libc をはじめとして ほとんどすべてのプログラムをアップデートしているので、 元のディストリビューションの痕跡は皆無といっていい。 自作ディストリビューションと呼べるかもしれない。 これを私が管理する全ての Linux マシンにコピーして使っている。

会社 (KLab(株)) のサーバは、私の直轄のチームが管理していて、 こちらはさすがに自作ディストリビューションというわけにはいかず、Debian をベースにしているが、 コアの部分は KLab 独自の拡張を加えている。 つまり誰が作っても同じようになる部分は 既存のディストリビューションを使うことによって「手を抜き」、 コアの部分は独自に開発して運用コストを下げたり、 耐故障性能を向上させたり、パフォーマンスを改善したりしている。

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

マルチキャスト(2)

VRRP のマルチキャスト (VRRP Advert) を取りこぼすのは、 NIC が悪いのかも、 と思って別NIC を使用するように変更してみたのだが、 相変わらずスタンバイが勝手にアクティブに昇格したがる。

アクティブ側から見ると

Mar 22 12:58:36 asao Keepalived_vrrp: VRRP_Instance(VI)
                     Received lower prio advert, forcing new election
Mar 22 12:58:36 asao Keepalived_vrrp: VRRP_Instance(VI)
                     Sending gratuitous ARPs on eth1 for 192.168.0.254

スタンバイ側から見ると

Mar 22 12:58:30 senri Keepalived_vrrp: VRRP_Instance(VI)
                      Transition to MASTER STATE
Mar 22 12:58:31 senri Keepalived_vrrp: VRRP_Instance(VI)
                      Entering MASTER STATE
Mar 22 12:58:31 senri Keepalived_vrrp: VRRP_Instance(VI)
                      setting protocol VIPs.
Mar 22 12:58:31 senri Keepalived_vrrp: VRRP_Instance(VI)
                      Sending gratuitous ARPs on eth1 for 192.168.0.254
Mar 22 12:58:31 senri Keepalived_vrrp:
                      Netlink reflector reports IP 192.168.0.254 added

Mar 22 12:58:36 senri Keepalived_vrrp: VRRP_Instance(VI)
                      Received higher prio advert
Mar 22 12:58:36 senri Keepalived_vrrp: VRRP_Instance(VI)
                      Entering BACKUP STATE
Mar 22 12:58:36 senri Keepalived_vrrp: VRRP_Instance(VI)
                      removing protocol VIPs.
Mar 22 12:58:36 senri Keepalived_vrrp:
                      Netlink reflector reports IP 192.168.0.254 removed

tcpdump で確認すると、 VRRP Advert パケットはスタンバイ側に届いているのだが、 keepalived がそれを読めないらしい。 勝手にアクティブになるくせに、 5秒程度で Received higher prio advert して おとなしくスタンバイに戻る。

アクティブになったときに、 (自分がゲートウェイになったつもりで) 本当のゲートウェイへのルーティングを削除してしまうと、 外部への通信が途絶してしまうので、 PPPoE が成功したときのみルーティングを変更するようにした。 これで、勝手にアクティブになったとしても PPPoE が失敗する限りは 実質的に何も変わらないようになった。

keepalived を単なる死活確認にしか使っていない (しかも死んでないのに死んだと誤判断することあり) わけで、 モッタイナイお化けがでそうだ (^^;)。

Filed under: システム構築・運用 — hiroaki_sengoku @ 14:58
2006年3月19日

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

sshによるバックアップ回線の監視を仕掛けて一日、 タイムアウト(監視プログラムには 10秒のalarmを仕掛けている) エラーが発生。

なぜかと思って調べてみると、 同一IPアドレスからのsshアクセスが多い、 という理由でブロックされてしまっていた (^^;)。 ssh攻撃が多い昨今、GCDのサーバには、 次のようなフィルタが仕掛けてある:

iptables -N block_ssh 2>/dev/null || iptables -F block_ssh
iptables -N ssh 2>/dev/null || iptables -F ssh
iptables -A block_ssh -j LOG --log-prefix block_ssh: \
        -m recent --name block_ssh --set
iptables -A block_ssh -j DROP
iptables -A ssh -j REJECT -p tcp --syn \
        -m recent --update --seconds 600 --name block_ssh
iptables -A ssh -j block_ssh -p tcp --syn \
        -m recent --rcheck --seconds 60 --hitcount 5 --name syn_ssh
iptables -A ssh -p tcp --syn \
        -m recent --set --name syn_ssh
iptables -A ssh -j ACCEPT

# この設定は http://d.hatena.ne.jp/hirose31/20050920/1127208718
# を参考にさせて頂きました (_O_)

つまり 1分間に 5回以上、同じIPアドレスから ssh接続があると、 10分間ブロックする。 監視元IPアドレスが、いったんブロックされると、 毎分接続を試みるわけだから、ずっとブロックされたままになる。 あわてて、監視元IPアドレスをブロック対象からはずした:

iptables -I ssh -j ACCEPT -s 60.32.85.216/29
Filed under: システム構築・運用 — hiroaki_sengoku @ 23:07
2006年3月18日

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

GCD は、bフレッツでインターネットに接続している。 普通に PPPoE しているほか、 フレッツ・ドット・ネットを使っているので、 ネイティブ IPv6 でも外部から (といっても、フレッツ・ドット・ネットを使っているサイト限定だが) 接続できるので、 PPPoE がこけた (設定変更をミスったときなど) ときでも リモートから復旧させることができる。

普通はこれで十分なのだが、さらに念のためということで、 フレッツADSL でもインターネットへ接続して バックアップ回線としている。 bフレッツ側が全滅しても、 ADSL経由でログインできるようにしてある (もちろん、それぞれ別系統のハブに接続してあるし、 ログイン先のサーバは複数ある)。

このバックアップ回線は滅多に使わないので、 いつのまにか不通になっていても気づかないかもしれない、 ということで、さくっと (設定込みで 30分くらい) 監視プログラムを仕掛けた。 単に bフレッツ→インターネット→フレッツADSL 経由で ssh ログインするだけのプログラムを cron で定期的に走らせるだけだが、 不通になっていることに気づかない、という事態は避けられるだろう。

Filed under: システム構築・運用 — hiroaki_sengoku @ 22:47
2006年3月16日

マルチキャスト (1)

GCDの二台のゲートウェイのうちの片方 (senri.gcd.org) の 1000baseT NIC (eth0) が時々マルチキャストをとりこぼす。 二台のゲートウェイは、 VRRP で アクティブ・スタンバイ構成になっているのだが、 senri がスタンバイのときに、 もう片方 (asao.gcd.org) からの VRRP Advert をとりこぼしてしまい、 勝手に アクティブへ昇格しようとする。 一日~数日に一度くらい、このとりこぼしは起きるようだ。 アクティブになっても、 OCN へ PPPoE しに行って失敗して (asao が PPPoE しているから) スタンバイへ戻るので、まあ実害はないのだが、 あまり気持ちのよいものではない。

eth0 で VRRP するのをやめて、 eth1 (100baseT NIC) で VRRP するようにしてみた。 eth1 は PPPoE (と、フレッツ・ドット・ネットのネイティブ IPv6) 専用で、 IPv4 アドレスは割り当てていないのだが、 マルチキャストなので VRRP Advert は受け取れるようだ。

keepalived.conf はこんな感じ:

vrrp_instance VI {
    state MASTER
    interface eth1
    garp_master_delay 10
    virtual_router_id 33
    priority 230
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass XXXX
    }
    virtual_ipaddress {
        192.168.0.254/24 dev eth1
    }
    preempt_delay 300
    notify "/etc/rc.d/vrrp_notify"
}

アクティブの時の asao:

asao.gcd.org:/ # ip addr show dev eth1
4: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
  link/ether 00:a0:cc:xx:xx:xx brd ff:ff:ff:ff:ff:ff
  inet 192.168.0.254/24 scope global eth1
  inet6 2001:c90:1448:200a:2a0:ccff:fexx:xxxx/64 scope global dynamic
    valid_lft 2591983sec preferred_lft 604783sec
  inet6 fe80::2a0:ccff:fexx:xxxx/64 scope link
    valid_lft forever preferred_lft forever
Filed under: システム構築・運用 — hiroaki_sengoku @ 08:50
2006年3月15日

セキュリティ

セキュリティって、 分かっている人にとっては、 条件反射というか無意識のうちに意識してしまうというか、 あまりに自然な感覚だけに、 分かっていない人にどう説明するのがいいのか、とても難しい。

Filed under: システム構築・運用 — hiroaki_sengoku @ 10:37
« Newer Posts