diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /epan/wslua/wslua_field.c | |
parent | Initial commit. (diff) | |
download | wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip |
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'epan/wslua/wslua_field.c')
-rw-r--r-- | epan/wslua/wslua_field.c | 832 |
1 files changed, 832 insertions, 0 deletions
diff --git a/epan/wslua/wslua_field.c b/epan/wslua/wslua_field.c new file mode 100644 index 00000000..17db1974 --- /dev/null +++ b/epan/wslua/wslua_field.c @@ -0,0 +1,832 @@ +/* + * wslua_field.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include <epan/dfilter/dfilter.h> +#include <epan/ftypes/ftypes.h> + +/* WSLUA_MODULE Field Obtaining Dissection Data */ + +#include "wslua.h" + +/* any call to checkFieldInfo() will now error on null or expired, so no need to check again */ +WSLUA_CLASS_DEFINE(FieldInfo,FAIL_ON_NULL_OR_EXPIRED("FieldInfo")); +/* + An extracted Field from dissected packet data. A `FieldInfo` object can only be used within + the callback functions of dissectors, post-dissectors, heuristic-dissectors, and taps. + + A `FieldInfo` can be called on either existing Wireshark fields by using either `Field.new()` + or `Field()` before-hand, or it can be called on new fields created by Lua from a `ProtoField`. + */ + +static GPtrArray* outstanding_FieldInfo = NULL; + +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) + +/* WSLUA_ATTRIBUTE FieldInfo_len RO The length of this field. */ +WSLUA_METAMETHOD FieldInfo__len(lua_State* L) { + /* + Obtain the Length of the field + */ + FieldInfo fi = checkFieldInfo(L,1); + + lua_pushnumber(L,fi->ws_fi->length); + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_offset RO The offset of this field. */ +WSLUA_METAMETHOD FieldInfo__unm(lua_State* L) { + /* + Obtain the Offset of the field + */ + FieldInfo fi = checkFieldInfo(L,1); + + lua_pushnumber(L,fi->ws_fi->start); + return 1; +} + +/* 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.range` + to get the `TvbRange`, and then use `tvbrange: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_uinteger64(fi->ws_fi->value)); + return 1; + case FT_CHAR: + 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)); + alloc_address_tvb(NULL,eth,AT_ETHER,fi->ws_fi->length,fi->ws_fi->ds_tvb,fi->ws_fi->start); + pushAddress(L,eth); + return 1; + } + case FT_IPv4:{ + Address ipv4 = (Address)g_malloc(sizeof(address)); + alloc_address_tvb(NULL,ipv4,AT_IPv4,fi->ws_fi->length,fi->ws_fi->ds_tvb,fi->ws_fi->start); + pushAddress(L,ipv4); + return 1; + } + case FT_IPv6: { + Address ipv6 = (Address)g_malloc(sizeof(address)); + alloc_address_tvb(NULL,ipv6,AT_IPv6,fi->ws_fi->length,fi->ws_fi->ds_tvb,fi->ws_fi->start); + pushAddress(L,ipv6); + return 1; + } + case FT_FCWWN: { + Address fcwwn = (Address)g_malloc(sizeof(address)); + alloc_address_tvb(NULL,fcwwn,AT_FCWWN,fi->ws_fi->length,fi->ws_fi->ds_tvb,fi->ws_fi->start); + pushAddress(L,fcwwn); + return 1; + } + case FT_IPXNET:{ + Address ipx = (Address)g_malloc(sizeof(address)); + alloc_address_tvb(NULL,ipx,AT_IPX,fi->ws_fi->length,fi->ws_fi->ds_tvb,fi->ws_fi->start); + pushAddress(L,ipx); + return 1; + } + case FT_ABSOLUTE_TIME: + case FT_RELATIVE_TIME: { + NSTime nstime = (NSTime)g_malloc(sizeof(nstime_t)); + *nstime = *fvalue_get_time(fi->ws_fi->value); + pushNSTime(L,nstime); + return 1; + } + case FT_STRING: + case FT_STRINGZ: + case FT_STRINGZPAD: { + gchar* repr = fvalue_to_string_repr(NULL, fi->ws_fi->value, FTREPR_DISPLAY, BASE_NONE); + if (repr) + { + lua_pushstring(L, repr); + wmem_free(NULL, 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, fvalue_get_bytes_data(fi->ws_fi->value), + (guint)fvalue_length2(fi->ws_fi->value)); + pushByteArray(L,ba); + return 1; + } + case FT_PROTOCOL: + { + ByteArray ba = g_byte_array_new(); + tvbuff_t* tvb = fvalue_get_protocol(fi->ws_fi->value); + guint8* raw; + if (tvb != NULL) { + raw = (guint8 *)tvb_memdup(NULL, tvb, 0, tvb_captured_length(tvb)); + g_byte_array_append(ba, raw, tvb_captured_length(tvb)); + wmem_free(NULL, raw); + } + + pushByteArray(L,ba); + return 1; + } + + case FT_GUID: + default: + luaL_error(L,"FT_ not yet supported"); + return 1; + } +} + +/* 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); + + gchar* repr = NULL; + + if (fi->ws_fi->hfinfo->type == FT_PROTOCOL) { + repr = fvalue_to_string_repr(NULL, fi->ws_fi->value,FTREPR_DFILTER,BASE_NONE); + } + else { + repr = fvalue_to_string_repr(NULL, fi->ws_fi->value,FTREPR_DISPLAY,fi->ws_fi->hfinfo->display); + } + + if (repr) { + lua_pushstring(L,repr); + /* fvalue_to_string_repr() wmem_alloc's the string's buffer */ + wmem_free(NULL, repr); + } + else { + lua_pushstring(L,"(unknown)"); + } + + return 1; +} + +/* 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); + gchar label_str[ITEM_LABEL_LENGTH+1]; + gchar *label_ptr; + gchar *value_ptr; + + if (!fi->ws_fi->rep) { + label_ptr = label_str; + proto_item_fill_label(fi->ws_fi, label_str); + } else + label_ptr = fi->ws_fi->rep->representation; + + if (!label_ptr) return 0; + + value_ptr = strstr(label_ptr, ": "); + if (!value_ptr) { + /* just use whatever's there */ + lua_pushstring(L, label_ptr); + } else { + value_ptr += 2; /* get past the ': ' */ + lua_pushstring(L, value_ptr); + } + + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_type RO The internal field type, a number which + matches one of the `ftype` values. + + @since 1.99.8 + */ +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.8 + */ +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 the bytes of this field in a Tvb or nil if there is none. */ +static int FieldInfo_get_range(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + + if (!fi->ws_fi->ds_tvb) { + lua_pushnil(L); + return 1; + } + + if (push_TvbRange (L, fi->ws_fi->ds_tvb, fi->ws_fi->start, fi->ws_fi->length)) { + return 1; + } + + return 0; +} + +/* 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); + + lua_pushboolean(L,FI_GET_FLAG(fi->ws_fi, FI_GENERATED)); + return 1; +} + +/* WSLUA_ATTRIBUTE FieldInfo_hidden RO Whether this field was marked as hidden (boolean). + + @since 1.99.8 + */ +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.8 + */ +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.8 + */ +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.8 + */ +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.8 + */ +static int FieldInfo_get_name(lua_State* L) { + /* The filter name of this field. */ + FieldInfo fi = checkFieldInfo(L,1); + + lua_pushstring(L,fi->ws_fi->hfinfo->abbrev); + return 1; +} + +WSLUA_METAMETHOD FieldInfo__eq(lua_State* L) { + /* Checks whether lhs is within rhs. */ + FieldInfo l = checkFieldInfo(L,1); + FieldInfo r = checkFieldInfo(L,2); + + /* it is not an error if their ds_tvb are different... they're just not equal */ + if (l->ws_fi->ds_tvb == r->ws_fi->ds_tvb && + l->ws_fi->start == r->ws_fi->start && + r->ws_fi->length == l->ws_fi->length) { + lua_pushboolean(L,1); + } else { + lua_pushboolean(L,0); + } + return 1; +} + +WSLUA_METAMETHOD FieldInfo__le(lua_State* L) { + /* Checks whether the end byte of lhs is before the end of rhs. */ + FieldInfo l = checkFieldInfo(L,1); + FieldInfo r = checkFieldInfo(L,2); + + if (l->ws_fi->ds_tvb != r->ws_fi->ds_tvb) + WSLUA_ERROR(FieldInfo__le,"Data source must be the same for both fields"); + + if (l->ws_fi->start + l->ws_fi->length <= r->ws_fi->start + r->ws_fi->length) { + lua_pushboolean(L,1); + } else { + lua_pushboolean(L,0); + } + return 1; +} + +WSLUA_METAMETHOD FieldInfo__lt(lua_State* L) { + /* Checks whether the end byte of lhs is before the beginning of rhs. */ + FieldInfo l = checkFieldInfo(L,1); + FieldInfo r = checkFieldInfo(L,2); + + if (l->ws_fi->ds_tvb != r->ws_fi->ds_tvb) { + WSLUA_ERROR(FieldInfo__lt,"Data source must be the same for both fields"); + return 0; + } + + if (l->ws_fi->start + l->ws_fi->length <= r->ws_fi->start) { + lua_pushboolean(L,1); + } else { + lua_pushboolean(L,0); + } + return 1; +} + +/* Gets registered as metamethod automatically by WSLUA_REGISTER_META */ +static int FieldInfo__gc(lua_State* L) { + FieldInfo fi = toFieldInfo(L,1); + + if (!fi) return 0; + + if (!fi->expired) + fi->expired = TRUE; + else + /* do NOT free fi->ws_fi */ + g_free(fi); + + return 0; +} + +/* This table is ultimately registered as a sub-table of the class' metatable, + * and if __index/__newindex is invoked then it calls the appropriate function + * from this table for getting/setting the members. + */ +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 }, + { "len", FieldInfo__len, NULL }, + { "offset", FieldInfo__unm, NULL }, + { NULL, NULL, NULL } +}; + +WSLUA_META FieldInfo_meta[] = { + WSLUA_CLASS_MTREG(FieldInfo,tostring), + WSLUA_CLASS_MTREG(FieldInfo,call), + WSLUA_CLASS_MTREG(FieldInfo,len), + WSLUA_CLASS_MTREG(FieldInfo,unm), + WSLUA_CLASS_MTREG(FieldInfo,eq), + WSLUA_CLASS_MTREG(FieldInfo,le), + WSLUA_CLASS_MTREG(FieldInfo,lt), + { NULL, NULL } +}; + +int FieldInfo_register(lua_State* L) { + WSLUA_REGISTER_META_WITH_ATTRS(FieldInfo); + return 0; +} + + +WSLUA_FUNCTION wslua_all_field_infos(lua_State* L) { + /* + Obtain all fields from the current tree. Note this only gets whatever fields the underlying + dissectors have filled in for this packet at this time - there may be fields applicable to + the packet that simply aren't being filled in because at this time they're not needed for anything. + This function only gets what the C-side code has currently populated, not the full list. + */ + GPtrArray* found; + int items_found = 0; + guint i; + + if (! lua_tree || ! lua_tree->tree ) { + WSLUA_ERROR(wslua_all_field_infos,"Cannot be called outside a listener or dissector"); + return 0; + } + + found = proto_all_finfos(lua_tree->tree); + + if (found) { + for (i=0; i<found->len; i++) { + push_FieldInfo(L, (field_info *)g_ptr_array_index(found,i)); + items_found++; + } + + g_ptr_array_free(found,TRUE); + } + + return items_found; +} + +WSLUA_CLASS_DEFINE(Field,FAIL_ON_NULL("Field")); +/* + A Field extractor to obtain field values. A `Field` object can only be created *outside* of + the callback functions of dissectors, post-dissectors, heuristic-dissectors, and taps. + + Once created, it is used *inside* the callback functions, to generate a `FieldInfo` object. + */ + +/* Array of Field (struct _wslua_header_field_info*) pointers.*/ +static GPtrArray* wanted_fields = NULL; +static dfilter_t* wslua_dfilter = NULL; + +/* We use a fake dfilter for Lua field extractors, so that + * epan_dissect_run() will populate the fields. This won't happen + * if the passed-in edt->tree is NULL, which it will be if the + * proto_tree isn't created by epan_dissect_init(). But that's by + * design - if shark doesn't pass in a proto_tree, it's probably for + * a good reason and we shouldn't override that. (right?) + */ +void wslua_prime_dfilter(epan_dissect_t *edt) { + if (wslua_dfilter && edt && edt->tree) { + dfilter_prime_proto_tree(wslua_dfilter, edt->tree); + } +} + +/* Check if we have any registered field extractors. */ +gboolean wslua_has_field_extractors(void) { + return (wslua_dfilter && dfilter_has_interesting_fields(wslua_dfilter)); +} + +/* + * field extractor registration is tricky, In order to allow + * the user to define them in the body of the script we will + * populate the Field value with a pointer of the abbrev of it + * to later replace it with the hfi. + * + * This will be added to the wanted_fields array that will + * exists only while they can be defined, and be cleared right + * after the fields are primed. + */ + +static gboolean fake_tap = FALSE; +void lua_prime_all_fields(proto_tree* tree _U_) { + GString* fake_tap_filter = g_string_new("frame"); + guint i; + df_error_t *df_err; + + for(i=0; i < wanted_fields->len; i++) { + Field f = (Field)g_ptr_array_index(wanted_fields,i); + + f->hfi = proto_registrar_get_byname(f->name); + if (!f->hfi) { + report_failure("Could not find field `%s'", f->name); + continue; + } + + g_string_append_printf(fake_tap_filter, " || %s", f->hfi->abbrev); + fake_tap = TRUE; + } + + g_ptr_array_free(wanted_fields,TRUE); + wanted_fields = NULL; + + if (fake_tap && fake_tap_filter->len > strlen("frame")) { + /* a boring tap :-) */ + GString* error = register_tap_listener("frame", + &fake_tap, + fake_tap_filter->str, + 0, /* XXX - do we need the protocol tree or columns? */ + NULL, NULL, NULL, NULL); + + if (error) { + report_failure("while registering lua_fake_tap:\n%s",error->str); + g_string_free(error,TRUE); + } else if (!dfilter_compile(fake_tap_filter->str, &wslua_dfilter, &df_err)) { + report_failure("while compiling dfilter \"%s\" for wslua: %s", fake_tap_filter->str, df_err->msg); + df_error_free(&df_err); + } + } + g_string_free(fake_tap_filter, TRUE); +} + +WSLUA_CONSTRUCTOR Field_new(lua_State *L) { + /* + Create a Field extractor. + */ +#define WSLUA_ARG_Field_new_FIELDNAME 1 /* The filter name of the field (e.g. ip.addr) */ + const gchar* name = luaL_checkstring(L,WSLUA_ARG_Field_new_FIELDNAME); + Field f; + + if (!proto_registrar_get_byname(name) && !wslua_is_field_available(L, name)) { + WSLUA_ARG_ERROR(Field_new,FIELDNAME,"a field with this name must exist"); + return 0; + } + + if (!wanted_fields) { + WSLUA_ERROR(Field_new,"A Field extractor must be defined before Taps or Dissectors get called"); + return 0; + } + + f = (Field)g_new0(struct _wslua_header_field_info, 1); + f->name = g_strdup(name); + + g_ptr_array_add(wanted_fields, f); + + pushField(L,f); + WSLUA_RETURN(1); /* The field extractor */ +} + +WSLUA_CONSTRUCTOR Field_list(lua_State *L) { + /* Gets a Lua array table of all registered field filter names. + + NOTE: This is an expensive operation, and should only be used for troubleshooting. + + @since 1.11.3 + */ + void *cookie, *cookie2; + int i = -1; + int count = 0; + header_field_info *hfinfo = NULL; + + lua_newtable(L); + + for (i = proto_get_first_protocol(&cookie); i != -1; + i = proto_get_next_protocol(&cookie)) { + + for (hfinfo = proto_get_first_protocol_field(i, &cookie2); hfinfo != NULL; + hfinfo = proto_get_next_protocol_field(i, &cookie2)) { + + if (hfinfo->same_name_prev_id != -1) /* ignore duplicate names */ + continue; + + count++; + lua_pushstring(L,hfinfo->abbrev); + lua_rawseti(L,-2,count); + } + } + + WSLUA_RETURN(1); /* The array table of field filter names */ +} + +/* the following is used in Field_get_xxx functions later. If called early + * (wanted_fields is not NULL), it will try to retrieve information directly. + * Otherwise it uses a cached field that was loaded in lua_prime_all_fields. */ +#define GET_HFINFO_MEMBER(luafunc, member) \ + if (wanted_fields) { \ + hfinfo = proto_registrar_get_byname(f->name); \ + if (!hfinfo) { \ + /* could be a Lua-created field */ \ + ProtoField pf = wslua_is_field_available(L, f->name); \ + if (pf) { \ + luafunc(L, pf->member); \ + return 1; \ + } \ + } \ + } else { \ + hfinfo = f->hfi; \ + } \ + \ + 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.8 + */ +static int Field_get_name(lua_State* L) { + Field f = 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.8 + */ +static int Field_get_display(lua_State* L) { + Field f = 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.8 + */ +static int Field_get_type(lua_State* L) { + Field f = 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); + header_field_info* in = f->hfi; + int items_found = 0; + + if (! in) { + luaL_error(L,"invalid field"); + return 0; + } + + if (! lua_pinfo ) { + WSLUA_ERROR(Field__call,"Fields cannot be used outside dissectors or taps"); + return 0; + } + + while (in) { + GPtrArray* found = proto_get_finfo_ptr_array(lua_tree->tree, in->id); + guint i; + if (found) { + for (i=0; i<found->len; i++) { + push_FieldInfo(L, (field_info *) g_ptr_array_index(found,i)); + items_found++; + } + } + in = (in->same_name_prev_id != -1) ? proto_registrar_get_nth(in->same_name_prev_id) : NULL; + } + + WSLUA_RETURN(items_found); /* All the values of this field */ +} + +WSLUA_METAMETHOD Field__tostring(lua_State* L) { + /* Obtain a string with the field filter name. */ + Field f = checkField(L,1); + + if (f->hfi) { + /* If a field was found, return the actual field info. */ + lua_pushstring(L, f->hfi->abbrev); + } else { + lua_pushstring(L, f->name); + } + + return 1; +} + +static int Field__gc(lua_State* L) { + Field f = toField(L,1); + if (!f) return 0; + + // If out of scope before lua_prime_all_fields is even called, be sure to + // remove the pointer to avoid a use-after-free. + if (wanted_fields) { + g_ptr_array_remove_fast(wanted_fields, f); + } + + g_free(f->name); + g_free(f); + 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), + { NULL, NULL } +}; + +WSLUA_META Field_meta[] = { + WSLUA_CLASS_MTREG(Field,tostring), + WSLUA_CLASS_MTREG(Field,call), + { NULL, NULL } +}; + +int Field_register(lua_State* L) { + + wanted_fields = g_ptr_array_new(); + + WSLUA_REGISTER_CLASS_WITH_ATTRS(Field); + outstanding_FieldInfo = g_ptr_array_new(); + + return 0; +} + +int wslua_deregister_fields(lua_State* L _U_) { + if (wslua_dfilter) { + dfilter_free(wslua_dfilter); + wslua_dfilter = NULL; + } + + if (fake_tap) { + remove_tap_listener(&fake_tap); + fake_tap = FALSE; + } + + return 0; +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |