[an error occurred while processing this directive]

LinuxマシンをADSLルータにする

作業の概要

ここでは、LinuxマシンをADSLルータとして使えるようにする。今回構築したネットワークは次のような構成である。

                                         +-----------+   192.168.0.1
                  +------------+  +------+           +------+
   [Internet]-----+ ADSLモデム +--+ eth1 | Linux Box | eth0 |-----[LAN]
                  +------------+  +------+           +------+       (192.168.0.0/24)
                                         +-----------+

作業の手順として、まずLinuxマシンからADSLモデムを使用してInternetにアクセスできる状態にし、次にLAN内のマシンからもインターネットにアクセスできるようにする。

ADSLモデムを使ってプロバイダに接続する

元帥府が利用しているADSLサービスは、モデムを通してPPPoEでアクセスするタイプのものだったので、PPPoEクライアントソフトが必要だった。というわけでいつものようにaptを使ってインストール。

    root@host# apt-get install pppoe

インストールが終わると、「pppoeconfコマンドで設定をしてね」と言われたので、pppoeconfを実行する。質問に答えていくと設定ファイル(/etc/ppp/peers/dsl-provider)が出来る、という仕組みである。

最初にどのNICにADSLモデムが繋がっているのか自動的に検出するのだが、なぜか最初はうまく見つからないと言われてしまった。何回かやり直しているうちに、eth1にモデムを検出。なんでだ?

接続ユーザー名やパスワードなどを設定し、そのほかの項目は適当に推奨されたほうを選択したが、「通知されたDNSサーバーをresolv.confに追加する」だけはNoにしておいた。そのうち自分をDNSサーバにするためである。

最後に、自動的に接続するかと聞かれたのでOKしたが、待ってても接続できなかったのでCTRL+Cで中断。手動で接続してみることにする。

    root@host# pon dsl-provider

しかし、やっぱりエラーが出る。エラーメッセージを適当に調べていると、どうもカーネルでpppがサポートされていないからのようだ。ガーン。menuconfigしてみると、たしかに「PPP support」がOFFになっている。仕方なくカーネルを再コンパイルして再起動。起動すると、無事に接続できた(pppoeconfで起動時に自動的に接続するように設定してたので)。

ifconfigでppp0が出来ていることを見たり、プロバイダのDNSサーバにpingを打ってみて、応答があるかを見たりしてみる。うまくいっているようだ。

LAN内の他のPCから外部と通信できるようにする

LAN側のNICを設定するIPフォワーディングを有効にする

まず、eth0自体のIPアドレスは固定指定しておく必要があるので、/etc/network/interfacesを編集する。

    # eth0の設定をdhcp取得から直接指定に変更
    iface eth0 inet static
                address 192.168.0.1
                netmask 255.255.255.0

/etc/network/interfacesの変更を反映させるため、ネットワークインタフェースを再起動しておく。

    root@host# /etc/init.d/networking restart

ここで、eth0のIPアドレスが変わる場合はsshは切れてしまう。しばらくしてから192.168.0.1に接続してみるとちゃんと繋がったので作業を続けた。

IPフォワーディングを有効にする

Linuxマシンがルータとして動作するためには、IPパケットを中継する機能をオンにして、かつIPマスカレードを設定する必要がある。

    root@host# echo 1 > /proc/sys/net/ipv4/ip_forward  IPフォワーディングを有効化

これでIPフォワーディングが有効になるが、この設定は再起動すると消えてしまう。Debianで再起動時に自動的にこの設定を行うためには、/etc/network/optionsを編集する。

    ip_forward=yes

つぎに、IPマスカレードである。これは、ルータがパケットを外部に送出するときに送信元アドレスと外部からの応答パケットのあて先アドレスを書き換えることで、複数のマシンがひとつのIPアドレスで通信できる仕組みである。仕組みは複雑だが、設定はこれ1行でOK。

    root@host# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

設定が終わったら、早速LAN内の別のマシンが外と通信できるか実験する。テストに使用するマシンのTCP/IPの設定を変更し、デフォルトゲートウェイの設定をLinuxマシンのLAN内のIPアドレスに設定する。ここでは、192.168.0.1である。

ためしに、LAN内のWindowsマシンで、プロバイダのDNSサーバにpingを打ってみたり、ブラウザを立ち上げて適当なサイトを見てみる。…問題ないように見える。

ファイアウォールの設定

