Impressum Kontakt

Bluetooth for fun and profit

(balle)

Bluetooth ist eine drahtlose Sprach- und Datenübertragungstechnik, die mittlerweile in den verschiedensten Geräten wie Handy, PDA, USB Stick, PCMCIA Karte, Tastatur, Maus, Headset, Drucker usw. zu finden ist. Im Gegensatz zu Infrarot ist Bluetooth nicht auf Sichtkontakt der zu verbindenden Geräte angewiesen und funktioniert mit guter Hardware auch durch Wände hindurch, ist also mit WLAN zu vergleichen und funkt ebenfalls im 2,4 GHz Bereich.

Beim Design von Bluetooth wurde speziell auf eine sichere Implementierung geachtet, so läßt sich die Verbindung verschlüsseln und authentifizieren und die Bluetooth Adresse wird von der Firmware des Bluetooth Geräts und nicht durch den Kernel gesetzt, was das Spoofen dieser Adresse nahezu unmöglich macht. Dennoch tauchten in der Vergangenheit immer wieder Meldung über Sicherheitslücken in den verschiedensten Bluetooth Implementationen von Herstellern wie Nokia und Siemens auf und man liest ständig über Bluejacking. Grund genug sich mal eingehend mit dieser Technologie auseinander zu setzen.

Here we are! :) Dieser Artikel beschreibt sowohl den Bluetooth Protokoll Stack und die Einrichtung von Bluetooth Hardware unter Linux 2.4 / 2.6 als auch typische Anwendungen wie Datenaustausch, Aufbau eines Netzwerks, Scannen nach Devices und Diensten und die Programmierung einfacher Anwendungen unter Verwendung der BlueZ Libraries.

Ein Überblick über den Bluetooth Protokollstack:

Bluetooth

Funk (Bluetooth Radio):

  • 2,4 GHz Ism Band (2400 - 2483,5 MHz)
  • 79 verfügbare Kanäle
  • Sendestärke: 1 mW - 100 mW
  • Reichweite: 1 - 100m
  • Frequenzwechsel nach jedem Paket

SCO / ACL (Bluetooth Baseband):

SCO (Synchonous Connection Oriented) baut eine synchrone verbindungsorientierte Punkt-zu-Punkt Verbindung auf und dient zur Sprachübertragung.

ACL (Asynchonous Connection Less) baut wahlweise eine synchrone oder asynchrone verbindungslose Punkt-zu-Punkt Verbindung auf und dient zur Datenübertragung.

Sowohl SCO als auch ACL werden durch die Firmware des Bluetooth Geräts implementiert.

LMP (Link Manager Protocol)

LMP kann man mit Ethernet vergleichen. Es implementiert die 48 Bit lange Bluetooth Adresse und ist für den Link Setup, die Authentifizierung sowie die Verschlüsselung zuständig. LMP wird durch die Firmware der Bluetooth Hardware implementiert. Einen guten Einblick in die Funktionsweise von LMP gibt es auf Palowireless.com.

HCI (Host Control Interface)

HCI bietet eine einheitliche Schnittstelle zur Bluetooth Firmware und gehört eigentlich nicht direkt zum Bluetooth Protokoll Stack, aber es wird unter anderem dazu verwendet L2CAP Pakete an den Link Manager der Firmware zu senden und ist somit der unterste Layer, der im Kernel implementiert ist. HCI dient außerdem dazu die aktuelle Config und Features sowie den Status des Geräts auszulesen und zu setzen. Die Kommunikation ist paket- und verbindungsorientiert.

L2CAP (Logical Link Control and Adaptation Protocol)

L2CAP kann man mit IP vergleichen. Die Hauptaufgabe dieses Protokolls ist die Fragmentierung, das Groupmanagement und die Implementierung höherer Protokolle wie RFCOMM, SDP oder BNEP. L2CAP baut über ACL eine Verbindung auf, über die dann die Pakete der anderen Protokolle geschleust werden. Auf Palowireless.com findest du mehr über L2CAP.

