static gboolean find_dir_tokens(tvbuff_t *tvb, gint name_start, gint *sel_start, gint *host_start, gint *port_start, gint *line_len, gint *next_offset) { gint remain; if (tvb_length_remaining(tvb, name_start) < MIN_DIR_LINE_LEN) return FALSE; if (! (sel_start && host_start && port_start && line_len && next_offset) ) return FALSE; *line_len = tvb_find_line_end(tvb, name_start, MAX_DIR_LINE_LEN, next_offset, FALSE); if (*line_len < MIN_DIR_LINE_LEN) return FALSE; remain = *line_len; *sel_start = tvb_find_guint8(tvb, name_start, remain, '\t') + 1; if (*sel_start < name_start + 1) return FALSE; remain -= *sel_start - name_start; *host_start = tvb_find_guint8(tvb, *sel_start, remain, '\t') + 1; if (*host_start < *sel_start + 1) return FALSE; remain -= *host_start - *sel_start; *port_start = tvb_find_guint8(tvb, *host_start, remain, '\t') + 1; if (*port_start < *host_start + 1) return FALSE; return TRUE; }
static void rtpproxy_add_notify_addr(proto_tree *rtpproxy_tree, tvbuff_t *tvb, guint begin, guint end) { gint offset = 0; gint tmp = 0; gboolean ipv6 = FALSE; proto_item *ti; /* Check for at least one colon */ offset = tvb_find_guint8(tvb, begin, end, ':'); if(offset != -1) { /* Find if it's the latest colon (not in case of a IPv6) */ while((tmp = tvb_find_guint8(tvb, offset+1, end, ':')) != -1) { ipv6 = TRUE; offset = tmp; } /* We have ip:port */ if(ipv6) proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_ipv6, tvb, begin, offset - begin, ENC_ASCII | ENC_NA); else proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, offset - begin, ENC_ASCII | ENC_NA); proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, offset+1, end - (offset+1), (guint16) g_ascii_strtoull((gchar*)tvb_get_string(wmem_packet_scope(), tvb, offset+1, end - (offset+1)), NULL, 10)); } else { /* Only port is supplied */ ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_notify_ipv4, tvb, begin, 0, ENC_ASCII | ENC_NA); proto_item_append_text(ti, "<skipped>"); PROTO_ITEM_SET_GENERATED(ti); proto_tree_add_uint(rtpproxy_tree, hf_rtpproxy_notify_port, tvb, begin, end - begin, (guint16) g_ascii_strtoull((gchar*)tvb_get_string(wmem_packet_scope(), tvb, begin, end - begin), NULL, 10)); } }
/* This code is modeled on the code in packet-sip.c * ABNF code for the MSRP header: * The following syntax specification uses the augmented Backus-Naur * Form (BNF) as described in RFC-2234 [6]. * * * msrp-req-or-resp = msrp-request / msrp-response * msrp-request = req-start headers [content-stuff] end-line * msrp-response = resp-start headers end-line * * req-start = pMSRP SP transact-id SP method CRLF * resp-start = pMSRP SP transact-id SP status-code [SP phrase] CRLF * phrase = utf8text * * pMSRP = %x4D.53.52.50 ; MSRP in caps * transact-id = ident * method = mSEND / mREPORT / other-method * mSEND = %x53.45.4e.44 ; SEND in caps * mREPORT = %x52.45.50.4f.52.54; REPORT in caps * other-method = 1*UPALPHA * Examples: * "MSRP 1234 SEND(CRLF)" * "MSRP 1234 200 OK(CRLF) */ static gboolean check_msrp_header(tvbuff_t *tvb) { gint offset = 0; gint linelen; gint space_offset; gint next_offset = 0; guint token_1_len; gint token_2_start; /* * 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()" calls below won't throw exceptions. * */ offset = 0; if(tvb_length(tvb) < 4 || tvb_get_ntohl(tvb, 0) != 0x4d535250 /* MSRP */){ return FALSE; } linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE); /* Find the first SP */ space_offset = tvb_find_guint8(tvb, 0, -1, ' '); if (space_offset <= 0) { /* * Either there's no space in the line (which means * the line is empty or doesn't have a token followed * by a space; neither is valid for a request or response), or * the first character in the line is a space ( which isn't valid * for a MSRP header.) */ return FALSE; } token_1_len = space_offset; token_2_start = space_offset + 1; space_offset = tvb_find_guint8(tvb, token_2_start, -1, ' '); if (space_offset == -1) { /* * There's no space after the second token, so we don't * have a third token. */ return FALSE; } /* * Is the first token "MSRP"? */ if (token_1_len == MSRP_HDR_LEN) { /* && tvb_strneql(tvb, 0, MSRP_HDR, MSRP_HDR_LEN) == 0){ */ /* This check can be made more strict but accept we do have MSRP for now */ return TRUE; } return FALSE; }
/* ---------------------------------------------- */ static int fix_header_len(tvbuff_t *tvb, int offset) { int base_offset, ctrla_offset; char *value; int size; fix_parameter *tag; base_offset = offset; /* get at least the fix version: 8=FIX.x.x */ if (fix_marker(tvb, offset) != 0) { return fix_next_header(tvb, offset); } /* begin string */ ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01); if (ctrla_offset == -1) { /* it should be there, (minimum size is big enough) * if not maybe it's not really * a FIX packet but it's too late to bail out. */ return fix_next_header(tvb, offset +MARKER_LEN) +MARKER_LEN; } offset = ctrla_offset + 1; /* msg length */ if (!(tag = fix_param(tvb, offset)) || tvb_strneql(tvb, offset, "9=", 2)) { /* not a tag or not the BodyLength tag, give up */ return fix_next_header(tvb, offset); } value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len); /* Fix version, msg type, length and checksum aren't in body length. * If the packet is big enough find the checksum */ size = atoi(value) +tag->ctrla_offset - base_offset +1; if (tvb_length_remaining(tvb, base_offset) > size +4) { /* 10= should be there */ offset = base_offset +size; if (tvb_strneql(tvb, offset, "10=", 3) != 0) { /* No? bogus packet, try to find the next header */ return fix_next_header(tvb, base_offset +MARKER_LEN) +MARKER_LEN; } ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01); if (ctrla_offset == -1) { /* assume checksum is 7 bytes 10=xxx\01 */ return size+7; } return size +ctrla_offset -offset +1; } else { } /* assume checksum is 7 bytes 10=xxx\01 */ return size +7; }
static gint find_printer_string(tvbuff_t *tvb, int offset) { int i; /* try to find end of string, either '\n' or '\0' */ i = tvb_find_guint8(tvb, offset, -1, '\0'); if (i == -1) i = tvb_find_guint8(tvb, offset, -1, '\n'); if (i == -1) return -1; return i - offset; /* length of string */ }
/** Dissects an SIR packet. */ static void dissect_sir(tvbuff_t *tvb, packet_info *pinfo, proto_tree *root) { gint offset = 0; gint bof_offset; gint eof_offset; while (tvb_length_remaining(tvb, offset) > 0) { bof_offset = tvb_find_guint8(tvb, offset, -1, SIR_BOF); eof_offset = (bof_offset == -1) ? -1 : tvb_find_guint8(tvb, bof_offset, -1, SIR_EOF); if (bof_offset == -1 || eof_offset == -1) { if (pinfo->can_desegment) { pinfo->desegment_offset = offset; pinfo->desegment_len = 1; } return; } else { guint preamble_len = bof_offset - offset; gint data_offset = bof_offset + 1; tvbuff_t* next_tvb = tvb_new_subset(tvb, data_offset, eof_offset - data_offset, -1); next_tvb = unescape_data(next_tvb, pinfo); if (root) { guint data_len = tvb_length(next_tvb) < 2 ? 0 : tvb_length(next_tvb) - 2; proto_tree* ti = proto_tree_add_protocol_format(root, proto_sir, tvb, offset, eof_offset - offset + 1, "Serial Infrared, Len: %d", data_len); proto_tree* tree = proto_item_add_subtree(ti, ett_sir); if (preamble_len > 0) proto_tree_add_item(tree, hf_sir_preamble, tvb, offset, preamble_len, ENC_NA); proto_tree_add_item(tree, hf_sir_bof, tvb, bof_offset, 1, ENC_BIG_ENDIAN); proto_tree_add_uint(tree, hf_sir_length, next_tvb, 0, data_len, data_len); next_tvb = checksum_data(next_tvb, tree); proto_tree_add_item(tree, hf_sir_eof, tvb, eof_offset, 1, ENC_BIG_ENDIAN); } else { next_tvb = checksum_data(next_tvb, NULL); } call_dissector(irda_handle, next_tvb, pinfo, root); } offset = eof_offset + 1; } }
/** Unescapes the data. */ static tvbuff_t * unescape_data(tvbuff_t *tvb, packet_info *pinfo) { if (tvb_find_guint8(tvb, 0, -1, SIR_CE) == -1) { return tvb; } else { guint length = tvb_length(tvb); guint offset; guint8 *data = (guint8 *)g_malloc(length); guint8 *dst = data; tvbuff_t *next_tvb; for (offset = 0; offset < length; ) { guint8 c = tvb_get_guint8(tvb, offset++); if ((c == SIR_CE) && (offset < length)) c = SIR_ESCAPE(tvb_get_guint8(tvb, offset++)); *dst++ = c; } next_tvb = tvb_new_child_real_data(tvb, data, (guint) (dst-data), (guint) (dst-data)); tvb_set_free_cb(next_tvb, g_free); add_new_data_source(pinfo, next_tvb, "Unescaped SIR"); return next_tvb; } }
static gint subset_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle) { struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb; return tvb_find_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needle); }
/* Find the delimiter, '*'. * Returns the number of bytes from foffset to the delimiter or 0 if not * found within 256 bytes from foffset */ static int find_delimiter(tvbuff_t *tvb, int foffset) { int offset; offset = tvb_find_guint8(tvb, foffset, 256, '*'); if (offset >= foffset) { return offset - foffset; } return 0; }
/* ---------------------------------------------- Format: name=value\001 */ static fix_parameter *fix_param(tvbuff_t *tvb, int offset) { static fix_parameter ret; int equals; ret.ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01); if (ret.ctrla_offset == -1) { return NULL; } ret.field_len = ret.ctrla_offset - offset + 1; equals = tvb_find_guint8(tvb, offset, ret.field_len, '='); if (equals == -1) { return NULL; } ret.value_offset = equals + 1; ret.tag_len = ret.value_offset - offset - 1; ret.value_len = ret.ctrla_offset - ret.value_offset; return &ret; }
static gint rtpproxy_add_tag(proto_tree *rtpproxy_tree, tvbuff_t *tvb, guint begin, guint realsize) { proto_item *ti = NULL; proto_tree *another_tree = NULL; gint new_offset; guint end; new_offset = tvb_find_guint8(tvb, begin, -1, ' '); if(new_offset < 0) end = realsize; /* No more parameters */ else end = new_offset; /* SER/OpenSER/OpenSIPS/Kamailio adds Media-ID right after the Tag * separated by a semicolon */ new_offset = tvb_find_guint8(tvb, begin, end, ';'); if(new_offset == -1) { ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, end - begin, ENC_ASCII | ENC_NA); another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag); ti = proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, 0, ENC_ASCII | ENC_NA); proto_item_append_text(ti, "<skipped>"); PROTO_ITEM_SET_GENERATED(ti); } else { ti = proto_tree_add_item(rtpproxy_tree, hf_rtpproxy_tag, tvb, begin, new_offset - begin, ENC_ASCII | ENC_NA); if ((guint)new_offset == begin) { proto_item_append_text(ti, "<skipped>"); /* A very first Offer/Update command */ PROTO_ITEM_SET_GENERATED(ti); } another_tree = proto_item_add_subtree(ti, ett_rtpproxy_tag); proto_tree_add_item(another_tree, hf_rtpproxy_mediaid, tvb, new_offset+1, end - (new_offset+1), ENC_ASCII | ENC_NA); } return (end == realsize ? -1 : (gint)end); }
static void dissect_cimd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint8 OC; /* Operation Code */ guint8 PN; /* Packet number */ guint16 checksum = 0; /* Checksum */ guint16 pkt_check = 0; gint etxp = 0; /* ETX position */ gint offset = 0; gboolean checksumIsValid = TRUE; guint8 last1, last2, last3; etxp = tvb_find_guint8(tvb, CIMD_PN_OFFSET + CIMD_PN_LENGTH, -1, CIMD_ETX); if (etxp == -1) return; OC = (guint8)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, CIMD_OC_OFFSET, CIMD_OC_LENGTH, ENC_ASCII), NULL, 10); PN = (guint8)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, CIMD_PN_OFFSET, CIMD_PN_LENGTH, ENC_ASCII), NULL, 10); last1 = tvb_get_guint8(tvb, etxp - 1); last2 = tvb_get_guint8(tvb, etxp - 2); last3 = tvb_get_guint8(tvb, etxp - 3); if (last1 == CIMD_DELIM) { /* valid packet, CC is missing */ } else if (last1 != CIMD_DELIM && last2 != CIMD_DELIM && last3 == CIMD_DELIM) { /* looks valid, it would be nice to check that last1 and last2 are HEXA */ /* CC is present */ checksum = (guint16)strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, etxp - 2, 2, ENC_ASCII), NULL, 16); for (; offset < (etxp - 2); offset++) { pkt_check += tvb_get_guint8(tvb, offset); pkt_check &= 0xFF; } checksumIsValid = (checksum == pkt_check); } else { checksumIsValid = FALSE; } /* Make entries in Protocol column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIMD"); if (checksumIsValid) col_add_str(pinfo->cinfo, COL_INFO, val_to_str(OC, vals_hdr_OC, "Unknown (%d)")); else col_add_fstr(pinfo->cinfo, COL_INFO, "%s - %s", val_to_str(OC, vals_hdr_OC, "Unknown (%d)"), "invalid checksum"); dissect_cimd_operation(tvb, tree, etxp, checksum, last1, OC, PN); }
WSLUA_METHOD TvbRange_strsize(lua_State* L) { /* Find the size of a zero terminated string from a `TvbRange`. The size of the string includes the terminating zero. @since 1.11.3 */ #define WSLUA_OPTARG_TvbRange_strsize_ENCODING 2 /* The encoding to use. Defaults to ENC_ASCII. */ TvbRange tvbr = checkTvbRange(L,1); guint encoding = (guint)luaL_optinteger(L,WSLUA_OPTARG_TvbRange_strsize_ENCODING, ENC_ASCII|ENC_NA); gint offset; gunichar2 uchar; if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } switch (encoding & ENC_CHARENCODING_MASK) { case ENC_UTF_16: case ENC_UCS_2: offset = tvbr->offset; do { if (!tvb_bytes_exist (tvbr->tvb->ws_tvb, offset, 2)) { luaL_error(L,"out of bounds"); return 0; } /* Endianness doesn't matter when looking for null */ uchar = tvb_get_ntohs (tvbr->tvb->ws_tvb, offset); offset += 2; } while (uchar != 0); lua_pushinteger(L, tvb_unicode_strsize(tvbr->tvb->ws_tvb, tvbr->offset)); break; default: if (tvb_find_guint8 (tvbr->tvb->ws_tvb, tvbr->offset, -1, 0) == -1) { luaL_error(L,"out of bounds"); return 0; } lua_pushinteger(L, tvb_strsize(tvbr->tvb->ws_tvb, tvbr->offset)); break; } WSLUA_RETURN(1); /* Length of the zero terminated string. */ }
WSLUA_METHOD TvbRange_stringz(lua_State* L) { /* Obtain a zero terminated string from a TvbRange */ #define WSLUA_OPTARG_TvbRange_stringz_ENCODING 2 /* The encoding to use. Defaults to ENC_ASCII. */ TvbRange tvbr = checkTvbRange(L,1); guint encoding = (guint)luaL_optint(L,WSLUA_OPTARG_TvbRange_stringz_ENCODING, ENC_ASCII|ENC_NA); gint offset; gunichar2 uchar; if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } switch (encoding & ENC_CHARENCODING_MASK) { case ENC_UTF_16: case ENC_UCS_2: offset = tvbr->offset; do { if (!tvb_bytes_exist (tvbr->tvb->ws_tvb, offset, 2)) { luaL_error(L,"out of bounds"); return 0; } /* Endianness doesn't matter when looking for null */ uchar = tvb_get_ntohs (tvbr->tvb->ws_tvb, offset); offset += 2; } while(uchar != 0); break; default: if (tvb_find_guint8 (tvbr->tvb->ws_tvb, tvbr->offset, -1, 0) == -1) { luaL_error(L,"out of bounds"); return 0; } break; } lua_pushstring(L, (gchar*)tvb_get_stringz_enc(wmem_packet_scope(),tvbr->tvb->ws_tvb,tvbr->offset,NULL,encoding)); WSLUA_RETURN(1); /* The zero terminated string */ }
static int dissect_fullcollectionname(tvbuff_t *tvb, guint offset, proto_tree *tree) { gint32 fcn_length, dbn_length; proto_item *ti; proto_tree *fcn_tree; fcn_length = tvb_strsize(tvb, offset); ti = proto_tree_add_item(tree, hf_mongo_fullcollectionname, tvb, offset, fcn_length, ENC_ASCII|ENC_NA); /* If this doesn't find anything, we'll just throw an exception below */ dbn_length = tvb_find_guint8(tvb, offset, fcn_length, '.') - offset; fcn_tree = proto_item_add_subtree(ti, ett_mongo_fcn); proto_tree_add_item(fcn_tree, hf_mongo_database_name, tvb, offset, dbn_length, ENC_ASCII|ENC_NA); proto_tree_add_item(fcn_tree, hf_mongo_collection_name, tvb, offset + 1 + dbn_length, fcn_length - dbn_length - 2, ENC_ASCII|ENC_NA); return fcn_length; }
/** * This is the ROS connection header dissector. The general packet format is described * here: http://wiki.ros.org/ROS/TCPROS * In short, a connection header looks like such: '4-byte length + [4-byte field length + "field=value" ]*' */ static gint dissect_ros_connection_header_field(tvbuff_t *tvb, proto_tree *tree, packet_info *pinfo, gint offset) { proto_item *ti; proto_tree *field_tree; guint32 fLen = 0; gint sep, ret = 0; /** Do we have enough for a length field? (ie: 4 bytes) */ if( tvb_reported_length_remaining(tvb, offset) > SIZE_OF_LENGTH_FIELD ) { /** Get the length of the next field */ fLen = tvb_get_letohl(tvb, offset); /** Display the field as a utf-8 string */ ti = proto_tree_add_item(tree, hf_tcpros_connection_header_field, tvb, offset, SIZE_OF_LENGTH_FIELD, ENC_UTF_8|ENC_LITTLE_ENDIAN); field_tree = proto_item_add_subtree(ti, ett_tcpros); proto_tree_add_item(field_tree, hf_tcpros_connection_header_field_length, tvb, offset, SIZE_OF_LENGTH_FIELD, ENC_LITTLE_ENDIAN); offset += SIZE_OF_LENGTH_FIELD; ti = proto_tree_add_item(field_tree, hf_tcpros_connection_header_field_data, tvb, offset, fLen, ENC_UTF_8|ENC_NA); /** Look for the '=' separator */ sep = (tvb_find_guint8(tvb, offset, fLen, '=') - offset); /** If we find a separator, then split field name and value */ if( sep > 0 ) { field_tree = proto_item_add_subtree(ti, ett_tcpros); proto_tree_add_item(field_tree, hf_tcpros_connection_header_field_name, tvb, offset, sep, ENC_UTF_8|ENC_NA); proto_tree_add_item(field_tree, hf_tcpros_connection_header_field_value, tvb, offset+sep+1, fLen - sep - 1, ENC_UTF_8|ENC_NA); col_append_str(pinfo->cinfo, COL_INFO, tvb_get_string_enc(wmem_packet_scope(), tvb, offset, sep, ENC_UTF_8)); } ret = fLen + SIZE_OF_LENGTH_FIELD; } return ret; }
static void dissect_cimd_operation(tvbuff_t *tvb, proto_tree *tree, gint etxp, guint16 checksum, guint8 last1,guint8 OC, guint8 PN) { guint32 PC = 0; /* Parameter code */ gint idx; gint offset = 0; gint endOffset = 0; proto_item *cimd_item; proto_tree *cimd_tree; /* create display subtree for the protocol */ cimd_item = proto_tree_add_item(tree, proto_cimd, tvb, 0, etxp + 1, ENC_NA); cimd_tree = proto_item_add_subtree(cimd_item, ett_cimd); proto_tree_add_uint(cimd_tree, hf_cimd_opcode_indicator, tvb, CIMD_OC_OFFSET, CIMD_OC_LENGTH, OC); proto_tree_add_uint(cimd_tree, hf_cimd_packet_number_indicator, tvb, CIMD_PN_OFFSET, CIMD_PN_LENGTH, PN); offset = CIMD_PN_OFFSET + CIMD_PN_LENGTH; while (offset < etxp && tvb_get_guint8(tvb, offset) == CIMD_DELIM) { endOffset = tvb_find_guint8(tvb, offset + 1, etxp, CIMD_DELIM); if (endOffset == -1) break; PC = (guint32) strtoul(tvb_get_string_enc(wmem_packet_scope(), tvb, offset + 1, CIMD_PC_LENGTH, ENC_ASCII), NULL, 10); try_val_to_str_idx(PC, cimd_vals_PC, &idx); if (idx != -1 && tree) { (vals_hdr_PC[idx].diss)(tvb, cimd_tree, idx, offset, endOffset); } offset = endOffset; } if (last1 != CIMD_DELIM) { /* Checksum is present */ proto_tree_add_uint(cimd_tree, hf_cimd_checksum_indicator, tvb, etxp - 2, 2, checksum); } }
static void dissect_imf_address(tvbuff_t *tvb, int offset, int length, proto_item *item, packet_info *pinfo) { proto_tree *group_tree; proto_item *group_item; int addr_pos; /* if there is a colon present it is a group */ if((addr_pos = tvb_find_guint8(tvb, offset, length, ':')) == -1) { /* there isn't - so it must be a mailbox */ dissect_imf_mailbox(tvb, offset, length, item, pinfo); } else { /* it is a group */ group_tree = proto_item_add_subtree(item, ett_imf_group); /* the display-name is mandatory */ group_item = proto_tree_add_item(group_tree, hf_imf_display_name, tvb, offset, addr_pos - offset - 1, ENC_ASCII|ENC_NA); /* consume any whitespace */ for(addr_pos++ ;addr_pos < (offset + length); addr_pos++) { if(!isspace(tvb_get_guint8(tvb, addr_pos))) { break; } } if(tvb_get_guint8(tvb, addr_pos) != ';') { dissect_imf_mailbox_list(tvb, addr_pos, length - (addr_pos - offset), group_item, pinfo); /* XXX: need to check for final ';' */ } } }
static const guint8* get_quoted_string(tvbuff_t *tvb, gint offset, gint *next_offset, guint *len) { int c; const guint8* s = NULL; guint l = 0; gint o; c = tvb_get_guint8(tvb, offset); if (c == '"') { o = tvb_find_guint8(tvb, offset+1, -1, '"'); if (o != -1) { offset++; l = o - offset; s = tvb_get_ptr(tvb, offset, l); offset = o + 1; } } *next_offset = offset; *len = l; return s; }
/* Code to actually dissect the packets */ static int dissect_msrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gint offset = 0; gint next_offset = 0; proto_item *ti, *th, *msrp_headers_item, *msrp_element_item; proto_tree *msrp_tree, *reqresp_tree, *raw_tree, *msrp_hdr_tree, *msrp_end_tree; proto_tree *msrp_element_tree, *msrp_data_tree; gint linelen; gint space_offset; gint token_2_start; guint token_2_len; gint token_3_start; guint token_3_len; gint token_4_start = 0; guint token_4_len = 0; gboolean is_msrp_response; gint end_line_offset; gint end_line_len; gint line_end_offset; gint message_end_offset; gint colon_offset; char *transaction_id_str = NULL; gint header_len; gint hf_index; gint value_offset; guchar c; gint value_len; char *value; gboolean have_body = FALSE; gboolean found_match = FALSE; gint content_type_len, content_type_parameter_str_len; gchar *media_type_str_lower_case = NULL; char *content_type_parameter_str = NULL; tvbuff_t *next_tvb; gint parameter_offset; gint semi_colon_offset; if ( !check_msrp_header(tvb)){ return 0; } /* We have a MSRP header with at least three tokens * * 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()" calls below won't throw exceptions. * */ offset = 0; linelen = tvb_find_line_end(tvb, 0, -1, &next_offset, FALSE); /* Find the first SP and skip the first token */ token_2_start = tvb_find_guint8(tvb, 0, linelen, ' ') + 1; /* Work out 2nd token's length by finding next space */ space_offset = tvb_find_guint8(tvb, token_2_start, linelen-token_2_start, ' '); token_2_len = space_offset - token_2_start; /* Transaction ID found store it for later use */ transaction_id_str = tvb_get_ephemeral_string(tvb, token_2_start, token_2_len); /* Look for another space in this line to indicate a 4th token */ token_3_start = space_offset + 1; space_offset = tvb_find_guint8(tvb, token_3_start,linelen-token_3_start, ' '); if ( space_offset == -1){ /* 3rd token runs to the end of the line */ token_3_len = linelen - token_3_start; }else{ /* We have a fourth token */ token_3_len = space_offset - token_3_start; token_4_start = space_offset + 1; token_4_len = linelen - token_4_start; } /* * Yes, so this is either a msrp-request or msrp-response. * To be a msrp-response, the second token must be * a 3-digit number. */ is_msrp_response = FALSE; if (token_3_len == 3) { if (isdigit(tvb_get_guint8(tvb, token_3_start)) && isdigit(tvb_get_guint8(tvb, token_3_start + 1)) && isdigit(tvb_get_guint8(tvb, token_3_start + 2))) { is_msrp_response = TRUE; } } /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MSRP"); if (is_msrp_response){ if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "Response: %s ", tvb_format_text(tvb, token_3_start, token_3_len)); if (token_4_len ) col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", tvb_format_text(tvb, token_4_start, token_4_len)); col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s", tvb_format_text(tvb, token_2_start, token_2_len)); } }else{ if (check_col(pinfo->cinfo, COL_INFO)) { proto_tree_add_text(tree, tvb, token_3_start, token_3_len, "Col %s L=%u", tvb_format_text(tvb, token_3_start, token_3_len),token_3_len); col_add_fstr(pinfo->cinfo, COL_INFO, "Request: %s ", tvb_format_text(tvb, token_3_start, token_3_len)); col_append_fstr(pinfo->cinfo, COL_INFO, "Transaction ID: %s", tvb_format_text(tvb, token_2_start, token_2_len)); } } /* Find the end line to be able to process the headers * Note that in case of [content-stuff] headers and [content-stuff] is separated by CRLF */ offset = next_offset; end_line_offset = find_end_line(tvb,offset); /* TODO if -1 (No end line found, is returned do something) */ end_line_len = tvb_find_line_end(tvb, end_line_offset, -1, &next_offset, FALSE); message_end_offset = end_line_offset + end_line_len + 2; if (tree) { ti = proto_tree_add_item(tree, proto_msrp, tvb, 0, message_end_offset, FALSE); msrp_tree = proto_item_add_subtree(ti, ett_msrp); if (is_msrp_response){ th = proto_tree_add_item(msrp_tree,hf_msrp_response_line,tvb,0,linelen,FALSE); reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp); proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE); proto_tree_add_uint(reqresp_tree,hf_msrp_status_code,tvb,token_3_start,token_3_len, atoi(tvb_get_ephemeral_string(tvb, token_3_start, token_3_len))); }else{ th = proto_tree_add_item(msrp_tree,hf_msrp_request_line,tvb,0,linelen,FALSE); reqresp_tree = proto_item_add_subtree(th, ett_msrp_reqresp); proto_tree_add_item(reqresp_tree,hf_msrp_transactionID,tvb,token_2_start,token_2_len,FALSE); proto_tree_add_item(reqresp_tree,hf_msrp_method,tvb,token_3_start,token_3_len,FALSE); } /* Conversation setup info */ if (global_msrp_show_setup_info) { show_setup_info(tvb, pinfo, msrp_tree); } /* Headers */ msrp_headers_item = proto_tree_add_item(msrp_tree, hf_msrp_msg_hdr, tvb, offset,(end_line_offset - offset), FALSE); msrp_hdr_tree = proto_item_add_subtree(msrp_headers_item, ett_msrp_hdr); /* * Process the headers */ while (tvb_reported_length_remaining(tvb, offset) > 0 && offset < end_line_offset ) { /* 'desegment' is FALSE so will set next_offset to beyond the end of the buffer if no line ending is found */ linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); if (linelen == 0) { /* * This is a blank line separating the * message header from the message body. */ have_body = TRUE; break; } line_end_offset = offset + linelen; colon_offset = tvb_find_guint8(tvb, offset, linelen, ':'); if (colon_offset == -1) { /* * Malformed header - no colon after the name. */ proto_tree_add_text(msrp_hdr_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, linelen)); } else { header_len = colon_offset - offset; hf_index = msrp_is_known_msrp_header(tvb, offset, header_len); if (hf_index == -1) { proto_tree_add_text(msrp_hdr_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, linelen)); } else { /* * Skip whitespace after the colon. */ value_offset = colon_offset + 1; while (value_offset < line_end_offset && ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t')) value_offset++; /* * Fetch the value. */ value_len = line_end_offset - value_offset; value = tvb_get_ephemeral_string(tvb, value_offset, value_len); /* * Add it to the protocol tree, * but display the line as is. */ msrp_element_item = proto_tree_add_string_format(msrp_hdr_tree, hf_header_array[hf_index], tvb, offset, next_offset - offset, value, "%s", tvb_format_text(tvb, offset, linelen)); msrp_element_tree = proto_item_add_subtree( msrp_element_item, ett_msrp_element); switch ( hf_index ) { case MSRP_CONTENT_TYPE : content_type_len = value_len; semi_colon_offset = tvb_find_guint8(tvb, value_offset,linelen, ';'); if ( semi_colon_offset != -1) { parameter_offset = semi_colon_offset +1; /* * Skip whitespace after the semicolon. */ while (parameter_offset < line_end_offset && ((c = tvb_get_guint8(tvb, parameter_offset)) == ' ' || c == '\t')) parameter_offset++; content_type_len = semi_colon_offset - value_offset; content_type_parameter_str_len = line_end_offset - parameter_offset; content_type_parameter_str = tvb_get_ephemeral_string(tvb, parameter_offset, content_type_parameter_str_len); } media_type_str_lower_case = ascii_strdown_inplace( (gchar *)tvb_get_ephemeral_string(tvb, value_offset, content_type_len)); break; default: break; } } } offset = next_offset; }/* End while */ if ( have_body ){ /* * There's a message body starting at "next_offset". * Set the length of the header item. */ proto_item_set_end(msrp_headers_item, tvb, next_offset); /* Create new tree & tvb for data */ next_tvb = tvb_new_subset_remaining(tvb, next_offset); ti = proto_tree_add_item(msrp_tree, hf_msrp_data, tvb, next_offset, -1, FALSE); msrp_data_tree = proto_item_add_subtree(ti, ett_msrp_data); /* give the content type parameters to sub dissectors */ if ( media_type_str_lower_case != NULL ) { void *save_private_data = pinfo->private_data; pinfo->private_data = content_type_parameter_str; found_match = dissector_try_string(media_type_dissector_table, media_type_str_lower_case, next_tvb, pinfo, msrp_data_tree); pinfo->private_data = save_private_data; /* If no match dump as text */ } if ( found_match != TRUE ) { offset = 0; while (tvb_offset_exists(next_tvb, offset)) { tvb_find_line_end(next_tvb, offset, -1, &next_offset, FALSE); linelen = next_offset - offset; proto_tree_add_text(msrp_data_tree, next_tvb, offset, linelen, "%s", tvb_format_text(next_tvb, offset, linelen)); offset = next_offset; }/* end while */ } } /* End line */ ti = proto_tree_add_item(msrp_tree,hf_msrp_end_line,tvb,end_line_offset,end_line_len,FALSE); msrp_end_tree = proto_item_add_subtree(ti, ett_msrp_end_line); proto_tree_add_item(msrp_end_tree,hf_msrp_transactionID,tvb,end_line_offset + 7,token_2_len,FALSE); /* continuation-flag */ proto_tree_add_item(msrp_end_tree,hf_msrp_cnt_flg,tvb,end_line_offset+end_line_len-1,1,FALSE); if (global_msrp_raw_text){ ti = proto_tree_add_text(tree, tvb, 0, -1,"Message Session Relay Protocol(as raw text)"); raw_tree = proto_item_add_subtree(ti, ett_msrp); tvb_raw_text_add(tvb,raw_tree); } }/* if tree */ return message_end_offset; /* return tvb_length(tvb); */ /* If this protocol has a sub-dissector call it here, see section 1.8 */ }
static int ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo, struct ssh_flow_data *global_data, int offset, proto_tree *tree, int is_response, guint * version, gboolean *need_desegmentation) { guint remain_length; gint linelen, protolen; /* * If the first packet do not contain the banner, * it is dump in the middle of a flow or not a ssh at all */ if (tvb_strncaseeql(tvb, offset, "SSH-", 4) != 0) { offset = ssh_dissect_encrypted_packet(tvb, pinfo, &global_data->peer_data[is_response], offset, tree); return offset; } if (!is_response) { if (tvb_strncaseeql(tvb, offset, "SSH-2.", 6) == 0) { *(version) = SSH_VERSION_2; } else if (tvb_strncaseeql(tvb, offset, "SSH-1.99-", 9) == 0) { *(version) = SSH_VERSION_2; } else if (tvb_strncaseeql(tvb, offset, "SSH-1.", 6) == 0) { *(version) = SSH_VERSION_1; } } /* * We use "tvb_ensure_length_remaining()" to make sure there * actually *is* data remaining. * * This means we're guaranteed that "remain_length" is positive. */ remain_length = tvb_ensure_length_remaining(tvb, offset); /*linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); */ linelen = tvb_find_guint8(tvb, offset, -1, '\n'); if (ssh_desegment && pinfo->can_desegment) { if (linelen == -1 || remain_length < (guint)linelen-offset) { pinfo->desegment_offset = offset; pinfo->desegment_len = linelen-remain_length; *need_desegmentation = TRUE; return offset; } } if (linelen == -1) { /* XXX - reassemble across segment boundaries? */ linelen = remain_length; protolen = linelen; } else { linelen = linelen - offset + 1; if (linelen > 1 && tvb_get_guint8(tvb, offset + linelen - 2) == '\r') protolen = linelen - 2; else protolen = linelen - 1; } col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Protocol (%s)", tvb_format_text(tvb, offset, protolen)); proto_tree_add_item(tree, hf_ssh_protocol, tvb, offset, linelen, ENC_ASCII|ENC_NA); offset+=linelen; return offset; }
static void dissect_exec(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *exec_tree=NULL; /* Variables for extracting and displaying data from the packet */ guchar *field_stringz; /* Temporary storage for each field we extract */ gint length; guint offset = 0; conversation_t *conversation; exec_hash_entry_t *hash_info; conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if(!conversation){ /* Conversation does not exist yet - create it */ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); } /* Retrieve information from conversation * or add it if it isn't there yet */ hash_info = conversation_get_proto_data(conversation, proto_exec); if(!hash_info){ hash_info = se_alloc(sizeof(exec_hash_entry_t)); hash_info->first_packet_number = pinfo->fd->num; hash_info->second_packet_number = 0; hash_info->third_packet_number = 0; hash_info->fourth_packet_number = 0; hash_info->state = WAIT_FOR_STDERR_PORT; /* The first field we'll see */ /* Start with empty username and command strings */ hash_info->username=NULL; hash_info->command=NULL; /* These will be set on the first pass by the first * four packets of the conversation */ hash_info->first_packet_state = NONE; hash_info->second_packet_state = NONE; hash_info->third_packet_state = NONE; hash_info->fourth_packet_state = NONE; conversation_add_proto_data(conversation, proto_exec, hash_info); } /* Store the number of the first three packets of this conversation * as we reach them the first time */ if(!hash_info->second_packet_number && pinfo->fd->num > hash_info->first_packet_number){ /* We're on the second packet of the conversation */ hash_info->second_packet_number = pinfo->fd->num; } else if(hash_info->second_packet_number && !hash_info->third_packet_number && pinfo->fd->num > hash_info->second_packet_number) { /* We're on the third packet of the conversation */ hash_info->third_packet_number = pinfo->fd->num; } else if(hash_info->third_packet_number && !hash_info->fourth_packet_number && pinfo->fd->num > hash_info->third_packet_number) { /* We're on the fourth packet of the conversation */ hash_info->fourth_packet_number = pinfo->fd->num; } /* Save this packet's state so we can retrieve it if this packet * is selected again later. If the packet's state was already stored, * then retrieve it */ if(pinfo->fd->num == hash_info->first_packet_number){ if(hash_info->first_packet_state == NONE){ hash_info->first_packet_state = hash_info->state; } else { hash_info->state = hash_info->first_packet_state; } } if(pinfo->fd->num == hash_info->second_packet_number){ if(hash_info->second_packet_state == NONE){ hash_info->second_packet_state = hash_info->state; } else { hash_info->state = hash_info->second_packet_state; } } if(pinfo->fd->num == hash_info->third_packet_number){ if(hash_info->third_packet_state == NONE){ hash_info->third_packet_state = hash_info->state; } else { hash_info->state = hash_info->third_packet_state; } } if(pinfo->fd->num == hash_info->fourth_packet_number){ if(hash_info->fourth_packet_state == NONE){ hash_info->fourth_packet_state = hash_info->state; } else { hash_info->state = hash_info->fourth_packet_state; } } col_set_str(pinfo->cinfo, COL_PROTOCOL, "EXEC"); if(check_col(pinfo->cinfo, COL_INFO)){ /* First, clear the info column */ col_clear(pinfo->cinfo, COL_INFO); /*username */ if(hash_info->username && preference_info_show_username == TRUE){ col_append_fstr(pinfo->cinfo, COL_INFO, "Username:%s ", hash_info->username); } /* Command */ if(hash_info->command && preference_info_show_command == TRUE){ col_append_fstr(pinfo->cinfo, COL_INFO, "Command:%s ", hash_info->command); } } /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_exec, tvb, 0, -1, FALSE); exec_tree = proto_item_add_subtree(ti, ett_exec); /* If this packet doesn't end with a null terminated string, * then it must be session data only and we can skip looking * for the other fields. */ if(tvb_find_guint8(tvb, tvb_length(tvb)-1, 1, '\0') == -1){ hash_info->state = WAIT_FOR_DATA; } if(hash_info->state == WAIT_FOR_STDERR_PORT && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the stderr_port field. * It is optional, so it may only be 1 character long * (the NULL) */ if(length == 1 || (exec_isdigit_string(field_stringz) && length <= EXEC_STDERR_PORT_LEN)){ proto_tree_add_string(exec_tree, hf_exec_stderr_port, tvb, offset, length, (gchar*)field_stringz); /* Next field we need */ hash_info->state = WAIT_FOR_USERNAME; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; } if(hash_info->state == WAIT_FOR_USERNAME && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the username field */ if(length != 1 && length <= EXEC_USERNAME_LEN && exec_isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_username, tvb, offset, length, (gchar*)field_stringz); /* Store the username so we can display it in the * info column of the entire conversation */ if(!hash_info->username){ hash_info->username=se_strdup((gchar*)field_stringz); } /* Next field we need */ hash_info->state = WAIT_FOR_PASSWORD; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; } if(hash_info->state == WAIT_FOR_PASSWORD && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the password field */ if(length != 1 && length <= EXEC_PASSWORD_LEN && exec_isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_password, tvb, offset, length, (gchar*)field_stringz); /* Next field we need */ hash_info->state = WAIT_FOR_COMMAND; } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } /* Used if the next field is in the same packet */ offset += length; /* Next field we are looking for */ hash_info->state = WAIT_FOR_COMMAND; } if(hash_info->state == WAIT_FOR_COMMAND && tvb_length_remaining(tvb, offset)){ field_stringz = tvb_get_ephemeral_stringz(tvb, offset, &length); /* Check if this looks like the command field */ if(length != 1 && length <= EXEC_COMMAND_LEN && exec_isprint_string(field_stringz)){ proto_tree_add_string(exec_tree, hf_exec_command, tvb, offset, length, (gchar*)field_stringz); /* Store the username so we can display it in the * info column of the entire conversation */ if(!hash_info->command){ hash_info->command=se_strdup((gchar*)field_stringz); } } else { /* Since the data doesn't match this field, it must be data only */ hash_info->state = WAIT_FOR_DATA; } } if(hash_info->state == WAIT_FOR_DATA && tvb_length_remaining(tvb, offset)){ if(pinfo->destport == EXEC_PORT){ /* Packet going to the server */ /* offset = 0 since the whole packet is data */ proto_tree_add_text(exec_tree, tvb, 0, -1, "Client -> Server Data"); if(check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Client -> Server data"); } else { /* This packet must be going back to the client */ /* offset = 0 since the whole packet is data */ proto_tree_add_text(exec_tree, tvb, 0, -1, "Server -> Client Data"); if(check_col(pinfo->cinfo, COL_INFO)) col_append_str(pinfo->cinfo, COL_INFO, "Server -> Client Data"); } } /* We haven't seen all of the fields yet */ if(hash_info->state < WAIT_FOR_DATA){ col_set_str(pinfo->cinfo, COL_INFO, "Session Establishment"); } }
/**************************************************************** * Main dissection function ****************************************************************/ static int dissect_rlogin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { struct tcpinfo *tcpinfo = (struct tcpinfo *)data; conversation_t *conversation; rlogin_hash_entry_t *hash_info; guint length; gint ti_offset; /* Get or create conversation */ conversation = find_or_create_conversation(pinfo); /* Get or create data associated with this conversation */ hash_info = (rlogin_hash_entry_t *)conversation_get_proto_data(conversation, proto_rlogin); if (!hash_info) { /* Populate new data struct... */ hash_info = wmem_new(wmem_file_scope(), rlogin_hash_entry_t); hash_info->state = NONE; hash_info->info_framenum = 0; /* no frame has the number 0 */ hash_info->user_name[0] = '\0'; /* ... and store in conversation */ conversation_add_proto_data(conversation, proto_rlogin, hash_info); } /* Set protocol column text */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "Rlogin"); /* Set info column */ /* Show user-name if available */ if (hash_info->user_name[0]) { col_add_fstr(pinfo->cinfo, COL_INFO, "User name: %s, ", hash_info->user_name); } else { col_clear(pinfo->cinfo, COL_INFO); } /* Work out packet content summary for display */ length = tvb_reported_length(tvb); if (length != 0) { /* Initial NULL byte represents part of connection handshake */ if (tvb_get_guint8(tvb, 0) == '\0') { col_append_str(pinfo->cinfo, COL_INFO, (pinfo->destport == RLOGIN_PORT) ? "Start Handshake" : "Startup info received"); } else if (tcpinfo && IS_TH_URG(tcpinfo->flags) && length >= tcpinfo->urgent_pointer) { /* Urgent pointer inside current data represents a control message */ col_append_str(pinfo->cinfo, COL_INFO, "Control Message"); } else { /* Search for 2 consecutive ff bytes (signifies window change control message) */ ti_offset = tvb_find_guint8(tvb, 0, -1, 0xff); if (ti_offset != -1 && tvb_bytes_exist(tvb, ti_offset + 1, 1) && tvb_get_guint8(tvb, ti_offset + 1) == 0xff) { col_append_str(pinfo->cinfo, COL_INFO, "Terminal Info"); } else { /* Show any text data in the frame */ int bytes_to_copy = tvb_captured_length(tvb); if (bytes_to_copy > 128) { /* Truncate to 128 bytes for display */ bytes_to_copy = 128; } /* Add data into info column */ col_append_fstr(pinfo->cinfo, COL_INFO, "Data: %s", tvb_format_text(tvb, 0, bytes_to_copy)); } } } /* See if conversation state needs to be updated */ rlogin_state_machine(hash_info, tvb, pinfo); /* Dissect in detail */ rlogin_display(hash_info, tvb, pinfo, tree, tcpinfo); return tvb_captured_length(tvb); }
/* 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); } }
static int dissect_rtspmessage(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) { proto_tree *rtsp_tree = NULL; proto_tree *sub_tree = NULL; proto_item *ti = NULL; const guchar *line; gint next_offset; const guchar *linep, *lineend; int orig_offset; int first_linelen, linelen; int line_end_offset; int colon_offset; gboolean is_request_or_reply; gboolean body_requires_content_len; gboolean saw_req_resp_or_header; guchar c; rtsp_type_t rtsp_type; gboolean is_header; int datalen; int content_length; int reported_datalen; int value_offset; int value_len; e164_info_t e164_info; gint rdt_feature_level = 0; gchar *media_type_str_lower_case = NULL; int semi_colon_offset; int par_end_offset; /* * Is this a request or response? * * 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. */ first_linelen = tvb_find_line_end(tvb, offset, tvb_ensure_length_remaining(tvb, offset), &next_offset, FALSE); /* * Is the first line a request or response? */ line = tvb_get_ptr(tvb, offset, first_linelen); is_request_or_reply = is_rtsp_request_or_reply(line, first_linelen, &rtsp_type); if (is_request_or_reply) { /* * Yes, it's a request or response. * Do header desegmentation if we've been told to, * and do body desegmentation if we've been told to and * we find a Content-Length header. */ if (!req_resp_hdrs_do_reassembly(tvb, offset, pinfo, rtsp_desegment_headers, rtsp_desegment_body)) { /* * More data needed for desegmentation. */ return -1; } } /* * RFC 2326 says that a content length must be specified * in requests that have a body, although section 4.4 speaks * of a server closing the connection indicating the end of * a reply body. * * We assume that an absent content length in a request means * that we don't have a body, and that an absent content length * in a reply means that the reply body runs to the end of * the connection. If the first line is neither, we assume * that whatever follows a blank line should be treated as a * body; there's not much else we can do, as we're jumping * into the message in the middle. * * XXX - if there was no Content-Length entity header, we should * accumulate all data until the end of the connection. * That'd require that the TCP dissector call subdissectors * for all frames with FIN, even if they contain no data, * which would require subdissectors to deal intelligently * with empty segments. */ if (rtsp_type == RTSP_REQUEST) body_requires_content_len = TRUE; else body_requires_content_len = FALSE; col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTSP"); if (check_col(pinfo->cinfo, COL_INFO)) { /* * Put the first line from the buffer into the summary * if it's an RTSP request or reply (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. */ line = tvb_get_ptr(tvb, offset, first_linelen); if (is_request_or_reply) if ( rtsp_type == RTSP_REPLY ) { col_set_str(pinfo->cinfo, COL_INFO, "Reply: "); col_append_str(pinfo->cinfo, COL_INFO, format_text(line, first_linelen)); } else col_add_str(pinfo->cinfo, COL_INFO, format_text(line, first_linelen)); else col_set_str(pinfo->cinfo, COL_INFO, "Continuation"); } orig_offset = offset; if (tree) { ti = proto_tree_add_item(tree, proto_rtsp, tvb, offset, -1, FALSE); rtsp_tree = proto_item_add_subtree(ti, ett_rtsp); } /* * We haven't yet seen a Content-Length header. */ content_length = -1; /* * Process the packet data, a line at a time. */ saw_req_resp_or_header = FALSE; /* haven't seen anything yet */ while (tvb_reported_length_remaining(tvb, offset) != 0) { /* * We haven't yet concluded that this is a header. */ is_header = FALSE; /* * Find the end of the line. */ linelen = tvb_find_line_end(tvb, offset, tvb_ensure_length_remaining(tvb, offset), &next_offset, FALSE); if (linelen < 0) return -1; line_end_offset = offset + linelen; /* * colon_offset may be -1 */ colon_offset = tvb_find_guint8(tvb, offset, linelen, ':'); /* * Get a buffer that refers to the line. */ line = tvb_get_ptr(tvb, offset, linelen); lineend = line + linelen; /* * OK, does it look like an RTSP request or response? */ is_request_or_reply = is_rtsp_request_or_reply(line, linelen, &rtsp_type); if (is_request_or_reply) goto is_rtsp; /* * No. Does it look like a blank line (as would appear * at the end of an RTSP request)? */ if (linelen == 0) goto is_rtsp; /* Yes. */ /* * No. Does it look like a header? */ linep = line; while (linep < lineend) { c = *linep++; /* * This must be a CHAR to be part of a token; that * means it must be ASCII. */ if (!isascii(c)) 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)) 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 tspecial, so it's not * part of a token, so it's not * a field name for the beginning * of a header. */ goto not_rtsp; case ':': /* * This ends the token; we consider * this to be a header. */ is_header = TRUE; goto is_rtsp; case ' ': case '\t': /* * LWS (RFC-2616, 4.2); continue the previous * header. */ goto is_rtsp; } } /* * We haven't seen the colon, but everything else looks * OK for a header line. * * If we've already seen an RTSP request or response * line, or a header line, and we're at the end of * the tvbuff, we assume this is an incomplete header * line. (We quit this loop after seeing a blank line, * so if we've seen a request or response line, or a * header line, this is probably more of the request * or response we're presumably seeing. There is some * risk of false positives, but the same applies for * full request or response lines or header lines, * although that's less likely.) * * We throw an exception in that case, by checking for * the existence of the next byte after the last one * in the line. If it exists, "tvb_ensure_bytes_exist()" * throws no exception, and we fall through to the * "not RTSP" case. If it doesn't exist, * "tvb_ensure_bytes_exist()" will throw the appropriate * exception. */ if (saw_req_resp_or_header) tvb_ensure_bytes_exist(tvb, offset, linelen + 1); not_rtsp: /* * We don't consider this part of an RTSP request or * reply, so we don't display it. */ break; is_rtsp: /* * Process this line. */ if (linelen == 0) { /* * This is a blank line, which means that * whatever follows it isn't part of this * request or reply. */ proto_tree_add_text(rtsp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); offset = next_offset; break; } /* * Not a blank line - either a request, a reply, or a header * line. */ saw_req_resp_or_header = TRUE; if (rtsp_tree) { switch (rtsp_type) { case RTSP_REQUEST: process_rtsp_request(tvb, offset, line, linelen, next_offset, rtsp_tree); break; case RTSP_REPLY: process_rtsp_reply(tvb, offset, line, linelen, next_offset, rtsp_tree); break; case RTSP_NOT_FIRST_LINE: /* Drop through, it may well be a header line */ break; } } if (is_header) { /* We know that colon_offset must be set */ /* Skip whitespace after the colon. */ value_offset = colon_offset + 1; while ((value_offset < line_end_offset) && ((c = tvb_get_guint8(tvb, value_offset)) == ' ' || c == '\t')) { value_offset++; } value_len = line_end_offset - value_offset; /* * Process some headers specially. */ #define HDR_MATCHES(header) \ ( (size_t)linelen > STRLEN_CONST(header) && \ g_ascii_strncasecmp(line, (header), STRLEN_CONST(header)) == 0) if (HDR_MATCHES(rtsp_transport)) { proto_tree_add_string(rtsp_tree, hf_rtsp_transport, tvb, offset, linelen, tvb_format_text(tvb, value_offset, value_len)); /* * Based on the port numbers specified * in the Transport: header, set up * a conversation that will be dissected * with the appropriate dissector. */ rtsp_create_conversation(pinfo, line, linelen, rdt_feature_level); } else if (HDR_MATCHES(rtsp_content_type)) { proto_tree_add_string(rtsp_tree, hf_rtsp_content_type, tvb, offset, linelen, tvb_format_text(tvb, value_offset, value_len)); offset = offset + STRLEN_CONST(rtsp_content_type); /* Skip wsp */ offset = tvb_skip_wsp(tvb, offset, value_len); semi_colon_offset = tvb_find_guint8(tvb, value_offset, value_len, ';'); if ( semi_colon_offset != -1) { /* m-parameter present */ par_end_offset = tvb_skip_wsp_return(tvb, semi_colon_offset-1); value_len = par_end_offset - offset; } media_type_str_lower_case = ascii_strdown_inplace( (gchar *)tvb_get_ephemeral_string(tvb, offset, value_len)); } else if (HDR_MATCHES(rtsp_content_length)) { proto_tree_add_uint(rtsp_tree, hf_rtsp_content_length, tvb, offset, linelen, atoi(tvb_format_text(tvb, value_offset, value_len))); /* * Only the amount specified by the * Content-Length: header should be treated * as payload. */ content_length = rtsp_get_content_length(line, linelen); } else if (HDR_MATCHES(rtsp_Session)) { /* Put the value into the protocol tree */ proto_tree_add_string(rtsp_tree, hf_rtsp_session, tvb, offset, linelen, tvb_format_text(tvb, value_offset, value_len)); } else if (HDR_MATCHES(rtsp_X_Vig_Msisdn)) { /* * Extract the X_Vig_Msisdn string */ if (colon_offset != -1) { /* Put the value into the protocol tree */ ti = proto_tree_add_string(rtsp_tree, hf_rtsp_X_Vig_Msisdn,tvb, offset, linelen , tvb_format_text(tvb, value_offset, value_len)); sub_tree = proto_item_add_subtree(ti, ett_rtsp_method); e164_info.e164_number_type = CALLING_PARTY_NUMBER; e164_info.nature_of_address = 0; e164_info.E164_number_str = tvb_get_ephemeral_string(tvb, value_offset, value_len); e164_info.E164_number_length = value_len; dissect_e164_number(tvb, sub_tree, value_offset, value_len, e164_info); } } else if (HDR_MATCHES(rtsp_rdt_feature_level)) { rdt_feature_level = atoi(tvb_format_text(tvb, value_offset, value_len)); proto_tree_add_uint(rtsp_tree, hf_rtsp_rdtfeaturelevel, tvb, offset, linelen, atoi(tvb_format_text(tvb, value_offset, value_len))); } else { /* Default case for headers. Show line as text */ proto_tree_add_text(rtsp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); } } else if (rtsp_type == RTSP_NOT_FIRST_LINE) { /* Catch-all for all other lines... Show line as text. TODO: should these be shown as errors? */ proto_tree_add_text(rtsp_tree, tvb, offset, next_offset - offset, "%s", tvb_format_text(tvb, offset, next_offset - offset)); } offset = next_offset; } /* * Have now read all of the lines of this message. * * If a content length was supplied, the amount of data to be * processed as RTSP payload is the minimum of the content * length and the amount of data remaining in the frame. * * If no content length was supplied (or if a bad content length * was supplied), the amount of data to be processed is the amount * of data remaining in the frame. */ datalen = tvb_length_remaining(tvb, offset); reported_datalen = tvb_reported_length_remaining(tvb, offset); if (content_length != -1) { /* * Content length specified; display only that amount * as payload. */ if (datalen > content_length) datalen = content_length; /* * XXX - limit the reported length in the tvbuff we'll * hand to a subdissector to be no greater than the * content length. * * We really need both unreassembled and "how long it'd * be if it were reassembled" lengths for tvbuffs, so * that we throw the appropriate exceptions for * "not enough data captured" (running past the length), * "packet needed reassembly" (within the length but * running past the unreassembled length), and * "packet is malformed" (running past the reassembled * length). */ if (reported_datalen > content_length) reported_datalen = content_length; } else { /* * No content length specified; if this message doesn't * have a body if no content length is specified, process * nothing as payload. */ if (body_requires_content_len) datalen = 0; } if (datalen > 0) { /* * There's stuff left over; process it. */ tvbuff_t *new_tvb; /* * Now create a tvbuff for the Content-type stuff and * dissect it. * * The amount of data to be processed that's * available in the tvbuff is "datalen", which * is the minimum of the amount of data left in * the tvbuff and any specified content length. * * The amount of data to be processed that's in * this frame, regardless of whether it was * captured or not, is "reported_datalen", * which, if no content length was specified, * is -1, i.e. "to the end of the frame. */ new_tvb = tvb_new_subset(tvb, offset, datalen, reported_datalen); if (media_type_str_lower_case && dissector_try_string(media_type_dissector_table, media_type_str_lower_case, new_tvb, pinfo, rtsp_tree)){ }else { /* * Fix up the top-level item so that it doesn't * include the SDP stuff. */ if (ti != NULL) proto_item_set_len(ti, offset); if (tvb_get_guint8(tvb, offset) == RTSP_FRAMEHDR) { /* * This is interleaved stuff; don't * treat it as raw data - set "datalen" * to 0, so we won't skip the offset * past it, which will cause our * caller to process that stuff itself. */ datalen = 0; } else { proto_tree_add_text(rtsp_tree, tvb, offset, datalen, "Data (%d bytes)", reported_datalen); } } /* * We've processed "datalen" bytes worth of data * (which may be no data at all); advance the * offset past whatever data we've processed. */ offset += datalen; } return offset - orig_offset; }
/* ---------------------------------------------- */ static void dissect_fix_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *fix_tree; int pdu_len; int offset = 0; int field_offset, ctrla_offset; int tag_value; char *value; char *tag_str; fix_parameter *tag; /* Make entries in Protocol column and Info column on summary display */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "FIX"); col_clear(pinfo->cinfo, COL_INFO); /* get at least the fix version: 8=FIX.x.x */ if (fix_marker(tvb, 0) != 0) { /* not a fix packet start but it's a fix packet */ col_set_str(pinfo->cinfo, COL_INFO, "[FIX continuation]"); ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA); fix_tree = proto_item_add_subtree(ti, ett_fix); proto_tree_add_item(fix_tree, hf_fix_data, tvb, 0, -1, ENC_NA); return; } pdu_len = tvb_reported_length(tvb); ti = proto_tree_add_item(tree, proto_fix, tvb, 0, -1, ENC_NA); fix_tree = proto_item_add_subtree(ti, ett_fix); /* begin string */ ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01); if (ctrla_offset == -1) { return; } offset = ctrla_offset + 1; /* msg length */ ctrla_offset = tvb_find_guint8(tvb, offset, -1, 0x01); if (ctrla_offset == -1) { return; } offset = ctrla_offset + 1; /* msg type */ if (!(tag = fix_param(tvb, offset)) || tag->value_len < 1) { return; } if (check_col(pinfo->cinfo, COL_INFO)) { const char *msg_type; value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len); msg_type = str_to_str(value, messages_val, "FIX Message (%s)"); col_add_str(pinfo->cinfo, COL_INFO, msg_type); } /* In the interest of speed, if "tree" is NULL, don't do any work not * necessary to generate protocol tree items. */ field_offset = 0; while(field_offset < pdu_len && (tag = fix_param(tvb, field_offset)) ) { int i, found; if (tag->tag_len < 1) { field_offset = tag->ctrla_offset + 1; continue; } tag_str = tvb_get_ephemeral_string(tvb, field_offset, tag->tag_len); tag_value = atoi(tag_str); if (tag->value_len < 1) { proto_tree *field_tree; /* XXX - put an error indication here. It's too late to return FALSE; we've already started dissecting, and if a heuristic dissector starts dissecting (either updating the columns or creating a protocol tree) and then gives up, it leaves crud behind that messes up other dissectors that might process the packet. */ ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: <missing value>", tag_value); field_tree = proto_item_add_subtree(ti, ett_badfield); proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value); field_offset = tag->ctrla_offset + 1; continue; } /* fix_fields array is sorted by tag_value */ found = 0; if ((i = tag_search(tag_value)) >= 0) { found = 1; } value = tvb_get_ephemeral_string(tvb, tag->value_offset, tag->value_len); if (found) { if (fix_fields[i].table) { if (tree) { switch (fix_fields[i].type) { case 1: /* strings */ proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value, "%s (%s)", value, str_to_str(value, fix_fields[i].table, "unknown %s")); break; case 2: /* char */ proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value, "%s (%s)", value, val_to_str(*value, fix_fields[i].table, "unknown %d")); break; default: proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value, "%s (%s)", value, val_to_str(atoi(value), fix_fields[i].table, "unknown %d")); break; } } } else { proto_item *item; /* checksum */ switch(tag_value) { case 10: { proto_tree *checksum_tree; guint8 sum = 0; const guint8 *data = tvb_get_ptr(tvb, 0, field_offset); gboolean sum_ok; int j; for (j = 0; j < field_offset; j++, data++) { sum += *data; } sum_ok = (atoi(value) == sum); if (sum_ok) { item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value, "%s [correct]", value); } else { item = proto_tree_add_string_format_value(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value, "%s [incorrect should be %d]", value, sum); } checksum_tree = proto_item_add_subtree(item, ett_checksum); item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_good, tvb, field_offset, tag->field_len, sum_ok); PROTO_ITEM_SET_GENERATED(item); item = proto_tree_add_boolean(checksum_tree, hf_fix_checksum_bad, tvb, field_offset, tag->field_len, !sum_ok); PROTO_ITEM_SET_GENERATED(item); if (!sum_ok) expert_add_info_format(pinfo, item, PI_CHECKSUM, PI_ERROR, "Bad checksum"); } break; default: proto_tree_add_string(fix_tree, fix_fields[i].hf_id, tvb, field_offset, tag->field_len, value); break; } } } else if (tree) { proto_tree *field_tree; /* XXX - it could be -1 if the tag isn't a number */ ti = proto_tree_add_text(fix_tree, tvb, field_offset, tag->field_len, "%i: %s", tag_value, value); field_tree = proto_item_add_subtree(ti, ett_unknow); proto_tree_add_uint(field_tree, hf_fix_field_tag, tvb, field_offset, tag->tag_len, tag_value); proto_tree_add_item(field_tree, hf_fix_field_value, tvb, tag->value_offset, tag->value_len, ENC_ASCII|ENC_NA); } field_offset = tag->ctrla_offset + 1; tag_str = NULL; } return; }
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, *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_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_find_guint8(tvb, offset+1, linelen-1, ' '); if (eop_offset == -1) { expert_add_info(pinfo, response_item, &ei_irc_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); 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, response_item, &ei_irc_response_command); return; } eoc_offset = tvb_find_guint8(tvb, offset, end_offset-offset, ' '); 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_string_enc(wmem_packet_scope(), tvb, offset, end_offset-offset, ENC_ASCII|ENC_NA)); /* if response command is numeric, allow it to be filtered as an integer */ if ((end_offset-offset == 3) && (g_ascii_isdigit(tvb_get_guint8(tvb, offset))) && (g_ascii_isdigit(tvb_get_guint8(tvb, offset+1))) && (g_ascii_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_string_enc(wmem_packet_scope(), tvb, offset, eoc_offset-offset, ENC_ASCII|ENC_NA); 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) && (g_ascii_isdigit(tvb_get_guint8(tvb, offset))) && (g_ascii_isdigit(tvb_get_guint8(tvb, offset+1))) && (g_ascii_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); } 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_find_guint8(tvb, offset, end_offset-offset, ' '); tag_start_offset = tvb_ws_mempbrk_pattern_guint8(tvb, offset, end_offset-offset, &pbrk_tag_delimiter, &found_tag_needle); /* Create subtree when the first parameter is found */ if (first_command_param) { command_tree = proto_tree_add_subtree(response_tree, tvb, offset, end_offset-offset, ett_irc_response_command , NULL, "Command parameters"); first_command_param = FALSE; } if ((tag_start_offset == -1) || (eocp_offset < tag_start_offset)) { /* regular message should be dissected */ 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_ws_mempbrk_pattern_guint8(tvb, tag_start_offset+1, end_offset-tag_start_offset-1, &pbrk_tag_delimiter, &found_tag_needle); if (tag_end_offset == -1) { expert_add_info(pinfo, response_item, &ei_irc_missing_end_delimiter); 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; } } }