前書き

FreeBSD 8.0-RELEASE 向けに説明しているサイトがないのでメモがてら。

注意点

ルーターの確認

ルーターが PPTP 変換をサポートしている必要がある。
OPT90 では PPPoE の詳細設定で「PPTP 変換を有効にする」にチェックを入れ、IP マスカレードテーブルで
プロトコル:tcp
先頭ポート番号:pptp
終了ポート番号:pptp
変換 IP アドレス:転送先サーバーの IP アドレス
と設定して再起動しておく。

カーネルコンフィギュレーション

TUN デバイスを使用するため、カーネルモジュールのロードが必要となる。
下記コマンドにて if_tun をロードする。

# kldload if_tun

ロードしたら再起動時に自動的にロードするように、/boot/loader.conf に下記 2行を追記する。

if_tun_load="YES"

サーバーへのインストール

packages で PopTop をインストールする。
# pkg_add ftp://ftp7.jp.freebsd.org/pub/FreeBSD/ports/i386/packages-8-stable/All/poptop-1.3.4_2.tbz

設定ファイルの編集

ppp 関係の設定ファイルについては secure ファイルは不要の模様。
/etc/ppp/ppp.conf

パーミッションは 600 とする。
また、ppp.conf はラベル行とコマンド行に別れており、コマンド行は先頭にスペースを 1つ入れること。

set ifaddr 行は

set ifaddr server_address client_address netmask
となっており、server_address には tun0 そのものに割り当てる一意の IP アドレスを指定する。
ここで指定する IP アドレスは他のどの IP アドレスとも競合してはならない (pptpd が動いているサーバーそのものの IP アドレスを指定してはならない)。
※pptpd 用 IP アドレスと考えればよい。
client_address には PPTP で接続するクライアントに割り当てる IP アドレスを指定する。
netmask は言わずもがな。

パラメータなどについては ppp(8)、pppctl(8)、及び FreeBSD Q&A - ppp を参照。

DNS は LAN 内の DNS を参照させるので set dns で LAN 内 DNS の IP アドレスを指定し、accept dns で指定した DNS を参照させる。
allow dns ではない事に注意!

enable proxy は Proxy ARP を使用することを宣言する。
これを宣言しておかないと PPTP サーバーより向こう側のホストにアクセスできなくなる。

ppp.conf の設定は以下の通り。

pptp:
 set timeout 0
 set device localhost:pptp
 set log phase chat connect lcp ipcp command
 set dial
 set login
 allow mode direct
 disable CHAP MSCHAP PAP
 enable MSChapV2 chap81
 disable deflate pred1
 deny deflate pred1
 enable MPPE
 accept MPPE
 set mppe 128 stateless
 enable proxy
 set server /tmp/pptp "" 0177
 set ifaddr 192.168.1.220 192.168.1.221-192.168.1.229 255.255.255.0
 set dns 192.168.1.10
 accept dns
/etc/ppp/ppp.secret

このファイルのパーミッションは 600 とする。

接続するユーザー名とパスワードを平文で記述する。
このユーザー名とパスワードは UNIX アカウントとは独立したアカウントとなる。

username1 password1
username2 password2
(以下接続するユーザー分だけ羅列)
/usr/local/etc/pptpd.conf

ほぼ pptpd.conf.sample 通りとなる。
/usr/local/etc/pptpd.conf は "option /etc/ppp/ppp.conf" の行を有効にすると何故か接続できなくなるので注意。

ARP リクエストにブロードキャストを使うので bcrelay が必要と思われたが不要の模様。

ppp /usr/sbin/ppp
noipparam
logwtmp
# set ifaddr の server_address に指定した IP アドレス
localip 192.168.1.220
# set ifaddr の client_address に指定した IP アドレス
# 記述書式が微妙に違うので注意。
remoteip 192.168.1.221-229
/etc/rc.conf
以下の 1行を書き足す。
pptpd_enable="YES"
以下の 2行を /etc/sysctl.conf に書き足す。
net.inet.ip.forwarding=1
net.link.ether.inet.proxyall=1

デーモンの起動

pptpd を起動する。
# /usr/local/etc/rc.d/pptpd start

クライアントの設定と接続

Android 端末の場合

※2011年12月15日現在、au/docomo/SofuBankMobile の三社が 3G 通信時の IP アドレスをプライベートアドレス化したことにより、同社端末で 3G 通信を利用中に限り PPTP での接続が行えません。

※2011年12月20日付けで au が 3G 通信時の PPTP 接続をサポートしました。