RFCOMM / SDP / BNEP

RFCOMM simuliert eine serielle Schnittstelle und wird somit z.B. für den Zugriff auf ein Modem, aber auch von weiteren Protokollen wie OBEX verwendet. Mehr zu RFCOMM * SDP (Service Discovery Protocol) dient der Abfrage der auf dem entfernten Device verfügbaren Dienste (Bluetooth Profile). Mehr zu SDP * BNEP kapselt Ipv4, Ipv6 oder IPX Pakete und dient somit für IP bzw. IPX Netzwerke via Bluetooth

Dienste heissen unter Bluetooth Profile. Sie bilden die Application Layer Protokolle einer Bluetooth Verbindung. Hier eine Auflistung der wichtigsten (diese Liste stammt von einem handelsüblichen Siemens S55 Mobiltelefon):

  • Modem Dial-up
  • Fax
  • OBEX File Transfer
  • OBEX Object Push
  • OBEX Synchronisation
  • Headset
  • SerialPort

Einen Überblick über diese und weitere Bluetooth Profile gibt es auf Palowireless.com.

Die Installation / Configuration / Benutzung geht von einem Linux System mit einem 2.4er oder 2.6er Kernel aus! Alle FreeBSDler seien auf das Bluetooth Kapitel des FreeBSD Handbuchs verwiesen. Mac OS X User sollten mit Bluetooth eh keine Probleme haben. ;P

Ok. Erstmal die Geschichte mit dem Kernel. Die BlueZ Treiber sind mittlerweile Bestandteil des offiziellen Kernels, ein patchen entfällt daher. Um sorglos mit Bluetooth spielen zu können solltest Du einfach alles was Dir zum Thema unter die Finger kommt als Modul compilen. Die absolut notwendigen Module, ausgehend von einem Bluetooth USB Stick und vorausgesetzt Du willst alle Beispiele in diesem Artikel nachvollziehen, sind

  • bluez / bluetooth
  • hci_usb
  • hci_uart
  • l2cap
  • rfcomm
  • bnep

Anschliessend installierst Du folgende Bluez Libraries und Tools:

  • bluez-utils
  • bluez-sdp
  • bluez-pin
  • bluez-pan
  • bluez-hcidump

Jetzt solltest Du Dein Bluetooth Device aktivieren können.

hciconfig hci0 up

Sollte das nicht der Fall sein, überprüfe, ob Du auch wirklich alle Kernel Module geladen hast! Mit hciconfig kann man sich außerdem die Eigenschaften seines Bluetooth Devices vergleichbar zu ifconfig anschauen und Verschlüsselung sowie Authentifikation ein- bzw. ausschalten.

hciconfig hci0 noauth noencrypt

Interessant ist noch, dass man mit hciconfig oder über die Config Datei /etc/bluetooth/hcid.conf die Device Class setzen kann. Eine Liste der Major und Minor Device Classes findet man auf Bluetooth.org.

Die Major und Minor Device Classes sind auf Bluetooth.org in Binär angegeben, hciconfig erwartet sie allerdings als Hex, deswegen hier ein kleines Rechenbeispiel:

  • Major Computer + Minor Laptop: 00001 000011 00 = 0x0001 0c
  • Major Phone + Minor Cellular: 00010 000001 00 = 0x0002 04

Wer zu faul zum umrechnen ist, der findet in khciconfig alle Major und Minor Device Classes zum zusammen klicken. ;)

Also um seinen Bluetooth USB Stick z.B. in ein Mobiltelefon zu "verwandeln", führt man folgenden Befehl aus:

hciconfig hci0 class 0x000204

Als erstes will man wahrscheinlich nach verfügbaren Bluetooth Geräten in seiner Umgebung suchen.

hcitool scan

