mirror of
https://github.com/rspamd/rspamd.git
synced 2024-09-13 15:45:47 +02:00
[Feature] Add SPF FFI library for Lua
This commit is contained in:
parent
fe1c8f88b7
commit
4824ea2d2b
@ -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 {}
|
@ -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
141
lualib/lua_ffi/spf.lua
Normal 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
|
||||
}
|
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user