Lua: add functions for more field information

Add Lua functions so a plugin can introspect field information, such
as the type of field, flags, tvb, etc. Also add a couple of Tvb and
ByteArray methods. And cleanup the TreeItem code a little.

Change-Id: I7b58ce589ace91cce14b8abccd01ceabb63e2653
Reviewed-on: https://code.wireshark.org/review/6500
Petri-Dish: Hadriel Kaplan <hadrielk@yahoo.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Hadriel Kaplan <hadrielk@yahoo.com>
Tested-by: Hadriel Kaplan <hadrielk@yahoo.com>
This commit is contained in:
Hadriel Kaplan 2015-07-08 15:20:50 -04:00
parent 7b85f62ba3
commit 281055af9c
9 changed files with 533 additions and 76 deletions

View File

@ -163,9 +163,6 @@ int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data
lua_pinfo = pinfo;
lua_tvb = tvb;
lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
PROTO_ITEM_SET_HIDDEN(lua_tree->item);
/*
* almost equivalent to Lua:
* dissectors[current_proto](tvb,pinfo,tree)
@ -185,7 +182,8 @@ int dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data
push_Tvb(L,tvb);
push_Pinfo(L,pinfo);
push_TreeItem(L,lua_tree);
lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
PROTO_ITEM_SET_HIDDEN(lua_tree->item);
if ( lua_pcall(L,3,1,0) ) {
proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0, "Lua Error: %s", lua_tostring(L,-1));
@ -278,12 +276,10 @@ gboolean heur_dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, v
return FALSE;
}
lua_tree = create_TreeItem(tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
PROTO_ITEM_SET_HIDDEN(lua_tree->item);
push_Tvb(L,tvb);
push_Pinfo(L,pinfo);
push_TreeItem(L,lua_tree);
lua_tree = push_TreeItem(L, tree, proto_tree_add_item(tree, hf_wslua_fake, tvb, 0, 0, ENC_NA));
PROTO_ITEM_SET_HIDDEN(lua_tree->item);
if ( lua_pcall(L,3,1,0) ) {
proto_tree_add_expert_format(tree, pinfo, &ei_lua_error, tvb, 0, 0,

View File

@ -53,9 +53,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* public function declarations */
REX_API int REX_OPENLIB (lua_State *L);
int Gregex_get_compile_flags (lua_State *L);
int Gregex_get_match_flags (lua_State *L);
int Gregex_get_flags (lua_State *L);
extern int Gregex_get_compile_flags (lua_State *L);
extern int Gregex_get_match_flags (lua_State *L);
extern int Gregex_get_flags (lua_State *L);
/* Special values for maxmatch in gsub. They all must be negative. */
#define GSUB_UNLIMITED -1

View File

