FreeBSD で PPPoE ルータ (mpd 編)

FreeBSD を,Flet's ADSL 等のブロードバンド回線のルータとして使う.

mpd とは

FreeBSD には,昔から userppp という,ppp プログラムがあります.これは,扱いが簡単な反面,kernel レベルでの動作では無く,ユーザランドで動作する物なのでパケットが kernel と ppp 間で行き来する際にメモリコピーが発生します.その為にパフォーマンスが上がらないと言った問題が発生していました.
今までの様な,ダイアルアップルータとして使う分にはなんら問題は無かったのですが,回線速度の上昇に伴って現れた問題と言えます.

そこで Archie Cobbs さんが書いた mpd が登場します.mpd は,Multi-Link PPP daemon for FreeBSD というもので,netgraph を利用した kernel level の ppp プログラムです.
機能及び設定ファイルの記述は殆ど user-ppp と同様で,複数の ppp セッションをサポートし,PPPoE が利用出来ます.さらには,PPTP も利用可能です.

前提条件

今回,mpd を利用するにあたって,以下の様な環境を元としています.
手元の環境と違う場合は適宜読み替えて下さい.

  • FreeBSD 6.0 RELASE (i386)
  • Internet 側 NIC Intel fxp0
  • Private 側 NIC Intel fxp1

mpd を動かす準備 - kernel compile

mpd は netgraph を利用して動作する為,kernel の再構築または kernel module の読み込みを行う必要があります.kernel module の仕組みによって kernel 再構築は必要なくなりましたが,mpd を動作させる際に自動的に読み込まれるモジュールでは足らない為,手動で追加モジュールの読み込みが必要となります.
自分でモジュールのロードを行うには以下の様なスクリプトを作成し,/usr/local/etc/rc.d 以下におく事で起動の際に勝手に読み込まれる為,動作しない等のトラブルを防ぐ事が可能です.

ls -l /usr/local/etc/rc.dkldload.sh
-rwxr-xr-x  1 root  wheel  236 Mar  8 00:19 /usr/local/etc/rc.d/kldload.sh
cat /usr/local/etc/rc.d/kldload.sh
#!/bin/sh
kldload /boot/kernel/netgraph.ko
kldload /boot/kernel/ng_socket.ko
kldload /boot/kernel/ng_iface.ko
kldload /boot/kernel/ng_ppp.ko
kldload /boot/kernel/ng_bpf.ko
kldload /boot/kernel/ng_vjc.ko
kldload /boot/kernel/ng_pppoe.ko
kldload /boot/kernel/ng_ether.ko

上記のスクリプトで mpd を動作させる際に必要なモジュールの全てを読み込む事が可能ですが,それならばいっその事,kernel compile して,静的に kernel に組み込んでしまう方が良いでしょう.
モジュールのロードが失敗した場合,mpd が正常に動作しませんので,外部からの接続が不可能等,不具合が起こる場合がある人は,最初から kernel に組み込んでしまった方が失敗が少なくなります.

kernel に組み込む場合,今使っている kernel の設定ファイルに,以下の様にオプションを追加します.

options         NETGRAPH                # netgraph(4) system
options         NETGRAPH_BPF
options         NETGRAPH_ETHER
options         NETGRAPH_IFACE
options         NETGRAPH_PPP
options         NETGRAPH_PPPOE
options         NETGRAPH_SOCKET
options         NETGRAPH_VJC

上記オプションで,mpd が動作するに必要な物を kernel に組み込む事になります.パケットフィルタリングや NAT(NAPT) を動作させる場合,追加で ipfilter や ipfw,pf のオプションを組み込みます.
ここでは,ipfilter を組み込みます.

options         IPFILTER                #ipfilter support
options         IPFILTER_LOG            #ipfilter logging
options         IPFILTER_DEFAULT_BLOCK  #block all packets by default
options         IPSTEALTH               #support for stealth forwarding

ipfw や pf でも良いのですが,pf は使った事が無い点や ipfw + natd の場合,natd がユーザランドで動作するプログラムな為,NAT 処理でパフォーマンスを引っ張られる事になってしまいます.その場合,ipfw + ipfilter + ipnat といった組み合わせを取る事で NAT 処理も kernel で行う事が可能になるのでパフォーマンスが良いと思います.
B-Flet's 等,高速な回線を使っており,特に natd に拘る必要のない方は,ipnat に置き換えてしまう方が良いと思います.

mpd を入れる

