local function avast_check(task, content, digest, rule, maybe_part)
local function avast_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local CRLF = '\r\n'
end
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
tcp_opts.upstream = upstream
tcp_opts.callback = avast_helo_cb
local function clamav_check(task, content, digest, rule, maybe_part)
local function clamav_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local header = rspamd_util.pack("c9 c1 >I4", "zINSTREAM", "\0",
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: error: %s; retry IP: %s; retries left: %s',
-- Detect cloudmark max size
local function cloudmark_preload(rule, cfg, ev_base, _)
local upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ rspamd_logger.errx(ev_base or rspamd_config,
+ 'cloudmark preload: no upstream available, will retry on next scan')
+ return
+ end
local addr = upstream:get_addr()
local function max_message_size_cb(http_err, code, body, _)
if http_err then
local function cloudmark_check(task, content, digest, rule, maybe_part)
local function cloudmark_check_uncached()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
url = cloudmark_url(rule, addr)
end
end
+--[[
+Pick a round-robin upstream from `rule.upstreams` and emit `symbol_fail` if
+none is currently usable (e.g. all hostnames are still pending DNS resolution
+or every backend has been marked dead). Returns the upstream on success or
+nil on failure — in the nil case `symbol_fail` has already been recorded, so
+the caller should just return.
+--]]
+local function get_upstream_or_fail(task, rule, maybe_part, reason)
+ local upstream = rule.upstreams and rule.upstreams:get_upstream_round_robin()
+
+ if not upstream then
+ yield_result(task, rule,
+ reason or 'no upstream available (DNS pending or all dead)',
+ 0.0, 'fail', maybe_part)
+ return nil
+ end
+
+ return upstream
+end
+
exports.log_clean = log_clean
exports.yield_result = yield_result
exports.match_patterns = match_patterns
exports.create_regex_table = create_regex_table
exports.check_parts_match = check_parts_match
exports.check_metric_results = check_metric_results
+exports.get_upstream_or_fail = get_upstream_or_fail
setmetatable(exports, {
__call = function(t, override)
end
local function dcc_check(task, content, digest, rule)
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, nil)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local client = rule.client
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail')
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: error: %s; retry IP: %s; retries left: %s',
return url
end
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
url = expurgate_spamd_url(addr)
local function fprot_check(task, content, digest, rule, maybe_part)
local function fprot_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local scan_id = task:get_queue_id()
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: error: %s; retry IP: %s; retries left: %s',
local function icap_check(task, content, digest, rule, maybe_part)
local function icap_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local http_headers = {}
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule, 'no upstream available for retry', 0.0,
+ 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: retry IP: %s:%s',
end
end
- local function get_req_headers()
+ local function get_req_headers()
local in_client_ip = task:get_from_ip()
local in_client_ip_str = in_client_ip:to_string()
local req_hlen = 2
local function kaspersky_check(task, content, digest, rule, maybe_part)
local function kaspersky_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local fname = string.format('%s/%s.tmp',
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: error: %s; retry IP: %s; retries left: %s',
return url
end
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
url = make_url(addr)
local function oletools_check(task, content, digest, rule, maybe_part)
local function oletools_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local protocol = 'OLEFY/1.0\nMethod: oletools\nRspamd-ID: ' .. task:get_uid() .. '\n\n'
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: error: %s; retry IP: %s; retries left: %s',
local function pyzor_check(task, content, digest, rule)
local function pyzor_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, nil)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail')
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(N, task, '%s: retry IP: %s:%s err: %s',
local function razor_check(task, content, digest, rule)
local function razor_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, nil)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail')
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: retry IP: %s:%s',
local function savapi_check(task, content, digest, rule)
local function savapi_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, nil)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local fname = string.format('%s/%s.tmp',
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail')
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: error: %s; retry IP: %s; retries left: %s',
local function sophos_check(task, content, digest, rule, maybe_part)
local function sophos_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
local protocol = 'SSSP/1.0\n'
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.name, task, '%s: error: %s; retry IP: %s; retries left: %s',
local function spamassassin_check(task, content, digest, rule)
local function spamassassin_check_uncached ()
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, nil)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail')
+ return
+ end
addr = upstream:get_addr()
lua_util.debugm(rule.N, task, '%s: retry IP: %s:%s',
return url
end
- local upstream = rule.upstreams:get_upstream_round_robin()
+ local upstream = common.get_upstream_or_fail(task, rule, maybe_part)
+ if not upstream then
+ return
+ end
local addr = upstream:get_addr()
local retransmits = rule.retransmits
-- Select a different upstream!
upstream = rule.upstreams:get_upstream_round_robin()
+ if not upstream then
+ common.yield_result(task, rule,
+ 'no upstream available for retry', 0.0, 'fail', maybe_part)
+ return
+ end
addr = upstream:get_addr()
url = vade_url(addr)