aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-irc.c
diff options
context:
space:
mode:
authorAnders Broman <anders.broman@ericsson.com>2012-04-12 05:46:42 +0000
committerAnders Broman <anders.broman@ericsson.com>2012-04-12 05:46:42 +0000
commit7f6a40b810ba991bc2b35f74ea6998b92de59048 (patch)
tree20f63ef693aa0b7bcb2fb7fde0fd51b143f9944b /epan/dissectors/packet-irc.c
parent5d101caa89e28875c5d2eeb2b353cbb8e2155336 (diff)
From Michael Mann: improved the IRC dissector to be able to pick out the CTCP protocol. https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1450
svn path=/trunk/; revision=42033
Diffstat (limited to 'epan/dissectors/packet-irc.c')
-rw-r--r--epan/dissectors/packet-irc.c408
1 files changed, 393 insertions, 15 deletions
diff --git a/epan/dissectors/packet-irc.c b/epan/dissectors/packet-irc.c
index 7b96e589ad..879c721c4e 100644
--- a/epan/dissectors/packet-irc.c
+++ b/epan/dissectors/packet-irc.c
@@ -45,28 +45,375 @@
#endif
#include <glib.h>
+#include <ctype.h>
#include <epan/packet.h>
+#include <epan/expert.h>
static int proto_irc = -1;
static int hf_irc_request = -1;
+static int hf_irc_request_prefix = -1;
+static int hf_irc_request_command = -1;
+static int hf_irc_request_command_param = -1;
+static int hf_irc_request_trailer = -1;
static int hf_irc_response = -1;
+static int hf_irc_response_prefix = -1;
+static int hf_irc_response_command = -1;
+static int hf_irc_response_num_command = -1;
+static int hf_irc_response_command_param = -1;
+static int hf_irc_response_trailer = -1;
+static int hf_irc_ctcp = -1;
static gint ett_irc = -1;
+static gint ett_irc_request = -1;
+static gint ett_irc_request_command = -1;
+static gint ett_irc_response = -1;
+static gint ett_irc_response_command = -1;
+
+static const guint8 TAG_DELIMITER[] = {0x01};
+
#define TCP_PORT_IRC 6667
#define TCP_PORT_DIRCPROXY 57000
/* good candidate for dynamic port specification */
static void
-dissect_irc_request(proto_tree *tree, tvbuff_t *tvb, int offset, int linelen)
+dissect_irc_tag_data(proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int datalen, packet_info *pinfo, char* command)
{
- proto_tree_add_item(tree, hf_irc_request, tvb, offset, linelen, ENC_ASCII|ENC_NA);
+ guchar found_start_needle = 0,
+ found_end_needle = 0;
+ gint tag_start_offset, tag_end_offset;
+
+ tag_start_offset = tvb_pbrk_guint8(tvb, offset, datalen, TAG_DELIMITER, &found_start_needle);
+ if (tag_start_offset == -1)
+ {
+ /* no tag data */
+ return;
+ }
+
+ tag_end_offset = tvb_pbrk_guint8(tvb, offset, datalen-offset, TAG_DELIMITER, &found_end_needle);
+ if (tag_end_offset == -1)
+ {
+ expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Missing ending tag delimited (0x01)");
+ return;
+ }
+
+ if ((strcmp(command, "NOTICE") != 0) &&
+ (strcmp(command, "PRIVMSG") != 0))
+ {
+ expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN, "Tag data outside of NOTICE or PRIVMSG command");
+ }
+
+ /* Placeholder to call CTCP dissector, strip out delimiter */
+ proto_tree_add_item(tree, hf_irc_ctcp, tvb, offset+1, datalen-2, ENC_ASCII|ENC_NA);
+}
+
+static void
+dissect_irc_request(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int linelen)
+{
+ proto_tree *request_tree, *command_tree = NULL;
+ proto_item *request_item, *command_item;
+ int start_offset = offset;
+ gint eop_offset = -1,
+ eoc_offset = -1,
+ eocp_offset,
+ tag_start_offset, tag_end_offset;
+ char* str_command;
+ guchar found_needle = 0,
+ found_tag_needle = 0;
+ gboolean first_command_param = TRUE;
+
+ request_item = proto_tree_add_item(tree, hf_irc_request, tvb, offset, linelen, ENC_ASCII|ENC_NA);
+ if (linelen <= 0)
+ return;
+
+ request_tree = proto_item_add_subtree(request_item, ett_irc_request );
+
+ /* Check if message has a prefix */
+ if (tvb_get_guint8(tvb, offset) == ':')
+ {
+ /* find the end of the prefix */
+ eop_offset = tvb_pbrk_guint8(tvb, offset+1, linelen-1, (const guint8 *)" ", &found_needle);
+ if (eop_offset == -1)
+ {
+ expert_add_info_format(pinfo, request_item, PI_MALFORMED, PI_ERROR, "Prefix missing ending <space>");
+ return;
+ }
+
+ proto_tree_add_item(request_tree, hf_irc_request_prefix, tvb, offset+1, eop_offset-offset-1, ENC_ASCII|ENC_NA);
+ found_needle = 0;
+ offset = eop_offset+1;
+ }
+
+ /* clear out any whitespace before command */
+ while(tvb_get_guint8(tvb, offset) == ' ')
+ {
+ offset++;
+ }
+
+ eoc_offset = tvb_pbrk_guint8(tvb, offset, linelen-offset, (const guint8 *)" ", &found_needle);
+ if (eoc_offset == -1)
+ {
+ proto_tree_add_item(request_tree, hf_irc_request_command, tvb, offset, linelen-offset, ENC_ASCII|ENC_NA);
+ col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", tvb_get_ephemeral_string(tvb, offset, linelen-offset));
+
+ /* Warn if there is a "numeric" command */
+ if ((linelen-offset == 3) &&
+ (isdigit(tvb_get_guint8(tvb, offset))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+1))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+2))))
+ {
+ expert_add_info_format(pinfo, request_item, PI_PROTOCOL, PI_WARN, "Numeric command not allowed in request");
+ }
+ return;
+ }
+
+ proto_tree_add_item(request_tree, hf_irc_request_command, tvb, offset, eoc_offset-offset, ENC_ASCII|ENC_NA);
+ str_command = tvb_get_ephemeral_string(tvb, offset, eoc_offset-offset);
+ col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", str_command);
+
+ /* Warn if there is a "numeric" command */
+ if ((eoc_offset-offset == 3) &&
+ (isdigit(tvb_get_guint8(tvb, offset))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+1))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+2))))
+ {
+ expert_add_info_format(pinfo, request_item, PI_PROTOCOL, PI_WARN, "Numeric command not allowed in request");
+ }
+
+ found_needle = 0;
+ offset = eoc_offset+1;
+
+ /* clear out any whitespace before command parameter */
+ while(tvb_get_guint8(tvb, offset) == ' ')
+ {
+ offset++;
+ }
+
+ /* Check if message has a trailer */
+ if (tvb_get_guint8(tvb, offset) == ':')
+ {
+ proto_tree_add_item(request_tree, hf_irc_request_trailer, tvb, offset+1, linelen-offset-1, ENC_ASCII|ENC_NA);
+ dissect_irc_tag_data(request_tree, request_item, tvb, offset+1, linelen-offset-1, pinfo, str_command);
+ return;
+ }
+
+ while(offset < start_offset+linelen)
+ {
+ eocp_offset = tvb_pbrk_guint8(tvb, offset, linelen-offset, (const guint8 *)" ", &found_needle);
+ tag_start_offset = tvb_pbrk_guint8(tvb, offset, linelen-offset, TAG_DELIMITER, &found_tag_needle);
+
+ /* Create subtree when the first parameter is found */
+ if (first_command_param)
+ {
+ command_item = proto_tree_add_text(request_tree, tvb, offset, linelen-offset, "Command parameters");
+ command_tree = proto_item_add_subtree(command_item, ett_irc_request_command );
+ first_command_param = FALSE;
+ }
+
+ if (((eocp_offset == -1) && (tag_start_offset == -1)) ||
+ ((eocp_offset != -1) && (tag_start_offset == -1)) ||
+ (eocp_offset < tag_start_offset))
+ {
+ /* regular message should be dissected */
+
+ found_needle = 0;
+ if (eocp_offset == -1)
+ {
+ proto_tree_add_item(command_tree, hf_irc_request_command_param, tvb, offset, linelen-offset, ENC_ASCII|ENC_NA);
+ return;
+ }
+
+ proto_tree_add_item(command_tree, hf_irc_request_command_param, tvb, offset, eocp_offset-offset, ENC_ASCII|ENC_NA);
+ offset = eocp_offset+1;
+
+ /* clear out any whitespace before next command parameter */
+ while(tvb_get_guint8(tvb, offset) == ' ')
+ {
+ offset++;
+ }
+
+ /* Check if message has a trailer */
+ if (tvb_get_guint8(tvb, offset) == ':')
+ {
+ proto_tree_add_item(request_tree, hf_irc_request_trailer, tvb, offset+1, linelen-offset-1, ENC_ASCII|ENC_NA);
+ dissect_irc_tag_data(request_tree, request_item, tvb, offset+1, linelen-offset-1, pinfo, str_command);
+ return;
+ }
+ }
+ else if (((eocp_offset == -1) && (tag_start_offset != -1)) ||
+ (eocp_offset > tag_start_offset))
+ {
+ /* tag data dissected */
+
+ found_tag_needle = 0;
+ tag_end_offset = tvb_pbrk_guint8(tvb, tag_start_offset+1, linelen-tag_start_offset-1, TAG_DELIMITER, &found_tag_needle);
+ if (tag_end_offset == -1)
+ {
+ expert_add_info_format(pinfo, request_item, PI_MALFORMED, PI_ERROR, "Missing ending tag delimited (0x01)");
+ return;
+ }
+
+ dissect_irc_tag_data(request_tree, request_item, tvb, tag_start_offset, tag_end_offset-tag_start_offset, pinfo, str_command);
+ offset = tag_end_offset+1;
+ }
+ }
}
static void
-dissect_irc_response(proto_tree *tree, tvbuff_t *tvb, int offset, int linelen)
+dissect_irc_response(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int linelen)
{
- proto_tree_add_item(tree, hf_irc_response, tvb, offset, linelen, ENC_ASCII|ENC_NA);
+ proto_tree *response_tree, *command_tree = NULL;
+ proto_item *response_item, *command_item, *hidden_item;
+ int start_offset = offset;
+ gint eop_offset = -1,
+ eoc_offset = -1,
+ eocp_offset,
+ tag_start_offset, tag_end_offset;
+ char* str_command;
+ guint16 num_command;
+ guchar found_needle = 0,
+ found_tag_needle = 0;
+ gboolean first_command_param = TRUE;
+
+ response_item = proto_tree_add_item(tree, hf_irc_response, tvb, offset, linelen, ENC_ASCII|ENC_NA);
+ if (linelen <= 0)
+ return;
+
+ response_tree = proto_item_add_subtree(response_item, ett_irc_response );
+
+ /* Check if message has a prefix */
+ if (tvb_get_guint8(tvb, offset) == ':')
+ {
+ /* find the end of the prefix */
+ eop_offset = tvb_pbrk_guint8(tvb, offset+1, linelen-1, (const guint8 *)" ", &found_needle);
+ if (eop_offset == -1)
+ {
+ expert_add_info_format(pinfo, response_item, PI_MALFORMED, PI_ERROR, "Prefix missing ending <space>");
+ return;
+ }
+
+ proto_tree_add_item(response_tree, hf_irc_response_prefix, tvb, offset+1, eop_offset-offset-1, ENC_ASCII|ENC_NA);
+ found_needle = 0;
+ offset = eop_offset+1;
+ }
+
+ /* clear out any whitespace before command */
+ while(tvb_get_guint8(tvb, offset) == ' ')
+ {
+ offset++;
+ }
+
+ eoc_offset = tvb_pbrk_guint8(tvb, offset, linelen-offset, (const guint8 *)" ", &found_needle);
+ if (eoc_offset == -1)
+ {
+ proto_tree_add_item(response_tree, hf_irc_response_command, tvb, offset, linelen-offset, ENC_ASCII|ENC_NA);
+ col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", tvb_get_ephemeral_string(tvb, offset, linelen-offset));
+
+ /* if response command is numeric, allow it to be filtered as an integer */
+ if ((linelen-offset == 3) &&
+ (isdigit(tvb_get_guint8(tvb, offset))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+1))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+2))))
+ {
+ num_command = ((tvb_get_guint8(tvb, offset)-0x30)*100) + ((tvb_get_guint8(tvb, offset+1)-0x30)*10) + (tvb_get_guint8(tvb, offset+2)-0x30);
+ hidden_item = proto_tree_add_uint(response_tree, hf_irc_response_num_command, tvb, offset, linelen-offset, num_command);
+ PROTO_ITEM_SET_HIDDEN(hidden_item);
+ }
+ return;
+ }
+
+ proto_tree_add_item(response_tree, hf_irc_response_command, tvb, offset, eoc_offset-offset, ENC_ASCII|ENC_NA);
+ str_command = tvb_get_ephemeral_string(tvb, offset, eoc_offset-offset);
+ col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", str_command);
+
+ /* if response command is numeric, allow it to be filtered as an integer */
+ if ((eoc_offset-offset == 3) &&
+ (isdigit(tvb_get_guint8(tvb, offset))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+1))) &&
+ (isdigit(tvb_get_guint8(tvb, offset+2))))
+ {
+ num_command = ((tvb_get_guint8(tvb, offset)-0x30)*100) + ((tvb_get_guint8(tvb, offset+1)-0x30)*10) + (tvb_get_guint8(tvb, offset+2)-0x30);
+ hidden_item = proto_tree_add_uint(response_tree, hf_irc_response_num_command, tvb, offset, eoc_offset-offset, num_command);
+ PROTO_ITEM_SET_HIDDEN(hidden_item);
+ }
+
+ found_needle = 0;
+ offset = eoc_offset+1;
+
+ /* clear out any whitespace before command parameter */
+ while(tvb_get_guint8(tvb, offset) == ' ')
+ {
+ offset++;
+ }
+
+ /* Check if message has a trailer */
+ if (tvb_get_guint8(tvb, offset) == ':')
+ {
+ proto_tree_add_item(response_tree, hf_irc_response_trailer, tvb, offset+1, linelen-offset-1, ENC_ASCII|ENC_NA);
+ dissect_irc_tag_data(response_tree, response_item, tvb, offset+1, linelen-offset-1, pinfo, str_command);
+ return;
+ }
+
+ while(offset < start_offset+linelen)
+ {
+ eocp_offset = tvb_pbrk_guint8(tvb, offset, linelen-offset, (const guint8 *)" ", &found_needle);
+ tag_start_offset = tvb_pbrk_guint8(tvb, offset, linelen-offset, TAG_DELIMITER, &found_tag_needle);
+
+ /* Create subtree when the first parameter is found */
+ if (first_command_param)
+ {
+ command_item = proto_tree_add_text(response_tree, tvb, offset, linelen-offset, "Command parameters");
+ command_tree = proto_item_add_subtree(command_item, ett_irc_response_command );
+ first_command_param = FALSE;
+ }
+
+ if (((eocp_offset == -1) && (tag_start_offset == -1)) ||
+ ((eocp_offset != -1) && (tag_start_offset == -1)) ||
+ (eocp_offset < tag_start_offset))
+ {
+ /* regular message should be dissected */
+
+ found_needle = 0;
+ if (eocp_offset == -1)
+ {
+ proto_tree_add_item(command_tree, hf_irc_response_command_param, tvb, offset, linelen-offset, ENC_ASCII|ENC_NA);
+ return;
+ }
+
+ proto_tree_add_item(command_tree, hf_irc_response_command_param, tvb, offset, eocp_offset-offset, ENC_ASCII|ENC_NA);
+ offset = eocp_offset+1;
+
+ /* clear out any whitespace before next command parameter */
+ while(tvb_get_guint8(tvb, offset) == ' ')
+ {
+ offset++;
+ }
+
+ /* Check if message has a trailer */
+ if (tvb_get_guint8(tvb, offset) == ':')
+ {
+ proto_tree_add_item(response_tree, hf_irc_response_trailer, tvb, offset+1, linelen-offset-1, ENC_ASCII|ENC_NA);
+ dissect_irc_tag_data(response_tree, response_item, tvb, offset+1, linelen-offset-1, pinfo, str_command);
+ return;
+ }
+ }
+ else if (((eocp_offset == -1) && (tag_start_offset != -1)) ||
+ (eocp_offset > tag_start_offset))
+ {
+ /* tag data dissected */
+
+ found_tag_needle = 0;
+ tag_end_offset = tvb_pbrk_guint8(tvb, tag_start_offset+1, linelen-tag_start_offset-1, TAG_DELIMITER, &found_tag_needle);
+ if (tag_end_offset == -1)
+ {
+ expert_add_info_format(pinfo, response_item, PI_MALFORMED, PI_ERROR, "Missing ending tag delimited (0x01)");
+ return;
+ }
+
+ dissect_irc_tag_data(response_tree, response_item, tvb, tag_start_offset, tag_end_offset-tag_start_offset, pinfo, str_command);
+ offset = tag_end_offset+1;
+ }
+ }
}
static void
@@ -115,11 +462,11 @@ dissect_irc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
if (pinfo->match_uint == pinfo->destport)
{
- dissect_irc_request(irc_tree, tvb, offset, linelen);
+ dissect_irc_request(irc_tree, tvb, pinfo, offset, linelen);
}
else
{
- dissect_irc_response(irc_tree, tvb, offset, linelen);
+ dissect_irc_response(irc_tree, tvb, pinfo, offset, linelen);
}
}
offset = next_offset;
@@ -131,20 +478,51 @@ void
proto_register_irc(void)
{
static hf_register_info hf[] = {
- { &hf_irc_response,
- { "Response", "irc.response",
- FT_STRING, BASE_NONE, NULL, 0x0,
- "Line of response message", HFILL }},
-
- { &hf_irc_request,
- { "Request", "irc.request",
- FT_STRING, BASE_NONE, NULL, 0x0,
- "Line of request message", HFILL }},
+ { &hf_irc_response, { "Response", "irc.response", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Line of response message", HFILL }},
+
+ { &hf_irc_request, { "Request", "irc.request", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Line of request message", HFILL }},
+
+ { &hf_irc_request_prefix, { "Prefix", "irc.request.prefix", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Request prefix", HFILL }},
+
+ { &hf_irc_request_command, { "Command", "irc.request.command", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Request command", HFILL }},
+
+ { &hf_irc_request_command_param, { "Parameter", "irc.request.command_parameter", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Request command parameter", HFILL }},
+
+ { &hf_irc_request_trailer, { "Trailer", "irc.request.trailer", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Request trailer", HFILL }},
+
+ { &hf_irc_response_prefix, { "Prefix", "irc.response.prefix", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Response prefix", HFILL }},
+
+ { &hf_irc_response_command, { "Command", "irc.response.command", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Response command", HFILL }},
+
+ { &hf_irc_response_num_command, { "Command", "irc.response.command", FT_UINT16, BASE_DEC,
+ NULL, 0x0, "Response (numeric) command", HFILL }},
+
+ { &hf_irc_response_command_param, { "Parameter", "irc.response.command_parameter", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Response command parameter", HFILL }},
+
+ { &hf_irc_response_trailer, { "Trailer", "irc.response.trailer", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Response trailer", HFILL }},
+
+ { &hf_irc_ctcp, { "CTCP Data", "irc.ctcp", FT_STRING, BASE_NONE,
+ NULL, 0x0, "Placeholder to dissect CTCP data", HFILL }}
};
static gint *ett[] = {
&ett_irc,
+ &ett_irc_request,
+ &ett_irc_request_command,
+ &ett_irc_response,
+ &ett_irc_response_command
};
+
proto_irc = proto_register_protocol("Internet Relay Chat", "IRC", "irc");
proto_register_field_array(proto_irc, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));