Introduce Libvirt Wireshark dissector

Introduce Wireshark dissector plugin which adds support to Wireshark
for dissecting libvirt RPC protocol.
Added following files to build Wireshark dissector from libvirt source
tree.
* tools/wireshark/*: Source tree of Wireshark dissector plugin.

Added followings to configure.ac or Makefile.am.
configure.ac
* --with-wireshark-dissector: Enable support for building Wireshark
  dissector.
* --with-ws-plugindir: Specify wireshark plugin directory that dissector
  will installed.
* Added tools/wireshark/{Makefile,src/Makefile} to  AC_CONFIG_FILES.
Makefile.am
* Added tools/wireshark/ to SUBDIR.
This commit is contained in:
Yuto KAWAMURA(kawamuray) 2014-01-16 02:06:58 +09:00 committed by Michal Privoznik
parent a1cbe4b5a9
commit 4f32c5f793
11 changed files with 2031 additions and 6 deletions

2
.gitignore vendored
View File

@ -226,6 +226,8 @@
/tools/virsh-*-edit.c
/tools/virt-*-validate
/tools/virt-sanlock-cleanup
/tools/wireshark/src/plugin.c
/tools/wireshark/src/libvirt
/update.log
GPATH
GRTAGS

View File

@ -22,7 +22,8 @@ GENHTML = genhtml
SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \
tests po examples/object-events examples/hellolibvirt \
examples/dominfo examples/domsuspend examples/apparmor \
examples/xml/nwfilter examples/openauth examples/systemtap
examples/xml/nwfilter examples/openauth examples/systemtap \
tools/wireshark
ACLOCAL_AMFLAGS = -I m4

8
cfg.mk
View File

@ -977,10 +977,10 @@ exclude_file_name_regexp--sc_prohibit_newline_at_end_of_diagnostic = \
^src/rpc/gendispatch\.pl$$
exclude_file_name_regexp--sc_prohibit_nonreentrant = \
^((po|tests)/|docs/.*(py|html\.in)|run.in$$)
^((po|tests)/|docs/.*(py|html\.in)|run.in$$|tools/wireshark/util/genxdrstub\.pl$$)
exclude_file_name_regexp--sc_prohibit_raw_allocation = \
^(docs/hacking\.html\.in)|(src/util/viralloc\.[ch]|examples/.*|tests/securityselinuxhelper\.c|tests/vircgroupmock\.c)$$
^(docs/hacking\.html\.in)|(src/util/viralloc\.[ch]|examples/.*|tests/securityselinuxhelper\.c|tests/vircgroupmock\.c|tools/wireshark/src/packet-libvirt.c)$$
exclude_file_name_regexp--sc_prohibit_readlink = \
^src/(util/virutil|lxc/lxc_container)\.c$$
@ -988,7 +988,7 @@ exclude_file_name_regexp--sc_prohibit_readlink = \
exclude_file_name_regexp--sc_prohibit_setuid = ^src/util/virutil\.c$$
exclude_file_name_regexp--sc_prohibit_sprintf = \
^(docs/hacking\.html\.in)|(examples/systemtap/.*stp)|(src/dtrace2systemtap\.pl)|(src/rpc/gensystemtap\.pl)$$
^(docs/hacking\.html\.in)|(examples/systemtap/.*stp)|(src/dtrace2systemtap\.pl)|(src/rpc/gensystemtap\.pl)|(tools/wireshark/util/genxdrstub\.pl)$$
exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/virstring\.c$$
@ -1021,7 +1021,7 @@ exclude_file_name_regexp--sc_correct_id_types = \
exclude_file_name_regexp--sc_m4_quote_check = m4/virt-lib.m4
exclude_file_name_regexp--sc_prohibit_include_public_headers_quote = \
^src/internal\.h$$
^(src/internal\.h$$|tools/wireshark/src/packet-libvirt.h$$)
exclude_file_name_regexp--sc_prohibit_include_public_headers_brackets = \
^(tools/|examples/|include/libvirt/(virterror|libvirt-(qemu|lxc))\.h$$)

View File

@ -2502,6 +2502,70 @@ AM_CONDITIONAL([HAVE_LIBNL], [test "$have_libnl" = "yes"])
AC_SUBST([LIBNL_CFLAGS])
AC_SUBST([LIBNL_LIBS])
dnl wireshark dissector
AC_ARG_WITH([wireshark-dissector],
[AS_HELP_STRING([--with-wireshark-dissector],
[enable wireshark dissector plugin support @<:@default=check@:>@])],
[ with_wireshark_dissector=$withval ],
[ with_wireshark_dissector=check ])
AC_DEFUN([LIBVIRT_WS_HANDLE_ERROR], [
if test "$with_wireshark_dissector" = "yes"; then
AC_MSG_ERROR([$1])
else
with_wireshark_dissector=no
fi
])
if test "$with_wireshark_dissector" != "no"; then
dnl Check for XDR headers existence
AC_CHECK_HEADERS([rpc/types.h])
dnl Check for glib-2.0 existence
PKG_CHECK_MODULES([GLIB], [glib-2.0], [
WS_DISSECTOR_CPPFLAGS="$WS_DISSECTOR_CPPFLAGS `$PKG_CONFIG --cflags glib-2.0`"
], [
LIBVIRT_WS_HANDLE_ERROR([pkg-config 'glib-2.0' is required for wireshark-dissector support])
])
dnl Search for wireshark(or tshark) command
AC_PATH_PROG([WIRESHARK], [wireshark])
AC_PATH_PROG([WIRESHARK], [tshark])
if test -z "$WIRESHARK"; then
LIBVIRT_WS_HANDLE_ERROR([command not found wireshark or tshark])
else
dnl Check for wireshark headers
save_CPPFLAGS="$CPPFLAGS"
WS_DISSECTOR_CPPFLAGS="$WS_DISSECTOR_CPPFLAGS -I`dirname $WIRESHARK`/../include/wireshark"
CPPFLAGS="$CPPFLAGS $WS_DISSECTOR_CPPFLAGS"
AC_CHECK_HEADERS([wireshark/config.h],, [
LIBVIRT_WS_HANDLE_ERROR([wireshark/config.h is required for wireshark-dissector support])
])
AC_CHECK_HEADERS([wireshark/epan/packet.h wireshark/epan/dissectors/packet-tcp.h],, [
LIBVIRT_WS_HANDLE_ERROR([wireshark/epan/{packet,packet-tcp}.h are required for wireshark-dissector support])
], [
#include <wireshark/config.h>
])
CPPFLAGS="$save_CPPFLAGS"
fi
if test "$with_wireshark_dissector" != "no"; then
with_wireshark_dissector=yes
fi
fi
AC_SUBST([WS_DISSECTOR_CPPFLAGS])
AM_CONDITIONAL([WITH_WIRESHARK_DISSECTOR], [test "$with_wireshark_dissector" = "yes"])
AC_ARG_WITH([ws-plugindir],
[AS_HELP_STRING([--with-ws-plugindir],
[wireshark plugins directory that plugin will installed])],
[ ws_plugindir=$withval ])
if test "$with_wireshark_dissector" != "no" && test -z "$ws_plugindir"; then
ws_version=`$WIRESHARK -v | head -1 | cut -f 2 -d' '`
ws_plugindir=`dirname $WIRESHARK`/../lib/wireshark/plugins/$ws_version
fi
AC_SUBST([ws_plugindir])
# Check for Linux vs. BSD ifreq members
AC_CHECK_MEMBERS([struct ifreq.ifr_newname,
struct ifreq.ifr_ifindex,
@ -2585,7 +2649,9 @@ AC_CONFIG_FILES([\
examples/openauth/Makefile \
examples/hellolibvirt/Makefile \
examples/systemtap/Makefile \
examples/xml/nwfilter/Makefile])
examples/xml/nwfilter/Makefile \
tools/wireshark/Makefile \
tools/wireshark/src/Makefile])
AC_OUTPUT
AC_MSG_NOTICE([])
@ -2746,6 +2812,10 @@ AC_MSG_NOTICE([ XML Catalog: $XML_CATALOG_FILE])
AC_MSG_NOTICE([ Init script: $with_init_script])
AC_MSG_NOTICE([Char device locks: $with_chrdev_lock_files])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Developer Tools])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Wireshark dissector: $with_wireshark_dissector])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Privileges])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([ QEMU: $QEMU_USER:$QEMU_GROUP])

View File

@ -0,0 +1,22 @@
## Process this file with automake to produce Makefile.in
# Copyright (C) 2013 Yuto KAWAMURA(kawamuray) <kawamuray.dadada@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
#
# Author: Yuto KAWAMURA(kawamuray)
if WITH_WIRESHARK_DISSECTOR
SUBDIRS = src
endif WITH_WIRESHARK_DISSECTOR

31
tools/wireshark/README.md Normal file
View File

@ -0,0 +1,31 @@
About
=====
This is the project of Google Summer of Code 2013 accepted by QEMU.org and
libvirt community. The goal of this project is, provide Wireshark dissector for
Libvirt RPC protocol. It will provide Libvirt packet overview/detail analysing
in Wireshark. Furthermore, it will be able to build(generated) from RPC protocol
definition placed in Libvirt source tree to support latest protocol
specification.
See also:
- http://www.google-melange.com/gsoc/project/google/gsoc2013/kawamuray/7001
- http://wiki.qemu.org/Features/LibvirtWiresharkDissector
Installation
=============
Run ./configure with --with-wireshark-dissector option enabled.
Then dissector will compiled with libvirt itself.
Add/Remove protocol from dissector's support
--------------------------------------------
Modify variable WS\_DISSECTOR\_PROTO\_FILES in tools/wireshark/src/Makefile.am.
Changing installation directory
-------------------------------
You can change installation directory of pluggable shared object(libvirt.so) by
specifying --with-ws-plugindir=<path>.
You can install libvirt.so into your local wireshark plugin directory:
./configure --with-wireshark-dissector \
--with-ws-plugindir=$HOME/.wireshark/plugins

View File

@ -0,0 +1,42 @@
## Process this file with automake to produce Makefile.in
# Copyright (C) 2013 Yuto KAWAMURA(kawamuray) <kawamuray.dadada@gmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
#
# Author: Yuto KAWAMURA(kawamuray)
ws_plugin_LTLIBRARIES = libvirt.la
libvirt_la_SOURCES = packet-libvirt.c plugin.c
libvirt_la_CPPFLAGS = $(WS_DISSECTOR_CPPFLAGS)
libvirt_la_LDFLAGS = -avoid-version -module
packet-libvirt.c: packet-libvirt.h libvirt/protocol.h
plugin.c: packet-libvirt.c
$(srcdir)/../util/make-dissector-reg . plugin $<
WS_DISSECTOR_PROTO_FILES = \
$(top_srcdir)/src/remote/remote_protocol.x \
$(top_srcdir)/src/remote/qemu_protocol.x \
$(top_srcdir)/src/remote/lxc_protocol.x \
$(top_srcdir)/src/rpc/virkeepaliveprotocol.x
libvirt/protocol.h: $(srcdir)/../util/genxdrstub.pl $(WS_DISSECTOR_PROTO_FILES)
$(MKDIR_P) libvirt
LIBVIRT_VERSION=$(LIBVIRT_VERSION) \
$(PERL) $(srcdir)/../util/genxdrstub.pl $(WS_DISSECTOR_PROTO_FILES)
clean-local:
-rm -rf libvirt plugin.c

View File

@ -0,0 +1,520 @@
/* packet-libvirt.c --- Libvirt packet dissector routines.
*
* Copyright (C) 2013 Yuto KAWAMURA(kawamuray) <kawamuray.dadada@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Authors:
* Michal Privoznik <mprivozn redhat com>
* Yuto KAWAMURA(kawamuray) <kawamuray.dadada gmail.com>
*/
#include <config.h>
#include <stdlib.h>
#include <wireshark/config.h>
#include <wireshark/epan/proto.h>
#include <wireshark/epan/packet.h>
#include <wireshark/epan/dissectors/packet-tcp.h>
#include <glib.h>
#include <glib/gprintf.h>
#ifdef HAVE_RPC_TYPES_H
# include <rpc/types.h>
#endif
#include <rpc/xdr.h>
#include "packet-libvirt.h"
static int proto_libvirt = -1;
static int hf_libvirt_length = -1;
static int hf_libvirt_program = -1;
static int hf_libvirt_version = -1;
static int hf_libvirt_procedure = -1;
static int hf_libvirt_type = -1;
static int hf_libvirt_serial = -1;
static int hf_libvirt_status = -1;
static int hf_libvirt_stream = -1;
static int hf_libvirt_num_of_fds = -1;
static int hf_libvirt_unknown = -1;
static gint ett_libvirt = -1;
#define XDR_PRIMITIVE_DISSECTOR(xtype, ctype, ftype) \
static gboolean \
dissect_xdr_##xtype(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf) \
{ \
goffset start; \
ctype val; \
start = xdr_getpos(xdrs); \
if (xdr_##xtype(xdrs, &val)) { \
proto_tree_add_##ftype(tree, hf, tvb, start, xdr_getpos(xdrs) - start, val); \
return TRUE; \
} else { \
proto_tree_add_item(tree, hf_libvirt_unknown, tvb, start, -1, ENC_NA); \
return FALSE; \
} \
}
XDR_PRIMITIVE_DISSECTOR(int, gint32, int)
XDR_PRIMITIVE_DISSECTOR(u_int, guint32, uint)
XDR_PRIMITIVE_DISSECTOR(short, gint16, int)
XDR_PRIMITIVE_DISSECTOR(u_short, guint16, uint)
XDR_PRIMITIVE_DISSECTOR(char, gchar, int)
XDR_PRIMITIVE_DISSECTOR(u_char, guchar, uint)
XDR_PRIMITIVE_DISSECTOR(hyper, gint64, int64)
XDR_PRIMITIVE_DISSECTOR(u_hyper, guint64, uint64)
XDR_PRIMITIVE_DISSECTOR(float, gfloat, float)
XDR_PRIMITIVE_DISSECTOR(double, gdouble, double)
XDR_PRIMITIVE_DISSECTOR(bool, bool_t, boolean)
static gboolean
dissect_xdr_string(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf,
guint32 maxlen)
{
goffset start;
gchar *val = NULL;
start = xdr_getpos(xdrs);
if (xdr_string(xdrs, &val, maxlen)) {
proto_tree_add_string(tree, hf, tvb, start, xdr_getpos(xdrs) - start, val);
xdr_free((xdrproc_t)xdr_string, (char *)&val);
return TRUE;
} else {
proto_tree_add_item(tree, hf_libvirt_unknown, tvb, start, -1, ENC_NA);
return FALSE;
}
}
static gchar *
format_xdr_bytes(guint8 *bytes, guint32 length)
{
gchar *buf;
guint32 i;
if (length == 0)
return "";
buf = ep_alloc(length*2 + 1);
for (i = 0; i < length; i++) {
/* We know that buf has enough size to contain
2 * length + '\0' characters. */
g_sprintf(buf, "%02x", bytes[i]);
buf += 2;
}
return buf - length*2;
}
static gboolean
dissect_xdr_opaque(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf,
guint32 size)
{
goffset start;
gboolean rc;
guint8 *val;
val = g_malloc(size);
start = xdr_getpos(xdrs);
if ((rc = xdr_opaque(xdrs, (caddr_t)val, size))) {
proto_tree_add_bytes_format_value(tree, hf, tvb, start, xdr_getpos(xdrs) - start,
NULL, "%s", format_xdr_bytes(val, size));
} else {
proto_tree_add_item(tree, hf_libvirt_unknown, tvb, start, -1, ENC_NA);
}
g_free(val);
return rc;
}
static gboolean
dissect_xdr_bytes(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf,
guint32 maxlen)
{
goffset start;
guint8 *val = NULL;
guint32 length;
start = xdr_getpos(xdrs);
if (xdr_bytes(xdrs, (char **)&val, &length, maxlen)) {
proto_tree_add_bytes_format_value(tree, hf, tvb, start, xdr_getpos(xdrs) - start,
NULL, "%s", format_xdr_bytes(val, length));
/* Seems I can't call xdr_free() for this case.
It will raises SEGV by referencing out of bounds call stack */
free(val);
return TRUE;
} else {
proto_tree_add_item(tree, hf_libvirt_unknown, tvb, start, -1, ENC_NA);
return FALSE;
}
}
static gboolean
dissect_xdr_pointer(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf,
vir_xdr_dissector_t dissect)
{
goffset start;
bool_t not_null;
start = xdr_getpos(xdrs);
if (!xdr_bool(xdrs, &not_null)) {
proto_tree_add_item(tree, hf_libvirt_unknown, tvb, start, -1, ENC_NA);
return FALSE;
}
if (not_null) {
return dissect(tvb, tree, xdrs, hf);
} else {
proto_item *ti;
ti = proto_tree_add_item(tree, hf, tvb, start, xdr_getpos(xdrs) - start, ENC_NA);
proto_item_append_text(ti, ": (null)");
return TRUE;
}
}
static gboolean
dissect_xdr_iterable(tvbuff_t *tvb, proto_item *ti, XDR *xdrs, gint ett, int rhf,
guint32 length, vir_xdr_dissector_t dissect, goffset start)
{
proto_tree *tree;
guint32 i;
tree = proto_item_add_subtree(ti, ett);
for (i = 0; i < length; i++) {
if (!dissect(tvb, tree, xdrs, rhf))
return FALSE;
}
proto_item_set_len(ti, xdr_getpos(xdrs) - start);
return TRUE;
}
static gboolean
dissect_xdr_vector(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf, gint ett,
int rhf, gchar *rtype, guint32 size, vir_xdr_dissector_t dissect)
{
goffset start;
proto_item *ti;
start = xdr_getpos(xdrs);
ti = proto_tree_add_item(tree, hf, tvb, start, -1, ENC_NA);
proto_item_append_text(ti, " :: %s[%u]", rtype, size);
return dissect_xdr_iterable(tvb, ti, xdrs, ett, rhf, size, dissect, start);
}
static gboolean
dissect_xdr_array(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf, gint ett,
int rhf, gchar *rtype, guint32 maxlen, vir_xdr_dissector_t dissect)
{
goffset start;
proto_item *ti;
guint32 length;
start = xdr_getpos(xdrs);
if (!xdr_u_int(xdrs, &length))
return FALSE;
if (length > maxlen)
return FALSE;
ti = proto_tree_add_item(tree, hf, tvb, start, -1, ENC_NA);
proto_item_append_text(ti, " :: %s<%u>", rtype, length);
return dissect_xdr_iterable(tvb, ti, xdrs, ett, rhf, length, dissect, start);
}
static vir_xdr_dissector_t
find_payload_dissector(guint32 proc, guint32 type,
const vir_dissector_index_t *pds, gsize length)
{
const vir_dissector_index_t *pd;
guint32 first, last, direction;
if (pds == NULL || length < 1)
return NULL;
first = pds[0].proc;
last = pds[length-1].proc;
if (proc < first || proc > last) {
return NULL;
}
pd = &pds[proc-first];
/* There is no guarantee to proc numbers has no gap */
if (pd->proc != proc) {
direction = (pd->proc < proc) ? 1 : -1;
while (pd->proc != proc) {
if (pd->proc == first || pd->proc == last)
return NULL;
pd += direction;
}
}
switch (type) {
case VIR_NET_CALL:
case VIR_NET_CALL_WITH_FDS:
return pd->args;
case VIR_NET_REPLY:
case VIR_NET_REPLY_WITH_FDS:
return pd->ret;
case VIR_NET_MESSAGE:
return pd->msg;
}
return NULL;
}
static void
dissect_libvirt_stream(tvbuff_t *tvb, proto_tree *tree, gint payload_length)
{
proto_tree_add_item(tree, hf_libvirt_stream, tvb, VIR_HEADER_LEN,
payload_length - VIR_HEADER_LEN, ENC_NA);
}
static gint32
dissect_libvirt_num_of_fds(tvbuff_t *tvb, proto_tree *tree)
{
gint32 nfds;
nfds = tvb_get_ntohl(tvb, VIR_HEADER_LEN);
proto_tree_add_int(tree, hf_libvirt_num_of_fds, tvb, VIR_HEADER_LEN, 4, nfds);
return nfds;
}
static void
dissect_libvirt_fds(tvbuff_t *tvb, gint start, gint32 nfds)
{
/* TODO: NOP for now */
}
static void
dissect_libvirt_payload_xdr_data(tvbuff_t *tvb, proto_tree *tree, gint payload_length,
gint32 status, vir_xdr_dissector_t dissect)
{
gint32 nfds = 0;
gint start = VIR_HEADER_LEN;
tvbuff_t *payload_tvb;
caddr_t payload_data;
XDR xdrs;
if (status == VIR_NET_CALL_WITH_FDS ||
status == VIR_NET_REPLY_WITH_FDS) {
nfds = dissect_libvirt_num_of_fds(tvb, tree);
start += 4;
payload_length -= 4;
}
payload_tvb = tvb_new_subset(tvb, start, -1, payload_length);
payload_data = (caddr_t)tvb_memdup(payload_tvb, 0, payload_length);
xdrmem_create(&xdrs, payload_data, payload_length, XDR_DECODE);
dissect(payload_tvb, tree, &xdrs, -1);
xdr_destroy(&xdrs);
g_free(payload_data);
if (nfds != 0) {
dissect_libvirt_fds(tvb, start + payload_length, nfds);
}
}
static void
dissect_libvirt_payload(tvbuff_t *tvb, proto_tree *tree,
guint32 prog, guint32 proc, guint32 type, guint32 status)
{
gssize payload_length;
payload_length = tvb_length(tvb) - VIR_HEADER_LEN;
if (payload_length <= 0)
return; /* No payload */
if (status == VIR_NET_OK) {
vir_xdr_dissector_t xd = find_payload_dissector(proc, type, get_program_data(prog, VIR_PROGRAM_DISSECTORS),
*(gsize *)get_program_data(prog, VIR_PROGRAM_DISSECTORS_LEN));
if (xd == NULL)
goto unknown;
dissect_libvirt_payload_xdr_data(tvb, tree, payload_length, status, xd);
} else if (status == VIR_NET_ERROR) {
dissect_libvirt_payload_xdr_data(tvb, tree, payload_length, status, VIR_ERROR_MESSAGE_DISSECTOR);
} else if (type == VIR_NET_STREAM) { /* implicitly, status == VIR_NET_CONTINUE */
dissect_libvirt_stream(tvb, tree, payload_length);
} else {
goto unknown;
}
return;
unknown:
dbg("Cannot determine payload: Prog=%u, Proc=%u, Type=%u, Status=%u", prog, proc, type, status);
proto_tree_add_item(tree, hf_libvirt_unknown, tvb, VIR_HEADER_LEN, -1, ENC_NA);
}
static void
dissect_libvirt_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
goffset offset;
guint32 prog, proc, type, serial, status;
const value_string *vs;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Libvirt");
col_clear(pinfo->cinfo, COL_INFO);
offset = 4; /* End of length field */
prog = tvb_get_ntohl(tvb, offset); offset += 4;
offset += 4; /* Ignore version header field */
proc = tvb_get_ntohl(tvb, offset); offset += 4;
type = tvb_get_ntohl(tvb, offset); offset += 4;
serial = tvb_get_ntohl(tvb, offset); offset += 4;
status = tvb_get_ntohl(tvb, offset); offset += 4;
col_add_fstr(pinfo->cinfo, COL_INFO, "Prog=%s",
val_to_str(prog, program_strings, "%x"));
vs = get_program_data(prog, VIR_PROGRAM_PROCSTRINGS);
if (vs == NULL) {
col_append_fstr(pinfo->cinfo, COL_INFO, " Proc=%u", proc);
} else {
col_append_fstr(pinfo->cinfo, COL_INFO, " Proc=%s", val_to_str(proc, vs, "%d"));
}
col_append_fstr(pinfo->cinfo, COL_INFO, " Type=%s Serial=%u Status=%s",
val_to_str(type, type_strings, "%d"), serial,
val_to_str(status, status_strings, "%d"));
if (tree) {
gint *hf_proc;
proto_item *ti;
proto_tree *libvirt_tree;
ti = proto_tree_add_item(tree, proto_libvirt, tvb, 0, tvb_length(tvb), ENC_NA);
libvirt_tree = proto_item_add_subtree(ti, ett_libvirt);
offset = 0;
proto_tree_add_item(libvirt_tree, hf_libvirt_length, tvb, offset, 4, ENC_NA); offset += 4;
proto_tree_add_item(libvirt_tree, hf_libvirt_program, tvb, offset, 4, ENC_NA); offset += 4;
proto_tree_add_item(libvirt_tree, hf_libvirt_version, tvb, offset, 4, ENC_NA); offset += 4;
hf_proc = (int *)get_program_data(prog, VIR_PROGRAM_PROCHFVAR);
if (hf_proc != NULL && *hf_proc != -1) {
proto_tree_add_item(libvirt_tree, *hf_proc, tvb, offset, 4, ENC_NA);
} else {
/* No string representation, but still useful displaying proc number */
proto_tree_add_item(libvirt_tree, hf_libvirt_procedure, tvb, offset, 4, ENC_NA);
}
offset += 4;
proto_tree_add_item(libvirt_tree, hf_libvirt_type, tvb, offset, 4, ENC_NA); offset += 4;
proto_tree_add_item(libvirt_tree, hf_libvirt_serial, tvb, offset, 4, ENC_NA); offset += 4;
proto_tree_add_item(libvirt_tree, hf_libvirt_status, tvb, offset, 4, ENC_NA); offset += 4;
/* Dissect payload remaining */
dissect_libvirt_payload(tvb, libvirt_tree, prog, proc, type, status);
}
}
static guint32
get_message_len(packet_info *pinfo __attribute__((unused)), tvbuff_t *tvb, int offset)
{
return tvb_get_ntohl(tvb, offset);
}
static void
dissect_libvirt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* Another magic const - 4; simply, how much bytes
* is needed to tell the length of libvirt packet. */
tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_message_len, dissect_libvirt_message);
}
void
proto_register_libvirt(void)
{
static hf_register_info hf[] = {
{ &hf_libvirt_length,
{ "length", "libvirt.length",
FT_UINT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL}
},
{ &hf_libvirt_program,
{ "program", "libvirt.program",
FT_UINT32, BASE_HEX,
VALS(program_strings), 0x0,
NULL, HFILL}
},
{ &hf_libvirt_version,
{ "version", "libvirt.version",
FT_UINT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL}
},
{ &hf_libvirt_procedure,
{ "procedure", "libvirt.procedure",
FT_INT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL}
},
{ &hf_libvirt_type,
{ "type", "libvirt.type",
FT_INT32, BASE_DEC,
VALS(type_strings), 0x0,
NULL, HFILL}
},
{ &hf_libvirt_serial,
{ "serial", "libvirt.serial",
FT_UINT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL}
},
{ &hf_libvirt_status,
{ "status", "libvirt.status",
FT_INT32, BASE_DEC,
VALS(status_strings), 0x0,
NULL, HFILL}
},
VIR_DYNAMIC_HFSET
{ &hf_libvirt_stream,
{ "stream", "libvirt.stream",
FT_BYTES, BASE_NONE,
NULL, 0x0,
NULL, HFILL}
},
{ &hf_libvirt_num_of_fds,
{ "num_of_fds", "libvirt.num_of_fds",
FT_INT32, BASE_DEC,
NULL, 0x0,
NULL, HFILL}
},
{ &hf_libvirt_unknown,
{ "unknown", "libvirt.unknown",
FT_BYTES, BASE_NONE,
NULL, 0x0,
NULL, HFILL}
},
};
static gint *ett[] = {
VIR_DYNAMIC_ETTSET
&ett_libvirt
};
proto_libvirt = proto_register_protocol(
"Libvirt", /* name */
"libvirt", /* short name */
"libvirt" /* abbrev */
);
proto_register_field_array(proto_libvirt, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_libvirt(void)
{
static dissector_handle_t libvirt_handle;
libvirt_handle = create_dissector_handle(dissect_libvirt, proto_libvirt);
dissector_add_uint("tcp.port", LIBVIRT_PORT, libvirt_handle);
}

View File

@ -0,0 +1,128 @@
/* packet-libvirt.h --- Libvirt packet dissector header file.
*
* Copyright (C) 2013 Yuto KAWAMURA(kawamuray) <kawamuray.dadada@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Yuto KAWAMURA(kawamuray)
*/
#ifndef _PACKET_LIBVIRT_H_
# define _PACKET_LIBVIRT_H_
# ifndef LIBVIRT_PORT
# define LIBVIRT_PORT 16509
# endif
# define VIR_HEADER_LEN 28
# ifdef DEBUG
# define dbg(fmt, ...) \
g_print("[LIBVIRT] " fmt " at " __FILE__ " line %d\n", ##__VA_ARGS__, __LINE__)
# else
# define dbg(fmt, ...)
# endif
typedef gboolean (*vir_xdr_dissector_t)(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
typedef struct vir_dissector_index vir_dissector_index_t;
struct vir_dissector_index {
guint32 proc;
vir_xdr_dissector_t args;
vir_xdr_dissector_t ret;
vir_xdr_dissector_t msg;
};
enum vir_net_message_type {
VIR_NET_CALL = 0,
VIR_NET_REPLY = 1,
VIR_NET_MESSAGE = 2,
VIR_NET_STREAM = 3,
VIR_NET_CALL_WITH_FDS = 4,
VIR_NET_REPLY_WITH_FDS = 5,
};
enum vir_net_message_status {
VIR_NET_OK = 0,
VIR_NET_ERROR = 1,
VIR_NET_CONTINUE = 2,
};
enum vir_program_data_index {
VIR_PROGRAM_PROCHFVAR,
VIR_PROGRAM_PROCSTRINGS,
VIR_PROGRAM_DISSECTORS,
VIR_PROGRAM_DISSECTORS_LEN,
VIR_PROGRAM_LAST,
};
static const value_string type_strings[] = {
{ VIR_NET_CALL, "CALL" },
{ VIR_NET_REPLY, "REPLY" },
{ VIR_NET_MESSAGE, "MESSAGE" },
{ VIR_NET_STREAM, "STREAM" },
{ VIR_NET_CALL_WITH_FDS, "CALL_WITH_FDS" },
{ VIR_NET_REPLY_WITH_FDS, "REPLY_WITH_FDS" },
{ -1, NULL }
};
static const value_string status_strings[] = {
{ VIR_NET_OK, "OK" },
{ VIR_NET_ERROR, "ERROR" },
{ VIR_NET_CONTINUE, "CONTINUE" },
{ -1, NULL }
};
/* TODO: These symbols will automatically included in generated headers in the feature */
# define VIR_SECURITY_MODEL_BUFLEN (256 + 1)
# define VIR_SECURITY_LABEL_BUFLEN (4096 + 1)
# define VIR_SECURITY_DOI_BUFLEN (256 + 1)
# define VIR_UUID_BUFLEN (16)
enum {
VIR_TYPED_PARAM_INT = 1, /* integer case */
VIR_TYPED_PARAM_UINT = 2, /* unsigned integer case */
VIR_TYPED_PARAM_LLONG = 3, /* long long case */
VIR_TYPED_PARAM_ULLONG = 4, /* unsigned long long case */
VIR_TYPED_PARAM_DOUBLE = 5, /* double case */
VIR_TYPED_PARAM_BOOLEAN = 6, /* boolean(character) case */
VIR_TYPED_PARAM_STRING = 7, /* string case */
};
/* / */
# define VIR_ERROR_MESSAGE_DISSECTOR dissect_xdr_remote_error
static gboolean dissect_xdr_int(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_u_int(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_short(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_u_short(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_char(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_u_char(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_hyper(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_u_hyper(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_float(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_double(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_bool(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf);
static gboolean dissect_xdr_string(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf, guint32 maxlen);
static gboolean dissect_xdr_opaque(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf, guint32 size);
static gboolean dissect_xdr_bytes(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf, guint32 maxlen);
static gboolean dissect_xdr_pointer(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf,
vir_xdr_dissector_t dp);
static gboolean dissect_xdr_vector(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf, gint ett,
int rhf, gchar *rtype, guint32 size, vir_xdr_dissector_t dp);
static gboolean dissect_xdr_array(tvbuff_t *tvb, proto_tree *tree, XDR *xdrs, int hf, gint ett,
int rhf, gchar *rtype, guint32 maxlen, vir_xdr_dissector_t dp);
# include "libvirt/protocol.h"
#endif /* _PACKET_LIBVIRT_H_ */

1011
tools/wireshark/util/genxdrstub.pl Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,198 @@
#! /bin/sh
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# Copied from Wireshark(http://www.wireshark.org/)
#
# The first argument is the directory in which the source files live.
#
srcdir="$1"
shift
#
# The second argument is either "plugin" or "dissectors"; if it's
# "plugin", we build a plugin.c for a plugin, and if it's
# "dissectors", we build a register.c for libwireshark.
#
registertype="$1"
shift
if [ "$registertype" = plugin ]
then
outfile="plugin.c"
elif [ "$registertype" = dissectors ]
then
outfile="register.c"
else
echo "Unknown output type '$registertype'" 1>&2
exit 1
fi
#
# All subsequent arguments are the files to scan.
#
rm -f ${outfile}-tmp
echo '/* Do not modify this file. */' >${outfile}-tmp
echo '/* It is created automatically by the Makefile. */'>>${outfile}-tmp
if [ "$registertype" = plugin ]
then
cat <<"EOF" >>${outfile}-tmp
#include "config.h"
#include <gmodule.h>
/* plugins are DLLs */
#define WS_BUILD_DLL
#include "ws_symbol_export.h"
#ifndef ENABLE_STATIC
WS_DLL_PUBLIC_NOEXTERN const gchar version[] = VERSION;
/* Start the functions we need for the plugin stuff */
WS_DLL_PUBLIC_NOEXTERN void
plugin_register (void)
{
EOF
#
# Build code to call all the protocol registration routines.
#
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp
else
cat <<"EOF" >>${outfile}-tmp
#include "register.h"
void
register_all_protocols(register_cb cb, gpointer client_data)
{
EOF
#
# Build code to call all the protocol registration routines.
#
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^void proto_register_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_REGISTER, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp
fi
echo '}' >>${outfile}-tmp
#
# Build code to call all the protocol handoff registration routines.
#
if [ "$registertype" = plugin ]
then
cat <<"EOF" >>${outfile}-tmp
WS_DLL_PUBLIC_NOEXTERN void
plugin_reg_handoff(void)
{
EOF
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); \1 ();}/' >>${outfile}-tmp
else
cat <<"EOF" >>${outfile}-tmp
void
register_all_protocol_handoffs(register_cb cb, gpointer client_data)
{
EOF
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp
for f in "$@"
do
if [ -f $f ]
then
srcfile=$f
else
srcfile=$srcdir/$f
fi
grep '^void proto_reg_handoff_[a-z_0-9A-Z]* *(' $srcfile 2>/dev/null | grep -v ';'
done | sed -e 's/^.*://' -e 's/^void \([a-z_0-9A-Z]*\).*/ {extern void \1 (void); if(cb) (*cb)(RA_HANDOFF, \"\1\", client_data); \1 ();}/' >>${outfile}-tmp
fi
echo '}' >>${outfile}-tmp
if [ "$registertype" = plugin ]
then
echo '#endif' >>${outfile}-tmp
else
cat <<"EOF" >>${outfile}-tmp
gulong register_count(void)
{
EOF
proto_regs=`grep RA_REGISTER ${outfile}-tmp | wc -l`
handoff_regs=`grep RA_HANDOFF ${outfile}-tmp | wc -l`
echo " return $proto_regs + $handoff_regs;" >>${outfile}-tmp
echo '}' >>${outfile}-tmp
fi
# Only overwrite outfile if it differs from newly generated file
mv ${outfile}-tmp ${outfile}