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
와 유사하지만 기본적으로 ERROR 메시지만 표시하는 STDOUT에 대한 로그 상세 수준을 설정합니다. 이는 디버깅 목적으로 사용됩니다.-t
이벤트가 파일에 덤프되는 빈도를 제어합니다. 기본적으로 이벤트는 1000밀리초마다 파일에 기록됩니다.-v
현재로서는 별로 쓸모가 없지만 strace
스타일로 tcpsnitch
장황한 모드로 설정해야 합니다. 아직 구현 중입니다(현재는 이벤트 이름만 표시됩니다).TCP_INFO
추출 -b <bytes>
및 -u <usec>
사용하면 사용자 정의 간격으로 각 소켓에 대한 TCP_INFO
소켓 옵션 값을 추출할 수 있습니다. TCP_INFO
값은 socekt의 JSON 추적에서 다른 이벤트로 나타납니다.
-b <bytes>
를 사용하면 TCP_INFO
소켓에서 전송+수신된 <bytes>
마다 기록됩니다.-u <usec>
를 사용하면 TCP_INFO
<usec>
마이크로초마다 기록됩니다.TCP_INFO
기록됩니다. 기본적으로 이 옵션은 꺼져 있습니다. 또한 tcpsnitch
재정의된 함수가 호출될 때만 이러한 조건을 확인한다는 점에 유의하세요.
-c
옵션은 각 소켓에 대한 .pcap
추적 캡처를 활성화합니다. 인터페이스에서 트래픽을 캡처하려면 적절한 권한이 있어야 합니다(이러한 권한에 대한 자세한 내용은 man pcap
참조).
현재 Android에서는 이 기능을 사용할 수 없습니다.
Android에서의 사용법은 Linux에서의 사용법과 매우 유사한 2단계 프로세스입니다. 먼저 tcpsnitch
설정하고 적절한 옵션을 사용하여 추적할 애플리케이션을 시작한 다음 추적을 장치에서 가져와 호스트 시스템에 복사합니다.
.pcap
추적 캡처를 위한 -c
옵션을 제외한 모든 옵션은 Android에서 지원됩니다.
장치에서 몇 가지 예비 설정 단계를 한 번 수행해야 합니다.
adb devices
발행하고 전화기가 보이는지 확인하십시오(두 번째 열에 device
표시되어야 함). adb
통해 장치에 액세스할 수 있는 경우 사용법은 Linux와 거의 동일합니다.
-a
옵션과 함께 일반 tcpsnitch
명령을 실행하여 연결된 Android 장치에서 애플리케이션을 추적하려고 함을 나타냅니다. <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 NDK(Native Development Kit)로 컴파일해야 합니다. 컴파일이 더 복잡하며 설정에는 루팅된 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
환경 변수에 로드됩니다. 명령 바이너리의 아키텍처를 쉽게 알 수 있는 방법이 없기 때문입니다(종종 다른 바이너리를 실행하는 쉘 스크립트임). 그런 다음 동적 링커는 호환 가능한 라이브러리를 로드하고 두 번째 라이브러리를 무시합니다(그러나 여전히 오류가 발생합니다).
https://gitter.im/Tcpsnitch에서 tcpsnitch
에 대해 토론해 보세요.
작성자의 이메일은 gregory.vanderschueren[at]gmail.com입니다.