Slackware 10.2 で ADSL ルータを構築してみる

SERVER


ADSL ルータを構築するには

ADSL に契約した時にルータ機能の備わった ADSL モデムがレンタルされてきましたので、わざわざ難しいことをしなくてもそれを使えば問題なく利用することは出来るのですけど、いろいろとしたかったところもあって、せっかくなので設定に融通の利く Linux を ADSL ルータとして利用してみることにしました。

 

Linux を用いて ADSL ルータを構築するためには、PPPoE 接続を行うためのソフトウェアをインストールする必要があります。これには Roaring Penguin - PPPoE for Linux にて公開されている RP-PPPoE を用いることで行えるようですので、今回もそれを使ってみることにします。

ルータを構築する PC の環境は、Linux Slackware 10.2 に LAN アダプタを 2 枚刺した感じの状態です。ここへ RP-PPPoE をインストールして、ルータとして適切に通信が行えるように調整してみる感じです。

 

RP-PPPoE をインストールする

Roaring Penguin - PPPoE for Linux から "rp-pppoe-3.8.tar.gz" をダウンロードしたら、次のようにして展開してインストールを行います。

tar xvzf rp-pppoe-3.8.tar.gz

cd rp-pppoe-3.8/src

 

cd src

./configure

 

make

make install

各種プログラムファイルは "/usr/sbin/" ディレクトリにインストールされます。また、"/etc/ppp/" ディレクトリに "pppoe.conf" という設定ファイルが用意されますので、続いてその編集を行ってみます。

"/etc/ppp/pppoe.conf" で設定する主だったものとしては次のような感じでしょうか。

ETH eth0 DSL モデムへ接続するネットワークアダプタ名を指定します。
USER xxxx@xxxx.xxx.xxx.xx PPPoE 接続を行うためのユーザ ID を指定します。
DEMANDO no
yes
接続要求のあった場合 (デマンドダイアリング) にのみ接続を行いたい場合には、ここに自動切断する秒数を指定します。"no" を指定した場合は常時接続状態となります。
DNSTYPE SERVER
NOCHANGE
SPECIFY
名前解決に使用する DNS サーバを自動取得 (SERVER) するか、または指定 (SPECIFY) するかを指定します。 指定する設定にした場合は "DNS1" および "DNS2" で、使用する DNS サーバを指定します。また NOCHANGE にしておくことで、RP-PPPoE が /etc/resolv.conf に関与しないように出来ます。
DEFAULT_ROUTE yes
no
PPPoE 接続を標準のインターネット接続とするかどうかの指定です。ここを yes としておくことで、自動的にルーティング情報が更新されます。
PPPOE_TIMEOUT 80 ここで指定された秒数の無通信時間があった場合に pppoe は接続を終了させます。初期値は 80 でしたけど、とりあえず常時接続の際には 0 に設定した方が良いかどうかは判りません。
FIREWALL NONE
STANDALONE
MASQUERADE
pppoe-connect が実行された時に自動的にファイアーウォールの設定を調整するかを指定できるそうです。NONE の場合は調整なし、STANDALONE の場合はそのホスト単体で接続を利用できるように、また MASQUERADE の場合はそのホストがルータとしての役割を担えるように、標準的なパケットフィルタのルールを追加してくれるとのことでした。

他にも設定できる項目があり、その意味合いとしては次のような感じです。

PEERDNS yes

no

PPP で取得した DNS サーバを resolv.conf 使用するという設定なのだそうですけど、試してみた感じでは "DNSTYPE" の方が効果を成しているような気がしました。以前は USEPEERDNS と呼ばれていたそうです。
DNS1
DNS2
  DNSTYPE で SPECIFY が指定されていた場合に、名前解決に使用する DNS サーバを IP アドレスで指定します。
CONNECT_TIMEOUT 30 PPPoE 接続が上手く行かない場合に、何秒まで接続を試みるかを指定します。
CONNECT_POLL 2 PPPoE 接続の際に、それに成功したかを何秒ごとに調べるかを指定します。1 秒以上を指定した場合は CONNECT_TIMEOUT まで状況を確認し、0 を指定した場合は成功したかどうかのチェックを行わないそうです。
ACNAME   pppoe の -C オプションに渡される、アクセス集信装置の名前を指定するところだそうです。通常は何も指定しない状態にします。
SERVICENAME   pppoe の -S オプションに渡される、使用したいサービス名を指定するところだそうです。通常は何も指定しない状態にします。
PING "." PPPoE 接続を試みている間に表示させる文字です。pppoe-start を実行して接続が確立されるまでの間に CONNECT_POLL 秒間隔でこの文字が表示されます。
CF_BASE basename $CONFIG プロセス ID ファイルを保存する際に使用する値です。設定ファイルの名前 "pppoe.conf" が取得されるようです。
PIDFILE "/var/run/$CF_BASE-pppoe.pid" pppoe が動作しているプロセス ID を記録するために使用するファイルです。実際に生成されるファイルは "$CF_BASE-pppoe.pid" の他に "$CF_BASE-pppoe.pid.pppd", "$CF_BASE-pppoe.pid.pppoe", "$CF_BASE-pppoe.pid.start" の 4 つのようです。
SYNCHRONOUS no

