static void dissect_irc_tag_data(proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int datalen, packet_info *pinfo, guint8* command) { 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_tag_data(proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int datalen, packet_info *pinfo, guint8* command) { 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(pinfo, item, &ei_irc_missing_end_delimiter); return; } if ((strcmp(command, "NOTICE") != 0) && (strcmp(command, "PRIVMSG") != 0)) { expert_add_info(pinfo, item, &ei_irc_tag_data_invalid); } /* 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 gint subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle) { struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb; return tvb_pbrk_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needles, found_needle); }
static gint frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle) { struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb; frame_cache(frame_tvb); return tvb_pbrk_guint8(tvb, abs_offset, limit, needles, found_needle); }
static const guint8* get_unquoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len) { const guint8* s = NULL; guint l = 0; gint o; o = tvb_pbrk_guint8(tvb, offset, -1, " \t\r\n", NULL); if (o != -1) { l = o - offset; s = tvb_get_ptr(tvb, offset, l); offset = o; } *next_offset = offset; *len = l; return s; }
static const guint8* get_unquoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len) { const guint8* s = NULL; guint l = 0; gint o; o = tvb_pbrk_guint8(tvb, offset, -1, " \t\r\n", NULL); if (o != -1) { l = o - offset; s = tvb_get_string_enc(wmem_packet_scope(), tvb, offset, l, ENC_ASCII); offset = o; } *next_offset = offset; *len = l; return s; }
static void dissect_irc_response(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int linelen) { proto_tree *response_tree, *command_tree = NULL; proto_item *response_item, *command_item, *hidden_item; int start_offset = offset; int end_offset = start_offset+linelen; gint eop_offset = -1, eoc_offset = -1, eocp_offset, tag_start_offset, tag_end_offset; guint8* 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, " ", &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(offset < end_offset && tvb_get_guint8(tvb, offset) == ' ') { offset++; } if (offset == end_offset) { expert_add_info_format(pinfo, response_item, PI_MALFORMED, PI_ERROR, "Response has no command"); return; } eoc_offset = tvb_pbrk_guint8(tvb, offset, end_offset-offset, " ", &found_needle); if (eoc_offset == -1) { proto_tree_add_item(response_tree, hf_irc_response_command, tvb, offset, end_offset-offset, ENC_ASCII|ENC_NA); col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", tvb_get_ephemeral_string(tvb, offset, end_offset-offset)); /* if response command is numeric, allow it to be filtered as an integer */ if ((end_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, end_offset-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(offset < end_offset && tvb_get_guint8(tvb, offset) == ' ') { offset++; } if (offset == end_offset) { /* No command parameters */ return; } /* 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, end_offset-offset-1, ENC_ASCII|ENC_NA); dissect_irc_tag_data(response_tree, response_item, tvb, offset+1, end_offset-offset-1, pinfo, str_command); return; } while(offset < end_offset) { eocp_offset = tvb_pbrk_guint8(tvb, offset, end_offset-offset, " ", &found_needle); tag_start_offset = tvb_pbrk_guint8(tvb, offset, end_offset-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, end_offset-offset, "Command parameters"); command_tree = proto_item_add_subtree(command_item, ett_irc_response_command ); first_command_param = FALSE; } if ((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, end_offset-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(offset < end_offset && tvb_get_guint8(tvb, offset) == ' ') { offset++; } if (offset == end_offset) { break; } /* 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, end_offset-offset-1, ENC_ASCII|ENC_NA); dissect_irc_tag_data(response_tree, response_item, tvb, offset+1, end_offset-offset-1, pinfo, str_command); return; } } else if ((eocp_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, end_offset-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 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; int end_offset = start_offset+linelen; gint eop_offset = -1, eoc_offset = -1, eocp_offset, tag_start_offset, tag_end_offset; guint8* 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, " ", &found_needle); if (eop_offset == -1) { expert_add_info(pinfo, request_item, &ei_irc_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(offset < end_offset && tvb_get_guint8(tvb, offset) == ' ') { offset++; } if (offset == end_offset) { expert_add_info(pinfo, request_item, &ei_irc_request_command); return; } eoc_offset = tvb_pbrk_guint8(tvb, offset, end_offset-offset, " ", &found_needle); if (eoc_offset == -1) { proto_tree_add_item(request_tree, hf_irc_request_command, tvb, offset, end_offset-offset, ENC_ASCII|ENC_NA); col_append_fstr( pinfo->cinfo, COL_INFO, " (%s)", tvb_get_string(wmem_packet_scope(), tvb, offset, end_offset-offset)); /* Warn if there is a "numeric" command */ if ((end_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(pinfo, request_item, &ei_irc_numeric_request_command); } return; } proto_tree_add_item(request_tree, hf_irc_request_command, tvb, offset, eoc_offset-offset, ENC_ASCII|ENC_NA); str_command = tvb_get_string(wmem_packet_scope(), 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(pinfo, request_item, &ei_irc_numeric_request_command); } found_needle = 0; offset = eoc_offset+1; /* clear out any whitespace before command parameter */ while(offset < end_offset && tvb_get_guint8(tvb, offset) == ' ') { offset++; } if (offset == end_offset) { /* No command parameters */ return; } /* 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, end_offset-offset-1, ENC_ASCII|ENC_NA); dissect_irc_tag_data(request_tree, request_item, tvb, offset+1, end_offset-offset-1, pinfo, str_command); return; } while(offset < end_offset) { eocp_offset = tvb_pbrk_guint8(tvb, offset, end_offset-offset, " ", &found_needle); tag_start_offset = tvb_pbrk_guint8(tvb, offset, end_offset-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, end_offset-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, end_offset-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(offset < end_offset && tvb_get_guint8(tvb, offset) == ' ') { offset++; } if (offset == end_offset) { break; } /* 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, end_offset-offset-1, ENC_ASCII|ENC_NA); dissect_irc_tag_data(request_tree, request_item, tvb, offset+1, end_offset-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, end_offset-tag_start_offset-1, TAG_DELIMITER, &found_tag_needle); if (tag_end_offset == -1) { expert_add_info(pinfo, request_item, &ei_irc_missing_end_delimiter); 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; } } }