読者です 読者をやめる 読者になる 読者になる

LGTM

Looks Good To Me

通信内容からiPhone アプリの振る舞いを推測する

networking

先日iPhone で撮った動画をメールで送ろうとして,送信エラーで送れなかった.ところがMessages.app だとちゃんと送れる.

「くそーなんだこれ.Messages なにやってんのかまったく分からん!」と思って,このアプリの振る舞いを調べてみた.

写真アプリの仕様で たぶん「特定サイズ以上のファイルはメールで送れない」が,Messages はそんな制限なくて「S3 経由で動画を送受信している」のを知った話.

通信内容を見る

Xcode を使うと iPhone デバイス上の通信を見ることができる.

Messages.app (iPhone) --> Messages.app (MBP)

上のように動画を送信したときのパケットシーケンスはだいたいこんな感じ.

f:id:codeout:20141012000809p:plain

パケット数で言うと90s で30,000 pkts を超えるが,コツをつかめばわりとパケットダンプが読める.

ところどころ ? になっているのは,通信がTLS で暗号化されていて「なにか通信している」ことしか分からない箇所.まあでも

  • 通信先アドレス / ホスト名 / ポート番号
  • 通信先サービス概要
  • 送信 / 受信のパケット数,バイト数
  • どちらから通信を開始しているか
  • ARP / NDP のしくみ
  • TCP のしくみ
  • DNS のしくみ
  • STUN やTURN のようなNAT 関連のしくみ
  • 暗号化のしくみ

が分かると なんとなく想像することができる.

2つのMessages アプリがやっていること

推測混じりで書くと

送信側 (iPhone)
  1. AppleAPI サーバー に「添付ファイルをアップロードしたい」と伝える
  2. API サーバーは添付ファイルのアップロード先 (ここでは たぶんAmazon S3 のエンドポイント) を返す
  3. 添付ファイルアップロード
  4. メッセージ本文 + 添付ファイルURL をAPI サーバーに送る
  5. "送信完了" サウンド再生
受信側 (MBP)
  1. プッシュ通知を受け取る
  2. API サーバーからメッセージをダウンロード
  3. 添付ファイルがあるので,S3 からダウンロード
  4. API サーバーに「受信完了 + メッセージを開いた」通知
  5. メッセージを表示

こういう動きをしていると思われる.

おもしろいのは,

  • iPhonexxx-content.icloud.com 宛てに通信しているのに,MBP はいきなり xxx-content.icloud.com.akadns.net と通信している
    • AppleAPI サーバーもGSLB のようなサービスを被せているっぽいが,CNAME 解決をしない
    • OS かアプリがキャッシュしていたか,なにか別の方法でホスト名を通知したか...--> よくわからなかった
  • iPhone からの添付ファイルアップロードがhttps (TLSv1.2) なのに,MBP へのダウンロードはhttp
    • 認証情報を渡さないと "403 Forbidden"
    • iPhone / MBP の仕様の違いなのか,アップロード / ダウンロードの違いなのか...--> 調べてない

まとめ

Messages 便利.S3 経由で デカいファイルを扱えるようにできてる.

  • 今まで SMS クライアント + テキストチャットアプリだと思ってた
  • SMS ですらなかった.普通にIP

ちなみに,送ろうとしてた動画は30MB もあった :)
メール送信がエラーしてよかった.

おまけ

iPhone デバイス上の通信を見る方法

iOS5 からRVI (Remote Virtual Interface) をサポートしているので,USB 接続されたOSX 端末に仮想インターフェイスを作れば そいつ経由でパケットをTap できる.

$ rvictl -s <iPhone のUDID>
# 仮想インターフェイス rvi0 (link type: PKTAP) ができる
  • UDID はiTunes などで確認できる
    • USB 接続し,概要タブ上の "シリアル番号" をクリック
  • iPhone 上のインターフェイスは区別できない
    • 全通信をTap し,混ざったものをrvi0 で見れるだけ
  • 付属のtcpdump でファイル出力すると,pcap-ng フォーマットになる

あとは例えば

$ tcpdump -i rvi0 -s 0 -w iphone.pcapng

のようにすればいい.

終わったら

$ rvictl -x <iPhone のUDID>

か,USB ケーブルを抜けば 仮想インターフェイス rvi0 が消える.

Messages.app (OSX) のデータ確認方法

sqlite データベースとして ~/Library/Messages/ に保存されているので,簡単に開ける.

$ sqlite3 ~/Library/Messages/chat.db
SQLite version 3.7.13 2012-07-17 17:46:21
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .tables
_SqliteDatabaseProperties  chat_message_join
attachment                 handle
chat                       message
chat_handle_join           message_attachment_join

ダウンロードした添付ファイルも ~/Library/Messages/Attachments/ にある.