1335640Shselasky/* 2335640Shselasky * Copyright (c) 2012 Jakub Zawadzki 3335640Shselasky * All rights reserved. 4335640Shselasky * 5335640Shselasky * Redistribution and use in source and binary forms, with or without 6335640Shselasky * modification, are permitted provided that the following conditions 7335640Shselasky * are met: 8335640Shselasky * 9335640Shselasky * 1. Redistributions of source code must retain the above copyright 10335640Shselasky * notice, this list of conditions and the following disclaimer. 11335640Shselasky * 2. Redistributions in binary form must reproduce the above copyright 12335640Shselasky * notice, this list of conditions and the following disclaimer in the 13335640Shselasky * documentation and/or other materials provided with the distribution. 14335640Shselasky * 3. The name of the author may not be used to endorse or promote 15335640Shselasky * products derived from this software without specific prior written 16335640Shselasky * permission. 17335640Shselasky * 18335640Shselasky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19335640Shselasky * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20335640Shselasky * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21335640Shselasky * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22335640Shselasky * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23335640Shselasky * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24335640Shselasky * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25335640Shselasky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26335640Shselasky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27335640Shselasky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28335640Shselasky * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29335640Shselasky */ 30335640Shselasky 31335640Shselasky#ifdef HAVE_CONFIG_H 32335640Shselasky#include <config.h> 33335640Shselasky#endif 34335640Shselasky 35335640Shselasky#include <string.h> 36335640Shselasky 37335640Shselasky#include <time.h> 38335640Shselasky#include <sys/time.h> 39335640Shselasky 40335640Shselasky#include <dbus/dbus.h> 41335640Shselasky 42335640Shselasky#include "pcap-int.h" 43335640Shselasky#include "pcap-dbus.h" 44335640Shselasky 45335640Shselasky/* 46335640Shselasky * Private data for capturing on D-Bus. 47335640Shselasky */ 48335640Shselaskystruct pcap_dbus { 49335640Shselasky DBusConnection *conn; 50335640Shselasky u_int packets_read; /* count of packets read */ 51335640Shselasky}; 52335640Shselasky 53335640Shselaskystatic int 54335640Shselaskydbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user) 55335640Shselasky{ 56335640Shselasky struct pcap_dbus *handlep = handle->priv; 57335640Shselasky 58335640Shselasky struct pcap_pkthdr pkth; 59335640Shselasky DBusMessage *message; 60335640Shselasky 61335640Shselasky char *raw_msg; 62335640Shselasky int raw_msg_len; 63335640Shselasky 64335640Shselasky int count = 0; 65335640Shselasky 66335640Shselasky message = dbus_connection_pop_message(handlep->conn); 67335640Shselasky 68335640Shselasky while (!message) { 69335640Shselasky /* XXX handle->opt.timeout = timeout_ms; */ 70335640Shselasky if (!dbus_connection_read_write(handlep->conn, 100)) { 71335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed"); 72335640Shselasky return -1; 73335640Shselasky } 74335640Shselasky 75335640Shselasky if (handle->break_loop) { 76335640Shselasky handle->break_loop = 0; 77335640Shselasky return -2; 78335640Shselasky } 79335640Shselasky 80335640Shselasky message = dbus_connection_pop_message(handlep->conn); 81335640Shselasky } 82335640Shselasky 83335640Shselasky if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) { 84335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected"); 85335640Shselasky return -1; 86335640Shselasky } 87335640Shselasky 88335640Shselasky if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) { 89335640Shselasky pkth.caplen = pkth.len = raw_msg_len; 90335640Shselasky /* pkth.caplen = min (payload_len, handle->snapshot); */ 91335640Shselasky 92335640Shselasky gettimeofday(&pkth.ts, NULL); 93335640Shselasky if (handle->fcode.bf_insns == NULL || 94335640Shselasky bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) { 95335640Shselasky handlep->packets_read++; 96335640Shselasky callback(user, &pkth, (u_char *)raw_msg); 97335640Shselasky count++; 98335640Shselasky } 99335640Shselasky 100335640Shselasky dbus_free(raw_msg); 101335640Shselasky } 102335640Shselasky return count; 103335640Shselasky} 104335640Shselasky 105335640Shselaskystatic int 106335640Shselaskydbus_write(pcap_t *handle, const void *buf, size_t size) 107335640Shselasky{ 108335640Shselasky /* XXX, not tested */ 109335640Shselasky struct pcap_dbus *handlep = handle->priv; 110335640Shselasky 111335640Shselasky DBusError error = DBUS_ERROR_INIT; 112335640Shselasky DBusMessage *msg; 113335640Shselasky 114335640Shselasky if (!(msg = dbus_message_demarshal(buf, size, &error))) { 115335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message); 116335640Shselasky dbus_error_free(&error); 117335640Shselasky return -1; 118335640Shselasky } 119335640Shselasky 120335640Shselasky dbus_connection_send(handlep->conn, msg, NULL); 121335640Shselasky dbus_connection_flush(handlep->conn); 122335640Shselasky 123335640Shselasky dbus_message_unref(msg); 124335640Shselasky return 0; 125335640Shselasky} 126335640Shselasky 127335640Shselaskystatic int 128335640Shselaskydbus_stats(pcap_t *handle, struct pcap_stat *stats) 129335640Shselasky{ 130335640Shselasky struct pcap_dbus *handlep = handle->priv; 131335640Shselasky 132335640Shselasky stats->ps_recv = handlep->packets_read; 133335640Shselasky stats->ps_drop = 0; 134335640Shselasky stats->ps_ifdrop = 0; 135335640Shselasky return 0; 136335640Shselasky} 137335640Shselasky 138335640Shselaskystatic void 139335640Shselaskydbus_cleanup(pcap_t *handle) 140335640Shselasky{ 141335640Shselasky struct pcap_dbus *handlep = handle->priv; 142335640Shselasky 143335640Shselasky dbus_connection_unref(handlep->conn); 144335640Shselasky 145335640Shselasky pcap_cleanup_live_common(handle); 146335640Shselasky} 147335640Shselasky 148335640Shselasky/* 149335640Shselasky * We don't support non-blocking mode. I'm not sure what we'd 150335640Shselasky * do to support it and, given that we don't support select()/ 151335640Shselasky * poll()/epoll_wait()/kevent() etc., it probably doesn't 152335640Shselasky * matter. 153335640Shselasky */ 154335640Shselaskystatic int 155335640Shselaskydbus_getnonblock(pcap_t *p) 156335640Shselasky{ 157335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 158335640Shselasky "Non-blocking mode isn't supported for capturing on D-Bus"); 159335640Shselasky return (-1); 160335640Shselasky} 161335640Shselasky 162335640Shselaskystatic int 163335640Shselaskydbus_setnonblock(pcap_t *p, int nonblock _U_) 164335640Shselasky{ 165335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 166335640Shselasky "Non-blocking mode isn't supported for capturing on D-Bus"); 167335640Shselasky return (-1); 168335640Shselasky} 169335640Shselasky 170335640Shselaskystatic int 171335640Shselaskydbus_activate(pcap_t *handle) 172335640Shselasky{ 173335640Shselasky#define EAVESDROPPING_RULE "eavesdrop=true," 174335640Shselasky 175335640Shselasky static const char *rules[] = { 176335640Shselasky EAVESDROPPING_RULE "type='signal'", 177335640Shselasky EAVESDROPPING_RULE "type='method_call'", 178335640Shselasky EAVESDROPPING_RULE "type='method_return'", 179335640Shselasky EAVESDROPPING_RULE "type='error'", 180335640Shselasky }; 181335640Shselasky 182335640Shselasky #define N_RULES sizeof(rules)/sizeof(rules[0]) 183335640Shselasky 184335640Shselasky struct pcap_dbus *handlep = handle->priv; 185335640Shselasky const char *dev = handle->opt.device; 186335640Shselasky 187335640Shselasky DBusError error = DBUS_ERROR_INIT; 188335640Shselasky u_int i; 189335640Shselasky 190335640Shselasky if (strcmp(dev, "dbus-system") == 0) { 191335640Shselasky if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) { 192335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message); 193335640Shselasky dbus_error_free(&error); 194335640Shselasky return PCAP_ERROR; 195335640Shselasky } 196335640Shselasky 197335640Shselasky } else if (strcmp(dev, "dbus-session") == 0) { 198335640Shselasky if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) { 199335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message); 200335640Shselasky dbus_error_free(&error); 201335640Shselasky return PCAP_ERROR; 202335640Shselasky } 203335640Shselasky 204335640Shselasky } else if (strncmp(dev, "dbus://", 7) == 0) { 205335640Shselasky const char *addr = dev + 7; 206335640Shselasky 207335640Shselasky if (!(handlep->conn = dbus_connection_open(addr, &error))) { 208335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message); 209335640Shselasky dbus_error_free(&error); 210335640Shselasky return PCAP_ERROR; 211335640Shselasky } 212335640Shselasky 213335640Shselasky if (!dbus_bus_register(handlep->conn, &error)) { 214335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message); 215335640Shselasky dbus_error_free(&error); 216335640Shselasky return PCAP_ERROR; 217335640Shselasky } 218335640Shselasky 219335640Shselasky } else { 220335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device); 221335640Shselasky return PCAP_ERROR; 222335640Shselasky } 223335640Shselasky 224335640Shselasky /* Initialize some components of the pcap structure. */ 225335640Shselasky handle->bufsize = 0; 226335640Shselasky handle->offset = 0; 227335640Shselasky handle->linktype = DLT_DBUS; 228335640Shselasky handle->read_op = dbus_read; 229335640Shselasky handle->inject_op = dbus_write; 230335640Shselasky handle->setfilter_op = install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */ 231335640Shselasky handle->setdirection_op = NULL; 232335640Shselasky handle->set_datalink_op = NULL; /* can't change data link type */ 233335640Shselasky handle->getnonblock_op = dbus_getnonblock; 234335640Shselasky handle->setnonblock_op = dbus_setnonblock; 235335640Shselasky handle->stats_op = dbus_stats; 236335640Shselasky handle->cleanup_op = dbus_cleanup; 237335640Shselasky 238335640Shselasky#ifndef _WIN32 239335640Shselasky /* 240335640Shselasky * Unfortunately, trying to do a select()/poll()/epoll_wait()/ 241335640Shselasky * kevent()/etc. on a D-Bus connection isn't a simple 242335640Shselasky * case of "give me an FD on which to wait". 243335640Shselasky * 244335640Shselasky * Apparently, you have to register "add watch", "remove watch", 245335640Shselasky * and "toggle watch" functions with 246335640Shselasky * dbus_connection_set_watch_functions(), 247335640Shselasky * keep a *set* of FDs, add to that set in the "add watch" 248335640Shselasky * function, subtract from it in the "remove watch" function, 249335640Shselasky * and either add to or subtract from that set in the "toggle 250335640Shselasky * watch" function, and do the wait on *all* of the FDs in the 251335640Shselasky * set. (Yes, you need the "toggle watch" function, so that 252335640Shselasky * the main loop doesn't itself need to check for whether 253335640Shselasky * a given watch is enabled or disabled - most libpcap programs 254335640Shselasky * know nothing about D-Bus and shouldn't *have* to know anything 255335640Shselasky * about D-Bus other than how to decode D-Bus messages.) 256335640Shselasky * 257335640Shselasky * Implementing that would require considerable changes in 258335640Shselasky * the way libpcap exports "selectable FDs" to its client. 259335640Shselasky * Until that's done, we just say "you can't do that". 260335640Shselasky */ 261335640Shselasky handle->selectable_fd = handle->fd = -1; 262335640Shselasky#endif 263335640Shselasky 264335640Shselasky if (handle->opt.rfmon) { 265335640Shselasky /* 266335640Shselasky * Monitor mode doesn't apply to dbus connections. 267335640Shselasky */ 268335640Shselasky dbus_cleanup(handle); 269335640Shselasky return PCAP_ERROR_RFMON_NOTSUP; 270335640Shselasky } 271335640Shselasky 272335640Shselasky /* 273335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 274335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 275335640Shselasky * value, into the maximum message length for D-Bus (128MB). 276335640Shselasky */ 277335640Shselasky if (handle->snapshot <= 0 || handle->snapshot > 134217728) 278335640Shselasky handle->snapshot = 134217728; 279335640Shselasky 280335640Shselasky /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */ 281335640Shselasky if (handle->opt.buffer_size != 0) 282335640Shselasky dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size); 283335640Shselasky 284335640Shselasky for (i = 0; i < N_RULES; i++) { 285335640Shselasky dbus_bus_add_match(handlep->conn, rules[i], &error); 286335640Shselasky if (dbus_error_is_set(&error)) { 287335640Shselasky dbus_error_free(&error); 288335640Shselasky 289335640Shselasky /* try without eavesdrop */ 290335640Shselasky dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error); 291335640Shselasky if (dbus_error_is_set(&error)) { 292335640Shselasky pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message); 293335640Shselasky dbus_error_free(&error); 294335640Shselasky dbus_cleanup(handle); 295335640Shselasky return PCAP_ERROR; 296335640Shselasky } 297335640Shselasky } 298335640Shselasky } 299335640Shselasky 300335640Shselasky return 0; 301335640Shselasky} 302335640Shselasky 303335640Shselaskypcap_t * 304335640Shselaskydbus_create(const char *device, char *ebuf, int *is_ours) 305335640Shselasky{ 306335640Shselasky pcap_t *p; 307335640Shselasky 308335640Shselasky if (strcmp(device, "dbus-system") && 309335640Shselasky strcmp(device, "dbus-session") && 310335640Shselasky strncmp(device, "dbus://", 7)) 311335640Shselasky { 312335640Shselasky *is_ours = 0; 313335640Shselasky return NULL; 314335640Shselasky } 315335640Shselasky 316335640Shselasky *is_ours = 1; 317335640Shselasky p = pcap_create_common(ebuf, sizeof (struct pcap_dbus)); 318335640Shselasky if (p == NULL) 319335640Shselasky return (NULL); 320335640Shselasky 321335640Shselasky p->activate_op = dbus_activate; 322335640Shselasky /* 323335640Shselasky * Set these up front, so that, even if our client tries 324335640Shselasky * to set non-blocking mode before we're activated, or 325335640Shselasky * query the state of non-blocking mode, they get an error, 326335640Shselasky * rather than having the non-blocking mode option set 327335640Shselasky * for use later. 328335640Shselasky */ 329335640Shselasky p->getnonblock_op = dbus_getnonblock; 330335640Shselasky p->setnonblock_op = dbus_setnonblock; 331335640Shselasky return (p); 332335640Shselasky} 333335640Shselasky 334335640Shselaskyint 335335640Shselaskydbus_findalldevs(pcap_if_list_t *devlistp, char *err_str) 336335640Shselasky{ 337335640Shselasky /* 338335640Shselasky * The notion of "connected" vs. "disconnected" doesn't apply. 339335640Shselasky * XXX - what about the notions of "up" and "running"? 340335640Shselasky */ 341335640Shselasky if (add_dev(devlistp, "dbus-system", 342335640Shselasky PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus system bus", 343335640Shselasky err_str) == NULL) 344335640Shselasky return -1; 345335640Shselasky if (add_dev(devlistp, "dbus-session", 346335640Shselasky PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus session bus", 347335640Shselasky err_str) == NULL) 348335640Shselasky return -1; 349335640Shselasky return 0; 350335640Shselasky} 351335640Shselasky 352