Wenn man ein Bluetooth Gerät gefunden hat, kann man meistens bequem über SDP die verfügbaren Dienste auslesen. Ich sage meistens, weil Headphones oder andere Geräte, die nur einen Dienst anbieten, haben keinen SDP Daemon implementiert.

sdptool browse <btaddr>

Hier ein Auszug (ein Dienst / Profil) aus einem SDP Scan eines handelsüblichen Mobiltelefons:

Service Name: Dial-up networking
Service RecHandle: 0x11103
Service Class ID List:
  "Dialup Networking" (0x1103)
  "Generic Networking" (0x1201)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100
Profile Descriptor List:
  "Dialup Networking" (0x1103)
    Version: 0x0100

Dieses Profil zeigt ein Dial-up Network sprich ein Modem. Das wichtigste in dieser Liste sind neben dem Service Namen der Hinweis auf die zu verwendenden Protokolle (L2CAP und RFCOMM), sowie der Channel 1.

Schön und gut, dann werden wir uns jetzt mal zu diesem Modem verbinden und mal schauen was wir damit so anstellen können! :)

rfcomm bind 0 <btaddr> 0

Der erste Parameter bind sorgt dafür, dass der Bluetooth Socket nur an die entsprechende Adresse gebunden wird, aber keine Verbindung initiiert wird. Der zweite Parameter 0 ist die Nummer des RFCOMM Devices in diesem Falls also /dev/rfcomm0, dann folgt die Bluetooth Geräte Adresse und last but not least der Channel zu dem wir uns verbinden wollen.

Je nachdem ob Du unter der Console oder unter X unterwegs bist, wird die PIN Eingabe anders geregelt. Unter der Console wird die Datei /etc/bluetooth/pin ausgelesen, unter X solltest Du nen hübsches Fenster bekommen, das Dich zur PIN-Eingabe auffordert. Auf dem entfernten Gerät wirst Du ebenfalls zu einer Eingabe genötigt. Die beiden PINs müssen übereinstimmen!

Wenn Du alles richtig gemacht hast, kannst Du jetzt entweder via Minicom oder auch direkt per echo ATZ > /dev/rfcomm0 AT Befehle an das entfernte Modem senden und es behandeln als wäre es lokal.

Dateiaustausch findet über das OBEX (Object Exchange) Protokoll statt, welches auch schon für Irda (Infrarot) verwendet wird.

Um von der Console Dateien zu pushen, nimmt man am besten ussp-push. Das Archiv entpackt man in das Verzeichnis openobex-app/src, welches man sich von openobex.sourceforge.net downloaded und compiled es mit folgendendermaßen:

gcc -o obexserver obexserver.c libmisc.a -lopenobex cd ussp-push make ; make install

Dann nimmt man per RFCOMM mit dem entfernten OBEX Push Dienst Verbindung auf.

rfcomm bind 0 <btaddr> 4

Und sendet die Datei.

ussp-push /dev/rfcomm0

Zum synchonisieren zwischen einem Handy und einem Laptop / PDA verwende ich Multisync, da es nicht nur ein Backup des Mobiltelefons wahlweise via Kabel, Infrarot oder Bluetooth unterstützt, sondern auch meinen Lieblingsgroupwareclient Ximian Evolution bedienen kann und ich damit alle wichtigen Klamotten wie Kalendar, Telefonbuch, Aufgaben und Notizen auf dem neuesten Stand halten kann.

Ansonsten sollte man sich auf jeden Fall noch obexftp und die Bluetooth Tools vom GNOME sowie vom KDE Projekt anschaun. Damit kann man weitaus bequemer und grafisch Dateien austauschen wahlweise via Nautilus (GNOME) oder FTP-like kbtobexclient (KDE). Für Debian gibt es fertige DEB Pakete. Dazu fügt man einfach nur die folgenden Server in seine /etc/apt/sources.list ein:

  • deb http://debian.usefulinc.com/gnome ./
  • deb-src http://debian.usefulinc.com/gnome ./
  • deb http://www.stud.uni-karlsruhe.de/~uddw/debian ./

