diff options
author | Luis Ontanon <luis.ontanon@gmail.com> | 2006-09-25 01:09:00 +0000 |
---|---|---|
committer | Luis Ontanon <luis.ontanon@gmail.com> | 2006-09-25 01:09:00 +0000 |
commit | 6462d05044d74e475253518912c0635222bd7fc2 (patch) | |
tree | 32834c107cb9baab32f865999d3d69d877452e71 /epan | |
parent | 299469d48d57337e6381f2d5363ece52c9a36d37 (diff) | |
download | wireshark-6462d05044d74e475253518912c0635222bd7fc2.tar.gz wireshark-6462d05044d74e475253518912c0635222bd7fc2.tar.bz2 wireshark-6462d05044d74e475253518912c0635222bd7fc2.zip |
Move the Lua interface into epan... (not a plugin anymore).
- Rename Tap into Listener
- add a mechanism to pass protocols' tap data to the Listener
svn path=/trunk/; revision=19319
Diffstat (limited to 'epan')
-rw-r--r-- | epan/Makefile.am | 19 | ||||
-rw-r--r-- | epan/epan.c | 8 | ||||
-rw-r--r-- | epan/wslua/Makefile.am | 121 | ||||
-rw-r--r-- | epan/wslua/Makefile.nmake | 69 | ||||
-rw-r--r-- | epan/wslua/init_wslua.c | 323 | ||||
-rwxr-xr-x | epan/wslua/make-doc.pl | 385 | ||||
-rwxr-xr-x | epan/wslua/make-init-lua.pl | 121 | ||||
-rwxr-xr-x | epan/wslua/make-reg.pl | 62 | ||||
-rw-r--r-- | epan/wslua/make-taps.pl | 206 | ||||
-rw-r--r-- | epan/wslua/taps | 81 | ||||
-rw-r--r-- | epan/wslua/template-init.lua | 61 | ||||
-rw-r--r-- | epan/wslua/wslua.h | 338 | ||||
-rw-r--r-- | epan/wslua/wslua_dumper.c | 389 | ||||
-rw-r--r-- | epan/wslua/wslua_field.c | 445 | ||||
-rw-r--r-- | epan/wslua/wslua_gui.c | 508 | ||||
-rw-r--r-- | epan/wslua/wslua_listener.c | 332 | ||||
-rw-r--r-- | epan/wslua/wslua_pinfo.c | 888 | ||||
-rw-r--r-- | epan/wslua/wslua_proto.c | 1350 | ||||
-rw-r--r-- | epan/wslua/wslua_tree.c | 290 | ||||
-rw-r--r-- | epan/wslua/wslua_tvb.c | 738 | ||||
-rw-r--r-- | epan/wslua/wslua_util.c | 129 |
21 files changed, 6859 insertions, 4 deletions
diff --git a/epan/Makefile.am b/epan/Makefile.am index 50c7edec44..735845b5a9 100644 --- a/epan/Makefile.am +++ b/epan/Makefile.am @@ -22,7 +22,17 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -SUBDIRS = ftypes dfilter dissectors + +if HAVE_LIBLUA +wslua_lib = wslua/libwslua.la +wslua_dir = wslua +else # HAVE_LIBLUA +wslua_lib = +wslua_dir = +endif # HAVE_LIBLUA + + +SUBDIRS = ftypes dfilter dissectors $(wslua_dir) # EPAN will eventually be a shared library. While I move source code around, # however, it is an archive library. @@ -34,7 +44,7 @@ libwireshark_la_LDFLAGS = -version-info 0:1:0 include Makefile.common -INCLUDES = -I$(srcdir)/.. -I$(srcdir)/$(LEMON) \ +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/$(LEMON) @LUA_INCLUDES@ \ $(LIBGNUTLS_CFLAGS) $(LIBGCRYPT_CFLAGS) libwireshark_la_SOURCES = \ @@ -82,11 +92,12 @@ MAINTAINERCLEANFILES = \ Makefile.in \ sminmpec.c + # # Add the object files for missing routines, if any. # -libwireshark_la_LIBADD = @G_ASCII_STRTOULL_LO@ @INET_ATON_LO@ @INET_PTON_LO@ @INET_NTOP_LO@ dfilter/libdfilter.la ftypes/libftypes.la dissectors/libdissectors.la @ADNS_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @KRB5_LIBS@ @SNMP_LIBS@ @SSL_LIBS@ -lm -libwireshark_la_DEPENDENCIES = @G_ASCII_STRTOULL_LO@ @INET_ATON_LO@ @INET_PTON_LO@ @INET_NTOP_LO@ dfilter/libdfilter.la ftypes/libftypes.la dissectors/libdissectors.la +libwireshark_la_LIBADD = @G_ASCII_STRTOULL_LO@ @INET_ATON_LO@ @INET_PTON_LO@ @INET_NTOP_LO@ dfilter/libdfilter.la ftypes/libftypes.la dissectors/libdissectors.la $(wslua_lib) @ADNS_LIBS@ @LIBGNUTLS_LIBS@ @LIBICONV@ @KRB5_LIBS@ @SNMP_LIBS@ @SSL_LIBS@ -lm +libwireshark_la_DEPENDENCIES = @G_ASCII_STRTOULL_LO@ @INET_ATON_LO@ @INET_PTON_LO@ @INET_NTOP_LO@ dfilter/libdfilter.la ftypes/libftypes.la dissectors/libdissectors.la $(wslua_lib) tvbtest: tvbtest.o tvbuff.o except.o strutil.o $(LINK) $^ $(GLIB_LIBS) -lz diff --git a/epan/epan.c b/epan/epan.c index 05e274e85b..fe68db2378 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -38,6 +38,10 @@ #include "emem.h" #include "expert.h" +#ifdef HAVE_LUA_5_1 +#include <epan/wslua/wslua.h> +#endif + static void (*report_failure_func)(const char *, va_list); static void (*report_open_failure_func)(const char *, int, gboolean); static void (*report_read_failure_func)(const char *, int); @@ -93,6 +97,10 @@ epan_init(const char *plugin_dir, void (*register_all_protocols)(void), final_registration_all_protocols(); host_name_lookup_init(); expert_init(); +#ifdef HAVE_LUA_5_1 + wslua_init(NULL); +#endif + } void diff --git a/epan/wslua/Makefile.am b/epan/wslua/Makefile.am new file mode 100644 index 0000000000..ecc39ff5f3 --- /dev/null +++ b/epan/wslua/Makefile.am @@ -0,0 +1,121 @@ +# Makefile.am +# +# $Id$ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# 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. +# + +INCLUDES = -I$(top_srcdir) @LUA_INCLUDES@ + +noinst_LTLIBRARIES = libwslua.la + +wslua_modules = \ + wslua_tvb.c \ + wslua_proto.c \ + wslua_tree.c \ + wslua_pinfo.c \ + wslua_listener.c \ + wslua_gui.c \ + wslua_util.c \ + wslua_field.c \ + wslua_dumper.c + +libwslua_la_SOURCES = \ + $(wslua_modules) \ + init_wslua.c \ + wslua.h + +libwslua_la_LIBADD = @LUA_LIBS@ + +BUILT_SOURCES = \ + wslua_register.h + +pkgdata_DATA = init.lua + +CLEANFILES = \ + *~ + +DISTCLEANFILES = \ + dummy + +MAINTAINERCLEANFILES = \ + Makefile.in \ + doc/*.pod \ + wslua_register.h \ + taps.c-inc \ + taps.txt \ + init.lua + +EXTRA_DIST = \ + wslua_register.h \ + taps \ + make-reg.pl \ + make-doc.pl \ + template-init.lua \ + make-init-lua.pl \ + make-taps.pl \ + Makefile.nmake + +taps_used = \ + ../dissectors/packet-http.h \ + ../dissectors/packet-ip.h \ + ../dissectors/packet-udp.h \ + ../dissectors/packet-h225.h + +taps: $(taps_used) + touch taps + +taps.c-inc: make-taps.pl taps + $(PERL) make-taps.pl taps taps.c-inc taps.txt + +taps.txt: taps.c-inc + +wslua.h: wslua_register.h + +# do not do not unnecessarilly modify the old file in order avoid recompiling every module every time +wslua_register.h: make-reg.pl $(lua_modules) taps.c-inc + $(PERL) make-reg.pl \ + wslua_tvb.c \ + wslua_proto.c \ + wslua_tree.c \ + wslua_pinfo.c \ + wslua_listener.c \ + wslua_gui.c \ + wslua_util.c \ + wslua_field.c \ + wslua_dumper.c > wslua_register.h.new ;\ + if diff wslua_register.h.new wslua_register.h >/dev/null; then rm wslua_register.h.new; else mv wslua_register.h.new wslua_register.h; fi + +doc: make-doc.pl $(lua_modules) + $(PERL) make-doc.pl \ + wslua_tvb.c \ + wslua_proto.c \ + wslua_tree.c \ + wslua_pinfo.c \ + wslua_listener.c \ + wslua_gui.c \ + wslua_util.c \ + wslua_field.c \ + wslua_dumper.c + +dummy: + touch dummy + +init.lua: template-init.lua make-init-lua.pl ../ftypes/ftypes.h ../../wiretap/wtap.h ../proto.h + $(PERL) make-init-lua.pl template-init.lua > init.lua diff --git a/epan/wslua/Makefile.nmake b/epan/wslua/Makefile.nmake new file mode 100644 index 0000000000..497ab2eebe --- /dev/null +++ b/epan/wslua/Makefile.nmake @@ -0,0 +1,69 @@ +# +# $Id$ +# + +include ..\..\config.nmake + +############### no need to modify below this line ######### + +CFLAGS=/DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) $(LUA_CFLAGS)\ + /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS) + +LDFLAGS = /NOLOGO /INCREMENTAL:no /MACHINE:I386 $(LOCAL_LDFLAGS) + +!IFDEF LUA_DIR +!IFDEF ENABLE_LIBWIRESHARK +LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib +CFLAGS=/DHAVE_WIN32_LIBWIRESHARK_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS) + +MODULES= \ + elua_dumper.c \ + elua_field.c \ + elua_gui.c \ + elua_pinfo.c \ + elua_proto.c \ + elua_tap.c \ + elua_tree.c \ + elua_tvb.c \ + elua_util.c + +OBJECTS= \ + elua.obj \ + elua_dumper.obj \ + elua_field.obj \ + elua_gui.obj \ + elua_pinfo.obj \ + elua_plugin.obj \ + elua_proto.obj \ + elua_tap.obj \ + elua_tree.obj \ + elua_tvb.obj \ + elua_util.obj + +lua.dll lua.exp lua.lib : $(OBJECTS) $(LINK_PLUGIN_WITH) + link -dll /out:lua.dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \ + $(GLIB_LIBS) $(LUA_LIBS) ..\..\wiretap\wiretap-$(WTAP_VERSION).lib + + +elua_register.h: elua_makereg.pl $(MODULES) + $(PERL) elua_makereg.pl $(MODULES) > elua_register.h + +elua.c: elua_register.h + +doc: $(MODULES) + $(PERL) elua_makedoc.pl $(MODULES) + +#elua.c: $(LUA_LIBS) + +init.lua: template-init.lua make-init-lua.pl ../../epan/ftypes/ftypes.h ../../wiretap/wtap.h ../../epan/proto.h + $(PERL) make-init-lua.pl template-init.lua > init.lua + +!ENDIF +!ENDIF + +clean: + rm -f $(OBJECTS) lua.dll lua.exp lua.lib *.pdb init.lua + +distclean: clean + +maintainer-clean: distclean diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c new file mode 100644 index 0000000000..9e7132190d --- /dev/null +++ b/epan/wslua/init_wslua.c @@ -0,0 +1,323 @@ +/* + * packet-lua.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id$ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" +#include <epan/nstime.h> +#include <math.h> +#include <epan/expert.h> +#include <epan/ex-opt.h> +#include <epan/privileges.h> + +static lua_State* L = NULL; + +packet_info* lua_pinfo; +struct _wslua_treeitem* lua_tree; +tvbuff_t* lua_tvb; +int lua_malformed; +int lua_dissectors_table_ref; + +dissector_handle_t lua_data_handle; + + +static int wslua_not_register_menu(lua_State* LS) { + luaL_error(LS,"too late to register a menu"); + return 0; +} + +void dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree) { + lua_pinfo = pinfo; + lua_tvb = tvb; + + lua_tree = ep_alloc(sizeof(struct _wslua_treeitem)); + lua_tree->tree = tree; + lua_tree->item = proto_tree_add_text(tree,tvb,0,0,"lua fake item"); + PROTO_ITEM_SET_HIDDEN(lua_tree->item); + + /* + * almost equivalent to Lua: + * dissectors[current_proto](tvb,pinfo,tree) + */ + + lua_settop(L,0); + + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_dissectors_table_ref); + + lua_pushstring(L, pinfo->current_proto); + lua_gettable(L, -2); + + lua_remove(L,1); + + + if (lua_isfunction(L,1)) { + + push_Tvb(L,tvb); + push_Pinfo(L,pinfo); + push_TreeItem(L,lua_tree); + + if ( lua_pcall(L,3,0,0) ) { + const gchar* error = lua_tostring(L,-1); + + proto_item* pi = proto_tree_add_text(tree,tvb,0,0,"Lua Error: %s",error); + expert_add_info_format(pinfo, pi, PI_DEBUG, PI_ERROR ,"Lua Error"); + } + } else { + proto_item* pi = proto_tree_add_text(tree,tvb,0,0,"Lua Error: did not find the %s dissector" + " in the dissectors table",pinfo->current_proto); + + expert_add_info_format(pinfo, pi, PI_DEBUG, PI_ERROR ,"Lua Error"); + } + + clear_outstanding_tvbs(); + clear_outstanding_pinfos(); + clear_outstanding_trees(); + + + lua_pinfo = NULL; + lua_tree = NULL; + lua_tvb = NULL; + +} + +static void iter_table_and_call(lua_State* LS, int env, const gchar* table_name, lua_CFunction error_handler) { + lua_settop(LS,0); + + lua_pushcfunction(LS,error_handler); + lua_pushstring(LS, table_name); + lua_gettable(LS, env); + + if (!lua_istable(LS, 2)) { + report_failure("Lua: either `%s' does not exist or it is not a table!\n",table_name); + lua_close(LS); + L = NULL; + return; + } + + lua_pushnil(LS); + + while (lua_next(LS, 2)) { + const gchar* name = lua_tostring(L,-2); + + if (lua_isfunction(LS,-1)) { + + if ( lua_pcall(LS,0,0,1) ) { + lua_pop(LS,1); + } + + } else { + report_failure("Lua: Something not a function got its way into the %s.%s",table_name,name); + lua_close(LS); + L = NULL; + return; + } + } + + lua_settop(LS,0); +} + + +static int init_error_handler(lua_State* LS) { + const gchar* error = lua_tostring(LS,1); + report_failure("Lua: Error During execution of Initialization:\n %s",error); + return 0; +} + + +static void wslua_init_routine(void) { + static gboolean initialized = FALSE; + + if ( ! initialized ) { + lua_prime_all_fields(NULL); + initialized = TRUE; + } + + if (L) { + iter_table_and_call(L, LUA_GLOBALSINDEX, WSLUA_INIT_ROUTINES,init_error_handler); + } + +} + + +static const char *getF(lua_State *L _U_, void *ud, size_t *size) +{ + FILE *f=(FILE *)ud; + static char buff[512]; + if (feof(f)) return NULL; + *size=fread(buff,1,sizeof(buff),f); + return (*size>0) ? buff : NULL; +} + +static int lua_main_error_handler(lua_State* LS) { + const gchar* error = lua_tostring(LS,1); + report_failure("Lua: Error during loading:\n %s",error); + return 0; +} + +void lua_load_script(const gchar* filename) { + FILE* file; + + if (! ( file = fopen(filename,"r")) ) { + report_open_failure(filename,errno,FALSE); + return; + } + + lua_settop(L,0); + + lua_pushcfunction(L,lua_main_error_handler); + + switch (lua_load(L,getF,file,filename)) { + case 0: + lua_pcall(L,0,0,1); + fclose(file); + return; + case LUA_ERRSYNTAX: { + report_failure("Lua: syntax error during precompilation of `%s':\n%s",filename,lua_tostring(L,-1)); + fclose(file); + return; + } + case LUA_ERRMEM: + report_failure("Lua: memory allocation error during execution of %s",filename); + fclose(file); + return; + } + +} + +static void basic_logger(const gchar *log_domain _U_, + GLogLevelFlags log_level _U_, + const gchar *message, + gpointer user_data _U_) { + fputs(message,stderr); +} + +static int wslua_panic(lua_State* LS) { + g_error("LUA PANIC: %s",lua_tostring(LS,-1)); + return 0; +} + +int wslua_init(lua_State* LS) { + const gchar* filename; + const funnel_ops_t* ops = funnel_get_funnel_ops(); + gboolean run_anyway = FALSE; + + /* set up the logger */ + g_log_set_handler(LOG_DOMAIN_LUA, G_LOG_LEVEL_CRITICAL| + G_LOG_LEVEL_WARNING| + G_LOG_LEVEL_MESSAGE| + G_LOG_LEVEL_INFO| + G_LOG_LEVEL_DEBUG, + ops ? ops->logger : basic_logger, NULL); + + if (!L) { + if (LS) + L = LS; + else + L = luaL_newstate(); + } + + WSLUA_INIT(L); + + lua_atpanic(L,wslua_panic); + + /* the init_routines table (accessible by the user) */ + lua_pushstring(L, WSLUA_INIT_ROUTINES); + lua_newtable (L); + lua_settable(L, LUA_GLOBALSINDEX); + + /* the dissectors table goes in the registry (not accessible) */ + lua_newtable (L); + lua_dissectors_table_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + /* set running_superuser variable to it's propper value */ + WSLUA_REG_GLOBAL_BOOL(L,"running_superuser",started_with_special_privs()); + + /* load system's init.lua */ + filename = get_datafile_path("init.lua"); + + if (( file_exists(filename))) { + lua_load_script(filename); + } + + /* check if lua is to be disabled */ + lua_pushstring(L,"lua_disabled"); + lua_gettable(L, LUA_GLOBALSINDEX); + + if (lua_isboolean(L,-1) && lua_toboolean(L,-1)) { + /* disable lua */ + lua_close(L); + L = NULL; + return; + } + + /* check whether we should run other scripts even if running superuser */ + lua_pushstring(L,"run_user_scripts_when_superuser"); + lua_gettable(L, LUA_GLOBALSINDEX); + + if (lua_isboolean(L,-1) && lua_toboolean(L,-1)) { + run_anyway = TRUE; + } + + + /* if we are indeed superuser run user scripts only if told to do so */ + if ( (!started_with_special_privs()) || run_anyway ) { + filename = get_persconffile_path("init.lua", FALSE); + + if (( file_exists(filename))) { + lua_load_script(filename); + } + + while((filename = ex_opt_get_next("lua_script"))) { + lua_load_script(filename); + } + } + + /* at this point we're set up so register the init routine */ + register_init_routine(wslua_init_routine); + + /* + * after this point it is too late to register a menu + * disable the function to avoid weirdness + */ + lua_pushstring(L, "register_menu"); + lua_pushcfunction(L, wslua_not_register_menu); + lua_settable(L, LUA_GLOBALSINDEX); + + /* set up some essential globals */ + lua_pinfo = NULL; + lua_tree = NULL; + lua_tvb = NULL; + + lua_data_handle = find_dissector("data"); + lua_malformed = proto_get_id_by_filter_name("malformed"); + + Proto_commit(L); + + return 0; +} + +lua_State* wslua_state() { return L; } + diff --git a/epan/wslua/make-doc.pl b/epan/wslua/make-doc.pl new file mode 100755 index 0000000000..47d2b1cf1f --- /dev/null +++ b/epan/wslua/make-doc.pl @@ -0,0 +1,385 @@ +#!/usr/bin/perl +# +# make-doc.pl +# WSLUA's Reference Manual Generator +# +# (c) 2006, Luis E. Garcia Onatnon <luis.ontanon@gmail.com> +# +# $Id$ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# 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. +# +# (-: I don't even think writing this in Lua :-) + +use strict; +#use V2P; + +sub deb { +# warn $_[0]; +} + +sub gorolla { +# a gorilla stays to a chimp like ... stays to chomp +# but this one returns the shrugged string. + my $s = shift; + $s =~ s/^([\n]|\s)*//ms; + $s =~ s/([\n]|\s)*$//ms; + $s; +} + +my $class; +my %classes; +my $function; +my @functions; + +my %template = %{{ + class_header => "= %s =\n", + class_desc => "%s\n", + class_constructors_header => "== %s constructors ==\n", + class_methods_header => "== %s methods ==\n", + class_attributes_header => "== %s Attributes ==\n", + class_attr_header => "=== %s ===\n", + class_attr_descr => "%s\n", + function_header => "=== %s ===\n", + function_descr => "%s\n", + function_arg_header => "==== %s ====\n", + function_arg_descr => "%s\n", + function_argerrors_header => "'''Errors:'''\n", + function_argerror => " * %s\n", + function_returns_header => "==== returns ====\n", + function_returns => " * %s\n", + function_errors_header => "==== errors ====\n", + function_errors => " * %s\n", + non_method_functions_header => "= Non method functions =\n", +}}; + + +my %metamethods = %{{ + __tostring => "tostring(__)", + __index => "__[]", + __newindex => "__[] = ", + __add => "__ + __", + __sub => "__ - __", + __mul => "__ * __", + __div => "__ / __", + __mod => "__ % __", + __pow => "__ ^ __", + __unm => "-___", + __concat => "__ .. __", + __len => "#__", + __call => "()", + __eq => "__ == __", + __lt => "__ < __", + __le => "__ <= __", +}}; + +# It's said that only perl can parse perl... my editor isn't perl... +# if unencoded this causes my editor's autoindent to bail out so I encoded in octal +# XXX: support \" within "" +my $QUOTED_RE = "\042\050\133^\042\135*\051\042"; + +my $TRAILING_COMMENT_RE = '((\s*|[\n\r]*)/\*(.*?)\*/)?'; + +my @control = +( +# This will be scanned in order trying to match the re if it matches +# the body will be executed immediatelly after. + + [ 'WSLUA_CLASS_DEFINE\050\s*([A-Z][a-zA-Z]+)\s*,.*?\051' . $TRAILING_COMMENT_RE, +sub { + deb ">c=$1=$2=$3=$4=$5=$6=$7=\n"; + $class = { + name => $1, + descr=> gorolla($4), + constructors => [], + methods => [], + metamethods => [], + attributes => [] + }; + $classes{$1} = $class; +}], + +[ 'WSLUA_FUNCTION\s+wslua_([a-z_]+)[^\173]*\173' . $TRAILING_COMMENT_RE, +sub { + deb ">f=$1=$2=$3=$4=$5=$6=$7=\n"; + $function = { + returns => [], + arglist => [], + args => {}, + name => $1, + descr => gorolla($4), + type => 'standalone' + }; + push @functions, $function; +} ] , + +[ 'WSLUA_CONSTRUCTOR\s+([A-Za-z]+)_([a-z_]+).*?\173' . $TRAILING_COMMENT_RE, +sub { + deb ">cc=$1=$2=$3=$4=$5=$6=$7=\n"; + $function = { + returns => [], + arglist => [], + args => {}, + name => "$1.$2", + descr => gorolla($5), + type => 'constructor' + }; + push @{${$class}{constructors}}, $function; +} ] , + +[ 'WSLUA_METHOD\s+([A-Za-z]+)_([a-z_]+)[^\173]*\173' . $TRAILING_COMMENT_RE, + sub { + deb ">cm=$1=$2=$3=$4=$5=$6=$7=\n"; + $function = { + returns => [], + arglist => [], + args => {}, + name => "$1:$2", + descr => gorolla($5), + type => 'method' + }; + push @{${$class}{methods}}, $function; + } ] , + +[ 'WSLUA_METAMETHOD\s+([A-Za-z]+)(__[a-z]+)[^\173]*\173' . $TRAILING_COMMENT_RE, + sub { + deb ">cm=$1=$2=$3=$4=$5=$6=$7=\n"; + my $name = $metamethods{$2}; + my ($c,$d) = ($1,$5); + $name =~ s/__/$c/g; + $function = { + returns => [], + arglist => [], + args => {}, + name => $name, + descr => gorolla($d), + type => 'metamethod' + }; + push @{${$class}{metamethods}}, $function; + } ] , + +[ '#define WSLUA_(OPT)?ARG_([a-z_]+)_([A-Z0-9]+)\s+\d+' . $TRAILING_COMMENT_RE, +sub { + deb ">a=$1=$2=$3=$4=$5=$6=$7=\n"; + push @{${$function}{arglist}} , $3; + ${${$function}{args}}{$3} = {descr=>$6} +} ], + +[ '#define WSLUA_(OPT)?ARG_([A-Za-z]+)_([a-z_]+)_([A-Z0-9]+)\s+\d+' . $TRAILING_COMMENT_RE, +sub { + deb ">ca=$1=$2=$3=$4=$5=$6=$7=\n"; + push @{${$function}{arglist}} , $4; + ${${$function}{args}}{$4} = {descr=>$7} +} ], + +[ '/\052\s+WSLUA_ATTRIBUTE\s+([A-Za-z]+)_([a-z_]+)\s+([A-Z]*)\s*(.*?)\052/', + sub { + deb ">at=$1=$2=$3=$4=$5=$6=$7=\n"; + push @{${$class}{attributes}}, { name => $2, descr => gorolla($4), mode=>$3 }; + } ], + +[ '/\052\s+WSLUA_MOREARGS\s+([A-Za-z_]+)\s+(.*?)\052/', + sub { + deb ">ma=$1=$2=$3=$4=$5=$6=$7=\n"; + push @{${$function}{arglist}} , "..."; + ${${$function}{args}}{"..."} = {descr=>gorolla($2)} + } ], + +[ 'WSLUA_(FINAL_)?RETURN\050\s*.*?\s*\051\s*;' . $TRAILING_COMMENT_RE, +sub { + deb ">fr=$1=$2=$3=$4=$5=$6=$7=\n"; + push @{${$function}{returns}} , gorolla($4) if $4 ne ''; +} ], + +[ 'WSLUA_ERROR\s*\050\s*(([A-Z][A-Za-z]+)_)?([a-z_]+),' . $QUOTED_RE , + sub { + deb ">e=$1=$2=$3=$4=$5=$6=$7=\n"; + my $errors; + unless (exists ${$function}{errors}) { + $errors = ${$function}{errors} = []; + } else { + $errors = ${$function}{errors}; + } + + push @{$errors}, gorolla($4); + } ], + +[ 'WSLUA_(OPT)?ARG_ERROR\s*\050\s*(([A-Z][A-Za-z]+)_)?([a-z_]+)\s*,\s*([A-Z0-9]+)\s*,\s*' . $QUOTED_RE, + sub { + deb ">ae=$1=$2=$3=$4=$5=$6=$7=\n"; + my $errors; + unless (exists ${${${$function}{args}}{$5}}{errors}) { + $errors = ${${${$function}{args}}{$5}}{errors} = []; + } else { + $errors = ${${${$function}{args}}{$5}}{errors}; + } + + push @{$errors}, gorolla($6); + } ] , +); + +my $anymatch = '(^ThIsWiLlNeVeRmAtCh$'; +for (@control) { + $anymatch .= "|${$_}[0]"; +} +$anymatch .= ')'; + +# for each file given in the command line args +my $file; +while ( $file = shift) { + + next unless -f $file; + + my $docfile = $file; + $docfile =~ s/\.c$/.pod/; + + open C, "< $file"; + open D, "> doc/$docfile"; + + my $b = ''; + $b .= $_ while (<C>); + + while ($b =~ /$anymatch/ms ) { + my $match = $1; +# print "\n-----\n$match\n-----\n"; + for (@control) { + my ($re,$f) = @{$_}; + if ( $match =~ /$re/ms) { + &{$f}(); + $b =~ s/.*?$re//ms; + last; + } + } + } + + for my $cname (sort keys %classes) { + my $cl = $classes{$cname}; + printf D $template{class_header}, $cname; + printf D $template{class_desc} , ${$cl}{descr} if ${$cl}{descr}; + + if ( $#{${$cl}{constructors}} >= 0) { + printf D $template{class_constructors_header}, $cname; + + for my $c (@{${$cl}{constructors}}) { + function_descr($c); + } + + printf D $template{class_constructors_footer}, $cname; + } + + if ( $#{${$cl}{methods}} >= 0) { + printf D $template{class_methods_header}, $cname; + + for my $m (@{${$cl}{methods}}) { + function_descr($m); + } + + printf D $template{class_methods_footer}, $cname; + } + + if ( $#{${$cl}{metamethods}} >= 0) { + printf D $template{class_metamethods_header}, $cname; + + for my $m (@{${$cl}{metamethods}}) { + function_descr($m,${$m}{name}); + } + + printf D $template{class_metamethods_footer}, $cname; + } + + if ( $#{${$cl}{attributes}} >= 0) { + printf D $template{class_attributes_header}, $cname; + + for my $a (@{${$cl}{attributes}}) { + printf D $template{class_attr_header}, ${$a}{name}; + printf D $template{class_attr_descr}, ${$a}{descr} if ${$a}{descr}; + printf D $template{class_attr_footer}, ${$a}{name}; + + } + + printf D $template{class_attributes_footer}, $cname; + } + } + + if ($#functions >= 0) { + print D $template{non_method_functions_header}; + + for my $f (@functions) { + function_descr($f); + } + } + + %classes = (); + $class = undef; + $function = undef; + @functions = (); + close C; + close D; +} + +sub function_descr { + my $f = $_[0]; + my $label = $_[1]; + + if (defined $label ) { + printf D $template{function_header}, $label; + } else { + my $arglist = ''; + + for (@{ ${$f}{arglist} }) { + my $a = $_; + $a =~ tr/A-Z/a-z/; + $arglist .= "$a, "; + } + + $arglist =~ s/, $//; + + printf D $template{function_header}, "${$f}{name}($arglist)"; + } + + printf D $template{function_descr}, ${$f}{descr} if ${$f}{descr}; + + for my $argname (@{${$f}{arglist}}) { + my $arg = ${${$f}{args}}{$argname}; + $argname =~ tr/A-Z/a-z/; + + printf D $template{function_arg_header}, $argname; + printf D $template{function_arg_descr}, ${$arg}{descr} if ${$arg}{descr}; + + if ( $#{${$arg}{errors}} >= 0) { + printf D $template{function_argerrors_header}, $argname; + printf D $template{function_argerror}, $_ for @{${$arg}{errors}}; + printf D $template{function_argerrors_footer}, $argname; + } + + } + + if ( $#{${$f}{returns}} >= 0) { + printf D $template{function_returns_header}, ${$f}{name}; + printf D $template{function_returns}, $_ for @{${$f}{returns}}; + printf D $template{function_returns_footer}, ${$f}{name}; + } + + if ( $#{${$f}{errors}} >= 0) { + printf D $template{function_errors_header}, ${$f}{name}; + printf D $template{function_errors}, $_ for @{${$f}{errors}}; + printf D $template{function_errors_footer}, ${$f}{name}; + } + +} diff --git a/epan/wslua/make-init-lua.pl b/epan/wslua/make-init-lua.pl new file mode 100755 index 0000000000..23fbe3601b --- /dev/null +++ b/epan/wslua/make-init-lua.pl @@ -0,0 +1,121 @@ +#!/usr/bin/perl +# +# make-init-lua.pl +# +# create the init.lua file based on a template (stdin) +# +# (c) 2006, Luis E. Garcia Onatnon <luis.ontanon@gmail.com> +# +# $Id$ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 2004 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. + +use strict; + +my $WSROOT = "../.."; + +my $wtap_encaps_table = ''; +my $ft_types_table = ''; +my $bases_table = ''; +my $expert_pi = ''; + +my %replacements = %{{ + WTAP_ENCAPS => \$wtap_encaps_table, + FT_TYPES => \$ft_types_table, + BASES => \$bases_table, + EXPERT => \$expert_pi, +}}; + + +# +# load template +# +my $template = ''; +$template .= $_ while(<>); + + +# +# make wiretap encapusulation table +# + +$wtap_encaps_table = "-- Wiretap encapsulations\nwtap = {\n"; + +open WTAP_H, "< $WSROOT/wiretap/wtap.h"; + +while(<WTAP_H>) { + if ( /^#define WTAP_ENCAP_([A-Z0-9_]+)\s+(\d+)/ ) { + $wtap_encaps_table .= "\t[\"$1\"] = $2,\n"; + } +} + +$wtap_encaps_table =~ s/,\n$/\n}\n/msi; + +# +# enum fttype +# + +$ft_types_table = " -- Field Types\nftypes = {\n"; + +my $ftype_num = 0; + +open FTYPES_H, "< $WSROOT/epan/ftypes/ftypes.h"; +while(<FTYPES_H>) { + if ( /^\s+FT_([A-Z0-9a-z_]+)\s*,/ ) { + $ft_types_table .= "\t[\"$1\"] = $ftype_num,\n"; + $ftype_num++; + } +} +close FTYPES_H; + +$ft_types_table =~ s/,\n$/\n}\n/msi; + + + +# +# enum base +# + +$bases_table = "-- Display Bases\n base = {\n"; +$expert_pi = "-- Expert flags and facilities\n"; + +my $base_num = 0; + +open PROTO_H, "< $WSROOT/epan/proto.h"; +while(<PROTO_H>) { + if (/^\s+BASE_([A-Z_]+),/ ) { + $bases_table .= "\t[\"$1\"] = $base_num,\n"; + $base_num++; + } + + if ( /^.define\s+(PI_[A-Z_]+)\s+((0x)?[0-9A-Fa-f]+)/ ) { + my ($name, $value) = ($1, hex($2)); + $expert_pi .= "$name = $value\n"; + } +} +close PROTO_H; + +$bases_table .= "}\n\n"; +$expert_pi .= "\n\n"; + +for my $key (keys %replacements) { + $template =~ s/%$key%/${$replacements{$key}}/msig; +} + + +print $template; diff --git a/epan/wslua/make-reg.pl b/epan/wslua/make-reg.pl new file mode 100755 index 0000000000..78d989954c --- /dev/null +++ b/epan/wslua/make-reg.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +# +# make-reg.pl +# Registration Macros Generator +# +# (c) 2006, Luis E. Garcia Onatnon <luis.ontanon@gmail.com> +# +# $Id$ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# 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. + +use strict; + +my @classes = (); +my @functions = (); + +while (<>) { + push @classes, $1 if /WSLUA_CLASS_DEFINE\050\s*([A-Za-z]+)/; + push @functions, $1 if /WSLUA_FUNCTION\s+wslua_([a-z_]+)/; +} + +print "/* This file is automatically genrated by elua_makereg.pl do not edit */\n\n"; + +print "#define WSLUA_DECLARE_CLASSES() \\\n"; +for (@classes) { + print "\tWSLUA_CLASS_DECLARE($_);\\\n" +} +print "\n\n"; + +print "#define WSLUA_REGISTER_CLASSES() { \\\n"; +for (@classes) { + print "\t${_}_register(L);\\\n" +} +print "}\n\n"; + +print "#define WSLUA_DECLARE_FUNCTIONS() \\\n"; +for (@functions) { + print "\tWSLUA_FUNCTION wslua_$_(lua_State* L);\\\n" +} +print "\n\n"; + +print "#define WSLUA_REGISTER_FUNCTIONS() {\\\n"; +for (@functions) { + print "\t WSLUA_REGISTER_FUNCTION($_); \\\n" +} +print "}\n\n"; diff --git a/epan/wslua/make-taps.pl b/epan/wslua/make-taps.pl new file mode 100644 index 0000000000..f287907ffb --- /dev/null +++ b/epan/wslua/make-taps.pl @@ -0,0 +1,206 @@ +#!/usr/bin/perl +# +# make-taps.pl +# Extract structs from C headers to generate a function that +# pushes a lua table into the stack containing the elements of +# the struct. +# +# (c) 2006 Luis E. Garcia Ontanon <luis.ontanon@gmail.com> +# +# $Id$ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 2006 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. + +use strict; + +my %types = %{{ + 'gchar[]' => 'lua_pushstring(L,(char*)v->%s);', + 'gchar*' => 'lua_pushstring(L,(char*)v->%s);', + 'guint' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'guint8' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'guint16' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'guint32' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'gint' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'gint8' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'gint16' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'gint32' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'gboolean' => 'lua_pushboolean(L,(int)v->%s);', + 'address' => '{ Address a = g_malloc(sizeof(address)); COPY_ADDRESS(a, &(v->%s)); pushAddress(L,a); }', + 'address*' => '{ Address a = g_malloc(sizeof(address)); COPY_ADDRESS(a, v->%s); pushAddress(L,a); }', + 'int' => 'lua_pushnumber(L,(lua_Number)v->%s);', + 'nstime_t' => '{lua_Number t = v->%s.secs; t += v->%s.nsecs * 1e-9; lua_pushnumber(L,t); }', + 'nstime_t*' => '{lua_Number t = v->%s->secs; t += v->%s->nsecs * 1e-9; lua_pushnumber(L,t); }', +}}; + +my %comments = %{{ + 'gchar[]' => 'string', + 'gchar*' => 'string', + 'guint' => 'number', + 'guint8' => 'number', + 'guint16' => 'number', + 'guint32' => 'number', + 'gint' => 'number', + 'gint8' => 'number', + 'gint16' => 'number', + 'gint32' => 'number', + 'gboolean' => 'boolean', + 'address' => 'Address', + 'address*' => 'Address', + 'int' => 'number', + 'nstime_t' => 'number (seconds, since 1-1-1970 if absolute)', + 'nstime_t*' => 'number (seconds, since 1-1-1970 if absolute)', +}}; + + +my %functs = (); + +my %enums = (); + +sub dotap { + my ($tname,$fname,$sname,@enums) = @_; + my $buf = ''; + + open FILE, "< $fname"; + while(<FILE>) { + $buf .= $_; + } + close FILE; + + $buf =~ s@/\*.*?\*/@@; + + for my $ename (@enums) { + $enums{$ename} = []; + my $a = $enums{$ename}; + + my $enumre = "typedef\\s+enum[^{]*{([^}]*)}[\\s\\n]*${ename}[\\s\\n]*;"; + if ($buf =~ s/$enumre//ms ) { + $types{$ename} = "/*$ename*/ lua_pushnumber(L,(lua_Number)v->%s);"; + my $ebody = $1; + $ebody =~ s/\s+//msg; + $comments{$ename} = "$ename: { $ebody }"; + $comments{$ename} =~ s/,/|/g; + for (split /,/, $ebody) { + push @{$a}, $_; + } + } + } + + my $re = "typedef\\s+struct.*?{([^}]*)}[\\s\\n]*($sname)[\\s\\n]*;"; + my $body; + + while ($buf =~ s/$re//ms) { + $body = $1; + } + + die "could not find typedef $sname in $fname" if not defined $body and $sname ne "void"; + + my %elems = (); + + while($body =~ s/\s*(.*?)([\w\d_]+)\s*\[\s*\d+\s*\]\s*;//) { + my ($k,$v) = ($2,$1 . "[]"); + $v =~ s/\s+//g; + $elems{$k} = $v; + } + + while($body =~ s/\s*(.*?)([\w\d_]+)\s*;//) { + my ($k,$v) = ($2,$1); + $v =~ s/\s+//g; + $elems{$k} = $v; + } + + my $code = "void wslua_${tname}_to_table(lua_State* L, const void* p) { $sname* v = (void*)p; lua_newtable(L);\n"; + my $doc = "Tap: $tname\n"; + + for my $n (sort keys %elems) { + my $fmt = $types{$elems{$n}}; + + if ($fmt) { + $code .= "\tlua_pushstring(L,\"$n\"); "; + $code .= sprintf($fmt,$n,$n) . " lua_settable(L,-3);\n"; + $doc .= "\t$n: $comments{$elems{$n}}\n"; + } + + } + + $code .= "}\n\n"; + $doc .= "\n"; + + $functs{$tname} = "wslua_${tname}_to_table"; + + return ($code,$doc); +} + + +open TAPSFILE, "< $ARGV[0]"; +open CFILE, "> $ARGV[1]"; +open DOCFILE, "> $ARGV[2]"; + +print CFILE <<"HEADER"; +/* This file is autogenerated from ./taps by ./make-taps.pl */ +/* DO NOT EDIT! */ + +HEADER + +print DOCFILE "\n"; + +while (<TAPSFILE>) { + s@#.*@@; + next if /^\s*$/; + my ($tname,$fname,$sname,@enums) = split /\s+/; + my ($c,$doc) = dotap($tname,$fname,$sname,@enums); + print CFILE "#include \"$fname\"\n"; + print CFILE $c; + print DOCFILE $doc; +} + +print CFILE <<"TBLHDR"; +tappable_t tappables[] = { +TBLHDR + + for my $tname (sort keys %functs) { + print CFILE <<"TBLELEM"; + {"$tname", $functs{$tname} }, +TBLELEM + } + +print CFILE <<"TBLFTR"; + {"frame",NULL}, + {NULL,NULL} +}; + +void set_enums(lua_State* L) { +TBLFTR + + +for my $ename (sort keys %enums) { + print CFILE "\n\t/*\n\t * $ename\n\t */\n\tlua_pushstring(L,\"$ename\"); lua_newtable(L);\n"; + for my $a (@{$enums{$ename}}) { + print CFILE <<"ENUMELEM"; + lua_pushstring(L,"$a"); lua_pushnumber(L,(lua_Number)$a); lua_settable(L,LUA_GLOBALSINDEX); + lua_pushnumber(L,(lua_Number)$a); lua_pushstring(L,"$a"); lua_settable(L,-3); +ENUMELEM + } + print CFILE "\tlua_settable(L,LUA_GLOBALSINDEX);\n"; +} + +print CFILE "};\n"; +exit 0; + + + diff --git a/epan/wslua/taps b/epan/wslua/taps new file mode 100644 index 0000000000..a35d61ccf1 --- /dev/null +++ b/epan/wslua/taps @@ -0,0 +1,81 @@ +# taps +# instructions for make-taps.pl to generate the taps.c file +# +# (c) 2006 Luis E. Garcia Ontanon <luis.ontanon@gmail.com> +# +# $Id$ +# +# Wireshark - Network traffic analyzer +# By Gerald Combs <gerald@wireshark.org> +# Copyright 2006 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. + +# Each line is a tap type (the data structure passed by dissectors). +# Elements are separated by whitespace. +# tapname source_file_for_struct typedef_name_of_struct an_enum_name another_enum_name ... +# +# Note: Make sure you update the taps_used variable in Makefile.am +# every time you add a new file to the list + +#frame ../dissectors/packet_frame.h void + +ip ../dissectors/packet-ip.h e_ip +udp ../dissectors/packet-udp.h e_udphdr +http ../dissectors/packet-http.h http_info_value_t +h225 ../dissectors/packet-h225.h h225_packet_info h225_msg_type h225_cs_type + +#actrace +#afp +#ansi_a +#ansi_map +#bootp +#dcerpc +#dccp +#dtls +#epl +#eth +#fc +#fddi +#gsm_a +#gsm_map +#h245 +#h245dg +#wlan +#ipx +#isup +#jxta +#ldap +#mtp3 +#ncp_srt +#ncp_hdr +#ntlmssp +#q931 +#rpc +#rsvp +#rtpevent +#rtp +#scsi +#sctp +#sdp +#sip +#smb +#smb2 +#ssl +#t38 +#tcp +#teredo +#tr +#wsp diff --git a/epan/wslua/template-init.lua b/epan/wslua/template-init.lua new file mode 100644 index 0000000000..d1b139f4af --- /dev/null +++ b/epan/wslua/template-init.lua @@ -0,0 +1,61 @@ +-- init.lua +-- +-- initilaize ethereal's lua +-- +-- This file is going to be executed before any other lua script. +-- It can be used to load libraries, disable functions and more. +-- +-- $Id$ +-- +-- Wireshark - Network traffic analyzer +-- By Gerald Combs <gerald@wireshark.org> +-- 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. + + +-- If lua is to be disabled even if it was installed uncomment the following +-- line. +-- disable_lua = true; do return end; + + +-- If set and we are running with special privileges this setting +-- tells whether scripts other than this one are to be run. +run_user_scripts_when_superuser = false + +-- disable potentialy harmful lua functions when running superuser +if running_superuser then + dofile = function() error("dofile has been disabled") end + loadfile = function() error("loadfile has been disabled") end + loadlib = function() error("loadlib has been disabled") end + require = function() error("require has been disabled") end + os = {} + io = {} + file = {} +end + +-- to avoid output to stdout which can caause problems lua's print () +-- has been suppresed so that it yields an error. +-- have print() call info() instead. +print = info + +-- %WTAP_ENCAPS% + +-- %FT_TYPES% + +-- %BASES% + +-- %EXPERT% + diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h new file mode 100644 index 0000000000..6b87bb490d --- /dev/null +++ b/epan/wslua/wslua.h @@ -0,0 +1,338 @@ +/* + * wslua.h + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua.h 18231 2006-05-28 16:32:49Z etxrab $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#ifndef _PACKET_LUA_H +#define _PACKET_LUA_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <glib.h> +#include <errno.h> +#include <string.h> +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> +#include <wiretap/wtap.h> +#include <epan/packet.h> +#include <epan/strutil.h> +#include <epan/prefs.h> +#include <epan/proto.h> +#include <epan/epan_dissect.h> +#include <epan/tap.h> +#include <epan/filesystem.h> +#include <epan/report_err.h> +#include <epan/emem.h> +#include <epan/funnel.h> +#include <epan/tvbparse.h> +#include <epan/epan.h> + +#include "wslua_register.h" + +#define WSLUA_INIT_ROUTINES "init_routines" +#define LOG_DOMAIN_LUA "wslua" + +struct _wslua_tvbrange { + tvbuff_t* tvb; + int offset; + int len; +}; + +typedef struct _wslua_field_t { + int hfid; + int ett; + char* name; + char* abbr; + char* blob; + enum ftenum type; + base_display_e base; + value_string* vs; + guint32 mask; +} wslua_field_t; + +typedef enum {PREF_NONE,PREF_BOOL,PREF_UINT,PREF_STRING} pref_type_t; + +typedef struct _wslua_pref_t { + gchar* name; + gchar* label; + gchar* desc; + pref_type_t type; + union { + gboolean b; + guint u; + const gchar* s; + void* p; + } value; + + struct _wslua_pref_t* next; + struct _wslua_proto_t* proto; +} wslua_pref_t; + +typedef struct _wslua_proto_t { + gchar* name; + gchar* desc; + int hfid; + int ett; + wslua_pref_t prefs; + int fields; + module_t *prefs_module; + dissector_handle_t handle; + gboolean is_postdissector; +} wslua_proto_t; + +struct _wslua_distbl_t { + dissector_table_t table; + gchar* name; +}; + +struct _wslua_col_info { + column_info* cinfo; + gint col; +}; + +struct _wslua_treeitem { + proto_item* item; + proto_tree* tree; +}; + +#if 0 +struct _wslua_main { + capture_options capture_opts; +}; +#endif + +typedef void (*tap_extractor_t)(lua_State*,const void*); + +typedef struct { const char* name; tap_extractor_t extractor; } tappable_t; + +typedef struct {const gchar* str; enum ftenum id; } wslua_ft_types_t; + +typedef wslua_pref_t* Pref; +typedef wslua_pref_t* Prefs; +typedef struct _wslua_field_t* ProtoField; +typedef struct _wslua_proto_t* Proto; +typedef struct _wslua_distbl_t* DissectorTable; +typedef dissector_handle_t Dissector; +typedef GByteArray* ByteArray; +typedef tvbuff_t* Tvb; +typedef struct _wslua_tvbrange* TvbRange; +typedef struct _wslua_col_info* Column; +typedef column_info* Columns; +typedef packet_info* Pinfo; +typedef struct _wslua_treeitem* TreeItem; +typedef address* Address; +typedef header_field_info** Field; +typedef field_info* FieldInfo; +typedef struct _wslua_tap* Listener; +typedef funnel_text_window_t* TextWindow; +typedef wtap_dumper* Dumper; +typedef struct lua_pseudo_header* PseudoHeader; +typedef tvbparse_t* Parser; +typedef tvbparse_wanted_t* Rule; +typedef tvbparse_elem_t* Node; +typedef tvbparse_action_t* Shortcut; +typedef struct _wslua_main* WireShark; + +/* + * toXxx(L,idx) gets a Xxx from an index (Lua Error if fails) + * checkXxx(L,idx) gets a Xxx from an index after calling check_code (No Lua Error if it fails) + * pushXxx(L,xxx) pushes an Xxx into the stack + * isXxx(L,idx) tests whether we have an Xxx at idx + * + * LUA_CLASS_DEFINE must be used without trailing ';' + */ +#define WSLUA_CLASS_DEFINE(C,check_code,push_code) \ +C to##C(lua_State* L, int index) { \ + C* v = (C*)lua_touserdata (L, index); \ + if (!v) luaL_typerror(L,index,#C); \ + return *v; \ +} \ +C check##C(lua_State* L, int index) { \ + C* p; \ + luaL_checktype(L,index,LUA_TUSERDATA); \ + p = (C*)luaL_checkudata(L, index, #C); \ + check_code; \ + return p ? *p : NULL; \ +} \ +C* push##C(lua_State* L, C v) { \ + C* p = lua_newuserdata(L,sizeof(C)); *p = v; \ + luaL_getmetatable(L, #C); lua_setmetatable(L, -2); \ + push_code; \ + return p; \ +}\ +gboolean is##C(lua_State* L,int i) { \ + void *p; \ + if(!lua_isuserdata(L,i)) return FALSE; \ + p = lua_touserdata(L, i); \ + lua_getfield(L, LUA_REGISTRYINDEX, #C); \ + if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ + lua_pop(L, 2); \ + return p ? TRUE : FALSE; \ +} \ +C shift##C(lua_State* L,int i) { \ + C* p; \ + if(!lua_isuserdata(L,i)) return NULL; \ + p = lua_touserdata(L, i); \ + lua_getfield(L, LUA_REGISTRYINDEX, #C); \ + if (p == NULL || !lua_getmetatable(L, i) || !lua_rawequal(L, -1, -2)) p=NULL; \ + lua_pop(L, 2); \ + if (p) { lua_remove(L,i); return *p; }\ + else return NULL;\ +} \ +int dummy##C + +#ifdef HAVE_LUA_5_1 + +#define WSLUA_REGISTER_CLASS(C) { \ + luaL_register (L, #C, C ## _methods); \ + luaL_newmetatable (L, #C); \ + luaL_register (L, NULL, C ## _meta); \ + lua_pushliteral(L, "__index"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pushliteral(L, "__metatable"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pop(L, 1); \ +} + +#define WSLUA_REGISTER_META(C) luaL_newmetatable (L, #C); luaL_register (L, NULL, C ## _meta); + +#define WSLUA_INIT(L) \ + L = luaL_newstate(); \ + luaL_openlibs(L); \ + WSLUA_REGISTER_CLASSES(); \ + WSLUA_REGISTER_FUNCTIONS(); + + +#else /* Lua 5.0 */ + +#define WSLUA_REGISTER_CLASS(C) { \ + luaL_openlib(L, #C, C ## _methods, 0); \ + luaL_newmetatable(L, #C); \ + luaL_openlib(L, 0, C ## _meta, 0); \ + lua_pushliteral(L, "__index"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pushliteral(L, "__metatable"); \ + lua_pushvalue(L, -3); \ + lua_rawset(L, -3); \ + lua_pop(L, 1); \ +} + +#define WSLUA_REGISTER_META(C) luaL_newmetatable (L, #C); luaL_openlib (L, NULL, C ## _meta, 0); + +#define WSLUA_INIT(L) \ + if ( ! L) L = lua_open(); \ + luaopen_base(L); \ + luaopen_table(L); \ + luaopen_io(L); \ + luaopen_string(L); \ + WSLUA_REGISTER_CLASSES(); \ + WSLUA_REGISTER_FUNCTIONS(); + +#endif + +#define WSLUA_FUNCTION extern int +#define WSLUA_REGISTER_FUNCTION(name) { lua_pushstring(L, #name); lua_pushcfunction(L, wslua_## name); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REGISTER extern int + +#define WSLUA_METHOD static int +#define WSLUA_CONSTRUCTOR static int +#define WSLUA_ATTR_SET static int +#define WSLUA_ATTR_GET static int +#define WSLUA_METAMETHOD static int + +#define WSLUA_METHODS static const luaL_reg +#define WSLUA_META static const luaL_reg +#define WSLUA_CLASS_FNREG(class,name) { #name, class##_##name } + +#define WSLUA_ERROR(name,error) { luaL_error(L, #name ": " error); return 0; } +#define WSLUA_ARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_ARG_ ## name ## _ ## attr, #name ": " error); return 0; } +#define WSLUA_OPTARG_ERROR(name,attr,error) { luaL_argerror(L,WSLUA_OPTARG_##name##_ ##attr, #name ": " error); return 0; } + +#define WSLUA_REG_GLOBAL_BOOL(L,n,v) { lua_pushstring(L,n); lua_pushboolean(L,v); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REG_GLOBAL_STRING(n,v) { lua_pushstring(L,n); lua_pushstring(L,v); lua_settable(L, LUA_GLOBALSINDEX); } +#define WSLUA_REG_GLOBAL_NUMBER(n,v) { lua_pushstring(L,n); lua_pushnumber(L,v); lua_settable(L, LUA_GLOBALSINDEX); } + +#define WSLUA_RETURN(i) return (i); + +#define WSLUA_API extern + +#define NOP +#define FAIL_ON_NULL(s) if (! *p) luaL_argerror(L,index,s) + + + +#define WSLUA_CLASS_DECLARE(C) \ +extern C to##C(lua_State* L, int index); \ +extern C check##C(lua_State* L, int index); \ +extern C* push##C(lua_State* L, C v); \ +extern int C##_register(lua_State* L); \ +extern gboolean is##C(lua_State* L,int i); \ +extern C shift##C(lua_State* L,int i) + + +extern packet_info* lua_pinfo; +extern TreeItem lua_tree; +extern tvbuff_t* lua_tvb; +extern int lua_malformed; +extern dissector_handle_t lua_data_handle; +extern gboolean lua_initialized; +extern int lua_dissectors_table_ref; + +WSLUA_DECLARE_CLASSES() +WSLUA_DECLARE_FUNCTIONS() + +extern lua_State* wslua_state(void); + +extern const gchar* lua_shiftstring(lua_State* L,int idx); +extern void dissect_lua(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree); + +extern void proto_register_lua(void); +extern GString* lua_register_all_taps(void); +extern void lua_prime_all_fields(proto_tree* tree); + +extern int Proto_commit(lua_State* L); + +extern void* push_Tvb(lua_State* L, Tvb tvb); +extern void clear_outstanding_tvbs(void); + +extern void* push_Pinfo(lua_State* L, Pinfo p); +extern void clear_outstanding_pinfos(void); + +extern void* push_TreeItem(lua_State* L, TreeItem ti); +extern void clear_outstanding_trees(void); + +extern void wslua_print_stack(char* s, lua_State* L); + +extern int wslua_init(lua_State* L); + +extern int luaopen_libwireshark(lua_State* L); +#endif diff --git a/epan/wslua/wslua_dumper.c b/epan/wslua/wslua_dumper.c new file mode 100644 index 0000000000..539e60d982 --- /dev/null +++ b/epan/wslua/wslua_dumper.c @@ -0,0 +1,389 @@ +/* + * lua_dumper.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_dumper.c 18231 2006-05-28 16:32:49Z etxrab $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" +#include <math.h> + +WSLUA_CLASS_DEFINE(PseudoHeader,NOP,NOP); +/* + A pseudoheader to be used to save captured frames. + */ + +enum lua_pseudoheader_type { + PHDR_NONE, + PHDR_ETH, + PHDR_X25, + PHDR_ISDN, + PHDR_ATM, + PHDR_ASCEND, + PHDR_P2P, + PHDR_WIFI, + PHDR_COSINE, + PHDR_IRDA, + PHDR_NETTL, + PHDR_MTP2, + PHDR_K12 +}; + +struct lua_pseudo_header { + enum lua_pseudoheader_type type; + union wtap_pseudo_header* wph; +}; + +WSLUA_CONSTRUCTOR PseudoHeader_none(lua_State* L) { + /* + Creates a "no" pseudoheader. + + */ + PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header)); + ph->type = PHDR_NONE; + ph->wph = NULL; + + pushPseudoHeader(L,ph); + + WSLUA_RETURN(1); + /* A null pseudoheader */ +} + +WSLUA_CONSTRUCTOR PseudoHeader_eth(lua_State* L) { + /* + Creates an ethernet pseudoheader + */ + +#define WSLUA_OPTARG_PseudoHeader_eth_FCSLEN 1 /* the fcs lenght */ + + PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header)); + ph->type = PHDR_ETH; + ph->wph = g_malloc(sizeof(union wtap_pseudo_header)); + ph->wph->eth.fcs_len = luaL_optint(L,1,-1); + + pushPseudoHeader(L,ph); + + WSLUA_RETURN(1); /* The ethernet pseudoheader */ +} + +WSLUA_CONSTRUCTOR PseudoHeader_atm(lua_State* L) { + /* + Creates an ATM pseudoheader + */ +#define WSLUA_OPTARG_PseudoHeader_atm_AAL 1 /* AAL number */ +#define WSLUA_OPTARG_PseudoHeader_atm_VPI 2 /* VPI */ +#define WSLUA_OPTARG_PseudoHeader_atm_VCI 3 /* VCI */ +#define WSLUA_OPTARG_PseudoHeader_atm_CHANNEL 4 /* Channel */ +#define WSLUA_OPTARG_PseudoHeader_atm_CELLS 5 /* Number of cells in the PDU */ +#define WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U 6 /* AAL5 User to User indicator */ +#define WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN 7 /* AAL5 Len */ + + PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header)); + ph->type = PHDR_ATM; + ph->wph = g_malloc(sizeof(union wtap_pseudo_header)); + ph->wph->atm.aal = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL,5); + ph->wph->atm.vpi = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_VPI,1); + ph->wph->atm.vci = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_VCI,1); + ph->wph->atm.channel = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_CHANNEL,0); + ph->wph->atm.cells = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_CELLS,1); + ph->wph->atm.aal5t_u2u = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL5U2U,1); + ph->wph->atm.aal5t_len = luaL_optint(L,WSLUA_OPTARG_PseudoHeader_atm_AAL5LEN,0); + + pushPseudoHeader(L,ph); + WSLUA_RETURN(1); + /* The ATM pseudoheader */ +} + +WSLUA_CONSTRUCTOR PseudoHeader_mtp2(lua_State* L) { + /* Creates an MTP2 PseudoHeader */ +#define WSLUA_OPTARG_PseudoHeader_mtp2_SENT 1 /* True if the packet is sent, False if received. */ +#define WSLUA_OPTARG_PseudoHeader_mtp2_ANNEXA 2 /* True if annex A is used */ +#define WSLUA_OPTARG_PseudoHeader_mtp2_LINKNUM 3 /* Link Number */ + PseudoHeader ph = g_malloc(sizeof(struct lua_pseudo_header)); + ph->type = PHDR_MTP2; + ph->wph = g_malloc(sizeof(union wtap_pseudo_header)); + ph->wph->mtp2.sent = luaL_optint(L,1,0); + ph->wph->mtp2.annex_a_used = luaL_optint(L,2,0); + ph->wph->mtp2.link_number = luaL_optint(L,3,0); + + pushPseudoHeader(L,ph); + WSLUA_RETURN(1); /* The MTP2 pseudoheader */ +} + +#if 0 +static int PseudoHeader_x25(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +static int PseudoHeader_isdn(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +static int PseudoHeader_ascend(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +static int PseudoHeader_wifi(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +static int PseudoHeader_cosine(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +static int PseudoHeader_irda(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +static int PseudoHeader_nettl(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +static int PseudoHeader_k12(lua_State* L) { luaL_error(L,"not implemented"); return 0; } +#endif + +WSLUA_METHODS PseudoHeader_methods[] = { + WSLUA_CLASS_FNREG(PseudoHeader,mtp2), + WSLUA_CLASS_FNREG(PseudoHeader,atm), + WSLUA_CLASS_FNREG(PseudoHeader,eth), + WSLUA_CLASS_FNREG(PseudoHeader,none), + {0,0} +}; + +WSLUA_META PseudoHeader_meta[] = { + {0,0} +}; + +int PseudoHeader_register(lua_State* L) { + WSLUA_REGISTER_CLASS(PseudoHeader) + return 0; +} + + +WSLUA_CLASS_DEFINE(Dumper,FAIL_ON_NULL("Dumper already closed"),NOP); + +static GHashTable* dumper_encaps = NULL; +#define DUMPER_ENCAP(d) GPOINTER_TO_INT(g_hash_table_lookup(dumper_encaps,d)) + +WSLUA_CONSTRUCTOR Dumper_new(lua_State* L) { + /* + Creates a file to write packets. + Dumper:new_for_current() will probably be a better choice. + */ +#define WSLUA_ARG_Dumper_new_FILENAME 1 /* The name of the capture file to be created */ +#define WSLUA_OPTARG_Dumper_new_FILETYPE 2 /* The type of the file to be created */ +#define WSLUA_OPTARG_Dumper_new_ENCAP 3 /* The encapsulation to be used in the file to be created */ + Dumper d; + const char* filename = luaL_checkstring(L,1); + int filetype = luaL_optint(L,2,WTAP_FILE_PCAP); + int encap = luaL_optint(L,3,WTAP_ENCAP_ETHERNET); + int err = 0; + + if (! filename) return 0; + + if (!wtap_dump_can_write_encap(filetype, encap)) + WSLUA_ERROR(Dumper_new,"not every filetype handles every encap"); + + d = wtap_dump_open(filename, filetype, encap,0 , FALSE, &err); + + if (! d ) { + /* WSLUA_ERROR("error while opening file for writing"); */ + luaL_error(L,"error while opening `%s': %s", + filename, + wtap_strerror(err)); + return 0; + } + + g_hash_table_insert(dumper_encaps,d,GINT_TO_POINTER(encap)); + + pushDumper(L,d); + WSLUA_RETURN(1); + /* The newly created Dumper object */ +} + +WSLUA_METHOD Dumper_close(lua_State* L) { + /* Closes a dumper */ + Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper"); + int err; + + if (! *dp) + WSLUA_ERROR(Dumper_close,"Cannot operate on a closed dumper"); + + g_hash_table_remove(dumper_encaps,*dp); + + if (!wtap_dump_close(*dp, &err)) { + luaL_error(L,"error closing: %s", + wtap_strerror(err)); + } + + /* this way if we close a dumper any attempt to use it (for everything but GC) will yield an error */ + dp = NULL; + + return 0; +} + +WSLUA_METHOD Dumper_flush(lua_State* L) { + /* + Writes all unsaved data of a dumper to the disk. + */ + Dumper d = checkDumper(L,1); + + if (!d) return 0; + + wtap_dump_flush(d); + + return 0; +} + +WSLUA_METHOD Dumper_dump(lua_State* L) { + /* + Dumps an arbitrary packet. + Note: Dumper:dump_current() will fit best in most cases. + */ +#define WSLUA_ARG_Dumper_dump_TIMESTAMP 2 /* The absolute timestamp the packet will have */ +#define WSLUA_ARG_Dumper_dump_PSEUDOHEADER 3 /* The Pseudoheader to use. */ +#define WSLUA_ARG_Dumper_dump_BYTEARRAY 4 /* the data to be saved */ + + Dumper d = checkDumper(L,1); + PseudoHeader ph; + ByteArray ba; + struct wtap_pkthdr pkthdr; + double ts; + int err; + + if (!d) return 0; + + ts = luaL_checknumber(L,WSLUA_ARG_Dumper_dump_TIMESTAMP); + ph = checkPseudoHeader(L,WSLUA_ARG_Dumper_dump_PSEUDOHEADER); + + if (!ph) WSLUA_ARG_ERROR(Dumper_dump,TIMESTAMP,"need a PseudoHeader"); + + ba = checkByteArray(L,WSLUA_ARG_Dumper_dump_BYTEARRAY); + + if (! ba) WSLUA_ARG_ERROR(Dumper_dump,BYTEARRAY,"must be a ByteArray"); + + pkthdr.ts.secs = (int)floor(ts); + pkthdr.ts.nsecs = (int)floor(ts - pkthdr.ts.secs) * 1000000000; + pkthdr.len = ba->len; + pkthdr.caplen = ba->len; + pkthdr.pkt_encap = DUMPER_ENCAP(d); + + if (! wtap_dump(d, &pkthdr, ph->wph, ba->data, &err)) { + luaL_error(L,"error while dumping: %s", + wtap_strerror(err)); + } + + return 0; + +} + +WSLUA_METHOD Dumper_new_for_current(lua_State* L) { + /* + Creates a capture file using the same encapsulation as the one of the cuurrent packet + */ +#define WSLUA_OPTARG_Dumper_new_for_current_FILETYPE 2 /* The file type. Defaults to pcap. */ + Dumper d; + const char* filename = luaL_checkstring(L,1); + int filetype = luaL_optint(L,2,WTAP_FILE_PCAP); + int encap; + int err = 0; + + if (! lua_pinfo ) + WSLUA_ERROR(Dumper_new_for_current,"cannot be used outside a tap or a dissector"); + + encap = lua_pinfo->fd->lnk_t; + + if (!wtap_dump_can_write_encap(filetype, encap)) { + luaL_error(L,"Cannot write encap %s in filetype %s", + wtap_encap_short_string(encap), + wtap_file_type_string(filetype)); + return 0; + } + + d = wtap_dump_open(filename, filetype, encap, 0 , FALSE, &err); + + if (! d ) { + luaL_error(L,"error while opening `%s': %s", + filename, + wtap_strerror(err)); + return 0; + } + + pushDumper(L,d); + WSLUA_RETURN(1); /* The newly created Dumper Object */ + +} + +WSLUA_METHOD Dumper_dump_current(lua_State* L) { + /* + Dumps the current packet as it is. + */ + Dumper d = checkDumper(L,1); + struct wtap_pkthdr pkthdr; + const guchar* data; + tvbuff_t* data_src; + int err = 0; + + if (!d) return 0; + + if (! lua_pinfo ) WSLUA_ERROR(Dumper_new_for_current,"cannot be used outside a tap or a dissector"); + + data_src = ((data_source*)(lua_pinfo->data_src->data))->tvb; + + pkthdr.ts.secs = lua_pinfo->fd->abs_ts.secs; + pkthdr.ts.nsecs = lua_pinfo->fd->abs_ts.nsecs; + pkthdr.len = tvb_reported_length(data_src); + pkthdr.caplen = tvb_length(data_src); + pkthdr.pkt_encap = lua_pinfo->fd->lnk_t; + + data = ep_tvb_memdup(data_src,0,pkthdr.caplen); + + if (! wtap_dump(d, &pkthdr, lua_pinfo->pseudo_header, data, &err)) { + luaL_error(L,"error while dumping: %s", + wtap_strerror(err)); + } + + return 0; +} + +static int Dumper__gc(lua_State* L) { + Dumper* dp = (Dumper*)luaL_checkudata(L, 1, "Dumper"); + int err; + + /* If we are Garbage Collected it means the Dumper is no longer usable. Close it */ + + if (! *dp) + return 0; /* already closed, nothing to do! */ + + g_hash_table_remove(dumper_encaps,*dp); + + if (!wtap_dump_close(*dp, &err)) { + luaL_error(L,"error closing: %s", + wtap_strerror(err)); + } + + return 0; +} + + +WSLUA_METHODS Dumper_methods[] = { + {"new", Dumper_new}, + {"new_for_current", Dumper_new_for_current}, + {"close", Dumper_close}, + {"flush", Dumper_flush}, + {"dump", Dumper_dump}, + {"dump_current", Dumper_dump_current}, + {0, 0} +}; + +WSLUA_META Dumper_meta[] = { + {"__gc", Dumper__gc}, + {0, 0} +}; + +int Dumper_register(lua_State* L) { + dumper_encaps = g_hash_table_new(g_direct_hash,g_direct_equal); + WSLUA_REGISTER_CLASS(Dumper); + return 1; +} + diff --git a/epan/wslua/wslua_field.c b/epan/wslua/wslua_field.c new file mode 100644 index 0000000000..c440ce6bc2 --- /dev/null +++ b/epan/wslua/wslua_field.c @@ -0,0 +1,445 @@ +/* + * wslua_field.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_field.c 18231 2006-05-28 16:32:49Z etxrab $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" + +WSLUA_CLASS_DEFINE(FieldInfo,NOP,NOP); +/* + An extracted Field + */ + +WSLUA_METAMETHOD FieldInfo__len(lua_State* L) { + /* + The Length of the field + */ + FieldInfo fi = checkFieldInfo(L,1); + lua_pushnumber(L,fi->length); + return 1; +} + +WSLUA_METAMETHOD FieldInfo__unm(lua_State* L) { + /* + The Offset of the field + */ + FieldInfo fi = checkFieldInfo(L,1); + lua_pushnumber(L,fi->start); + return 1; +} + +WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { + /* + 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: + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + lua_pushnumber(L,(lua_Number)fvalue_get_integer(&(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) { + FieldInfo fi = checkFieldInfo(L,1); + if (fi) { + lua_pushstring(L,fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL)); + } + return 1; +} + +WSLUA_ATTR_GET FieldInfo_get_data_source(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + pushTvb(L,fi->ds_tvb); + return 1; +} + +WSLUA_ATTR_GET FieldInfo_get_range(lua_State* L) { + 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; +} + + +WSLUA_ATTR_GET FieldInfo_get_hidden(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + lua_pushboolean(L,FI_GET_FLAG(fi, FI_HIDDEN)); + return 1; +} + +WSLUA_ATTR_GET FieldInfo_get_generated(lua_State* L) { + FieldInfo fi = checkFieldInfo(L,1); + lua_pushboolean(L,FI_GET_FLAG(fi, FI_GENERATED)); + return 1; +} + +WSLUA_ATTR_GET FieldInfo_get_name(lua_State* L) { + 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}, + {"name", FieldInfo_get_name}, + {"label", FieldInfo__tostring}, + {"value", FieldInfo__call}, + {"len", FieldInfo__len}, + {"offset", FieldInfo__unm}, + {0, 0} +}; + +WSLUA_METAMETHOD 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) { + 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) { + 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 + r->length) { + lua_pushboolean(L,1); + return 1; + } else { + return 0; + } +} + +WSLUA_METAMETHOD FieldInfo__lt(lua_State* L) { + 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) { + GPtrArray* found = lua_tree->tree ? proto_all_finfos(lua_tree->tree) : NULL; + int items_found = 0; + guint i; + + if (found) { + for (i=0; i<found->len; 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) { + 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; i<found->len; i++) { + pushFieldInfo(L,g_ptr_array_index(found,i)); + items_found++; + } + } + } + + WSLUA_RETURN(items_found); /* All the values of this field */ +} + +static int Field_tostring(lua_State* L) { + 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; +} + + diff --git a/epan/wslua/wslua_gui.c b/epan/wslua/wslua_gui.c new file mode 100644 index 0000000000..9c7c563913 --- /dev/null +++ b/epan/wslua/wslua_gui.c @@ -0,0 +1,508 @@ +/* + * lua_gui.c + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_gui.c 18611 2006-06-29 13:49:56Z lego $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" + +static const funnel_ops_t* ops = NULL; + +struct _lua_menu_data { + lua_State* L; + int cb_ref; + int data_ref; +}; + +static int menu_cb_error_handler(lua_State* L) { + const gchar* error = lua_tostring(L,1); + report_failure("Lua: Error During execution of Menu Callback:\n %s",error); + return 0; +} + +WSLUA_FUNCTION wslua_gui_enabled(lua_State* L) { /* Checks whether the GUI facility is enabled. */ + lua_pushboolean(L,GPOINTER_TO_INT(ops)); + WSLUA_RETURN(1); /* A boolean: true if it is enabled, false if it isn't. */ +} + +void lua_menu_callback(gpointer data) { + struct _lua_menu_data* md = data; + + lua_pushcfunction(md->L,menu_cb_error_handler); + lua_rawgeti(md->L, LUA_REGISTRYINDEX, md->cb_ref); + lua_rawgeti(md->L, LUA_REGISTRYINDEX, md->data_ref); + + lua_pcall(md->L,1,0,1); + + return; +} + +WSLUA_FUNCTION wslua_register_menu(lua_State* L) { /* Register a menu item in the Statistics menu. */ +#define WSLUA_ARG_register_menu_NAME 1 /* The name of the menu item. */ +#define WSLUA_ARG_register_menu_ACTION 2 /* The function to be called when the menu item is invoked. */ +#define WSLUA_OPTARG_register_menu_USERDATA 3 /* To be passed to the action. */ + + const gchar* name = luaL_checkstring(L,WSLUA_ARG_register_menu_NAME); + struct _lua_menu_data* md; + gboolean retap = FALSE; + + if(!name) + WSLUA_ARG_ERROR(register_menu,NAME,"must be a string"); + + if (!lua_isfunction(L,WSLUA_ARG_register_menu_ACTION)) + WSLUA_ARG_ERROR(register_menu,ACTION,"must be a function"); + + md = g_malloc(sizeof(struct _lua_menu_data)); + md->L = L; + + lua_pushvalue(L, 2); + md->cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + if ( lua_gettop(L) > 2) { + lua_pushvalue(L, WSLUA_OPTARG_register_menu_USERDATA); + md->data_ref = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + md->data_ref = LUA_NOREF; + } + + funnel_register_menu(name, + REGISTER_STAT_GROUP_GENERIC, + lua_menu_callback, + md, + retap); + + WSLUA_RETURN(0); +} + + + + +struct _dlg_cb_data { + lua_State* L; + int func_ref; + int data_ref; +}; + +static int dlg_cb_error_handler(lua_State* L) { + const gchar* error = lua_tostring(L,1); + report_failure("Lua: Error During execution of dialog callback:\n %s",error); + return 0; +} + +static void lua_dialog_cb(gchar** user_input, void* data) { + struct _dlg_cb_data* dcbd = data; + int i = 0; + gchar* input; + lua_State* L = dcbd->L; + + lua_settop(L,0); + lua_pushcfunction(L,dlg_cb_error_handler); + lua_rawgeti(L, LUA_REGISTRYINDEX, dcbd->func_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, dcbd->data_ref); + + for (i = 0; (input = user_input[i]) ; i++) { + lua_pushstring(L,input); + g_free(input); + } + + g_free(user_input); + + switch ( lua_pcall(L,i+1,0,1) ) { + case 0: + break; + case LUA_ERRRUN: + g_warning("Runtime error while calling dialog callback"); + break; + case LUA_ERRMEM: + g_warning("Memory alloc error while calling dialog callback"); + break; + default: + g_assert_not_reached(); + break; + } + +} + +WSLUA_FUNCTION wslua_new_dialog(lua_State* L) { /* Pops up a new dialog */ +#define WSLUA_ARG_new_dialog_TITLE 1 /* Title of the dialog's window. */ +#define WSLUA_ARG_new_dialog_ACTION 2 /* Action to be performed when OKd. */ +/* WSLUA_MOREARGS new_dialog A series of strings to be used as labels of the dialog's fields */ + + const gchar* title; + int top = lua_gettop(L); + int i; + GPtrArray* labels; + struct _dlg_cb_data* dcbd; + + if (! ops) { + luaL_error(L,"the GUI facility has to be enabled"); + return 0; + } + + if (! (title = luaL_checkstring(L,WSLUA_ARG_new_dialog_TITLE)) ) { + WSLUA_ARG_ERROR(new_dialog,TITLE,"must be a string"); + return 0; + } + + if (! lua_isfunction(L,WSLUA_ARG_new_dialog_ACTION)) { + WSLUA_ARG_ERROR(new_dialog,ACTION,"must be a function"); + return 0; + } + + if (top < 3) { + WSLUA_ERROR(new_dialog,"at least one field required"); + return 0; + } + + + dcbd = g_malloc(sizeof(struct _dlg_cb_data)); + dcbd->L = L; + + lua_remove(L,1); + + lua_pushvalue(L, 1); + dcbd->func_ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_remove(L,1); + + lua_pushvalue(L, 1); + dcbd->data_ref = luaL_ref(L, LUA_REGISTRYINDEX); + lua_remove(L,1); + + labels = g_ptr_array_new(); + + top -= 3; + + for (i = 1; i <= top; i++) { + gchar* label = (void*)luaL_checkstring(L,i); + + /* XXX leaks labels on error */ + if (! label) + WSLUA_ERROR(new_dialog,"all fields must be strings"); + + g_ptr_array_add(labels,label); + } + + g_ptr_array_add(labels,NULL); + + ops->new_dialog(title, (const gchar**)labels->pdata, lua_dialog_cb, dcbd); + + g_ptr_array_free(labels,TRUE); + + WSLUA_RETURN(0); +} + + + +WSLUA_CLASS_DEFINE(TextWindow,NOP,NOP); /* Manages a text window. */ + +WSLUA_CONSTRUCTOR TextWindow_new(lua_State* L) { /* Creates a new TextWindow. */ +#define WSLUA_OPTARG_TextWindow_new_TITLE 1 /* Title of the new window. */ + + const gchar* title; + TextWindow tw; + + title = luaL_optstring(L,WSLUA_OPTARG_TextWindow_new_TITLE,"Untitled Window"); + tw = ops->new_text_window(title); + pushTextWindow(L,tw); + + WSLUA_RETURN(1); /* The newly created TextWindow object. */ +} + +struct _close_cb_data { + lua_State* L; + int func_ref; + int data_ref; +}; + +int text_win_close_cb_error_handler(lua_State* L) { + const gchar* error = lua_tostring(L,1); + report_failure("Lua: Error During execution of TextWindow close callback:\n %s",error); + return 0; +} + +static void text_win_close_cb(void* data) { + struct _close_cb_data* cbd = data; + lua_State* L = cbd->L; + + lua_pushcfunction(L,text_win_close_cb_error_handler); + lua_rawgeti(L, LUA_REGISTRYINDEX, cbd->func_ref); + lua_rawgeti(L, LUA_REGISTRYINDEX, cbd->data_ref); + + switch ( lua_pcall(L,1,0,1) ) { + case 0: + break; + case LUA_ERRRUN: + g_warning("Runtime error during execution of TextWindow close callback"); + break; + case LUA_ERRMEM: + g_warning("Memory alloc error during execution of TextWindow close callback"); + break; + default: + g_assert_not_reached(); + break; + } +} + +WSLUA_METHOD TextWindow_set_atclose(lua_State* L) { /* Set the function that will be called when the window closes */ +#define WSLUA_ARG_TextWindow_at_close_ACTION 2 /* A function to be executed when the user closes the window */ + + TextWindow tw = checkTextWindow(L,1); + struct _close_cb_data* cbd; + + if (!tw) + WSLUA_ERROR(TextWindow_at_close,"cannot be called for something not a TextWindow"); + + lua_settop(L,3); + + if (! lua_isfunction(L,2)) + WSLUA_ARG_ERROR(TextWindow_at_close,ACTION,"must be a function"); + + cbd = g_malloc(sizeof(struct _close_cb_data)); + + cbd->L = L; + cbd->data_ref = luaL_ref(L, LUA_REGISTRYINDEX); + cbd->func_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + ops->set_close_cb(tw,text_win_close_cb,cbd); + + pushTextWindow(L,tw); + WSLUA_RETURN(1); /* The TextWindow object. */ +} + +WSLUA_METHOD TextWindow_set(lua_State* L) { /* Sets the text. */ +#define WSLUA_ARG_TextWindow_set_TEXT 2 /* The text to be used. */ + + TextWindow tw = checkTextWindow(L,1); + const gchar* text = luaL_checkstring(L,2); + + if (!tw) + WSLUA_ERROR(TextWindow_set,"cannot be called for something not a TextWindow"); + + if (!text) + WSLUA_ARG_ERROR(TextWindow_set,TEXT,"must be a string"); + + ops->set_text(tw,text); + + pushTextWindow(L,tw); + WSLUA_RETURN(1); /* The TextWindow object. */ +} + +WSLUA_METHOD TextWindow_append(lua_State* L) { /* Appends text */ +#define WSLUA_ARG_TextWindow_append_TEXT 2 /* The text to be appended */ + TextWindow tw = checkTextWindow(L,1); + const gchar* text = luaL_checkstring(L,2); + + if (!tw) + WSLUA_ERROR(TextWindow_append,"cannot be called for something not a TextWindow"); + + if (!text) + WSLUA_ARG_ERROR(TextWindow_append,TEXT,"must be a string"); + + ops->append_text(tw,text); + + pushTextWindow(L,tw); + WSLUA_RETURN(1); /* The TextWindow object. */ +} + +WSLUA_METHOD TextWindow_prepend(lua_State* L) { /* Prepends text */ +#define WSLUA_ARG_TextWindow_prepend_TEXT 2 /* The text to be appended */ + TextWindow tw = checkTextWindow(L,1); + const gchar* text = luaL_checkstring(L,2); + + if (!tw) + WSLUA_ERROR(TextWindow_prepend,"cannot be called for something not a TextWindow"); + + if (!text) + WSLUA_ARG_ERROR(TextWindow_prepend,TEXT,"must be a string"); + + ops->prepend_text(tw,text); + + pushTextWindow(L,tw); + WSLUA_RETURN(1); /* The TextWindow object. */ +} + +WSLUA_METHOD TextWindow_clear(lua_State* L) { /* Errases all text in the window. */ + TextWindow tw = checkTextWindow(L,1); + + if (!tw) + WSLUA_ERROR(TextWindow_clear,"cannot be called for something not a TextWindow"); + + ops->clear_text(tw); + + pushTextWindow(L,tw); + WSLUA_RETURN(1); /* The TextWindow object. */ +} + +WSLUA_METHOD TextWindow_get_text(lua_State* L) { /* Get the text of the window */ + TextWindow tw = checkTextWindow(L,1); + const gchar* text; + + if (!tw) + WSLUA_ERROR(TextWindow_get_text,"cannot be called for something not a TextWindow"); + + text = ops->get_text(tw); + + lua_pushstring(L,text); + WSLUA_RETURN(1); /* The TextWindow's text. */ +} + +static int TextWindow__gc(lua_State* L) { + TextWindow tw = checkTextWindow(L,1); + + if (!tw) + WSLUA_ERROR(TextWindow_gc,"cannot be called for something not a TextWindow"); + + ops->destroy_text_window(tw); + return 1; +} + +WSLUA_METHOD TextWindow_set_editable(lua_State* L) { /* Set the function that will be called when the window closes */ +#define WSLUA_OPTARG_TextWindow_at_close_EDITABLE 2 /* A boolean flag, defaults to true */ + + TextWindow tw = checkTextWindow(L,1); + gboolean editable = luaL_optint(L,2,1); + + if (!tw) + WSLUA_ERROR(TextWindow_at_close,"cannot be called for something not a TextWindow"); + + if (ops->set_editable) + ops->set_editable(tw,editable); + + pushTextWindow(L,tw); + WSLUA_RETURN(1); /* The TextWindow object. */ +} + +typedef struct _wslua_bt_cb_t { + lua_State* L; + int func_ref; + int data_ref; +} wslua_bt_cb_t; + +static gboolean wslua_button_callback(funnel_text_window_t* tw, void* data) { + wslua_bt_cb_t* cbd = data; + lua_State* L = cbd->L; + + lua_settop(L,0); + lua_pushcfunction(L,dlg_cb_error_handler); + lua_rawgeti(L, LUA_REGISTRYINDEX, cbd->func_ref); + pushTextWindow(L,tw); + lua_rawgeti(L, LUA_REGISTRYINDEX, cbd->data_ref); + + switch ( lua_pcall(L,2,0,1) ) { + case 0: + break; + case LUA_ERRRUN: + g_warning("Runtime error while calling button callback"); + break; + case LUA_ERRMEM: + g_warning("Memory alloc error while calling button callback"); + break; + default: + g_assert_not_reached(); + break; + } + + return TRUE; +} + +WSLUA_METHOD TextWindow_add_button(lua_State* L) { +#define WSLUA_ARG_TextWindow_add_button_LABEL 2 /* The label of the button */ +#define WSLUA_ARG_TextWindow_add_button_FUNCTION 3 /* The function to be called when clicked */ +#define WSLUA_ARG_TextWindow_add_button_DATA 4 /* The data to be passed to the function (other than the window) */ + TextWindow tw = checkTextWindow(L,1); + const gchar* label = luaL_checkstring(L,WSLUA_ARG_TextWindow_add_button_LABEL); + + funnel_bt_t* fbt; + wslua_bt_cb_t* cbd; + + if (!tw) + WSLUA_ERROR(TextWindow_at_close,"cannot be called for something not a TextWindow"); + + if (! lua_isfunction(L,WSLUA_ARG_TextWindow_add_button_FUNCTION) ) + WSLUA_ARG_ERROR(TextWindow_add_button,FUNCTION,"must be a function"); + + lua_settop(L,4); + + if (ops->add_button) { + fbt = ep_alloc(sizeof(funnel_bt_t)); + cbd = ep_alloc(sizeof(wslua_bt_cb_t)); + + fbt->tw = tw; + fbt->func = wslua_button_callback; + fbt->data = cbd; + + cbd->L = L; + cbd->data_ref = luaL_ref(L, LUA_REGISTRYINDEX); + cbd->func_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + ops->add_button(tw,fbt,label); + } + + pushTextWindow(L,tw); + WSLUA_RETURN(1); /* The TextWindow object. */ +} + +WSLUA_METHODS TextWindow_methods[] = { + WSLUA_CLASS_FNREG(TextWindow,new), + WSLUA_CLASS_FNREG(TextWindow,set), + WSLUA_CLASS_FNREG(TextWindow,new), + WSLUA_CLASS_FNREG(TextWindow,append), + WSLUA_CLASS_FNREG(TextWindow,prepend), + WSLUA_CLASS_FNREG(TextWindow,clear), + WSLUA_CLASS_FNREG(TextWindow,set_atclose), + WSLUA_CLASS_FNREG(TextWindow,set_editable), + WSLUA_CLASS_FNREG(TextWindow,get_text), + WSLUA_CLASS_FNREG(TextWindow,add_button), + {0, 0} +}; + +WSLUA_META TextWindow_meta[] = { + {"__tostring", TextWindow_get_text}, + {"__gc", TextWindow__gc}, + {0, 0} +}; + +int TextWindow_register(lua_State* L) { + + ops = funnel_get_funnel_ops(); + + WSLUA_REGISTER_CLASS(TextWindow); + + return 1; +} + + +WSLUA_FUNCTION wslua_retap_packets(lua_State* L) { + /* + Rescan all packets and just run taps - don't reconstruct the display. + */ + if ( ops->retap_packets ) { + ops->retap_packets(); + } else { + WSLUA_ERROR(wslua_retap_packets, "does not work on TShark"); + } + + return 0; +} + + diff --git a/epan/wslua/wslua_listener.c b/epan/wslua/wslua_listener.c new file mode 100644 index 0000000000..e7b9dd73ff --- /dev/null +++ b/epan/wslua/wslua_listener.c @@ -0,0 +1,332 @@ +/* + * wslua_tap.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_tap.c 18268 2006-05-31 17:38:42Z gerald $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" + +/* generated file gets included */ +#include "taps.c-inc" + +WSLUA_CLASS_DEFINE(Listener,NOP,NOP); +/* + A Listener, is called once for every packet that matches a certain filter or has a certain tap. + It can read the tree, the packet's Tvb eventually the tapped data but it cannot + add elements to the tree. + */ +struct _wslua_tap { + gchar* name; + gchar* filter; + tap_extractor_t extractor; + lua_State* L; + int packet_ref; + int draw_ref; + int init_ref; +}; + +tap_extractor_t get_extractor(const gchar* name) { + tappable_t* t; + for(t = tappables; t->name; t++ ) { + if (g_str_equal(t->name,name)) return t->extractor; + } + + return NULL; +} + +int tap_packet_cb_error_handler(lua_State* L) { + const gchar* error = lua_tostring(L,1); + static gchar* last_error = NULL; + static int repeated = 0; + static int next = 2; + const gchar* where = (lua_pinfo) ? + ep_strdup_printf("Lua: on packet %i Error During execution of Listener Packet Callback",lua_pinfo->fd->num) : + ep_strdup_printf("Lua: Error During execution of Listener Packet Callback") ; + + /* show the error the 1st, 3rd, 5th, 9th, 17th, 33th... time it appears to avoid window flooding */ + /* XXX the last series of identical errors won't be shown (the user however gets at least one message) */ + + if (! last_error) { + report_failure("%s:\n%s",where,error); + last_error = g_strdup(error); + repeated = 0; + next = 2; + return 0; + } + + if (g_str_equal(last_error,error) ) { + repeated++; + if ( repeated == next ) { + report_failure("%s happened %i times:\n %s",where,repeated,error); + next *= 2; + } + } else { + report_failure("%s happened %i times:\n %s",where,repeated,last_error); + g_free(last_error); + last_error = g_strdup(error); + repeated = 0; + next = 2; + report_failure("%s:\n %s",where,error); + } + + return 0; +} + + +int lua_tap_packet(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *data) { + Listener tap = tapdata; + int retval = 0; + + if (tap->packet_ref == LUA_NOREF) return 0; + + lua_settop(tap->L,0); + + lua_pushcfunction(tap->L,tap_packet_cb_error_handler); + lua_rawgeti(tap->L, LUA_REGISTRYINDEX, tap->packet_ref); + + push_Pinfo(tap->L, pinfo); + push_Tvb(tap->L, edt->tvb); + + if (tap->extractor) { + tap->extractor(tap->L,data); + } else { + lua_pushnil(tap->L); + } + + lua_pinfo = pinfo; + lua_tvb = edt->tvb; + lua_tree = ep_alloc(sizeof(struct _wslua_treeitem)); + lua_tree->tree = edt->tree; + lua_tree->item = NULL; + + switch ( lua_pcall(tap->L,3,1,1) ) { + case 0: + + if (lua_gettop(tap->L) == 1) + retval = luaL_checkint(tap->L,1); + else + retval = 1; + + break; + case LUA_ERRRUN: + break; + case LUA_ERRMEM: + g_warning("Memory alloc error while calling listenet tap callback packet"); + break; + default: + g_assert_not_reached(); + break; + } + + clear_outstanding_pinfos(); + clear_outstanding_tvbs(); + + lua_pinfo = NULL; + lua_tvb = NULL; + lua_tree = NULL; + + return retval; +} + +int tap_reset_cb_error_handler(lua_State* L) { + const gchar* error = lua_tostring(L,1); + report_failure("Lua: Error During execution of Listener init Callback:\n %s",error); + return 1; +} + +void lua_tap_reset(void *tapdata) { + Listener tap = tapdata; + + if (tap->init_ref == LUA_NOREF) return; + + lua_pushcfunction(tap->L,tap_reset_cb_error_handler); + lua_rawgeti(tap->L, LUA_REGISTRYINDEX, tap->init_ref); + + switch ( lua_pcall(tap->L,0,0,1) ) { + case 0: + break; + case LUA_ERRRUN: + g_warning("Runtime error while calling a listener's init()"); + break; + case LUA_ERRMEM: + g_warning("Memory alloc error while calling a listener's init()"); + break; + default: + g_assert_not_reached(); + break; + } +} + +int tap_draw_cb_error_handler(lua_State* L) { + const gchar* error = lua_tostring(L,1); + report_failure("Lua: Error During execution of Listener Draw Callback:\n %s",error); + return 1; +} + +void lua_tap_draw(void *tapdata) { + Listener tap = tapdata; + const gchar* error; + if (tap->draw_ref == LUA_NOREF) return; + + lua_pushcfunction(tap->L,tap_reset_cb_error_handler); + lua_rawgeti(tap->L, LUA_REGISTRYINDEX, tap->draw_ref); + + switch ( lua_pcall(tap->L,0,0,1) ) { + case 0: + /* OK */ + break; + case LUA_ERRRUN: + error = lua_tostring(tap->L,-1); + g_warning("Runtime error while calling a listener's draw(): %s",error); + break; + case LUA_ERRMEM: + g_warning("Memory alloc error while calling a listener's draw()"); + break; + default: + g_assert_not_reached(); + break; + } +} + +WSLUA_CONSTRUCTOR Listener_new(lua_State* L) { + /* Creates a new Listener listener */ +#define WSLUA_OPTARG_Listener_new_TAP 1 /* the name of this tap */ +#define WSLUA_OPTARG_Listener_new_FILTER 2 /* a filter that when matches the tap.packet function gets called (use nil to be called for every packet) */ + + const gchar* tap_type = luaL_optstring(L,WSLUA_OPTARG_Listener_new_TAP,"frame"); + const gchar* filter = luaL_optstring(L,WSLUA_OPTARG_Listener_new_FILTER,NULL); + Listener tap; + GString* error; + + tap = g_malloc(sizeof(struct _wslua_tap)); + + tap->name = g_strdup(tap_type); + tap->filter = filter ? g_strdup(filter) : NULL; + tap->extractor = get_extractor(tap_type); + tap->L = L; + tap->packet_ref = LUA_NOREF; + tap->draw_ref = LUA_NOREF; + tap->init_ref = LUA_NOREF; + + error = register_tap_listener(tap_type, tap, tap->filter, lua_tap_reset, lua_tap_packet, lua_tap_draw); + + if (error) { + if (tap->filter) g_free(tap->filter); + g_free(tap->name); + g_free(tap); + /* WSLUA_ERROR(new_tap,"tap registration error"); */ + luaL_error(L,"Error while registering tap:\n%s",error->str); + g_string_free(error,TRUE); /* XXX LEAK? */ + } + + pushListener(L,tap); + WSLUA_RETURN(1); /* The newly created Listener listener object */ +} + +WSLUA_METHOD Listener_remove(lua_State* L) { + /* Removes a tap listener */ + Listener tap = checkListener(L,1); + + if (!tap) return 0; + + remove_tap_listener(tap); + + return 0; +} + +static int Listener_tostring(lua_State* L) { + Listener tap = checkListener(L,1); + gchar* str; + + if (!tap) return 0; + + str = g_strdup_printf("Listener(%s) filter: %s",tap->name, tap->filter ? tap->filter : "NONE"); + lua_pushstring(L,str); + g_free(str); + + return 1; +} + + +static int Listener_newindex(lua_State* L) { + /* WSLUA_ATTRIBUTE Listener_packet WO A function that will be called once every packet matches the Listener listener filter. + + function tap.packet(pinfo,tvb,userdata) ... end + */ + /* WSLUA_ATTRIBUTE Listener_draw WO A function that will be called once every few seconds to redraw the gui objects + in tshark this funtion is called oly at the very end of the capture file. + + function tap.draw(userdata) ... end + */ + /* WSLUA_ATTRIBUTE Listener_reset WO A function that will be called at the end of the capture run. + + function tap.reset(userdata) ... end + */ + Listener tap = shiftListener(L,1); + const gchar* index = lua_shiftstring(L,1); + int* refp = NULL; + + if (!index) return 0; + + if (g_str_equal(index,"packet")) { + refp = &(tap->packet_ref); + } else if (g_str_equal(index,"draw")) { + refp = &(tap->draw_ref); + } else if (g_str_equal(index,"reset")) { + refp = &(tap->init_ref); + } else { + luaL_error(L,"No such attribute `%s' for a tap",index); + return 0; + } + + if (! lua_isfunction(L,1)) { + luaL_error(L,"Listener's attribute `%s' must be a function"); + return 0; + } + + lua_pushvalue(L, 1); + *refp = luaL_ref(L, LUA_REGISTRYINDEX); + + return 0; +} + + +static const luaL_reg Listener_methods[] = { + {"new", Listener_new}, + {"remove", Listener_remove}, + {0, 0} +}; + +static const luaL_reg Listener_meta[] = { + {"__tostring", Listener_tostring}, + {"__newindex", Listener_newindex}, + {0, 0} +}; + +int Listener_register(lua_State* L) { + WSLUA_REGISTER_CLASS(Listener); + return 1; +} + diff --git a/epan/wslua/wslua_pinfo.c b/epan/wslua/wslua_pinfo.c new file mode 100644 index 0000000000..9037505857 --- /dev/null +++ b/epan/wslua/wslua_pinfo.c @@ -0,0 +1,888 @@ +/* + * wslua_pinfo.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_pinfo.c 18231 2006-05-28 16:32:49Z etxrab $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" + +#include <epan/addr_resolv.h> +#include <string.h> + + +/* + * NULLify lua userdata to avoid crashing when trying to + * access saved copies of invalid stuff. + * + * see comment on lua_tvb.c + */ + +static GPtrArray* outstanding_stuff = NULL; + +void clear_outstanding_pinfos(void) { + while (outstanding_stuff->len) { + void** p = (void**)g_ptr_array_remove_index_fast(outstanding_stuff,0); + *p = NULL; + } +} + +void* push_Pinfo(lua_State* L, Pinfo pinfo) { + void** p = (void**)pushPinfo(L,pinfo); + g_ptr_array_add(outstanding_stuff,p); + return p; +} + +#define PUSH_COLUMN(L,c) g_ptr_array_add(outstanding_stuff,pushColumn(L,c)) +#define PUSH_COLUMNS(L,c) g_ptr_array_add(outstanding_stuff,pushColumns(L,c)) + +WSLUA_CLASS_DEFINE(Address,NOP,NOP); + +WSLUA_CONSTRUCTOR Address_ip(lua_State* L) { /* Creates an Address Object representing an IP address. */ +#define WSLUA_ARG_Address_ip_HOSTNAME 1 /* The address or name of the IP host. */ + Address addr = g_malloc(sizeof(address)); + guint32* ip_addr = g_malloc(sizeof(guint32)); + const gchar* name = luaL_checkstring(L,WSLUA_ARG_Address_ip_HOSTNAME); + + if (! get_host_ipaddr(name, (guint32*)ip_addr)) { + *ip_addr = 0; + } + + SET_ADDRESS(addr, AT_IPv4, 4, ip_addr); + pushAddress(L,addr); + WSLUA_RETURN(1); /* the Address object */ +} + +#if 0 +/* TODO */ +static int Address_ipv6(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_ss7(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_eth(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_sna(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_atalk(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_vines(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_osi(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_arcnet(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_fc(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_string(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_eui64(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_uri(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +static int Address_tipc(lua_State* L) { + Address addr = g_malloc(sizeof(address)); + + SET_ADDRESS(addr, AT_NONE, 4, g_malloc(4)); + + pushAddress(L,addr); + return 1; +} +#endif + +WSLUA_METHODS Address_methods[] = { + {"ip", Address_ip }, + {"ipv4", Address_ip }, +#if 0 + {"ipv6", Address_ipv6 }, + {"ss7pc", Address_ss7 }, + {"eth", Address_eth }, + {"sna", Address_sna }, + {"atalk", Address_atalk }, + {"vines", Address_vines }, + {"osi", Address_osi }, + {"arcnet", Address_arcnet }, + {"fc", Address_fc }, + {"string", Address_string }, + {"eui64", Address_eui64 }, + {"uri", Address_uri }, + {"tipc", Address_tipc }, +#endif + {0,0} +}; + +WSLUA_METAMETHOD Address__tostring(lua_State* L) { + Address addr = checkAddress(L,1); + + lua_pushstring(L,get_addr_name(addr)); + + WSLUA_RETURN(1); /* The string representing the address. */ +} + +static int Address__gc(lua_State* L) { + Address addr = checkAddress(L,1); + + if (addr) { + if (addr->data) g_free((void*)addr->data); + g_free((void*)addr); + } + + return 0; +} + +WSLUA_METAMETHOD Address__eq(lua_State* L) { /* compares two Addresses */ + Address addr1 = checkAddress(L,1); + Address addr2 = checkAddress(L,2); + gboolean result = FALSE; + + if (ADDRESSES_EQUAL(addr1, addr2)) + result = TRUE; + + lua_pushboolean(L,result); + + return 1; +} + +WSLUA_METAMETHOD Address__le(lua_State* L) { /* compares two Addresses */ + Address addr1 = checkAddress(L,1); + Address addr2 = checkAddress(L,2); + gboolean result = FALSE; + + if (CMP_ADDRESS(addr1, addr2) <= 0) + result = TRUE; + + lua_pushboolean(L,result); + + return 1; +} + +WSLUA_METAMETHOD Address__lt(lua_State* L) { /* compares two Addresses */ + Address addr1 = checkAddress(L,1); + Address addr2 = checkAddress(L,2); + gboolean result = FALSE; + + if (CMP_ADDRESS(addr1, addr2) < 0) + result = TRUE; + + lua_pushboolean(L,result); + + return 1; +} + +WSLUA_META Address_meta[] = { + {"__gc", Address__gc }, + {"__tostring", Address__tostring }, + {"__eq",Address__eq}, + {"__le",Address__le}, + {"__lt",Address__lt}, + {0,0} +}; + + +int Address_register(lua_State *L) { + WSLUA_REGISTER_CLASS(Address); + return 1; +} + + +WSLUA_CLASS_DEFINE(Column,FAIL_ON_NULL("expired column"),NOP); /* A Column in the packet list */ + +struct col_names_t { + const gchar* name; + int id; +}; + +static const struct col_names_t colnames[] = { + {"number",COL_NUMBER}, + {"abs_time",COL_ABS_TIME}, + {"cls_time",COL_CLS_TIME}, + {"rel_time",COL_REL_TIME}, + {"date",COL_ABS_DATE_TIME}, + {"delta_time",COL_DELTA_TIME}, + {"src",COL_DEF_SRC}, + {"src_res",COL_RES_SRC}, + {"src_unres",COL_UNRES_SRC}, + {"dl_src",COL_DEF_DL_SRC}, + {"dl_src_res",COL_RES_DL_SRC}, + {"dl_src_unres",COL_UNRES_DL_SRC}, + {"net_src",COL_DEF_NET_SRC}, + {"net_src_res",COL_RES_NET_SRC}, + {"net_src_unres",COL_UNRES_NET_SRC}, + {"dst",COL_DEF_DST}, + {"dst_res",COL_RES_DST}, + {"dst_unres",COL_UNRES_DST}, + {"dl_dst",COL_DEF_DL_DST}, + {"dl_dst_res",COL_RES_DL_DST}, + {"dl_dst_unres",COL_UNRES_DL_DST}, + {"net_dst",COL_DEF_NET_DST}, + {"net_dst_res",COL_RES_NET_DST}, + {"net_dst_unres",COL_UNRES_NET_DST}, + {"src_port",COL_DEF_SRC_PORT}, + {"src_port_res",COL_RES_SRC_PORT}, + {"src_port_unres",COL_UNRES_SRC_PORT}, + {"dst_port",COL_DEF_DST_PORT}, + {"dst_port_res",COL_RES_DST_PORT}, + {"dst_port_unres",COL_UNRES_DST_PORT}, + {"protocol",COL_PROTOCOL}, + {"info",COL_INFO}, + {"packet_len",COL_PACKET_LENGTH}, + {"cumulative_bytes",COL_CUMULATIVE_BYTES}, + {"oxid",COL_OXID}, + {"rxid",COL_RXID}, + {"direction",COL_IF_DIR}, + {"circuit_id",COL_CIRCUIT_ID}, + {"src_idx",COL_SRCIDX}, + {"dst_idx",COL_DSTIDX}, + {"vsan",COL_VSAN}, + {"tx_rate",COL_TX_RATE}, + {"rssi",COL_RSSI}, + {"hpux_subsys",COL_HPUX_SUBSYS}, + {"hpux_devid",COL_HPUX_DEVID}, + {"dce_call",COL_DCE_CALL}, + {NULL,0} +}; + +static gint col_name_to_id(const gchar* name) { + const struct col_names_t* cn; + for(cn = colnames; cn->name; cn++) { + if (g_str_equal(cn->name,name)) { + return cn->id; + } + } + + return 0; +} + +static const gchar* col_id_to_name(gint id) { + const struct col_names_t* cn; + for(cn = colnames; cn->name; cn++) { + if ( cn->id == id ) { + return cn->name; + } + } + return NULL; +} + + +WSLUA_METAMETHOD Column__tostring(lua_State *L) { + Column c = checkColumn(L,1); + const gchar* name; + + if (!(c)) { + return 0; + } + + /* XXX: should return the column's text ! */ + name = col_id_to_name(c->col); + lua_pushstring(L,name ? name : "Unknown Column"); + + WSLUA_RETURN(1); /* A string representing the column */ +} + +WSLUA_METHOD Column_clear(lua_State *L) { + /* Clears a Column */ + Column c = checkColumn(L,1); + + if (!(c && c->cinfo)) return 0; + + if (check_col(c->cinfo, c->col)) + col_clear(c->cinfo, c->col); + + return 0; +} + +WSLUA_METHOD Column_set(lua_State *L) { + /* Sets the text of a Column */ +#define WSLUA_ARG_Column_set_TEXT 2 /* The text to which to set the Column */ + Column c = checkColumn(L,1); + const gchar* s = luaL_checkstring(L,WSLUA_ARG_Column_set_TEXT); + + if (!(c && c->cinfo)) + return 0; + + if (!s) WSLUA_ARG_ERROR(Column_set,TEXT,"must be a string"); + + if (check_col(c->cinfo, c->col)) + col_set_str(c->cinfo, c->col, s); + + return 0; +} + +WSLUA_METHOD Column_append(lua_State *L) { + /* Appends text to a Column */ +#define WSLUA_ARG_Column_append_TEXT 2 /* The text to append to the Column */ + Column c = checkColumn(L,1); + const gchar* s = luaL_checkstring(L,WSLUA_ARG_Column_append_TEXT); + + if (!(c && c->cinfo)) + return 0; + + if (!s) WSLUA_ARG_ERROR(Column_append,TEXT,"must be a string"); + + + if (check_col(c->cinfo, c->col)) + col_append_str(c->cinfo, c->col, s); + + return 0; +} + +WSLUA_METHOD Column_preppend(lua_State *L) { + /* Prepends text to a Column */ +#define WSLUA_ARG_Column_prepend_TEXT 2 /* The text to prepend to the Column */ + Column c = checkColumn(L,1); + const gchar* s = luaL_checkstring(L,WSLUA_ARG_Column_prepend_TEXT); + + if (!(c && c->cinfo)) + return 0; + + if (!s) WSLUA_ARG_ERROR(Column_prepend,TEXT,"must be a string"); + + if (check_col(c->cinfo, c->col)) + col_prepend_fstr(c->cinfo, c->col, "%s",s); + + return 0; +} + +WSLUA_METHODS Column_methods[] = { + {"clear", Column_clear }, + {"set", Column_set }, + {"append", Column_append }, + {"preppend", Column_preppend }, + {0,0} +}; + + +WSLUA_META Column_meta[] = { + {"__tostring", Column__tostring }, + {0,0} +}; + + +int Column_register(lua_State *L) { + WSLUA_REGISTER_CLASS(Column); + return 1; +} + + + + + + +WSLUA_CLASS_DEFINE(Columns,NOP,NOP); +/* The Columns of the packet list. */ + +WSLUA_METAMETHOD Columns__tostring(lua_State *L) { + lua_pushstring(L,"Columns"); + WSLUA_RETURN(1); + /* The string "Columns", no real use, just for debugging purposes. */ +} + +WSLUA_METAMETHOD Columns__newindex(lua_State *L) { + /* Sets the text of a specific column */ +#define WSLUA_ARG_Columns__newindex_COLUMN 2 /* the name of the column to set */ +#define WSLUA_ARG_Columns__newindex_TEXT 3 /* the text for the column */ + Columns cols = checkColumns(L,1); + const struct col_names_t* cn; + const char* colname; + const char* text; + + if (!cols) return 0; + + colname = luaL_checkstring(L,WSLUA_ARG_Columns__newindex_COLUMN); + text = luaL_checkstring(L,WSLUA_ARG_Columns__newindex_TEXT); + + for(cn = colnames; cn->name; cn++) { + if( g_str_equal(cn->name,colname) ) { + if (check_col(cols, cn->id)) + col_set_str(cols, cn->id, text); + return 0; + } + } + + WSLUA_ARG_ERROR(Columns__newindex,COLUMN,"the column name must be a valid column"); + + return 0; +} + +WSLUA_METAMETHOD Columns_index(lua_State *L) { + Columns cols = checkColumns(L,1); + const struct col_names_t* cn; + const char* colname = luaL_checkstring(L,2); + + if (!cols) { + Column c = ep_alloc(sizeof(struct _wslua_col_info)); + c->cinfo = NULL; + c->col = col_name_to_id(colname); + + PUSH_COLUMN(L,c); + return 1; + } + + + + if (!colname) return 0; + + for(cn = colnames; cn->name; cn++) { + if( g_str_equal(cn->name,colname) ) { + Column c = ep_alloc(sizeof(struct _wslua_col_info)); + c->cinfo = cols; + c->col = col_name_to_id(colname); + + PUSH_COLUMN(L,c); + return 1; + } + } + + return 0; +} + + +static const luaL_reg Columns_meta[] = { + {"__tostring", Columns__tostring }, + {"__newindex", Columns__newindex }, + {"__index", Columns_index}, + {0,0} +}; + + +int Columns_register(lua_State *L) { + WSLUA_REGISTER_META(Columns); + return 1; +} + + +WSLUA_CLASS_DEFINE(Pinfo,FAIL_ON_NULL("expired pinfo"),NOP); +/* Packet information */ + +static int Pinfo_tostring(lua_State *L) { lua_pushstring(L,"a Pinfo"); return 1; } + +#define PINFO_GET_NUMBER(name,val) static int name(lua_State *L) { \ + Pinfo pinfo = checkPinfo(L,1); \ + if (!pinfo) return 0;\ + lua_pushnumber(L,(lua_Number)(val));\ + return 1;\ +} + +#define PINFO_GET_STRING(name,val) static int name(lua_State *L) { \ + Pinfo pinfo = checkPinfo(L,1); \ + const gchar* value; \ + if (!pinfo) return 0; \ + value = val; \ + if (value) lua_pushstring(L,(const char*)(value)); else lua_pushnil(L); \ + return 1; \ +} + +#define PINFO_GET_ADDRESS(name,role) static int name(lua_State *L) { \ + Pinfo pinfo = checkPinfo(L,1); \ + Address addr = g_malloc(sizeof(address)); \ + if (!pinfo) return 0; \ + COPY_ADDRESS(addr, &(pinfo->role)); \ + pushAddress(L,addr); \ + return 1; \ +} + +PINFO_GET_NUMBER(Pinfo_number,pinfo->fd->num) +PINFO_GET_NUMBER(Pinfo_len,pinfo->fd->pkt_len) +PINFO_GET_NUMBER(Pinfo_caplen,pinfo->fd->cap_len) +PINFO_GET_NUMBER(Pinfo_abs_ts,(((double)pinfo->fd->abs_ts.secs) + (((double)pinfo->fd->abs_ts.nsecs) / 1000000000.0) )) +PINFO_GET_NUMBER(Pinfo_rel_ts,(((double)pinfo->fd->rel_ts.secs) + (((double)pinfo->fd->rel_ts.nsecs) / 1000000000.0) )) +PINFO_GET_NUMBER(Pinfo_delta_ts,(((double)pinfo->fd->del_ts.secs) + (((double)pinfo->fd->del_ts.nsecs) / 1000000000.0) )) +PINFO_GET_NUMBER(Pinfo_ipproto,pinfo->ipproto) +PINFO_GET_NUMBER(Pinfo_circuit_id,pinfo->circuit_id) +PINFO_GET_NUMBER(Pinfo_ptype,pinfo->ptype) +PINFO_GET_NUMBER(Pinfo_src_port,pinfo->srcport) +PINFO_GET_NUMBER(Pinfo_dst_port,pinfo->destport) + +PINFO_GET_STRING(Pinfo_curr_proto,pinfo->current_proto) + +PINFO_GET_ADDRESS(Pinfo_net_src,net_src) +PINFO_GET_ADDRESS(Pinfo_net_dst,net_dst) +PINFO_GET_ADDRESS(Pinfo_dl_src,dl_src) +PINFO_GET_ADDRESS(Pinfo_dl_dst,dl_dst) +PINFO_GET_ADDRESS(Pinfo_src,src) +PINFO_GET_ADDRESS(Pinfo_dst,dst) + +static int Pinfo_visited(lua_State *L) { + Pinfo pinfo = checkPinfo(L,1); + if (!pinfo) return 0; + lua_pushboolean(L,pinfo->fd->flags.visited); + return 1; +} + + +static int Pinfo_match(lua_State *L) { + Pinfo pinfo = checkPinfo(L,1); + + if (!pinfo) return 0; + + if (pinfo->match_string) { + lua_pushstring(L,pinfo->match_string); + } else { + lua_pushnumber(L,(lua_Number)(pinfo->match_port)); + } + + return 1; +} + +static int Pinfo_columns(lua_State *L) { + Pinfo pinfo = checkPinfo(L,1); + const gchar* colname = luaL_optstring(L,2,NULL); + + if (!colname) { + PUSH_COLUMNS(L,pinfo->cinfo); + } else { + lua_settop(L,0); + PUSH_COLUMNS(L,pinfo->cinfo); + lua_pushstring(L,colname); + return Columns_index(L); + } + return 1; +} + + +typedef enum { + PARAM_NONE, + PARAM_ADDR_SRC, + PARAM_ADDR_DST, + PARAM_ADDR_DL_SRC, + PARAM_ADDR_DL_DST, + PARAM_ADDR_NET_SRC, + PARAM_ADDR_NET_DST, + PARAM_PORT_SRC, + PARAM_PORT_DST, + PARAM_CIRCUIT_ID, + PARAM_PORT_TYPE, +} pinfo_param_type_t; + +static int pushnil_param(lua_State* L, packet_info* pinfo _U_, pinfo_param_type_t pt _U_ ) { + lua_pushnil(L); + return 1; +} + +int Pinfo_set_addr(lua_State* L, packet_info* pinfo, pinfo_param_type_t pt) { + const address* from = checkAddress(L,1); + address* to; + + if (! from ) { + luaL_error(L,"Not an OK address"); + return 0; + } + + switch(pt) { + case PARAM_ADDR_SRC: + to = &(pinfo->src); + break; + case PARAM_ADDR_DST: + to = &(pinfo->dst); + break; + case PARAM_ADDR_DL_SRC: + to = &(pinfo->dl_src); + break; + case PARAM_ADDR_DL_DST: + to = &(pinfo->dl_dst); + break; + case PARAM_ADDR_NET_SRC: + to = &(pinfo->net_src); + break; + case PARAM_ADDR_NET_DST: + to = &(pinfo->net_dst); + break; + default: + g_assert(!"BUG: A bad parameter"); + } + + COPY_ADDRESS(to,from); + return 0; +} + +int Pinfo_set_int(lua_State* L, packet_info* pinfo, pinfo_param_type_t pt) { + guint v = luaL_checkint(L,1); + + switch(pt) { + case PARAM_PORT_SRC: + pinfo->srcport = v; + return 0; + case PARAM_PORT_DST: + pinfo->destport = v; + return 0; + case PARAM_CIRCUIT_ID: + pinfo->circuit_id = v; + return 0; + default: + g_assert(!"BUG: A bad parameter"); + } + + return 0; +} + +typedef struct _pinfo_method_t { + const gchar* name; + lua_CFunction get; + int (*set)(lua_State*, packet_info*, pinfo_param_type_t); + pinfo_param_type_t param; +} pinfo_method_t; + +static int Pinfo_hi(lua_State *L) { + Pinfo pinfo = checkPinfo(L,1); + Address addr = g_malloc(sizeof(address)); + + if (!pinfo) return 0; + + if (CMP_ADDRESS(&(pinfo->src), &(pinfo->dst) ) >= 0) { + COPY_ADDRESS(addr, &(pinfo->src)); + } else { + COPY_ADDRESS(addr, &(pinfo->dst)); + } + + pushAddress(L,addr); + return 1; +} + +static int Pinfo_lo(lua_State *L) { + Pinfo pinfo = checkPinfo(L,1); + Address addr = g_malloc(sizeof(address)); + + if (!pinfo) return 0; + + if (CMP_ADDRESS(&(pinfo->src), &(pinfo->dst) ) < 0) { + COPY_ADDRESS(addr, &(pinfo->src)); + } else { + COPY_ADDRESS(addr, &(pinfo->dst)); + } + + pushAddress(L,addr); + return 1; +} + + +static const pinfo_method_t Pinfo_methods[] = { + + /* WSLUA_ATTRIBUTE Pinfo_number RO The number of this packet in the current file */ + {"number", Pinfo_number, pushnil_param, PARAM_NONE}, + + /* WSLUA_ATTRIBUTE Pinfo_len RO The length of the frame */ + {"len", Pinfo_len, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_caplen RO The captured length of the frame */ + {"caplen", Pinfo_caplen, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_abs_ts RO When the packet was captured */ + {"abs_ts",Pinfo_abs_ts, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_rel_ts RO Number of seconds passed since beginning of capture */ + {"rel_ts",Pinfo_rel_ts, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_delta_ts RO Number of seconds passed since the last packet */ + {"delta_ts",Pinfo_delta_ts, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_visited RO Whether this packet hass been already visited */ + {"visited",Pinfo_visited, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_src RW Source Address of this Packet */ + {"src", Pinfo_src, Pinfo_set_addr, PARAM_ADDR_SRC }, + + /* WSLUA_ATTRIBUTE Pinfo_dst RW Destination Address of this Packet */ + {"dst", Pinfo_dst, Pinfo_set_addr, PARAM_ADDR_DST }, + + /* WSLUA_ATTRIBUTE Pinfo_lo RO lower Address of this Packet */ + {"lo", Pinfo_lo, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_hi RW higher Address of this Packet */ + {"hi", Pinfo_hi, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_dl_src RW Data Link Source Address of this Packet */ + {"dl_src", Pinfo_dl_src, Pinfo_set_addr, PARAM_ADDR_DL_SRC }, + + /* WSLUA_ATTRIBUTE Pinfo_dl_dst RW Data Link Destination Address of this Packet */ + {"dl_dst", Pinfo_dl_dst, Pinfo_set_addr, PARAM_ADDR_DL_DST }, + + /* WSLUA_ATTRIBUTE Pinfo_net_src RW Network Layer Source Address of this Packet */ + {"net_src", Pinfo_net_src, Pinfo_set_addr, PARAM_ADDR_NET_SRC }, + + /* WSLUA_ATTRIBUTE Pinfo_net_dst RW Network Layer Destination Address of this Packet */ + {"net_dst", Pinfo_net_dst, Pinfo_set_addr, PARAM_ADDR_NET_DST }, + + /* WSLUA_ATTRIBUTE Pinfo_ptype RW Type of Port of .src_port and .dst_port */ + {"port_type", Pinfo_ptype, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_src_port RW Source Port of this Packet */ + {"src_port", Pinfo_src_port, Pinfo_set_int, PARAM_PORT_SRC }, + + /* WSLUA_ATTRIBUTE Pinfo_dst_port RW Source Address of this Packet */ + {"dst_port", Pinfo_dst_port, Pinfo_set_int, PARAM_PORT_SRC }, + + /* WSLUA_ATTRIBUTE Pinfo_ipproto RO IP Protocol id */ + {"ipproto", Pinfo_ipproto, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_circuit_id RO For circuit based protocols */ + {"circuit_id", Pinfo_circuit_id, Pinfo_set_int, PARAM_CIRCUIT_ID }, + + /* WSLUA_ATTRIBUTE Pinfo_match RO Port/Data we are matching */ + {"match", Pinfo_match, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_match RO Which Protocol are we dissecting */ + {"curr_proto", Pinfo_curr_proto, pushnil_param, PARAM_NONE }, + + /* WSLUA_ATTRIBUTE Pinfo_columns RO Accesss to the packet list columns */ + {"cols", Pinfo_columns, pushnil_param, PARAM_NONE }, + + {NULL,NULL,NULL,PARAM_NONE} +}; + + +static int pushnil(lua_State* L) { + lua_pushnil(L); + return 1; +} + +static int Pinfo_index(lua_State* L) { + Pinfo pinfo = checkPinfo(L,1); + const gchar* name = luaL_checkstring(L,2); + lua_CFunction method = pushnil; + const pinfo_method_t* curr; + + if (! (pinfo && name) ) { + lua_pushnil(L); + return 1; + } + + for (curr = Pinfo_methods ; curr->name ; curr++) { + if (g_str_equal(curr->name,name)) { + method = curr->get; + break; + } + } + + lua_settop(L,1); + return method(L); +} + +static int Pinfo_setindex(lua_State* L) { + Pinfo pinfo = checkPinfo(L,1); + const gchar* name = luaL_checkstring(L,2); + int (*method)(lua_State*, packet_info* pinfo, pinfo_param_type_t) = pushnil_param; + const pinfo_method_t* curr; + pinfo_param_type_t param_type = PARAM_NONE; + + if (! (pinfo && name) ) { + return 0; + } + + for (curr = Pinfo_methods ; curr->name ; curr++) { + if (g_str_equal(curr->name,name)) { + method = curr->set; + param_type = curr->param; + break; + } + } + + lua_remove(L,1); + lua_remove(L,1); + return method(L,pinfo,param_type); +} + +static const luaL_reg Pinfo_meta[] = { + {"__index", Pinfo_index}, + {"__newindex",Pinfo_setindex}, + {"__tostring", Pinfo_tostring}, + {0, 0} +}; + +int Pinfo_register(lua_State* L) { + WSLUA_REGISTER_META(Pinfo); + outstanding_stuff = g_ptr_array_new(); + return 1; +} + diff --git a/epan/wslua/wslua_proto.c b/epan/wslua/wslua_proto.c new file mode 100644 index 0000000000..0a30f93d6f --- /dev/null +++ b/epan/wslua/wslua_proto.c @@ -0,0 +1,1350 @@ +/* + * lua_proto.c + * + * wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_proto.c 18611 2006-06-29 13:49:56Z lego $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" + +WSLUA_CLASS_DEFINE(Pref,NOP,NOP); /* A preference of a Protocol. */ + +static int new_pref(lua_State* L, pref_type_t type) { + const gchar* label = luaL_optstring(L,1,NULL); + const gchar* descr = luaL_optstring(L,3,""); + + Pref pref = g_malloc(sizeof(wslua_pref_t)); + pref->name = NULL; + pref->label = label ? g_strdup(label) : NULL; + pref->desc = g_strdup(descr); + pref->type = type; + pref->next = NULL; + pref->proto = NULL; + + switch(type) { + case PREF_BOOL: { + gboolean def = lua_toboolean(L,2); + pref->value.b = def; + break; + } + case PREF_UINT: { + guint32 def = (guint32)luaL_optnumber(L,2,0); + pref->value.u = def; + break; + } + case PREF_STRING: { + gchar* def = g_strdup(luaL_optstring(L,2,"")); + pref->value.s = def; + break; + } + default: + g_assert_not_reached(); + break; + + } + + pushPref(L,pref); + return 1; + +} + +WSLUA_CONSTRUCTOR Pref_bool(lua_State* L) { + /* + * Creates a boolean preference to be added to a Protocol's prefs table. + */ +#define WSLUA_ATTR_Pref_bool_LABEL 1 /* The Label (text in the right side of the preference input) for this preference */ +#define WSLUA_ATTR_Pref_bool_DEFAULT 2 /* The default value for this preference */ +#define WSLUA_ATTR_Pref_bool_DESCR 3 /* A description of what this preference is */ + return new_pref(L,PREF_BOOL); +} + +WSLUA_CONSTRUCTOR Pref_uint(lua_State* L) { + /* + * Creates an (unsigned) integer preference to be added to a Protocol's prefs table. + */ +#define WSLUA_ATTR_Pref_uint_LABEL 1 /* The Label (text in the right side of the preference input) for this preference */ +#define WSLUA_ATTR_Pref_uint_DEFAULT 2 /* The default value for this preference */ +#define WSLUA_ATTR_Pref_uint_DESCR 3 /* A description of what this preference is */ + return new_pref(L,PREF_UINT); +} + +WSLUA_CONSTRUCTOR Pref_string(lua_State* L) { + /* + * Creates a string preference to be added to a Protocol's prefs table. + */ +#define WSLUA_ATTR_Pref_string_LABEL 1 /* The Label (text in the right side of the preference input) for this preference */ +#define WSLUA_ATTR_Pref_string_DEFAULT 2 /* The default value for this preference */ +#define WSLUA_ATTR_Pref_string_DESCR 3 /* A description of what this preference is */ + return new_pref(L,PREF_STRING); +} + +static int Pref_gc(lua_State* L) { + Pref pref = checkPref(L,1); + + if (pref && ! pref->name) { + if (pref->label) g_free(pref->label); + if (pref->desc) g_free(pref->desc); + if (pref->type == PREF_STRING) g_free((void*)pref->value.s); + g_free(pref); + } + + return 0; +} + +WSLUA_METHODS Pref_methods[] = { + {"bool", Pref_bool}, + {"uint", Pref_uint}, + {"string", Pref_string}, + {0,0} +}; + +WSLUA_META Pref_meta[] = { + {"__gc", Pref_gc}, + {0,0} +}; + + +WSLUA_REGISTER Pref_register(lua_State* L) { + WSLUA_REGISTER_CLASS(Pref); + return 1; +} + +WSLUA_CLASS_DEFINE(Prefs,NOP,NOP); /* The table of preferences of a protocol */ + +WSLUA_METAMETHOD Prefs__newindex(lua_State* L) { + /* creates a new preference */ +#define WSLUA_ARG_Prefs__newindex_NAME 2 /* The abbreviation of this preference */ +#define WSLUA_ARG_Prefs__newindex_PREF 3 /* A valid still unassigned Pref object */ + + Pref prefs = checkPrefs(L,1); + const gchar* name = luaL_checkstring(L,WSLUA_ARG_Prefs__newindex_NAME); + Pref pref = checkPref(L,WSLUA_ARG_Prefs__newindex_PREF); + Pref p; + + if (! prefs ) return 0; + + if (! name ) + WSLUA_ARG_ERROR(Prefs__newindex,NAME,"must be a string"); + + if (! pref ) + WSLUA_ARG_ERROR(Prefs__newindex,PREF,"must be a valid Pref"); + + if (pref->name) + WSLUA_ARG_ERROR(Prefs__newindex,NAME,"cannot change existing preference"); + + if (pref->proto) + WSLUA_ARG_ERROR(Prefs__newindex,PREF,"cannot be added to more than one protocol"); + + p = prefs; + + do { + if ( p->name && g_str_equal(p->name,name) ) { + luaL_error(L,"a preference named %s exists already",name); + return 0; + } + + if ( ! p->next) { + p->next = pref; + + pref->name = g_strdup(name); + + if (!pref->label) + pref->label = g_strdup(name); + + if (!prefs->proto->prefs_module) { + prefs->proto->prefs_module = prefs_register_protocol(prefs->proto->hfid, NULL); + + } + + switch(pref->type) { + case PREF_BOOL: + prefs_register_bool_preference(prefs->proto->prefs_module, + pref->name, + pref->label, + pref->desc, + &(pref->value.b)); + break; + case PREF_UINT: + prefs_register_uint_preference(prefs->proto->prefs_module, + pref->name, + pref->label, + pref->desc, + 10, + &(pref->value.u)); + break; + case PREF_STRING: + prefs_register_string_preference(prefs->proto->prefs_module, + pref->name, + pref->label, + pref->desc, + &(pref->value.s)); + break; + default: + WSLUA_ERROR(Prefs__newindex,"unknow Pref type"); + } + + pref->proto = p->proto; + + WSLUA_RETURN(0); + } + } while (( p = p->next )); + + luaL_error(L,"this should not happen!"); + + WSLUA_RETURN(0); +} + +WSLUA_METAMETHOD Prefs__index(lua_State* L) { + /* get the value of a preference setting */ +#define WSLUA_ARG_Prefs__index_NAME 2 /* The abbreviation of this preference */ + + Pref prefs = checkPrefs(L,1); + const gchar* name = luaL_checkstring(L,2); + + if (! ( name && prefs ) ) return 0; + + prefs = prefs->next; + + do { + if ( g_str_equal(prefs->name,name) ) { + switch (prefs->type) { + case PREF_BOOL: lua_pushboolean(L, prefs->value.b); break; + case PREF_UINT: lua_pushnumber(L,(lua_Number)prefs->value.u); break; + case PREF_STRING: lua_pushstring(L,prefs->value.s); break; + default: WSLUA_ERROR(Prefs__index,"unknow Pref type"); + } + WSLUA_RETURN(1); /* the current value of the preference */ + } + } while (( prefs = prefs->next )); + + WSLUA_ARG_ERROR(Prefs__index,NAME,"no preference named like this"); + WSLUA_RETURN(0); +} + +WSLUA_META Prefs_meta[] = { + {"__newindex", Prefs__newindex}, + {"__index", Prefs__index}, + {0,0} +}; + +WSLUA_REGISTER Prefs_register(lua_State* L) { + WSLUA_REGISTER_META(Prefs); + return 1; +} + + +WSLUA_CLASS_DEFINE(ProtoField,FAIL_ON_NULL("null ProtoField"),NOP); +/* + * A Protocol field (to be used when adding items to the dissection tree) + */ + +static const wslua_ft_types_t ftenums[] = { +{"FT_BOOLEAN",FT_BOOLEAN}, +{"FT_UINT8",FT_UINT8}, +{"FT_UINT16",FT_UINT16}, +{"FT_UINT24",FT_UINT24}, +{"FT_UINT32",FT_UINT32}, +{"FT_UINT64",FT_UINT64}, +{"FT_INT8",FT_INT8}, +{"FT_INT16",FT_INT16}, +{"FT_INT24",FT_INT24}, +{"FT_INT32",FT_INT32}, +{"FT_INT64",FT_INT64}, +{"FT_FLOAT",FT_FLOAT}, +{"FT_DOUBLE",FT_DOUBLE}, +{"FT_STRING",FT_STRING}, +{"FT_STRINGZ",FT_STRINGZ}, +{"FT_ETHER",FT_ETHER}, +{"FT_BYTES",FT_BYTES}, +{"FT_UINT_BYTES",FT_UINT_BYTES}, +{"FT_IPv4",FT_IPv4}, +{"FT_IPv6",FT_IPv6}, +{"FT_IPXNET",FT_IPXNET}, +{"FT_FRAMENUM",FT_FRAMENUM}, +{"FT_GUID",FT_GUID}, +{"FT_OID",FT_OID}, +{NULL,FT_NONE} +}; + +static enum ftenum get_ftenum(const gchar* type) { + const wslua_ft_types_t* ts; + for (ts = ftenums; ts->str; ts++) { + if ( g_str_equal(ts->str,type) ) { + return ts->id; + } + } + + return FT_NONE; +} + +static const gchar* ftenum_to_string(enum ftenum ft) { + const wslua_ft_types_t* ts; + for (ts = ftenums; ts->str; ts++) { + if ( ts->id == ft ) { + return ts->str; + } + } + + return NULL; +} + +struct base_display_string_t { + const gchar* str; + base_display_e base; +}; + +static const struct base_display_string_t base_displays[] = { + { "BASE_NONE", BASE_NONE}, + {"BASE_DEC", BASE_DEC}, + {"BASE_HEX", BASE_HEX}, + {"BASE_OCT", BASE_OCT}, + {"BASE_DEC_HEX", BASE_DEC_HEX}, + {"BASE_HEX_DEC", BASE_HEX_DEC}, + {NULL,0} +}; + +static const gchar* base_to_string(base_display_e base) { + const struct base_display_string_t* b; + for (b=base_displays;b->str;b++) { + if ( base == b->base) + return b->str; + } + return NULL; +} + +static base_display_e string_to_base(const gchar* str) { + const struct base_display_string_t* b; + for (b=base_displays;b->str;b++) { + if ( g_str_equal(str,b->str)) + return b->base; + } + return BASE_NONE; +} + +static value_string* value_string_from_table(lua_State* L, int idx) { + GArray* vs = g_array_new(TRUE,TRUE,sizeof(value_string)); + value_string* ret; + + if(lua_isnil(L,idx)) { + return NULL; + } else if (!lua_istable(L,idx)) { + luaL_argerror(L,idx,"must be a table"); + g_array_free(vs,TRUE); + return NULL; + } + + lua_pushnil(L); + + while (lua_next(L, idx) != 0) { + value_string v = {0,NULL}; + + if (! lua_isnumber(L,-2)) { + luaL_argerror(L,idx,"All keys of a table used as vaalue_string must be integers"); + g_array_free(vs,TRUE); + return NULL; + } + + if (! lua_isstring(L,-1)) { + luaL_argerror(L,idx,"All values of a table used as vaalue_string must be strings"); + g_array_free(vs,TRUE); + return NULL; + } + + v.value = (guint32)lua_tonumber(L,-2); + v.strptr = g_strdup(lua_tostring(L,-1)); + + g_array_append_val(vs,v); + + lua_pop(L, 1); + } + + lua_pop(L, 1); + + ret = (value_string*)vs->data; + + g_array_free(vs,FALSE); + + return ret; + +} + +WSLUA_CONSTRUCTOR ProtoField_new(lua_State* L) { /* Creates a new field to be used in a protocol. */ +#define WSLUA_ARG_ProtoField_new_NAME 1 /* Actual name of the field (the string that appears in the tree). */ +#define WSLUA_ARG_ProtoField_new_ABBR 2 /* Filter name of the field (the string that is used in filters). */ +#define WSLUA_ARG_ProtoField_new_TYPE 3 /* Field Type (FT_*). */ +#define WSLUA_OPTARG_ProtoField_new_VALUESTRING 4 /* a ValueString object. */ +#define WSLUA_OPTARG_ProtoField_new_BASE 5 /* The representation BASE_*. */ +#define WSLUA_OPTARG_ProtoField_new_MASK 6 /* the bitmask to be used. */ +#define WSLUA_OPTARG_ProtoField_new_DESCR 7 /* The description of the field. */ + + ProtoField f = g_malloc(sizeof(wslua_field_t)); + value_string* vs; + + /* will be using -2 as far as the field has not been added to an array then it will turn -1 */ + f->hfid = -2; + f->ett = -1; + f->name = g_strdup(luaL_checkstring(L,WSLUA_ARG_ProtoField_new_NAME)); + f->abbr = g_strdup(luaL_checkstring(L,WSLUA_ARG_ProtoField_new_ABBR)); + f->type = get_ftenum(luaL_checkstring(L,WSLUA_ARG_ProtoField_new_TYPE)); + + /*XXX do it better*/ + if (f->type == FT_NONE) { + WSLUA_ARG_ERROR(ProtoField_new,TYPE,"invalid FT_type"); + return 0; + } + + if (! lua_isnil(L,WSLUA_OPTARG_ProtoField_new_VALUESTRING) ) { + vs = value_string_from_table(L,WSLUA_OPTARG_ProtoField_new_VALUESTRING); + + if (vs) { + f->vs = vs; + } else { + g_free(f); + return 0; + } + + + } else { + f->vs = NULL; + } + + /* XXX: need BASE_ERROR */ + f->base = string_to_base(luaL_optstring(L, WSLUA_OPTARG_ProtoField_new_BASE, "BASE_NONE")); + f->mask = luaL_optint(L, WSLUA_OPTARG_ProtoField_new_MASK, 0x0); + f->blob = g_strdup(luaL_optstring(L,WSLUA_OPTARG_ProtoField_new_DESCR,"")); + + pushProtoField(L,f); + + WSLUA_RETURN(1); /* The newly created ProtoField object */ +} + + +static int ProtoField_integer(lua_State* L, enum ftenum type) { + ProtoField f = g_malloc(sizeof(wslua_field_t)); + const gchar* abbr = luaL_checkstring(L,1); + const gchar* name = luaL_optstring(L,2,abbr); + base_display_e base = luaL_optint(L, 3, BASE_DEC); + value_string* vs = (lua_gettop(L) > 3) ? value_string_from_table(L,4) : NULL; + int mask = luaL_optint(L, 5, 0x0); + const gchar* blob = luaL_optstring(L,6,""); + + if (base < BASE_DEC || base > BASE_HEX_DEC) { + luaL_argerror(L,2,"Base must be either BASE_DEC, BASE_HEX, BASE_OCT," + " BASE_DEC_HEX, BASE_DEC_HEX or BASE_HEX_DEC"); + return 0; + } + + f->hfid = -2; + f->ett = -1; + f->name = g_strdup(name); + f->abbr = g_strdup(abbr); + f->type = type; + f->vs = vs; + f->base = base; + f->mask = mask; + f->blob = g_strdup(blob); + + + pushProtoField(L,f); + + return 1; +} + +#define PROTOFIELD_INTEGER(lower,FT) static int ProtoField_##lower(lua_State* L) { return ProtoField_integer(L,FT); } +/* WSLUA_SECTION Protofield integer constructors */ +/* WSLUA_TEXT integer type ProtoField constructors use the following arguments */ +/* WSLUA_ARG_DESC Protofield_integer ABBR abbreviated name of the field (the string used in filters) */ +/* WSLUA_OPTARG_DESC Protofield_integer NAME Actual name of the field (the string that appears in the tree) */ +/* WSLUA_ARGDESC Protofield_integer DESC description of the field */ +/* _WSLUA_RETURNS_ Protofield_integer a protofiled item to be added to a ProtoFieldArray */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_uint8 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_uint16 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_uint24 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_uint32 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_uint64 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_int8 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_int16 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_int24 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_int32 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_int64 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_framenum */ +PROTOFIELD_INTEGER(uint8,FT_UINT8) +PROTOFIELD_INTEGER(uint16,FT_UINT16) +PROTOFIELD_INTEGER(uint24,FT_UINT24) +PROTOFIELD_INTEGER(uint32,FT_UINT32) +PROTOFIELD_INTEGER(uint64,FT_UINT64) +PROTOFIELD_INTEGER(int8,FT_INT8) +PROTOFIELD_INTEGER(int16,FT_INT8) +PROTOFIELD_INTEGER(int24,FT_INT8) +PROTOFIELD_INTEGER(int32,FT_INT8) +PROTOFIELD_INTEGER(int64,FT_INT8) +PROTOFIELD_INTEGER(framenum,FT_FRAMENUM) + +static int ProtoField_other(lua_State* L,enum ftenum type) { + ProtoField f = g_malloc(sizeof(wslua_field_t)); + const gchar* abbr = luaL_checkstring(L,1); + const gchar* name = luaL_optstring(L,2,abbr); + const gchar* blob = luaL_optstring(L,3,""); + + f->hfid = -2; + f->ett = -1; + f->name = g_strdup(name); + f->abbr = g_strdup(abbr); + f->type = type; + f->vs = NULL; + f->base = ( type == FT_FLOAT || type == FT_DOUBLE) ? BASE_DEC : BASE_NONE; + f->mask = 0; + f->blob = g_strdup(blob); + + pushProtoField(L,f); + + return 1; +} + +#define PROTOFIELD_OTHER(lower,FT) static int ProtoField_##lower(lua_State* L) { return ProtoField_other(L,FT); } +/* WSLUA_SECTION Protofield integer constructors */ +/* WSLUA_TEXT integer type ProtoField constructors use the following arguments */ +/* WSLUA_ARG_DESC Protofield_integer ABBR abbreviated name of the field (the string used in filters) */ +/* WSLUA_OPTARG_DESC Protofield_integer NAME Actual name of the field (the string that appears in the tree) */ +/* WSLUA_ARGDESC Protofield_integer DESC : description of the field */ +/* _WSLUA_RETURNS_ Protofield non integer : a protofiled item to be added to a ProtoFieldArray */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_ipv4 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_ipv6 */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_ether */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_float */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_double */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_string */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_strigz */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_bytes */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_ubytes */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_guid */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_oid */ +/* _WSLUA_CONSTRUCTOR_ ProtoField_bool */ +PROTOFIELD_OTHER(ipv4,FT_IPv4) +PROTOFIELD_OTHER(ipv6,FT_IPv6) +PROTOFIELD_OTHER(ipx,FT_IPXNET) +PROTOFIELD_OTHER(ether,FT_ETHER) +PROTOFIELD_OTHER(float,FT_FLOAT) +PROTOFIELD_OTHER(double,FT_DOUBLE) +PROTOFIELD_OTHER(string,FT_STRING) +PROTOFIELD_OTHER(stringz,FT_STRINGZ) +PROTOFIELD_OTHER(bytes,FT_BYTES) +PROTOFIELD_OTHER(ubytes,FT_UINT_BYTES) +PROTOFIELD_OTHER(guid,FT_GUID) +PROTOFIELD_OTHER(oid,FT_OID) + +/* XXX: T/F strings */ +PROTOFIELD_OTHER(bool,FT_BOOLEAN) + + +static int ProtoField_tostring(lua_State* L) { + 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,ftenum_to_string(f->type),base_to_string(f->base),f->vs,f->mask,f->blob); + + lua_pushstring(L,s); + g_free(s); + + return 1; +} + +static int ProtoField_gc(lua_State* L) { + ProtoField f = checkProtoField(L,1); + + /* + * A garbage collector for ProtoFields makes little sense. + * Even if This cannot be used anymore because it has gone out of scope, + * we can destroy the ProtoField only if it is not part of a ProtoFieldArray, + * if it actualy belongs to one we need to preserve it as it is pointed by + * a field array that may be registered afterwards causing a crash or memory corruption. + */ + + if (!f) { + luaL_argerror(L,1,"BUG: ProtoField_gc called for something not ProtoField"); + /* g_assert() ?? */ + } else if (f->hfid == -2) { + g_free(f->name); + g_free(f->abbr); + g_free(f->blob); + g_free(f); + } + + return 0; +} + + +static const luaL_reg ProtoField_methods[] = { + {"new", ProtoField_new}, + {"uint8",ProtoField_uint8}, + {"uint16",ProtoField_uint16}, + {"uint24",ProtoField_uint24}, + {"uint32",ProtoField_uint32}, + {"uint64",ProtoField_uint64}, + {"int8",ProtoField_int8}, + {"int16",ProtoField_int16}, + {"int24",ProtoField_int24}, + {"int32",ProtoField_int32}, + {"int64",ProtoField_int64}, + {"framenum",ProtoField_framenum}, + {"ipv4",ProtoField_ipv4}, + {"ipv6",ProtoField_ipv6}, + {"ipx",ProtoField_ipx}, + {"ether",ProtoField_ether}, + {"bool",ProtoField_bool}, + {"float",ProtoField_float}, + {"double",ProtoField_double}, + {"string",ProtoField_string}, + {"stringz",ProtoField_stringz}, + {"bytes",ProtoField_bytes}, + {"ubytes",ProtoField_ubytes}, + {"guid",ProtoField_guid}, + {"oid",ProtoField_oid}, + {0,0} +}; + +static const luaL_reg ProtoField_meta[] = { + {"__gc", ProtoField_gc }, + {"__tostring", ProtoField_tostring }, + {0, 0} +}; + +int ProtoField_register(lua_State* L) { + + WSLUA_REGISTER_CLASS(ProtoField); + + return 1; +} + +WSLUA_CLASS_DEFINE(Proto,NOP,NOP); +/* + A new protocol in wireshark. Protocols have more uses, the main one is to dissect + a protocol. But they can be just dummies used to register preferences for + other purposes. + */ + +static int protocols_table_ref = LUA_NOREF; + +WSLUA_CONSTRUCTOR Proto_new(lua_State* L) { +#define WSLUA_ARG_Proto_new_NAME 1 /* The name of the protocol */ +#define WSLUA_ARG_Proto_new_DESC 1 /* A Long Text description of the protocol (usually lowercase) */ + const gchar* name = luaL_checkstring(L,1); + const gchar* desc = luaL_checkstring(L,2); + + if ( name ) { + gchar* loname = ep_strdup(name); + g_strdown(loname); + if ( proto_get_id_by_filter_name(loname) > 0 ) { + WSLUA_ARG_ERROR(Proto_new,NAME,"there cannot be two protocols with the same name"); + } else { + Proto proto = g_malloc(sizeof(wslua_proto_t)); + gchar* loname = g_strdup(name); + gchar* hiname = g_strdup(name); + + g_strdown(loname); + g_strup(hiname); + + proto->name = hiname; + proto->desc = g_strdup(desc); + proto->hfid = proto_register_protocol(proto->desc,hiname,loname); + proto->ett = -1; + proto->is_postdissector = FALSE; + + lua_newtable (L); + proto->fields = luaL_ref(L, LUA_REGISTRYINDEX); + + proto->prefs.name = NULL; + proto->prefs.label = NULL; + proto->prefs.desc = NULL; + proto->prefs.value.u = 0; + proto->prefs.next = NULL; + proto->prefs.proto = proto; + + proto->prefs_module = NULL; + proto->handle = NULL; + + lua_rawgeti(L, LUA_REGISTRYINDEX, protocols_table_ref); + + lua_pushstring(L,loname); + pushProto(L,proto); + + lua_settable(L, -3); + + pushProto(L,proto); + + WSLUA_RETURN(1); /* The newly created protocol */ + } + } else { + WSLUA_ARG_ERROR(Proto_new,NAME,"must be a string"); + } + + return 0; +} + + + +static int Proto_tostring(lua_State* L) { + Proto proto = checkProto(L,1); + gchar* s; + + if (!proto) return 0; + + s = g_strdup_printf("Proto: %s",proto->name); + lua_pushstring(L,s); + g_free(s); + + return 1; +} + +WSLUA_FUNCTION wslua_register_postdissector(lua_State* L) { + Proto proto = checkProto(L,1); + if (!proto) return 0; + + if(!proto->is_postdissector) { + if (! proto->handle) { + proto->handle = create_dissector_handle(dissect_lua, proto->hfid); + } + + register_postdissector(proto->handle); + } else { + luaL_argerror(L,1,"this protocol is already registered as postdissector"); + } + + return 0; +} + + +static int Proto_get_dissector(lua_State* L) { + Proto proto = toProto(L,1); + + if (proto->handle) { + pushDissector(L,proto->handle); + return 1; + } else { + luaL_error(L,"The protocol hasn't been registered yet"); + return 0; + } +} + + +static int Proto_set_dissector(lua_State* L) { + Proto proto = toProto(L,1); + + if (lua_isfunction(L,3)) { + /* insert the dissector into the dissectors table */ + + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_dissectors_table_ref); + lua_replace(L, 1); + lua_pushstring(L,proto->name); + lua_replace(L, 2); + lua_settable(L,1); + + proto->handle = create_dissector_handle(dissect_lua, proto->hfid); + + return 0; + } else { + luaL_argerror(L,3,"The dissector of a protocol must be a function"); + return 0; + } +} + +static int Proto_get_prefs(lua_State* L) { + Proto proto = toProto(L,1); + + pushPrefs(L,&proto->prefs); + return 1; +} + +static int Proto_set_init(lua_State* L) { + Proto proto = toProto(L,1); + + if (lua_isfunction(L,3)) { + /* insert the dissector into the dissectors table */ + lua_pushstring(L, WSLUA_INIT_ROUTINES); + lua_gettable(L, LUA_GLOBALSINDEX); + lua_replace(L, 1); + lua_pushstring(L,proto->name); + lua_replace(L, 2); + lua_settable(L,1); + + return 0; + } else { + luaL_argerror(L,3,"The initializer of a protocol must be a function"); + return 0; + } +} + +static int Proto_get_name(lua_State* L) { + Proto proto = toProto(L,1); + + lua_pushstring(L,proto->name); + return 1; +} + + +static int Proto_get_fields(lua_State* L) { + Proto proto = toProto(L,1); + lua_rawgeti(L, LUA_REGISTRYINDEX, proto->fields); + return 1; +} + +void wslua_print_stack(char* s, lua_State* L) { + int i; + + for (i=1;i<=lua_gettop(L);i++) { + printf("%s-%i: %s\n",s,i,lua_typename (L,lua_type(L, i))); + } + printf("\n"); +} + +static int Proto_set_fields(lua_State* L) { + Proto proto = toProto(L,1); +#define FIELDS_TABLE 2 +#define NEW_TABLE 3 +#define NEW_FIELD 3 + + lua_rawgeti(L, LUA_REGISTRYINDEX, proto->fields); + lua_replace(L,FIELDS_TABLE); + + + if( lua_istable(L,NEW_TABLE)) { + for (lua_pushnil(L); lua_next(L, NEW_TABLE); ) { + if (isProtoField(L,5)) { + luaL_ref(L,FIELDS_TABLE); + } else if (! lua_isnil(L,5) ) { + return luaL_error(L,"only ProtoFields should be in the table"); + } + } + } else if (isProtoField(L,NEW_FIELD)){ + lua_pushvalue(L, NEW_FIELD); + luaL_ref(L,FIELDS_TABLE); + + } else { + return luaL_error(L,"either a ProtoField or an array of protofields"); + } + + lua_pushvalue(L, 3); + + return 1; +} + + + +typedef struct { + gchar* name; + lua_CFunction get; + lua_CFunction set; +} proto_actions_t; + +static const proto_actions_t proto_actions[] = { + /* WSLUA_ATTRIBUTE Pinfo_dissector RW the protocol's dissector, a function you define */ + {"dissector",Proto_get_dissector, Proto_set_dissector}, + + /* WSLUA_ATTRIBUTE Pinfo_fields RO the Fields Table of this dissector */ + {"fields" ,Proto_get_fields, Proto_set_fields}, + + /* WSLUA_ATTRIBUTE Proto_get_prefs RO the preferences of this dissector */ + {"prefs",Proto_get_prefs,NULL}, + + /* WSLUA_ATTRIBUTE Proto_init WO the init routine of this dissector, a function you define */ + {"init",NULL,Proto_set_init}, + + /* WSLUA_ATTRIBUTE Proto_init RO the name given to this dissector */ + {"name",Proto_get_name,NULL}, + {NULL,NULL,NULL} +}; + +static int Proto_index(lua_State* L) { + Proto proto = checkProto(L,1); + const gchar* name = luaL_checkstring(L,2); + const proto_actions_t* pa; + + if (! (proto && name) ) return 0; + + for (pa = proto_actions; pa->name; pa++) { + if ( g_str_equal(name,pa->name) ) { + if (pa->get) { + return pa->get(L); + } else { + luaL_error(L,"You cannot get the `%s' attribute of a protocol",name); + return 0; + } + } + } + + luaL_error(L,"A protocol doesn't have a `%s' attribute",name); + return 0; +} + + +static int Proto_newindex(lua_State* L) { + Proto proto = checkProto(L,1); + const gchar* name = luaL_checkstring(L,2); + const proto_actions_t* pa; + + if (! (proto && name) ) return 0; + + for (pa = proto_actions; pa->name; pa++) { + if ( g_str_equal(name,pa->name) ) { + if (pa->set) { + return pa->set(L); + } else { + luaL_error(L,"You cannot set the `%s' attribute of a protocol",name); + return 0; + } + } + } + + luaL_error(L,"A protocol doesn't have a `%s' attribute",name); + return 0; +} + +static const luaL_reg Proto_meta[] = { + {"__tostring", Proto_tostring}, + {"__index", Proto_index}, + {"__newindex", Proto_newindex}, + {0, 0} +}; + +int Proto_register(lua_State* L) { + + WSLUA_REGISTER_META(Proto); + + lua_newtable(L); + protocols_table_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + lua_pushstring(L, "Proto"); + lua_pushcfunction(L, Proto_new); + lua_settable(L, LUA_GLOBALSINDEX); + + Pref_register(L); + Prefs_register(L); + + return 1; +} + +int Proto_commit(lua_State* L) { + lua_settop(L,0); + lua_rawgeti(L, LUA_REGISTRYINDEX, protocols_table_ref); + + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 2)) { + GArray* hfa = g_array_new(TRUE,TRUE,sizeof(hf_register_info)); + GArray* etta = g_array_new(TRUE,TRUE,sizeof(gint*)); + Proto proto; + const gchar* proto_name; + proto_name = lua_tostring(L,2); + proto = checkProto(L,3); + + lua_rawgeti(L, LUA_REGISTRYINDEX, proto->fields); + + for (lua_pushnil(L); lua_next(L, 4); lua_pop(L, 1)) { + ProtoField f = checkProtoField(L,6); + hf_register_info hfri = { &(f->hfid), {f->name,f->abbr,f->type,f->base,VALS(f->vs),f->mask,f->blob,HFILL}}; + gint* ettp = &(f->ett); + + if (f->hfid != -2) { + return luaL_error(L,"fields can be registered only once"); + } + + f->hfid = -1; + g_array_append_val(hfa,hfri); + g_array_append_val(etta,ettp); + } + + proto_register_field_array(proto->hfid,(hf_register_info*)hfa->data,hfa->len); + proto_register_subtree_array((gint**)etta->data,etta->len); + + g_array_free(hfa,FALSE); + g_array_free(etta,FALSE); + } + + return 0; +} + + + +WSLUA_CLASS_DEFINE(Dissector,NOP,NOP); +/* + A refererence to a dissector, used to call a dissector against a packet or a part of it. + */ + + +WSLUA_CONSTRUCTOR Dissector_get (lua_State *L) { + /* + * Obtains a dissector reference by name + */ +#define WSLUA_ARG_Dissector_get_NAME 1 /* The name of the dissector */ + const gchar* name = luaL_checkstring(L,1); + Dissector d; + + if (!name) + WSLUA_ARG_ERROR(Dissector_get,NAME,"must be a string"); + + if ((d = find_dissector(name))) { + pushDissector(L, d); + WSLUA_RETURN(1); /* The Dissector reference */ + } else + WSLUA_ARG_ERROR(Dissector_get,NAME,"No such dissector"); + +} + +WSLUA_METHOD Dissector_call(lua_State* L) { + /* + * Calls a dissector against a given packet (or part of it) + */ +#define WSLUA_ARG_Dissector_call_TVB 2 /* The buffer to dissect */ +#define WSLUA_ARG_Dissector_call_PINFO 3 /* The packet info */ +#define WSLUA_ARG_Dissector_call_TREE 4 /* The tree on which to add the protocol items */ + + Dissector d = checkDissector(L,1); + Tvb tvb = checkTvb(L,WSLUA_ARG_Dissector_call_TVB); + Pinfo pinfo = checkPinfo(L,WSLUA_ARG_Dissector_call_PINFO); + TreeItem ti = checkTreeItem(L,WSLUA_ARG_Dissector_call_TREE); + + if (! ( d && tvb && pinfo) ) return 0; + + TRY { + call_dissector(d, tvb, pinfo, ti->tree); + /* XXX Are we sure about this??? is this the right/only thing to catch */ + } CATCH(ReportedBoundsError) { + proto_tree_add_protocol_format(lua_tree->tree, lua_malformed, lua_tvb, 0, 0, "[Malformed Frame: Packet Length]" ); + WSLUA_ERROR(Dissector_call,"malformed frame"); + return 0; + } ENDTRY; + + return 0; +} + + +static int Dissector_tostring(lua_State* L) { + Dissector d = checkDissector(L,1); + if (!d) return 0; + lua_pushstring(L,dissector_handle_get_short_name(d)); + return 1; +} + +static const luaL_reg Dissector_methods[] = { + {"get", Dissector_get }, + {"call", Dissector_call }, + {0,0} +}; + +static const luaL_reg Dissector_meta[] = { + {"__tostring", Dissector_tostring}, + {0, 0} +}; + +int Dissector_register(lua_State* L) { + WSLUA_REGISTER_CLASS(Dissector); + return 1; +} + + +WSLUA_CLASS_DEFINE(DissectorTable,NOP,NOP); +/* + A table of subdissectors of a particular protocol (e.g. TCP subdissectors like http, smtp, sip are added to table "tcp.port"). + Useful to add more dissectors to a table so that they appear in the Decode As... dialog. + */ + +WSLUA_CONSTRUCTOR DissectorTable_new (lua_State *L) { + /* + Creates a new DissectorTable for your dissector's use . + */ +#define WSLUA_ARG_DissectorTable_new_TABLENAME 1 /* The short name of the table. */ +#define WSLUA_OPTARG_DissectorTable_new_UINAME 2 /* The name of the table in the User Interface (defaults to the name given). */ +#define WSLUA_OPTARG_DissectorTable_new_TYPE 3 /* either FT_UINT* or FT_STRING (defaults to FT_UINT32) */ + gchar* name = (void*)luaL_checkstring(L,WSLUA_ARG_DissectorTable_new_TABLENAME); + gchar* ui_name = (void*)luaL_optstring(L,WSLUA_OPTARG_DissectorTable_new_UINAME,name); + enum ftenum type = luaL_optint(L,WSLUA_OPTARG_DissectorTable_new_TYPE,FT_UINT32); + base_display_e base = luaL_optint(L,4,BASE_DEC); + + if(!(name && ui_name)) return 0; + + name = g_strdup(name); + ui_name = g_strdup(ui_name); + + switch(type) { + case FT_STRING: + base = BASE_NONE; + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + { + DissectorTable dt = g_malloc(sizeof(struct _wslua_distbl_t)); + + dt->table = register_dissector_table(name, ui_name, type, base); + dt->name = name; + pushDissectorTable(L, dt); + } + WSLUA_RETURN(1); /* The newly created DissectorTable */ + default: + WSLUA_OPTARG_ERROR(DissectorTable_new,TYPE,"must be FTUINT* or FT_STRING"); + } + return 0; +} + +WSLUA_CONSTRUCTOR DissectorTable_get (lua_State *L) { + /* + Obtain a reference to an existing dissector table. + */ +#define WSLUA_ARG_DissectorTable_get_TABLENAME 1 /* The short name of the table. */ + const gchar* name = luaL_checkstring(L,WSLUA_ARG_DissectorTable_get_TABLENAME); + dissector_table_t table; + + if(!name) return 0; + + table = find_dissector_table(name); + + if (table) { + DissectorTable dt = g_malloc(sizeof(struct _wslua_distbl_t)); + dt->table = table; + dt->name = g_strdup(name); + + pushDissectorTable(L, dt); + + WSLUA_RETURN(1); /* The DissectorTable */ + } else + WSLUA_ARG_ERROR(DissectorTable_get,TABLENAME,"no such dissector_table"); + +} + + +WSLUA_METHOD DissectorTable_add (lua_State *L) { + /* + Add a dissector to a table. + */ +#define WSLUA_ARG_DissectorTable_add_PATTERN 2 /* The pattern to match (either an integer or a string depending on the table's type). */ +#define WSLUA_ARG_DissectorTable_add_DISSECTOR 3 /* The dissector to add (either an Proto or a Dissector). */ + + DissectorTable dt = checkDissectorTable(L,1); + ftenum_t type; + Dissector handle; + + if (!dt) return 0; + + if( isProto(L,WSLUA_ARG_DissectorTable_add_DISSECTOR) ) { + Proto p; + p = toProto(L,WSLUA_ARG_DissectorTable_add_DISSECTOR); + handle = p->handle; + + if (! handle) + WSLUA_ARG_ERROR(DissectorTable_add,DISSECTOR,"a Protocol that does not have a dissector cannot be added to a table"); + + } else if ( isDissector(L,WSLUA_ARG_DissectorTable_add_DISSECTOR) ) { + handle = toDissector(L,WSLUA_ARG_DissectorTable_add_DISSECTOR); + } else + WSLUA_ARG_ERROR(DissectorTable_add,DISSECTOR,"must be either Proto or Dissector"); + + type = get_dissector_table_selector_type(dt->name); + + if (type == FT_STRING) { + gchar* pattern = g_strdup(luaL_checkstring(L,WSLUA_ARG_DissectorTable_add_PATTERN)); + dissector_add_string(dt->name, pattern,handle); + } else if ( type == FT_UINT32 || type == FT_UINT16 || type == FT_UINT8 || type == FT_UINT24 ) { + int port = luaL_checkint(L, WSLUA_ARG_DissectorTable_add_PATTERN); + dissector_add(dt->name, port, handle); + } else { + luaL_error(L,"Strange type %d for a DissectorTable",type); + } + + return 0; +} + +WSLUA_METHOD DissectorTable_remove (lua_State *L) { + /* + Remove a dissector from a table + */ +#define WSLUA_ARG_DissectorTable_remove_PATTERN 2 /* The pattern to match (either an integer or a string depending on the table's type). */ +#define WSLUA_ARG_DissectorTable_remove_DISSECTOR 3 /* The dissector to add (either an Proto or a Dissector). */ + DissectorTable dt = checkDissectorTable(L,1); + ftenum_t type; + Dissector handle; + + if (!dt) return 0; + + if( isProto(L,WSLUA_ARG_DissectorTable_remove_DISSECTOR) ) { + Proto p; + p = toProto(L,WSLUA_ARG_DissectorTable_remove_DISSECTOR); + handle = p->handle; + + } else if ( isDissector(L,WSLUA_ARG_DissectorTable_remove_DISSECTOR) ) { + handle = toDissector(L,WSLUA_ARG_DissectorTable_remove_DISSECTOR); + } else + WSLUA_ARG_ERROR(DissectorTable_add,DISSECTOR,"must be either Proto or Dissector"); + + type = get_dissector_table_selector_type(dt->name); + + if (type == FT_STRING) { + gchar* pattern = g_strdup(luaL_checkstring(L,2)); + dissector_delete_string(dt->name, pattern,handle); + } else if ( type == FT_UINT32 || type == FT_UINT16 || type == FT_UINT8 || type == FT_UINT24 ) { + int port = luaL_checkint(L, 2); + dissector_delete(dt->name, port, handle); + } + + return 0; +} + + +WSLUA_METHOD DissectorTable_try (lua_State *L) { + /* + Try to call a dissector from a table + */ +#define WSLUA_ARG_DissectorTable_try_PATTERN 2 /* The pattern to be matched (either an integer or a string depending on the table's type). */ +#define WSLUA_ARG_DissectorTable_try_TVB 3 /* The buffer to dissect */ +#define WSLUA_ARG_DissectorTable_try_PINFO 4 /* The packet info */ +#define WSLUA_ARG_DissectorTable_try_TREE 5 /* The tree on which to add the protocol items */ + DissectorTable dt = checkDissectorTable(L,1); + Tvb tvb = checkTvb(L,3); + Pinfo pinfo = checkPinfo(L,4); + TreeItem ti = checkTreeItem(L,5); + ftenum_t type; + + if (! (dt && tvb && pinfo && ti) ) return 0; + + type = get_dissector_table_selector_type(dt->name); + + TRY { + + if (type == FT_STRING) { + const gchar* pattern = luaL_checkstring(L,2); + + if (!pattern) return 0; + + if (dissector_try_string(dt->table,pattern,tvb,pinfo,ti->tree)) + return 0; + + } else if ( type == FT_UINT32 || type == FT_UINT16 || type == FT_UINT8 || type == FT_UINT24 ) { + int port = luaL_checkint(L, 2); + + if (dissector_try_port(dt->table,port,tvb,pinfo,ti->tree)) + return 0; + + } else { + luaL_error(L,"No such type of dissector_table"); + } + + call_dissector(lua_data_handle,tvb,pinfo,ti->tree); + + /* XXX Are we sure about this??? is this the right/only thing to catch */ + } CATCH(ReportedBoundsError) { + proto_tree_add_protocol_format(lua_tree->tree, lua_malformed, lua_tvb, 0, 0, "[Malformed Frame: Packet Length]" ); + WSLUA_ERROR(DissectorTable_try,"malformed frame"); + } ENDTRY; + + return 0; + +} + +WSLUA_METHOD DissectorTable_get_dissector (lua_State *L) { + /* + Try to obtain a dissector from a table. + */ +#define WSLUA_ARG_DissectorTable_try_PATTERN 2 /* The pattern to be matched (either an integer or a string depending on the table's type). */ + + DissectorTable dt = checkDissectorTable(L,1); + ftenum_t type; + dissector_handle_t handle = lua_data_handle; + + if (!dt) return 0; + + type = get_dissector_table_selector_type(dt->name); + + if (type == FT_STRING) { + const gchar* pattern = luaL_checkstring(L,WSLUA_ARG_DissectorTable_try_PATTERN); + + if (!pattern) WSLUA_ARG_ERROR(DissectorTable_try,PATTERN,"must be a string"); + + handle = dissector_get_string_handle(dt->table,pattern); + } else if ( type == FT_UINT32 || type == FT_UINT16 || type == FT_UINT8 || type == FT_UINT24 ) { + int port = luaL_checkint(L, WSLUA_ARG_DissectorTable_try_PATTERN); + handle = dissector_get_port_handle(dt->table,port); + } + + if (handle) { + pushDissector(L,handle); + WSLUA_RETURN(1); /* The dissector handle if found */ + } else { + lua_pushnil(L); + WSLUA_RETURN(1); /* nil if not found */ + } +} + + +static int DissectorTable_tostring(lua_State* L) { + /* XXX It would be nice to iterate and print which dissectors it has */ + DissectorTable dt = checkDissectorTable(L,1); + GString* s; + ftenum_t type; + + if (!dt) return 0; + + type = get_dissector_table_selector_type(dt->name); + s = g_string_new("DissectorTable "); + + switch(type) { + case FT_STRING: + { + g_string_sprintfa(s,"%s String:\n",dt->name); + break; + } + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + { + int base = get_dissector_table_base(dt->name); + g_string_sprintfa(s,"%s Integer(%i):\n",dt->name,base); + break; + } + default: + luaL_error(L,"Strange table type"); + } + + lua_pushstring(L,s->str); + g_string_free(s,TRUE); + return 1; +} + +static const luaL_reg DissectorTable_methods[] = { + {"new", DissectorTable_new }, + {"get", DissectorTable_get }, + {"add", DissectorTable_add }, + {"remove", DissectorTable_remove }, + {"try", DissectorTable_try }, + {"get_dissector", DissectorTable_get_dissector }, + {0,0} +}; + +static const luaL_reg DissectorTable_meta[] = { + {"__tostring", DissectorTable_tostring}, + {0, 0} +}; + +int DissectorTable_register(lua_State* L) { + WSLUA_REGISTER_CLASS(DissectorTable); + return 1; +} + + + diff --git a/epan/wslua/wslua_tree.c b/epan/wslua/wslua_tree.c new file mode 100644 index 0000000000..b4f2c97de9 --- /dev/null +++ b/epan/wslua/wslua_tree.c @@ -0,0 +1,290 @@ +/* + * wslua_tree.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_tree.c 18231 2006-05-28 16:32:49Z etxrab $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" +#include <epan/expert.h> + +static gint wslua_ett = -1; + +static GPtrArray* outstanding_stuff = NULL; + +#define PUSH_TREEITEM(L,i) g_ptr_array_add(outstanding_stuff,push_TreeItem(L,i)) + +void* push_TreeItem(lua_State*L, TreeItem t) { + void** p = (void**)pushTreeItem(L,t); + g_ptr_array_add(outstanding_stuff,p); + return p; +} + +void clear_outstanding_trees(void) { + while (outstanding_stuff->len) { + void** p = (void**)g_ptr_array_remove_index_fast(outstanding_stuff,0); + *p = NULL; + } +} + +WSLUA_CLASS_DEFINE(TreeItem,NOP,NOP); + +/* ProtoTree class */ +static int TreeItem_add_item_any(lua_State *L, gboolean little_endian) { + TvbRange tvbr; + Proto proto; + ProtoField field; + int hfid = -1; + int ett = -1; + ftenum_t type = FT_NONE; + TreeItem tree_item = shiftTreeItem(L,1); + proto_item* item = NULL; + + if (!tree_item) { + return luaL_error(L,"not a TreeItem!"); + } + if (! ( field = shiftProtoField(L,1) ) ) { + if (( proto = shiftProto(L,1) )) { + hfid = proto->hfid; + type = FT_PROTOCOL; + ett = proto->ett; + } + } else { + hfid = field->hfid; + type = field->type; + ett = field->ett; + } + + tvbr = shiftTvbRange(L,1); + + if (!tvbr) { + tvbr = ep_alloc(sizeof(struct _wslua_tvbrange)); + tvbr->tvb = lua_tvb; + tvbr->offset = 0; + tvbr->len = 0; + } + + if (hfid > 0 ) { + if (lua_gettop(L)) { + switch(type) { + case FT_PROTOCOL: + item = proto_tree_add_item(tree_item->tree,hfid,tvbr->tvb,tvbr->offset,tvbr->len,FALSE); + lua_pushnumber(L,0); + lua_insert(L,1); + break; + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + case FT_FRAMENUM: + item = proto_tree_add_uint(tree_item->tree,hfid,tvbr->tvb,tvbr->offset,tvbr->len,(guint32)luaL_checknumber(L,1)); + break; + case FT_INT8: + case FT_INT16: + case FT_INT24: + case FT_INT32: + item = proto_tree_add_int(tree_item->tree,hfid,tvbr->tvb,tvbr->offset,tvbr->len,(gint32)luaL_checknumber(L,1)); + break; + case FT_FLOAT: + item = proto_tree_add_float(tree_item->tree,hfid,tvbr->tvb,tvbr->offset,tvbr->len,(float)luaL_checknumber(L,1)); + break; + case FT_DOUBLE: + item = proto_tree_add_double(tree_item->tree,hfid,tvbr->tvb,tvbr->offset,tvbr->len,(double)luaL_checknumber(L,1)); + break; + case FT_STRING: + case FT_STRINGZ: + item = proto_tree_add_string(tree_item->tree,hfid,tvbr->tvb,tvbr->offset,tvbr->len,luaL_checkstring(L,1)); + break; + case FT_UINT64: + case FT_INT64: + case FT_ETHER: + case FT_BYTES: + case FT_UINT_BYTES: + case FT_IPv4: + case FT_IPv6: + case FT_IPXNET: + case FT_GUID: + case FT_OID: + default: + luaL_error(L,"FT_ not yet supported"); + return 0; + } + + lua_remove(L,1); + + } else { + item = proto_tree_add_item(tree_item->tree, hfid, tvbr->tvb, tvbr->offset, tvbr->len, little_endian); + } + + if ( lua_gettop(L) ) { + const gchar* s = lua_tostring(L,1); + + if (s) proto_item_set_text(item,"%s",s); + + lua_remove(L,1); + + } + + } else if (tvbr) { + if (lua_gettop(L)) { + const gchar* s = lua_tostring(L,1); + + item = proto_tree_add_text(tree_item->tree, tvbr->tvb, tvbr->offset, tvbr->len,"%s",s); + lua_remove(L,1); + } + } else { + if (lua_gettop(L)) { + const gchar* s = lua_tostring(L,1); + item = proto_tree_add_text(tree_item->tree, lua_tvb, 0, 0,"%s",s); + lua_remove(L,1); + } + } + + while(lua_gettop(L)) { + const gchar* s = lua_tostring(L,1); + + if (s) proto_item_append_text(item, " %s", s); + + lua_remove(L,1); + + } + + + tree_item = ep_alloc(sizeof(struct _wslua_treeitem)); + tree_item->item = item; + tree_item->tree = proto_item_add_subtree(item,ett > 0 ? ett : wslua_ett); + + PUSH_TREEITEM(L,tree_item); + + return 1; +} + + +WSLUA_METHOD TreeItem_add(lua_State *L) { return TreeItem_add_item_any(L,FALSE); } +WSLUA_METHOD TreeItem_add_le(lua_State *L) { return TreeItem_add_item_any(L,TRUE); } + +WSLUA_METHOD TreeItem_set_text(lua_State *L) { + TreeItem ti = checkTreeItem(L,1); + + if (ti) { + const gchar* s = luaL_checkstring(L,2); + proto_item_set_text(ti->item,"%s",s); + } + + return 0; +} + +WSLUA_METHOD TreeItem_append_text(lua_State *L) { + TreeItem ti = checkTreeItem(L,1); + const gchar* s; + + if (ti) { + s = luaL_checkstring(L,2); + proto_item_append_text(ti->item,"%s",s); + } + return 0; +} + +WSLUA_METHOD TreeItem_set_len(lua_State *L) { + TreeItem ti = checkTreeItem(L,1); + int len; + + if (ti) { + len = luaL_checkint(L,2); + proto_item_set_len(ti->item,len); + } + + return 0; +} + +WSLUA_METHOD TreeItem_set_expert_flags(lua_State *L) { + TreeItem ti = checkTreeItem(L,1); + int group = luaL_checkint(L,2); + int severity = luaL_checkint(L,3); + + if ( ti && ti->item ) { + proto_item_set_expert_flags(ti->item,group,severity); + } + + return 0; +} + +WSLUA_METHOD TreeItem_add_expert_info(lua_State *L) { + TreeItem ti = checkTreeItem(L,1); + int group = luaL_checkint(L,2); + int severity = luaL_checkint(L,3); + const gchar* str = luaL_optstring(L,4,"Expert Info"); + + if ( ti && ti->item ) { + expert_add_info_format(lua_pinfo, ti->item, group, severity, "%s", str); + } + + return 0; +} + +WSLUA_METHOD TreeItem_set_generated(lua_State *L) { + TreeItem ti = checkTreeItem(L,1); + if (ti) { + PROTO_ITEM_SET_GENERATED(ti->item); + } + return 0; +} + + +WSLUA_METHOD TreeItem_set_hidden(lua_State *L) { + TreeItem ti = checkTreeItem(L,1); + if (ti) { + PROTO_ITEM_SET_HIDDEN(ti->item); + } + return 0; +} + +static const luaL_reg TreeItem_methods[] = { + {"add", TreeItem_add}, + {"add_le", TreeItem_add_le}, + {"set_text", TreeItem_set_text}, + {"append_text", TreeItem_append_text}, + {"set_len", TreeItem_set_len}, + {"set_expert_flags", TreeItem_set_expert_flags}, + {"add_expert_info", TreeItem_add_expert_info}, + {"set_generated", TreeItem_set_generated}, + {"set_hidden", TreeItem_set_hidden}, + {0, 0} +}; +static const luaL_reg TreeItem_meta[] = { + {0, 0} +}; + + + +int TreeItem_register(lua_State *L) { + gint* etts[] = { &wslua_ett }; + + WSLUA_REGISTER_CLASS(TreeItem); + outstanding_stuff = g_ptr_array_new(); + + proto_register_subtree_array(etts,1); + + return 1; +} diff --git a/epan/wslua/wslua_tvb.c b/epan/wslua/wslua_tvb.c new file mode 100644 index 0000000000..01c8437188 --- /dev/null +++ b/epan/wslua/wslua_tvb.c @@ -0,0 +1,738 @@ +/* + * wslua_tvb.c + * + * Wireshark's interface to the Lua Programming Language + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_tvb.c 18231 2006-05-28 16:32:49Z etxrab $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" + +WSLUA_CLASS_DEFINE(ByteArray,FAIL_ON_NULL("null bytearray"),NOP); + +WSLUA_CONSTRUCTOR ByteArray_new(lua_State* L) { /* creates a ByteArray Object */ +#define WSLUA_OPTARG_ByteArray_new_HEXBYTES 1 /* A string consisting of hexadecimal bytes like "00 B1 A2" or "1a2b3c4d" */ + GByteArray* ba = g_byte_array_new(); + const gchar* s; + int nibble[2]; + int i = 0; + gchar c; + + if (lua_gettop(L) == 1) { + s = luaL_checkstring(L,WSLUA_OPTARG_ByteArray_new_HEXBYTES); + + if (!s) { + WSLUA_OPTARG_ERROR(ByteArray_new,HEXBYTES,"must be a string"); + return 0; + } + + /* XXX: slow! */ + for (; (c = *s); s++) { + switch(c) { + case '0': case '1': case '2': case '3': case '4': case '5' : case '6' : case '7': case '8' : case '9' : + nibble[(i++)%2] = c - '0'; + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f' : + nibble[(i++)%2] = c - 'a' + 0xa; + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F' : + nibble[(i++)%2] = c - 'A' + 0xa; + break; + default: + break; + } + + if ( i == 2 ) { + guint8 b = (guint8)(nibble[0] * 16 + nibble[1]); + g_byte_array_append(ba,&b,1); + i = 0; + } + } + } + + pushByteArray(L,ba); + + WSLUA_RETURN(1); /* The new ByteArray object. */ +} + +static int ByteArray_gc(lua_State* L) { + ByteArray ba = checkByteArray(L,1); + + if (!ba) return 0; + + g_byte_array_free(ba,TRUE); + return 0; +} + +WSLUA_METAMETHOD ByteArray__concat(lua_State* L) { +#define WSLUA_ARG_ByteArray__cat_FIRST 1 +#define WSLUA_ARG_ByteArray__cat_SECOND 1 + + ByteArray ba = checkByteArray(L,1); + ByteArray ba2 = checkByteArray(L,2); + + if (! (ba && ba2) ) + WSLUA_ERROR(ByteArray__cat,"both arguments must be ByteArrays"); + + g_byte_array_append(ba,ba2->data,ba2->len); + + pushByteArray(L,ba); + WSLUA_RETURN(1); /* The new composite ByteArray. */ +} + +WSLUA_METHOD ByteArray_prepend(lua_State* L) { +#define WSLUA_ARG_ByteArray_prepend_BYTES 1 + ByteArray ba = checkByteArray(L,1); + ByteArray ba2 = checkByteArray(L,2); + + if (! (ba && ba2) ) + WSLUA_ERROR(ByteArray_prepend,"both arguments must be ByteArrays"); + + g_byte_array_prepend(ba,ba2->data,ba2->len); + + pushByteArray(L,ba); + return 1; +} + +WSLUA_METHOD ByteArray_append(lua_State* L) { + ByteArray ba = checkByteArray(L,1); + ByteArray ba2 = checkByteArray(L,2); + + if (! (ba && ba2) ) + WSLUA_ERROR(ByteArray_prepend,"both arguments must be ByteArrays"); + + g_byte_array_prepend(ba,ba2->data,ba2->len); + + pushByteArray(L,ba); + return 1; +} + +WSLUA_METHOD ByteArray_set_size(lua_State* L) { + ByteArray ba = checkByteArray(L,1); + int siz = luaL_checkint(L,2); + + if (!ba) return 0; + + g_byte_array_set_size(ba,siz); + return 0; +} + +WSLUA_METHOD ByteArray_set_index(lua_State* L) { + ByteArray ba = checkByteArray(L,1); + int idx = luaL_checkint(L,2); + int v = luaL_checkint(L,3); + + if (!ba) return 0; + + if (idx == 0 && ! g_str_equal(luaL_optstring(L,2,""),"0") ) { + luaL_argerror(L,2,"bad index"); + return 0; + } + + if (idx < 0 || (guint)idx >= ba->len) { + luaL_argerror(L,2,"index out of range"); + return 0; + } + + if (v < 0 || v > 255) { + luaL_argerror(L,3,"Byte out of range"); + return 0; + } + + ba->data[idx] = (guint8)v; + + return 0; +} + + +WSLUA_METHOD ByteArray_get_index(lua_State* L) { + ByteArray ba = checkByteArray(L,1); + int idx = luaL_checkint(L,2); + + if (!ba) return 0; + + if (idx == 0 && ! g_str_equal(luaL_optstring(L,2,""),"0") ) { + luaL_argerror(L,2,"bad index"); + return 0; + } + + if (idx < 0 || (guint)idx >= ba->len) { + luaL_argerror(L,2,"index out of range"); + return 0; + } + lua_pushnumber(L,ba->data[idx]); + + return 1; +} + +WSLUA_METHOD ByteArray_len(lua_State* L) { + ByteArray ba = checkByteArray(L,1); + + if (!ba) return 0; + + lua_pushnumber(L,(lua_Number)ba->len); + + return 1; +} + +WSLUA_METHOD ByteArray_subset(lua_State* L) { + ByteArray ba = checkByteArray(L,1); + int offset = luaL_checkint(L,2); + int len = luaL_checkint(L,3); + ByteArray sub; + + if (!ba) return 0; + + if ((offset + len) > (int)ba->len || offset < 0 || len < 1) { + luaL_error(L,"Out Of Bounds"); + return 0; + } + + sub = g_byte_array_new(); + g_byte_array_append(sub,ba->data + offset,len); + + pushByteArray(L,sub); + + return 1; +} + +static int ByteArray_tostring(lua_State* L) { + static const gchar* byte_to_str[] = { + "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F", + "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F", + "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F", + "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F", + "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F", + "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F", + "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F", + "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F", + "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F", + "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F", + "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF", + "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF", + "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF", + "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF", + "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF", + "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF" + }; + ByteArray ba = checkByteArray(L,1); + int i; + GString* s; + + if (!ba) return 0; + + s = g_string_new(""); + + for (i = 0; i < (int)ba->len; i++) { + g_string_append(s,byte_to_str[(ba->data)[i]]); + } + + lua_pushstring(L,s->str); + g_string_free(s,TRUE); + + return 1; +} + +static int Tvb_new_real (lua_State *L); + +static const luaL_reg ByteArray_methods[] = { + {"new", ByteArray_new}, + {"len", ByteArray_len}, + {"prepend", ByteArray_prepend}, + {"append", ByteArray_append}, + {"subset", ByteArray_subset}, + {"set_size", ByteArray_set_size}, + {"tvb", Tvb_new_real}, + {"get_index", ByteArray_get_index}, + {"set_index", ByteArray_set_index}, + {0,0} +}; + +static const luaL_reg ByteArray_meta[] = { + {"__tostring", ByteArray_tostring}, + {"__gc", ByteArray_gc}, + {"__concat", ByteArray__concat}, + {"__call",ByteArray_subset}, + {0, 0} +}; + +int ByteArray_register(lua_State* L) { + WSLUA_REGISTER_CLASS(ByteArray); + return 1; +} + + +/* + * Tvb & TvbRange + * + * a Tvb represents a tvbuff_t in Lua. + * a TvbRange represents a range in a tvb (tvb,offset,lenght) it's main purpose is to do bounds checking, + * it helps too simplifing argument passing to Tree. In wireshark terms this is worthless nothing + * not already done by the TVB itself. In lua's terms is necessary to avoid abusing TRY{}CATCH(){} + * via preemptive bounds checking. + * + * These lua objects have to be "NULLified after use", that is, we cannot leave pointers in the + * lua machine to a tvb or a tvbr that might exist anymore. + * + * To do so we are going to keep a pointer to every "box" in which lua has placed a pointer to our object + * and then NULLify the object lua points to. + * + * Other than that we are going to check every instance of a potentialy NULLified object before using it + * and report an error to the lua machine if it happens to be NULLified. + */ + +WSLUA_CLASS_DEFINE(Tvb,FAIL_ON_NULL("expired tvb"),NOP); + +static GPtrArray* outstanding_stuff = NULL; + +#define PUSH_TVB(L,t) g_ptr_array_add(outstanding_stuff,pushTvb(L,t)) +#define PUSH_TVBRANGE(L,t) g_ptr_array_add(outstanding_stuff,pushTvbRange(L,t)) + +void clear_outstanding_tvbs(void) { + while (outstanding_stuff->len) { + void** p = (void**)g_ptr_array_remove_index_fast(outstanding_stuff,0); + *p = NULL; + } +} + +void* push_Tvb(lua_State* L, Tvb tvb) { + void** p = (void**)pushTvb(L,tvb); + g_ptr_array_add(outstanding_stuff,p); + return p; +} + + + +/* + * Tvb_new_real(bytearray,name) + * Creates a new Tvb from a bytearray (adds it to the frame too) + */ +static int Tvb_new_real (lua_State *L) { + ByteArray ba = checkByteArray(L,1); + const gchar* name = luaL_optstring(L,2,"Unnamed") ; + guint8* data; + Tvb tvb; + + if (!ba) return 0; + + if (!lua_tvb) { + luaL_error(L,"Tvbs can only be created and used in dissectors"); + return 0; + } + + data = g_memdup(ba->data, ba->len); + + tvb = tvb_new_real_data(data, ba->len,ba->len); + tvb_set_free_cb(tvb, g_free); + + add_new_data_source(lua_pinfo, tvb, name); + PUSH_TVB(L,tvb); + return 1; +} + +/* + * creates a subtvb from a tvbrange + * + */ +static int Tvb_new_subset (lua_State *L) { + TvbRange tvbr = checkTvbRange(L,1); + + if (! tvbr) return 0; + + if (tvb_offset_exists(tvbr->tvb, tvbr->offset + tvbr->len -1 )) { + PUSH_TVB(L, tvb_new_subset(tvbr->tvb,tvbr->offset,tvbr->len, tvbr->len) ); + return 1; + } else { + luaL_error(L,"Out Of Bounds"); + return 0; + } +} + +/* + * convert the bytes to string, mainly for debugging purposes (mind the ...) + */ +static int Tvb_tostring(lua_State* L) { + Tvb tvb = checkTvb(L,1); + int len; + gchar* str; + + if (!tvb) return 0; + + len = tvb_length(tvb); + str = ep_strdup_printf("TVB(%i) : %s",len,tvb_bytes_to_str(tvb,0,len)); + lua_pushstring(L,str); + return 1; +} + + +/* + * returns the length of a TVB + */ +static int Tvb_len(lua_State* L) { + Tvb tvb = checkTvb(L,1); + + if (!tvb) return 0; + + lua_pushnumber(L,tvb_length(tvb)); + return 1; +} + +/* + * returns the raw offset of a sub TVB + */ +static int Tvb_offset(lua_State* L) { + Tvb tvb = checkTvb(L,1); + + if (!tvb) return 0; + + lua_pushnumber(L,TVB_RAW_OFFSET(tvb)); + return 1; +} + + +static const luaL_reg Tvb_methods[] = { + {"len", Tvb_len}, + {"offset", Tvb_offset}, + {0,0} +}; + +static int Tvb_range(lua_State* L); + +static const luaL_reg Tvb_meta[] = { + {"__call", Tvb_range}, + {"__tostring", Tvb_tostring}, + {0, 0} +}; + +int Tvb_register(lua_State* L) { + WSLUA_REGISTER_CLASS(Tvb); + return 1; +} + +/* + * TVB RAnge helper class + * + */ + +TvbRange new_TvbRange(lua_State* L, tvbuff_t* tvb, int offset, int len) { + TvbRange tvbr; + + if (len == -1) { + len = tvb_length_remaining(tvb,offset); + if (len < 0) { + luaL_error(L,"out of bounds"); + return 0; + } + } else if ( (guint)(len + offset) > tvb_length(tvb)) { + luaL_error(L,"Range is out of bounds"); + return NULL; + } + + tvbr = ep_alloc(sizeof(struct _wslua_tvbrange)); + tvbr->tvb = tvb; + tvbr->offset = offset; + tvbr->len = len; + + return tvbr; +} + +/* + * creates a tvbr given the triplet (tvb,offset,len) + */ +static int Tvb_range(lua_State* L) { + Tvb tvb = checkTvb(L,1); + int offset = luaL_optint(L,2,0); + int len = luaL_optint(L,3,-1); + TvbRange tvbr; + + if (!tvb) return 0; + + if ((tvbr = new_TvbRange(L,tvb,offset,len))) { + PUSH_TVBRANGE(L,tvbr); + return 1; + } + + return 0; + +} + +WSLUA_CLASS_DEFINE(TvbRange,FAIL_ON_NULL("expired tvbrange"),NOP); + +/* + * read access to tvbr's data + */ +static int TvbRange_get_index(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + const gchar* index = luaL_checkstring(L,2); + + if (!(tvbr && index)) return 0; + + if (g_str_equal(index,"offset")) { + lua_pushnumber(L,(lua_Number)tvbr->offset); + return 1; + } else if (g_str_equal(index,"len")) { + lua_pushnumber(L,(lua_Number)tvbr->len); + return 1; + } else if (g_str_equal(index,"tvb")) { + PUSH_TVB(L,tvbr->tvb); + return 1; + } else { + luaL_error(L,"TvbRange has no `%s' attribute",index); + } + + return 0; +} + +/* + * write access to tvbr's data + */ +static int TvbRange_set_index(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + const gchar* index = luaL_checkstring(L,2); + + if (!tvbr) return 0; + + if (g_str_equal(index,"offset")) { + int offset = (int)lua_tonumber(L,3); + + if ( (guint)(tvbr->len + offset) > tvb_length(tvbr->tvb)) { + luaL_error(L,"out of bounds"); + return 0; + } else { + tvbr->offset = offset; + PUSH_TVBRANGE(L,tvbr); + return 1; + } + } else if (g_str_equal(index,"len")) { + int len = (int)lua_tonumber(L,3); + + if ( (guint)(tvbr->offset + len) > tvb_length(tvbr->tvb)) { + luaL_error(L,"out of bounds"); + return 0; + } else { + tvbr->len = len; + PUSH_TVBRANGE(L,tvbr); + return 1; + } + } else { + luaL_error(L,"cannot set `%s' attribute on TvbRange",index); + return 0; + } + + return 0; +} + +/* + * get a Blefuscuoan unsigned integer from a tvb + */ +static int TvbRange_get_uint(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + if (!tvbr) return 0; + + switch (tvbr->len) { + case 1: + lua_pushnumber(L,tvb_get_guint8(tvbr->tvb,tvbr->offset)); + return 1; + case 2: + lua_pushnumber(L,tvb_get_ntohs(tvbr->tvb,tvbr->offset)); + return 1; + case 3: + lua_pushnumber(L,tvb_get_ntoh24(tvbr->tvb,tvbr->offset)); + return 1; + case 4: + lua_pushnumber(L,tvb_get_ntohl(tvbr->tvb,tvbr->offset)); + return 1; + /* + * 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:get_uint() does not handle %d byte integers",tvbr->len); + return 0; + } +} + +/* + * get a Lilliputian unsigned integer from a tvb + */ +static int TvbRange_get_le_uint(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + if (!tvbr) return 0; + + switch (tvbr->len) { + case 1: + /* XXX unsigned anyway */ + lua_pushnumber(L,(lua_Number)tvb_get_guint8(tvbr->tvb,tvbr->offset)); + return 1; + case 2: + lua_pushnumber(L,tvb_get_letohs(tvbr->tvb,tvbr->offset)); + return 1; + case 3: + lua_pushnumber(L,tvb_get_letoh24(tvbr->tvb,tvbr->offset)); + return 1; + case 4: + lua_pushnumber(L,tvb_get_letohl(tvbr->tvb,tvbr->offset)); + return 1; + default: + luaL_error(L,"TvbRange:get_le_uint() does not handle %d byte integers",tvbr->len); + return 0; + } +} + +/* + * get a Blefuscuoan float + */ +static int TvbRange_get_float(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + if (!tvbr) return 0; + + switch (tvbr->len) { + case 4: + lua_pushnumber(L,(double)tvb_get_ntohieee_float(tvbr->tvb,tvbr->offset)); + return 1; + case 8: + lua_pushnumber(L,tvb_get_ntohieee_double(tvbr->tvb,tvbr->offset)); + return 1; + default: + luaL_error(L,"TvbRange:get_float() does not handle %d byte floating numbers",tvbr->len); + return 0; + } +} + +/* + * get a Lilliputian float + */ +static int TvbRange_get_le_float(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + if (!tvbr) return 0; + + switch (tvbr->len) { + case 4: + lua_pushnumber(L,tvb_get_letohieee_float(tvbr->tvb,tvbr->offset)); + return 1; + case 8: + lua_pushnumber(L,tvb_get_letohieee_double(tvbr->tvb,tvbr->offset)); + return 1; + default: + luaL_error(L,"TvbRange:get_float() does not handle %d byte floating numbers",tvbr->len); + return 0; + } +} + +static int TvbRange_get_ipv4(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + Address addr; + guint32* ip_addr; + + if ( !tvbr ) return 0; + + addr = g_malloc(sizeof(address)); + + ip_addr = g_malloc(sizeof(guint32)); + *ip_addr = tvb_get_ntohl(tvbr->tvb,tvbr->offset); + + SET_ADDRESS(addr, AT_IPv4, 4, ip_addr); + pushAddress(L,addr); + + return 1; +} + +static int TvbRange_get_ether(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + Address addr; + guint8* buff; + + if ( !tvbr ) return 0; + + addr = g_malloc(sizeof(address)); + + buff = tvb_memdup(tvbr->tvb,tvbr->offset,tvbr->len); + + SET_ADDRESS(addr, AT_ETHER, 6, buff); + pushAddress(L,addr); + + return 1; +} + + +static int TvbRange_get_string(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + + if ( !tvbr ) return 0; + + lua_pushstring(L, (gchar*)tvb_get_ephemeral_string(tvbr->tvb,tvbr->offset,tvbr->len) ); + + return 1; +} + +static int TvbRange_get_bytes(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + GByteArray* ba; + + if ( !tvbr ) return 0; + + ba = g_byte_array_new(); + g_byte_array_append(ba,ep_tvb_memdup(tvbr->tvb,tvbr->offset,tvbr->len),tvbr->len); + + pushByteArray(L,ba); + + return 1; +} + +static int TvbRange_tostring(lua_State* L) { + TvbRange tvbr = checkTvbRange(L,1); + + if (!tvbr) return 0; + + lua_pushstring(L,tvb_bytes_to_str(tvbr->tvb,tvbr->offset,tvbr->len)); + return 1; +} + +static const luaL_reg TvbRange_methods[] = { + {"uint", TvbRange_get_uint}, + {"le_uint", TvbRange_get_le_uint}, + {"float", TvbRange_get_float}, + {"le_float", TvbRange_get_le_float}, + {"ether", TvbRange_get_ether}, + {"ipv4", TvbRange_get_ipv4}, + {"string", TvbRange_get_string}, + {"bytes", TvbRange_get_bytes}, + {"tvb", Tvb_new_subset}, + {0, 0} +}; + +static const luaL_reg TvbRange_meta[] = { + {"__index", TvbRange_get_index}, + {"__newindex", TvbRange_set_index}, + {"__tostring", TvbRange_tostring}, + {0, 0} +}; + +int TvbRange_register(lua_State* L) { + outstanding_stuff = g_ptr_array_new(); + WSLUA_REGISTER_CLASS(TvbRange); + return 1; +} diff --git a/epan/wslua/wslua_util.c b/epan/wslua/wslua_util.c new file mode 100644 index 0000000000..a2b5329c03 --- /dev/null +++ b/epan/wslua/wslua_util.c @@ -0,0 +1,129 @@ +/* + * wslua_util.c + * + * (c) 2006, Luis E. Garcia Ontanon <luis.ontanon@gmail.com> + * + * $Id: wslua_util.c 18197 2006-05-21 05:12:17Z sahlberg $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * 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. + */ + +#include "wslua.h" +#include <math.h> + +WSLUA_API const gchar* lua_shiftstring(lua_State* L, int i) { + const gchar* p = luaL_checkstring(L, i); + + if (p) { + lua_remove(L,i); + return p; + } else { + return NULL; + } +} + +WSLUA_FUNCTION wslua_format_date(lua_State* LS) { /* Formats an absolute timestamp into a human readable date */ +#define WSLUA_ARG_format_date_TIMESTAMP 1 /* A timestamp value to convert. */ + lua_Number time = luaL_checknumber(LS,WSLUA_ARG_format_date_TIMESTAMP); + nstime_t then; + gchar* str; + + then.secs = (guint32)floor(time); + then.nsecs = (guint32) ( (time-(double)(then.secs))*1000000000); + str = abs_time_to_str(&then); + lua_pushstring(LS,str); + + WSLUA_RETURN(1); /* a string with the formated date */ +} + +WSLUA_FUNCTION wslua_format_time(lua_State* LS) { /* Formats an absolute timestamp in a human readable form */ +#define WSLUA_ARG_format_time_TIMESTAMP 1 /* a timestamp value to convert */ + lua_Number time = luaL_checknumber(LS,WSLUA_ARG_format_time_TIMESTAMP); + nstime_t then; + gchar* str; + + then.secs = (guint32)floor(time); + then.nsecs = (guint32) ( (time-(double)(then.secs))*1000000000); + str = rel_time_to_str(&then); + lua_pushstring(LS,str); + + WSLUA_RETURN(1); /* a string with the formated time */ +} + +WSLUA_FUNCTION wslua_report_failure(lua_State* LS) { /* reports a failure to the user */ +#define WSLUA_ARG_report_failure_TEXT 1 /* message */ + const gchar* s = luaL_checkstring(LS,WSLUA_ARG_report_failure_TEXT); + report_failure("%s",s); + return 0; +} + +static int wslua_log(lua_State* L, GLogLevelFlags log_level) { + GString* str = g_string_new(""); + int n = lua_gettop(L); /* number of arguments */ + int i; + + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + const char *s; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tostring(L, -1); /* get result */ + if (s == NULL) + return luaL_error(L, "`tostring' must return a string"); + + if (i>1) g_string_append(str,"\t"); + g_string_append(str,s); + + lua_pop(L, 1); /* pop result */ + } + + g_log(LOG_DOMAIN_LUA, log_level, "%s\n", str->str); + g_string_free(str,TRUE); + + return 0; +} + +WSLUA_FUNCTION wslua_critical( lua_State* L ) { /* Will add a log entry with critical severity*/ +/* WSLUA_MOREARGS critical objects to be printed */ + wslua_log(L,G_LOG_LEVEL_CRITICAL); + return 0; +} +WSLUA_FUNCTION wslua_warn( lua_State* L ) { /* Will add a log entry with warn severity */ +/* WSLUA_MOREARGS warn objects to be printed */ + wslua_log(L,G_LOG_LEVEL_WARNING); + return 0; +} +WSLUA_FUNCTION wslua_message( lua_State* L ) { /* Will add a log entry with message severity */ +/* WSLUA_MOREARGS message objects to be printed */ + wslua_log(L,G_LOG_LEVEL_MESSAGE); + return 0; +} +WSLUA_FUNCTION wslua_info( lua_State* L ) { /* Will add a log entry with info severity */ +/* WSLUA_MOREARGS info objects to be printed */ + wslua_log(L,G_LOG_LEVEL_INFO); + return 0; +} +WSLUA_FUNCTION wslua_debug( lua_State* L ) { /* Will add a log entry with debug severity */ +/* WSLUA_MOREARGS debug objects to be printed */ + wslua_log(L,G_LOG_LEVEL_DEBUG); + return 0; +} + + |