static void dissect_smtp_data(tvbuff_t *tvb, int offset, proto_tree *smtp_tree) { gint next_offset; if (smtp_tree) { while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_text(smtp_tree, tvb, offset, next_offset - offset, "Message: %s", tvb_format_text(tvb, offset, next_offset - offset)); /* * Step to the next line. */ offset = next_offset; } } }
WSLUA_CONSTRUCTOR TvbRange_tvb (lua_State *L) { /* Creates a (sub)Tvb from using a TvbRange */ #define WSLUA_ARG_Tvb_new_subset_RANGE 1 /* The TvbRange from which to create the new Tvb. */ TvbRange tvbr = checkTvbRange(L,WSLUA_ARG_Tvb_new_subset_RANGE); Tvb tvb; if (! (tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } if (tvb_offset_exists(tvbr->tvb->ws_tvb, tvbr->offset + tvbr->len -1 )) { tvb = (Tvb)g_malloc(sizeof(struct _wslua_tvb)); tvb->expired = FALSE; tvb->need_free = FALSE; tvb->ws_tvb = tvb_new_subset(tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len, tvbr->len); PUSH_TVB(L, tvb); return 1; } else { luaL_error(L,"Out Of Bounds"); return 0; } }
static void add_dix_trailer(packet_info *pinfo, proto_tree *tree, proto_tree *fh_tree, int trailer_id, tvbuff_t *tvb, tvbuff_t *next_tvb, int offset_after_etype, guint length_before, gint fcs_len) { guint length; tvbuff_t *trailer_tvb; /* OK, how much is there in that tvbuff now? */ length = tvb_reported_length(next_tvb); /* If there's less than there was before, what's left is a trailer. */ if (length < length_before) { /* * Is any of the padding present in the tvbuff? */ if (tvb_offset_exists(tvb, offset_after_etype + length)) { /* * Yes - create a tvbuff for the padding. */ trailer_tvb = tvb_new_subset_remaining(tvb, offset_after_etype + length); } else { /* * No - don't bother showing the trailer. * XXX - show a Short Frame indication? */ trailer_tvb = NULL; } } else trailer_tvb = NULL; /* no trailer */ add_ethernet_trailer(pinfo, tree, fh_tree, trailer_id, tvb, trailer_tvb, fcs_len); }
static void dissect_smtp_data(tvbuff_t *tvb, int offset, proto_tree *smtp_tree) { gint next_offset; if (smtp_tree) { 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_item(smtp_tree, hf_smtp_message, tvb, offset, next_offset - offset, ENC_ASCII|ENC_NA); /* * Step to the next line. */ offset = next_offset; } } }
static void dissect_msnms(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *msnms_tree; proto_item *ti; gint offset = 0; const guchar *line; gint next_offset; int linelen; /* int tokenlen; */ /* const guchar *next_token; */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSNMS"); /* * 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 (check_col(pinfo->cinfo, COL_INFO)) { /* * Put the first line from the buffer into the summary. */ col_add_str(pinfo->cinfo, COL_INFO, format_text(line, linelen)); } if (tree) { ti = proto_tree_add_item(tree, proto_msnms, tvb, offset, -1, FALSE); msnms_tree = proto_item_add_subtree(ti, ett_msnms); /* * Show the rest of the packet as text, * a line at a time. */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_text(msnms_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } }
static void dissect_rsh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *rsh_tree; proto_item *ti, *hidden_item; gint offset = 0; gint next_offset; int linelen; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RSH"); if (check_col(pinfo->cinfo, COL_INFO)) { /* Put the first line from the buffer into the summary. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); linelen = next_offset - offset; /* include the line terminator */ /* * Make sure the line terminator isn't past the end of * the captured data in the packet, so we don't throw * an exception in the "tvb_get_ptr()" call. */ if (linelen > (int) tvb_length(tvb)) linelen = tvb_length(tvb); col_add_str(pinfo->cinfo, COL_INFO, tvb_format_text(tvb, offset, linelen)); } if (tree) { ti = proto_tree_add_item(tree, proto_rsh, tvb, offset, -1, FALSE); rsh_tree = proto_item_add_subtree(ti, ett_rsh); /* * Process the packet data, 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_text(rsh_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } if (pinfo->match_port == pinfo->destport) { hidden_item = proto_tree_add_boolean(rsh_tree, hf_rsh_request, tvb, 0, 0, 1); } else { hidden_item = proto_tree_add_boolean(rsh_tree, hf_rsh_response, tvb, 0, 0, 1); } PROTO_ITEM_SET_HIDDEN(hidden_item); } }
static void dissect_auto_rp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint8 ver_type, rp_count; col_set_str(pinfo->cinfo, COL_PROTOCOL, "Auto-RP"); col_clear(pinfo->cinfo, COL_INFO); ver_type = tvb_get_guint8(tvb, 0); rp_count = tvb_get_guint8(tvb, 1); if (check_col(pinfo->cinfo, COL_INFO)) col_add_fstr(pinfo->cinfo, COL_INFO, "%s (v%s) for %u RP%s", val_to_str(lo_nibble(ver_type), auto_rp_type_vals, "Unknown"), val_to_str(hi_nibble(ver_type), auto_rp_ver_vals, "Unknown"), rp_count, plurality(rp_count, "", "s")); if (tree) { proto_item *ti, *tv; proto_tree *auto_rp_tree, *ver_type_tree; int i, offset; guint16 holdtime; offset = 0; ti = proto_tree_add_item(tree, proto_auto_rp, tvb, offset, -1, FALSE); auto_rp_tree = proto_item_add_subtree(ti, ett_auto_rp); tv = proto_tree_add_text(auto_rp_tree, tvb, offset, 1, "Version: %s, Packet type: %s", val_to_str(hi_nibble(ver_type), auto_rp_ver_vals, "Unknown"), val_to_str(lo_nibble(ver_type), auto_rp_type_vals, "Unknown")); ver_type_tree = proto_item_add_subtree(tv, ett_auto_rp_ver_type); proto_tree_add_uint(ver_type_tree, hf_auto_rp_version, tvb, offset, 1, ver_type); proto_tree_add_uint(ver_type_tree, hf_auto_rp_type, tvb, offset, 1, ver_type); offset++; proto_tree_add_uint(auto_rp_tree, hf_auto_rp_count, tvb, offset, 1, rp_count); offset++; holdtime = tvb_get_ntohs(tvb, offset); proto_tree_add_uint_format_value(auto_rp_tree, hf_auto_rp_holdtime, tvb, offset, 2, holdtime, "%u second%s", holdtime, plurality(holdtime, "", "s")); offset+=2; proto_tree_add_text(auto_rp_tree, tvb, offset, 4, "Reserved: 0x%x", tvb_get_ntohs(tvb, offset)); offset+=4; for (i = 0; i < rp_count; i++) offset = do_auto_rp_map(tvb, offset, auto_rp_tree); if (tvb_offset_exists(tvb, offset)) proto_tree_add_text(tree, tvb, offset, -1, "Trailing junk"); } return; }
/* ---------------------------- */ static void dissect_nasdaq_soup(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *nasdaq_soup_tree = NULL; guint8 nasdaq_soup_type; int linelen; gint next_offset; int offset = 0; gint col_info; gint counter = 0; col_info = check_col(pinfo->cinfo, COL_INFO); while (tvb_offset_exists(tvb, offset)) { /* there's only a \n no \r */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, nasdaq_soup_desegment && pinfo->can_desegment); if (linelen == -1) { /* * 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 one more byte * (we may need more, but we'll try again if what we get next * isn't enough), and return. */ pinfo->desegment_offset = offset; pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT; return; } nasdaq_soup_type = tvb_get_guint8(tvb, offset); if (counter == 0) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "Nasdaq-SOUP"); if (col_info) col_clear(pinfo->cinfo, COL_INFO); } if (col_info ) { if (counter) { col_append_str(pinfo->cinfo, COL_INFO, "; "); col_set_fence(pinfo->cinfo, COL_INFO); } col_append_str(pinfo->cinfo, COL_INFO, val_to_str(nasdaq_soup_type, message_types_val, "Unknown packet type (0x%02x)")); } counter++; if (tree) { ti = proto_tree_add_item(tree, proto_nasdaq_soup, tvb, offset, linelen +1, ENC_NA); nasdaq_soup_tree = proto_item_add_subtree(ti, ett_nasdaq_soup); } dissect_nasdaq_soup_packet(tvb, pinfo, tree, nasdaq_soup_tree, offset, linelen); offset = next_offset; } }
static void dissect_irc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *irc_tree, *ti; gint offset = 0; gint next_offset; int linelen; col_set_str(pinfo->cinfo, COL_PROTOCOL, "IRC"); col_set_str(pinfo->cinfo, COL_INFO, (pinfo->match_uint == pinfo->destport) ? "Request" : "Response"); ti = proto_tree_add_item(tree, proto_irc, tvb, 0, -1, ENC_NA); irc_tree = proto_item_add_subtree(ti, ett_irc); /* * Process the packet data, a line at a time. */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (next_offset == offset) { /* * XXX - we really want the "show data a * line at a time" loops in various * dissectors to do reassembly and to * throw an exception if there's no * line ending in the current packet * and we're not doing reassembly. */ break; } if (linelen != 0) { if (pinfo->match_uint == pinfo->destport) { dissect_irc_request(irc_tree, tvb, pinfo, offset, linelen); } else { dissect_irc_response(irc_tree, tvb, pinfo, offset, linelen); } } offset = next_offset; } }
/* Main dissection function. */ static void dissect_sipfrag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *sipfrag_tree; proto_item *ti; gint offset = 0; gint next_offset; int linelen; char *string; gint lines = 0; /* Append this protocol name rather than replace. */ col_append_str(pinfo->cinfo, COL_PROTOCOL, "/sipfrag"); /* Add mention of this protocol to info column */ col_append_str(pinfo->cinfo, COL_INFO, ", with Sipfrag"); /* Create sipfrag tree. */ ti = proto_tree_add_item(tree, proto_sipfrag, tvb, offset, -1, ENC_NA); sipfrag_tree = proto_item_add_subtree(ti, ett_sipfrag); /* Show the sipfrag message a line at a time. */ while (tvb_offset_exists(tvb, offset)) { /* Find the end of the line. */ linelen = tvb_find_line_end_unquoted(tvb, offset, -1, &next_offset); /* For now, add all lines as unparsed strings */ /* Extract & add the string. */ string = (char*)tvb_get_string(wmem_packet_scope(), tvb, offset, linelen); proto_tree_add_string_format(sipfrag_tree, hf_sipfrag_line, tvb, offset, linelen, string, "%s", string); lines++; /* Show first line in info column */ if (lines == 1) { col_append_fstr(pinfo->cinfo, COL_INFO, "(%s", string); } /* Move onto next line. */ offset = next_offset; } /* Close off summary of sipfrag in info column */ col_append_str(pinfo->cinfo, COL_INFO, (lines > 1) ? "...)" : ")"); }
/* * Unless the first boundary, subsequent boundaries include a line-end sequence * before the dashed boundary string. * * Return the offset to the 1st byte of the boundary delimiter line. * Set boundary_line_len to the length of the entire boundary delimiter. * Set last_boundary to TRUE if we've seen the last-boundary delimiter. */ static gint find_next_boundary(tvbuff_t *tvb, gint start, const guint8 *boundary, gint boundary_len, gint *boundary_line_len, gboolean *last_boundary) { gint offset = start, next_offset, line_len, boundary_start; while (tvb_offset_exists(tvb, offset + 2 + boundary_len)) { line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (line_len == -1) { return -1; } boundary_start = offset + line_len; if (((tvb_strneql(tvb, next_offset, (const guint8 *)"--", 2) == 0) && (tvb_strneql(tvb, next_offset + 2, boundary, boundary_len) == 0))) { /* Boundary string; now check if last */ if ((tvb_reported_length_remaining(tvb, next_offset + 2 + boundary_len + 2) >= 0) && (tvb_strneql(tvb, next_offset + 2 + boundary_len, (const guint8 *)"--", 2) == 0)) { *last_boundary = TRUE; } else { *last_boundary = FALSE; } /* Look for line end of the boundary line */ line_len = tvb_find_line_end(tvb, next_offset, -1, &offset, FALSE); if (line_len == -1) { *boundary_line_len = -1; } else { *boundary_line_len = offset - boundary_start; } return boundary_start; /* check if last before CRLF; some ignore the standard, so there is no CRLF before the boundary */ } else if ((tvb_strneql(tvb, boundary_start - 2, (const guint8 *)"--", 2) == 0) && (tvb_strneql(tvb, boundary_start - (2 + boundary_len), boundary, boundary_len) == 0) && (tvb_strneql(tvb, boundary_start - (2 + boundary_len + 2), (const guint8 *)"--", 2) == 0)) { boundary_start -= 2 + boundary_len + 2; *boundary_line_len = next_offset - boundary_start; *last_boundary = TRUE; return boundary_start; } offset = next_offset; } return -1; }
static void tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, guint16 opcode, tftp_conv_info_t *tftp_info) { int option_len, value_len; int value_offset; const char *optionname; const char *optionvalue; proto_tree *opt_tree; while (tvb_offset_exists(tvb, offset)) { /* option_len and value_len include the trailing 0 byte */ option_len = tvb_strsize(tvb, offset); value_offset = offset + option_len; value_len = tvb_strsize(tvb, value_offset); /* use xxx_len-1 to exclude the trailing 0 byte, it would be displayed as nonprinting character tvb_format_text() creates a temporary 0-terminated buffer */ optionname = tvb_format_text(tvb, offset, option_len-1); optionvalue = tvb_format_text(tvb, value_offset, value_len-1); opt_tree = proto_tree_add_subtree_format(tree, tvb, offset, option_len+value_len, ett_tftp_option, NULL, "Option: %s = %s", optionname, optionvalue); proto_tree_add_item(opt_tree, hf_tftp_option_name, tvb, offset, option_len, ENC_ASCII|ENC_NA); proto_tree_add_item(opt_tree, hf_tftp_option_value, tvb, value_offset, value_len, ENC_ASCII|ENC_NA); offset += option_len + value_len; col_append_fstr(pinfo->cinfo, COL_INFO, ", %s=%s", optionname, optionvalue); /* Special code to handle individual options */ if (!g_ascii_strcasecmp((const char *)optionname, "blksize") && opcode == TFTP_OACK) { gint blocksize = (gint)strtol((const char *)optionvalue, NULL, 10); if (blocksize < 8 || blocksize > 65464) { expert_add_info(pinfo, NULL, &ei_tftp_blocksize_range); } else { tftp_info->blocksize = blocksize; } } } }
/* * Display the entire message as raw text. */ static void tvb_raw_text_add(tvbuff_t *tvb, proto_tree *tree) { int offset, next_offset, linelen; offset = 0; while (tvb_offset_exists(tvb, offset)) { /* 'desegment' is FALSE so will set next_offset to beyond the end of the buffer if no line ending is found */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); linelen = next_offset - offset; if(tree) { proto_tree_add_text(tree, tvb, offset, linelen, "%s", tvb_format_text(tvb, offset, linelen)); } offset = next_offset; } }
static void tftp_dissect_options(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, guint16 opcode, tftp_conv_info_t *tftp_info) { int option_len, value_len; int value_offset; const char *optionname; const char *optionvalue; proto_item *opt_item; proto_tree *opt_tree; while (tvb_offset_exists(tvb, offset)) { option_len = tvb_strsize(tvb, offset); /* length of option */ value_offset = offset + option_len; value_len = tvb_strsize(tvb, value_offset); /* length of value */ optionname = tvb_format_text(tvb, offset, option_len); optionvalue = tvb_format_text(tvb, value_offset, value_len); opt_item = proto_tree_add_text(tree, tvb, offset, option_len+value_len, "Option: %s = %s", optionname, optionvalue); opt_tree = proto_item_add_subtree(opt_item, ett_tftp_option); proto_tree_add_item(opt_tree, hf_tftp_option_name, tvb, offset, option_len, ENC_ASCII|ENC_NA); proto_tree_add_item(opt_tree, hf_tftp_option_value, tvb, value_offset, value_len, ENC_ASCII|ENC_NA); offset += option_len + value_len; col_append_fstr(pinfo->cinfo, COL_INFO, ", %s=%s", optionname, optionvalue); /* Special code to handle individual options */ if (!g_ascii_strcasecmp((const char *)optionname, "blksize") && opcode == TFTP_OACK) { gint blocksize = (gint)strtol((const char *)optionvalue, NULL, 10); if (blocksize < 8 || blocksize > 65464) { expert_add_info(pinfo, NULL, &ei_tftp_blocksize_range); } else { tftp_info->blocksize = blocksize; } } } }
/* * The first boundary does not implicitly contain the leading * line-end sequence. * * Return the offset to the 1st byte of the boundary delimiter line. * Set boundary_line_len to the length of the entire boundary delimiter. * Set last_boundary to TRUE if we've seen the last-boundary delimiter. */ static gint find_first_boundary(tvbuff_t *tvb, gint start, const guint8 *boundary, gint boundary_len, gint *boundary_line_len, gboolean *last_boundary) { gint offset = start, next_offset, line_len, boundary_start; while (tvb_offset_exists(tvb, offset + 2 + boundary_len)) { boundary_start = offset; if (((tvb_strneql(tvb, offset, (const guint8 *)"--", 2) == 0) && (tvb_strneql(tvb, offset + 2, boundary, boundary_len) == 0))) { /* Boundary string; now check if last */ if ((tvb_reported_length_remaining(tvb, offset + 2 + boundary_len + 2) >= 0) && (tvb_strneql(tvb, offset + 2 + boundary_len, (const guint8 *)"--", 2) == 0)) { *last_boundary = TRUE; } else { *last_boundary = FALSE; } /* Look for line end of the boundary line */ line_len = tvb_find_line_end(tvb, offset, -1, &offset, FALSE); if (line_len == -1) { *boundary_line_len = -1; } else { *boundary_line_len = offset - boundary_start; } return boundary_start; } line_len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (line_len == -1) { return -1; } offset = next_offset; } return -1; }
static void dissect_ncp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean is_tcp) { proto_tree *ncp_tree = NULL; proto_item *ti; struct ncp_ip_header ncpiph; struct ncp_ip_rqhdr ncpiphrq; guint16 ncp_burst_seqno, ncp_ack_seqno; guint16 flags = 0; proto_tree *flags_tree = NULL; int hdr_offset = 0; int commhdr = 0; int offset = 0; gint length_remaining; tvbuff_t *next_tvb; guint32 testvar = 0, ncp_burst_command, burst_len, burst_off, burst_file; guint8 subfunction; guint32 nw_connection = 0, data_offset; guint16 data_len = 0; guint16 missing_fraglist_count = 0; mncp_rhash_value *request_value = NULL; conversation_t *conversation; proto_item *expert_item; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NCP"); col_clear(pinfo->cinfo, COL_INFO); ncp_hdr = &header; ti = proto_tree_add_item(tree, proto_ncp, tvb, 0, -1, ENC_NA); ncp_tree = proto_item_add_subtree(ti, ett_ncp); if (is_tcp) { if (tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RQST && tvb_get_ntohl(tvb, hdr_offset) != NCPIP_RPLY) commhdr += 1; /* Get NCPIP Header data */ ncpiph.signature = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_sig, tvb, commhdr, 4, ncpiph.signature); ncpiph.length = (0x7fffffff & tvb_get_ntohl(tvb, commhdr+4)); proto_tree_add_uint(ncp_tree, hf_ncp_ip_length, tvb, commhdr+4, 4, ncpiph.length); commhdr += 8; if (ncpiph.signature == NCPIP_RQST) { ncpiphrq.version = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_ver, tvb, commhdr, 4, ncpiphrq.version); commhdr += 4; ncpiphrq.rplybufsize = tvb_get_ntohl(tvb, commhdr); proto_tree_add_uint(ncp_tree, hf_ncp_ip_rplybufsize, tvb, commhdr, 4, ncpiphrq.rplybufsize); commhdr += 4; } /* Check to see if this is a valid offset, otherwise increment for packet signature */ if (try_val_to_str(tvb_get_ntohs(tvb, commhdr), ncp_type_vals)==NULL) { /* Check to see if we have a valid type after packet signature length */ if (try_val_to_str(tvb_get_ntohs(tvb, commhdr+8), ncp_type_vals)!=NULL) { proto_tree_add_item(ncp_tree, hf_ncp_ip_packetsig, tvb, commhdr, 8, ENC_NA); commhdr += 8; } } } else { /* Initialize this structure, we use it below */ memset(&ncpiph, 0, sizeof(ncpiph)); } header.type = tvb_get_ntohs(tvb, commhdr); header.sequence = tvb_get_guint8(tvb, commhdr+2); header.conn_low = tvb_get_guint8(tvb, commhdr+3); header.task = tvb_get_guint8(tvb, commhdr+4); header.conn_high = tvb_get_guint8(tvb, commhdr+5); proto_tree_add_uint(ncp_tree, hf_ncp_type, tvb, commhdr, 2, header.type); nw_connection = (header.conn_high*256)+header.conn_low; /* Ok, we need to track the conversation so that we can * determine if a new server session is occuring for this * connection. */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); if ((ncpiph.length & 0x80000000) || ncpiph.signature == NCPIP_RPLY) { /* First time through we will record the initial connection and task * values */ if (!pinfo->fd->flags.visited) { if (conversation != NULL) { /* find the record telling us the * request made that caused this * reply */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); /* if for some reason we have no * conversation in our hash, create * one */ if (request_value == NULL) { mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } } else { /* It's not part of any conversation * - create a new one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } /* If this is a request packet then we * might have a new task */ if (ncpiph.signature == NCPIP_RPLY) { /* Now on reply packets we have to * use the state of the original * request packet, so look up the * request value and check the task number */ /*request_value = mncp_hash_lookup(conversation, nw_connection, header.task);*/ } } else { /* Get request value data */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); if (request_value) { if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn) { expert_add_info_format(pinfo, NULL, &ei_ncp_new_server_session, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task); } } } } else { if (!pinfo->fd->flags.visited) { if (conversation != NULL) { /* find the record telling us the * request made that caused this * reply */ request_value = mncp_hash_lookup(conversation, nw_connection, header.task); /* if for some reason we have no * conversation in our hash, create * one */ if (request_value == NULL) { mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } } else { /* It's not part of any conversation * - create a new one. */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_NCP, (guint32) pinfo->srcport, (guint32) pinfo->destport, 0); mncp_hash_insert(conversation, nw_connection, header.task, pinfo); } /* find the record telling us the request * made that caused this reply */ } else { request_value = mncp_hash_lookup(conversation, nw_connection, header.task); if (request_value) { if ((request_value->session_start_packet_num == pinfo->fd->num) && ncp_echo_conn) { expert_add_info_format(pinfo, NULL, &ei_ncp_new_server_session, "Detected New Server Session. Connection %d, Task %d", nw_connection, header.task); } } } } tap_queue_packet(ncp_tap.hdr, pinfo, ncp_hdr); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); /* * Process the packet-type-specific header. */ switch (header.type) { case NCP_BROADCAST_SLOT: /* Server Broadcast */ proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence); proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection); proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_oplock_flag, tvb, commhdr + 9, 1, tvb_get_guint8(tvb, commhdr+9)); proto_tree_add_item(ncp_tree, hf_ncp_oplock_handle, tvb, commhdr + 10, 4, ENC_BIG_ENDIAN); if ((tvb_get_guint8(tvb, commhdr+9)==0x24) && ncp_echo_file) { expert_add_info_format(pinfo, NULL, &ei_ncp_oplock_handle, "Server requesting station to clear oplock on handle - %08x", tvb_get_ntohl(tvb, commhdr+10)); } break; case NCP_LIP_ECHO: /* Lip Echo Packet */ proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr, 13, ENC_ASCII|ENC_NA); break; case NCP_BURST_MODE_XFER: /* Packet Burst Packet */ /* * XXX - we should keep track of whether there's a burst * outstanding on a connection and, if not, treat the * beginning of the data as a burst header. * * The burst header contains: * * 4 bytes of little-endian function number: * 1 = read, 2 = write; * * 4 bytes of file handle; * * 8 reserved bytes; * * 4 bytes of big-endian file offset; * * 4 bytes of big-endian byte count. * * The data follows for a burst write operation. * * The first packet of a burst read reply contains: * * 4 bytes of little-endian result code: * 0: No error * 1: Initial error * 2: I/O error * 3: No data read; * * 4 bytes of returned byte count (big-endian?). * * The data follows. * * Each burst of a write request is responded to with a * burst packet with a 2-byte little-endian result code: * * 0: Write successful * 4: Write error */ flags = tvb_get_guint8(tvb, commhdr + 2); ti = proto_tree_add_uint(ncp_tree, hf_ncp_system_flags, tvb, commhdr + 2, 1, flags); flags_tree = proto_item_add_subtree(ti, ett_ncp_system_flags); proto_tree_add_item(flags_tree, hf_ncp_system_flags_abt, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & ABT) { proto_item_append_text(ti, " ABT"); } flags&=(~( ABT )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_bsy, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & BSY) { proto_item_append_text(ti, " BSY"); } flags&=(~( BSY )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_eob, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & EOB) { proto_item_append_text(ti, " EOB"); } flags&=(~( EOB )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_lst, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & LST) { proto_item_append_text(ti, " LST"); } flags&=(~( LST )); proto_tree_add_item(flags_tree, hf_ncp_system_flags_sys, tvb, commhdr + 2, 1, ENC_BIG_ENDIAN); if (flags & SYS) { proto_item_append_text(ti, " SYS"); } flags&=(~( SYS )); proto_tree_add_item(ncp_tree, hf_ncp_stream_type, tvb, commhdr + 3, 1, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_src_connection, tvb, commhdr + 4, 4, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_dst_connection, tvb, commhdr + 8, 4, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_packet_seqno, tvb, commhdr + 12, 4, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_delay_time, tvb, commhdr + 16, 4, ENC_BIG_ENDIAN); ncp_burst_seqno = tvb_get_ntohs(tvb, commhdr+20); proto_tree_add_item(ncp_tree, hf_ncp_burst_seqno, tvb, commhdr + 20, 2, ENC_BIG_ENDIAN); ncp_ack_seqno = tvb_get_ntohs(tvb, commhdr+22); proto_tree_add_item(ncp_tree, hf_ncp_ack_seqno, tvb, commhdr + 22, 2, ENC_BIG_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_burst_len, tvb, commhdr + 24, 4, ENC_BIG_ENDIAN); data_offset = tvb_get_ntohl(tvb, commhdr + 28); proto_tree_add_uint(ncp_tree, hf_ncp_data_offset, tvb, commhdr + 28, 4, data_offset); data_len = tvb_get_ntohs(tvb, commhdr + 32); proto_tree_add_uint(ncp_tree, hf_ncp_data_bytes, tvb, commhdr + 32, 2, data_len); missing_fraglist_count = tvb_get_ntohs(tvb, commhdr + 34); proto_tree_add_item(ncp_tree, hf_ncp_missing_fraglist_count, tvb, commhdr + 34, 2, ENC_BIG_ENDIAN); offset = commhdr + 36; if (!(flags & SYS) && ncp_burst_seqno == ncp_ack_seqno && data_offset == 0) { /* * This is either a Burst Read or Burst Write * command. The data length includes the burst * mode header, plus any data in the command * (there shouldn't be any in a read, but there * might be some in a write). */ if (data_len < 4) return; ncp_burst_command = tvb_get_ntohl(tvb, offset); proto_tree_add_item(ncp_tree, hf_ncp_burst_command, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; data_len -= 4; if (data_len < 4) return; burst_file = tvb_get_ntohl(tvb, offset); proto_tree_add_item(ncp_tree, hf_ncp_burst_file_handle, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; data_len -= 4; if (data_len < 8) return; proto_tree_add_item(ncp_tree, hf_ncp_burst_reserved, tvb, offset, 8, ENC_NA); offset += 8; data_len -= 8; if (data_len < 4) return; burst_off = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(ncp_tree, hf_ncp_burst_offset, tvb, offset, 4, burst_off); offset += 4; data_len -= 4; if (data_len < 4) return; burst_len = tvb_get_ntohl(tvb, offset); proto_tree_add_uint(ncp_tree, hf_ncp_burst_len, tvb, offset, 4, burst_len); offset += 4; data_len -= 4; col_add_fstr(pinfo->cinfo, COL_INFO, "%s %d bytes starting at offset %d in file 0x%08x", val_to_str(ncp_burst_command, burst_command, "Unknown (0x%08x)"), burst_len, burst_off, burst_file); break; } else { if (tvb_get_guint8(tvb, commhdr + 2) & 0x10) { col_set_str(pinfo->cinfo, COL_INFO, "End of Burst"); } } break; case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */ length_remaining = tvb_length_remaining(tvb, commhdr + 4); if (length_remaining > 4) { testvar = tvb_get_ntohl(tvb, commhdr+4); if (testvar == 0x4c495020) { proto_tree_add_item(ncp_tree, hf_lip_echo, tvb, commhdr+4, 13, ENC_ASCII|ENC_NA); break; } } /* otherwise fall through */ case NCP_POSITIVE_ACK: /* Positive Acknowledgement */ case NCP_SERVICE_REQUEST: /* Server NCP Request */ case NCP_SERVICE_REPLY: /* Server NCP Reply */ case NCP_WATCHDOG: /* Watchdog Packet */ case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */ default: proto_tree_add_uint(ncp_tree, hf_ncp_seq, tvb, commhdr + 2, 1, header.sequence); proto_tree_add_uint(ncp_tree, hf_ncp_connection,tvb, commhdr + 3, 3, nw_connection); proto_tree_add_item(ncp_tree, hf_ncp_task, tvb, commhdr + 4, 1, ENC_BIG_ENDIAN); break; } /* * Process the packet body. */ switch (header.type) { case NCP_ALLOCATE_SLOT: /* Allocate Slot Request */ length_remaining = tvb_length_remaining(tvb, commhdr + 4); if (length_remaining > 4) { testvar = tvb_get_ntohl(tvb, commhdr+4); if (testvar == 0x4c495020) { proto_tree_add_text(ncp_tree, tvb, commhdr, -1, "Lip Echo Packet"); /*break;*/ } } next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case NCP_DEALLOCATE_SLOT: /* Deallocate Slot Request */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case NCP_SERVICE_REQUEST: /* Server NCP Request */ case NCP_BROADCAST_SLOT: /* Server Broadcast Packet */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); if (tvb_get_guint8(tvb, commhdr+6) == 0x68) { subfunction = tvb_get_guint8(tvb, commhdr+7); switch (subfunction) { case 0x02: /* NDS Frag Packet to decode */ dissect_nds_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; case 0x01: /* NDS Ping */ dissect_ping_req(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; default: dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); break; } } else { dissect_ncp_request(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree); } break; case NCP_SERVICE_REPLY: /* Server NCP Reply */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); nds_defrag(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, &ncp_tap); break; case NCP_POSITIVE_ACK: /* Positive Acknowledgement */ /* * XXX - this used to call "nds_defrag()", which would * clear out "frags". Was that the right thing to * do? */ next_tvb = tvb_new_subset_remaining(tvb, commhdr); dissect_ncp_reply(next_tvb, pinfo, nw_connection, header.sequence, header.type, ncp_tree, &ncp_tap); break; case NCP_WATCHDOG: /* Watchdog Packet */ /* * XXX - should the completion code be interpreted as * it is in "packet-ncp2222.inc"? If so, this * packet should be handled by "dissect_ncp_reply()". */ proto_tree_add_item(ncp_tree, hf_ncp_completion_code, tvb, commhdr + 6, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_connection_status, tvb, commhdr + 7, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_slot, tvb, commhdr + 8, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(ncp_tree, hf_ncp_control_code, tvb, commhdr + 9, 1, ENC_LITTLE_ENDIAN); /* * Display the rest of the packet as data. */ if (tvb_offset_exists(tvb, commhdr + 10)) { call_dissector(data_handle, tvb_new_subset_remaining(tvb, commhdr + 10), pinfo, ncp_tree); } break; case NCP_BURST_MODE_XFER: /* Packet Burst Packet */ if (flags & SYS) { /* * System packet; show missing fragments if there * are any. */ while (missing_fraglist_count != 0) { proto_tree_add_item(ncp_tree, hf_ncp_missing_data_offset, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; proto_tree_add_item(ncp_tree, hf_ncp_missing_data_count, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; missing_fraglist_count--; } } else { /* * XXX - do this by using -1 and -1 as the length * arguments to "tvb_new_subset()" and then calling * "tvb_set_reported_length()"? That'll throw an * exception if "data_len" goes past the reported * length of the packet, but that's arguably a * feature in this case. */ length_remaining = tvb_length_remaining(tvb, offset); if (length_remaining > data_len) length_remaining = data_len; if (data_len != 0) { call_dissector(data_handle, tvb_new_subset(tvb, offset, length_remaining, data_len), pinfo, ncp_tree); } } break; case NCP_LIP_ECHO: /* LIP Echo Packet */ proto_tree_add_text(ncp_tree, tvb, commhdr, -1, "Lip Echo Packet"); break; default: expert_item = proto_tree_add_text(ncp_tree, tvb, commhdr + 6, -1, "%s packets not supported yet", val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); if (ncp_echo_err) { expert_add_info_format(pinfo, expert_item, &ei_ncp_type, "%s packets not supported yet", val_to_str(header.type, ncp_type_vals, "Unknown type (0x%04x)")); } break; } }
static int dissect_nbipx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { gboolean has_routes; proto_tree *nbipx_tree = NULL; proto_item *ti = NULL; int offset = 0; guint8 packet_type; proto_tree *name_type_flag_tree; proto_item *tf; char name[(NETBIOS_NAME_LEN - 1)*4 + 1]; int name_type; gboolean has_payload; tvbuff_t *next_tvb; ipxhdr_t *ipxh; /* Reject the packet if data is NULL */ if (data == NULL) return 0; ipxh = (ipxhdr_t*)data; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NBIPX"); col_clear(pinfo->cinfo, COL_INFO); if (ipxh->ipx_type == IPX_PACKET_TYPE_WANBCAST) { /* * This is a WAN Broadcast packet; we assume it will have * 8 IPX addresses at the beginning. */ has_routes = TRUE; } else { /* * This isn't a WAN Broadcast packet, but it still might * have the 8 addresses. * * If it's the right length for a name operation, * and, if we assume it has routes, the packet type * is a name operation, assume it has routes. * * NOTE: this will throw an exception if the byte that * would be the packet type byte if this has the 8 * addresses isn't present; if that's the case, we don't * know how to interpret this packet, so we can't dissect * it anyway. */ has_routes = FALSE; /* start out assuming it doesn't */ if (tvb_reported_length(tvb) == 50) { packet_type = tvb_get_guint8(tvb, offset + 32 + 1); switch (packet_type) { case NBIPX_FIND_NAME: case NBIPX_NAME_RECOGNIZED: case NBIPX_CHECK_NAME: case NBIPX_NAME_IN_USE: case NBIPX_DEREGISTER_NAME: has_routes = TRUE; break; } } } if (tree) { ti = proto_tree_add_item(tree, proto_nbipx, tvb, 0, -1, ENC_NA); nbipx_tree = proto_item_add_subtree(ti, ett_nbipx); } if (has_routes) { if (tree) add_routers(nbipx_tree, tvb, 0); offset += 32; } packet_type = tvb_get_guint8(tvb, offset + 1); switch (packet_type) { case NBIPX_FIND_NAME: case NBIPX_NAME_RECOGNIZED: case NBIPX_CHECK_NAME: case NBIPX_NAME_IN_USE: case NBIPX_DEREGISTER_NAME: name_type = get_netbios_name(tvb, offset+2, name, (NETBIOS_NAME_LEN - 1)*4 + 1); col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s<%02x>", val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown"), name, name_type); if (nbipx_tree) { tf = proto_tree_add_item(nbipx_tree, hf_nbipx_name_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN); name_type_flag_tree = proto_item_add_subtree(tf, ett_nbipx_name_type_flags); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_group, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_in_use, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_registered, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_duplicated, tvb, offset, 1, ENC_LITTLE_ENDIAN); proto_tree_add_item(name_type_flag_tree, hf_nbipx_name_flags_deregistered, tvb, offset, 1, ENC_LITTLE_ENDIAN); } offset += 1; proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; if (nbipx_tree) netbios_add_name("Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; /* * No payload to be interpreted by another protocol. */ has_payload = FALSE; break; case NBIPX_SESSION_DATA: case NBIPX_SESSION_END: case NBIPX_SESSION_END_ACK: col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); dissect_conn_control(tvb, offset, nbipx_tree); offset += 1; proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; proto_tree_add_item(nbipx_tree, hf_nbipx_session_src_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_dest_conn_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_send_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_total_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_data_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_recv_seq_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(nbipx_tree, hf_nbipx_session_bytes_received, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* * We may have payload to dissect. */ has_payload = TRUE; break; case NBIPX_DIRECTED_DATAGRAM: col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); dissect_conn_control(tvb, offset, nbipx_tree); offset += 1; proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; if (nbipx_tree) netbios_add_name("Receiver's Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; if (nbipx_tree) netbios_add_name("Sender's Name", tvb, offset, nbipx_tree); offset += NETBIOS_NAME_LEN; /* * We may have payload to dissect. */ has_payload = TRUE; break; default: col_set_str(pinfo->cinfo, COL_INFO, val_to_str_const(packet_type, nbipx_data_stream_type_vals, "Unknown")); /* * We don't know what the first byte is. */ offset += 1; /* * The second byte is a data stream type byte. */ proto_tree_add_uint(nbipx_tree, hf_nbipx_packettype, tvb, offset, 1, packet_type); offset += 1; /* * We don't know what the rest of the packet is. */ has_payload = FALSE; } /* * Set the length of the NBIPX tree item. */ if (ti != NULL) proto_item_set_len(ti, offset); if (has_payload && tvb_offset_exists(tvb, offset)) { next_tvb = tvb_new_subset_remaining(tvb, offset); dissect_netbios_payload(next_tvb, pinfo, tree); } return tvb_captured_length(tvb); }
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_nntp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { const gchar *type; proto_tree *nntp_tree; proto_item *ti; gint offset = 0; gint next_offset; int linelen; if (pinfo->match_uint == pinfo->destport) type = "Request"; else type = "Response"; col_set_str(pinfo->cinfo, COL_PROTOCOL, "NNTP"); /* * Put the first line from the buffer into the summary * (but leave out the line terminator). * * 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); col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", type, tvb_format_text(tvb, offset, linelen)); if (tree) { ti = proto_tree_add_item(tree, proto_nntp, tvb, offset, -1, ENC_NA); nntp_tree = proto_item_add_subtree(ti, ett_nntp); if (pinfo->match_uint == pinfo->destport) { ti = proto_tree_add_boolean(nntp_tree, hf_nntp_request, tvb, 0, 0, TRUE); } else { ti = proto_tree_add_boolean(nntp_tree, hf_nntp_response, tvb, 0, 0, TRUE); } PROTO_ITEM_SET_HIDDEN(ti); /* * Show the request or response as text, a line at a time. * XXX - for requests, we could display the stuff after the * first line, if any, based on what the request was, and * for responses, we could display it based on what the * matching request was, although the latter requires us to * know what the matching request was.... */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_text(nntp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } }
/* Dissect details of packet */ static void rlogin_display(rlogin_hash_entry_t *hash_info, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct tcpinfo *tcpinfo) { /* Display the proto tree */ int offset = 0; proto_tree *rlogin_tree, *user_info_tree, *window_tree; proto_item *ti; guint length; int str_len; gint ti_offset; proto_item *user_info_item, *window_info_item; /* Create rlogin subtree */ ti = proto_tree_add_item(tree, proto_rlogin, tvb, 0, -1, ENC_NA); rlogin_tree = proto_item_add_subtree(ti, ett_rlogin); /* Return if data empty */ length = tvb_captured_length(tvb); if (length == 0) { return; } /* * XXX - this works only if the urgent pointer points to something * in this segment; to make it work if the urgent pointer points * to something past this segment, we'd have to remember the urgent * pointer setting for this conversation. */ if (tcpinfo && IS_TH_URG(tcpinfo->flags) && /* if urgent pointer set */ length >= tcpinfo->urgent_pointer) /* and it's in this frame */ { /* Get urgent byte into Temp */ int urgent_offset = tcpinfo->urgent_pointer - 1; guint8 control_byte; /* Check for text data in front */ if (urgent_offset > offset) { proto_tree_add_item(rlogin_tree, hf_data, tvb, offset, urgent_offset, ENC_ASCII|ENC_NA); } /* Show control byte */ proto_tree_add_item(rlogin_tree, hf_control_message, tvb, urgent_offset, 1, ENC_BIG_ENDIAN); control_byte = tvb_get_guint8(tvb, urgent_offset); col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", val_to_str_const(control_byte, control_message_vals, "Unknown")); offset = urgent_offset + 1; /* adjust offset */ } else if (tvb_get_guint8(tvb, offset) == '\0') { /* Startup */ if (pinfo->srcport == RLOGIN_PORT) /* from server */ { proto_tree_add_item(rlogin_tree, hf_startup_info_received_flag, tvb, offset, 1, ENC_BIG_ENDIAN); } else { proto_tree_add_item(rlogin_tree, hf_client_startup_flag, tvb, offset, 1, ENC_BIG_ENDIAN); } ++offset; } if (!tvb_offset_exists(tvb, offset)) { /* No more data to check */ return; } if (hash_info->info_framenum == pinfo->num) { gint info_len; gint slash_offset; /* First frame of conversation, assume user info... */ info_len = tvb_captured_length_remaining(tvb, offset); if (info_len <= 0) return; /* User info tree */ user_info_item = proto_tree_add_string_format(rlogin_tree, hf_user_info, tvb, offset, info_len, FALSE, "User info (%s)", tvb_format_text(tvb, offset, info_len)); user_info_tree = proto_item_add_subtree(user_info_item, ett_rlogin_user_info); /* Client user name. */ str_len = tvb_strsize(tvb, offset); proto_tree_add_item(user_info_tree, hf_user_info_client_user_name, tvb, offset, str_len, ENC_ASCII|ENC_NA); offset += str_len; /* Server user name. */ str_len = tvb_strsize(tvb, offset); proto_tree_add_item(user_info_tree, hf_user_info_server_user_name, tvb, offset, str_len, ENC_ASCII|ENC_NA); offset += str_len; /* Terminal type/speed. */ slash_offset = tvb_find_guint8(tvb, offset, -1, '/'); if (slash_offset != -1) { guint8* str = NULL; guint32 term_len = 0; gboolean term_len_valid; proto_item* pi = NULL; /* Terminal type */ proto_tree_add_item(user_info_tree, hf_user_info_terminal_type, tvb, offset, slash_offset-offset, ENC_ASCII|ENC_NA); offset = slash_offset + 1; /* Terminal speed */ str_len = tvb_strsize(tvb, offset); str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, str_len, ENC_NA|ENC_ASCII); term_len_valid = ws_strtou32(str, NULL, &term_len); pi = proto_tree_add_uint(user_info_tree, hf_user_info_terminal_speed, tvb, offset, str_len, term_len); if (!term_len_valid) expert_add_info(pinfo, pi, &ei_rlogin_termlen_invalid); offset += str_len; } } if (!tvb_offset_exists(tvb, offset)) { /* No more data to check */ return; } /* Test for terminal information, the data will have 2 0xff bytes */ /* look for first 0xff byte */ ti_offset = tvb_find_guint8(tvb, offset, -1, 0xff); /* Next byte must also be 0xff */ if (ti_offset != -1 && tvb_bytes_exist(tvb, ti_offset + 1, 1) && tvb_get_guint8(tvb, ti_offset + 1) == 0xff) { guint16 rows, columns; /* Have found terminal info. */ if (ti_offset > offset) { /* There's data before the terminal info. */ proto_tree_add_item(rlogin_tree, hf_data, tvb, offset, ti_offset - offset, ENC_ASCII|ENC_NA); } /* Create window info tree */ window_info_item = proto_tree_add_item(rlogin_tree, hf_window_info, tvb, offset, 12, ENC_NA); window_tree = proto_item_add_subtree(window_info_item, ett_rlogin_window); /* Cookie */ proto_tree_add_item(window_tree, hf_magic_cookie, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* These bytes should be "ss" */ proto_tree_add_item(window_tree, hf_window_info_ss, tvb, offset, 2, ENC_ASCII|ENC_NA); offset += 2; /* Character rows */ rows = tvb_get_ntohs(tvb, offset); proto_tree_add_item(window_tree, hf_window_info_rows, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Characters per row */ columns = tvb_get_ntohs(tvb, offset); proto_tree_add_item(window_tree, hf_window_info_cols, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* x pixels */ proto_tree_add_item(window_tree, hf_window_info_x_pixels, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* y pixels */ proto_tree_add_item(window_tree, hf_window_info_y_pixels, tvb, offset, 2, ENC_BIG_ENDIAN); offset += 2; /* Show setting highlights in info column */ col_append_fstr(pinfo->cinfo, COL_INFO, " (rows=%u, cols=%u)", rows, columns); } if (tvb_offset_exists(tvb, offset)) { /* There's more data in the frame. */ proto_tree_add_item(rlogin_tree, hf_data, tvb, offset, -1, ENC_ASCII|ENC_NA); } }
static void dissect_icap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *icap_tree = NULL; proto_item *ti = NULL; proto_item *hidden_item; gint offset = 0; const guchar *line; gint next_offset; const guchar *linep, *lineend; int linelen; guchar c; icap_type_t icap_type; int datalen; col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICAP"); /* * Put the first line from the buffer into the summary * if it's an ICAP header (but leave out the * line terminator). * Otherwise, just call it a continuation. * * 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); icap_type = ICAP_OTHER; /* type not known yet */ if (is_icap_message(line, linelen, &icap_type)) col_add_str(pinfo->cinfo, COL_INFO, format_text(line, linelen)); else col_set_str(pinfo->cinfo, COL_INFO, "Continuation"); if (tree) { ti = proto_tree_add_item(tree, proto_icap, tvb, offset, -1, ENC_NA); icap_tree = proto_item_add_subtree(ti, ett_icap); } /* * Process the packet data, a line at a time. */ icap_type = ICAP_OTHER; /* type not known yet */ while (tvb_offset_exists(tvb, offset)) { gboolean is_icap = FALSE; gboolean loop_done = FALSE; /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Get a buffer that refers to the line. */ line = tvb_get_ptr(tvb, offset, linelen); lineend = line + linelen; /* * find header format */ if (is_icap_message(line, linelen, &icap_type)) { goto is_icap_header; } /* * if it looks like a blank line, end of header perhaps? */ if (linelen == 0) { goto is_icap_header; } /* * No. Does it look like a header? */ linep = line; loop_done = FALSE; while (linep < lineend && (!loop_done)) { c = *linep++; /* * This must be a CHAR to be part of a token; that * means it must be ASCII. */ if (!isascii(c)) { is_icap = FALSE; break; /* not ASCII, thus not a CHAR */ } /* * This mustn't be a CTL to be part of a token. * * XXX - what about leading LWS on continuation * lines of a header? */ if (iscntrl(c)) { is_icap = FALSE; break; /* CTL, not part of a header */ } switch (c) { case '(': case ')': case '<': case '>': case '@': case ',': case ';': case '\\': case '"': case '/': case '[': case ']': case '?': case '=': case '{': case '}': /* * It's a separator, so it's not part of a * token, so it's not a field name for the * beginning of a header. * * (We don't have to check for HT; that's * already been ruled out by "iscntrl()".) * * XXX - what about ' '? HTTP's checks * check for that. */ is_icap = FALSE; loop_done = TRUE; break; case ':': /* * This ends the token; we consider this * to be a header. */ goto is_icap_header; } } /* * We don't consider this part of an ICAP message, * so we don't display it. * (Yeah, that means we don't display, say, a text/icap * page, but you can get that from the data pane.) */ if (!is_icap) break; is_icap_header: if (tree) { proto_tree_add_text(icap_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset) ); } offset = next_offset; } if (tree) { switch (icap_type) { case ICAP_OPTIONS: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_options, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_REQMOD: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_reqmod, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_RESPMOD: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_respmod, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_RESPONSE: hidden_item = proto_tree_add_boolean(icap_tree, hf_icap_response, tvb, 0, 0, 1); PROTO_ITEM_SET_HIDDEN(hidden_item); break; case ICAP_OTHER: default: break; } } datalen = tvb_length_remaining(tvb, offset); if (datalen > 0) { call_dissector(data_handle, tvb_new_subset_remaining(tvb, offset), pinfo, icap_tree); } }
static void dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request; proto_tree *ftp_tree = NULL; proto_tree *reqresp_tree = NULL; proto_item *ti, *hidden_item; gint offset = 0; const guchar *line; guint32 code; gchar code_str[4]; gboolean is_port_request = FALSE; gboolean is_pasv_response = FALSE; gboolean is_epasv_response = FALSE; gint next_offset; int linelen; int tokenlen; const guchar *next_token; guint32 pasv_ip; guint32 ftp_ip; guint16 ftp_port; address ftp_ip_address; gboolean ftp_nat; conversation_t *conversation; ftp_ip_address = pinfo->src; if (pinfo->match_uint == pinfo->destport) is_request = TRUE; else is_request = FALSE; col_set_str(pinfo->cinfo, COL_PROTOCOL, "FTP"); /* * Find the end of the first line. * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); /* * Put the first line from the buffer into the summary * (but leave out the line terminator). */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "Request" : "Response", format_text(line, linelen)); if (tree) { ti = proto_tree_add_item(tree, proto_ftp, tvb, offset, -1, ENC_NA); ftp_tree = proto_item_add_subtree(ti, ett_ftp); if (is_request) { hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); } else { hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_request, tvb, 0, 0, FALSE); PROTO_ITEM_SET_HIDDEN(hidden_item); hidden_item = proto_tree_add_boolean(ftp_tree, hf_ftp_response, tvb, 0, 0, TRUE); PROTO_ITEM_SET_HIDDEN(hidden_item); } /* * Put the line into the protocol tree. */ ti = proto_tree_add_text(ftp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); reqresp_tree = proto_item_add_subtree(ti, ett_ftp_reqresp); } if (is_request) { /* * Extract the first token, and, if there is a first * token, add it as the request. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { if (tree) { proto_tree_add_item(reqresp_tree, hf_ftp_request_command, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); } if (strncmp(line, "PORT", tokenlen) == 0) is_port_request = TRUE; } } else { /* * This is a response; the response code is 3 digits, * followed by a space or hyphen, possibly followed by * text. * * If the line doesn't start with 3 digits, it's part of * a continuation. * * XXX - keep track of state in the first pass, and * treat non-continuation lines not beginning with digits * as errors? */ if (linelen >= 3 && isdigit(line[0]) && isdigit(line[1]) && isdigit(line[2])) { /* * One-line reply, or first or last line * of a multi-line reply. */ tvb_get_nstringz0(tvb, offset, sizeof(code_str), code_str); code = strtoul(code_str, NULL, 10); if (tree) { proto_tree_add_uint(reqresp_tree, hf_ftp_response_code, tvb, offset, 3, code); } /* * See if it's a passive-mode response. * * XXX - does anybody do FOOBAR, as per RFC * 1639, or has that been supplanted by RFC 2428? */ if (code == 227) is_pasv_response = TRUE; /* * Responses to EPSV command, as per RFC 2428 * XXX - handle IPv6? */ if (code == 229) is_epasv_response = TRUE; /* * Skip the 3 digits and, if present, the * space or hyphen. */ if (linelen >= 4) next_token = line + 4; else next_token = line + linelen; } else { /* * Line doesn't start with 3 digits; assume it's * a line in the middle of a multi-line reply. */ next_token = line; } } offset += (gint) (next_token - line); linelen -= (int) (next_token - line); line = next_token; if (tree) { /* * Add the rest of the first line as request or * reply data. */ if (linelen != 0) { if (is_request) { proto_tree_add_item(reqresp_tree, hf_ftp_request_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } else { proto_tree_add_item(reqresp_tree, hf_ftp_response_arg, tvb, offset, linelen, ENC_ASCII|ENC_NA); } } offset = next_offset; } /* * If this is a PORT request or a PASV response, handle it. */ if (is_port_request) { if (parse_port_pasv(line, linelen, &ftp_ip, &ftp_port)) { if (tree) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_active_ip, tvb, 0, 0, ftp_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_active_port, tvb, 0, 0, ftp_port); } SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&ftp_ip); ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, &ftp_ip_address); if (ftp_nat) { if (tree) { proto_tree_add_boolean( reqresp_tree, hf_ftp_active_nat, tvb, 0, 0, ftp_nat); } } } } if (is_pasv_response) { if (linelen != 0) { /* * This frame contains a PASV response; set up a * conversation for the data. */ if (parse_port_pasv(line, linelen, &pasv_ip, &ftp_port)) { if (tree) { proto_tree_add_ipv4(reqresp_tree, hf_ftp_pasv_ip, tvb, 0, 0, pasv_ip); proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, 0, 0, ftp_port); } SET_ADDRESS(&ftp_ip_address, AT_IPv4, 4, (const guint8 *)&pasv_ip); ftp_nat = !ADDRESSES_EQUAL(&pinfo->src, &ftp_ip_address); if (ftp_nat) { if (tree) { proto_tree_add_boolean(reqresp_tree, hf_ftp_pasv_nat, tvb, 0, 0, ftp_nat); } } /* * We use "ftp_ip_address", so that if * we're NAT'd we look for the un-NAT'd * connection. * * XXX - should this call to * "find_conversation()" just use * "ftp_ip_address" and "server_port", and * wildcard everything else? */ conversation = find_conversation(pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { /* * XXX - should this call to "conversation_new()" * just use "ftp_ip_address" and "server_port", * and wildcard everything else? * * XXX - what if we did find a conversation? As * we create it only on the first pass through the * packets, if we find one, it's presumably an * unrelated conversation. Should we remove the * old one from the hash table and put this one in * its place? Can the conversation code handle * conversations not in the hash table? Or should * we make conversations support start and end * frames, as circuits do, and treat this as an * indication that one conversation was closed and * a new one was opened? */ conversation = conversation_new( pinfo->fd->num, &ftp_ip_address, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } } } if (is_epasv_response) { if (linelen != 0) { /* * This frame contains an EPSV response; set up a * conversation for the data. */ if (parse_extended_pasv_response(line, linelen, &ftp_port)) { /* Add port number to tree */ if (tree) { proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port, tvb, 0, 0, ftp_port); } /* Find/create conversation for data */ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT_B); if (conversation == NULL) { conversation = conversation_new( pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_TCP, ftp_port, 0, NO_PORT2); conversation_set_dissector(conversation, ftpdata_handle); } } } } if (tree) { /* * Show the rest of the request or response as text, * a line at a time. * XXX - only if there's a continuation indicator? */ while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Put this line. */ proto_tree_add_text(ftp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; } } }
/* 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 doesn't 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, void* data) { 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; /* Reject the packet if data is NULL */ if (data == NULL) return 0; transfer_tcpinfo = (struct tcpinfo *)data; col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDSS"); /* Look for the transfer conversation; this was created during * earlier broadcast dissection (see prepare_ldss_transfer_conv) */ transfer_conv = find_conversation (pinfo->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); /* 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->num) { already_dissected = FALSE; transfer_info->req = wmem_new0(wmem_file_scope(), ldss_file_request_t); transfer_info->req->file = wmem_new0(wmem_file_scope(), ldss_file_t); highest_num_seen = pinfo->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 (tvb_offset_exists(tvb, offset)) { gint next_offset; const guint8 *line; int linelen; gboolean is_digest_line; guint digest_type_len; linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* Include new-line in line */ line = (guint8 *)tvb_memdup(NULL, tvb, offset, linelen+1); /* XXX - memory leak? */ line_tree = proto_tree_add_subtree(ldss_tree, tvb, offset, linelen, ett_ldss_transfer_req, NULL, tvb_format_text(tvb, offset, next_offset-offset)); /* 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 { proto_tree_add_expert(line_tree, pinfo, &ei_ldss_unrecognized_line, tvb, offset, linelen); } 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 *)wmem_alloc0(wmem_file_scope(), 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, MIN(linelen-digest_type_len, DIGEST_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->num; transfer_info->req->ts = pinfo->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_captured_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->num; transfer_info->resp_ts = pinfo->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_captured_length(tvb), NULL, compression == COMPRESSION_GZIP ? "Gzip compressed data: %d bytes" : "File data: %d bytes", tvb_captured_length(tvb)); #ifdef HAVE_ZLIB /* Be nice and uncompress the file data. */ if (compression == COMPRESSION_GZIP) { tvbuff_t *uncomp_tvb; uncomp_tvb = tvb_child_uncompress(tvb, tvb, 0, tvb_captured_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_captured_length(uncomp_tvb), NULL, "Uncompressed data: %d bytes", tvb_captured_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_captured_length(tvb); }
static void dissect_rmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *rmp_tree = NULL; proto_item *ti = NULL; guint8 type, len; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RMP"); col_clear(pinfo->cinfo, COL_INFO); type = tvb_get_guint8(tvb, 0); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_str(pinfo->cinfo, COL_INFO, val_to_str(type, rmp_type_vals, "Unknown Type")); } if (tree) { ti = proto_tree_add_item(tree, proto_rmp, tvb, 0, -1, ENC_NA); rmp_tree = proto_item_add_subtree(ti, ett_rmp); proto_tree_add_uint(rmp_tree, hf_rmp_type, tvb, 0, 1, type); switch (type) { case RMP_BOOT_REQ: proto_tree_add_item(rmp_tree, hf_rmp_retcode, tvb, 1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_seqnum, tvb, 2, 4, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_sessionid, tvb, 6, 2, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_version, tvb, 8, 2, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_machtype, tvb, 10, 20, ENC_ASCII|ENC_NA); /* The remaining fields are optional */ if(!tvb_offset_exists(tvb, 30)) return; len = tvb_get_guint8(tvb, 30); proto_tree_add_item(rmp_tree, hf_rmp_filename, tvb, 30, 1, ENC_ASCII|ENC_BIG_ENDIAN); if(tvb_offset_exists(tvb, len+31)) call_dissector(data_handle, tvb_new_subset_remaining(tvb, len+31), pinfo, tree); break; case RMP_BOOT_REPL: proto_tree_add_item(rmp_tree, hf_rmp_retcode, tvb, 1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_seqnum, tvb, 2, 4, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_sessionid, tvb, 6, 2, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_version, tvb, 8, 2, ENC_BIG_ENDIAN); len = tvb_get_guint8(tvb, 10); proto_tree_add_item(rmp_tree, hf_rmp_filename, tvb, 10, 1, ENC_ASCII|ENC_BIG_ENDIAN); if(tvb_offset_exists(tvb, len+11)) call_dissector(data_handle, tvb_new_subset_remaining(tvb, len+11), pinfo, tree); break; case RMP_READ_REQ: proto_tree_add_item(rmp_tree, hf_rmp_retcode, tvb, 1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_offset, tvb, 2, 4, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_sessionid, tvb, 6, 2, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_size, tvb, 8, 2, ENC_BIG_ENDIAN); if(tvb_offset_exists(tvb, 10)) call_dissector(data_handle, tvb_new_subset_remaining(tvb, 10), pinfo, tree); break; case RMP_READ_REPL: proto_tree_add_item(rmp_tree, hf_rmp_retcode, tvb, 1, 1, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_offset, tvb, 2, 4, ENC_BIG_ENDIAN); proto_tree_add_item(rmp_tree, hf_rmp_sessionid, tvb, 6, 2, ENC_BIG_ENDIAN); call_dissector(data_handle, tvb_new_subset_remaining(tvb, 8), pinfo, rmp_tree); break; case RMP_BOOT_DONE: proto_tree_add_item(rmp_tree, hf_rmp_retcode, tvb, 1, 1, ENC_BIG_ENDIAN); proto_tree_add_text(rmp_tree, tvb, 2, 4, "Reserved"); proto_tree_add_item(rmp_tree, hf_rmp_sessionid, tvb, 6, 2, ENC_BIG_ENDIAN); if(tvb_offset_exists(tvb, 8)) call_dissector(data_handle, tvb_new_subset_remaining(tvb, 6), pinfo, tree); break; default: call_dissector(data_handle, tvb_new_subset_remaining(tvb, 1), pinfo, tree); } } }
static void dissect_imap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gboolean is_request; proto_tree *imap_tree, *reqresp_tree; proto_item *ti, *hidden_item; gint offset = 0; gint uid_offset = 0; gint folder_offset = 0; const guchar *line; const guchar *uid_line; const guchar *folder_line; gint next_offset; int linelen; int tokenlen; int uid_tokenlen; int folder_tokenlen; const guchar *next_token; const guchar *uid_next_token; const guchar *folder_next_token; guchar *tokenbuf; guchar *command_token; int iter; int commandlen; conversation_t *conversation; imap_state_t *session_state; conversation = find_or_create_conversation(pinfo); session_state = (imap_state_t *)conversation_get_proto_data(conversation, proto_imap); if (!session_state) { session_state = wmem_new0(wmem_file_scope(), imap_state_t); session_state->ssl_requested = FALSE; conversation_add_proto_data(conversation, proto_imap, session_state); } tokenbuf = (guchar *)wmem_alloc0(wmem_packet_scope(), MAX_BUFFER); command_token = (guchar *)wmem_alloc0(wmem_packet_scope(), MAX_BUFFER); commandlen = 0; folder_offset = 0; folder_tokenlen = 0; folder_line = NULL; col_set_str(pinfo->cinfo, COL_PROTOCOL, "IMAP"); if (pinfo->match_uint == pinfo->destport) is_request = TRUE; else is_request = FALSE; /* * Put the first line from the buffer into the summary * (but leave out the line terminator). */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "Request" : "Response", format_text(line, linelen)); { ti = proto_tree_add_item(tree, proto_imap, tvb, offset, -1, ENC_NA); imap_tree = proto_item_add_subtree(ti, ett_imap); hidden_item = proto_tree_add_boolean(imap_tree, hf_imap_isrequest, tvb, 0, 0, is_request); PROTO_ITEM_SET_HIDDEN(hidden_item); while(tvb_offset_exists(tvb, offset)) { /* * Find the end of each line * * Note that "tvb_find_line_end()" will return a value that is * not longer than what's in the buffer, so the "tvb_get_ptr()" * call won't throw an exception. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); line = tvb_get_ptr(tvb, offset, linelen); /* * Put the line into the protocol tree. */ ti = proto_tree_add_item(imap_tree, hf_imap_line, tvb, offset, next_offset - offset, ENC_ASCII|ENC_NA); reqresp_tree = proto_item_add_subtree(ti, ett_imap_reqresp); /* * Check that the line doesn't begin with '*', because that's a continuation line. * Otherwise if a tag is present then extract tokens. */ if ( (line) && ((line[0] != '*') || (TRUE == is_request)) ) { /* * Show each line as tags + requests or replies. */ /* * Extract the first token, and, if there is a first * token, add it as the request or reply tag. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_imap_request_tag : hf_imap_response_tag, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); offset += (gint) (next_token - line); linelen -= (int) (next_token - line); line = next_token; } /* * Extract second token, and, if there is a second * token, and it's not uid, add it as the request or reply command. */ tokenlen = get_token_len(line, line + linelen, &next_token); if (tokenlen != 0) { for (iter = 0; iter < tokenlen && iter < MAX_BUFFER-1; iter++) { tokenbuf[iter] = g_ascii_tolower(line[iter]); } if (tree && is_request && strncmp(tokenbuf, "uid", tokenlen) == 0) { proto_tree_add_item(reqresp_tree, hf_imap_request_uid, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); /* * UID is a precursor to a command, if following the tag, * so move to next token to grab the actual command. */ uid_offset = offset; uid_offset += (gint) (next_token - line); uid_line = next_token; uid_tokenlen = get_token_len(uid_line, uid_line + (linelen - tokenlen), &uid_next_token); if (tokenlen != 0) { proto_tree_add_item(reqresp_tree, hf_imap_request_command, tvb, uid_offset, uid_tokenlen, ENC_ASCII|ENC_NA); /* * Save command string to do specialized processing. */ for (iter = 0; iter < uid_tokenlen && iter < MAX_BUFFER-1; iter++) { command_token[iter] = g_ascii_tolower(uid_line[iter]); } commandlen = uid_tokenlen; folder_offset = uid_offset; folder_offset += (gint) (uid_next_token - uid_line); folder_line = uid_next_token; folder_tokenlen = get_token_len(folder_line, folder_line + (linelen - tokenlen - uid_tokenlen), &folder_next_token); } } else { /* * Not a UID request so perform normal parsing. */ proto_tree_add_item(reqresp_tree, (is_request) ? hf_imap_request_command : hf_imap_response_status, tvb, offset, tokenlen, ENC_ASCII|ENC_NA); if (is_request) { /* * Save command string to do specialized processing. */ for (iter = 0; iter < tokenlen && iter < 256; iter++) { command_token[iter] = g_ascii_tolower(line[iter]); } commandlen = tokenlen; folder_offset = offset; folder_offset += (gint) (next_token - line); folder_line = next_token; folder_tokenlen = get_token_len(folder_line, folder_line + (linelen - tokenlen - 1), &folder_next_token); } } if (tree && commandlen > 0 && ( strncmp(command_token, "select", commandlen) == 0 || strncmp(command_token, "examine", commandlen) == 0 || strncmp(command_token, "create", commandlen) == 0 || strncmp(command_token, "delete", commandlen) == 0 || strncmp(command_token, "rename", commandlen) == 0 || strncmp(command_token, "subscribe", commandlen) == 0 || strncmp(command_token, "unsubscribe", commandlen) == 0 || strncmp(command_token, "status", commandlen) == 0 || strncmp(command_token, "append", commandlen) == 0 || strncmp(command_token, "search", commandlen) == 0)) { /* * These commands support folder as an argument, * so parse out the folder name. */ if (folder_tokenlen != 0) proto_tree_add_item(reqresp_tree, hf_imap_request_folder, tvb, folder_offset, folder_tokenlen, ENC_ASCII|ENC_NA); } if (tree && is_request && (NULL != folder_line) && strncmp(command_token, "copy", commandlen) == 0) { /* * Handle the copy command separately since folder * is the second argument for this command. */ folder_offset += (gint) (folder_next_token - folder_line); folder_line = folder_next_token; folder_tokenlen = get_token_len(folder_line, folder_line + (linelen - tokenlen), &folder_next_token); if (folder_tokenlen != 0) proto_tree_add_item(reqresp_tree, hf_imap_request_folder, tvb, folder_offset, folder_tokenlen, ENC_ASCII|ENC_NA); } /* If not yet switched to TLS, check for STARTTLS. */ if (session_state->ssl_requested) { if (!is_request && session_state->ssl_requested && strncmp(tokenbuf, "ok", tokenlen) == 0) { /* STARTTLS accepted, next reply will be TLS. */ ssl_starttls_ack(ssl_handle, pinfo, imap_handle); } session_state->ssl_requested = FALSE; } if (is_request && commandlen > 0 && strncmp(command_token, "starttls", commandlen) == 0) { /* If next response is OK, then TLS should be commenced. */ session_state->ssl_requested = TRUE; } } /* * Add the rest of the line as request or reply data. */ if (linelen != 0) { proto_tree_add_item(reqresp_tree, (is_request) ? hf_imap_request : hf_imap_response, tvb, offset, linelen, ENC_ASCII|ENC_NA); } } offset = next_offset; /* Skip over last line and \r\n at the end of it */ } } }
static int parse_attributes(tvbuff_t *tvb, int offset, proto_tree *tree) { guint8 tag; const gchar *tag_desc; int name_length, value_length; proto_tree *as_tree = tree; proto_item *tas = NULL; int start_offset = offset; proto_tree *attr_tree = tree; while (tvb_offset_exists(tvb, offset)) { tag = tvb_get_guint8(tvb, offset); tag_desc = val_to_str(tag, tag_vals, "Reserved (0x%02x)"); if (TAG_TYPE(tag) == TAG_TYPE_DELIMITER) { /* * If we had an attribute sequence we were * working on, we're done with it; set its * length to the length of all the stuff * we've done so far. */ if (tas != NULL) proto_item_set_len(tas, offset - start_offset); /* * This tag starts a new attribute sequence; * create a new tree under this tag when we see * a non-delimiter tag, under which to put * those attributes. */ as_tree = NULL; attr_tree = tree; /* * Remember the offset at which this attribute * sequence started, so we can use it to compute * its length when it's finished. */ start_offset = offset; /* * Now create a new item for this tag. * XXX - should use proto_tree_add_subtree */ tas = proto_tree_add_text(tree, tvb, offset, 1, "%s", tag_desc); offset += 1; if (tag == TAG_END_OF_ATTRIBUTES) { /* * No more attributes. */ break; } } else { /* * Value tag - get the name length. */ name_length = tvb_get_ntohs(tvb, offset + 1); /* * OK, get the value length. */ value_length = tvb_get_ntohs(tvb, offset + 1 + 2 + name_length); /* * OK, does the value run past the end of the * frame? */ if (as_tree == NULL) { /* * OK, there's an attribute to hang * under a delimiter tag, but we don't * have a tree for that tag yet; create * a tree. */ as_tree = proto_item_add_subtree(tas, ett_ipp_as); attr_tree = as_tree; } switch (TAG_TYPE(tag)) { case TAG_TYPE_INTEGER: if (name_length != 0) { /* * This is an attribute, not * an additional value, so * start a tree for it. */ attr_tree = add_integer_tree(as_tree, tvb, offset, name_length, value_length, tag); } add_integer_value(tag_desc, attr_tree, tvb, offset, name_length, value_length, tag); break; case TAG_TYPE_OCTETSTRING: if (name_length != 0) { /* * This is an attribute, not * an additional value, so * start a tree for it. */ attr_tree = add_octetstring_tree(as_tree, tvb, offset, name_length, value_length); } add_octetstring_value(tag_desc, attr_tree, tvb, offset, name_length, value_length); break; case TAG_TYPE_CHARSTRING: if (name_length != 0) { /* * This is an attribute, not * an additional value, so * start a tree for it. */ attr_tree = add_charstring_tree(as_tree, tvb, offset, name_length, value_length); } add_charstring_value(tag_desc, attr_tree, tvb, offset, name_length, value_length); break; } offset += 1 + 2 + name_length + 2 + value_length; } } return offset; }
/* UA/UDP DISSECTOR */ static void _dissect_uaudp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, e_ua_direction direction) { gint offset = 0; guint8 opcode; proto_item *uaudp_item; proto_tree *uaudp_tree; col_set_str(pinfo->cinfo, COL_PROTOCOL, "UAUDP"); /* get the identifier; it means operation code */ opcode = tvb_get_guint8(tvb, offset); offset += 1; ua_tap_info.opcode = opcode; ua_tap_info.expseq = 0; ua_tap_info.sntseq = 0; /* print in "INFO" column the type of UAUDP message */ col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str_ext(opcode, &uaudp_opcode_str_ext, "unknown (0x%02x)")); uaudp_item = proto_tree_add_protocol_format(tree, proto_uaudp, tvb, 0, 5, "Universal Alcatel/UDP Encapsulation Protocol, %s", val_to_str_ext(opcode, &uaudp_opcode_str_ext, "unknown (0x%02x)")); uaudp_tree = proto_item_add_subtree(uaudp_item, ett_uaudp); /* print the identifier */ proto_tree_add_uint(uaudp_tree, hf_uaudp_opcode, tvb, 0, 1, opcode); switch(opcode) { case UAUDP_CONNECT: { if (!tree) break; while (tvb_offset_exists(tvb, offset)) { guint8 T = tvb_get_guint8(tvb, offset+0); guint8 L = tvb_get_guint8(tvb, offset+1); switch(T) { case UAUDP_CONNECT_VERSION: rV(uaudp_tree, &hf_uaudp_version , tvb, offset, L); break; case UAUDP_CONNECT_WINDOW_SIZE: rV(uaudp_tree, &hf_uaudp_window_size , tvb, offset, L); break; case UAUDP_CONNECT_MTU: rV(uaudp_tree, &hf_uaudp_mtu , tvb, offset, L); break; case UAUDP_CONNECT_UDP_LOST: rV(uaudp_tree, &hf_uaudp_udp_lost , tvb, offset, L); break; case UAUDP_CONNECT_UDP_LOST_REINIT: rV(uaudp_tree, &hf_uaudp_udp_lost_reinit, tvb, offset, L); break; case UAUDP_CONNECT_KEEPALIVE: rV(uaudp_tree, &hf_uaudp_keepalive , tvb, offset, L); break; case UAUDP_CONNECT_QOS_IP_TOS: rV(uaudp_tree, &hf_uaudp_qos_ip_tos , tvb, offset, L); break; case UAUDP_CONNECT_QOS_8021_VLID: rV(uaudp_tree, &hf_uaudp_qos_8021_vlid , tvb, offset, L); break; case UAUDP_CONNECT_QOS_8021_PRI: rV(uaudp_tree, &hf_uaudp_qos_8021_pri , tvb, offset, L); break; } offset += (2 + L); } break; } case UAUDP_NACK: { proto_tree_add_uint(uaudp_tree, hf_uaudp_expseq, tvb, offset, 2, tvb_get_ntohs(tvb, offset)); break; } case UAUDP_DATA: { int datalen; proto_tree_add_uint(uaudp_tree, hf_uaudp_expseq, tvb, offset+0, 2, tvb_get_ntohs(tvb, offset+0)); proto_tree_add_uint(uaudp_tree, hf_uaudp_sntseq, tvb, offset+2, 2, tvb_get_ntohs(tvb, offset+2)); ua_tap_info.expseq = hf_uaudp_expseq; ua_tap_info.sntseq = hf_uaudp_sntseq; offset += 4; datalen = tvb_reported_length(tvb) - offset; /* if there is remaining data, call the UA dissector */ if (datalen > 0) { if (direction == SYS_TO_TERM) call_dissector(ua_sys_to_term_handle, tvb_new_subset(tvb, offset, datalen, datalen), pinfo, tree); else if (direction == TERM_TO_SYS) call_dissector(ua_term_to_sys_handle, tvb_new_subset(tvb, offset, datalen, datalen), pinfo, tree); else { /* XXX: expert ?? */ col_set_str(pinfo->cinfo, COL_INFO, "Data - Couldn't resolve direction. Check UAUDP Preferences."); } ua_tap_info.expseq = hf_uaudp_expseq; } else { /* print in "INFO" column */ col_set_str(pinfo->cinfo, COL_INFO, "Data ACK"); } break; } default: break; } #if 0 tap_queue_packet(uaudp_tap, pinfo, &ua_tap_info); #endif }
static void dissect_x29(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { int offset = 0; proto_tree *x29_tree = NULL; proto_item *ti; gboolean *q_bit_set = pinfo->private_data; guint8 msg_code; guint8 error_type; guint8 type_ref; gint next_offset; int linelen; col_set_str(pinfo->cinfo, COL_PROTOCOL, "X.29"); col_clear(pinfo->cinfo, COL_INFO); if (tree) { ti = proto_tree_add_item(tree, proto_x29, tvb, offset, -1, ENC_NA); x29_tree = proto_item_add_subtree(ti, ett_x29); } if (*q_bit_set) { /* * Q bit set - this is a PAD message. */ msg_code = tvb_get_guint8(tvb, offset); if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s PAD message", val_to_str(msg_code, message_code_vals, "Unknown (0x%02x)")); } proto_tree_add_uint(x29_tree, hf_msg_code, tvb, offset, 1, msg_code); offset++; switch (msg_code) { case SET_MSG: case READ_MSG: case SET_AND_READ_MSG: case PARAMETER_IND_MSG: /* * XXX - dissect the references as per X.3. */ while (tvb_reported_length_remaining(tvb, offset) > 0) { proto_tree_add_text(x29_tree, tvb, offset, 2, "Parameter %u, value %u", tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1)); offset += 2; } break; case INV_TO_CLEAR_MSG: /* * No data for this message. */ break; case ERROR_MSG: error_type = tvb_get_guint8(tvb, offset); proto_tree_add_uint(x29_tree, hf_error_type, tvb, offset, 1, error_type); offset++; if (error_type != 0) { proto_tree_add_item(x29_tree, hf_inv_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN); } break; case BREAK_IND_MSG: if (tvb_reported_length_remaining(tvb, offset) > 0) { type_ref = tvb_get_guint8(tvb, offset); switch (type_ref) { case 0x01: /* change in PAD Aspect */ /* * XXX - dissect as per X.28. */ proto_tree_add_text(x29_tree, tvb, offset, 1, "Type reference: Change in PAD Aspect"); offset++; proto_tree_add_text(x29_tree, tvb, offset, 1, "Type of aspect: 0x%02x", type_ref); offset++; break; case 0x08: /* break */ proto_tree_add_text(x29_tree, tvb, offset, 1, "Type reference: Break"); offset++; proto_tree_add_text(x29_tree, tvb, offset, 1, "Break value: 0x%02x", type_ref); offset++; break; default: proto_tree_add_text(x29_tree, tvb, offset, 1, "Unknown type reference (0x%02x)", type_ref); offset++; proto_tree_add_text(x29_tree, tvb, offset, 1, "Type value: 0x%02x", type_ref); offset++; break; } } break; case RESELECTION_MSG: /* * XXX - dissect me. */ proto_tree_add_text(x29_tree, tvb, offset, -1, "Reselection message data"); break; case RESEL_WITH_TOA_NPI_MSG: /* * XXX - dissect me. */ proto_tree_add_text(x29_tree, tvb, offset, -1, "Reselection message data"); break; default: proto_tree_add_text(x29_tree, tvb, offset, -1, "PAD message data"); break; } } else { /* * Q bit not set - this is data. */ col_set_str(pinfo->cinfo, COL_INFO, "Data ..."); if (tree) { while (tvb_offset_exists(tvb, offset)) { /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* * Now compute the length of the line * *including* the end-of-line indication, * if any; we display it all. */ linelen = next_offset - offset; proto_tree_add_text(x29_tree, tvb, offset, linelen, "Data: %s", tvb_format_text(tvb, offset, linelen)); offset = next_offset; } } } }
static int dissect_text_lines(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { proto_tree *subtree; proto_item *ti; gint offset = 0, next_offset; gint len; http_message_info_t *message_info; const char *data_name; int length = tvb_captured_length(tvb); /* Check if this is actually xml * If there is less than 38 characters this is not XML * <?xml version="1.0" encoding="UTF-8"?> */ if(length > 38){ if (tvb_strncaseeql(tvb, 0, "<?xml", 5) == 0){ call_dissector(xml_handle, tvb, pinfo, tree); return length; } } data_name = pinfo->match_string; if (! (data_name && data_name[0])) { /* * No information from "match_string" */ message_info = (http_message_info_t *)data; if (message_info == NULL) { /* * No information from dissector data */ data_name = NULL; } else { data_name = message_info->media_str; if (! (data_name && data_name[0])) { /* * No information from dissector data */ data_name = NULL; } } } if (data_name) col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "(%s)", data_name); if (tree) { guint lines_read = 0; ti = proto_tree_add_item(tree, proto_text_lines, tvb, 0, -1, ENC_NA); if (data_name) proto_item_append_text(ti, ": %s", data_name); subtree = proto_item_add_subtree(ti, ett_text_lines); /* Read the media line by line */ while (tvb_offset_exists(tvb, offset)) { /* * XXX - we need to be passed the parameters * of the content type via data parameter, * so that we know the character set. We'd * have to handle that character set, which * might be a multibyte character set such * as "iso-10646-ucs-2", or might require other * special processing. */ len = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (len == -1) break; /* We use next_offset - offset instead of len in the * call to proto_tree_add_format_text() so it will include the * line terminator(s) (\r and/or \n) in the display. */ proto_tree_add_format_text(subtree, tvb, offset, next_offset - offset); lines_read++; offset = next_offset; } proto_item_append_text(subtree, " (%u lines)", lines_read); } return length; }
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; } } }