2013年9月10日

AndroidでCalDAVカレンダを使う

NOOKというAndroidのタブレットの環境を整備している。今回はカレンダ。

我が家のカレンダシステムはThunderbird/Lightningを基にしている。ぐぐるなどの外部サービスに生殺与奪権を与えるのは嫌なので、サーバは自前で、汎用性のあるCalDAVを使っている。CalDAVはWebDAVというHTTP1.1上のプロトコルの上で動作するプロトコル上のカレンダ同期専用プロトコル。WebDAVの上では、CalDAV以外にもXMarksのブラウザの同期プロトコルなどが走る。
 
色々調べた結果、Androidでは個々のカレンダクライアントは直接外部CalDAV(あるいは別のプロトコルの)サーバと交信するのではなく、Android内部の共通カレンダデータベースをアクセスするらしいことが分かった。そうなると、カレンダ(CalDAV)同期用クライアントとカレンダ表示クライアントが別になり、自由度が増す。

と言うことでまた色々調べたが、 CalDAV同期用クライアントで使えそうなICSSyncという有料アプリが見つかった。現在まだお試し期間中だが、必要にして十分な機能をソツなく実現している印象だ。CalDAVサーバとAndroid内部のデータベースを双方向に同期してくれる。

我が家内部の家族メンバ別のカレンダとMozillaの休日カレンダを設定し、同期が実現したのでこれでうまくいくはず、と思ったが、そうは問屋がおろさない。NOOKにデフォルトでインストールされているカレンダが同期したデータを安定に表示しない。そこで代替カレンダを探したのだが、Lightningのようなシンプルでスケジュール管理のできるカレンダはあまりない。結局、ぐぐるのカレンダがこちらの要求に一番合っているのでこれをインストール。
 
しかし、ここでまた伏兵。ぐぐるカレンダは予定の表示は問題なく動作するのだが、 新規予定を作成しようとしたり、既存の予定を編集しようとしたりすると「LOADING...」を表示して固まってしまう。と言っても、致命的ではなく、「戻る」の左矢印をタップすれば抜け出せるが、カレンダの予定が読み出し専用なことに変わりはない。まぁ、とりあえず新規作成と変更はThunderbird/Lightningで行い、ぐぐるがアプリをアップデートするまで待つことにする。

PPTPD VPNサーバを走らせる

最近ハマっているVPNプロジェクトの中でPPTPサーバを走らせてみたが、巷の情報と実際が食い違ったり、よそ様の情報では不明瞭だった事柄が見つかったので書いてみる。
 

その1:PPPD

LinuxのPPTPやIPSecのようなVPNプロトコルの実装は、プロトコル独自の通信レイヤと、複数の異なるVPNプロトコルに共通の仮想ネットワークインタフェースレイヤが明確に分離していて、この共通部分はPPPD(Point-to-Point Protocol)というデーモンで実現される。PPPDはPPTPD(サーバ側)/PPTP(クライアント側)やIPSecといった「プロトコルプロセッサ」から起動され、ユーザが直接起動することはない。
 
ところで、実際にPPTPDを走らせる前にいろいろなサイトで情報を事前チェックしてみると、PPTPDが立ち上がるとすぐにPPPDが起動され仮想ネットワークインタフェースとしてppp+が作成されるようなことが書いてあったにもかかわらず、実際にPPTPDを走らせてみるとPPPDは起動されずppp+も作成されない。さては何かまずい設定か、といろいろなサイトと/etc/pptpd.conf/etc/ppp/options.pptpdの比較をしてみるが、問題は見つからない。PPTPDを起動するときにstraceで追っかけるが、PPPDの起動に失敗した形跡はなく、むしろPPPDなんか起動するつもりがなさそうな形跡だけが目につく。しかも、PPTPDはPPPDなしでそ知らぬ顔でデーモンとしてふんぞり返っている。
 
こういうミステリアスな状態にすっかり混乱し、LinuxQuestions.orgに質問を投げたりもしてみたが有益な情報は得られなかった。
 
ふと思い立って、PPTPDだけが走りPPPDのない状態でクライアントから接続を試みたら、ビックリ仰天!他にも問題があってこの時点でのVPN接続は最終的には失敗するも、サーバ側では接続の試行中にPPPDが走り、ppp+もIPアドレスこそ与えられていないが作成されているではないか!
 
PPTPD(そしてIPSecも)では、サーバデーモン起動時にはPPPD(およびppp+)は起動されず、クライアントから接続要求があったときにオンデマンドで動的に起動・作成されることが分かった。
 

その2:パケットフィルタリング

これは完全に私のチョンボだが、PPTPで開放しなければならないのはGREプロトコル(47)とTCPのPPTPポート(1723)。UDPを使ったOpenVPNのつもりでUDPを開いていたら最初のLCPのハンドシェークで失敗していた。
 

その3:options.pptpd

PPPDに様々なオプションを渡すために、/etc/pptpd.confに「option /etc/ppp/options.pptpd」というコマンドを書くようになっており、そのコメントには「指定省略時には/etc/ppp/optionsが使われる」と書いてある。これは正しくない、あるいは少なくとも正確ではない。PPPDには、「option」で指定したオプションファイルに加え、常に/etc/ppp/optionsのオプションファイルが渡される/etc/ppp/optionsはPPPDの共通オプションファイルで、VPNのプロトコルやサーバかクライアントかに関わらず常にPPPDに渡されるから、内容は真に共通な最小限にするか、または/etc/ppp/optionsが存在しないほうがよい。インストール時のデフォルトの/etc/ppp/optionsの内容は「Lock」の一行のみ。
 