「ホーム」→「三」→「設定」→「無線とネットワーク」→「VPN 設定」→「VPN の追加」→「PPTP VPN を追加」で PPTP VPN サーバーを追加する。

  • 「VPN 名」に適当な名前を付ける。
  • 「VPN サーバーの設定」は PPTP VPN の IP アドレスもしくはホスト名を入力する。
  • 「暗号化を有効にする」にチェックを入れる。
  • 「DNS 検索ドメイン」は空のまま。
設定をキャンセルする場合は「三」→「キャンセル」で抜ける。

VPN に接続するたびに階層を下りるのは面倒なので、「QuickVPN」というアプリを入れておくと良い。

ちなみに PPTP 接続すると PPTP VPN サーバーの tap は以下のように変化する。
tun0: flags=8010<POINTOPOINT,MULTICAST> metric 0 mtu 1500
↓
tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1398
        inet 192.168.1.220 --> 192.168.1.224 netmask 0xffffff00
        Opened by PID 16305

APPENDIX

pppd はどこへ?

FreeBSD 8.0-RELEASE からは ppp に統合されました。

Proxy ARP について

Android 端末から PPTP VPN サーバー (以下「サーバー」) までは ping が飛んだり SMB に接続できたりするが、サーバーより向こう側のホストには到達できない。
調べてみると、どうも ARP が関係しているようなので、更に調べてみると Proxy ARP が関係しているようだ。

そこで試しにサーバーより向こう側にあるホストから Android 端末に ping を投げてみたところ・・・

C:\>ping 192.168.1.229
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Android 端末に ping が届かないのでサーバーを境にパケットが飛ばない模様。
ARP リクエスト/リプライの状況を見るために re0 を tcpdump でキャプチャ。
# tcpdump arp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on re0, link-type EN10MB (Ethernet), capture size 96 bytes

13:14:34.449702 ARP, Request who-has 192.168.1.229 tell 192.168.1.13, length 46
13:14:43.424894 ARP, Request who-has 192.168.1.229 tell 192.168.1.13, length 46
13:15:04.141811 ARP, Request who-has 192.168.1.229 tell 192.168.1.13, length 46
13:15:09.206920 ARP, Request who-has 192.168.1.229 tell 192.168.1.13, length 46
13:15:14.707070 ARP, Request who-has 192.168.1.229 tell 192.168.1.13, length 46
13:15:20.207235 ARP, Request who-has 192.168.1.229 tell 192.168.1.13, length 46
ping を投げたホスト (192.168.1.13) から Android 端末 (192.168.1.229) に対して ARP リクエストを送っているが返答は一行に返ってこない。

そこで Proxy ARP を有効にすべく sysctl で net.link.ether.inet.proxyall を 1 にしたところ・・・

C:\>ping 192.168.1.229
Reply from 192.168.1.229: bytes=32 time=1060ms TTL=63
Reply from 192.168.1.229: bytes=32 time=113ms TTL=63
Reply from 192.168.1.229: bytes=32 time=110ms TTL=63
Reply from 192.168.1.229: bytes=32 time=137ms TTL=63
帰ってきた!
ARP リクエスト/リプライを見てみると・・・
# tcpdump arp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on re0, link-type EN10MB (Ethernet), capture size 96 bytes

13:16:54.851597 ARP, Request who-has 192.168.1.229 tell 192.168.1.13, length 46
13:16:54.851682 ARP, Reply 192.168.1.229 is-at 00:1c:c0:45:f4:f6 (oui Unknown), length 28
Android 端末に到達するインターフェイスの MAC アドレスを答えている。

ちなみにこの MAC アドレスは サーバーの re0 のもので、詳しくは「proxy arp」でぐぐれ。

そこで、net.link.ether.inet.proxyall か enable proxy のどちらかを有効にすれば通信できるのでは?と思ったので実験してみた。

結果としてはどちらも有効にする必要があるようだ。
なお、enable proxyall にすると通信できなくなった (接続さえ出来ない) ので使わないように。

PPTP が使えないときの兆候

携帯電話会社が IPv4 枯渇対策として、スマートフォンが利用する IP アドレスを NAT 変換によるプライベートアドレスにしたおかげで PPTP による VPN 接続が出来なくなったが、その時のログを採取できたので掲載しておく。

正常に接続できたとき

SendConfig* コマンド (SendConfigReq/SendConfigRej/SendConfigNak/SendConfigAck) の他にも RecvConfig* コマンド (RecvConfigReq/RecvConfigAck/RecvConfigRej) が見られる。

