IP Phone顛末記

自宅にて流行(?)のIPPhoneをBフレッツにつないでFreeBSDで使えるようにしたときの顛末です。何がなんでも絶対 *BSDでやるぞという*BSD Hackerの方の参考になれば幸いです。BフレッツでなくてもフレッツADSLでもそのまま使えるはずです。
(2003-12)

追補:FreeBSDのバージョンを5.1から5.2.1に上げたところライブラリの関係なのか動作しなくなりました。 一旦削除 (make deinstall) して最初からやり直したらちゃんと繋がるようになりました。

基本情報

Bフレッツはニューファミリー契約

ハードはDELLを使っています。NICとしてはIntel EtherExpress100が二枚ささっています。

OSは FreeBSD 5.1です。これをやった時点でパッチレベルはp11になっています。(注:その後FreeBSD 5.2にアップしました)

VoIPアダプタはNTT東日本のVoIPアダプタを月380円でレンタルしました
14800円/380円/月=3年2か月なのでその頃になればもっといい機器が出るだろうということで...1200ボーのモデムとか一つ一つは小さいけど使わない器材が山ほどあって邪魔なんですよね。

FreeBSDのマシンからPPPoEで直接ISPにつないでいます。pppではNATは指定していません。

家庭内LAN(192.168.252.0/24) -> FreeBSD -> 光終端装置

NTTのVoIPアダプタのWAN側アドレスは192.168.252.251に設定を変更しローカルアドレスのハブに接続しています。当然ゲートウエイアドレスとNetmaskはNAT内の他のPCと同じになります。
VoIPアダプタのLAN側は変更しません。DHCPが動き、そのアドレスは192.168.100.1になっているはずです。要するにVoIPアダプタのLAN側は二段NATの環境になるわけですね。
詳細な設定方法についてはVoIPアダプタのマニュアルを参照してください。

PPPoEで接続したときのインターフェース
tun0  グローバル側
fxp0  tun0へインターフェース
fxp1  ローカルアドレス(192.168.252.0/24)
FreeBSDではIntel EtherExpress100はfxp0, fxp1 というインターフェース名で扱われます。他のNICの場合には名前が異なります。
tun0はトンネルデバイスというそうで、PPPoEはここを経由してつながり、仮想ネットワークデバイスとしてfxp0の代りに使われます。この名前はどんなNICを入れても変わりません。
PPPoEでの接続については他サイトを参考に設定してください。

最初の失敗

ファイアウオールとNATは当初慣れているipfwとnatdで構築していましたが TCPのポートフォワーディングはうまくいくのですがUDPは divertがあるとフォワードがうまくいかず、divertを外すと今度はNATが効かなくなって駄目で結局1日頑張ってあきらめて、すなおにipnatとipfで行くことに しました。 ソースを見るとupnpdというソフトはipnatを内部から呼んでいる(*1)のですなおに それを使うのがいいと判断しました。(READMEも何も読んでいないんですがきっとそういうことが書いてあるんでしょうね RTFM)
(*1)ソースはこんなふうになっています pmlist.cpp:     FILE *ipnat = popen("/sbin/ipnat -f -", "w");
ソースによると本来のLinuxで動作するときには/usr/sbin/iptablesが呼ばれていました。

ソフトのインストール

UPnP関連のソフトをインストールします。このソフトはもともとLinux用だったようなのですがFreeBSDではパッチまで自動的に行ってくれるものがportsに用意されているのでportsからインストールします。(packageでも行けると思いますが)
su
cd /usr/ports/devel/upnp
make
make install

cd /usr/ports/net/linuxigd/
make 
make install
インストールすると起動スクリプトが /usr/local/etc/rc.d/linuxigd.sh.sample
としてできますのでそれを/usr/local/etc/rc.d/linuxigd.sh と名称を変更してchmod 755 /usr/local/etc/rc.d/linuxigd.sh と実行モードにしておきます。
これでマシンが起動するとupnpdがデモンとして 動くようになります。まだリブートしてはいけません。

設定

ipf ファイアウオールの設定
うまくいかないときに、それがファイアウオールのせいなのか本当に設定がまずいのかわからないので試験のときにはオールパスに設定にしておきます。
ファイル名は/etc/ipf.rules
pass in all
pass out all
ipnat NATの設定
内部ローカルマシンからブラウジングできたりsshでつなげたりできないとまずいので内部のマシンは全部NATをかまして繋がるようにします。ここにVoIPアダプタのための設定はする必要はありません。(自動的に設定されます)
ファイル名は/etc/ipnat.rules
map tun0 192.168.252.0/24 -> 0/32 portmap tcp/udp auto
map tun0 192.168.252.0/24 -> 0/32
0/32という記述は自分自身ということだそうでつなぐたびに自分のグローバルアドレスが異なる場合に便利な表現ですね。

VoIPアダプとしての設定
upnpdはVoIPアダプタなどのUPnP機器からの接続を認識すると自動的に各種設定をしてくれた上でipnatのテーブルにも設定を追加してくれるのでFreeBSDとしては何もする必要はありません。(それがUPnPの機能だそうです)
ファイアウオールをつけるときにはUDPのポート5060,5090,5091を通すようにすることをお忘れなく。今のところupnpdが自動的にipfを呼んで穴を開けてくれるようにはなっていないようです。

ipf/ipnatを起動時に動作
/etc/rc.confに以下を追加します。
ipnat_enable="YES"
ipnat_rules="/etc/ipnat.rules"
ipnat_program="/sbin/ipnat -CF -f"
ipnat_flags=""

