static gboolean val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { fvalue_t *fv_bytes; tvbuff_t *new_tvb; guint8 *private_data; /* Free up the old value, if we have one */ value_free(fv); /* Does this look like a byte string? */ fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL); if (fv_bytes) { /* Make a tvbuff from the bytes */ private_data = (guint8 *)g_memdup(fv_bytes->value.bytes->data, fv_bytes->value.bytes->len); new_tvb = tvb_new_real_data(private_data, fv_bytes->value.bytes->len, fv_bytes->value.bytes->len); /* Let the tvbuff know how to delete the data. */ tvb_set_free_cb(new_tvb, free_tvb_data); /* And let us know that we need to free the tvbuff */ fv->tvb_is_private = TRUE; fv->value.tvb = new_tvb; return TRUE; } /* Treat it as a string. */ return val_from_string(fv, s, logfunc); }
/* * ByteArray_tvb(name) */ WSLUA_CONSTRUCTOR ByteArray_tvb (lua_State *L) { /* Creates a new Tvb from a bytearray (it gets added to the current frame too) */ #define WSLUA_ARG_ByteArray_tvb_NAME 2 /* The name to be given to the new data-source. */ ByteArray ba = checkByteArray(L,1); const gchar* name = luaL_optstring(L,WSLUA_ARG_ByteArray_tvb_NAME,"Unnamed") ; guint8* data; Tvb tvb; if (!ba) return 0; if (!lua_tvb) { luaL_error(L,"Tvbs can only be created and used in dissectors"); return 0; } data = (guint8 *)g_memdup(ba->data, ba->len); tvb = (Tvb)g_malloc(sizeof(struct _wslua_tvb)); tvb->ws_tvb = tvb_new_real_data(data, ba->len,ba->len); tvb->expired = FALSE; tvb->need_free = TRUE; tvb_set_free_cb(tvb->ws_tvb, g_free); add_new_data_source(lua_pinfo, tvb->ws_tvb, name); PUSH_TVB(L,tvb); WSLUA_RETURN(1); /* The created Tvb. */ }
int main(int argc, char **argv) { frame_data fd; char src[] = {1,2,3,4}, dst[] = {5,6,7,8}; unsigned int i; void (*tests[])(void) = { test_simple_fragment_add_seq, test_fragment_add_seq_partial_reassembly, test_fragment_add_dcerpc_dg, test_fragment_add_seq_check, test_fragment_add_seq_check_1, test_fragment_add_seq_802_11_0, test_fragment_add_seq_802_11_1, test_simple_fragment_add_seq_next, test_missing_data_fragment_add_seq_next, test_missing_data_fragment_add_seq_next_2, test_missing_data_fragment_add_seq_next_3 }; /* we don't use our params */ argc=argc; argv=argv; /* initialise stuff */ ep_init_chunk(); tvbuff_init(); reassemble_init(); /* a tvbuff for testing with */ data = g_malloc(DATA_LEN); /* make sure it's full of stuff */ for(i=0; i<DATA_LEN; i++) { data[i]=i & 0xFF; } tvb = tvb_new_real_data(data, DATA_LEN, DATA_LEN*2); /* other test stuff */ pinfo.fd = &fd; fd.flags.visited = 0; SET_ADDRESS(&pinfo.src,AT_IPv4,4,src); SET_ADDRESS(&pinfo.dst,AT_IPv4,4,dst); /*************************************************************************/ for(i=0; i < sizeof(tests)/sizeof(tests[0]); i++ ) { /* re-init the fragment tables */ fragment_table_init(&fragment_table); ASSERT(fragment_table != NULL); reassembled_table_init(&reassembled_table); ASSERT(reassembled_table != NULL); pinfo.fd->flags.visited = FALSE; tests[i](); } printf(failure?"FAILURE\n":"SUCCESS\n"); return failure; }
static int dissect_bmc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint8 message_type; guint8 *p_rev, *reversing_buffer; gint offset = 0; gint i, len; proto_item *ti; proto_tree *bmc_tree; tvbuff_t *bit_reversed_tvb; col_set_str(pinfo->cinfo, COL_PROTOCOL, "BMC"); col_clear(pinfo->cinfo, COL_INFO); ti = proto_tree_add_item(tree, proto_bmc, tvb, 0, -1, ENC_NA); bmc_tree = proto_item_add_subtree(ti, ett_bmc); /* Needs bit-reversing. Create a new buffer, copy the message to it and bit-reverse */ len = tvb_length(tvb); reversing_buffer = se_alloc(len); memcpy(reversing_buffer, tvb_get_ptr(tvb, offset, -1), len); p_rev = reversing_buffer; /* Entire message is bit reversed */ for (i=0; i<len; i++, p_rev++) *p_rev = BIT_SWAP(*p_rev); /* Make this new buffer part of the display and provide a way to dispose of it */ bit_reversed_tvb = tvb_new_real_data(reversing_buffer, len, len); tvb_set_child_real_data_tvbuff(tvb, bit_reversed_tvb); add_new_data_source(pinfo, bit_reversed_tvb, "Bit-reversed Data"); message_type = tvb_get_guint8(bit_reversed_tvb, offset); proto_tree_add_item(bmc_tree, hf_bmc_message_type, bit_reversed_tvb, offset, 1, ENC_BIG_ENDIAN); offset++; col_add_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(message_type, message_type_vals,"Reserved 0x%02x")); switch (message_type) { case MESSAGE_TYPE_CBS_MESSAGE: offset = dissect_bmc_cbs_message(bit_reversed_tvb, pinfo, bmc_tree); break; case MESSAGE_TYPE_SCHEDULE_MESSAGE: offset = dissect_bmc_schedule_message(bit_reversed_tvb, pinfo, bmc_tree); break; case MESSAGE_TYPE_CBS41_MESSAGE: offset = dissect_bmc_cbs41_message(bit_reversed_tvb, pinfo, bmc_tree); break; default: break; } return offset; }
tvbuff_t * tvb_new_proxy(tvbuff_t *backing) { tvbuff_t *tvb; if (backing) tvb = tvb_new_with_subset(backing, backing->reported_length, 0, backing->length); else tvb = tvb_new_real_data(NULL, 0, 0); tvb->ds_tvb = tvb; return tvb; }
static void dissect_gwtb_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { gwtb_info_t *info_ptr = (gwtb_info_t*) p_get_proto_data(pinfo->fd, proto_gwtb, 0); tvbuff_t *next_tvb; proto_item *gwtb_item = NULL; proto_tree *gwtb_tree = NULL; guint32 offset = 0; guint32 length = tvb_length(tvb); guint16 size; if (!info_ptr->data) { info_ptr->auth = FALSE; info_ptr->data = (guchar*) se_alloc(length); tvb_memcpy(tvb, info_ptr->data, offset, length); crypt_rc4(info_ptr->rc4, info_ptr->data, length); } next_tvb = tvb_new_real_data(info_ptr->data, length, length); tvb_set_child_real_data_tvbuff(tvb, next_tvb); add_new_data_source(pinfo, next_tvb, "Data"); length = tvb_length(next_tvb); if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_GWTB); if (check_col(pinfo->cinfo, COL_INFO)) { col_clear(pinfo->cinfo, COL_INFO); col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d - %s", pinfo->srcport, pinfo->destport, (pinfo->match_port == pinfo->destport || TCP_PORT_GWTB == pinfo->destport) ? "Request" : "Response" ); } if (tree) { /* we are being asked for details */ while(offset < length) { gwtb_item = proto_tree_add_item(tree, proto_gwtb, next_tvb, offset, length-offset, FALSE); gwtb_tree = proto_item_add_subtree(gwtb_item, ett_gwtb); size = tvb_get_ntohs(next_tvb, offset); proto_tree_add_item(gwtb_tree, hf_length, next_tvb, offset, FRAME_HEADER_LEN, FALSE); offset += FRAME_HEADER_LEN; proto_tree_add_item(gwtb_tree, hf_string, next_tvb, offset, size, FALSE); offset += size; } } }
static gboolean dissect_xml_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { if (pref_heuristic_media || pref_heuristic_tcp || pref_heuristic_udp) { if (tvbparse_peek(tvbparse_init(tvb,0,-1,NULL,want_ignore), want_heur)) { dissect_xml(tvb, pinfo, tree); return TRUE; } else if (pref_heuristic_unicode) { const guint8 *data = tvb_get_ephemeral_faked_unicode(tvb, 0, tvb_length(tvb)/2, TRUE); tvbuff_t *unicode_tvb = tvb_new_real_data(data, tvb_length(tvb)/2, tvb_length(tvb)/2); if (tvbparse_peek(tvbparse_init(unicode_tvb,0,-1,NULL,want_ignore), want_heur)) { dissect_xml(unicode_tvb, pinfo, tree); return TRUE; } } } return FALSE; }
static tvbuff_t * tvb_unmasked(tvbuff_t *tvb, packet_info *pinfo, const guint offset, guint payload_length, const guint8 *masking_key) { gchar *data_unmask; guint i; const guint8 *data_mask; guint unmasked_length = payload_length > MAX_UNMASKED_LEN ? MAX_UNMASKED_LEN : payload_length; data_unmask = (gchar *)wmem_alloc(pinfo->pool, unmasked_length); data_mask = tvb_get_ptr(tvb, offset, unmasked_length); /* Unmasked(XOR) Data... */ for(i=0; i < unmasked_length; i++) { data_unmask[i] = data_mask[i] ^ masking_key[i%4]; } return tvb_new_real_data(data_unmask, unmasked_length, payload_length); }
tvbuff_t * tvb_unmasked(tvbuff_t *tvb, const int offset, int payload_length, const guint8 *masking_key) { gchar *data_unmask; tvbuff_t *tvb_unmask = NULL; int i; const guint8 *data_mask; int unmasked_length = payload_length > MAX_UNMASKED_LEN ? MAX_UNMASKED_LEN : payload_length; data_unmask = g_malloc(unmasked_length); data_mask = tvb_get_ptr(tvb, offset, unmasked_length); /* Unmasked(XOR) Data... */ for(i=0; i < unmasked_length; i++){ data_unmask[i] = data_mask[i] ^ masking_key[i%4]; } tvb_unmask = tvb_new_real_data(data_unmask, unmasked_length, unmasked_length); tvb_set_free_cb(tvb_unmask, g_free); return tvb_unmask; }
static gboolean val_from_string(fvalue_t *fv, char *s, LogFunc logfunc _U_) { tvbuff_t *new_tvb; guint8 *private_data; /* Free up the old value, if we have one */ value_free(fv); /* Make a tvbuff from the string. We can drop the * terminating NUL. */ private_data = (guint8 *)g_memdup(s, (guint)strlen(s)); new_tvb = tvb_new_real_data(private_data, (guint)strlen(s), (gint)strlen(s)); /* Let the tvbuff know how to delete the data. */ tvb_set_free_cb(new_tvb, free_tvb_data); /* And let us know that we need to free the tvbuff */ fv->tvb_is_private = TRUE; fv->value.tvb = new_tvb; return TRUE; }
static fragment_head * force_reassemble_seq(reassembly_table *table, packet_info *pinfo, guint32 id) { fragment_head *fd_head; fragment_item *fd_i; fragment_item *last_fd; guint32 dfpos, size, packet_lost, burst_lost, seq_num; guint8 *data; fd_head = fragment_get(table, pinfo, id, NULL); /* have we already seen this frame ?*/ if (pinfo->fd->flags.visited) { if (fd_head != NULL && fd_head->flags & FD_DEFRAGMENTED) { return fd_head; } else { return NULL; } } if (fd_head==NULL){ /* we must have it to continue */ return NULL; } /* check for packet lost and count the burst of packet lost */ packet_lost = 0; burst_lost = 0; seq_num = 0; for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { if (seq_num != fd_i->offset) { packet_lost += fd_i->offset - seq_num; if ( (fd_i->offset - seq_num) > burst_lost ) { burst_lost = fd_i->offset - seq_num; } } seq_num = fd_i->offset + 1; } /* we have received an entire packet, defragment it and * free all fragments */ size=0; last_fd=NULL; for(fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { if(!last_fd || last_fd->offset!=fd_i->offset){ size+=fd_i->len; } last_fd=fd_i; } data = (guint8 *) g_malloc(size); fd_head->tvb_data = tvb_new_real_data(data, size, size); fd_head->len = size; /* record size for caller */ /* add all data fragments */ dfpos = 0; last_fd=NULL; for (fd_i=fd_head->next;fd_i && fd_i->len + dfpos <= size;fd_i=fd_i->next) { if (fd_i->len) { if(!last_fd || last_fd->offset!=fd_i->offset){ memcpy(data+dfpos,tvb_get_ptr(fd_i->tvb_data,0,fd_i->len),fd_i->len); dfpos += fd_i->len; } else { /* duplicate/retransmission/overlap */ fd_i->flags |= FD_OVERLAP; fd_head->flags |= FD_OVERLAP; if( (last_fd->len!=fd_i->datalen) || tvb_memeql(last_fd->tvb_data, 0, tvb_get_ptr(fd_i->tvb_data, 0, last_fd->len), last_fd->len) ){ fd_i->flags |= FD_OVERLAPCONFLICT; fd_head->flags |= FD_OVERLAPCONFLICT; } } } last_fd=fd_i; } /* we have defragmented the pdu, now free all fragments*/ for (fd_i=fd_head->next;fd_i;fd_i=fd_i->next) { if(fd_i->tvb_data){ tvb_free(fd_i->tvb_data); fd_i->tvb_data=NULL; } } /* mark this packet as defragmented */ fd_head->flags |= FD_DEFRAGMENTED; fd_head->reassembled_in=pinfo->fd->num; col_append_fstr(pinfo->cinfo, COL_INFO, " (t4-data Reassembled: %d pack lost, %d pack burst lost)", packet_lost, burst_lost); p_t38_packet_conv_info->packet_lost = packet_lost; p_t38_packet_conv_info->burst_lost = burst_lost; return fd_head; }
static int dissect_corosynec_totemnet_with_decryption(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolean check_crypt_type, const gchar* key_for_trial) { unsigned char keys[48]; sober128_prng keygen_prng_state; sober128_prng stream_prng_state; unsigned char *hmac_key = &keys[32]; unsigned char *cipher_key = &keys[16]; unsigned char *initial_vector = &keys[0]; unsigned char digest_comparison[SHA1_DIGEST_LEN]; int io_len; guint8 *io_base; #define PRIVATE_KEY_LEN_MAX 256 gchar private_key[PRIVATE_KEY_LEN_MAX]; gsize private_key_len; unsigned char* hash_digest; unsigned char* salt; io_len = tvb_reported_length(tvb) - (check_crypt_type? 1: 0); if (io_len < SHA1_DIGEST_LEN + SALT_SIZE) { return 0; } io_base = (guint8 *)tvb_memdup(pinfo->pool, tvb, 0, io_len + (check_crypt_type? 1: 0)); if (check_crypt_type && ( io_base[io_len] != TOTEM_CRYPTO_SOBER )) { return 0; } hash_digest = io_base; salt = io_base + SHA1_DIGEST_LEN; memset(private_key, 0, sizeof(private_key)); private_key_len = (strlen(key_for_trial)+4) & 0xFC; if (private_key_len > PRIVATE_KEY_LEN_MAX) private_key_len = PRIVATE_KEY_LEN_MAX; g_strlcpy(private_key, key_for_trial, private_key_len); /* * Generate MAC, CIPHER, IV keys from private key */ memset (keys, 0, sizeof(keys)); sober128_start (&keygen_prng_state); sober128_add_entropy(private_key, (unsigned long)private_key_len, &keygen_prng_state); sober128_add_entropy (salt, SALT_SIZE, &keygen_prng_state); sober128_read (keys, sizeof (keys), &keygen_prng_state); /* * Setup stream cipher */ sober128_start (&stream_prng_state); sober128_add_entropy (cipher_key, 16, &stream_prng_state); sober128_add_entropy (initial_vector, 16, &stream_prng_state); /* * Authenticate contents of message */ sha1_hmac(hmac_key, 16, io_base + SHA1_DIGEST_LEN, io_len - SHA1_DIGEST_LEN, digest_comparison); if (memcmp (digest_comparison, hash_digest, SHA1_DIGEST_LEN) != 0) return 0; /* * Decrypt the contents of the message with the cipher key */ sober128_read (io_base + SHA1_DIGEST_LEN + SALT_SIZE, io_len - (SHA1_DIGEST_LEN + SALT_SIZE), &stream_prng_state); /* * Dissect the decrypted data */ { tvbuff_t *decrypted_tvb; tvbuff_t *next_tvb; decrypted_tvb = tvb_new_real_data(io_base, io_len, io_len); tvb_set_child_real_data_tvbuff(tvb, decrypted_tvb); add_new_data_source(pinfo, decrypted_tvb, "Decrypted Data"); dissect_corosync_totemnet_security_header(decrypted_tvb, pinfo, parent_tree, check_crypt_type, key_for_trial); next_tvb = tvb_new_subset(decrypted_tvb, SHA1_DIGEST_LEN + SALT_SIZE, io_len - (SHA1_DIGEST_LEN + SALT_SIZE), io_len - (SHA1_DIGEST_LEN + SALT_SIZE)); return call_dissector(corosync_totemsrp_handle, next_tvb, pinfo, parent_tree) + SHA1_DIGEST_LEN + SALT_SIZE; } }
tvbuff_t * tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen) { gint err; guint bytes_out = 0; guint8 *compr; guint8 *uncompr = NULL; tvbuff_t *uncompr_tvb = NULL; z_streamp strm; Bytef *strmbuf; guint inits_done = 0; gint wbits = MAX_WBITS; guint8 *next; guint bufsiz; #ifdef TVB_Z_DEBUG guint inflate_passes = 0; guint bytes_in = tvb_captured_length_remaining(tvb, offset); #endif if (tvb == NULL || comprlen <= 0) { return NULL; } compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen); if (compr == NULL) { return NULL; } /* * Assume that the uncompressed data is at least twice as big as * the compressed size. */ bufsiz = tvb_captured_length_remaining(tvb, offset) * 2; bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ); #ifdef TVB_Z_DEBUG ws_debug_printf("bufsiz: %u bytes\n", bufsiz); #endif next = compr; strm = g_new0(z_stream, 1); strm->next_in = next; strm->avail_in = comprlen; strmbuf = (Bytef *)g_malloc0(bufsiz); strm->next_out = strmbuf; strm->avail_out = bufsiz; err = inflateInit2(strm, wbits); inits_done = 1; if (err != Z_OK) { inflateEnd(strm); g_free(strm); wmem_free(NULL, compr); g_free(strmbuf); return NULL; } while (1) { memset(strmbuf, '\0', bufsiz); strm->next_out = strmbuf; strm->avail_out = bufsiz; err = inflate(strm, Z_SYNC_FLUSH); if (err == Z_OK || err == Z_STREAM_END) { guint bytes_pass = bufsiz - strm->avail_out; #ifdef TVB_Z_DEBUG ++inflate_passes; #endif if (uncompr == NULL) { /* * This is ugly workaround for bug #6480 * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480) * * g_memdup(..., 0) returns NULL (g_malloc(0) also) * when uncompr is NULL logic below doesn't create tvb * which is later interpreted as decompression failed. */ uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ? g_memdup(strmbuf, bytes_pass) : g_strdup("")); } else { guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass); memcpy(new_data, uncompr, bytes_out); memcpy(new_data + bytes_out, strmbuf, bytes_pass); g_free(uncompr); uncompr = new_data; } bytes_out += bytes_pass; if (err == Z_STREAM_END) { inflateEnd(strm); g_free(strm); g_free(strmbuf); break; } } else if (err == Z_BUF_ERROR) { /* * It's possible that not enough frames were captured * to decompress this fully, so return what we've done * so far, if any. */ inflateEnd(strm); g_free(strm); g_free(strmbuf); if (uncompr != NULL) { break; } else { wmem_free(NULL, compr); return NULL; } } else if (err == Z_DATA_ERROR && inits_done == 1 && uncompr == NULL && comprlen >= 2 && (*compr == 0x1f) && (*(compr + 1) == 0x8b)) { /* * inflate() is supposed to handle both gzip and deflate * streams automatically, but in reality it doesn't * seem to handle either (at least not within the * context of an HTTP response.) We have to try * several tweaks, depending on the type of data and * version of the library installed. */ /* * Gzip file format. Skip past the header, since the * fix to make it work (setting windowBits to 31) * doesn't work with all versions of the library. */ Bytef *c = compr + 2; Bytef flags = 0; /* we read two bytes already (0x1f, 0x8b) and need at least Z_DEFLATED, 1 byte flags, 4 bytes MTIME, 1 byte XFL, 1 byte OS */ if (comprlen < 10 || *c != Z_DEFLATED) { inflateEnd(strm); g_free(strm); wmem_free(NULL, compr); g_free(strmbuf); return NULL; } c++; flags = *c; c++; /* Skip past the MTIME (4 bytes), XFL, and OS fields (1 byte each). */ c += 6; if (flags & (1 << 2)) { /* An Extra field is present. It consists of 2 bytes xsize and xsize bytes of data. Read byte-by-byte (least significant byte first) to make sure we abort cleanly when the xsize is truncated after the first byte. */ guint16 xsize = 0; if (c-compr < comprlen) { xsize += *c; c++; } if (c-compr < comprlen) { xsize += *c << 8; c++; } c += xsize; } if (flags & (1 << 3)) { /* A null terminated filename */ while ((c - compr) < comprlen && *c != '\0') { c++; } c++; } if (flags & (1 << 4)) { /* A null terminated comment */ while ((c - compr) < comprlen && *c != '\0') { c++; } c++; } if (c - compr > comprlen) { inflateEnd(strm); g_free(strm); wmem_free(NULL, compr); g_free(strmbuf); return NULL; } /* Drop gzip header */ comprlen -= (int) (c - compr); next = c; inflateReset(strm); strm->next_in = next; strm->avail_in = comprlen; inflateEnd(strm); inflateInit2(strm, wbits); inits_done++; } else if (err == Z_DATA_ERROR && uncompr == NULL && inits_done <= 3) { /* * Re-init the stream with a negative * MAX_WBITS. This is necessary due to * some servers (Apache) not sending * the deflate header with the * content-encoded response. */ wbits = -MAX_WBITS; inflateReset(strm); strm->next_in = next; strm->avail_in = comprlen; inflateEnd(strm); memset(strmbuf, '\0', bufsiz); strm->next_out = strmbuf; strm->avail_out = bufsiz; err = inflateInit2(strm, wbits); inits_done++; if (err != Z_OK) { g_free(strm); g_free(strmbuf); wmem_free(NULL, compr); g_free(uncompr); return NULL; } } else { inflateEnd(strm); g_free(strm); g_free(strmbuf); if (uncompr == NULL) { wmem_free(NULL, compr); return NULL; } break; } } #ifdef TVB_Z_DEBUG ws_debug_printf("inflate() total passes: %u\n", inflate_passes); ws_debug_printf("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out); #endif if (uncompr != NULL) { uncompr_tvb = tvb_new_real_data((guint8*) uncompr, bytes_out, bytes_out); tvb_set_free_cb(uncompr_tvb, g_free); } wmem_free(NULL, compr); return uncompr_tvb; }
static tvbuff_t * dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree, guint32 findex, guint32 fcount, guint16 seq, gint offset, guint16 plen, gboolean fec _U_, guint16 rsk, guint16 rsz, fragment_data *fdx ) { guint16 decoded_size; guint32 c_max; guint32 rx_min; gboolean first, last; tvbuff_t *new_tvb=NULL; if (fcount > MAX_FRAGMENTS) { if (tree) proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", fcount); return NULL; } first = findex == 0; last = fcount == (findex+1); decoded_size = fcount*plen; c_max = fcount*plen/(rsk+PFT_RS_P); /* rounded down */ rx_min = c_max*rsk/plen; if(rx_min*plen<c_max*rsk) rx_min++; if (fdx) new_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled DCP (ETSI)", fdx, &dcp_frag_items, NULL, tree); else { guint fragments=0; guint32 *got; fragment_data *fd; fragment_data *fd_head; if(tree) proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d", fcount, fragments, rx_min ); got = ep_alloc(fcount*sizeof(guint32)); /* make a list of the findex (offset) numbers of the fragments we have */ fd = fragment_get(pinfo, seq, dcp_fragment_table); for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) { if(fd_head->data) { got[fragments++] = fd_head->offset; /* this is the findex of the fragment */ } } /* put a sentinel at the end */ got[fragments++] = fcount; /* have we got enough for Reed Solomon to try to correct ? */ if(fragments>=rx_min) { /* yes, in theory */ guint i,current_findex; fragment_data *frag=NULL; guint8 *dummy_data = (guint8*) ep_alloc0 (plen); tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen); /* try and decode with missing fragments */ if(tree) proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d", fcount, fragments, rx_min ); /* fill the fragment table with empty fragments */ current_findex = 0; for(i=0; i<fragments; i++) { guint next_fragment_we_have = got[i]; if (next_fragment_we_have > MAX_FRAGMENTS) { if (tree) proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", next_fragment_we_have); return NULL; } for(; current_findex<next_fragment_we_have; current_findex++) { frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq, dcp_fragment_table, dcp_reassembled_table, current_findex, plen, (current_findex+1!=fcount)); } current_findex++; /* skip over the fragment we have */ } if(frag) new_tvb = process_reassembled_data (tvb, offset, pinfo, "Reassembled DCP (ETSI)", frag, &dcp_frag_items, NULL, tree); } } if(new_tvb) { gboolean decoded = TRUE; tvbuff_t *dtvb = NULL; const guint8 *input = tvb_get_ptr(new_tvb, 0, -1); guint16 reassembled_size = tvb_length(new_tvb); guint8 *deinterleaved = (guint8*) g_malloc (reassembled_size); guint8 *output = (guint8*) g_malloc (decoded_size); rs_deinterleave(input, deinterleaved, plen, fcount); dtvb = tvb_new_child_real_data(tvb, deinterleaved, reassembled_size, reassembled_size); add_new_data_source(pinfo, dtvb, "Deinterleaved"); tvb_set_free_cb(dtvb, g_free); decoded = rs_correct_data(deinterleaved, output, c_max, rsk, rsz); if(tree) proto_tree_add_boolean (tree, hf_edcp_rs_ok, tvb, offset, 2, decoded); new_tvb = tvb_new_child_real_data(dtvb, output, decoded_size, decoded_size); add_new_data_source(pinfo, new_tvb, "RS Error Corrected Data"); tvb_set_free_cb(new_tvb, g_free); } return new_tvb; }
static void dissect_rtmpt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *rtmpt_tree = NULL; proto_tree *rtmptroot_tree = NULL; proto_item *ti = NULL; gint offset = 0; struct tcpinfo* tcpinfo = pinfo->private_data; guint8 iCommand = -1; guint32 iLength = 1; guint16 iHeaderType = 4; guint16 iHeaderLength; guint8 iID; guint rtmp_index; conversation_t * current_conversation; rtmpt_conversation_data_t * conversation_data; rtmpt_packet_data_t * packet_data; rtmpt_chunk_data_t *current_chunk_data = NULL; rtmpt_chunk_data_t *initial_chunk_data = NULL; tvbuff_t* amf_tvb; current_conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0); if (NULL != current_conversation) { conversation_data = (rtmpt_conversation_data_t*)conversation_get_proto_data(current_conversation, proto_rtmpt); if (NULL == conversation_data) { conversation_data = se_alloc(sizeof(rtmpt_conversation_data_t)); memset((void*)conversation_data, 0, sizeof(rtmpt_conversation_data_t)); conversation_add_proto_data(current_conversation, proto_rtmpt, conversation_data); conversation_data->current_chunks = g_hash_table_new(g_direct_hash, g_direct_equal); conversation_data->previous_frame_number = -1; conversation_data->current_chunk_size = RTMPT_DEFAULT_CHUNK_SIZE; conversation_data->is_rtmpe = 0; } packet_data = p_get_proto_data(pinfo->fd, proto_rtmpt); if (NULL == packet_data) { packet_data = se_alloc(sizeof(rtmpt_packet_data_t)); memset((void*)packet_data, 0, sizeof(rtmpt_packet_data_t)); p_add_proto_data(pinfo->fd, proto_rtmpt, packet_data); packet_data->initial_chunks = g_hash_table_new(g_direct_hash, g_direct_equal); packet_data->initial_chunk_size = conversation_data->current_chunk_size; } if (conversation_data->is_rtmpe == 1) { col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMPE"); return; } else { col_set_str(pinfo->cinfo, COL_PROTOCOL, "RTMP"); } if (conversation_data->previous_frame_number != (guint) pinfo->fd->num) { conversation_data->current_chunk_size = packet_data->initial_chunk_size; } col_set_writable(pinfo->cinfo, TRUE); col_clear(pinfo->cinfo, COL_INFO); conversation_data->previous_frame_number = pinfo->fd->num; if (tvb_length_remaining(tvb, offset) >= 1) { if (tcpinfo->lastackseq == RTMPT_HANDSHAKE_OFFSET_1 && tcpinfo->seq == RTMPT_HANDSHAKE_OFFSET_1) { iCommand = RTMPT_TYPE_HANDSHAKE_1; } else if (tcpinfo->lastackseq == RTMPT_HANDSHAKE_OFFSET_2 && tcpinfo->seq == RTMPT_HANDSHAKE_OFFSET_1) iCommand = RTMPT_TYPE_HANDSHAKE_2; else if (tcpinfo->seq == RTMPT_HANDSHAKE_OFFSET_2 && tvb_length(tvb) == RTMPT_HANDSHAKE_LENGTH_3) iCommand = RTMPT_TYPE_HANDSHAKE_3; else { iID = tvb_get_guint8(tvb, offset + 0); iHeaderType = iID >> 6; rtmp_index = iID & 0x3F; current_chunk_data = g_hash_table_lookup(conversation_data->current_chunks, GUINT_TO_POINTER(rtmp_index)); initial_chunk_data = g_hash_table_lookup(packet_data->initial_chunks, GUINT_TO_POINTER(rtmp_index)); if (iHeaderType <= 2) iLength = tvb_get_ntoh24(tvb, offset + 4); if (iHeaderType <= 1) { iCommand = tvb_get_guint8(tvb, offset + 7); if (NULL == current_chunk_data) { current_chunk_data = se_alloc(sizeof(rtmpt_chunk_data_t)); memset((void*)current_chunk_data, 0, sizeof(rtmpt_chunk_data_t)); g_hash_table_insert(conversation_data->current_chunks, GUINT_TO_POINTER(rtmp_index), current_chunk_data); } current_chunk_data->data_type = iCommand; current_chunk_data->last_length = iLength; current_chunk_data->frame_modified = pinfo->fd->num; } else { /* must get the command type from the previous entries in the hash table */ /* try to use the current_chunk_data unless it is from a different frame */ if (NULL != current_chunk_data && NULL != initial_chunk_data) { /* we have precedent data (we should)*/ if (current_chunk_data->frame_modified != pinfo->fd->num) { iCommand = initial_chunk_data->data_type; iLength = initial_chunk_data->length_remaining; current_chunk_data->frame_modified = pinfo->fd->num; current_chunk_data->data_type = iCommand; current_chunk_data->last_length = iLength; current_chunk_data->dechunk_buffer = initial_chunk_data->dechunk_buffer; } else { iCommand = current_chunk_data->data_type; iLength = current_chunk_data->length_remaining; } if (iLength > conversation_data->current_chunk_size) { iLength = conversation_data->current_chunk_size; } } } } iHeaderLength = rtmpt_header_length_from_type(iHeaderType); if (check_col(pinfo->cinfo, COL_INFO)) { col_append_sep_fstr(pinfo->cinfo, COL_INFO, " | ", "%s", val_to_str(iCommand, rtmpt_opcode_vals, "Unknown (0x%01x)")); col_set_fence(pinfo->cinfo, COL_INFO); } if (tree) { ti = proto_tree_add_item(tree, proto_rtmpt, tvb, offset, -1, FALSE); proto_item_append_text(ti, " (%s)", val_to_str(iCommand, rtmpt_opcode_vals, "Unknown (0x%01x)")); rtmptroot_tree = proto_item_add_subtree(ti, ett_rtmpt); ti = proto_tree_add_text(rtmptroot_tree, tvb, offset, iHeaderLength, RTMPT_TEXT_RTMP_HEADER); proto_item_append_text(ti, " (%s)", val_to_str(iCommand, rtmpt_opcode_vals, "Unknown (0x%01x)")); rtmpt_tree = proto_item_add_subtree(ti, ett_rtmpt_header); if (iHeaderType <= 3) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_objid, tvb, offset + 0, 1, FALSE); if (iHeaderType <= 2) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_timestamp, tvb, offset + 1, 3, FALSE); if (iHeaderType <= 1) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_body_size, tvb, offset + 4, 3, FALSE); if (iHeaderType <= 1) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_function, tvb, offset + 7, 1, FALSE); if (iHeaderType <= 0) proto_tree_add_item(rtmpt_tree, hf_rtmpt_header_source, tvb, offset + 8, 4, TRUE); if (iCommand == RTMPT_TYPE_HANDSHAKE_1) { proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 1, 1536, FALSE); } else if (iCommand == RTMPT_TYPE_HANDSHAKE_2) { proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 1, 1536, FALSE); proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 1537, 1536, FALSE); } else if (iCommand == RTMPT_TYPE_HANDSHAKE_3) { proto_tree_add_item(rtmpt_tree, hf_rtmpt_handshake_data, tvb, 0, -1, FALSE); } else if (iCommand == RTMPT_TYPE_CHUNK_SIZE) { conversation_data->current_chunk_size = tvb_get_ntohl (tvb, offset + iHeaderLength); } offset = iHeaderLength; if (tvb_length_remaining(tvb, offset)) { ti = proto_tree_add_text(rtmptroot_tree, tvb, offset, -1, RTMPT_TEXT_RTMP_BODY); } if (iCommand == RTMPT_TYPE_INVOKE || iCommand == RTMPT_TYPE_NOTIFY) { guint iChunkSize = tvb_length_remaining(tvb, iHeaderLength); /* we have data which will be AMF */ /* we should add it to a new tvb */ if (NULL != current_chunk_data) { if (NULL == current_chunk_data->dechunk_buffer) { /* we have to create a new tvbuffer */ current_chunk_data->dechunk_buffer = tvb_new_composite(); } if (!(current_chunk_data->dechunk_buffer->initialized)) { /* add the existing data to the new buffer */ tvb_composite_append(current_chunk_data->dechunk_buffer, tvb_new_real_data(tvb_memdup(tvb, iHeaderLength, iChunkSize), iChunkSize, iChunkSize)); if (current_chunk_data->length_remaining <= 0) { guint amf_length; guint8* amf_data; tvb_composite_finalize(current_chunk_data->dechunk_buffer); amf_length = tvb_length(current_chunk_data->dechunk_buffer); if (amf_length == 0) { return; } amf_data = tvb_memdup(current_chunk_data->dechunk_buffer, 0, amf_length); amf_tvb = tvb_new_real_data(amf_data, tvb_length_remaining(current_chunk_data->dechunk_buffer, 0), tvb_length_remaining(current_chunk_data->dechunk_buffer, 0)); add_new_data_source(pinfo, amf_tvb, "Dechunked AMF data"); ti = proto_tree_add_item(tree, proto_rtmpt, amf_tvb, 0, -1, FALSE); rtmpt_tree = proto_item_add_subtree(ti, ett_rtmpt_body); proto_tree_set_appendix(rtmpt_tree, amf_tvb, 0, tvb_length_remaining(amf_tvb, 0)); proto_item_append_text(rtmpt_tree, " (%s)", "AMF Data"); dissect_rtmpt_amf(amf_tvb, rtmpt_tree); current_chunk_data->dechunk_buffer = NULL; } } } } } } }
g_free(data); } static gboolean val_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_) { tvbuff_t *new_tvb; guint8 *private_data; /* Free up the old value, if we have one */ value_free(fv); /* Make a tvbuff from the string. We can drop the * terminating NUL. */ private_data = (guint8 *)g_memdup(s, (guint)strlen(s)); new_tvb = tvb_new_real_data(private_data, (guint)strlen(s), (gint)strlen(s)); /* Let the tvbuff know how to delete the data. */ tvb_set_free_cb(new_tvb, free_tvb_data); /* And let us know that we need to free the tvbuff */ fv->tvb_is_private = TRUE; fv->value.tvb = new_tvb; return TRUE; } static gboolean val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg) { fvalue_t *fv_bytes; tvbuff_t *new_tvb;