[Japanese|English]

FreeBSDのnatdのalias.logファイルの形式を変更するパッチ

開発の動機

実際には、「開発」というほど大げさなものではありません。ちょっとした苦労談とでも言いましょうか。

東京めたりっく通信のころはPPPoEだったので、パケットのフィルタリングも、NATも、pppで設定していました。しかし、Yahoo! BBはブリッジ (IPoE) なので、ipfwnatdとの組合せに変更しました。ところが、なかなか思うように動きません。設定内容は、従来と同じにしているはずなのに、なぜか振舞いが違うのです。

原因を調べて、正しく設定するために、さまざまなデバッグ環境を使ったのですが、NATテーブルを参照することができません。しかたがないので、とりあえず作ったのが、以下のパッチです。

もともとnatdにはalias.logというログファイルを生成する機能があり、-lオプションで有効にできます。これはNATテーブルの状態を出力することになっています。しかし実際には、プロトコル別の有効トランスレーションエントリの個数がわかるだけなので、アドレスが意図通りに変換されているかどうかの確認には使えません。そこで、NATテーブルの内容を追跡できるように、新しいエントリが追加または削除されるたびに、そのエントリの内容をログとして出力するようにしたものです。

パッチの使い方

コンパイル

このパッチは、natdが内部的に利用するlibaliasの一部を変更するものです。本格的にパッチを適用するには、natdlibaliasのソース一式を取り寄せて、全体をコンパイルし直すことになります。手軽に試すためには、natdlibaliasの全ソースをまとめて一つのディレクトリに置き、Makefileは利用せず、全*.cを一気にコンパイルしてしまうといいでしょう。

パッチと言っても、実際に修正を行うのは、libaliasの一部であるalias_db.cというファイルだけです。

natdのソースは、FreeBSDソースツリーのsrc/sbin/natd/配下にあります。libaliasは、src/lib/libalias/配下にあります。

新しいログの形式

このパッチを適用すると、ログの形式が変わります。natdを起動する際に-lオプションを指定すると、新しい形式でalias.logが採取されます。修正したソースでは、従来の形式のalias.logを採取することはできなくなります。

採取されるログの例を以下に示します。ローカル側が192.168.1.1、パブリック側が219.63.255.49というアドレスを持つマシン上でnatdを動かしています。このマシンではDNSサーバも動作しており、ローカル側のサブネットに接続されたパソコンは、このマシンにDNSの問い合わせを送るようになっています。

+ udp 219.63.255.49:1024 211.5.1.219:53 219.63.255.49:1024 *:* (0x8060100)
+ udp 219.63.255.49:1024 165.76.0.98:53 219.63.255.49:1024 *:* (0x8060180)
+ udp 219.63.255.49:1024 165.76.4.2:53 219.63.255.49:1024 *:* (0x8060200)
+ udp 219.63.255.49:1024 211.5.1.217:53 219.63.255.49:1024 *:* (0x8060280)
+ tcp 192.168.1.188:1346 210.142.46.154:80 219.63.255.49:1346 *:* (0x8060300)
+ udp 219.63.255.49:1024 210.141.108.194:53 219.63.255.49:1024 *:* (0x8060400)
+ udp 219.63.255.49:1024 210.239.166.194:53 219.63.255.49:1024 *:* (0x8060480)
+ tcp 192.168.1.188:1347 219.106.255.170:80 219.63.255.49:1347 *:* (0x8060500)
+ tcp 192.168.1.188:1348 219.106.255.170:80 219.63.255.49:1348 *:* (0x8060600)
+ udp 219.63.255.49:1024 210.142.46.155:53 219.63.255.49:1024 *:* (0x8060700)
+ udp 219.63.255.49:1024 211.18.214.210:53 219.63.255.49:1024 *:* (0x8060780)
- tcp 192.168.1.188:1346 210.142.46.154:80 219.63.255.49:1346 *:* (0x8060300)
+ tcp 192.168.1.188:1349 210.142.46.155:80 219.63.255.49:1349 *:* (0x8060300)
- tcp 192.168.1.188:1349 210.142.46.155:80 219.63.255.49:1349 *:* (0x8060300)
- udp 219.63.255.49:1024 211.5.1.217:53 219.63.255.49:1024 *:* (0x8060280)
- tcp 192.168.1.188:1348 219.106.255.170:80 219.63.255.49:1348 *:* (0x8060600)
- udp 219.63.255.49:1024 165.76.4.2:53 219.63.255.49:1024 *:* (0x8060200)
- udp 219.63.255.49:1024 210.239.166.194:53 219.63.255.49:1024 *:* (0x8060480)
- udp 219.63.255.49:1024 165.76.0.98:53 219.63.255.49:1024 *:* (0x8060180)

