summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/Makefile.am2
-rw-r--r--tools/idevicebtlogger.c183
2 files changed, 106 insertions, 79 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index d701bab..e8ef3ab 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -33,7 +33,7 @@ bin_PROGRAMS = \
33 33
34idevicebtlogger_SOURCES = idevicebtlogger.c 34idevicebtlogger_SOURCES = idevicebtlogger.c
35iidevicebtlogger_CFLAGS = $(AM_CFLAGS) 35iidevicebtlogger_CFLAGS = $(AM_CFLAGS)
36idevicebtlogger_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS) -lpcap 36idevicebtlogger_LDFLAGS = $(top_builddir)/common/libinternalcommon.la $(AM_LDFLAGS)
37idevicebtlogger_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la 37idevicebtlogger_LDADD = $(top_builddir)/src/libimobiledevice-1.0.la
38 38
39ideviceinfo_SOURCES = ideviceinfo.c 39ideviceinfo_SOURCES = ideviceinfo.c
diff --git a/tools/idevicebtlogger.c b/tools/idevicebtlogger.c
index c780143..e2ace34 100644
--- a/tools/idevicebtlogger.c
+++ b/tools/idevicebtlogger.c
@@ -1,8 +1,9 @@
1/* 1/*
2 * idevicebt_packet_logger.c 2 * idevicebt_packet_logger.c
3 * Capture bt HCI packet log to pcap 3 * Capture Bluetooth HCI traffic to native PKLG or PCAP
4 * 4 *
5 * Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved. 5 * Copyright (c) 2021 Geoffrey Kruse, All Rights Reserved.
6 * Copyright (c) 2022 Matthias Ringwald, All Rights Reserved.
6 * 7 *
7 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public 9 * modify it under the terms of the GNU Lesser General Public
@@ -45,11 +46,15 @@
45 46
46#include <libimobiledevice/libimobiledevice.h> 47#include <libimobiledevice/libimobiledevice.h>
47#include <libimobiledevice/bt_packet_logger.h> 48#include <libimobiledevice/bt_packet_logger.h>
48#include <pcap.h>
49 49
50#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 50typedef enum {
51#define LIBPCAP_BT_PHDR_SENT 0x00000000 51 HCI_COMMAND = 0x00,
52#define LIBPCAP_BT_PHDR_RECV htonl(0x00000001) 52 HCI_EVENT = 0x01,
53 SENT_ACL_DATA = 0x02,
54 RECV_ACL_DATA = 0x03,
55 SENT_SCO_DATA = 0x08,
56 RECV_SCO_DATA = 0x09,
57} PacketLoggerPacketType;
53 58
54static int quit_flag = 0; 59static int quit_flag = 0;
55static int exit_on_disconnect = 0; 60static int exit_on_disconnect = 0;
@@ -60,27 +65,46 @@ static bt_packet_logger_client_t bt_packet_logger = NULL;
60static int use_network = 0; 65static int use_network = 0;
61static char* out_filename = NULL; 66static char* out_filename = NULL;
62static char* log_format_string = NULL; 67static char* log_format_string = NULL;
63static pcap_dumper_t * pcap_dumper = NULL; 68static FILE * packetlogger_file = NULL;
64static int packetlogger_fd = -1;
65 69
66static enum { 70static enum {
67 LOG_FORMAT_PACKETLOGGER, 71 LOG_FORMAT_PACKETLOGGER,
68 LOG_FORMAT_PCAP 72 LOG_FORMAT_PCAP
69} log_format = LOG_FORMAT_PACKETLOGGER; 73} log_format = LOG_FORMAT_PACKETLOGGER;
70 74
71typedef enum { 75const uint8_t pcap_file_header[] = {
72 HCI_COMMAND = 0x00, 76 // Magic Number
73 HCI_EVENT = 0x01, 77 0xA1, 0xB2, 0xC3, 0xD4,
74 SENT_ACL_DATA = 0x02, 78 // Major / Minor Version
75 RECV_ACL_DATA = 0x03 79 0x00, 0x02, 0x00, 0x04,
76} PacketLoggerPacketType; 80 // Reserved1
81 0x00, 0x00, 0x00, 0x00,
82 // Reserved2
83 0x00, 0x00, 0x00, 0x00,
84 // Snaplen == max packet size - use 2kB (larger than any ACL)
85 0x00, 0x00, 0x08, 0x00,
86 // LinkType: DLT_BLUETOOTH_HCI_H4_WITH_PHDR
87 0x00, 0x00, 0x00, 201,
88};
89
90static uint32_t big_endian_read_32(const uint8_t * buffer, int position) {
91 return ((uint32_t) buffer[position+3]) | (((uint32_t)buffer[position+2]) << 8) | (((uint32_t)buffer[position+1]) << 16) | (((uint32_t) buffer[position]) << 24);
92}
93
94static void big_endian_store_32(uint8_t * buffer, uint16_t position, uint32_t value){
95 uint16_t pos = position;
96 buffer[pos++] = (uint8_t)(value >> 24);
97 buffer[pos++] = (uint8_t)(value >> 16);
98 buffer[pos++] = (uint8_t)(value >> 8);
99 buffer[pos++] = (uint8_t)(value);
100}
77 101
78/** 102/**
79 * Callback from the packet logger service to handle packets and log to PacketLoggger format 103 * Callback from the packet logger service to handle packets and log to PacketLoggger format
80 */ 104 */
81static void bt_packet_logger_callback_packetlogger(uint8_t * data, uint16_t len, void *user_data) 105static void bt_packet_logger_callback_packetlogger(uint8_t * data, uint16_t len, void *user_data)
82{ 106{
83 write(packetlogger_fd, data, len); 107 (void) fwrite(data, 1, len, packetlogger_file);
84} 108}
85 109
86/** 110/**
@@ -88,64 +112,68 @@ static void bt_packet_logger_callback_packetlogger(uint8_t * data, uint16_t len,
88 */ 112 */
89static void bt_packet_logger_callback_pcap(uint8_t * data, uint16_t len, void *user_data) 113static void bt_packet_logger_callback_pcap(uint8_t * data, uint16_t len, void *user_data)
90{ 114{
91 bt_packet_logger_header_t * header = (bt_packet_logger_header_t *)data; 115 // check len
92 uint16_t offset = sizeof(bt_packet_logger_header_t); 116 if (len < 13) {
93
94 // size + sizeof(uint32_t) to account for the direction pseudo header
95 struct pcap_pkthdr pcap_header;
96 pcap_header.caplen = ntohl(header->length) + sizeof(uint32_t);
97 pcap_header.len = len - sizeof(bt_packet_logger_header_t) + sizeof(uint32_t);
98 pcap_header.ts.tv_sec = ntohl(header->ts_secs);
99 pcap_header.ts.tv_usec = ntohl(header->ts_usecs);
100
101 // Sanity check incoming data and drop packet if its unreasonable.
102 if(pcap_header.len > BT_MAX_PACKET_SIZE || pcap_header.caplen > BT_MAX_PACKET_SIZE) {
103 fprintf(stderr, "WARNING: Packet length exceeded max size, corruption likely.\n ");
104 return; 117 return;
105 } 118 }
106 119
107 uint8_t packet_type = data[offset]; 120 // parse packet header (ignore len field)
108 uint8_t hci_h4_type = 0xff; 121 uint32_t ts_secs = big_endian_read_32(data, 4);
109 uint32_t direction; 122 uint32_t ts_us = big_endian_read_32(data, 8);
123 uint8_t packet_type = data[12];
124 data += 13;
125 len -= 13;
110 126
127 // map PacketLogger packet type onto PCAP direction flag and hci_h4_type
128 uint8_t direction_in = 0;
129 uint8_t hci_h4_type = 0xff;
111 switch(packet_type) { 130 switch(packet_type) {
112 case HCI_EVENT:
113 hci_h4_type = 0x04;
114 direction = LIBPCAP_BT_PHDR_RECV;
115 break;
116
117 case HCI_COMMAND: 131 case HCI_COMMAND:
118 hci_h4_type = 0x01; 132 hci_h4_type = 0x01;
119 direction = LIBPCAP_BT_PHDR_SENT; 133 direction_in = 0;
120 break; 134 break;
121
122 case SENT_ACL_DATA: 135 case SENT_ACL_DATA:
123 hci_h4_type = 0x02; 136 hci_h4_type = 0x02;
124 direction = LIBPCAP_BT_PHDR_SENT; 137 direction_in = 0;
125 break; 138 break;
126
127 case RECV_ACL_DATA: 139 case RECV_ACL_DATA:
128 hci_h4_type = 0x02; 140 hci_h4_type = 0x02;
129 direction = LIBPCAP_BT_PHDR_RECV; 141 direction_in = 1;
130 break; 142 break;
131 143 case SENT_SCO_DATA:
132 default: 144 hci_h4_type = 0x03;
133 // unknown packet logger type, just pass it on 145 direction_in = 0;
134 hci_h4_type = packet_type;
135 direction = LIBPCAP_BT_PHDR_RECV;
136 break; 146 break;
147 case RECV_SCO_DATA:
148 hci_h4_type = 0x03;
149 direction_in = 1;
150 break;
151 case HCI_EVENT:
152 hci_h4_type = 0x04;
153 direction_in = 1;
154 break;
155 default:
156 // unknown packet logger type, drop packet
157 return;
137 } 158 }
138 if(hci_h4_type != 0xff) { 159
139 data[offset] = hci_h4_type; 160 // setup pcap record header, 4 byte direction flag, 1 byte HCI H4 packet type, data
140 // we know we are sizeof(bt_packet_logger_header_t) into the buffer passed in to 161 uint8_t pcap_record_header[21];
141 // this function. We need to add the uint32_t pseudo header to the front of the packet 162 big_endian_store_32(pcap_record_header, 0, ts_secs); // Timestamp seconds
142 // so adjust the offset back by sizeof(uint32_t) and write it to the buffer. This avoids 163 big_endian_store_32(pcap_record_header, 4, ts_us); // Timestamp microseconds
143 // having to memcpy things around. 164 big_endian_store_32(pcap_record_header, 8, 4 + 1 + len); // Captured Packet Length
144 offset -= sizeof(uint32_t); 165 big_endian_store_32(pcap_record_header, 12, 4 + 1 + len); // Original Packet Length
145 *(uint32_t*)&data[offset] = direction; 166 big_endian_store_32(pcap_record_header, 16, direction_in); // Direction: Incoming = 1
146 pcap_dump((unsigned char*)pcap_dumper, &pcap_header, &data[offset]); 167 pcap_record_header[20] = hci_h4_type;
147 pcap_dump_flush(pcap_dumper); 168
148 } 169 // write header
170 (void) fwrite(pcap_record_header, 1, sizeof(pcap_record_header), packetlogger_file);
171
172 // write packet
173 (void) fwrite(data, 1, len, packetlogger_file);
174
175 // flush
176 (void) fflush(packetlogger_file);
149} 177}
150 178
151/** 179/**
@@ -212,8 +240,8 @@ static int start_logging(void)
212 return -1; 240 return -1;
213 } 241 }
214 242
215 fprintf(stdout, "[connected:%s]\n", udid); 243 fprintf(stderr, "[connected:%s]\n", udid);
216 fflush(stdout); 244 fflush(stderr);
217 245
218 return 0; 246 return 0;
219} 247}
@@ -242,7 +270,7 @@ static void device_event_cb(const idevice_event_t* event, void* userdata)
242 } else if (event->event == IDEVICE_DEVICE_REMOVE) { 270 } else if (event->event == IDEVICE_DEVICE_REMOVE) {
243 if (bt_packet_logger && (strcmp(udid, event->udid) == 0)) { 271 if (bt_packet_logger && (strcmp(udid, event->udid) == 0)) {
244 stop_logging(); 272 stop_logging();
245 fprintf(stdout, "[disconnected:%s]\n", udid); 273 fprintf(stderr, "[disconnected:%s]\n", udid);
246 if (exit_on_disconnect) { 274 if (exit_on_disconnect) {
247 quit_flag++; 275 quit_flag++;
248 } 276 }
@@ -352,7 +380,7 @@ int main(int argc, char *argv[])
352 380
353 if (optind < argc) { 381 if (optind < argc) {
354 out_filename = argv[optind]; 382 out_filename = argv[optind];
355 printf("Output File: %s\n", out_filename); 383 // printf("Output File: %s\n", out_filename);
356 } 384 }
357 else { 385 else {
358 print_usage(argc, argv, 1); 386 print_usage(argc, argv, 1);
@@ -375,7 +403,6 @@ int main(int argc, char *argv[])
375 idevice_info_t *devices = NULL; 403 idevice_info_t *devices = NULL;
376 idevice_get_device_list_extended(&devices, &num); 404 idevice_get_device_list_extended(&devices, &num);
377 idevice_device_list_extended_free(devices); 405 idevice_device_list_extended_free(devices);
378 int oflags;
379 if (num == 0) { 406 if (num == 0) {
380 if (!udid) { 407 if (!udid) {
381 fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n"); 408 fprintf(stderr, "No device found. Plug in a device or pass UDID with -u to wait for device to be available.\n");
@@ -385,22 +412,27 @@ int main(int argc, char *argv[])
385 } 412 }
386 } 413 }
387 414
415 // support streaming to stdout
416 if (strcmp(out_filename, "-") == 0){
417 packetlogger_file = stdout;
418 } else {
419 packetlogger_file = fopen(out_filename, "wb");
420 }
421
422
423 if (packetlogger_file == NULL){
424 fprintf(stderr, "Failed to open file %s, errno = %d\n", out_filename, errno);
425 return -2;
426 }
427
388 switch (log_format){ 428 switch (log_format){
389 case LOG_FORMAT_PCAP: 429 case LOG_FORMAT_PCAP:
390 printf("Output Format: PCAP\n"); 430 // printf("Output Format: PCAP\n");
391 pcap_dumper = pcap_dump_open(pcap_open_dead(DLT_BLUETOOTH_HCI_H4_WITH_PHDR, BT_MAX_PACKET_SIZE), out_filename); 431 // write PCAP file header
432 (void) fwrite(&pcap_file_header, 1, sizeof(pcap_file_header), packetlogger_file);
392 break; 433 break;
393 case LOG_FORMAT_PACKETLOGGER: 434 case LOG_FORMAT_PACKETLOGGER:
394 printf("Output Format: PacketLogger\n"); 435 printf("Output Format: PacketLogger\n");
395 oflags = O_WRONLY | O_CREAT | O_TRUNC;
396#ifdef WIN32
397 default_oflags |= O_BINARY;
398#endif
399 packetlogger_fd = open(out_filename, oflags);
400 if (packetlogger_fd < 0){
401 fprintf(stderr, "Failed to open file %s, errno = %d\n", out_filename, errno);
402 return -2;
403 }
404 break; 436 break;
405 default: 437 default:
406 assert(0); 438 assert(0);
@@ -415,12 +447,7 @@ int main(int argc, char *argv[])
415 idevice_event_unsubscribe(); 447 idevice_event_unsubscribe();
416 stop_logging(); 448 stop_logging();
417 449
418 if (pcap_dumper) { 450 fclose(packetlogger_file);
419 pcap_dump_close(pcap_dumper);
420 }
421 if (packetlogger_fd >= 0){
422 close(packetlogger_fd);
423 }
424 451
425 free(udid); 452 free(udid);
426 453