yes

Synchronous PPP を利用するかどうかを指定します。これが利用できるのは n_hdlc ライン制御機能 (discipline) を備えた Linux のみで、通常は "no" を指定しておいた方が良いようです。なお、これを利用することで CPU 負荷が 1/4 程度になることが期待できるそうです。
CLAMPMSS 1412 TCP セッションの advertised MSS 値を指定することができるそうです。
LCP_INTERVAL 20 pppd が接続状態を確認するために LCP echo リクエストを送信する間隔を秒数で指定します。
LCP_FAILURE 3 LCP echo リクエストに対する応答 (REPLY) が何回戻ってこなかった場合に回線切断と判断するかを指定します。
LINUX_PLUGIN   Linux 2.4.x で pppoe-connect にカーネルモード PPPoE を使用させたい場合に、カーネルモード PPPoE プラグインへの完全なパスを指定するのだそうです。
PPPOE_EXTRA "" pppoe に渡す引数だそうです。
PPP_EXTRA "" pppd に渡す引数だそうです。

 

これらを踏まえて今回は、次のような "/etc/ppp/pppoe.conf" を用意してみました。 下記にはあらかじめ用意されていた "pppoe.conf" ファイルに指定されていたディフォルト値も含まれています。

今回は DNSTYPE=SPECIFY として DNS サーバを指定しましたけど、通常は DNSTYPE=SERVER としておけば、プロバイダから自動的に DNS サーバ情報を取得することが出来ます。またこのとき "/etc/resolv.conf" の内容が自動的に更新されるようなので気をつけましょう。

ETH=eth0

USER=xxx@xxxx.xxx.xxx.xx

DEMAND=no

DNSTYPE=NOCHANGE

PEERDNS=no

DNS1=

DNS2=

DEFAULTROUTE=yes

CONNECT_TIMEOUT=30

CONNECT_POLL=2

PING="."

CF_BASE=`basename $CONFIG`

PIDFILE="/var/run/$CF_BASE-pppoe.pid"

SYNCHRONOUS=no

LCP_INTERVAL=20

LCP_FAILURE=3

PPPOE_TIMEOUT=80

FIREWALL=MASQUERADE

パスワードの指定は "/etc/ppp/chap-secrets" または "/etc/ppp/pap-secrets" で行うとのことで、そのどちらが利用されるかどうかはプロバイダが採用している認証方法にかかってくるとのことでした。 ですのでその両方に、次のように指定します。

xxxx@xxxx.xxx.xxx.xx * password *

設定項目は左から順に "ユーザ ID", "接続先サーバ", "パスワード", "IP アドレス指定" となるような感じです。通常はプロバイダへユーザ ID とパスワードを指定すれば良いはずですので、それ以外の部分は "*" としておくことにします。

 

あとは次のようにして、PPPoE 接続を開始させます。

/usr/sbin/pppoe-start

 

ルーティング環境を調査してみる…

いざ RP-PPPoE の設定をしてみると、ルーティングなどの何かと細かなところにまで気を配ってくれそうだったので簡単に行くかと思ったのですけど、設定を終えて "pppoe-start" を実行してみたところ、" ... Connected!" と表示されはするものの、 通信を行うことが出来ませんでした。症状としては PPPoE 接続は確立されるもののルーティングが上手く働かなくて、パケットが正しい経路を選択できない感じです。

そこで経路情報を "route" コマンドにて調べてみると、今まで使用していたディフォルトゲートウェイの他に、たしか次のような感じの、PPPoE で使用するインターフェイス eth0 に割り当てられている IP アドレス "192.168.0.2" を宛先としたホスト情報が登録されてるようでした。他にも ppp0 をディフォルトとするルーティング情報も登録されている感じです。

Destination    Gateway     Genmask         Flags Metric Ref    Use Iface

192.168.0.2    *           255.255.255.255 UH    0      0        0 ppp0

