diff --git a/CMakeLists.txt b/CMakeLists.txt index 58ed434a49..b446bbde1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -763,6 +763,9 @@ endif() if(HAVE_LIBSBC) set(HAVE_SBC 1) endif() +if(EXTCAP_ANDROIDDUMP_LIBPCAP) + set(ANDROIDDUMP_USE_LIBPCAP 1) +endif() if (HAVE_LIBWINSPARKLE) set(HAVE_SOFTWARE_UPDATE 1) @@ -2083,6 +2086,39 @@ if (WIN32) endif() endif() +if(BUILD_androiddump) + if(EXTCAP_ANDROIDDUMP_LIBPCAP) + if(HAVE_LIBPCAP) + set(androiddump_LIBS + ${GLIB2_LIBRARIES} + ${PCAP_LIBRARIES} + ) + else() + message(FATAL_ERROR "You try to build androiddump with libpcap but do not have it") + endif() + else() + set(androiddump_LIBS + wiretap + ${GLIB2_LIBRARIES} + ${CMAKE_DL_LIBS} + ) + endif() + set(androiddump_FILES + ${GLIB2_LIBRARIES} + extcap/androiddump.c + ) + + set(COPY_CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/run/extcap) + add_executable(androiddump ${androiddump_FILES}) + add_dependencies(androiddump gitversion) + set_target_properties(androiddump PROPERTIES LINK_FLAGS "${WS_LINK_FLAGS}") + set_target_properties(androiddump PROPERTIES FOLDER "Executables/Extcaps") + target_link_libraries(androiddump ${androiddump_LIBS}) + install(TARGETS androiddump RUNTIME DESTINATION ${EXTCAP_DIR}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${COPY_CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_BINARY_DIR}/AUTHORS-SHORT COMMAND ${PERL_EXECUTABLE} diff --git a/CMakeOptions.txt b/CMakeOptions.txt index 03015d28ab..f986a39364 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -14,10 +14,12 @@ option(BUILD_capinfos "Build capinfos" ON) option(BUILD_captype "Build captype" ON) option(BUILD_randpkt "Build randpkt" ON) option(BUILD_dftest "Build dftest" ON) +option(BUILD_androiddump "Build androiddump" ON) option(AUTOGEN_dcerpc "Autogenerate DCE RPC dissectors" OFF) option(AUTOGEN_pidl "Autogenerate pidl dissectors" OFF) option(DISABLE_WERROR "Do not treat warnings as errors" OFF) +option(EXTCAP_ANDROIDDUMP_LIBPCAP "Build androiddump using libpcap" OFF) option(ENABLE_EXTRA_COMPILER_WARNINGS "Do additional compiler warnings (disables -Werror)" OFF) option(ENABLE_CODE_ANALYSIS "Enable the compiler's static analyzer if possible" OFF) option(ENABLE_ASAN "Enable AddressSanitizer (ASAN) for debugging (May be slow down)" OFF) diff --git a/Makefile.am b/Makefile.am index 12967ed90b..384a7697e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,10 +42,11 @@ bin_PROGRAMS = \ @dumpcap_bin@ \ @reordercap_bin@ \ @rawshark_bin@ \ + @androiddump_bin@ \ @echld_test_bin@ EXTRA_PROGRAMS = wireshark-gtk wireshark tshark tfshark capinfos captype editcap \ - mergecap dftest randpkt text2pcap dumpcap reordercap rawshark \ + mergecap dftest randpkt text2pcap dumpcap reordercap rawshark androiddump \ echld_test # @@ -532,6 +533,21 @@ rawshark_LDADD = \ rawshark_CFLAGS = $(AM_CLEAN_CFLAGS) +if ENABLE_STATIC +androiddump_LDFLAGS = -Wl,-static -all-static +else +androiddump_LDFLAGS = -export-dynamic +endif + +# Libraries and plugin flags with which to link androiddump. +androiddump_LDADD = \ + wiretap/libwiretap.la \ + wsutil/libwsutil.la \ + @GLIB_LIBS@ \ + @SOCKET_LIBS@ + +androiddump_CFLAGS = $(AM_CLEAN_CFLAGS) + # Libraries with which to link text2pcap. text2pcap_LDADD = \ wsutil/libwsutil.la \ diff --git a/Makefile.common b/Makefile.common index 8268e30d0f..88e648b34f 100644 --- a/Makefile.common +++ b/Makefile.common @@ -95,6 +95,10 @@ rawshark_SOURCES = \ $(SHARK_COMMON_SRC) \ rawshark.c +# androiddump specifics +androiddump_SOURCES = \ + extcap/androiddump.c + # text2pcap specifics text2pcap_SOURCES = \ pcapio.c \ diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in index b5d3cf990b..8b7e99e605 100644 --- a/cmakeconfig.h.in +++ b/cmakeconfig.h.in @@ -397,6 +397,9 @@ first (like Motorola and SPARC, unlike Intel and VAX). */ #cmakedefine WORDS_BIGENDIAN 1 +/* Build androiddump with libpcap instead of wireshark stuff */ +#cmakedefine ANDROIDDUMP_USE_LIBPCAP 1 + /* Large file support */ #cmakedefine _LARGEFILE_SOURCE #cmakedefine _LARGEFILE64_SOURCE diff --git a/configure.ac b/configure.ac index 085b663a52..1abc56ee46 100644 --- a/configure.ac +++ b/configure.ac @@ -2296,6 +2296,38 @@ fi AC_SUBST(rawshark_bin) AC_SUBST(rawshark_man) +dnl androiddump check +AC_MSG_CHECKING(whether to build androiddump) + +AC_ARG_ENABLE(androiddump, + AC_HELP_STRING( [--enable-androiddump], + [build androiddump @<:@default=yes@:>@]), + androiddump=$enableval,enable_androiddump=yes) + +if test "x$enable_androiddump" = "xyes" ; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AC_ARG_ENABLE(androiddump_use_libpcap, + AC_HELP_STRING( [--enable-androiddump-use-libpcap], + [build androiddump using libpcap @<:@default=no@:>@]), + androiddump_use_libpcap=$enableval,enable_androiddump_use_libpcap=no) + +if test "x$enable_androiddump_use_libpcap" = "xyes" ; then + AC_DEFINE(ANDROIDDUMP_USE_LIBPCAP, 1, [Androiddump will use Libpcap]) +fi + +if test "x$enable_androiddump" = "xyes" ; then + androiddump_bin="androiddump\$(EXEEXT)" + androiddump_man="" +else + androiddump_bin="" + androiddump_man="" +fi +AC_SUBST(androiddump_bin) +AC_SUBST(androiddump_man) # Enable/disable echld AC_ARG_ENABLE(echld, @@ -3343,6 +3375,7 @@ echo " Build text2pcap : $enable_text2pcap" echo " Build randpkt : $enable_randpkt" echo " Build dftest : $enable_dftest" echo " Build rawshark : $enable_rawshark" +echo " Build androiddump : $enable_androiddump" echo " Build echld : $have_echld" echo "" echo " Save files as pcap-ng by default : $enable_pcap_ng_default" diff --git a/extcap/androiddump.c b/extcap/androiddump.c new file mode 100644 index 0000000000..986823cb50 --- /dev/null +++ b/extcap/androiddump.c @@ -0,0 +1,2131 @@ +/* androiddump.c + * androiddump is extcap tool used to capture Android specific stuff + * + * Copyright 2015, Michal Labedzki for Tieto Corporation + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_UNISTD_H + #include +#endif + +#ifdef HAVE_GETOPT_H + #include +#endif + +#ifndef HAVE_GETOPT_LONG + #include "wsutil/wsgetopt.h" +#endif + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) + #ifdef HAVE_WINDOWS_H + #include + #endif + + #include + + #ifdef HAVE_WINSOCK2_H + #include + #endif +#endif +#if (defined(__linux__) || defined(__CYGWIN__)) + #include + + #define closesocket(socket) close(socket) +#endif + +/* Configuration options */ +/* #define ANDROIDDUMP_USE_LIBPCAP */ + + +#define EXTCAP_ENCAP_BLUETOOTH_H4_WITH_PHDR 1 +#define EXTCAP_ENCAP_WIRESHARK_UPPER_PDU 2 + + +#ifdef ANDROIDDUMP_USE_LIBPCAP + #include + #include + #include + + #ifndef DLT_BLUETOOTH_H4_WITH_PHDR + #define DLT_BLUETOOTH_H4_WITH_PHDR 201 + #endif + + #ifndef DLT_WIRESHARK_UPPER_PDU + #define DLT_WIRESHARK_UPPER_PDU 252 + #endif + + #ifndef PCAP_TSTAMP_PRECISION_MICRO + #define PCAP_TSTAMP_PRECISION_MICRO 0 + #endif + + #ifndef PCAP_TSTAMP_PRECISION_NANO + #define PCAP_TSTAMP_PRECISION_NANO 1 + #endif +#else + #include "wiretap/wtap.h" +#endif + +#define WIRESHARK_UPPER_PDU_TAG_DISSECTOR_NAME 0x000C + +#define INTERFACE_ANDROID_LOGCAT_MAIN "android-logcat-main" +#define INTERFACE_ANDROID_LOGCAT_SYSTEM "android-logcat-system" +#define INTERFACE_ANDROID_LOGCAT_RADIO "android-logcat-radio" +#define INTERFACE_ANDROID_LOGCAT_EVENTS "android-logcat-events" +#define INTERFACE_ANDROID_LOGCAT_TEXT_MAIN "android-logcat-text-main" +#define INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM "android-logcat-text-system" +#define INTERFACE_ANDROID_LOGCAT_TEXT_RADIO "android-logcat-text-radio" +#define INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS "android-logcat-text-events" +#define INTERFACE_ANDROID_LOGCAT_TEXT_CRASH "android-logcat-text-crash" +#define INTERFACE_ANDROID_BLUETOOTH_HCIDUMP "android-bluetooth-hcidump" +#define INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER "android-bluetooth-external-parser" +#define INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET "android-bluetooth-btsnoop-net" + +#define ANDROIDDUMP_VERSION_MAJOR 1 +#define ANDROIDDUMP_VERSION_MINOR 0 +#define ANDROIDDUMP_VERSION_RELEASE 0 + +#define PACKET_LENGTH 65535 + +enum { + OPT_HELP = 1, + OPT_VERSION, + OPT_LIST_INTERFACES, + OPT_LIST_DLTS, + OPT_INTERFACE, + OPT_CONFIG, + OPT_CAPTURE, + OPT_FIFO, + OPT_CONFIG_ADB_SERVER_IP, + OPT_CONFIG_ADB_SERVER_TCP_PORT, + OPT_CONFIG_LOGCAT_TEXT, + OPT_CONFIG_BT_SERVER_TCP_PORT, + OPT_CONFIG_BT_FORWARD_SOCKET, + OPT_CONFIG_BT_LOCAL_IP, + OPT_CONFIG_BT_LOCAL_TCP_PORT +}; + +static struct option longopts[] = { + { "help", no_argument, NULL, OPT_HELP}, + { "version", no_argument, NULL, OPT_VERSION}, + { "extcap-interfaces", no_argument, NULL, OPT_LIST_INTERFACES}, + { "extcap-dlts", no_argument, NULL, OPT_LIST_DLTS}, + { "extcap-interface", required_argument, NULL, OPT_INTERFACE}, + { "extcap-config", no_argument, NULL, OPT_CONFIG}, + { "capture", no_argument, NULL, OPT_CAPTURE}, + { "fifo", required_argument, NULL, OPT_FIFO}, + { "adb-server-ip", required_argument, NULL, OPT_CONFIG_ADB_SERVER_IP}, + { "adb-server-tcp-port", required_argument, NULL, OPT_CONFIG_ADB_SERVER_TCP_PORT}, + { "logcat-text", required_argument, NULL, OPT_CONFIG_LOGCAT_TEXT}, + { "bt-server-tcp-port", required_argument, NULL, OPT_CONFIG_BT_SERVER_TCP_PORT}, + { "bt-forward-socket", required_argument, NULL, OPT_CONFIG_BT_FORWARD_SOCKET}, + { "bt-local-ip", required_argument, NULL, OPT_CONFIG_BT_LOCAL_IP}, + { "bt-local-tcp-port", required_argument, NULL, OPT_CONFIG_BT_LOCAL_TCP_PORT}, + { 0, 0, 0, 0 } +}; + +struct interface_t { + const char *display_name; + const char *interface_name; + struct interface_t *next; +}; + +struct exported_pdu_header { + uint16_t tag; + uint16_t length; +/* unsigned char value[0]; */ +}; + + +typedef struct _own_pcap_bluetooth_h4_header { + uint32_t direction; +} own_pcap_bluetooth_h4_header; + + +/* This fix compilator warning like "warning: cast from 'char *' to 'uint32_t *' (aka 'unsigned int *') increases required alignment from 1 to 4 " */ +typedef union { + char *value_char; + uint8_t *value_u8; + uint16_t *value_u16; + uint32_t *value_u32; + uint64_t *value_u64; + int8_t *value_i8; + int16_t *value_i16; + int32_t *value_i32; + int64_t *value_i64; + own_pcap_bluetooth_h4_header *value_own_pcap_bluetooth_h4_header; +} data_aligned_t; + +#define SET_DATA(dest, type, src) \ + { \ + data_aligned_t data_aligned; \ + \ + data_aligned.value_char = src; \ + dest = data_aligned.type; \ + } + +struct extcap_dumper { + int encap; + union { +#ifdef ANDROIDDUMP_USE_LIBPCAP + pcap_dumper_t *pcap; +#else + wtap_dumper *wtap; +#endif + } dumper; +}; + +/* Globals */ +static int verbose = 0; +static int endless_loop = 1; + +/* Functions */ +static inline int is_specified_interface(char *interface, const char *interface_prefix) { + return !strncmp(interface, interface_prefix, strlen(interface_prefix)); +} + +static struct extcap_dumper extcap_dumper_open(char *fifo, int encap) { + struct extcap_dumper extcap_dumper; + int encap_ext; + +#ifdef ANDROIDDUMP_USE_LIBPCAP + pcap_t *pcap; + + if (encap == EXTCAP_ENCAP_BLUETOOTH_H4_WITH_PHDR) + encap_ext = DLT_BLUETOOTH_H4_WITH_PHDR; + else if (encap == EXTCAP_ENCAP_WIRESHARK_UPPER_PDU) + encap_ext = DLT_WIRESHARK_UPPER_PDU; + else { + fprintf(stderr, "Unknown encapsulation\n"); + exit(1); + } + + pcap = pcap_open_dead_with_tstamp_precision(encap_ext, PACKET_LENGTH, PCAP_TSTAMP_PRECISION_NANO); + extcap_dumper.dumper.pcap = pcap_dump_open(pcap, fifo); + extcap_dumper.encap = encap; + pcap_dump_flush(extcap_dumper.dumper.pcap); +#else + int err = 0; + + if (encap == EXTCAP_ENCAP_BLUETOOTH_H4_WITH_PHDR) + encap_ext = WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR; + else if (encap == EXTCAP_ENCAP_WIRESHARK_UPPER_PDU) + encap_ext = WTAP_ENCAP_WIRESHARK_UPPER_PDU; + else { + fprintf(stderr, "Unknown encapsulation\n"); + exit(1); + } + + extcap_dumper.dumper.wtap = wtap_dump_open(fifo, WTAP_FILE_TYPE_SUBTYPE_PCAP_NSEC, encap_ext, PACKET_LENGTH, FALSE, &err); + extcap_dumper.encap = encap; + wtap_dump_flush(extcap_dumper.dumper.wtap); +#endif + + return extcap_dumper; +} + +static void extcap_dumper_dump(struct extcap_dumper extcap_dumper, char *buffer, + ssize_t captured_length, ssize_t reported_length, + time_t seconds, long nanoseconds) { +#ifdef ANDROIDDUMP_USE_LIBPCAP + struct pcap_pkthdr pcap_header; + + pcap_header.caplen = (bpf_u_int32) captured_length; + pcap_header.len = (bpf_u_int32) reported_length; + pcap_header.ts.tv_sec = seconds; + pcap_header.ts.tv_usec = nanoseconds / 1000; + + pcap_dump((u_char *) extcap_dumper.dumper.pcap, &pcap_header, buffer); + pcap_dump_flush(extcap_dumper.dumper.pcap); +#else + int err = 0; + char *err_info; + struct wtap_pkthdr hdr; + + hdr.presence_flags = WTAP_HAS_TS; + hdr.caplen = (guint32) captured_length; + hdr.len = (guint32) reported_length; + + hdr.ts.secs = seconds; + hdr.ts.nsecs = (int) nanoseconds; + + hdr.opt_comment = 0; + hdr.opt_comment = NULL; + hdr.drop_count = 0; + hdr.pack_flags = 0; + hdr.rec_type = REC_TYPE_PACKET; + +/* NOTE: Try to handle pseudoheaders manually */ + if (extcap_dumper.encap == EXTCAP_ENCAP_BLUETOOTH_H4_WITH_PHDR) { + uint32_t *direction; + + SET_DATA(direction, value_u32, buffer) + + hdr.pseudo_header.bthci.sent = GINT32_FROM_BE(*direction) ? 0 : 1; + + hdr.len -= sizeof(own_pcap_bluetooth_h4_header); + hdr.caplen -= sizeof(own_pcap_bluetooth_h4_header); + + buffer += sizeof(own_pcap_bluetooth_h4_header); + hdr.pkt_encap = WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR; + } else { + hdr.pkt_encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU; + } + + wtap_dump(extcap_dumper.dumper.wtap, &hdr, (const guint8 *) buffer, &err, &err_info); + wtap_dump_flush(extcap_dumper.dumper.wtap); +#endif +} + + +static int adb_connect(const char *server_ip, unsigned short *server_tcp_port) { + int sock; + socklen_t length; + struct sockaddr_in server; + + server.sin_family = AF_INET; + server.sin_port = GINT16_TO_BE(*server_tcp_port); + server.sin_addr.s_addr = inet_addr(server_ip); + + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + fprintf(stderr, "ERROR: Cannot open system TCP socket: %s\n", strerror(errno)); + return -1; + } + + if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { + if (system("adb start-server") == -1) { + fprintf(stderr, "WARNING: Cannot execute system command to start adb: %s\n", strerror(errno)); + }; + + if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { + fprintf(stderr, "ERROR: Cannot connect to ADB: %s\n", strerror(errno)); + fprintf(stderr, "INFO: Please check that adb daemon is running.\n"); + return -2; + } + } + + if (verbose) { + struct sockaddr_in client; + + length = sizeof(client); + if (getsockname(sock, (struct sockaddr *) &client, &length)) { + fprintf(stderr, "ERROR getsockname: %s\n", strerror(errno)); + return -3; + } + + if (length != sizeof(client)) { + fprintf(stderr, "ERROR: incorrect length\n"); + return -4; + } + + fprintf(stderr, "VERBOSE: Client port %u\n", GINT16_FROM_BE(client.sin_port)); + } + + return sock; +} + + +static char *adb_send_and_receive(int sock, const char *adb_service, + char *buffer, int buffer_length, ssize_t *data_length) { + ssize_t used_buffer_length; + ssize_t length; + ssize_t result; + char status[4]; + + result = send(sock, adb_service, strlen(adb_service), 0); + if (result != (ssize_t) strlen(adb_service)) { + fprintf(stderr, "ERROR: Error while sending <%s> to ADB\n", adb_service); + if (data_length) + *data_length = 0; + return 0; + } + + used_buffer_length = 0; + while (used_buffer_length < 8) { + used_buffer_length += recv(sock, buffer + used_buffer_length, buffer_length - used_buffer_length, 0); + } + + memcpy(status, buffer, 4); + result = buffer[8]; + buffer[8] = '\0'; + length = (ssize_t) strtol(buffer + 4, NULL, 16); + buffer[8] = result; + + while (used_buffer_length < length + 8) { + used_buffer_length += recv(sock, buffer + used_buffer_length, buffer_length - used_buffer_length, 0); + } + + if (data_length) + *data_length = used_buffer_length - 8; + + if (memcmp(status, "OKAY", 4)) { + fprintf(stderr, "ERROR: Error while receiving by ADB for <%s>\n", adb_service); + if (data_length) + *data_length = 0; + return 0; + } + + return buffer + 8; +} + + +static char *adb_send_and_read(int sock, const char *adb_service, char *buffer, + int buffer_length, ssize_t *data_length) { + ssize_t used_buffer_length; + ssize_t result; + char status[4]; + + result = send(sock, adb_service, strlen(adb_service), 0); + if (result != (ssize_t) strlen(adb_service)) { + fprintf(stderr, "ERROR: Error while sending <%s> to ADB\n", adb_service); + if (data_length) + *data_length = 0; + return 0; + } + + used_buffer_length = 0; + while (used_buffer_length < 4) { + used_buffer_length += recv(sock, buffer + used_buffer_length, buffer_length - used_buffer_length, 0); + } + + memcpy(status, buffer, 4); + + while (result > 0) { + result= recv(sock, buffer + used_buffer_length, buffer_length - used_buffer_length, 0); + if (result > 0) + used_buffer_length += result; + } + + if (data_length) + *data_length = used_buffer_length - 4; + + if (memcmp(status, "OKAY", 4)) { + fprintf(stderr, "ERROR: Error while receiving by ADB for <%s>\n", adb_service); + if (data_length) + *data_length = 0; + return 0; + } + + return buffer + 4; +} + + +static int adb_send(int sock, const char *adb_service) { + char buffer[4]; + ssize_t used_buffer_length; + ssize_t result; + + result = send(sock, adb_service, strlen(adb_service), 0); + if (result != (ssize_t) strlen(adb_service)) { + fprintf(stderr, "ERROR: Error while sending <%s> to ADB\n", adb_service); + return 1; + } + + used_buffer_length = 0; + while (used_buffer_length < 4) { + used_buffer_length += recv(sock, buffer + used_buffer_length, sizeof(buffer) - used_buffer_length, 0); + } + + if (memcmp(buffer, "OKAY", 4)) { + fprintf(stderr, "ERROR: Error while receiving by ADB for <%s>\n", adb_service); + return 2; + } + + return 0; +} + + +static int add_android_interfaces(struct interface_t **interface_list, + const char *adb_server_ip, unsigned short *adb_server_tcp_port) +{ + static char packet[PACKET_LENGTH]; + static char helpful_packet[PACKET_LENGTH]; + char *response; + char *device_list; + ssize_t data_length; + ssize_t device_length; + int sock; + const char *adb_transport_serial_templace = "%04x""host:transport:%s"; + const char *adb_check_port_templace = "%04x""shell:cat /proc/%s/net/tcp"; + const char *adb_devices = "000C""host:devices"; + const char *adb_api_level = "0022""shell:getprop ro.build.version.sdk"; + const char *adb_hcidump_version = "0017""shell:hcidump --version"; + const char *adb_ps_droid_bluetooth = "0018""shell:ps droid.bluetooth"; + char *serial_number; + int result; + char *interface_name; + char *pos; + char *prev_pos; + struct interface_t *i_interface_list; + int api_level; + int disable_interface; + +/* NOTE: It seems that "adb devices" and "adb shell" closed connection + so cannot send next command after them, there is need to reconnect */ + + i_interface_list = *interface_list; + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + device_list = adb_send_and_receive(sock, adb_devices, packet, sizeof(packet), &device_length); + closesocket(sock); + + device_list[device_length] = '\0'; + pos = (char *) device_list; + + while (pos < (char *) (device_list + device_length)) { + prev_pos = pos; + pos = strchr(pos, '\t'); + result = (int) (pos - prev_pos); + serial_number = (char *) malloc(result + 1); + memcpy(serial_number, prev_pos, result); + serial_number[result] = '\0'; + pos = strchr(pos, '\n') + 1; + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + response = adb_send_and_read(sock, adb_api_level, helpful_packet, sizeof(helpful_packet), &data_length); + closesocket(sock); + response[data_length] = '\0'; + api_level = (int) strtol(response, NULL, 10); + fprintf(stderr, "VERBOSE: Android API Level for %s is %u\n", serial_number, api_level); + + if (api_level < 21) { + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_MAIN) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_MAIN); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + if (*interface_list == NULL) { + i_interface_list = (struct interface_t *) malloc(sizeof(struct interface_t)); + *interface_list = i_interface_list; + } else { + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + } + i_interface_list->display_name = "Android Logcat Main"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + + + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_SYSTEM) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_SYSTEM); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Logcat System"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_RADIO) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_RADIO); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Logcat Radio"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_EVENTS) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_EVENTS); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Logcat Events"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + } else { + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_TEXT_MAIN) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_TEXT_MAIN); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + if (*interface_list == NULL) { + i_interface_list = (struct interface_t *) malloc(sizeof(struct interface_t)); + *interface_list = i_interface_list; + } else { + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + } + i_interface_list->display_name = "Android Logcat Main"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + + + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Logcat System"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_TEXT_RADIO) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_TEXT_RADIO); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Logcat Radio"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Logcat Events"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_LOGCAT_TEXT_CRASH) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_LOGCAT_TEXT_CRASH); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Logcat Crash"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + } + + if (api_level >= 5 && api_level < 17) { + disable_interface = 0; + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + response = adb_send_and_read(sock, adb_hcidump_version, helpful_packet, sizeof(helpful_packet), &data_length); + closesocket(sock); + if (!response || data_length < 1) { + fprintf(stderr, "WARNING: Error while getting hcidump version by <%s> (%p len=%"G_GSSIZE_FORMAT")\n", adb_hcidump_version, response, data_length); + fprintf(stderr, "VERBOSE: Android hcidump version for %s is unknown\n", serial_number); + disable_interface = 1; + } else { + response[data_length] = '\0'; + + if (strtoul(response, NULL, 10) == 0) { + fprintf(stderr, "VERBOSE: Android hcidump version for %s is unknown\n", serial_number); + disable_interface = 1; + } else { + fprintf(stderr, "VERBOSE: Android hcidump version for %s is %s\n", serial_number, response); + } + } + + if (!disable_interface) { + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_BLUETOOTH_HCIDUMP) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_BLUETOOTH_HCIDUMP); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Bluetooth Hcidump"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + } + } + + if (api_level >= 17 && api_level < 21) { + disable_interface = 0; + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + + response = adb_send_and_read(sock, adb_ps_droid_bluetooth, helpful_packet, sizeof(helpful_packet), &data_length); + closesocket(sock); + if (!response || data_length < 1) { + fprintf(stderr, "WARNING: Error while getting Bluetooth application process id by <%s> (%p len=%"G_GSSIZE_FORMAT")\n", adb_hcidump_version, response, data_length); + fprintf(stderr, "VERBOSE: Android Bluetooth application PID for %s is unknown\n", serial_number); + disable_interface = 1; + } else { + char *data_str; + char pid[16]; + + response[data_length] = '\0'; + + data_str = strchr(response, '\n'); + if (data_str && sscanf(data_str, "%*s %s", pid) == 1) { + fprintf(stderr, "VERBOSE: Android Bluetooth application PID for %s is %s\n", serial_number, pid); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + sprintf((char *) helpful_packet, adb_check_port_templace, strlen(adb_check_port_templace) - 6 + strlen(pid), pid); + response = adb_send_and_read(sock, helpful_packet, helpful_packet, sizeof(helpful_packet), &data_length); + response[data_length] = '\0'; + closesocket(sock); + + data_str = strchr(response, '\n'); + if (data_str && sscanf(data_str, "%*s %s", pid) == 1 && strcmp(pid + 9, "10EA") == 0) { + fprintf(stderr, "VERBOSE: Bluedroid External Parser Port for %s is %s\n", serial_number, pid + 9); + } else { + disable_interface = 1; + fprintf(stderr, "VERBOSE: Bluedroid External Parser Port for %s is unknown\n", serial_number); + } + } else { + disable_interface = 1; + fprintf(stderr, "VERBOSE: Android Bluetooth application PID for %s is unknown\n", serial_number); + } + } + + if (!disable_interface) { + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Bluetooth External Parser"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + } + } + + if (api_level >= 21) { + disable_interface = 0; + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + + response = adb_send_and_read(sock, adb_ps_droid_bluetooth, helpful_packet, sizeof(helpful_packet), &data_length); + closesocket(sock); + if (!response || data_length < 1) { + fprintf(stderr, "WARNING: Error while getting Bluetooth application process id by <%s> (%p len=%"G_GSSIZE_FORMAT")\n", adb_hcidump_version, response, data_length); + fprintf(stderr, "VERBOSE: Android Bluetooth application PID for %s is unknown\n", serial_number); + disable_interface = 1; + } else { + char *data_str; + char pid[16]; + + response[data_length] = '\0'; + + data_str = strchr(response, '\n'); + if (data_str && sscanf(data_str, "%*s %s", pid) == 1) { + fprintf(stderr, "VERBOSE: Android Bluetooth application PID for %s is %s\n", serial_number, pid); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + sprintf((char *) helpful_packet, adb_check_port_templace, strlen(adb_check_port_templace) - 6 + strlen(pid), pid); + response = adb_send_and_read(sock, helpful_packet, helpful_packet, sizeof(helpful_packet), &data_length); + response[data_length] = '\0'; + closesocket(sock); + + data_str = strchr(response, '\n'); + if (data_str && sscanf(data_str, "%*s %s", pid) == 1 && strcmp(pid + 9, "22A8") == 0) { + fprintf(stderr, "VERBOSE: Btsnoop Net Port for %s is %s\n", serial_number, pid + 9); + } else { + disable_interface = 1; + fprintf(stderr, "VERBOSE: Btsnoop Net Port for %s is unknown\n", serial_number); + } + } else { + disable_interface = 1; + fprintf(stderr, "VERBOSE: Android Bluetooth application PID for %s is unknown\n", serial_number); + } + } + + if (!disable_interface) { + interface_name = (char *) malloc(strlen(INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET) + 1 + strlen(serial_number) + 1); + interface_name[0]= '\0'; + strcat(interface_name, INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET); + strcat(interface_name, "-"); + strcat(interface_name, serial_number); + i_interface_list->next = (struct interface_t *) malloc(sizeof(struct interface_t)); + i_interface_list = i_interface_list->next; + i_interface_list->display_name = "Android Bluetooth Btsnoop Net"; + i_interface_list->interface_name = interface_name; + i_interface_list->next = NULL; + } + } + } + + return 0; +} + + +static int list_interfaces(const char *server_ip, unsigned short *server_tcp_port) { + struct interface_t *interface_list = NULL; + struct interface_t *i_interface; + int result; + + result = add_android_interfaces(&interface_list, server_ip, server_tcp_port); + + for (i_interface = interface_list; i_interface; i_interface = i_interface->next) + printf("interface {display=%s}{value=%s}\n", + i_interface->display_name, + i_interface->interface_name); + + return result; +} + + +static int list_dlts(char *interface) { + if (!interface) { + fprintf(stderr, "ERROR: No interface specified.\n"); + return 1; + } + + if (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_HCIDUMP) || + is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER) || + is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET)) { + printf("dlt {number=99}{name=BluetoothH4}{display=Bluetooth HCI UART transport layer plus pseudo-header}\n"); + return 0; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_MAIN) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_RADIO) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_CRASH)) { + printf("dlt {number=252}{name=Upper PDU}{display=Upper PDU}\n"); + return 0; + } + + fprintf(stderr, "ERROR: Invalid interface: <%s>\n", interface); + return 1; +} + + +static int list_config(char *interface) { + if (!interface) { + fprintf(stderr, "ERROR: No interface specified.\n"); + return 1; + } + + if (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER)) { + printf("arg {number=0}{call=--adb-server-ip}{display=ADB Server IP Address}{type=string}{default=127.0.0.1}\n" + "arg {number=1}{call=--adb-server-tcp-port}{display=ADB Server TCP Port}{type=integer}{range=0,65535}{default=5037}\n" + "arg {number=2}{call=--bt-server-tcp-port}{display=Bluetooth Server TCP Port}{type=integer}{range=0,65535}{default=4330}\n" + "arg {number=3}{call=--bt-forward-socket}{display=Forward Bluetooth Socket}{type=boolean}{default=false}\n" + "arg {number=4}{call=--bt-local-ip}{display=Bluetooth Local IP Address}{type=string}{default=127.0.0.1}\n" + "arg {number=5}{call=--bt-local-tcp-port}{display=Bluetooth Local TCP Port}{type=integer}{range=0,65535}{default=4330}{tooltip=Used to do \"adb forward tcp:LOCAL_TCP_PORT tcp:SERVER_TCP_PORT\"}\n"); + return 0; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_HCIDUMP) || + is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET)) { + printf("arg {number=0}{call=--adb-server-ip}{display=ADB Server IP Address}{type=string}{default=127.0.0.1}\n" + "arg {number=1}{call=--adb-server-tcp-port}{display=ADB Server TCP Port}{type=integer}{range=0,65535}{default=5037}\n"); + return 0; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS)) { + printf("arg {number=0}{call=--adb-server-ip}{display=ADB Server IP Address}{type=string}{default=127.0.0.1}\n" + "arg {number=1}{call=--adb-server-tcp-port}{display=ADB Server TCP Port}{type=integer}{range=0,65535}{default=5037}\n" + "arg {number=2}{call=--logcat-text}{display=Use text logcat}{type=boolean}{default=false}\n"); + return 0; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_MAIN) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_RADIO) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_CRASH)) { + printf("arg {number=0}{call=--adb-server-ip}{display=ADB Server IP Address}{type=string}{default=127.0.0.1}\n" + "arg {number=1}{call=--adb-server-tcp-port}{display=ADB Server TCP Port}{type=integer}{range=0,65535}{default=5037}\n"); + return 0; + } + + fprintf(stderr, "ERROR: Invalid interface: <%s>\n", interface); + return 1; +} + + +static void help(void) { + unsigned int i_opt; + + printf("Help\n"); + printf(" Usage:\n" + " androiddump --extcap-interfaces [--server-ip=] [--server-tcp-port=]\n" + " androiddump --extcap-interface=INTERFACE --extcap-dlts\n" + " androiddump --extcap-interface=INTERFACE --extcap-config\n" + " androiddump --extcap-interface=INTERFACE --fifo=PATH_FILENAME --capture \n"); + + printf("\n Parameters:\n"); + for (i_opt = 0; i_opt < (sizeof(longopts) / sizeof(longopts[0])) - 1; i_opt += 1) { + printf(" --%s%s\n", longopts[i_opt].name, + (longopts[i_opt].has_arg == required_argument) ? "=" : + ((longopts[i_opt].has_arg == optional_argument) ? "[=arg]" : "")); + } + +} + + +/*----------------------------------------------------------------------------*/ +/* Android Bluetooth Hcidump */ +/*----------------------------------------------------------------------------*/ + +static int capture_android_bluetooth_hcidump(char *interface, char *fifo, + const char *adb_server_ip, unsigned short *adb_server_tcp_port) { + struct extcap_dumper extcap_dumper; + static char data[PACKET_LENGTH]; + static char packet[PACKET_LENGTH]; + static char helpful_packet[PACKET_LENGTH]; + ssize_t length; + ssize_t used_buffer_length = 0; + int sock; + const char *adb_transport = "0012""host:transport-any"; + const char *adb_transport_serial_templace = "%04x""host:transport:%s"; + const char *adb_shell_hcidump = "0013""shell:hcidump -R -t"; + const char *adb_shell_su_hcidump = "0019""shell:su -c hcidump -R -t"; + int result; + char *serial_number = NULL; + time_t ts = 0; + unsigned int captured_length; + long hex; + char *hex_data; + char *new_hex_data; + own_pcap_bluetooth_h4_header *h4_header; + long raw_length = 0; + long frame_length; + int ms = 0; + struct tm date; + char direction_character; + int try_next = 0; + + SET_DATA(h4_header, value_own_pcap_bluetooth_h4_header, packet); + + extcap_dumper = extcap_dumper_open(fifo, EXTCAP_ENCAP_BLUETOOTH_H4_WITH_PHDR); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + if (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_HCIDUMP) && + strlen(interface) > strlen(INTERFACE_ANDROID_BLUETOOTH_HCIDUMP) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_BLUETOOTH_HCIDUMP) + 1; + } + + if (!serial_number) { + result = adb_send(sock, adb_transport); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", adb_transport); + return 1; + } + } else { + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + } + + closesocket(sock); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + result = adb_send(sock, adb_shell_hcidump); + if (result) { + fprintf(stderr, "ERROR: Error while starting capture by sending command: %s\n", adb_shell_hcidump); + return 1; + } + + while (endless_loop) { + char *i_position; + + errno = 0; + length = recv(sock, data + used_buffer_length, PACKET_LENGTH - used_buffer_length, 0); + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + else if (errno != 0) { + printf("ERROR capture: %s\n", strerror(errno)); + return 100; + } + + used_buffer_length += length; + i_position = (char *) memchr(data, '\n', used_buffer_length); + if (i_position && i_position < data + used_buffer_length) { + char *state_line_position = i_position + 1; + + if (!strncmp(data, "/system/bin/sh: hcidump: not found", 34)) { + fprintf(stderr, "ERROR: Command not found for <%s>\n", adb_shell_hcidump); + return 2; + } + + i_position = (char *) memchr(i_position + 1, '\n', used_buffer_length); + if (i_position) { + i_position += 1; + if (!strncmp(state_line_position, "Can't access device: Permission denied", 38)) { + fprintf(stderr, "WARNING: No permission for command <%s>\n", adb_shell_hcidump); + used_buffer_length = 0; + try_next += 1; + break; + } + memmove(data, i_position, used_buffer_length - (i_position - data)); + used_buffer_length = used_buffer_length - (i_position - data); + break; + } + } + } + + if (try_next == 1) { + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + sprintf((char *) helpful_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helpful_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helpful_packet); + return 1; + } + + result = adb_send(sock, adb_shell_su_hcidump); + if (result) { + fprintf(stderr, "ERROR: Error while starting capture by sending command: <%s>\n", adb_shell_su_hcidump); + return 1; + } + + used_buffer_length = 0; + while (endless_loop) { + char *i_position; + + errno = 0; + length = recv(sock, data + used_buffer_length, PACKET_LENGTH - used_buffer_length, 0); + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + else if (errno != 0) { + printf("ERROR capture: %s\n", strerror(errno)); + return 100; + } + + used_buffer_length += length; + i_position = (char *) memchr(data, '\n', used_buffer_length); + if (i_position && i_position < data + used_buffer_length) { + if (!strncmp(data, "/system/bin/sh: su: not found", 29)) { + fprintf(stderr, "ERROR: Command 'su' not found for <%s>\n", adb_shell_su_hcidump); + return 2; + } + + i_position = (char *) memchr(i_position + 1, '\n', used_buffer_length); + if (i_position) { + i_position += 1; + memmove(data, i_position, used_buffer_length - (i_position - data)); + used_buffer_length = used_buffer_length - (i_position - data); + break; + } + } + } + } + + while (endless_loop) { + errno = 0; + length = recv(sock, data + used_buffer_length, PACKET_LENGTH - used_buffer_length, 0); + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + else if (errno != 0) { + printf("ERROR capture: %s\n", strerror(errno)); + return 100; + } + + while (endless_loop) { + if (used_buffer_length + length >= 1) { + hex_data = data + 29; + hex = strtol(hex_data, &new_hex_data, 16); + + if ((hex == 0x01 && used_buffer_length + length >= 4) || + (hex == 0x02 && used_buffer_length + length >= 5) || + (hex == 0x04 && used_buffer_length + length >= 3)) { + + if (hex == 0x01) { + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + raw_length = hex + 4; + } else if (hex == 0x04) { + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + raw_length = hex +3; + } else if (hex == 0x02) { + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + raw_length = hex + 5; + + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + raw_length += hex << 8; + } + + } else { + fprintf(stderr, "ERROR: bad raw stream\n"); + exit(1); + } + } else { + used_buffer_length += length; + length = 0; + break; + } + + frame_length = raw_length * 3 + (raw_length / 20) * 4 + ((raw_length % 20) ? 2 : -2) + 29; + + if (used_buffer_length + length < frame_length) { + used_buffer_length += length; + length = 0; + break; + } + + if (8 == sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d.%06d %c", + &date.tm_year, &date.tm_mon, &date.tm_mday, &date.tm_hour, + &date.tm_min, &date.tm_sec, &ms, &direction_character)) { + + if (verbose) { + fprintf(stderr, "time %04d-%02d-%02d %02d:%02d:%02d.%06d %c\n", + date.tm_year, date.tm_mon, date.tm_mday, date.tm_hour, + date.tm_min, date.tm_sec, ms, direction_character); + } + date.tm_mon -= 1; + date.tm_year -= 1900; + ts = mktime(&date); + + hex_data = new_hex_data = data + 29; + } + + captured_length = 0; + + while ((long)(new_hex_data - data + sizeof(own_pcap_bluetooth_h4_header)) < frame_length) { + hex_data = new_hex_data; + hex = strtol(hex_data, &new_hex_data, 16); + + packet[sizeof(own_pcap_bluetooth_h4_header) + captured_length] = (char) hex; + captured_length += 1; + } + + h4_header->direction = GINT32_TO_BE(direction_character == '>'); + + extcap_dumper_dump(extcap_dumper, packet, + captured_length + sizeof(own_pcap_bluetooth_h4_header), + captured_length + sizeof(own_pcap_bluetooth_h4_header), + ts, + ms * 1000); + + if (used_buffer_length + length >= frame_length) { + memmove(data, data + frame_length, used_buffer_length + length - frame_length); + used_buffer_length = used_buffer_length + length - frame_length; + length = 0; + continue; + } + length = 0; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Android Bluetooth External Parser */ +/*----------------------------------------------------------------------------*/ + +#define BLUEDROID_H4_PACKET_TYPE 0 +#define BLUEDROID_TIMESTAMP_SIZE 8 +#define BLUEDROID_H4_SIZE 1 + +static const uint64_t BLUEDROID_TIMESTAMP_BASE = 0x00dcddb30f2f8000UL; + +#define BLUEDROID_H4_PACKET_TYPE_HCI_CMD 0x01 +#define BLUEDROID_H4_PACKET_TYPE_ACL 0x02 +#define BLUEDROID_H4_PACKET_TYPE_SCO 0x03 +#define BLUEDROID_H4_PACKET_TYPE_HCI_EVT 0x04 + +#define BLUEDROID_DIRECTION_SENT 0 +#define BLUEDROID_DIRECTION_RECV 1 + +static int adb_forward(char *serial_number, const char *adb_server_ip, unsigned short *adb_server_tcp_port, + unsigned short local_tcp_port, unsigned short server_tcp_port) { + int sock; + int result; + static char helpful_packet[PACKET_LENGTH]; + static const char *adb_forward_template = "%04x""%s%s:forward:tcp:%05u;tcp:%05u"; + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + g_snprintf(helpful_packet, PACKET_LENGTH, adb_forward_template, (serial_number) ? 5 + 7 + strlen(serial_number) + 28 : 4 + 28, (serial_number) ? "host-serial:" : "host", (serial_number) ? serial_number: "", local_tcp_port, server_tcp_port); + result = adb_send(sock, helpful_packet); + closesocket(sock); + + return result; +} + +static int capture_android_bluetooth_external_parser(char *interface, + char *fifo, const char *adb_server_ip, unsigned short *adb_server_tcp_port, + unsigned short *bt_server_tcp_port, unsigned int bt_forward_socket, const char *bt_local_ip, + unsigned short *bt_local_tcp_port) { + struct extcap_dumper extcap_dumper; + char buffer[PACKET_LENGTH]; + uint64_t *timestamp; + char *packet = buffer + BLUEDROID_TIMESTAMP_SIZE - sizeof(own_pcap_bluetooth_h4_header); /* skip timestamp (8 bytes) and reuse its space for header */ + own_pcap_bluetooth_h4_header *h4_header; + char *payload = packet + sizeof(own_pcap_bluetooth_h4_header); + const char *adb_transport = "0012""host:transport-any"; + const char *adb_transport_serial_templace = "%04x""host:transport:%s"; + const char *adb_tcp_bluedroid_external_parser_template = "%04x""tcp:%05u"; + ssize_t length; + ssize_t used_buffer_length = 0; + uint64_t ts; + int sock; + struct sockaddr_in server; + int captured_length; + char *serial_number = NULL; + + SET_DATA(timestamp, value_u64, buffer); + SET_DATA(h4_header, value_own_pcap_bluetooth_h4_header, packet); + + extcap_dumper = extcap_dumper_open(fifo, EXTCAP_ENCAP_BLUETOOTH_H4_WITH_PHDR); + + if (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER) && + strlen(interface) > strlen(INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER) + 1; + } + + if (bt_forward_socket) { + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + printf("ERROR: Cannot open system TCP socket: %s\n", strerror(errno)); + return 1; + } + + if (verbose) { + printf("Using config: Server TCP Port=%u, Local IP=%s, Local TCP Port=%u\n", + *bt_server_tcp_port, bt_local_ip, *bt_local_tcp_port); + } + + if (*bt_local_tcp_port != 0) { + int result; + + result = adb_forward(serial_number, adb_server_ip, adb_server_tcp_port, *bt_local_tcp_port, *bt_server_tcp_port); + printf("DO: adb forward tcp:%u (local) tcp:%u (remote) result=%i\n", + *bt_local_tcp_port, *bt_server_tcp_port, result); + } + + server.sin_family = AF_INET; + server.sin_port = GINT16_TO_BE(*bt_local_tcp_port); + server.sin_addr.s_addr = inet_addr(bt_local_ip); + + if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { + printf("ERROR: %s\n", strerror(errno)); + printf("INFO: Please check that adb daemon is running.\n"); + return 2; + } + + if (verbose) { + struct sockaddr_in client; + + length = sizeof(client); + if (getsockname(sock, (struct sockaddr *) &client, (socklen_t *) &length)) { + printf("ERROR getsockname: %s\n", strerror(errno)); + return 3; + } + + if (length != sizeof(client)) { + printf("ERROR: incorrect length\n"); + return 4; + } + + printf("VERBOSE: Client port %u\n", GINT16_FROM_BE(client.sin_port)); + } + } else { + int result; + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + if (!serial_number) { + result = adb_send(sock, adb_transport); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport\n"); + return 1; + } + } else { + g_snprintf((char *) buffer, PACKET_LENGTH, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, buffer); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport\n"); + return 1; + } + } + + sprintf((char *) buffer, adb_tcp_bluedroid_external_parser_template, 4 + 5, *bt_server_tcp_port); + result = adb_send(sock, buffer); + if (result) { + fprintf(stderr, "ERROR: Error while forwarding adb port\n"); + return 1; + } + } + + while (endless_loop) { + errno = 0; + length = recv(sock, buffer + used_buffer_length, PACKET_LENGTH - used_buffer_length, 0); + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + else if (errno != 0) { + printf("ERROR capture: %s\n", strerror(errno)); + return 100; + } + + if (length <= 0) { + if (bt_forward_socket) { + /* NOTE: Workaround... It seems that Bluedroid is slower and we can connect to socket that are not really ready... */ + printf("WARNING: Broken socket connection. Try reconnect.\n"); + closesocket(sock); + + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + printf("ERROR1: %s\n", strerror(errno)); + return 1; + } + + server.sin_family = AF_INET; + server.sin_port = GINT16_TO_BE(*bt_local_tcp_port); + server.sin_addr.s_addr = inet_addr(bt_local_ip); + + if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { + printf("ERROR reconnect: %s\n", strerror(errno)); + printf("INFO: Please check that adb daemon is running.\n"); + return 2; + } + } else { + printf("ERROR: Broken socket connection.\n"); + return 1; + } + + continue; + } + + used_buffer_length += length; + + if (verbose) printf("Received: length=%"G_GSSIZE_FORMAT"\n", length); + + while (((payload[BLUEDROID_H4_PACKET_TYPE] == BLUEDROID_H4_PACKET_TYPE_HCI_CMD || payload[BLUEDROID_H4_PACKET_TYPE] == BLUEDROID_H4_PACKET_TYPE_SCO) && + used_buffer_length >= BLUEDROID_TIMESTAMP_SIZE + BLUEDROID_H4_SIZE + 2 + 1 && + BLUEDROID_TIMESTAMP_SIZE + BLUEDROID_H4_SIZE + 2 + payload[BLUEDROID_H4_SIZE + 2] + 1 <= used_buffer_length) || + (payload[BLUEDROID_H4_PACKET_TYPE] == BLUEDROID_H4_PACKET_TYPE_ACL && + used_buffer_length >= BLUEDROID_TIMESTAMP_SIZE + BLUEDROID_H4_SIZE + 2 + 2 && + BLUEDROID_TIMESTAMP_SIZE + BLUEDROID_H4_SIZE + 2 + payload[BLUEDROID_H4_SIZE + 2] + (payload[BLUEDROID_H4_SIZE + 2 + 1] << 8) + 2 <= used_buffer_length) || + (payload[BLUEDROID_H4_PACKET_TYPE] == BLUEDROID_H4_PACKET_TYPE_HCI_EVT && + used_buffer_length >= BLUEDROID_TIMESTAMP_SIZE + BLUEDROID_H4_SIZE + 1 + 1 && + BLUEDROID_TIMESTAMP_SIZE + BLUEDROID_H4_SIZE + 1 + payload[BLUEDROID_H4_SIZE + 1] + 1 <= used_buffer_length)) { + + ts = GINT64_FROM_BE(*timestamp); + + switch (payload[BLUEDROID_H4_PACKET_TYPE]) { + case BLUEDROID_H4_PACKET_TYPE_HCI_CMD: + h4_header->direction = GINT32_TO_BE(BLUEDROID_DIRECTION_SENT); + + captured_length = sizeof(own_pcap_bluetooth_h4_header) + payload[3] + 4; + + length = sizeof(own_pcap_bluetooth_h4_header) + BLUEDROID_H4_SIZE + 2 + 1 + payload[3]; + + break; + case BLUEDROID_H4_PACKET_TYPE_ACL: + h4_header->direction = (payload[2] & 0x80) ? GINT32_TO_BE(BLUEDROID_DIRECTION_RECV) : GINT32_TO_BE(BLUEDROID_DIRECTION_SENT); + + captured_length = sizeof(own_pcap_bluetooth_h4_header) + payload[3] + (payload[3 + 1] << 8) + 5; + + length = sizeof(own_pcap_bluetooth_h4_header) + BLUEDROID_H4_SIZE + 2 + 2 + payload[3] + (payload[3 + 1] << 8); + + break; + case BLUEDROID_H4_PACKET_TYPE_SCO: + h4_header->direction = (payload[2] & 0x80) ? GINT32_TO_BE(BLUEDROID_DIRECTION_RECV) : GINT32_TO_BE(BLUEDROID_DIRECTION_SENT); + + captured_length = sizeof(own_pcap_bluetooth_h4_header) + payload[3] + 4; + + length = sizeof(own_pcap_bluetooth_h4_header) + BLUEDROID_H4_SIZE + 2 + 1 + payload[3]; + + break; + case BLUEDROID_H4_PACKET_TYPE_HCI_EVT: + h4_header->direction = GINT32_TO_BE(BLUEDROID_DIRECTION_RECV); + + captured_length = sizeof(own_pcap_bluetooth_h4_header) + payload[2] + 3; + + length = sizeof(own_pcap_bluetooth_h4_header) + BLUEDROID_H4_SIZE + 1 + 1 + payload[2]; + + break; + default: + printf("ERROR: Invalid stream\n"); + return 1; + } + + ts -= BLUEDROID_TIMESTAMP_BASE; + + extcap_dumper_dump(extcap_dumper, packet, + captured_length, + captured_length, + (uint32_t)(ts / 1000000), + ((uint32_t)(ts % 1000000)) * 1000); + + used_buffer_length -= length - sizeof(own_pcap_bluetooth_h4_header) + BLUEDROID_TIMESTAMP_SIZE; + if (used_buffer_length < 0) { + printf("ERROR: Internal error: Negative used buffer length.\n"); + return 1; + } + memmove(buffer, packet + length, used_buffer_length); + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Android Btsnoop Net */ +/*----------------------------------------------------------------------------*/ + +static int capture_android_bluetooth_btsnoop_net(char *interface, char *fifo, + const char *adb_server_ip, unsigned short *adb_server_tcp_port) { + struct extcap_dumper extcap_dumper; + static char packet[PACKET_LENGTH]; + ssize_t length; + ssize_t used_buffer_length = 0; + int sock; + const char *adb_transport = "0012""host:transport-any"; + const char *adb_transport_serial_templace = "%04x""host:transport:%s"; + const char *adb_tcp_btsnoop_net = "0008""tcp:8872"; + int result; + char *serial_number = NULL; + uint64_t ts; + static const uint64_t BTSNOOP_TIMESTAMP_BASE = 0x00dcddb30f2f8000UL; + uint32_t *reported_length; + uint32_t *captured_length; + uint32_t *flags; +/* uint32_t *cummulative_dropped_packets; */ + uint64_t *timestamp; + char *payload = packet + sizeof(own_pcap_bluetooth_h4_header) + 24; + own_pcap_bluetooth_h4_header *h4_header; + + SET_DATA(reported_length, value_u32, packet + sizeof(own_pcap_bluetooth_h4_header) + 0); + SET_DATA(captured_length, value_u32, packet + sizeof(own_pcap_bluetooth_h4_header) + 4); + SET_DATA(flags, value_u32, packet + sizeof(own_pcap_bluetooth_h4_header) + 8); +/* SET_DATA(cummulative_dropped_packets, value_u32, packet + sizeof(own_pcap_bluetooth_h4_header) + 12); */ + SET_DATA(timestamp, value_u64, packet + sizeof(own_pcap_bluetooth_h4_header) + 16); + SET_DATA(h4_header, value_own_pcap_bluetooth_h4_header, payload - sizeof(own_pcap_bluetooth_h4_header)); + + extcap_dumper = extcap_dumper_open(fifo, EXTCAP_ENCAP_BLUETOOTH_H4_WITH_PHDR); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + if (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET) && + strlen(interface) > strlen(INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET) + 1; + } + + if (!serial_number) { + result = adb_send(sock, adb_transport); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", adb_transport); + return 1; + } + } else { + sprintf((char *) packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", packet); + return 1; + } + } + + result = adb_send(sock, adb_tcp_btsnoop_net); + if (result) { + fprintf(stderr, "ERROR: Error while sending command <%s>\n", adb_tcp_btsnoop_net); + return 1; + } + + /* Read "btsnoop" header - 16 bytes */ + while (used_buffer_length < 16) { + length = recv(sock, packet + used_buffer_length, PACKET_LENGTH - used_buffer_length, 0); + used_buffer_length += length; + } + if (used_buffer_length > 16) + memmove(packet, packet + 16, used_buffer_length - 16); + + used_buffer_length = 0; + + while (endless_loop) { + errno = 0; + length = recv(sock, packet + used_buffer_length + sizeof(own_pcap_bluetooth_h4_header), + PACKET_LENGTH - sizeof(own_pcap_bluetooth_h4_header) - used_buffer_length, 0); + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + else if (errno != 0) { + printf("ERROR capture: %s\n", strerror(errno)); + return 100; + } + + if (length <= 0) { + printf("ERROR: Broken socket connection.\n"); + closesocket(sock); + return 101; + } + + used_buffer_length += length; + + while (used_buffer_length >= 24 && + used_buffer_length >= (int) (24 + GINT32_FROM_BE(*captured_length))) { + ts = GINT64_FROM_BE(*timestamp); + ts -= BTSNOOP_TIMESTAMP_BASE; + + h4_header->direction = GINT32_TO_BE(GINT32_FROM_BE(*flags) & 0x01); + + extcap_dumper_dump(extcap_dumper, payload - sizeof(own_pcap_bluetooth_h4_header), + GINT32_FROM_BE(*captured_length) + sizeof(own_pcap_bluetooth_h4_header), + GINT32_FROM_BE(*reported_length) + sizeof(own_pcap_bluetooth_h4_header), + (uint32_t)(ts / 1000000), + ((uint32_t)(ts % 1000000)) * 1000); + + used_buffer_length -= 24 + GINT32_FROM_BE(*captured_length); + if (used_buffer_length < 0) { + printf("ERROR: Internal error: Negative used buffer length.\n"); + return 1; + } + + if (used_buffer_length > 0) + memmove(packet + sizeof(own_pcap_bluetooth_h4_header), payload + GINT32_FROM_BE(*captured_length), used_buffer_length); + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Android Logcat Text*/ +/*----------------------------------------------------------------------------*/ + +static int capture_android_logcat_text(char *interface, char *fifo, + const char *adb_server_ip, unsigned short *adb_server_tcp_port) { + struct extcap_dumper extcap_dumper; + static char packet[PACKET_LENGTH]; + ssize_t length; + ssize_t used_buffer_length = 0; + int sock; + const char *protocol_name; + int exported_pdu_headers_size = 0; + struct exported_pdu_header exported_pdu_header_protocol_normal; + struct exported_pdu_header *exported_pdu_header_protocol; + struct exported_pdu_header exported_pdu_header_end = {0, 0}; + static const char *wireshark_protocol_logcat_text = "logcat_text_threadtime"; + const char *adb_transport = "0012""host:transport-any"; + const char *adb_logcat_template = "%04x""shell:export ANDROID_LOG_TAGS=\"\" ; exec logcat -v threadtime%s%s"; + const char *adb_transport_serial_templace = "%04x""host:transport:%s"; + char *serial_number = NULL; + int result; + char *pos; + const char *logcat_buffer; + + extcap_dumper = extcap_dumper_open(fifo, EXTCAP_ENCAP_WIRESHARK_UPPER_PDU); + + exported_pdu_header_protocol_normal.tag = GINT16_TO_BE(WIRESHARK_UPPER_PDU_TAG_DISSECTOR_NAME); + exported_pdu_header_protocol_normal.length = GINT16_TO_BE(strlen(wireshark_protocol_logcat_text) + 2); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_MAIN) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_MAIN) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_SYSTEM) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_SYSTEM) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_RADIO) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_RADIO) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_EVENTS) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_EVENTS) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_MAIN) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_TEXT_MAIN) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_TEXT_MAIN) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_RADIO) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_TEXT_RADIO) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_TEXT_RADIO) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_CRASH) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_TEXT_CRASH) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_TEXT_CRASH) + 1; + } + + if (!serial_number) { + result = adb_send(sock, adb_transport); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", adb_transport); + return 1; + } + } else { + sprintf((char *) packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", packet); + return 1; + } + } + + if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN) || is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_MAIN)) + logcat_buffer = " -b main"; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM) || is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM)) + logcat_buffer = " -b system"; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO) || is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_RADIO)) + logcat_buffer = " -b radio"; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS) || is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS)) + logcat_buffer = " -b events"; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_CRASH)) + logcat_buffer = " -b crash"; + else { + printf("ERROR: Unknown interface: <%s>\n", interface); + return -1; + } + + + g_snprintf((char *) packet, sizeof(packet), adb_logcat_template, strlen(adb_logcat_template) + -8 + strlen(logcat_buffer), logcat_buffer, ""); + result = adb_send(sock, packet); + if (result) { + fprintf(stderr, "ERROR: Error while sending command <%s>\n", packet); + return 1; + } + + protocol_name = wireshark_protocol_logcat_text; + exported_pdu_header_protocol = &exported_pdu_header_protocol_normal; + + memcpy(packet + exported_pdu_headers_size, exported_pdu_header_protocol, sizeof(struct exported_pdu_header)); + exported_pdu_headers_size += sizeof(struct exported_pdu_header); + + memcpy(packet + exported_pdu_headers_size, protocol_name, GINT16_FROM_BE(exported_pdu_header_protocol->length) - 2); + exported_pdu_headers_size += GINT16_FROM_BE(exported_pdu_header_protocol->length); + + packet[exported_pdu_headers_size - 1] = 0; + packet[exported_pdu_headers_size - 2] = 0; + + memcpy(packet + exported_pdu_headers_size, &exported_pdu_header_end, sizeof(struct exported_pdu_header)); + exported_pdu_headers_size += sizeof(struct exported_pdu_header) + GINT16_FROM_BE(exported_pdu_header_end.length); + + used_buffer_length = 0; + while (endless_loop) { + errno = 0; + length = recv(sock, packet + exported_pdu_headers_size + used_buffer_length, PACKET_LENGTH - exported_pdu_headers_size - used_buffer_length , 0); + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + else if (errno != 0) { + printf("ERROR capture: %s\n", strerror(errno)); + return 100; + } + + if (length <= 0) { + printf("ERROR: Broken socket connection. Try reconnect.\n"); + exit(1); + } + + used_buffer_length += length; + + while (used_buffer_length > 0 && (pos = (char *) memchr(packet + exported_pdu_headers_size, '\n', used_buffer_length))) { + int ms; + struct tm date; + time_t seconds; + time_t secs = 0; + int nsecs = 0; + + length = (pos - packet) + 1; + + if (6 == sscanf(packet + exported_pdu_headers_size, "%d-%d %d:%d:%d.%d", &date.tm_mon, &date.tm_mday, &date.tm_hour, + &date.tm_min, &date.tm_sec, &ms)) { + date.tm_year = 70; + date.tm_mon -= 1; + seconds = mktime(&date); + secs = (time_t) seconds; + nsecs = (int) (ms * 1e6); + } + + extcap_dumper_dump(extcap_dumper, packet, + length, + length, + secs, nsecs); + + memmove(packet + exported_pdu_headers_size, packet + length, used_buffer_length + exported_pdu_headers_size - length); + used_buffer_length -= length - exported_pdu_headers_size; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* Android Logger / Logcat */ +/*----------------------------------------------------------------------------*/ + +static int capture_android_logcat(char *interface, char *fifo, + const char *adb_server_ip, unsigned short *adb_server_tcp_port) { + struct extcap_dumper extcap_dumper; + static char packet[PACKET_LENGTH]; + static char helper_packet[PACKET_LENGTH]; + ssize_t length; + ssize_t used_buffer_length = 0; + int sock; + const char *protocol_name; + int exported_pdu_headers_size = 0; + struct exported_pdu_header exported_pdu_header_protocol_events; + struct exported_pdu_header exported_pdu_header_protocol_normal; + struct exported_pdu_header *exported_pdu_header_protocol; + struct exported_pdu_header exported_pdu_header_end = {0, 0}; + static const char *wireshark_protocol_logcat = "logcat"; + static const char *wireshark_protocol_logcat_events = "logcat_events"; + const char *adb_transport = "0012""host:transport-any"; + const char *adb_log_main = "0008""log:main"; + const char *adb_log_system = "000A""log:system"; + const char *adb_log_radio = "0009""log:radio"; + const char *adb_log_events = "000A""log:events"; + const char *adb_transport_serial_templace = "%04x""host:transport:%s"; + const char *adb_command; + uint16_t *payload_length; + uint16_t *try_header_size; + uint32_t *timestamp_secs; + uint32_t *timestamp_nsecs; + uint16_t header_size; + int result; + char *serial_number = NULL; + + extcap_dumper = extcap_dumper_open(fifo, EXTCAP_ENCAP_WIRESHARK_UPPER_PDU); + + exported_pdu_header_protocol_events.tag = GINT16_TO_BE(WIRESHARK_UPPER_PDU_TAG_DISSECTOR_NAME); + exported_pdu_header_protocol_events.length = GINT16_TO_BE(strlen(wireshark_protocol_logcat_events) + 2); + + exported_pdu_header_protocol_normal.tag = GINT16_TO_BE(WIRESHARK_UPPER_PDU_TAG_DISSECTOR_NAME); + exported_pdu_header_protocol_normal.length = GINT16_TO_BE(strlen(wireshark_protocol_logcat) + 2); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_MAIN) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_MAIN) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_SYSTEM) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_SYSTEM) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_RADIO) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_RADIO) + 1; + } else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS) && strlen(interface) > strlen(INTERFACE_ANDROID_LOGCAT_EVENTS) + 1) { + serial_number = interface + strlen(INTERFACE_ANDROID_LOGCAT_EVENTS) + 1; + } + + if (!serial_number) { + result = adb_send(sock, adb_transport); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport\n"); + return 1; + } + } else { + g_snprintf(packet, PACKET_LENGTH, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport\n"); + return 1; + } + } + + if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN)) + adb_command = adb_log_main; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM)) + adb_command = adb_log_system; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO)) + adb_command = adb_log_radio; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS)) + adb_command = adb_log_events; + else { + printf("ERROR: Unknown interface: <%s>\n", interface); + return -1; + } + + result = adb_send(sock, adb_command); + if (result) { + fprintf(stderr, "ERROR: Error while sending command <%s>\n", adb_command); + return 1; + } + + if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS)) + { + protocol_name = wireshark_protocol_logcat_events; + exported_pdu_header_protocol = &exported_pdu_header_protocol_events; + } else { + protocol_name = wireshark_protocol_logcat; + exported_pdu_header_protocol = &exported_pdu_header_protocol_normal; + } + + memcpy(packet + exported_pdu_headers_size, exported_pdu_header_protocol, sizeof(struct exported_pdu_header)); + exported_pdu_headers_size += sizeof(struct exported_pdu_header); + + memcpy(packet + exported_pdu_headers_size, protocol_name, GINT16_FROM_BE(exported_pdu_header_protocol->length) - 2); + exported_pdu_headers_size += GINT16_FROM_BE(exported_pdu_header_protocol->length); + + packet[exported_pdu_headers_size - 1] = 0; + packet[exported_pdu_headers_size - 2] = 0; + + memcpy(packet + exported_pdu_headers_size, &exported_pdu_header_end, sizeof(struct exported_pdu_header)); + exported_pdu_headers_size += sizeof(struct exported_pdu_header) + GINT16_FROM_BE(exported_pdu_header_end.length); + + SET_DATA(payload_length, value_u16, packet + exported_pdu_headers_size + 0); + SET_DATA(try_header_size, value_u16, packet + exported_pdu_headers_size + 2); + SET_DATA(timestamp_secs, value_u32, packet + exported_pdu_headers_size + 12); + SET_DATA(timestamp_nsecs, value_u32, packet + exported_pdu_headers_size + 16); + + while (endless_loop) { + errno = 0; + length = recv(sock, packet + exported_pdu_headers_size + used_buffer_length, PACKET_LENGTH - exported_pdu_headers_size - used_buffer_length , 0); + if (errno == EAGAIN || errno == EWOULDBLOCK) continue; + else if (errno != 0) { + printf("ERROR capture: %s\n", strerror(errno)); + return 100; + } + + if (length <= 0) { + while (endless_loop) { + printf("WARNING: Broken socket connection. Try reconnect.\n"); + used_buffer_length = 0; + closesocket(sock); + + sock = adb_connect(adb_server_ip, adb_server_tcp_port); + if (sock < 0) + return -1; + + if (!serial_number) { + result = adb_send(sock, adb_transport); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", adb_transport); + return 1; + } + } else { + sprintf((char *) helper_packet, adb_transport_serial_templace, 15 + strlen(serial_number), serial_number); + result = adb_send(sock, helper_packet); + if (result) { + fprintf(stderr, "ERROR: Error while setting adb transport for <%s>\n", helper_packet); + return 1; + } + } + + if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN)) + adb_command = adb_log_main; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM)) + adb_command = adb_log_system; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO)) + adb_command = adb_log_radio; + else if (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS)) + adb_command = adb_log_events; + else { + printf("ERROR: Unknown interface: <%s>\n", interface); + return 1; + } + + result = adb_send(sock, adb_command); + if (result) { + fprintf(stderr, "ERROR: Error while sending command <%s>\n", adb_command); + continue; + } + + break; + } + } + + used_buffer_length += length + exported_pdu_headers_size; + + if (*try_header_size == 0 || *try_header_size != 24) + header_size = 20; + else + header_size = *try_header_size; + + length = (*payload_length) + header_size + exported_pdu_headers_size; + + while (used_buffer_length >= exported_pdu_headers_size + header_size && length <= used_buffer_length) { + extcap_dumper_dump(extcap_dumper, packet, + length, + length, + *timestamp_secs, *timestamp_nsecs); + + memmove(packet + exported_pdu_headers_size, packet + length, used_buffer_length - length); + used_buffer_length -= length; + used_buffer_length += exported_pdu_headers_size; + + + length = (*payload_length) + header_size + exported_pdu_headers_size; + + if (*try_header_size == 0 || *try_header_size != 24) + header_size = 20; + else + header_size = *try_header_size; + } + used_buffer_length -= exported_pdu_headers_size; + } + + return 0; +} + +/*============================================================================*/ + +int main(int argc, char **argv) { + int option_idx = 0; + int do_capture = 0; + int do_config = 0; + int do_list_interfaces = 0; + int do_dlts = 0; + int result; + char *fifo = NULL; + char *interface = NULL; + const char *adb_server_ip = NULL; + unsigned short *adb_server_tcp_port = NULL; + unsigned int logcat_text = 0; + const char *default_adb_server_ip = "127.0.0.1"; + unsigned short default_adb_server_tcp_port = 5037; + unsigned short *bt_server_tcp_port = NULL; + unsigned int bt_forward_socket = 0; + const char *bt_local_ip = NULL; + unsigned short *bt_local_tcp_port = NULL; + unsigned short default_bt_server_tcp_port = 4330; + const char *default_bt_local_ip = "127.0.0.1"; + unsigned short default_bt_local_tcp_port = 4330; +#ifdef _WIN32 + WSADATA wsaData; +#endif /* _WIN32 */ + + opterr = 0; + optind = 0; + + if (verbose) { + int j = 0; + while(j < argc) { + fprintf(stderr, "%s ", argv[j]); + j += 1; + } + fprintf(stderr, "\n"); + } + + if (argc == 1) { + help(); + return 0; + } + + while ((result = getopt_long(argc, argv, "", longopts, &option_idx)) != -1) { + switch (result) { + + case OPT_VERSION: + printf("%u.%u.%u\n", ANDROIDDUMP_VERSION_MAJOR, ANDROIDDUMP_VERSION_MINOR, ANDROIDDUMP_VERSION_RELEASE); + return 0; + case OPT_LIST_INTERFACES: + do_list_interfaces = 1; + break; + case OPT_LIST_DLTS: + do_dlts = 1; + break; + case OPT_INTERFACE: + interface = strdup(optarg); + break; + case OPT_CONFIG: + do_config = 1; + break; + case OPT_CAPTURE: + do_capture = 1; + break; + case OPT_FIFO: + fifo = strdup(optarg); + break; + case OPT_HELP: + help(); + return 0; + case OPT_CONFIG_ADB_SERVER_IP: + adb_server_ip = strdup(optarg); + break; + case OPT_CONFIG_ADB_SERVER_TCP_PORT: + adb_server_tcp_port = (unsigned short *) malloc(sizeof(adb_server_tcp_port)); + *adb_server_tcp_port = (unsigned short) strtoul(optarg, NULL, 10); + break; + case OPT_CONFIG_LOGCAT_TEXT: + logcat_text = (strcmp(optarg, "TRUE") == 0); + break; + case OPT_CONFIG_BT_SERVER_TCP_PORT: + bt_server_tcp_port = (unsigned short *) malloc(sizeof(bt_server_tcp_port)); + *bt_server_tcp_port = (unsigned short) strtoul(optarg, NULL, 10); + break; + case OPT_CONFIG_BT_FORWARD_SOCKET: + bt_forward_socket = (strcmp(optarg, "TRUE") == 0); + break; + case OPT_CONFIG_BT_LOCAL_IP: + bt_local_ip = strdup(optarg); + break; + case OPT_CONFIG_BT_LOCAL_TCP_PORT: + bt_local_tcp_port = (unsigned short *) malloc(sizeof(bt_local_tcp_port)); + *bt_local_tcp_port = (unsigned short) strtoul(optarg, NULL, 10); + break; + default: + printf("Invalid argument <%s>. Try --help.\n", argv[optind - 1]); + return -1; + } + } + + if (!adb_server_ip) + adb_server_ip = default_adb_server_ip; + + if (!adb_server_tcp_port) + adb_server_tcp_port = &default_adb_server_tcp_port; + + if (!bt_server_tcp_port) + bt_server_tcp_port = &default_bt_server_tcp_port; + + if (!bt_local_ip) + bt_local_ip = default_bt_local_ip; + + if (!bt_local_tcp_port) + bt_local_tcp_port = &default_bt_local_tcp_port; + + if (do_config) + return list_config(interface); + + if (do_dlts) + return list_dlts(interface); + +#ifdef _WIN32 + result = WSAStartup(MAKEWORD(1,1), &wsaData); + if (result != 0) { + printf("ERROR: WSAStartup failed with error: %d\n", result); + return 1; + } +#endif /* _WIN32 */ + + if (do_list_interfaces) + return list_interfaces(adb_server_ip, adb_server_tcp_port); + + if (fifo == NULL) { + printf("ERROR: No FIFO or file specified\n"); + return 1; + } + + if (do_capture) { + if (interface && (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_MAIN) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_SYSTEM) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_RADIO) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_EVENTS))) + if (logcat_text) + return capture_android_logcat_text(interface, fifo, adb_server_ip, adb_server_tcp_port); + else + return capture_android_logcat(interface, fifo, adb_server_ip, adb_server_tcp_port); + else if (interface && (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_MAIN) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_SYSTEM) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_RADIO) || + is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) || + (is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_CRASH)))) + return capture_android_logcat_text(interface, fifo, adb_server_ip, adb_server_tcp_port); + else if (interface && is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_HCIDUMP)) + return capture_android_bluetooth_hcidump(interface, fifo, adb_server_ip, adb_server_tcp_port); + else if (interface && is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER)) + return capture_android_bluetooth_external_parser(interface, fifo, adb_server_ip, adb_server_tcp_port, + bt_server_tcp_port, bt_forward_socket, bt_local_ip, bt_local_tcp_port); + else if (interface && (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET))) + return capture_android_bluetooth_btsnoop_net(interface, fifo, adb_server_ip, adb_server_tcp_port); + else + return 2; + } + + return 0; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/tools/pre-commit b/tools/pre-commit index 02a52b1a58..9f213a3d15 100755 --- a/tools/pre-commit +++ b/tools/pre-commit @@ -26,7 +26,7 @@ fi exit_status=0 -for FILE in `git diff-index --cached --name-status ${COMMIT_ID} | grep -v "^D" | cut -f2 | grep "\.[ch]$"` ; do +for FILE in `git diff-index --cached --name-status ${COMMIT_ID} | grep -v "^D" | cut -f2 | grep "\.[ch]$" | grep -v "extcap/"` ; do #Check if checkhf is good ./tools/checkhf.pl $FILE || exit_status=1