diff options
author | Anders Broman <anders.broman@ericsson.com> | 2012-04-12 05:46:42 +0000 |
---|---|---|
committer | Anders Broman <anders.broman@ericsson.com> | 2012-04-12 05:46:42 +0000 |
commit | 7f6a40b810ba991bc2b35f74ea6998b92de59048 (patch) | |
tree | 20f63ef693aa0b7bcb2fb7fde0fd51b143f9944b /epan/dissectors/packet-irc.c | |
parent | 5d101caa89e28875c5d2eeb2b353cbb8e2155336 (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.c | 408 |
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)); |