--[[ Copyright (c) 2022, Vsevolod Stakhov Copyright (c) 2016, Andrew Lewis 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. ]]-- local rspamd_logger = require "rspamd_logger" local rspamd_regexp = require "rspamd_regexp" local lua_util = require "lua_util" local N = "asn" if confighelp then return end local options = { provider_type = 'rspamd', provider_info = { ip4 = 'asn.rspamd.com', ip6 = 'asn6.rspamd.com', }, symbol = 'ASN', check_local = false, } local rspamd_re = rspamd_regexp.create_cached("[\\|\\s]") local function asn_check(task) local function asn_set(asn, ipnet, country) local descr_t = {} local mempool = task:get_mempool() if asn then if tonumber(asn) ~= nil then mempool:set_variable("asn", asn) table.insert(descr_t, "asn:" .. asn) else rspamd_logger.errx(task, 'malformed ASN "%s" for ip %s', asn, task:get_from_ip()) end end if ipnet then mempool:set_variable("ipnet", ipnet) table.insert(descr_t, "ipnet:" .. ipnet) end if country then mempool:set_variable("country", country) table.insert(descr_t, "country:" .. country) end if options['symbol'] then task:insert_result(options['symbol'], 0.0, table.concat(descr_t, ', ')) end end local asn_check_func = {} asn_check_func.rspamd = function(ip) local dnsbl = options['provider_info']['ip' .. ip:get_version()] local req_name = string.format("%s.%s", table.concat(ip:inversed_str_octets(), '.'), dnsbl) local function rspamd_dns_cb(_, _, results, dns_err, _, _, serv) if dns_err and (dns_err ~= 'requested record is not found' and dns_err ~= 'no records with this name') then rspamd_logger.errx(task, 'error querying dns "%s" on %s: %s', req_name, serv, dns_err) task:insert_result(options['symbol_fail'], 0, string.format('%s:%s', req_name, dns_err)) return end if not results or not results[1] then rspamd_logger.infox(task, 'no ASN information is available for the IP address "%s" on %s', req_name, serv) return end lua_util.debugm(N, task, 'got reply from %s when requesting %s: %s', serv, req_name, results[1]) local parts = rspamd_re:split(results[1]) -- "15169 | 8.8.8.0/24 | US | arin |" for 8.8.8.8 asn_set(parts[1], parts[2], parts[3]) end task:get_resolver():resolve_txt({ task = task, name = req_name, callback = rspamd_dns_cb }) end local ip = task:get_from_ip() if not (ip and ip:is_valid()) or (not options.check_local and ip:is_local()) then return end asn_check_func[options['provider_type']](ip) end -- Configuration options local configure_asn_module = function() local opts = rspamd_config:get_all_opt('asn') if opts then for k, v in pairs(opts) do options[k] = v end end local auth_and_local_conf = lua_util.config_check_local_or_authed(rspamd_config, N, false, true) options.check_local = auth_and_local_conf[1] options.check_authed = auth_and_local_conf[2] if options['provider_type'] == 'rspamd' then if not options['provider_info'] and options['provider_info']['ip4'] and options['provider_info']['ip6'] then rspamd_logger.errx("Missing required provider_info for rspamd") return false end else rspamd_logger.errx("Unknown provider_type: %s", options['provider_type']) return false end if options['symbol'] then options['symbol_fail'] = options['symbol'] .. '_FAIL' else options['symbol_fail'] = 'ASN_FAIL' end return true end if configure_asn_module() then local id = rspamd_config:register_symbol({ name = 'ASN_CHECK', type = 'prefilter', callback = asn_check, priority = lua_util.symbols_priorities.high, flags = 'empty,nostat', augmentations = { lua_util.dns_timeout_augmentation(rspamd_config) }, }) if options['symbol'] then rspamd_config:register_symbol({ name = options['symbol'], parent = id, type = 'virtual', flags = 'empty,nostat', score = 0, }) end rspamd_config:register_symbol { name = options['symbol_fail'], parent = id, type = 'virtual', flags = 'empty,nostat', score = 0, } else lua_util.disable_module(N, 'config') end