diff options
Diffstat (limited to '')
-rw-r--r-- | lualib/lua_ffi/spf.lua | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/lualib/lua_ffi/spf.lua b/lualib/lua_ffi/spf.lua new file mode 100644 index 0000000..0f982f2 --- /dev/null +++ b/lualib/lua_ffi/spf.lua @@ -0,0 +1,143 @@ +--[[ +Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com> + +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 NULL = ffi.new 'void*' + +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 ~= NULL 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 ~= NULL 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 +}
\ No newline at end of file |