first
This commit is contained in:
commit
5aa7d034f7
3292 changed files with 465160 additions and 0 deletions
40
data/Dockerfiles/rspamd/Dockerfile
Executable file
40
data/Dockerfiles/rspamd/Dockerfile
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
FROM debian:bookworm-slim
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG RSPAMD_VER=rspamd_3.9.1-1~82f43560f
|
||||
ARG CODENAME=bookworm
|
||||
ENV LC_ALL=C
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
tzdata \
|
||||
ca-certificates \
|
||||
gnupg2 \
|
||||
apt-transport-https \
|
||||
dnsutils \
|
||||
netcat-traditional \
|
||||
wget \
|
||||
redis-tools \
|
||||
procps \
|
||||
nano \
|
||||
lua-cjson \
|
||||
&& arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \
|
||||
&& wget -P /tmp https://rspamd.com/apt-stable/pool/main/r/rspamd/${RSPAMD_VER}~${CODENAME}_${arch}.deb\
|
||||
&& apt install -y /tmp/${RSPAMD_VER}~${CODENAME}_${arch}.deb \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/*\
|
||||
&& apt-get autoremove --purge \
|
||||
&& apt-get clean \
|
||||
&& mkdir -p /run/rspamd \
|
||||
&& chown _rspamd:_rspamd /run/rspamd \
|
||||
&& echo 'alias ll="ls -la --color"' >> ~/.bashrc \
|
||||
&& sed -i 's/#analysis_keyword_table > 0/analysis_cat_table.macro_exist == "M"/g' /usr/share/rspamd/lualib/lua_scanners/oletools.lua
|
||||
|
||||
COPY settings.conf /etc/rspamd/settings.conf
|
||||
COPY set_worker_password.sh /set_worker_password.sh
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
|
||||
STOPSIGNAL SIGTERM
|
||||
|
||||
CMD ["/usr/bin/rspamd", "-f", "-u", "_rspamd", "-g", "_rspamd"]
|
||||
313
data/Dockerfiles/rspamd/docker-entrypoint.sh
Executable file
313
data/Dockerfiles/rspamd/docker-entrypoint.sh
Executable file
|
|
@ -0,0 +1,313 @@
|
|||
#!/bin/bash
|
||||
|
||||
until nc phpfpm 9001 -z; do
|
||||
echo "Waiting for PHP on port 9001..."
|
||||
sleep 3
|
||||
done
|
||||
|
||||
until nc phpfpm 9002 -z; do
|
||||
echo "Waiting for PHP on port 9002..."
|
||||
sleep 3
|
||||
done
|
||||
|
||||
mkdir -p /etc/rspamd/plugins.d \
|
||||
/etc/rspamd/custom
|
||||
|
||||
touch /etc/rspamd/rspamd.conf.local \
|
||||
/etc/rspamd/rspamd.conf.override
|
||||
|
||||
chmod 755 /var/lib/rspamd
|
||||
|
||||
|
||||
[[ ! -f /etc/rspamd/override.d/worker-controller-password.inc ]] && echo '# Autogenerated by mailcow' > /etc/rspamd/override.d/worker-controller-password.inc
|
||||
|
||||
echo ${IPV4_NETWORK}.0/24 > /etc/rspamd/custom/mailcow_networks.map
|
||||
echo ${IPV6_NETWORK} >> /etc/rspamd/custom/mailcow_networks.map
|
||||
|
||||
DOVECOT_V4=
|
||||
DOVECOT_V6=
|
||||
until [[ ! -z ${DOVECOT_V4} ]]; do
|
||||
DOVECOT_V4=$(dig a dovecot +short)
|
||||
DOVECOT_V6=$(dig aaaa dovecot +short)
|
||||
[[ ! -z ${DOVECOT_V4} ]] && break;
|
||||
echo "Waiting for Dovecot..."
|
||||
sleep 3
|
||||
done
|
||||
echo ${DOVECOT_V4}/32 > /etc/rspamd/custom/dovecot_trusted.map
|
||||
if [[ ! -z ${DOVECOT_V6} ]]; then
|
||||
echo ${DOVECOT_V6}/128 >> /etc/rspamd/custom/dovecot_trusted.map
|
||||
fi
|
||||
|
||||
RSPAMD_V4=
|
||||
RSPAMD_V6=
|
||||
until [[ ! -z ${RSPAMD_V4} ]]; do
|
||||
RSPAMD_V4=$(dig a rspamd +short)
|
||||
RSPAMD_V6=$(dig aaaa rspamd +short)
|
||||
[[ ! -z ${RSPAMD_V4} ]] && break;
|
||||
echo "Waiting for Rspamd..."
|
||||
sleep 3
|
||||
done
|
||||
echo ${RSPAMD_V4}/32 > /etc/rspamd/custom/rspamd_trusted.map
|
||||
if [[ ! -z ${RSPAMD_V6} ]]; then
|
||||
echo ${RSPAMD_V6}/128 >> /etc/rspamd/custom/rspamd_trusted.map
|
||||
fi
|
||||
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
||||
read_servers = "redis:6379";
|
||||
write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}";
|
||||
timeout = 10;
|
||||
EOF
|
||||
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis @redis-mailcow..."
|
||||
sleep 2
|
||||
done
|
||||
until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..."
|
||||
sleep 2
|
||||
done
|
||||
redis-cli -h redis-mailcow SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT}
|
||||
else
|
||||
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
||||
servers = "redis:6379";
|
||||
timeout = 10;
|
||||
EOF
|
||||
until [[ $(redis-cli -h redis-mailcow PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis slave..."
|
||||
sleep 2
|
||||
done
|
||||
redis-cli -h redis-mailcow SLAVEOF NO ONE
|
||||
fi
|
||||
|
||||
# Provide additional lua modules
|
||||
ln -s /usr/lib/$(uname -m)-linux-gnu/liblua5.1-cjson.so.0.0.0 /usr/lib/rspamd/cjson.so
|
||||
|
||||
chown -R _rspamd:_rspamd /var/lib/rspamd \
|
||||
/etc/rspamd/local.d \
|
||||
/etc/rspamd/override.d \
|
||||
/etc/rspamd/rspamd.conf.local \
|
||||
/etc/rspamd/rspamd.conf.override \
|
||||
/etc/rspamd/plugins.d
|
||||
|
||||
# Fix missing default global maps, if any
|
||||
# These exists in mailcow UI and should not be removed
|
||||
touch /etc/rspamd/custom/global_mime_from_blacklist.map \
|
||||
/etc/rspamd/custom/global_rcpt_blacklist.map \
|
||||
/etc/rspamd/custom/global_smtp_from_blacklist.map \
|
||||
/etc/rspamd/custom/global_mime_from_whitelist.map \
|
||||
/etc/rspamd/custom/global_rcpt_whitelist.map \
|
||||
/etc/rspamd/custom/global_smtp_from_whitelist.map \
|
||||
/etc/rspamd/custom/bad_languages.map \
|
||||
/etc/rspamd/custom/sa-rules \
|
||||
/etc/rspamd/custom/dovecot_trusted.map \
|
||||
/etc/rspamd/custom/rspamd_trusted.map \
|
||||
/etc/rspamd/custom/mailcow_networks.map \
|
||||
/etc/rspamd/custom/ip_wl.map \
|
||||
/etc/rspamd/custom/fishy_tlds.map \
|
||||
/etc/rspamd/custom/bad_words.map \
|
||||
/etc/rspamd/custom/bad_asn.map \
|
||||
/etc/rspamd/custom/bad_words_de.map \
|
||||
/etc/rspamd/custom/bulk_header.map \
|
||||
/etc/rspamd/custom/bad_header.map
|
||||
|
||||
# www-data (82) group needs to write to these files
|
||||
chown _rspamd:_rspamd /etc/rspamd/custom/
|
||||
chmod 0755 /etc/rspamd/custom/.
|
||||
chown -R 82:82 /etc/rspamd/custom/*
|
||||
chmod 644 -R /etc/rspamd/custom/*
|
||||
|
||||
# Run hooks
|
||||
for file in /hooks/*; do
|
||||
if [ -x "${file}" ]; then
|
||||
echo "Running hook ${file}"
|
||||
"${file}"
|
||||
fi
|
||||
done
|
||||
|
||||
# If DQS KEY is set in mailcow.conf add Spamhaus DQS RBLs
|
||||
if [[ ! -z ${SPAMHAUS_DQS_KEY} ]]; then
|
||||
cat <<EOF > /etc/rspamd/custom/dqs-rbl.conf
|
||||
# Autogenerated by mailcow. DO NOT TOUCH!
|
||||
spamhaus {
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net";
|
||||
from = false;
|
||||
}
|
||||
spamhaus_from {
|
||||
from = true;
|
||||
received = false;
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net";
|
||||
returncodes {
|
||||
SPAMHAUS_ZEN = [ "127.0.0.2", "127.0.0.3", "127.0.0.4", "127.0.0.5", "127.0.0.6", "127.0.0.7", "127.0.0.9", "127.0.0.10", "127.0.0.11" ];
|
||||
}
|
||||
}
|
||||
spamhaus_authbl_received {
|
||||
# Check if the sender client is listed in AuthBL (AuthBL is *not* part of ZEN)
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.authbl.dq.spamhaus.net";
|
||||
from = false;
|
||||
received = true;
|
||||
ipv6 = true;
|
||||
returncodes {
|
||||
SH_AUTHBL_RECEIVED = "127.0.0.20"
|
||||
}
|
||||
}
|
||||
spamhaus_dbl {
|
||||
# Add checks on the HELO string
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net";
|
||||
helo = true;
|
||||
rdns = true;
|
||||
dkim = true;
|
||||
disable_monitoring = true;
|
||||
returncodes {
|
||||
RBL_DBL_SPAM = "127.0.1.2";
|
||||
RBL_DBL_PHISH = "127.0.1.4";
|
||||
RBL_DBL_MALWARE = "127.0.1.5";
|
||||
RBL_DBL_BOTNET = "127.0.1.6";
|
||||
RBL_DBL_ABUSED_SPAM = "127.0.1.102";
|
||||
RBL_DBL_ABUSED_PHISH = "127.0.1.104";
|
||||
RBL_DBL_ABUSED_MALWARE = "127.0.1.105";
|
||||
RBL_DBL_ABUSED_BOTNET = "127.0.1.106";
|
||||
RBL_DBL_DONT_QUERY_IPS = "127.0.1.255";
|
||||
}
|
||||
}
|
||||
spamhaus_dbl_fullurls {
|
||||
ignore_defaults = true;
|
||||
no_ip = true;
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net";
|
||||
selector = 'urls:get_host'
|
||||
disable_monitoring = true;
|
||||
returncodes {
|
||||
DBLABUSED_SPAM_FULLURLS = "127.0.1.102";
|
||||
DBLABUSED_PHISH_FULLURLS = "127.0.1.104";
|
||||
DBLABUSED_MALWARE_FULLURLS = "127.0.1.105";
|
||||
DBLABUSED_BOTNET_FULLURLS = "127.0.1.106";
|
||||
}
|
||||
}
|
||||
spamhaus_zrd {
|
||||
# Add checks on the HELO string also for DQS
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net";
|
||||
helo = true;
|
||||
rdns = true;
|
||||
dkim = true;
|
||||
disable_monitoring = true;
|
||||
returncodes {
|
||||
RBL_ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"];
|
||||
RBL_ZRD_FRESH_DOMAIN = [
|
||||
"127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24"
|
||||
];
|
||||
RBL_ZRD_DONT_QUERY_IPS = "127.0.2.255";
|
||||
}
|
||||
}
|
||||
"SPAMHAUS_ZEN_URIBL" {
|
||||
enabled = true;
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.zen.dq.spamhaus.net";
|
||||
resolve_ip = true;
|
||||
checks = ['urls'];
|
||||
replyto = true;
|
||||
emails = true;
|
||||
ipv4 = true;
|
||||
ipv6 = true;
|
||||
emails_domainonly = true;
|
||||
returncodes {
|
||||
URIBL_SBL = "127.0.0.2";
|
||||
URIBL_SBL_CSS = "127.0.0.3";
|
||||
URIBL_XBL = ["127.0.0.4", "127.0.0.5", "127.0.0.6", "127.0.0.7"];
|
||||
URIBL_PBL = ["127.0.0.10", "127.0.0.11"];
|
||||
URIBL_DROP = "127.0.0.9";
|
||||
}
|
||||
}
|
||||
SH_EMAIL_DBL {
|
||||
ignore_defaults = true;
|
||||
replyto = true;
|
||||
emails_domainonly = true;
|
||||
disable_monitoring = true;
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net";
|
||||
returncodes = {
|
||||
SH_EMAIL_DBL = [
|
||||
"127.0.1.2",
|
||||
"127.0.1.4",
|
||||
"127.0.1.5",
|
||||
"127.0.1.6"
|
||||
];
|
||||
SH_EMAIL_DBL_ABUSED = [
|
||||
"127.0.1.102",
|
||||
"127.0.1.104",
|
||||
"127.0.1.105",
|
||||
"127.0.1.106"
|
||||
];
|
||||
SH_EMAIL_DBL_DONT_QUERY_IPS = [ "127.0.1.255" ];
|
||||
}
|
||||
}
|
||||
SH_EMAIL_ZRD {
|
||||
ignore_defaults = true;
|
||||
replyto = true;
|
||||
emails_domainonly = true;
|
||||
disable_monitoring = true;
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net";
|
||||
returncodes = {
|
||||
SH_EMAIL_ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"];
|
||||
SH_EMAIL_ZRD_FRESH_DOMAIN = [
|
||||
"127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24"
|
||||
];
|
||||
SH_EMAIL_ZRD_DONT_QUERY_IPS = [ "127.0.2.255" ];
|
||||
}
|
||||
}
|
||||
"DBL" {
|
||||
# override the defaults for DBL defined in modules.d/rbl.conf
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.dbl.dq.spamhaus.net";
|
||||
disable_monitoring = true;
|
||||
}
|
||||
"ZRD" {
|
||||
ignore_defaults = true;
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.zrd.dq.spamhaus.net";
|
||||
no_ip = true;
|
||||
dkim = true;
|
||||
emails = true;
|
||||
emails_domainonly = true;
|
||||
urls = true;
|
||||
returncodes = {
|
||||
ZRD_VERY_FRESH_DOMAIN = ["127.0.2.2", "127.0.2.3", "127.0.2.4"];
|
||||
ZRD_FRESH_DOMAIN = ["127.0.2.5", "127.0.2.6", "127.0.2.7", "127.0.2.8", "127.0.2.9", "127.0.2.10", "127.0.2.11", "127.0.2.12", "127.0.2.13", "127.0.2.14", "127.0.2.15", "127.0.2.16", "127.0.2.17", "127.0.2.18", "127.0.2.19", "127.0.2.20", "127.0.2.21", "127.0.2.22", "127.0.2.23", "127.0.2.24"];
|
||||
}
|
||||
}
|
||||
spamhaus_sbl_url {
|
||||
ignore_defaults = true
|
||||
rbl = "${SPAMHAUS_DQS_KEY}.sbl.dq.spamhaus.net";
|
||||
checks = ['urls'];
|
||||
disable_monitoring = true;
|
||||
returncodes {
|
||||
SPAMHAUS_SBL_URL = "127.0.0.2";
|
||||
}
|
||||
}
|
||||
|
||||
SH_HBL_EMAIL {
|
||||
ignore_defaults = true;
|
||||
rbl = "_email.${SPAMHAUS_DQS_KEY}.hbl.dq.spamhaus.net";
|
||||
emails_domainonly = false;
|
||||
selector = "from('smtp').lower;from('mime').lower";
|
||||
ignore_whitelist = true;
|
||||
checks = ['emails', 'replyto'];
|
||||
hash = "sha1";
|
||||
returncodes = {
|
||||
SH_HBL_EMAIL = [
|
||||
"127.0.3.2"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
spamhaus_dqs_hbl {
|
||||
symbol = "HBL_FILE_UNKNOWN";
|
||||
rbl = "_file.${SPAMHAUS_DQS_KEY}.hbl.dq.spamhaus.net.";
|
||||
selector = "attachments('rbase32', 'sha256')";
|
||||
ignore_whitelist = true;
|
||||
ignore_defaults = true;
|
||||
returncodes {
|
||||
SH_HBL_FILE_MALICIOUS = "127.0.3.10";
|
||||
SH_HBL_FILE_SUSPICIOUS = "127.0.3.15";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
else
|
||||
rm -rf /etc/rspamd/custom/dqs-rbl.conf
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
443
data/Dockerfiles/rspamd/sa_trivial_convert.lua
Executable file
443
data/Dockerfiles/rspamd/sa_trivial_convert.lua
Executable file
|
|
@ -0,0 +1,443 @@
|
|||
local fun = require "fun"
|
||||
local rspamd_logger = require "rspamd_logger"
|
||||
local util = require "rspamd_util"
|
||||
local lua_util = require "lua_util"
|
||||
local rspamd_regexp = require "rspamd_regexp"
|
||||
local ucl = require "ucl"
|
||||
|
||||
local complicated = {}
|
||||
local rules = {}
|
||||
local scores = {}
|
||||
|
||||
local function words_to_re(words, start)
|
||||
return table.concat(fun.totable(fun.drop_n(start, words)), " ");
|
||||
end
|
||||
|
||||
local function split(str, delim)
|
||||
local result = {}
|
||||
|
||||
if not delim then
|
||||
delim = '[^%s]+'
|
||||
end
|
||||
|
||||
for token in string.gmatch(str, delim) do
|
||||
table.insert(result, token)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function handle_header_def(hline, cur_rule)
|
||||
--Now check for modifiers inside header's name
|
||||
local hdrs = split(hline, '[^|]+')
|
||||
local hdr_params = {}
|
||||
local cur_param = {}
|
||||
-- Check if an re is an ordinary re
|
||||
local ordinary = true
|
||||
|
||||
for _,h in ipairs(hdrs) do
|
||||
if h == 'ALL' or h == 'ALL:raw' then
|
||||
ordinary = false
|
||||
else
|
||||
local args = split(h, '[^:]+')
|
||||
cur_param['strong'] = false
|
||||
cur_param['raw'] = false
|
||||
cur_param['header'] = args[1]
|
||||
|
||||
if args[2] then
|
||||
-- We have some ops that are required for the header, so it's not ordinary
|
||||
ordinary = false
|
||||
end
|
||||
|
||||
fun.each(function(func)
|
||||
if func == 'addr' then
|
||||
cur_param['function'] = function(str)
|
||||
local addr_parsed = util.parse_addr(str)
|
||||
local ret = {}
|
||||
if addr_parsed then
|
||||
for _,elt in ipairs(addr_parsed) do
|
||||
if elt['addr'] then
|
||||
table.insert(ret, elt['addr'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
elseif func == 'name' then
|
||||
cur_param['function'] = function(str)
|
||||
local addr_parsed = util.parse_addr(str)
|
||||
local ret = {}
|
||||
if addr_parsed then
|
||||
for _,elt in ipairs(addr_parsed) do
|
||||
if elt['name'] then
|
||||
table.insert(ret, elt['name'])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
elseif func == 'raw' then
|
||||
cur_param['raw'] = true
|
||||
elseif func == 'case' then
|
||||
cur_param['strong'] = true
|
||||
else
|
||||
rspamd_logger.warnx(rspamd_config, 'Function %1 is not supported in %2',
|
||||
func, cur_rule['symbol'])
|
||||
end
|
||||
end, fun.tail(args))
|
||||
|
||||
-- Some header rules require splitting to check of multiple headers
|
||||
if cur_param['header'] == 'MESSAGEID' then
|
||||
-- Special case for spamassassin
|
||||
ordinary = false
|
||||
elseif cur_param['header'] == 'ToCc' then
|
||||
ordinary = false
|
||||
else
|
||||
table.insert(hdr_params, cur_param)
|
||||
end
|
||||
end
|
||||
|
||||
cur_rule['ordinary'] = ordinary and (not (#hdr_params > 1))
|
||||
cur_rule['header'] = hdr_params
|
||||
end
|
||||
end
|
||||
|
||||
local function process_sa_conf(f)
|
||||
local cur_rule = {}
|
||||
local valid_rule = false
|
||||
|
||||
local function insert_cur_rule()
|
||||
if not rules[cur_rule.type] then
|
||||
rules[cur_rule.type] = {}
|
||||
end
|
||||
|
||||
local target = rules[cur_rule.type]
|
||||
|
||||
if cur_rule.type == 'header' then
|
||||
if not cur_rule.header[1].header then
|
||||
rspamd_logger.errx(rspamd_config, 'bad rule definition: %1', cur_rule)
|
||||
return
|
||||
end
|
||||
if not target[cur_rule.header[1].header] then
|
||||
target[cur_rule.header[1].header] = {}
|
||||
end
|
||||
target = target[cur_rule.header[1].header]
|
||||
end
|
||||
|
||||
if not cur_rule['symbol'] then
|
||||
rspamd_logger.errx(rspamd_config, 'bad rule definition: %1', cur_rule)
|
||||
return
|
||||
end
|
||||
target[cur_rule['symbol']] = cur_rule
|
||||
cur_rule = {}
|
||||
valid_rule = false
|
||||
end
|
||||
|
||||
local function parse_score(words)
|
||||
if #words == 3 then
|
||||
-- score rule <x>
|
||||
return tonumber(words[3])
|
||||
elseif #words == 6 then
|
||||
-- score rule <x1> <x2> <x3> <x4>
|
||||
-- we assume here that bayes and network are enabled and select <x4>
|
||||
return tonumber(words[6])
|
||||
else
|
||||
rspamd_logger.errx(rspamd_config, 'invalid score for %1', words[2])
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local skip_to_endif = false
|
||||
local if_nested = 0
|
||||
for l in f:lines() do
|
||||
(function ()
|
||||
l = lua_util.rspamd_str_trim(l)
|
||||
-- Replace bla=~/re/ with bla =~ /re/ (#2372)
|
||||
l = l:gsub('([^%s])%s*([=!]~)%s*([^%s])', '%1 %2 %3')
|
||||
|
||||
if string.len(l) == 0 or string.sub(l, 1, 1) == '#' then
|
||||
return
|
||||
end
|
||||
|
||||
-- Unbalanced if/endif
|
||||
if if_nested < 0 then if_nested = 0 end
|
||||
if skip_to_endif then
|
||||
if string.match(l, '^endif') then
|
||||
if_nested = if_nested - 1
|
||||
|
||||
if if_nested == 0 then
|
||||
skip_to_endif = false
|
||||
end
|
||||
elseif string.match(l, '^if') then
|
||||
if_nested = if_nested + 1
|
||||
elseif string.match(l, '^else') then
|
||||
-- Else counterpart for if
|
||||
skip_to_endif = false
|
||||
end
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
else
|
||||
if string.match(l, '^ifplugin') then
|
||||
skip_to_endif = true
|
||||
if_nested = if_nested + 1
|
||||
table.insert(complicated, l)
|
||||
elseif string.match(l, '^if !plugin%(') then
|
||||
skip_to_endif = true
|
||||
if_nested = if_nested + 1
|
||||
table.insert(complicated, l)
|
||||
elseif string.match(l, '^if') then
|
||||
-- Unknown if
|
||||
skip_to_endif = true
|
||||
if_nested = if_nested + 1
|
||||
table.insert(complicated, l)
|
||||
elseif string.match(l, '^else') then
|
||||
-- Else counterpart for if
|
||||
skip_to_endif = true
|
||||
table.insert(complicated, l)
|
||||
elseif string.match(l, '^endif') then
|
||||
if_nested = if_nested - 1
|
||||
table.insert(complicated, l)
|
||||
end
|
||||
end
|
||||
|
||||
-- Skip comments
|
||||
local words = fun.totable(fun.take_while(
|
||||
function(w) return string.sub(w, 1, 1) ~= '#' end,
|
||||
fun.filter(function(w)
|
||||
return w ~= "" end,
|
||||
fun.iter(split(l)))))
|
||||
|
||||
if words[1] == "header" then
|
||||
-- header SYMBOL Header ~= /regexp/
|
||||
if valid_rule then
|
||||
insert_cur_rule()
|
||||
end
|
||||
if words[4] and (words[4] == '=~' or words[4] == '!~') then
|
||||
cur_rule['type'] = 'header'
|
||||
cur_rule['symbol'] = words[2]
|
||||
|
||||
if words[4] == '!~' then
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
|
||||
cur_rule['re_expr'] = words_to_re(words, 4)
|
||||
local unset_comp = string.find(cur_rule['re_expr'], '%s+%[if%-unset:')
|
||||
if unset_comp then
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
|
||||
cur_rule['re'] = rspamd_regexp.create(cur_rule['re_expr'])
|
||||
|
||||
if not cur_rule['re'] then
|
||||
rspamd_logger.warnx(rspamd_config, "Cannot parse regexp '%1' for %2",
|
||||
cur_rule['re_expr'], cur_rule['symbol'])
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
else
|
||||
handle_header_def(words[3], cur_rule)
|
||||
if not cur_rule['ordinary'] then
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
valid_rule = true
|
||||
else
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
elseif words[1] == "body" then
|
||||
-- body SYMBOL /regexp/
|
||||
if valid_rule then
|
||||
insert_cur_rule()
|
||||
end
|
||||
|
||||
cur_rule['symbol'] = words[2]
|
||||
if words[3] and (string.sub(words[3], 1, 1) == '/'
|
||||
or string.sub(words[3], 1, 1) == 'm') then
|
||||
cur_rule['type'] = 'sabody'
|
||||
cur_rule['re_expr'] = words_to_re(words, 2)
|
||||
cur_rule['re'] = rspamd_regexp.create(cur_rule['re_expr'])
|
||||
if cur_rule['re'] then
|
||||
|
||||
valid_rule = true
|
||||
end
|
||||
else
|
||||
-- might be function
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
elseif words[1] == "rawbody" then
|
||||
-- body SYMBOL /regexp/
|
||||
if valid_rule then
|
||||
insert_cur_rule()
|
||||
end
|
||||
|
||||
cur_rule['symbol'] = words[2]
|
||||
if words[3] and (string.sub(words[3], 1, 1) == '/'
|
||||
or string.sub(words[3], 1, 1) == 'm') then
|
||||
cur_rule['type'] = 'sarawbody'
|
||||
cur_rule['re_expr'] = words_to_re(words, 2)
|
||||
cur_rule['re'] = rspamd_regexp.create(cur_rule['re_expr'])
|
||||
if cur_rule['re'] then
|
||||
valid_rule = true
|
||||
end
|
||||
else
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
elseif words[1] == "full" then
|
||||
-- body SYMBOL /regexp/
|
||||
if valid_rule then
|
||||
insert_cur_rule()
|
||||
end
|
||||
|
||||
cur_rule['symbol'] = words[2]
|
||||
|
||||
if words[3] and (string.sub(words[3], 1, 1) == '/'
|
||||
or string.sub(words[3], 1, 1) == 'm') then
|
||||
cur_rule['type'] = 'message'
|
||||
cur_rule['re_expr'] = words_to_re(words, 2)
|
||||
cur_rule['re'] = rspamd_regexp.create(cur_rule['re_expr'])
|
||||
cur_rule['raw'] = true
|
||||
if cur_rule['re'] then
|
||||
valid_rule = true
|
||||
end
|
||||
else
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
elseif words[1] == "uri" then
|
||||
-- uri SYMBOL /regexp/
|
||||
if valid_rule then
|
||||
insert_cur_rule()
|
||||
end
|
||||
cur_rule['type'] = 'uri'
|
||||
cur_rule['symbol'] = words[2]
|
||||
cur_rule['re_expr'] = words_to_re(words, 2)
|
||||
cur_rule['re'] = rspamd_regexp.create(cur_rule['re_expr'])
|
||||
if cur_rule['re'] and cur_rule['symbol'] then
|
||||
valid_rule = true
|
||||
else
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
elseif words[1] == "meta" then
|
||||
-- meta SYMBOL expression
|
||||
if valid_rule then
|
||||
insert_cur_rule()
|
||||
end
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
elseif words[1] == "describe" and valid_rule then
|
||||
cur_rule['description'] = words_to_re(words, 2)
|
||||
elseif words[1] == "score" then
|
||||
scores[words[2]] = parse_score(words)
|
||||
else
|
||||
table.insert(complicated, l)
|
||||
return
|
||||
end
|
||||
end)()
|
||||
end
|
||||
if valid_rule then
|
||||
insert_cur_rule()
|
||||
end
|
||||
end
|
||||
|
||||
for _,matched in ipairs(arg) do
|
||||
local f = io.open(matched, "r")
|
||||
if f then
|
||||
rspamd_logger.messagex(rspamd_config, 'loading SA rules from %s', matched)
|
||||
process_sa_conf(f)
|
||||
else
|
||||
rspamd_logger.errx(rspamd_config, "cannot open %1", matched)
|
||||
end
|
||||
end
|
||||
|
||||
local multimap_conf = {}
|
||||
|
||||
local function handle_rule(what, syms, hdr)
|
||||
local mtype
|
||||
local filter
|
||||
local fname
|
||||
local header
|
||||
local sym = what:upper()
|
||||
if what == 'sabody' then
|
||||
mtype = 'content'
|
||||
fname = 'body_re.map'
|
||||
filter = 'oneline'
|
||||
elseif what == 'sarawbody' then
|
||||
fname = 'raw_body_re.map'
|
||||
mtype = 'content'
|
||||
filter = 'rawtext'
|
||||
elseif what == 'full' then
|
||||
fname = 'full_re.map'
|
||||
mtype = 'content'
|
||||
filter = 'full'
|
||||
elseif what == 'uri' then
|
||||
fname = 'uri_re.map'
|
||||
mtype = 'url'
|
||||
filter = 'full'
|
||||
elseif what == 'header' then
|
||||
fname = ('hdr_' .. hdr .. '_re.map'):lower()
|
||||
mtype = 'header'
|
||||
header = hdr
|
||||
sym = sym .. '_' .. hdr:upper()
|
||||
else
|
||||
rspamd_logger.errx('unknown type: %s', what)
|
||||
return
|
||||
end
|
||||
local conf = {
|
||||
type = mtype,
|
||||
filter = filter,
|
||||
symbol = 'SA_MAP_AUTO_' .. sym,
|
||||
regexp = true,
|
||||
map = fname,
|
||||
header = header,
|
||||
symbols = {}
|
||||
}
|
||||
local re_file = io.open(fname, 'w')
|
||||
|
||||
for k,r in pairs(syms) do
|
||||
local score = 0.0
|
||||
if scores[k] then
|
||||
score = scores[k]
|
||||
end
|
||||
re_file:write(string.format('/%s/ %s:%f\n', tostring(r.re), k, score))
|
||||
table.insert(conf.symbols, k)
|
||||
end
|
||||
|
||||
re_file:close()
|
||||
|
||||
multimap_conf[sym:lower()] = conf
|
||||
rspamd_logger.messagex('stored %s regexp in %s', sym:lower(), fname)
|
||||
end
|
||||
|
||||
for k,v in pairs(rules) do
|
||||
if k == 'header' then
|
||||
for h,r in pairs(v) do
|
||||
handle_rule(k, r, h)
|
||||
end
|
||||
else
|
||||
handle_rule(k, v)
|
||||
end
|
||||
end
|
||||
|
||||
local out = ucl.to_format(multimap_conf, 'ucl')
|
||||
local mmap_conf = io.open('auto_multimap.conf', 'w')
|
||||
mmap_conf:write(out)
|
||||
mmap_conf:close()
|
||||
rspamd_logger.messagex('stored multimap conf in %s', 'auto_multimap.conf')
|
||||
|
||||
local sa_remain = io.open('auto_sa.conf', 'w')
|
||||
fun.each(function(l)
|
||||
sa_remain:write(l)
|
||||
sa_remain:write('\n')
|
||||
end, fun.filter(function(l) return not string.match(l, '^%s+$') end, complicated))
|
||||
sa_remain:close()
|
||||
rspamd_logger.messagex('stored sa remains conf in %s', 'auto_sa.conf')
|
||||
12
data/Dockerfiles/rspamd/set_worker_password.sh
Executable file
12
data/Dockerfiles/rspamd/set_worker_password.sh
Executable file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
password_file='/etc/rspamd/override.d/worker-controller-password.inc'
|
||||
password_hash=`/usr/bin/rspamadm pw -e -p $1`
|
||||
|
||||
echo 'enable_password = "'$password_hash'";' > $password_file
|
||||
|
||||
if grep -q "$password_hash" "$password_file"; then
|
||||
echo "OK"
|
||||
else
|
||||
echo "ERROR"
|
||||
fi
|
||||
1
data/Dockerfiles/rspamd/settings.conf
Executable file
1
data/Dockerfiles/rspamd/settings.conf
Executable file
|
|
@ -0,0 +1 @@
|
|||
settings = "http://nginx:8081/settings.php";
|
||||
Loading…
Add table
Add a link
Reference in a new issue