iOS7のSiriのMPTCP通信をキャプチャしてみた

iOS7のSiriはMPTCP (Multi-path TCP) に対応しているとのこと。

参考: iOS 7は3G・4G通信とWi-Fiなどを同時使用して回線速度を安定させる「MPTCP(マルチパスTCP)」に対応していることが判明 - GIGAZINE
参考: iOS 7でMPTCPがサポートされた話 | nunnun's weblog
RFC: RFC 6824 - TCP Extensions for Multipath Operation with Multiple Addresses


ということで、実際にその通信をキャプチャしてみました。(ちなみにSiri以外の通信にはMPTCPは有効にならないようです。残念。)
3G/LTEの通信を直接キャプチャすることはできないので、ちょっとした細工がDNSに必要です。


まず、iPhoneからWi-Fiで接続できるゲートウェイ・サーバが必要です。今回はLinuxを使用しました。iPhoneと同一のネットワークセグメントになるように接続します。

 Internet -- Wi-Fi router
             +-- Gateway Server
             +-- iPhone

Wi-Fiルータの設定

あらかじめWi-Fiルータの設定で、インターネットからゲートウェイ・サーバにHTTPS接続できるように、グローバルアドレスに対するHTTPS接続(TCP port 443)をゲートウェイ・サーバにフォワードするように設定しておきます。加えて、Wi-FiからグローバルアドレスへのHTTPS接続もゲートウェイ・サーバに繋がるようにする必要があります。これができるかはWi-Fiルータの仕様によります。できない場合は、外部ネットワークにゲートウェイをおくなどの工夫が必要になります。

ゲートウェイサーバの設定

HTTPS接続をAppleのSiriサーバに転送するようにします。やり方はいくつかありますが、

1. iptablesを使う

DNATでTCP 443番ポートのパケットをAppleのサーバに中継します。ファイアウォールで443をACCEPTするのもお忘れなく。

sudo iptables -t nat -A PREROUTING -d <ゲートウェイサーバのIPアドレス> -p tcp --dport 443 -j DNAT --to <guzzoni.apple.comのIPアドレス>:443
sudo iptables -t nat -A POSTROUTING -p tcp --dport 443 -j MASQUERADE

guzzoni.apple.comのIPアドレスはhostコマンドで調べてください。akamaiを使っているようなので環境により違うと思います。

2. MPTCPパッチ + stoneなどのTCPリピーターを使う

まず、MPTCPパッチLinuxカーネルに当てて再コンパイルしておく必要があります。ビルド方法はこのページを参照
ビルドしたカーネルで起動したら、stoneを導入し、

stone guzzoni.apple.com:443 443

とすればOKです。この場合、AppleのサーバとのiPhoneの直接MPTCP通信ではなく、ゲートウェイ・サーバを介した3者間でのMPTCP通信をキャプチャすることになります。ついでにLinuxのMPTCPともiPhoneAppleのサーバが通信できることも確認できますね:-)


両方ともやってみましたが、以下は2の方を使った場合の結果です。

DNSの導入

ゲートウェイにSiriサーバのエントリを改変するためのDNSを導入します。dnsmasqなどを使えばよいでしょう。こちらの記事にあるSiriProxyでも良いです。そして、「guzzoni.apple.com」の問い合わせに対して、自分のグローバルアドレスを返すように設定します。


そして、iPhoneWi-FI設定のDNSのアドレスを導入したサーバのものに変更します。


Wi-Fi側のDNSさえ弄っておけば、3G/LTE側の接続でもそこで引いたアドレスを使ってくれます。同一ホストに接続しなければMPTCPは意味がないので当然ですね。だからこそこの仕掛けでキャプチャができるわけですが。

MPTCP対応tcpdumpを導入

MPTCP対応tcpdumpも開発されているようです。ありがたく使わせていただきましょう。ビルドして…

git clone git://github.com/multipath-tcp/tcpdump.git
cd tcpdump
yum install libpcap-devel  # Fedoraの場合
./configure
make -j4

実行します。

./tcpdump -i <NICのインターフェース名> port https and not host guzzoni.apple.com

guzzoni.apple.comとの通信を除外しているのは、受信したパケットと転送パケットの両方がキャプチャされてしまうのを抑制するためです。

Siriを起動

この状態でSiriを起動してみると、

22:28:46.003820 IP iPhone.1024 > daisy.apple.com.https: Flags [S], seq 3599195999, win 65535, options [mss 1460,nop,wscale 3,mptcp capable {0x72d38468f5b08cec},nop,nop,TS val 172462590 ecr 0,sackOK,eol], length 0
22:28:46.005030 IP daisy.apple.com.https > iPhone.1024: Flags [S.], seq 486719052, ack 3599196000, win 14280, options [mss 1460,sackOK,TS val 12199698 ecr 172462590,nop,wscale 7,mptcp capable csum {0x2bbdacfe975af7bf}], length 0
22:28:46.028714 IP iPhone.1024 > daisy.apple.com.https: Flags [.], ack 1, win 8211, options [nop,nop,TS val 172462684 ecr 12199698,mptcp capable csum {0x72d38468f5b08cec,0x2bbdacfe975af7bf}], length 0

まずWi-Fiで通信が始まります。MPTCPオプションがついてますね(ホスト名がdaisy.apple.comとなっていますが、実際にはゲートウェイです。iPhoneというのはiPhoneWi-Fi側アドレスです)。さらに…

22:28:46.388811 IP LTE.51471 > daisy.apple.com.https: Flags [S], seq 970380433, win 65535, options [mss 1388,nop,wscale 3,mptcp join backup id 2 token 0x79701d4c nonce 0xa55d4e97,nop,nop,TS val 172462952 ecr 0,sackOK,eol], length 0
22:28:46.388923 IP daisy.apple.com.https > LTE.51471: Flags [S.], seq 130921612, ack 970380434, win 14280, options [mss 1460,sackOK,TS val 12200088 ecr 172462952,nop,wscale 7,mptcp join id 0 hmac 0xeddb2cca2f4efad9 nonce 0x76d9b16d], length 0

LTE側からもセッションが張られています(ホスト名がLTEとなっていますが、実際にはiPhoneLTE側のIPアドレスです)。今回キャプチャした限りでは、LTE側にはデータは流れておらず、制御用のパケットだけのようです。Wi-Fi側を故意に切断したりパケットをブロックしたりすると、LTE側にもデータが流れるのかもしれません。


キャプチャした内容はこちら → tcpdump of Siri connection with MPTCP option Captured with https://github.com/multipath-tcp/tcpdump on the gateway server (Linux with MPTCP patch). DNS server is modified to answer the gateway server's IP address for guzzoni.apple.com "LTE" means iPhone's LTE network address. · GitHub