これでも一応通常の使用には耐えるのだが、このままではすべてのパケットを中継してしまうので気持ちが悪い。不要なパケットは中継しないようにフィルタルールを設定しておくべきだろう。「iptablesによるパケットフィルタリング」で紹介したのと同じように、こちらも基本は「デフォルトオフ」の思想で設定する。

    どのルールにも合致しないパケットは破棄する
    root@host# iptables -P FORWARD DROP
    
    外からLANに送られるパケットを調べるチェインを作成
    root@host# iptables -N i_to_l
    root@host# iptables -A FORWARD -i ppp0 -o eth0 -j i_to_l
    すでに確立されたTCPコネクションのパケットは通過させる
    root@host# iptables -A i_to_l -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT
    DNSサーバからの応答は通過させる
    root@host# iptables -A i_to_l -p udp --sport domain -j ACCEPT
    pingへの応答は通過させる
    root@host# iptables -A i_to_l -p icmp --icmp-type echo-reply -j ACCPET
    パケットが届かなかったことを示すicmpメッセージは通過させる
    root@host# iptables -A i_to_l -p icmp --icmp-type destination-unreachable -j ACCPET
    
    LANから外に送られるパケットを調べるチェインを作成
    root@host# iptables -P FORWARD DROP
    root@host# iptables -A FORWARD -i eth0 -o ppp0 -j l_to_i
    LANから外に送られるパケットはすべて通過させる
    root@host# iptables -A l_to_i -j ACCPET

最低限こんな感じでいいと思う。あとはお好みで検査を厳重に。最後に、フィルタルールは再起動すると消えてしまうので、設定が終わったら忘れずに

    root@host# /etc/init.d/iptables save active

を実行して、ルールを記憶させておくこと。

外部からLAN内のPCのサービスが利用できるようにする

ここまでの設定で、内部から外部にコネクションを張ったりする通信は問題なく出来るようになったのだが、外部からLAN内のマシンにアクセスしたい場合や、一部のネットワークゲームをやりたい場合などは、あて先が判断できないので通信が確立できない。市販のルータで「静的NAT」などといわれる設定をLinuxルータでも施さなければならない。ここでは例として、外部からのリモートデスクトップ接続(WindowsXPのリモートコントロール機能)を192.168.0.5に転送する設定をしてみる。

    root@host# iptables -t nat -A PREROUTING -p tcp --dport 3389 -i ppp0 -j DNAT --to 192.168.0.5

注意が必要なのは、この設定はあくまでパケットのあて先を判断できるようにしただけ、ということである。実際に通信が出来るためには、さらにパケットがファイアウォールを通過できるようにしなければならない。

    あて先ポートが3389のTCPパケットで、192.168.0.5向けの物は通過させる
    root@host# iptables -A i_to_l -d 192.168.0.5 -p tcp --dport 3389 -j ACCEPT

しばらくして外出し、帰ってから普段どおりWindowsマシンでWebを見ようとしたらサイトが見つからないとエラーが。どのサイトでも出るのでおかしいと思い、そのマシンのデフォルトゲートウェイの設定を確認したらちゃんと192.168.0.1になっていた。とすれば原因はLinux側か、と考えて192.168.0.1にpingをかけても応答がない。

sshも繋がらないので仕方なく久しぶりにキーボードを引っ張り出してコンソールログインしてみると原因は比較的すぐ分かった。LAN側のIPアドレスがなぜか変わっていた。

IPアドレスをもとの192.168.0.1に戻したらまた正常に動くようになったが、ではなぜ勝手にIPアドレスが変わったのだろうか?

そのあとも原因を探って、原因はdhclientだとわかった。よく考えたら以前eth0はDHCPを使っていたので、dhclientが実行中のままだった。これがおそらくeth0のIPアドレスを変更していたのだろう。設定ファイルを書き換えただけではeth0は固定IPアドレスになっていなかったのである。dhclientをkillしたらそれ以降は勝手にIPアドレスが変わることはなくなった。

LAN内のPCで一部のWebサイトが閲覧できない

最後におまけ。これはLinuxがルータになる場合に特有の問題というわけではないのだが、ルータが外部との通信にPPPoEを使用している環境では、特定のウェブサイトが閲覧できない問題が発生する。これは、「パスMTU問題」といわれる問題で、詳しい説明は省くが、通信相手とTCPパケットのサイズ(MTU)の交渉がうまく出来ず、その結果サイズが大きくて分割禁止のパケットが届いてPPPoEの通信路に乗れず、通信が失敗するために起きるものである。

一言で言うと相手側に責任があるのだが、そうは言っても困るのはこっちなので、なんとか対策したい。対策には以下の呪文を唱えるといいらしい。

    root@host# iptables -A FORWARD -o ppp0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

これによって、ルータが接続要求パケットの中の、「期待する応答パケットの最大サイズ」を適切な値に書き換えてから送信するので、たとえ分割禁止フラグを立てて応答パケットを送るサーバも通信できる範囲内のサイズのパケットで応答を返してくれるようになるのである。


Last Update: Tuesday, 03-May-2005 21:44:18 JST

Copyright© 1999-2003,Gensui