1697 lines
55 KiB
C
1697 lines
55 KiB
C
/* packet-rpcap.c
|
|
*
|
|
* Routines for RPCAP message formats.
|
|
*
|
|
* Copyright 2008, Stig Bjorlykke <stig@bjorlykke.org>, Thales Norway AS
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <epan/packet.h>
|
|
#include <epan/aftypes.h>
|
|
#include <epan/prefs.h>
|
|
#include <epan/to_str.h>
|
|
#include <epan/expert.h>
|
|
#include <epan/exceptions.h>
|
|
#include <epan/show_exception.h>
|
|
#include <wsutil/str_util.h>
|
|
|
|
#include "packet-frame.h"
|
|
#include "packet-pcap_pktdata.h"
|
|
#include "packet-tcp.h"
|
|
|
|
#define PNAME "Remote Packet Capture"
|
|
#define PSNAME "RPCAP"
|
|
#define PFNAME "rpcap"
|
|
|
|
#define RPCAP_MSG_ERROR 0x01
|
|
#define RPCAP_MSG_FINDALLIF_REQ 0x02
|
|
#define RPCAP_MSG_OPEN_REQ 0x03
|
|
#define RPCAP_MSG_STARTCAP_REQ 0x04
|
|
#define RPCAP_MSG_UPDATEFILTER_REQ 0x05
|
|
#define RPCAP_MSG_CLOSE 0x06
|
|
#define RPCAP_MSG_PACKET 0x07
|
|
#define RPCAP_MSG_AUTH_REQ 0x08
|
|
#define RPCAP_MSG_STATS_REQ 0x09
|
|
#define RPCAP_MSG_ENDCAP_REQ 0x0A
|
|
#define RPCAP_MSG_SETSAMPLING_REQ 0x0B
|
|
|
|
#define RPCAP_MSG_FINDALLIF_REPLY (0x80+RPCAP_MSG_FINDALLIF_REQ)
|
|
#define RPCAP_MSG_OPEN_REPLY (0x80+RPCAP_MSG_OPEN_REQ)
|
|
#define RPCAP_MSG_STARTCAP_REPLY (0x80+RPCAP_MSG_STARTCAP_REQ)
|
|
#define RPCAP_MSG_UPDATEFILTER_REPLY (0x80+RPCAP_MSG_UPDATEFILTER_REQ)
|
|
#define RPCAP_MSG_AUTH_REPLY (0x80+RPCAP_MSG_AUTH_REQ)
|
|
#define RPCAP_MSG_STATS_REPLY (0x80+RPCAP_MSG_STATS_REQ)
|
|
#define RPCAP_MSG_ENDCAP_REPLY (0x80+RPCAP_MSG_ENDCAP_REQ)
|
|
#define RPCAP_MSG_SETSAMPLING_REPLY (0x80+RPCAP_MSG_SETSAMPLING_REQ)
|
|
|
|
#define RPCAP_ERR_NETW 1
|
|
#define RPCAP_ERR_INITTIMEOUT 2
|
|
#define RPCAP_ERR_AUTH 3
|
|
#define RPCAP_ERR_FINDALLIF 4
|
|
#define RPCAP_ERR_NOREMOTEIF 5
|
|
#define RPCAP_ERR_OPEN 6
|
|
#define RPCAP_ERR_UPDATEFILTER 7
|
|
#define RPCAP_ERR_GETSTATS 8
|
|
#define RPCAP_ERR_READEX 9
|
|
#define RPCAP_ERR_HOSTNOAUTH 10
|
|
#define RPCAP_ERR_REMOTEACCEPT 11
|
|
#define RPCAP_ERR_STARTCAPTURE 12
|
|
#define RPCAP_ERR_ENDCAPTURE 13
|
|
#define RPCAP_ERR_RUNTIMETIMEOUT 14
|
|
#define RPCAP_ERR_SETSAMPLING 15
|
|
#define RPCAP_ERR_WRONGMSG 16
|
|
#define RPCAP_ERR_WRONGVER 17
|
|
|
|
#define RPCAP_SAMP_NOSAMP 0
|
|
#define RPCAP_SAMP_1_EVERY_N 1
|
|
#define RPCAP_SAMP_FIRST_AFTER_N_MS 2
|
|
|
|
#define RPCAP_RMTAUTH_NULL 0
|
|
#define RPCAP_RMTAUTH_PWD 1
|
|
|
|
#define FLAG_PROMISC 0x0001
|
|
#define FLAG_DGRAM 0x0002
|
|
#define FLAG_SERVEROPEN 0x0004
|
|
#define FLAG_INBOUND 0x0008
|
|
#define FLAG_OUTBOUND 0x0010
|
|
|
|
void proto_register_rpcap (void);
|
|
void proto_reg_handoff_rpcap (void);
|
|
|
|
static int proto_rpcap = -1;
|
|
|
|
static int hf_version = -1;
|
|
static int hf_type = -1;
|
|
static int hf_value = -1;
|
|
static int hf_plen = -1;
|
|
|
|
static int hf_error = -1;
|
|
static int hf_error_value = -1;
|
|
|
|
static int hf_packet = -1;
|
|
static int hf_timestamp = -1;
|
|
static int hf_caplen = -1;
|
|
static int hf_len = -1;
|
|
static int hf_npkt = -1;
|
|
|
|
static int hf_auth_request = -1;
|
|
static int hf_auth_type = -1;
|
|
static int hf_auth_slen1 = -1;
|
|
static int hf_auth_slen2 = -1;
|
|
static int hf_auth_username = -1;
|
|
static int hf_auth_password = -1;
|
|
|
|
static int hf_auth_reply = -1;
|
|
static int hf_auth_minvers = -1;
|
|
static int hf_auth_maxvers = -1;
|
|
|
|
static int hf_open_request = -1;
|
|
|
|
static int hf_open_reply = -1;
|
|
static int hf_linktype = -1;
|
|
static int hf_tzoff = -1;
|
|
|
|
static int hf_startcap_request = -1;
|
|
static int hf_snaplen = -1;
|
|
static int hf_read_timeout = -1;
|
|
static int hf_flags = -1;
|
|
static int hf_flags_promisc = -1;
|
|
static int hf_flags_dgram = -1;
|
|
static int hf_flags_serveropen = -1;
|
|
static int hf_flags_inbound = -1;
|
|
static int hf_flags_outbound = -1;
|
|
static int hf_client_port = -1;
|
|
static int hf_startcap_reply = -1;
|
|
static int hf_bufsize = -1;
|
|
static int hf_server_port = -1;
|
|
static int hf_dummy = -1;
|
|
|
|
static int hf_filter = -1;
|
|
static int hf_filtertype = -1;
|
|
static int hf_nitems = -1;
|
|
|
|
static int hf_filterbpf_insn = -1;
|
|
static int hf_code = -1;
|
|
static int hf_code_class = -1;
|
|
static int hf_code_fields = -1;
|
|
static int hf_code_ld_size = -1;
|
|
static int hf_code_ld_mode = -1;
|
|
static int hf_code_alu_op = -1;
|
|
static int hf_code_jmp_op = -1;
|
|
static int hf_code_src = -1;
|
|
static int hf_code_rval = -1;
|
|
static int hf_code_misc_op = -1;
|
|
static int hf_jt = -1;
|
|
static int hf_jf = -1;
|
|
static int hf_instr_value = -1;
|
|
|
|
static int hf_stats_reply = -1;
|
|
static int hf_ifrecv = -1;
|
|
static int hf_ifdrop = -1;
|
|
static int hf_krnldrop = -1;
|
|
static int hf_srvcapt = -1;
|
|
|
|
static int hf_findalldevs_reply = -1;
|
|
static int hf_findalldevs_if = -1;
|
|
static int hf_namelen = -1;
|
|
static int hf_desclen = -1;
|
|
static int hf_if_flags = -1;
|
|
static int hf_naddr = -1;
|
|
static int hf_if_name = -1;
|
|
static int hf_if_desc = -1;
|
|
|
|
static int hf_findalldevs_ifaddr = -1;
|
|
static int hf_if_addr = -1;
|
|
static int hf_if_netmask = -1;
|
|
static int hf_if_broadaddr = -1;
|
|
static int hf_if_dstaddr = -1;
|
|
static int hf_if_af = -1;
|
|
static int hf_if_port = -1;
|
|
static int hf_if_ipv4 = -1;
|
|
static int hf_if_flowinfo = -1;
|
|
static int hf_if_ipv6 = -1;
|
|
static int hf_if_scopeid = -1;
|
|
static int hf_if_padding = -1;
|
|
static int hf_if_unknown = -1;
|
|
|
|
static int hf_sampling_request = -1;
|
|
static int hf_sampling_method = -1;
|
|
static int hf_sampling_dummy1 = -1;
|
|
static int hf_sampling_dummy2 = -1;
|
|
static int hf_sampling_value = -1;
|
|
|
|
static gint ett_rpcap = -1;
|
|
static gint ett_error = -1;
|
|
static gint ett_packet = -1;
|
|
static gint ett_auth_request = -1;
|
|
static gint ett_auth_reply = -1;
|
|
static gint ett_open_reply = -1;
|
|
static gint ett_startcap_request = -1;
|
|
static gint ett_startcap_reply = -1;
|
|
static gint ett_startcap_flags = -1;
|
|
static gint ett_filter = -1;
|
|
static gint ett_filterbpf_insn = -1;
|
|
static gint ett_filterbpf_insn_code = -1;
|
|
static gint ett_stats_reply = -1;
|
|
static gint ett_findalldevs_reply = -1;
|
|
static gint ett_findalldevs_if = -1;
|
|
static gint ett_findalldevs_ifaddr = -1;
|
|
static gint ett_ifaddr = -1;
|
|
static gint ett_sampling_request = -1;
|
|
|
|
static expert_field ei_error = EI_INIT;
|
|
static expert_field ei_if_unknown = EI_INIT;
|
|
static expert_field ei_no_more_data = EI_INIT;
|
|
static expert_field ei_caplen_too_big = EI_INIT;
|
|
|
|
static dissector_handle_t pcap_pktdata_handle;
|
|
static dissector_handle_t rpcap_tcp_handle;
|
|
|
|
/* User definable values */
|
|
static gboolean rpcap_desegment = TRUE;
|
|
static gboolean decode_content = TRUE;
|
|
static int global_linktype = -1;
|
|
|
|
/* Global variables */
|
|
static int linktype = -1;
|
|
static gboolean info_added = FALSE;
|
|
|
|
static const value_string message_type[] = {
|
|
{ RPCAP_MSG_ERROR, "Error" },
|
|
{ RPCAP_MSG_FINDALLIF_REQ, "Find all interfaces request" },
|
|
{ RPCAP_MSG_OPEN_REQ, "Open request" },
|
|
{ RPCAP_MSG_STARTCAP_REQ, "Start capture request" },
|
|
{ RPCAP_MSG_UPDATEFILTER_REQ, "Update filter request" },
|
|
{ RPCAP_MSG_CLOSE, "Close" },
|
|
{ RPCAP_MSG_PACKET, "Packet" },
|
|
{ RPCAP_MSG_AUTH_REQ, "Authentication request" },
|
|
{ RPCAP_MSG_STATS_REQ, "Statistics request" },
|
|
{ RPCAP_MSG_ENDCAP_REQ, "End capture request" },
|
|
{ RPCAP_MSG_SETSAMPLING_REQ, "Set sampling request" },
|
|
{ RPCAP_MSG_FINDALLIF_REPLY, "Find all interfaces reply" },
|
|
{ RPCAP_MSG_OPEN_REPLY, "Open reply" },
|
|
{ RPCAP_MSG_STARTCAP_REPLY, "Start capture reply" },
|
|
{ RPCAP_MSG_UPDATEFILTER_REPLY, "Update filter reply" },
|
|
{ RPCAP_MSG_AUTH_REPLY, "Authentication reply" },
|
|
{ RPCAP_MSG_STATS_REPLY, "Statistics reply" },
|
|
{ RPCAP_MSG_ENDCAP_REPLY, "End capture reply" },
|
|
{ RPCAP_MSG_SETSAMPLING_REPLY, "Set sampling reply" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string error_codes[] = {
|
|
{ RPCAP_ERR_NETW, "Network error" },
|
|
{ RPCAP_ERR_INITTIMEOUT, "Initial timeout has expired" },
|
|
{ RPCAP_ERR_AUTH, "Authentication error" },
|
|
{ RPCAP_ERR_FINDALLIF, "Generic findalldevs error" },
|
|
{ RPCAP_ERR_NOREMOTEIF, "No remote interfaces" },
|
|
{ RPCAP_ERR_OPEN, "Generic pcap_open error" },
|
|
{ RPCAP_ERR_UPDATEFILTER, "Generic updatefilter error" },
|
|
{ RPCAP_ERR_GETSTATS, "Generic pcap_stats error" },
|
|
{ RPCAP_ERR_READEX, "Generic pcap_next_ex error" },
|
|
{ RPCAP_ERR_HOSTNOAUTH, "The host is not authorized" },
|
|
{ RPCAP_ERR_REMOTEACCEPT, "Generic pcap_remoteaccept error" },
|
|
{ RPCAP_ERR_STARTCAPTURE, "Generic pcap_startcapture error" },
|
|
{ RPCAP_ERR_ENDCAPTURE, "Generic pcap_endcapture error" },
|
|
{ RPCAP_ERR_RUNTIMETIMEOUT, "Runtime timeout has expired" },
|
|
{ RPCAP_ERR_SETSAMPLING, "Error in setting sampling parameters" },
|
|
{ RPCAP_ERR_WRONGMSG, "Unrecognized message" },
|
|
{ RPCAP_ERR_WRONGVER, "Incompatible version" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string sampling_method[] = {
|
|
{ RPCAP_SAMP_NOSAMP, "No sampling" },
|
|
{ RPCAP_SAMP_1_EVERY_N, "1 every N" },
|
|
{ RPCAP_SAMP_FIRST_AFTER_N_MS, "First after N ms" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string auth_type[] = {
|
|
{ RPCAP_RMTAUTH_NULL, "None" },
|
|
{ RPCAP_RMTAUTH_PWD, "Password" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_class[] = {
|
|
{ 0x00, "ld" },
|
|
{ 0x01, "ldx" },
|
|
{ 0x02, "st" },
|
|
{ 0x03, "stx" },
|
|
{ 0x04, "alu" },
|
|
{ 0x05, "jmp" },
|
|
{ 0x06, "ret" },
|
|
{ 0x07, "misc" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_size[] = {
|
|
{ 0x00, "w" },
|
|
{ 0x01, "h" },
|
|
{ 0x02, "b" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_mode[] = {
|
|
{ 0x00, "imm" },
|
|
{ 0x01, "abs" },
|
|
{ 0x02, "ind" },
|
|
{ 0x03, "mem" },
|
|
{ 0x04, "len" },
|
|
{ 0x05, "msh" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_alu_op[] = {
|
|
{ 0x00, "add" },
|
|
{ 0x01, "sub" },
|
|
{ 0x02, "mul" },
|
|
{ 0x03, "div" },
|
|
{ 0x04, "or" },
|
|
{ 0x05, "and" },
|
|
{ 0x06, "lsh" },
|
|
{ 0x07, "rsh" },
|
|
{ 0x08, "neg" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_jmp_op[] = {
|
|
{ 0x00, "ja" },
|
|
{ 0x01, "jeq" },
|
|
{ 0x02, "jgt" },
|
|
{ 0x03, "jge" },
|
|
{ 0x04, "jset" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_src[] = {
|
|
{ 0x00, "k" },
|
|
{ 0x01, "x" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_rval[] = {
|
|
{ 0x00, "k" },
|
|
{ 0x01, "x" },
|
|
{ 0x02, "a" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static const value_string bpf_misc_op[] = {
|
|
{ 0x00, "tax" },
|
|
{ 0x10, "txa" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
|
|
static void rpcap_frame_end (void)
|
|
{
|
|
info_added = FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_error (tvbuff_t *tvb, packet_info *pinfo,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_item *ti;
|
|
gint len;
|
|
|
|
len = tvb_reported_length_remaining (tvb, offset);
|
|
if (len <= 0)
|
|
return;
|
|
|
|
col_append_fstr (pinfo->cinfo, COL_INFO, ": %s",
|
|
tvb_format_text_wsp (pinfo->pool, tvb, offset, len));
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_error, tvb, offset, len, ENC_ASCII);
|
|
expert_add_info_format(pinfo, ti, &ei_error,
|
|
"Error: %s", tvb_format_text_wsp (pinfo->pool, tvb, offset, len));
|
|
}
|
|
|
|
/*
|
|
* There's some painful history with this part of a findalldevs reply.
|
|
*
|
|
* Older RPCAPDs sent the addresses over the wire in the OS's native
|
|
* structure format. For most OSes, this looks like the over-the-wire
|
|
* format, but might have a different value for AF_INET6 than the value
|
|
* on the machine receiving the reply. For OSes with the newer BSD-style
|
|
* sockaddr structures, this has, instead of a 2-byte address family,
|
|
* a 1-byte structure length followed by a 1-byte address family. The
|
|
* RPCAPD code would put the address family in network byte order before
|
|
* sending it; that would set it to 0 on a little-endian machine, as
|
|
* htons() of any value between 1 and 255 would result in a value > 255,
|
|
* with its lower 8 bits zero, so putting that back into a 1-byte field
|
|
* would set it to 0.
|
|
*
|
|
* Therefore, for older RPCAPDs running on an OS with newer BSD-style
|
|
* sockaddr structures, the family field, if treated as a big-endian
|
|
* (network byte order) 16-bit field, would be:
|
|
*
|
|
* (length << 8) | family if sent by a big-endian machine
|
|
* (length << 8) if sent by a little-endian machine
|
|
*
|
|
* For current RPCAPDs, and for older RPCAPDs running on an OS with
|
|
* older BSD-style sockaddr structures, the family field, if treated
|
|
* as a big-endian 16-bit field, would just contain the family.
|
|
*
|
|
* (An additional bit of pain was that the structure was sent over the
|
|
* wire as a network-byte-order struct sockaddr_storage, which does
|
|
* *not* have the same size on all platforms. On most platforms, the
|
|
* structure is 128 bytes long; on Solaris, however, it's 256 bytes
|
|
* long. Neither the rpcap client code in libpcap, nor we, try to
|
|
* detect Solaris addresses and deal with them.)
|
|
*
|
|
* The current rpcapd serializes the socket addresses as 128-byte
|
|
* structures, containing:
|
|
*
|
|
* a 2-octet address family value, in network byte order;
|
|
*
|
|
* a 4-octet IPv4 address, if the address family value is 2
|
|
* (the AF_INET value on all supported platforms);
|
|
*
|
|
* a 16-octet IPv6 address, if the address family value is
|
|
* 23 (the Windows AF_INET6 value, chosen because Windows
|
|
* was, before rpcap was changed to standardize the format,
|
|
* the only platform for which precompiled binaries for
|
|
* rpcapd were generally available);
|
|
*
|
|
* padding up to 128 bytes.
|
|
*
|
|
* The rpcap client code, and we, check for those address family values,
|
|
* as well as other values that might have been produced by the old
|
|
* code on various platforms.
|
|
*/
|
|
|
|
/*
|
|
* Possible IPv4 family values other than the designated over-the-wire value,
|
|
* which is 2 (because everybody uses 2 for AF_INET4).
|
|
*/
|
|
#define SOCKADDR_IN_LEN 16 /* length of struct sockaddr_in */
|
|
#define NEW_BSD_AF_INET_BE ((SOCKADDR_IN_LEN << 8) | BSD_AF_INET)
|
|
#define NEW_BSD_AF_INET_LE (SOCKADDR_IN_LEN << 8)
|
|
|
|
/*
|
|
* Possible IPv6 family values other than the designated over-the-wire value,
|
|
* which is 23 (because that's what Windows uses, and most RPCAP servers
|
|
* out there are probably running Windows, as WinPcap includes the server
|
|
* but few if any UN*Xes build and ship it). Some are defined in
|
|
* <epan/aftypes.h>.
|
|
*
|
|
* The new BSD sockaddr structure format was in place before 4.4-Lite, so
|
|
* all the free-software BSDs use it.
|
|
*/
|
|
#define SOCKADDR_IN6_LEN 28 /* length of struct sockaddr_in6 */
|
|
#define NEW_BSD_AF_INET6_BSD_BE ((SOCKADDR_IN6_LEN << 8) | BSD_AF_INET6_BSD) /* NetBSD, OpenBSD, BSD/OS */
|
|
#define NEW_BSD_AF_INET6_FREEBSD_BE ((SOCKADDR_IN6_LEN << 8) | BSD_AF_INET6_FREEBSD) /* FreeBSD, DragonFly BSD */
|
|
#define NEW_BSD_AF_INET6_DARWIN_BE ((SOCKADDR_IN6_LEN << 8) | BSD_AF_INET6_DARWIN) /* macOS, iOS, anything else Darwin-based */
|
|
#define NEW_BSD_AF_INET6_LE (SOCKADDR_IN6_LEN << 8)
|
|
#define HPUX_AF_INET6 22
|
|
#define AIX_AF_INET6 24
|
|
|
|
static const value_string address_family[] = {
|
|
{ COMMON_AF_UNSPEC, "AF_UNSPEC" },
|
|
{ COMMON_AF_INET, "AF_INET" },
|
|
{ NEW_BSD_AF_INET_BE, "AF_INET (old server code on big-endian 4.4-Lite-based OS)" },
|
|
{ NEW_BSD_AF_INET_LE, "AF_INET (old server code on little-endian 4.4-Lite-based OS)" },
|
|
{ WINSOCK_AF_INET6, "AF_INET6" },
|
|
{ NEW_BSD_AF_INET6_BSD_BE, "AF_INET6 (old server code on big-endian NetBSD, OpenBSD, BSD/OS)" },
|
|
{ NEW_BSD_AF_INET6_FREEBSD_BE, "AF_INET6 (old server code on big-endian FreeBSD)" },
|
|
{ NEW_BSD_AF_INET6_DARWIN_BE, "AF_INET6 (old server code on big-endian Mac OS X)" },
|
|
{ NEW_BSD_AF_INET6_LE, "AF_INET6 (old server code on little-endian 4.4-Lite-based OS)" },
|
|
{ LINUX_AF_INET6, "AF_INET6 (old server code on Linux)" },
|
|
{ HPUX_AF_INET6, "AF_INET6 (old server code on HP-UX)" },
|
|
{ AIX_AF_INET6, "AF_INET6 (old server code on AIX)" },
|
|
{ SOLARIS_AF_INET6, "AF_INET6 (old server code on Solaris)" },
|
|
{ 0, NULL }
|
|
};
|
|
|
|
static gint
|
|
dissect_rpcap_ifaddr (tvbuff_t *tvb, packet_info *pinfo,
|
|
proto_tree *parent_tree, gint offset, int hf_id,
|
|
proto_item *parent_item)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
guint16 af;
|
|
guint32 ipv4;
|
|
ws_in6_addr ipv6;
|
|
gchar ipaddr[MAX_ADDR_STR_LEN];
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_id, tvb, offset, 128, ENC_BIG_ENDIAN);
|
|
tree = proto_item_add_subtree (ti, ett_ifaddr);
|
|
|
|
af = tvb_get_ntohs (tvb, offset);
|
|
proto_tree_add_item (tree, hf_if_af, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
switch (af) {
|
|
|
|
case COMMON_AF_INET:
|
|
case NEW_BSD_AF_INET_BE:
|
|
case NEW_BSD_AF_INET_LE:
|
|
proto_tree_add_item (tree, hf_if_port, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
ipv4 = tvb_get_ipv4 (tvb, offset);
|
|
ip_to_str_buf((guint8 *)&ipv4, ipaddr, MAX_ADDR_STR_LEN);
|
|
proto_item_append_text (ti, ": %s", ipaddr);
|
|
if (parent_item) {
|
|
proto_item_append_text (parent_item, ": %s", ipaddr);
|
|
}
|
|
proto_tree_add_item (tree, hf_if_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_if_padding, tvb, offset, 120, ENC_NA);
|
|
offset += 120;
|
|
break;
|
|
|
|
case WINSOCK_AF_INET6:
|
|
case NEW_BSD_AF_INET6_BSD_BE:
|
|
case NEW_BSD_AF_INET6_FREEBSD_BE:
|
|
case NEW_BSD_AF_INET6_DARWIN_BE:
|
|
case NEW_BSD_AF_INET6_LE:
|
|
case LINUX_AF_INET6:
|
|
case HPUX_AF_INET6:
|
|
case AIX_AF_INET6:
|
|
case SOLARIS_AF_INET6:
|
|
proto_tree_add_item (tree, hf_if_port, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_if_flowinfo, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
tvb_get_ipv6 (tvb, offset, &ipv6);
|
|
ip6_to_str_buf(&ipv6, ipaddr, MAX_ADDR_STR_LEN);
|
|
proto_item_append_text (ti, ": %s", ipaddr);
|
|
if (parent_item) {
|
|
proto_item_append_text (parent_item, ": %s", ipaddr);
|
|
}
|
|
proto_tree_add_item (tree, hf_if_ipv6, tvb, offset, 16, ENC_NA);
|
|
offset += 16;
|
|
|
|
proto_tree_add_item (tree, hf_if_scopeid, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_if_padding, tvb, offset, 108, ENC_NA);
|
|
offset += 100;
|
|
break;
|
|
|
|
default:
|
|
ti = proto_tree_add_item (tree, hf_if_unknown, tvb, offset, 126, ENC_NA);
|
|
if (af != COMMON_AF_UNSPEC) {
|
|
expert_add_info_format(pinfo, ti, &ei_if_unknown,
|
|
"Unknown address family: %d", af);
|
|
}
|
|
offset += 126;
|
|
break;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
static gint
|
|
dissect_rpcap_findalldevs_ifaddr (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
gint boffset = offset;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_findalldevs_ifaddr, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_findalldevs_ifaddr);
|
|
|
|
offset = dissect_rpcap_ifaddr (tvb, pinfo, tree, offset, hf_if_addr, ti);
|
|
offset = dissect_rpcap_ifaddr (tvb, pinfo, tree, offset, hf_if_netmask, NULL);
|
|
offset = dissect_rpcap_ifaddr (tvb, pinfo, tree, offset, hf_if_broadaddr, NULL);
|
|
offset = dissect_rpcap_ifaddr (tvb, pinfo, tree, offset, hf_if_dstaddr, NULL);
|
|
|
|
proto_item_set_len (ti, offset - boffset);
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
static gint
|
|
dissect_rpcap_findalldevs_if (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
guint16 namelen, desclen, naddr, i;
|
|
gint boffset = offset;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_findalldevs_if, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_findalldevs_if);
|
|
|
|
namelen = tvb_get_ntohs (tvb, offset);
|
|
proto_tree_add_item (tree, hf_namelen, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
desclen = tvb_get_ntohs (tvb, offset);
|
|
proto_tree_add_item (tree, hf_desclen, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_if_flags, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
naddr = tvb_get_ntohs (tvb, offset);
|
|
proto_tree_add_item (tree, hf_naddr, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_dummy, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
if (namelen) {
|
|
const guint8* name;
|
|
proto_tree_add_item_ret_string(tree, hf_if_name, tvb, offset, namelen, ENC_ASCII|ENC_NA, pinfo->pool, &name);
|
|
proto_item_append_text (ti, ": %s", name);
|
|
offset += namelen;
|
|
}
|
|
|
|
if (desclen) {
|
|
proto_tree_add_item (tree, hf_if_desc, tvb, offset, desclen, ENC_ASCII);
|
|
offset += desclen;
|
|
}
|
|
|
|
for (i = 0; i < naddr; i++) {
|
|
offset = dissect_rpcap_findalldevs_ifaddr (tvb, pinfo, tree, offset);
|
|
if (tvb_reported_length_remaining (tvb, offset) < 0) {
|
|
/* No more data in packet */
|
|
expert_add_info(pinfo, ti, &ei_no_more_data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
proto_item_set_len (ti, offset - boffset);
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_findalldevs_reply (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset, guint16 no_devs)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
guint16 i;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_findalldevs_reply, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_findalldevs_reply);
|
|
|
|
for (i = 0; i < no_devs; i++) {
|
|
offset = dissect_rpcap_findalldevs_if (tvb, pinfo, tree, offset);
|
|
if (tvb_reported_length_remaining (tvb, offset) < 0) {
|
|
/* No more data in packet */
|
|
expert_add_info(pinfo, ti, &ei_no_more_data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
proto_item_append_text (ti, ", %d item%s", no_devs, plurality (no_devs, "", "s"));
|
|
}
|
|
|
|
|
|
static gint
|
|
dissect_rpcap_filterbpf_insn (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree, *code_tree;
|
|
proto_item *ti, *code_ti;
|
|
guint8 inst_class;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_filterbpf_insn, tvb, offset, 8, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_filterbpf_insn);
|
|
|
|
code_ti = proto_tree_add_item (tree, hf_code, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
code_tree = proto_item_add_subtree (code_ti, ett_filterbpf_insn_code);
|
|
proto_tree_add_item (code_tree, hf_code_class, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
inst_class = tvb_get_guint8 (tvb, offset + 1) & 0x07;
|
|
proto_item_append_text (ti, ": %s", val_to_str_const (inst_class, bpf_class, ""));
|
|
switch (inst_class) {
|
|
case 0x00: /* ld */
|
|
case 0x01: /* ldx */
|
|
proto_tree_add_item (code_tree, hf_code_ld_size, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item (code_tree, hf_code_ld_mode, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
break;
|
|
case 0x04: /* alu */
|
|
proto_tree_add_item (code_tree, hf_code_src, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item (code_tree, hf_code_alu_op, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
break;
|
|
case 0x05: /* jmp */
|
|
proto_tree_add_item (code_tree, hf_code_src, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item (code_tree, hf_code_jmp_op, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
break;
|
|
case 0x06: /* ret */
|
|
proto_tree_add_item (code_tree, hf_code_rval, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
break;
|
|
case 0x07: /* misc */
|
|
proto_tree_add_item (code_tree, hf_code_misc_op, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
break;
|
|
default:
|
|
proto_tree_add_item (code_tree, hf_code_fields, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
break;
|
|
}
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_jt, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
proto_tree_add_item (tree, hf_jf, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
proto_tree_add_item (tree, hf_instr_value, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
return offset;
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_filter (tvbuff_t *tvb, packet_info *pinfo,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
guint32 nitems, i;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_filter, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_filter);
|
|
|
|
proto_tree_add_item (tree, hf_filtertype, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_dummy, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
nitems = tvb_get_ntohl (tvb, offset);
|
|
proto_tree_add_item (tree, hf_nitems, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
for (i = 0; i < nitems; i++) {
|
|
offset = dissect_rpcap_filterbpf_insn (tvb, pinfo, tree, offset);
|
|
if (tvb_reported_length_remaining (tvb, offset) < 0) {
|
|
/* No more data in packet */
|
|
expert_add_info(pinfo, ti, &ei_no_more_data);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
dissect_rpcap_auth_request (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
guint16 type, slen1, slen2;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_auth_request, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_auth_request);
|
|
|
|
type = tvb_get_ntohs (tvb, offset);
|
|
proto_tree_add_item (tree, hf_auth_type, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_dummy, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
slen1 = tvb_get_ntohs (tvb, offset);
|
|
proto_tree_add_item (tree, hf_auth_slen1, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
slen2 = tvb_get_ntohs (tvb, offset);
|
|
proto_tree_add_item (tree, hf_auth_slen2, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
if (type == RPCAP_RMTAUTH_NULL) {
|
|
proto_item_append_text (ti, " (none)");
|
|
} else if (type == RPCAP_RMTAUTH_PWD) {
|
|
const guint8 *username, *password;
|
|
|
|
proto_tree_add_item_ret_string(tree, hf_auth_username, tvb, offset, slen1, ENC_ASCII|ENC_NA, pinfo->pool, &username);
|
|
offset += slen1;
|
|
|
|
proto_tree_add_item_ret_string(tree, hf_auth_password, tvb, offset, slen2, ENC_ASCII|ENC_NA, pinfo->pool, &password);
|
|
offset += slen2;
|
|
|
|
proto_item_append_text (ti, " (%s/%s)", username, password);
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_auth_reply (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
guint32 minvers, maxvers;
|
|
|
|
/*
|
|
* Authentication replies from older servers have no payload.
|
|
* Replies from newer servers have a payload.
|
|
* Dissect the payload if we have any.
|
|
*/
|
|
if (tvb_reported_length_remaining(tvb, offset) != 0) {
|
|
ti = proto_tree_add_item (parent_tree, hf_auth_reply, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_auth_reply);
|
|
|
|
proto_tree_add_item_ret_uint (tree, hf_auth_minvers, tvb, offset, 1, ENC_BIG_ENDIAN, &minvers);
|
|
offset += 1;
|
|
|
|
proto_tree_add_item_ret_uint (tree, hf_auth_maxvers, tvb, offset, 1, ENC_BIG_ENDIAN, &maxvers);
|
|
|
|
proto_item_append_text (ti, ", minimum version %u, maximum version %u", minvers, maxvers);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_open_request (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
gint len;
|
|
|
|
len = tvb_reported_length_remaining (tvb, offset);
|
|
proto_tree_add_item (parent_tree, hf_open_request, tvb, offset, len, ENC_ASCII);
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_open_reply (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_open_reply, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_open_reply);
|
|
|
|
linktype = tvb_get_ntohl (tvb, offset);
|
|
proto_tree_add_item (tree, hf_linktype, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_tzoff, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_startcap_request (tvbuff_t *tvb, packet_info *pinfo,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree, *field_tree;
|
|
proto_item *ti, *field_ti;
|
|
guint16 flags;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_startcap_request, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_startcap_request);
|
|
|
|
proto_tree_add_item (tree, hf_snaplen, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_read_timeout, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
flags = tvb_get_ntohs (tvb, offset);
|
|
field_ti = proto_tree_add_uint_format (tree, hf_flags, tvb, offset, 2, flags, "Flags");
|
|
field_tree = proto_item_add_subtree (field_ti, ett_startcap_flags);
|
|
proto_tree_add_item (field_tree, hf_flags_promisc, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item (field_tree, hf_flags_dgram, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item (field_tree, hf_flags_serveropen, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item (field_tree, hf_flags_inbound, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
proto_tree_add_item (field_tree, hf_flags_outbound, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
|
|
if (flags & 0x1F) {
|
|
gchar *flagstr = wmem_strdup_printf (pinfo->pool, "%s%s%s%s%s",
|
|
(flags & FLAG_PROMISC) ? ", Promiscuous" : "",
|
|
(flags & FLAG_DGRAM) ? ", Datagram" : "",
|
|
(flags & FLAG_SERVEROPEN) ? ", ServerOpen" : "",
|
|
(flags & FLAG_INBOUND) ? ", Inbound" : "",
|
|
(flags & FLAG_OUTBOUND) ? ", Outbound" : "");
|
|
proto_item_append_text (field_ti, ":%s", &flagstr[1]);
|
|
} else {
|
|
proto_item_append_text (field_ti, " (none)");
|
|
}
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_client_port, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
dissect_rpcap_filter (tvb, pinfo, tree, offset);
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_startcap_reply (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_startcap_reply, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_startcap_reply);
|
|
|
|
proto_tree_add_item (tree, hf_bufsize, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_server_port, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_dummy, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_stats_reply (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_stats_reply, tvb, offset, 16, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_stats_reply);
|
|
|
|
proto_tree_add_item (tree, hf_ifrecv, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_ifdrop, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_krnldrop, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_tree_add_item (tree, hf_srvcapt, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
}
|
|
|
|
|
|
static int
|
|
dissect_rpcap_sampling_request (tvbuff_t *tvb, packet_info *pinfo _U_,
|
|
proto_tree *parent_tree, gint offset)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
guint32 value;
|
|
guint8 method;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_sampling_request, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_sampling_request);
|
|
|
|
method = tvb_get_guint8 (tvb, offset);
|
|
proto_tree_add_item (tree, hf_sampling_method, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
proto_tree_add_item (tree, hf_sampling_dummy1, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset += 1;
|
|
|
|
proto_tree_add_item (tree, hf_sampling_dummy2, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
offset += 2;
|
|
|
|
value = tvb_get_ntohl (tvb, offset);
|
|
proto_tree_add_item (tree, hf_sampling_value, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
switch (method) {
|
|
case RPCAP_SAMP_NOSAMP:
|
|
proto_item_append_text (ti, ": None");
|
|
break;
|
|
case RPCAP_SAMP_1_EVERY_N:
|
|
proto_item_append_text (ti, ": 1 every %d", value);
|
|
break;
|
|
case RPCAP_SAMP_FIRST_AFTER_N_MS:
|
|
proto_item_append_text (ti, ": First after %d ms", value);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
|
|
static void
|
|
dissect_rpcap_packet (tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree,
|
|
proto_tree *parent_tree, gint offset, proto_item *top_item)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
tvbuff_t *new_tvb;
|
|
guint caplen, len, frame_no;
|
|
gint reported_length_remaining;
|
|
|
|
ti = proto_tree_add_item (parent_tree, hf_packet, tvb, offset, 20, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_packet);
|
|
|
|
proto_tree_add_item(tree, hf_timestamp, tvb, offset, 8, ENC_TIME_SECS_USECS|ENC_BIG_ENDIAN);
|
|
offset += 8;
|
|
|
|
caplen = tvb_get_ntohl (tvb, offset);
|
|
ti = proto_tree_add_item (tree, hf_caplen, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
len = tvb_get_ntohl (tvb, offset);
|
|
proto_tree_add_item (tree, hf_len, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
frame_no = tvb_get_ntohl (tvb, offset);
|
|
proto_tree_add_item (tree, hf_npkt, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
proto_item_append_text (ti, ", Frame %u", frame_no);
|
|
proto_item_append_text (top_item, " Frame %u", frame_no);
|
|
|
|
/*
|
|
* reported_length_remaining should not be -1, as offset is at
|
|
* most right past the end of the available data in the packet.
|
|
*/
|
|
reported_length_remaining = tvb_reported_length_remaining (tvb, offset);
|
|
if (caplen > (guint)reported_length_remaining) {
|
|
expert_add_info(pinfo, ti, &ei_caplen_too_big);
|
|
return;
|
|
}
|
|
|
|
new_tvb = tvb_new_subset_length_caplen (tvb, offset, caplen, len);
|
|
if (decode_content && linktype != -1) {
|
|
TRY {
|
|
call_dissector_with_data(pcap_pktdata_handle, new_tvb, pinfo, top_tree, &linktype);
|
|
}
|
|
CATCH_BOUNDS_ERRORS {
|
|
show_exception(tvb, pinfo, top_tree, EXCEPT_CODE, GET_MESSAGE);
|
|
}
|
|
ENDTRY;
|
|
|
|
if (!info_added) {
|
|
/* Only indicate when not added before */
|
|
/* Indicate RPCAP in the protocol column */
|
|
col_prepend_fence_fstr(pinfo->cinfo, COL_PROTOCOL, "R|");
|
|
|
|
/* Indicate RPCAP in the info column */
|
|
col_prepend_fence_fstr (pinfo->cinfo, COL_INFO, "Remote | ");
|
|
info_added = TRUE;
|
|
register_frame_end_routine(pinfo, rpcap_frame_end);
|
|
}
|
|
} else {
|
|
if (linktype == -1) {
|
|
proto_item_append_text (ti, ", Unknown link-layer type");
|
|
}
|
|
call_data_dissector(new_tvb, pinfo, top_tree);
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
dissect_rpcap (tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree, void* data _U_)
|
|
{
|
|
proto_tree *tree;
|
|
proto_item *ti;
|
|
tvbuff_t *new_tvb;
|
|
gint len, offset = 0;
|
|
guint8 msg_type;
|
|
guint16 msg_value;
|
|
|
|
col_set_str (pinfo->cinfo, COL_PROTOCOL, PSNAME);
|
|
|
|
col_clear(pinfo->cinfo, COL_INFO);
|
|
|
|
ti = proto_tree_add_item (top_tree, proto_rpcap, tvb, offset, -1, ENC_NA);
|
|
tree = proto_item_add_subtree (ti, ett_rpcap);
|
|
|
|
proto_tree_add_item (tree, hf_version, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset++;
|
|
|
|
msg_type = tvb_get_guint8 (tvb, offset);
|
|
proto_tree_add_item (tree, hf_type, tvb, offset, 1, ENC_BIG_ENDIAN);
|
|
offset++;
|
|
|
|
col_append_str (pinfo->cinfo, COL_INFO,
|
|
val_to_str (msg_type, message_type, "Unknown: 0x%02x"));
|
|
|
|
proto_item_append_text (ti, ", %s", val_to_str (msg_type, message_type, "Unknown: 0x%02x"));
|
|
|
|
msg_value = tvb_get_ntohs (tvb, offset);
|
|
if (msg_type == RPCAP_MSG_ERROR) {
|
|
proto_tree_add_item (tree, hf_error_value, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
} else {
|
|
proto_tree_add_item (tree, hf_value, tvb, offset, 2, ENC_BIG_ENDIAN);
|
|
}
|
|
offset += 2;
|
|
|
|
proto_tree_add_item (tree, hf_plen, tvb, offset, 4, ENC_BIG_ENDIAN);
|
|
offset += 4;
|
|
|
|
|
|
switch (msg_type) {
|
|
case RPCAP_MSG_ERROR:
|
|
dissect_rpcap_error (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_OPEN_REQ:
|
|
dissect_rpcap_open_request (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_STARTCAP_REQ:
|
|
dissect_rpcap_startcap_request (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_UPDATEFILTER_REQ:
|
|
dissect_rpcap_filter (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_PACKET:
|
|
proto_item_set_len (ti, 28);
|
|
dissect_rpcap_packet (tvb, pinfo, top_tree, tree, offset, ti);
|
|
break;
|
|
case RPCAP_MSG_AUTH_REQ:
|
|
dissect_rpcap_auth_request (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_SETSAMPLING_REQ:
|
|
dissect_rpcap_sampling_request (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_AUTH_REPLY:
|
|
dissect_rpcap_auth_reply (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_FINDALLIF_REPLY:
|
|
dissect_rpcap_findalldevs_reply (tvb, pinfo, tree, offset, msg_value);
|
|
break;
|
|
case RPCAP_MSG_OPEN_REPLY:
|
|
dissect_rpcap_open_reply (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_STARTCAP_REPLY:
|
|
dissect_rpcap_startcap_reply (tvb, pinfo, tree, offset);
|
|
break;
|
|
case RPCAP_MSG_STATS_REPLY:
|
|
dissect_rpcap_stats_reply (tvb, pinfo, tree, offset);
|
|
break;
|
|
default:
|
|
len = tvb_reported_length_remaining (tvb, offset);
|
|
if (len) {
|
|
/* Yet unknown, dump as data */
|
|
proto_item_set_len (ti, 8);
|
|
new_tvb = tvb_new_subset_remaining (tvb, offset);
|
|
call_data_dissector(new_tvb, pinfo, top_tree);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return tvb_captured_length(tvb);
|
|
}
|
|
|
|
|
|
static gboolean
|
|
check_rpcap_heur (tvbuff_t *tvb, gboolean tcp)
|
|
{
|
|
gint offset = 0;
|
|
guint8 version, msg_type;
|
|
guint16 msg_value;
|
|
guint32 plen, len, caplen;
|
|
|
|
if (tvb_captured_length (tvb) < 8)
|
|
/* Too short */
|
|
return FALSE;
|
|
|
|
version = tvb_get_guint8 (tvb, offset);
|
|
if (version != 0)
|
|
/* Incorrect version */
|
|
return FALSE;
|
|
offset++;
|
|
|
|
msg_type = tvb_get_guint8 (tvb, offset);
|
|
if (!tcp && msg_type != 7) {
|
|
/* UDP is only used for packets */
|
|
return FALSE;
|
|
}
|
|
if (try_val_to_str(msg_type, message_type) == NULL)
|
|
/* Unknown message type */
|
|
return FALSE;
|
|
offset++;
|
|
|
|
msg_value = tvb_get_ntohs (tvb, offset);
|
|
if (msg_value > 0) {
|
|
if (msg_type == RPCAP_MSG_ERROR) {
|
|
/* Must have a valid error code */
|
|
if (try_val_to_str(msg_value, error_codes) == NULL)
|
|
return FALSE;
|
|
} else if (msg_type != RPCAP_MSG_FINDALLIF_REPLY) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
offset += 2;
|
|
|
|
plen = tvb_get_ntohl (tvb, offset);
|
|
offset += 4;
|
|
len = (guint32) tvb_reported_length_remaining (tvb, offset);
|
|
|
|
switch (msg_type) {
|
|
|
|
case RPCAP_MSG_FINDALLIF_REQ:
|
|
case RPCAP_MSG_UPDATEFILTER_REPLY:
|
|
case RPCAP_MSG_STATS_REQ:
|
|
case RPCAP_MSG_CLOSE:
|
|
case RPCAP_MSG_SETSAMPLING_REPLY:
|
|
case RPCAP_MSG_ENDCAP_REQ:
|
|
case RPCAP_MSG_ENDCAP_REPLY:
|
|
/* Empty payload */
|
|
if (plen != 0 || len != 0)
|
|
return FALSE;
|
|
break;
|
|
|
|
case RPCAP_MSG_OPEN_REPLY:
|
|
case RPCAP_MSG_STARTCAP_REPLY:
|
|
case RPCAP_MSG_SETSAMPLING_REQ:
|
|
/* Always 8 bytes */
|
|
if (plen != 8 || len != 8)
|
|
return FALSE;
|
|
break;
|
|
|
|
case RPCAP_MSG_STATS_REPLY:
|
|
/* Always 16 bytes */
|
|
if (plen != 16 || len != 16)
|
|
return FALSE;
|
|
break;
|
|
|
|
case RPCAP_MSG_PACKET:
|
|
/* Must have the frame header */
|
|
if (plen < 20)
|
|
return FALSE;
|
|
|
|
/* Check if capture length is valid */
|
|
caplen = tvb_get_ntohl (tvb, offset+8);
|
|
/* Always 20 bytes less than packet length */
|
|
if (caplen != (plen - 20) || caplen > 65535)
|
|
return FALSE;
|
|
break;
|
|
|
|
case RPCAP_MSG_FINDALLIF_REPLY:
|
|
case RPCAP_MSG_ERROR:
|
|
case RPCAP_MSG_OPEN_REQ:
|
|
case RPCAP_MSG_STARTCAP_REQ:
|
|
case RPCAP_MSG_UPDATEFILTER_REQ:
|
|
case RPCAP_MSG_AUTH_REQ:
|
|
case RPCAP_MSG_AUTH_REPLY:
|
|
/* Variable length */
|
|
if (plen != len)
|
|
return FALSE;
|
|
break;
|
|
default:
|
|
/* Unknown message type */
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static guint
|
|
get_rpcap_pdu_len (packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
|
|
{
|
|
return tvb_get_ntohl (tvb, offset + 4) + 8;
|
|
}
|
|
|
|
|
|
static int
|
|
dissect_rpcap_tcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|
{
|
|
tcp_dissect_pdus (tvb, pinfo, tree, rpcap_desegment, 8,
|
|
get_rpcap_pdu_len, dissect_rpcap, data);
|
|
return tvb_captured_length (tvb);
|
|
}
|
|
|
|
static gboolean
|
|
dissect_rpcap_heur_tcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|
{
|
|
if (check_rpcap_heur (tvb, TRUE)) {
|
|
/*
|
|
* This is probably a rpcap TCP packet.
|
|
* Make the dissector for this conversation the non-heuristic
|
|
* rpcap dissector, so that malformed rpcap packets are reported
|
|
* as such.
|
|
*/
|
|
conversation_t *conversation = find_conversation_pinfo (pinfo, 0);
|
|
if (conversation)
|
|
conversation_set_dissector_from_frame_number (conversation,
|
|
pinfo->num,
|
|
rpcap_tcp_handle);
|
|
tcp_dissect_pdus (tvb, pinfo, tree, rpcap_desegment, 8,
|
|
get_rpcap_pdu_len, dissect_rpcap, data);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static gboolean
|
|
dissect_rpcap_heur_udp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
|
|
{
|
|
if (check_rpcap_heur (tvb, FALSE)) {
|
|
/* This is probably a rpcap udp package */
|
|
dissect_rpcap (tvb, pinfo, tree, data);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void
|
|
proto_register_rpcap (void)
|
|
{
|
|
static hf_register_info hf[] = {
|
|
/* Common header for all messages */
|
|
{ &hf_version,
|
|
{ "Version", "rpcap.version", FT_UINT8, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_type,
|
|
{ "Message type", "rpcap.type", FT_UINT8, BASE_HEX,
|
|
VALS(message_type), 0x0, NULL, HFILL } },
|
|
{ &hf_value,
|
|
{ "Message value", "rpcap.value", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_plen,
|
|
{ "Payload length", "rpcap.len", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Error */
|
|
{ &hf_error,
|
|
{ "Error", "rpcap.error", FT_STRING, BASE_NONE,
|
|
NULL, 0x0, "Error text", HFILL } },
|
|
{ &hf_error_value,
|
|
{ "Error value", "rpcap.error_value", FT_UINT16, BASE_DEC,
|
|
VALS(error_codes), 0x0, NULL, HFILL } },
|
|
|
|
/* Packet header */
|
|
{ &hf_packet,
|
|
{ "Packet", "rpcap.packet", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, "Packet data", HFILL } },
|
|
{ &hf_timestamp,
|
|
{ "Arrival time", "rpcap.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_caplen,
|
|
{ "Capture length", "rpcap.cap_len", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_len,
|
|
{ "Frame length", "rpcap.len", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, "Frame length (off wire)", HFILL } },
|
|
{ &hf_npkt,
|
|
{ "Frame number", "rpcap.number", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Authentication request */
|
|
{ &hf_auth_request,
|
|
{ "Authentication request", "rpcap.auth_request", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_auth_type,
|
|
{ "Authentication type", "rpcap.auth_type", FT_UINT16, BASE_DEC,
|
|
VALS(auth_type), 0x0, NULL, HFILL } },
|
|
{ &hf_auth_slen1,
|
|
{ "Authentication item length 1", "rpcap.auth_len1", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_auth_slen2,
|
|
{ "Authentication item length 2", "rpcap.auth_len2", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_auth_username,
|
|
{ "Username", "rpcap.username", FT_STRING, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_auth_password,
|
|
{ "Password", "rpcap.password", FT_STRING, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Authentication reply */
|
|
{ &hf_auth_reply,
|
|
{ "Authentication reply", "rpcap.auth_reply", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_auth_minvers,
|
|
{ "Minimum version number supported", "rpcap.auth_minvers", FT_UINT8, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_auth_maxvers,
|
|
{ "Maximum version number supported", "rpcap.auth_maxvers", FT_UINT8, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Open request */
|
|
{ &hf_open_request,
|
|
{ "Open request", "rpcap.open_request", FT_STRING, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Open reply */
|
|
{ &hf_open_reply,
|
|
{ "Open reply", "rpcap.open_reply", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
/*
|
|
* XXX - the code probably sends a DLT_ value over the wire, but
|
|
* it should really send a LINKTYPE_ value, so that if the client
|
|
* and server are running OSes that disagree on the numerical value
|
|
* of that DLT_, they won't get confused (LINKTYPE_ values aren't
|
|
* platform-dependent). The vast majority of LINKTYPE_ values and
|
|
* DLT_ values are the same for the same link-layer type.
|
|
*/
|
|
{ &hf_linktype,
|
|
{ "Link type", "rpcap.linktype", FT_UINT32, BASE_DEC,
|
|
VALS(link_type_vals), 0x0, NULL, HFILL } },
|
|
{ &hf_tzoff,
|
|
{ "Timezone offset", "rpcap.tzoff", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Start capture request */
|
|
{ &hf_startcap_request,
|
|
{ "Start capture request", "rpcap.startcap_request", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_snaplen,
|
|
{ "Snap length", "rpcap.snaplen", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_read_timeout,
|
|
{ "Read timeout", "rpcap.read_timeout", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_flags,
|
|
{ "Flags", "rpcap.flags", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, "Capture flags", HFILL } },
|
|
{ &hf_flags_promisc,
|
|
{ "Promiscuous mode", "rpcap.flags.promisc", FT_BOOLEAN, 16,
|
|
TFS(&tfs_enabled_disabled), FLAG_PROMISC, NULL, HFILL } },
|
|
{ &hf_flags_dgram,
|
|
{ "Use Datagram", "rpcap.flags.dgram", FT_BOOLEAN, 16,
|
|
TFS(&tfs_yes_no), FLAG_DGRAM, NULL, HFILL } },
|
|
{ &hf_flags_serveropen,
|
|
{ "Server open", "rpcap.flags.serveropen", FT_BOOLEAN, 16,
|
|
TFS(&tfs_open_closed), FLAG_SERVEROPEN, NULL, HFILL } },
|
|
{ &hf_flags_inbound,
|
|
{ "Inbound", "rpcap.flags.inbound", FT_BOOLEAN, 16,
|
|
TFS(&tfs_yes_no), FLAG_INBOUND, NULL, HFILL } },
|
|
{ &hf_flags_outbound,
|
|
{ "Outbound", "rpcap.flags.outbound", FT_BOOLEAN, 16,
|
|
TFS(&tfs_yes_no), FLAG_OUTBOUND, NULL, HFILL } },
|
|
{ &hf_client_port,
|
|
{ "Client Port", "rpcap.client_port", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Start capture reply */
|
|
{ &hf_startcap_reply,
|
|
{ "Start capture reply", "rpcap.startcap_reply", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_bufsize,
|
|
{ "Buffer size", "rpcap.bufsize", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_server_port,
|
|
{ "Server port", "rpcap.server_port", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_dummy,
|
|
{ "Dummy", "rpcap.dummy", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Filter */
|
|
{ &hf_filter,
|
|
{ "Filter", "rpcap.filter", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_filtertype,
|
|
{ "Filter type", "rpcap.filtertype", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, "Filter type (BPF)", HFILL } },
|
|
{ &hf_nitems,
|
|
{ "Number of items", "rpcap.nitems", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Filter BPF instruction */
|
|
{ &hf_filterbpf_insn,
|
|
{ "Filter BPF instruction", "rpcap.filterbpf_insn", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_code,
|
|
{ "Op code", "rpcap.opcode", FT_UINT16, BASE_HEX,
|
|
NULL, 0x0, "Operation code", HFILL } },
|
|
{ &hf_code_class,
|
|
{ "Class", "rpcap.opcode.class", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_class), 0x07, "Instruction Class", HFILL } },
|
|
{ &hf_code_fields,
|
|
{ "Fields", "rpcap.opcode.fields", FT_UINT16, BASE_HEX,
|
|
NULL, 0xF8, "Class Fields", HFILL } },
|
|
{ &hf_code_ld_size,
|
|
{ "Size", "rpcap.opcode.size", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_size), 0x18, NULL, HFILL } },
|
|
{ &hf_code_ld_mode,
|
|
{ "Mode", "rpcap.opcode.mode", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_mode), 0xE0, NULL, HFILL } },
|
|
{ &hf_code_alu_op,
|
|
{ "Op", "rpcap.opcode.aluop", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_alu_op), 0xF0, NULL, HFILL } },
|
|
{ &hf_code_jmp_op,
|
|
{ "Op", "rpcap.opcode.jmpop", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_jmp_op), 0xF0, NULL, HFILL } },
|
|
{ &hf_code_src,
|
|
{ "Src", "rpcap.opcode.src", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_src), 0x08, NULL, HFILL } },
|
|
{ &hf_code_rval,
|
|
{ "Rval", "rpcap.opcode.rval", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_rval), 0x18, NULL, HFILL } },
|
|
{ &hf_code_misc_op,
|
|
{ "Op", "rpcap.opcode.miscop", FT_UINT16, BASE_HEX,
|
|
VALS(bpf_misc_op), 0xF8, NULL, HFILL } },
|
|
{ &hf_jt,
|
|
{ "JT", "rpcap.jt", FT_UINT8, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_jf,
|
|
{ "JF", "rpcap.jf", FT_UINT8, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_instr_value,
|
|
{ "Instruction value", "rpcap.instr_value", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, "Instruction-Dependent value", HFILL } },
|
|
|
|
/* Statistics reply */
|
|
{ &hf_stats_reply,
|
|
{ "Statistics", "rpcap.stats_reply", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, "Statistics reply data", HFILL } },
|
|
{ &hf_ifrecv,
|
|
{ "Received by kernel filter", "rpcap.ifrecv", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, "Received by kernel", HFILL } },
|
|
{ &hf_ifdrop,
|
|
{ "Dropped by network interface", "rpcap.ifdrop", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_krnldrop,
|
|
{ "Dropped by kernel filter", "rpcap.krnldrop", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_srvcapt,
|
|
{ "Captured by rpcapd", "rpcap.srvcapt", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, "Captured by RPCAP daemon", HFILL } },
|
|
|
|
/* Find all devices reply */
|
|
{ &hf_findalldevs_reply,
|
|
{ "Find all devices", "rpcap.findalldevs_reply", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_findalldevs_if,
|
|
{ "Interface", "rpcap.if", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_namelen,
|
|
{ "Name length", "rpcap.namelen", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_desclen,
|
|
{ "Description length", "rpcap.desclen", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_flags,
|
|
{ "Interface flags", "rpcap.if.flags", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_naddr,
|
|
{ "Number of addresses", "rpcap.naddr", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_name,
|
|
{ "Name", "rpcap.ifname", FT_STRING, BASE_NONE,
|
|
NULL, 0x0, "Interface name", HFILL } },
|
|
{ &hf_if_desc,
|
|
{ "Description", "rpcap.ifdesc", FT_STRING, BASE_NONE,
|
|
NULL, 0x0, "Interface description", HFILL } },
|
|
|
|
/* Find all devices / Interface addresses */
|
|
{ &hf_findalldevs_ifaddr,
|
|
{ "Interface address", "rpcap.ifaddr", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_addr,
|
|
{ "Address", "rpcap.addr", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, "Network address", HFILL } },
|
|
{ &hf_if_netmask,
|
|
{ "Netmask", "rpcap.netmask", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_broadaddr,
|
|
{ "Broadcast", "rpcap.broadaddr", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_dstaddr,
|
|
{ "P2P destination address", "rpcap.dstaddr", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_af,
|
|
{ "Address family", "rpcap.if.af", FT_UINT16, BASE_HEX,
|
|
VALS(address_family), 0x0, NULL, HFILL } },
|
|
{ &hf_if_port,
|
|
{ "Port", "rpcap.if.port", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, "Port number", HFILL } },
|
|
{ &hf_if_ipv4,
|
|
{ "IPv4 address", "rpcap.if.ipv4", FT_IPv4, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_flowinfo,
|
|
{ "Flow information", "rpcap.if.flowinfo", FT_UINT32, BASE_HEX,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_ipv6,
|
|
{ "IPv6 address", "rpcap.if.ipv6", FT_IPv6, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_scopeid,
|
|
{ "Scope ID", "rpcap.if.scopeid", FT_UINT32, BASE_HEX,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_padding,
|
|
{ "Padding", "rpcap.if.padding", FT_BYTES, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_if_unknown,
|
|
{ "Unknown address", "rpcap.if.unknown", FT_BYTES, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
|
|
/* Sampling request */
|
|
{ &hf_sampling_request,
|
|
{ "Sampling", "rpcap.sampling_request", FT_NONE, BASE_NONE,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_sampling_method,
|
|
{ "Method", "rpcap.sampling_method", FT_UINT8, BASE_DEC,
|
|
VALS(sampling_method), 0x0, "Sampling method", HFILL } },
|
|
{ &hf_sampling_dummy1,
|
|
{ "Dummy1", "rpcap.dummy", FT_UINT8, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_sampling_dummy2,
|
|
{ "Dummy2", "rpcap.dummy", FT_UINT16, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
{ &hf_sampling_value,
|
|
{ "Value", "rpcap.sampling_value", FT_UINT32, BASE_DEC,
|
|
NULL, 0x0, NULL, HFILL } },
|
|
};
|
|
|
|
static gint *ett[] = {
|
|
&ett_rpcap,
|
|
&ett_error,
|
|
&ett_packet,
|
|
&ett_auth_request,
|
|
&ett_auth_reply,
|
|
&ett_open_reply,
|
|
&ett_startcap_request,
|
|
&ett_startcap_reply,
|
|
&ett_startcap_flags,
|
|
&ett_filter,
|
|
&ett_filterbpf_insn,
|
|
&ett_filterbpf_insn_code,
|
|
&ett_stats_reply,
|
|
&ett_findalldevs_reply,
|
|
&ett_findalldevs_if,
|
|
&ett_findalldevs_ifaddr,
|
|
&ett_ifaddr,
|
|
&ett_sampling_request
|
|
};
|
|
|
|
static ei_register_info ei[] = {
|
|
{ &ei_error, { "rpcap.error.expert", PI_SEQUENCE, PI_NOTE, "Error", EXPFILL }},
|
|
{ &ei_if_unknown, { "rpcap.if_unknown", PI_SEQUENCE, PI_NOTE, "Unknown address family", EXPFILL }},
|
|
{ &ei_no_more_data, { "rpcap.no_more_data", PI_MALFORMED, PI_ERROR, "No more data in packet", EXPFILL }},
|
|
{ &ei_caplen_too_big, { "rpcap.caplen_too_big", PI_MALFORMED, PI_ERROR, "Caplen is bigger than the remaining message length", EXPFILL }},
|
|
};
|
|
|
|
module_t *rpcap_module;
|
|
expert_module_t* expert_rpcap;
|
|
|
|
proto_rpcap = proto_register_protocol (PNAME, PSNAME, PFNAME);
|
|
register_dissector (PFNAME, dissect_rpcap, proto_rpcap);
|
|
expert_rpcap = expert_register_protocol(proto_rpcap);
|
|
expert_register_field_array(expert_rpcap, ei, array_length(ei));
|
|
|
|
proto_register_field_array (proto_rpcap, hf, array_length (hf));
|
|
proto_register_subtree_array (ett, array_length (ett));
|
|
|
|
/* Register our configuration options */
|
|
rpcap_module = prefs_register_protocol (proto_rpcap, proto_reg_handoff_rpcap);
|
|
|
|
prefs_register_bool_preference (rpcap_module, "desegment_pdus",
|
|
"Reassemble PDUs spanning multiple TCP segments",
|
|
"Whether the RPCAP dissector should reassemble PDUs"
|
|
" spanning multiple TCP segments."
|
|
" To use this option, you must also enable \"Allow subdissectors"
|
|
" to reassemble TCP streams\" in the TCP protocol settings.",
|
|
&rpcap_desegment);
|
|
prefs_register_bool_preference (rpcap_module, "decode_content",
|
|
"Decode content according to link-layer type",
|
|
"Whether the packets should be decoded according to"
|
|
" the link-layer type.",
|
|
&decode_content);
|
|
prefs_register_uint_preference (rpcap_module, "linktype",
|
|
"Default link-layer type",
|
|
"Default link-layer type to use if an Open Reply packet"
|
|
" has not been captured.",
|
|
10, &global_linktype);
|
|
}
|
|
|
|
void
|
|
proto_reg_handoff_rpcap (void)
|
|
{
|
|
static gboolean rpcap_prefs_initialized = FALSE;
|
|
|
|
if (!rpcap_prefs_initialized) {
|
|
pcap_pktdata_handle = find_dissector_add_dependency("pcap_pktdata", proto_rpcap);
|
|
rpcap_prefs_initialized = TRUE;
|
|
|
|
heur_dissector_add ("tcp", dissect_rpcap_heur_tcp, "RPCAP over TCP", "rpcap_tcp", proto_rpcap, HEURISTIC_ENABLE);
|
|
heur_dissector_add ("udp", dissect_rpcap_heur_udp, "RPCAP over UDP", "rpcap_udp", proto_rpcap, HEURISTIC_ENABLE);
|
|
|
|
rpcap_tcp_handle = create_dissector_handle(dissect_rpcap_tcp, proto_rpcap);
|
|
}
|
|
|
|
info_added = FALSE;
|
|
linktype = global_linktype;
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local Variables:
|
|
* c-basic-offset: 2
|
|
* tab-width: 8
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*
|
|
* ex: set shiftwidth=2 tabstop=8 expandtab:
|
|
* :indentSize=2:tabSize=8:noTabs=true:
|
|
*/
|