tcpsnitch
は、アプリケーションと TCP/IP スタック間の相互作用を調査するために設計されたトレース ツールです。 tcpsnitch
指定されたコマンドを終了するまで実行し、インターネット ソケット上のすべての libc 関数呼び出しをインターセプトします。
穏やかに開始するには、次のコマンドを実行して、 curl
プログラムをトレースします。
$ tcpsnitch curl google.com
開かれたインターネット ソケットごとに、 tcpsnitch
関数呼び出しの順序付きリストを作成します (このドキュメントの残りの部分では、関数呼び出しをイベントと呼びます)。各イベントについて、 tcpsnitch
引数、戻り値、および現在のタイムスタンプやスレッド ID などのさまざまな情報を記録します。具体的には、ソケット トレース内のconnect()
イベントは次のようになります。
{
"type" : " connect " ,
"timestamp_usec" : 1491043720731853 ,
"return_value" : 0 ,
"success" : true ,
"thread_id" : 17313 ,
"details" : {
"addr" : {
"sa_family" : " AF_INET " ,
"ip" : " 127.0.1.1 " ,
"port" : " 53 "
}
}
}
ソケット トレースは、各行が単一のイベントを表す JSON オブジェクトであるテキスト ファイルに書き込まれます。このようなトレースの先頭は次のようになります。
{ "type" : " socket " , "timestamp_usec" : 1491043720731840 , "return_value" : 6 , "success" : true , "thread_id" : 17313 , "details" : { "sock_info" : { "domain" : " AF_INET " , "type" : " SOCK_DGRAM " , "protocol" : 0 , "SOCK_CLOEXEC" : false , "SOCK_NONBLOCK" : true }}}
{ "type" : " ioctl " , "timestamp_usec" : 1491043720765019 , "return_value" : 0 , "success" : true , "thread_id" : 17313 , "details" : { "request" : " FIONREAD " }}
{ "type" : " recvfrom " , "timestamp_usec" : 1491043720765027 , "return_value" : 44 , "success" : true , "thread_id" : 17313 , "details" : { "bytes" : 2048 , "flags" : { "MSG_CMSG_CLOEXEC" : false , "MSG_DONTWAIT" : false , "MSG_ERRQUEUE" : false , "MSG_OOB" : false , "MSG_PEEK" : false , "MSG_TRUNC" : false , "MSG_WAITALL" : false }, "addr" : { "sa_family" : " AF_INET " , "ip" : " 127.0.1.1 " , "port" : " 53 " }}}
{ "type" : " ioctl " , "timestamp_usec" : 1491043720770075 , "return_value" : 0 , "success" : true , "thread_id" : 17313 , "details" : { "request" : " FIONREAD " }}
{ "type" : " recvfrom " , "timestamp_usec" : 1491043720770094 , "return_value" : 56 , "success" : true , "thread_id" : 17313 , "details" : { "bytes" : 65536 , "flags" : { "MSG_CMSG_CLOEXEC" : false , "MSG_DONTWAIT" : false , "MSG_ERRQUEUE" : false , "MSG_OOB" : false , "MSG_PEEK" : false , "MSG_TRUNC" : false , "MSG_WAITALL" : false }, "addr" : { "sa_family" : " AF_INET " , "ip" : " 127.0.1.1 " , "port" : " 53 " }}}
単一のコマンドが複数のプロセスをフォークする可能性があるため ( tcpsnitch
フォークの後に続きます)、特定のプロセスに属するすべてのソケット トレースは、トレースされたプロセスにちなんで名付けられたディレクトリにまとめられます。このようなディレクトリ内では、ソケット トレースはプロセスによって開かれた順序に基づいて名前が付けられます。
デフォルトでは、トレースは/tmp
の下のランダムなディレクトリに保存され、トレースを一元管理、視覚化、分析するように設計されたプラットフォームである www.tcpsnitch.org に自動的にアップロードされます。アップロードされたすべてのトレースは公開されており、誰でも参照したりダウンロードしたりできることに注意してください。
次のコード スニペットに示されているように、 tcpsnitch
トレースを利用できる URL を提供します。
$ tcpsnitch curl google.com
Trace saved in /tmp/tmp.4ERKizKyU3.
Uploading trace....
Trace successfully uploaded at https://tcpsnitch.org/app_traces/20.
Trace archive will be imported shortly. Refresh this page in a few minutes...
トレースのインポート (つまり、トレース アーカイブを抽出し、すべてのイベントをデータベースに挿入) には数分かかることに注意してください。インポート後、トレースの定量分析を計算するにはさらに数分かかる場合があります。
最後に、 tcpsnitch
使用すると、ユーザー定義の間隔でTCP_INFO
ソケット オプションを抽出し、個々のソケットごとに.pcap
トレースを記録することもできます。詳細については、使用法のセクションを参照してください。
tcpsnitch
使用すると、以下のアプリケーションをトレースできます。
tcpsnitch
、 LD_PRELOAD
環境変数を使用して libc 関数の呼び出しをインターセプトすることで機能するため、libc に静的にリンクされているアプリケーションのトレースは実行できません。
注: Linux では、Chrome (および Electron、Opera などの Chromium ベースのアプリ) には互換性がないことが知られています。
Android アプリケーションをトレースしたいユーザーの場合は、「Android 用のコンパイル」セクションまで下にスクロールしてください。
Ubuntu 16 & 14、Debian 8、Elementary 0.4、Mint 18 でテスト済み
sudo dpkg --add-architecture i386 && sudo apt-get update && sudo apt-get install make gcc gcc-multilib libc6-dev libc6-dev:i386 libjansson-dev libjansson-dev:i386 libpcap0.8 libpcap0.8:i386 libpcap0.8-dev
Fedora 25 および CentOS 7 でテスト済み
sudo yum install make gcc glibc-devel glibc-devel.i686 libgcc libgcc.i686 libpcap-devel.x86_64 libpcap-devel.i686 jansson jansson.i686 && curl -O http://www.digip.org/jansson/releases/jansson-2.10.tar.bz2 && bunzip2 -c jansson-2.10.tar.bz2 | tar xf - && rm -f jansson-2.10.tar.bz2 && cd jansson-2.10 && ./configure && make && sudo make install && cd .. && rm -rf jansson-2.10
ビルドとインストール:
./configure
make
sudo make install
使用法: tcpsnitch [<options>] <cmd> [<cmd_args>]
ここで:
<options>
はtcpsnitch
オプションです<cmd>
トレースするコマンドです (必須)<cmd_args>
は<cmd>
の引数です。以下は、 curl
とすべてのデフォルト オプションを使用した簡単な例です。
tcpsnitch curl google.com
tcpsnitch -h
発行すると、サポートされているオプションに関する詳細情報を取得できます。最も重要なものは次のとおりです。
-b
および-u
、ユーザー定義の間隔でTCP_INFO
抽出するために使用されます。詳細については、「 TCP_INFO
の抽出」セクションを参照してください。-c
、ソケットのpcap
トレースをキャプチャするために使用されます。詳細については、「パケット キャプチャ」セクションを参照してください。-a
と-k
Android アプリケーションをトレースするために使用されます。詳細については、「Android の使用法」セクションを参照してください。-n
トレースの自動アップロードを無効にします。-d
( /tmp
内のランダムなディレクトリの代わりに) トレースが書き込まれるディレクトリを設定します。-f
ファイルに保存されるログの詳細レベルを設定します。デフォルトでは、WARN メッセージと ERROR メッセージのみがログに書き込まれます。これは主にバグの報告やデバッグに役立ちます。-l
は-f
に似ていますが、STDOUT にログの詳細度を設定します。デフォルトではエラー メッセージのみが表示されます。これはデバッグの目的で使用されます。-t
イベントがファイルにダンプされる頻度を制御します。デフォルトでは、イベントは 1000 ミリ秒ごとにファイルに書き込まれます。-v
現時点ではほとんど役に立ちませんが、 strace
のスタイルでtcpsnitch
冗長モードにすることになっています。まだ実装予定です (現時点ではイベント名のみを表示します)。TCP_INFO
を抽出しています-b <bytes>
および-u <usec>
使用すると、ユーザー定義の間隔で各ソケットのTCP_INFO
ソケット オプションの値を抽出できます。 TCP_INFO
値は、ソケットの JSON トレース内の他のイベントとして表示されることに注意してください。
-b <bytes>
を指定すると、ソケット上で送受信された<bytes>
ごとにTCP_INFO
記録されます。-u <usec>
を指定すると、 TCP_INFO
<usec>
マイクロ秒ごとに記録されます。TCP_INFO
が記録されます。デフォルトでは、このオプションはオフになっています。また、 tcpsnitch
オーバーライドされた関数が呼び出されたときにのみこれらの条件をチェックすることにも注意してください。
-c
オプションは、各ソケットの.pcap
トレースのキャプチャをアクティブにします。インターフェイス上のトラフィックをキャプチャできるようにするには、適切な権限が必要であることに注意してください (そのような権限の詳細については、 man pcap
参照してください)。
この機能は現時点では Android では利用できません。
Android での使用は 2 段階のプロセスであり、Linux での使用と非常によく似ています。まず、 tcpsnitch
セットアップし、適切なオプションを使用してトレースするアプリケーションを起動します。その後、トレースがデバイスから取得され、ホスト マシンにコピーされます。
Android では、 .pcap
トレースをキャプチャするための-c
オプションを除くすべてのオプションがサポートされています。
デバイス上でいくつかの事前セットアップ手順を一度実行する必要があります。
adb devices
発行し、電話が表示されていることを確認します (2 列目にdevice
表示されるはずです)。デバイスがadb
経由でアクセスできる場合、使用方法は Linux の場合とほぼ同じです。
-a
を指定して通常のtcpsnitch
コマンドを発行します。 <cmd>
引数は、単純なgrep
を介してデバイスにインストールされたパッケージの名前と一致する必要があることに注意してください。たとえば、パッケージ名がorg.firefox.com
である Firefox アプリケーションをトレースするには、 tcpsnitch -a firefox
を発行します。 tcpsnitch
一致するパッケージが見つかったことを通知し、アプリケーションをすぐに開始します。tcpsnitch -k <package>
を発行してアプリケーションを強制終了し、トレース プロセスを終了します。トレースはデバイスから取得され、www.tcpsnitch.org にアップロードされる前にディスクの/tmp
に保存されます。重要:トレースを完全に無効にするには、Android デバイスを再起動する必要があります。 tcpsnitch
Android プロパティを使用してLD_PRELOAD
ライブラリをセットアップし、これらのプロパティを設定解除することはできないため、プロパティを削除するにはデバイスを再起動する必要があります (誰かがより良い解決策を知っているかもしれません)。
Firefox をトレースする完全な例を次に示します。
$ tcpsnitch -a firefox
Found Android package: ' org.mozilla.firefox ' .
Uploading tcpsnitch library to /data/libtcpsnitch.so.0.1-arm.
Start package ' org.mozilla.firefox ' .
Execute ' ./tcpsnitch -k firefox ' to terminate the capture.
# INTERACTING WITH APPLICATION
$ tcpsnitch -k firefox
Found Android package: ' org.mozilla.firefox ' .
Pulling trace from Android device....
Trace saved in /tmp/tmp.MidCH9rm3x.
Uploading trace....
Trace successfully uploaded at https://tcpsnitch.org/app_traces/21.
Trace archive will be imported shortly. Refresh this page in a few minutes...
パッケージに複数の一致がある場合は、最初に一致したパッケージが使用されることに注意してください。したがって、競合を避けるために、より具体的にする必要がある場合があります。 adb shell pm list packages
実行すると、デバイスにインストールされているすべてのパッケージの名前を取得できます。
また、単一のデバイスがadb
から認識できる必要があることにも注意してください。
Android アプリケーションをトレースするには、 tcpsnitch
Android Native Development Kit (NDK) でコンパイルする必要があります。コンパイルはより複雑で、セットアップには root 化された Android デバイスが必要です。
基本的に、これには次の手順が含まれます。
libjansson
とlibpcap
コンパイルし、コンパイルされたライブラリとヘッダー ファイルをスタンドアロン ツールチェーンで使用できるようにします。tcpsnitch
コンパイルし、Android デバイスを準備します。次のセクションでは、すべての手順を説明する複雑な例を示します。
いくつかの仮定:
<NDK_PATH>
に抽出しました。<TCPSNITCH_PATH>
にあります。まず、いくつかの変数を定義しましょう。
export TCPSNITCH=<TCPSNITCH_PATH>
export NDK=<NDK_PATH>
# Where the standalone toolchain WILL be created
export TOOLCHAIN=<TOOLCHAIN_PATH>
ここで、Android API 23 (バージョン 6.0、Marshmallow) を実行する ARM デバイス用のスタンドアロン ツールチェーンを生成することから始めましょう。 Android のバージョンと API レベルのマッピングは次のページにあります。
$NDK/build/tools/make_standalone_toolchain.py --arch arm --api 23 --install-dir $TOOLCHAIN
次に、NDK を使用してlibjansson
とlibpcap
両方をコンパイルする必要があります。これが完了したら、ヘッダー ファイルとコンパイルされたライブラリをスタンドアロン ツールチェーンの「sysroot」にインストールする必要があります。
libjansson
から始めましょう:
git clone https://github.com/akheron/jansson && cd jansson
# Configuration file which we don't use, we may leave it empty
touch src/jansson_private_config.h
sed -i 's/BUILD_SHARED_LIBRARY/BUILD_STATIC_LIBRARY/g' Android.mk
$NDK/ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk
cp obj/local/armeabi/libjansson.a $TOOLCHAIN/sysroot/usr/lib/
cp src/jansson.h android/jansson_config.h $TOOLCHAIN/sysroot/usr/include/
cd .. && rm -rf jansson
さて、 libpcap
に取り組んでみましょう。
git clone https://github.com/the-tcpdump-group/libpcap && cd libpcap
export CC=$TOOLCHAIN/bin/arm-linux-androideabi-gcc
./configure --host=arm-linux --with-pcap=linux --prefix=/usr
# You will need to install some missing dependencies (e.g. `flex` & `bison`)
sudo apt-get install flex bison
# Reissue ./configure untill all dependencies are met
./configure --host=arm-linux --with-pcap=linux --prefix=/usr
# Compile && install in toolchain
make && sudo make install DESTDIR=$TOOLCHAIN/sysroot
cd .. && rm -rf libpcap
これで、 tcpsnitch
コンパイルする準備が整いました。
# First, let's fix the buggy `tcp.h` header from the NDK
sed -i 's/include <linux/tcp.h>/include <sys/cdefs.h>n#include <linux/tcp.h>/g' $TOOLCHAIN/sysroot/usr/include/netinet/tcp.h
# Configure the compiler
export CC_ANDROID=$TOOLCHAIN/bin/arm-linux-androideabi-gcc
# Build & install tcpsnitch
make android && sudo make install
準備は完了です!アプリケーションのトレースを開始する方法については、「Android の使用法」セクションを参照してください。
Linux ダイナミック リンカー ( ld.so
) の興味深い機能は、プログラムの依存関係のリストで指定されたライブラリの前に、ユーザー指定の共有ライブラリをリンクできることです。この機能は、追加のユーザー指定ライブラリの (空の可能性がある) リストを含むLD_PRELOAD
環境変数で制御できます。特に、このLD_PRELOAD
変数は、ダイナミック リンカーにlibc
ライブラリの前にユーザー指定の共有ライブラリをリンクさせる可能性があります。その結果、このユーザー指定のライブラリで定義された関数は、 libc
で定義された同じシグネチャを持つ関数よりも優先されます。
ここでの意味は、システム コール ラッパー関数への呼び出しをインターセプトできるということです。これらのシステム コール ラッパー関数を再定義するカスタム共有ライブラリをLD_PRELOAD
に追加するだけです。このような shim ライブラリは、 libc
関数呼び出しを透過的にインターセプトし、元のlibc
ラッパー関数を呼び出す前にいくつかの処理を実行します。
wrong ELF class
エラーは何ですか?何も悪いことはありません。これらは無視して構いません。 tcpsnitch
共有ライブラリは、32 ビットと 64 ビットの両方のアーキテクチャ用にコンパイルされています。コマンドをトレースする場合、コマンド バイナリのアーキテクチャ (多くの場合、別のバイナリを実行するシェル スクリプト) を知る簡単な方法がないため、両方のライブラリがLD_PRELOAD
環境変数にロードされます。その後、ダイナミック リンカーは互換性のあるライブラリのロードを処理し、2 番目のライブラリは無視します (ただし、エラーはスローされます)。
https://gitter.im/Tcpsnitch でtcpsnitch
について話し合ってください。
著者のメールアドレスは gregory.vanderschueren[at]gmail.com です。