pcap-dbus.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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. #ifdef HAVE_CONFIG_H
  31. #include <config.h>
  32. #endif
  33. #include <string.h>
  34. #include <time.h>
  35. #include <sys/time.h>
  36. #include <dbus/dbus.h>
  37. #include "pcap-int.h"
  38. #include "pcap-dbus.h"
  39. /*
  40. * Private data for capturing on D-Bus.
  41. */
  42. struct pcap_dbus {
  43. DBusConnection *conn;
  44. u_int packets_read; /* count of packets read */
  45. };
  46. static int
  47. dbus_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user)
  48. {
  49. struct pcap_dbus *handlep = handle->priv;
  50. struct pcap_pkthdr pkth;
  51. DBusMessage *message;
  52. char *raw_msg;
  53. int raw_msg_len;
  54. int count = 0;
  55. message = dbus_connection_pop_message(handlep->conn);
  56. while (!message) {
  57. /* XXX handle->opt.timeout = timeout_ms; */
  58. if (!dbus_connection_read_write(handlep->conn, 100)) {
  59. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Connection closed");
  60. return -1;
  61. }
  62. if (handle->break_loop) {
  63. handle->break_loop = 0;
  64. return -2;
  65. }
  66. message = dbus_connection_pop_message(handlep->conn);
  67. }
  68. if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
  69. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Disconnected");
  70. return -1;
  71. }
  72. if (dbus_message_marshal(message, &raw_msg, &raw_msg_len)) {
  73. pkth.caplen = pkth.len = raw_msg_len;
  74. /* pkth.caplen = min (payload_len, handle->snapshot); */
  75. gettimeofday(&pkth.ts, NULL);
  76. if (handle->fcode.bf_insns == NULL ||
  77. bpf_filter(handle->fcode.bf_insns, (u_char *)raw_msg, pkth.len, pkth.caplen)) {
  78. handlep->packets_read++;
  79. callback(user, &pkth, (u_char *)raw_msg);
  80. count++;
  81. }
  82. dbus_free(raw_msg);
  83. }
  84. return count;
  85. }
  86. static int
  87. dbus_write(pcap_t *handle, const void *buf, size_t size)
  88. {
  89. /* XXX, not tested */
  90. struct pcap_dbus *handlep = handle->priv;
  91. DBusError error = DBUS_ERROR_INIT;
  92. DBusMessage *msg;
  93. if (!(msg = dbus_message_demarshal(buf, size, &error))) {
  94. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dbus_message_demarshal() failed: %s", error.message);
  95. dbus_error_free(&error);
  96. return -1;
  97. }
  98. dbus_connection_send(handlep->conn, msg, NULL);
  99. dbus_connection_flush(handlep->conn);
  100. dbus_message_unref(msg);
  101. return 0;
  102. }
  103. static int
  104. dbus_stats(pcap_t *handle, struct pcap_stat *stats)
  105. {
  106. struct pcap_dbus *handlep = handle->priv;
  107. stats->ps_recv = handlep->packets_read;
  108. stats->ps_drop = 0;
  109. stats->ps_ifdrop = 0;
  110. return 0;
  111. }
  112. static void
  113. dbus_cleanup(pcap_t *handle)
  114. {
  115. struct pcap_dbus *handlep = handle->priv;
  116. dbus_connection_unref(handlep->conn);
  117. pcap_cleanup_live_common(handle);
  118. }
  119. /*
  120. * We don't support non-blocking mode. I'm not sure what we'd
  121. * do to support it and, given that we don't support select()/
  122. * poll()/epoll_wait()/kevent() etc., it probably doesn't
  123. * matter.
  124. */
  125. static int
  126. dbus_getnonblock(pcap_t *p)
  127. {
  128. pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
  129. "Non-blocking mode isn't supported for capturing on D-Bus");
  130. return (-1);
  131. }
  132. static int
  133. dbus_setnonblock(pcap_t *p, int nonblock _U_)
  134. {
  135. pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
  136. "Non-blocking mode isn't supported for capturing on D-Bus");
  137. return (-1);
  138. }
  139. static int
  140. dbus_activate(pcap_t *handle)
  141. {
  142. #define EAVESDROPPING_RULE "eavesdrop=true,"
  143. static const char *rules[] = {
  144. EAVESDROPPING_RULE "type='signal'",
  145. EAVESDROPPING_RULE "type='method_call'",
  146. EAVESDROPPING_RULE "type='method_return'",
  147. EAVESDROPPING_RULE "type='error'",
  148. };
  149. #define N_RULES sizeof(rules)/sizeof(rules[0])
  150. struct pcap_dbus *handlep = handle->priv;
  151. const char *dev = handle->opt.device;
  152. DBusError error = DBUS_ERROR_INIT;
  153. u_int i;
  154. if (strcmp(dev, "dbus-system") == 0) {
  155. if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
  156. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get system bus: %s", error.message);
  157. dbus_error_free(&error);
  158. return PCAP_ERROR;
  159. }
  160. } else if (strcmp(dev, "dbus-session") == 0) {
  161. if (!(handlep->conn = dbus_bus_get(DBUS_BUS_SESSION, &error))) {
  162. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to get session bus: %s", error.message);
  163. dbus_error_free(&error);
  164. return PCAP_ERROR;
  165. }
  166. } else if (strncmp(dev, "dbus://", 7) == 0) {
  167. const char *addr = dev + 7;
  168. if (!(handlep->conn = dbus_connection_open(addr, &error))) {
  169. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to open connection to: %s: %s", addr, error.message);
  170. dbus_error_free(&error);
  171. return PCAP_ERROR;
  172. }
  173. if (!dbus_bus_register(handlep->conn, &error)) {
  174. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to register bus %s: %s\n", addr, error.message);
  175. dbus_error_free(&error);
  176. return PCAP_ERROR;
  177. }
  178. } else {
  179. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get bus address from %s", handle->opt.device);
  180. return PCAP_ERROR;
  181. }
  182. /* Initialize some components of the pcap structure. */
  183. handle->bufsize = 0;
  184. handle->offset = 0;
  185. handle->linktype = DLT_DBUS;
  186. handle->read_op = dbus_read;
  187. handle->inject_op = dbus_write;
  188. handle->setfilter_op = install_bpf_program; /* XXX, later add support for dbus_bus_add_match() */
  189. handle->setdirection_op = NULL;
  190. handle->set_datalink_op = NULL; /* can't change data link type */
  191. handle->getnonblock_op = dbus_getnonblock;
  192. handle->setnonblock_op = dbus_setnonblock;
  193. handle->stats_op = dbus_stats;
  194. handle->cleanup_op = dbus_cleanup;
  195. #ifndef _WIN32
  196. /*
  197. * Unfortunately, trying to do a select()/poll()/epoll_wait()/
  198. * kevent()/etc. on a D-Bus connection isn't a simple
  199. * case of "give me an FD on which to wait".
  200. *
  201. * Apparently, you have to register "add watch", "remove watch",
  202. * and "toggle watch" functions with
  203. * dbus_connection_set_watch_functions(),
  204. * keep a *set* of FDs, add to that set in the "add watch"
  205. * function, subtract from it in the "remove watch" function,
  206. * and either add to or subtract from that set in the "toggle
  207. * watch" function, and do the wait on *all* of the FDs in the
  208. * set. (Yes, you need the "toggle watch" function, so that
  209. * the main loop doesn't itself need to check for whether
  210. * a given watch is enabled or disabled - most libpcap programs
  211. * know nothing about D-Bus and shouldn't *have* to know anything
  212. * about D-Bus other than how to decode D-Bus messages.)
  213. *
  214. * Implementing that would require considerable changes in
  215. * the way libpcap exports "selectable FDs" to its client.
  216. * Until that's done, we just say "you can't do that".
  217. */
  218. handle->selectable_fd = handle->fd = -1;
  219. #endif
  220. if (handle->opt.rfmon) {
  221. /*
  222. * Monitor mode doesn't apply to dbus connections.
  223. */
  224. dbus_cleanup(handle);
  225. return PCAP_ERROR_RFMON_NOTSUP;
  226. }
  227. /*
  228. * Turn a negative snapshot value (invalid), a snapshot value of
  229. * 0 (unspecified), or a value bigger than the normal maximum
  230. * value, into the maximum message length for D-Bus (128MB).
  231. */
  232. if (handle->snapshot <= 0 || handle->snapshot > 134217728)
  233. handle->snapshot = 134217728;
  234. /* dbus_connection_set_max_message_size(handlep->conn, handle->snapshot); */
  235. if (handle->opt.buffer_size != 0)
  236. dbus_connection_set_max_received_size(handlep->conn, handle->opt.buffer_size);
  237. for (i = 0; i < N_RULES; i++) {
  238. dbus_bus_add_match(handlep->conn, rules[i], &error);
  239. if (dbus_error_is_set(&error)) {
  240. dbus_error_free(&error);
  241. /* try without eavesdrop */
  242. dbus_bus_add_match(handlep->conn, rules[i] + strlen(EAVESDROPPING_RULE), &error);
  243. if (dbus_error_is_set(&error)) {
  244. pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Failed to add bus match: %s\n", error.message);
  245. dbus_error_free(&error);
  246. dbus_cleanup(handle);
  247. return PCAP_ERROR;
  248. }
  249. }
  250. }
  251. return 0;
  252. }
  253. pcap_t *
  254. dbus_create(const char *device, char *ebuf, int *is_ours)
  255. {
  256. pcap_t *p;
  257. if (strcmp(device, "dbus-system") &&
  258. strcmp(device, "dbus-session") &&
  259. strncmp(device, "dbus://", 7))
  260. {
  261. *is_ours = 0;
  262. return NULL;
  263. }
  264. *is_ours = 1;
  265. p = pcap_create_common(ebuf, sizeof (struct pcap_dbus));
  266. if (p == NULL)
  267. return (NULL);
  268. p->activate_op = dbus_activate;
  269. /*
  270. * Set these up front, so that, even if our client tries
  271. * to set non-blocking mode before we're activated, or
  272. * query the state of non-blocking mode, they get an error,
  273. * rather than having the non-blocking mode option set
  274. * for use later.
  275. */
  276. p->getnonblock_op = dbus_getnonblock;
  277. p->setnonblock_op = dbus_setnonblock;
  278. return (p);
  279. }
  280. int
  281. dbus_findalldevs(pcap_if_list_t *devlistp, char *err_str)
  282. {
  283. /*
  284. * The notion of "connected" vs. "disconnected" doesn't apply.
  285. * XXX - what about the notions of "up" and "running"?
  286. */
  287. if (add_dev(devlistp, "dbus-system",
  288. PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus system bus",
  289. err_str) == NULL)
  290. return -1;
  291. if (add_dev(devlistp, "dbus-session",
  292. PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE, "D-Bus session bus",
  293. err_str) == NULL)
  294. return -1;
  295. return 0;
  296. }