% egrep '(Send|Recv)Config' pptp-ok.txt
Dec 21 09:45:38 leviathan ppp[71304]: LCP: deflink: RecvConfigReq(1) state = Stopped
Dec 21 09:45:38 leviathan ppp[71304]: LCP: deflink: SendConfigReq(1) state = Stopped
Dec 21 09:45:38 leviathan ppp[71304]: LCP: deflink: SendConfigAck(1) state = Stopped
Dec 21 09:45:38 leviathan ppp[71304]: LCP: deflink: RecvConfigAck(1) state = Ack-Sent
Dec 21 09:45:39 leviathan ppp[71304]: IPCP: deflink: SendConfigReq(1) state = Closed
Dec 21 09:45:39 leviathan ppp[71304]: IPCP: deflink: RecvConfigReq(1) state = Req-Sent
Dec 21 09:45:39 leviathan ppp[71304]: IPCP: deflink: SendConfigRej(1) state = Req-Sent
Dec 21 09:45:39 leviathan ppp[71304]: IPCP: deflink: RecvConfigReq(2) state = Req-Sent
Dec 21 09:45:39 leviathan ppp[71304]: IPCP: deflink: SendConfigNak(2) state = Req-Sent
Dec 21 09:45:39 leviathan ppp[71304]: IPCP: deflink: RecvConfigReq(3) state = Req-Sent
Dec 21 09:45:39 leviathan ppp[71304]: IPCP: deflink: SendConfigAck(3) state = Req-Sent
Dec 21 09:45:42 leviathan ppp[71304]: IPCP: deflink: SendConfigReq(2) state = Ack-Sent
Dec 21 09:45:42 leviathan ppp[71304]: IPCP: deflink: RecvConfigRej(2) state = Ack-Sent
Dec 21 09:45:42 leviathan ppp[71304]: IPCP: deflink: SendConfigReq(3) state = Ack-Sent
Dec 21 09:45:42 leviathan ppp[71304]: IPCP: deflink: RecvConfigAck(3) state = Ack-Sent
利用できないとき

SendConfigReq が Req-Sent しか投げず RecvConfig* が返ってこない。

% egrep '(Send|Recv)Config' pptp-not_support.txt
Dec 15 11:41:16 leviathan ppp[17904]: LCP: deflink: SendConfigReq(1) state = Stopped
Dec 15 11:41:19 leviathan ppp[17904]: LCP: deflink: SendConfigReq(1) state = Req-Sent
Dec 15 11:41:22 leviathan ppp[17904]: LCP: deflink: SendConfigReq(1) state = Req-Sent
Dec 15 11:41:25 leviathan ppp[17904]: LCP: deflink: SendConfigReq(1) state = Req-Sent
Dec 15 11:41:28 leviathan ppp[17904]: LCP: deflink: SendConfigReq(1) state = Req-Sent
認証失敗したとき

"Phase: Chap Output" で "FAILURE" が返ってくる。
ちなみに PPTP が利用できない場合は帰って来さえしない。

[PPTP が使える、かつ認証成功したとき]
% grep 'Chap Output' pptp-ok.txt
Dec 21 09:45:38 leviathan ppp[71304]: Phase: Chap Output: CHALLENGE
Dec 21 09:45:39 leviathan ppp[71304]: Phase: Chap Output: SUCCESS

[PPTP が使えないとき]
% grep 'Chap Output' pptp-not_support.txt
※無し

[認証失敗したとき]
% grep 'Chap Output' pptp-auth_fail.txt
Dec 21 09:51:48 leviathan ppp[71794]: Phase: Chap Output: CHALLENGE
Dec 21 09:51:48 leviathan ppp[71794]: Phase: Chap Output: FAILURE

接続不可時の切り分けとしては、認証の成功可否をチェックしてから PPTP が利用できる環境かを確認すればよいと思われる。

3G/WiFi/PPTP 接続自の DNS 設定

ppp.conf を適切に設定することにより、PPTP 接続自に LAN 内の DNS を参照させることが出来るが、nslookup や dig が使えないので LAN 内 DNS を参照しているか否かの判断が付きにくい場合がある。
その場合は、「ConnectBot」で localhost に接続し、ホスト名で ping を打ってみれば DNS 参照できているかどうかがわかる。

また、getprop で DNS 設定を見てみるのも 1つの手段。
方法は「ConnectBot」で localhost に接続し、

% cd /sdcard
% getprop > getprop.pptp.txt
のように一旦ファイルにリダイレクトしてから「net.dns」の文字列を探そう。