192.168.255.0  *           255.255.255.0   U     0      0        0 eth0

192.168.0.0    *           255.255.255.0   U     0      0        0 eth1

loopback       *           255.0.0.0       U     0      0        0 lo

default        192.168.0.1 0.0.0.0         UG    1      0        0 eth1

default        *           0.0.0.0         U     0      0        0 ppp0

"/etc/ppp/pppoe.conf" の FIREWALL=MASQUERADE の設定も何やら複雑そうなフィルタがたくさん登録されていたのが気になったので、とりあえず問題点を把握するためにとりあえず FIREWALL=NONE と設定してみてもインターネットを利用することが出来なかったので、やはりルーティングの問題が影響しているような感じです。

また、このとき ppp0 が取得した接続先 IP アドレスおよび、eth0 と eth1 それぞれの同一ネットワーク内へのパケット送信は可能でした。

 

そんな感じでとりあえず eth0 の IP アドレスが ppp0 の宛先とされているのがおかしいような気がするのと、ディフォルトゲートウェイとなり得る情報が eth1 と ppp0 とで 2 つ存在していたところが気になるところです。

そこで "/etc/rc.d/rc.inet1.conf" のゲートウェイ指定のところで GATEWAY="" としてみました。そうして再起動してみたところ、とりあえず eth1 をインターフェイスとするゲートウェイ設定 (Flags: G) の行はなくなりましたけど、相変わらず上手く通信が行えない状況でした。

次のようにしてディフォルトゲートウェイの設定を無効化した上で、意図的に ppp0 が取得したサーバ (P-t-P) の IP アドレス (10.0.0.1) をディフォルトゲートウェイに設定してみれば、通信が出来るようにはなるのですけど…。

route del default

route add default gw 10.0.0.1

 

eth0 の IP アドレスが ppp0 のホスト (Flags: H) として現れているところも気になったので、それなら試に "/etc/rc.d/rc.inet1.conf" の USE_DHCP[0] に "yes" と指定してみれば PPPoE で割り当てられた IP アドレスを取得できるのではないかと思いましたけど、そうしたところ ADSL モデムに備わっている DHCP サーバから IP アドレスを取得してしまいました。

 

あらためて RP-PPPoE に付属していた文書を眺めてみると、利用する上での注意点が見つかりました。それによると、RP-PPPoE が使用するネットワークアダプタには IP アドレスを割り当てたり、起動時に使用するネットワークアダプタを 指定してはいけないとのことでした。見事にこの状況に引っかかる感じです。

そこで "/etc/rc.d/rc.inet1.conf" の eth0 にまつわる IPADDR[0], NETMASK[0], USE_DHCP[0], DHCP_HOSTNAME[0] の全てを "" に設定してみましたけど、起動時に eth0 が動作することもなく、ルーティング情報にも eth0 に関わるものはなくなったものの、それでも ppp0 経由でインターネットへ出ることは出来ませんでした。

 

そんな感じで少し困ったのですけど、何も設定しない場合でも、先に初期化されるであろう eth0 よりもそれより後の eth1 の方が確実なように感じたので、LAN ケーブルを差し替えて、今まで eth1 だったネットワーク設定を eth0 にしてみました。その上で RP-PPPoE が使用するインターフェイスを eth1 とします。

このようにして Linux を再起動してみたところ、問題なく通信が行えるようになりました。

 

ただし今回はこのサーバを ADSL ルータとして利用しようと思うので、改めて "/etc/ppp/pppoe.conf" で FIREWALL=MASQUERADE を試してみましたけど、こうすると何故だかまた通信が出来なくなってしまいました。

その理由を調べてみようかとも思ったのですけど、でも自動設定はあまり好きではない性格なので、今回は FIREWALL=NONE としてそれは無効としておくことにしました。そして後は自分で iptables の設定を調整すれば、ルータの役割も果たすこともできました。

 

なお、パケットフィルタを設定ときはその環境に合わせていろいろと気を配った方が良いですけど、とりあえず iptables で IP Masquerade を設定するという点でみれば、次のような設定が必要になってくる感じです。

iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

 

起動時に PPPoE 接続を有効にする

とりあえず "pppoe-start" を実行すれば問題なく PPPoE 接続を利用できるようにはなりましたけど、Linux を起動した直後からすぐに利用できるように、起動スクリプト回りを調整しておくことにします。Linux Slackware 10.2 の場合、起動関連のスクリプトは基本的に "/etc/rc.d" に集まっています。

