diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/dissectors/packet-rpcap.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/dissectors/packet-rpcap.c')
-rw-r--r-- | epan/dissectors/packet-rpcap.c | 1693 |
1 files changed, 1693 insertions, 0 deletions
diff --git a/epan/dissectors/packet-rpcap.c b/epan/dissectors/packet-rpcap.c new file mode 100644 index 00000000..1c86babc --- /dev/null +++ b/epan/dissectors/packet-rpcap.c @@ -0,0 +1,1693 @@ +/* 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; + char *str; + + len = tvb_reported_length_remaining (tvb, offset); + if (len <= 0) + return; + + ti = proto_tree_add_item_ret_display_string(parent_tree, hf_error, tvb, offset, len, ENC_ASCII, pinfo->pool, &str); + expert_add_info_format(pinfo, ti, &ei_error, "Error: %s", str); + col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", str); +} + +/* + * 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_STR_WSP, + 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); + rpcap_tcp_handle = register_dissector(PFNAME ".tcp", dissect_rpcap_tcp, 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); + } + + 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: + */ |