idevicebtlogger: add --format option for 'pcap' and 'packetlogger'
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 @@
.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 @@
.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 @@
.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 <stdlib.h>
#include <unistd.h>
#include <getopt.h>
+#include <assert.h>
+#include <fcntl.h>
#ifdef WIN32
#include <windows.h>
@@ -57,7 +59,14 @@
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,
@@ -67,9 +76,17 @@
} 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 @@
// 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 @@
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 @@
"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 @@
{ "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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
idevice_event_unsubscribe();
stop_logging();
+ if (pcap_dumper) {
+ pcap_dump_close(pcap_dumper);
+ }
+ if (packetlogger_fd >= 0){
+ close(packetlogger_fd);
+ }
+
free(udid);
return 0;