mpd は,標準ではインストールされていませんので,packages/ports でインストールする事になります.特にオプションも必要ない為,packages の利用で十分なのですが,ここでは ports にての導入を行います.
ports ツリーは最新ですか? 最新にしたい方は FreeBSD を最新に保つ - CVSup も参考にしてください

cd /usr/ports/net/mpd
make install

これで,mpd のインストールが完了します.次に,設定に移ります.設定ファイル郡は,/usr/local/etc/mpd 以下に置かれていますので,確認しましょう.各ファイルには役割がありますので,以下で簡単に役割を説明します.

mpd.confmpd の大本の設定ファイル.このファイルで接続先の設定等を行う.
mpd.linksppp セッションを張る際にどのインタフェースから接続するか等の設定を行う.
mpd.script接続先との接続の際に対話型で接続する場合に利用する.
mpd.secretユーザ名に紐づくパスワードを mpd.conf から切り離したもの.


これらファイルを利用して,mpd の設定を進めていきましょう.

mpd.conf

mpd.conf は,mpd を利用する際の基本的なファイルになります.ここでは,B-Flet's を利用する場合を想定して記述してありますが,その他の Flet's 等 PPPoE を使う方法の場合でもほぼ同様の設定で接続が可能です.

default:
        load provider
        load flets

provider:
        new -i ng0 provider PPPoE0
        set iface route default
        set iface up-script /usr/local/etc/mpd/script-provider.sh
        set iface down-script /usr/local/etc/mpd/script-provider.sh

        set bundle authname [userName]

        set ipcp set ipcp ranges 0.0.0.0/0 0.0.0.0/0
        load common_setting

flets:
        new -i ng1 flets PPPoE1
        set iface up-script /usr/local/etc/mpd/script-flets.sh
        set iface down-script /usr/local/etc/mpd/script-flets.sh

        set iface route 220.210.194.0/25
        set iface route 220.210.195.0/26
        set iface route 220.210.195.64/26
        set iface route 220.210.198.128/26
        set iface route 220.210.199.0/27
        set iface route 220.210.199.128/28
        set iface route 220.210.199.160/28
        set iface route 220.210.199.192/29
        set iface route 220.210.199.176/28

        set bundle authname guest@flets

        set ipcp ranges 0.0.0.0/0 0.0.0.0/0
        load common_setting

common_setting:
        set iface addrs 1.1.1.1 2.2.2.2
        set iface disable on-demand
        set iface idle 0
        set iface mtu 1454

        set bundle disable multilink

        set link no acfcomp protocomp
        set link disable pap chap
        set link accept chap
        set link mtu 1454
        set link mru 1454

        set ipcp yes vjcomp

        open iface

上記設定ファイルを見てみると,大きく分けて4つのセクションがある事が分かるかと思います.defaultproviderfletscommon_setting です.この設定の場合のセクションは次の通りです.

defaultどのセクションを読み込むか
providerプロバイダへの PPPoE 接続の設定
fletsFlet's スクウェアへの接続の設定
common_settingprovider と flets が共通して読み込む設定事項を纏めたもの


まず,default は説明が必要無い位に明快なセクションなので省き,provider のセクションを例にとって説明します.

new -i ng0 provider PPPoE0

ここで,ng0 というデバイスを作成し,次にセクションと同一の名前をつけ,最後に PPPoE0 と mpd.links のラベルを付けています.

set iface route default

デフォルトルートを,このプロバイダから出て行く様に設定します.

set iface up-script /usr/local/etc/mpd/script-provider.sh
set iface down-script /usr/local/etc/mpd/script-provider.sh

この2行は,mpd が 接続した時 及び 切断した時 に実行するスクリプトのパスを記述しています.実際には後で詳しく書きますが,ipnat の再設定をこの中で行っています.

set bundle authname [userName]

接続する際に使用するユーザ名をここに書きます.

set ipcp set ipcp ranges 0.0.0.0/0 0.0.0.0/0

ipcp で IP アドレスが通知される際に自身が許可するアドレスレンジをここに記述します.複数の固定IPアドレスが利用可能なプロバイダで,それが利用可能な方はここに静的に記述した方が良いでしょう.1IP が利用可能な方は特に書かなくても ipcp で通知されるので上記のままでも良いと思います.

load common_setting

ここで,その他の設定を読み込みます.今回,プロバイダと Flet's スクウェアの2セッションを張る為の共通部分が出たためにこの様に設定を分けてありますが,この手法を取らずに個々の設定を各セクションで書いても問題はありません.

セクション名 provider の項目は以上です.次に common_setting セクションでの項目を説明します.

set iface addrs 1.1.1.1 2.2.2.2

