androiddump: Support packet capture on any interface that is up

androiddump used to start tcpdump without specifying the interface
to capture packets on. This works when only one interface is up
but when multiple interfaces are up the output might be empty.

This change let tcpdump list all available network interfaces
and adds a unique extcap interface for each interface that is 'up'
on the device.

Change-Id: Icf0d7fa8f38320092579d4163dcdbcf2b687d8cc
Reviewed-on: https://code.wireshark.org/review/22402
Petri-Dish: Roland Knall <rknall@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Roland Knall <rknall@gmail.com>
This commit is contained in:
Mikael Kanstrup 2017-06-19 00:06:02 +02:00 committed by Anders Broman
parent 129a84df60
commit 564445f799
1 changed files with 101 additions and 32 deletions

View File

@ -103,7 +103,9 @@
#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 INTERFACE_ANDROID_WIFI_TCPDUMP "android-wifi-tcpdump"
#define INTERFACE_ANDROID_TCPDUMP "android-tcpdump"
#define INTERFACE_ANDROID_TCPDUMP_FORMAT INTERFACE_ANDROID_TCPDUMP "-%s"
#define INTERFACE_ANDROID_TCPDUMP_SERIAL_FORMAT INTERFACE_ANDROID_TCPDUMP_FORMAT "-%s"
#define ANDROIDDUMP_VERSION_MAJOR "1"
#define ANDROIDDUMP_VERSION_MINOR "1"
@ -838,7 +840,7 @@ static void new_interface(extcap_parameters * extcap_conf, const gchar *interfac
is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_EVENTS) ||
is_specified_interface(interface, INTERFACE_ANDROID_LOGCAT_TEXT_CRASH)) {
extcap_base_register_interface(extcap_conf, interface, ifdisplay, 252, "Upper PDU" );
} else if (is_specified_interface(interface, INTERFACE_ANDROID_WIFI_TCPDUMP)) {
} else if (is_specified_interface(interface, INTERFACE_ANDROID_TCPDUMP)) {
extcap_base_register_interface(extcap_conf, interface, ifdisplay, 1, "Ethernet");
}
g_free(interface);
@ -846,6 +848,63 @@ static void new_interface(extcap_parameters * extcap_conf, const gchar *interfac
}
static int add_tcpdump_interfaces(extcap_parameters * extcap_conf, const char *adb_server_ip, unsigned short *adb_server_tcp_port, const char *serial_number)
{
static const char *const adb_tcpdump_list = "shell:tcpdump -D";
static const char *const regex_ifaces = "\\d+\\.(?<iface>\\S+)\\s+?(?:(?:\\(.*\\))*)\\s*?\\[(?<flags>.*?)\\]";
static char recv_buffer[PACKET_LENGTH];
char *response;
gssize data_length;
socket_handle_t sock;
GRegex* regex = NULL;
GError *err = NULL;
GMatchInfo *match = NULL;
char* tok;
char iface_name[80];
sock = adb_connect_transport(adb_server_ip, adb_server_tcp_port, serial_number);
if (sock == INVALID_SOCKET) {
g_warning("Failed to connect to adb server");
return EXIT_CODE_GENERIC;
}
response = adb_send_and_read(sock, adb_tcpdump_list, recv_buffer, sizeof(recv_buffer), &data_length);
closesocket(sock);
if (!response) {
g_warning("Failed to get list of available tcpdump interfaces");
return EXIT_CODE_GENERIC;
}
response[data_length] = '\0';
regex = g_regex_new(regex_ifaces, (GRegexCompileFlags)0, (GRegexMatchFlags)0, &err);
if (!regex) {
g_warning("Failed to compile regex for tcpdump interface matching");
return EXIT_CODE_GENERIC;
}
tok = strtok(response, "\n");
while (tok != NULL) {
g_regex_match(regex, tok, (GRegexMatchFlags)0, &match);
if (g_match_info_matches(match)) {
gchar *iface = g_match_info_fetch_named(match, "iface");
gchar *flags = g_match_info_fetch_named(match, "flags");
if (strstr(flags, "Up")) {
g_snprintf(iface_name, sizeof(iface_name), INTERFACE_ANDROID_TCPDUMP_FORMAT, iface);
new_interface(extcap_conf, iface_name, iface, serial_number, "Android tcpdump");
}
g_free(flags);
g_free(iface);
}
g_match_info_free(match);
tok = strtok(NULL, "\n");
}
g_regex_unref(regex);
return 0;
}
static int register_interfaces(extcap_parameters * extcap_conf, const char *adb_server_ip, unsigned short *adb_server_tcp_port) {
static char packet[PACKET_LENGTH];
static char helpful_packet[PACKET_LENGTH];
@ -862,7 +921,6 @@ static int register_interfaces(extcap_parameters * extcap_conf, const char *adb_
const char *adb_ps_droid_bluetooth = "shell:ps droid.bluetooth";
const char *adb_ps_bluetooth_app = "shell:ps com.android.bluetooth";
const char *adb_ps_with_grep = "shell:ps | grep com.android.bluetooth";
const char *adb_tcpdump_help = "shell:tcpdump -h";
char serial_number[SERIAL_NUMBER_LENGTH_MAX];
char model_name[MODEL_NAME_LENGTH_MAX];
int result;
@ -921,23 +979,10 @@ static int register_interfaces(extcap_parameters * extcap_conf, const char *adb_
g_debug("Processing device: \"%s\" <%s>" , serial_number, model_name);
/* Check for the presence of tcpdump in the android device. */
sock = adb_connect_transport(adb_server_ip, adb_server_tcp_port, serial_number);
if (sock == INVALID_SOCKET) continue;
response = adb_send_and_read(sock, adb_tcpdump_help, helpful_packet, sizeof(helpful_packet), &data_length);
closesocket(sock);
if (response) {
response[data_length] = '\0';
/* If tcpdump is found in the android device, add Android Wifi Tcpdump as an interface */
if (strstr(response,"tcpdump version")) {
new_interface(extcap_conf, INTERFACE_ANDROID_WIFI_TCPDUMP, model_name, serial_number, "Android WiFi");
}
} else {
g_warning("Error on socket: <%s>", adb_tcpdump_help);
/* Function will only add tcpdump interfaces if tcpdump is present on the device */
result = add_tcpdump_interfaces(extcap_conf, adb_server_ip, adb_server_tcp_port, serial_number );
if (result) {
g_warning("Error while adding tcpdump interfaces");
}
sock = adb_connect_transport(adb_server_ip, adb_server_tcp_port, serial_number);
@ -1156,7 +1201,7 @@ static int list_config(char *interface) {
return EXIT_CODE_SUCCESS;
} else if (is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_HCIDUMP) ||
is_specified_interface(interface, INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET) ||
is_specified_interface(interface, INTERFACE_ANDROID_WIFI_TCPDUMP)) {
is_specified_interface(interface, INTERFACE_ANDROID_TCPDUMP)) {
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=--verbose}{display=Verbose/Debug output on console}{type=boolean}{default=false}\n");
@ -2280,8 +2325,10 @@ static int linktype_to_extcap_encap(const char* linktype)
/* The Tcpdump sends data in pcap format. So for using the extcap_dumper we */
/* need to unpack the pcap and then send the packet data to the dumper. */
/*----------------------------------------------------------------------------*/
static int capture_android_wifi_tcpdump(char *interface, char *fifo,
static int capture_android_tcpdump(char *interface, char *fifo,
const char *adb_server_ip, unsigned short *adb_server_tcp_port) {
static const char *const adb_shell_tcpdump_format = "shell:tcpdump -n -s 0 -u -i %s -w -";
static const char *const regex_interface = INTERFACE_ANDROID_TCPDUMP "-(?<iface>.*?)-(?<serial>.*)";
static const char *const regex_linktype = "tcpdump: listening on .*?, link-type (?<linktype>.*?) ";
struct extcap_dumper extcap_dumper;
static char data[PACKET_LENGTH];
@ -2290,9 +2337,9 @@ static int capture_android_wifi_tcpdump(char *interface, char *fifo,
gssize filter_buffer_length = 0;
gssize frame_length=0;
socket_handle_t sock;
const char *adb_shell_tcpdump = "shell:tcpdump -n -s 0 -u -w -";
gint result;
char *serial_number = NULL;
char *iface = NULL;
char *serial_number = NULL;
static char filter_buffer[PACKET_LENGTH];
gint device_endiness = G_LITTLE_ENDIAN;
gboolean global_header_skipped=FALSE;
@ -2301,18 +2348,40 @@ static int capture_android_wifi_tcpdump(char *interface, char *fifo,
GRegex *regex = NULL;
GError *err = NULL;
GMatchInfo *match = NULL;
char tcpdump_cmd[80];
if (is_specified_interface(interface, INTERFACE_ANDROID_WIFI_TCPDUMP)
&& strlen(interface) > strlen(INTERFACE_ANDROID_WIFI_TCPDUMP) + 1) {
serial_number = interface + strlen(INTERFACE_ANDROID_WIFI_TCPDUMP) + 1;
regex = g_regex_new(regex_interface, (GRegexCompileFlags)0, (GRegexMatchFlags)0, &err);
if (!regex) {
g_warning("Failed to compile regex for tcpdump interface");
return EXIT_CODE_GENERIC;
}
g_regex_match(regex, interface, (GRegexMatchFlags)0, &match);
if (!g_match_info_matches(match)) {
g_warning("Failed to determine iface name and serial number");
g_regex_unref(regex);
return EXIT_CODE_GENERIC;
}
iface = g_match_info_fetch_named(match, "iface");
serial_number = g_match_info_fetch_named(match, "serial");
g_match_info_free(match);
g_regex_unref(regex);
/* First check for the device if it is connected or not */
sock = adb_connect_transport(adb_server_ip, adb_server_tcp_port, serial_number);
if (sock == INVALID_SOCKET)
if (sock == INVALID_SOCKET) {
g_free(iface);
g_free(serial_number);
return EXIT_CODE_INVALID_SOCKET_11;
}
g_snprintf(tcpdump_cmd, sizeof(tcpdump_cmd), adb_shell_tcpdump_format, iface);
g_free(iface);
g_free(serial_number);
result = adb_send(sock, tcpdump_cmd);
result = adb_send(sock, adb_shell_tcpdump);
if (result) {
g_warning("Error while setting adb transport");
closesocket(sock);
@ -2554,7 +2623,7 @@ int main(int argc, char **argv) {
"\t"INTERFACE_ANDROID_BLUETOOTH_HCIDUMP"\n"
"\t"INTERFACE_ANDROID_BLUETOOTH_EXTERNAL_PARSER"\n"
"\t"INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET"\n"
"\t"INTERFACE_ANDROID_WIFI_TCPDUMP"\n"
"\t"INTERFACE_ANDROID_TCPDUMP"\n"
"\n"
"\t""DEVICEID is the identifier of the device provided by Android SDK (see \"adb devices\")\n"
"\t""For example: W3D7N15C29005648""\n",
@ -2734,8 +2803,8 @@ int main(int argc, char **argv) {
bt_server_tcp_port, bt_forward_socket, bt_local_ip, bt_local_tcp_port);
else if (extcap_conf->interface && (is_specified_interface(extcap_conf->interface, INTERFACE_ANDROID_BLUETOOTH_BTSNOOP_NET)))
ret = capture_android_bluetooth_btsnoop_net(extcap_conf->interface, extcap_conf->fifo, adb_server_ip, adb_server_tcp_port);
else if (extcap_conf->interface && (is_specified_interface(extcap_conf->interface,INTERFACE_ANDROID_WIFI_TCPDUMP)))
ret = capture_android_wifi_tcpdump(extcap_conf->interface, extcap_conf->fifo, adb_server_ip,adb_server_tcp_port);
else if (extcap_conf->interface && (is_specified_interface(extcap_conf->interface,INTERFACE_ANDROID_TCPDUMP)))
ret = capture_android_tcpdump(extcap_conf->interface, extcap_conf->fifo, adb_server_ip, adb_server_tcp_port);
goto end;
}