From be6eca8654f9bc7c686840a85a576b6453ad012d Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Mon, 10 Jan 2022 23:47:47 +0100 Subject: idevicebtlogger: add --format option for 'pcap' and 'packetlogger' --- docs/idevicebtlogger.1 | 14 ++++++- tools/idevicebtlogger.c | 106 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 106 insertions(+), 14 deletions(-) diff --git a/docs/idevicebtlogger.1 b/docs/idevicebtlogger.1 index 24903b5..39ffff7 100644 --- a/docs/idevicebtlogger.1 +++ b/docs/idevicebtlogger.1 @@ -8,7 +8,9 @@ idevicebtlogger \- Capture HCI traffic of a connected device. .SH DESCRIPTION -Capture HCI traffic of a connected device. Requires Bluetooth logging profile to be installed on device. +Capture HCI traffic of a connected device. Requires Bluetooth logging profile to be installed on device with iOS 13 or higher. See https://www.bluetooth.com/blog/a-new-way-to-debug-iosbluetooth-applications/ for iOS device configuration. + +The HCI traffic can be stored in Apple's native PacketLogger format or converted into PCAP format for live feedback in Wireshark. .SH OPTIONS .TP @@ -18,6 +20,9 @@ target specific device by UDID .B \-n, \-\-network connect to network device .TP +.B \-f, \-\-format FORMAT +set log format: PacketLoggger (default), or pcap +.TP .B \-x, \-\-exit exit when device disconnects .TP @@ -37,9 +42,16 @@ Capture HCI traffic of device with UDID 00008030-0000111ABC000DEF. .TP .B idevicebtlogger \-x Capture HCI traffic of device and exit when the device is unplugged. +.TP +.B idevicebtlogger \-f pcap +Capture HCI traffic of device in PCAP format. +.TP +.B idevicebtlogger -f pcap - | wireshark -k -i - +Capture HCI traffic and pipe it into Wireshark for live feedback. .SH AUTHORS Geoffrey Kruse +Matthias Ringwald .SH ON THE WEB https://libimobiledevice.org diff --git a/tools/idevicebtlogger.c b/tools/idevicebtlogger.c index b73d958..c780143 100644 --- a/tools/idevicebtlogger.c +++ b/tools/idevicebtlogger.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #ifdef WIN32 #include @@ -57,7 +59,14 @@ static idevice_t device = NULL; static bt_packet_logger_client_t bt_packet_logger = NULL; static int use_network = 0; static char* out_filename = NULL; -static pcap_dumper_t * dump; +static char* log_format_string = NULL; +static pcap_dumper_t * pcap_dumper = NULL; +static int packetlogger_fd = -1; + +static enum { + LOG_FORMAT_PACKETLOGGER, + LOG_FORMAT_PCAP +} log_format = LOG_FORMAT_PACKETLOGGER; typedef enum { HCI_COMMAND = 0x00, @@ -66,10 +75,18 @@ typedef enum { RECV_ACL_DATA = 0x03 } PacketLoggerPacketType; +/** + * Callback from the packet logger service to handle packets and log to PacketLoggger format + */ +static void bt_packet_logger_callback_packetlogger(uint8_t * data, uint16_t len, void *user_data) +{ + write(packetlogger_fd, data, len); +} + /** * Callback from the packet logger service to handle packets and log to pcap */ -static void bt_packet_logger_callback(uint8_t * data, uint16_t len, void *user_data) +static void bt_packet_logger_callback_pcap(uint8_t * data, uint16_t len, void *user_data) { bt_packet_logger_header_t * header = (bt_packet_logger_header_t *)data; uint16_t offset = sizeof(bt_packet_logger_header_t); @@ -126,8 +143,8 @@ static void bt_packet_logger_callback(uint8_t * data, uint16_t len, void *user_d // having to memcpy things around. offset -= sizeof(uint32_t); *(uint32_t*)&data[offset] = direction; - pcap_dump((unsigned char*)dump, &pcap_header, &data[offset]); - pcap_dump_flush(dump); + pcap_dump((unsigned char*)pcap_dumper, &pcap_header, &data[offset]); + pcap_dump_flush(pcap_dumper); } } @@ -173,7 +190,19 @@ static int start_logging(void) bt_packet_logger_client_start_service(device, &bt_packet_logger, TOOL_NAME); /* start capturing bt_packet_logger */ - bt_packet_logger_error_t serr = bt_packet_logger_start_capture(bt_packet_logger, bt_packet_logger_callback, NULL); + void (*callback)(uint8_t * data, uint16_t len, void *user_data); + switch (log_format){ + case LOG_FORMAT_PCAP: + callback = bt_packet_logger_callback_pcap; + break; + case LOG_FORMAT_PACKETLOGGER: + callback = bt_packet_logger_callback_packetlogger; + break; + default: + assert(0); + return 0; + } + bt_packet_logger_error_t serr = bt_packet_logger_start_capture(bt_packet_logger, callback, NULL); if (serr != BT_PACKET_LOGGER_E_SUCCESS) { fprintf(stderr, "ERROR: Unable to start capturing bt_packet_logger.\n"); bt_packet_logger_client_free(bt_packet_logger); @@ -243,12 +272,13 @@ static void print_usage(int argc, char **argv, int is_error) "Capture HCI packets from a connected device.\n" \ "\n" \ "OPTIONS:\n" \ - " -u, --udid UDID target specific device by UDID\n" \ - " -n, --network connect to network device\n" \ - " -x, --exit exit when device disconnects\n" \ - " -h, --help prints usage information\n" \ - " -d, --debug enable communication debugging\n" \ - " -v, --version prints version information\n" \ + " -u, --udid UDID target specific device by UDID\n" \ + " -n, --network connect to network device\n" \ + " -f, --format FORMAT logging format: packetlogger (default) or pcap\n" \ + " -x, --exit exit when device disconnects\n" \ + " -h, --help prints usage information\n" \ + " -d, --debug enable communication debugging\n" \ + " -v, --version prints version information\n" \ "\n" \ "Homepage: <" PACKAGE_URL ">\n" "Bug Reports: <" PACKAGE_BUGREPORT ">\n" @@ -265,6 +295,7 @@ int main(int argc, char *argv[]) { "debug", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "udid", required_argument, NULL, 'u' }, + { "format", required_argument, NULL, 'f' }, { "network", no_argument, NULL, 'n' }, { "exit", no_argument, NULL, 'x' }, { "version", no_argument, NULL, 'v' }, @@ -278,7 +309,7 @@ int main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); #endif - while ((c = getopt_long(argc, argv, "dhu:nxv", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "dhu:f:nxv", longopts, NULL)) != -1) { switch (c) { case 'd': idevice_set_debug_level(1); @@ -292,6 +323,15 @@ int main(int argc, char *argv[]) free(udid); udid = strdup(optarg); break; + case 'f': + if (!*optarg) { + fprintf(stderr, "ERROR: FORMAT must not be empty!\n"); + print_usage(argc, argv, 1); + return 2; + } + free(log_format_string); + log_format_string = strdup(optarg); + break; case 'n': use_network = 1; break; @@ -319,10 +359,23 @@ int main(int argc, char *argv[]) return 2; } + if (log_format_string != NULL){ + if (strcmp("packetlogger", log_format_string) == 0){ + log_format = LOG_FORMAT_PACKETLOGGER; + } else if (strcmp("pcap", log_format_string) == 0){ + log_format = LOG_FORMAT_PCAP; + } else { + printf("Unknown logging format: '%s'\n", log_format_string); + print_usage(argc, argv, 1); + return 2; + } + } + int num = 0; idevice_info_t *devices = NULL; idevice_get_device_list_extended(&devices, &num); idevice_device_list_extended_free(devices); + int oflags; if (num == 0) { if (!udid) { fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n"); @@ -332,7 +385,27 @@ int main(int argc, char *argv[]) } } - dump = pcap_dump_open(pcap_open_dead(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, BT_MAX_PACKET_SIZE), out_filename); + switch (log_format){ + case LOG_FORMAT_PCAP: + printf("Output Format: PCAP\n"); + pcap_dumper = pcap_dump_open(pcap_open_dead(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, BT_MAX_PACKET_SIZE), out_filename); + break; + case LOG_FORMAT_PACKETLOGGER: + printf("Output Format: PacketLogger\n"); + oflags = O_WRONLY | O_CREAT | O_TRUNC; +#ifdef WIN32 + default_oflags |= O_BINARY; +#endif + packetlogger_fd = open(out_filename, oflags); + if (packetlogger_fd < 0){ + fprintf(stderr, "Failed to open file %s, errno = %d\n", out_filename, errno); + return -2; + } + break; + default: + assert(0); + return -2; + } idevice_event_subscribe(device_event_cb, NULL); while (!quit_flag) { @@ -342,6 +415,13 @@ int main(int argc, char *argv[]) idevice_event_unsubscribe(); stop_logging(); + if (pcap_dumper) { + pcap_dump_close(pcap_dumper); + } + if (packetlogger_fd >= 0){ + close(packetlogger_fd); + } + free(udid); return 0; -- cgit v1.1-32-gdbae