示例#1
0
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;
    }
  }
}
示例#2
0
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;
    }
}
示例#3
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);
}
示例#4
0
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;
    }
}
示例#9
0
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;
    }
}
示例#10
0
/* 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) ? "...)" : ")");
}
示例#11
0
/*
 * 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;
}
示例#12
0
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;
      }
    }
  }
}
示例#13
0
/*
 * 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;
	}
}
示例#14
0
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;
		}
	  }
	}
}
示例#15
0
/*
 * 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;
}
示例#16
0
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;
    }
}
示例#17
0
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);
}
示例#18
0
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;
    }
  } 
}
示例#19
0
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;
		}
	}
}
示例#20
0
/* 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);
	}
}
示例#21
0
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);
	}
}
示例#22
0
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;
        }
    }
}
示例#23
0
/* 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);
}
示例#24
0
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);
		}
	}
}
示例#25
0
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 */
    }
  }
}
示例#26
0
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;
}
示例#27
0
/* 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
}
示例#28
0
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;
			}
		}
	}
}
示例#29
0
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;
}
示例#30
0
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;

    }
  }
}