aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2019-11-29 19:19:52 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2019-11-29 19:19:52 +0000
commit48f2cbc9bf284d90a70fa7a4c84450552f593927 (patch)
tree3d3279301754e404f7388de53215e52cf86d5da9 /src
parent0330f5c96e2eb47497b912709fa46deea52dcd0c (diff)
downloadrspamd-48f2cbc9bf284d90a70fa7a4c84450552f593927.tar.gz
rspamd-48f2cbc9bf284d90a70fa7a4c84450552f593927.zip
[Project] Implement IP check for an SPF record
Diffstat (limited to 'src')
-rw-r--r--src/lua/lua_spf.c130
1 files changed, 126 insertions, 4 deletions
diff --git a/src/lua/lua_spf.c b/src/lua/lua_spf.c
index bfa041051..a6daa26c6 100644
--- a/src/lua/lua_spf.c
+++ b/src/lua/lua_spf.c
@@ -26,16 +26,12 @@
LUA_FUNCTION_DEF (spf, resolve);
LUA_FUNCTION_DEF (spf, config);
-LUA_FUNCTION_DEF (spf, set_credentials);
-LUA_FUNCTION_DEF (spf, get_domain);
LUA_FUNCTION_DEF (spf_record, check_ip);
LUA_FUNCTION_DEF (spf_record, dtor);
static luaL_reg rspamd_spf_f[] = {
LUA_INTERFACE_DEF (spf, resolve),
LUA_INTERFACE_DEF (spf, config),
- LUA_INTERFACE_DEF (spf, set_credentials),
- LUA_INTERFACE_DEF (spf, get_domain),
{NULL, NULL},
};
@@ -233,6 +229,132 @@ lua_spf_record_dtor (lua_State *L)
return 0;
}
+static gint
+spf_check_element (lua_State *L, struct spf_resolved *rec, struct spf_addr *addr,
+ struct rspamd_lua_ip *ip)
+{
+ gboolean res = FALSE;
+ const guint8 *s, *d;
+ guint af, mask, bmask, addrlen;
+
+
+ if (addr->flags & RSPAMD_SPF_FLAG_TEMPFAIL) {
+ /* Ignore failed addresses */
+ lua_pushboolean (L, false);
+ lua_pushinteger (L, RSPAMD_SPF_FLAG_TEMPFAIL);
+ lua_pushstring (L, "temp failed");
+
+ return 3;
+ }
+
+ af = rspamd_inet_address_get_af (ip->addr);
+ /* Basic comparing algorithm */
+ if (((addr->flags & RSPAMD_SPF_FLAG_IPV6) && af == AF_INET6) ||
+ ((addr->flags & RSPAMD_SPF_FLAG_IPV4) && af == AF_INET)) {
+ d = rspamd_inet_address_get_hash_key (ip->addr, &addrlen);
+
+ if (af == AF_INET6) {
+ s = (const guint8 *)addr->addr6;
+ mask = addr->m.dual.mask_v6;
+ }
+ else {
+ s = (const guint8 *)addr->addr4;
+ mask = addr->m.dual.mask_v4;
+ }
+
+ /* Compare the first bytes */
+ bmask = mask / CHAR_BIT;
+ if (mask > addrlen * CHAR_BIT) {
+ /* XXX: add logging */
+ }
+ else if (memcmp (s, d, bmask) == 0) {
+ if (bmask * CHAR_BIT < mask) {
+ /* Compare the remaining bits */
+ s += bmask;
+ d += bmask;
+ mask = (0xff << (CHAR_BIT - (mask - bmask * 8))) & 0xff;
+
+ if ((*s & mask) == (*d & mask)) {
+ res = TRUE;
+ }
+ }
+ else {
+ res = TRUE;
+ }
+ }
+ }
+ else {
+ if (addr->flags & RSPAMD_SPF_FLAG_ANY) {
+ res = TRUE;
+ }
+ else {
+ res = FALSE;
+ }
+ }
+
+ if (res) {
+ if (addr->flags & RSPAMD_SPF_FLAG_ANY) {
+ if (rec->flags & RSPAMD_SPF_RESOLVED_PERM_FAILED) {
+ lua_pushboolean (L, false);
+ lua_pushinteger (L, RSPAMD_SPF_RESOLVED_PERM_FAILED);
+ lua_pushstring (L, addr->spf_string);
+ }
+ else if (rec->flags & RSPAMD_SPF_RESOLVED_TEMP_FAILED) {
+ lua_pushboolean (L, false);
+ lua_pushinteger (L, RSPAMD_SPF_RESOLVED_TEMP_FAILED);
+ lua_pushstring (L, addr->spf_string);
+ }
+ }
+ else {
+ lua_pushboolean (L, true);
+ lua_pushinteger (L, addr->mech);
+ lua_pushstring (L, addr->spf_string);
+ }
+
+ return 3;
+ }
+
+ return -1;
+}
+
+/***
+ * @method rspamd_spf_record:check_ip(ip)
+ * Checks the processed record versus a specific IP address. This function
+ * returns 3 values normally:
+ * 1. Boolean check result
+ * 2. If result is `false` then the second value is the error flag (e.g. rspamd_spf.flags.temp_fail), otherwise it will be an SPF method
+ * 3. If result is `false` then this will be an error string, otherwise - an SPF string (e.g. `mx` or `ip4:x.y.z.1`)
+ * @param {rspamd_ip} ip address
+ * @return {result,flag_or_policy,error_or_addr} - triplet
+*/
+static gint
+lua_spf_record_check_ip (lua_State *L)
+{
+ struct spf_resolved *record =
+ * (struct spf_resolved **)rspamd_lua_check_udata (L, 1,
+ SPF_RECORD_CLASS);
+ struct rspamd_lua_ip *ip = lua_check_ip (L, 2);
+ gint nres = 0;
+
+ if (record && ip && ip->addr) {
+ for (guint i = 0; i < record->elts->len; i ++) {
+ struct spf_addr *addr = &g_array_index (record->elts, struct spf_addr, i);
+ if ((nres = spf_check_element (L, record, addr, ip)) > 0) {
+ return nres;
+ }
+ }
+ }
+ else {
+ return luaL_error (L, "invalid arguments");
+ }
+
+ lua_pushboolean (L, false);
+ lua_pushinteger (L, RSPAMD_SPF_RESOLVED_NA);
+ lua_pushstring (L, "no result");
+
+ return 3;
+}
+
/***
* @function rspamd_spf.config(object)
* Configures SPF library according to the UCL config