OpenVPNによるLAN間接続VPN
Category : サーバ管理日記
Published by M-naka on 2005/7/8
念願のLAN間接続VPN、ついに完成!
 ずっと懸案事項になっていた、実家とのLAN間接続VPNをついに構築した。

 VPNには具体的な利用形態で2つに大別される。

 一つはリモートアクセスVPN。外出先から社内ネットワークにセキュアにアクセスする、というのが典型例。この場合、社外ネットワークにある端末が社内ネットワーク上に存在するかのように振舞う。PPTPが典型例で、リモートアクセスであるが故に端末毎に接続のための設定が必要。これは、2年前に既に導入済である。

 もう一つはLAN間接続VPN。これはネットワーク同士をVPNトンネルで結ぶもので、企業の拠点間通信に使われるのはこっち。ネットワーク同士が接続されるので、設定が必要なのはVPNゲートウェイだけで、端末毎には不要。今回導入したのはこっち。

 実際のところはPPTPでもLAN間接続VPNを構築できるようなのだが、PPTP自体がLinuxの世界ではマイナーな存在であり、認証がCHAPベースなので常時接続に向いているとは言い難い。Windows端末接続用サーバとしては非常に良い働きをするが。

 ではIPSecはどうかというと、コイツは動的IPアドレスとの親和性が高くないのである。カーネル2.6に取り込まれたのに、どうもあまり活用されていない気がする。使うにしてもハードウェアルータで拠点間(固定IP同士のインターネットVPNかIP-VPN)接続に使うイメージだろうか? 積極的にLinuxでIPSecを使おうという動きはあまり見られないなぁ。

 で、OpenVPN。コイツはWindows、MacOS、Linux、*BSDで動作し、OpenSSLライブラリで暗号化を行う。リモートアクセスVPNもLAN間接続VPNもサポート。おまけにDynamicDNSのホスト間でもバッチリ使えるというスグレモノ。流石にリモートアクセスVPNには専用の接続ソフトが必要だが、OpenVPN自体のアドバンテージが大きいのであまり気にならない。

 今回は実家と自宅、OmoikaneとCasperをOpenVPNで結び、LAN間接続VPNを構築した。自宅側をAmatsuではなくCasperにしたのは負荷分散のため。接続モードにはブリッジモードとルーティングモードの2種類があり、このうちルーティングモードを選択。


【0】カーネルモジュールの確認とポートマッピング設定

 OpenVPNではtun(レイヤ3)かtap(レイヤ2)を使うので、これがカーネルモジュールとして作成されているかを確認する。

#modprobe tun
#modprobe tap

でエラーが出なければOK。エラーが出るときはカーネルモジュールがないので、カーネルとカーネルモジュールを作り直す。

 OpenVPNで使うのは5000/TCPと5000/UDPだから、これがmythril.ne.jp側とmythril.jp側でそれぞれCasperとOmoikaneにマッピングされるよう、ADSLモデムにポートマッピング設定を仕込む。


【1】OpenVPNのインストール

 まずは関連ライブラリから。OpenSSLとLZOをそれぞれのdevelパッケージも一緒にインストールする。OpenSSLは言わずもがなの暗号化ライブラリで、LZOは圧縮ライブラリ。LZOはOpenVPNを使う上ではインストール必須ではないが、スループット向上のためにインストールしておく。

 最新版は2.0で、OpenVPNのウェブサイトからtarボールをダウンロード可能。これにはRPMパッケージ作成用のSPECファイルが入っているので、

#rpmbuild -tb [OpenVPNのパッケージ]

でRPMパッケージを作成できる。あとはrpmコマンドでいつもどおりインストールしてやればよい。


【2】OpenVPNの設定

 セキュリティレベルはTLSを利用した方が上だが、まずはお手軽な事前共有鍵を使ってみる。以下のコマンドで事前共有鍵を作成する。

#openvpn --genkey --secret [任意の事前共有鍵名]
#chmod 600 [事前共有鍵]

設定はCasperはこんな感じで、Omoikaneはこんな感じである。ifconfigとrouteの設定もOpenVPNの設定ファイル内に書けばOK。

・Casperは192.168.1.0/24、Omoikaneは192.168.2.0/24。
・CasperとOmoikaneを172.16.1.0/24のVPNトンネルで結ぶ。
・Casperのtun0には172.16.1.1を、Omoikaneのtun0には172.16.1.2を割り付ける。
・Casperには192.168.2.0/24へのゲートウェイとして172.16.1.2を、Omoikaneには192.168.1.0/24へのゲートウェイとして172.16.1.1を、それぞれルーティング設定。
 

【3】iptablesの設定

 /etc/sysconfig/iptablesに以下を加筆。

