aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--interface/js/app/config.js10
-rw-r--r--lualib/lua_maps.lua85
-rw-r--r--src/libserver/fuzzy_backend/fuzzy_backend_redis.c4
-rw-r--r--src/libserver/symcache/symcache_impl.cxx4
-rw-r--r--src/lua/lua_common.h3
-rw-r--r--src/lua/lua_logger.c485
-rw-r--r--src/plugins/lua/gpt.lua13
-rw-r--r--src/rspamadm/lua_repl.c8
-rw-r--r--test/functional/cases/001_merged/102_multimap.robot10
-rw-r--r--test/functional/configs/merged-override.conf8
10 files changed, 330 insertions, 300 deletions
diff --git a/interface/js/app/config.js b/interface/js/app/config.js
index 037dabfdd..0f35e3107 100644
--- a/interface/js/app/config.js
+++ b/interface/js/app/config.js
@@ -116,7 +116,6 @@ define(["jquery", "app/common"],
success: function (json) {
const [{data}] = json;
$listmaps.empty();
- $("#modalBody").empty();
const $tbody = $("<tbody>");
$.each(data, (i, item) => {
@@ -126,8 +125,7 @@ define(["jquery", "app/common"],
}
const $tr = $("<tr>").append($td);
- const $span = $('<span class="map-link" data-bs-toggle="modal" data-bs-target="#modalDialog">' +
- item.uri + "</span>").data("item", item);
+ const $span = $('<span class="map-link">' + item.uri + "</span>").data("item", item);
$span.wrap("<td>").parent().appendTo($tr);
$("<td>" + item.description + "</td>").appendTo($tr);
$tr.appendTo($tbody);
@@ -157,7 +155,7 @@ define(["jquery", "app/common"],
let mode = "advanced";
// Modal form for maps
- $(document).on("click", "[data-bs-toggle=\"modal\"]", function () {
+ $(document).on("click", ".map-link", function () {
const item = $(this).data("item");
common.query("getmap", {
headers: {
@@ -167,6 +165,7 @@ define(["jquery", "app/common"],
// Highlighting a large amount of text is unresponsive
mode = (new Blob([data[0].data]).size > 5120) ? "basic" : $("input[name=editorMode]:checked").val();
+ $("#modalBody").empty();
$("<" + editor[mode].elt + ' id="editor" class="' + editor[mode].class + '" data-id="' + item.map +
'"></' + editor[mode].elt + ">").appendTo("#modalBody");
@@ -198,10 +197,9 @@ define(["jquery", "app/common"],
errorMessage: "Cannot receive maps data",
server: common.getServer()
});
- return false;
});
$("#modalDialog").on("hidden.bs.modal", () => {
- if (editor[mode].codejar) {
+ if (editor[mode].codejar && jar && typeof jar.destroy === "function") {
jar.destroy();
$(".codejar-wrap").remove();
} else {
diff --git a/lualib/lua_maps.lua b/lualib/lua_maps.lua
index 6dad3b6ad..d4ba30306 100644
--- a/lualib/lua_maps.lua
+++ b/lualib/lua_maps.lua
@@ -88,16 +88,64 @@ end
local external_map_schema = ts.shape {
external = ts.equivalent(true), -- must be true
- backend = ts.string, -- where to get data, required
- method = ts.one_of { "body", "header", "query" }, -- how to pass input
+ backend = ts.string:is_optional(), -- where to get data, required for HTTP
+ cdb = ts.string:is_optional(), -- path to CDB file, required for CDB
+ method = ts.one_of { "body", "header", "query" }:is_optional(), -- how to pass input
encode = ts.one_of { "json", "messagepack" }:is_optional(), -- how to encode input (if relevant)
timeout = (ts.number + ts.string / lua_util.parse_time_interval):is_optional(),
}
+-- Storage for CDB instances
+local cdb_maps = {}
+local cdb_finisher_set = false
+
local rspamd_http = require "rspamd_http"
local ucl = require "ucl"
+-- Function to handle CDB maps
+local function handle_cdb_map(map_config, key, callback, task)
+ local rspamd_cdb = require "rspamd_cdb"
+ local hash_key = map_config.cdb
+
+ -- Check if we need to open the CDB file
+ if not cdb_maps[hash_key] then
+ local cdb_file = map_config.cdb
+ -- Provide ev_base to monitor changes
+ local cdb_handle = rspamd_cdb.open(cdb_file, task:get_ev_base())
+
+ if not cdb_handle then
+ local err_msg = string.format("Failed to open CDB file: %s", cdb_file)
+ rspamd_logger.errx(task, err_msg)
+ if callback then
+ callback(false, err_msg, 500, task)
+ end
+ return nil
+ else
+ cdb_maps[hash_key] = cdb_handle
+ end
+ end
+
+ -- Look up the key in CDB
+ local result = cdb_maps[hash_key]:find(key)
+
+ if callback then
+ if result then
+ callback(true, result, 200, task)
+ else
+ callback(false, 'not found', 404, task)
+ end
+ return nil
+ end
+
+ return result
+end
+
local function query_external_map(map_config, upstreams, key, callback, task)
+ -- Check if this is a CDB map
+ if map_config.cdb then
+ return handle_cdb_map(map_config, key, callback, task)
+ end
+ -- Fallback to HTTP
local http_method = (map_config.method == 'body' or map_config.method == 'form') and 'POST' or 'GET'
local upstream = upstreams:get_upstream_round_robin()
local http_headers = {
@@ -138,7 +186,8 @@ local function query_external_map(map_config, upstreams, key, callback, task)
local params_table = {}
for k, v in pairs(key) do
if type(v) == 'string' then
- table.insert(params_table, string.format('%s=%s', lua_util.url_encode_string(k), lua_util.url_encode_string(v)))
+ table.insert(params_table,
+ string.format('%s=%s', lua_util.url_encode_string(k), lua_util.url_encode_string(v)))
end
end
url = string.format('%s?%s', url, table.concat(params_table, '&'))
@@ -448,17 +497,39 @@ local function rspamd_map_add_from_ucl(opt, mtype, description, callback)
local parse_res, parse_err = external_map_schema(opt)
if parse_res then
- ret.__upstreams = lua_util.http_upstreams_by_url(rspamd_config:get_mempool(), opt.backend)
- if ret.__upstreams then
+ if opt.cdb then
ret.__data = opt
ret.__external = true
setmetatable(ret, ret_mt)
maybe_register_selector()
+ if not cdb_finisher_set then
+ -- Register a finalize script to close all CDB handles when Rspamd stops
+ rspamd_config:register_finish_script(function()
+ for path, _ in pairs(cdb_maps) do
+ rspamd_logger.infox(rspamd_config, 'closing CDB map: %s', path)
+ cdb_maps[path] = nil
+ end
+ end)
+ cdb_finisher_set = true
+ end
+
return ret
+ elseif opt.backend then
+ ret.__upstreams = lua_util.http_upstreams_by_url(rspamd_config:get_mempool(), opt.backend)
+ if ret.__upstreams then
+ ret.__data = opt
+ ret.__external = true
+ setmetatable(ret, ret_mt)
+ maybe_register_selector()
+
+ return ret
+ else
+ rspamd_logger.errx(rspamd_config, 'cannot parse external map upstreams: %s',
+ opt.backend)
+ end
else
- rspamd_logger.errx(rspamd_config, 'cannot parse external map upstreams: %s',
- opt.backend)
+ rspamd_logger.errx(rspamd_config, 'external map requires either "cdb" or "backend" parameter')
end
else
rspamd_logger.errx(rspamd_config, 'cannot parse external map: %s',
diff --git a/src/libserver/fuzzy_backend/fuzzy_backend_redis.c b/src/libserver/fuzzy_backend/fuzzy_backend_redis.c
index 27c663070..f150d48be 100644
--- a/src/libserver/fuzzy_backend/fuzzy_backend_redis.c
+++ b/src/libserver/fuzzy_backend/fuzzy_backend_redis.c
@@ -116,11 +116,9 @@ rspamd_redis_get_servers(struct rspamd_fuzzy_backend_redis *ctx,
res = *((struct upstream_list **) lua_touserdata(L, -1));
}
else {
- struct lua_logger_trace tr;
char outbuf[8192];
- memset(&tr, 0, sizeof(tr));
- lua_logger_out_type(L, -2, outbuf, sizeof(outbuf) - 1, &tr,
+ lua_logger_out(L, -2, outbuf, sizeof(outbuf),
LUA_ESCAPE_UNPRINTABLE);
msg_err("cannot get %s upstreams for Redis fuzzy storage %s; table content: %s",
diff --git a/src/libserver/symcache/symcache_impl.cxx b/src/libserver/symcache/symcache_impl.cxx
index 4d17348c2..c0278cfc1 100644
--- a/src/libserver/symcache/symcache_impl.cxx
+++ b/src/libserver/symcache/symcache_impl.cxx
@@ -126,7 +126,7 @@ auto symcache::init() -> bool
}
else {
msg_err_cache("cannot register delayed dependency %s -> %s: "
- "destionation %s is missing",
+ "destination %s is missing",
delayed_dep.from.data(),
delayed_dep.to.data(), delayed_dep.to.data());
}
@@ -1338,4 +1338,4 @@ auto symcache::get_max_timeout(std::vector<std::pair<double, const cache_item *>
return accumulated_timeout;
}
-}// namespace rspamd::symcache \ No newline at end of file
+}// namespace rspamd::symcache
diff --git a/src/lua/lua_common.h b/src/lua/lua_common.h
index a29444394..5819da8cb 100644
--- a/src/lua/lua_common.h
+++ b/src/lua/lua_common.h
@@ -538,8 +538,7 @@ enum lua_logger_escape_type {
* @param len
* @return
*/
-gsize lua_logger_out_type(lua_State *L, int pos, char *outbuf,
- gsize len, struct lua_logger_trace *trace,
+gsize lua_logger_out(lua_State *L, int pos, char *outbuf, gsize len,
enum lua_logger_escape_type esc_type);
/**
diff --git a/src/lua/lua_logger.c b/src/lua/lua_logger.c
index 004b82e72..8f2aa5be1 100644
--- a/src/lua/lua_logger.c
+++ b/src/lua/lua_logger.c
@@ -174,6 +174,11 @@ static const struct luaL_reg loggerlib_f[] = {
{"__tostring", rspamd_lua_class_tostring},
{NULL, NULL}};
+static gsize
+lua_logger_out_type(lua_State *L, int pos, char *outbuf,
+ gsize len, struct lua_logger_trace *trace,
+ enum lua_logger_escape_type esc_type);
+
static void
lua_common_log_line(GLogLevelFlags level,
lua_State *L,
@@ -203,23 +208,19 @@ lua_common_log_line(GLogLevelFlags level,
d.currentline);
}
- rspamd_common_log_function(NULL,
- level,
- module,
- uid,
- func_buf,
- "%s",
- msg);
+ p = func_buf;
}
else {
- rspamd_common_log_function(NULL,
- level,
- module,
- uid,
- G_STRFUNC,
- "%s",
- msg);
+ p = (char *) G_STRFUNC;
}
+
+ rspamd_common_log_function(NULL,
+ level,
+ module,
+ uid,
+ p,
+ "%s",
+ msg);
}
/*** Logger interface ***/
@@ -279,105 +280,139 @@ lua_logger_char_safe(int t, unsigned int esc_type)
return true;
}
+/* Could return negative value in case of wrong argument number */
+static glong
+lua_logger_log_format_str(lua_State *L, int offset, char *logbuf, gsize remain,
+ const char *fmt,
+ enum lua_logger_escape_type esc_type)
+{
+ const char *c;
+ gsize r;
+ int digit;
+
+ char *d = logbuf;
+ unsigned int arg_num, cur_arg = 0, arg_max = lua_gettop(L) - offset;
+
+ while (remain > 1 && *fmt) {
+ if (*fmt == '%') {
+ ++fmt;
+ c = fmt;
+ if (*fmt == 's') {
+ ++fmt;
+ ++cur_arg;
+ } else {
+ arg_num = 0;
+ while ((digit = g_ascii_digit_value(*fmt)) >= 0) {
+ ++fmt;
+ arg_num = arg_num * 10 + digit;
+ if (arg_num >= 100) {
+ /* Avoid ridiculously large numbers */
+ fmt = c;
+ break;
+ }
+ }
+
+ if (fmt > c) {
+ /* Update the current argument */
+ cur_arg = arg_num;
+ }
+ }
+
+ if (fmt > c) {
+ if (cur_arg < 1 || cur_arg > arg_max) {
+ *d = 0;
+ return -((glong) cur_arg + 1); /* wrong argument number */
+ }
+
+ r = lua_logger_out(L, offset + cur_arg, d, remain, esc_type);
+ g_assert(r < remain);
+ remain -= r;
+ d += r;
+ continue;
+ }
+
+ /* Copy % */
+ --fmt;
+ }
+
+ *d++ = *fmt++;
+ --remain;
+ }
+
+ *d = 0;
+
+ return d - logbuf;
+}
+
static gsize
lua_logger_out_str(lua_State *L, int pos,
char *outbuf, gsize len,
- struct lua_logger_trace *trace,
enum lua_logger_escape_type esc_type)
{
- gsize slen, flen;
- const char *str = lua_tolstring(L, pos, &slen);
static const char hexdigests[16] = "0123456789abcdef";
- gsize r = 0, s;
+ gsize slen;
+ const unsigned char *str = lua_tolstring(L, pos, &slen);
+ unsigned char c;
+ char *out = outbuf;
if (str) {
- gboolean normal = TRUE;
- flen = MIN(slen, len - 1);
-
- for (r = 0; r < flen; r++) {
- if (!lua_logger_char_safe(str[r], esc_type)) {
- normal = FALSE;
- break;
+ while (slen > 0 && len > 1) {
+ c = *str++;
+ if (lua_logger_char_safe(c, esc_type)) {
+ *out++ = c;
}
- }
-
- if (normal) {
- r = rspamd_strlcpy(outbuf, str, flen + 1);
- }
- else {
- /* Need to escape non-printed characters */
- r = 0;
- s = 0;
-
- while (slen > 0 && len > 1) {
- if (!lua_logger_char_safe(str[s], esc_type)) {
- if (len >= 3) {
- outbuf[r++] = '\\';
- outbuf[r++] = hexdigests[((str[s] >> 4) & 0xF)];
- outbuf[r++] = hexdigests[((str[s]) & 0xF)];
-
- len -= 2;
- }
- else {
- outbuf[r++] = '?';
- }
- }
- else {
- outbuf[r++] = str[s];
- }
-
- s++;
- slen--;
- len--;
+ else if (len > 3) {
+ /* Need to escape non-printed characters */
+ *out++ = '\\';
+ *out++ = hexdigests[c >> 4];
+ *out++ = hexdigests[c & 0xF];
+ len -= 2;
}
-
- outbuf[r] = '\0';
+ else {
+ *out++ = '?';
+ }
+ --slen;
+ --len;
}
}
+ *out = 0;
- return r;
+ return out - outbuf;
}
static gsize
-lua_logger_out_num(lua_State *L, int pos, char *outbuf, gsize len,
- struct lua_logger_trace *trace)
+lua_logger_out_num(lua_State *L, int pos, char *outbuf, gsize len)
{
double num = lua_tonumber(L, pos);
- glong inum;
- gsize r = 0;
+ glong inum = (glong) num;
- if ((double) (glong) num == num) {
- inum = num;
- r = rspamd_snprintf(outbuf, len + 1, "%l", inum);
- }
- else {
- r = rspamd_snprintf(outbuf, len + 1, "%f", num);
+ if ((double) inum == num) {
+ return rspamd_snprintf(outbuf, len, "%l", inum);
}
- return r;
+ return rspamd_snprintf(outbuf, len, "%f", num);
}
static gsize
-lua_logger_out_boolean(lua_State *L, int pos, char *outbuf, gsize len,
- struct lua_logger_trace *trace)
+lua_logger_out_boolean(lua_State *L, int pos, char *outbuf, gsize len)
{
gboolean val = lua_toboolean(L, pos);
- gsize r = 0;
-
- r = rspamd_strlcpy(outbuf, val ? "true" : "false", len + 1);
- return r;
+ return rspamd_snprintf(outbuf, len, val ? "true" : "false");
}
static gsize
-lua_logger_out_userdata(lua_State *L, int pos, char *outbuf, gsize len,
- struct lua_logger_trace *trace)
+lua_logger_out_userdata(lua_State *L, int pos, char *outbuf, gsize len)
{
- int r = 0, top;
+ gsize r = 0;
+ int top;
const char *str = NULL;
gboolean converted_to_str = FALSE;
top = lua_gettop(L);
+ if (pos < 0) {
+ pos += top + 1; /* Convert to absolute */
+ }
if (!lua_getmetatable(L, pos)) {
return 0;
@@ -396,26 +431,17 @@ lua_logger_out_userdata(lua_State *L, int pos, char *outbuf, gsize len,
if (lua_isfunction(L, -1)) {
lua_pushvalue(L, pos);
- if (lua_pcall(L, 1, 1, 0) != 0) {
- lua_settop(L, top);
-
- return 0;
- }
-
- str = lua_tostring(L, -1);
-
- if (str) {
- r = rspamd_snprintf(outbuf, len, "%s", str);
+ if (lua_pcall(L, 1, 1, 0) == 0) {
+ str = lua_tostring(L, -1);
+ if (str) {
+ r = rspamd_snprintf(outbuf, len, "%s", str);
+ }
}
-
- lua_settop(L, top);
-
- return r;
}
}
lua_settop(L, top);
- return 0;
+ return r;
}
lua_pushstring(L, "__tostring");
@@ -460,12 +486,12 @@ lua_logger_out_userdata(lua_State *L, int pos, char *outbuf, gsize len,
return r;
}
-#define MOVE_BUF(d, remain, r) \
+#define MOVE_BUF(d, remain, r) \
(d) += (r); \
(remain) -= (r); \
- if ((remain) == 0) { \
- lua_settop(L, old_top); \
- break; \
+ if ((remain) <= 1) { \
+ lua_settop(L, top); \
+ goto table_oob; \
}
static gsize
@@ -473,169 +499,154 @@ lua_logger_out_table(lua_State *L, int pos, char *outbuf, gsize len,
struct lua_logger_trace *trace,
enum lua_logger_escape_type esc_type)
{
- char *d = outbuf;
- gsize remain = len, r;
+ char *d = outbuf, *str;
+ gsize remain = len;
+ glong r;
gboolean first = TRUE;
gconstpointer self = NULL;
- int i, tpos, last_seq = -1, old_top;
+ int i, last_seq = 0, top;
+ double num;
+ glong inum;
- if (!lua_istable(L, pos) || remain == 0) {
- return 0;
- }
+ /* Type and length checks are done in logger_out_type() */
- old_top = lua_gettop(L);
self = lua_topointer(L, pos);
/* Check if we have seen this pointer */
for (i = 0; i < TRACE_POINTS; i++) {
if (trace->traces[i] == self) {
- r = rspamd_snprintf(d, remain + 1, "ref(%p)", self);
-
- d += r;
-
- return (d - outbuf);
+ if ((trace->cur_level + TRACE_POINTS - 1) % TRACE_POINTS == i) {
+ return rspamd_snprintf(d, remain, "__self");
+ }
+ return rspamd_snprintf(d, remain, "ref(%p)", self);
}
}
trace->traces[trace->cur_level % TRACE_POINTS] = self;
+ ++trace->cur_level;
- lua_pushvalue(L, pos);
- r = rspamd_snprintf(d, remain + 1, "{");
- remain -= r;
- d += r;
+ top = lua_gettop(L);
+ if (pos < 0) {
+ pos += top + 1; /* Convert to absolute */
+ }
+
+ r = rspamd_snprintf(d, remain, "{");
+ MOVE_BUF(d, remain, r);
/* Get numeric keys (ipairs) */
for (i = 1;; i++) {
- lua_rawgeti(L, -1, i);
+ lua_rawgeti(L, pos, i);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
+ last_seq = i;
break;
}
- last_seq = i;
-
- if (!first) {
- r = rspamd_snprintf(d, remain + 1, ", ");
- MOVE_BUF(d, remain, r);
+ if (first) {
+ first = FALSE;
+ str = "[%d] = ";
+ } else {
+ str = ", [%d] = ";
}
-
- r = rspamd_snprintf(d, remain + 1, "[%d] = ", i);
+ r = rspamd_snprintf(d, remain, str, i);
MOVE_BUF(d, remain, r);
- tpos = lua_gettop(L);
- if (lua_topointer(L, tpos) == self) {
- r = rspamd_snprintf(d, remain + 1, "__self");
- }
- else {
- r = lua_logger_out_type(L, tpos, d, remain, trace, esc_type);
- }
+ r = lua_logger_out_type(L, -1, d, remain, trace, esc_type);
MOVE_BUF(d, remain, r);
- first = FALSE;
lua_pop(L, 1);
}
/* Get string keys (pairs) */
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
+ for (lua_pushnil(L); lua_next(L, pos); lua_pop(L, 1)) {
/* 'key' is at index -2 and 'value' is at index -1 */
- if (lua_type(L, -2) == LUA_TNUMBER) {
- if (last_seq > 0) {
- lua_pushvalue(L, -2);
- if (lua_tonumber(L, -1) <= last_seq + 1) {
- lua_pop(L, 1);
+ /* Preserve key */
+ lua_pushvalue(L, -2);
+ if (last_seq > 0) {
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ num = lua_tonumber(L, -1); /* no conversion here */
+ inum = (glong) num;
+ if ((double) inum == num && inum > 0 && inum < last_seq) {
/* Already seen */
+ lua_pop(L, 1);
continue;
}
-
- lua_pop(L, 1);
}
}
- if (!first) {
- r = rspamd_snprintf(d, remain + 1, ", ");
- MOVE_BUF(d, remain, r);
+ if (first) {
+ first = FALSE;
+ str = "[%2] = %1";
+ } else {
+ str = ", [%2] = %1";
}
-
- /* Preserve key */
- lua_pushvalue(L, -2);
- r = rspamd_snprintf(d, remain + 1, "[%s] = ",
- lua_tostring(L, -1));
- lua_pop(L, 1); /* Remove key */
- MOVE_BUF(d, remain, r);
- tpos = lua_gettop(L);
-
- if (lua_topointer(L, tpos) == self) {
- r = rspamd_snprintf(d, remain + 1, "__self");
- }
- else {
- r = lua_logger_out_type(L, tpos, d, remain, trace, esc_type);
+ r = lua_logger_log_format_str(L, top + 1, d, remain, str, esc_type);
+ if (r < 0) {
+ /* should not happen */
+ goto table_oob;
}
MOVE_BUF(d, remain, r);
- first = FALSE;
+ /* Remove key */
+ lua_pop(L, 1);
}
- lua_settop(L, old_top);
-
- r = rspamd_snprintf(d, remain + 1, "}");
+ r = rspamd_snprintf(d, remain, "}");
d += r;
+table_oob:
+ --trace->cur_level;
+
return (d - outbuf);
}
#undef MOVE_BUF
-gsize lua_logger_out_type(lua_State *L, int pos,
+static gsize
+lua_logger_out_type(lua_State *L, int pos,
char *outbuf, gsize len,
struct lua_logger_trace *trace,
enum lua_logger_escape_type esc_type)
{
- int type;
- gsize r = 0;
-
if (len == 0) {
return 0;
}
- type = lua_type(L, pos);
- trace->cur_level++;
+ int type = lua_type(L, pos);
switch (type) {
case LUA_TNUMBER:
- r = lua_logger_out_num(L, pos, outbuf, len, trace);
- break;
+ return lua_logger_out_num(L, pos, outbuf, len);
case LUA_TBOOLEAN:
- r = lua_logger_out_boolean(L, pos, outbuf, len, trace);
- break;
+ return lua_logger_out_boolean(L, pos, outbuf, len);
case LUA_TTABLE:
- r = lua_logger_out_table(L, pos, outbuf, len, trace, esc_type);
- break;
+ return lua_logger_out_table(L, pos, outbuf, len, trace, esc_type);
case LUA_TUSERDATA:
- r = lua_logger_out_userdata(L, pos, outbuf, len, trace);
- break;
+ return lua_logger_out_userdata(L, pos, outbuf, len);
case LUA_TFUNCTION:
- r = rspamd_snprintf(outbuf, len + 1, "function");
- break;
+ return rspamd_snprintf(outbuf, len, "function");
case LUA_TLIGHTUSERDATA:
- r = rspamd_snprintf(outbuf, len + 1, "0x%p", lua_topointer(L, pos));
- break;
+ return rspamd_snprintf(outbuf, len, "0x%p", lua_topointer(L, pos));
case LUA_TNIL:
- r = rspamd_snprintf(outbuf, len + 1, "nil");
- break;
+ return rspamd_snprintf(outbuf, len, "nil");
case LUA_TNONE:
- r = rspamd_snprintf(outbuf, len + 1, "no value");
- break;
- default:
- /* Try to push everything as string using tostring magic */
- r = lua_logger_out_str(L, pos, outbuf, len, trace, esc_type);
- break;
+ return rspamd_snprintf(outbuf, len, "no value");
}
- trace->cur_level--;
+ /* Try to push everything as string using tostring magic */
+ return lua_logger_out_str(L, pos, outbuf, len, esc_type);
+}
- return r;
+gsize lua_logger_out(lua_State *L, int pos,
+ char *outbuf, gsize len,
+ enum lua_logger_escape_type esc_type)
+{
+ struct lua_logger_trace tr;
+ memset(&tr, 0, sizeof(tr));
+
+ return lua_logger_out_type(L, pos, outbuf, len, &tr, esc_type);
}
static const char *
@@ -731,72 +742,16 @@ static gboolean
lua_logger_log_format(lua_State *L, int fmt_pos, gboolean is_string,
char *logbuf, gsize remain)
{
- char *d;
- const char *s, *c;
- gsize r;
- unsigned int arg_num, arg_max, cur_arg;
- struct lua_logger_trace tr;
- int digit;
-
- s = lua_tostring(L, fmt_pos);
- if (s == NULL) {
+ const char *fmt = lua_tostring(L, fmt_pos);
+ if (fmt == NULL) {
return FALSE;
}
- arg_max = (unsigned int) lua_gettop(L) - fmt_pos;
- d = logbuf;
- cur_arg = 0;
-
- while (remain > 0 && *s) {
- if (*s == '%') {
- ++s;
- c = s;
- if (*s == 's') {
- ++s;
- ++cur_arg;
- } else {
- arg_num = 0;
- while ((digit = g_ascii_digit_value(*s)) >= 0) {
- ++s;
- arg_num = arg_num * 10 + digit;
- if (arg_num >= 100) {
- /* Avoid ridiculously large numbers */
- s = c;
- break;
- }
- }
-
- if (s > c) {
- /* Update the current argument */
- cur_arg = arg_num;
- }
- }
-
- if (s > c) {
- if (cur_arg < 1 || cur_arg > arg_max) {
- msg_err("wrong argument number: %ud", cur_arg);
- return FALSE;
- }
-
- memset(&tr, 0, sizeof(tr));
- r = lua_logger_out_type(L, fmt_pos + cur_arg, d, remain, &tr,
- is_string ? LUA_ESCAPE_UNPRINTABLE : LUA_ESCAPE_LOG);
- g_assert(r <= remain);
- remain -= r;
- d += r;
- continue;
- }
-
- /* Copy % */
- --s;
- }
-
- *d++ = *s++;
- --remain;
+ glong ret = lua_logger_log_format_str(L, fmt_pos, logbuf, remain, fmt, is_string ? LUA_ESCAPE_UNPRINTABLE : LUA_ESCAPE_LOG);
+ if (ret < 0) {
+ msg_err("wrong argument number: %ud", -((int) ret + 1));
+ return FALSE;
}
-
- *d = '\0';
-
return TRUE;
}
@@ -808,15 +763,10 @@ lua_logger_do_log(lua_State *L,
{
char logbuf[RSPAMD_LOGBUF_SIZE - 128];
const char *uid = NULL;
- int fmt_pos = start_pos;
int ret;
- GError *err = NULL;
- if (lua_type(L, start_pos) == LUA_TSTRING) {
- fmt_pos = start_pos;
- }
- else if (lua_type(L, start_pos) == LUA_TUSERDATA) {
- fmt_pos = start_pos + 1;
+ if (lua_type(L, start_pos) == LUA_TUSERDATA) {
+ GError *err = NULL;
uid = lua_logger_get_id(L, start_pos, &err);
@@ -830,15 +780,17 @@ lua_logger_do_log(lua_State *L,
return ret;
}
+
+ ++start_pos;
}
- else {
+
+ if (lua_type(L, start_pos) != LUA_TSTRING) {
/* Bad argument type */
return luaL_error(L, "bad format string type: %s",
lua_typename(L, lua_type(L, start_pos)));
}
- ret = lua_logger_log_format(L, fmt_pos, is_string,
- logbuf, sizeof(logbuf) - 1);
+ ret = lua_logger_log_format(L, start_pos, is_string, logbuf, sizeof(logbuf));
if (ret) {
if (is_string) {
@@ -849,12 +801,9 @@ lua_logger_do_log(lua_State *L,
lua_common_log_line(level, L, logbuf, uid, "lua", 1);
}
}
- else {
- if (is_string) {
- lua_pushnil(L);
-
- return 1;
- }
+ else if (is_string) {
+ lua_pushnil(L);
+ return 1;
}
return 0;
@@ -917,11 +866,11 @@ lua_logger_logx(lua_State *L)
if (uid && modname) {
if (lua_type(L, 4) == LUA_TSTRING) {
- ret = lua_logger_log_format(L, 4, FALSE, logbuf, sizeof(logbuf) - 1);
+ ret = lua_logger_log_format(L, 4, FALSE, logbuf, sizeof(logbuf));
}
else if (lua_type(L, 4) == LUA_TNUMBER) {
stack_pos = lua_tonumber(L, 4);
- ret = lua_logger_log_format(L, 5, FALSE, logbuf, sizeof(logbuf) - 1);
+ ret = lua_logger_log_format(L, 5, FALSE, logbuf, sizeof(logbuf));
}
else {
return luaL_error(L, "invalid argument on pos 4");
@@ -959,11 +908,11 @@ lua_logger_debugm(lua_State *L)
if (uid && module) {
if (lua_type(L, 3) == LUA_TSTRING) {
- ret = lua_logger_log_format(L, 3, FALSE, logbuf, sizeof(logbuf) - 1);
+ ret = lua_logger_log_format(L, 3, FALSE, logbuf, sizeof(logbuf));
}
else if (lua_type(L, 3) == LUA_TNUMBER) {
stack_pos = lua_tonumber(L, 3);
- ret = lua_logger_log_format(L, 4, FALSE, logbuf, sizeof(logbuf) - 1);
+ ret = lua_logger_log_format(L, 4, FALSE, logbuf, sizeof(logbuf));
}
else {
return luaL_error(L, "invalid argument on pos 3");
diff --git a/src/plugins/lua/gpt.lua b/src/plugins/lua/gpt.lua
index 98a3e38ee..5d1cf5e06 100644
--- a/src/plugins/lua/gpt.lua
+++ b/src/plugins/lua/gpt.lua
@@ -494,6 +494,7 @@ local function insert_results(task, result, sel_part)
rspamd_logger.errx(task, 'no probability in result')
return
end
+
if result.probability > 0.5 then
task:insert_result('GPT_SPAM', (result.probability - 0.5) * 2, tostring(result.probability))
if settings.autolearn then
@@ -504,10 +505,6 @@ local function insert_results(task, result, sel_part)
process_categories(task, result.categories)
end
else
- if result.reason and settings.reason_header then
- lua_mime.modify_headers(task,
- { add = { [settings.reason_header] = { value = 'value', order = 1 } } })
- end
task:insert_result('GPT_HAM', (0.5 - result.probability) * 2, tostring(result.probability))
if settings.autolearn then
task:set_flag("learn_ham")
@@ -516,6 +513,10 @@ local function insert_results(task, result, sel_part)
process_categories(task, result.categories)
end
end
+ if result.reason and settings.reason_header then
+ lua_mime.modify_headers(task,
+ { add = { [settings.reason_header] = { value = tostring(result.reason), order = 1 } } })
+ end
if cache_context then
lua_cache.cache_set(task, redis_cache_key(sel_part), result, cache_context)
@@ -958,14 +959,14 @@ if opts then
"FROM and url domains. Evaluate spam probability (0-1). " ..
"Output ONLY 3 lines:\n" ..
"1. Numeric score (0.00-1.00)\n" ..
- "2. One-sentence reason citing strongest red flag\n" ..
+ "2. One-sentence reason citing whether it is spam, the strongest red flag, or why it is ham\n" ..
"3. Primary concern category if found from the list: " .. table.concat(lua_util.keys(categories_map), ', ')
else
settings.prompt = "Analyze this email strictly as a spam detector given the email message, subject, " ..
"FROM and url domains. Evaluate spam probability (0-1). " ..
"Output ONLY 2 lines:\n" ..
"1. Numeric score (0.00-1.00)\n" ..
- "2. One-sentence reason citing strongest red flag\n"
+ "2. One-sentence reason citing whether it is spam, the strongest red flag, or why it is ham\n"
end
end
end
diff --git a/src/rspamadm/lua_repl.c b/src/rspamadm/lua_repl.c
index 1d6da5aa9..41a319de9 100644
--- a/src/rspamadm/lua_repl.c
+++ b/src/rspamadm/lua_repl.c
@@ -232,7 +232,6 @@ rspamadm_exec_input(lua_State *L, const char *input)
int i, cbref;
int top = 0;
char outbuf[8192];
- struct lua_logger_trace tr;
struct thread_entry *thread = lua_thread_pool_get_for_config(rspamd_main->cfg);
L = thread->lua_state;
@@ -272,8 +271,7 @@ rspamadm_exec_input(lua_State *L, const char *input)
rspamd_printf("local function: %d\n", cbref);
}
else {
- memset(&tr, 0, sizeof(tr));
- lua_logger_out_type(L, i, outbuf, sizeof(outbuf) - 1, &tr,
+ lua_logger_out(L, i, outbuf, sizeof(outbuf),
LUA_ESCAPE_UNPRINTABLE);
rspamd_printf("%s\n", outbuf);
}
@@ -393,7 +391,6 @@ rspamadm_lua_message_handler(lua_State *L, int argc, char **argv)
gpointer map;
gsize len;
char outbuf[8192];
- struct lua_logger_trace tr;
if (argv[1] == NULL) {
rspamd_printf("no callback is specified\n");
@@ -455,8 +452,7 @@ rspamadm_lua_message_handler(lua_State *L, int argc, char **argv)
rspamd_printf("lua callback for %s returned:\n", argv[i]);
for (j = old_top + 1; j <= lua_gettop(L); j++) {
- memset(&tr, 0, sizeof(tr));
- lua_logger_out_type(L, j, outbuf, sizeof(outbuf), &tr,
+ lua_logger_out(L, j, outbuf, sizeof(outbuf),
LUA_ESCAPE_UNPRINTABLE);
rspamd_printf("%s\n", outbuf);
}
diff --git a/test/functional/cases/001_merged/102_multimap.robot b/test/functional/cases/001_merged/102_multimap.robot
index 50d1af6b6..a16d0e5c4 100644
--- a/test/functional/cases/001_merged/102_multimap.robot
+++ b/test/functional/cases/001_merged/102_multimap.robot
@@ -418,6 +418,16 @@ MAP - EXTERNAL MISS
... Settings={symbols_enabled = [EXTERNAL_MULTIMAP]}
Do Not Expect Symbol EXTERNAL_MULTIMAP
+MAP - EXTERNAL CDB
+ Scan File ${MESSAGE} IP=127.0.0.1 Hostname=example.com
+ ... Settings={symbols_enabled = [EXTERNAL_MULTIMAP_CDB]}
+ Expect Symbol EXTERNAL_MULTIMAP_CDB
+
+MAP - EXTERNAL CDB MISS
+ Scan File ${MESSAGE} IP=127.0.0.1 Hostname=example.com.bg
+ ... Settings={symbols_enabled = [EXTERNAL_MULTIMAP_CDB]}
+ Do Not Expect Symbol EXTERNAL_MULTIMAP_CDB
+
MAP - DYNAMIC SYMBOLS - SYM1
Scan File ${MESSAGE} IP=127.0.0.1 Hostname=foo
... Settings={symbols_enabled = [DYN_TEST1,DYN_TEST2,DYN_MULTIMAP]}
diff --git a/test/functional/configs/merged-override.conf b/test/functional/configs/merged-override.conf
index 344e30786..e302e88fc 100644
--- a/test/functional/configs/merged-override.conf
+++ b/test/functional/configs/merged-override.conf
@@ -254,6 +254,14 @@ multimap {
}
}
+ EXTERNAL_MULTIMAP_CDB {
+ type = "hostname";
+ map = {
+ external = true;
+ cdb = "{= env.TESTDIR =}/configs/maps/domains.cdb";
+ }
+ }
+
DYN_MULTIMAP {
type = "hostname";
map = "{= env.TESTDIR =}/configs/maps/dynamic_symbols.map";