ログは1行1件の形式で、各項目を空白で区切って並べています。各項目は、先頭から順に、以下の内容です。

  1. 追加 ("+" の場合)、削除 ("-" の場合)、または変更 ("=" のいずれか。
  2. プロトコル (link_type)。natdが特別扱いしないプロトコルの場合には、名前の代わりにプロトコル番号になります。
  3. ローカル側エンドポイントのIPアドレスとポート番号 (src_addrsrc_port)。
  4. パブリック側エンドポイントのIPアドレスとポート番号 (dst_addrdst_port)。
  5. (ローカル側エンドポイントの) トランスレート後のアリアスIPアドレスとポート番号 (alias_addralias_port)。
  6. トランスペアレントプロキシの転送先IPアドレスとポート番号 (proxy_addrproxy_port)。
  7. struct alias_linkデータブロックの先頭アドレス。(大抵の場合、この情報は必要ありません。)

おおざっぱに言うと、"+" から始まる行は、新しいトランスレーションルールが追加されたことを表し、"-" から始まる行は、既存のトランスレーションルールが削除されたことを表し、"=" から始まる行は、既存のトランスレーションルールの内容の一部が変更されたことを表します。(現在のところ、"=" は、トランスペアレントプロキシのルールの場合にだけ使われます。)

上の例では、192.168.1.188というアドレスのパソコンが、あるWWWサーバにアクセスしたときのログを示しています。

udp のエントリでは、パブリック側エンドポイントのポート番号はすべて53で、これがDNSの問い合わせであることを暗示しています。また、ローカル側エンドポイントがすべて219.63.255.49:1024ですが、これはこのマシンで動作するnamedが使用している問い合わせ用のポートです。この例では、udpのエントリはどれもソースとアリアスが一致していますが、これは、udpのリンクが全てこのマシンで動作するプログラム (named) による通信だったために実際にはトランスレーションが行われなかったためです。

tcpのエントリでは、パブリック側エンドポイントのポート番号はすべて80で、これがHTTPのアクセスであることを暗示しています。ローカル側エンドポイントのIPアドレスは192.168.1.188というパソコンのものになっています。アリアスのIPアドレスは、natdが動作するマシンのパブリック側のIPアドレスになっており、アドレスがトランスレートされていることを示しています。ポート番号は、ローカル側とアリアスで同じ値になっていますが、これは偶然ではなく、natdが (デフォルトでは) できるだけポート番号を変更しないようにトランスレーションルールを生成するためです。

前半では、新規に発生したトラヒックをトランスレートするために新しいエントリが次々と作られ、後半では不要になったエントリが次々と削除されています。ただし、上に示した範囲では、全エントリが削除されていず、一部のエントリが残っています。このエントリは、もう少し時間が経つと削除されるはずです。

使用上の注意

新しい形式のログは、従来の形式に比べてファイルの寸法が大きくなりがちです。もともとalias.logというファイルは、すぐにファイルサイズが大きくなりすぎるという問題を持っています。デバッグ用に、必要なときだけ採取するという使い方が現実的だと思います。alias.logを採取したまま、長時間natdを動かすような使い方は、お勧めできません。

新しい形式のログは、従来の形式に比べて、ログの生成にかかるCPUのオーバーヘッドが増えています。高い負荷のかかるルーターでalias.logを採取することはお勧めできません。

このパッチは十分にテストされていません。このパッチは、ログの形式を変更するだけで、natdの動作自体を変更するものではないため、もしもバグがあっても、ログの形式がおかしくなること以上の不具合は起きないはずですが、保証はできません。このパッチの利用は自己責任でお願いします。

トランスレーションテーブルの内容を表示するツール

ついでなんで、新しい形式のログを集計して、「現時点での」トランスレーションテーブルの内容を一覧形式で表示するツールも作ってみました。最近は、こういうツールは普通PerlかRubyで書くものだと思うのですが、これはawkで書いてあります。(年齢がバレますね。)

awk -f natstat.awk /var/log/alias.logとして使います。出力はこんな感じになります。

Type  Local                  Public                 Alias                  Proxy
tcp   192.168.1.188:1347     219.106.255.170:80     219.63.255.49:1347
udp   219.63.255.49:1024     211.5.1.219:53         219.63.255.49:1024
udp   219.63.255.49:1024     210.142.46.155:53      219.63.255.49:1024
udp   219.63.255.49:1024     211.18.214.210:53      219.63.255.49:1024
udp   219.63.255.49:1024     210.141.108.194:53     219.63.255.49:1024

内容から考えて、表示の順番は、Type、Local、Alias、Public、Proxyという並びの方が分かりやすいと思うのですが、ここではログと同じ順にしてあります。(変に順番を入れ換えると混乱の元なので。因みに、ログがこの順なのは、libaliasが内部で使っているstruct alias_linkというデータ構造の順番に合わせたものです。)

ダウンロード