libpcap  1.10.1
About: libpcap is a packet filter library used by tools like tcpdump.
  Fossies Dox: libpcap-1.10.1.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

pcap-dbus.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 Jakub Zawadzki
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote
15  * products derived from this software without specific prior written
16  * permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 
35 #include <string.h>
36 
37 #include <time.h>
38 #include <sys/time.h>
39 
40 #include <dbus/dbus.h>
41 
42 #include "pcap-int.h"
43 #include "pcap-dbus.h"
44 
45 /*
46  * Private data for capturing on D-Bus.
47  */
48 struct pcap_dbus {
49  DBusConnection *conn;
50  u_int packets_read; /* count of packets read */
51 };
52 
53 static int
54 dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user)
55 {
56  struct pcap_dbus *handlep = handle->priv;
57 
58  struct pcap_pkthdr pkth;
59  DBusMessage *message;
60 
61  char *raw_msg;
62  int raw_msg_len;
63 
64  int count = 0;
65 
66  message = dbus_connection_pop_message(handlep->conn);
67 
68  while (!message) {
69  /* XXX handle->opt.timeout = timeout_ms; */
70  if (!dbus_connection_read_write(handlep->conn, 100)) {
71  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed");
72  return -1;
73  }
74 
75  if (handle->break_loop) {
76  handle->break_loop = 0;
77  return -2;
78  }
79 
80  message = dbus_connection_pop_message(handlep->conn);
81  }
82 
83  if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
84  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected");
85  return -1;
86  }
87 
88  if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) {
89  pkth.caplen = pkth.len = raw_msg_len;
90  /* pkth.caplen = min (payload_len, handle->snapshot); */
91 
92  gettimeofday(&pkth.ts, NULL);
93  if (handle->fcode.bf_insns == NULL ||
94  pcap_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) {
95  handlep->packets_read++;
96  callback(user, &pkth, (u_char *)raw_msg);
97  count++;
98  }
99 
100  dbus_free(raw_msg);
101  }
102  return count;
103 }
104 
105 static int
106 dbus_write(pcap_t *handle, const void *buf, int size)
107 {
108  /* XXX, not tested */
109  struct pcap_dbus *handlep = handle->priv;
110 
111  DBusError error = DBUS_ERROR_INIT;
112  DBusMessage *msg;
113 
114  if (!(msg = dbus_message_demarshal(buf, size, &error))) {
115  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message);
116  dbus_error_free(&error);
117  return -1;
118  }
119 
120  dbus_connection_send(handlep->conn, msg, NULL);
121  dbus_connection_flush(handlep->conn);
122 
123  dbus_message_unref(msg);
124  return 0;
125 }
126 
127 static int
128 dbus_stats(pcap_t *handle, struct pcap_stat *stats)
129 {
130  struct pcap_dbus *handlep = handle->priv;
131 
132  stats->ps_recv = handlep->packets_read;
133  stats->ps_drop = 0;
134  stats->ps_ifdrop = 0;
135  return 0;
136 }
137 
138 static void
140 {
141  struct pcap_dbus *handlep = handle->priv;
142 
143  dbus_connection_unref(handlep->conn);
144 
145  pcap_cleanup_live_common(handle);
146 }
147 
148 /*
149  * We don't support non-blocking mode. I'm not sure what we'd
150  * do to support it and, given that we don't support select()/
151  * poll()/epoll_wait()/kevent() etc., it probably doesn't
152  * matter.
153  */
154 static int
156 {
158  "Non-blocking mode isn't supported for capturing on D-Bus");
159  return (-1);
160 }
161 
162 static int
163 dbus_setnonblock(pcap_t *p, int nonblock _U_)
164 {
166  "Non-blocking mode isn't supported for capturing on D-Bus");
167  return (-1);
168 }
169 
170 static int
172 {
173 #define EAVESDROPPING_RULE "eavesdrop=true,"
174 
175  static const char *rules[] = {
176  EAVESDROPPING_RULE "type='signal'",
177  EAVESDROPPING_RULE "type='method_call'",
178  EAVESDROPPING_RULE "type='method_return'",
179  EAVESDROPPING_RULE "type='error'",
180  };
181 
182  #define N_RULES sizeof(rules)/sizeof(rules[0])
183 
184  struct pcap_dbus *handlep = handle->priv;
185  const char *dev = handle->opt.device;
186 
187  DBusError error = DBUS_ERROR_INIT;
188  u_int i;
189 
190  if (strcmp(dev, "dbus-system") == 0) {
191  if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
192  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message);
193  dbus_error_free(&error);
194  return PCAP_ERROR;
195  }
196 
197  } else if (strcmp(dev, "dbus-session") == 0) {
198  if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) {
199  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message);
200  dbus_error_free(&error);
201  return PCAP_ERROR;
202  }
203 
204  } else if (strncmp(dev, "dbus://", 7) == 0) {
205  const char *addr = dev + 7;
206 
207  if (!(handlep->conn = dbus_connection_open(addr, &error))) {
208  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message);
209  dbus_error_free(&error);
210  return PCAP_ERROR;
211  }
212 
213  if (!dbus_bus_register(handlep->conn, &error)) {
214  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message);
215  dbus_error_free(&error);
216  return PCAP_ERROR;
217  }
218 
219  } else {
220  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device);
221  return PCAP_ERROR;
222  }
223 
224  /* Initialize some components of the pcap structure. */
225  handle->bufsize = 0;
226  handle->offset = 0;
227  handle->linktype = DLT_DBUS;
228  handle->read_op = dbus_read;
229  handle->inject_op = dbus_write;
230  handle->setfilter_op = install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */
231  handle->setdirection_op = NULL;
232  handle->set_datalink_op = NULL; /* can't change data link type */
235  handle->stats_op = dbus_stats;
236  handle->cleanup_op = dbus_cleanup;
237 
238 #ifndef _WIN32
239  /*
240  * Unfortunately, trying to do a select()/poll()/epoll_wait()/
241  * kevent()/etc. on a D-Bus connection isn't a simple
242  * case of "give me an FD on which to wait".
243  *
244  * Apparently, you have to register "add watch", "remove watch",
245  * and "toggle watch" functions with
246  * dbus_connection_set_watch_functions(),
247  * keep a *set* of FDs, add to that set in the "add watch"
248  * function, subtract from it in the "remove watch" function,
249  * and either add to or subtract from that set in the "toggle
250  * watch" function, and do the wait on *all* of the FDs in the
251  * set. (Yes, you need the "toggle watch" function, so that
252  * the main loop doesn't itself need to check for whether
253  * a given watch is enabled or disabled - most libpcap programs
254  * know nothing about D-Bus and shouldn't *have* to know anything
255  * about D-Bus other than how to decode D-Bus messages.)
256  *
257  * Implementing that would require considerable changes in
258  * the way libpcap exports "selectable FDs" to its client.
259  * Until that's done, we just say "you can't do that".
260  */
261  handle->selectable_fd = handle->fd = -1;
262 #endif
263 
264  if (handle->opt.rfmon) {
265  /*
266  * Monitor mode doesn't apply to dbus connections.
267  */
268  dbus_cleanup(handle);
270  }
271 
272  /*
273  * Turn a negative snapshot value (invalid), a snapshot value of
274  * 0 (unspecified), or a value bigger than the normal maximum
275  * value, into the maximum message length for D-Bus (128MB).
276  */
277  if (handle->snapshot <= 0 || handle->snapshot > 134217728)
278  handle->snapshot = 134217728;
279 
280  /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */
281  if (handle->opt.buffer_size != 0)
282  dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size);
283 
284  for (i = 0; i < N_RULES; i++) {
285  dbus_bus_add_match(handlep->conn, rules[i], &error);
286  if (dbus_error_is_set(&error)) {
287  dbus_error_free(&error);
288 
289  /* try without eavesdrop */
290  dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error);
291  if (dbus_error_is_set(&error)) {
292  snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message);
293  dbus_error_free(&error);
294  dbus_cleanup(handle);
295  return PCAP_ERROR;
296  }
297  }
298  }
299 
300  return 0;
301 }
302 
303 pcap_t *
304 dbus_create(const char *device, char *ebuf, int *is_ours)
305 {
306  pcap_t *p;
307 
308  if (strcmp(device, "dbus-system") &&
309  strcmp(device, "dbus-session") &&
310  strncmp(device, "dbus://", 7))
311  {
312  *is_ours = 0;
313  return NULL;
314  }
315 
316  *is_ours = 1;
317  p = PCAP_CREATE_COMMON(ebuf, struct pcap_dbus);
318  if (p == NULL)
319  return (NULL);
320 
322  /*
323  * Set these up front, so that, even if our client tries
324  * to set non-blocking mode before we're activated, or
325  * query the state of non-blocking mode, they get an error,
326  * rather than having the non-blocking mode option set
327  * for use later.
328  */
331  return (p);
332 }
333 
334 int
335 dbus_findalldevs(pcap_if_list_t *devlistp, char *err_str)
336 {
337  /*
338  * The notion of "connected" vs. "disconnected" doesn't apply.
339  * XXX - what about the notions of "up" and "running"?
340  */
341  if (add_dev(devlistp, "dbus-system",
342  PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus system bus",
343  err_str) == NULL)
344  return -1;
345  if (add_dev(devlistp, "dbus-session",
346  PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus session bus",
347  err_str) == NULL)
348  return -1;
349  return 0;
350 }
351 
u_int pcap_filter(const struct bpf_insn *pc, const u_char *p, u_int wirelen, u_int buflen)
Definition: bpf_filter.c:391
static void error(const char *,...)
#define DLT_DBUS
Definition: dlt.h:1067
int install_bpf_program(pcap_t *p, struct bpf_program *fp)
Definition: optimize.c:2939
int snprintf(char *, size_t, const char *,...)
int gettimeofday(struct timeval *, struct timezone *)
#define EAVESDROPPING_RULE
int dbus_findalldevs(pcap_if_list_t *devlistp, char *err_str)
Definition: pcap-dbus.c:335
static void dbus_cleanup(pcap_t *handle)
Definition: pcap-dbus.c:139
static int dbus_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
Definition: pcap-dbus.c:54
#define N_RULES
pcap_t * dbus_create(const char *device, char *ebuf, int *is_ours)
Definition: pcap-dbus.c:304
static int dbus_write(pcap_t *handle, const void *buf, int size)
Definition: pcap-dbus.c:106
static int dbus_stats(pcap_t *handle, struct pcap_stat *stats)
Definition: pcap-dbus.c:128
static int dbus_setnonblock(pcap_t *p, int nonblock)
Definition: pcap-dbus.c:163
static int dbus_getnonblock(pcap_t *p)
Definition: pcap-dbus.c:155
static int dbus_activate(pcap_t *handle)
Definition: pcap-dbus.c:171
#define _U_
Definition: pcap-dos.h:93
pcap_if_t * add_dev(pcap_if_list_t *, const char *, bpf_u_int32, const char *, char *)
Definition: pcap.c:1308
void pcap_cleanup_live_common(pcap_t *)
Definition: pcap.c:3987
#define PCAP_CREATE_COMMON(ebuf, type)
Definition: pcap-int.h:474
#define PCAP_ERROR_RFMON_NOTSUP
Definition: pcap.h:344
#define PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE
Definition: pcap.h:317
void(* pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *)
Definition: pcap.h:330
#define PCAP_ERRBUF_SIZE
Definition: pcap.h:152
#define PCAP_ERROR
Definition: pcap.h:339
struct bpf_insn * bf_insns
Definition: bpf.h:119
DBusConnection * conn
Definition: pcap-dbus.c:49
u_int packets_read
Definition: pcap-dbus.c:50
char * device
Definition: pcap-int.h:146
int rfmon
Definition: pcap-int.h:150
u_int buffer_size
Definition: pcap-int.h:148
bpf_u_int32 caplen
Definition: pcap.h:247
struct timeval ts
Definition: pcap.h:246
bpf_u_int32 len
Definition: pcap.h:248
u_int ps_drop
Definition: pcap.h:256
u_int ps_recv
Definition: pcap.h:255
u_int ps_ifdrop
Definition: pcap.h:257
Definition: pcap-int.h:200
stats_op_t stats_op
Definition: pcap-int.h:320
activate_op_t activate_op
Definition: pcap-int.h:311
setnonblock_op_t setnonblock_op
Definition: pcap-int.h:319
setfilter_op_t setfilter_op
Definition: pcap-int.h:315
sig_atomic_t break_loop
Definition: pcap-int.h:225
u_int bufsize
Definition: pcap-int.h:220
void * priv
Definition: pcap-int.h:227
getnonblock_op_t getnonblock_op
Definition: pcap-int.h:318
int offset
Definition: pcap-int.h:250
read_op_t read_op
Definition: pcap-int.h:204
int snapshot
Definition: pcap-int.h:247
cleanup_op_t cleanup_op
Definition: pcap-int.h:346
setdirection_op_t setdirection_op
Definition: pcap-int.h:316
inject_op_t inject_op
Definition: pcap-int.h:313
struct bpf_program fcode
Definition: pcap-int.h:293
set_datalink_op_t set_datalink_op
Definition: pcap-int.h:317
char errbuf[256+1]
Definition: pcap-int.h:295
int linktype
Definition: pcap-int.h:248
int selectable_fd
Definition: pcap-int.h:274
int fd
Definition: pcap-int.h:214
struct pcap_opt opt
Definition: pcap-int.h:254