Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

rspamd_config_transform.lua 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. --[[
  2. Copyright (c) 2017, 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 logger = require "rspamd_logger"
  14. local function override_defaults(def, override)
  15. if not override then
  16. return def
  17. end
  18. if not def then
  19. return override
  20. end
  21. for k,v in pairs(override) do
  22. if def[k] then
  23. if type(v) == 'table' then
  24. def[k] = override_defaults(def[k], v)
  25. else
  26. def[k] = v
  27. end
  28. else
  29. def[k] = v
  30. end
  31. end
  32. return def
  33. end
  34. local function is_implicit(t)
  35. local mt = getmetatable(t)
  36. return mt and mt.class and mt.class == 'ucl.type.impl_array'
  37. end
  38. local function metric_pairs(t)
  39. -- collect the keys
  40. local keys = {}
  41. local implicit_array = is_implicit(t)
  42. local function gen_keys(tbl)
  43. if implicit_array then
  44. for _,v in ipairs(tbl) do
  45. if v.name then
  46. table.insert(keys, {v.name, v})
  47. v.name = nil
  48. else
  49. -- Very tricky to distinguish:
  50. -- group {name = "foo" ... } + group "blah" { ... }
  51. for gr_name,gr in pairs(v) do
  52. if type(gr_name) ~= 'number' then
  53. -- We can also have implicit arrays here
  54. local gr_implicit = is_implicit(gr)
  55. if gr_implicit then
  56. for _,gr_elt in ipairs(gr) do
  57. table.insert(keys, {gr_name, gr_elt})
  58. end
  59. else
  60. table.insert(keys, {gr_name, gr})
  61. end
  62. end
  63. end
  64. end
  65. end
  66. else
  67. if tbl.name then
  68. table.insert(keys, {tbl.name, tbl})
  69. tbl.name = nil
  70. else
  71. for k,v in pairs(tbl) do
  72. if type(k) ~= 'number' then
  73. -- We can also have implicit arrays here
  74. local sym_implicit = is_implicit(v)
  75. if sym_implicit then
  76. for _,elt in ipairs(v) do
  77. table.insert(keys, {k, elt})
  78. end
  79. else
  80. table.insert(keys, {k, v})
  81. end
  82. end
  83. end
  84. end
  85. end
  86. end
  87. gen_keys(t)
  88. -- return the iterator function
  89. local i = 0
  90. return function()
  91. i = i + 1
  92. if keys[i] then
  93. return keys[i][1], keys[i][2]
  94. end
  95. end
  96. end
  97. local function group_transform(cfg, k, v)
  98. if v.name then k = v.name end
  99. local new_group = {
  100. symbols = {}
  101. }
  102. if v.enabled then new_group.enabled = v.enabled end
  103. if v.disabled then new_group.disabled = v.disabled end
  104. if v.max_score then new_group.max_score = v.max_score end
  105. if v.symbol then
  106. for sk,sv in metric_pairs(v.symbol) do
  107. if sv.name then
  108. sk = sv.name
  109. sv.name = nil -- Remove field
  110. end
  111. new_group.symbols[sk] = sv
  112. end
  113. end
  114. if not cfg.group then cfg.group = {} end
  115. if cfg.group[k] then
  116. cfg.group[k] = override_defaults(cfg.group[k], new_group)
  117. else
  118. cfg.group[k] = new_group
  119. end
  120. logger.infox("overriding group %s from the legacy metric settings", k)
  121. end
  122. local function symbol_transform(cfg, k, v)
  123. -- first try to find any group where there is a definition of this symbol
  124. for gr_n, gr in pairs(cfg.group) do
  125. if gr.symbols and gr.symbols[k] then
  126. -- We override group symbol with ungrouped symbol
  127. logger.infox("overriding group symbol %s in the group %s", k, gr_n)
  128. gr.symbols[k] = override_defaults(gr.symbols[k], v)
  129. return
  130. end
  131. end
  132. -- Otherwise we just use group 'ungrouped'
  133. if not cfg.group.ungrouped then
  134. cfg.group.ungrouped = {
  135. symbols = {}
  136. }
  137. end
  138. cfg.group.ungrouped.symbols[k] = v
  139. logger.infox("adding symbol %s to the group 'ungrouped'", k)
  140. end
  141. local function test_groups(groups)
  142. local all_symbols = {}
  143. for gr_name, gr in pairs(groups) do
  144. if not gr.symbols then
  145. local cnt = 0
  146. for _,_ in pairs(gr) do cnt = cnt + 1 end
  147. if cnt == 0 then
  148. logger.errx('group %s is empty', gr_name)
  149. else
  150. logger.infox('group %s has no symbols', gr_name)
  151. end
  152. else
  153. for sn,_ in pairs(gr.symbols) do
  154. if all_symbols[sn] then
  155. logger.errx('symbol %s has registered in multiple groups: %s and %s',
  156. sn, all_symbols[sn], gr_name)
  157. else
  158. all_symbols[sn] = gr_name
  159. end
  160. end
  161. end
  162. end
  163. end
  164. local function convert_metric(cfg, metric)
  165. if metric.actions then
  166. cfg.actions = override_defaults(cfg.actions, metric.actions)
  167. logger.infox("overriding actions from the legacy metric settings")
  168. end
  169. if metric.unknown_weight then
  170. cfg.actions.unknown_weight = metric.unknown_weight
  171. end
  172. if metric.subject then
  173. logger.infox("overriding subject from the legacy metric settings")
  174. cfg.actions.subject = metric.subject
  175. end
  176. if metric.group then
  177. for k, v in metric_pairs(metric.group) do
  178. group_transform(cfg, k, v)
  179. end
  180. else
  181. if not cfg.group then
  182. cfg.group = {
  183. ungrouped = {
  184. symbols = {}
  185. }
  186. }
  187. end
  188. end
  189. if metric.symbol then
  190. for k, v in metric_pairs(metric.symbol) do
  191. symbol_transform(cfg, k, v)
  192. end
  193. end
  194. return cfg
  195. end
  196. -- Converts a table of groups indexed by number (implicit array) to a
  197. -- merged group definition
  198. local function merge_groups(groups)
  199. local ret = {}
  200. for k,gr in pairs(groups) do
  201. if type(k) == 'number' then
  202. for key,sec in pairs(gr) do
  203. ret[key] = sec
  204. end
  205. else
  206. ret[k] = gr
  207. end
  208. end
  209. return ret
  210. end
  211. return function(cfg)
  212. local ret = false
  213. if cfg['metric'] then
  214. for _, v in metric_pairs(cfg.metric) do
  215. cfg = convert_metric(cfg, v)
  216. end
  217. ret = true
  218. end
  219. if not cfg.actions then
  220. logger.errx('no actions defined')
  221. else
  222. -- Perform sanity check for actions
  223. local actions_defs = {'greylist', 'add header', 'add_header',
  224. 'rewrite subject', 'rewrite_subject', 'reject'}
  225. if not cfg.actions['no action'] and not cfg.actions['no_action'] and
  226. not cfg.actions['accept'] then
  227. for _,d in ipairs(actions_defs) do
  228. if cfg.actions[d] then
  229. if cfg.actions[d] < 0 then
  230. cfg.actions['no action'] = cfg.actions[d] - 0.001
  231. logger.infox('set no action score to: %s, as action %s has negative score',
  232. cfg.actions['no action'], d)
  233. break
  234. end
  235. end
  236. end
  237. end
  238. end
  239. if not cfg.group then
  240. logger.errx('no symbol groups defined')
  241. else
  242. if cfg.group[1] then
  243. -- We need to merge groups
  244. cfg.group = merge_groups(cfg.group)
  245. ret = true
  246. end
  247. test_groups(cfg.group)
  248. end
  249. return ret, cfg
  250. end