[Feature] Add SPF FFI library for Lua

This commit is contained in:
Vsevolod Stakhov 2019-04-12 16:01:11 +01:00
parent fe1c8f88b7
commit 4824ea2d2b
4 changed files with 154 additions and 1 deletions

View File

@ -27,8 +27,19 @@ struct GString {
size_t len;
size_t allocated_len;
};
struct GArray {
char *data;
unsigned len;
};
typedef void (*ref_dtor_cb_t)(void *data);
struct ref_entry_s {
unsigned int refcount;
ref_dtor_cb_t dtor;
};
void g_string_free (struct GString *st, int free_data);
void g_free (void *p);
long rspamd_snprintf (char *buf, long max, const char *fmt, ...);
]]
return {}

View File

@ -49,5 +49,6 @@ end
pcall(ffi.load, "rspamd-server", true)
exports.common = require "lua_ffi/common"
exports.dkim = require "lua_ffi/dkim"
exports.spf = require "lua_ffi/spf"
return exports

141
lualib/lua_ffi/spf.lua Normal file
View File

@ -0,0 +1,141 @@
--[[
Copyright (c) 2019, Vsevolod Stakhov <vsevolod@highsecure.ru>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
]]--
--[[[
-- @module lua_ffi/spf
-- This module contains ffi interfaces to SPF
--]]
local ffi = require 'ffi'
ffi.cdef[[
enum spf_mech_e {
SPF_FAIL,
SPF_SOFT_FAIL,
SPF_PASS,
SPF_NEUTRAL
};
static const unsigned RSPAMD_SPF_FLAG_IPV6 = (1 << 0);
static const unsigned RSPAMD_SPF_FLAG_IPV4 = (1 << 1);
static const unsigned RSPAMD_SPF_FLAG_ANY = (1 << 3);
struct spf_addr {
unsigned char addr6[16];
unsigned char addr4[4];
union {
struct {
uint16_t mask_v4;
uint16_t mask_v6;
} dual;
uint32_t idx;
} m;
unsigned flags;
enum spf_mech_e mech;
char *spf_string;
struct spf_addr *prev, *next;
};
struct spf_resolved {
char *domain;
unsigned ttl;
int temp_failed;
int na;
int perm_failed;
uint64_t digest;
struct GArray *elts;
struct ref_entry_s ref;
};
typedef void (*spf_cb_t)(struct spf_resolved *record,
struct rspamd_task *task, void *data);
struct rspamd_task;
int rspamd_spf_resolve(struct rspamd_task *task, spf_cb_t callback,
void *cbdata);
const char * rspamd_spf_get_domain (struct rspamd_task *task);
struct spf_resolved * spf_record_ref (struct spf_resolved *rec);
void spf_record_unref (struct spf_resolved *rec);
char * spf_addr_mask_to_string (struct spf_addr *addr);
struct spf_addr * spf_addr_match_task (struct rspamd_task *task, struct spf_resolved *rec);
]]
local function convert_mech(mech)
if mech == ffi.C.SPF_FAIL then
return 'fail'
elseif mech == ffi.C.SPF_SOFT_FAIL then
return 'softfail'
elseif mech == ffi.C.SPF_PASS then
return 'pass'
elseif mech == ffi.C.SPF_NEUTRAL then
return 'neutral'
end
end
local function spf_addr_tolua(ffi_spf_addr)
local ipstr = ffi.C.spf_addr_mask_to_string(ffi_spf_addr)
local ret = {
res = convert_mech(ffi_spf_addr.mech),
ipnet = ffi.string(ipstr),
}
if ffi_spf_addr.spf_string then
ret.spf_str = ffi.string(ffi_spf_addr.spf_string)
end
ffi.C.g_free(ipstr)
return ret
end
local function spf_resolve(task, cb)
local function spf_cb(rec, _, _)
if not rec then
cb(false, 'record is empty')
else
local nelts = rec.elts.len
local elts = ffi.cast("struct spf_addr *", rec.elts.data)
local res = {
addrs = {}
}
local digstr = ffi.new("char[64]")
ffi.C.rspamd_snprintf(digstr, 64, "0x%xuL", rec.digest)
res.digest = ffi.string(digstr)
for i = 1,nelts do
res.addrs[i] = spf_addr_tolua(elts[i - 1])
end
local matched = ffi.C.spf_addr_match_task(task:topointer(), rec)
if matched then
cb(true, res, spf_addr_tolua(matched))
else
cb(true, res, nil)
end
end
end
local ret = ffi.C.rspamd_spf_resolve(task:topointer(), spf_cb, nil)
if not ret then
cb(false, 'cannot perform resolving')
end
end
local function spf_unref(rec)
ffi.C.spf_record_unref(rec)
end
return {
spf_resolve = spf_resolve,
spf_unref = spf_unref
}

View File

@ -43,7 +43,7 @@ parser:mutex(
:description "UCL output"
)
parser:flag "-C --compact"
:description "Use compactl format"
:description "Use compact format"
parser:flag "--no-file"
:description "Do not print filename"