/* Set up an MSRP conversation using the info given */ void msrp_add_address( packet_info *pinfo, address *addr, int port, const gchar *setup_method, guint32 setup_frame_number) { address null_addr; conversation_t* p_conv; struct _msrp_conversation_info *p_conv_data = NULL; /* * If this isn't the first time this packet has been processed, * we've already done this work, so we don't need to do it * again. */ if (pinfo->fd->flags.visited) { return; } SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); /* * Check if the ip address and port combination is not * already registered as a conversation. */ p_conv = find_conversation( pinfo->fd->num, addr, &null_addr, PT_TCP, port, 0, NO_ADDR_B | NO_PORT_B); /* * If not, create a new conversation. */ if (!p_conv) { p_conv = conversation_new( pinfo->fd->num, addr, &null_addr, PT_TCP, (guint32)port, 0, NO_ADDR2 | NO_PORT2); } /* Set dissector */ conversation_set_dissector(p_conv, msrp_handle); /* * Check if the conversation has data associated with it. */ p_conv_data = conversation_get_proto_data(p_conv, proto_msrp); /* * If not, add a new data item. */ if (!p_conv_data) { /* Create conversation data */ p_conv_data = se_alloc0(sizeof(struct _msrp_conversation_info)); conversation_add_proto_data(p_conv, proto_msrp, p_conv_data); } /* * Update the conversation data. */ p_conv_data->setup_method_set = TRUE; g_strlcpy(p_conv_data->setup_method, setup_method, MAX_MSRP_SETUP_METHOD_SIZE); p_conv_data->setup_frame_number = setup_frame_number; }
/* A helper function that calls find_conversation() and, if a conversation is * not found, calls conversation_new(). * The frame number and addresses are taken from pinfo. * No options are used, though we could extend this API to include an options * parameter. */ conversation_t * find_or_create_conversation(packet_info *pinfo) { conversation_t *conv=NULL; DPRINT(("called for frame #%d: %s:%d -> %s:%d (ptype=%d)", pinfo->fd->num, address_to_str(wmem_packet_scope(), &pinfo->src), pinfo->srcport, address_to_str(wmem_packet_scope(), &pinfo->dst), pinfo->destport, pinfo->ptype)); DINDENT(); /* Have we seen this conversation before? */ if((conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0)) != NULL) { DPRINT(("found previous conversation for frame #%d (last_frame=%d)", pinfo->fd->num, conv->last_frame)); if (pinfo->fd->num > conv->last_frame) { conv->last_frame = pinfo->fd->num; } } else { /* No, this is a new conversation. */ DPRINT(("did not find previous conversation for frame #%d", pinfo->fd->num)); DINDENT(); conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); DENDENT(); } DENDENT(); return conv; }
static lbmtcp_transport_t * lbmtcp_transport_add(const address * address1, guint16 port1, const address * address2, guint16 port2, guint32 frame) { lbmtcp_transport_t * entry; conversation_t * conv = NULL; conv = find_conversation(frame, address1, address2, PT_TCP, port1, port2, 0); if (conv == NULL) { conv = conversation_new(frame, address1, address2, PT_TCP, port1, port2, 0); } entry = (lbmtcp_transport_t *) conversation_get_proto_data(conv, lbmpdm_tcp_protocol_handle); if (entry != NULL) { return (entry); } entry = wmem_new(wmem_file_scope(), lbmtcp_transport_t); copy_address_wmem(wmem_file_scope(), &(entry->addr1), address1); entry->port1 = port1; copy_address_wmem(wmem_file_scope(), &(entry->addr2), address2); entry->port2 = port2; lbmtcp_order_key(entry); entry->channel = lbm_channel_assign(LBM_CHANNEL_TCP); conversation_add_proto_data(conv, lbmpdm_tcp_protocol_handle, (void *) entry); return (entry); }
lbttcp_transport_t * lbttcp_transport_add(const address * source_address, guint16 source_port, guint32 session_id, guint32 frame) { lbttcp_transport_t * entry = NULL; conversation_t * conv = NULL; lbttcp_transport_conv_data_t * conv_data = NULL; conv = find_conversation(frame, source_address, &lbttcp_null_address, PT_TCP, source_port, 0, 0); if (conv == NULL) { conv = conversation_new(frame, source_address, &lbttcp_null_address, PT_TCP, source_port, 0, 0); } conv_data = (lbttcp_transport_conv_data_t *) conversation_get_proto_data(conv, proto_lbttcp); if (conv_data == NULL) { conv_data = wmem_new(wmem_file_scope(), lbttcp_transport_conv_data_t); conv_data->frame_tree = wmem_tree_new(wmem_file_scope()); conv_data->session_tree = wmem_tree_new(wmem_file_scope()); conversation_add_proto_data(conv, proto_lbttcp, (void *) conv_data); } entry = (lbttcp_transport_t *) wmem_tree_lookup32(conv_data->session_tree, session_id); if (entry != NULL) { return (entry); } entry = lbttcp_transport_create(source_address, source_port, session_id); wmem_tree_insert32(conv_data->session_tree, session_id, (void *) entry); wmem_tree_insert32(conv_data->frame_tree, frame, (void *) entry); return (entry); }
void lbttcp_transport_sid_add(const address * source_address, guint16 source_port, guint32 frame, guint32 session_id) { conversation_t * conv = NULL; lbttcp_transport_conv_data_t * conv_data = NULL; lbttcp_transport_t * transport = NULL; conv = find_conversation(frame, source_address, &lbttcp_null_address, PT_TCP, source_port, 0, 0); if (conv == NULL) { conv = conversation_new(frame, source_address, &lbttcp_null_address, PT_TCP, source_port, 0, 0); } conv_data = (lbttcp_transport_conv_data_t *) conversation_get_proto_data(conv, proto_lbttcp); if (conv_data == NULL) { conv_data = wmem_new(wmem_file_scope(), lbttcp_transport_conv_data_t); conv_data->frame_tree = wmem_tree_new(wmem_file_scope()); conv_data->session_tree = wmem_tree_new(wmem_file_scope()); conversation_add_proto_data(conv, proto_lbttcp, (void *) conv_data); } /* Lookup by frame */ transport = (lbttcp_transport_t *) wmem_tree_lookup32_le(conv_data->frame_tree, frame); if (transport != NULL) { if (transport->session_id != session_id) { transport = NULL; } } if (transport == NULL) { transport = lbttcp_transport_create(source_address, source_port, session_id); wmem_tree_insert32(conv_data->session_tree, session_id, (void *) transport); wmem_tree_insert32(conv_data->frame_tree, frame, (void *) transport); } }
static gboolean dissect_msrp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; conversation_t* conversation; if ( check_msrp_header(tvb)){ /* * TODO Set up conversation here */ if (pinfo->fd->flags.visited){ /* Look for existing conversation */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); /* Create new one if not found */ if (conversation == NULL){ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); /* Set dissector */ conversation_set_dissector(conversation, msrp_handle); } } offset = dissect_msrp(tvb, pinfo, tree); return TRUE; } return FALSE; }
/* Find the current conversation or make a new one if required */ static ts2_conversation* ts2_get_conversation(packet_info *pinfo) { conversation_t *conversation; ts2_conversation *conversation_data; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if(conversation) { conversation_data = (ts2_conversation*)conversation_get_proto_data(conversation, proto_ts2); } else { conversation_data = g_mem_chunk_alloc(conv_vals); conversation_data->last_inorder_server_frame=0; /* sequence number should never be zero so we can use this as an initial number */ conversation_data->last_inorder_client_frame=0; conversation_data->server_port=pinfo->srcport; conversation_data->server_frag_size=0; conversation_data->server_frag_num=0; conversation_data->client_frag_size=0; conversation_data->client_frag_num=0; conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); conversation_add_proto_data(conversation, proto_ts2, (void *)conversation_data); } return conversation_data; }
static void new_udp_conversation( socks_hash_entry_t *hash_info, packet_info *pinfo){ conversation_t *conversation = conversation_new( pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP, hash_info->udp_port, hash_info->port, 0); DISSECTOR_ASSERT( conversation); conversation_add_proto_data(conversation, proto_socks, hash_info); conversation_set_dissector(conversation, socks_udp_handle); }
/* Set up an MSRP conversation using the info given */ void msrp_add_address( packet_info *pinfo, address *addr, int port, const gchar *setup_method, guint32 setup_frame_number) { address null_addr; conversation_t* p_conv; struct _msrp_conversation_info *p_conv_data = NULL; /* * If this isn't the first time this packet has been processed, * we've already done this work, so we don't need to do it * again. */ if (pinfo->fd->flags.visited) { return; } clear_address(&null_addr); /* * Check if the ip address and port combination is not * already registered as a conversation. */ p_conv = find_conversation( pinfo->num, addr, &null_addr, ENDPOINT_TCP, port, 0, NO_ADDR_B | NO_PORT_B); /* * If not, create a new conversation. */ if (!p_conv) { p_conv = conversation_new( pinfo->num, addr, &null_addr, ENDPOINT_TCP, (guint32)port, 0, NO_ADDR2 | NO_PORT2); } /* Set dissector */ conversation_set_dissector(p_conv, msrp_handle); /* * Check if the conversation has data associated with it. */ p_conv_data = (struct _msrp_conversation_info *)conversation_get_proto_data(p_conv, proto_msrp); /* * If not, add a new data item. */ if (!p_conv_data) { /* Create conversation data */ p_conv_data = wmem_new0(wmem_file_scope(), struct _msrp_conversation_info); conversation_add_proto_data(p_conv, proto_msrp, p_conv_data); }
/* returns TRUE if this TCP segment carries a MPA REQUEST and FLASE otherwise */ static gboolean is_mpa_req(tvbuff_t *tvb, packet_info *pinfo) { conversation_t *conversation = NULL; mpa_state_t *state = NULL; guint8 mcrres; if (tvb_get_ntoh64(tvb, 0) != MPA_REQ_REP_FRAME || tvb_get_ntoh64(tvb, 8) != MPA_ID_REQ_FRAME) return FALSE; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (!conversation) { conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } if (!get_mpa_state(conversation)) { /* associate a MPA connection state to this conversation if * there is no MPA state already associated to this connection */ state = init_mpa_state(); /* anaylize MPA connection parameter and record them */ mcrres = tvb_get_guint8(tvb, 16); state->ini_exp_m_res = mcrres & MPA_MARKER_FLAG; state->crc = mcrres & MPA_CRC_FLAG; state->revision = tvb_get_guint8(tvb, 17); state->req_frame_num = pinfo->fd->num; state->minfo[MPA_INITIATOR].port = pinfo->srcport; state->minfo[MPA_RESPONDER].port = pinfo->destport; conversation_add_proto_data(conversation, proto_iwarp_mpa, state); /* update expert info */ if (mcrres & MPA_RESERVED_FLAG) expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN, "Res field is NOT set to zero as required by RFC 5044"); if (state->revision != 1) expert_add_info_format(pinfo, NULL, PI_REQUEST_CODE, PI_WARN, "Rev field is NOT set to one as required by RFC 5044"); } return TRUE; }
/* When seeing a broadcast talking about an open TCP port on a host, create * a conversation to dissect anything sent/received at that address. Setup * protocol data so the TCP dissection knows what broadcast triggered it. */ static void prepare_ldss_transfer_conv(ldss_broadcast_t *broadcast) { conversation_t *transfer_conv; ldss_transfer_info_t *transfer_info; transfer_info = wmem_new0(wmem_file_scope(), ldss_transfer_info_t); transfer_info->broadcast = broadcast; /* Preparation for later push/pull dissection */ transfer_conv = conversation_new (broadcast->num, &broadcast->broadcaster->addr, &broadcast->broadcaster->addr, PT_TCP, broadcast->broadcaster->port, broadcast->broadcaster->port, NO_ADDR2|NO_PORT2); conversation_add_proto_data(transfer_conv, proto_ldss, transfer_info); conversation_set_dissector(transfer_conv, ldss_tcp_handle); }
static void add_msproxy_conversation( packet_info *pinfo, hash_entry_t *hash_info){ /* check to see if a conversation already exists, if it does assume */ /* it's our conversation and quit. Otherwise create a new conversation. */ /* Load the conversation dissector to our dissector and load the */ /* conversation data structure with the info needed to call the TCP or */ /* UDP port decoder. */ /* NOTE: Currently this assume that the conversation will be created */ /* during a packet from the server. If that changes, pinfo->src */ /* and pinfo->dst will not be correct and this routine will have */ /* to change. */ conversation_t *conversation; redirect_entry_t *new_conv_info; if (pinfo->fd->flags.visited) { /* * We've already processed this frame once, so we * should already have done this. */ return; } conversation = find_conversation( pinfo->fd->num, &pinfo->src, &pinfo->dst, (port_type)hash_info->proto, hash_info->server_int_port, hash_info->clnt_port, 0); if ( !conversation) { conversation = conversation_new( pinfo->fd->num, &pinfo->src, &pinfo->dst, (port_type)hash_info->proto, hash_info->server_int_port, hash_info->clnt_port, 0); } conversation_set_dissector(conversation, msproxy_sub_handle); new_conv_info = se_new(redirect_entry_t); new_conv_info->remote_addr = hash_info->dst_addr; new_conv_info->clnt_port = hash_info->clnt_port; new_conv_info->remote_port = hash_info->dst_port; new_conv_info->server_int_port = hash_info->server_int_port; new_conv_info->proto = hash_info->proto; conversation_add_proto_data(conversation, proto_msproxy, new_conv_info); }
/* A helper function that calls find_conversation() and, if a conversation is * not found, calls conversation_new(). * The frame number and addresses are taken from pinfo. * No options are used, though we could extend this API to include an options * parameter. */ conversation_t * find_or_create_conversation(packet_info *pinfo) { conversation_t *conv=NULL; /* Have we seen this conversation before? */ if((conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0)) == NULL) { /* No, this is a new conversation. */ conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } return conv; }
static lbttcp_client_transport_t * lbttcp_client_transport_add(lbttcp_transport_t * transport, const address * receiver_address, guint16 receiver_port, guint32 frame) { lbttcp_client_transport_t * entry; conversation_t * client_conv = NULL; wmem_tree_t * session_tree = NULL; if (transport == NULL) { return (NULL); } entry = lbttcp_client_transport_find(transport, receiver_address, receiver_port, frame); if (entry != NULL) { return (entry); } entry = wmem_new(wmem_file_scope(), lbttcp_client_transport_t); copy_address_wmem(wmem_file_scope(), &(entry->receiver_address), receiver_address); entry->receiver_port = receiver_port; entry->id = transport->next_client_id++; /* See if a conversation for this address/port pair exists. */ client_conv = find_conversation(frame, &(transport->source_address), receiver_address, PT_TCP, transport->source_port, receiver_port, 0); if (client_conv == NULL) { client_conv = conversation_new(frame, &(transport->source_address), receiver_address, PT_TCP, transport->source_port, receiver_port, 0); session_tree = wmem_tree_new(wmem_file_scope()); conversation_add_proto_data(client_conv, proto_lbttcp, (void *) session_tree); } session_tree = (wmem_tree_t *) conversation_get_proto_data(client_conv, proto_lbttcp); if (session_tree == NULL) { session_tree = wmem_tree_new(wmem_file_scope()); conversation_add_proto_data(client_conv, proto_lbttcp, (void *) session_tree); } wmem_tree_insert32(session_tree, transport->session_id, (void *) entry); /* Add this client to the transport. */ wmem_list_append(transport->client_list, (void *) entry); return (entry); }
static gboolean dissect_tuxedo_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { if (tvb_length(tvb) >= 8) { guint32 magic; magic = tvb_get_ntohl(tvb, 0); if (magic == TUXEDO_MAGIC || magic == TUXEDO_SMAGIC) { /* Register this dissector for this conversation */ conversation_t *conversation = NULL; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } conversation_set_dissector(conversation, tuxedo_handle); dissect_tuxedo(tvb, pinfo, tree); return TRUE; } } return FALSE; }
static void dissect_pop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { struct pop_proto_data *frame_data_p; gboolean is_request; gboolean is_continuation; proto_tree *pop_tree, *reqresp_tree; proto_item *ti; gint offset = 0; const guchar *line; gint next_offset; int linelen; int tokenlen; const guchar *next_token; fragment_data *frag_msg = NULL; tvbuff_t *next_tvb = NULL; conversation_t *conversation = NULL; struct pop_data_val *data_val = NULL; gint length_remaining; col_set_str(pinfo->cinfo, COL_PROTOCOL, "POP"); /* * Find the end of the first line. * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); if (pinfo->match_port == pinfo->destport) { is_request = TRUE; is_continuation = FALSE; } else { is_request = FALSE; is_continuation = response_is_continuation(line); } frame_data_p = p_get_proto_data(pinfo->fd, proto_pop); if (!frame_data_p) { conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { /* No conversation, create one */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } data_val = conversation_get_proto_data(conversation, proto_pop); if (!data_val) { /* * No - create one and attach it. */ data_val = se_alloc0(sizeof(struct pop_data_val)); conversation_add_proto_data(conversation, proto_pop, data_val); } } if (check_col(pinfo->cinfo, COL_INFO)) { /* * Put the first line from the buffer into the summary * if it's a POP request or reply (but leave out the * line terminator). * Otherwise, just call it a continuation. */ if (is_continuation) { length_remaining = tvb_length_remaining(tvb, offset); col_add_fstr(pinfo->cinfo, COL_INFO, "S: DATA fragment, %d byte%s", length_remaining, plurality (length_remaining, "", "s")); } else col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "C" : "S", format_text(line, linelen)); } ti = proto_tree_add_item(tree, proto_pop, tvb, offset, -1, FALSE); pop_tree = proto_item_add_subtree(ti, ett_pop); if (is_continuation) { if (pop_data_desegment) { if (!frame_data_p) { data_val->msg_read_len += tvb_length(tvb); frame_data_p = se_alloc(sizeof(struct pop_proto_data)); frame_data_p->conversation_id = conversation->index; frame_data_p->more_frags = data_val->msg_read_len < data_val->msg_tot_len; p_add_proto_data(pinfo->fd, proto_pop, frame_data_p); } frag_msg = fragment_add_seq_next(tvb, 0, pinfo, frame_data_p->conversation_id, pop_data_segment_table, pop_data_reassembled_table, tvb_length(tvb), frame_data_p->more_frags); next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled DATA", frag_msg, &pop_data_frag_items, NULL, pop_tree); if (next_tvb) { if (imf_handle) call_dissector(imf_handle, next_tvb, pinfo, tree); if (data_val) { /* we have read everything - reset */ data_val->msg_read_len = 0; data_val->msg_tot_len = 0; } pinfo->fragmented = FALSE; } else { pinfo->fragmented = TRUE; } } else { /* * Put the whole packet into the tree as data. */ call_dissector(data_handle,tvb, pinfo, pop_tree); } return; } /* * Put the line into the protocol tree. */ ti = proto_tree_add_string_format(pop_tree, (is_request) ? hf_pop_request : hf_pop_response, tvb, offset, next_offset - offset, "", "%s", tvb_format_text(tvb, offset, next_offset - offset)); reqresp_tree = proto_item_add_subtree(ti, ett_pop_reqresp); /* * Extract the first token, and, if there is a first * token, add it as the request or reply code. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_pop_request_command : hf_pop_response_indicator, tvb, offset, tokenlen, FALSE); if (data_val) { if (is_request) { /* see if this is RETR or TOP command */ if (g_ascii_strncasecmp(line, "RETR", 4) == 0 || g_ascii_strncasecmp(line, "TOP", 3) == 0) /* the next response will tell us how many bytes */ data_val->msg_request = TRUE; } else { if (data_val->msg_request) { /* this is a response to a RETR or TOP command */ if (g_ascii_strncasecmp(line, "+OK ", 4) == 0) { /* the message will be sent - work out how many bytes */ data_val->msg_read_len = 0; data_val->msg_tot_len = atoi(line + 4); } data_val->msg_request = FALSE; } } } offset += (gint) (next_token - line); linelen -= (int) (next_token - line); } if (tree) { /* * Add the rest of the first line as request or * reply param/description. */ if (linelen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_pop_request_parameter : hf_pop_response_description, tvb, offset, linelen, FALSE); } offset = next_offset; /* * Show the rest of the request or response as text, * a line at a time. */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_string_format(pop_tree, (is_request) ? hf_pop_request_data : hf_pop_response_data, tvb, offset, next_offset - offset, "", "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } }
/* * Creates a new conversation with known endpoints based on a conversation * created with the CONVERSATION_TEMPLATE option while keeping the * conversation created with the CONVERSATION_TEMPLATE option so it can still * match future connections. * * Passing a pointer to a conversation whose options mask does not include * CONVERSATION_TEMPLATE or where the conversation's protocol type (ptype) * indicates a non-connnection oriented protocol will return the conversation * without changes. * * addr2 and port2 are used in the function if their respective conversation * options bits are set (NO_ADDR2 and NO_PORT2). */ static conversation_t * conversation_create_from_template(conversation_t *conversation, const address *addr2, const guint32 port2) { /* * Add a new conversation and keep the conversation template only if the * CONVERSATION_TEMPLATE bit is set for a connection oriented protocol. */ if(conversation->options & CONVERSATION_TEMPLATE && conversation->key_ptr->ptype != PT_UDP) { /* * Set up a new options mask where the conversation template bit and the * bits for absence of a second address and port pair have been removed. */ conversation_t *new_conversation_from_template; guint options = conversation->options & ~(CONVERSATION_TEMPLATE | NO_ADDR2 | NO_PORT2); /* * Are both the NO_ADDR2 and NO_PORT2 wildcards set in the options mask? */ if(conversation->options & NO_ADDR2 && conversation->options & NO_PORT2) { /* * The conversation template was created without knowledge of both * the second address as well as the second port. Create a new * conversation with new 2nd address and 2nd port. */ new_conversation_from_template = conversation_new(conversation->setup_frame, &conversation->key_ptr->addr1, addr2, conversation->key_ptr->ptype, conversation->key_ptr->port1, port2, options); } else if(conversation->options & NO_PORT2) { /* * The conversation template was created without knowledge of port 2 * only. Create a new conversation with new 2nd port. */ new_conversation_from_template = conversation_new(conversation->setup_frame, &conversation->key_ptr->addr1, &conversation->key_ptr->addr2, conversation->key_ptr->ptype, conversation->key_ptr->port1, port2, options); } else if(conversation->options & NO_ADDR2) { /* * The conversation template was created without knowledge of address * 2. Create a new conversation with new 2nd address. */ new_conversation_from_template = conversation_new(conversation->setup_frame, &conversation->key_ptr->addr1, addr2, conversation->key_ptr->ptype, conversation->key_ptr->port1, conversation->key_ptr->port2, options); } else { /* * The CONVERSATION_TEMPLATE bit was set, but no other bit that the * CONVERSATION_TEMPLATE bit controls is active. Just return the old * conversation. */ return conversation; } /* * Set the protocol dissector used for the template conversation as * the handler of the new conversation as well. */ new_conversation_from_template->dissector_handle = conversation->dissector_handle; return new_conversation_from_template; } else { return conversation; } }
static void dissect_spx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *spx_tree = NULL; proto_item *ti; tvbuff_t *next_tvb; guint8 conn_ctrl; proto_tree *cc_tree; guint8 datastream_type; const char *datastream_type_string; guint16 spx_seq; const char *spx_msg_string; guint16 low_socket, high_socket; guint32 src; conversation_t *conversation; spx_hash_value *pkt_value; spx_rexmit_info *spx_rexmit_info_p; spx_info spx_infox; col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPX"); col_set_str(pinfo->cinfo, COL_INFO, "SPX"); if (tree) { ti = proto_tree_add_item(tree, proto_spx, tvb, 0, SPX_HEADER_LEN, ENC_NA); spx_tree = proto_item_add_subtree(ti, ett_spx); } conn_ctrl = tvb_get_guint8(tvb, 0); spx_msg_string = spx_conn_ctrl(conn_ctrl); if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, " %s", spx_msg_string); if (tree) { ti = proto_tree_add_uint_format(spx_tree, hf_spx_connection_control, tvb, 0, 1, conn_ctrl, "Connection Control: %s (0x%02X)", spx_msg_string, conn_ctrl); cc_tree = proto_item_add_subtree(ti, ett_spx_connctrl); proto_tree_add_boolean(cc_tree, hf_spx_connection_control_sys, tvb, 0, 1, conn_ctrl); proto_tree_add_boolean(cc_tree, hf_spx_connection_control_send_ack, tvb, 0, 1, conn_ctrl); proto_tree_add_boolean(cc_tree, hf_spx_connection_control_attn, tvb, 0, 1, conn_ctrl); proto_tree_add_boolean(cc_tree, hf_spx_connection_control_eom, tvb, 0, 1, conn_ctrl); } datastream_type = tvb_get_guint8(tvb, 1); datastream_type_string = spx_datastream(datastream_type); if (datastream_type_string != NULL) { if (check_col(pinfo->cinfo, COL_INFO)) col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", datastream_type_string); } if (tree) { if (datastream_type_string != NULL) { proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb, 1, 1, datastream_type, "Datastream Type: %s (0x%02X)", datastream_type_string, datastream_type); } else { proto_tree_add_uint_format(spx_tree, hf_spx_datastream_type, tvb, 1, 1, datastream_type, "Datastream Type: 0x%02X", datastream_type); } proto_tree_add_item(spx_tree, hf_spx_src_id, tvb, 2, 2, ENC_BIG_ENDIAN); proto_tree_add_item(spx_tree, hf_spx_dst_id, tvb, 4, 2, ENC_BIG_ENDIAN); } spx_seq = tvb_get_ntohs(tvb, 6); if (tree) { proto_tree_add_uint(spx_tree, hf_spx_seq_nr, tvb, 6, 2, spx_seq); proto_tree_add_item(spx_tree, hf_spx_ack_nr, tvb, 8, 2, ENC_BIG_ENDIAN); proto_tree_add_item(spx_tree, hf_spx_all_nr, tvb, 10, 2, ENC_BIG_ENDIAN); } /* * SPX is Connection Oriented and Delivery Guaranteed. * On the first pass, we need to flag retransmissions by the SPX * protocol, so that subdissectors know whether a packet was * retransmitted. * * We start out by creating a conversation for this direction of the * IPX session; we use "pinfo->srcport" twice, so that we have * separate conversations for the two directions. * * XXX - that might not work correctly if there's more than one * SPX session using that source port; can that happen? If so, * we should probably use the direction, as well as the conversation, * as part of the hash key; if we do that, we can probably just * use PT_IPX as the port type, and possibly get rid of PT_NCP. * * According to * * http://developer.novell.com/research/appnotes/1995/december/03/apv.htm * * the sequence number is not incremented for system packets, so * presumably that means there is no notion of a system packet * being retransmitted; that document also says that system * packets are used as "I'm still here" keepalives and as * acknowledgements (presumably meaning ACK-only packets), which * suggests that they might not be ACKed and thus might not * be retransmitted. */ if (conn_ctrl & SPX_SYS_PACKET) { /* * It's a system packet, so it isn't a retransmission. */ spx_rexmit_info_p = NULL; } else { /* * Not a system packet - check for retransmissions. */ if (!pinfo->fd->flags.visited) { conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, pinfo->srcport, pinfo->srcport, 0); if (conversation == NULL) { /* * It's not part of any conversation - create * a new one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, pinfo->srcport, pinfo->srcport, 0); } /* * Now we'll hash the SPX header and use the result * of that, plus the conversation, as a hash key to * identify this packet. * * If we don't find it in the hash table, it's not a * retransmission, otherwise it is. If we don't find * it, we enter it into the hash table, with the * frame number. * If we do, we attach to this frame a structure giving * the frame number of the original transmission, so * that we, and subdissectors, know it's a * retransmission. */ src = tvb_get_ntohs(tvb, 0)+tvb_get_ntohs(tvb, 2)+tvb_get_ntohs(tvb, 4)+tvb_get_ntohs(tvb, 6)+tvb_get_ntohs(tvb, 8); pkt_value = spx_hash_lookup(conversation, src, spx_seq); if (pkt_value == NULL) { /* * Not found in the hash table. * Enter it into the hash table. */ pkt_value = spx_hash_insert(conversation, src, spx_seq); pkt_value->spx_ack = tvb_get_ntohs(tvb, 8); pkt_value->spx_all = tvb_get_ntohs(tvb, 10); pkt_value->num = pinfo->fd->num; /* * This is not a retransmission, so we shouldn't * have any retransmission indicator. */ spx_rexmit_info_p = NULL; } else { /* * Found in the hash table. Mark this frame as * a retransmission. */ spx_rexmit_info_p = se_alloc(sizeof(spx_rexmit_info)); spx_rexmit_info_p->num = pkt_value->num; p_add_proto_data(pinfo->fd, proto_spx, spx_rexmit_info_p); } } else { /* * Do we have per-packet SPX data for this frame? * If so, it's a retransmission, and the per-packet * data indicates which frame had the original * transmission. */ spx_rexmit_info_p = p_get_proto_data(pinfo->fd, proto_spx); } } /* * It's a retransmission if we have a retransmission indicator. * Flag this as a retransmission, but don't pass it to the * subdissector. */ if (spx_rexmit_info_p != NULL) { if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "[Retransmission] Original Packet %u", spx_rexmit_info_p->num); } if (tree) { proto_tree_add_uint_format(spx_tree, hf_spx_rexmt_frame, tvb, 0, 0, spx_rexmit_info_p->num, "This is a retransmission of frame %u", spx_rexmit_info_p->num); if (tvb_length_remaining(tvb, SPX_HEADER_LEN) > 0) { proto_tree_add_text(spx_tree, tvb, SPX_HEADER_LEN, -1, "Retransmitted data"); } } return; } if (tvb_reported_length_remaining(tvb, SPX_HEADER_LEN) > 0) { void* pd_save; /* * Call subdissectors based on the IPX socket numbers; a * subdissector might have registered with our IPX socket * dissector table rather than the IPX dissector's socket * dissector table. * * Assume the lower-numbered socket number is more likely * to be the right one, along the lines of what we do for * TCP and UDP. We've seen NCP packets with a type of NCP, * a source socket of IPX_SOCKET_NCP, and a destination * socket of IPX_SOCKET_IPX_MESSAGE, and we've seen NCP * packets with a type of NCP, a source socket of * IPX_SOCKET_IPX_MESSAGE, and a destination socket of * IPX_SOCKET_NCP. */ if (pinfo->srcport > pinfo->destport) { low_socket = pinfo->destport; high_socket = pinfo->srcport; } else { low_socket = pinfo->srcport; high_socket = pinfo->destport; } /* * Pass information to subdissectors. */ spx_infox.eom = conn_ctrl & SPX_EOM; spx_infox.datastream_type = datastream_type; pd_save = pinfo->private_data; pinfo->private_data = &spx_infox; next_tvb = tvb_new_subset_remaining(tvb, SPX_HEADER_LEN); if (dissector_try_uint(spx_socket_dissector_table, low_socket, next_tvb, pinfo, tree)) { pinfo->private_data = pd_save; return; } if (dissector_try_uint(spx_socket_dissector_table, high_socket, next_tvb, pinfo, tree)) { pinfo->private_data = pd_save; return; } call_dissector(data_handle, next_tvb, pinfo, tree); pinfo->private_data = pd_save; } }
static void dissect_fcfcs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ int offset = 0; proto_item *ti; proto_tree *fcfcs_tree = NULL; fc_ct_preamble cthdr; gboolean isreq = 1; conversation_t *conversation; fcfcs_conv_data_t *cdata; fcfcs_conv_key_t ckey, *req_key; int opcode, failed_opcode = 0; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FC-FCS"); if (tree) { ti = proto_tree_add_protocol_format (tree, proto_fcfcs, tvb, 0, tvb_reported_length (tvb), "FCS"); fcfcs_tree = proto_item_add_subtree (ti, ett_fcfcs); } tvb_memcpy (tvb, (guint8 *)&cthdr, offset, FCCT_PRMBL_SIZE); cthdr.revision = tvb_get_guint8 (tvb, offset); cthdr.in_id = tvb_get_ntoh24 (tvb, offset+1); cthdr.opcode = g_ntohs (cthdr.opcode); opcode = tvb_get_ntohs (tvb, offset+8); cthdr.maxres_size = g_ntohs (cthdr.maxres_size); if ((opcode != FCCT_MSG_ACC) && (opcode != FCCT_MSG_RJT)) { conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->oxid, pinfo->rxid, NO_PORT2); if (!conversation) { conversation = conversation_new (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->oxid, pinfo->rxid, NO_PORT2); } ckey.conv_idx = conversation->index; cdata = (fcfcs_conv_data_t *)g_hash_table_lookup (fcfcs_req_hash, &ckey); if (cdata) { /* Since we never free the memory used by an exchange, this maybe a * case of another request using the same exchange as a previous * req. */ cdata->opcode = opcode; } else { req_key = se_alloc (sizeof(fcfcs_conv_key_t)); req_key->conv_idx = conversation->index; cdata = se_alloc (sizeof(fcfcs_conv_data_t)); cdata->opcode = opcode; g_hash_table_insert (fcfcs_req_hash, req_key, cdata); } if (check_col (pinfo->cinfo, COL_INFO)) { col_add_str (pinfo->cinfo, COL_INFO, val_to_str (opcode, fc_fcs_opcode_abbrev_val, "0x%x")); } } else { /* Opcode is ACC or RJT */ conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->oxid, pinfo->rxid, NO_PORT2); isreq = 0; if (!conversation) { if (tree && (opcode == FCCT_MSG_ACC)) { if (check_col (pinfo->cinfo, COL_INFO)) { col_add_str (pinfo->cinfo, COL_INFO, val_to_str (opcode, fc_fcs_opcode_abbrev_val, "0x%x")); } /* No record of what this accept is for. Can't decode */ proto_tree_add_text (fcfcs_tree, tvb, 0, tvb_length (tvb), "No record of Exchg. Unable to decode MSG_ACC/RJT"); return; } } else { ckey.conv_idx = conversation->index; cdata = (fcfcs_conv_data_t *)g_hash_table_lookup (fcfcs_req_hash, &ckey); if (cdata != NULL) { if (opcode == FCCT_MSG_ACC) opcode = cdata->opcode; else failed_opcode = cdata->opcode; } if (check_col (pinfo->cinfo, COL_INFO)) { if (opcode != FCCT_MSG_RJT) { col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_ACC (%s)", val_to_str (opcode, fc_fcs_opcode_abbrev_val, "0x%x")); } else { col_add_fstr (pinfo->cinfo, COL_INFO, "MSG_RJT (%s)", val_to_str (failed_opcode, fc_fcs_opcode_abbrev_val, "0x%x")); } } if (tree) { if ((cdata == NULL) && (opcode != FCCT_MSG_RJT)) { /* No record of what this accept is for. Can't decode */ proto_tree_add_text (fcfcs_tree, tvb, 0, tvb_length (tvb), "No record of Exchg. Unable to decode MSG_ACC/RJT"); return; } } } } if (tree) { proto_tree_add_item (fcfcs_tree, hf_fcs_opcode, tvb, offset+8, 2, ENC_BIG_ENDIAN); proto_tree_add_item (fcfcs_tree, hf_fcs_maxres_size, tvb, offset+10, 2, ENC_BIG_ENDIAN); } switch (opcode) { case FCCT_MSG_RJT: dissect_fcfcs_rjt (tvb, fcfcs_tree); break; case FCFCS_GIEL: dissect_fcfcs_giel (tvb, fcfcs_tree, isreq); break; case FCFCS_GIET: dissect_fcfcs_giet (tvb, fcfcs_tree, isreq); break; case FCFCS_GDID: dissect_fcfcs_gdid (tvb, fcfcs_tree, isreq); break; case FCFCS_GMID: dissect_fcfcs_gmid (tvb, fcfcs_tree, isreq); break; case FCFCS_GFN: dissect_fcfcs_gfn (tvb, fcfcs_tree, isreq); break; case FCFCS_GIELN: dissect_fcfcs_gieln (tvb, fcfcs_tree, isreq); break; case FCFCS_GMAL: dissect_fcfcs_gmal (tvb, fcfcs_tree, isreq); break; case FCFCS_GIEIL: dissect_fcfcs_gieil (tvb, fcfcs_tree, isreq); break; case FCFCS_GPL: dissect_fcfcs_gpl (tvb, fcfcs_tree, isreq); break; case FCFCS_GPT: dissect_fcfcs_gpt (tvb, fcfcs_tree, isreq); break; case FCFCS_GPPN: dissect_fcfcs_gppn (tvb, fcfcs_tree, isreq); break; case FCFCS_GAPNL: dissect_fcfcs_gapnl (tvb, fcfcs_tree, isreq); break; case FCFCS_GPS: dissect_fcfcs_gps (tvb, fcfcs_tree, isreq); break; case FCFCS_GPLNL: dissect_fcfcs_gplnl (tvb, fcfcs_tree, isreq); break; case FCFCS_GPLT: dissect_fcfcs_gplt (tvb, fcfcs_tree, isreq); break; case FCFCS_GPLML: dissect_fcfcs_gplml (tvb, fcfcs_tree, isreq); break; case FCFCS_GNPL: dissect_fcfcs_gnpl (tvb, fcfcs_tree, isreq); break; case FCFCS_GPNL: dissect_fcfcs_gpnl (tvb, fcfcs_tree, isreq); break; case FCFCS_RIELN: dissect_fcfcs_rieln (tvb, fcfcs_tree, isreq); break; case FCFCS_RPL: dissect_fcfcs_rpl (tvb, fcfcs_tree, isreq); break; case FCFCS_RPLN: dissect_fcfcs_rpln (tvb, fcfcs_tree, isreq); break; case FCFCS_RPLT: dissect_fcfcs_rplt (tvb, fcfcs_tree, isreq); break; case FCFCS_RPLM: dissect_fcfcs_rplm (tvb, fcfcs_tree, isreq); break; case FCFCS_DPL: dissect_fcfcs_dpl (tvb, fcfcs_tree, isreq); break; case FCFCS_DPLN: dissect_fcfcs_dpln (tvb, fcfcs_tree, isreq); break; case FCFCS_DPLML: dissect_fcfcs_dplml (tvb, fcfcs_tree, isreq); break; case FCFCS_GCAP: dissect_fcfcs_gcap (tvb, fcfcs_tree, isreq); break; default: call_dissector (data_handle, tvb, pinfo, fcfcs_tree); break; } }
static void dissect_exec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *exec_tree=NULL; /* Variables for extracting and displaying data from the packet */ guchar *field_stringz; /* Temporary storage for each field we extract */ gint length; guint offset = 0; conversation_t *conversation; exec_hash_entry_t *hash_info; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if(!conversation){ /* Conversation does not exist yet - create it */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } /* Retrieve information from conversation * or add it if it isn't there yet */ hash_info = conversation_get_proto_data(conversation, proto_exec); if(!hash_info){ hash_info = se_alloc(sizeof(exec_hash_entry_t)); hash_info->first_packet_number = pinfo->fd->num; hash_info->second_packet_number = 0; hash_info->third_packet_number = 0; hash_info->fourth_packet_number = 0; hash_info->state = WAIT_FOR_STDERR_PORT; /* The first field we'll see */ /* Start with empty username and command strings */ hash_info->username=NULL; hash_info->command=NULL; /* These will be set on the first pass by the first * four packets of the conversation */ hash_info->first_packet_state = NONE; hash_info->second_packet_state = NONE; hash_info->third_packet_state = NONE; hash_info->fourth_packet_state = NONE; conversation_add_proto_data(conversation, proto_exec, hash_info); } /* Store the number of the first three packets of this conversation * as we reach them the first time */ if(!hash_info->second_packet_number && pinfo->fd->num > hash_info->first_packet_number){ /* We're on the second packet of the conversation */ hash_info->second_packet_number = pinfo->fd->num; } else if(hash_info->second_packet_number && !hash_info->third_packet_number && pinfo->fd->num > hash_info->second_packet_number) { /* We're on the third packet of the conversation */ hash_info->third_packet_number = pinfo->fd->num; } else if(hash_info->third_packet_number && !hash_info->fourth_packet_number && pinfo->fd->num > hash_info->third_packet_number) { /* We're on the fourth packet of the conversation */ hash_info->fourth_packet_number = pinfo->fd->num; } /* Save this packet's state so we can retrieve it if this packet * is selected again later. If the packet's state was already stored, * then retrieve it */ if(pinfo->fd->num == hash_info->first_packet_number){ if(hash_info->first_packet_state == NONE){ hash_info->first_packet_state = hash_info->state; } else { hash_info->state = hash_info->first_packet_state; } } if(pinfo->fd->num == hash_info->second_packet_number){ if(hash_info->second_packet_state == NONE){ hash_info->second_packet_state = hash_info->state; } else { hash_info->state = hash_info->second_packet_state; } } if(pinfo->fd->num == hash_info->third_packet_number){ if(hash_info->third_packet_state == NONE){ hash_info->third_packet_state = hash_info->state; } else { hash_info->state = hash_info->third_packet_state; } } if(pinfo->fd->num == hash_info->fourth_packet_number){ if(hash_info->fourth_packet_state == NONE){ hash_info->fourth_packet_state = hash_info->state; } else { hash_info->state = hash_info->fourth_packet_state; } } col_set_str(pinfo->cinfo, COL_PROTOCOL, "EXEC"); if(check_col(pinfo->cinfo, COL_INFO)){ /* First, clear the info column */ col_clear(pinfo->cinfo, COL_INFO); /*username */ if(hash_info->username && preference_info_show_username == TRUE){ col_append_fstr(pinfo->cinfo, COL_INFO, "Username:%s ", hash_info->username); } /* Command */ if(hash_info->command && preference_info_show_command == TRUE){ col_append_fstr(pinfo->cinfo, COL_INFO, "Command:%s ", hash_info->command); } } /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_exec, tvb, 0, -1, FALSE); exec_tree = proto_item_add_subtree(ti, ett_exec); /* If this packet doesn't end with a null terminated string, * then it must be session data only and we can skip looking * for the other fields. */ if(tvb_find_guint8(tvb, tvb_length(tvb)-1, 1, '\0') == -1){ hash_info->state = WAIT_FOR_DATA; } if(hash_info->state == WAIT_FOR_STDERR_PORT && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the stderr_port field. * It is optional, so it may only be 1 character long * (the NULL) */ if(length == 1 || (exec_isdigit_string(field_stringz) && length <= EXEC_STDERR_PORT_LEN)){ proto_tree_add_string(exec_tree, hf_exec_stderr_port, tvb, offset, length, (gchar*)field_stringz); /* Next field we need */ hash_info->state = WAIT_FOR_USERNAME; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; } if(hash_info->state == WAIT_FOR_USERNAME && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the username field */ if(length != 1 && length <= EXEC_USERNAME_LEN && exec_isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_username, tvb, offset, length, (gchar*)field_stringz); /* Store the username so we can display it in the * info column of the entire conversation */ if(!hash_info->username){ hash_info->username=se_strdup((gchar*)field_stringz); } /* Next field we need */ hash_info->state = WAIT_FOR_PASSWORD; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; } if(hash_info->state == WAIT_FOR_PASSWORD && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the password field */ if(length != 1 && length <= EXEC_PASSWORD_LEN && exec_isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_password, tvb, offset, length, (gchar*)field_stringz); /* Next field we need */ hash_info->state = WAIT_FOR_COMMAND; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; /* Next field we are looking for */ hash_info->state = WAIT_FOR_COMMAND; } if(hash_info->state == WAIT_FOR_COMMAND && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the command field */ if(length != 1 && length <= EXEC_COMMAND_LEN && exec_isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_command, tvb, offset, length, (gchar*)field_stringz); /* Store the username so we can display it in the * info column of the entire conversation */ if(!hash_info->command){ hash_info->command=se_strdup((gchar*)field_stringz); } } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } } if(hash_info->state == WAIT_FOR_DATA && tvb_length_remaining(tvb, offset)){ if(pinfo->destport == EXEC_PORT){ /* Packet going to the server */ /* offset = 0 since the whole packet is data */ proto_tree_add_text(exec_tree, tvb, 0, -1, "Client -> Server Data"); if(check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Client -> Server data"); } else { /* This packet must be going back to the client */ /* offset = 0 since the whole packet is data */ proto_tree_add_text(exec_tree, tvb, 0, -1, "Server -> Client Data"); if(check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Server -> Client Data"); } } /* We haven't seen all of the fields yet */ if(hash_info->state < WAIT_FOR_DATA){ col_set_str(pinfo->cinfo, COL_INFO, "Session Establishment"); } }
static void dissect_beep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset; struct beep_proto_data *beep_frame_data = NULL; proto_tree *beep_tree = NULL, *ti = NULL; conversation_t *conversation = NULL; struct beep_request_key request_key, *new_request_key; struct beep_request_val *request_val = NULL; offset = 0; /* If we have per frame data, use that, else, we must have lost the per- * frame data, and we have to do a full dissect pass again. * * The per-frame data tells us how much of this frame is left over from a * previous frame, so we dissect it as payload and then try to dissect the * rest. * * We use the conversation to build up info on the first pass over the * packets of type BEEP, and record anything that is needed if the user * does random dissects of packets in per packet data. * * Once we have per-packet data, we don't need the conversation stuff * anymore, but if per-packet data and conversation stuff gets deleted, as * it does under some circumstances when a rescan is done, it all gets * rebuilt. */ /* Find out what conversation this packet is part of ... but only * if we have no information on this packet, so find the per-frame * info first. */ beep_frame_data = p_get_proto_data(pinfo->fd, proto_beep); if (!beep_frame_data) { conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { /* No conversation, create one */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } /* * Check for and insert an entry in the request table if does not exist */ request_key.conversation = conversation->index; request_val = (struct beep_request_val *)g_hash_table_lookup(beep_request_hash, &request_key); if (!request_val) { /* Create one */ new_request_key = se_alloc(sizeof(struct beep_request_key)); new_request_key->conversation = conversation->index; request_val = se_alloc(sizeof(struct beep_request_val)); request_val->processed = 0; request_val->size = 0; g_hash_table_insert(beep_request_hash, new_request_key, request_val); } } col_set_str(pinfo->cinfo, COL_PROTOCOL, "BEEP"); if (check_col(pinfo->cinfo, COL_INFO)) { /* Check the type ... */ /* "tvb_format_text()" is passed a value that won't go past the end * of the packet, so it won't throw an exception. */ col_add_str(pinfo->cinfo, COL_INFO, tvb_format_text(tvb, offset, tvb_length_remaining(tvb, offset))); } /* Here, we parse the message so we can retrieve the info we need, which * is that there is some payload left from a previous segment on the * front of this segment ... This all depends on TCP segments not getting * out of order ... * * As a huge kludge, we push the checking for the tree down into the code * and process as if we were given a tree but not call the routines that * adorn the protocol tree if they were NULL. */ if (tree) { /* Build the tree info ... */ ti = proto_tree_add_item(tree, proto_beep, tvb, offset, -1, FALSE); beep_tree = proto_item_add_subtree(ti, ett_beep); } /* Check the per-frame data and the conversation for any left-over * payload from the previous frame * * We check that per-frame data exists first, and if so, use it, * else we use the conversation data. * * We create per-frame data here as well, but we must ensure we create it * after we have done the check for per-frame or conversation data. * * We also depend on the first frame in a group having a pl_size of 0. */ if (beep_frame_data && beep_frame_data->pl_left > 0) { int pl_left = beep_frame_data->pl_left; pl_left = MIN(pl_left, tvb_length_remaining(tvb, offset)); /* Add the payload bit, only if we have a tree */ if (tree) { proto_tree_add_text(beep_tree, tvb, offset, pl_left, "Payload: %s", tvb_format_text(tvb, offset, pl_left)); } offset += pl_left; } else if (request_val && request_val->size > 0) { int pl_left = request_val->size; request_val->size = 0; /* We create the frame data here for this case, and * elsewhere for other frames */ beep_frame_data = se_alloc(sizeof(struct beep_proto_data)); beep_frame_data->pl_left = pl_left; beep_frame_data->pl_size = 0; beep_frame_data->mime_hdr = 0; p_add_proto_data(pinfo->fd, proto_beep, beep_frame_data); } /* Set up the per-frame data here if not already done so * This _must_ come after the checks above ... */ if (beep_frame_data == NULL) { beep_frame_data = se_alloc(sizeof(struct beep_proto_data)); beep_frame_data->pl_left = 0; beep_frame_data->pl_size = 0; beep_frame_data->mime_hdr = 0; p_add_proto_data(pinfo->fd, proto_beep, beep_frame_data); } if (tvb_length_remaining(tvb, offset) > 0) { offset += dissect_beep_tree(tvb, offset, pinfo, beep_tree, request_val, beep_frame_data); } }
static void dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_tcp) { proto_tree *ncp_tree = NULL; proto_item *ti; struct ncp_ip_header ncpiph; struct ncp_ip_rqhdr ncpiphrq; guint16 ncp_burst_seqno, ncp_ack_seqno; guint16 flags = 0; proto_tree *flags_tree = NULL; int hdr_offset = 0; int commhdr = 0; int offset = 0; gint length_remaining; tvbuff_t *next_tvb; guint32 testvar = 0, ncp_burst_command, burst_len, burst_off, burst_file; guint8 subfunction; guint32 nw_connection = 0, data_offset; guint16 data_len = 0; guint16 missing_fraglist_count = 0; mncp_rhash_value *request_value = NULL; conversation_t *conversation; proto_item *expert_item; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP"); col_clear(pinfo->cinfo, COL_INFO); ncp_hdr = &header; ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, ENC_NA); ncp_tree = proto_item_add_subtree(ti, ett_ncp); if (is_tcp) { if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY) commhdr += 1; /* Get NCPIP Header data */ ncpiph.signature = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, commhdr, 4, ncpiph.signature); ncpiph.length = (0x7fffffff & tvb_get_ntohl(tvb, commhdr+4)); proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, commhdr+4, 4, ncpiph.length); commhdr += 8; if (ncpiph.signature == NCPIP_RQST) { ncpiphrq.version = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, commhdr, 4, ncpiphrq.version); commhdr += 4; ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, commhdr, 4, ncpiphrq.rplybufsize); commhdr += 4; } /* Check to see if this is a valid offset, otherwise increment for packet signature */ if (try_val_to_str(tvb_get_ntohs(tvb, commhdr), ncp_type_vals)==NULL) { /* Check to see if we have a valid type after packet signature length */ if (try_val_to_str(tvb_get_ntohs(tvb, commhdr+8), ncp_type_vals)!=NULL) { proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, commhdr, 8, ENC_NA); commhdr += 8; } } } else { /* Initialize this structure, we use it below */ memset(&ncpiph, 0, sizeof(ncpiph)); } header.type = tvb_get_ntohs(tvb, commhdr); header.sequence = tvb_get_guint8(tvb, commhdr+2); header.conn_low = tvb_get_guint8(tvb, commhdr+3); header.task = tvb_get_guint8(tvb, commhdr+4); header.conn_high = tvb_get_guint8(tvb, commhdr+5); proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr, 2, header.type); nw_connection = (header.conn_high*256)+header.conn_low; /* Ok, we need to track the conversation so that we can * determine if a new server session is occuring for this * connection. */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); if ((ncpiph.length & 0x80000000) || ncpiph.signature == NCPIP_RPLY) { /* First time through we will record the initial connection and task * values */ if (!pinfo->fd->flags.visited) { if (conversation != NULL) { /* find the record telling us the * request made that caused this * reply */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); /* if for some reason we have no * conversation in our hash, create * one */ if (request_value == NULL) { mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } } else { /* It's not part of any conversation * - create a new one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } /* If this is a request packet then we * might have a new task */ if (ncpiph.signature == NCPIP_RPLY) { /* Now on reply packets we have to * use the state of the original * request packet, so look up the * request value and check the task number */ /*request_value = mncp_hash_lookup(conversation, nw_connection, header.task);*/ } } else { /* Get request value data */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); if (request_value) { if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn) { expert_add_info_format(pinfo, NULL, &ei_ncp_new_server_session, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task); } } } } else { if (!pinfo->fd->flags.visited) { if (conversation != NULL) { /* find the record telling us the * request made that caused this * reply */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); /* if for some reason we have no * conversation in our hash, create * one */ if (request_value == NULL) { mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } } else { /* It's not part of any conversation * - create a new one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } /* find the record telling us the request * made that caused this reply */ } else { request_value = mncp_hash_lookup(conversation, nw_connection, header.task); if (request_value) { if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn) { expert_add_info_format(pinfo, NULL, &ei_ncp_new_server_session, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task); } } } } tap_queue_packet(ncp_tap.hdr, pinfo, ncp_hdr); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); /* * Process the packet-type-specific header. */ switch (header.type) { case NCP_BROADCAST_SLOT: /* Server Broadcast */ proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence); proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection); proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, tvb_get_guint8(tvb, commhdr+9)); proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, ENC_BIG_ENDIAN); if ((tvb_get_guint8(tvb, commhdr+9)==0x24) && ncp_echo_file) { expert_add_info_format(pinfo, NULL, &ei_ncp_oplock_handle, "Server requesting station to clear oplock on handle - %08x", tvb_get_ntohl(tvb, commhdr+10)); } break; case NCP_LIP_ECHO: /* Lip Echo Packet */ proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, ENC_ASCII|ENC_NA); break; case NCP_BURST_MODE_XFER: /* Packet Burst Packet */ /* * XXX - we should keep track of whether there's a burst * outstanding on a connection and, if not, treat the * beginning of the data as a burst header. * * The burst header contains: * * 4 bytes of little-endian function number: * 1 = read, 2 = write; * * 4 bytes of file handle; * * 8 reserved bytes; * * 4 bytes of big-endian file offset; * * 4 bytes of big-endian byte count. * * The data follows for a burst write operation. * * The first packet of a burst read reply contains: * * 4 bytes of little-endian result code: * 0: No error * 1: Initial error * 2: I/O error * 3: No data read; * * 4 bytes of returned byte count (big-endian?). * * The data follows. * * Each burst of a write request is responded to with a * burst packet with a 2-byte little-endian result code: * * 0: Write successful * 4: Write error */ flags = tvb_get_guint8(tvb, commhdr + 2); ti = proto_tree_add_uint(ncp_tree, hf_ncp_system_flags, tvb, commhdr + 2, 1, flags); flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags); proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & ABT) { proto_item_append_text(ti, " ABT"); } flags&=(~( ABT )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & BSY) { proto_item_append_text(ti, " BSY"); } flags&=(~( BSY )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & EOB) { proto_item_append_text(ti, " EOB"); } flags&=(~( EOB )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & LST) { proto_item_append_text(ti, " LST"); } flags&=(~( LST )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & SYS) { proto_item_append_text(ti, " SYS"); } flags&=(~( SYS )); proto_tree_add_item(ncp_tree, hf_ncp_stream_type, tvb, commhdr + 3, 1, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_src_connection, tvb, commhdr + 4, 4, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_dst_connection, tvb, commhdr + 8, 4, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno, tvb, commhdr + 12, 4, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_delay_time, tvb, commhdr + 16, 4, ENC_BIG_ENDIAN); ncp_burst_seqno = tvb_get_ntohs(tvb, commhdr+20); proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno, tvb, commhdr + 20, 2, ENC_BIG_ENDIAN); ncp_ack_seqno = tvb_get_ntohs(tvb, commhdr+22); proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno, tvb, commhdr + 22, 2, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_burst_len, tvb, commhdr + 24, 4, ENC_BIG_ENDIAN); data_offset = tvb_get_ntohl(tvb, commhdr + 28); proto_tree_add_uint(ncp_tree, hf_ncp_data_offset, tvb, commhdr + 28, 4, data_offset); data_len = tvb_get_ntohs(tvb, commhdr + 32); proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes, tvb, commhdr + 32, 2, data_len); missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34); proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count, tvb, commhdr + 34, 2, ENC_BIG_ENDIAN); offset = commhdr + 36; if (!(flags & SYS) && ncp_burst_seqno == ncp_ack_seqno && data_offset == 0) { /* * This is either a Burst Read or Burst Write * command. The data length includes the burst * mode header, plus any data in the command * (there shouldn't be any in a read, but there * might be some in a write). */ if (data_len < 4) return; ncp_burst_command = tvb_get_ntohl(tvb, offset); proto_tree_add_item(ncp_tree, hf_ncp_burst_command, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; data_len -= 4; if (data_len < 4) return; burst_file = tvb_get_ntohl(tvb, offset); proto_tree_add_item(ncp_tree, hf_ncp_burst_file_handle, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; data_len -= 4; if (data_len < 8) return; proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved, tvb, offset, 8, ENC_NA); offset += 8; data_len -= 8; if (data_len < 4) return; burst_off = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(ncp_tree, hf_ncp_burst_offset, tvb, offset, 4, burst_off); offset += 4; data_len -= 4; if (data_len < 4) return; burst_len = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(ncp_tree, hf_ncp_burst_len, tvb, offset, 4, burst_len); offset += 4; data_len -= 4; col_add_fstr(pinfo->cinfo, COL_INFO, "%s %d bytes starting at offset %d in file 0x%08x", val_to_str(ncp_burst_command, burst_command, "Unknown (0x%08x)"), burst_len, burst_off, burst_file); break; } else { if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) { col_set_str(pinfo->cinfo, COL_INFO, "End of Burst"); } } break; case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */ length_remaining = tvb_length_remaining(tvb, commhdr + 4); if (length_remaining > 4) { testvar = tvb_get_ntohl(tvb, commhdr+4); if (testvar == 0x4c495020) { proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, ENC_ASCII|ENC_NA); break; } } /* otherwise fall through */ case NCP_POSITIVE_ACK: /* Positive Acknowledgement */ case NCP_SERVICE_REQUEST: /* Server NCP Request */ case NCP_SERVICE_REPLY: /* Server NCP Reply */ case NCP_WATCHDOG: /* Watchdog Packet */ case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */ default: proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence); proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection); proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN); break; } /* * Process the packet body. */ switch (header.type) { case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */ length_remaining = tvb_length_remaining(tvb, commhdr + 4); if (length_remaining > 4) { testvar = tvb_get_ntohl(tvb, commhdr+4); if (testvar == 0x4c495020) { proto_tree_add_text(ncp_tree, tvb, commhdr, -1, "Lip Echo Packet"); /*break;*/ } } next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case NCP_SERVICE_REQUEST: /* Server NCP Request */ case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); if (tvb_get_guint8(tvb, commhdr+6) == 0x68) { subfunction = tvb_get_guint8(tvb, commhdr+7); switch (subfunction) { case 0x02: /* NDS Frag Packet to decode */ dissect_nds_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case 0x01: /* NDS Ping */ dissect_ping_req(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; default: dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; } } else { dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); } break; case NCP_SERVICE_REPLY: /* Server NCP Reply */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); nds_defrag(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, &ncp_tap); break; case NCP_POSITIVE_ACK: /* Positive Acknowledgement */ /* * XXX - this used to call "nds_defrag()", which would * clear out "frags". Was that the right thing to * do? */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_reply(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, &ncp_tap); break; case NCP_WATCHDOG: /* Watchdog Packet */ /* * XXX - should the completion code be interpreted as * it is in "packet-ncp2222.inc"? If so, this * packet should be handled by "dissect_ncp_reply()". */ proto_tree_add_item(ncp_tree, hf_ncp_completion_code, tvb, commhdr + 6, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, commhdr + 7, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_slot, tvb, commhdr + 8, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_control_code, tvb, commhdr + 9, 1, ENC_LITTLE_ENDIAN); /* * Display the rest of the packet as data. */ if (tvb_offset_exists(tvb, commhdr + 10)) { call_dissector(data_handle, tvb_new_subset_remaining(tvb, commhdr + 10), pinfo, ncp_tree); } break; case NCP_BURST_MODE_XFER: /* Packet Burst Packet */ if (flags & SYS) { /* * System packet; show missing fragments if there * are any. */ while (missing_fraglist_count != 0) { proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; missing_fraglist_count--; } } else { /* * XXX - do this by using -1 and -1 as the length * arguments to "tvb_new_subset()" and then calling * "tvb_set_reported_length()"? That'll throw an * exception if "data_len" goes past the reported * length of the packet, but that's arguably a * feature in this case. */ length_remaining = tvb_length_remaining(tvb, offset); if (length_remaining > data_len) length_remaining = data_len; if (data_len != 0) { call_dissector(data_handle, tvb_new_subset(tvb, offset, length_remaining, data_len), pinfo, ncp_tree); } } break; case NCP_LIP_ECHO: /* LIP Echo Packet */ proto_tree_add_text(ncp_tree, tvb, commhdr, -1, "Lip Echo Packet"); break; default: expert_item = proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1, "%s packets not supported yet", val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); if (ncp_echo_err) { expert_add_info_format(pinfo, expert_item, &ei_ncp_type, "%s packets not supported yet", val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); } break; } }
/* Set up an T38 conversation */ void t38_add_address(packet_info *pinfo, address *addr, int port, int other_port, const gchar *setup_method, guint32 setup_frame_number) { address null_addr; conversation_t* p_conversation; t38_conv* p_conversation_data = NULL; /* * If this isn't the first time this packet has been processed, * we've already done this work, so we don't need to do it * again. */ if ((pinfo->fd->flags.visited) || (t38_udp_handle == NULL)) { return; } SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); /* * Check if the ip address and port combination is not * already registered as a conversation. */ p_conversation = find_conversation( setup_frame_number, addr, &null_addr, PT_UDP, port, other_port, NO_ADDR_B | (!other_port ? NO_PORT_B : 0)); /* * If not, create a new conversation. */ if ( !p_conversation || p_conversation->setup_frame != setup_frame_number) { p_conversation = conversation_new( setup_frame_number, addr, &null_addr, PT_UDP, (guint32)port, (guint32)other_port, NO_ADDR2 | (!other_port ? NO_PORT2 : 0)); } /* Set dissector */ conversation_set_dissector(p_conversation, t38_udp_handle); /* * Check if the conversation has data associated with it. */ p_conversation_data = (t38_conv*)conversation_get_proto_data(p_conversation, proto_t38); /* * If not, add a new data item. */ if ( ! p_conversation_data ) { /* Create conversation data */ p_conversation_data = wmem_new(wmem_file_scope(), t38_conv); conversation_add_proto_data(p_conversation, proto_t38, p_conversation_data); } /* * Update the conversation data. */ g_strlcpy(p_conversation_data->setup_method, setup_method, MAX_T38_SETUP_METHOD_SIZE); p_conversation_data->setup_frame_number = setup_frame_number; p_conversation_data->src_t38_info.reass_ID = 0; p_conversation_data->src_t38_info.reass_start_seqnum = -1; p_conversation_data->src_t38_info.reass_data_type = 0; p_conversation_data->src_t38_info.last_seqnum = -1; p_conversation_data->src_t38_info.packet_lost = 0; p_conversation_data->src_t38_info.burst_lost = 0; p_conversation_data->src_t38_info.time_first_t4_data = 0; p_conversation_data->dst_t38_info.reass_ID = 0; p_conversation_data->dst_t38_info.reass_start_seqnum = -1; p_conversation_data->dst_t38_info.reass_data_type = 0; p_conversation_data->dst_t38_info.last_seqnum = -1; p_conversation_data->dst_t38_info.packet_lost = 0; p_conversation_data->dst_t38_info.burst_lost = 0; p_conversation_data->dst_t38_info.time_first_t4_data = 0; }
/** Dissector for SoupBinTCP messages */ static void dissect_soupbintcp_common( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { struct conv_data *conv_data; struct pdu_data *pdu_data; const char *pkt_name; const char *tmp_buf; proto_item *ti; proto_tree *soupbintcp_tree = NULL; conversation_t *conv = NULL; guint16 expected_len; guint8 pkt_type; gint offset = 0; guint this_seq = 0, next_seq; heur_dtbl_entry_t *hdtbl_entry; /* Get the 16-bit big-endian SOUP packet length */ expected_len = tvb_get_ntohs(tvb, 0); /* Get the 1-byte SOUP message type */ pkt_type = tvb_get_guint8(tvb, 2); /* Since we use the packet name a few times, get and save that value */ pkt_name = val_to_str(pkt_type, pkt_type_val, "Unknown (%u)"); /* Set the protocol name in the summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SoupBinTCP"); /* Set the packet name in the info column */ col_add_str(pinfo->cinfo, COL_INFO, pkt_name); /* Sequence number tracking * * SOUP does not number packets from client to server (the server * acknowledges all important messages, so the client should use * the acks to figure out if the server received the message, and * otherwise resend it). * * Packets from server to client are numbered, but it's implicit. * The Login Accept packet contains the next sequence number that * the server will send, and the client needs to count the * Sequenced Data packets that it receives to know what their * sequence numbers are. * * So, we grab the next sequence number from the Login Acceptance * packet, and save it in a conversation_t we associate with the * TCP session. Then, for each Sequenced Data packet we receive, * the first time it's processed (when PINFO_FD_VISITED() is * false), we write it into the PDU's frame's private data pointer * and increment the saved sequence number (in the conversation_t). * * If the visited flag is true, then we've dissected this packet * already, and so we can fetch the sequence number from the * frame's private data area. * * In either case, if there's any problem, we report zero as the * sequence number, and try to continue dissecting. */ /* If first dissection of Login Accept, save sequence number */ if (pkt_type == 'A' && !PINFO_FD_VISITED(pinfo)) { tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, 13, 20, ENC_ASCII); next_seq = atoi(tmp_buf); /* Create new conversation for this session */ conv = conversation_new(PINFO_FD_NUM(pinfo), &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); /* Store starting sequence number for session's packets */ conv_data = (struct conv_data *)wmem_alloc(wmem_file_scope(), sizeof(struct conv_data)); conv_data->next_seq = next_seq; conversation_add_proto_data(conv, proto_soupbintcp, conv_data); } /* Handle sequence numbering for a Sequenced Data packet */ if (pkt_type == 'S') { if (!PINFO_FD_VISITED(pinfo)) { /* Get next expected sequence number from conversation */ conv = find_conversation(PINFO_FD_NUM(pinfo), &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (!conv) { this_seq = 0; } else { conv_data = (struct conv_data *)conversation_get_proto_data(conv, proto_soupbintcp); if (conv_data) { this_seq = conv_data->next_seq++; } else { this_seq = 0; } pdu_data = (struct pdu_data *)wmem_alloc( wmem_file_scope(), sizeof(struct pdu_data)); pdu_data->seq_num = this_seq; p_add_proto_data(wmem_file_scope(), pinfo, proto_soupbintcp, 0, pdu_data); } } else { pdu_data = (struct pdu_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_soupbintcp, 0); if (pdu_data) { this_seq = pdu_data->seq_num; } else { this_seq = 0; } } col_append_fstr(pinfo->cinfo, COL_INFO, ", SeqNum = %u", this_seq); } if (tree) { /* Create sub-tree for SoupBinTCP details */ ti = proto_tree_add_item(tree, proto_soupbintcp, tvb, 0, -1, ENC_NA); soupbintcp_tree = proto_item_add_subtree(ti, ett_soupbintcp); /* Append the packet name to the sub-tree item */ proto_item_append_text(ti, ", %s", pkt_name); /* Length */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_packet_length, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Type */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN); offset += 1; switch (pkt_type) { case '+': /* Debug Message */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_text, tvb, offset, expected_len - 1, ENC_ASCII|ENC_NA); break; case 'A': /* Login Accept */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_session, tvb, offset, 10, ENC_ASCII|ENC_NA); offset += 10; tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 20, ENC_ASCII); proto_tree_add_string_format_value(soupbintcp_tree, hf_soupbintcp_next_seq_num, tvb, offset, 20, "X", "%d", atoi(tmp_buf)); break; case 'J': /* Login Reject */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_reject_code, tvb, offset, 1, ENC_BIG_ENDIAN); break; case 'U': /* Unsequenced Data */ /* Display handled by sub-dissector */ break; case 'S': /* Sequenced Data */ proto_item_append_text(ti, ", SeqNum=%u", this_seq); proto_tree_add_string_format_value(soupbintcp_tree, hf_soupbintcp_seq_num, tvb, offset, 0, "X", "%u (Calculated)", this_seq); /* Display handled by sub-dissector */ break; case 'L': /* Login Request */ proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_username, tvb, offset, 6, ENC_ASCII|ENC_NA); offset += 6; proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_password, tvb, offset, 10, ENC_ASCII|ENC_NA); offset += 10; proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_session, tvb, offset, 10, ENC_ASCII|ENC_NA); offset += 10; tmp_buf = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, 20, ENC_ASCII); proto_tree_add_string_format_value(soupbintcp_tree, hf_soupbintcp_req_seq_num, tvb, offset, 20, "X", "%d", atoi(tmp_buf)); break; case 'H': /* Server Heartbeat */ break; case 'O': /* Logout Request */ break; case 'R': /* Client Heartbeat */ break; case 'Z': /* End of Session */ break; default: /* Unknown */ proto_tree_add_item(tree, hf_soupbintcp_message, tvb, offset, -1, ENC_NA); break; } } /* Call sub-dissector for encapsulated data */ if (pkt_type == 'S' || pkt_type == 'U') { tvbuff_t *sub_tvb; /* Sub-dissector tvb starts at 3 (length (2) + pkt_type (1)) */ sub_tvb = tvb_new_subset_remaining(tvb, 3); #if 0 /* XXX: It's not valid for a soupbintcp subdissector to call */ /* conversation_set_dissector() since the conversation is really */ /* a TCP conversation. (A 'soupbintcp' port type would need to */ /* be defined to be able to use conversation_set_dissector()). */ /* In addition, no current soupbintcp subdissector calls */ /* conversation_set_dissector(). */ /* If this packet is part of a conversation, call dissector * for the conversation if available */ if (try_conversation_dissector(&pinfo->dst, &pinfo->src, pinfo->ptype, pinfo->srcport, pinfo->destport, sub_tvb, pinfo, tree, NULL)) { return; } #endif /* Otherwise, try heuristic dissectors */ if (dissector_try_heuristic(heur_subdissector_list, sub_tvb, pinfo, tree, &hdtbl_entry, NULL)) { return; } /* Otherwise, give up, and just print the bytes in hex */ if (tree) { proto_tree_add_item(soupbintcp_tree, hf_soupbintcp_message, sub_tvb, 0, -1, ENC_NA); } } }
static void dissect_xyplex(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *xyplex_tree = NULL; proto_item *ti; conversation_t *conversation; gint offset = 0; guint8 prototype; guint8 padding; guint16 server_port; guint16 return_port; guint16 reserved; guint16 reply; col_set_str(pinfo->cinfo, COL_PROTOCOL, "XYPLEX"); if (tree) { ti = proto_tree_add_item(tree, proto_xyplex, tvb, offset, -1, FALSE); xyplex_tree = proto_item_add_subtree(ti, ett_xyplex); } if (pinfo->destport == UDP_PORT_XYPLEX) { /* This is a registration request from a Unix server * to the Xyplex server. The server_port indicates * which Xyplex serial port is desired. The * return_port tells the Xyplex server what TCP port * to open to the Unix server. */ prototype = tvb_get_guint8(tvb, offset); padding = tvb_get_guint8(tvb, offset+1); server_port = tvb_get_ntohs(tvb, offset+2); return_port = tvb_get_ntohs(tvb, offset+4); reserved = tvb_get_ntohs(tvb, offset+6); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "Registration Request: %d Return: %d", server_port, return_port); } if (tree) { proto_tree_add_uint(xyplex_tree, hf_xyplex_type, tvb, offset, 1, prototype); proto_tree_add_uint(xyplex_tree, hf_xyplex_pad, tvb, offset+1, 1, padding); proto_tree_add_uint(xyplex_tree, hf_xyplex_server_port, tvb, offset+2, 2, server_port); proto_tree_add_uint(xyplex_tree, hf_xyplex_return_port, tvb, offset+4, 2, return_port); proto_tree_add_uint(xyplex_tree, hf_xyplex_reserved, tvb, offset+6, 2, reserved); } offset += 8; /* Look for all future TCP conversations between the * requestiong server and the Xyplex host using the * return_port. */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, return_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, return_port, 0, NO_PORT2); conversation_set_dissector(conversation, xyplex_handle); } return; } if (pinfo->srcport == UDP_PORT_XYPLEX) { prototype = tvb_get_guint8(tvb, offset); padding = tvb_get_guint8(tvb, offset+1); reply = tvb_get_ntohs(tvb, offset+2); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "Registration Reply: %s", val_to_str(reply, xyplex_reg_vals, "Unknown (0x%02x)")); } if (tree) { proto_tree_add_uint(xyplex_tree, hf_xyplex_type, tvb, offset, 1, prototype); proto_tree_add_uint(xyplex_tree, hf_xyplex_pad, tvb, offset+1, 1, padding); proto_tree_add_uint(xyplex_tree, hf_xyplex_reply, tvb, offset+2, 2, reply); } offset += 4; return; } /* * This must be the TCP data stream. This will just be * the raw data being transfered from the remote server * and the Xyplex serial port. */ if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d Data", pinfo->srcport, pinfo->destport); } if (tree) { proto_tree_add_text(xyplex_tree, tvb, offset, -1, "Data (%d bytes)", tvb_reported_length_remaining(tvb, offset)); } }
/* * Function for the PANA PDU dissector. */ static void dissect_pana_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *pana_tree=NULL; proto_tree *avp_tree=NULL; proto_item *ti=NULL; proto_item *avp_item=NULL; tvbuff_t *avp_tvb; guint16 flags = 0; guint16 msg_type; gint16 msg_length; gint16 avp_length; guint32 session_id; guint32 seq_num; conversation_t *conversation; pana_conv_info_t *pana_info; pana_transaction_t *pana_trans; int offset = 0; /* Get message length, type and flags */ msg_length = tvb_get_ntohs(tvb, 2); flags = tvb_get_ntohs(tvb, 4); msg_type = tvb_get_ntohs(tvb, 6); session_id = tvb_get_ntohl(tvb, 8); seq_num = tvb_get_ntohl(tvb, 12); avp_length = msg_length-16; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "PANA"); if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_add_fstr(pinfo->cinfo, COL_INFO, "Type %s-%s", val_to_str(msg_type, msg_type_names, "Unknown (%d)"), val_to_str(flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)")); } /* Make the protocol tree */ if (tree) { ti = proto_tree_add_item(tree, proto_pana, tvb, 0, -1, FALSE); pana_tree = proto_item_add_subtree(ti, ett_pana); } /* * We need to track some state for this protocol on a per conversation * basis so we can do neat things like request/response tracking */ /* * Do we have a conversation for this connection? */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation == NULL) { /* We don't yet have a conversation, so create one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } /* * Do we already have a state structure for this conv */ pana_info = conversation_get_proto_data(conversation, proto_pana); if (!pana_info) { /* No. Attach that information to the conversation, and add * it to the list of information structures. */ pana_info = se_alloc(sizeof(pana_conv_info_t)); pana_info->pdus=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "pana_pdus"); conversation_add_proto_data(conversation, proto_pana, pana_info); } if(!pinfo->fd->flags.visited){ if(flags&PANA_FLAG_R){ /* This is a request */ pana_trans=se_alloc(sizeof(pana_transaction_t)); pana_trans->req_frame=pinfo->fd->num; pana_trans->rep_frame=0; pana_trans->req_time=pinfo->fd->abs_ts; se_tree_insert32(pana_info->pdus, seq_num, (void *)pana_trans); } else { pana_trans=se_tree_lookup32(pana_info->pdus, seq_num); if(pana_trans){ pana_trans->rep_frame=pinfo->fd->num; } } } else { pana_trans=se_tree_lookup32(pana_info->pdus, seq_num); } if(!pana_trans){ /* create a "fake" pana_trans structure */ pana_trans=ep_alloc(sizeof(pana_transaction_t)); pana_trans->req_frame=0; pana_trans->rep_frame=0; pana_trans->req_time=pinfo->fd->abs_ts; } /* print state tracking in the tree */ if(flags&PANA_FLAG_R){ /* This is a request */ if(pana_trans->rep_frame){ proto_item *it; it=proto_tree_add_uint(pana_tree, hf_pana_response_in, tvb, 0, 0, pana_trans->rep_frame); PROTO_ITEM_SET_GENERATED(it); } } else { /* This is a reply */ if(pana_trans->req_frame){ proto_item *it; nstime_t ns; it=proto_tree_add_uint(pana_tree, hf_pana_response_to, tvb, 0, 0, pana_trans->req_frame); PROTO_ITEM_SET_GENERATED(it); nstime_delta(&ns, &pinfo->fd->abs_ts, &pana_trans->req_time); it=proto_tree_add_time(pana_tree, hf_pana_time, tvb, 0, 0, &ns); PROTO_ITEM_SET_GENERATED(it); } } /* Reserved field */ proto_tree_add_item(pana_tree, hf_pana_reserved_type, tvb, offset, 2, FALSE); offset += 2; /* Length */ proto_tree_add_item(pana_tree, hf_pana_length_type, tvb, offset, 2, FALSE); offset += 2; /* Flags */ dissect_pana_flags(pana_tree, tvb, offset, flags); offset += 2; /* Message Type */ proto_tree_add_uint_format_value(pana_tree, hf_pana_msg_type, tvb, offset, 2, msg_type, "%s-%s (%d)", val_to_str(msg_type, msg_type_names, "Unknown (%d)"), val_to_str(flags & PANA_FLAG_R, msg_subtype_names, "Unknown (%d)"), msg_type); offset += 2; /* Session ID */ proto_tree_add_item(pana_tree, hf_pana_session_id, tvb, offset, 4, FALSE); offset += 4; /* Sequence Number */ proto_tree_add_item(pana_tree, hf_pana_seqnumber, tvb, offset, 4, FALSE); offset += 4; /* AVPs */ if(avp_length>0){ avp_tvb = tvb_new_subset(tvb, offset, avp_length, avp_length); avp_item = proto_tree_add_text(pana_tree, tvb, offset, avp_length, "Attribute Value Pairs"); avp_tree = proto_item_add_subtree(avp_item, ett_pana_avp); if (avp_tree != NULL) { dissect_avps(avp_tvb, pinfo, avp_tree); } } }
static void dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request; proto_tree *ftp_tree = NULL; proto_tree *reqresp_tree = NULL; proto_item *ti, *hidden_item; gint offset = 0; const guchar *line; guint32 code; gchar code_str[4]; gboolean is_port_request = FALSE; gboolean is_pasv_response = FALSE; gboolean is_epasv_response = FALSE; gint next_offset; int linelen; int tokenlen; const guchar *next_token; guint32 pasv_ip; guint32 ftp_ip; guint16 ftp_port; address ftp_ip_address; gboolean ftp_nat; conversation_t *conversation; ftp_ip_address = pinfo->src; if (pinfo->match_uint == pinfo->destport) is_request = TRUE; else is_request = FALSE; col_set_str(pinfo->cinfo, COL_PROTOCOL, "FTP"); /* * Find the end of the first line. * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); /* * Put the first line from the buffer into the summary * (but leave out the line terminator). */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "Request" : "Response", format_text(line, linelen)); if (tree) { ti = proto_tree_add_item(tree, proto_ftp, tvb, offset, -1, ENC_NA); ftp_tree = proto_item_add_subtree(ti, ett_ftp); if (is_request) { hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); } else { hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); } /* * Put the line into the protocol tree. */ ti = proto_tree_add_text(ftp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); reqresp_tree = proto_item_add_subtree(ti, ett_ftp_reqresp); } if (is_request) { /* * Extract the first token, and, if there is a first * token, add it as the request. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { if (tree) { proto_tree_add_item(reqresp_tree, hf_ftp_request_command, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); } if (strncmp(line, "PORT", tokenlen) == 0) is_port_request = TRUE; } } else { /* * This is a response; the response code is 3 digits, * followed by a space or hyphen, possibly followed by * text. * * If the line doesn't start with 3 digits, it's part of * a continuation. * * XXX - keep track of state in the first pass, and * treat non-continuation lines not beginning with digits * as errors? */ if (linelen >= 3 && isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2])) { /* * One-line reply, or first or last line * of a multi-line reply. */ tvb_get_nstringz0(tvb, offset, sizeof(code_str), code_str); code = strtoul(code_str, NULL, 10); if (tree) { proto_tree_add_uint(reqresp_tree, hf_ftp_response_code, tvb, offset, 3, code); } /* * See if it's a passive-mode response. * * XXX - does anybody do FOOBAR, as per RFC * 1639, or has that been supplanted by RFC 2428? */ if (code == 227) is_pasv_response = TRUE; /* * Responses to EPSV command, as per RFC 2428 * XXX - handle IPv6? */ if (code == 229) is_epasv_response = TRUE; /* * Skip the 3 digits and, if present, the * space or hyphen. */ if (linelen >= 4) next_token = line + 4; else next_token = line + linelen; } else { /* * Line doesn't start with 3 digits; assume it's * a line in the middle of a multi-line reply. */ next_token = line; } } offset += (gint) (next_token - line); linelen -= (int) (next_token - line); line = next_token; if (tree) { /* * Add the rest of the first line as request or * reply data. */ if (linelen != 0) { if (is_request) { proto_tree_add_item(reqresp_tree, hf_ftp_request_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } else { proto_tree_add_item(reqresp_tree, hf_ftp_response_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } } offset = next_offset; } /* * If this is a PORT request or a PASV response, handle it. */ if (is_port_request) { if (parse_port_pasv(line, linelen, &ftp_ip, &ftp_port)) { if (tree) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_active_ip, tvb, 0, 0, ftp_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_active_port, tvb, 0, 0, ftp_port); } SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&ftp_ip); ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, &ftp_ip_address); if (ftp_nat) { if (tree) { proto_tree_add_boolean( reqresp_tree, hf_ftp_active_nat, tvb, 0, 0, ftp_nat); } } } } if (is_pasv_response) { if (linelen != 0) { /* * This frame contains a PASV response; set up a * conversation for the data. */ if (parse_port_pasv(line, linelen, &pasv_ip, &ftp_port)) { if (tree) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_pasv_ip, tvb, 0, 0, pasv_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, 0, 0, ftp_port); } SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&pasv_ip); ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, &ftp_ip_address); if (ftp_nat) { if (tree) { proto_tree_add_boolean(reqresp_tree, hf_ftp_pasv_nat, tvb, 0, 0, ftp_nat); } } /* * We use "ftp_ip_address", so that if * we're NAT'd we look for the un-NAT'd * connection. * * XXX - should this call to * "find_conversation()" just use * "ftp_ip_address" and "server_port", and * wildcard everything else? */ conversation = find_conversation(pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { /* * XXX - should this call to "conversation_new()" * just use "ftp_ip_address" and "server_port", * and wildcard everything else? * * XXX - what if we did find a conversation? As * we create it only on the first pass through the * packets, if we find one, it's presumably an * unrelated conversation. Should we remove the * old one from the hash table and put this one in * its place? Can the conversation code handle * conversations not in the hash table? Or should * we make conversations support start and end * frames, as circuits do, and treat this as an * indication that one conversation was closed and * a new one was opened? */ conversation = conversation_new( pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } } } if (is_epasv_response) { if (linelen != 0) { /* * This frame contains an EPSV response; set up a * conversation for the data. */ if (parse_extended_pasv_response(line, linelen, &ftp_port)) { /* Add port number to tree */ if (tree) { proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, 0, 0, ftp_port); } /* Find/create conversation for data */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new( pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } } } if (tree) { /* * Show the rest of the request or response as text, * a line at a time. * XXX - only if there's a continuation indicator? */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_text(ftp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } }
static void rtsp_create_conversation(packet_info *pinfo, const guchar *line_begin, size_t line_len, gint rdt_feature_level) { conversation_t *conv; guchar buf[256]; guchar *tmp; gboolean rtp_transport = FALSE; gboolean rdt_transport = FALSE; guint c_data_port, c_mon_port; guint s_data_port, s_mon_port; gboolean is_video = FALSE; /* FIX ME - need to indicate video or not */ /* Copy line into buf */ if (line_len > sizeof(buf) - 1) { /* Don't overflow the buffer. */ line_len = sizeof(buf) - 1; } memcpy(buf, line_begin, line_len); buf[line_len] = '\0'; /* Get past "Transport:" and spaces */ tmp = buf + STRLEN_CONST(rtsp_transport); while (*tmp && isspace(*tmp)) tmp++; /* Work out which transport type is here */ if (g_ascii_strncasecmp(tmp, rtsp_rtp, strlen(rtsp_rtp)) == 0) rtp_transport = TRUE; else if (g_ascii_strncasecmp(tmp, rtsp_real_rdt, strlen(rtsp_real_rdt)) == 0 || g_ascii_strncasecmp(tmp, rtsp_real_tng, strlen(rtsp_real_tng)) == 0) rdt_transport = TRUE; else { /* Give up on unknown transport types */ return; } c_data_port = c_mon_port = 0; s_data_port = s_mon_port = 0; /* Look for server port */ if ((tmp = strstr(buf, rtsp_sps))) { tmp += strlen(rtsp_sps); if (sscanf(tmp, "%u-%u", &s_data_port, &s_mon_port) < 1) { g_warning("Frame %u: rtsp: bad server_port", pinfo->fd->num); return; } } /* Look for client port */ if ((tmp = strstr(buf, rtsp_cps))) { tmp += strlen(rtsp_cps); if (sscanf(tmp, "%u-%u", &c_data_port, &c_mon_port) < 1) { g_warning("Frame %u: rtsp: bad client_port", pinfo->fd->num); return; } } /* Deal with RTSP TCP-interleaved conversations. */ if (!c_data_port) { rtsp_conversation_data_t *data; guint s_data_chan, s_mon_chan; int i; /* Search tranport line for interleaved string */ if ((tmp = strstr(buf, rtsp_inter)) == NULL) { /* * No interleaved or server_port - probably a * SETUP request, rather than reply. */ return; } /* Move tmp to beyone interleaved string */ tmp += strlen(rtsp_inter); /* Look for channel number(s) */ i = sscanf(tmp, "%u-%u", &s_data_chan, &s_mon_chan); if (i < 1) { g_warning("Frame %u: rtsp: bad interleaved", pinfo->fd->num); return; } /* At least data channel present, look for conversation (presumably TCP) */ conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); /* Create new conversation if necessary */ if (!conv) { conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } /* Look for previous data */ data = conversation_get_proto_data(conv, proto_rtsp); /* Create new data if necessary */ if (!data) { data = se_alloc(sizeof(rtsp_conversation_data_t)); conversation_add_proto_data(conv, proto_rtsp, data); } /* Now set the dissector handle of the interleaved channel according to the transport protocol used */ if (rtp_transport) { if (s_data_chan < RTSP_MAX_INTERLEAVED) { data->interleaved[s_data_chan].dissector = rtp_handle; } if (i > 1 && s_mon_chan < RTSP_MAX_INTERLEAVED) { data->interleaved[s_mon_chan].dissector = rtcp_handle; } } else if (rdt_transport) { if (s_data_chan < RTSP_MAX_INTERLEAVED) { data->interleaved[s_data_chan].dissector = rdt_handle; } } return; } /* * We only want to match on the destination address, not the * source address, because the server might send back a packet * from an address other than the address to which its client * sent the packet, so we construct a conversation with no * second address. */ if (rtp_transport) { /* There is always data for RTP */ rtp_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port, "RTSP", pinfo->fd->num, is_video, NULL); /* RTCP only if indicated */ if (c_mon_port) { rtcp_add_address(pinfo, &pinfo->dst, c_mon_port, s_mon_port, "RTSP", pinfo->fd->num); } } else if (rdt_transport) { /* Real Data Transport */ rdt_add_address(pinfo, &pinfo->dst, c_data_port, s_data_port, "RTSP", rdt_feature_level); } }
/* initialize the tap t38_info and the conversation */ static void init_t38_info_conv(packet_info *pinfo) { /* tap info */ t38_info_current++; if (t38_info_current==MAX_T38_MESSAGES_IN_PACKET) { t38_info_current=0; } t38_info = &t38_info_arr[t38_info_current]; t38_info->seq_num = 0; t38_info->type_msg = 0; t38_info->data_value = 0; t38_info->t30ind_value =0; t38_info->setup_frame_number = 0; t38_info->Data_Field_field_type_value = 0; t38_info->desc[0] = '\0'; t38_info->desc_comment[0] = '\0'; t38_info->time_first_t4_data = 0; t38_info->frame_num_first_t4_data = 0; /* p_t38_packet_conv hold the conversation info in each of the packets. p_t38_conv hold the conversation info used to reassemble the HDLC packets, and also the Setup info (e.g SDP) If we already have p_t38_packet_conv in the packet, it means we already reassembled the HDLC packets, so we don't need to use p_t38_conv */ p_t38_packet_conv = NULL; p_t38_conv = NULL; /* Use existing packet info if available */ p_t38_packet_conv = (t38_conv *)p_get_proto_data(wmem_file_scope(), pinfo, proto_t38, 0); /* find the conversation used for Reassemble and Setup Info */ p_conv = find_conversation(pinfo->fd->num, &pinfo->net_dst, &pinfo->net_src, pinfo->ptype, pinfo->destport, pinfo->srcport, NO_ADDR_B | NO_PORT_B); /* create a conv if it doen't exist */ if (!p_conv) { p_conv = conversation_new(pinfo->fd->num, &pinfo->net_src, &pinfo->net_dst, pinfo->ptype, pinfo->srcport, pinfo->destport, NO_ADDR_B | NO_PORT_B); /* Set dissector */ conversation_set_dissector(p_conv, t38_udp_handle); } if (!p_t38_packet_conv) { p_t38_conv = (t38_conv *)conversation_get_proto_data(p_conv, proto_t38); /* create the conversation if it doen't exist */ if (!p_t38_conv) { p_t38_conv = wmem_new(wmem_file_scope(), t38_conv); p_t38_conv->setup_method[0] = '\0'; p_t38_conv->setup_frame_number = 0; p_t38_conv->src_t38_info.reass_ID = 0; p_t38_conv->src_t38_info.reass_start_seqnum = -1; p_t38_conv->src_t38_info.reass_data_type = 0; p_t38_conv->src_t38_info.last_seqnum = -1; p_t38_conv->src_t38_info.packet_lost = 0; p_t38_conv->src_t38_info.burst_lost = 0; p_t38_conv->src_t38_info.time_first_t4_data = 0; p_t38_conv->src_t38_info.additional_hdlc_data_field_counter = 0; p_t38_conv->src_t38_info.seqnum_prev_data_field = -1; p_t38_conv->dst_t38_info.reass_ID = 0; p_t38_conv->dst_t38_info.reass_start_seqnum = -1; p_t38_conv->dst_t38_info.reass_data_type = 0; p_t38_conv->dst_t38_info.last_seqnum = -1; p_t38_conv->dst_t38_info.packet_lost = 0; p_t38_conv->dst_t38_info.burst_lost = 0; p_t38_conv->dst_t38_info.time_first_t4_data = 0; p_t38_conv->dst_t38_info.additional_hdlc_data_field_counter = 0; p_t38_conv->dst_t38_info.seqnum_prev_data_field = -1; conversation_add_proto_data(p_conv, proto_t38, p_t38_conv); } /* copy the t38 conversation info to the packet t38 conversation */ p_t38_packet_conv = wmem_new(wmem_file_scope(), t38_conv); g_strlcpy(p_t38_packet_conv->setup_method, p_t38_conv->setup_method, MAX_T38_SETUP_METHOD_SIZE); p_t38_packet_conv->setup_frame_number = p_t38_conv->setup_frame_number; memcpy(&(p_t38_packet_conv->src_t38_info), &(p_t38_conv->src_t38_info), sizeof(t38_conv_info)); memcpy(&(p_t38_packet_conv->dst_t38_info), &(p_t38_conv->dst_t38_info), sizeof(t38_conv_info)); p_add_proto_data(wmem_file_scope(), pinfo, proto_t38, 0, p_t38_packet_conv); } if (ADDRESSES_EQUAL(&p_conv->key_ptr->addr1, &pinfo->net_src)) { p_t38_conv_info = &(p_t38_conv->src_t38_info); p_t38_packet_conv_info = &(p_t38_packet_conv->src_t38_info); } else { p_t38_conv_info = &(p_t38_conv->dst_t38_info); p_t38_packet_conv_info = &(p_t38_packet_conv->dst_t38_info); } /* update t38_info */ t38_info->setup_frame_number = p_t38_packet_conv->setup_frame_number; }
/* main dissector function. wireshark calls it for segments in both * directions. */ static void dissect_ajp13_tcp_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 mag; guint16 len; conversation_t *conv = NULL; ajp13_conv_data *cd = NULL; proto_tree *ajp13_tree = NULL; ajp13_frame_data* fd = NULL; /* conversational state really only does us good during the first * in-order traversal */ conv = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (!conv) { conv = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } cd = (ajp13_conv_data*)conversation_get_proto_data(conv, proto_ajp13); if (!cd) { cd = se_alloc(sizeof(ajp13_conv_data)); cd->content_length = 0; cd->was_get_body_chunk = FALSE; conversation_add_proto_data(conv, proto_ajp13, cd); } /* we use the per segment user data to record the conversational * state for use later on when we're called out of order (see * comments at top of this file) */ fd = (ajp13_frame_data*)p_get_proto_data(pinfo->fd, proto_ajp13); if (!fd) { /*printf("ajp13:dissect_ajp13_common():no frame data, adding");*/ /* since there's no per-packet user data, this must be the first * time we've see the packet, and it must be the first "in order" * pass through the data. */ fd = se_alloc(sizeof(ajp13_frame_data)); p_add_proto_data(pinfo->fd, proto_ajp13, fd); fd->is_request_body = FALSE; if (cd->content_length) { /* this is screwy, see AJPv13.html. the idea is that if the * request has a body (as determined by the content-length * header), then there's always an immediate follow-up PDU with * no GET_BODY_CHUNK from the container. */ fd->is_request_body = TRUE; } } col_clear(pinfo->cinfo, COL_INFO); mag = tvb_get_ntohs(tvb, 0); len = tvb_get_ntohs(tvb, 2); col_set_str(pinfo->cinfo, COL_PROTOCOL, "AJP13"); if (check_col(pinfo->cinfo, COL_INFO)) { if (mag == 0x1234 && !fd->is_request_body) col_append_fstr(pinfo->cinfo, COL_INFO, "%d:REQ:", conv->index); else if (mag == 0x1234 && fd->is_request_body) col_append_fstr(pinfo->cinfo, COL_INFO, "%d:REQ:Body", conv->index); else if (mag == 0x4142) col_append_fstr(pinfo->cinfo, COL_INFO, "%d:RSP:", conv->index); else col_set_str(pinfo->cinfo, COL_INFO, "AJP13 Error?"); } if (tree) { proto_item *ti; ti = proto_tree_add_item(tree, proto_ajp13, tvb, 0, tvb_length(tvb), FALSE); ajp13_tree = proto_item_add_subtree(ti, ett_ajp13); } if (mag == 0x1234) { if (fd->is_request_body) display_req_body(tvb, ajp13_tree, cd); else display_req_forward(tvb, pinfo, ajp13_tree, cd); } else if (mag == 0x4142) { display_rsp(tvb, pinfo, ajp13_tree, cd); } }