この、PPPDがプロトコルやクライアント・サーバを区別しない(と言うより区別できない)問題はip-up.localip-down.localにも共通するから、PPPDを使う複数のVPNプロトコルやクライアントとサーバを同時に走らせるシステムでは適切な対応が必要。具体的には、これらのスクリプトは以下のような引数で起動されるので、(必要なら)それらで区別する。
  • PPTP(クライアント): インタフェース名(ppp+) pty名(pts+) ボーレート(38400) ローカル(クライアント側)エンドポイントアドレス リモート(サーバ側)エンドポイントアドレス
  • PPTPD(サーバ): インタフェース名(ppp+) pty名(pts+) ボーレート(38400) ローカル(サーバ側)エンドポイントアドレス リモート(クライアント側)エンドポイントアドレス クライアントの物理IPアドレス
PPTPDは6番目の引数としてクライアントの物理IPアドレス(正確にはVPNが走る下位ネットワークのIPアドレス)が追加される。インタフェース名は動的に割り当てられるので、これをプロトコルやクライアント/サーバの識別に使ってはいけない。
 
IPsecはどうなるのかは解析していない。
 

その4:ppp+

上でPPPDはクライアントから接続要求があったときにオンデマンドで起動されると書いたが、これは最初に接続するクライアントのみ。PPTPDは複数のクライアントを受け付けるが、二番目以降のクライアントは最初に起動されたPPPDが面倒をみるので、新たなPPPDプロセスは起動されず、したがってppp+仮想ネットワークインタフェースも「Point-to-Point」の名に反し一つだけで複数のクライアントと接続する。P-t-Pと言うことでOpenVPNのtunインタフェースのイメージを抱いていたが、むしろtapに近い。なおクライアントのエンドポイントアドレスは各クライアント個別に/etc/pptpd.confの「remoteip」で指定されたレンジの先頭からわりあてらていくようだ。ifconfigで見たときのppp+には、最初に接続したのクライアントのエンドポイントアドレスだけがリモート側に表示される。

iPhoneをVPNでLANにつなぐ

このところVPNに少々ハマっている。

数年前から、まず日本に置いた録画サーバをファイルバックアップサーバとして使うときのセキュリティのためにOpenVPNを開通させており、次いで職場のWSと自宅のLANの間にやはりOpenVPNを開通させて重宝している。また、ラップトップから自宅LANへのOpenVPNも構築し、旅行先から自宅の全ネットワークソースを使えている。

最近、NOOKというAndroidのタブレットとAmazonのKindle Paperwhiteを二台づつ買った。Kindleの方は電子本リーダ専用ということで我が家のVPNとは直接関係ないが、二台のうち一台は日本のキンドルストアから日本の本を買うため専用ということで、アマゾンの国別サービス制限を回避するために外部VPNを使っている(こちらの記事参照)。NOOKの方は少なくとも一台は配偶者の仕事用ということで、仕事先から我が家のLANにアクセスできるようにOpenVPNを開通させた。

となると、完璧主義者の小生としては、残りのモバイル機器である家族3人が使っているiPhoneも何とかVPNで我が家のLANに接続させたくなる。実を言うと、接続できたからと言って何ができるようになると言うあてはない。とにかく、まず接続してみたいのだ。

と言うことで仕事が暇になったのをよいことにあれこれやってみた。

使ったのは
・Linuxサーバ:Fedora 13
・iPhone 4S:iOS 6.1.3
・ネットワーク:WiFi(3G/4Gはまだ試していない)

iPhoneはネイティブでPPTP、IPSec、L2TPのVPNをサポートしている(私にはIPSecとL2TPの区別がよくつかない)いるが、結論としてこれらのいづれもダメで、やはりiPhoneもOpenVPNを採用することにした。
 

PPTP

少々の紆余曲折はあったが、Linuxのファイアウォール上でPPTPDを動かし、外部のLinuxクライアントから暗号付きでVPNを構築する異に成功した。

ところがiPhoneで同じように開通させようとしてもエラーになるばかりで、結局暗号化をすべて禁止しないとダメだということが分かった。VPNの目的が中国のようにサイトのアクセス規制のある国から禁止されているサイトをアクセスするためで、VPNの先がパブリックのインターネットなら暗号化は不要だが、ここで目的としているようにプライベートなLANをアクセスするためには暗号化されていないのは論外と言うことで却下。
 

IPSec/L2TP

こちらのVPNの比較記事を読み、試すまでもなくやめた。iPhoneのネイティブサポートに対する期待はあったが、PPTPのような結末では時間の無駄と判断し、性能と安全性にすぐれ(我が家で)実績のあるOpenVPNを進めることにした。
 

OpenVPN

iTunesからOpenVPNのアプリをダウンロードしてインストールしたら、基本的な設定はAndroidの場合と変わるところはない。*.confファイルから*.ovpnファイルを作成するところも同じ(こちらのスクリプトを使う)。
 
*.ovpnファイルの取り込みはさらに簡単で、ファイルを(本文ではなく)添付したメイルをiPhoneに送ってやって、そのファイルを開くとOpenVPNのアプリが起動してインポートが始まる。

さあ、iPhoneからもOpenVPNが開通した。何をさせよう?