ipfilter_enable="YES"
ipfilter_flags=""
ipfilter_rules="/etc/ipf.rules"

ipmon_enable="YES"
ipmon_flags="-D /var/log/ipflog"

gateway_enable="YES"
マルチキャスト経路指定
/etc/rc.localに以下を追加。内部インターフェースを指定します。NICが違う場合にはそのローカル側のネットワークインターフェース名に置き換えてください。
route add -net 239.0.0.0/8 -interface fxp1

新カーネルの構築

カーネル定義ファイル(抜粋です)を
device           bpf
#options         IPFIREWALL             
#options         IPFIREWALL_VERBOSE     
#options         IPFIREWALL_VERBOSE_LIMIT=100
#options         IPFIREWALL_DEFAULT_TO_ACCEPT
#options IPFIREWALL_FORWARD
options         IPFILTER  
options  IPFILTER_DEFAULT_BLOCK
options  IPFILTER_LOG
options  PFIL_HOOKS   # FreeBSD5.2ではさらにこれが必要
としてコンパイル、インストールします。(先頭の#はコメントなので使わない事を意味します)

bpfは本来VoIPの設定とは関係無いはずなのですが参考のために記載しています(無くてもかまいません)。他サイトにbpfは使うなと書いてあったのですそれを検証するため入れています。bpfを使うtcpdumpが動いているので今のところ問題は無いようです。

状況の監視

設定が終わったらマシンをリブートします。このときまだVoIPアダプタは電気を切っておきます。
リブートしたあとsuになり以下のコマンドを入れて以下のようになればとりあえず準備は良し。試しにローカル側につながっているPCからブラウジングなどが正しくできるかも確認してください。
NATの確認
# ipnat -l
List of active MAP/Redirect filters:
map tun0 192.168.252.0/24 -> 0.0.0.0/32 portmap tcp/udp auto
map tun0 192.168.252.0/24 -> 0.0.0.0/32

ipfの確認
# ipfstat -o
pass out from any to any
# ipfstat -i
pass in from any to any
さていよいよVoIPアダプタに電気を入れ、ISPの登録ページに行って申し込みをします。VoIPアダプタのLAN側にノートPCをDHCPでつなぎそのままブラウザで申込みページにつなぎます。VoIPアダプタのLANポートからでも二段NATでインターネットにつなげるようになっているわけです。
このときの接続は

ノートPC(DHCP) ->(LANポート192.168.100.1) VoIPアダプタ (WANポート192.168.252.251)->
->ローカルアドレスのハブ(192.168.252.0/24)-> (fxp1) FreeBSD (fxp0) -> 光終端装置

になります。(別にノートPCでなくてもデスクトップPCでもかまいませんけどね)

申し込みのあと自動的に設定がダウンロードされるようになっていました。
自動設定が終わるとVoIPは再起動し30秒くらいして うまくつながると表のパネルのVoIPランプが緑になります。upnpdはrdrの指定を自動的にやってくれています。偉い!
NATの状況を調べてみると確かに追加されています。
# ipnat -l
List of active MAP/Redirect filters:
map tun0 192.168.252.0/24 -> 0.0.0.0/32 portmap tcp/udp auto
map tun0 192.168.252.0/24 -> 0.0.0.0/32
rdr tun0 210.XX.XX.XX/32 port 5060 -> 192.168.252.251 port 5060 udp
rdr tun0 210.XX.XX.XX/32 port 5090 -> 192.168.252.251 port 5090 udp
rdr tun0 210.XX.XX.XX/32 port 5091 -> 192.168.252.251 port 5091 udp
実際には210.XX.XX.XXのところはPPPoEでつないだときにこのFreeBSDのtun0に割り当てられたIPアドレスになります。さらにはこのリストの下に現在のセッションが表示されているはずです。

さてこれでいよいよ電話をかけられます。まずは自分とか知人に電話してみてはいかがでしょうか?

動作が確認できたらLANポートにつないだノートPCはもう必要無いので取り外してかまいません。VoIPアダプタの電源が切れてもまた入れれば今度はノートPCの助けなしに勝手につないでくれます。

ファームウエアがアップデートされたら(実際に12月に一回ありました)LANポートにまたノートPCをつないでアップデートページにつなぎます。

余談ですがUPnPメカニズムがちゃんと動いているらしいので試しにWindows Messengerを立ち上げるとまたそれに対応したUDPポートのリダイレクトが自動的に登録されました。相手がいないので確認はしていませんがきっと音声チャットなどもできると期待しています。なんでも音声チャットはUPnP必須らしいですから。

本格的ファイアウオールの設定

さてこのあとはいよいよファイアウオールの設定です。いろいろな優れた解説サイトがあるのでそちらを参考にして強固な環境を作ってください。使う人によって千差万別なのでここでは具体例は出しません。
まずというmkfilters コマンドで自分の環境を調べてテンプレートを作るのが最初でしょうね。

謝辞:このようなportsを作っていただいたFreeBSDチームの皆様本当にありがとうございました。またその元であるupnpdのソフトを作成していただいた方にもお礼申し上げます。

お約束ごとですがこの説明により動作しなくてもおかしくなっても何も保証はいたしません。At your own riskということで。

参考リンク:http://bb.watch.impress.co.jp/cda/special/1731.html
BigBrotherの設定をPHPで行ったり東芝の名機リブレットのXの設定ファイルなどがあるgnuコーナー(英文)もよろしく。