インタフェースレイヤでのアドレスを割り当てる項目な様ですが,無くても良いようです.実は,この項については詳しくはわかりません.ごめんなさい…

set iface disable on-demand

オンデマンド接続を無効にしています.ダイアルアップルータの場合は,enable として,外との接続が必要な際にオンデマンド接続が可能になります.

set iface idle 0

アイドルタイムアウトを 0 としています.0 とするとアイドル時の切断を行わない様になります.これもダイアルアップルータの場合はある程度の値を入れる事を推奨します.

set iface mtu 1454

MTU(Maximum Transmission Unit) の値を 1454 にしています.Flet's の場合,PPPoE の MTU 値は 1492 のようで,その値から PPP ヘッダを抜いた値が 1454 です.

set bundle disable multilink

接続の際のマルチリンクを無効にしています.これは,ISDN でおなじみの 64 + 64 = 128 の機能を使うか,使わないかです.Flet's 等では利用が出来ない為,無効とします.

set link no acfcomp protocomp

acfcomp 及び protocomp を無効にしています.acfcomp は Address と ControlField の圧縮,protocomp は Protocol の圧縮を意味しています.Flet's では,そもそも仕様上利用不可なので,無効にしましょう.その他のラインを使っている方は調べて下さい.

set link disable pap chap

pap 及び chap での接続を受付ません.次の行とは扱いが違い,自身が受け付けるか,受け付けないかを enable/disable で指定します.

set link accept chap

サーバとの認証の際に chap を利用します.accept/deny を使って,pap,chap を指定します.

set link mtu 1454
set link mru 1454

リンクレイヤで,MTU 及び MRU を 1454 にします.こちらも,Flet's の仕様上この様な設定になります.

set ipcp yes vjcomp

ipcp の Van Jacobson TCP ヘッダ圧縮を有効にします.殆どの場合,この圧縮は有効に機能しますので,このままでも問題無いと思われます.

open iface

インタフェースをオープンします.この段階で,ようやくセッションが開始されます.

mpd.secret

mpd.secret は,ユーザ名に紐づくパスワードを mpd.conf から分離させた物になります.パスワードを mpd.conf に書かずに,mpd.secret に書き,mpd.secret のパーミッションを 600 等にし,厳重に管理する事で,よりセキュアになります.

mpd.conf にパスワードを書く場合は,次の様に書きます.authname の次の行あたりに書いておけばよいでしょう.

set bundle password [Password]


mpd.secret に書く場合,以下の様になります.

UserName        Password
guest           guest
Provider2       Password2

最初の列がユーザ名,次の列がパスワードとなります.ユーザ名で,mpd.conf と紐付けを行いますので,mpd.conf にあるユーザ名と同一かを確認して下さい.

mpd.links

mpd.links ファイルは,どのインタフェースを利用して ppp セッションを張るか.を定義するファイルになります.このファイルで,ppp なのか,pppoe なのか,pptp なのかを決定します.

PPPoE0:
        set link type pppoe
        set pppoe iface fxp0
        set pppoe service "whatever"
        set pppoe disable incoming
        set pppoe enable originate

PPPoE1:
        set link type pppoe
        set pppoe iface fxp0
        set pppoe service "whatever"
        set pppoe disable incoming
        set pppoe enable originate

このファイルの場合,セクションは PPPoE0 と PPPoE1 の 2つある事が分かります.
このセクション名は,mpd.conf の new の行の最後で指定している名前と紐付けられます.今回の場合,PPPoE0 が provider,PPPoE1 が flets と紐づいています.
以下では,PPPoE0 を例に中身を解説します.

set link type pppoe


この行で,リンクタイプを PPPoE とする事を宣言しています.ダイアルアップモデム等での接続の場合は ppp となります.

set pppoe iface fxp0

PPPoE セッションを張る際に利用するインタフェースを決定しています.この場合は,fxp0 という Intel チップセットのインタフェースを指定しています.ADSL モデムや光の終端装置に繋がっているインタフェースを指定して下さい.

set pppoe service "whatever"


PPPoE のサービス名を明記します.が,通常は whatever で問題無いようです.サービス名をプロバイダから指定された場合はここに変更を加えて下さい.

set pppoe disable incoming
PPPoE の着信を拒否します.PPPoE でプロバイダに接続する利用方法の場合は,相手からの着信の必要がありませんので,disable を忘れない様にして下さい.

set pppoe enable originate
PPPoE の発信を許可します.自身から発信して PPPoE セッションを開始しますので,当然許可.になります.

mpd.script

