PPTPサーバ立てた

最近カンファレンスなどに出かけてオープンな無線LANアクセスポイントが提供されている場合、よく「セキュリティに気をつけて! VPNを使って下さい」てな掲示を見かけます。
そうだよねーと思って、ARMなLinuxマシン(NAS)をPPTPサーバに仕立ててみた時のメモです。(今時PPTP?とも思ったが、今使っているNASだとカーネルの都合上、IPsecはモジュールだけでなくカーネル自体の入れ替えが必要そう(?)だったので断念。)

PPPカーネルモジュールの導入

今回使うのはARM搭載のNAS上で動くLinuxですが、標準状態ではpppドライバが入っていませんでしたので、まずはこれを導入。
make menuconfig で
Device Drivers => Network device support =>PPP (point-to-point protocol) support を M に。

  │ │ <M> PPP (point-to-point protocol) support                           │ │   
  │ │ [ ]   PPP multilink support (EXPERIMENTAL)                          │ │   
  │ │ [*]   PPP filtering                                                 │ │   
  │ │ <M>   PPP support for async serial ports                            │ │   
  │ │ <M>   PPP support for sync tty ports                                │ │   
  │ │ <M>   PPP Deflate compression                                       │ │   
  │ │ <M>   PPP BSD-Compress compression                                  │ │   
  │ │ <M>   PPP MPPE compression (encryption) (EXPERIMENTAL)              │ │   

そしたら

% make modules
# make modules_install

PPPデーモン (pppd) の導入

最新版はppp-2.4.5ですが、ここではpoptop-1.3.4が対応するppp-2.4.3を入れる必要があります。
ダウンロード先: ftp://ftp.samba.org/pub/ppp/ppp-2.4.3.tar.gz
展開して configure && make && make install でOK。

Poptop (pptpd) の導入

http://poptop.sourceforge.net/ からpptpd-1.3.4をダウンロード。
ARM環境では、このままではビルドできるものの下記の通信エラーになって正常に動かないようです。

GRE: Discarding packet by header check

こちらを参考に、下記のパッチをあてておきます。(CVSから取ってくれば直ってたのかも。)

RCS file: /cvsroot/poptop/poptop/pptpdefs.h,v 
retrieving revision 1.4 
diff -u -r1.4 pptpdefs.h 
--- pptpdefs.h	8 Dec 2006 00:01:40 -0000	1.4 
+++ pptpdefs.h	20 Jul 2007 00:29:43 -0000 
@@ -309,7 +309,7 @@ 
 	u_int32_t seq;	 /* sequence number.  Present if S==1 */ 
 	u_int32_t ack;	 /* seq number of highest packet recieved by */ 
 	/* sender in this session */ 
-}; 
+} __attribute__((packed)); 

struct pptp_gre_header構造体のアラインメントが変わっちゃったんだなー。

あとはconfigure && make && make install。

/usr/local/以下に入りますが、pppdのライブラリ等が /usr/以下にある必要があるようなので、いくつかシンボリックリンクを張っておきます。ついでに /usr/sbin/pppd も。

# cd /usr/lib
# ln -s /usr/local/lib/pppd
# ln -s /usr/local/lib/pptpd

# cd /usr/sbin
# ln -s /usr/local/sbin/pppd

設定ファイルの編集

サンプル設定が pptpd-1.3.4/samples に入っているので、/etc 以下にコピーして編集します。

# cp samples/pptpd.conf /etc/
# mkdir /etc/ppp/
# cp samples/chap-secrets samples/options.pptpd /etc/ppp/


pptpd.confに、サーバ、クライアントがそれぞれ使用するIPアドレスの範囲を指定。

connections 4
localip 192.168.0.250
remoteip 192.168.0.251-254

これでサーバが 250、クライアントが251〜254になります。他の機器(サーバマシンのeth0等も含む)はこの範囲を使えなくなるので注意。


options.pptpd の方は、暗号化やpptpdの動作の設定。もともと脆弱なMS-CHAPは使わず(refuse-mschap)MS-CHAP-v2/MPPE-128を使用する(require-mschap-v2, require-mppe-128)設定となっていたため、dnsの設定だけ変更しました。

ms-dns 192.168.0.1

あとはchap-secrets にユーザ名/パスワードを書く。(平文かよーと思いつつ, rootのみ読めるようにしておくなどする。)

IPフォワードをonに

