Implement a Lua 5.3 plugin loader plugin
Also implemented SOCKS detection in said language. There are probably going to be some bugs. The program is no longer Valgrind-clean, as that would require plugin deinitialization, in which there is very little point.
This commit is contained in:
parent
7cb6fcdaff
commit
eb0f8a028c
|
@ -73,7 +73,11 @@ set_target_properties (plugin-http PROPERTIES OUTPUT_NAME http PREFIX "")
|
||||||
install (TARGETS plugin-http DESTINATION ${plugin_dir})
|
install (TARGETS plugin-http DESTINATION ${plugin_dir})
|
||||||
|
|
||||||
# Build the other plugins
|
# Build the other plugins
|
||||||
foreach (plugin irc ssh)
|
set (plugins irc ssh)
|
||||||
|
if (WITH_LUA)
|
||||||
|
list (APPEND plugins lua-loader)
|
||||||
|
endif (WITH_LUA)
|
||||||
|
foreach (plugin ${plugins})
|
||||||
set (target plugin-${plugin})
|
set (target plugin-${plugin})
|
||||||
add_library (${target} SHARED plugins/${plugin}.c plugin-api.h)
|
add_library (${target} SHARED plugins/${plugin}.c plugin-api.h)
|
||||||
target_link_libraries (${target} ${project_libraries})
|
target_link_libraries (${target} ${project_libraries})
|
||||||
|
|
|
@ -38,11 +38,12 @@ struct service
|
||||||
{
|
{
|
||||||
const char *name; ///< Name of the service
|
const char *name; ///< Name of the service
|
||||||
int flags; ///< Service flags
|
int flags; ///< Service flags
|
||||||
|
void *user_data; ///< User data
|
||||||
|
|
||||||
// scan_init -> on_data* -> [on_eof/on_error] -> on_aborted -> scan_free
|
// scan_init -> on_data* -> [on_eof/on_error] -> on_aborted -> scan_free
|
||||||
|
|
||||||
/// Initialize a scan, returning a handle to it
|
/// Initialize a scan, returning a handle to it
|
||||||
void *(*scan_init) (struct unit *u);
|
void *(*scan_init) (struct service *self, struct unit *u);
|
||||||
|
|
||||||
/// Destroy the handle created for the scan
|
/// Destroy the handle created for the scan
|
||||||
void (*scan_free) (void *handle);
|
void (*scan_free) (void *handle);
|
||||||
|
@ -67,6 +68,9 @@ struct plugin_api
|
||||||
/// Register the plugin for a service
|
/// Register the plugin for a service
|
||||||
void (*register_service) (void *ctx, struct service *info);
|
void (*register_service) (void *ctx, struct service *info);
|
||||||
|
|
||||||
|
/// Retrieve an item from the configuration
|
||||||
|
const char *(*get_config) (void *ctx, const char *key);
|
||||||
|
|
||||||
/// Get the IP address of the target as a string
|
/// Get the IP address of the target as a string
|
||||||
const char *(*unit_get_address) (struct unit *u);
|
const char *(*unit_get_address) (struct unit *u);
|
||||||
|
|
||||||
|
|
|
@ -94,8 +94,10 @@ on_headers_complete (http_parser *parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
scan_init (struct unit *u)
|
scan_init (struct service *service, struct unit *u)
|
||||||
{
|
{
|
||||||
|
(void) service;
|
||||||
|
|
||||||
struct str hello;
|
struct str hello;
|
||||||
str_init (&hello);
|
str_init (&hello);
|
||||||
str_append_printf (&hello, "GET / HTTP/1.0\r\n"
|
str_append_printf (&hello, "GET / HTTP/1.0\r\n"
|
||||||
|
|
|
@ -214,8 +214,10 @@ struct scan_data
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
scan_init (struct unit *u)
|
scan_init (struct service *service, struct unit *u)
|
||||||
{
|
{
|
||||||
|
(void) service;
|
||||||
|
|
||||||
char nick[IRC_MAX_NICKNAME + 1];
|
char nick[IRC_MAX_NICKNAME + 1];
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = 0; i < sizeof nick - 1; i++)
|
for (i = 0; i < sizeof nick - 1; i++)
|
||||||
|
|
|
@ -0,0 +1,446 @@
|
||||||
|
/*
|
||||||
|
* lua-loader.c: Lua plugin loader plugin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// I can't really recommend using this interface as it adds a lot of overhead
|
||||||
|
|
||||||
|
#include "../utils.c"
|
||||||
|
#include "../plugin-api.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
// --- Utilities ---------------------------------------------------------------
|
||||||
|
|
||||||
|
static struct plugin_data
|
||||||
|
{
|
||||||
|
void *ctx; ///< Application context
|
||||||
|
struct plugin_api *api; ///< Plugin API vtable
|
||||||
|
}
|
||||||
|
g_data;
|
||||||
|
|
||||||
|
static void *
|
||||||
|
xlua_alloc (void *ud, void *ptr, size_t o_size, size_t n_size)
|
||||||
|
{
|
||||||
|
(void) ud;
|
||||||
|
(void) o_size;
|
||||||
|
|
||||||
|
if (n_size)
|
||||||
|
return realloc (ptr, n_size);
|
||||||
|
|
||||||
|
free (ptr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_panic (lua_State *L)
|
||||||
|
{
|
||||||
|
// XXX: we might be able to do something better
|
||||||
|
print_fatal ("Lua panicked: %s", lua_tostring (L, -1));
|
||||||
|
lua_close (L);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Unit wrapper ------------------------------------------------------------
|
||||||
|
|
||||||
|
struct unit_wrapper
|
||||||
|
{
|
||||||
|
struct unit *unit; ///< The underlying unit
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UNIT_METATABLE "unit"
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_unit_get_address (lua_State *L)
|
||||||
|
{
|
||||||
|
struct unit_wrapper *data = luaL_checkudata (L, 1, UNIT_METATABLE);
|
||||||
|
lua_pushstring (L, g_data.api->unit_get_address (data->unit));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_unit_write (lua_State *L)
|
||||||
|
{
|
||||||
|
struct unit_wrapper *data = luaL_checkudata (L, 1, UNIT_METATABLE);
|
||||||
|
size_t buffer_len;
|
||||||
|
const char *buffer = luaL_checklstring (L, 2, &buffer_len);
|
||||||
|
lua_pushinteger (L, g_data.api->unit_write
|
||||||
|
(data->unit, buffer, buffer_len));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_unit_set_success (lua_State *L)
|
||||||
|
{
|
||||||
|
struct unit_wrapper *data = luaL_checkudata (L, 1, UNIT_METATABLE);
|
||||||
|
bool success = lua_toboolean (L, 2);
|
||||||
|
g_data.api->unit_set_success (data->unit, success);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_unit_add_info (lua_State *L)
|
||||||
|
{
|
||||||
|
struct unit_wrapper *data = luaL_checkudata (L, 1, UNIT_METATABLE);
|
||||||
|
const char *info = luaL_checkstring (L, 2);
|
||||||
|
g_data.api->unit_add_info (data->unit, info);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_unit_abort (lua_State *L)
|
||||||
|
{
|
||||||
|
struct unit_wrapper *data = luaL_checkudata (L, 1, UNIT_METATABLE);
|
||||||
|
g_data.api->unit_abort (data->unit);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_unit_destroy (lua_State *L)
|
||||||
|
{
|
||||||
|
// TODO: when creating the wrapper object, increase the reference
|
||||||
|
// count for the unit and decrease it in here again. If we don't do
|
||||||
|
// this, the Lua plugin may cause a use-after-free error.
|
||||||
|
(void) L;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static luaL_Reg xlua_unit_table[] =
|
||||||
|
{
|
||||||
|
{ "get_address", xlua_unit_get_address },
|
||||||
|
{ "write", xlua_unit_write },
|
||||||
|
{ "set_success", xlua_unit_set_success },
|
||||||
|
{ "add_info", xlua_unit_add_info },
|
||||||
|
{ "abort", xlua_unit_abort },
|
||||||
|
{ "__gc", xlua_unit_destroy },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Scan wrapper ------------------------------------------------------------
|
||||||
|
|
||||||
|
struct service_data
|
||||||
|
{
|
||||||
|
struct service *service; ///< The corresponding service
|
||||||
|
lua_State *L; ///< Lua state
|
||||||
|
int new_scan_cb_ref; ///< Reference to "new_scan" callback
|
||||||
|
};
|
||||||
|
|
||||||
|
struct scan_data
|
||||||
|
{
|
||||||
|
struct service *service; ///< The corresponding service
|
||||||
|
struct unit *unit; ///< The corresponding unit
|
||||||
|
lua_State *L; ///< Lua state
|
||||||
|
int scan_ref; ///< Reference to scan data in Lua
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *
|
||||||
|
scan_init (struct service *self, struct unit *unit)
|
||||||
|
{
|
||||||
|
struct service_data *service = self->user_data;
|
||||||
|
lua_geti (service->L, LUA_REGISTRYINDEX, service->new_scan_cb_ref);
|
||||||
|
|
||||||
|
// Wrap the unit in Lua userdata so that Lua code can use it
|
||||||
|
struct unit_wrapper *wrapper =
|
||||||
|
lua_newuserdata (service->L, sizeof *wrapper);
|
||||||
|
wrapper->unit = unit;
|
||||||
|
luaL_setmetatable (service->L, UNIT_METATABLE);
|
||||||
|
|
||||||
|
// Ask for a Lua object (table) to use for protocol detection
|
||||||
|
if (lua_pcall (service->L, 1, 1, 0))
|
||||||
|
{
|
||||||
|
print_error ("Lua: service `%s': new_scan: %s",
|
||||||
|
service->service->name, lua_tostring (service->L, -1));
|
||||||
|
lua_pop (service->L, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lua_istable (service->L, -1))
|
||||||
|
{
|
||||||
|
print_error ("Lua: service `%s': new_scan must return a table",
|
||||||
|
service->service->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a scan handle
|
||||||
|
struct scan_data *data = xmalloc (sizeof *data);
|
||||||
|
data->service = self;
|
||||||
|
data->L = service->L;
|
||||||
|
data->scan_ref = luaL_ref (service->L, LUA_REGISTRYINDEX);
|
||||||
|
data->unit = unit;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scan_free (void *handle)
|
||||||
|
{
|
||||||
|
if (!handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct scan_data *data = handle;
|
||||||
|
luaL_unref (data->L, LUA_REGISTRYINDEX, data->scan_ref);
|
||||||
|
free (handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_scan_method_failure (struct scan_data *data)
|
||||||
|
{
|
||||||
|
print_error ("Lua: service `%s': %s", data->service->name,
|
||||||
|
lua_tostring (data->L, -1));
|
||||||
|
g_data.api->unit_abort (data->unit);
|
||||||
|
lua_pop (data->L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
prepare_scan_method (struct scan_data *data, const char *method_name)
|
||||||
|
{
|
||||||
|
if (!data)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lua_geti (data->L, LUA_REGISTRYINDEX, data->scan_ref);
|
||||||
|
lua_getfield (data->L, -1, method_name);
|
||||||
|
if (lua_isnil (data->L, -1))
|
||||||
|
{
|
||||||
|
lua_pop (data->L, 2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lua_isfunction (data->L, -1))
|
||||||
|
{
|
||||||
|
lua_pop (data->L, 2);
|
||||||
|
lua_pushfstring (data->L, "`%s' must be a function", method_name);
|
||||||
|
handle_scan_method_failure (data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the first two values on the stack, so that the function
|
||||||
|
// is first and the object we're calling it on is second
|
||||||
|
lua_insert (data->L, -2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_data (void *handle, const void *network_data, size_t len)
|
||||||
|
{
|
||||||
|
struct scan_data *data = handle;
|
||||||
|
if (!prepare_scan_method (data, "on_data"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lua_pushlstring (data->L, network_data, len);
|
||||||
|
if (lua_pcall (data->L, 2, 0, 0))
|
||||||
|
handle_scan_method_failure (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_eof (void *handle)
|
||||||
|
{
|
||||||
|
struct scan_data *data = handle;
|
||||||
|
if (!prepare_scan_method (data, "on_eof"))
|
||||||
|
return;
|
||||||
|
if (lua_pcall (data->L, 1, 0, 0))
|
||||||
|
handle_scan_method_failure (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_error (void *handle)
|
||||||
|
{
|
||||||
|
struct scan_data *data = handle;
|
||||||
|
if (!prepare_scan_method (data, "on_error"))
|
||||||
|
return;
|
||||||
|
if (lua_pcall (data->L, 1, 0, 0))
|
||||||
|
handle_scan_method_failure (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_aborted (void *handle)
|
||||||
|
{
|
||||||
|
struct scan_data *data = handle;
|
||||||
|
if (!prepare_scan_method (data, "on_aborted"))
|
||||||
|
return;
|
||||||
|
if (lua_pcall (data->L, 1, 0, 0))
|
||||||
|
handle_scan_method_failure (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Top-level interface -----------------------------------------------------
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_register_service (lua_State *L)
|
||||||
|
{
|
||||||
|
// Validate and decode the arguments
|
||||||
|
luaL_checktype (L, 1, LUA_TTABLE);
|
||||||
|
|
||||||
|
lua_getfield (L, 1, "name");
|
||||||
|
if (!lua_isstring (L, -1))
|
||||||
|
return luaL_error (L, "service registration failed: "
|
||||||
|
"invalid or missing `%s'", "name");
|
||||||
|
const char *name = lua_tostring (L, -1);
|
||||||
|
lua_pop (L, 1);
|
||||||
|
|
||||||
|
lua_getfield (L, 1, "flags");
|
||||||
|
lua_Unsigned flags;
|
||||||
|
if (lua_isnil (L, -1))
|
||||||
|
flags = 0;
|
||||||
|
else if (lua_isinteger (L, -1))
|
||||||
|
flags = lua_tointeger (L, -1);
|
||||||
|
else
|
||||||
|
return luaL_error (L, "service registration failed: "
|
||||||
|
"invalid or missing `%s'", "flags");
|
||||||
|
lua_pop (L, 1);
|
||||||
|
|
||||||
|
lua_getfield (L, 1, "new_scan");
|
||||||
|
if (!lua_isfunction (L, -1))
|
||||||
|
return luaL_error (L, "service registration failed: "
|
||||||
|
"invalid or missing `%s'", "new_scan");
|
||||||
|
|
||||||
|
// Reference the "new_scan" function for later use
|
||||||
|
struct service_data *data = xcalloc (1, sizeof *data);
|
||||||
|
data->L = L;
|
||||||
|
data->new_scan_cb_ref = luaL_ref (L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
// Register a new service that proxies calls to Lua code
|
||||||
|
struct service *s = data->service = xcalloc (1, sizeof *s);
|
||||||
|
s->name = xstrdup (name);
|
||||||
|
s->flags = flags;
|
||||||
|
s->user_data = data;
|
||||||
|
|
||||||
|
s->scan_init = scan_init;
|
||||||
|
s->scan_free = scan_free;
|
||||||
|
s->on_data = on_data;
|
||||||
|
s->on_eof = on_eof;
|
||||||
|
s->on_error = on_error;
|
||||||
|
s->on_aborted = on_aborted;
|
||||||
|
|
||||||
|
g_data.api->register_service (g_data.ctx, s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xlua_get_config (lua_State *L)
|
||||||
|
{
|
||||||
|
const char *key = luaL_checkstring (L, 1);
|
||||||
|
lua_pushstring (L, g_data.api->get_config (g_data.ctx, key));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static luaL_Reg xlua_library[] =
|
||||||
|
{
|
||||||
|
{ "register_service", xlua_register_service },
|
||||||
|
{ "get_config", xlua_get_config },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
load_one_plugin (lua_State *L, const char *name, const char *path)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if (!(ret = luaL_loadfile (L, path))
|
||||||
|
&& !(ret = lua_pcall (L, 0, 0, 0)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
print_error ("Lua: could not load `%s': %s", name, lua_tostring (L, -1));
|
||||||
|
lua_pop (L, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
initialize (void *ctx, struct plugin_api *api)
|
||||||
|
{
|
||||||
|
g_data = (struct plugin_data) { .ctx = ctx, .api = api };
|
||||||
|
|
||||||
|
if (sizeof (lua_Integer) < 8)
|
||||||
|
{
|
||||||
|
print_error ("%s: %s", "Lua",
|
||||||
|
"at least 64-bit Lua integers are required");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *plugin_dir = api->get_config (ctx, "plugin_dir");
|
||||||
|
if (!plugin_dir)
|
||||||
|
{
|
||||||
|
print_fatal ("%s: %s", "Lua", "no plugin directory defined");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR *dir = opendir (plugin_dir);
|
||||||
|
if (!dir)
|
||||||
|
{
|
||||||
|
print_fatal ("%s: %s: %s", "Lua",
|
||||||
|
"cannot open plugin directory", strerror (errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
lua_State *L;
|
||||||
|
if (!(L = lua_newstate (xlua_alloc, NULL)))
|
||||||
|
{
|
||||||
|
print_fatal ("%s: %s", "Lua", "initialization failed");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_atpanic (L, xlua_panic);
|
||||||
|
luaL_openlibs (L);
|
||||||
|
|
||||||
|
// Register the ponymap library
|
||||||
|
luaL_newlib (L, xlua_library);
|
||||||
|
lua_pushinteger (L, SERVICE_SUPPORTS_TLS);
|
||||||
|
lua_setfield (L, -2, "SERVICE_SUPPORTS_TLS");
|
||||||
|
lua_setglobal (L, PROGRAM_NAME);
|
||||||
|
|
||||||
|
// Create a metatable for the units
|
||||||
|
luaL_newmetatable (L, UNIT_METATABLE);
|
||||||
|
lua_pushvalue (L, -1);
|
||||||
|
lua_setfield (L, -2, "__index");
|
||||||
|
luaL_setfuncs (L, xlua_unit_table, 0);
|
||||||
|
|
||||||
|
struct dirent buf, *iter;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (readdir_r (dir, &buf, &iter))
|
||||||
|
{
|
||||||
|
print_fatal ("%s: %s: %s", "Lua", "readdir_r", strerror (errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!iter)
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *dot = strrchr (iter->d_name, '.');
|
||||||
|
if (!dot || strcmp (dot, ".lua"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char *path = xstrdup_printf ("%s/%s", plugin_dir, iter->d_name);
|
||||||
|
(void) load_one_plugin (L, iter->d_name, path);
|
||||||
|
free (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
closedir (dir);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct plugin_info ponymap_plugin_info =
|
||||||
|
{
|
||||||
|
.api_version = API_VERSION,
|
||||||
|
.initialize = initialize
|
||||||
|
};
|
|
@ -0,0 +1,99 @@
|
||||||
|
--
|
||||||
|
-- socks.lua: SOCKS service detection plugin
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2015, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
|
-- All rights reserved.
|
||||||
|
--
|
||||||
|
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
-- purpose with or without fee is hereby granted, provided that the above
|
||||||
|
-- copyright notice and this permission notice appear in all copies.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
--
|
||||||
|
|
||||||
|
-- This plugin serves as an example of how to write Lua plugins for ponymap
|
||||||
|
|
||||||
|
-- SOCKS 4
|
||||||
|
|
||||||
|
local Socks4 = {}
|
||||||
|
Socks4.__index = Socks4
|
||||||
|
|
||||||
|
function Socks4.new (unit)
|
||||||
|
unit:write (string.pack ("> I1 I1 I2 I1 I1 I1 I1 z",
|
||||||
|
4, 1, 80, 127, 0, 0, 1, ""))
|
||||||
|
return setmetatable ({ unit = unit, buf = "" }, Socks4)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Socks4:on_data (data)
|
||||||
|
self.buf = self.buf .. data
|
||||||
|
if #self.buf >= 8 then
|
||||||
|
null, code = string.unpack ("> I1 I1", self.buf)
|
||||||
|
if null == 0 and code >= 90 and code <= 93 then
|
||||||
|
self.unit:set_success (true)
|
||||||
|
end
|
||||||
|
self.unit:abort ()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SOCKS 4A
|
||||||
|
|
||||||
|
local Socks4A = {}
|
||||||
|
Socks4A.__index = Socks4A
|
||||||
|
|
||||||
|
function Socks4A.new (unit)
|
||||||
|
unit:write (string.pack ("> I1 I1 I2 I4 z z",
|
||||||
|
4, 1, 80, 1, "", "google.com"))
|
||||||
|
return setmetatable ({ unit = unit, buf = "" }, Socks4A)
|
||||||
|
end
|
||||||
|
|
||||||
|
Socks4A.on_data = Socks4.on_data
|
||||||
|
|
||||||
|
-- SOCKS 5
|
||||||
|
|
||||||
|
local Socks5 = {}
|
||||||
|
Socks5.__index = Socks5
|
||||||
|
|
||||||
|
function Socks5.new (unit)
|
||||||
|
unit:write (string.pack ("> I1 I1 I1", 5, 1, 0))
|
||||||
|
return setmetatable ({ unit = unit, buf = "" }, Socks5)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Socks5:on_data (data)
|
||||||
|
self.buf = self.buf .. data
|
||||||
|
if #self.buf >= 2 then
|
||||||
|
version, result = string.unpack ("> I1 I1", self.buf)
|
||||||
|
if version == 5 and (result == 0 or result == 255) then
|
||||||
|
if result == 0 then
|
||||||
|
self.unit:add_info ("no authentication required")
|
||||||
|
end
|
||||||
|
self.unit:set_success (true)
|
||||||
|
end
|
||||||
|
self.unit:abort ()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Register everything
|
||||||
|
|
||||||
|
ponymap.register_service ({
|
||||||
|
name = "SOCKS4",
|
||||||
|
flags = 0,
|
||||||
|
new_scan = Socks4.new
|
||||||
|
})
|
||||||
|
|
||||||
|
ponymap.register_service ({
|
||||||
|
name = "SOCKS4A",
|
||||||
|
flags = 0,
|
||||||
|
new_scan = Socks4A.new
|
||||||
|
})
|
||||||
|
|
||||||
|
ponymap.register_service ({
|
||||||
|
name = "SOCKS5",
|
||||||
|
flags = 0,
|
||||||
|
new_scan = Socks5.new
|
||||||
|
})
|
|
@ -37,8 +37,10 @@ struct scan_data
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
scan_init (struct unit *u)
|
scan_init (struct service *service, struct unit *u)
|
||||||
{
|
{
|
||||||
|
(void) service;
|
||||||
|
|
||||||
struct scan_data *scan = xcalloc (1, sizeof *scan);
|
struct scan_data *scan = xcalloc (1, sizeof *scan);
|
||||||
str_init (&scan->input);
|
str_init (&scan->input);
|
||||||
scan->u = u;
|
scan->u = u;
|
||||||
|
|
10
ponymap.c
10
ponymap.c
|
@ -623,7 +623,7 @@ unit_start_scan (struct unit *u)
|
||||||
u->scan_started = true;
|
u->scan_started = true;
|
||||||
poller_timer_set (&u->timeout_event, u->target->ctx->scan_timeout * 1000);
|
poller_timer_set (&u->timeout_event, u->target->ctx->scan_timeout * 1000);
|
||||||
|
|
||||||
u->service_data = u->service->scan_init (u);
|
u->service_data = u->service->scan_init (u->service, u);
|
||||||
u->fd_event.dispatcher = (poller_fd_fn) on_unit_ready;
|
u->fd_event.dispatcher = (poller_fd_fn) on_unit_ready;
|
||||||
unit_update_poller (u, NULL);
|
unit_update_poller (u, NULL);
|
||||||
}
|
}
|
||||||
|
@ -791,6 +791,13 @@ plugin_api_register_service (void *app_context, struct service *info)
|
||||||
str_map_set (&ctx->services, info->name, info);
|
str_map_set (&ctx->services, info->name, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
plugin_api_get_config (void *app_context, const char *key)
|
||||||
|
{
|
||||||
|
struct app_context *ctx = app_context;
|
||||||
|
return str_map_find (&ctx->config, key);
|
||||||
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
plugin_api_unit_get_address (struct unit *u)
|
plugin_api_unit_get_address (struct unit *u)
|
||||||
{
|
{
|
||||||
|
@ -828,6 +835,7 @@ plugin_api_unit_abort (struct unit *u)
|
||||||
static struct plugin_api g_plugin_vtable =
|
static struct plugin_api g_plugin_vtable =
|
||||||
{
|
{
|
||||||
.register_service = plugin_api_register_service,
|
.register_service = plugin_api_register_service,
|
||||||
|
.get_config = plugin_api_get_config,
|
||||||
.unit_get_address = plugin_api_unit_get_address,
|
.unit_get_address = plugin_api_unit_get_address,
|
||||||
.unit_write = plugin_api_unit_write,
|
.unit_write = plugin_api_unit_write,
|
||||||
.unit_set_success = plugin_api_unit_set_success,
|
.unit_set_success = plugin_api_unit_set_success,
|
||||||
|
|
Loading…
Reference in New Issue