mpd.script は,mpd での接続時や,切断時に実行させる事が出来るスクリプトファイルです.上記の mpd.conf に次の記述がありますが,これが mpd.script になります.ファイル名はプロバイダ名に合わせて変更してあります.

set iface up-script /usr/local/etc/mpd/script-provider.sh
set iface down-script /usr/local/etc/mpd/script-provider.sh

up-script が接続時に実行されるもので,down-script が切断時に実行されるものです.自分の場合,同一のスクリプトファイルを用意しており,引数を元に動作を変えるようにしてあります.
スクリプト自体は,接続時の場合は次の様な引数で呼ばれます.

[scriptname] <interface> inet <local address> <remote address> <authname>


切断時には次の様な引数で呼ばれます.

[scriptname] <interface> inet <authname>


両者を比べてもらうとわかるのですが,引数の数が違いますので,この数の違いを利用したスクリプトを作成する事でスクリプトファイルは1つで済みます.
実際のスクリプトは次の様に作成しています.

#!/bin/sh
case $# in

# Connect
5)
        /etc/rc.d/ipnat restart
        ;;
# Disconnect
3)
        /etc/rc.d/ipnat restart
        ;;
*)
        ;;
esac

この場合,接続時及び切断時に ipnat を再起動しています.こうしている理由は,プロバイダとフレッツスクウェアの2つに接続していますので,ipnat を停止させる訳にも行かず,面倒だったので再起動とさせているだけです.
本来は,接続時や切断時に ipnat や ipfilter のルールセットの動的な差換えを行えれば良いのですが,そうする理由も無かったので現状は上記のままのスクリプトを利用しています.

起動のテスト

実際にここまで完了したら,mpd を起動してみましょう.

手で起動する

ナニハトモワレ,最初は出て起動させて動作を確認しましょう.mpd を手で起動させるには次のようにタイプします.

/usr/local/sbin/mpd

すると,画面に大量の文字列があわられますがあわてないで下さい.これはふぉわグラウンドで動作し,ログを標準出力に書き出す仕様なので正常動作なのです.
まず画面の文字列をめげないで見てみましょう.PPPoE のセッションを張りに行き,認証し,アドレスを割り当てられている事などが分かるかと思います.別のターミナルもしくは ssh 等のセッションを張り,インタフェースの状態を確認してください.以下の様に ng というデバイスが作成されているかと思います.

> ifconfig -a
ng0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> mtu 1454
        inet 219.117.xxx.yyy --> 219.117.xxx.yyy netmask 0xffffffff

この状態が確認出来たら,mpd は PPPoE セッションをうまく張れている状態となります.外部のホストへアクセスしてみる等,動作を確認してみて下さい.

スクリプトで起動する

mpd を ports/packages でインストールした場合,/usr/local/etc/rc.d 以下に,mpd.sh というスクリプトもインストールされます.
このスクリプトは,rcNG 形式のスクリプトですので,/etc/rc.conf に以下の値を必要とします.

mpd_enable="YES"

これによって,mpd.sh を実行した際に,スタートの処理が進みます.
また,mpd へのコマンドオプションを渡したい場合,以下の値を入れる事で,mpd.sh へ反映させる事が可能となります.

mpd_flags=""

mpd.sh を見てもらうと分かるのですが,デフォルト状態で mpd_flags には -b のオプションが渡されています.これは mpd が動作する際に,起動した後にバックグラウンドで動作させる為のオプションとなります.
通常はバックグラウンドの動作を期待しているでしょうからこのままで良いでしょう.ただし,その他のオプションを渡したい場合で,バックグラウンド動作を期待している場合は,-b オプションを mpd_flags から削ることの無いように注意して下さい.

実際の起動は,以下の様にスクリプトを実行して下さい.

/usr/local/etc/rc.d/mpd.sh start

この様に実行する事で mpd が起動し,PPPoE での接続が行われます.
こちらも,別のターミナルもしくは ssh 等のセッションを張り,インタフェースの状態を確認してください.以下の様に ng というデバイスが作成されているかと思います.

> ifconfig -a
ng0: flags=88d1<UP,POINTOPOINT,RUNNING,NOARP,SIMPLEX,MULTICAST> mtu 1454
        inet 219.117.xxx.yyy --> 219.117.xxx.yyy netmask 0xffffffff


上記の状態が確認出来たら,とりあえずの mpd 接続は完了です.

接続確認作業

実際に mpd での接続が行われ,ng デバイスに IP アドレスが割り振られていれば,その FreeBSD ボックスからの Internet への接続は出来る状態です.が,デフォルトルート等が設定されているかの確認も重要ですので,これらもちゃんと確認しておきましょう.

