1*681ed54cSXin LI /* 2*681ed54cSXin LI * Copyright (c) 2012 Jakub Zawadzki 3*681ed54cSXin LI * All rights reserved. 4*681ed54cSXin LI * 5*681ed54cSXin LI * Redistribution and use in source and binary forms, with or without 6*681ed54cSXin LI * modification, are permitted provided that the following conditions 7*681ed54cSXin LI * are met: 8*681ed54cSXin LI * 9*681ed54cSXin LI * 1. Redistributions of source code must retain the above copyright 10*681ed54cSXin LI * notice, this list of conditions and the following disclaimer. 11*681ed54cSXin LI * 2. Redistributions in binary form must reproduce the above copyright 12*681ed54cSXin LI * notice, this list of conditions and the following disclaimer in the 13*681ed54cSXin LI * documentation and/or other materials provided with the distribution. 14*681ed54cSXin LI * 3. The name of the author may not be used to endorse or promote 15*681ed54cSXin LI * products derived from this software without specific prior written 16*681ed54cSXin LI * permission. 17*681ed54cSXin LI * 18*681ed54cSXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19*681ed54cSXin LI * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20*681ed54cSXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21*681ed54cSXin LI * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22*681ed54cSXin LI * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23*681ed54cSXin LI * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24*681ed54cSXin LI * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25*681ed54cSXin LI * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26*681ed54cSXin LI * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27*681ed54cSXin LI * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28*681ed54cSXin LI * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29*681ed54cSXin LI */ 30*681ed54cSXin LI 31*681ed54cSXin LI #ifdef HAVE_CONFIG_H 32*681ed54cSXin LI #include "config.h" 33*681ed54cSXin LI #endif 34*681ed54cSXin LI 35*681ed54cSXin LI #include <string.h> 36*681ed54cSXin LI 37*681ed54cSXin LI #include <time.h> 38*681ed54cSXin LI #include <sys/time.h> 39*681ed54cSXin LI 40*681ed54cSXin LI #include <dbus/dbus.h> 41*681ed54cSXin LI 42*681ed54cSXin LI #include "pcap-int.h" 43*681ed54cSXin LI #include "pcap-dbus.h" 44*681ed54cSXin LI 45*681ed54cSXin LI /* 46*681ed54cSXin LI * Private data for capturing on D-Bus. 47*681ed54cSXin LI */ 48*681ed54cSXin LI struct pcap_dbus { 49*681ed54cSXin LI DBusConnection *conn; 50*681ed54cSXin LI u_int packets_read; /* count of packets read */ 51*681ed54cSXin LI }; 52*681ed54cSXin LI 53*681ed54cSXin LI static int 54*681ed54cSXin LI dbus_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 55*681ed54cSXin LI { 56*681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 57*681ed54cSXin LI 58*681ed54cSXin LI struct pcap_pkthdr pkth; 59*681ed54cSXin LI DBusMessage *message; 60*681ed54cSXin LI 61*681ed54cSXin LI char *raw_msg; 62*681ed54cSXin LI int raw_msg_len; 63*681ed54cSXin LI 64*681ed54cSXin LI int count = 0; 65*681ed54cSXin LI 66*681ed54cSXin LI message = dbus_connection_pop_message(handlep->conn); 67*681ed54cSXin LI 68*681ed54cSXin LI while (!message) { 69*681ed54cSXin LI // XXX handle->opt.timeout = timeout_ms; 70*681ed54cSXin LI if (!dbus_connection_read_write(handlep->conn, 100)) { 71*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed"); 72*681ed54cSXin LI return -1; 73*681ed54cSXin LI } 74*681ed54cSXin LI 75*681ed54cSXin LI if (handle->break_loop) { 76*681ed54cSXin LI handle->break_loop = 0; 77*681ed54cSXin LI return -2; 78*681ed54cSXin LI } 79*681ed54cSXin LI 80*681ed54cSXin LI message = dbus_connection_pop_message(handlep->conn); 81*681ed54cSXin LI } 82*681ed54cSXin LI 83*681ed54cSXin LI if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { 84*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected"); 85*681ed54cSXin LI return -1; 86*681ed54cSXin LI } 87*681ed54cSXin LI 88*681ed54cSXin LI if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) { 89*681ed54cSXin LI pkth.caplen = pkth.len = raw_msg_len; 90*681ed54cSXin LI /* pkth.caplen = min (payload_len, handle->snapshot); */ 91*681ed54cSXin LI 92*681ed54cSXin LI gettimeofday(&pkth.ts, NULL); 93*681ed54cSXin LI if (handle->fcode.bf_insns == NULL || 94*681ed54cSXin LI bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) { 95*681ed54cSXin LI handlep->packets_read++; 96*681ed54cSXin LI callback(user, &pkth, (u_char *)raw_msg); 97*681ed54cSXin LI count++; 98*681ed54cSXin LI } 99*681ed54cSXin LI 100*681ed54cSXin LI dbus_free(raw_msg); 101*681ed54cSXin LI } 102*681ed54cSXin LI return count; 103*681ed54cSXin LI } 104*681ed54cSXin LI 105*681ed54cSXin LI static int 106*681ed54cSXin LI dbus_write(pcap_t *handle, const void *buf, size_t size) 107*681ed54cSXin LI { 108*681ed54cSXin LI /* XXX, not tested */ 109*681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 110*681ed54cSXin LI 111*681ed54cSXin LI DBusError error = DBUS_ERROR_INIT; 112*681ed54cSXin LI DBusMessage *msg; 113*681ed54cSXin LI 114*681ed54cSXin LI if (!(msg = dbus_message_demarshal(buf, size, &error))) { 115*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message); 116*681ed54cSXin LI dbus_error_free(&error); 117*681ed54cSXin LI return -1; 118*681ed54cSXin LI } 119*681ed54cSXin LI 120*681ed54cSXin LI dbus_connection_send(handlep->conn, msg, NULL); 121*681ed54cSXin LI dbus_connection_flush(handlep->conn); 122*681ed54cSXin LI 123*681ed54cSXin LI dbus_message_unref(msg); 124*681ed54cSXin LI return 0; 125*681ed54cSXin LI } 126*681ed54cSXin LI 127*681ed54cSXin LI static int 128*681ed54cSXin LI dbus_stats(pcap_t *handle, struct pcap_stat *stats) 129*681ed54cSXin LI { 130*681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 131*681ed54cSXin LI 132*681ed54cSXin LI stats->ps_recv = handlep->packets_read; 133*681ed54cSXin LI stats->ps_drop = 0; 134*681ed54cSXin LI stats->ps_ifdrop = 0; 135*681ed54cSXin LI return 0; 136*681ed54cSXin LI } 137*681ed54cSXin LI 138*681ed54cSXin LI static void 139*681ed54cSXin LI dbus_cleanup(pcap_t *handle) 140*681ed54cSXin LI { 141*681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 142*681ed54cSXin LI 143*681ed54cSXin LI dbus_connection_unref(handlep->conn); 144*681ed54cSXin LI 145*681ed54cSXin LI pcap_cleanup_live_common(handle); 146*681ed54cSXin LI } 147*681ed54cSXin LI 148*681ed54cSXin LI static int 149*681ed54cSXin LI dbus_activate(pcap_t *handle) 150*681ed54cSXin LI { 151*681ed54cSXin LI #define EAVESDROPPING_RULE "eavesdrop=true," 152*681ed54cSXin LI 153*681ed54cSXin LI static const char *rules[] = { 154*681ed54cSXin LI EAVESDROPPING_RULE "type='signal'", 155*681ed54cSXin LI EAVESDROPPING_RULE "type='method_call'", 156*681ed54cSXin LI EAVESDROPPING_RULE "type='method_return'", 157*681ed54cSXin LI EAVESDROPPING_RULE "type='error'", 158*681ed54cSXin LI }; 159*681ed54cSXin LI 160*681ed54cSXin LI #define N_RULES sizeof(rules)/sizeof(rules[0]) 161*681ed54cSXin LI 162*681ed54cSXin LI struct pcap_dbus *handlep = handle->priv; 163*681ed54cSXin LI const char *dev = handle->opt.source; 164*681ed54cSXin LI 165*681ed54cSXin LI DBusError error = DBUS_ERROR_INIT; 166*681ed54cSXin LI int i; 167*681ed54cSXin LI 168*681ed54cSXin LI if (strcmp(dev, "dbus-system") == 0) { 169*681ed54cSXin LI if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) { 170*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message); 171*681ed54cSXin LI dbus_error_free(&error); 172*681ed54cSXin LI return PCAP_ERROR; 173*681ed54cSXin LI } 174*681ed54cSXin LI 175*681ed54cSXin LI } else if (strcmp(dev, "dbus-session") == 0) { 176*681ed54cSXin LI if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) { 177*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message); 178*681ed54cSXin LI dbus_error_free(&error); 179*681ed54cSXin LI return PCAP_ERROR; 180*681ed54cSXin LI } 181*681ed54cSXin LI 182*681ed54cSXin LI } else if (strncmp(dev, "dbus://", 7) == 0) { 183*681ed54cSXin LI const char *addr = dev + 7; 184*681ed54cSXin LI 185*681ed54cSXin LI if (!(handlep->conn = dbus_connection_open(addr, &error))) { 186*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message); 187*681ed54cSXin LI dbus_error_free(&error); 188*681ed54cSXin LI return PCAP_ERROR; 189*681ed54cSXin LI } 190*681ed54cSXin LI 191*681ed54cSXin LI if (!dbus_bus_register(handlep->conn, &error)) { 192*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message); 193*681ed54cSXin LI dbus_error_free(&error); 194*681ed54cSXin LI return PCAP_ERROR; 195*681ed54cSXin LI } 196*681ed54cSXin LI 197*681ed54cSXin LI } else { 198*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.source); 199*681ed54cSXin LI return PCAP_ERROR; 200*681ed54cSXin LI } 201*681ed54cSXin LI 202*681ed54cSXin LI /* Initialize some components of the pcap structure. */ 203*681ed54cSXin LI handle->bufsize = 0; 204*681ed54cSXin LI handle->offset = 0; 205*681ed54cSXin LI handle->linktype = DLT_DBUS; 206*681ed54cSXin LI handle->read_op = dbus_read; 207*681ed54cSXin LI handle->inject_op = dbus_write; 208*681ed54cSXin LI handle->setfilter_op = install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */ 209*681ed54cSXin LI handle->setdirection_op = NULL; 210*681ed54cSXin LI handle->set_datalink_op = NULL; /* can't change data link type */ 211*681ed54cSXin LI handle->getnonblock_op = pcap_getnonblock_fd; 212*681ed54cSXin LI handle->setnonblock_op = pcap_setnonblock_fd; 213*681ed54cSXin LI handle->stats_op = dbus_stats; 214*681ed54cSXin LI 215*681ed54cSXin LI handle->selectable_fd = handle->fd = -1; 216*681ed54cSXin LI 217*681ed54cSXin LI if (handle->opt.rfmon) { 218*681ed54cSXin LI /* 219*681ed54cSXin LI * Monitor mode doesn't apply to dbus connections. 220*681ed54cSXin LI */ 221*681ed54cSXin LI dbus_cleanup(handle); 222*681ed54cSXin LI return PCAP_ERROR_RFMON_NOTSUP; 223*681ed54cSXin LI } 224*681ed54cSXin LI 225*681ed54cSXin LI /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */ 226*681ed54cSXin LI if (handle->opt.buffer_size != 0) 227*681ed54cSXin LI dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size); 228*681ed54cSXin LI 229*681ed54cSXin LI for (i = 0; i < N_RULES; i++) { 230*681ed54cSXin LI dbus_bus_add_match(handlep->conn, rules[i], &error); 231*681ed54cSXin LI if (dbus_error_is_set(&error)) { 232*681ed54cSXin LI dbus_error_free(&error); 233*681ed54cSXin LI 234*681ed54cSXin LI /* try without eavesdrop */ 235*681ed54cSXin LI dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error); 236*681ed54cSXin LI if (dbus_error_is_set(&error)) { 237*681ed54cSXin LI snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message); 238*681ed54cSXin LI dbus_error_free(&error); 239*681ed54cSXin LI dbus_cleanup(handle); 240*681ed54cSXin LI return PCAP_ERROR; 241*681ed54cSXin LI } 242*681ed54cSXin LI } 243*681ed54cSXin LI } 244*681ed54cSXin LI 245*681ed54cSXin LI return 0; 246*681ed54cSXin LI } 247*681ed54cSXin LI 248*681ed54cSXin LI pcap_t * 249*681ed54cSXin LI dbus_create(const char *device, char *ebuf, int *is_ours) 250*681ed54cSXin LI { 251*681ed54cSXin LI pcap_t *p; 252*681ed54cSXin LI 253*681ed54cSXin LI if (strcmp(device, "dbus-system") && 254*681ed54cSXin LI strcmp(device, "dbus-session") && 255*681ed54cSXin LI strncmp(device, "dbus://", 7)) 256*681ed54cSXin LI { 257*681ed54cSXin LI *is_ours = 0; 258*681ed54cSXin LI return NULL; 259*681ed54cSXin LI } 260*681ed54cSXin LI 261*681ed54cSXin LI *is_ours = 1; 262*681ed54cSXin LI p = pcap_create_common(device, ebuf, sizeof (struct pcap_dbus)); 263*681ed54cSXin LI if (p == NULL) 264*681ed54cSXin LI return (NULL); 265*681ed54cSXin LI 266*681ed54cSXin LI p->activate_op = dbus_activate; 267*681ed54cSXin LI return (p); 268*681ed54cSXin LI } 269*681ed54cSXin LI 270*681ed54cSXin LI int 271*681ed54cSXin LI dbus_findalldevs(pcap_if_t **alldevsp, char *err_str) 272*681ed54cSXin LI { 273*681ed54cSXin LI if (pcap_add_if(alldevsp, "dbus-system", 0, "D-Bus system bus", err_str) < 0) 274*681ed54cSXin LI return -1; 275*681ed54cSXin LI if (pcap_add_if(alldevsp, "dbus-session", 0, "D-Bus session bus", err_str) < 0) 276*681ed54cSXin LI return -1; 277*681ed54cSXin LI return 0; 278*681ed54cSXin LI } 279*681ed54cSXin LI 280