Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. --[[
  2. Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com>
  3. Copyright (c) 2018, Carsten Rosenberg <c.rosenberg@heinlein-support.de>
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. ]]--
  14. --[[[
  15. -- @module razor
  16. -- This module contains razor access functions
  17. --]]
  18. local lua_util = require "lua_util"
  19. local tcp = require "rspamd_tcp"
  20. local upstream_list = require "rspamd_upstream_list"
  21. local rspamd_logger = require "rspamd_logger"
  22. local common = require "lua_scanners/common"
  23. local N = 'razor'
  24. local function razor_config(opts)
  25. local razor_conf = {
  26. name = N,
  27. default_port = 11342,
  28. timeout = 5.0,
  29. log_clean = false,
  30. retransmits = 2,
  31. cache_expire = 7200, -- expire redis in 2h
  32. message = '${SCANNER}: spam message found: "${VIRUS}"',
  33. detection_category = "hash",
  34. default_score = 1,
  35. action = false,
  36. dynamic_scan = false,
  37. symbol_fail = 'RAZOR_FAIL',
  38. symbol = 'RAZOR',
  39. }
  40. razor_conf = lua_util.override_defaults(razor_conf, opts)
  41. if not razor_conf.prefix then
  42. razor_conf.prefix = 'rs_' .. razor_conf.name .. '_'
  43. end
  44. if not razor_conf.log_prefix then
  45. razor_conf.log_prefix = razor_conf.name
  46. end
  47. if not razor_conf.servers and razor_conf.socket then
  48. razor_conf.servers = razor_conf.socket
  49. end
  50. if not razor_conf.servers then
  51. rspamd_logger.errx(rspamd_config, 'no servers defined')
  52. return nil
  53. end
  54. razor_conf.upstreams = upstream_list.create(rspamd_config,
  55. razor_conf.servers,
  56. razor_conf.default_port)
  57. if razor_conf.upstreams then
  58. lua_util.add_debug_alias('external_services', razor_conf.name)
  59. return razor_conf
  60. end
  61. rspamd_logger.errx(rspamd_config, 'cannot parse servers %s',
  62. razor_conf['servers'])
  63. return nil
  64. end
  65. local function razor_check(task, content, digest, rule)
  66. local function razor_check_uncached ()
  67. local upstream = rule.upstreams:get_upstream_round_robin()
  68. local addr = upstream:get_addr()
  69. local retransmits = rule.retransmits
  70. local function razor_callback(err, data, conn)
  71. local function razor_requery()
  72. -- retry with another upstream until retransmits exceeds
  73. if retransmits > 0 then
  74. retransmits = retransmits - 1
  75. lua_util.debugm(rule.name, task, '%s: Request Error: %s - retries left: %s',
  76. rule.log_prefix, err, retransmits)
  77. -- Select a different upstream!
  78. upstream = rule.upstreams:get_upstream_round_robin()
  79. addr = upstream:get_addr()
  80. lua_util.debugm(rule.name, task, '%s: retry IP: %s:%s',
  81. rule.log_prefix, addr, addr:get_port())
  82. tcp.request({
  83. task = task,
  84. host = addr:to_string(),
  85. port = addr:get_port(),
  86. upstream = upstream,
  87. timeout = rule.timeout or 2.0,
  88. shutdown = true,
  89. data = content,
  90. callback = razor_callback,
  91. })
  92. else
  93. rspamd_logger.errx(task, '%s: failed to scan, maximum retransmits ' ..
  94. 'exceed', rule.log_prefix)
  95. common.yield_result(task, rule, 'failed to scan and retransmits exceed', 0.0, 'fail')
  96. end
  97. end
  98. if err then
  99. razor_requery()
  100. else
  101. --[[
  102. @todo: Razorsocket currently only returns ham or spam. When the wrapper is fixed we should add dynamic scores here.
  103. Maybe check spamassassin implementation.
  104. This implementation is based on https://github.com/cgt/rspamd-plugins
  105. Thanks @cgt!
  106. ]] --
  107. local threat_string = tostring(data)
  108. if threat_string == "spam" then
  109. lua_util.debugm(N, task, '%s: returned result is spam', rule['symbol'], rule['type'])
  110. common.yield_result(task, rule, threat_string, rule.default_score)
  111. common.save_cache(task, digest, rule, threat_string, rule.default_score)
  112. elseif threat_string == "ham" then
  113. if rule.log_clean then
  114. rspamd_logger.infox(task, '%s: returned result is ham', rule['symbol'], rule['type'])
  115. else
  116. lua_util.debugm(N, task, '%s: returned result is ham', rule['symbol'], rule['type'])
  117. end
  118. common.save_cache(task, digest, rule, 'OK', rule.default_score)
  119. else
  120. rspamd_logger.errx(task, "%s - unknown response from razorfy: %s", addr:to_string(), threat_string)
  121. end
  122. end
  123. end
  124. tcp.request({
  125. task = task,
  126. host = addr:to_string(),
  127. port = addr:get_port(),
  128. upstream = upstream,
  129. timeout = rule.timeout or 2.0,
  130. shutdown = true,
  131. data = content,
  132. callback = razor_callback,
  133. })
  134. end
  135. if common.condition_check_and_continue(task, content, rule, digest, razor_check_uncached) then
  136. return
  137. else
  138. razor_check_uncached()
  139. end
  140. end
  141. return {
  142. type = { 'razor', 'spam', 'hash', 'scanner' },
  143. description = 'razor bulk scanner',
  144. configure = razor_config,
  145. check = razor_check,
  146. name = N
  147. }