先の設定ファイル (mpd.conf) で provider への接続のセクションに次の行があったかと思います.

set iface route default

この行がある事で,デフォルトルートが設定されるはずですので確認してみましょう.

> netstat -rn
Routing tables

Internet:
Destination        Gateway            Flags    Refs      Use  Netif Expire
default            219.117.xxx.zzz    UGS         0   755833    ng0

この様にデフォルトルートが設定されている事を確認出来たら大丈夫です.

NAT ボックスとしての設定

これまでの段階で,FreeBSD ボックスでの接続が行われていると仮定し,ここでは NAT ボックスとして仕上げて行く事とします.

daemontools で起動する

qmail の作者である D. J. Bernstein 氏が作成している daemontools というソフトウェアがあります.このソフトウェアを使用する事で,起動及び停止,再起動が容易になります.また,PPPoE が切断した後の復旧が自動化出来るようになり,ルータとして使っている場合はとても便利に利用できます.
mpd を daemontools と組み合わせて利用する事で,さらに便利な FreeBSD Router として利用できるのです.

起動スクリプトの用意

とりあえず,起動スクリプトを作成しなければ始まりません.ここでは /var/daemontools/mpd 以下に作成します.

  • ./run (0755)
    #!/bin/sh
    echo ' mpd'
    exec envdir ./env  \
    /usr/local/sbin/mpd 2>&1
  • ./env/PATH (0644)
    /bin:/usr/bin:/usr/local/bin:/usr/local/sbin
  • ./log/run (0755)
    #!/bin/sh
    # s = Logfile Size, n = LogLotateSize
    # Logfile Size = 5MB
    exec envdir ./env \
    multilog t s5242880 n10 /var/log/mpd
  • ./log/env/PATH (0644)
    /bin:/usr/bin:/usr/local/bin:/usr/local/sbin

最初の run はプログラムの起動の為のスクリプトになります.ここでは単純に mpd をフォアグラウンドで起動しています.これは,daemontools はフォアグラウンドプロセスのみ扱えるからです.パーミッションは 755 にしておきます

次に,env/PATH ですが,これは run に設定される環境変数 PATH になります.特に今回の run では必要ないのですが… クセです.

最後2つは,ログ用のスクリプトです.log/run はログ取りの為の起動スクリプトで,/var/log/mpd 以下にログがたまります.この際,s5242880 オプションでログファイルサイズは 5MBn10 オプションで,10個ローテーションされるようになっています.

最後の log/env/PATH はログ取りスクリプトに渡される環境変数です.
ログ保存場所の /var/log/mpd の作成を忘れないで下さい.

daemontools に管理させる

上記のスクリプトを,daemontools に管理させるには,daemontools が管理しているディレクトリへリンクを張ることで可能になります.
自宅の環境では /service が監視ディレクトリですが,FreeBSD ports から入れた場合ですと /var/service になります.このあたりを確認して,以下のようにリンクを張ってください.

ln -s /var/PPPoE/mpd mpd

以上で,daemontools への組み込みは完了です.5秒ほどするとプロセスが開始されるはずです.以下のように,ps の出力を確認し,mpd が表示されていれば完了です.

ps -ax | grep mpd
870  ??  I      0:00.11 supervise mpd
878  ??  S      2:23.73 /usr/local/sbin/mpd
880  ??  I      0:00.01 multilog t s5242880 n10 /var/log/mpd

supervise mpd が,daemontools が管理している事を示すプロセスで,その下に /usr/local/sbin/mpd が表示されています.この2行が1セットになって表示されていると正常に動作していると考えられます.PPPoE 用のインタフェースが出来ているか,IP アドレスが取得できているか,外につながるか,等の確認をして下さい.

最後の行の,multilog t s5242880 n10 /var/log/mpd は,ログ取りが行われている事をあらわします.本来はこのプロセスを管理している supervise もありますが,上記 ps コマンドの結果では出力されていません.

ログは /var/log/mpd 以下に出力されます.current が最新のログになり,規定量を超えた物はローテーションされます.daemontools で管理する利点として,フォアグラウンド動作させる為,mpd のメッセージが豊富に出力されます.これら全てが取得可能なので状態を追いかける事も容易になるのです.

以上,mpd を daemontools で管理でした.

daemontools の詳細な使用方法はまだ纏めていないので検索してください…


Hiroyuki Seino http://www.seichan.org/ http://www.seichan.org/blog/
Today:1 Yesterday:0 All:25663