static gint tacplus_decrypted_tvb_setup( tvbuff_t *tvb, tvbuff_t **dst_tvb, packet_info *pinfo, guint32 len, guint8 version, const char *key ) { guint8 *buff; guint8 session_id[4]; /* TODO Check the possibility to use pinfo->decrypted_data */ /* session_id is in NETWORK Byte Order, and is used as byte array in the md5_xor */ tvb_memcpy(tvb, session_id, 4,4); buff = tvb_memdup(tvb, TAC_PLUS_HDR_SIZE, len); md5_xor( buff, key, len, session_id,version, tvb_get_guint8(tvb,2) ); /* Allocate a new tvbuff, referring to the decrypted data. */ *dst_tvb = tvb_new_child_real_data(tvb, buff, len, len ); /* Arrange that the allocated packet data copy be freed when the tvbuff is freed. */ tvb_set_free_cb( *dst_tvb, g_free ); /* Add the decrypted data to the data source list. */ add_new_data_source(pinfo, *dst_tvb, "TACACS+ Decrypted"); return 0; }
/*! * Decodes a Text-string from the protocol data * Text-string = [Quote] *TEXT End-of-string * Quote = <Octet 127> * End-of-string = <Octet 0> * * \todo Shouldn't we be sharing this with WSP (packet-wap.c)? * * \param tvb The buffer with PDU-data * \param offset Offset within that buffer * \param strval Pointer to variable into which to put pointer to * buffer allocated to hold the text; must be freed * when no longer used * * \return The length in bytes of the entire field */ static guint get_text_string(tvbuff_t *tvb, guint offset, const char **strval) { guint len; DebugLog(("get_text_string(tvb = %p, offset = %u, **strval) - start\n", tvb, offset)); len = tvb_strsize(tvb, offset); DebugLog((" [1] tvb_strsize(tvb, offset) == %u\n", len)); if (tvb_get_guint8(tvb, offset) == MM_QUOTE) *strval = (const char *)tvb_memdup(wmem_packet_scope(), tvb, offset+1, len-1); else *strval = (const char *)tvb_memdup(wmem_packet_scope(), tvb, offset, len); DebugLog((" [3] Return(len) == %u\n", len)); return len; }
WSLUA_METHOD TvbRange_ether(lua_State* L) { /* Get an Ethernet Address from a TvbRange. */ TvbRange tvbr = checkTvbRange(L,1); Address addr; guint8* buff; if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } if (tvbr->len != 6) { WSLUA_ERROR(TvbRange_ether,"The range must be 6 bytes long"); return 0; } addr = g_new(address,1); buff = (guint8 *)tvb_memdup(NULL,tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len); SET_ADDRESS(addr, AT_ETHER, 6, buff); pushAddress(L,addr); WSLUA_RETURN(1); /* The Ethernet Address */ }
WSLUA_METHOD TvbRange_bytes(lua_State* L) { /* Obtain a `ByteArray` from a `TvbRange`. Starting in 1.11.4, this function also takes an optional `encoding` argument, which can be set to `ENC_STR_HEX` to decode a hex-string from the `TvbRange` into the returned `ByteArray`. The `encoding` can be bitwise-or'ed with one or more separator encodings, such as `ENC_SEP_COLON`, to allow separators to occur between each pair of hex characters. The return value also now returns the number of bytes used as a second return value. On failure or error, nil is returned for both return values. @note The encoding type of the hex string should also be set, for example `ENC_ASCII` or `ENC_UTF_8`, along with `ENC_STR_HEX`. */ #define WSLUA_OPTARG_TvbRange_bytes_ENCODING 2 /* An optional ENC_* encoding value to use */ TvbRange tvbr = checkTvbRange(L,1); GByteArray* ba; const guint encoding = (guint)luaL_optinteger(L, WSLUA_OPTARG_TvbRange_bytes_ENCODING, 0); if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } if (encoding == 0) { ba = g_byte_array_new(); g_byte_array_append(ba,(const guint8 *)tvb_memdup(wmem_packet_scope(),tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len),tvbr->len); pushByteArray(L,ba); lua_pushinteger(L, tvbr->len); } else if ((encoding & ENC_STR_HEX) == 0) { WSLUA_OPTARG_ERROR(TvbRange_nstime, ENCODING, "invalid encoding value"); } else { gint endoff = 0; GByteArray* retval; ba = g_byte_array_new(); retval = tvb_get_string_bytes(tvbr->tvb->ws_tvb, tvbr->offset, tvbr->len, encoding, ba, &endoff); if (!retval || endoff == 0) { g_byte_array_free(ba, TRUE); /* push nil nstime and offset */ lua_pushnil(L); lua_pushnil(L); } else { pushByteArray(L,ba); lua_pushinteger(L, endoff); } } WSLUA_RETURN(2); /* The `ByteArray` object or nil, and number of bytes consumed or nil. */ }
const QByteArray FrameInformation::printableData() { QByteArray data; if ( fi_ ) { int rem_length = tvb_captured_length(edt_.tvb); uint8_t * dataSet = (uint8_t *)tvb_memdup(wmem_file_scope(), edt_.tvb, 0, rem_length ); data = QByteArray::fromRawData((char *)dataSet, rem_length); } return data; }
WSLUA_METHOD TvbRange_bytes(lua_State* L) { /* Obtain a ByteArray */ TvbRange tvbr = checkTvbRange(L,1); GByteArray* ba; if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { luaL_error(L,"expired tvb"); return 0; } ba = g_byte_array_new(); g_byte_array_append(ba,(const guint8 *)tvb_memdup(wmem_packet_scope(),tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len),tvbr->len); pushByteArray(L,ba); WSLUA_RETURN(1); /* The ByteArray */ }
const QByteArray FieldInformation::printableData() { QByteArray data; if ( fi_ && fi_->ds_tvb ) { FieldInformation::Position pos = position(); int rem_length = tvb_captured_length_remaining(fi_->ds_tvb, pos.start); int length = pos.length; if ( length > rem_length ) length = rem_length; uint8_t * dataSet = (uint8_t *)tvb_memdup(wmem_file_scope(), fi_->ds_tvb, pos.start, length ); data = QByteArray::fromRawData((char *)dataSet, length); } return data; }
static void ess_dissect_attribute_flags (tvbuff_t *tvb, asn1_ctx_t *actx) { proto_tree *tree; guint8 *value; guint i; tree = proto_item_add_subtree (actx->created_item, ett_Category_attributes); value = (guint8 *)tvb_memdup (wmem_packet_scope(), tvb, 0, tvb_captured_length (tvb)); for (i = 0; i < num_ess_category_attributes; i++) { ess_category_attributes_t *u = &(ess_category_attributes[i]); if ((strcmp (u->oid, object_identifier_id) == 0) && ((u->lacv / 8) < tvb_captured_length (tvb)) && (value[u->lacv / 8] & (1 << (7 - (u->lacv % 8))))) { proto_tree_add_string_format (tree, hf_ess_Category_attribute, tvb, u->lacv / 8, 1, u->name, "%s (%d)", u->name, u->lacv); } } }
static void nlm_register_unmatched_msg(packet_info *pinfo, tvbuff_t *tvb, int offset) { nlm_msg_res_unmatched_data *umd; nlm_msg_res_unmatched_data *old_umd; /* allocate and build the unmatched structure for this request */ umd=(nlm_msg_res_unmatched_data *)g_malloc(sizeof(nlm_msg_res_unmatched_data)); umd->req_frame=pinfo->fd->num; umd->ns=pinfo->fd->abs_ts; umd->cookie_len=tvb_get_ntohl(tvb, offset); umd->cookie=(const guint8 *)tvb_memdup(tvb, offset+4, umd->cookie_len); /* remove any old duplicates */ old_umd=(nlm_msg_res_unmatched_data *)g_hash_table_lookup(nlm_msg_res_unmatched, (gconstpointer)umd); if(old_umd){ g_hash_table_remove(nlm_msg_res_unmatched, (gconstpointer)old_umd); g_free((gpointer)old_umd->cookie); g_free(old_umd); } /* add new one */ g_hash_table_insert(nlm_msg_res_unmatched, (gpointer)umd, (gpointer)umd); }
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 int generate_key_or_iv(unsigned int id, tvbuff_t *salt_tvb, unsigned int iter, const char *pw, unsigned int req_keylen, char * keybuf) { int rc; unsigned int i, j; gcry_md_hd_t md; gcry_mpi_t num_b1 = NULL; size_t pwlen; char hash[20], buf_b[64], buf_i[128], *p; char *salt_p; int salt_size; size_t cur_keylen; size_t n; gcry_error_t err; cur_keylen = 0; salt_size = tvb_captured_length(salt_tvb); salt_p = (char *)tvb_memdup(wmem_packet_scope(), salt_tvb, 0, salt_size); if (pw == NULL) pwlen = 0; else pwlen = strlen(pw); if (pwlen > 63 / 2) { return FALSE; } /* Store salt and password in BUF_I */ p = buf_i; for (i = 0; i < 64; i++) *p++ = salt_p[i % salt_size]; if (pw) { for (i = j = 0; i < 64; i += 2) { *p++ = 0; *p++ = pw[j]; if (++j > pwlen) /* Note, that we include the trailing zero */ j = 0; } } else memset (p, 0, 64); for (;;) { err = gcry_md_open(&md, GCRY_MD_SHA1, 0); if (gcry_err_code(err)) { return FALSE; } for (i = 0; i < 64; i++) { unsigned char lid = id & 0xFF; gcry_md_write (md, &lid, 1); } gcry_md_write(md, buf_i, pw ? 128 : 64); gcry_md_final (md); memcpy (hash, gcry_md_read (md, 0), 20); gcry_md_close (md); for (i = 1; i < iter; i++) gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20); for (i = 0; i < 20 && cur_keylen < req_keylen; i++) keybuf[cur_keylen++] = hash[i]; if (cur_keylen == req_keylen) { gcry_mpi_release (num_b1); return TRUE; /* ready */ } /* need more bytes. */ for (i = 0; i < 64; i++) buf_b[i] = hash[i % 20]; n = 64; rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, n, &n); if (rc != 0) { return FALSE; } gcry_mpi_add_ui (num_b1, num_b1, 1); for (i = 0; i < 128; i += 64) { gcry_mpi_t num_ij; n = 64; rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, n, &n); if (rc != 0) { return FALSE; } gcry_mpi_add (num_ij, num_ij, num_b1); gcry_mpi_clear_highbit (num_ij, 64 * 8); n = 64; rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, n, &n, num_ij); if (rc != 0) { return FALSE; } gcry_mpi_release (num_ij); } } }
int PBE_decrypt_data(const char *object_identifier_id_param, tvbuff_t *encrypted_tvb, asn1_ctx_t *actx, proto_item *item) { #ifdef HAVE_LIBGCRYPT const char *encryption_algorithm; gcry_cipher_hd_t cipher; gcry_error_t err; int algo; int mode; int ivlen = 0; int keylen = 0; int datalen = 0; char *key = NULL; char *iv = NULL; char *clear_data = NULL; tvbuff_t *clear_tvb = NULL; const gchar *oidname; GString *name; proto_tree *tree; char byte; gboolean decrypt_ok = TRUE; if(((password == NULL) || (*password == '\0')) && (try_null_password == FALSE)) { /* we are not configured to decrypt */ return FALSE; } encryption_algorithm = x509af_get_last_algorithm_id(); /* these are the only encryption schemes we understand for now */ if(!strcmp(encryption_algorithm, PKCS12_PBE_3DES_SHA1_OID)) { ivlen = 8; keylen = 24; algo = GCRY_CIPHER_3DES; mode = GCRY_CIPHER_MODE_CBC; } else if(!strcmp(encryption_algorithm, PKCS12_PBE_ARCFOUR_SHA1_OID)) { ivlen = 0; keylen = 16; algo = GCRY_CIPHER_ARCFOUR; mode = GCRY_CIPHER_MODE_NONE; } else if(!strcmp(encryption_algorithm, PKCS12_PBE_RC2_40_SHA1_OID)) { ivlen = 8; keylen = 5; algo = GCRY_CIPHER_RFC2268_40; mode = GCRY_CIPHER_MODE_CBC; } else { /* we don't know how to decrypt this */ proto_item_append_text(item, " [Unsupported encryption algorithm]"); return FALSE; } if((iteration_count == 0) || (salt == NULL)) { proto_item_append_text(item, " [Insufficient parameters]"); return FALSE; } /* allocate buffers */ key = (char *)wmem_alloc(wmem_packet_scope(), keylen); if(!generate_key_or_iv(1 /*LEY */, salt, iteration_count, password, keylen, key)) return FALSE; if(ivlen) { iv = (char *)wmem_alloc(wmem_packet_scope(), ivlen); if(!generate_key_or_iv(2 /* IV */, salt, iteration_count, password, ivlen, iv)) return FALSE; } /* now try an internal function */ err = gcry_cipher_open(&cipher, algo, mode, 0); if (gcry_err_code (err)) return FALSE; err = gcry_cipher_setkey (cipher, key, keylen); if (gcry_err_code (err)) { gcry_cipher_close (cipher); return FALSE; } if(ivlen) { err = gcry_cipher_setiv (cipher, iv, ivlen); if (gcry_err_code (err)) { gcry_cipher_close (cipher); return FALSE; } } datalen = tvb_captured_length(encrypted_tvb); clear_data = (char *)g_malloc(datalen); err = gcry_cipher_decrypt (cipher, clear_data, datalen, (char *)tvb_memdup(wmem_packet_scope(), encrypted_tvb, 0, datalen), datalen); if (gcry_err_code (err)) { proto_item_append_text(item, " [Failed to decrypt with password preference]"); gcry_cipher_close (cipher); g_free(clear_data); return FALSE; } gcry_cipher_close (cipher); /* We don't know if we have successfully decrypted the data or not so we: a) check the trailing bytes b) see if we start with a sequence or a set (is this too constraining? */ /* first the trailing bytes */ byte = clear_data[datalen-1]; if(byte <= 0x08) { int i; for(i = (int)byte; i > 0 ; i--) { if(clear_data[datalen - i] != byte) { decrypt_ok = FALSE; break; } } } else { /* XXX: is this a failure? */ } /* we assume the result is ASN.1 - check it is a SET or SEQUENCE */ byte = clear_data[0]; if((byte != 0x30) && (byte != 0x31)) { /* do we need more here? OCTET STRING? */ decrypt_ok = FALSE; } if(!decrypt_ok) { g_free(clear_data); proto_item_append_text(item, " [Failed to decrypt with supplied password]"); return FALSE; } proto_item_append_text(item, " [Decrypted successfully]"); tree = proto_item_add_subtree(item, ett_decrypted_pbe); /* OK - so now clear_data contains the decrypted data */ clear_tvb = tvb_new_child_real_data(encrypted_tvb,(const guint8 *)clear_data, datalen, datalen); tvb_set_free_cb(clear_tvb, g_free); name = g_string_new(""); oidname = oid_resolved_from_string(object_identifier_id_param); g_string_printf(name, "Decrypted %s", oidname ? oidname : object_identifier_id_param); /* add it as a new source */ add_new_data_source(actx->pinfo, clear_tvb, name->str); g_string_free(name, TRUE); /* now try and decode it */ call_ber_oid_callback(object_identifier_id_param, clear_tvb, 0, actx->pinfo, tree, NULL); return TRUE; #else /* we cannot decrypt */ return FALSE; #endif }
static void dissect_tftp_message(tftp_conv_info_t *tftp_info, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_tree *tftp_tree; proto_item *ti; gint offset = 0; guint16 opcode; guint16 bytes; guint16 blocknum; guint i1; guint16 error; tvbuff_t *data_tvb = NULL; col_set_str(pinfo->cinfo, COL_PROTOCOL, "TFTP"); /* Protocol root */ ti = proto_tree_add_item(tree, proto_tftp, tvb, offset, -1, ENC_NA); tftp_tree = proto_item_add_subtree(ti, ett_tftp); /* Opcode */ opcode = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(tftp_tree, hf_tftp_opcode, tvb, offset, 2, opcode); col_add_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, tftp_opcode_vals, "Unknown (0x%04x)")); offset += 2; /* read and write requests contain file names for other messages, we add the filenames from the conversation */ if (opcode!=TFTP_RRQ && opcode!=TFTP_WRQ) { if (tftp_info->source_file) { ti = proto_tree_add_string(tftp_tree, hf_tftp_source_file, tvb, 0, 0, tftp_info->source_file); PROTO_ITEM_SET_GENERATED(ti); } if (tftp_info->destination_file) { ti = proto_tree_add_string(tftp_tree, hf_tftp_destination_file, tvb, 0, 0, tftp_info->destination_file); PROTO_ITEM_SET_GENERATED(ti); } } switch (opcode) { case TFTP_RRQ: i1 = tvb_strsize(tvb, offset); proto_tree_add_item(tftp_tree, hf_tftp_source_file, tvb, offset, i1, ENC_ASCII|ENC_NA); tftp_info->source_file = tvb_get_string_enc(wmem_file_scope(), tvb, offset, i1, ENC_ASCII); /* we either have a source file name (for read requests) or a destination file name (for write requests) when we set one of the names, we clear the other */ tftp_info->destination_file = NULL; col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s", tvb_format_stringzpad(tvb, offset, i1)); offset += i1; i1 = tvb_strsize(tvb, offset); proto_tree_add_item(tftp_tree, hf_tftp_transfer_type, tvb, offset, i1, ENC_ASCII|ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s", tvb_format_stringzpad(tvb, offset, i1)); offset += i1; tftp_dissect_options(tvb, pinfo, offset, tftp_tree, opcode, tftp_info); break; case TFTP_WRQ: i1 = tvb_strsize(tvb, offset); proto_tree_add_item(tftp_tree, hf_tftp_destination_file, tvb, offset, i1, ENC_ASCII|ENC_NA); tftp_info->destination_file = tvb_get_string_enc(wmem_file_scope(), tvb, offset, i1, ENC_ASCII); tftp_info->source_file = NULL; /* see above */ col_append_fstr(pinfo->cinfo, COL_INFO, ", File: %s", tvb_format_stringzpad(tvb, offset, i1)); offset += i1; i1 = tvb_strsize(tvb, offset); proto_tree_add_item(tftp_tree, hf_tftp_transfer_type, tvb, offset, i1, ENC_ASCII|ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, ", Transfer type: %s", tvb_format_stringzpad(tvb, offset, i1)); offset += i1; tftp_dissect_options(tvb, pinfo, offset, tftp_tree, opcode, tftp_info); break; case TFTP_INFO: tftp_dissect_options(tvb, pinfo, offset, tftp_tree, opcode, tftp_info); break; case TFTP_DATA: blocknum = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2, blocknum); /* Sequence analysis on blocknums (first pass only) */ if (!pinfo->fd->flags.visited) { if (blocknum > tftp_info->next_block_num) { /* There is a gap. Don't try to recover from this. */ tftp_info->next_block_num = blocknum + 1; tftp_info->blocks_missing = TRUE; /* TODO: add info to a result table for showing expert info in later passes */ } else if (blocknum == tftp_info->next_block_num) { /* OK, inc what we expect next */ tftp_info->next_block_num++; } } offset += 2; /* Show number of bytes in this block, and whether it is the end of the file */ bytes = tvb_reported_length_remaining(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i%s", blocknum, (bytes < tftp_info->blocksize)?" (last)":"" ); /* Show data in tree */ if (bytes > 0) { data_tvb = tvb_new_subset(tvb, offset, -1, bytes); call_dissector(data_handle, data_tvb, pinfo, tree); } /* If Export Object tap is listening, need to accumulate blocks info list to send to tap. But if already know there are blocks missing, there is no point in trying. */ if (have_tap_listener(tftp_eo_tap) && !tftp_info->blocks_missing) { file_block_t *block; if (blocknum == 1) { /* Reset data for this conversation, freeing any accumulated blocks! */ cleanup_tftp_blocks(tftp_info); tftp_info->next_tap_block_num = 1; } if (blocknum != tftp_info->next_tap_block_num) { /* Ignore. Could be missing frames, or just clicking previous frame */ return; } if (bytes > 0) { /* Create a block for this block */ block = (file_block_t*)g_malloc(sizeof(file_block_t)); block->length = bytes; block->data = tvb_memdup(NULL, data_tvb, 0, bytes); /* Add to the end of the list (does involve traversing whole list..) */ tftp_info->block_list = g_slist_append(tftp_info->block_list, block); tftp_info->file_length += bytes; /* Look for next blocknum next time */ tftp_info->next_tap_block_num++; } /* Tap export object only when reach end of file */ if (bytes < tftp_info->blocksize) { tftp_eo_t *eo_info; /* If don't have a filename, won't tap file info */ if ((tftp_info->source_file == NULL) && (tftp_info->destination_file == NULL)) { cleanup_tftp_blocks(tftp_info); return; } /* Create the eo_info to pass to the listener */ eo_info = wmem_new(wmem_packet_scope(), tftp_eo_t); /* Set filename */ if (tftp_info->source_file) { eo_info->filename = g_strdup(tftp_info->source_file); } else if (tftp_info->destination_file) { eo_info->filename = g_strdup(tftp_info->destination_file); } /* Send block list, which will be combined and freed at tap. */ eo_info->payload_len = tftp_info->file_length; eo_info->pkt_num = blocknum; eo_info->block_list = tftp_info->block_list; /* Send to tap */ tap_queue_packet(tftp_eo_tap, pinfo, eo_info); /* Have sent, so forget list of blocks, and only pay attention if we get back to the first block again. */ tftp_info->block_list = NULL; tftp_info->next_tap_block_num = 1; } } break; case TFTP_ACK: blocknum = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(tftp_tree, hf_tftp_blocknum, tvb, offset, 2, blocknum); col_append_fstr(pinfo->cinfo, COL_INFO, ", Block: %i", blocknum); break; case TFTP_ERROR: error = tvb_get_ntohs(tvb, offset); proto_tree_add_uint(tftp_tree, hf_tftp_error_code, tvb, offset, 2, error); col_append_fstr(pinfo->cinfo, COL_INFO, ", Code: %s", val_to_str(error, tftp_error_code_vals, "Unknown (%u)")); offset += 2; i1 = tvb_strsize(tvb, offset); proto_tree_add_item(tftp_tree, hf_tftp_error_string, tvb, offset, i1, ENC_ASCII|ENC_NA); col_append_fstr(pinfo->cinfo, COL_INFO, ", Message: %s", tvb_format_stringzpad(tvb, offset, i1)); expert_add_info(pinfo, NULL, &ei_tftp_blocksize_range); break; case TFTP_OACK: tftp_dissect_options(tvb, pinfo, offset, tftp_tree, opcode, tftp_info); break; default: proto_tree_add_item(tftp_tree, hf_tftp_data, tvb, offset, -1, ENC_NA); break; } }
/* Transfers happen in response to broadcasts, they are always TCP and are * used to send the file to the port mentioned in the broadcast. There are * 2 types of transfers: Pushes, which are direct responses to searches, * in which the peer that has the file connects to the peer that doesn't and * sends it, then disconnects. The other type of transfer is a pull, where * the peer that doesn't have the file connects to the peer that does and * requests it be sent. * * Pulls have a file request which identifies the desired file, * while pushes simply send the file. In practice this works because every * file the implementation sends searches for is on a different TCP port * on the searcher's machine. */ static int dissect_ldss_transfer (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data) { conversation_t *transfer_conv; ldss_transfer_info_t *transfer_info; struct tcpinfo *transfer_tcpinfo; proto_tree *ti, *line_tree = NULL, *ldss_tree = NULL; nstime_t broadcast_response_time; /* Reject the packet if data is NULL */ if (data == NULL) return 0; transfer_tcpinfo = (struct tcpinfo *)data; col_set_str(pinfo->cinfo, COL_PROTOCOL, "LDSS"); /* Look for the transfer conversation; this was created during * earlier broadcast dissection (see prepare_ldss_transfer_conv) */ transfer_conv = find_conversation (pinfo->num, &pinfo->src, &pinfo->dst, PT_TCP, pinfo->srcport, pinfo->destport, 0); transfer_info = (ldss_transfer_info_t *)conversation_get_proto_data(transfer_conv, proto_ldss); /* For a pull, the first packet in the TCP connection is the file request. * First packet is identified by relative seq/ack numbers of 1. * File request only appears on a pull (triggered by an offer - see above * about broadcasts) */ if (transfer_tcpinfo->seq == 1 && transfer_tcpinfo->lastackseq == 1 && transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND) { /* LDSS pull transfers look a lot like HTTP. * Sample request: * md5:01234567890123... * Size: 2550 * Start: 0 * Compression: 0 * (remote end sends the file identified by the digest) */ guint offset = 0; gboolean already_dissected = TRUE; col_set_str(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Requesting file - pull)"); if (highest_num_seen == 0 || highest_num_seen < pinfo->num) { already_dissected = FALSE; transfer_info->req = wmem_new0(wmem_file_scope(), ldss_file_request_t); transfer_info->req->file = wmem_new0(wmem_file_scope(), ldss_file_t); highest_num_seen = pinfo->num; } if (tree) { ti = proto_tree_add_item(tree, proto_ldss, tvb, 0, tvb_reported_length(tvb), ENC_NA); ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer); } /* Populate digest data into the file struct in the request */ transfer_info->file = transfer_info->req->file; /* Grab each line from the packet, there should be 4 but lets * not walk off the end looking for more. */ while (tvb_offset_exists(tvb, offset)) { gint next_offset; const guint8 *line; int linelen; gboolean is_digest_line; guint digest_type_len; linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE); /* Include new-line in line */ line = (guint8 *)tvb_memdup(NULL, tvb, offset, linelen+1); /* XXX - memory leak? */ line_tree = proto_tree_add_subtree(ldss_tree, tvb, offset, linelen, ett_ldss_transfer_req, NULL, tvb_format_text(tvb, offset, next_offset-offset)); /* Reduce code duplication processing digest lines. * There are too many locals to pass to a function - the signature * looked pretty ugly when I tried! */ is_digest_line = FALSE; if (strncmp(line,"md5:",4)==0) { is_digest_line = TRUE; digest_type_len = 4; transfer_info->file->digest_type = DIGEST_TYPE_MD5; } else if (strncmp(line, "sha1:", 5)==0) { is_digest_line = TRUE; digest_type_len = 5; transfer_info->file->digest_type = DIGEST_TYPE_SHA1; } else if (strncmp(line, "sha256:", 7)==0) { is_digest_line = TRUE; digest_type_len = 7; transfer_info->file->digest_type = DIGEST_TYPE_SHA256; } else if (strncmp(line, "unknown:", 8)==0) { is_digest_line = TRUE; digest_type_len = 8; transfer_info->file->digest_type = DIGEST_TYPE_UNKNOWN; } else if (strncmp(line, "Size: ", 6)==0) { /* Sample size line: * Size: 2550\n */ transfer_info->req->size = g_ascii_strtoull(line+6, NULL, 10); if (tree) { ti = proto_tree_add_uint64(line_tree, hf_ldss_size, tvb, offset+6, linelen-6, transfer_info->req->size); PROTO_ITEM_SET_GENERATED(ti); } } else if (strncmp(line, "Start: ", 7)==0) { /* Sample offset line: * Start: 0\n */ transfer_info->req->offset = g_ascii_strtoull(line+7, NULL, 10); if (tree) { ti = proto_tree_add_uint64(line_tree, hf_ldss_offset, tvb, offset+7, linelen-7, transfer_info->req->offset); PROTO_ITEM_SET_GENERATED(ti); } } else if (strncmp(line, "Compression: ", 13)==0) { /* Sample compression line: * Compression: 0\n */ transfer_info->req->compression = (gint8)strtol(line+13, NULL, 10); /* XXX - bad cast */ if (tree) { ti = proto_tree_add_uint(line_tree, hf_ldss_compression, tvb, offset+13, linelen-13, transfer_info->req->compression); PROTO_ITEM_SET_GENERATED(ti); } } else { proto_tree_add_expert(line_tree, pinfo, &ei_ldss_unrecognized_line, tvb, offset, linelen); } if (is_digest_line) { /* Sample digest-type/digest line: * md5:0123456789ABCDEF\n */ if (!already_dissected) { GByteArray *digest_bytes; digest_bytes = g_byte_array_new(); hex_str_to_bytes( tvb_get_ptr(tvb, offset+digest_type_len, linelen-digest_type_len), digest_bytes, FALSE); if(digest_bytes->len >= DIGEST_LEN) digest_bytes->len = (DIGEST_LEN-1); /* Ensure the digest is zero-padded */ transfer_info->file->digest = (guint8 *)wmem_alloc0(wmem_file_scope(), DIGEST_LEN); memcpy(transfer_info->file->digest, digest_bytes->data, digest_bytes->len); g_byte_array_free(digest_bytes, TRUE); } if (tree) { proto_item *tii = NULL; tii = proto_tree_add_uint(line_tree, hf_ldss_digest_type, tvb, offset, digest_type_len, transfer_info->file->digest_type); PROTO_ITEM_SET_GENERATED(tii); tii = proto_tree_add_bytes(line_tree, hf_ldss_digest, tvb, offset+digest_type_len, MIN(linelen-digest_type_len, DIGEST_LEN), transfer_info->file->digest); PROTO_ITEM_SET_GENERATED(tii); } } offset = next_offset; } /* Link forwards to the response for this pull. */ if (tree && transfer_info->resp_num != 0) { ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_in, tvb, 0, 0, transfer_info->resp_num); PROTO_ITEM_SET_GENERATED(ti); } transfer_info->req->num = pinfo->num; transfer_info->req->ts = pinfo->abs_ts; } /* Remaining packets are the file response */ else { guint64 size; guint64 offset; guint8 compression; /* size, digest, compression come from the file request for a pull but * they come from the broadcast for a push. Pushes don't bother * with a file request - they just send the data. We have to get file * info from the offer broadcast which triggered this transfer. * If we cannot find the file request, default to the broadcast. */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL) { transfer_info->file = transfer_info->req->file; size = transfer_info->req->size; offset = transfer_info->req->offset; compression = transfer_info->req->compression; } else { transfer_info->file = transfer_info->broadcast->file; size = transfer_info->broadcast->size; offset = transfer_info->broadcast->offset; compression = transfer_info->broadcast->compression; } /* Remaining data in this TCP connection is all file data. * Always desegment if the size is 0 (ie. unknown) */ if (pinfo->can_desegment) { if (size == 0 || tvb_captured_length(tvb) < size) { pinfo->desegment_offset = 0; pinfo->desegment_len = DESEGMENT_UNTIL_FIN; return 0; } } /* OK. Now we have the whole file that was transferred. */ transfer_info->resp_num = pinfo->num; transfer_info->resp_ts = pinfo->abs_ts; col_add_fstr(pinfo->cinfo, COL_INFO, "LDSS File Transfer (Sending file - %s)", transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND ? "pull" : "push"); if (tree) { ti = proto_tree_add_item(tree, proto_ldss, tvb, 0, tvb_reported_length(tvb), ENC_NA); ldss_tree = proto_item_add_subtree(ti, ett_ldss_transfer); proto_tree_add_bytes_format(ldss_tree, hf_ldss_file_data, tvb, 0, tvb_captured_length(tvb), NULL, compression == COMPRESSION_GZIP ? "Gzip compressed data: %d bytes" : "File data: %d bytes", tvb_captured_length(tvb)); #ifdef HAVE_ZLIB /* Be nice and uncompress the file data. */ if (compression == COMPRESSION_GZIP) { tvbuff_t *uncomp_tvb; uncomp_tvb = tvb_child_uncompress(tvb, tvb, 0, tvb_captured_length(tvb)); if (uncomp_tvb != NULL) { /* XXX: Maybe not a good idea to add a data_source for what may very well be a large buffer since then the full uncompressed buffer will be shown in a tab in the hex bytes pane ? However, if we don't, bytes in an unrelated tab will be highlighted. */ add_new_data_source(pinfo, uncomp_tvb, "Uncompressed Data"); proto_tree_add_bytes_format_value(ldss_tree, hf_ldss_file_data, uncomp_tvb, 0, tvb_captured_length(uncomp_tvb), NULL, "Uncompressed data: %d bytes", tvb_captured_length(uncomp_tvb)); } } #endif ti = proto_tree_add_uint(ldss_tree, hf_ldss_digest_type, tvb, 0, 0, transfer_info->file->digest_type); PROTO_ITEM_SET_GENERATED(ti); if (transfer_info->file->digest != NULL) { /* This is ugly. You can't add bytes of nonzero length and have * filtering work correctly unless you give a valid location in * the packet. This hack pretends the first 32 bytes of the packet * are the digest, which they aren't: they're actually the first 32 * bytes of the file that was sent. */ ti = proto_tree_add_bytes(ldss_tree, hf_ldss_digest, tvb, 0, DIGEST_LEN, transfer_info->file->digest); } PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint64(ldss_tree, hf_ldss_size, tvb, 0, 0, size); PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint64(ldss_tree, hf_ldss_offset, tvb, 0, 0, offset); PROTO_ITEM_SET_GENERATED(ti); ti = proto_tree_add_uint(ldss_tree, hf_ldss_compression, tvb, 0, 0, compression); PROTO_ITEM_SET_GENERATED(ti); /* Link to the request for a pull. */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL && transfer_info->req->num != 0) { ti = proto_tree_add_uint(ldss_tree, hf_ldss_response_to, tvb, 0, 0, transfer_info->req->num); PROTO_ITEM_SET_GENERATED(ti); } } } /* Print the pull response time */ if (transfer_info->broadcast->message_id == MESSAGE_ID_WILLSEND && transfer_info->req != NULL && transfer_info->resp_num != 0) { nstime_t pull_response_time; nstime_delta(&pull_response_time, &transfer_info->resp_ts, &transfer_info->req->ts); ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_response_time, tvb, 0, 0, &pull_response_time); PROTO_ITEM_SET_GENERATED(ti); } /* Link the transfer back to the initiating broadcast. Response time is * calculated as the time from broadcast to completed transfer. */ ti = proto_tree_add_uint(ldss_tree, hf_ldss_initiated_by, tvb, 0, 0, transfer_info->broadcast->num); PROTO_ITEM_SET_GENERATED(ti); if (transfer_info->resp_num != 0) { nstime_delta(&broadcast_response_time, &transfer_info->resp_ts, &transfer_info->broadcast->ts); ti = proto_tree_add_time(ldss_tree, hf_ldss_transfer_completed_in, tvb, 0, 0, &broadcast_response_time); PROTO_ITEM_SET_GENERATED(ti); } /* This conv got its addr2/port2 set by the TCP dissector because a TCP * connection was established. Make a new one to handle future connections * to the addr/port mentioned in the broadcast, because that socket is * still open. */ if (transfer_tcpinfo->seq == 1 && transfer_tcpinfo->lastackseq == 1) { prepare_ldss_transfer_conv(transfer_info->broadcast); } return tvb_captured_length(tvb); }
/* Broadcasts are searches, offers or promises. * * Searches are sent by * a peer when it needs a file (ie. while applying its policy, when it needs * files such as installers to install software.) * * Each broadcast relates to one file and each file is identified only by its * checksum - no file names are ever used. A search times out after 10 seconds * (configurable) and the peer will then attempt to act on any offers by * downloading (via push or pull - see dissect_ldss_transfer) from those peers. * * If no offers are received, the search fails and the peer fetches the file * from a remote server, generally a HTTP server on the other side of a WAN. * The protocol exists to minimize the number of WAN downloads needed. * * While downloading from WAN the peer sends promises to inform other peers * when it will be available for them to download. This prevents multiple peers * simultaneously downloading the same file. Promises also inform other peers * how much download bandwidth is being used by their download. Other peers use * this information and the configured knowledge of the WAN bandwidth to avoid * saturating the WAN link, as file downloads are a non-time-critical and * non-business-critical network function. LDSS is intended for networks of * 5-20 machines connected by slow WAN link. The current implementation of the * protocol allows administrator to configure "time windows" when WAN usage is * throttled/unthrottled, though this isn't visible in LDSS. * * Once a WAN download or a LAN transfer (see below above dissect_ldss_transfer) * has complete the peer will offer the file to other peers on the LAN so they * don't need to download it themselves. * * Peers also notify when they shut down in case any other peer is waiting for * a file. */ static int dissect_ldss_broadcast(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint16 messageID; guint8 digest_type; guint8 compression; guint32 cookie; guint8 *digest; guint64 size; guint64 offset; guint32 targetTime; guint16 port; guint16 rate; guint16 messageDetail = INFERRED_NONE; proto_tree *ti, *ldss_tree; const gchar *packet_type, *packet_detail; messageID = tvb_get_ntohs (tvb, 0); digest_type = tvb_get_guint8 (tvb, 2); compression = tvb_get_guint8 (tvb, 3); cookie = tvb_get_ntohl (tvb, 4); digest = (guint8 *)tvb_memdup (NULL, tvb, 8, DIGEST_LEN); size = tvb_get_ntoh64 (tvb, 40); offset = tvb_get_ntoh64 (tvb, 48); targetTime = tvb_get_ntohl (tvb, 56); port = tvb_get_ntohs (tvb, 64); rate = tvb_get_ntohs (tvb, 66); packet_type = val_to_str_const(messageID, ldss_message_id_value, "unknown"); if (messageID == MESSAGE_ID_WILLSEND) { if (cookie == 0) { /* Shutdown: Dishonor promises from this peer. Current * implementation abuses WillSend for this. */ messageDetail = INFERRED_PEERSHUTDOWN; } else if (size == 0 && offset == 0) { /* NeedFile search failed - going to WAN */ messageDetail = INFERRED_WANDOWNLOAD; } else if (size > 0) { /* Size is known (not always the case) */ if (size == offset) { /* File is available for pull on this peer's TCP port */ messageDetail = INFERRED_OFFER; } else { /* WAN download progress announcement from this peer */ messageDetail = INFERRED_PROMISE; } } } else if (messageID == MESSAGE_ID_NEEDFILE) { messageDetail = INFERRED_SEARCH; } packet_detail = val_to_str_const(messageDetail, ldss_inferred_info, "unknown"); /* Set the info column */ col_add_fstr(pinfo->cinfo, COL_INFO, "LDSS Broadcast (%s%s)", packet_type, packet_detail); /* If we have a non-null tree (ie we are building the proto_tree * instead of just filling out the columns), then give more detail. */ if (tree) { ti = proto_tree_add_item(tree, proto_ldss, tvb, 0, (tvb_captured_length(tvb) > 72) ? tvb_captured_length(tvb) : 72, ENC_NA); ldss_tree = proto_item_add_subtree(ti, ett_ldss_broadcast); proto_tree_add_item(ldss_tree, hf_ldss_message_id, tvb, 0, 2, ENC_BIG_ENDIAN); ti = proto_tree_add_uint(ldss_tree, hf_ldss_message_detail, tvb, 0, 0, messageDetail); PROTO_ITEM_SET_GENERATED(ti); proto_tree_add_item(ldss_tree, hf_ldss_digest_type, tvb, 2, 1, ENC_BIG_ENDIAN); proto_tree_add_item(ldss_tree, hf_ldss_compression, tvb, 3, 1, ENC_BIG_ENDIAN); proto_tree_add_uint_format_value(ldss_tree, hf_ldss_cookie, tvb, 4, 4, FALSE, "0x%x%s", cookie, (cookie == 0) ? " - shutdown (promises from this peer are no longer valid)" : ""); proto_tree_add_item(ldss_tree, hf_ldss_digest, tvb, 8, DIGEST_LEN, ENC_NA); proto_tree_add_item(ldss_tree, hf_ldss_size, tvb, 40, 8, ENC_BIG_ENDIAN); proto_tree_add_item(ldss_tree, hf_ldss_offset, tvb, 48, 8, ENC_BIG_ENDIAN); proto_tree_add_uint_format_value(ldss_tree, hf_ldss_target_time, tvb, 56, 4, FALSE, "%d:%02d:%02d", (int)(targetTime / 3600), (int)((targetTime / 60) % 60), (int)(targetTime % 60)); proto_tree_add_item(ldss_tree, hf_ldss_reserved_1, tvb, 60, 4, ENC_BIG_ENDIAN); proto_tree_add_uint_format_value(ldss_tree, hf_ldss_port, tvb, 64, 2, FALSE, "%d%s", port, (messageID == MESSAGE_ID_WILLSEND && size > 0 && size == offset) ? " - file can be pulled at this TCP port" : (messageID == MESSAGE_ID_NEEDFILE ? " - file can be pushed to this TCP port" : "")); proto_tree_add_uint_format_value(ldss_tree, hf_ldss_rate, tvb, 66, 2, FALSE, "%ld", (rate > 0) ? (long)floor(exp(rate * G_LN2 / 2048)) : 0); proto_tree_add_item(ldss_tree, hf_ldss_priority, tvb, 68, 2, ENC_BIG_ENDIAN); proto_tree_add_item(ldss_tree, hf_ldss_property_count, tvb, 70, 2, ENC_BIG_ENDIAN); if (tvb_reported_length(tvb) > 72) { proto_tree_add_item(ldss_tree, hf_ldss_properties, tvb, 72, tvb_captured_length(tvb) - 72, ENC_NA); } } /* Finally, store the broadcast and register ourselves to dissect * any pushes or pulls that result from this broadcast. All data * is pushed/pulled over TCP using the port from the broadcast * packet's port field. * Track each by a TCP conversation with the remote end wildcarded. * The TCP conv tracks back to a broadcast conv to determine what it * is in response to. * * These steps only need to be done once per packet, so a variable * tracks the highest frame number seen. Handles the case of first frame * being frame zero. */ if (messageDetail != INFERRED_PEERSHUTDOWN && (highest_num_seen == 0 || highest_num_seen < pinfo->num)) { ldss_broadcast_t *data; /* Populate data from the broadcast */ data = wmem_new0(wmem_file_scope(), ldss_broadcast_t); data->num = pinfo->num; data->ts = pinfo->abs_ts; data->message_id = messageID; data->message_detail = messageDetail; data->port = port; data->size = size; data->offset = offset; data->compression = compression; data->file = wmem_new0(wmem_file_scope(), ldss_file_t); data->file->digest = digest; data->file->digest_type = digest_type; data->broadcaster = wmem_new0(wmem_file_scope(), ldss_broadcaster_t); copy_address(&data->broadcaster->addr, &pinfo->src); data->broadcaster->port = port; /* Dissect any future pushes/pulls */ if (port > 0) { prepare_ldss_transfer_conv(data); } /* Record that the frame was processed */ highest_num_seen = pinfo->num; } return tvb_captured_length(tvb); }
WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { /* Obtain the Value of the field */ FieldInfo fi = checkFieldInfo(L,1); switch(fi->hfinfo->type) { case FT_NONE: lua_pushnil(L); return 1; case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: case FT_FRAMENUM: lua_pushnumber(L,(lua_Number)fvalue_get_uinteger(&(fi->value))); return 1; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: lua_pushnumber(L,(lua_Number)fvalue_get_sinteger(&(fi->value))); return 1; case FT_FLOAT: case FT_DOUBLE: lua_pushnumber(L,(lua_Number)fvalue_get_floating(&(fi->value))); return 1; case FT_INT64: { Int64 num = g_malloc(sizeof(gint64)); *num = fvalue_get_integer64(&(fi->value)); pushInt64(L,num); return 1; } case FT_UINT64: { UInt64 num = g_malloc(sizeof(guint64)); *num = fvalue_get_integer64(&(fi->value)); pushUInt64(L,num); return 1; } case FT_ETHER: { Address eth = g_malloc(sizeof(address)); eth->type = AT_ETHER; eth->len = fi->length; eth->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,eth); return 1; } case FT_IPv4:{ Address ipv4 = g_malloc(sizeof(address)); ipv4->type = AT_IPv4; ipv4->len = fi->length; ipv4->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv4); return 1; } case FT_IPv6: { Address ipv6 = g_malloc(sizeof(address)); ipv6->type = AT_IPv6; ipv6->len = fi->length; ipv6->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv6); return 1; } case FT_IPXNET:{ Address ipx = g_malloc(sizeof(address)); ipx->type = AT_IPX; ipx->len = fi->length; ipx->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipx); return 1; } case FT_STRING: case FT_STRINGZ: { gchar* repr = fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL); if (repr) lua_pushstring(L,repr); else luaL_error(L,"field cannot be represented as string because it may contain invalid characters"); return 1; } case FT_BYTES: case FT_UINT_BYTES: case FT_GUID: case FT_OID: { ByteArray ba = g_byte_array_new(); g_byte_array_append(ba, ep_tvb_memdup(fi->ds_tvb,fi->start,fi->length),fi->length); pushByteArray(L,ba); return 1; } default: luaL_error(L,"FT_ not yet supported"); return 1; } }
WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { /* Obtain the Value of the field */ FieldInfo fi = checkFieldInfo(L,1); switch(fi->hfinfo->type) { case FT_BOOLEAN: lua_pushboolean(L,(int)fvalue_get_uinteger(&(fi->value))); return 1; case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: case FT_FRAMENUM: lua_pushnumber(L,(lua_Number)fvalue_get_uinteger(&(fi->value))); return 1; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: lua_pushnumber(L,(lua_Number)fvalue_get_sinteger(&(fi->value))); return 1; case FT_FLOAT: case FT_DOUBLE: lua_pushnumber(L,(lua_Number)fvalue_get_floating(&(fi->value))); return 1; case FT_INT64: { Int64 num = (Int64)g_malloc(sizeof(gint64)); *num = fvalue_get_integer64(&(fi->value)); pushInt64(L,num); return 1; } case FT_UINT64: { UInt64 num = (UInt64)g_malloc(sizeof(guint64)); *num = fvalue_get_integer64(&(fi->value)); pushUInt64(L,num); return 1; } case FT_ETHER: { Address eth = (Address)g_malloc(sizeof(address)); eth->type = AT_ETHER; eth->len = fi->length; eth->data = tvb_memdup(NULL,fi->ds_tvb,fi->start,fi->length); pushAddress(L,eth); return 1; } case FT_IPv4:{ Address ipv4 = (Address)g_malloc(sizeof(address)); ipv4->type = AT_IPv4; ipv4->len = fi->length; ipv4->data = tvb_memdup(NULL,fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv4); return 1; } case FT_IPv6: { Address ipv6 = (Address)g_malloc(sizeof(address)); ipv6->type = AT_IPv6; ipv6->len = fi->length; ipv6->data = tvb_memdup(NULL,fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv6); return 1; } case FT_IPXNET:{ Address ipx = (Address)g_malloc(sizeof(address)); ipx->type = AT_IPX; ipx->len = fi->length; ipx->data = tvb_memdup(NULL,fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipx); return 1; } case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: { NSTime nstime = (NSTime)g_malloc(sizeof(nstime_t)); *nstime = *(NSTime)fvalue_get(&(fi->value)); pushNSTime(L,nstime); return 1; } case FT_STRING: case FT_STRINGZ: { gchar* repr = fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL); if (repr) lua_pushstring(L,repr); else luaL_error(L,"field cannot be represented as string because it may contain invalid characters"); return 1; } case FT_NONE: if (fi->length == 0) { lua_pushnil(L); return 1; } /* FALLTHROUGH */ case FT_BYTES: case FT_UINT_BYTES: case FT_GUID: case FT_PROTOCOL: case FT_REL_OID: case FT_SYSTEM_ID: case FT_OID: { ByteArray ba = g_byte_array_new(); g_byte_array_append(ba, (const guint8 *)tvb_memdup(wmem_packet_scope(),fi->ds_tvb,fi->start,fi->length),fi->length); pushByteArray(L,ba); return 1; } default: luaL_error(L,"FT_ not yet supported"); return 1; } }
/*FUNCTION:------------------------------------------------------ * NAME * dissect_zbee_secure * DESCRIPTION * Dissects and decrypts secured ZigBee frames. * * Will return a valid tvbuff only if security processing was * successful. If processing fails, then this function will * handle internally and return NULL. * PARAMETERS * tvbuff_t *tvb - pointer to buffer containing raw packet. * packet_info *pinfo - pointer to packet information fields * proto_tree *tree - pointer to data tree Wireshark uses to display packet. * guint offset - pointer to the start of the auxiliary security header. * guint64 src64 - extended source address, or 0 if unknown. * RETURNS * tvbuff_t * *--------------------------------------------------------------- */ tvbuff_t * dissect_zbee_secure(tvbuff_t *tvb, packet_info *pinfo, proto_tree* tree, guint offset) { proto_tree *sec_tree; zbee_security_packet packet; guint mic_len; gint payload_len; tvbuff_t *payload_tvb; #ifdef HAVE_LIBGCRYPT proto_item *ti; proto_item *key_item; guint8 *enc_buffer; guint8 *dec_buffer; gboolean decrypted; GSList **nwk_keyring; GSList *GSList_i; key_record_t *key_rec = NULL; #endif zbee_nwk_hints_t *nwk_hints; ieee802154_hints_t *ieee_hints; ieee802154_map_rec *map_rec = NULL; static const int * sec_flags[] = { &hf_zbee_sec_key_id, &hf_zbee_sec_nonce, NULL }; /* Init */ memset(&packet, 0, sizeof(zbee_security_packet)); /* Get pointers to any useful frame data from lower layers */ nwk_hints = (zbee_nwk_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_filter_name(ZBEE_PROTOABBREV_NWK), 0); ieee_hints = (ieee802154_hints_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_filter_name(IEEE802154_PROTOABBREV_WPAN), 0); /* Create a subtree for the security information. */ sec_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_zbee_sec, NULL, "ZigBee Security Header"); /* Get and display the Security control field */ packet.control = tvb_get_guint8(tvb, offset); /* Patch the security level. */ packet.control &= ~ZBEE_SEC_CONTROL_LEVEL; packet.control |= (ZBEE_SEC_CONTROL_LEVEL & gPREF_zbee_sec_level); /* * Eww, I think I just threw up a little... ZigBee requires this field * to be patched before computing the MIC, but we don't have write-access * to the tvbuff. So we need to allocate a copy of the whole thing just * so we can fix these 3 bits. Memory allocated by tvb_memdup(wmem_packet_scope(),...) * is automatically freed before the next packet is processed. */ #ifdef HAVE_LIBGCRYPT enc_buffer = (guint8 *)tvb_memdup(wmem_packet_scope(), tvb, 0, tvb_captured_length(tvb)); /* * Override the const qualifiers and patch the security level field, we * know it is safe to overide the const qualifiers because we just * allocated this memory via tvb_memdup(wmem_packet_scope(),...). */ enc_buffer[offset] = packet.control; #endif /* HAVE_LIBGCRYPT */ packet.level = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_LEVEL); packet.key_id = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_KEY); packet.nonce = zbee_get_bit_field(packet.control, ZBEE_SEC_CONTROL_NONCE); proto_tree_add_bitmask(sec_tree, tvb, offset, hf_zbee_sec_field, ett_zbee_sec_control, sec_flags, ENC_NA); offset += 1; /* Get and display the frame counter field. */ packet.counter = tvb_get_letohl(tvb, offset); proto_tree_add_uint(sec_tree, hf_zbee_sec_counter, tvb, offset, 4, packet.counter); offset += 4; if (packet.nonce) { /* Get and display the source address of the device that secured this payload. */ packet.src64 = tvb_get_letoh64(tvb, offset); proto_tree_add_item(sec_tree, hf_zbee_sec_src64, tvb, offset, 8, ENC_LITTLE_ENDIAN); #if 1 if (!pinfo->fd->flags.visited) { switch ( packet.key_id ) { case ZBEE_SEC_KEY_LINK: if (nwk_hints && ieee_hints) { /* Map this long address with the nwk layer short address. */ nwk_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, nwk_hints->src, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->num); } break; case ZBEE_SEC_KEY_NWK: if (ieee_hints) { /* Map this long address with the ieee short address. */ ieee_hints->map_rec = ieee802154_addr_update(&zbee_nwk_map, ieee_hints->src16, ieee_hints->src_pan, packet.src64, pinfo->current_proto, pinfo->num); } break; /* We ignore the extended source addresses used to encrypt payloads with these * types of keys, because they can emerge from APS tunnels created by nodes whose * short address is not recorded in the packet. */ case ZBEE_SEC_KEY_TRANSPORT: case ZBEE_SEC_KEY_LOAD: break; } } #endif offset += 8; } else { /* Look for a source address in hints */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: /* use the ieee extended source address for NWK decryption */ if ( ieee_hints && (map_rec = ieee_hints->map_rec) ) packet.src64 = map_rec->addr64; else proto_tree_add_expert(sec_tree, pinfo, &ei_zbee_sec_extended_source_unknown, tvb, 0, 0); break; default: /* use the nwk extended source address for APS decryption */ if ( nwk_hints && (map_rec = nwk_hints->map_rec) ) packet.src64 = map_rec->addr64; else proto_tree_add_expert(sec_tree, pinfo, &ei_zbee_sec_extended_source_unknown, tvb, 0, 0); break; } } if (packet.key_id == ZBEE_SEC_KEY_NWK) { /* Get and display the key sequence number. */ packet.key_seqno = tvb_get_guint8(tvb, offset); proto_tree_add_uint(sec_tree, hf_zbee_sec_key_seqno, tvb, offset, 1, packet.key_seqno); offset += 1; } /* Determine the length of the MIC. */ switch (packet.level) { case ZBEE_SEC_ENC: case ZBEE_SEC_NONE: default: mic_len=0; break; case ZBEE_SEC_ENC_MIC32: case ZBEE_SEC_MIC32: mic_len=4; break; case ZBEE_SEC_ENC_MIC64: case ZBEE_SEC_MIC64: mic_len=8; break; case ZBEE_SEC_ENC_MIC128: case ZBEE_SEC_MIC128: mic_len=16; break; } /* switch */ /* Get and display the MIC. */ if (mic_len) { /* Display the MIC. */ proto_tree_add_item(sec_tree, hf_zbee_sec_mic, tvb, (gint)(tvb_captured_length(tvb)-mic_len), mic_len, ENC_NA); } /* Check for null payload. */ payload_len = tvb_reported_length_remaining(tvb, offset+mic_len); if (payload_len == 0) return NULL; /********************************************** * Perform Security Operations on the Frame * ********************************************** */ if ((packet.level == ZBEE_SEC_NONE) || (packet.level == ZBEE_SEC_MIC32) || (packet.level == ZBEE_SEC_MIC64) || (packet.level == ZBEE_SEC_MIC128)) { /* Payload is only integrity protected. Just return the sub-tvbuff. */ return tvb_new_subset_length(tvb, offset, payload_len); } #ifdef HAVE_LIBGCRYPT /* Have we captured all the payload? */ if (tvb_captured_length_remaining(tvb, offset+mic_len) < payload_len) { /* * No - don't try to decrypt it. * * XXX - it looks as if the decryption code is assuming we have the * MIC, which won't be the case if the packet was cut short. Is * that in fact that case, or can we still make this work with a * partially-captured packet? */ /* Add expert info. */ expert_add_info(pinfo, sec_tree, &ei_zbee_sec_encrypted_payload_sliced); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset_length(tvb, offset, payload_len); /* Dump the payload to the data dissector. */ call_data_dissector(payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* Allocate memory to decrypt the payload into. */ dec_buffer = (guint8 *)g_malloc(payload_len); decrypted = FALSE; if ( packet.src64 ) { if (pinfo->fd->flags.visited) { if ( nwk_hints ) { /* Use previously found key */ switch ( packet.key_id ) { case ZBEE_SEC_KEY_NWK: if ( (key_rec = nwk_hints->nwk) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->nwk->key); } break; default: if ( (key_rec = nwk_hints->link) ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, nwk_hints->link->key); } break; } } } /* ( !pinfo->fd->flags.visited ) */ else { /* We only search for sniffed keys in the first pass, * to save time, and because decrypting with keys * transported in future packets is cheating */ /* Lookup NWK and link key in hash for this pan. */ /* This overkill approach is a placeholder for a hash that looks up * a key ring for a link key associated with a pair of devices. */ if ( nwk_hints ) { nwk_keyring = (GSList **)g_hash_table_lookup(zbee_table_nwk_keyring, &nwk_hints->src_pan); if ( nwk_keyring ) { GSList_i = *nwk_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } /* Loop through user's password table for preconfigured keys, our last resort */ GSList_i = zbee_pc_keyring; while ( GSList_i && !decrypted ) { decrypted = zbee_sec_decrypt_payload( &packet, enc_buffer, offset, dec_buffer, payload_len, mic_len, ((key_record_t *)(GSList_i->data))->key); if (decrypted) { /* save pointer to the successful key record */ switch (packet.key_id) { case ZBEE_SEC_KEY_NWK: key_rec = nwk_hints->nwk = (key_record_t *)(GSList_i->data); break; default: key_rec = nwk_hints->link = (key_record_t *)(GSList_i->data); break; } } else { GSList_i = g_slist_next(GSList_i); } } } } /* ( ! pinfo->fd->flags.visited ) */ } /* ( packet.src64 ) */ if ( decrypted ) { if ( tree && key_rec ) { key_item = proto_tree_add_bytes(sec_tree, hf_zbee_sec_key, tvb, 0, ZBEE_SEC_CONST_KEYSIZE, key_rec->key); PROTO_ITEM_SET_GENERATED(key_item); if ( key_rec->frame_num == ZBEE_SEC_PC_KEY ) { ti = proto_tree_add_string(sec_tree, hf_zbee_sec_decryption_key, tvb, 0, 0, key_rec->label); } else { ti = proto_tree_add_uint(sec_tree, hf_zbee_sec_key_origin, tvb, 0, 0, key_rec->frame_num); } PROTO_ITEM_SET_GENERATED(ti); } /* Found a key that worked, setup the new tvbuff_t and return */ payload_tvb = tvb_new_child_real_data(tvb, dec_buffer, payload_len, payload_len); tvb_set_free_cb(payload_tvb, g_free); /* set up callback to free dec_buffer */ add_new_data_source(pinfo, payload_tvb, "Decrypted ZigBee Payload"); /* Done! */ return payload_tvb; } g_free(dec_buffer); #endif /* HAVE_LIBGCRYPT */ /* Add expert info. */ expert_add_info(pinfo, sec_tree, &ei_zbee_sec_encrypted_payload); /* Create a buffer for the undecrypted payload. */ payload_tvb = tvb_new_subset_length(tvb, offset, payload_len); /* Dump the payload to the data dissector. */ call_data_dissector(payload_tvb, pinfo, tree); /* Couldn't decrypt, so return NULL. */ return NULL; } /* dissect_zbee_secure */
guint8 *reversing_buffer; gint offset = 0; gint 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_reported_length(tvb); reversing_buffer = (guint8 *)tvb_memdup(NULL, tvb, offset, len); bitswap_buf_inplace(reversing_buffer, len); /* Make this new buffer part of the display and provide a way to dispose of it */ bit_reversed_tvb = tvb_new_child_real_data(tvb, reversing_buffer, len, len); tvb_set_free_cb(bit_reversed_tvb, g_free); 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);
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; } } } } } } }
/* WSLUA_ATTRIBUTE FieldInfo_value RO The value of this field. */ WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { /* Obtain the Value of the field. Previous to 1.11.4, this function retrieved the value for most field types, but for `ftypes.UINT_BYTES` it retrieved the `ByteArray` of the field's entire `TvbRange`. In other words, it returned a `ByteArray` that included the leading length byte(s), instead of just the *value* bytes. That was a bug, and has been changed in 1.11.4. Furthermore, it retrieved an `ftypes.GUID` as a `ByteArray`, which is also incorrect. If you wish to still get a `ByteArray` of the `TvbRange`, use `FieldInfo:get_range()` to get the `TvbRange`, and then use `Tvb:bytes()` to convert it to a `ByteArray`. */ FieldInfo fi = checkFieldInfo(L,1); switch(fi->ws_fi->hfinfo->type) { case FT_BOOLEAN: lua_pushboolean(L,(int)fvalue_get_uinteger(&(fi->ws_fi->value))); return 1; case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: case FT_FRAMENUM: lua_pushnumber(L,(lua_Number)(fvalue_get_uinteger(&(fi->ws_fi->value)))); return 1; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: lua_pushnumber(L,(lua_Number)(fvalue_get_sinteger(&(fi->ws_fi->value)))); return 1; case FT_FLOAT: case FT_DOUBLE: lua_pushnumber(L,(lua_Number)(fvalue_get_floating(&(fi->ws_fi->value)))); return 1; case FT_INT64: { pushInt64(L,(Int64)(fvalue_get_sinteger64(&(fi->ws_fi->value)))); return 1; } case FT_UINT64: { pushUInt64(L,fvalue_get_uinteger64(&(fi->ws_fi->value))); return 1; } case FT_ETHER: { Address eth = (Address)g_malloc(sizeof(address)); eth->type = AT_ETHER; eth->len = fi->ws_fi->length; eth->data = tvb_memdup(NULL,fi->ws_fi->ds_tvb,fi->ws_fi->start,fi->ws_fi->length); pushAddress(L,eth); return 1; } case FT_IPv4:{ Address ipv4 = (Address)g_malloc(sizeof(address)); ipv4->type = AT_IPv4; ipv4->len = fi->ws_fi->length; ipv4->data = tvb_memdup(NULL,fi->ws_fi->ds_tvb,fi->ws_fi->start,fi->ws_fi->length); pushAddress(L,ipv4); return 1; } case FT_IPv6: { Address ipv6 = (Address)g_malloc(sizeof(address)); ipv6->type = AT_IPv6; ipv6->len = fi->ws_fi->length; ipv6->data = tvb_memdup(NULL,fi->ws_fi->ds_tvb,fi->ws_fi->start,fi->ws_fi->length); pushAddress(L,ipv6); return 1; } case FT_FCWWN: { Address fcwwn = (Address)g_malloc(sizeof(address)); fcwwn->type = AT_FCWWN; fcwwn->len = fi->ws_fi->length; fcwwn->data = tvb_memdup(NULL,fi->ws_fi->ds_tvb,fi->ws_fi->start,fi->ws_fi->length); pushAddress(L,fcwwn); return 1; } case FT_IPXNET:{ Address ipx = (Address)g_malloc(sizeof(address)); ipx->type = AT_IPX; ipx->len = fi->ws_fi->length; ipx->data = tvb_memdup(NULL,fi->ws_fi->ds_tvb,fi->ws_fi->start,fi->ws_fi->length); pushAddress(L,ipx); return 1; } case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: { NSTime nstime = (NSTime)g_malloc(sizeof(nstime_t)); *nstime = *(NSTime)fvalue_get(&(fi->ws_fi->value)); pushNSTime(L,nstime); return 1; } case FT_STRING: case FT_STRINGZ: { gchar* repr = fvalue_to_string_repr(&fi->ws_fi->value,FTREPR_DISPLAY,BASE_NONE,NULL); if (repr) lua_pushstring(L,repr); else luaL_error(L,"field cannot be represented as string because it may contain invalid characters"); return 1; } case FT_NONE: if (fi->ws_fi->length > 0 && fi->ws_fi->rep) { /* it has a length, but calling fvalue_get() on an FT_NONE asserts, so get the label instead (it's a FT_NONE, so a label is what it basically is) */ lua_pushstring(L, fi->ws_fi->rep->representation); return 1; } return 0; case FT_BYTES: case FT_UINT_BYTES: case FT_REL_OID: case FT_SYSTEM_ID: case FT_OID: { ByteArray ba = g_byte_array_new(); g_byte_array_append(ba, (const guint8 *) fvalue_get(&fi->ws_fi->value), fvalue_length(&fi->ws_fi->value)); pushByteArray(L,ba); return 1; } case FT_PROTOCOL: { ByteArray ba = g_byte_array_new(); tvbuff_t* tvb = (tvbuff_t *) fvalue_get(&fi->ws_fi->value); g_byte_array_append(ba, (const guint8 *)tvb_memdup(wmem_packet_scope(), tvb, 0, tvb_captured_length(tvb)), tvb_captured_length(tvb)); pushByteArray(L,ba); return 1; } case FT_GUID: default: luaL_error(L,"FT_ not yet supported"); return 1; } }