そして通常は "/etc/rc.d/rc.local" 辺りにでも書き込んであげれば大丈夫なことが多いのですけど、今回の場合は、あくまでも噂の範囲ではあるけれど ADSL はちゃんと手続きを取って切断させないと再接続時に何分か待たされることがあるような話しを聞いたことがあったので、その辺りも考慮しつつ、そしてシステムの一部という意味合いを強めるのもかねて、"/etc/rc.d/rc.M" と "/etc/rc.d/rc.0" とに記載してみることにします。

 

把握しやすくするために、まずは RP-PPPoE を制御するためのスクリプトを "/etc/rc.d/rc.pppoe" として用意しておきます。

#!/bin/sh

 

pppoe_start()

{

echo -n "Starting: PPPoE Connection "

/usr/sbin/pppoe-start

}

 

pppoe_stop()

{

echo "Stopping: PPPoE Connection ... "

/usr/sbin/pppoe-stop

}

 

pppoe_restart()

{

pppoe_stop()

sleep 1

pppoe_start()

}

 

case "$1" in

'start')

pppoe_start

;;

'stop')

pppoe_stop

;;

'restart')

pppoe_restart

;;

*)

echo "usage $0 start|stop|restart"

esac

このような内容のスクリプトが出来たら、次のようにして実行可能としておきます。

chmod +x /etc/rc.d/rc.pppoe

 

そして PPPoE 接続を開始させるところです。Slackware 10.2 は、マルチユーザーモードに突入する時に "/etc/rc.d/rc.M" が呼び出されるようになっているので、その中の適切なところで PPPoE 接続を開始するように、そのスクリプトを編集しておきます。

もっと適切な部分は部分があるのかもしれないですけど、とりあえず今回は 275 行目あたりの "/etc/rc.d/rc.inet2" が組み込まれた次辺りにおいておくことにします。

# Start networking daemons:

if [ -x /etc/rc.d/rc.inet2 ]; then

. /etc/rc.d/rc.inet2

fi

 

# Start PPPoE Connection:

if [ -x /etc/rc.d/rc.pppoe ]; then

. /etc/rc.d/rc.pppoe start

fi

PPPoE 接続を停止させるのは "/etc/rc.d/rc.0" に記載します。これも他によい場所があるかもしれないですけど、今回は 85 行目あたりの NFS や SMB といったネットワークファイルシステムのマウント解除を行った後、PPP 接続を停止させる前に入れておくことにしました。

# Unmount any NFS or SMB filesystems:

echo "Unmounting remote filesystems."

umount -a -r -t nfs,smbfs

 

# PPPoE Stop

if [ -x /etc/rc.d/rc.pppoe ]; then

. /etc/rc.d/rc.pppoe stop

fi

 

# Try to shut down pppd:

PS="$(ps ax)"

if echo "$PS" | grep -q -w pppd ; then

if [ -x /usr/sbin/ppp-off ]; then

/usr/sbin/ppp-off

fi

fi

IP Masquerade 環境を構築したい場合は、Slackware 10.2 の場合、"/etc/rc.d" ディレクトリに "rc.firewall" というファイルを用意して実行権限を与えてあげれば、自動的に "/etc/rc.d/rc.inet2" から読み込まれるようになっているので、その中で次の行を実行させてあげる感じで、IP Masquerade 用のパケットフィルタルールを登録することが出来ました。

iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

 

SYNCHRONOUS = "yes" にしてみる

RP-PPPoE を設定して行く中で、SYNCHRONOUS の設定がなんだか少し気になりました。

細かい仕組みはわかりませんけど、とりあえずここを "yes" に設定すれば Synchronous PPP が有効になり、PPPoE 処理にかかる CPU 負荷が 1/4 くらいに抑えられる見込みがでてくるそうです。ただしこれを有効にするためには n_hdlc ライン制御機能 (discipline) を備えていることが必須とのことでした。

n_hdlc を備えているかどうかは "n_hdlc.o" モジュールがあるかどうかで 確認することができるとのことでしたので、さっそく調べてみたところ、Slackware 10.2 の場合は "/lib/modules/2.4.31/kernel/drivers/char/n_hdlc.o" として存在していることが判りました。

それならきっと大丈夫でしょうと、SYNCHRONOUS=yes にして PPPoE 接続を行ってみたところ、問題なく接続することが出来ました。"lsmod" を実行してみると、ちゃんと "n_hdlc.o" モジュールが読み込まれていることも確認できました。その後の稼動も安定していて、CPU の負荷が軽くなったかどうかまではわかりませんけど、とりあえずこれで良さそうな感じです。