pppからのパケットを外部に転送できるようにします。/etc/sysctl.conf に

net.ipv4.ip_forward=1

と書いて、sysctl -p を実行。

ルータの設定

ルータのフォワーディングの設定。今回設定したマシンはルータ配下にあるので、ルータをPPTPが通れるようにフォワーディング設定が必要です。
外部からのTCPポート1723、プロトコル番号47(GRE)をサーバマシンのIPアドレスフォワードするように設定します。プロトコル番号47はポート番号とは別物なので注意。プロトコル番号の転送に対応していないルータだとNGかも。うちで使っているAtermは対応してました。

pptpdの起動

# pptpd

/var/log/messages にメッセージが出るので、 tail -f で確認しつつ、テスト接続してみると良いでしょう。

うちではiPod touchVPN設定を作って、確認しました。設定の仕方は以下などを参考に。
iPhone'z: おすすめ!iPhoneでVPN設定環境を構築して活用すれば、できなかったことができ便利(構築方法)

接続した状態で ifconfig すると

ppp0      Link encap:Point-Point Protocol  
          inet addr:192.168.0.250  P-t-P:192.168.0.251  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1396  Metric:1
          RX packets:54 errors:0 dropped:0 overruns:0 frame:0
          TX packets:58 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:3 
          RX bytes:4706 (4.5 KiB)  TX bytes:18532 (18.0 KiB)

と、ppp0インターフェースが稼働しているのが分かります。

ppp0のMTUが1396になってしまいますが、本当は適切な値に調整すると良いらしい。

AppleTalkを外した

Linux-2.6.16の問題なのか分かりませんが、appletalkモジュールが有効の状態でPPTPが動くと、カーネルがパニックするようです。

古いMacがあるわけでもなくAppleTalkなんて使わないので、atalkdなどが起動しないようにしました。さらにこれだけだとafpdが勝手にモジュールをロードしてしまうようだったので、appletalkモジュール ( /lib/modules/`uname -r`/kernel/net/appletalk/appletalk.ko ) そのものを外してしまいました。

ちなみにパニックした時のログは以下。

kernel BUG at net/appletalk/ddp.c:1013!
Unable to handle kernel NULL pointer dereference at virtual address 00000000

Backtrace: 
[<c0029290>] (__bug+0x0/0x58) from [<bf0070e4>] (atalk_sum_skb+0x1bc/0x1e4 [appletalk])
[<bf006f28>] (atalk_sum_skb+0x0/0x1e4 [appletalk]) from [<bf007128>] (atalk_checksum+0x1c/0x44 [appletalk])
[<bf00710c>] (atalk_checksum+0x0/0x44 [appletalk]) from [<bf00795c>] (atalk_rcv+0x148/0x644 [appletalk])
[<bf007814>] (atalk_rcv+0x0/0x644 [appletalk]) from [<c02720dc>] (netif_receive_skb+0x1b8/0x210)
[<c0271f24>] (netif_receive_skb+0x0/0x210) from [<c02721e4>] (process_backlog+0xb0/0x190)
 r7 = C04FBF34  r6 = 00000000  r5 = C03A95C4  r4 = C327D800
[<c0272134>] (process_backlog+0x0/0x190) from [<c0272354>] (net_rx_action+0x90/0x174)
[<c02722c4>] (net_rx_action+0x0/0x174) from [<c0058498>] (__do_softirq+0x60/0xd8)
 r8 = C039CBC0  r7 = 00000009  r6 = C04FA000  r5 = C039CC00
 r4 = 00000001 
[<c0058438>] (__do_softirq+0x0/0xd8) from [<c005855c>] (do_softirq+0x4c/0x58)
 r8 = 00000001  r7 = C0058ADC  r6 = C039CBC0  r5 = 00000000
 r4 = 60000013 
[<c0058510>] (do_softirq+0x0/0x58) from [<c0058b54>] (ksoftirqd+0x78/0xb8)
 r4 = C04FA000 
[<c0058adc>] (ksoftirqd+0x0/0xb8) from [<c0067424>] (kthread+0xf0/0x124)
 r6 = C04F9F50  r5 = C04FA000  r4 = 00000000 
[<c0067334>] (kthread+0x0/0x124) from [<c0055700>] (do_exit+0x0/0x7dc)
Code: eb00ab21 e59f0014 eb00ab1f e3a03000 (e5833000) 
 <0>Kernel panic - not syncing: Aiee, killing interrupt handler!