/* 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 #ifdef HAVE_SYS_SOCKET_H #include #endif #ifndef HAVE_GETOPT_LONG #include "wsutil/wsgetopt.h" #endif #if defined(_WIN32) && !defined(__CYGWIN__) #ifdef HAVE_WINDOWS_H #include #endif #include #ifdef HAVE_WINSOCK2_H #include #endif #else /* * UN*X, or Windows pretending to be UN*X with the aid of 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 -= (guint32)sizeof(own_pcap_bluetooth_h4_header); hdr.caplen -= (guint32)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[512]; 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); pos = strchr(pos, '\n') + 1; if (result > (int) sizeof(serial_number)) { fprintf(stderr, "WARNING: Serial number too long, ignore device\n"); continue; } memcpy(serial_number, prev_pos, result); serial_number[result] = '\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_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; } } 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; strtol(hex_data, &new_hex_data, 16); hex_data = new_hex_data; 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; 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; strtol(hex_data, &new_hex_data, 16); hex_data = new_hex_data; 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; 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; 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); 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 = G_GUINT64_CONSTANT(0x00dcddb30f2f8000); #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 = (unsigned int)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 = (unsigned int)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 = (unsigned int)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 = (unsigned int)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 = G_GUINT64_CONSTANT(0x00dcddb30f2f8000); 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))) { gint32 direction; ts = GINT64_FROM_BE(*timestamp); ts -= BTSNOOP_TIMESTAMP_BASE; direction = GINT32_FROM_BE(*flags) & 0x01; h4_header->direction = GINT32_TO_BE(direction); 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; size_t 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; size_t used_buffer_length = 0; int sock; const char *protocol_name; size_t 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 && (size_t)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 local_adb_server_tcp_port; unsigned short local_bt_server_tcp_port; unsigned short local_bt_local_tcp_port; 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 = &local_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 = &local_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 = &local_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: */