/* * wslua_field.c * * Wireshark's interface to the Lua Programming Language * * (c) 2006, Luis E. Garcia Ontanon * * $Id$ * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* WSLUA_MODULE Field obtaining dissection data */ #include "wslua.h" WSLUA_CLASS_DEFINE(FieldInfo,NOP,NOP); /* An extracted Field */ WSLUA_METAMETHOD FieldInfo__len(lua_State* L) { /* Obtain the Length of the field */ FieldInfo fi = checkFieldInfo(L,1); lua_pushnumber(L,fi->length); return 1; } WSLUA_METAMETHOD FieldInfo__unm(lua_State* L) { /* Obtain the Offset of the field */ FieldInfo fi = checkFieldInfo(L,1); lua_pushnumber(L,fi->start); return 1; } WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { /* Obtain the Value of the field */ FieldInfo fi = checkFieldInfo(L,1); switch(fi->hfinfo->type) { case FT_NONE: lua_pushnil(L); return 1; case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: case FT_FRAMENUM: lua_pushnumber(L,(lua_Number)fvalue_get_uinteger(&(fi->value))); return 1; case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: lua_pushnumber(L,(lua_Number)fvalue_get_sinteger(&(fi->value))); return 1; case FT_FLOAT: case FT_DOUBLE: lua_pushnumber(L,(lua_Number)fvalue_get_floating(&(fi->value))); return 1; case FT_INT64: case FT_UINT64: /* * XXX: double has 53 bits integer precision, n > 2^22 will cause a loss in precision */ lua_pushnumber(L,(lua_Number)(gint64)fvalue_get_integer64(&(fi->value))); return 1; case FT_ETHER: { Address eth = g_malloc(sizeof(address)); eth->type = AT_ETHER; eth->len = fi->length; eth->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,eth); return 1; } case FT_IPv4:{ Address ipv4 = g_malloc(sizeof(address)); ipv4->type = AT_IPv4; ipv4->len = fi->length; ipv4->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv4); return 1; } case FT_IPv6: { Address ipv6 = g_malloc(sizeof(address)); ipv6->type = AT_IPv6; ipv6->len = fi->length; ipv6->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipv6); return 1; } case FT_IPXNET:{ Address ipx = g_malloc(sizeof(address)); ipx->type = AT_IPX; ipx->len = fi->length; ipx->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length); pushAddress(L,ipx); return 1; } case FT_STRING: case FT_STRINGZ: lua_pushstring(L,fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL)); return 1; case FT_BYTES: case FT_UINT_BYTES: case FT_GUID: case FT_OID: { ByteArray ba = g_byte_array_new(); g_byte_array_append(ba, ep_tvb_memdup(fi->ds_tvb,fi->start,fi->length),fi->length); pushByteArray(L,ba); return 1; } default: luaL_error(L,"FT_ not yet supported"); return 1; } } WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) { /* the string representation of the field */ FieldInfo fi = checkFieldInfo(L,1); if (fi) { if (fi->value.ftype->val_to_string_repr) lua_pushstring(L,fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL)); else luaL_error(L,"field has no string representation"); } return 1; } int FieldInfo_get_range(lua_State* L) { /* the TvbRange covering this field */ FieldInfo fi = checkFieldInfo(L,1); TvbRange r = ep_alloc(sizeof(struct _wslua_tvbrange)); r->tvb = fi->ds_tvb; r->offset = fi->start; r->len = fi->length; pushTvbRange(L,r); return 1; } 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, FI_GENERATED)); return 1; } int FieldInfo_get_name(lua_State* L) { /* the filter name of this field. */ FieldInfo fi = checkFieldInfo(L,1); lua_pushstring(L,fi->hfinfo->abbrev); return 1; } static const luaL_reg FieldInfo_get[] = { /* {"data_source", FieldInfo_get_data_source }, */ {"range", FieldInfo_get_range}, /* {"hidden", FieldInfo_get_hidden}, */ {"generated", FieldInfo_get_generated}, /* WSLUA_ATTRIBUTE FieldInfo_name RO The name of this field */ {"name", FieldInfo_get_name}, /* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field */ {"label", FieldInfo__tostring}, /* WSLUA_ATTRIBUTE FieldInfo_value RO The value of this field */ {"value", FieldInfo__call}, /* WSLUA_ATTRIBUTE FieldInfo_len RO The length of this field */ {"len", FieldInfo__len}, /* WSLUA_ATTRIBUTE FieldInfo_offset RO The offset of this field */ {"offset", FieldInfo__unm}, {0, 0} }; static int FieldInfo__index(lua_State* L) { /* Other attributes: */ const gchar* index = luaL_checkstring(L,2); const luaL_reg* r; checkFieldInfo(L,1); for (r = FieldInfo_get; r->name; r++) { if (g_str_equal(r->name, index)) { return r->func(L); } } return 0; } WSLUA_METAMETHOD FieldInfo__eq(lua_State* L) { /* checks whether lhs is within rhs */ FieldInfo l = checkFieldInfo(L,1); FieldInfo r = checkFieldInfo(L,2); if (l->ds_tvb != r->ds_tvb) WSLUA_ERROR(FieldInfo__eq,"data source must be the same for both fields"); if (l->start <= r->start && r->start + r->length <= l->start + r->length) { lua_pushboolean(L,1); return 1; } else { return 0; } } 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->ds_tvb != r->ds_tvb) return 0; if (r->start + r->length <= l->start + r->length) { lua_pushboolean(L,1); return 1; } else { return 0; } } 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->ds_tvb != r->ds_tvb) WSLUA_ERROR(FieldInfo__eq,"data source must be the same for both fields"); if ( r->start + r->length < l->start ) { lua_pushboolean(L,1); return 1; } else { return 0; } } static const luaL_reg FieldInfo_meta[] = { {"__tostring", FieldInfo__tostring}, {"__call", FieldInfo__call}, {"__index", FieldInfo__index}, {"__len", FieldInfo__len}, {"__unm", FieldInfo__unm}, {"__eq", FieldInfo__eq}, {"__le", FieldInfo__le}, {"__lt", FieldInfo__lt}, {0, 0} }; int FieldInfo_register(lua_State* L) { WSLUA_REGISTER_META(FieldInfo); return 1; } WSLUA_FUNCTION wslua_all_field_infos(lua_State* L) { /* obtain all fields from the current tree */ 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"); } found = proto_all_finfos(lua_tree->tree); if (found) { for (i=0; ilen; i++) { pushFieldInfo(L,g_ptr_array_index(found,i)); items_found++; } g_ptr_array_free(found,TRUE); } return items_found; } WSLUA_CLASS_DEFINE(Field,NOP,NOP); /* A Field extractor to to obtain field values. */ static GPtrArray* wanted_fields = NULL; /* * field extractor registartion 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. */ void lua_prime_all_fields(proto_tree* tree _U_) { GString* fake_tap_filter = g_string_new("frame"); guint i; static gboolean fake_tap = FALSE; for(i=0; i < wanted_fields->len; i++) { Field f = g_ptr_array_index(wanted_fields,i); gchar* name = *((gchar**)f); *f = proto_registrar_get_byname(name); if (!*f) { report_failure("Could not find field `%s'",name); *f = NULL; g_free(name); continue; } g_free(name); g_string_sprintfa(fake_tap_filter," || %s",(*f)->abbrev); fake_tap = TRUE; } g_ptr_array_free(wanted_fields,TRUE); wanted_fields = NULL; if (fake_tap) { /* a boring tap :-) */ GString* error = register_tap_listener("frame", &fake_tap, fake_tap_filter->str, NULL, NULL, NULL); if (error) { report_failure("while registering lua_fake_tap:\n%s",error->str); g_string_free(error,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 (!name) return 0; if (!proto_registrar_get_byname(name)) WSLUA_ARG_ERROR(Field_new,FIELDNAME,"a field with this name must exist"); if (!wanted_fields) WSLUA_ERROR(Field_get,"a Field extractor must be defined before Taps or Dissectors get called"); f = g_malloc(sizeof(void*)); *f = (header_field_info*)g_strdup(name); /* cheating */ g_ptr_array_add(wanted_fields,f); pushField(L,f); WSLUA_RETURN(1); /* The field extractor */ } 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; 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; } for (;in;in = in->same_name_next) { GPtrArray* found = proto_get_finfo_ptr_array(lua_tree->tree, in->id); guint i; if (found) { for (i=0; ilen; i++) { pushFieldInfo(L,g_ptr_array_index(found,i)); items_found++; } } } WSLUA_RETURN(items_found); /* All the values of this field */ } WSLUA_METAMETHOD Field_tostring(lua_State* L) { /* obtain a srting with the field name */ Field f = checkField(L,1); if ( !(f && *f) ) { luaL_error(L,"invalid Field"); return 0; } if (wanted_fields) { lua_pushstring(L,*((gchar**)f)); } else { lua_pushstring(L,(*f)->abbrev); } return 1; } static const luaL_reg Field_methods[] = { {"new", Field_new}, {0, 0} }; static const luaL_reg Field_meta[] = { {"__tostring", Field_tostring}, {"__call", Field__call}, {0, 0} }; int Field_register(lua_State* L) { wanted_fields = g_ptr_array_new(); WSLUA_REGISTER_CLASS(Field); return 1; }