##Casper##
#tunを192.168.1.0/24にマスカレード
-A POSTROUTING -o tun0 -s 192.168.1.0/24 -j MASQUERADE
#eth0を172.16.1.0/24にマスカレード
-A POSTROUTING -o eth0 -s 172.16.1.0/24 -j MASQUERADE
#tap0とtun0をフォワード
-A FORWARD -i tap0 -j ACCEPT
-A FORWARD -i tun0 -j ACCEPT
#tap0とtun0のパケットの通過を許可
-A RH-Firewall-1-INPUT -i tap0 -j ACCEPT
-A RH-Firewall-1-INPUT -i tun0 -j ACCEPT
#OpenVPNで使うTCPポート5000番とUDPポート5000番のパケットの通過を許可
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 5000 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 5000 -j ACCEPT

##Omoikane##
#tunを192.168.2.0/24にマスカレード
-A POSTROUTING -o tun0 -s 192.168.2.0/24 -j MASQUERADE
#br0を172.16.1.0/24にマスカレード
-A POSTROUTING -o br0 -s 172.16.1.0/24 -j MASQUERADE
#tap0とtun0をフォワード
-A FORWARD -i tap0 -j ACCEPT
-A FORWARD -i tun0 -j ACCEPT
#tap0とtun0のパケットの通過を許可
-A RH-Firewall-1-INPUT -i tap0 -j ACCEPT
-A RH-Firewall-1-INPUT -i tun0 -j ACCEPT
#OpenVPNで使うTCPポート5000番とUDPポート5000番のパケットの通過を許可
-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 5000 -j ACCEPT
-A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 5000 -j ACCEPT


 最初Omoikaneのbr0をeth0にしておいたのだが、これだとパケットがOmoikaneより先に行かない。実際に生きているネットワークインターフェースはbr0だから、これを割り付けないといけない。これ気づかず暫くハマった。


【4】デフォルトゲートウェイへの静的ルーティング設定

 iptablesの設定まで終えればLAN間接続VPNとしては一応使えるのだが、端末毎にルーティングの設定を仕込まないと上手くパケットが流れない。それでは面倒なので、それぞれのLANのデフォルトゲートウェイ(ADSLモデム)に静的ルーティングの設定を加える。

・Casper側
 192.168.2.0/24のゲートウェイは192.168.2.80(Omoikane)

・Omoikane側
 192.168.1.0/24のゲートウェイは192.168.1.30(Casper)

 それぞれ、VPNの向こう側への通信はVPNゲートウェイ(CasperかOmoikane)に投げられるようになる。これをデフォルトゲートウェイに仕込めば、LAN配下にある全端末に追加で設定を加える必要ななくなる。


【5】DNSサーバのフォワード設定とリゾルバの再設定

 静的ルーティングまで仕込めばIPアドレスベースで通信可能になっているが、mythril.ne.jpゾーンとmythril.jpゾーンで自分とは異なるゾーンにあるホスト名の名前解決ができない。これは双方に設置されているDNSサーバにもう一方のゾーンを新規に設定してやれば解決する。しかしこれでは非常に面倒なので、お手軽な解決法として、異なるゾーンの名前解決はそれが属するゾーンのDNSサーバにフォワードを掛けるようにした。

・mythril.ne.jp(192.168.1.0/24)側の設定
 名前解決対象がmythril.jpのときのみOmoikaneにフォワード、172.16.1.0/24からのクエリ要求を許可。

・mythril.jp(192.168.2.0/24)側の設定
 名前解決対象がmythril.ne.jpのときのみCasperにフォワード、、172.16.1.0/24からのクエリ要求を許可。

 具体的には以下の記述を/etc/named.conf(もしくは/var/named/chroot/etc/named.conf)に加える。

zone "フォワードを掛けるドメイン" {
type forward;
forwarders {フォワード先DNSサーバIPアドレス;};
};


 逆引きは不要だから、それぞれVPN先のホスト名を名前解決できればよい。

※フォワード対象を限定しないと、自分で名前解決できないホスト名を全てフォワードしてしまい(=毎回VPN越しに名前解決される)、DNS応答のパフォーマンスが著しく低下する。

 クエリ要求の許可は/etc/named.confでallowディレクティブにネットワークアドレスを加えるのみ。最初はここを192.168.1.0/24と192.168.2.0/24にしたのだが、クエリ要求は172.16.1.0/24で出されている(※エラーログで把握)ので、このような設定になる。

 あとはリゾルバ(/etc/resolv.conf)で双方のゾーンのプレフィックスとDNSサーバを追記すればよい。

search mythril.ne.jp
search mythril.jp
nameserver 192.168.1.120
nameserver 192.168.1.30
nameserver 192.168.2.80


これでOK。ホストによってプレフィックスとネームサーバの記述の上下関係が若干異なるが、この記述が全て入っていれば基本的に問題ない。

 ここまですると、ホスト名ベースでVPN越しの通信ができるようになる。バックグラウンドで動作しているので、VPNを意識することなく使える。自宅LAN内ホストと同様の動作で実家のリソースを使えるようになった(逆も然り)ので、頗る便利だ。