@ -54,9 +54,6 @@ THE SOFTWARE.
#include "lauxlib.h"
#include "lrexlib.h"
extern int Gregex_get_flags (lua_State *L);
extern int Gregex_get_compile_flags (lua_State *L);
extern int Gregex_get_match_flags (lua_State *L);
extern flag_pair gregex_error_flags[];
/* These 2 settings may be redefined from the command-line or the makefile.

View File

@ -118,7 +118,7 @@ typedef struct _wslua_field_t {
int hfid;
int ett;
char* name;
char* abbr;
char* abbrev;
char* blob;
enum ftenum type;
unsigned base;
@ -128,7 +128,7 @@ typedef struct _wslua_field_t {
typedef struct _wslua_expert_field_t {
expert_field ids;
const gchar *abbr;
const gchar *abbrev;
const gchar *text;
int group;
int severity;
@ -707,9 +707,10 @@ extern void clear_outstanding_Columns(void);
extern void clear_outstanding_PrivateTable(void);
extern int get_hf_wslua_text(void);
extern TreeItem* push_TreeItem(lua_State* L, TreeItem ti);
extern TreeItem push_TreeItem(lua_State *L, proto_tree *tree, proto_item *item);
extern void clear_outstanding_TreeItem(void);
extern FieldInfo* push_FieldInfo(lua_State *L, field_info* f);
extern void clear_outstanding_FieldInfo(void);
extern void wslua_print_stack(char* s, lua_State* L);
@ -720,7 +721,7 @@ extern int wslua_cleanup(void);
extern tap_extractor_t wslua_get_tap_extractor(const gchar* name);
extern int wslua_set_tap_enums(lua_State* L);
extern int wslua_is_field_available(lua_State* L, const char* field_abbr);
extern ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr);
extern char* wslua_get_actual_filename(const char* fname);

View File

@ -45,7 +45,13 @@ WSLUA_CLASS_DEFINE(FieldInfo,FAIL_ON_NULL_OR_EXPIRED("FieldInfo"),NOP);
static GPtrArray* outstanding_FieldInfo = NULL;
#define PUSH_FIELDINFO(L,fi) {g_ptr_array_add(outstanding_FieldInfo,fi);pushFieldInfo(L,fi);}
FieldInfo* push_FieldInfo(lua_State* L, field_info* f) {
FieldInfo fi = (FieldInfo) g_malloc(sizeof(struct _wslua_field_info));
fi->ws_fi = f;
fi->expired = FALSE;
g_ptr_array_add(outstanding_FieldInfo,fi);
return pushFieldInfo(L,fi);
}
CLEAR_OUTSTANDING(FieldInfo,expired,TRUE)
@ -210,7 +216,7 @@ WSLUA_METAMETHOD FieldInfo__call(lua_State* L) {
}
}
/* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field */
/* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field. */
WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) {
/* The string representation of the field. */
FieldInfo fi = checkFieldInfo(L,1);
@ -244,7 +250,7 @@ WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) {
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_display RO The string display of this field as seen in GUI */
/* WSLUA_ATTRIBUTE FieldInfo_display RO The string display of this field as seen in GUI. */
static int FieldInfo_get_display(lua_State* L) {
/* The display string of this field as seen in GUI. */
FieldInfo fi = checkFieldInfo(L,1);
@ -272,7 +278,43 @@ static int FieldInfo_get_display(lua_State* L) {
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_range RO The `TvbRange` covering this field */
/* WSLUA_ATTRIBUTE FieldInfo_type RO The internal field type, a number which
matches one of the `ftype` values in `init.lua`.
@since 1.99.9
*/
static int FieldInfo_get_type(lua_State* L) {
FieldInfo fi = checkFieldInfo(L,1);
if (fi->ws_fi->hfinfo) {
lua_pushnumber(L, fi->ws_fi->hfinfo->type);
}
else {
lua_pushnil(L);
}
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_source RO The source `Tvb` object the `FieldInfo` is derived
from, or nil if there is none.
@since 1.99.9
*/
static int FieldInfo_get_source(lua_State* L) {
FieldInfo fi = checkFieldInfo(L,1);
if (fi->ws_fi->ds_tvb) {
push_Tvb(L, fi->ws_fi->ds_tvb);
}
else {
lua_pushnil(L);
}
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_range RO The `TvbRange` covering this field. */
static int FieldInfo_get_range(lua_State* L) {
/* The `TvbRange` covering this field. */
FieldInfo fi = checkFieldInfo(L,1);
@ -284,7 +326,7 @@ static int FieldInfo_get_range(lua_State* L) {
return 0;
}
/* WSLUA_ATTRIBUTE FieldInfo_generated RO Whether this field was marked as generated (boolean) */
/* WSLUA_ATTRIBUTE FieldInfo_generated RO Whether this field was marked as generated (boolean). */
static int FieldInfo_get_generated(lua_State* L) {
/* Whether this field was marked as generated. */
FieldInfo fi = checkFieldInfo(L,1);
@ -293,7 +335,54 @@ static int FieldInfo_get_generated(lua_State* L) {
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_name RO The name of this field */
/* WSLUA_ATTRIBUTE FieldInfo_hidden RO Whether this field was marked as hidden (boolean).
@since 1.99.9
*/
static int FieldInfo_get_hidden(lua_State* L) {
FieldInfo fi = checkFieldInfo(L,1);
lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_HIDDEN));
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_is_url RO Whether this field was marked as being a URL (boolean).
@since 1.99.9
*/
static int FieldInfo_get_is_url(lua_State* L) {
FieldInfo fi = checkFieldInfo(L,1);
lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_URL));
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_little_endian RO Whether this field is little-endian encoded (boolean).
@since 1.99.9
*/
static int FieldInfo_get_little_endian(lua_State* L) {
FieldInfo fi = checkFieldInfo(L,1);
lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_LITTLE_ENDIAN));
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_big_endian RO Whether this field is big-endian encoded (boolean).
@since 1.99.9
*/
static int FieldInfo_get_big_endian(lua_State* L) {
FieldInfo fi = checkFieldInfo(L,1);
lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_BIG_ENDIAN));
return 1;
}
/* WSLUA_ATTRIBUTE FieldInfo_name RO The filter name of this field.
@since 1.99.9
*/
static int FieldInfo_get_name(lua_State* L) {
/* The filter name of this field. */
FieldInfo fi = checkFieldInfo(L,1);
@ -374,8 +463,14 @@ static int FieldInfo__gc(lua_State* L _U_) {
WSLUA_ATTRIBUTES FieldInfo_attributes[] = {
WSLUA_ATTRIBUTE_ROREG(FieldInfo,range),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,generated),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,hidden),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,is_url),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,little_endian),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,big_endian),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,name),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,display),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,type),
WSLUA_ATTRIBUTE_ROREG(FieldInfo,source),
{ "label", FieldInfo__tostring, NULL },
{ "value", FieldInfo__call, NULL },
{ "tvb", FieldInfo_get_range, NULL },
@ -422,11 +517,7 @@ WSLUA_FUNCTION wslua_all_field_infos(lua_State* L) {
if (found) {
for (i=0; i<found->len; i++) {
FieldInfo fi = (FieldInfo)g_malloc(sizeof(struct _wslua_field_info));
fi->ws_fi = (field_info *)g_ptr_array_index(found,i);
fi->expired = FALSE;
PUSH_FIELDINFO(L,fi);
push_FieldInfo(L, (field_info *)g_ptr_array_index(found,i));
items_found++;
}
@ -583,6 +674,74 @@ WSLUA_CONSTRUCTOR Field_list(lua_State *L) {
WSLUA_RETURN(1); /* The array table of field filter names */
}
/* the following is used in Field_get_xxx functions later */
#define GET_HFINFO_MEMBER(luafunc, member) \
if (wanted_fields) { \
/* before registration, so it's a gchar** of the abbrev */ \
const gchar* name = (const gchar*) *fi; \
if (name) { \
hfinfo = proto_registrar_get_byname(name); \
if (!hfinfo) { \
/* could be a Lua-created field */ \
ProtoField pf = wslua_is_field_available(L, name); \
if (pf) { \
luafunc(L, pf->member); \
return 1; \
} \
} \
} else { \
luaL_error(L, "Field." #member ": unknown field"); \
return 0; \
} \
} else { \
hfinfo = *fi; \
} \
\
if (hfinfo) { \
luafunc(L,hfinfo->member); \
} else \
lua_pushnil(L)
/* WSLUA_ATTRIBUTE Field_name RO The filter name of this field, or nil.
@since 1.99.9
*/
static int Field_get_name(lua_State* L) {
Field fi = checkField(L,1);
header_field_info* hfinfo = NULL;
GET_HFINFO_MEMBER(lua_pushstring, abbrev);
return 1;
}
/* WSLUA_ATTRIBUTE Field_display RO The full display name of this field, or nil.
@since 1.99.9
*/
static int Field_get_display(lua_State* L) {
Field fi = checkField(L,1);
header_field_info* hfinfo = NULL;
GET_HFINFO_MEMBER(lua_pushstring, name);
return 1;
}
/* WSLUA_ATTRIBUTE Field_type RO The `ftype` of this field, or nil.
@since 1.99.9
*/
static int Field_get_type(lua_State* L) {
Field fi = checkField(L,1);
header_field_info* hfinfo = NULL;
GET_HFINFO_MEMBER(lua_pushnumber, type);
return 1;
}
WSLUA_METAMETHOD Field__call (lua_State* L) {
/* Obtain all values (see `FieldInfo`) for this field. */
Field f = checkField(L,1);
@ -604,11 +763,7 @@ WSLUA_METAMETHOD Field__call (lua_State* L) {
guint i;
if (found) {
for (i=0; i<found->len; i++) {
FieldInfo fi = (FieldInfo)g_malloc(sizeof(struct _wslua_field_info));
fi->ws_fi = (field_info *)g_ptr_array_index(found,i);
fi->expired = FALSE;
PUSH_FIELDINFO(L,fi);
push_FieldInfo(L, (field_info *) g_ptr_array_index(found,i));
items_found++;
}
}
@ -619,7 +774,7 @@ WSLUA_METAMETHOD Field__call (lua_State* L) {
}
WSLUA_METAMETHOD Field__tostring(lua_State* L) {
/* Obtain a string with the field name. */
/* Obtain a string with the field filter name. */
Field f = checkField(L,1);
if (wanted_fields) {
@ -636,6 +791,13 @@ static int Field__gc(lua_State* L _U_) {
return 0;
}
WSLUA_ATTRIBUTES Field_attributes[] = {
WSLUA_ATTRIBUTE_ROREG(Field,name),
WSLUA_ATTRIBUTE_ROREG(Field,display),
WSLUA_ATTRIBUTE_ROREG(Field,type),
{ NULL, NULL, NULL }
};
WSLUA_METHODS Field_methods[] = {
WSLUA_CLASS_FNREG(Field,new),
WSLUA_CLASS_FNREG(Field,list),
@ -653,6 +815,7 @@ int Field_register(lua_State* L) {
wanted_fields = g_ptr_array_new();
WSLUA_REGISTER_CLASS(Field);
WSLUA_REGISTER_ATTRIBUTES(Field);
outstanding_FieldInfo = g_ptr_array_new();
return 0;

View File

@ -876,7 +876,7 @@ WSLUA_CONSTRUCTOR ProtoField_new(lua_State* L) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
f->abbr = g_strdup(abbr);
f->abbrev = g_strdup(abbr);
f->type = type;
f->base = base;
if (tfs) {
@ -940,7 +940,7 @@ static int ProtoField_integer(lua_State* L, enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
f->abbr = g_strdup(abbr);
f->abbrev = g_strdup(abbr);
f->type = type;
f->base = base;
if (vs64) {
@ -1104,7 +1104,7 @@ static int ProtoField_boolean(lua_State* L, enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
f->abbr = g_strdup(abbr);
f->abbrev = g_strdup(abbr);
f->type = type;
f->vs = TFS(tfs);
f->base = base;
@ -1157,7 +1157,7 @@ static int ProtoField_time(lua_State* L,enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
f->abbr = g_strdup(abbr);
f->abbrev = g_strdup(abbr);
f->type = type;
f->vs = NULL;
f->base = base;
@ -1201,7 +1201,7 @@ static int ProtoField_other(lua_State* L,enum ftenum type) {
f->hfid = -2;
f->ett = -1;
f->name = g_strdup(name);
f->abbr = g_strdup(abbr);
f->abbrev = g_strdup(abbr);
f->type = type;
f->vs = NULL;
f->base = BASE_NONE;
@ -1330,7 +1330,7 @@ WSLUA_METAMETHOD ProtoField__tostring(lua_State* L) {
/* Returns a string with info about a protofield (for debugging purposes). */
ProtoField f = checkProtoField(L,1);
gchar* s = g_strdup_printf("ProtoField(%i): %s %s %s %s %p %.8x %s",
f->hfid,f->name,f->abbr,
f->hfid,f->name,f->abbrev,
ftenum_to_string(f->type),
base_to_string(f->base),
f->vs,f->mask,f->blob);
@ -1355,7 +1355,7 @@ static int ProtoField__gc(lua_State* L) {
/* g_assert() ?? */
} else if (f->hfid == -2) {
g_free(f->name);
g_free(f->abbr);
g_free(f->abbrev);
g_free(f->blob);
g_free(f);
}
@ -1443,7 +1443,7 @@ WSLUA_CONSTRUCTOR ProtoExpert_new(lua_State* L) {
pe->ids.ei = EI_INIT_EI;
pe->ids.hf = EI_INIT_HF;
pe->abbr = g_strdup(abbr);
pe->abbrev = g_strdup(abbr);
pe->text = g_strdup(text);
pe->group = group;
pe->severity = severity;
@ -1464,7 +1464,7 @@ WSLUA_METAMETHOD ProtoExpert__tostring(lua_State* L) {
lua_pushstring(L,"ProtoExpert pointer is NULL!");
} else {
lua_pushfstring(L, "ProtoExpert: ei=%d, hf=%d, abbr=%s, text=%s, group=%d, severity=%d",
pe->ids.ei, pe->ids.hf, pe->abbr, pe->text, pe->group, pe->severity);
pe->ids.ei, pe->ids.hf, pe->abbrev, pe->text, pe->group, pe->severity);
}
return 1;
}
@ -1953,7 +1953,7 @@ int Proto_register(lua_State* L) {
* Query field abbr that is defined and bound to a Proto in lua.
* They are not registered until the end of the initialization.
*/
int wslua_is_field_available(lua_State* L, const char* field_abbr) {
ProtoField wslua_is_field_available(lua_State* L, const char* field_abbr) {
lua_rawgeti(L, LUA_REGISTRYINDEX, protocols_table_ref);
lua_pushnil(L);
while (lua_next(L, -2)) {
@ -1965,10 +1965,10 @@ int wslua_is_field_available(lua_State* L, const char* field_abbr) {
lua_pushnil(L);
while (lua_next(L, -2)) {
ProtoField f = checkProtoField(L, -1);
if (strcmp(field_abbr, f->abbr) == 0) {
if (strcmp(field_abbr, f->abbrev) == 0) {
/* found! */
lua_pop(L, 6);
return 1;
return f;
}
lua_pop(L, 1); /* table value */
}
@ -1976,7 +1976,7 @@ int wslua_is_field_available(lua_State* L, const char* field_abbr) {
}
lua_pop(L, 1); /* protocols_table_ref */
return 0;
return NULL;
}
int Proto_commit(lua_State* L) {
@ -2010,7 +2010,7 @@ int Proto_commit(lua_State* L) {
hfri.p_id = &(f->hfid);
hfri.hfinfo.name = f->name;
hfri.hfinfo.abbrev = f->abbr;
hfri.hfinfo.abbrev = f->abbrev;
hfri.hfinfo.type = f->type;
hfri.hfinfo.display = f->base;
hfri.hfinfo.strings = VALS(f->vs);
@ -2043,7 +2043,7 @@ int Proto_commit(lua_State* L) {
ei_register_info eiri = { NULL, { NULL, 0, 0, NULL, EXPFILL } };
eiri.ids = &(e->ids);
eiri.eiinfo.name = e->abbr;
eiri.eiinfo.name = e->abbrev;
eiri.eiinfo.group = e->group;
eiri.eiinfo.severity = e->severity;
eiri.eiinfo.summary = e->text;
@ -2143,12 +2143,11 @@ wslua_dissect_tcp_dissector(tvbuff_t *tvb, packet_info *pinfo,
lua_rawgeti(L, LUA_REGISTRYINDEX, fs->dissect_ref);
if (lua_isfunction(L,1)) {
/* XXX: not sure if it's kosher to just use the tree as the item */
TreeItem ti = create_TreeItem(tree, (proto_item*)tree);
push_Tvb(L,tvb);
push_Pinfo(L,pinfo);
push_TreeItem(L,ti);
/* XXX: not sure if it's kosher to just use the tree as the item */
push_TreeItem(L, tree, (proto_item*)tree);
if ( lua_pcall(L,3,1,0) ) {
luaL_error(L, "Lua Error dissect_tcp_pdus dissect_func: %s", lua_tostring(L,-1));

View File

@ -37,13 +37,21 @@ static gint wslua_ett = -1;
static GPtrArray* outstanding_TreeItem = NULL;
#define PUSH_TREEITEM(L,i) {g_ptr_array_add(outstanding_TreeItem,i);pushTreeItem(L,i);}
TreeItem* push_TreeItem(lua_State*L, TreeItem t) {
g_ptr_array_add(outstanding_TreeItem,t);
return pushTreeItem(L,t);
/* pushing a TreeItem with a NULL item or subtree is completely valid for this function */
TreeItem push_TreeItem(lua_State *L, proto_tree *tree, proto_item *item) {
TreeItem ti = (struct _wslua_treeitem *)g_malloc(sizeof(struct _wslua_treeitem));
ti->tree = tree;
ti->item = item;
ti->expired = FALSE;
g_ptr_array_add(outstanding_TreeItem, ti);
return *(pushTreeItem(L,ti));
}
/* creates the TreeItem but does NOT push it into Lua */
TreeItem create_TreeItem(proto_tree* tree, proto_item* item)
{
TreeItem tree_item = (TreeItem)g_malloc(sizeof(struct _wslua_treeitem));
@ -57,8 +65,25 @@ TreeItem create_TreeItem(proto_tree* tree, proto_item* item)
CLEAR_OUTSTANDING(TreeItem, expired, TRUE)
WSLUA_CLASS_DEFINE(TreeItem,FAIL_ON_NULL_OR_EXPIRED("TreeItem"),NOP);
/* ++TreeItem++s represent information in the packet-details pane.
A root +TreeItem+ is passed to dissectors as the third argument. */
/* ++TreeItem++s represent information in the packet-details pane of
Wireshark, and the packet details view of Tshark. A `TreeItem` represents
a node in the tree, which might also be a subtree and have a list of
children. The children of a subtree have zero or more siblings: other children
of the same `TreeItem` subtree.
During dissection, heuristic-dissection, and post-dissection, a root
+TreeItem+ is passed to dissectors as the third argument of the function
callback (e.g., `myproto.dissector(tvbuf,pktinfo,root)`).
In some cases the tree is not truly added to, in order to improve performance.
For example for packets not currently displayed/selected in Wireshark's visible
window pane, or if Tshark isn't invoked with the `-V` switch. However the
"add" type `TreeItem` functions can still be called, and still return `TreeItem`
objects - but the info isn't really added to the tree. Therefore you do not
typically need to worry about whether there's a real tree or not. If, for some
reason, you need to know it, you can use the `tree.visible` attribute getter
to retrieve the state.
*/
/* the following is used by TreeItem_add_packet_field() - this can THROW errors */
static proto_item *
@ -264,9 +289,7 @@ WSLUA_METHOD TreeItem_add_packet_field(lua_State *L) {
nargs--;
}
tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
PUSH_TREEITEM(L,tree_item);
tree_item = push_TreeItem(L, proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
/* move the tree object before the field value */
lua_insert(L, 1);
@ -315,7 +338,11 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) {
}
if (hfid > 0 ) {
/* hfid is > 0 when the first arg was a ProtoField or Proto */
if (lua_gettop(L)) {
/* if we got here, the (L,1) index is the value to add, instead of decoding from the Tvb */
switch(type) {
case FT_PROTOCOL:
item = proto_tree_add_item(tree_item->tree,hfid,tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len,ENC_NA);
@ -388,17 +415,20 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) {
lua_remove(L,1);
} else {
/* the Lua stack is empty - no value was given - so decode the value from the tvb */
if (type == FT_STRINGZ) tvbr->len = tvb_strsize (tvbr->tvb->ws_tvb, tvbr->offset);
item = proto_tree_add_item(tree_item->tree, hfid, tvbr->tvb->ws_tvb, tvbr->offset, tvbr->len, little_endian ? ENC_LITTLE_ENDIAN : ENC_BIG_ENDIAN);
}
if ( lua_gettop(L) ) {
/* if there was a value, it was removed earlier, so what's left is the display string to set */
const gchar* s = lua_tostring(L,1);
if (s) proto_item_set_text(item,"%s",s);
lua_remove(L,1);
}
} else {
/* no ProtoField or Proto was given */
if (lua_gettop(L)) {
const gchar* s = lua_tostring(L,1);
const int hf = get_hf_wslua_text();
@ -416,14 +446,13 @@ static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) {
}
while(lua_gettop(L)) {
/* keep appending more text */
const gchar* s = lua_tostring(L,1);
if (s) proto_item_append_text(item, " %s", s);
lua_remove(L,1);
}
tree_item = create_TreeItem(proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
PUSH_TREEITEM(L,tree_item);
tree_item = push_TreeItem(L, proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett), item);
return 1;
}
@ -467,6 +496,38 @@ WSLUA_METHOD TreeItem_add_le(lua_State *L) {
WSLUA_RETURN(TreeItem_add_item_any(L,TRUE)); /* The new child TreeItem. */
}
/* WSLUA_ATTRIBUTE TreeItem_text RW Set/get the `TreeItem`'s display string (string).
For the getter, if the TreeItem has no display string, then nil is returned.
@since 1.99.3
*/
static int TreeItem_get_text(lua_State* L) {
TreeItem ti = checkTreeItem(L,1);
gchar label_str[ITEM_LABEL_LENGTH+1];
gchar *label_ptr;
field_info *fi = PITEM_FINFO(ti->item);
if(fi) {
if (!fi->rep) {
label_ptr = label_str;
proto_item_fill_label(fi, label_str);
} else
label_ptr = fi->rep->representation;
if (label_ptr) {
lua_pushstring(L, label_ptr);
} else {
lua_pushnil(L);
}
} else {
lua_pushnil(L);
}
return 1;
}
/* the following is used as both a method and attribute */
WSLUA_METHOD TreeItem_set_text(lua_State *L) {
/* Sets the text of the label.
@ -636,14 +697,55 @@ WSLUA_METHOD TreeItem_add_tvb_expert_info(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
/* WSLUA_ATTRIBUTE TreeItem_visible RO Get the `TreeItem`'s subtree visibility status (boolean).
@since 1.99.9
*/
static int TreeItem_get_visible(lua_State* L) {
TreeItem ti = checkTreeItem(L,1);
if (ti->tree) {
lua_pushboolean(L, PTREE_DATA(ti->tree)->visible);
}
else {
lua_pushboolean(L, FALSE);
}
return 1;
}
/* WSLUA_ATTRIBUTE TreeItem_generated RW Set/get the `TreeItem`'s generated state (boolean).
@since 1.99.9
*/
static int TreeItem_get_generated(lua_State* L) {
TreeItem ti = checkTreeItem(L,1);
lua_pushboolean(L, PROTO_ITEM_IS_GENERATED(ti->item));
return 1;
}
/* the following is used as both a method and attribute. As a method it defaults
to setting the value, because that's what it used to do before. */
WSLUA_METHOD TreeItem_set_generated(lua_State *L) {
/* Marks the `TreeItem` as a generated field (with data inferred but not contained in the packet).
This used to return nothing, but as of 1.11.3 it returns the same tree item to allow chained calls.
*/
#define WSLUA_OPTARG_TreeItem_set_generated_BOOL 2 /* A Lua boolean, which if `true` sets the `TreeItem`
generated flag, else clears it (default=true) */
TreeItem ti = checkTreeItem(L,1);
gboolean set = wslua_optbool(L, WSLUA_OPTARG_TreeItem_set_generated_BOOL, TRUE);
PROTO_ITEM_SET_GENERATED(ti->item);
if (set) {
PROTO_ITEM_SET_GENERATED(ti->item);
} else {
if (ti->item)
FI_RESET_FLAG(PITEM_FINFO(ti->item), FI_GENERATED);
}
/* copy the TreeItem userdata so we give it back */
lua_pushvalue(L, 1);
@ -651,12 +753,35 @@ WSLUA_METHOD TreeItem_set_generated(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
/* WSLUA_ATTRIBUTE TreeItem_hidden RW Set/get `TreeItem`'s hidden state (boolean).
WSLUA_METHOD TreeItem_set_hidden(lua_State *L) {
/* This function should not be used, and is provided for backwards-compatibility only. */
@since 1.99.9
*/
static int TreeItem_get_hidden(lua_State* L) {
TreeItem ti = checkTreeItem(L,1);
PROTO_ITEM_SET_HIDDEN(ti->item);
lua_pushboolean(L, PROTO_ITEM_IS_HIDDEN(ti->item));
return 1;
}
/* the following is used as both a method and attribute. As a method it defaults
to setting the value, because that's what it used to do before. */
WSLUA_METHOD TreeItem_set_hidden(lua_State *L) {
/* Marks the `TreeItem` as a hidden field (neither displayed nor used in filters).
This used to return nothing, but as of 1.11.3 it returns the same tree item to allow chained calls.
*/
#define WSLUA_OPTARG_TreeItem_set_hidden_BOOL 2 /* A Lua boolean, which if `true` sets the `TreeItem`
hidden flag, else clears it (default=true) */
TreeItem ti = checkTreeItem(L,1);
gboolean set = wslua_optbool(L, WSLUA_OPTARG_TreeItem_set_hidden_BOOL, TRUE);
if (set) {
PROTO_ITEM_SET_HIDDEN(ti->item);
} else {
PROTO_ITEM_SET_VISIBLE(ti->item);
}
/* copy the TreeItem userdata so we give it back */
lua_pushvalue(L, 1);
@ -664,6 +789,21 @@ WSLUA_METHOD TreeItem_set_hidden(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
/* WSLUA_ATTRIBUTE TreeItem_len RW Set/get `TreeItem`'s length inside tvb, after it has already been created.
@since 1.99.9
*/
static int TreeItem_get_len(lua_State* L) {
TreeItem ti = checkTreeItem(L,1);
int len = 0;
len = proto_item_get_len(ti->item);
lua_pushinteger(L, len > 0 ? len : 0);
return 1;
}
WSLUA_METHOD TreeItem_set_len(lua_State *L) {
/* Set `TreeItem`'s length inside tvb, after it has already been created.
@ -681,6 +821,28 @@ WSLUA_METHOD TreeItem_set_len(lua_State *L) {
WSLUA_RETURN(1); /* The same TreeItem. */
}
WSLUA_METAMETHOD TreeItem__tostring(lua_State* L) {
/* Returns string debug information about the `TreeItem`.
@since 1.99.9
*/
TreeItem ti = toTreeItem(L,1);
if (ti) {
lua_pushfstring(L,
"TreeItem: expired=%s, has item=%s, has subtree=%s, they are %sthe same",
ti->expired ? "true" : "false",
ti->item ? "true" : "false",
ti->tree ? "true" : "false",
(ti->tree == ti->item) ? "" : "not ");
}
else {
lua_pushstring(L, "No TreeItem object!");
}
return 1;
}
/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
static int TreeItem__gc(lua_State* L) {
TreeItem ti = toTreeItem(L,1);
@ -692,6 +854,15 @@ static int TreeItem__gc(lua_State* L) {
return 0;
}
WSLUA_ATTRIBUTES TreeItem_attributes[] = {
WSLUA_ATTRIBUTE_RWREG(TreeItem,generated),
WSLUA_ATTRIBUTE_RWREG(TreeItem,hidden),
WSLUA_ATTRIBUTE_RWREG(TreeItem,len),
WSLUA_ATTRIBUTE_RWREG(TreeItem,text),
WSLUA_ATTRIBUTE_ROREG(TreeItem,visible),
{ NULL, NULL, NULL }
};
WSLUA_METHODS TreeItem_methods[] = {
WSLUA_CLASS_FNREG(TreeItem,add_packet_field),
WSLUA_CLASS_FNREG(TreeItem,add),
@ -709,12 +880,14 @@ WSLUA_METHODS TreeItem_methods[] = {
};
WSLUA_META TreeItem_meta[] = {
WSLUA_CLASS_MTREG(TreeItem,tostring),
{ NULL, NULL }
};
int TreeItem_register(lua_State *L) {
gint* etts[] = { &wslua_ett };
WSLUA_REGISTER_CLASS(TreeItem);
WSLUA_REGISTER_ATTRIBUTES(TreeItem);
outstanding_TreeItem = g_ptr_array_new();
proto_register_subtree_array(etts,1);
return 0;

View File

@ -563,6 +563,42 @@ WSLUA_METHOD Tvb_reported_length_remaining(lua_State* L) {
WSLUA_RETURN(1); /* The captured length of the `Tvb`. */
}
WSLUA_METHOD Tvb_bytes(lua_State* L) {
/* Obtain a `ByteArray` from a `Tvb`.
@since 1.99.9
*/
#define WSLUA_OPTARG_Tvb_bytes_OFFSET 2 /* The offset (in octets) from the beginning of the `Tvb`. Defaults to 0. */
#define WSLUA_OPTARG_Tvb_bytes_LENGTH 3 /* The length (in octets) of the range. Defaults to until the end of the `Tvb`. */
Tvb tvb = checkTvb(L,1);
GByteArray* ba;
int offset = luaL_optint(L, WSLUA_OPTARG_Tvb_bytes_OFFSET, 0);
int len = luaL_optint(L,WSLUA_OPTARG_Tvb_bytes_LENGTH,-1);
if (tvb->expired) {
luaL_error(L,"expired tvb");
return 0;
}
ba = g_byte_array_new();
if (len < 0) {
len = tvb_captured_length_remaining(tvb->ws_tvb,offset);
if (len < 0) {
luaL_error(L,"out of bounds");
return 0;
}
} else if ( (guint)(len + offset) > tvb_captured_length(tvb->ws_tvb)) {
luaL_error(L,"Range is out of bounds");
return 0;
}
g_byte_array_append(ba, tvb_get_ptr(tvb->ws_tvb, offset, len), len);
pushByteArray(L,ba);
WSLUA_RETURN(1); /* The `ByteArray` object or nil. */
}
WSLUA_METHOD Tvb_offset(lua_State* L) {
/* Returns the raw offset (from the beginning of the source `Tvb`) of a sub `Tvb`. */
Tvb tvb = checkTvb(L,1);
@ -674,7 +710,40 @@ WSLUA_METHOD Tvb_raw(lua_State* L) {
WSLUA_RETURN(1); /* A Lua string of the binary bytes in the `Tvb`. */
}
WSLUA_METAMETHOD Tvb__eq(lua_State* L) {
/* Checks whether the two `Tvb` contents are equal.
@since 1.99.9
*/
Tvb tvb_l = checkTvb(L,1);
Tvb tvb_r = checkTvb(L,2);
int len_l = tvb_captured_length(tvb_l->ws_tvb);
int len_r = tvb_captured_length(tvb_r->ws_tvb);
/* it is not an error if their ds_tvb are different... they're just not equal */
if (len_l == len_r)
{
const gchar* lp = tvb_get_ptr(tvb_l->ws_tvb, 0, len_l);
const gchar* rp = tvb_get_ptr(tvb_r->ws_tvb, 0, len_r);
int i = 0;
for (; i < len_l; ++i) {
if (lp[i] != rp[i]) {
lua_pushboolean(L,0);
return 1;
}
}
lua_pushboolean(L,1);
} else {
lua_pushboolean(L,0);
}
return 1;
}
WSLUA_METHODS Tvb_methods[] = {
WSLUA_CLASS_FNREG(Tvb,bytes),
WSLUA_CLASS_FNREG(Tvb,range),
WSLUA_CLASS_FNREG(Tvb,len),
WSLUA_CLASS_FNREG(Tvb,offset),
@ -685,6 +754,7 @@ WSLUA_METHODS Tvb_methods[] = {
};
WSLUA_META Tvb_meta[] = {
WSLUA_CLASS_MTREG(Tvb,eq),
WSLUA_CLASS_MTREG(Tvb,tostring),
{"__call", Tvb_range},
{ NULL, NULL }
@ -722,13 +792,6 @@ WSLUA_METHOD TvbRange_uint(lua_State* L) {
case 4:
lua_pushnumber(L,tvb_get_ntohl(tvbr->tvb->ws_tvb,tvbr->offset));
WSLUA_RETURN(1); /* The unsigned integer value. */
/*
* XXX:
* lua uses double so we have 52 bits to play with
* we are missing 5 and 6 byte integers within lua's range
* and 64 bit integers are not supported (there's a lib for
* lua that does).
*/
default:
luaL_error(L,"TvbRange:uint() does not handle %d byte integers",tvbr->len);
return 0;
@ -1576,6 +1639,36 @@ WSLUA_METHOD TvbRange_raw(lua_State* L) {
WSLUA_RETURN(1); /* A Lua string of the binary bytes in the `TvbRange`. */
}
WSLUA_METAMETHOD TvbRange__eq(lua_State* L) {
/* Checks whether the two `TvbRange` contents are equal.
@since 1.99.9
*/
TvbRange tvb_l = checkTvbRange(L,1);
TvbRange tvb_r = checkTvbRange(L,2);
/* it is not an error if their ds_tvb are different... they're just not equal */
if (tvb_l->len == tvb_r->len &&
tvb_l->len <= tvb_captured_length_remaining(tvb_l->tvb->ws_tvb, tvb_l->offset) &&
tvb_r->len <= tvb_captured_length_remaining(tvb_r->tvb->ws_tvb, tvb_r->offset))
{
const gchar* lp = tvb_get_ptr(tvb_l->tvb->ws_tvb, tvb_l->offset, tvb_l->len);
const gchar* rp = tvb_get_ptr(tvb_r->tvb->ws_tvb, tvb_r->offset, tvb_r->len);
int i = 0;
for (; i < tvb_r->len; ++i) {
if (lp[i] != rp[i]) {
lua_pushboolean(L,0);
return 1;
}
}
lua_pushboolean(L,1);
} else {
lua_pushboolean(L,0);
}
return 1;
}
WSLUA_METAMETHOD TvbRange__tostring(lua_State* L) {
/* Converts the `TvbRange` into a string. Since the string gets truncated,
@ -1635,6 +1728,7 @@ WSLUA_METHODS TvbRange_methods[] = {
WSLUA_META TvbRange_meta[] = {
WSLUA_CLASS_MTREG(TvbRange,tostring),
WSLUA_CLASS_MTREG(wslua,concat),
WSLUA_CLASS_MTREG(TvbRange,eq),
{"__call", TvbRange_range},
{ NULL, NULL }
};

View File

@ -72,6 +72,18 @@ local f_bootp_opt = Field.new("bootp.option.type")
test("Field__tostring-1", tostring(f_frame_proto) == "frame.protocols")
test("Field.name-1", f_frame_proto.name == "frame.protocols")
test("Field.name-2", f_eth_src.name == "eth.src")
test("Field.display-1", f_frame_proto.display == "Protocols in frame")
test("Field.display-2", f_eth_src.display == "Source")
test("Field.type-1", f_frame_proto.type == ftypes.STRING)
test("Field.type-2", f_eth_src.type == ftypes.ETHER)
test("Field.type-3", f_ip_src.type == ftypes.IPv4)
test("Field.type-4", f_udp_srcport.type == ftypes.UINT16)
test("Field.type-5", f_bootp_opt.type == ftypes.UINT8)
-- make sure can't create a FieldInfo outside tap
test("Field__call-1",not pcall(makeFieldInfo,f_eth_src))
@ -90,11 +102,33 @@ function tap.packet(pinfo,tvb)
test("Field__call-2",pcall(makeFieldInfo,f_eth_src))
test("Field.name-3", f_frame_proto.name == "frame.protocols")
test("Field.name-4", f_eth_src.name == "eth.src")
test("Field.display-3", f_frame_proto.display == "Protocols in frame")
test("Field.display-4", f_eth_src.display == "Source")
test("Field.type-6", f_frame_proto.type == ftypes.STRING)
test("Field.type-7", f_eth_src.type == ftypes.ETHER)
test("Field.type-8", f_ip_src.type == ftypes.IPv4)
test("Field.type-9", f_udp_srcport.type == ftypes.UINT16)
test("Field.type-10", f_bootp_opt.type == ftypes.UINT8)
testing("FieldInfo")
local finfo_udp_srcport = f_udp_srcport()
test("FieldInfo.name-1", finfo_udp_srcport.name == "udp.srcport")
test("FieldInfo.type-1", finfo_udp_srcport.type == ftypes.UINT16)
test("FieldInfo.little_endian-1", finfo_udp_srcport.little_endian == false)
-- the following should be true, but UDP doesn't set it right?
-- test("FieldInfo.big_endian-1", finfo_udp_srcport.big_endian == true)
test("FieldInfo.is_url-1", finfo_udp_srcport.is_url == false)
test("FieldInfo.offset-1", finfo_udp_srcport.offset == 34)
test("FieldInfo.source-1", finfo_udp_srcport.source == tvb)
-- check ether addr
local fi_eth_src = f_eth_src()
test("FieldInfo.type-2", fi_eth_src.type == ftypes.ETHER)
test("FieldInfo.range-0",pcall(getFieldInfo,fi_eth_src,"range"))
local eth_macs = { f_eth_mac() }
local eth_src1 = tostring(f_eth_src().range)