#endif
#include <glib.h>
-#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <epan/packet.h>
*/
static gboolean rpc_find_fragment_start = FALSE;
-static struct true_false_string yesno = { "Yes", "No" };
-
static int rpc_tap = -1;
static const value_string rpc_msg_type[] = {
{ 0, NULL }
};
-value_string rpc_authgss_svc[] = {
+const value_string rpc_authgss_svc[] = {
{ RPCSEC_GSS_SVC_NONE, "rpcsec_gss_svc_none" },
{ RPCSEC_GSS_SVC_INTEGRITY, "rpcsec_gss_svc_integrity" },
{ RPCSEC_GSS_SVC_PRIVACY, "rpcsec_gss_svc_privacy" },
static int hf_rpc_authgss_token_length = -1;
static int hf_rpc_authgss_data_length = -1;
static int hf_rpc_authgss_data = -1;
+static int hf_rpc_authgss_token = -1;
static int hf_rpc_authgss_checksum = -1;
static int hf_rpc_authgssapi_v = -1;
static int hf_rpc_authgssapi_msg = -1;
static int hf_rpc_fragment_multiple_tails = -1;
static int hf_rpc_fragment_too_long_fragment = -1;
static int hf_rpc_fragment_error = -1;
+static int hf_rpc_fragment_count = -1;
+static int hf_rpc_reassembled_length = -1;
static gint ett_rpc = -1;
static gint ett_rpc_unknown_program = -1;
static dissector_handle_t gssapi_handle;
static dissector_handle_t data_handle;
-static guint max_rpc_tcp_pdu_size = 262144;
+static guint max_rpc_tcp_pdu_size = 4 * 1024 * 1024;
static const fragment_items rpc_frag_items = {
&ett_rpc_fragment,
&hf_rpc_fragment_multiple_tails,
&hf_rpc_fragment_too_long_fragment,
&hf_rpc_fragment_error,
+ &hf_rpc_fragment_count,
NULL,
+ &hf_rpc_reassembled_length,
"fragments"
};
rpc_proc_info_value *value;
char *procname;
- procname=ep_alloc(20);
key.prog = prog;
key.vers = vers;
key.proc = proc;
else {
/* happens only with strange program versions or
non-existing dissectors */
- g_snprintf(procname, 20, "proc-%u", key.proc);
+ procname = ep_strdup_printf("proc-%u", key.proc);
}
return procname;
}
/* return the hf_field associated with a previously registered program.
*/
-int rpc_prog_hf(guint32 prog, guint32 vers)
+int
+rpc_prog_hf(guint32 prog, guint32 vers)
{
rpc_prog_info_key rpc_prog_key;
rpc_prog_info_value *rpc_prog;
/* return the name associated with a previously registered program. This
should probably eventually be expanded to use the rpc YP/NIS map
so that it can give names for programs not handled by wireshark */
-const char *rpc_prog_name(guint32 prog)
+const char *
+rpc_prog_name(guint32 prog)
{
const char *progname = NULL;
rpc_prog_info_key rpc_prog_key;
int
dissect_rpc_bool(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+ int hfindex, int offset)
{
if (tree)
proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
int
dissect_rpc_uint32(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+ int hfindex, int offset)
{
if (tree)
proto_tree_add_item(tree, hfindex, tvb, offset, 4, FALSE);
int
dissect_rpc_uint64(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+ int hfindex, int offset)
{
header_field_info *hfinfo;
}
if (string_data) {
- char *tmpstr;
- tmpstr = tvb_get_ephemeral_string(tvb, data_offset, string_length_copy);
- string_buffer = memcpy(ep_alloc(string_length_copy+1), tmpstr, string_length_copy);
+ string_buffer = tvb_get_ephemeral_string(tvb, data_offset, string_length_copy);
} else {
string_buffer = tvb_memcpy(tvb, ep_alloc(string_length_copy+1), data_offset, string_length_copy);
}
char *formatted;
formatted = format_text(string_buffer, strlen(string_buffer));
- /* alloc maximum data area */
-#define STRING_BUFFER_PRINT_MAX_LEN (strlen(formatted)+12+1)
- string_buffer_print = (char*)ep_alloc(STRING_BUFFER_PRINT_MAX_LEN);
/* copy over the data and append <TRUNCATED> */
- g_snprintf(string_buffer_print, STRING_BUFFER_PRINT_MAX_LEN, "%s<TRUNCATED>", formatted);
+ string_buffer_print=ep_strdup_printf("%s%s", formatted, RPC_STRING_TRUNCATED);
} else {
- string_buffer_print="<DATA><TRUNCATED>";
+ string_buffer_print=RPC_STRING_DATA RPC_STRING_TRUNCATED;
}
} else {
if (string_data) {
string_buffer_print =
ep_strdup(format_text(string_buffer, strlen(string_buffer)));
} else {
- string_buffer_print="<DATA>";
+ string_buffer_print=RPC_STRING_DATA;
}
}
} else {
- string_buffer_print="<EMPTY>";
+ string_buffer_print=RPC_STRING_EMPTY;
}
if (tree) {
static int
dissect_rpc_authdes_desblock(tvbuff_t *tvb, proto_tree *tree,
-int hfindex, int offset)
+ int hfindex, int offset)
{
guint32 value_low;
guint32 value_high;
*/
static int
dissect_rpc_authgss_token(tvbuff_t* tvb, proto_tree* tree, int offset,
- packet_info *pinfo)
+ packet_info *pinfo, int hfindex)
{
guint32 opaque_length, rounded_length;
gint len_consumed, length, reported_length;
opaque_length = tvb_get_ntohl(tvb, offset+0);
rounded_length = rpc_roundup(opaque_length);
if (tree) {
- gitem = proto_tree_add_text(tree, tvb, offset,
- 4+rounded_length, "GSS Token");
+ gitem = proto_tree_add_item(tree, hfindex, tvb, offset, 4+rounded_length, FALSE);
gtree = proto_item_add_subtree(gitem, ett_rpc_gss_token);
proto_tree_add_uint(gtree, hf_rpc_authgss_token_length,
tvb, offset+0, 4, opaque_length);
}
break;
case RPCSEC_GSS:
- dissect_rpc_authgss_token(tvb, vtree, offset+4, pinfo);
+ dissect_rpc_authgss_token(tvb, vtree, offset+4, pinfo, hf_rpc_authgss_token);
break;
default:
proto_tree_add_uint(vtree, hf_rpc_auth_length, tvb,
dissect_rpc_authgss_initarg(tvbuff_t* tvb, proto_tree* tree, int offset,
packet_info *pinfo)
{
- return dissect_rpc_authgss_token(tvb, tree, offset, pinfo);
+ return dissect_rpc_authgss_token(tvb, tree, offset, pinfo, hf_rpc_authgss_token);
}
static int
offset+0, 4, window);
offset += 4;
- offset = dissect_rpc_authgss_token(tvb, tree, offset, pinfo);
+ offset = dissect_rpc_authgss_token(tvb, tree, offset, pinfo, hf_rpc_authgss_token);
return offset;
}
}
offset += 4;
- offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo);
+ offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo, hf_rpc_authgss_token);
return offset;
}
}
offset += 4;
- offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo);
+ offset = dissect_rpc_authgss_token(tvb, mtree, offset, pinfo, hf_rpc_authgss_token);
offset = dissect_rpc_data(tvb, mtree, hf_rpc_authgssapi_isn, offset);
dissect_function, progname);
}
offset += rounded_length - 4;
- offset = dissect_rpc_data(tvb, tree, hf_rpc_authgss_checksum,
- offset);
+ offset = dissect_rpc_authgss_token(tvb, tree, offset, pinfo, hf_rpc_authgss_checksum);
+
return offset;
}
procname = (char *)rpc_call->proc_info->name;
}
else {
- procname=ep_alloc(20);
- g_snprintf(procname, 20, "proc-%u", rpc_call->proc);
+ procname=ep_strdup_printf("proc-%u", rpc_call->proc);
}
}
else {
#if 0
dissect_function = NULL;
#endif
- procname=ep_alloc(20);
- g_snprintf(procname, 20, "proc-%u", rpc_call->proc);
+ procname=ep_strdup_printf("proc-%u", rpc_call->proc);
}
if ( tree )
proto_item *rpc_item;
proto_tree *rpc_tree;
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
- if (check_col(pinfo->cinfo, COL_INFO))
- col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
+ col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
if (tree) {
rpc_item = proto_tree_add_item(tree, proto_rpc, tvb, 0, -1,
* and version values.
*/
-static void make_fake_rpc_prog_if_needed (rpc_prog_info_key *prpc_prog_key,
- guint prog_ver)
+static void
+make_fake_rpc_prog_if_needed (rpc_prog_info_key *prpc_prog_key, guint prog_ver)
{
-
-rpc_prog_info_value *rpc_prog = NULL;
-
-
/* sanity check: no one uses versions > 10 */
if(prog_ver>10){
return;
}
- if( (rpc_prog = g_hash_table_lookup(rpc_progs, prpc_prog_key)) == NULL) {
+ if(g_hash_table_lookup(rpc_progs, prpc_prog_key) == NULL) {
/* ok this is not a known rpc program so we
* will have to fake it.
*/
{ 0,NULL,NULL,NULL }
};
- NAME=g_malloc(36);
- Name=g_malloc(32);
- name=g_malloc(32);
- g_snprintf(NAME, 36, "Unknown RPC Program:%d",prpc_prog_key->prog);
- g_snprintf(Name, 32, "RPC:%d",prpc_prog_key->prog);
- g_snprintf(name, 32, "rpc%d",prpc_prog_key->prog);
+ NAME = g_strdup_printf("Unknown RPC Program:%d",prpc_prog_key->prog);
+ Name = g_strdup_printf("RPC:%d",prpc_prog_key->prog);
+ name = g_strdup_printf("rpc%d",prpc_prog_key->prog);
proto_rpc_unknown_program = proto_register_protocol(NAME, Name, name);
rpc_init_prog(proto_rpc_unknown_program, prpc_prog_key->prog, ett_rpc_unknown_program);
nstime_t ns;
dissect_function_t *dissect_function = NULL;
- gboolean dissect_rpc = TRUE;
+ gboolean dissect_rpc_flag = TRUE;
rpc_conv_info_t *rpc_conv_info=NULL;
}
}
- if (check_col(pinfo->cinfo, COL_PROTOCOL))
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
if (tree) {
rpc_item = proto_tree_add_item(tree, proto_rpc, tvb, 0, -1,
"Program: %s (%u)", progname, prog);
}
- if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
- /* Set the protocol name to the underlying
- program name. */
- col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
- }
+ /* Set the protocol name to the underlying
+ program name. */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
vers = tvb_get_ntohl(tvb, offset+8);
if (rpc_tree) {
#if 0
dissect_function = NULL;
#endif
- procname=ep_alloc(20);
- g_snprintf(procname, 20, "proc-%u", proc);
+ procname=ep_strdup_printf("proc-%u", proc);
}
/* Check for RPCSEC_GSS and AUTH_GSSAPI */
flavor = FLAVOR_AUTHGSSAPI_MSG;
gss_proc = proc;
procname = (char *)
- match_strval(gss_proc,
- rpc_authgssapi_proc);
+ val_to_str(gss_proc,
+ rpc_authgssapi_proc, "Unknown (%d)");
} else {
flavor = FLAVOR_AUTHGSSAPI;
}
"Procedure: %s (%u)", procname, proc);
}
- if (check_col(pinfo->cinfo, COL_INFO)) {
- if (first_pdu)
- col_clear(pinfo->cinfo, COL_INFO);
- else
- col_append_str(pinfo->cinfo, COL_INFO, " ; ");
+ /* Print the program version, procedure name, and message type (call or reply). */
+ if (first_pdu)
+ col_clear(pinfo->cinfo, COL_INFO);
+ else
+ col_append_str(pinfo->cinfo, COL_INFO, " ; ");
+ /* Special case for NFSv4 - if the type is COMPOUND, do not print the procedure name */
+ if (vers==4 && prog==NFS_PROGRAM && !strcmp(procname, "COMPOUND"))
+ col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s", vers,
+ msg_type_name);
+ else
col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s %s",
- vers,
- procname,
- msg_type_name);
- }
+ vers, procname, msg_type_name);
/* Keep track of the address whence the call came, and the
port to which the call is being sent, so that we can
if (pinfo->fd->num != rpc_call->req_num) {
/* No, so it's a duplicate request.
Mark it as such. */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_prepend_fstr(pinfo->cinfo, COL_INFO,
- "[RPC retransmission of #%d]", rpc_call->req_num);
- }
- proto_tree_add_item(rpc_tree,
- hf_rpc_dup, tvb, 0,0, TRUE);
- proto_tree_add_uint(rpc_tree,
- hf_rpc_call_dup, tvb, 0,0, rpc_call->req_num);
+ col_prepend_fstr(pinfo->cinfo, COL_INFO,
+ "[RPC retransmission of #%d]",
+ rpc_call->req_num);
+ proto_tree_add_item(rpc_tree, hf_rpc_dup, tvb,
+ 0, 0, ENC_NA);
+ proto_tree_add_uint(rpc_tree, hf_rpc_call_dup,
+ tvb, 0,0, rpc_call->req_num);
}
if(rpc_call->rep_num){
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO," (Reply In %d)", rpc_call->rep_num);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO," (Reply In %d)", rpc_call->rep_num);
}
} else {
/* Prepare the value data.
procname = (char *)rpc_call->proc_info->name;
}
else {
- procname=ep_alloc(20);
- g_snprintf(procname, 20, "proc-%u", proc);
+ procname=ep_strdup_printf("proc-%u", proc);
}
}
else {
#if 0
dissect_function = NULL;
#endif
- procname=ep_alloc(20);
- g_snprintf(procname, 20, "proc-%u", proc);
+ procname=ep_strdup_printf("proc-%u", proc);
}
/*
* AUTH_GSSAPI procname.
*/
if (flavor == FLAVOR_AUTHGSSAPI_MSG) {
- procname = (char *)match_strval(gss_proc, rpc_authgssapi_proc);
+ procname = (char *)val_to_str_const(gss_proc, rpc_authgssapi_proc, "(null)");
}
rpc_prog_key.prog = prog;
ett = rpc_prog->ett;
progname = rpc_prog->progname;
- if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
- /* Set the protocol name to the underlying
- program name. */
- col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
- }
+ /* Set the protocol name to the underlying
+ program name. */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, progname);
}
- if (check_col(pinfo->cinfo, COL_INFO)) {
- if (first_pdu)
- col_clear(pinfo->cinfo, COL_INFO);
- else
- col_append_str(pinfo->cinfo, COL_INFO, " ; ");
+ /* Print the program version, procedure name, and message type (call or reply). */
+ if (first_pdu)
+ col_clear(pinfo->cinfo, COL_INFO);
+ else
+ col_append_str(pinfo->cinfo, COL_INFO, " ; ");
+ /* Special case for NFSv4 - if the type is COMPOUND, do not print the procedure name */
+ if (vers==4 && prog==NFS_PROGRAM && !strcmp(procname, "COMPOUND"))
+ col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s",
+ vers, msg_type_name);
+ else
col_append_fstr(pinfo->cinfo, COL_INFO,"V%u %s %s",
- vers,
- procname,
- msg_type_name);
- }
+ vers, procname, msg_type_name);
if (rpc_tree) {
proto_item *tmp_item;
&ns);
PROTO_ITEM_SET_GENERATED(tmp_item);
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_append_fstr(pinfo->cinfo, COL_INFO," (Call In %d)", rpc_call->req_num);
- }
+ col_append_fstr(pinfo->cinfo, COL_INFO," (Call In %d)", rpc_call->req_num);
}
/* No, so it's a duplicate reply.
Mark it as such. */
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_prepend_fstr(pinfo->cinfo, COL_INFO,
+ col_prepend_fstr(pinfo->cinfo, COL_INFO,
"[RPC duplicate of #%d]", rpc_call->rep_num);
- }
tmp_item=proto_tree_add_item(rpc_tree,
- hf_rpc_dup, tvb, 0,0, TRUE);
+ hf_rpc_dup, tvb, 0,0, ENC_NA);
PROTO_ITEM_SET_GENERATED(tmp_item);
tmp_item=proto_tree_add_uint(rpc_tree,
* There's no protocol reply, so don't
* try to dissect it.
*/
- dissect_rpc = FALSE;
+ dissect_rpc_flag = FALSE;
break;
default:
* There's no protocol reply, so don't
* try to dissect it.
*/
- dissect_rpc = FALSE;
+ dissect_rpc_flag = FALSE;
break;
}
break;
* There's no protocol reply, so don't
* try to dissect it.
*/
- dissect_rpc = FALSE;
+ dissect_rpc_flag = FALSE;
break;
default:
* no clue what's going on; don't try to dissect
* the protocol reply.
*/
- dissect_rpc = FALSE;
+ dissect_rpc_flag = FALSE;
break;
}
break; /* end of RPC reply */
proto_item_set_end(rpc_item, tvb, offset);
}
- if (!dissect_rpc) {
+ if (!dissect_rpc_flag) {
/*
* There's no RPC call or reply here; just dissect
* whatever's left as data.
*/
call_dissector(data_handle,
- tvb_new_subset(tvb, offset, -1, -1), pinfo, rpc_tree);
+ tvb_new_subset_remaining(tvb, offset), pinfo, rpc_tree);
return TRUE;
}
+ /* we must queue this packet to the tap system before we actually
+ call the subdissectors since short packets (i.e. nfs read reply)
+ will cause an exception and execution would never reach the call
+ to tap_queue_packet() in that case
+ */
+ tap_queue_packet(rpc_tap, pinfo, rpc_call);
+
/* create here the program specific sub-tree */
if (tree && (flavor != FLAVOR_AUTHGSSAPI_MSG)) {
pitem = proto_tree_add_item(tree, proto_id, tvb, offset, -1,
}
}
- /* we must queue this packet to the tap system before we actually
- call the subdissectors since short packets (i.e. nfs read reply)
- will cause an exception and execution would never reach the call
- to tap_queue_packet() in that case
- */
- tap_queue_packet(rpc_tap, pinfo, rpc_call);
-
/* proto==0 if this is an unknown program */
if( (proto==0) || !proto_is_protocol_enabled(proto)){
dissect_function = NULL;
}
+ /*
+ * Don't call any subdissector if we have no more date to dissect.
+ */
+ if (tvb_length_remaining(tvb, offset) == 0) {
+ return TRUE;
+ }
+
/*
* Handle RPCSEC_GSS and AUTH_GSSAPI specially.
*/
* protocol and info fields to indicate that this is
* an RPC auth level message, then process the args.
*/
- if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
- }
- if (check_col(pinfo->cinfo, COL_INFO)) {
- col_clear(pinfo->cinfo, COL_INFO);
- col_append_fstr(pinfo->cinfo, COL_INFO,
- "%s %s XID 0x%x",
- match_strval(gss_proc, rpc_authgssapi_proc),
- msg_type_name, xid);
- }
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RPC");
+ col_clear(pinfo->cinfo, COL_INFO);
+ col_append_fstr(pinfo->cinfo, COL_INFO,
+ "%s %s XID 0x%x",
+ val_to_str(gss_proc, rpc_authgssapi_proc, "Unknown (%d)"),
+ msg_type_name, xid);
switch (gss_proc) {
*/
call_dissector(data_handle,
- tvb_new_subset(tvb, offset, -1, -1), pinfo, ptree);
+ tvb_new_subset_remaining(tvb, offset), pinfo, ptree);
}
/* XXX this should really loop over all fhandles registred for the frame */
guint32 conv_id;
guint32 seq;
guint32 offset;
+ guint32 port;
/* xxx */
guint32 start_seq;
} rpc_fragment_key;
const rpc_fragment_key *key2 = (const rpc_fragment_key *)k2;
return key1->conv_id == key2->conv_id &&
- key1->seq == key2->seq;
+ key1->seq == key2->seq && key1->port == key2->port;
}
static void
{
const char *saved_proto;
volatile gboolean rpc_succeeded;
+ void *pd_save;
/*
* Catch the ReportedBoundsError exception; if
*/
saved_proto = pinfo->current_proto;
rpc_succeeded = FALSE;
+ pd_save = pinfo->private_data;
TRY {
rpc_succeeded = (*dissector)(rec_tvb, pinfo, tree,
frag_tvb, ipfd_head, TRUE, rpc_rm, first_pdu);
show_reported_bounds_error(tvb, pinfo, tree);
pinfo->current_proto = saved_proto;
+ /* Restore the private_data structure in case one of the
+ * called dissectors modified it (and, due to the exception,
+ * was unable to restore it).
+ */
+ pinfo->private_data = pd_save;
+
/*
* We treat this as a "successful" dissection of
* an RPC packet, as "dissect_rpc_message()"
}
old_rfk.conv_id = conversation->index;
old_rfk.seq = seq;
+ old_rfk.port = pinfo->srcport;
rfk = g_hash_table_lookup(rpc_reassembly_table, &old_rfk);
if (rfk == NULL) {
rfk = se_alloc(sizeof(rpc_fragment_key));
rfk->conv_id = conversation->index;
rfk->seq = seq;
+ rfk->port = pinfo->srcport;
rfk->offset = 0;
rfk->start_seq = seq;
g_hash_table_insert(rpc_reassembly_table, rfk, rfk);
new_rfk = se_alloc(sizeof(rpc_fragment_key));
new_rfk->conv_id = rfk->conv_id;
new_rfk->seq = seq + len;
+ new_rfk->port = pinfo->srcport;
new_rfk->offset = rfk->offset + len - 4;
new_rfk->start_seq = rfk->start_seq;
g_hash_table_insert(rpc_reassembly_table, new_rfk,
new_rfk = se_alloc(sizeof(rpc_fragment_key));
new_rfk->conv_id = rfk->conv_id;
new_rfk->seq = seq + len;
+ new_rfk->port = pinfo->srcport;
new_rfk->offset = rfk->offset + len - 4;
new_rfk->start_seq = rfk->start_seq;
g_hash_table_insert(rpc_reassembly_table, new_rfk,
* Create a new TVB structure for
* defragmented data.
*/
- rec_tvb = tvb_new_real_data(ipfd_head->data,
+ rec_tvb = tvb_new_child_real_data(tvb, ipfd_head->data,
ipfd_head->datalen, ipfd_head->datalen);
- /*
- * Add this tvb as a child to the original
- * one.
- */
- tvb_set_child_real_data_tvbuff(tvb, rec_tvb);
-
/*
* Add defragmented data to the data source list.
*/
find_rpc_over_tcp_reply_start(tvbuff_t *tvb, int offset)
{
-/*
- * Looking for partial header sequence. From beginning of
- * stream-style header, including "record mark", full ONC-RPC
- * looks like:
- * BE int32 record mark (rfc 1831 sec. 10)
- * ? int32 XID (rfc 1831 sec. 8)
- * BE int32 msg_type (ibid sec. 8, call = 0, reply = 1)
- *
- * -------------------------------------------------------------
- * Then reply-specific fields are
- * BE int32 reply_stat (ibid, accept = 0, deny = 1)
- *
- * Then, assuming accepted,
- * opaque_auth
- * BE int32 auth_flavor (ibid, none = 0)
- * BE int32 ? auth_len (ibid, none = 0)
- *
- * BE int32 accept_stat (ibid, success = 0, errs are 1..5 in rpc v2)
- *
- * -------------------------------------------------------------
- * Or, call-specific fields are
- * BE int32 rpc_vers (rfc 1831 sec 8, always == 2)
- * BE int32 prog (NFS == 000186A3)
- * BE int32 prog_ver (NFS v2/3 == 2 or 3)
- * BE int32 proc_id (NFS, <= 256 ???)
- * opaque_auth
- * ...
- */
+ /*
+ * Looking for partial header sequence. From beginning of
+ * stream-style header, including "record mark", full ONC-RPC
+ * looks like:
+ * BE int32 record mark (rfc 1831 sec. 10)
+ * ? int32 XID (rfc 1831 sec. 8)
+ * BE int32 msg_type (ibid sec. 8, call = 0, reply = 1)
+ *
+ * -------------------------------------------------------------
+ * Then reply-specific fields are
+ * BE int32 reply_stat (ibid, accept = 0, deny = 1)
+ *
+ * Then, assuming accepted,
+ * opaque_auth
+ * BE int32 auth_flavor (ibid, none = 0)
+ * BE int32 ? auth_len (ibid, none = 0)
+ *
+ * BE int32 accept_stat (ibid, success = 0, errs are 1..5 in rpc v2)
+ *
+ * -------------------------------------------------------------
+ * Or, call-specific fields are
+ * BE int32 rpc_vers (rfc 1831 sec 8, always == 2)
+ * BE int32 prog (NFS == 000186A3)
+ * BE int32 prog_ver (NFS v2/3 == 2 or 3)
+ * BE int32 proc_id (NFS, <= 256 ???)
+ * opaque_auth
+ * ...
+ */
-/* Initially, we search only for something matching the template
- * of a successful reply with no auth verifier.
- * Our first qualification test is search for a string of zero bytes,
- * corresponding the four guint32 values
- * reply_stat
- * auth_flavor
- * auth_len
- * accept_stat
- *
- * If this string of zeros matches, then we go back and check the
- * preceding msg_type and record_mark fields.
- */
+ /* Initially, we search only for something matching the template
+ * of a successful reply with no auth verifier.
+ * Our first qualification test is search for a string of zero bytes,
+ * corresponding the four guint32 values
+ * reply_stat
+ * auth_flavor
+ * auth_len
+ * accept_stat
+ *
+ * If this string of zeros matches, then we go back and check the
+ * preceding msg_type and record_mark fields.
+ */
-const gint cbZeroTail = 4 * 4; /* four guint32s of zeros */
-const gint ibPatternStart = 3 * 4; /* offset of zero fill from reply start */
-const guint8 * pbWholeBuf; /* all of tvb, from offset onwards */
-const int NoMatch = -1;
+ const gint cbZeroTail = 4 * 4; /* four guint32s of zeros */
+ const gint ibPatternStart = 3 * 4; /* offset of zero fill from reply start */
+ const guint8 * pbWholeBuf; /* all of tvb, from offset onwards */
+ const int NoMatch = -1;
-gint ibSearchStart; /* offset of search start, in case of false hits. */
+ gint ibSearchStart; /* offset of search start, in case of false hits. */
-const guint8 * pbBuf;
+ const guint8 * pbBuf;
-gint cbInBuf; /* bytes in tvb, from offset onwards */
+ gint cbInBuf; /* bytes in tvb, from offset onwards */
-guint32 ulMsgType;
-guint32 ulRecMark;
+ guint32 ulMsgType;
+ guint32 ulRecMark;
-int i;
+ int i;
cbInBuf = tvb_reported_length_remaining(tvb, offset);
static int
find_and_dissect_rpc_fragment(tvbuff_t *tvb, int offset, packet_info *pinfo,
- proto_tree *tree, rec_dissector_t dissector,
- gboolean is_heur,
- int proto, int ett, gboolean defragment)
+ proto_tree *tree, rec_dissector_t dissector,
+ gboolean is_heur,
+ int proto, int ett, gboolean defragment)
{
int offReply;
}
len = dissect_rpc_fragment(tvb, offReply,
- pinfo, tree,
- dissector, is_heur, proto, ett,
- defragment,
- TRUE /* force first-pdu state */);
+ pinfo, tree,
+ dissector, is_heur, proto, ett,
+ defragment,
+ TRUE /* force first-pdu state */);
/* misses are reported as-is */
if (len == 0)
- {
+ {
return (0);
- }
+ }
/* returning a non-zero length, correct it to reflect the extra offset
* we found necessary
break;
}
+ /* Set a fence so whatever the subdissector put in the
+ * Info column stays there. This is useful when the
+ * subdissector clears the column (which it might have to do
+ * if it runs over some other protocol too) and there are
+ * multiple PDUs in one frame.
+ */
+ col_set_fence(pinfo->cinfo, COL_INFO);
+
/* PDU tracking
If the length indicates that the PDU continues beyond
the end of this tvb, then tell TCP about it so that it
static hf_register_info hf[] = {
{ &hf_rpc_reqframe, {
"Request Frame", "rpc.reqframe", FT_FRAMENUM, BASE_NONE,
- NULL, 0, "Request Frame", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_repframe, {
"Reply Frame", "rpc.repframe", FT_FRAMENUM, BASE_NONE,
- NULL, 0, "Reply Frame", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_lastfrag, {
"Last Fragment", "rpc.lastfrag", FT_BOOLEAN, 32,
- &yesno, RPC_RM_LASTFRAG, "Last Fragment", HFILL }},
+ TFS(&tfs_yes_no), RPC_RM_LASTFRAG, NULL, HFILL }},
{ &hf_rpc_fraglen, {
"Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
- NULL, RPC_RM_FRAGLEN, "Fragment Length", HFILL }},
+ NULL, RPC_RM_FRAGLEN, NULL, HFILL }},
{ &hf_rpc_xid, {
"XID", "rpc.xid", FT_UINT32, BASE_HEX,
- NULL, 0, "XID", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_msgtype, {
"Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
- VALS(rpc_msg_type), 0, "Message Type", HFILL }},
+ VALS(rpc_msg_type), 0, NULL, HFILL }},
{ &hf_rpc_state_reply, {
"Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
- VALS(rpc_reply_state), 0, "Reply State", HFILL }},
+ VALS(rpc_reply_state), 0, NULL, HFILL }},
{ &hf_rpc_state_accept, {
"Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
- VALS(rpc_accept_state), 0, "Accept State", HFILL }},
+ VALS(rpc_accept_state), 0, NULL, HFILL }},
{ &hf_rpc_state_reject, {
"Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
- VALS(rpc_reject_state), 0, "Reject State", HFILL }},
+ VALS(rpc_reject_state), 0, NULL, HFILL }},
{ &hf_rpc_state_auth, {
"Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
- VALS(rpc_auth_state), 0, "Auth State", HFILL }},
+ VALS(rpc_auth_state), 0, NULL, HFILL }},
{ &hf_rpc_version, {
"RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
- NULL, 0, "RPC Version", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_version_min, {
"RPC Version (Minimum)", "rpc.version.min", FT_UINT32,
BASE_DEC, NULL, 0, "Program Version (Minimum)", HFILL }},
{ &hf_rpc_version_max, {
"RPC Version (Maximum)", "rpc.version.max", FT_UINT32,
- BASE_DEC, NULL, 0, "RPC Version (Maximum)", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_program, {
"Program", "rpc.program", FT_UINT32, BASE_DEC,
- NULL, 0, "Program", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_programversion, {
"Program Version", "rpc.programversion", FT_UINT32,
- BASE_DEC, NULL, 0, "Program Version", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_programversion_min, {
"Program Version (Minimum)", "rpc.programversion.min", FT_UINT32,
- BASE_DEC, NULL, 0, "Program Version (Minimum)", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_programversion_max, {
"Program Version (Maximum)", "rpc.programversion.max", FT_UINT32,
- BASE_DEC, NULL, 0, "Program Version (Maximum)", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_procedure, {
"Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
- NULL, 0, "Procedure", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_auth_flavor, {
"Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
- VALS(rpc_auth_flavor), 0, "Flavor", HFILL }},
+ VALS(rpc_auth_flavor), 0, NULL, HFILL }},
{ &hf_rpc_auth_length, {
"Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
- NULL, 0, "Length", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_auth_stamp, {
"Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
- NULL, 0, "Stamp", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_auth_uid, {
"UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
- NULL, 0, "UID", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_auth_gid, {
"GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
- NULL, 0, "GID", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_v, {
"GSS Version", "rpc.authgss.version", FT_UINT32,
- BASE_DEC, NULL, 0, "GSS Version", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_proc, {
"GSS Procedure", "rpc.authgss.procedure", FT_UINT32,
- BASE_DEC, VALS(rpc_authgss_proc), 0, "GSS Procedure", HFILL }},
+ BASE_DEC, VALS(rpc_authgss_proc), 0, NULL, HFILL }},
{ &hf_rpc_authgss_seq, {
"GSS Sequence Number", "rpc.authgss.seqnum", FT_UINT32,
- BASE_DEC, NULL, 0, "GSS Sequence Number", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_svc, {
"GSS Service", "rpc.authgss.service", FT_UINT32,
- BASE_DEC, VALS(rpc_authgss_svc), 0, "GSS Service", HFILL }},
+ BASE_DEC, VALS(rpc_authgss_svc), 0, NULL, HFILL }},
{ &hf_rpc_authgss_ctx, {
"GSS Context", "rpc.authgss.context", FT_BYTES,
- BASE_HEX, NULL, 0, "GSS Context", HFILL }},
+ BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_major, {
"GSS Major Status", "rpc.authgss.major", FT_UINT32,
- BASE_DEC, NULL, 0, "GSS Major Status", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_minor, {
"GSS Minor Status", "rpc.authgss.minor", FT_UINT32,
- BASE_DEC, NULL, 0, "GSS Minor Status", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_window, {
"GSS Sequence Window", "rpc.authgss.window", FT_UINT32,
- BASE_DEC, NULL, 0, "GSS Sequence Window", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_token_length, {
"GSS Token Length", "rpc.authgss.token_length", FT_UINT32,
- BASE_DEC, NULL, 0, "GSS Token Length", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_data_length, {
"Length", "rpc.authgss.data.length", FT_UINT32,
- BASE_DEC, NULL, 0, "Length", HFILL }},
+ BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_data, {
"GSS Data", "rpc.authgss.data", FT_BYTES,
- BASE_HEX, NULL, 0, "GSS Data", HFILL }},
+ BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgss_checksum, {
"GSS Checksum", "rpc.authgss.checksum", FT_BYTES,
- BASE_HEX, NULL, 0, "GSS Checksum", HFILL }},
+ BASE_NONE, NULL, 0, NULL, HFILL }},
+ { &hf_rpc_authgss_token, {
+ "GSS Token", "rpc.authgss.token", FT_BYTES,
+ BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgssapi_v, {
"AUTH_GSSAPI Version", "rpc.authgssapi.version",
- FT_UINT32, BASE_DEC, NULL, 0, "AUTH_GSSAPI Version",
+ FT_UINT32, BASE_DEC, NULL, 0, NULL,
HFILL }},
{ &hf_rpc_authgssapi_msg, {
"AUTH_GSSAPI Message", "rpc.authgssapi.message",
- FT_BOOLEAN, BASE_NONE, &yesno, 0, "AUTH_GSSAPI Message",
+ FT_BOOLEAN, BASE_NONE, TFS(&tfs_yes_no), 0x0, NULL,
HFILL }},
{ &hf_rpc_authgssapi_msgv, {
"Msg Version", "rpc.authgssapi.msgversion",
- FT_UINT32, BASE_DEC, NULL, 0, "Msg Version",
+ FT_UINT32, BASE_DEC, NULL, 0, NULL,
HFILL }},
{ &hf_rpc_authgssapi_handle, {
"Client Handle", "rpc.authgssapi.handle",
- FT_BYTES, BASE_HEX, NULL, 0, "Client Handle", HFILL }},
+ FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authgssapi_isn, {
"Signed ISN", "rpc.authgssapi.isn",
- FT_BYTES, BASE_HEX, NULL, 0, "Signed ISN", HFILL }},
+ FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authdes_namekind, {
"Namekind", "rpc.authdes.namekind", FT_UINT32, BASE_DEC,
- VALS(rpc_authdes_namekind), 0, "Namekind", HFILL }},
+ VALS(rpc_authdes_namekind), 0, NULL, HFILL }},
{ &hf_rpc_authdes_netname, {
"Netname", "rpc.authdes.netname", FT_STRING,
- BASE_DEC, NULL, 0, "Netname", HFILL }},
+ BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authdes_convkey, {
"Conversation Key (encrypted)", "rpc.authdes.convkey", FT_UINT32,
- BASE_HEX, NULL, 0, "Conversation Key (encrypted)", HFILL }},
+ BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authdes_window, {
"Window (encrypted)", "rpc.authdes.window", FT_UINT32,
BASE_HEX, NULL, 0, "Windows (encrypted)", HFILL }},
{ &hf_rpc_authdes_nickname, {
"Nickname", "rpc.authdes.nickname", FT_UINT32,
- BASE_HEX, NULL, 0, "Nickname", HFILL }},
+ BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authdes_timestamp, {
"Timestamp (encrypted)", "rpc.authdes.timestamp", FT_UINT32,
- BASE_HEX, NULL, 0, "Timestamp (encrypted)", HFILL }},
+ BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authdes_windowverf, {
"Window verifier (encrypted)", "rpc.authdes.windowverf", FT_UINT32,
- BASE_HEX, NULL, 0, "Window verifier (encrypted)", HFILL }},
+ BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_rpc_authdes_timeverf, {
"Timestamp verifier (encrypted)", "rpc.authdes.timeverf", FT_UINT32,
- BASE_HEX, NULL, 0, "Timestamp verifier (encrypted)", HFILL }},
+ BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_rpc_auth_machinename, {
"Machine Name", "rpc.auth.machinename", FT_STRING,
- BASE_DEC, NULL, 0, "Machine Name", HFILL }},
+ BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_rpc_dup, {
"Duplicate Call/Reply", "rpc.dup", FT_NONE, BASE_NONE,
- NULL, 0, "Duplicate Call/Reply", HFILL }},
+ NULL, 0, NULL, HFILL }},
{ &hf_rpc_call_dup, {
- "Duplicate to the call in", "rpc.call.dup", FT_FRAMENUM, BASE_DEC,
+ "Duplicate to the call in", "rpc.call.dup", FT_FRAMENUM, BASE_NONE,
NULL, 0, "This is a duplicate to the call in frame", HFILL }},
{ &hf_rpc_reply_dup, {
- "Duplicate to the reply in", "rpc.reply.dup", FT_FRAMENUM, BASE_DEC,
+ "Duplicate to the reply in", "rpc.reply.dup", FT_FRAMENUM, BASE_NONE,
NULL, 0, "This is a duplicate to the reply in frame", HFILL }},
{ &hf_rpc_value_follows, {
"Value Follows", "rpc.value_follows", FT_BOOLEAN, BASE_NONE,
- &yesno, 0, "Value Follows", HFILL }},
+ TFS(&tfs_yes_no), 0x0, NULL, HFILL }},
{ &hf_rpc_array_len, {
"num", "rpc.array.len", FT_UINT32, BASE_DEC,
NULL, 0, "Length of RPC array", HFILL }},
{ "Defragmentation error", "rpc.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
"Defragmentation error due to illegal fragments", HFILL }},
+ { &hf_rpc_fragment_count,
+ { "Fragment count", "rpc.fragment.count", FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }},
+
{ &hf_rpc_fragment,
{ "RPC Fragment", "rpc.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
- "RPC Fragment", HFILL }},
+ NULL, HFILL }},
{ &hf_rpc_fragments,
{ "RPC Fragments", "rpc.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
- "RPC Fragments", HFILL }},
+ NULL, HFILL }},
+
+ { &hf_rpc_reassembled_length,
+ { "Reassembled RPC length", "rpc.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "The total length of the reassembled payload", HFILL }},
};
static gint *ett[] = {
&ett_rpc,
&rpc_find_fragment_start);
register_dissector("rpc", dissect_rpc, proto_rpc);
- rpc_handle = find_dissector("rpc");
register_dissector("rpc-tcp", dissect_rpc_tcp, proto_rpc);
- rpc_tcp_handle = find_dissector("rpc-tcp");
rpc_tap = register_tap("rpc");
/*
void
proto_reg_handoff_rpc(void)
{
- dissector_handle_t rpc_tcp_handle;
- dissector_handle_t rpc_udp_handle;
-
/* tcp/udp port 111 is used by portmapper which is an onc-rpc service.
we register onc-rpc on this port so that we can choose RPC in
the list offered by DecodeAs, and so that traffic to or from
probably RPC traffic from some randomly-chosen port that happens
to match some port for which we have a dissector)
*/
- rpc_tcp_handle = create_dissector_handle(dissect_rpc_tcp, proto_rpc);
- dissector_add("tcp.port", 111, rpc_tcp_handle);
- rpc_udp_handle = create_dissector_handle(dissect_rpc, proto_rpc);
- dissector_add("udp.port", 111, rpc_udp_handle);
+ rpc_tcp_handle = find_dissector("rpc-tcp");
+ dissector_add_uint("tcp.port", 111, rpc_tcp_handle);
+ rpc_handle = find_dissector("rpc");
+ dissector_add_uint("udp.port", 111, rpc_handle);
heur_dissector_add("tcp", dissect_rpc_tcp_heur, proto_rpc);
heur_dissector_add("udp", dissect_rpc_heur, proto_rpc);
* Local Variables:
* c-basic-offset: 8
* tab-width: 8
- * indent-tabs-mode: tabs
+ * indent-tabs-mode: t
* End:
*
- * ex: set shiftwidth=8 tabstop=8 noexpandtab
+ * ex: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/