diff options
author | Michal Labedzki <michal.labedzki@tieto.com> | 2014-02-15 18:00:00 +0100 |
---|---|---|
committer | Michal Labedzki <michal.labedzki@tieto.com> | 2014-02-18 09:50:39 +0100 |
commit | 722d8fc9fe29e9712eda8a9467775323b8d5d316 (patch) | |
tree | 8d1b4655d386c55ac86caf4b10e561d7cf1a07c9 | |
parent | 5c8077e1fa83fb788e33ec1fedfe60074504e4d5 (diff) |
Add support for Bluetooth Linux Monitor interface
Interface "bluetooth_monitor" is used to monitoring all Bluetooth
adapters together on Linux platform.
-rw-r--r-- | CREDITS | 2 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rwxr-xr-x | configure | 3 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | pcap-bt-monitor-linux.c | 244 | ||||
-rw-r--r-- | pcap-bt-monitor-linux.h | 32 | ||||
-rw-r--r-- | pcap.c | 9 | ||||
-rw-r--r-- | pcap/bluetooth.h | 11 |
8 files changed, 304 insertions, 3 deletions
@@ -111,7 +111,7 @@ Additional people who have contributed patches: Márton Németh <nm127 at freemail dot hu> Matthew Luckie <mjl at luckie dot org dot nz> Max Laier <max at love2party dot net> - Michal Labedzki + Michal Labedzki <michal dot labedzki at tieto dot com> Michal Sekletar <msekleta at redhat dot com> Mike Frysinger <vapier at gmail dot com> Mike Kershaw <dragorn at kismetwireless dot net> diff --git a/Makefile.in b/Makefile.in index 47f5a06b..1c2d7459 100644 --- a/Makefile.in +++ b/Makefile.in @@ -83,7 +83,7 @@ YACC = @V_YACC@ @rm -f $@ $(CC) $(FULL_CFLAGS) -c $(srcdir)/$*.c -PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ +PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ @CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ FSRC = fad-@V_FINDALLDEVS@.c SSRC = @SSRC@ CSRC = pcap.c inet.c gencode.c optimize.c nametoaddr.c etherent.c \ @@ -295,6 +295,8 @@ EXTRA_DIST = \ pcap-bpf.c \ pcap-bt-linux.c \ pcap-bt-linux.h \ + pcap-bt-monitor-linux.c \ + pcap-bt-monitor-linux.h \ pcap-can-linux.c \ pcap-can-linux.h \ pcap-canusb-linux.c \ @@ -630,6 +630,7 @@ CAN_SRC PCAP_SUPPORT_CAN CANUSB_SRC PCAP_SUPPORT_CANUSB +BT_MONITOR_SRC BT_SRC PCAP_SUPPORT_BT NETFILTER_SRC @@ -8013,6 +8014,7 @@ if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes; then : $as_echo "#define PCAP_SUPPORT_BT 1" >>confdefs.h BT_SRC=pcap-bt-linux.c + BT_MONITOR_SRC=pcap-bt-monitor-linux.c { $as_echo "$as_me:${as_lineno-$LINENO}: Bluetooth sniffing is supported" >&5 $as_echo "$as_me: Bluetooth sniffing is supported" >&6;} @@ -8070,6 +8072,7 @@ $as_echo "$as_me: no Bluetooth sniffing support implemented for $host_os" >&6;} esac + fi # Check whether --enable-canusb was given. diff --git a/configure.in b/configure.in index 42cbe9b0..78ae5625 100644 --- a/configure.in +++ b/configure.in @@ -1465,6 +1465,7 @@ if test "x$enable_bluetooth" != "xno" ; then [ AC_DEFINE(PCAP_SUPPORT_BT, 1, [target host supports Bluetooth sniffing]) BT_SRC=pcap-bt-linux.c + BT_MONITOR_SRC=pcap-bt-monitor-linux.c AC_MSG_NOTICE(Bluetooth sniffing is supported) # @@ -1496,6 +1497,7 @@ if test "x$enable_bluetooth" != "xno" ; then esac AC_SUBST(PCAP_SUPPORT_BT) AC_SUBST(BT_SRC) + AC_SUBST(BT_MONITOR_SRC) fi AC_ARG_ENABLE([canusb], diff --git a/pcap-bt-monitor-linux.c b/pcap-bt-monitor-linux.c new file mode 100644 index 00000000..c96378d0 --- /dev/null +++ b/pcap-bt-monitor-linux.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2014 Michal Labedzki for Tieto Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef SOCKADDR_HCI_HAS_HCI_CHANNEL + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/hci.h> +#include <bluetooth/mgmt.h> + +#include "pcap/bluetooth.h" +#include "pcap-int.h" + +#define BT_CONTROL_SIZE 32 +#define INTERFACE_NAME "bluetooth-monitor" + +int +bt_monitor_findalldevs(pcap_if_t **alldevsp, char *err_str) +{ + int ret = 0; + + if (pcap_add_if(alldevsp, INTERFACE_NAME, 0, + "Bluetooth Linux Monitor", err_str) < 0) + { + ret = -1; + } + + return ret; +} + +static int +bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) +{ + struct cmsghdr *cmsg; + struct msghdr msg; + struct iovec iv[2]; + ssize_t ret; + struct pcap_pkthdr pkth; + pcap_bluetooth_linux_monitor_header *bthdr; + struct mgmt_hdr hdr; + int in = 0; + + bthdr = (pcap_bluetooth_linux_monitor_header*) &handle->buffer[handle->offset]; + + iv[0].iov_base = &hdr; + iv[0].iov_len = MGMT_HDR_SIZE; + iv[1].iov_base = &handle->buffer[handle->offset + sizeof(pcap_bluetooth_linux_monitor_header)]; + iv[1].iov_len = handle->snapshot; + + memset(&pkth.ts, 0, sizeof(pkth.ts)); + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iv; + msg.msg_iovlen = 2; + msg.msg_control = handle->buffer; + msg.msg_controllen = handle->offset; + + do { + ret = recvmsg(handle->fd, &msg, 0); + if (handle->break_loop) + { + handle->break_loop = 0; + return -2; + } + } while ((ret == -1) && (errno == EINTR)); + + if (ret < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't receive packet: %s", strerror(errno)); + return -1; + } + + pkth.caplen = ret - MGMT_HDR_SIZE + sizeof(pcap_bluetooth_linux_monitor_header); + pkth.len = pkth.caplen; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET) continue; + + if (cmsg->cmsg_type == SCM_TIMESTAMP) { + memcpy(&pkth.ts, CMSG_DATA(cmsg), sizeof(pkth.ts)); + } + } + + bthdr->adapter_id = htons(hdr.index); + bthdr->opcode = htons(hdr.opcode); + + if (handle->fcode.bf_insns == NULL || + bpf_filter(handle->fcode.bf_insns, &handle->buffer[handle->offset], + pkth.len, pkth.caplen)) { + callback(user, &pkth, &handle->buffer[handle->offset]); + return 1; + } + return 0; /* didn't pass filter */ +} + +static int +bt_monitor_inject(pcap_t *handle, const void *buf _U_, size_t size _U_) +{ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported yet"); + return -1; +} + +static int +bt_monitor_setdirection(pcap_t *p, pcap_direction_t d) +{ + p->direction = d; + return 0; +} + +static int +bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats) +{ + stats->ps_recv = 0; + stats->ps_drop = 0; + stats->ps_ifdrop = 0; + + return 0; +} + +static int +bt_monitor_activate(pcap_t* handle) +{ + struct sockaddr_hci addr; + int err = PCAP_ERROR; + int opt; + + if (handle->opt.rfmon) { + /* monitor mode doesn't apply here */ + return PCAP_ERROR_RFMON_NOTSUP; + } + + handle->bufsize = handle->snapshot + BT_CONTROL_SIZE + sizeof(pcap_bluetooth_linux_monitor_header); + handle->offset = BT_CONTROL_SIZE; + handle->linktype = DLT_BLUETOOTH_LINUX_MONITOR; + + handle->read_op = bt_monitor_read; + handle->inject_op = bt_monitor_inject; + handle->setfilter_op = install_bpf_program; /* no kernel filtering */ + handle->setdirection_op = bt_monitor_setdirection; + handle->set_datalink_op = NULL; /* can't change data link type */ + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = bt_monitor_stats; + + handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); + if (handle->fd < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't create raw socket: %s", strerror(errno)); + return PCAP_ERROR; + } + + handle->buffer = malloc(handle->bufsize); + if (!handle->buffer) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", + pcap_strerror(errno)); + goto close_fail; + } + + /* Bind socket to the HCI device */ + addr.hci_family = AF_BLUETOOTH; + addr.hci_dev = HCI_DEV_NONE; + addr.hci_channel = HCI_CHANNEL_MONITOR; + + if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't attach to interface: %s", strerror(errno)); + goto close_fail; + } + + opt = 1; + if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, + "Can't enable time stamp: %s", strerror(errno)); + goto close_fail; + } + + handle->selectable_fd = handle->fd; + + return 0; + +close_fail: + pcap_cleanup_live_common(handle); + return err; +} + +pcap_t * +bt_monitor_create(const char *device, char *ebuf, int *is_ours) +{ + pcap_t *p; + const char *cp; + + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + + if (strcmp(cp, INTERFACE_NAME) != 0) { + *is_ours = 0; + return NULL; + } + + *is_ours = 1; + p = pcap_create_common(device, ebuf, 0); + if (p == NULL) + return NULL; + + p->activate_op = bt_monitor_activate; + + return p; +} +#endif /* SOCKADDR_HCI_HAS_HCI_CHANNEL */
\ No newline at end of file diff --git a/pcap-bt-monitor-linux.h b/pcap-bt-monitor-linux.h new file mode 100644 index 00000000..aada2bc7 --- /dev/null +++ b/pcap-bt-monitor-linux.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Michal Labedzki for Tieto Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +int bt_monitor_findalldevs(pcap_if_t **alldevsp, char *err_str); +pcap_t *bt_monitor_create(const char *device, char *ebuf, int *is_ours); @@ -86,8 +86,13 @@ #ifdef PCAP_SUPPORT_BT #include "pcap-bt-linux.h" + +#ifdef SOCKADDR_HCI_HAS_HCI_CHANNEL +#include "pcap-bt-monitor-linux.h" #endif +#endif /* PCAP_SUPPORT_BT */ + #ifdef PCAP_SUPPORT_CAN #include "pcap-can-linux.h" #endif @@ -318,7 +323,10 @@ struct capture_source_type { #endif #ifdef PCAP_SUPPORT_BT { bt_findalldevs, bt_create }, +#ifdef SOCKADDR_HCI_HAS_HCI_CHANNEL + { bt_monitor_findalldevs, bt_monitor_create }, #endif +#endif /* PCAP_SUPPORT_BT */ #if PCAP_SUPPORT_CANUSB { canusb_findalldevs, canusb_create }, #endif @@ -1200,6 +1208,7 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(DLT_IPOIB, "RFC 4391 IP-over-Infiniband"), DLT_CHOICE(DLT_DBUS, "D-Bus"), DLT_CHOICE(DLT_NETLINK, "Linux netlink"), + DLT_CHOICE(DLT_BLUETOOTH_LINUX_MONITOR, "Bluetooth Linux Monitor"), DLT_CHOICE_SENTINEL }; diff --git a/pcap/bluetooth.h b/pcap/bluetooth.h index 06e86891..7cb0a8e8 100644 --- a/pcap/bluetooth.h +++ b/pcap/bluetooth.h @@ -35,12 +35,21 @@ #define _PCAP_BLUETOOTH_STRUCTS_H__ /* - * Header prepended libpcap to each bluetooth h:4 frame. + * Header prepended libpcap to each bluetooth h4 frame, * fields are in network byte order */ typedef struct _pcap_bluetooth_h4_header { u_int32_t direction; /* if first bit is set direction is incoming */ } pcap_bluetooth_h4_header; +/* + * Header prepended libpcap to each bluetooth linux monitor frame, + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_linux_monitor_header { + u_int16_t adapter_id; + u_int16_t opcode; +} pcap_bluetooth_linux_monitor_header; + #endif |