tcpsnitch
— это инструмент трассировки, предназначенный для исследования взаимодействия между приложением и стеком TCP/IP. tcpsnitch
запускает указанную команду до тех пор, пока она не завершится, и перехватит все вызовы функций libc в интернет-сокетах.
Чтобы начать осторожно, можно запустить следующую команду, чтобы отследить программу curl
:
$ tcpsnitch curl google.com
Для каждого открытого интернет-сокета tcpsnitch
создает упорядоченный список вызовов функций (в оставшейся части этого документа вызов функции называется событием ). Для каждого события tcpsnitch
записывает аргументы, возвращаемое значение и различную информацию, такую как текущая временная метка или идентификатор потока. В частности, событие 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
перехватывает вызовы функций libc с использованием переменной среды LD_PRELOAD
, трассировку невозможно выполнить для приложений, которые статически связаны с libc.
Примечание. Известно, что в Linux Chrome (и любые приложения на основе Chromium, такие как Electron, Opera и т. д.) НЕсовместимы.
Для пользователей, которые хотят отслеживать приложения 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
на данный момент совершенно бесполезен, но предполагается, что он переводит tcpsnitch
в подробный режим в стиле strace
. Еще предстоит реализовать (на данный момент отображаются только имена событий).TCP_INFO
-b <bytes>
и -u <usec>
позволяют извлекать значение параметра сокета TCP_INFO
для каждого сокета через заданные пользователем интервалы. Обратите внимание, что значения TCP_INFO
отображаются как любое другое событие в трассировке JSON сокета.
-b <bytes>
TCP_INFO
записывается каждые <bytes>
, отправленные и полученные в сокете.-u <usec>
TCP_INFO
записывается каждые <usec>
микросекунды.TCP_INFO
записывается при выполнении любого из двух условий. По умолчанию эта опция отключена. Также обратите внимание, что tcpsnitch
проверяет эти условия только при вызове переопределенной функции.
Опция -c
активирует запись трассировки .pcap
для каждого сокета. Обратите внимание, что вам необходимо иметь соответствующие разрешения, чтобы иметь возможность перехватывать трафик на интерфейсе (дополнительную информацию о таких разрешениях см. в man pcap
).
На данный момент эта функция недоступна для Android.
Использование на Android представляет собой двухэтапный процесс, очень похожий на использование в Linux. Сначала настройте tcpsnitch
и запустите отслеживаемое приложение с соответствующими параметрами, затем трассировки извлекаются с устройства и копируются на хост-компьютер.
В Android поддерживаются все параметры, кроме параметра -c
для захвата трассировок .pcap
.
На устройстве необходимо один раз выполнить несколько предварительных шагов по настройке:
adb devices
и убедитесь, что ваш телефон виден (во втором столбце вы должны увидеть device
). Когда устройство доступно через adb
, использование почти такое же, как и в Linux:
tcpsnitch
с опцией -a
, чтобы указать, что вы хотите отслеживать приложение на подключенном устройстве Android. Обратите внимание, что аргумент <cmd>
должен соответствовать имени пакета, установленного на устройстве с помощью простого grep
. Например, чтобы отследить приложение Firefox, имя пакета которого — org.firefox.com
, можно ввести команду tcpsnitch -a firefox
. tcpsnitch
сообщит вам о найденном соответствующем пакете и немедленно запустит приложение.tcpsnitch -k <package>
чтобы завершить работу приложения и завершить процесс трассировки. Следы будут извлечены из устройства и сохранены на вашем диске в /tmp
перед загрузкой на сайт www.tcpsnitch.org. Важно: вам необходимо перезагрузить ваше 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). Компиляция более сложна, и для установки требуется рутованное устройство Android.
По сути, это включает в себя следующие шаги:
libjansson
и libpcap
с помощью NDK и сделайте скомпилированные библиотеки и файлы заголовков доступными для автономной цепочки инструментов.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>
Теперь давайте начнем с создания автономной цепочки инструментов для устройства ARM под управлением Android API 23 (версия 6.0, Marshmallow). Сопоставление версий Android и уровней API на следующей странице.
$NDK/build/tools/make_standalone_toolchain.py --arch arm --api 23 --install-dir $TOOLCHAIN
Теперь нам нужно скомпилировать libjansson
и libpcap
с помощью NDK. Когда это будет сделано, мы должны установить их заголовочные файлы и скомпилированные библиотеки в «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
. Такая библиотека-оболочка затем прозрачно перехватывает вызовы функций libc
и выполняет некоторую обработку перед вызовом исходных функций-оболочек libc
.
wrong ELF class
? Ничего плохого, это можно игнорировать. Общая библиотека tcpsnitch
скомпилирована как для 32-битной, так и для 64-битной архитектуры. При трассировке команды обе библиотеки загружаются в переменную среды LD_PRELOAD
, поскольку не существует простого способа узнать архитектуру двоичного файла команды (часто это сценарий оболочки, выполняющий другой двоичный файл). Затем динамический компоновщик загружает совместимую библиотеку и игнорирует вторую (но все равно выдает ошибку).
Приходите обсудить tcpsnitch
на https://gitter.im/Tcpsnitch.
Электронная почта автора: gregory.vanderschueren[at]gmail.com.