Und installiert die gewünschten Tools:

apt-get update apt-get install gnome-bluetooth apt-get install kdebluetooth

Vielleicht möchte man auch eine Datei von einem Handy oder sonst einem Bluetooth Gerät an den eigenen Rechner schicken und das ohne Hilfe dieser grafischen Tools? Nichts einfacher als das! Zuerst startet man netterweise einen SDP Daemon.

sdpd

Und teilt ihm mit, dass wir OBEX Push anbieten

sdptool --add --channel 10 OPUSH

Als letztes startet man den obexftp server und findet anschliessend hoch geladene Dateien im Verzeichnis /tmp.

obexftpserver

Jetzt basteln wir mit zwei Bluetooth Sticks mal ein kleines Netzwerk und verwenden es, um einen Gateway (wahlweise auch mit DHCP und was weiss ich) aufzubauen.

Auf dem Gateway startet man

pand --listen --persist --encrypt --role NAP

Auf dem Client

pand --connect <remote_btaddr>

Jetzt stehen auf beiden Rechner bnep0 Netzwerk Interfaces zur Verfügung, die man mit ifconfig upped und mit IP Adressen versieht.

ifconfig bnep0 <ipaddr> up

Abschließend aktiviert man auf dem Gateway noch Masquerading.

iptables -A POSTROUTING -t nat -o bnep0 -j MASQUERADE

Und trägt auf dem Client diese Kiste als Standardroute ein.

route add default gw <gateway_ipaddr>

Blue-CMD - Führe ein beliebiges Kommando aus, wenn sich ein Bluetooth Device im bzw. ausserhalb des Empfangsbereichs befindet. Ideal zum automatischen (ent)locken des Laptop, wenn man sich mit seinem Bluetooth Handy durch die Kneipe bewegt ;)

Blue-Scanner - Ein kleines Script, das ich auf dem 20C3 geschrieben habe. Es scannt nach Bluetooth Devices, liest die vorhandenen Profile via SDP aus und versucht mit OBEX Push eine Vcard hoch zu laden.

Redfang - Bruteforce Bluetooth Adressen. Ermöglicht es Geräte zu finden, die nicht sichtbar sind.

Bluesniff - Ein Ncurses basierter Bluetooth Sniffer.

Btscanner - Ein Ncurses basierter Bluetooth Scanner.

Alle Source Codes benötigen die Bluez Header Dateien und Libraries und werden wie folgt compiled:

gcc -lbluetooth -o <executable> <source>

Ein Beispiel für einen RFCOMM Client

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
#include <bluetooth/hci.h>

#define BTADDR "aa:bb:cc:aa:bb:cc"
#define CHANNEL 4

int main(void)
{
  int sock;
  struct sockaddr_rc laddr, raddr;
  struct hci_dev_info di;

  if(hci_devinfo(0, &di) < 0) 
    {
      perror("HCI device info failed");
      exit(1);
    }

  laddr.rc_family = AF_BLUETOOTH;
  laddr.rc_bdaddr = di.bdaddr;
  laddr.rc_channel = 0;

  raddr.rc_family = AF_BLUETOOTH;
  str2ba(BTADDR,&raddr.rc_bdaddr);
  raddr.rc_channel = htobs(CHANNEL);

  if(sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) < 0)
    {
      perror("socket");
      exit(1);
    }

  if(bind(sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0)
    {
      perror("bind");
      exit(1);
    }

  if(connect(sock, (struct sockaddr *)&raddr, sizeof(raddr)) < 0)
    {
      perror("connect");
      exit(1);
    }

  printf("Connected.\n");
  close(sock);
  return 0;
}

Ein Beispiel für einen RFCOMM Server

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>

#define CHANNEL 4
#define QUEUE 10

