/* Set up an MSRP conversation using the info given */ void msrp_add_address( packet_info *pinfo, address *addr, int port, const gchar *setup_method, guint32 setup_frame_number) { address null_addr; conversation_t* p_conv; struct _msrp_conversation_info *p_conv_data = NULL; /* * If this isn't the first time this packet has been processed, * we've already done this work, so we don't need to do it * again. */ if (pinfo->fd->flags.visited) { return; } SET_ADDRESS(&null_addr, AT_NONE, 0, NULL); /* * Check if the ip address and port combination is not * already registered as a conversation. */ p_conv = find_conversation( pinfo->fd->num, addr, &null_addr, PT_TCP, port, 0, NO_ADDR_B | NO_PORT_B); /* * If not, create a new conversation. */ if (!p_conv) { p_conv = conversation_new( pinfo->fd->num, addr, &null_addr, PT_TCP, (guint32)port, 0, NO_ADDR2 | NO_PORT2); } /* Set dissector */ conversation_set_dissector(p_conv, msrp_handle); /* * Check if the conversation has data associated with it. */ p_conv_data = conversation_get_proto_data(p_conv, proto_msrp); /* * If not, add a new data item. */ if (!p_conv_data) { /* Create conversation data */ p_conv_data = se_alloc0(sizeof(struct _msrp_conversation_info)); conversation_add_proto_data(p_conv, proto_msrp, p_conv_data); } /* * Update the conversation data. */ p_conv_data->setup_method_set = TRUE; g_strlcpy(p_conv_data->setup_method, setup_method, MAX_MSRP_SETUP_METHOD_SIZE); p_conv_data->setup_frame_number = setup_frame_number; }
static void dissect_Conf2ACK(packet_info *pinfo) { /* Signals start of SRT(C)P streams */ struct srtp_info *dummy_srtp_info = se_alloc0(sizeof(struct srtp_info)); dummy_srtp_info->encryption_algorithm = SRTP_ENC_ALG_AES_CM; dummy_srtp_info->auth_algorithm = SRTP_AUTH_ALG_HMAC_SHA1; dummy_srtp_info->mki_len = 0; dummy_srtp_info->auth_tag_len = 4; srtp_add_address(pinfo, &pinfo->net_src, pinfo->srcport, pinfo->destport, "ZRTP", PINFO_FD_NUM(pinfo), FALSE, NULL, dummy_srtp_info); srtp_add_address(pinfo, &pinfo->net_dst, pinfo->destport, pinfo->srcport, "ZRTP", PINFO_FD_NUM(pinfo), FALSE, NULL, dummy_srtp_info); srtcp_add_address(pinfo, &pinfo->net_src, pinfo->srcport+1, pinfo->destport+1, "ZRTP", PINFO_FD_NUM(pinfo), dummy_srtp_info); srtcp_add_address(pinfo, &pinfo->net_dst, pinfo->destport+1, pinfo->srcport+1, "ZRTP", PINFO_FD_NUM(pinfo), dummy_srtp_info); col_set_str(pinfo->cinfo, COL_INFO, "Conf2ACK Packet"); }
/* * Returns an initialized MPA connection state or throws an out of * memory exception. */ static mpa_state_t * init_mpa_state(void) { mpa_state_t *state; state = (mpa_state_t *) se_alloc0(sizeof(mpa_state_t)); state->revision = -1; return state; }
static struct rlc_frag *rlc_frag_create(tvbuff_t *tvb, enum rlc_mode mode, packet_info *pinfo, guint16 offset, guint16 length, guint16 seq, guint16 li) { struct rlc_frag *frag; frag = se_alloc0(sizeof(struct rlc_frag)); rlc_frag_assign(frag, mode, pinfo, seq, li); rlc_frag_assign_data(frag, tvb, offset, length); return frag; }
/* 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(pinfo->fd, proto_mac_lte); if (p_mac_lte_info == NULL) { /* Allocate new info struct for this frame */ p_mac_lte_info = (struct mac_lte_info*)se_alloc0(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(pinfo->fd, proto_mac_lte, 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 h245_setup_channels(packet_info *pinfo, channel_info_t *upcoming_channel_lcl) { gint *key; GHashTable *rtp_dyn_payload = NULL; struct srtp_info *dummy_srtp_info = NULL; if (!upcoming_channel_lcl) return; /* T.38 */ if (!strcmp(upcoming_channel_lcl->data_type_str, "t38fax")) { if (upcoming_channel_lcl->media_addr.addr.type!=AT_NONE && upcoming_channel_lcl->media_addr.port!=0 && t38_handle) { t38_add_address(pinfo, &upcoming_channel_lcl->media_addr.addr, upcoming_channel_lcl->media_addr.port, 0, "H245", pinfo->fd->num); } return; } /* (S)RTP, (S)RTCP */ if (upcoming_channel_lcl->rfc2198 > 0) { encoding_name_and_rate_t *encoding_name_and_rate = g_malloc( sizeof(encoding_name_and_rate_t)); rtp_dyn_payload = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, free_encoding_name_str); encoding_name_and_rate->encoding_name = g_strdup("red"); encoding_name_and_rate->sample_rate = 8000; key = g_malloc(sizeof(gint)); *key = upcoming_channel_lcl->rfc2198; g_hash_table_insert(rtp_dyn_payload, key, encoding_name_and_rate); } if (upcoming_channel_lcl->srtp_flag) { dummy_srtp_info = se_alloc0(sizeof(struct srtp_info)); } /* DEBUG g_warning("h245_setup_channels media_addr.addr.type %u port %u",upcoming_channel_lcl->media_addr.addr.type, upcoming_channel_lcl->media_addr.port ); */ if (upcoming_channel_lcl->media_addr.addr.type!=AT_NONE && upcoming_channel_lcl->media_addr.port!=0 && rtp_handle) { srtp_add_address(pinfo, &upcoming_channel_lcl->media_addr.addr, upcoming_channel_lcl->media_addr.port, 0, "H245", pinfo->fd->num, upcoming_channel_lcl->is_video , rtp_dyn_payload, dummy_srtp_info); } if (upcoming_channel_lcl->media_control_addr.addr.type!=AT_NONE && upcoming_channel_lcl->media_control_addr.port!=0 && rtcp_handle) { srtcp_add_address(pinfo, &upcoming_channel_lcl->media_control_addr.addr, upcoming_channel_lcl->media_control_addr.port, 0, "H245", pinfo->fd->num, dummy_srtp_info); } }
static spx_hash_value* spx_hash_insert(conversation_t *conversation, guint32 spx_src, guint16 spx_seq) { spx_hash_key *key; spx_hash_value *value; /* Now remember the packet, so we can find it if we later. */ key = se_alloc(sizeof(spx_hash_key)); key->conversation = conversation; key->spx_src = spx_src; key->spx_seq = spx_seq; value = se_alloc0(sizeof(spx_hash_value)); g_hash_table_insert(spx_hash, key, value); return value; }
gcp_term_t* gcp_cmd_add_term(gcp_msg_t* m, gcp_trx_t* tr, gcp_cmd_t* c, gcp_term_t* t, gcp_wildcard_t wildcard, gboolean persistent) { gcp_terms_t* ct; gcp_terms_t* ct2; static gcp_term_t all_terms = {"$",(guint8*)"",1,GCP_TERM_TYPE_UNKNOWN,NULL,NULL,NULL}; if ( !c ) return NULL; if ( wildcard == GCP_WILDCARD_CHOOSE) { return &all_terms; } if (persistent) { if ( c->msg->commited ) { if (wildcard == GCP_WILDCARD_ALL) { for (ct = c->ctx->terms.next; ct; ct = ct->next) { /* XXX not handling more wilcards in one msg */ if ( ct->term->start == m ) { return ct->term; } } return NULL; } else { for (ct = c->ctx->terms.next; ct; ct = ct->next) { if ( g_str_equal(ct->term->str,t->str) ) { return ct->term; } } return NULL; } } else { for (ct = c->ctx->terms.next; ct; ct = ct->next) { if ( g_str_equal(ct->term->str,t->str) || ct->term->start == m) { break; } } if ( ! ct ) { if (wildcard == GCP_WILDCARD_ALL) { ct = se_alloc(sizeof(gcp_terms_t)); ct->next = NULL; ct->term = se_alloc0(sizeof(gcp_term_t)); ct->term->start = m; ct->term->str = "*"; ct->term->buffer = NULL; ct->term->len = 0; c->terms.last = c->terms.last->next = ct; ct2 = se_alloc0(sizeof(gcp_terms_t)); ct2->term = ct->term; c->ctx->terms.last->next = ct2; c->ctx->terms.last = ct2; return ct->term; } else { for (ct = c->ctx->terms.next; ct; ct = ct->next) { /* XXX not handling more wilcards in one msg */ if ( ct->term->buffer == NULL && tr->cmds->cmd->msg == ct->term->start ) { ct->term->str = se_strdup(t->str); ct->term->buffer = se_memdup(t->buffer,t->len); ct->term->len = t->len; ct2 = se_alloc0(sizeof(gcp_terms_t)); ct2->term = ct->term; c->terms.last = c->terms.last->next = ct2; return ct->term; } if ( g_str_equal(ct->term->str,t->str) ) { ct2 = se_alloc0(sizeof(gcp_terms_t)); ct2->term = ct->term; c->terms.last = c->terms.last->next = ct2; return ct->term; } } ct = se_alloc(sizeof(gcp_terms_t)); ct->next = NULL; ct->term = se_alloc0(sizeof(gcp_term_t)); ct->term->start = m; ct->term->str = se_strdup(t->str); ct->term->buffer = se_memdup(t->buffer,t->len); ct->term->len = t->len; ct2 = se_alloc0(sizeof(gcp_terms_t)); ct2->term = ct->term; c->terms.last = c->terms.last->next = ct2; ct2 = se_alloc0(sizeof(gcp_terms_t)); ct2->term = ct->term; c->ctx->terms.last = c->ctx->terms.last->next = ct2; return ct->term; } } else { ct2 = se_alloc0(sizeof(gcp_terms_t)); ct2->term = ct->term; c->terms.last = c->terms.last->next = ct2; return ct->term; } DISSECTOR_ASSERT_NOT_REACHED(); return NULL; } } else { ct = ep_new(gcp_terms_t); ct->term = t; ct->next = NULL; c->terms.last = c->terms.last->next = ct; return t; } }
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; } } }
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; } } }
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); }
/* Transfers happen in response to broadcasts, they are always TCP and are * used to send the file to the port mentioned in the broadcast. There are * 2 types of transfers: Pushes, which are direct responses to searches, * in which the peer that has the file connects to the peer that doesnt and * sends it, then disconnects. The other type of transfer is a pull, where * the peer that doesn't have the file connects to the peer that does and * requests it be sent. * * Pulls have a file request which identifies the desired file, * while pushes simply send the file. In practice this works because every * file the implementation sends searches for is on a different TCP port * on the searcher's machine. */ static int dissect_ldss_transfer (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { conversation_t *transfer_conv; ldss_transfer_info_t *transfer_info; struct tcpinfo *transfer_tcpinfo; proto_tree *ti, *line_tree = NULL, *ldss_tree = NULL; nstime_t broadcast_response_time; /* Look for the transfer conversation; this was created during * earlier broadcast dissection (see prepate_ldss_transfer_conv) */ transfer_conv = find_conversation (pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, pinfo->srcport, pinfo->destport, 0); transfer_info = (ldss_transfer_info_t *)conversation_get_proto_data(transfer_conv, proto_ldss); transfer_tcpinfo = (struct tcpinfo *)pinfo->private_data; /* For a pull, the first packet in the TCP connection is the file request. * First packet is identified by relative seq/ack numbers of 1. * File request only appears on a pull (triggered by an offer - see above * about broadcasts) */ if (transfer_tcpinfo->seq == 1 && transfer_tcpinfo->lastackseq == 1 && transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND) { /* LDSS pull transfers look a lot like HTTP. * Sample request: * md5:01234567890123... * Size: 2550 * Start: 0 * Compression: 0 * (remote end sends the file identified by the digest) */ guint offset = 0; gboolean already_dissected = TRUE; col_set_str(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Requesting file - pull)"); if (highest_num_seen == 0 || highest_num_seen < pinfo->fd->num) { already_dissected = FALSE; transfer_info->req = se_new0(ldss_file_request_t); transfer_info->req->file = se_new0(ldss_file_t); highest_num_seen = pinfo->fd->num; } if (tree) { ti = proto_tree_add_item(tree, proto_ldss, tvb, 0, tvb_reported_length(tvb), ENC_NA); ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer); } /* Populate digest data into the file struct in the request */ transfer_info->file = transfer_info->req->file; /* Grab each line from the packet, there should be 4 but lets * not walk off the end looking for more. */ while (offset < tvb_reported_length(tvb)) { gint next_offset; const guint8 *line; int linelen; gboolean is_digest_line; guint digest_type_len; linelen = tvb_find_line_end(tvb, offset, tvb_ensure_length_remaining(tvb, offset), &next_offset, FALSE); /* Include new-line in line */ line = (guint8 *)tvb_memdup(tvb, offset, linelen+1); /* XXX - memory leak? */ if (tree) { ti = proto_tree_add_text(ldss_tree, tvb, offset, linelen, "%s", tvb_format_text(tvb, offset, next_offset-offset)); line_tree = proto_item_add_subtree(ti, ett_ldss_transfer_req); } /* Reduce code duplication processing digest lines. * There are too many locals to pass to a function - the signature * looked pretty ugly when I tried! */ is_digest_line = FALSE; if (strncmp(line,"md5:",4)==0) { is_digest_line = TRUE; digest_type_len = 4; transfer_info->file->digest_type = DIGEST_TYPE_MD5; } else if (strncmp(line, "sha1:", 5)==0) { is_digest_line = TRUE; digest_type_len = 5; transfer_info->file->digest_type = DIGEST_TYPE_SHA1; } else if (strncmp(line, "sha256:", 7)==0) { is_digest_line = TRUE; digest_type_len = 7; transfer_info->file->digest_type = DIGEST_TYPE_SHA256; } else if (strncmp(line, "unknown:", 8)==0) { is_digest_line = TRUE; digest_type_len = 8; transfer_info->file->digest_type = DIGEST_TYPE_UNKNOWN; } else if (strncmp(line, "Size: ", 6)==0) { /* Sample size line: * Size: 2550\n */ transfer_info->req->size = g_ascii_strtoull(line+6, NULL, 10); if (tree) { ti = proto_tree_add_uint64(line_tree, hf_ldss_size, tvb, offset+6, linelen-6, transfer_info->req->size); PROTO_ITEM_SET_GENERATED(ti); } } else if (strncmp(line, "Start: ", 7)==0) { /* Sample offset line: * Start: 0\n */ transfer_info->req->offset = g_ascii_strtoull(line+7, NULL, 10); if (tree) { ti = proto_tree_add_uint64(line_tree, hf_ldss_offset, tvb, offset+7, linelen-7, transfer_info->req->offset); PROTO_ITEM_SET_GENERATED(ti); } } else if (strncmp(line, "Compression: ", 13)==0) { /* Sample compression line: * Compression: 0\n */ transfer_info->req->compression = (gint8)strtol(line+13, NULL, 10); /* XXX - bad cast */ if (tree) { ti = proto_tree_add_uint(line_tree, hf_ldss_compression, tvb, offset+13, linelen-13, transfer_info->req->compression); PROTO_ITEM_SET_GENERATED(ti); } } else { if (tree) { ti = proto_tree_add_text(line_tree, tvb, offset, linelen, "Unrecognized line ignored"); PROTO_ITEM_SET_GENERATED(ti); } } if (is_digest_line) { /* Sample digest-type/digest line: * md5:0123456789ABCDEF\n */ if (!already_dissected) { GByteArray *digest_bytes; digest_bytes = g_byte_array_new(); hex_str_to_bytes( tvb_get_ptr(tvb, offset+digest_type_len, linelen-digest_type_len), digest_bytes, FALSE); if(digest_bytes->len >= DIGEST_LEN) digest_bytes->len = (DIGEST_LEN-1); /* Ensure the digest is zero-padded */ transfer_info->file->digest = (guint8 *)se_alloc0(DIGEST_LEN); memcpy(transfer_info->file->digest, digest_bytes->data, digest_bytes->len); g_byte_array_free(digest_bytes, TRUE); } if (tree) { proto_item *tii = NULL; tii = proto_tree_add_uint(line_tree, hf_ldss_digest_type, tvb, offset, digest_type_len, transfer_info->file->digest_type); PROTO_ITEM_SET_GENERATED(tii); tii = proto_tree_add_bytes(line_tree, hf_ldss_digest, tvb, offset+digest_type_len, linelen-digest_type_len, transfer_info->file->digest); PROTO_ITEM_SET_GENERATED(tii); } } offset = next_offset; } /* Link forwards to the response for this pull. */ if (tree && transfer_info->resp_num != 0) { ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_in, tvb, 0, 0, transfer_info->resp_num); PROTO_ITEM_SET_GENERATED(ti); } transfer_info->req->num = pinfo->fd->num; transfer_info->req->ts = pinfo->fd->abs_ts; } /* Remaining packets are the file response */ else { guint64 size; guint64 offset; guint8 compression; /* size, digest, compression come from the file request for a pull but * they come from the broadcast for a push. Pushes don't bother * with a file request - they just send the data. We have to get file * info from the offer broadcast which triggered this transfer. * If we cannot find the file request, default to the broadcast. */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL) { transfer_info->file = transfer_info->req->file; size = transfer_info->req->size; offset = transfer_info->req->offset; compression = transfer_info->req->compression; } else { transfer_info->file = transfer_info->broadcast->file; size = transfer_info->broadcast->size; offset = transfer_info->broadcast->offset; compression = transfer_info->broadcast->compression; } /* Remaining data in this TCP connection is all file data. * Always desegment if the size is 0 (ie. unknown) */ if (pinfo->can_desegment) { if (size == 0 || tvb_length(tvb) < size) { pinfo->desegment_offset = 0; pinfo->desegment_len = DESEGMENT_UNTIL_FIN; return 0; } } /* OK. Now we have the whole file that was transferred. */ transfer_info->resp_num = pinfo->fd->num; transfer_info->resp_ts = pinfo->fd->abs_ts; col_add_fstr(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Sending file - %s)", transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND ? "pull" : "push"); if (tree) { ti = proto_tree_add_item(tree, proto_ldss, tvb, 0, tvb_reported_length(tvb), ENC_NA); ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer); proto_tree_add_bytes_format(ldss_tree, hf_ldss_file_data, tvb, 0, tvb_length(tvb), NULL, compression == COMPRESSION_GZIP ? "Gzip compressed data: %d bytes" : "File data: %d bytes", tvb_length(tvb)); #ifdef HAVE_LIBZ /* Be nice and uncompress the file data. */ if (compression == COMPRESSION_GZIP) { tvbuff_t *uncomp_tvb; uncomp_tvb = tvb_child_uncompress(tvb, tvb, 0, tvb_length(tvb)); if (uncomp_tvb != NULL) { /* XXX: Maybe not a good idea to add a data_source for what may very well be a large buffer since then the full uncompressed buffer will be shown in a tab in the hex bytes pane ? However, if we don't, bytes in an unrelated tab will be highlighted. */ add_new_data_source(pinfo, uncomp_tvb, "Uncompressed Data"); proto_tree_add_bytes_format_value(ldss_tree, hf_ldss_file_data, uncomp_tvb, 0, tvb_length(uncomp_tvb), NULL, "Uncompressed data: %d bytes", tvb_length(uncomp_tvb)); } } #endif ti = proto_tree_add_uint(ldss_tree, hf_ldss_digest_type, tvb, 0, 0, transfer_info->file->digest_type); PROTO_ITEM_SET_GENERATED(ti); if (transfer_info->file->digest != NULL) { /* This is ugly. You can't add bytes of nonzero length and have * filtering work correctly unless you give a valid location in * the packet. This hack pretends the first 32 bytes of the packet * are the digest, which they aren't: they're actually the first 32 * bytes of the file that was sent. */ ti = proto_tree_add_bytes(ldss_tree, hf_ldss_digest, tvb, 0, DIGEST_LEN, transfer_info->file->digest); } PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint64(ldss_tree, hf_ldss_size, tvb, 0, 0, size); PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint64(ldss_tree, hf_ldss_offset, tvb, 0, 0, offset); PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint(ldss_tree, hf_ldss_compression, tvb, 0, 0, compression); PROTO_ITEM_SET_GENERATED(ti); /* Link to the request for a pull. */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL && transfer_info->req->num != 0) { ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_to, tvb, 0, 0, transfer_info->req->num); PROTO_ITEM_SET_GENERATED(ti); } } } /* Print the pull response time */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL && transfer_info->resp_num != 0) { nstime_t pull_response_time; nstime_delta(&pull_response_time, &transfer_info->resp_ts, &transfer_info->req->ts); ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_response_time, tvb, 0, 0, &pull_response_time); PROTO_ITEM_SET_GENERATED(ti); } /* Link the transfer back to the initiating broadcast. Response time is * calculated as the time from broadcast to completed transfer. */ ti = proto_tree_add_uint(ldss_tree, hf_ldss_initiated_by, tvb, 0, 0, transfer_info->broadcast->num); PROTO_ITEM_SET_GENERATED(ti); if (transfer_info->resp_num != 0) { nstime_delta(&broadcast_response_time, &transfer_info->resp_ts, &transfer_info->broadcast->ts); ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_completed_in, tvb, 0, 0, &broadcast_response_time); PROTO_ITEM_SET_GENERATED(ti); } /* This conv got its addr2/port2 set by the TCP dissector because a TCP * connection was established. Make a new one to handle future connections * to the addr/port mentioned in the broadcast, because that socket is * still open. */ if (transfer_tcpinfo->seq == 1 && transfer_tcpinfo->lastackseq == 1) { prepare_ldss_transfer_conv(transfer_info->broadcast); } return tvb_length(tvb); }
static void dissect_rtmpt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *rtmpt_tree = NULL; proto_tree *rtmptroot_tree = NULL; proto_item *ti = NULL; gint offset = 0; struct tcpinfo* tcpinfo = pinfo->private_data; guint8 iCommand = -1; guint32 iLength = 1; guint16 iHeaderType = 4; guint16 iHeaderLength; guint8 iID; guint rtmp_index; conversation_t * current_conversation; rtmpt_conversation_data_t * conversation_data; rtmpt_packet_data_t * packet_data; rtmpt_chunk_data_t *current_chunk_data = NULL; rtmpt_chunk_data_t *initial_chunk_data = NULL; tvbuff_t* amf_tvb; current_conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (NULL != current_conversation) { conversation_data = (rtmpt_conversation_data_t*)conversation_get_proto_data(current_conversation, proto_rtmpt); if (NULL == conversation_data) { conversation_data = se_alloc0(sizeof(rtmpt_conversation_data_t)); conversation_add_proto_data(current_conversation, proto_rtmpt, conversation_data); conversation_data->current_chunks = g_hash_table_new(g_direct_hash, g_direct_equal); conversation_data->previous_frame_number = -1; conversation_data->current_chunk_size = RTMPT_DEFAULT_CHUNK_SIZE; conversation_data->is_rtmpe = 0; } packet_data = p_get_proto_data(pinfo->fd, proto_rtmpt); if (NULL == packet_data) { packet_data = se_alloc0(sizeof(rtmpt_packet_data_t)); p_add_proto_data(pinfo->fd, proto_rtmpt, packet_data); packet_data->initial_chunks = g_hash_table_new(g_direct_hash, g_direct_equal); packet_data->initial_chunk_size = conversation_data->current_chunk_size; } if (conversation_data->is_rtmpe == 1) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMPE"); return; } else { col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP"); } if (conversation_data->previous_frame_number != (guint) pinfo->fd->num) { conversation_data->current_chunk_size = packet_data->initial_chunk_size; } col_set_writable(pinfo->cinfo, TRUE); col_clear(pinfo->cinfo, COL_INFO); conversation_data->previous_frame_number = pinfo->fd->num; if (tvb_length_remaining(tvb, offset) >= 1) { if (tcpinfo->lastackseq == RTMPT_HANDSHAKE_OFFSET_1 && tcpinfo->seq == RTMPT_HANDSHAKE_OFFSET_1) { iCommand = RTMPT_TYPE_HANDSHAKE_1; } else if (tcpinfo->lastackseq == RTMPT_HANDSHAKE_OFFSET_2 && tcpinfo->seq == RTMPT_HANDSHAKE_OFFSET_1) iCommand = RTMPT_TYPE_HANDSHAKE_2; else if (tcpinfo->seq == RTMPT_HANDSHAKE_OFFSET_2 && tvb_length(tvb) == RTMPT_HANDSHAKE_LENGTH_3) iCommand = RTMPT_TYPE_HANDSHAKE_3; else { iID = tvb_get_guint8(tvb, offset + 0); iHeaderType = iID >> 6; rtmp_index = iID & 0x3F; current_chunk_data = g_hash_table_lookup(conversation_data->current_chunks, GUINT_TO_POINTER(rtmp_index)); initial_chunk_data = g_hash_table_lookup(packet_data->initial_chunks, GUINT_TO_POINTER(rtmp_index)); if (iHeaderType <= 2) iLength = tvb_get_ntoh24(tvb, offset + 4); if (iHeaderType <= 1) { iCommand = tvb_get_guint8(tvb, offset + 7); if (NULL == current_chunk_data) { current_chunk_data = se_alloc0(sizeof(rtmpt_chunk_data_t)); g_hash_table_insert(conversation_data->current_chunks, GUINT_TO_POINTER(rtmp_index), current_chunk_data); } current_chunk_data->data_type = iCommand; current_chunk_data->last_length = iLength; current_chunk_data->frame_modified = pinfo->fd->num; } else { /* must get the command type from the previous entries in the hash table */ /* try to use the current_chunk_data unless it is from a different frame */ if (NULL != current_chunk_data && NULL != initial_chunk_data) { /* we have precedent data (we should)*/ if (current_chunk_data->frame_modified != pinfo->fd->num) { iCommand = initial_chunk_data->data_type; iLength = initial_chunk_data->length_remaining; current_chunk_data->frame_modified = pinfo->fd->num; current_chunk_data->data_type = iCommand; current_chunk_data->last_length = iLength; current_chunk_data->dechunk_buffer = initial_chunk_data->dechunk_buffer; } else { iCommand = current_chunk_data->data_type; iLength = current_chunk_data->length_remaining; } if (iLength > conversation_data->current_chunk_size) { iLength = conversation_data->current_chunk_size; } } } } iHeaderLength = rtmpt_header_length_from_type(iHeaderType); if (check_col(pinfo->cinfo, COL_INFO)) { col_append_sep_fstr(pinfo->cinfo, COL_INFO, " | ", "%s", val_to_str(iCommand, rtmpt_opcode_vals, "Unknown (0x%01x)")); col_set_fence(pinfo->cinfo, COL_INFO); } if (tree) { ti = proto_tree_add_item(tree, proto_rtmpt, tvb, offset, -1, FALSE); proto_item_append_text(ti, " (%s)", val_to_str(iCommand, rtmpt_opcode_vals, "Unknown (0x%01x)")); rtmptroot_tree = proto_item_add_subtree(ti, ett_rtmpt); ti = proto_tree_add_text(rtmptroot_tree, tvb, offset, iHeaderLength, RTMPT_TEXT_RTMP_HEADER); proto_item_append_text(ti, " (%s)", val_to_str(iCommand, rtmpt_opcode_vals, "Unknown (0x%01x)")); rtmpt_tree = proto_item_add_subtree(ti, ett_rtmpt_header); if (iHeaderType <= 3) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_objid, tvb, offset + 0, 1, FALSE); if (iHeaderType <= 2) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_timestamp, tvb, offset + 1, 3, FALSE); if (iHeaderType <= 1) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_body_size, tvb, offset + 4, 3, FALSE); if (iHeaderType <= 1) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_function, tvb, offset + 7, 1, FALSE); if (iHeaderType <= 0) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_source, tvb, offset + 8, 4, TRUE); if (iCommand == RTMPT_TYPE_HANDSHAKE_1) { proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 1, 1536, FALSE); } else if (iCommand == RTMPT_TYPE_HANDSHAKE_2) { proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 1, 1536, FALSE); proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 1537, 1536, FALSE); } else if (iCommand == RTMPT_TYPE_HANDSHAKE_3) { proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 0, -1, FALSE); } else if (iCommand == RTMPT_TYPE_CHUNK_SIZE) { conversation_data->current_chunk_size = tvb_get_ntohl (tvb, offset + iHeaderLength); } offset = iHeaderLength; if (tvb_length_remaining(tvb, offset)) { ti = proto_tree_add_text(rtmptroot_tree, tvb, offset, -1, RTMPT_TEXT_RTMP_BODY); } if (iCommand == RTMPT_TYPE_INVOKE || iCommand == RTMPT_TYPE_NOTIFY) { guint iChunkSize = tvb_length_remaining(tvb, iHeaderLength); /* we have data which will be AMF */ /* we should add it to a new tvb */ if (NULL != current_chunk_data) { if (NULL == current_chunk_data->dechunk_buffer) { /* we have to create a new tvbuffer */ current_chunk_data->dechunk_buffer = tvb_new_composite(); } if (!(current_chunk_data->dechunk_buffer->initialized)) { /* add the existing data to the new buffer */ tvb_composite_append(current_chunk_data->dechunk_buffer, tvb_new_real_data(tvb_memdup(tvb, iHeaderLength, iChunkSize), iChunkSize, iChunkSize)); if (current_chunk_data->length_remaining <= 0) { guint amf_length; guint8* amf_data; tvb_composite_finalize(current_chunk_data->dechunk_buffer); amf_length = tvb_length(current_chunk_data->dechunk_buffer); if (amf_length == 0) { return; } amf_data = tvb_memdup(current_chunk_data->dechunk_buffer, 0, amf_length); amf_tvb = tvb_new_real_data(amf_data, tvb_length_remaining(current_chunk_data->dechunk_buffer, 0), tvb_length_remaining(current_chunk_data->dechunk_buffer, 0)); add_new_data_source(pinfo, amf_tvb, "Dechunked AMF data"); ti = proto_tree_add_item(tree, proto_rtmpt, amf_tvb, 0, -1, FALSE); rtmpt_tree = proto_item_add_subtree(ti, ett_rtmpt_body); proto_tree_set_appendix(rtmpt_tree, amf_tvb, 0, tvb_length_remaining(amf_tvb, 0)); proto_item_append_text(rtmpt_tree, " (%s)", "AMF Data"); dissect_rtmpt_amf(amf_tvb, rtmpt_tree); current_chunk_data->dechunk_buffer = NULL; } } } } } } }
static struct rlc_sdu *rlc_sdu_create(void) { struct rlc_sdu *sdu; sdu = se_alloc0(sizeof(struct rlc_sdu)); return sdu; }