1681ed54cSXin LI /* 2681ed54cSXin LI * Copyright (c) 2012 Jakub Zawadzki 3681ed54cSXin LI * All rights reserved. 4681ed54cSXin LI * 5681ed54cSXin LI * Redistribution and use in source and binary forms, with or without 6681ed54cSXin LI * modification, are permitted provided that the following conditions 7681ed54cSXin LI * are met: 8681ed54cSXin LI * 9681ed54cSXin LI * 1. Redistributions of source code must retain the above copyright 10681ed54cSXin LI * notice, this list of conditions and the following disclaimer. 11681ed54cSXin LI * 2. Redistributions in binary form must reproduce the above copyright 12681ed54cSXin LI * notice, this list of conditions and the following disclaimer in the 13681ed54cSXin LI * documentation and/or other materials provided with the distribution. 14681ed54cSXin LI * 3. The name of the author may not be used to endorse or promote 15681ed54cSXin LI * products derived from this software without specific prior written 16681ed54cSXin LI * permission. 17681ed54cSXin LI * 18681ed54cSXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19681ed54cSXin LI * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20681ed54cSXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21681ed54cSXin LI * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22681ed54cSXin LI * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23681ed54cSXin LI * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24681ed54cSXin LI * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25681ed54cSXin LI * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26681ed54cSXin LI * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27681ed54cSXin LI * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28681ed54cSXin LI * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29681ed54cSXin LI */ 30681ed54cSXin LI 31681ed54cSXin LI #ifdef HAVE_CONFIG_H 32681ed54cSXin LI #include "config.h" 33681ed54cSXin LI #endif 34681ed54cSXin LI 35681ed54cSXin LI #include <string.h> 36681ed54cSXin LI 37681ed54cSXin LI #include <time.h> 38681ed54cSXin LI #include <sys/time.h> 39681ed54cSXin LI 40681ed54cSXin LI #include <dbus/dbus.h> 41681ed54cSXin LI 42681ed54cSXin LI #include "pcap-int.h" 43681ed54cSXin LI #include "pcap-dbus.h" 44681ed54cSXin LI 45681ed54cSXin LI /* 46681ed54cSXin LI * Private data for capturing on D-Bus. 47681ed54cSXin LI */ 48681ed54cSXin LI struct pcap_dbus { 49681ed54cSXin LI DBusConnection *conn; 50681ed54cSXin LI u_int packets_read; /* count of packets read */ 51681ed54cSXin LI }; 52681ed54cSXin LI 53681ed54cSXin LI static int 54681ed54cSXin LI dbus_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 55681ed54cSXin LI { 56681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 57681ed54cSXin LI 58681ed54cSXin LI struct pcap_pkthdr pkth; 59681ed54cSXin LI DBusMessage *message; 60681ed54cSXin LI 61681ed54cSXin LI char *raw_msg; 62681ed54cSXin LI int raw_msg_len; 63681ed54cSXin LI 64681ed54cSXin LI int count = 0; 65681ed54cSXin LI 66681ed54cSXin LI message = dbus_connection_pop_message(handlep->conn); 67681ed54cSXin LI 68681ed54cSXin LI while (!message) { 69*ada6f083SXin LI /* XXX handle->opt.timeout = timeout_ms; */ 70681ed54cSXin LI if (!dbus_connection_read_write(handlep->conn, 100)) { 71*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed"); 72681ed54cSXin LI return -1; 73681ed54cSXin LI } 74681ed54cSXin LI 75681ed54cSXin LI if (handle->break_loop) { 76681ed54cSXin LI handle->break_loop = 0; 77681ed54cSXin LI return -2; 78681ed54cSXin LI } 79681ed54cSXin LI 80681ed54cSXin LI message = dbus_connection_pop_message(handlep->conn); 81681ed54cSXin LI } 82681ed54cSXin LI 83681ed54cSXin LI if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { 84*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected"); 85681ed54cSXin LI return -1; 86681ed54cSXin LI } 87681ed54cSXin LI 88681ed54cSXin LI if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) { 89681ed54cSXin LI pkth.caplen = pkth.len = raw_msg_len; 90681ed54cSXin LI /* pkth.caplen = min (payload_len, handle->snapshot); */ 91681ed54cSXin LI 92681ed54cSXin LI gettimeofday(&pkth.ts, NULL); 93681ed54cSXin LI if (handle->fcode.bf_insns == NULL || 94681ed54cSXin LI bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) { 95681ed54cSXin LI handlep->packets_read++; 96681ed54cSXin LI callback(user, &pkth, (u_char *)raw_msg); 97681ed54cSXin LI count++; 98681ed54cSXin LI } 99681ed54cSXin LI 100681ed54cSXin LI dbus_free(raw_msg); 101681ed54cSXin LI } 102681ed54cSXin LI return count; 103681ed54cSXin LI } 104681ed54cSXin LI 105681ed54cSXin LI static int 106681ed54cSXin LI dbus_write(pcap_t *handle, const void *buf, size_t size) 107681ed54cSXin LI { 108681ed54cSXin LI /* XXX, not tested */ 109681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 110681ed54cSXin LI 111681ed54cSXin LI DBusError error = DBUS_ERROR_INIT; 112681ed54cSXin LI DBusMessage *msg; 113681ed54cSXin LI 114681ed54cSXin LI if (!(msg = dbus_message_demarshal(buf, size, &error))) { 115*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message); 116681ed54cSXin LI dbus_error_free(&error); 117681ed54cSXin LI return -1; 118681ed54cSXin LI } 119681ed54cSXin LI 120681ed54cSXin LI dbus_connection_send(handlep->conn, msg, NULL); 121681ed54cSXin LI dbus_connection_flush(handlep->conn); 122681ed54cSXin LI 123681ed54cSXin LI dbus_message_unref(msg); 124681ed54cSXin LI return 0; 125681ed54cSXin LI } 126681ed54cSXin LI 127681ed54cSXin LI static int 128681ed54cSXin LI dbus_stats(pcap_t *handle, struct pcap_stat *stats) 129681ed54cSXin LI { 130681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 131681ed54cSXin LI 132681ed54cSXin LI stats->ps_recv = handlep->packets_read; 133681ed54cSXin LI stats->ps_drop = 0; 134681ed54cSXin LI stats->ps_ifdrop = 0; 135681ed54cSXin LI return 0; 136681ed54cSXin LI } 137681ed54cSXin LI 138681ed54cSXin LI static void 139681ed54cSXin LI dbus_cleanup(pcap_t *handle) 140681ed54cSXin LI { 141681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 142681ed54cSXin LI 143681ed54cSXin LI dbus_connection_unref(handlep->conn); 144681ed54cSXin LI 145681ed54cSXin LI pcap_cleanup_live_common(handle); 146681ed54cSXin LI } 147681ed54cSXin LI 148681ed54cSXin LI static int 149681ed54cSXin LI dbus_activate(pcap_t *handle) 150681ed54cSXin LI { 151681ed54cSXin LI #define EAVESDROPPING_RULE "eavesdrop=true," 152681ed54cSXin LI 153681ed54cSXin LI static const char *rules[] = { 154681ed54cSXin LI EAVESDROPPING_RULE "type='signal'", 155681ed54cSXin LI EAVESDROPPING_RULE "type='method_call'", 156681ed54cSXin LI EAVESDROPPING_RULE "type='method_return'", 157681ed54cSXin LI EAVESDROPPING_RULE "type='error'", 158681ed54cSXin LI }; 159681ed54cSXin LI 160681ed54cSXin LI #define N_RULES sizeof(rules)/sizeof(rules[0]) 161681ed54cSXin LI 162681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 163*ada6f083SXin LI const char *dev = handle->opt.device; 164681ed54cSXin LI 165681ed54cSXin LI DBusError error = DBUS_ERROR_INIT; 166*ada6f083SXin LI u_int i; 167681ed54cSXin LI 168681ed54cSXin LI if (strcmp(dev, "dbus-system") == 0) { 169681ed54cSXin LI if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) { 170*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message); 171681ed54cSXin LI dbus_error_free(&error); 172681ed54cSXin LI return PCAP_ERROR; 173681ed54cSXin LI } 174681ed54cSXin LI 175681ed54cSXin LI } else if (strcmp(dev, "dbus-session") == 0) { 176681ed54cSXin LI if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) { 177*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message); 178681ed54cSXin LI dbus_error_free(&error); 179681ed54cSXin LI return PCAP_ERROR; 180681ed54cSXin LI } 181681ed54cSXin LI 182681ed54cSXin LI } else if (strncmp(dev, "dbus://", 7) == 0) { 183681ed54cSXin LI const char *addr = dev + 7; 184681ed54cSXin LI 185681ed54cSXin LI if (!(handlep->conn = dbus_connection_open(addr, &error))) { 186*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message); 187681ed54cSXin LI dbus_error_free(&error); 188681ed54cSXin LI return PCAP_ERROR; 189681ed54cSXin LI } 190681ed54cSXin LI 191681ed54cSXin LI if (!dbus_bus_register(handlep->conn, &error)) { 192*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message); 193681ed54cSXin LI dbus_error_free(&error); 194681ed54cSXin LI return PCAP_ERROR; 195681ed54cSXin LI } 196681ed54cSXin LI 197681ed54cSXin LI } else { 198*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device); 199681ed54cSXin LI return PCAP_ERROR; 200681ed54cSXin LI } 201681ed54cSXin LI 202681ed54cSXin LI /* Initialize some components of the pcap structure. */ 203681ed54cSXin LI handle->bufsize = 0; 204681ed54cSXin LI handle->offset = 0; 205681ed54cSXin LI handle->linktype = DLT_DBUS; 206681ed54cSXin LI handle->read_op = dbus_read; 207681ed54cSXin LI handle->inject_op = dbus_write; 208681ed54cSXin LI handle->setfilter_op = install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */ 209681ed54cSXin LI handle->setdirection_op = NULL; 210681ed54cSXin LI handle->set_datalink_op = NULL; /* can't change data link type */ 211681ed54cSXin LI handle->getnonblock_op = pcap_getnonblock_fd; 212681ed54cSXin LI handle->setnonblock_op = pcap_setnonblock_fd; 213681ed54cSXin LI handle->stats_op = dbus_stats; 214681ed54cSXin LI 215681ed54cSXin LI handle->selectable_fd = handle->fd = -1; 216681ed54cSXin LI 217681ed54cSXin LI if (handle->opt.rfmon) { 218681ed54cSXin LI /* 219681ed54cSXin LI * Monitor mode doesn't apply to dbus connections. 220681ed54cSXin LI */ 221681ed54cSXin LI dbus_cleanup(handle); 222681ed54cSXin LI return PCAP_ERROR_RFMON_NOTSUP; 223681ed54cSXin LI } 224681ed54cSXin LI 225681ed54cSXin LI /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */ 226681ed54cSXin LI if (handle->opt.buffer_size != 0) 227681ed54cSXin LI dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size); 228681ed54cSXin LI 229681ed54cSXin LI for (i = 0; i < N_RULES; i++) { 230681ed54cSXin LI dbus_bus_add_match(handlep->conn, rules[i], &error); 231681ed54cSXin LI if (dbus_error_is_set(&error)) { 232681ed54cSXin LI dbus_error_free(&error); 233681ed54cSXin LI 234681ed54cSXin LI /* try without eavesdrop */ 235681ed54cSXin LI dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error); 236681ed54cSXin LI if (dbus_error_is_set(&error)) { 237*ada6f083SXin LI pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message); 238681ed54cSXin LI dbus_error_free(&error); 239681ed54cSXin LI dbus_cleanup(handle); 240681ed54cSXin LI return PCAP_ERROR; 241681ed54cSXin LI } 242681ed54cSXin LI } 243681ed54cSXin LI } 244681ed54cSXin LI 245681ed54cSXin LI return 0; 246681ed54cSXin LI } 247681ed54cSXin LI 248681ed54cSXin LI pcap_t * 249681ed54cSXin LI dbus_create(const char *device, char *ebuf, int *is_ours) 250681ed54cSXin LI { 251681ed54cSXin LI pcap_t *p; 252681ed54cSXin LI 253681ed54cSXin LI if (strcmp(device, "dbus-system") && 254681ed54cSXin LI strcmp(device, "dbus-session") && 255681ed54cSXin LI strncmp(device, "dbus://", 7)) 256681ed54cSXin LI { 257681ed54cSXin LI *is_ours = 0; 258681ed54cSXin LI return NULL; 259681ed54cSXin LI } 260681ed54cSXin LI 261681ed54cSXin LI *is_ours = 1; 262*ada6f083SXin LI p = pcap_create_common(ebuf, sizeof (struct pcap_dbus)); 263681ed54cSXin LI if (p == NULL) 264681ed54cSXin LI return (NULL); 265681ed54cSXin LI 266681ed54cSXin LI p->activate_op = dbus_activate; 267681ed54cSXin LI return (p); 268681ed54cSXin LI } 269681ed54cSXin LI 270681ed54cSXin LI int 271681ed54cSXin LI dbus_findalldevs(pcap_if_t **alldevsp, char *err_str) 272681ed54cSXin LI { 273681ed54cSXin LI if (pcap_add_if(alldevsp, "dbus-system", 0, "D-Bus system bus", err_str) < 0) 274681ed54cSXin LI return -1; 275681ed54cSXin LI if (pcap_add_if(alldevsp, "dbus-session", 0, "D-Bus session bus", err_str) < 0) 276681ed54cSXin LI return -1; 277681ed54cSXin LI return 0; 278681ed54cSXin LI } 279681ed54cSXin LI 280