Esempio n. 1
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:
		proto_tree_add_format_text(icap_tree, 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_captured_length_remaining(tvb, offset);
	if (datalen > 0) {
		call_dissector(data_handle,
		    tvb_new_subset_remaining(tvb, offset), pinfo, icap_tree);
	}
}
Esempio n. 2
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;
}
static void
dissect_gift(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	proto_item	*ti, *hidden_item;
	proto_tree	*gift_tree, *cmd_tree;
	gboolean	is_request;
	gint            offset = 0;
	const guchar    *line;
	gint            next_offset;
	int             linelen;
	int             tokenlen;
	const guchar    *next_token;

	/* set "Protocol" column text */
	col_set_str(pinfo->cinfo, COL_PROTOCOL, "giFT");

	/* determine whether it is a request to or response from the server */
	if (pinfo->match_uint == pinfo->destport)
		is_request = TRUE;
	else
		is_request = FALSE;

	linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
	line = tvb_get_ptr(tvb, offset, linelen);

	/* set "Info" column text */
	col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
			     is_request ? "Request" : "Response",
			     format_text(line, linelen));

	/* if tree != NULL, build protocol tree */
	if (tree) {
		ti = proto_tree_add_item(tree, proto_gift, tvb, 0, -1, ENC_NA);
		gift_tree = proto_item_add_subtree(ti, ett_gift);

		if (is_request) {
			hidden_item = proto_tree_add_boolean(gift_tree, hf_gift_request, tvb, 0, 0, TRUE);
		} else {
			hidden_item = proto_tree_add_boolean(gift_tree, hf_gift_response, tvb, 0, 0, TRUE);
		}
		PROTO_ITEM_SET_HIDDEN(hidden_item);

		ti = proto_tree_add_format_text(gift_tree, tvb, offset, next_offset - offset);
		cmd_tree = proto_item_add_subtree(ti, ett_gift_cmd);

		tokenlen = get_token_len(line, line + linelen, &next_token);
		if (tokenlen != 0) {
			if (is_request) {
				proto_tree_add_string(cmd_tree, hf_gift_request_cmd, tvb, offset,
						    tokenlen, format_text(line, tokenlen));
			} else {
				proto_tree_add_string(cmd_tree, hf_gift_response_cmd, tvb, offset,
						    tokenlen, format_text(line, tokenlen));
			}
			offset += (gint) (next_token - line);
			linelen -= (int) (next_token - line);
			line = next_token;
		}

		if (linelen != 0) {
			if (is_request) {
				proto_tree_add_string(cmd_tree, hf_gift_request_arg, tvb, offset,
						    linelen, format_text(line, linelen));
			} else {
				proto_tree_add_string(cmd_tree, hf_gift_response_arg, tvb, offset,
						    linelen, format_text(line, linelen));
			}
		}
	}
}
static void
dissect_acap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
	gboolean        is_request;
	proto_tree      *acap_tree, *reqresp_tree;
	proto_item      *ti, *hidden_item;
	gint			offset = 0;
	const guchar	*line;
	gint			next_offset;
	int				linelen;
	int				tokenlen;
	const guchar	*next_token;

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "ACAP");

	/*
	 * 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_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).
	 */
	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, hfi_acap, tvb, offset, -1,
		    ENC_NA);
		acap_tree = proto_item_add_subtree(ti, ett_acap);

		if (is_request) {
			hidden_item = proto_tree_add_boolean(acap_tree,
			    &hfi_acap_request, tvb, 0, 0, TRUE);
			PROTO_ITEM_SET_HIDDEN(hidden_item);
		} else {
			hidden_item = proto_tree_add_boolean(acap_tree,
			    &hfi_acap_response, tvb, 0, 0, TRUE);
			PROTO_ITEM_SET_HIDDEN(hidden_item);
		}

		/*
		 * Put the line into the protocol tree.
		 */
		ti = proto_tree_add_format_text(acap_tree, tvb, offset, next_offset - offset);
		reqresp_tree = proto_item_add_subtree(ti, ett_acap_reqresp);

		/*
		 * Show the first 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) {
			if (is_request) {
				proto_tree_add_text(reqresp_tree, tvb, offset,
				    tokenlen, "Request Tag: %s",
				    format_text(line, tokenlen));
			} else {
				proto_tree_add_text(reqresp_tree, tvb, offset,
				    tokenlen, "Response Tag: %s",
				    format_text(line, tokenlen));
			}
			offset += (int)(next_token - line);
			linelen -= (int)(next_token - line);
			line = next_token;
		}

		/*
		 * Add the rest of the line as request or reply data.
		 */
		if (linelen != 0) {
			if (is_request) {
				proto_tree_add_text(reqresp_tree, tvb, offset,
				    linelen, "Request: %s",
				    format_text(line, linelen));
			} else {
				proto_tree_add_text(reqresp_tree, tvb, offset,
				    linelen, "Response: %s",
				    format_text(line, linelen));
			}
		}

		/*
		 * XXX - show the rest of the frame; this requires that
		 * we handle literals, quoted strings, continuation
		 * responses, etc..
		 *
		 * This involves a state machine, and attaching
		 * state information to the packets.
		 */
	}
}
Esempio n. 5
0
static void
dissect_ftp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
    gboolean        is_request;
    proto_tree     *ftp_tree;
    proto_tree     *reqresp_tree;
    proto_item     *ti, *hidden_item;
    gint            offset;
    const guchar   *line;
    guint32         code;
    gchar           code_str[4];
    gboolean        is_port_request   = FALSE;
    gboolean        is_eprt_request   = FALSE;
    gboolean        is_pasv_response  = FALSE;
    gboolean        is_epasv_response = FALSE;
    gint            next_offset;
    int             linelen;
    int             tokenlen          = 0;
    const guchar   *next_token;
    guint32         pasv_ip;
    guint32         pasv_offset;
    guint32         ftp_ip;
    guint32         ftp_ip_len;
    guint32         eprt_offset;
    guint32         eprt_af           = 0;
    guint32         eprt_ip;
    guint16         eprt_ipv6[8];
    guint32         eprt_ip_len       = 0;
    guint16         ftp_port;
    guint32         ftp_port_len;
    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, 0, -1, &next_offset, FALSE);
    line    = tvb_get_ptr(tvb, 0, 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));

    ti = proto_tree_add_item(tree, proto_ftp, tvb, 0, -1, ENC_NA);
    ftp_tree = proto_item_add_subtree(ti, ett_ftp);

    hidden_item = proto_tree_add_boolean(ftp_tree,
            hf_ftp_request, tvb, 0, 0, is_request);
    PROTO_ITEM_SET_HIDDEN(hidden_item);
    hidden_item = proto_tree_add_boolean(ftp_tree,
            hf_ftp_response, tvb, 0, 0, is_request == FALSE);
    PROTO_ITEM_SET_HIDDEN(hidden_item);

    /* Put the line into the protocol tree. */
    ti = proto_tree_add_format_text(ftp_tree, tvb, 0, next_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) {
            proto_tree_add_item(reqresp_tree, hf_ftp_request_command,
                    tvb, 0, tokenlen, ENC_ASCII|ENC_NA);
            if (strncmp(line, "PORT", tokenlen) == 0)
                is_port_request = TRUE;
            /*
             * EPRT request command, as per RFC 2428
             */
            else if (strncmp(line, "EPRT", tokenlen) == 0)
                is_eprt_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 && g_ascii_isdigit(line[0]) && g_ascii_isdigit(line[1])
            && g_ascii_isdigit(line[2])) {
            /*
             * One-line reply, or first or last line
             * of a multi-line reply.
             */
            tvb_get_nstringz0(tvb, 0, sizeof(code_str), code_str);
            code = (guint32)strtoul(code_str, NULL, 10);

            proto_tree_add_uint(reqresp_tree,
                    hf_ftp_response_code, tvb, 0, 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
             */
            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;

    /*
     * 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, &pasv_offset, &ftp_ip_len, &ftp_port_len)) {
            proto_tree_add_ipv4(reqresp_tree, hf_ftp_active_ip,
                    tvb, pasv_offset + (tokenlen+1) , ftp_ip_len, ftp_ip);
            proto_tree_add_uint(reqresp_tree, hf_ftp_active_port,
                    tvb, pasv_offset + 1 + (tokenlen+1) + ftp_ip_len, ftp_port_len, 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) {
                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, &pasv_offset, &ftp_ip_len, &ftp_port_len)) {
                proto_tree_add_ipv4(reqresp_tree, hf_ftp_pasv_ip,
                        tvb, pasv_offset + 4, ftp_ip_len, pasv_ip);
                proto_tree_add_uint(reqresp_tree, hf_ftp_pasv_port,
                        tvb, pasv_offset + 4 + 1 + ftp_ip_len, ftp_port_len, 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) {
                    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_eprt_request) {
        /*
         * RFC2428 - sect. 2
         * This frame contains a EPRT request; let's dissect it and set up a
         * conversation for the data connection.
         */
        if (parse_eprt_request(line, linelen,
                    &eprt_af, &eprt_ip, eprt_ipv6, &ftp_port,
                    &eprt_ip_len, &ftp_port_len)) {

            /* since parse_eprt_request() returned TRUE,
               we know that we have a valid address family */
            eprt_offset = tokenlen + 1 + 1;  /* token, space, 1st delimiter */
            proto_tree_add_uint(reqresp_tree, hf_ftp_eprt_af, tvb,
                    eprt_offset, 1, eprt_af);
            eprt_offset += 1 + 1; /* addr family, 2nd delimiter */

            if (eprt_af == EPRT_AF_IPv4) {
                proto_tree_add_ipv4(reqresp_tree, hf_ftp_eprt_ip,
                        tvb, eprt_offset, eprt_ip_len, eprt_ip);
                set_address(&ftp_ip_address, AT_IPv4, 4,
                        (const guint8 *)&eprt_ip);
            }
            else if (eprt_af == EPRT_AF_IPv6) {
                proto_tree_add_ipv6(reqresp_tree, hf_ftp_eprt_ipv6,
                        tvb, eprt_offset, eprt_ip_len, (const struct e_in6_addr *)eprt_ipv6);
                set_address(&ftp_ip_address, AT_IPv6, 16, eprt_ipv6);
            }
            eprt_offset += eprt_ip_len + 1; /* addr, 3rd delimiter */

            proto_tree_add_uint(reqresp_tree, hf_ftp_eprt_port,
                    tvb, eprt_offset, ftp_port_len, ftp_port);

            /* Find/create conversation for data */
            conversation = find_conversation(pinfo->fd->num,
                    &pinfo->src, &ftp_ip_address,
                    PT_TCP, ftp_port, 0, NO_PORT_B);
            if (conversation == NULL) {
                conversation = conversation_new(
                        pinfo->fd->num, &pinfo->src, &ftp_ip_address,
                        PT_TCP, ftp_port, 0, NO_PORT2);
                conversation_set_dissector(conversation,
                        ftpdata_handle);
            }
        }
        else {
            proto_tree_add_expert(reqresp_tree, pinfo, &ei_ftp_eprt_args_invalid,
                    tvb, offset - linelen - 1, linelen);
        }
    }

    if (is_epasv_response) {
        if (linelen != 0) {
            proto_item *addr_it;
            /*
             * RFC2428 - sect. 3
             * This frame contains an  EPSV response; set up a
             * conversation for the data.
             */
            if (parse_extended_pasv_response(line, linelen,
                        &ftp_port, &pasv_offset, &ftp_port_len)) {
                /* Add IP address and port number to tree */

                if (ftp_ip_address.type == AT_IPv4) {
                    guint32 addr;
                    memcpy(&addr, ftp_ip_address.data, 4);
                    addr_it = proto_tree_add_ipv4(reqresp_tree,
                            hf_ftp_epsv_ip, tvb, 0, 0, addr);
                    PROTO_ITEM_SET_GENERATED(addr_it);
                }
                else if (ftp_ip_address.type == AT_IPv6) {
                    addr_it = proto_tree_add_ipv6(reqresp_tree,
                            hf_ftp_epsv_ipv6, tvb, 0, 0,
                            (const struct e_in6_addr *)ftp_ip_address.data);
                    PROTO_ITEM_SET_GENERATED(addr_it);
                }

                proto_tree_add_uint(reqresp_tree,
                        hf_ftp_epsv_port, tvb, pasv_offset + 4,
                        ftp_port_len, ftp_port);

                /* Find/create conversation for data */
                conversation = find_conversation(pinfo->fd->num, &ftp_ip_address,
                                                 &pinfo->dst, PT_TCP, ftp_port, 0,
                                                 NO_PORT_B);
                if (conversation == NULL) {
                    conversation = conversation_new(
                        pinfo->fd->num, &ftp_ip_address, &pinfo->dst,
                        PT_TCP, ftp_port, 0, NO_PORT2);
                    conversation_set_dissector(conversation,
                        ftpdata_handle);
                }
            }
            else {
                proto_tree_add_expert(reqresp_tree, pinfo, &ei_ftp_epsv_args_invalid,
                        tvb, offset - linelen - 1, linelen);
            }
        }
    }

    /*
     * 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_format_text(ftp_tree, tvb, offset,
                next_offset - offset);
        offset = next_offset;
    }
}
Esempio n. 6
0
static int
dissect_l1_events(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
{
	proto_tree	*subtree;
	proto_item	*ti;
	gint		offset = 0, next_offset;
	gint		len;
	const char	*data_name;

	data_name = pinfo->match_string;
	if (! (data_name && data_name[0])) {
		/*
		 * No information from "match_string"
		 */
		data_name = (char *)data;
		if (! (data_name && data_name[0])) {
			/*
			 * No information from dissector data
			 */
			data_name = NULL;
		}
	}

	col_set_str(pinfo->cinfo, COL_PROTOCOL, "Layer1");
	col_set_str(pinfo->cinfo, COL_DEF_SRC,
			    pinfo->pseudo_header->l1event.uton? "TE" : "NT");
	len = tvb_find_line_end(tvb, 0, tvb_ensure_length_remaining(tvb, 0),
					&next_offset, FALSE);
	if(len>0)
		col_add_str(pinfo->cinfo, COL_INFO, tvb_format_text(tvb, 0, len));

	if (tree) {
		ti = proto_tree_add_item(tree, proto_l1_events,
				tvb, 0, -1, ENC_NA);
		if (data_name)
			proto_item_append_text(ti, ": %s", data_name);
		subtree = proto_item_add_subtree(ti, ett_l1_events);
		/* Read the media line by line */
		while (tvb_reported_length_remaining(tvb, offset) != 0) {
			/*
			 * 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,
					tvb_ensure_length_remaining(tvb, offset),
					&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);
			offset = next_offset;
		}
	}

	return tvb_length(tvb);
}
Esempio n. 7
0
/*
 * Process a multipart body-part:
 *      MIME-part-headers [ line-end *OCTET ]
 *      line-end dashed-boundary transport-padding line-end
 *
 * If applicable, call a media subdissector.
 *
 * Return the offset to the start of the next body-part.
 */
static gint
process_body_part(proto_tree *tree, tvbuff_t *tvb, multipart_info_t *m_info,
                  packet_info *pinfo, gint start, gint idx,
                  gboolean *last_boundary)
{
    proto_tree *subtree;
    proto_item *ti;
    gint offset = start, next_offset = 0;
    char *parameters = NULL;
    gint body_start, boundary_start, boundary_line_len;

    gchar *content_type_str = NULL;
    gchar *content_encoding_str = NULL;
    char *filename = NULL;
    char *mimetypename = NULL;
    int  len = 0;
    gboolean last_field = FALSE;
    gboolean is_raw_data = FALSE;

    const guint8 *boundary = (guint8 *)m_info->boundary;
    gint boundary_len = m_info->boundary_length;

    ti = proto_tree_add_item(tree, hf_multipart_part, tvb, start, 0, ENC_ASCII|ENC_NA);
    subtree = proto_item_add_subtree(ti, ett_multipart_body);

    /* find the next boundary to find the end of this body part */
    boundary_start = find_next_boundary(tvb, offset, boundary, boundary_len,
                                        &boundary_line_len, last_boundary);

    if (boundary_start <= 0) {
        return -1;
    }

    /*
     * Process the MIME-part-headers
     */

    while (!last_field)
    {
        gint colon_offset;
        char *hdr_str;
        char *header_str;

        /* Look for the end of the header (denoted by cr)
         * 3:d argument to imf_find_field_end() maxlen; must be last offset in the tvb.
         */
        next_offset = imf_find_field_end(tvb, offset, tvb_reported_length_remaining(tvb, offset)+offset, &last_field);
        /* the following should never happen */
        /* If cr not found, won't have advanced - get out to avoid infinite loop! */
        /*
        if (next_offset == offset) {
            break;
        }
        */
        if (last_field && (next_offset+2) <= boundary_start) {
            /* Add the extra CRLF of the last field */
            next_offset += 2;
        } else if((next_offset-2) == boundary_start) {
            /* if CRLF is the start of next boundary it belongs to the boundary and not the field,
               so it's the last field without CRLF */
            last_field = TRUE;
            next_offset -= 2;
        } else if (next_offset > boundary_start) {
            /* if there is no CRLF between last field and next boundary - trim it! */
            next_offset = boundary_start;
        }

        hdr_str = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, next_offset - offset, ENC_ASCII);

        header_str = unfold_and_compact_mime_header(hdr_str, &colon_offset);
        if (colon_offset <= 0) {
            /* if there is no colon it's no header, so break and add complete line to the body */
            next_offset = offset;
            break;
        } else {
            gint hf_index;

            /* Split header name from header value */
            header_str[colon_offset] = '\0';
            hf_index = is_known_multipart_header(header_str, colon_offset);

            if (hf_index == -1) {
                if(isprint_string(hdr_str)) {
                    proto_tree_add_format_text(subtree, tvb, offset, next_offset - offset);
                } else {
                    /* if the header name is unkown and not printable, break and add complete line to the body */
                    next_offset = offset;
                    break;
                }
            } else {
                char *value_str = header_str + colon_offset + 1;

                proto_tree_add_string_format(subtree,
                                             hf_header_array[hf_index], tvb,
                                             offset, next_offset - offset,
                                             (const char *)value_str, "%s",
                                             tvb_format_text(tvb, offset, next_offset - offset));

                switch (hf_index) {
                case POS_ORIGINALCONTENT:
                {
                    gint semicolon_offset;
                    /* The Content-Type starts at colon_offset + 1 or after the type parameter */
                    char* type_str = find_parameter(value_str, "type=", NULL);
                    if(type_str != NULL) {
                        value_str = type_str;
                    }

                    semicolon_offset = index_of_char(
                                           value_str, ';');

                    if (semicolon_offset > 0) {
                        value_str[semicolon_offset] = '\0';
                        m_info->orig_parameters = wmem_strdup(wmem_packet_scope(),
                                                              value_str + semicolon_offset + 1);
                    }

                    m_info->orig_content_type = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1);
                }
                break;
                case POS_CONTENT_TYPE:
                {
                    /* The Content-Type starts at colon_offset + 1 */
                    gint semicolon_offset = index_of_char(
                                                value_str, ';');

                    if (semicolon_offset > 0) {
                        value_str[semicolon_offset] = '\0';
                        parameters = wmem_strdup(wmem_packet_scope(), value_str + semicolon_offset + 1);
                    } else {
                        parameters = NULL;
                    }

                    content_type_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1);

                    /* Show content-type in root 'part' label */
                    proto_item_append_text(ti, " (%s)", content_type_str);

                    /* find the "name" parameter in case we don't find a content disposition "filename" */
                    if((mimetypename = find_parameter(parameters, "name=", &len)) != NULL) {
                        mimetypename = g_strndup(mimetypename, len);
                    }

                    if(strncmp(content_type_str, "application/octet-stream",
                               sizeof("application/octet-stream")-1) == 0) {
                        is_raw_data = TRUE;
                    }

                    /* there are only 2 body parts possible and each part has specific content types */
                    if(m_info->protocol && idx == 0
                            && (is_raw_data || g_ascii_strncasecmp(content_type_str, m_info->protocol,
                                    strlen(m_info->protocol)) != 0))
                    {
                        return -1;
                    }
                }
                break;
                case POS_CONTENT_TRANSFER_ENCODING:
                {
                    /* The Content-Transferring starts at colon_offset + 1 */
                    gint cr_offset = index_of_char(value_str, '\r');

                    if (cr_offset > 0) {
                        value_str[cr_offset] = '\0';
                    }

                    content_encoding_str = wmem_ascii_strdown(wmem_packet_scope(), value_str, -1);
                }
                break;
                case POS_CONTENT_DISPOSITION:
                {
                    /* find the "filename" parameter */
                    if((filename = find_parameter(value_str, "filename=", &len)) != NULL) {
                        filename = g_strndup(filename, len);
                    }
                }
                break;
                default:
                    break;
                }
            }
        }
        offset = next_offset;
    }

    body_start = next_offset;

    /*
     * Process the body
     */

    {
        gint body_len = boundary_start - body_start;
        tvbuff_t *tmp_tvb = tvb_new_subset_length(tvb, body_start, body_len);
        /* if multipart subtype is encrypted the protcol string was set */
        /* see: https://msdn.microsoft.com/en-us/library/cc251581.aspx */
        /* there are only 2 body parts possible and each part has specific content types */
        if(m_info->protocol && idx == 1 && is_raw_data)
        {
            gssapi_encrypt_info_t  encrypt;

            memset(&encrypt, 0, sizeof(encrypt));
            encrypt.decrypt_gssapi_tvb=DECRYPT_GSSAPI_NORMAL;

            dissect_kerberos_encrypted_message(tmp_tvb, pinfo, subtree, &encrypt);

            if(encrypt.gssapi_decrypted_tvb) {
                tmp_tvb = encrypt.gssapi_decrypted_tvb;
                is_raw_data = FALSE;
                content_type_str = m_info->orig_content_type;
                parameters = m_info->orig_parameters;
            } else if(encrypt.gssapi_encrypted_tvb) {
                tmp_tvb = encrypt.gssapi_encrypted_tvb;
                proto_tree_add_expert(tree, pinfo, &ei_multipart_decryption_not_possible, tmp_tvb, 0, -1);
            }
        }

        if (!is_raw_data &&
                content_type_str) {

            /*
             * subdissection
             */
            gboolean dissected;

            /*
             * Try and remove any content transfer encoding so that each sub-dissector
             * doesn't have to do it itself
             *
             */

            if(content_encoding_str && remove_base64_encoding) {

                if(!g_ascii_strncasecmp(content_encoding_str, "base64", 6))
                    tmp_tvb = base64_decode(pinfo, tmp_tvb, filename ? filename : (mimetypename ? mimetypename : content_type_str));

            }

            /*
             * First try the dedicated multipart dissector table
             */
            dissected = dissector_try_string(multipart_media_subdissector_table,
                                             content_type_str, tmp_tvb, pinfo, subtree, parameters);
            if (! dissected) {
                /*
                 * Fall back to the default media dissector table
                 */
                dissected = dissector_try_string(media_type_dissector_table,
                                                 content_type_str, tmp_tvb, pinfo, subtree, parameters);
            }
            if (! dissected) {
                const char *save_match_string = pinfo->match_string;
                pinfo->match_string = content_type_str;
                call_dissector_with_data(media_handle, tmp_tvb, pinfo, subtree, parameters);
                pinfo->match_string = save_match_string;
            }
            parameters = NULL; /* Shares same memory as content_type_str */
        } else {
            call_dissector(data_handle, tmp_tvb, pinfo, subtree);
        }
        proto_item_set_len(ti, boundary_start - start);
        if (*last_boundary == TRUE) {
            proto_tree_add_item(tree, hf_multipart_last_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII);
        } else {
            proto_tree_add_item(tree, hf_multipart_boundary, tvb, boundary_start, boundary_line_len, ENC_NA|ENC_ASCII);
        }

        g_free(filename);
        g_free(mimetypename);

        return boundary_start + boundary_line_len;
    }
}