You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rbl.lua 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. --[[
  2. Copyright (c) 2020, Vsevolod Stakhov <vsevolod@highsecure.ru>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ]]--
  13. local ts = require("tableshape").types
  14. local lua_maps = require "lua_maps"
  15. local lua_util = require "lua_util"
  16. -- Common RBL plugin definitions
  17. local check_types = {
  18. from = {
  19. connfilter = true,
  20. },
  21. received = {},
  22. helo = {
  23. connfilter = true,
  24. },
  25. urls = {},
  26. content_urls = {},
  27. emails = {},
  28. replyto = {},
  29. dkim = {},
  30. rdns = {
  31. connfilter = true,
  32. },
  33. selector = {
  34. require_argument = true,
  35. },
  36. }
  37. local default_options = {
  38. ['default_enabled'] = true,
  39. ['default_ipv4'] = true,
  40. ['default_ipv6'] = true,
  41. ['default_unknown'] = false,
  42. ['default_dkim_domainonly'] = true,
  43. ['default_emails_domainonly'] = false,
  44. ['default_exclude_private_ips'] = true,
  45. ['default_exclude_users'] = false,
  46. ['default_exclude_local'] = true,
  47. ['default_no_ip'] = false,
  48. ['default_dkim_match_from'] = false,
  49. }
  50. local return_codes_schema = ts.map_of(
  51. ts.string / string.upper, -- Symbol name
  52. (
  53. ts.array_of(ts.string) +
  54. (ts.string / function(s)
  55. return { s }
  56. end) -- List of IP patterns
  57. )
  58. )
  59. local return_bits_schema = ts.map_of(
  60. ts.string / string.upper, -- Symbol name
  61. (
  62. ts.array_of(ts.number + ts.string / tonumber) +
  63. (ts.string / function(s)
  64. return { tonumber(s) }
  65. end) +
  66. (ts.number / function(s)
  67. return { s }
  68. end)
  69. )
  70. )
  71. local rule_schema_tbl = {
  72. content_urls = ts.boolean:is_optional(),
  73. disable_monitoring = ts.boolean:is_optional(),
  74. disabled = ts.boolean:is_optional(),
  75. dkim = ts.boolean:is_optional(),
  76. dkim_domainonly = ts.boolean:is_optional(),
  77. dkim_match_from = ts.boolean:is_optional(),
  78. emails = ts.boolean:is_optional(),
  79. emails_delimiter = ts.string:is_optional(),
  80. emails_domainonly = ts.boolean:is_optional(),
  81. enabled = ts.boolean:is_optional(),
  82. exclude_local = ts.boolean:is_optional(),
  83. exclude_private_ips = ts.boolean:is_optional(),
  84. exclude_users = ts.boolean:is_optional(),
  85. from = ts.boolean:is_optional(),
  86. hash = ts.one_of{"sha1", "sha256", "sha384", "sha512", "md5", "blake2"}:is_optional(),
  87. hash_format = ts.one_of{"hex", "base32", "base64"}:is_optional(),
  88. hash_len = (ts.integer + ts.string / tonumber):is_optional(),
  89. helo = ts.boolean:is_optional(),
  90. ignore_default = ts.boolean:is_optional(), -- alias
  91. ignore_defaults = ts.boolean:is_optional(),
  92. ignore_whitelist = ts.boolean:is_optional(),
  93. ignore_whitelists = ts.boolean:is_optional(), -- alias
  94. images = ts.boolean:is_optional(),
  95. ipv4 = ts.boolean:is_optional(),
  96. ipv6 = ts.boolean:is_optional(),
  97. is_whitelist = ts.boolean:is_optional(),
  98. local_exclude_ip_map = ts.string:is_optional(),
  99. monitored_address = ts.string:is_optional(),
  100. no_ip = ts.boolean:is_optional(),
  101. process_script = ts.string:is_optional(),
  102. rbl = ts.string,
  103. rdns = ts.boolean:is_optional(),
  104. received = ts.boolean:is_optional(),
  105. replyto = ts.boolean:is_optional(),
  106. requests_limit = (ts.integer + ts.string / tonumber):is_optional(),
  107. resolve_ip = ts.boolean:is_optional(),
  108. return_bits = return_bits_schema:is_optional(),
  109. return_codes = return_codes_schema:is_optional(),
  110. returnbits = return_bits_schema:is_optional(),
  111. returncodes = return_codes_schema:is_optional(),
  112. selector = ts.one_of{ts.string, ts.table}:is_optional(),
  113. symbol = ts.string:is_optional(),
  114. symbols_prefixes = ts.map_of(ts.string, ts.string):is_optional(),
  115. unknown = ts.boolean:is_optional(),
  116. url_compose_map = lua_maps.map_schema:is_optional(),
  117. urls = ts.boolean:is_optional(),
  118. whitelist = lua_maps.map_schema:is_optional(),
  119. whitelist_exception = (
  120. ts.array_of(ts.string) + (ts.string / function(s) return {s} end)
  121. ):is_optional(),
  122. checks = ts.array_of(ts.one_of(lua_util.keys(check_types))):is_optional(),
  123. }
  124. local function convert_checks(rule)
  125. local rspamd_logger = require "rspamd_logger"
  126. if rule.checks then
  127. local all_connfilter = true
  128. for _,check in ipairs(rule.checks) do
  129. local check_type = check_types[check]
  130. if check_type.require_argument then
  131. if not rule[check] then
  132. rspamd_logger.errx(rspamd_config, 'rbl rule %s has check %s which requires an argument',
  133. rule.symbol, check)
  134. return nil
  135. end
  136. end
  137. rule[check] = check_type
  138. if not check_type.connfilter then
  139. all_connfilter = false
  140. end
  141. if not check_type then
  142. rspamd_logger.errx(rspamd_config, 'rbl rule %s has invalid check type: %s',
  143. rule.symbol, check)
  144. return nil
  145. end
  146. end
  147. rule.connfilter = all_connfilter
  148. end
  149. -- Now check if we have any check enabled at all
  150. local check_found = false
  151. for k,_ in pairs(check_types) do
  152. if type(rule[k]) ~= 'nil' then
  153. check_found = true
  154. break
  155. end
  156. end
  157. if not check_found then
  158. -- Enable implicit `from` check to allow upgrade
  159. rspamd_logger.warnx(rspamd_config, 'rbl rule %s has no check enabled, enable default `from` check',
  160. rule.symbol)
  161. rule.from = true
  162. end
  163. return rule
  164. end
  165. -- Add default boolean flags to the schema
  166. for def_k,_ in pairs(default_options) do
  167. rule_schema_tbl[def_k:sub(#('default_') + 1)] = ts.boolean:is_optional()
  168. end
  169. return {
  170. check_types = check_types,
  171. rule_schema = ts.shape(rule_schema_tbl),
  172. default_options = default_options,
  173. convert_checks = convert_checks,
  174. }