wireshark/epan/wslua/wslua_field.c
João Valverde a0d77e9329 dfilter: Return an error object instead of string
Return an struct containing error information. This simplifies
the interface to more easily provide richer diagnostics in the future.

Add an error code besides a human-readable error string to allow
checking programmatically for errors in a robust manner. Currently
there is only a generic error code, it is expected to increase
in the future.

Move error location information to the struct. Change callers and
implementation to use the new interface.
2022-11-28 15:46:44 +00:00

833 lines
25 KiB
C

/*
* 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(&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 = 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 in `init.lua`.
@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 (r->ws_fi->start + r->ws_fi->length <= l->ws_fi->start + l->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 rhs 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 (r->ws_fi->start + r->ws_fi->length < l->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);
dfilter_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:
*/