int main(void)
{
  int sock, client, alen;
  struct sockaddr_rc addr;

  if(sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM) < 0)
    {
      perror("socket");
      exit(1);
    }

  addr.rc_family = AF_BLUETOOTH;
  bacpy(&addr.rc_bdaddr, BDADDR_ANY);
  addr.rc_channel = htobs(CHANNEL);
  alen = sizeof(addr);

  if(bind(sock, (struct sockaddr *)&addr, alen) < 0)
    {
      perror("bind");
      exit(1);
    }

  listen(sock,QUEUE);
  printf("Waiting for connections...\n\n");

  while(client = accept(sock, (struct sockaddr *)&addr, &alen))
    {
      printf("Got a connection attempt!\n");
      close(client);
    }

  close(sock);
  return 0;
}

HCI Inquiry Scan

#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>

int main(void)
{
  inquiry_info *info = NULL;
  bdaddr_t bdaddr;
  char name[248];
  int dev_id = 0;
  int num_rsp = 10;
  int flags = 0;
  int length = 8;
  int dd, i;

  printf("Scanning ...\n");

  num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags);
  if(num_rsp < 0)
    {
      perror("Inquiry failed.");
      exit(1);
    }

  if((dd = hci_open_dev(dev_id)) < 0)
    {
      perror("HCI device open failed");
      free(info);
      exit(1);
    }

  for(i = 0; i < num_rsp; i++)
    {
      memset(name, 0, sizeof(name));

      if(hci_read_remote_name(dd, &(info+i)->bdaddr, sizeof(name), name, 100000) < 0)
	{
	  strcpy(name, "n/a");
	}

      baswap(&bdaddr, &(info+i)->bdaddr);
      printf("\t%s\t%s\n", batostr(&bdaddr), name);
  }

  close(dd);
  free(info);
  return 0;
}

Beispiel Code zum auslesen der Dienste eines SDP Servers

gcc -lbluetooth -lsdp -o <executable> <source>

#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>

int main(int argc, char *argv[])
{
  bdaddr_t bdaddr;
  sdp_list_t *attrid, *search, *seq;
  uint32_t range = 0x0000ffff;
  sdp_session_t *sess;
  struct hci_dev_info di;
  uuid_t root_uuid;

  if(argc < 2)
    {
      printf("%s <btaddr>\n", argv[0]);
      exit(0);
    }

  if(hci_devinfo(0, &di) < 0)
    {
      perror("HCI device info failed");
      exit(1);
    }

  str2ba(argv[1],&bdaddr);

  sess = sdp_connect(&di.bdaddr, &bdaddr, SDP_RETRY_IF_BUSY);

  if(!sess)
    {
      perror("Failed to connect to SDP server");
      exit(1);
    }

  printf("Browsing %s ...\n", argv[1]);

  sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
  attrid = sdp_list_append(0, &range);
  search = sdp_list_append(0, &root_uuid);

  if(sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq) < 0)
    {
      perror("SDP service search");
      sdp_close(sess);
      exit(1);
    }

  sdp_list_free(attrid, 0);
  sdp_list_free(search, 0);

  for(; seq; seq = seq->next)
    {
      sdp_record_t *rec = (sdp_record_t *) seq->data;
      sdp_list_t *access = NULL;
      int channel;

      sdp_record_print(rec);
      sdp_get_access_protos(rec, &access);

      if(access)
	{
	  channel = sdp_get_proto_port(access, RFCOMM_UUID);
	  printf("Channel: %d\n", channel);
	}
    }

    free(seq);
    sdp_close(sess);
    return 0;
}

Bluetooth.org - Die Bluetooth Spezifikation.

Holtmann.org - Jede Menge Artikel rund ums Thema Bluetooth.

Palowireless Bluetooth - Bluetooth Resource Center.

Irda.org - Hier gibt's die Spezifikation zu OBEX.

BlueZ - Der offizielle Linux Bluetooth Stack.

Affix - Ein alternativer Bluetooth Stack für Linux.

Bluetooth Security Bluetooth unter FreeBSD GNOME Bluetooth Subsystem KDE Bluetooth Framework