summaryrefslogtreecommitdiffstats
path: root/epan/wslua/wslua_field.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/wslua/wslua_field.c')
-rw-r--r--epan/wslua/wslua_field.c832
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 0000000..17db197
--- /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:
+ */