static void dissect_gwtb_request(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gwtb_entry_t *data_ptr = dissect_gwtb_get_data(pinfo); gwtb_info_t *info_ptr = (gwtb_info_t*) p_get_proto_data(pinfo->fd, proto_gwtb, 0); proto_item *gwtb_item = NULL; proto_tree *gwtb_tree = NULL; guint32 offset = 0; guint32 i; if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_GWTB); if (tvb_get_guint8(tvb, 0) == 1 && tvb_get_guint8(tvb, 2) == 1 && tvb_get_guint8(tvb, 15) == 105) { if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "Authentication Request"); if (tree) { /* we are being asked for details */ gwtb_item = proto_tree_add_item(tree, proto_gwtb, tvb, 0, -1, FALSE); gwtb_tree = proto_item_add_subtree(gwtb_item, ett_gwtb); proto_tree_add_item(gwtb_tree, hf_greeting, tvb, offset, 16, FALSE); proto_tree_add_item(gwtb_tree, hf_authkey, tvb, offset+16, 16, FALSE); proto_tree_add_item(gwtb_tree, hf_authkey, tvb, offset+32, 16, FALSE); } if (data_ptr && data_ptr->request_rc4 == NULL) { data_ptr->greeting = (gwtb_key_t *)tvb_get_ptr(tvb, offset, sizeof(gwtb_key_t)); offset += sizeof(gwtb_key_t); data_ptr->request_key[0] = (gwtb_key_t *)tvb_get_ptr(tvb, offset, sizeof(gwtb_key_t)); offset += sizeof(gwtb_key_t); data_ptr->request_key[1] = (gwtb_key_t *)tvb_get_ptr(tvb, offset, sizeof(gwtb_key_t)); offset += sizeof(gwtb_key_t); for (i = 0; i < sizeof(gwtb_key_t); i++) { data_ptr->request_key[1]->chars[i] ^= data_ptr->request_key[0]->chars[i]; } info_ptr->auth = TRUE; data_ptr->request_rc4 = (rc4_state_struct*)se_alloc(sizeof(rc4_state_struct)); crypt_rc4_init(data_ptr->request_rc4, data_ptr->request_key[1]->chars, sizeof(gwtb_key_t)); } } else { if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "Unknown Data Transmission"); if (tree) { /* we are being asked for details */ gwtb_item = proto_tree_add_item(tree, proto_gwtb, tvb, 0, -1, FALSE); gwtb_tree = proto_item_add_subtree(gwtb_item, ett_gwtb); } } }
/* Main dissection function. */ static void dissect_mac_lte_framed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; struct mac_lte_info *p_mac_lte_info; tvbuff_t *mac_tvb; gboolean infoAlreadySet = FALSE; /* Need to find enabled mac-lte dissector */ dissector_handle_t mac_lte_handle = find_dissector("mac-lte"); if (!mac_lte_handle) { return; } /* Do this again on re-dissection to re-discover offset of actual PDU */ /* Needs to be at least as long as: - fixed header bytes - tag for data - at least one byte of MAC PDU payload */ if ((size_t)tvb_length_remaining(tvb, offset) < (3+2)) { return; } /* If redissecting, use previous info struct (if available) */ p_mac_lte_info = (struct mac_lte_info*)p_get_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0); if (p_mac_lte_info == NULL) { /* Allocate new info struct for this frame */ p_mac_lte_info = (struct mac_lte_info*)wmem_alloc0(wmem_file_scope(), sizeof(struct mac_lte_info)); infoAlreadySet = FALSE; } else { infoAlreadySet = TRUE; } /* Dissect the fields to populate p_mac_lte */ if (!dissect_mac_lte_context_fields(p_mac_lte_info, tvb, &offset)) { return; } /* Store info in packet (first time) */ if (!infoAlreadySet) { p_add_proto_data(wmem_file_scope(), pinfo, proto_mac_lte, 0, p_mac_lte_info); } /**************************************/ /* OK, now dissect as MAC LTE */ /* Create tvb that starts at actual MAC PDU */ mac_tvb = tvb_new_subset_remaining(tvb, offset); call_dissector_only(mac_lte_handle, mac_tvb, pinfo, tree, NULL); }
static void dissect_gwtb_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gwtb_info_t *info_ptr = (gwtb_info_t*) p_get_proto_data(pinfo->fd, proto_gwtb, 0); tvbuff_t *next_tvb; proto_item *gwtb_item = NULL; proto_tree *gwtb_tree = NULL; guint32 offset = 0; guint32 length = tvb_length(tvb); guint16 size; if (!info_ptr->data) { info_ptr->auth = FALSE; info_ptr->data = (guchar*) se_alloc(length); tvb_memcpy(tvb, info_ptr->data, offset, length); crypt_rc4(info_ptr->rc4, info_ptr->data, length); } next_tvb = tvb_new_real_data(info_ptr->data, length, length); tvb_set_child_real_data_tvbuff(tvb, next_tvb); add_new_data_source(pinfo, next_tvb, "Data"); length = tvb_length(next_tvb); if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_GWTB); if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d - %s", pinfo->srcport, pinfo->destport, (pinfo->match_port == pinfo->destport || TCP_PORT_GWTB == pinfo->destport) ? "Request" : "Response" ); } if (tree) { /* we are being asked for details */ while(offset < length) { gwtb_item = proto_tree_add_item(tree, proto_gwtb, next_tvb, offset, length-offset, FALSE); gwtb_tree = proto_item_add_subtree(gwtb_item, ett_gwtb); size = tvb_get_ntohs(next_tvb, offset); proto_tree_add_item(gwtb_tree, hf_length, next_tvb, offset, FRAME_HEADER_LEN, FALSE); offset += FRAME_HEADER_LEN; proto_tree_add_item(gwtb_tree, hf_string, next_tvb, offset, size, FALSE); offset += size; } } }
static void dissect_rrc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* FIX ME Currently don't know the 'starting point' of this protocol * exported DL-DCCH-Message is the entry point. */ proto_item *rrc_item = NULL; proto_tree *rrc_tree = NULL; struct rrc_info *rrcinf; top_tree = tree; rrcinf = (struct rrc_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rrc, 0); /* make entry in the Protocol column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RRC"); /*Clear memory*/ memset(num_chans_per_flow,0,sizeof(guint8)*RRC_MAX_NUM_HSDHSCH_MACDFLOW); /* create the rrc protocol tree */ rrc_item = proto_tree_add_item(tree, proto_rrc, tvb, 0, -1, ENC_NA); rrc_tree = proto_item_add_subtree(rrc_item, ett_rrc); if (rrcinf) { switch (rrcinf->msgtype[pinfo->fd->subnum]) { case RRC_MESSAGE_TYPE_PCCH: call_dissector(rrc_pcch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_UL_CCCH: call_dissector(rrc_ul_ccch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_DL_CCCH: call_dissector(rrc_dl_ccch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_UL_DCCH: call_dissector(rrc_ul_dcch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_DL_DCCH: call_dissector(rrc_dl_dcch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_BCCH_FACH: call_dissector(rrc_bcch_fach_handle, tvb, pinfo, rrc_tree); break; default: ; } } }
static guint dissect_norm_hdrext(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, guint offset, guint8 hlen) { lct_data_exchange_t data_exchange; norm_packet_data_t *packet_data = (norm_packet_data_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_rmt_norm, 0); memset(&data_exchange, 0, sizeof(data_exchange)); if (packet_data != NULL) data_exchange.codepoint = packet_data->encoding_id; offset += lct_ext_decode(tree, tvb, pinfo, offset, hdrlen2bytes(hlen), &data_exchange, hf_extension, ett_hdrext); return offset; }
static void dissect_rrc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* FIX ME Currently don't know the 'starting point' of this protocol * exported DL-DCCH-Message is the entry point. */ proto_item *rrc_item = NULL; proto_tree *rrc_tree = NULL; struct rrc_info *rrcinf; top_tree = tree; rrcinf = p_get_proto_data(pinfo->fd, proto_rrc); /* make entry in the Protocol column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "RRC"); /* create the rrc protocol tree */ rrc_item = proto_tree_add_item(tree, proto_rrc, tvb, 0, -1, ENC_NA); rrc_tree = proto_item_add_subtree(rrc_item, ett_rrc); if (rrcinf) { switch (rrcinf->msgtype[pinfo->fd->subnum]) { case RRC_MESSAGE_TYPE_PCCH: call_dissector(rrc_pcch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_UL_CCCH: call_dissector(rrc_ul_ccch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_DL_CCCH: call_dissector(rrc_dl_ccch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_UL_DCCH: call_dissector(rrc_ul_dcch_handle, tvb, pinfo, rrc_tree); break; case RRC_MESSAGE_TYPE_DL_DCCH: call_dissector(rrc_dl_dcch_handle, tvb, pinfo, rrc_tree); break; default: ; } } }
static guint get_gwtb_message_len(packet_info *pinfo, tvbuff_t *tvb, int offset) { gwtb_info_t *info_ptr = (gwtb_info_t*) p_get_proto_data(pinfo->fd, proto_gwtb, 0); rc4_state_struct rc4 = *info_ptr->rc4; guint32 length = tvb_length(tvb); guchar *data; guint len; if (!info_ptr->length) { data = (guchar*) ep_alloc(length); if (data) { tvb_memcpy(tvb, data, offset, length); crypt_rc4(&rc4, data, length); while (info_ptr->length < length) { len = ((guint) pntohs((guint16*) (data+offset)))+FRAME_HEADER_LEN; offset += len; info_ptr->length += len; } } } return info_ptr->length; }
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; } } }
/* 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_or_create_conversation(pinfo); cd = (ajp13_conv_data*)conversation_get_proto_data(conv, proto_ajp13); if (!cd) { cd = se_new(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_new(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 (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, -1, ENC_NA); 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); } }
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; } }
void decode_udp_ports(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int uh_sport, int uh_dport, int uh_ulen) { tvbuff_t *next_tvb; int low_port, high_port; gint len, reported_len; udp_p_info_t *udp_p_info = NULL; /* Save curr_layer_num as it might be changed by subdissector */ guint8 curr_layer_num = pinfo->curr_layer_num; heur_dtbl_entry_t *hdtbl_entry; len = tvb_captured_length_remaining(tvb, offset); reported_len = tvb_reported_length_remaining(tvb, offset); if (uh_ulen != -1) { /* This is the length from the UDP header; the payload should be cut off at that length. (If our caller passed a value here, they are assumed to have checked that it's >= 8, and hence >= offset.) XXX - what if it's *greater* than the reported length? */ if ((uh_ulen - offset) < reported_len) reported_len = uh_ulen - offset; if (len > reported_len) len = reported_len; } next_tvb = tvb_new_subset(tvb, offset, len, reported_len); /* If the user has a "Follow UDP Stream" window loading, pass a pointer * to the payload tvb through the tap system. */ if (have_tap_listener(udp_follow_tap)) tap_queue_packet(udp_follow_tap, pinfo, next_tvb); if (pinfo->fd->flags.visited) { udp_p_info = (udp_p_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, hfi_udp->id, pinfo->curr_layer_num); if (udp_p_info) { call_heur_dissector_direct(udp_p_info->heur_dtbl_entry, next_tvb, pinfo, tree, NULL); return; } } /* determine if this packet is part of a conversation and call dissector */ /* for the conversation if available */ if (try_conversation_dissector(&pinfo->dst, &pinfo->src, PT_UDP, uh_dport, uh_sport, next_tvb, pinfo, tree, NULL)) { return; } if (try_heuristic_first) { /* Do lookup with the heuristic subdissector table */ if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { if (!udp_p_info) { udp_p_info = wmem_new0(wmem_file_scope(), udp_p_info_t); udp_p_info->heur_dtbl_entry = hdtbl_entry; p_add_proto_data(wmem_file_scope(), pinfo, hfi_udp->id, curr_layer_num, udp_p_info); } return; } } /* Do lookups with the subdissector table. We try the port number with the lower value first, followed by the port number with the higher value. This means that, for packets where a dissector is registered for *both* port numbers: 1) we pick the same dissector for traffic going in both directions; 2) we prefer the port number that's more likely to be the right one (as that prefers well-known ports to reserved ports); although there is, of course, no guarantee that any such strategy will always pick the right port number. XXX - we ignore port numbers of 0, as some dissectors use a port number of 0 to disable the port, and as RFC 768 says that the source port in UDP datagrams is optional and is 0 if not used. */ if (uh_sport > uh_dport) { low_port = uh_dport; high_port = uh_sport; } else { low_port = uh_sport; high_port = uh_dport; } if ((low_port != 0) && dissector_try_uint(udp_dissector_table, low_port, next_tvb, pinfo, tree)) return; if ((high_port != 0) && dissector_try_uint(udp_dissector_table, high_port, next_tvb, pinfo, tree)) return; if (!try_heuristic_first) { /* Do lookup with the heuristic subdissector table */ if (dissector_try_heuristic(heur_subdissector_list, next_tvb, pinfo, tree, &hdtbl_entry, NULL)) { if (!udp_p_info) { udp_p_info = wmem_new0(wmem_file_scope(), udp_p_info_t); udp_p_info->heur_dtbl_entry = hdtbl_entry; p_add_proto_data(wmem_file_scope(), pinfo, hfi_udp->id, curr_layer_num, udp_p_info); } return; } } call_dissector(data_handle,next_tvb, pinfo, tree); }
/* 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; }
static gpointer eth_value(packet_info *pinfo) { return p_get_proto_data(pinfo->pool, pinfo, proto_ethertype, 0); }
/* * Dissect an SPDU. */ static int dissect_spdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean tokens, gboolean connectionless) { gboolean has_user_information = FALSE; guint8 type; proto_item *ti = NULL; proto_tree *ses_tree = NULL; int len_len; guint16 parameters_len; tvbuff_t *next_tvb = NULL; guint32 *pres_ctx_id = NULL; guint8 enclosure_item_flags = BEGINNING_SPDU|END_SPDU; struct SESSION_DATA_STRUCTURE session; /* * Get SPDU type. */ type = tvb_get_guint8(tvb, offset); session.spdu_type = type; session.abort_type = SESSION_NO_ABORT; session.pres_ctx_id = 0; session.ros_op = 0; session.rtse_reassemble = FALSE; if(connectionless) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_clses, tvb, offset, -1, ENC_NA); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } has_user_information = TRUE; } else if (tokens) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_category0_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, ENC_NA); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type_0, tvb, offset, 1, type); } } else { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, ses_vals, "Unknown SPDU type (0x%02x)")); if (tree) { ti = proto_tree_add_item(tree, proto_ses, tvb, offset, -1, ENC_NA); ses_tree = proto_item_add_subtree(ti, ett_ses); proto_tree_add_uint(ses_tree, hf_ses_type, tvb, offset, 1, type); } /* * Might this SPDU have a User Information field? */ switch (type) { case SES_DATA_TRANSFER: case SES_EXPEDITED: case SES_TYPED_DATA: has_user_information = TRUE; break; case SES_MAJOR_SYNC_POINT: pres_ctx_id = (guint32 *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ses, 0); if (ses_rtse_reassemble != 0 && !pres_ctx_id) { /* First time visited - save pres_ctx_id */ pres_ctx_id = wmem_new(wmem_file_scope(), guint32); *pres_ctx_id = ses_pres_ctx_id; p_add_proto_data(wmem_file_scope(), pinfo, proto_ses, 0, pres_ctx_id); } if (pres_ctx_id) { session.pres_ctx_id = *pres_ctx_id; session.rtse_reassemble = TRUE; has_user_information = TRUE; } ses_rtse_reassemble = FALSE; break; } } offset++; /* get length of SPDU parameter field */ parameters_len = get_item_len(tvb, offset, &len_len); if (tree) proto_tree_add_uint(ses_tree, hf_ses_length, tvb, offset, len_len, parameters_len); offset += len_len; /* Dissect parameters. */ if (!dissect_parameters(tvb, offset, parameters_len, tree, ses_tree, pinfo, &enclosure_item_flags, &session)) has_user_information = FALSE; offset += parameters_len; proto_item_set_end(ti, tvb, offset); /* Dissect user information, if present */ if (!ses_desegment || enclosure_item_flags == (BEGINNING_SPDU|END_SPDU)) { if (has_user_information) { /* Not desegment or only one segment */ if (tvb_reported_length_remaining(tvb, offset) > 0 || type == SES_MAJOR_SYNC_POINT) { next_tvb = tvb_new_subset_remaining(tvb, offset); } } } else { conversation_t *conversation = NULL; fragment_head *frag_msg = NULL; gint fragment_len; guint32 ses_id = 0; /* Use conversation index as segment id */ conversation = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (conversation != NULL) { ses_id = conversation->index; } fragment_len = tvb_reported_length_remaining (tvb, offset); ti = proto_tree_add_item (ses_tree, hf_ses_segment_data, tvb, offset, fragment_len, ENC_NA); proto_item_append_text (ti, " (%d byte%s)", fragment_len, plurality (fragment_len, "", "s")); frag_msg = fragment_add_seq_next (&ses_reassembly_table, tvb, offset, pinfo, ses_id, NULL, fragment_len, (enclosure_item_flags & END_SPDU) ? FALSE : TRUE); next_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled SES", frag_msg, &ses_frag_items, NULL, (enclosure_item_flags & END_SPDU) ? tree : ses_tree); has_user_information = TRUE; offset += fragment_len; } if (has_user_information && next_tvb) { if (!pres_handle) { call_dissector(data_handle, next_tvb, pinfo, tree); } else { /* Pass the session pdu to the presentation dissector */ call_dissector_with_data(pres_handle, next_tvb, pinfo, tree, &session); } /* * No more SPDUs to dissect. Set the offset to the * end of the tvbuff. */ offset = tvb_captured_length(tvb); if (session.rtse_reassemble && type == SES_DATA_TRANSFER) { ses_pres_ctx_id = session.pres_ctx_id; ses_rtse_reassemble = TRUE; } } return offset; }
/* Packet dissection routine called by tcp (& udp) when port 873 detected */ static void dissect_rsync_encap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean desegment _U_) { conversation_t *conversation; struct rsync_conversation_data *conversation_data; struct rsync_frame_data *rsync_frame_data_p; proto_item *ti; proto_tree *rsync_tree; int offset = 0; gchar version[5]; gchar auth_string[10]; guint buff_length; gchar magic_string[14]; gchar *version_out; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RSYNC"); col_clear(pinfo->cinfo, COL_INFO); conversation = find_or_create_conversation(pinfo); conversation_data = conversation_get_proto_data(conversation, proto_rsync); if (conversation_data == NULL) { conversation_data = se_alloc(sizeof(struct rsync_conversation_data)); conversation_data->state = RSYNC_INIT; conversation_add_proto_data(conversation, proto_rsync, conversation_data); } conversation_set_dissector(conversation, rsync_handle); ti = proto_tree_add_item(tree, proto_rsync, tvb, 0, -1, ENC_NA); rsync_tree = proto_item_add_subtree(ti, ett_rsync); rsync_frame_data_p = p_get_proto_data(pinfo->fd, proto_rsync); if (!rsync_frame_data_p) { /* then we haven't seen this frame before */ rsync_frame_data_p = se_alloc(sizeof(struct rsync_frame_data)); rsync_frame_data_p->state = conversation_data->state; p_add_proto_data(pinfo->fd, proto_rsync, rsync_frame_data_p); } switch (rsync_frame_data_p->state) { case RSYNC_INIT: proto_tree_add_item(rsync_tree, hf_rsync_hdr_magic, tvb, offset, 8, ENC_ASCII|ENC_NA); offset += 8; proto_tree_add_item(rsync_tree, hf_rsync_hdr_version, tvb, offset, 4, ENC_ASCII|ENC_NA); tvb_get_nstringz0(tvb, offset, sizeof(version), version); offset += 4; if (check_col(pinfo->cinfo, COL_INFO)) { /* XXX - is this really a string? */ version_out = format_text(version, 4); col_append_fstr(pinfo->cinfo, COL_INFO, "Client Initialisation (Version %s)", version_out); } conversation_data->state = RSYNC_SERV_INIT; break; case RSYNC_SERV_INIT: proto_tree_add_item(rsync_tree, hf_rsync_hdr_magic, tvb, offset, 8, ENC_ASCII|ENC_NA); offset += 8; proto_tree_add_item(rsync_tree, hf_rsync_hdr_version, tvb, offset, 4, ENC_ASCII|ENC_NA); tvb_get_nstringz0(tvb, offset, sizeof(version), version); offset += 4; if (check_col(pinfo->cinfo, COL_INFO)) { /* XXX - is this really a string? */ version_out = format_text(version, 4); col_append_fstr(pinfo->cinfo, COL_INFO, "Server Initialisation (Version %s)", version_out); } conversation_data->state = RSYNC_CLIENT_QUERY; break; case RSYNC_CLIENT_QUERY: proto_tree_add_item(rsync_tree, hf_rsync_query_string, tvb, offset, -1, ENC_ASCII|ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Client Query"); conversation_data->state = RSYNC_SERV_MOTD; break; case RSYNC_SERV_MOTD: proto_tree_add_item(rsync_tree, hf_rsync_motd_string, tvb, offset, -1, ENC_ASCII|ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Server MOTD"); conversation_data->state = RSYNC_SERV_RESPONSE; break; case RSYNC_SERV_RESPONSE: /* there are two cases - file list, or authentication */ tvb_get_nstringz0(tvb, offset, sizeof(auth_string), auth_string); if (0 == strncmp("@RSYNCD:", auth_string, 8)) { /* matches, so we assume its an authentication message */ /* needs to handle the AUTHREQD case, but doesn't - FIXME */ proto_tree_add_item(rsync_tree, hf_rsync_rsyncdok_string, tvb, offset, -1, ENC_ASCII|ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Authentication"); conversation_data->state = RSYNC_COMMAND; } else { /* it didn't match, so it is probably a module list */ proto_tree_add_item(rsync_tree, hf_rsync_response_string, tvb, offset, -1, ENC_ASCII|ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Module list"); /* we need to check the end of the buffer for magic string */ buff_length = tvb_length_remaining(tvb, offset); tvb_get_nstringz0(tvb, buff_length-14, sizeof(magic_string), magic_string); if (0 == strncmp("@RSYNCD: EXIT", magic_string, 14)) { /* that's all, folks */ conversation_data->state = RSYNC_COMMAND; } else { /* there must be more data */ conversation_data->state = RSYNC_SERV_RESPONSE; } } break; case RSYNC_COMMAND: if (pinfo->destport == glb_rsync_tcp_port) { /* then we are still sending commands */ proto_tree_add_item(rsync_tree, hf_rsync_command_string, tvb, offset, -1, ENC_ASCII|ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Command"); conversation_data->state = RSYNC_COMMAND; break; } /* else we fall through to the data phase */ case RSYNC_DATA: /* then we are still sending commands */ proto_tree_add_item(rsync_tree, hf_rsync_data, tvb, offset, -1, ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, "Data"); conversation_data->state = RSYNC_DATA; break; } }
static void dissect_smb_direct_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 remaining_length) { gboolean save_fragmented = pinfo->fragmented; int save_visited = pinfo->fd->flags.visited; conversation_t *conversation = NULL; fragment_head *fd_head = NULL; tvbuff_t *payload_tvb = NULL; gboolean more_frags = FALSE; gboolean fd_head_not_cached = FALSE; heur_dtbl_entry_t *hdtbl_entry; if (!smb_direct_reassemble) { payload_tvb = tvb; goto dissect_payload; } conversation = find_or_create_conversation(pinfo); if (remaining_length > 0) { more_frags = TRUE; } fd_head = (fragment_head *)p_get_proto_data(wmem_file_scope(), pinfo, proto_smb_direct, 0); if (fd_head == NULL) { fd_head_not_cached = TRUE; pinfo->fd->flags.visited = 0; fd_head = fragment_add_seq_next(&smb_direct_reassembly_table, tvb, 0, pinfo, conversation->index, NULL, tvb_captured_length(tvb), more_frags); } if (fd_head == NULL) { /* * We really want the fd_head and pass it to * process_reassembled_data() * * So that individual fragments gets the * reassembled in field. */ fd_head = fragment_get_reassembled_id(&smb_direct_reassembly_table, pinfo, conversation->index); } if (fd_head == NULL) { /* * we need more data... */ goto done; } if (fd_head_not_cached) { p_add_proto_data(wmem_file_scope(), pinfo, proto_smb_direct, 0, fd_head); } payload_tvb = process_reassembled_data(tvb, 0, pinfo, "Reassembled SMB Direct", fd_head, &smb_direct_frag_items, NULL, /* update_col_info*/ tree); if (payload_tvb == NULL) { /* * we need more data... */ goto done; } dissect_payload: pinfo->fragmented = FALSE; if (!dissector_try_heuristic(smb_direct_heur_subdissector_list, payload_tvb, pinfo, tree, &hdtbl_entry, NULL)) { call_dissector(data_handle, payload_tvb, pinfo, tree); } done: pinfo->fragmented = save_fragmented; pinfo->fd->flags.visited = save_visited; return; }
/** 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_k12(tvbuff_t* tvb,packet_info* pinfo,proto_tree* tree) { static dissector_handle_t data_handles[] = {NULL,NULL}; proto_item* k12_item; proto_tree* k12_tree; proto_item* stack_item; dissector_handle_t sub_handle = NULL; dissector_handle_t* handles; guint i; k12_item = proto_tree_add_protocol_format(tree, proto_k12, tvb, 0, 0, "Packet from: '%s' (0x%.8x)", pinfo->pseudo_header->k12.input_name, pinfo->pseudo_header->k12.input); k12_tree = proto_item_add_subtree(k12_item, ett_k12); proto_tree_add_uint(k12_tree, hf_k12_port_id, tvb, 0,0,pinfo->pseudo_header->k12.input); proto_tree_add_string(k12_tree, hf_k12_port_name, tvb, 0,0,pinfo->pseudo_header->k12.input_name); stack_item = proto_tree_add_string(k12_tree, hf_k12_stack_file, tvb, 0,0,pinfo->pseudo_header->k12.stack_file); k12_item = proto_tree_add_uint(k12_tree, hf_k12_port_type, tvb, 0, 0, pinfo->pseudo_header->k12.input_type); k12_tree = proto_item_add_subtree(k12_item, ett_port); switch ( pinfo->pseudo_header->k12.input_type ) { case K12_PORT_DS0S: proto_tree_add_uint(k12_tree, hf_k12_ts, tvb, 0,0,pinfo->pseudo_header->k12.input_info.ds0mask); break; case K12_PORT_ATMPVC: { gchar* circuit_str = ep_strdup_printf("%u:%u:%u", (guint)pinfo->pseudo_header->k12.input_info.atm.vp, (guint)pinfo->pseudo_header->k12.input_info.atm.vc, (guint)pinfo->pseudo_header->k12.input_info.atm.cid); /* * XXX: this is prone to collisions! * we need an uniform way to manage circuits between dissectors */ pinfo->circuit_id = g_str_hash(circuit_str); proto_tree_add_uint(k12_tree, hf_k12_atm_vp, tvb, 0, 0, pinfo->pseudo_header->k12.input_info.atm.vp); proto_tree_add_uint(k12_tree, hf_k12_atm_vc, tvb, 0, 0, pinfo->pseudo_header->k12.input_info.atm.vc); if (pinfo->pseudo_header->k12.input_info.atm.cid) proto_tree_add_uint(k12_tree, hf_k12_atm_cid, tvb, 0, 0, pinfo->pseudo_header->k12.input_info.atm.cid); break; } default: break; } handles = se_tree_lookup32(port_handles, pinfo->pseudo_header->k12.input); if (! handles ) { for (i=0 ; i < nk12_handles; i++) { if ( epan_strcasestr(pinfo->pseudo_header->k12.stack_file, k12_handles[i].match) || epan_strcasestr(pinfo->pseudo_header->k12.input_name, k12_handles[i].match) ) { handles = k12_handles[i].handles; break; } } if (!handles) { data_handles[0] = data_handle; handles = data_handles; } se_tree_insert32(port_handles, pinfo->pseudo_header->k12.input, handles); } if (handles == data_handles) { proto_tree* stack_tree = proto_item_add_subtree(stack_item,ett_stack_item); proto_item* item; item = proto_tree_add_text(stack_tree,tvb,0,0, "Warning: stk file not matched in the 'K12 Protocols' table"); PROTO_ITEM_SET_GENERATED(item); expert_add_info_format(pinfo, item, PI_UNDECODED, PI_WARN, "unmatched stk file"); item = proto_tree_add_text(stack_tree,tvb,0,0, "Info: You can edit the 'K12 Protocols' table from Preferences->Protocols->k12xx"); PROTO_ITEM_SET_GENERATED(item); call_dissector(data_handle, tvb, pinfo, tree); return; } /* Setup subdissector information */ for (i = 0; handles[i] && handles[i+1]; ++i) { if (handles[i] == sscop_handle) { sscop_payload_info *p_sscop_info = p_get_proto_data(pinfo->fd, proto_sscop); if (!p_sscop_info) { p_sscop_info = se_alloc0(sizeof(sscop_payload_info)); p_add_proto_data(pinfo->fd, proto_sscop, p_sscop_info); p_sscop_info->subdissector = handles[i+1]; } } /* Add more protocols here */ } sub_handle = handles[0]; /* Setup information required by certain protocols */ if (sub_handle == fp_handle) { fp_info *p_fp_info = p_get_proto_data(pinfo->fd, proto_fp); if (!p_fp_info) { p_fp_info = se_alloc0(sizeof(fp_info)); p_add_proto_data(pinfo->fd, proto_fp, p_fp_info); fill_fp_info(p_fp_info, pinfo->pseudo_header->k12.extra_info, pinfo->pseudo_header->k12.extra_length); } } call_dissector(sub_handle, tvb, pinfo, tree); }
static void dissect_rtp_events( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) { proto_item *ti = NULL; proto_tree *rtp_events_tree = NULL; unsigned int offset = 0; struct _rtp_conversation_info *p_conv_data = NULL; guint8 rtp_evt; guint8 octet; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTP EVENT"); col_clear(pinfo->cinfo, COL_INFO); /* Get event fields */ rtp_evt = tvb_get_guint8(tvb, offset ); /* get tap info */ rtp_event_info.info_rtp_evt = rtp_evt; p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_filter_name("rtp"), 0); if (p_conv_data) rtp_event_info.info_setup_frame_num = p_conv_data->frame_number; else rtp_event_info.info_setup_frame_num = 0; col_add_fstr( pinfo->cinfo, COL_INFO, "Payload type=RTP Event, %s", val_to_str( rtp_evt, rtp_event_type_values, "Unknown (%u)" )); ti = proto_tree_add_item( tree, proto_rtp_events, tvb, offset, -1, ENC_NA ); rtp_events_tree = proto_item_add_subtree( ti, ett_rtp_events ); proto_tree_add_uint ( rtp_events_tree, hf_rtp_events_event, tvb, offset, 1, rtp_evt); offset++; octet = tvb_get_guint8(tvb, offset); proto_tree_add_boolean (rtp_events_tree, hf_rtp_events_end, tvb, offset, 1, octet); proto_tree_add_boolean (rtp_events_tree, hf_rtp_events_reserved, tvb, offset, 1, octet); proto_tree_add_uint ( rtp_events_tree, hf_rtp_events_volume, tvb, offset, 1, octet); offset++; /* The duration field indicates the duration of the event or segment * being reported, in timestamp units. */ rtp_event_info.info_duration = tvb_get_ntohs(tvb, offset); proto_tree_add_item ( rtp_events_tree, hf_rtp_events_duration, tvb, offset, 2, ENC_BIG_ENDIAN); /* set the end info for the tap */ if (octet & 0x80) { rtp_event_info.info_end = TRUE; } else { rtp_event_info.info_end = FALSE; } /* Make end-of-event packets obvious in the info column */ if ((octet & 0x80)) { col_append_str(pinfo->cinfo, COL_INFO, " (end)"); } tap_queue_packet(rtp_event_tap, pinfo, &rtp_event_info); }
gboolean is_from_server; StringInfo data; } SslDecryptedRecord; static int ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ssl) { follow_info_t * follow_info = (follow_info_t*) tapdata; SslDecryptedRecord * rec = NULL; SslDataInfo * appl_data = NULL; int proto_ssl = GPOINTER_TO_INT(ssl); SslPacketInfo * pi = NULL; show_stream_t from = FROM_CLIENT; /* Skip packets without decrypted payload data. */ pi = (SslPacketInfo*) p_get_proto_data(pinfo->fd, proto_ssl, 0); if (!pi || !pi->appl_data) return 0; /* Compute the packet's sender. */ if (follow_info->client_port == 0) { follow_info->client_port = pinfo->srcport; COPY_ADDRESS(&follow_info->client_ip, &pinfo->src); } if (ADDRESSES_EQUAL(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport) { from = FROM_CLIENT; } else { from = FROM_SERVER; } for (appl_data = pi->appl_data; appl_data != NULL; appl_data = appl_data->next) {
static gpointer sll_value(packet_info *pinfo) { return p_get_proto_data(pinfo->pool, pinfo, proto_sll, 0); }
#else #include <epan/dissectors/packet-ssl-utils.h> #endif static int ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ssl) { follow_info_t * follow_info = (follow_info_t*) tapdata; SslDecryptedRecord * rec = NULL; SslDataInfo * appl_data = NULL; int proto_ssl = GPOINTER_TO_INT(ssl); SslPacketInfo * pi = NULL; show_stream_t from = FROM_CLIENT; /* Skip packets without decrypted payload data. */ pi = (SslPacketInfo*) p_get_proto_data(wmem_file_scope(), pinfo, proto_ssl, 0); if (!pi || !pi->appl_data) return 0; /* Compute the packet's sender. */ if (follow_info->client_port == 0) { follow_info->client_port = pinfo->srcport; COPY_ADDRESS(&follow_info->client_ip, &pinfo->src); } if (ADDRESSES_EQUAL(&follow_info->client_ip, &pinfo->src) && follow_info->client_port == pinfo->srcport) { from = FROM_CLIENT; } else { from = FROM_SERVER; } for (appl_data = pi->appl_data; appl_data != NULL; appl_data = appl_data->next) {
/* Code to actually dissect the packets */ static void dissect_brdwlk (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti, *hidden_item; proto_tree *brdwlk_tree = NULL; tvbuff_t *next_tvb; guint8 error, eof, sof; int hdrlen = 2, offset = 0; gint len, reported_len, plen; guint16 pkt_cnt; gboolean dropped_packets; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Boardwalk"); col_clear(pinfo->cinfo, COL_INFO); pinfo->vsan = (tvb_get_ntohs (tvb, offset) & 0xFFF); sof = (tvb_get_guint8 (tvb, offset) & 0xF0) >> 4; if ((sof == FCM_DELIM_SOFI3) || (sof == FCM_DELIM_SOFI2) || (sof == FCM_DELIM_SOFI1) || (sof == FCM_DELIM_SOFI4)) { pinfo->sof_eof = PINFO_SOF_FIRST_FRAME; } else if (sof == FCM_DELIM_SOFF) { pinfo->sof_eof = PINFO_SOF_SOFF; } if (tree) { ti = proto_tree_add_protocol_format (tree, proto_brdwlk, tvb, 0, hdrlen, "Boardwalk"); brdwlk_tree = proto_item_add_subtree (ti, ett_brdwlk); proto_tree_add_item (brdwlk_tree, hf_brdwlk_sof, tvb, offset, 1, 0); proto_tree_add_item (brdwlk_tree, hf_brdwlk_vsan, tvb, offset, 2, 0); } /* Locate EOF which is the last 4 bytes of the frame */ len = tvb_length_remaining(tvb, hdrlen); reported_len = tvb_reported_length_remaining(tvb, hdrlen); if (reported_len < 4) { /* * This packet is claimed not to even have enough data for * a 4-byte EOF. * Don't try to process the EOF. */ ; } else if (len < reported_len) { /* * This packet is claimed to have enough data for a 4-byte EOF, * but we didn't capture all of the packet. * Slice off the 4-byte EOF from the reported length, and trim * the captured length so it's no more than the reported length; * that will slice off what of the EOF, if any, is in the * captured length. */ reported_len -= 4; if (len > reported_len) len = reported_len; } else { /* * We have the entire packet, and it includes a 4-byte EOF. * Slice it off, and put it into the tree if we're building * a tree. */ len -= 4; reported_len -= 4; offset = tvb_reported_length(tvb) - 4; pkt_cnt = tvb_get_ntohs (tvb, offset); if (tree) { proto_tree_add_uint (brdwlk_tree, hf_brdwlk_pktcnt, tvb, offset, 2, pkt_cnt); } dropped_packets = FALSE; if (pinfo->fd->flags.visited) { /* * This isn't the first pass, so we can't use the global * "packet_count" variable to determine whether there were * any dropped frames or not. * We therefore attach a non-null pointer as frame data to * any frame preceded by dropped packets. */ if (p_get_proto_data(pinfo->fd, proto_brdwlk) != NULL) dropped_packets = TRUE; } else { /* * This is the first pass, so we have to use the global * "packet_count" variable to determine whether there were * any dropped frames or not. * * XXX - can there be more than one stream of packets, so that * we can't just use a global variable? */ if (pkt_cnt != packet_count + 1) { if (!first_pkt && (pkt_cnt != 0 || (packet_count != BRDWLK_MAX_PACKET_CNT))) { dropped_packets = TRUE; /* * Mark this frame as having been preceded by dropped * packets. (The data we use as the frame data doesn't * matter - it just matters that it's non-null.) */ p_add_proto_data(pinfo->fd, proto_brdwlk, &packet_count); } } if (tree) { hidden_item = proto_tree_add_boolean (brdwlk_tree, hf_brdwlk_drop, tvb, offset, 0, dropped_packets); PROTO_ITEM_SET_HIDDEN(hidden_item); } } packet_count = pkt_cnt; error=tvb_get_guint8(tvb, offset+2); dissect_brdwlk_err(brdwlk_tree, tvb, offset+2); eof = tvb_get_guint8 (tvb, offset+3); if (eof != FCM_DELIM_EOFN) { pinfo->sof_eof |= PINFO_EOF_LAST_FRAME; } else if (eof != FCM_DELIM_EOFT) { pinfo->sof_eof |= PINFO_EOF_INVALID; } if (tree) { proto_tree_add_item (brdwlk_tree, hf_brdwlk_eof, tvb, offset+3, 1, 0); } if ((error & BRDWLK_HAS_PLEN) && tree) { /* In newer Boardwalks, if this bit is set, the actual frame length * is also provided. This length is the size between SOF & EOF * including FC CRC. */ plen = tvb_get_ntohl (tvb, offset-4); plen *= 4; proto_tree_add_uint (brdwlk_tree, hf_brdwlk_plen, tvb, offset-4, 4, plen); #if 0 /* XXX - this would throw an exception if it would increase * the reported length. */ if (error & BRDWLK_TRUNCATED_BIT) { tvb_set_reported_length (tvb, plen); } #endif } } next_tvb = tvb_new_subset (tvb, 2, len, reported_len); if (fc_dissector_handle) { call_dissector (fc_dissector_handle, next_tvb, pinfo, tree); } }
static int dissect_gssapi_work(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_verifier) { proto_item *volatile item; proto_tree *volatile subtree; volatile int return_offset = 0; gssapi_conv_info_t *volatile gss_info; gssapi_oid_value *oidvalue; dissector_handle_t handle; conversation_t *conversation; tvbuff_t *oid_tvb; int len, start_offset, oid_start_offset; volatile int offset; gint8 appclass; gboolean pc, ind_field; gint32 tag; guint32 len1; const char *oid; fragment_data *fd_head=NULL; gssapi_frag_info_t *fi; tvbuff_t *volatile gss_tvb=NULL; asn1_ctx_t asn1_ctx; void *pd_save; start_offset=0; offset=0; asn1_ctx_init(&asn1_ctx, ASN1_ENC_BER, TRUE, pinfo); /* * We don't know whether the data is encrypted, so say it's * not, for now. The subdissector must set gssapi_data_encrypted * if it is. */ pinfo->gssapi_data_encrypted = FALSE; /* * We need a conversation for later */ conversation = find_or_create_conversation(pinfo); gss_info = (gssapi_conv_info_t *)conversation_get_proto_data(conversation, proto_gssapi); if (!gss_info) { gss_info = se_new(gssapi_conv_info_t); gss_info->oid=NULL; gss_info->do_reassembly=FALSE; gss_info->frags=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "gssapi_frags"); conversation_add_proto_data(conversation, proto_gssapi, gss_info); } item = proto_tree_add_item( tree, proto_gssapi, tvb, offset, -1, ENC_NA); subtree = proto_item_add_subtree(item, ett_gssapi); /* * Catch the ReportedBoundsError exception; the stuff we've been * handed doesn't necessarily run to the end of the packet, it's * an item inside a packet, so if it happens to be malformed (or * we, or a dissector we call, has a bug), so that an exception * is thrown, we want to report the error, but return and let * our caller dissect the rest of the packet. * * If it gets a BoundsError, we can stop, as there's nothing more * in the packet after our blob to see, so we just re-throw the * exception. */ pd_save = pinfo->private_data; TRY { gss_tvb=tvb; /* First of all, if it's the first time we see this packet * then check whether we are in the middle of reassembly or not */ if( (!pinfo->fd->flags.visited) && (gss_info->do_reassembly) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, gss_info->first_frame); if(!fi){ goto done; } se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fd_head=fragment_add(&gssapi_reassembly_table, tvb, 0, pinfo, fi->first_frame, NULL, gss_info->frag_offset, tvb_length(tvb), TRUE); gss_info->frag_offset+=tvb_length(tvb); /* we need more fragments */ if(!fd_head){ goto done; } /* this blob is now fully reassembled */ gss_info->do_reassembly=FALSE; fi->reassembled_in=pinfo->fd->num; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); } /* We have seen this packet before. * Is this blob part of reassembly or a normal blob ? */ if( (pinfo->fd->flags.visited) && (gssapi_reassembly) ){ fi=(gssapi_frag_info_t *)se_tree_lookup32(gss_info->frags, pinfo->fd->num); if(fi){ fd_head=fragment_get(&gssapi_reassembly_table, pinfo, fi->first_frame, NULL); if(fd_head && (fd_head->flags&FD_DEFRAGMENTED)){ if(pinfo->fd->num==fi->reassembled_in){ proto_item *frag_tree_item; gss_tvb=tvb_new_child_real_data(tvb, fd_head->data, fd_head->datalen, fd_head->datalen); add_new_data_source(pinfo, gss_tvb, "Reassembled GSSAPI"); show_fragment_tree(fd_head, &gssapi_frag_items, tree, pinfo, tvb, &frag_tree_item); } else { proto_item *it; it=proto_tree_add_uint(tree, hf_gssapi_reassembled_in, tvb, 0, 0, fi->reassembled_in); PROTO_ITEM_SET_GENERATED(it); goto done; } } } } /* Read header */ offset = get_ber_identifier(gss_tvb, offset, &appclass, &pc, &tag); offset = get_ber_length(gss_tvb, offset, &len1, &ind_field); if (!(appclass == BER_CLASS_APP && pc && tag == 0)) { /* It could be NTLMSSP, with no OID. This can happen for anything that microsoft calls 'Negotiate' or GSS-SPNEGO */ if ((tvb_length_remaining(gss_tvb, start_offset)>7) && (tvb_strneql(gss_tvb, start_offset, "NTLMSSP", 7) == 0)) { return_offset = call_dissector(ntlmssp_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* Maybe it's new NTLMSSP payload */ if ((tvb_length_remaining(gss_tvb, start_offset)>16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { return_offset = call_dissector(ntlmssp_payload_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; goto done; } if ((tvb_length_remaining(gss_tvb, start_offset)==16) && ((tvb_memeql(gss_tvb, start_offset, "\x01\x00\x00\x00", 4) == 0))) { if( is_verifier ) { return_offset = call_dissector(ntlmssp_verf_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); } else if( pinfo->gssapi_encrypted_tvb ) { return_offset = call_dissector(ntlmssp_data_only_handle, tvb_new_subset_remaining(pinfo->gssapi_encrypted_tvb, 0), pinfo, subtree); pinfo->gssapi_data_encrypted = TRUE; } goto done; } /* Maybe it's new GSSKRB5 CFX Wrapping */ if ((tvb_length_remaining(gss_tvb, start_offset)>2) && ((tvb_memeql(gss_tvb, start_offset, "\04\x04", 2) == 0) || (tvb_memeql(gss_tvb, start_offset, "\05\x04", 2) == 0))) { return_offset = call_dissector(spnego_krb5_wrap_handle, tvb_new_subset_remaining(gss_tvb, start_offset), pinfo, subtree); goto done; } /* * If we do not recognise an Application class, * then we are probably dealing with an inner context * token or a wrap token, and we should retrieve the * gssapi_oid_value pointer from the per-frame data or, * if there is no per-frame data (as would be the case * the first time we dissect this frame), from the * conversation that exists or that we created from * pinfo (and then make it per-frame data). * We need to make it per-frame data as there can be * more than one GSS-API negotiation in a conversation. * * Note! We "cheat". Since we only need the pointer, * we store that as the data. (That's not really * "cheating" - the per-frame data and per-conversation * data code doesn't care what you supply as a data * pointer; it just treats it as an opaque pointer, it * doesn't dereference it or free what it points to.) */ oidvalue = (gssapi_oid_value *)p_get_proto_data(pinfo->fd, proto_gssapi, 0); if (!oidvalue && !pinfo->fd->flags.visited) { /* No handle attached to this frame, but it's the first */ /* pass, so it'd be attached to the conversation. */ oidvalue = gss_info->oid; if (gss_info->oid) p_add_proto_data(pinfo->fd, proto_gssapi, 0, gss_info->oid); } if (!oidvalue) { proto_tree_add_text(subtree, gss_tvb, start_offset, 0, "Unknown header (class=%d, pc=%d, tag=%d)", appclass, pc, tag); return_offset = tvb_length(gss_tvb); goto done; } else { tvbuff_t *oid_tvb_local; oid_tvb_local = tvb_new_subset_remaining(gss_tvb, start_offset); if (is_verifier) handle = oidvalue->wrap_handle; else handle = oidvalue->handle; len = call_dissector(handle, oid_tvb_local, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = start_offset + len; goto done; /* We are finished here */ } } /* Read oid */ oid_start_offset=offset; offset=dissect_ber_object_identifier_str(FALSE, &asn1_ctx, subtree, gss_tvb, offset, hf_gssapi_oid, &oid); oidvalue = gssapi_lookup_oid_str(oid); /* Check if we need reassembly of this blob. * Only try reassembly for OIDs we recognize * and when we have the entire tvb * * SMB will sometimes split one large GSSAPI blob * across multiple SMB/SessionSetup commands. * While we should look at the uid returned in the response * to the first SessionSetup and use that as a key * instead for simplicity we assume there will not be several * such authentication at once on a single tcp session */ if( (!pinfo->fd->flags.visited) && (oidvalue) && (tvb_length(gss_tvb)==tvb_reported_length(gss_tvb)) && (len1>(guint32)tvb_length_remaining(gss_tvb, oid_start_offset)) && (gssapi_reassembly) ){ fi=se_new(gssapi_frag_info_t); fi->first_frame=pinfo->fd->num; fi->reassembled_in=0; se_tree_insert32(gss_info->frags, pinfo->fd->num, fi); fragment_add(&gssapi_reassembly_table, gss_tvb, 0, pinfo, pinfo->fd->num, NULL, 0, tvb_length(gss_tvb), TRUE); fragment_set_tot_len(&gssapi_reassembly_table, pinfo, pinfo->fd->num, NULL, len1+oid_start_offset); gss_info->do_reassembly=TRUE; gss_info->first_frame=pinfo->fd->num; gss_info->frag_offset=tvb_length(gss_tvb); goto done; } /* * Hand off to subdissector. */ if ((oidvalue == NULL) || !proto_is_protocol_enabled(oidvalue->proto)) { /* No dissector for this oid */ proto_tree_add_text(subtree, gss_tvb, oid_start_offset, -1, "Token object"); return_offset = tvb_length(gss_tvb); goto done; } /* Save a pointer to the data for the OID for the * GSSAPI protocol for this conversation. */ /* * Now add the proto data ... * but only if it is not already there. */ if(!gss_info->oid){ gss_info->oid=oidvalue; } if (is_verifier) { handle = oidvalue->wrap_handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication verifier"); return_offset = tvb_length(gss_tvb); } } else { handle = oidvalue->handle; if (handle != NULL) { oid_tvb = tvb_new_subset_remaining(gss_tvb, offset); len = call_dissector(handle, oid_tvb, pinfo, subtree); if (len == 0) return_offset = tvb_length(gss_tvb); else return_offset = offset + len; } else { proto_tree_add_text(subtree, gss_tvb, offset, -1, "Authentication credentials"); return_offset = tvb_length(gss_tvb); } } done: ; } CATCH_NONFATAL_ERRORS { /* * Somebody threw an exception that means that there * was a problem dissecting the payload; that means * that a dissector was found, so we don't need to * dissect the payload as data or update the protocol * or info columns. * * Just show the exception and then drive on to show * the trailer, after noting that a dissector was found * and restoring the protocol value that was in effect * before we called the subdissector. * * Restore the private_data structure in case one of the * called dissectors modified it (and, due to the exception, * was unable to restore it). */ pinfo->private_data = pd_save; show_exception(gss_tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE); } ENDTRY; proto_item_set_len(item, return_offset); return return_offset; }
static void eth_prompt(packet_info *pinfo, gchar* result) { g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Ethertype 0x%04x as", GPOINTER_TO_UINT(p_get_proto_data(pinfo->pool, pinfo, proto_ethertype, 0))); }
typedef struct { gboolean is_server; StringInfo data; } SslDecryptedRecord; static int ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt _U_, const void *ssl) { follow_info_t* follow_info = tapdata; SslDecryptedRecord* rec; SslDataInfo* appl_data; gint total_len; guchar *p; int proto_ssl = (long) ssl; SslPacketInfo* pi = p_get_proto_data(pinfo->fd, proto_ssl); /* skip packet without decrypted data payload*/ if (!pi || !pi->appl_data) return 0; /* compute total length */ total_len = 0; appl_data = pi->appl_data; do { total_len += appl_data->plain_data.data_len; appl_data = appl_data->next; } while (appl_data); /* compute packet direction */ rec = g_malloc(sizeof(SslDecryptedRecord) + total_len);
/* * Dissect a standard (reliable) ts2 packet, reassembling if required. */ static void ts2_standard_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *ts2_tree, ts2_conversation *conversation_data) { guint8 save_fragmented; tvbuff_t *new_tvb, *next_tvb; fragment_data *frag_msg ; guint16 fragment_number; ts2_frag *frag; gboolean outoforder; guint16 type = tvb_get_letohs(tvb, 2); /*guint16 class = tvb_get_letohs(tvb, 0);*/ proto_tree_add_item(ts2_tree, hf_ts2_seqnum, tvb, 12, 4, TRUE); /* XXX: Following fragmentation stuff should be separate from the GUI stuff ?? */ /* Get our stored fragmentation data or create one! */ if ( ! ( frag = p_get_proto_data(pinfo->fd, proto_ts2) ) ) { frag = se_alloc(sizeof(ts2_frag)); frag->frag_num=0; } /* decide if the packet is server to client or client to server * then check its fragmentation */ if(!(pinfo->fd->flags.visited)) { if(conversation_data->server_port == pinfo->srcport) { frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_server_frame, &conversation_data->server_frag_size, &conversation_data->server_frag_num, &outoforder); frag->frag_num=conversation_data->server_frag_num; frag->frag_size=conversation_data->server_frag_size; } else { frag->fragmented = ts2_standard_find_fragments(tvb, &conversation_data->last_inorder_client_frame, &conversation_data->client_frag_size, &conversation_data->client_frag_num, &outoforder); frag->frag_num=conversation_data->client_frag_num; frag->frag_size=conversation_data->client_frag_size; } frag->outoforder=outoforder; p_add_proto_data(pinfo->fd, proto_ts2, frag); } /* Get our stored fragmentation data */ frag = p_get_proto_data(pinfo->fd, proto_ts2); proto_tree_add_item(ts2_tree, hf_ts2_resend_count, tvb, 16, 2, TRUE); proto_tree_add_item(ts2_tree, hf_ts2_fragmentnumber, tvb, 18, 2, TRUE); ts2_add_checked_crc32(ts2_tree, hf_ts2_crc32, tvb, 20, tvb_get_letohl(tvb, 20)); /* Reassemble the packet if its fragmented */ new_tvb = NULL; if(frag->fragmented) { save_fragmented = pinfo->fragmented; frag_msg = NULL; pinfo->fragmented = TRUE; fragment_number = tvb_get_letohs(tvb, 18); frag_msg = fragment_add_seq_check(tvb, 24, pinfo, type, msg_fragment_table, msg_reassembled_table, frag->frag_num, tvb_length_remaining(tvb, 24), fragment_number); new_tvb = process_reassembled_data(tvb, 24, pinfo,"Reassembled Message", frag_msg, &msg_frag_items, NULL, ts2_tree); if (frag_msg) { /* Reassembled */ if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Message Reassembled)"); } else { /* Not last packet of reassembled Short Message */ if (check_col(pinfo->cinfo, COL_INFO))col_append_fstr(pinfo->cinfo, COL_INFO," (Message fragment %u)", frag->frag_num); } if (new_tvb) next_tvb = new_tvb; else next_tvb = tvb_new_subset_remaining(tvb, 24); pinfo->fragmented = save_fragmented; } else next_tvb = tvb_new_subset_remaining(tvb, 24); /* If we have a full packet now dissect it */ if((new_tvb || !frag->fragmented) && !frag->outoforder) { switch(type) { case TS2T_LOGINPART2: ts2_parse_loginpart2(next_tvb, ts2_tree); break; case TS2T_CHANNELLIST: ts2_parse_channellist(next_tvb, ts2_tree); break; case TS2T_PLAYERLIST: ts2_parse_playerlist(next_tvb, ts2_tree); break; case TS2T_NEWPLAYERJOINED: ts2_parse_newplayerjoined(next_tvb, ts2_tree); break; case TS2T_KNOWNPLAYERUPDATE: ts2_parse_knownplayerupdate(next_tvb, ts2_tree); break; case TS2T_PLAYERLEFT: ts2_parse_playerleft(next_tvb, ts2_tree); break; case TS2T_PLAYERKICKED: ts2_parse_playerleft(next_tvb, ts2_tree); break; case TS2T_LOGINEND: ts2_parse_loginend(next_tvb, ts2_tree); break; case TS2T_CHANGESTATUS: ts2_parse_changestatus(next_tvb, ts2_tree); break; case TS2T_SWITCHCHANNEL: ts2_parse_switchchannel(next_tvb, ts2_tree); break; case TS2T_CHANNELCHANGE: ts2_parse_channelchange(next_tvb, ts2_tree); break; } } /* The packet is out of order, update the cinfo and ignore the packet */ if(frag->outoforder) if (check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, " (Out Of Order, ignored)"); }
static void dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { struct smtp_proto_data *spd_frame_data; proto_tree *smtp_tree = NULL; proto_tree *cmdresp_tree; proto_item *ti, *hidden_item; int offset = 0; int request = 0; conversation_t *conversation; struct smtp_session_state *session_state; const guchar *line, *linep, *lineend; guint32 code; int linelen = 0; gint length_remaining; gboolean eom_seen = FALSE; gint next_offset; gint loffset = 0; int cmdlen; fragment_data *frag_msg = NULL; tvbuff_t *next_tvb; /* As there is no guarantee that we will only see frames in the * the SMTP conversation once, and that we will see them in * order - in Wireshark, the user could randomly click on frames * in the conversation in any order in which they choose - we * have to store information with each frame indicating whether * it contains commands or data or an EOM indication. * * XXX - what about frames that contain *both*? TCP is a * byte-stream protocol, and there are no guarantees that * TCP segment boundaries will correspond to SMTP commands * or EOM indications. * * We only need that for the client->server stream; responses * are easy to manage. * * If we have per frame data, use that, else, we must be on the first * pass, so we figure it out on the first pass. */ /* * Find or create the conversation for this. */ conversation = find_or_create_conversation(pinfo); /* * Is there a request structure attached to this conversation? */ session_state = conversation_get_proto_data(conversation, proto_smtp); if (!session_state) { /* * No - create one and attach it. */ session_state = se_alloc(sizeof(struct smtp_session_state)); session_state->smtp_state = SMTP_STATE_READING_CMDS; session_state->crlf_seen = FALSE; session_state->data_seen = FALSE; session_state->msg_read_len = 0; session_state->msg_tot_len = 0; session_state->msg_last = TRUE; session_state->last_nontls_frame = 0; conversation_add_proto_data(conversation, proto_smtp, session_state); } /* Are we doing TLS? * FIXME In my understanding of RFC 2487 client and server can send SMTP cmds * after a rejected TLS negotiation */ if (session_state->last_nontls_frame != 0 && pinfo->fd->num > session_state->last_nontls_frame) { guint16 save_can_desegment; guint32 save_last_nontls_frame; /* This is TLS, not raw SMTP. TLS can desegment */ save_can_desegment = pinfo->can_desegment; pinfo->can_desegment = pinfo->saved_can_desegment; /* Make sure the SSL dissector will not be called again after decryption */ save_last_nontls_frame = session_state->last_nontls_frame; session_state->last_nontls_frame = 0; call_dissector(ssl_handle, tvb, pinfo, tree); pinfo->can_desegment = save_can_desegment; session_state->last_nontls_frame = save_last_nontls_frame; return; } /* Is this a request or a response? */ request = pinfo->destport == pinfo->match_uint; /* * Is there any data attached to this frame? */ spd_frame_data = p_get_proto_data(pinfo->fd, proto_smtp); if (!spd_frame_data) { /* * No frame data. */ if(request) { /* * Create a frame data structure and attach it to the packet. */ spd_frame_data = se_alloc0(sizeof(struct smtp_proto_data)); spd_frame_data->conversation_id = conversation->index; spd_frame_data->more_frags = TRUE; p_add_proto_data(pinfo->fd, proto_smtp, spd_frame_data); } /* * Get the first line from the buffer. * * Note that "tvb_find_line_end()" will, if it doesn't return * -1, return a value that is not longer than what's in the buffer, * and "tvb_find_line_end()" will always return a value that is not * longer than what's in the buffer, so the "tvb_get_ptr()" call * won't throw an exception. */ loffset = offset; while (tvb_offset_exists(tvb, loffset)) { linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, smtp_desegment && pinfo->can_desegment); if (linelen == -1) { if (offset == loffset) { /* * We didn't find a line ending, and we're doing desegmentation; * tell the TCP dissector where the data for this message starts * in the data it handed us, and tell it we need more bytes */ pinfo->desegment_offset = loffset; pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; return; } else { linelen = tvb_length_remaining(tvb, loffset); next_offset = loffset + linelen; } } line = tvb_get_ptr(tvb, loffset, linelen); /* * Check whether or not this packet is an end of message packet * We should look for CRLF.CRLF and they may be split. * We have to keep in mind that we may see what we want on * two passes through here ... */ if (session_state->smtp_state == SMTP_STATE_READING_DATA) { /* * The order of these is important ... We want to avoid * cases where there is a CRLF at the end of a packet and a * .CRLF at the begining of the same packet. */ if ((session_state->crlf_seen && tvb_strneql(tvb, loffset, ".\r\n", 3) == 0) || tvb_strneql(tvb, loffset, "\r\n.\r\n", 5) == 0) eom_seen = TRUE; length_remaining = tvb_length_remaining(tvb, loffset); if (length_remaining == tvb_reported_length_remaining(tvb, loffset) && tvb_strneql(tvb, loffset + length_remaining - 2, "\r\n", 2) == 0) session_state->crlf_seen = TRUE; else session_state->crlf_seen = FALSE; } /* * OK, Check if we have seen a DATA request. We do it here for * simplicity, but we have to be careful below. */ if (request) { if (session_state->smtp_state == SMTP_STATE_READING_DATA) { /* * This is message data. */ if (eom_seen) { /* Seen the EOM */ /* * EOM. * Everything that comes after it is commands. */ spd_frame_data->pdu_type = SMTP_PDU_EOM; session_state->smtp_state = SMTP_STATE_READING_CMDS; break; } else { /* * Message data with no EOM. */ spd_frame_data->pdu_type = SMTP_PDU_MESSAGE; if (session_state->msg_tot_len > 0) { /* * We are handling a BDAT message. * Check if we have reached end of the data chunk. */ session_state->msg_read_len += tvb_length_remaining(tvb, loffset); if (session_state->msg_read_len == session_state->msg_tot_len) { /* * We have reached end of BDAT data chunk. * Everything that comes after this is commands. */ session_state->smtp_state = SMTP_STATE_READING_CMDS; if (session_state->msg_last) { /* * We have found the LAST data chunk. * The message can now be reassembled. */ spd_frame_data->more_frags = FALSE; } break; /* no need to go through the remaining lines */ } } } } else { /* * This is commands - unless the capture started in the * middle of a session, and we're in the middle of data. * * Commands are not necessarily 4 characters; look * for a space or the end of the line to see where * the putative command ends. */ linep = line; lineend = line + linelen; while (linep < lineend && *linep != ' ') linep++; cmdlen = (int)(linep - line); if (line_is_smtp_command(line, cmdlen)) { if (g_ascii_strncasecmp(line, "DATA", 4) == 0) { /* * DATA command. * This is a command, but everything that comes after it, * until an EOM, is data. */ spd_frame_data->pdu_type = SMTP_PDU_CMD; session_state->smtp_state = SMTP_STATE_READING_DATA; session_state->data_seen = TRUE; } else if (g_ascii_strncasecmp(line, "BDAT", 4) == 0) { /* * BDAT command. * This is a command, but everything that comes after it, * until given length is received, is data. */ guint32 msg_len; msg_len = strtoul (line+5, NULL, 10); spd_frame_data->pdu_type = SMTP_PDU_CMD; session_state->data_seen = TRUE; session_state->msg_tot_len += msg_len; if (msg_len == 0) { /* No data to read, next will be a command */ session_state->smtp_state = SMTP_STATE_READING_CMDS; } else { session_state->smtp_state = SMTP_STATE_READING_DATA; } if (g_ascii_strncasecmp(line+linelen-4, "LAST", 4) == 0) { /* * This is the last data chunk. */ session_state->msg_last = TRUE; if (msg_len == 0) { /* * No more data to expect. * The message can now be reassembled. */ spd_frame_data->more_frags = FALSE; } } else { session_state->msg_last = FALSE; } } else if (g_ascii_strncasecmp(line, "STARTTLS", 8) == 0) { /* * STARTTLS command. * This is a command, but if the response is 220, * everything after the response is TLS. */ session_state->smtp_state = SMTP_STATE_AWAITING_STARTTLS_RESPONSE; spd_frame_data->pdu_type = SMTP_PDU_CMD; } else { /* * Regular command. */ spd_frame_data->pdu_type = SMTP_PDU_CMD; } } else { /* * Assume it's message data. */ spd_frame_data->pdu_type = session_state->data_seen ? SMTP_PDU_MESSAGE : SMTP_PDU_CMD; } } } /* * Step past this line. */ loffset = next_offset; } } /* * From here, we simply add items to the tree and info to the info * fields ... */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMTP"); if (check_col(pinfo->cinfo, COL_INFO)) { /* Add the appropriate type here */ col_clear(pinfo->cinfo, COL_INFO); /* * If it is a request, we have to look things up, otherwise, just * display the right things */ if (request) { /* We must have frame_data here ... */ switch (spd_frame_data->pdu_type) { case SMTP_PDU_MESSAGE: length_remaining = tvb_length_remaining(tvb, offset); col_set_str(pinfo->cinfo, COL_INFO, smtp_data_desegment ? "C: DATA fragment" : "C: Message Body"); col_append_fstr(pinfo->cinfo, COL_INFO, ", %d byte%s", length_remaining, plurality (length_remaining, "", "s")); break; case SMTP_PDU_EOM: col_set_str(pinfo->cinfo, COL_INFO, "C: ."); break; case SMTP_PDU_CMD: loffset = offset; while (tvb_offset_exists(tvb, loffset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, loffset, linelen); if(loffset == offset) col_append_fstr(pinfo->cinfo, COL_INFO, "C: %s", format_text(line, linelen)); else { col_append_fstr(pinfo->cinfo, COL_INFO, " | %s", format_text(line, linelen)); } loffset = next_offset; } break; } } else { loffset = offset; while (tvb_offset_exists(tvb, loffset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, loffset, linelen); if (loffset == offset) col_append_fstr(pinfo->cinfo, COL_INFO, "S: %s", format_text(line, linelen)); else { col_append_fstr(pinfo->cinfo, COL_INFO, " | %s", format_text(line, linelen)); } loffset = next_offset; } } } if (tree) { /* Build the tree info ... */ ti = proto_tree_add_item(tree, proto_smtp, tvb, offset, -1, ENC_NA); smtp_tree = proto_item_add_subtree(ti, ett_smtp); } if (request) { /* * Check out whether or not we can see a command in there ... * What we are looking for is not data_seen and the word DATA * and not eom_seen. * * We will see DATA and session_state->data_seen when we process the * tree view after we have seen a DATA packet when processing * the packet list pane. * * On the first pass, we will not have any info on the packets * On second and subsequent passes, we will. */ switch (spd_frame_data->pdu_type) { case SMTP_PDU_MESSAGE: if (smtp_data_desegment) { frag_msg = fragment_add_seq_next(tvb, 0, pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table, tvb_length(tvb), spd_frame_data->more_frags); } else { /* * Message body. * Put its lines into the protocol tree, a line at a time. */ dissect_smtp_data(tvb, offset, smtp_tree); } break; case SMTP_PDU_EOM: /* * End-of-message-body indicator. * * XXX - what about stuff after the first line? * Unlikely, as the client should wait for a response to the * DATA command this terminates before sending another * request, but we should probably handle it. */ proto_tree_add_text(smtp_tree, tvb, offset, linelen, "C: ."); if (smtp_data_desegment) { /* add final data segment */ if (loffset) fragment_add_seq_next(tvb, 0, pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table, loffset, spd_frame_data->more_frags); /* terminate the desegmentation */ frag_msg = fragment_end_seq_next (pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table); } break; case SMTP_PDU_CMD: /* * Command. * * XXX - what about stuff after the first line? * Unlikely, as the client should wait for a response to the * previous command before sending another request, but we * should probably handle it. */ loffset = offset; while (tvb_offset_exists(tvb, loffset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE); if (linelen >= 4) cmdlen = 4; else cmdlen = linelen; hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_req, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); /* * Put the command line into the protocol tree. */ ti = proto_tree_add_item(smtp_tree, hf_smtp_command_line, tvb, loffset, next_offset - loffset, ENC_ASCII|ENC_NA); cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp); proto_tree_add_item(cmdresp_tree, hf_smtp_req_command, tvb, loffset, cmdlen, ENC_ASCII|ENC_NA); if (linelen > 5) { proto_tree_add_item(cmdresp_tree, hf_smtp_req_parameter, tvb, loffset + 5, linelen - 5, ENC_ASCII|ENC_NA); } if (smtp_data_desegment && !spd_frame_data->more_frags) { /* terminate the desegmentation */ frag_msg = fragment_end_seq_next (pinfo, spd_frame_data->conversation_id, smtp_data_segment_table, smtp_data_reassembled_table); } /* * Step past this line. */ loffset = next_offset; } } if (smtp_data_desegment) { next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled SMTP", frag_msg, &smtp_data_frag_items, NULL, smtp_tree); if (next_tvb) { /* XXX: this is presumptious - we may have negotiated something else */ if (imf_handle) { call_dissector(imf_handle, next_tvb, pinfo, tree); } else { /* * Message body. * Put its lines into the protocol tree, a line at a time. */ dissect_smtp_data(tvb, offset, smtp_tree); } pinfo->fragmented = FALSE; } else { pinfo->fragmented = TRUE; } } } else { /* * Process the response, a line at a time, until we hit a line * that doesn't have a continuation indication on it. */ if (tree) { hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_rsp, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); } while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (tree) { /* * Put it into the protocol tree. */ ti = proto_tree_add_item(smtp_tree, hf_smtp_response, tvb, offset, next_offset - offset, ENC_ASCII|ENC_NA); cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp); } else cmdresp_tree = NULL; line = tvb_get_ptr(tvb, offset, linelen); if (linelen >= 3 && isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2])) { /* * We have a 3-digit response code. */ code = (line[0] - '0')*100 + (line[1] - '0')*10 + (line[2] - '0'); /* * If we're awaiting the response to a STARTTLS code, this * is it - if it's 220, all subsequent traffic will * be TLS, otherwise we're back to boring old SMTP. */ if (session_state->smtp_state == SMTP_STATE_AWAITING_STARTTLS_RESPONSE) { if (code == 220) { /* This is the last non-TLS frame. */ session_state->last_nontls_frame = pinfo->fd->num; } session_state->smtp_state = SMTP_STATE_READING_CMDS; } if (tree) { /* * Put the response code and parameters into the protocol tree. */ proto_tree_add_uint(cmdresp_tree, hf_smtp_rsp_code, tvb, offset, 3, code); if (linelen >= 4) { proto_tree_add_item(cmdresp_tree, hf_smtp_rsp_parameter, tvb, offset + 4, linelen - 4, ENC_ASCII|ENC_NA); } } } /* * Step past this line. */ offset = next_offset; } } }
conversation_data = (struct rsync_conversation_data *)conversation_get_proto_data(conversation, hfi_rsync->id); if (conversation_data == NULL) { /* new conversation */ conversation_data = wmem_new(wmem_file_scope(), struct rsync_conversation_data); conversation_data->client_state = RSYNC_INIT; conversation_data->server_state = RSYNC_SERV_INIT; conversation_add_proto_data(conversation, hfi_rsync->id, conversation_data); } conversation_set_dissector(conversation, rsync_handle); ti = proto_tree_add_item(tree, hfi_rsync, tvb, 0, -1, ENC_NA); rsync_tree = proto_item_add_subtree(ti, ett_rsync); rsync_frame_data_p = (struct rsync_frame_data *)p_get_proto_data(wmem_file_scope(), pinfo, hfi_rsync->id, 0); if (!rsync_frame_data_p) { /* then we haven't seen this frame before */ rsync_frame_data_p = wmem_new(wmem_file_scope(), struct rsync_frame_data); rsync_frame_data_p->state = (me == SERVER) ? conversation_data->server_state : conversation_data->client_state; p_add_proto_data(wmem_file_scope(), pinfo, hfi_rsync->id, 0, rsync_frame_data_p); } if (me == SERVER) { switch (rsync_frame_data_p->state) { case RSYNC_SERV_INIT: dissect_rsync_version_header(tvb, pinfo, rsync_tree, me); conversation_data->server_state = RSYNC_SERV_MOTD; break;
/*FUNCTION:------------------------------------------------------ * NAME * dissect_zbee_secure * DESCRIPTION * Dissects and decrypts secured ZigBee frames. * * Will return a valid tvbuff only if security processing was * successful. If processing fails, then this function will * handle internally and return NULL. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * guint offset - pointer to the start of the auxilliary security header. * guint64 src64 - extended source address, or 0 if unknown. * RETURNS * tvbuff_t * *--------------------------------------------------------------- */ tvbuff_t * dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset) { proto_tree *sec_tree = NULL; proto_item *sec_root; proto_tree *field_tree; proto_item *ti; zbee_security_packet packet; guint mic_len; gint payload_len; tvbuff_t *payload_tvb; #ifdef HAVE_LIBGCRYPT guint8 *enc_buffer; guint8 *dec_buffer; gboolean decrypted; GSList **nwk_keyring; GSList *GSList_i; key_record_t *key_rec = NULL; #endif zbee_nwk_hints_t *nwk_hints; ieee802154_hints_t *ieee_hints; ieee802154_map_rec *map_rec = NULL; /* Init */ memset(&packet, 0, sizeof(zbee_security_packet)); /* Get pointers to any useful frame data from lower layers */ nwk_hints = (zbee_nwk_hints_t *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK)); ieee_hints = (ieee802154_hints_t *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN)); /* Create a subtree for the security information. */ if (tree) { sec_root = proto_tree_add_text(tree, tvb, offset, tvb_length_remaining(tvb, offset), "ZigBee Security Header"); sec_tree = proto_item_add_subtree(sec_root, ett_zbee_sec); } /* Get and display the Security control field */ packet.control = tvb_get_guint8(tvb, offset); /* Patch the security level. */ packet.control &= ~ZBEE_SEC_CONTROL_LEVEL; packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level); /* * Eww, I think I just threw up a little... ZigBee requires this field * to be patched before computing the MIC, but we don't have write-access * to the tvbuff. So we need to allocate a copy of the whole thing just * so we can fix these 3 bits. Memory allocated by ep_tvb_memdup() is * automatically freed before the next packet is processed. */ #ifdef HAVE_LIBGCRYPT enc_buffer = (guint8 *)ep_tvb_memdup(tvb, 0, tvb_length(tvb)); /* * Override the const qualifiers and patch the security level field, we * know it is safe to overide the const qualifiers because we just * allocated this memory via ep_tvb_memdup(). */ enc_buffer[offset] = packet.control; #endif /* HAVE_LIBGCRYPT */ packet.level = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL); packet.key_id = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); packet.nonce = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE); if (tree) { ti = proto_tree_add_text(sec_tree, tvb, offset, 1, "Security Control Field"); field_tree = proto_item_add_subtree(ti, ett_zbee_sec_control); proto_tree_add_uint(field_tree, hf_zbee_sec_key_id, tvb, offset, 1, packet.control & ZBEE_SEC_CONTROL_KEY); proto_tree_add_boolean(field_tree, hf_zbee_sec_nonce, tvb, offset, 1, packet.control & ZBEE_SEC_CONTROL_NONCE); } offset += 1; /* Get and display the frame counter field. */ packet.counter = tvb_get_letohl(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_counter, tvb, offset, 4, packet.counter); } offset += 4; if (packet.nonce) { /* Get and display the source address of the device that secured this payload. */ packet.src64 = tvb_get_letoh64(tvb, offset); if (tree) { proto_tree_add_item(sec_tree, hf_zbee_sec_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN); } #if 1 if (!pinfo->fd->flags.visited) { switch ( packet.key_id ) { case ZBEE_SEC_KEY_LINK: if (nwk_hints) { /* Map this long address with the nwk layer short address. */ nwk_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, nwk_hints->src, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->fd->num); } break; case ZBEE_SEC_KEY_NWK: if (ieee_hints) { /* Map this long address with the ieee short address. */ ieee_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, ieee_hints->src16, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->fd->num); } break; /* We ignore the extended source addresses used to encrypt payloads with these * types of keys, because they can emerge from APS tunnels created by nodes whose * short address is not recorded in the packet. */ case ZBEE_SEC_KEY_TRANSPORT: case ZBEE_SEC_KEY_LOAD: break; } } #endif offset += 8; } else { /* Look for a source address in hints */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: /* use the ieee extended source address for NWK decryption */ if ( ieee_hints && (map_rec = ieee_hints->map_rec) ) packet.src64 = map_rec->addr64; else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "[Extended Source: Unknown]"); break; default: /* use the nwk extended source address for APS decryption */ if ( nwk_hints && (map_rec = nwk_hints->map_rec) ) packet.src64 = map_rec->addr64; else if (tree) proto_tree_add_text(sec_tree, tvb, 0, 0, "[Extended Source: Unknown]"); break; } } if (packet.key_id == ZBEE_SEC_KEY_NWK) { /* Get and display the key sequence number. */ packet.key_seqno = tvb_get_guint8(tvb, offset); if (tree) { proto_tree_add_uint(sec_tree, hf_zbee_sec_key_seqno, tvb, offset, 1, packet.key_seqno); } offset += 1; } /* Determine the length of the MIC. */ switch (packet.level) { case ZBEE_SEC_ENC: case ZBEE_SEC_NONE: default: mic_len=0; break; case ZBEE_SEC_ENC_MIC32: case ZBEE_SEC_MIC32: mic_len=4; break; case ZBEE_SEC_ENC_MIC64: case ZBEE_SEC_MIC64: mic_len=8; break; case ZBEE_SEC_ENC_MIC128: case ZBEE_SEC_MIC128: mic_len=16; break; } /* switch */ /* Get and display the MIC. */ if (mic_len) { /* Display the MIC. */ if (tree) { proto_tree_add_item(sec_tree, hf_zbee_sec_mic, tvb, (gint)(tvb_length(tvb)-mic_len), mic_len, ENC_NA); } } /* Check for null payload. */ if ( !(payload_len = tvb_reported_length_remaining(tvb, offset+mic_len)) ) { return NULL; } else if ( payload_len < 0 ) { THROW(ReportedBoundsError); } /********************************************** * Perform Security Operations on the Frame * ********************************************** */ if ((packet.level == ZBEE_SEC_NONE) || (packet.level == ZBEE_SEC_MIC32) || (packet.level == ZBEE_SEC_MIC64) || (packet.level == ZBEE_SEC_MIC128)) { /* Payload is only integrity protected. Just return the sub-tvbuff. */ return tvb_new_subset(tvb, offset, payload_len, payload_len); } #ifdef HAVE_LIBGCRYPT /* Allocate memory to decrypt the payload into. */ dec_buffer = (guint8 *)g_malloc(payload_len); decrypted = FALSE; if ( packet.src64 ) { if (pinfo->fd->flags.visited) { if ( nwk_hints ) { /* Use previously found key */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: if ( (key_rec = nwk_hints->nwk) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->nwk->key); } break; default: if ( (key_rec = nwk_hints->link) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->link->key); } break; } } } /* ( !pinfo->fd->flags.visited ) */ else { /* We only search for sniffed keys in the first pass, * to save time, and because decrypting with keys * transported in future packets is cheating */ /* Lookup NWK and link key in hash for this pan. */ /* This overkill approach is a placeholder for a hash that looks up * a key ring for a link key associated with a pair of devices. */ if ( nwk_hints ) { nwk_keyring = (GSList **)g_hash_table_lookup(zbee_table_nwk_keyring, &nwk_hints->src_pan); if ( nwk_keyring ) { GSList_i = *nwk_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } /* Loop through user's password table for preconfigured keys, our last resort */ GSList_i = zbee_pc_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } } /* ( ! pinfo->fd->flags.visited ) */ } /* ( packet.src64 ) */ if ( decrypted ) { if ( tree && key_rec ) { if ( key_rec->frame_num == ZBEE_SEC_PC_KEY ) { ti = proto_tree_add_text(sec_tree, tvb, 0, 0, "Decryption Key: %s", key_rec->label); } else { ti = proto_tree_add_uint(sec_tree, hf_zbee_sec_key_origin, tvb, 0, 0, key_rec->frame_num); } PROTO_ITEM_SET_GENERATED(ti); } /* Found a key that worked, setup the new tvbuff_t and return */ payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); tvb_set_free_cb(payload_tvb, g_free); /* set up callback to free dec_buffer */ add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); /* Done! */ return payload_tvb; } g_free(dec_buffer); #endif /* HAVE_LIBGCRYPT */ /* Add expert info. */ expert_add_info_format(pinfo, sec_tree, PI_UNDECODED, PI_WARN, "Encrypted Payload"); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset(tvb, offset, payload_len, -1); /* Dump the payload to the data dissector. */ call_dissector(data_handle, payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* dissect_zbee_secure */