Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

dns_tool.lua 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. --[[
  2. Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com>
  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 argparse = require "argparse"
  14. local rspamd_logger = require "rspamd_logger"
  15. local ansicolors = require "ansicolors"
  16. local bit = require "bit"
  17. local parser = argparse()
  18. :name "rspamadm dnstool"
  19. :description "DNS tools provided by Rspamd"
  20. :help_description_margin(30)
  21. :command_target("command")
  22. :require_command(true)
  23. parser:option "-c --config"
  24. :description "Path to config file"
  25. :argname("<cfg>")
  26. :default(rspamd_paths["CONFDIR"] .. "/" .. "rspamd.conf")
  27. local spf = parser:command "spf"
  28. :description "Extracts spf records"
  29. spf:mutex(
  30. spf:option "-d --domain"
  31. :description "Domain to use"
  32. :argname("<domain>"),
  33. spf:option "-f --from"
  34. :description "SMTP from to use"
  35. :argname("<from>")
  36. )
  37. spf:option "-i --ip"
  38. :description "Source IP address to use"
  39. :argname("<ip>")
  40. spf:flag "-a --all"
  41. :description "Print all records"
  42. local function printf(fmt, ...)
  43. if fmt then
  44. io.write(string.format(fmt, ...))
  45. end
  46. io.write('\n')
  47. end
  48. local function highlight(str)
  49. return ansicolors.white .. str .. ansicolors.reset
  50. end
  51. local function green(str)
  52. return ansicolors.green .. str .. ansicolors.reset
  53. end
  54. local function red(str)
  55. return ansicolors.red .. str .. ansicolors.reset
  56. end
  57. local function load_config(opts)
  58. local _r, err = rspamd_config:load_ucl(opts['config'])
  59. if not _r then
  60. rspamd_logger.errx('cannot parse %s: %s', opts['config'], err)
  61. os.exit(1)
  62. end
  63. _r, err = rspamd_config:parse_rcl({ 'logging', 'worker' })
  64. if not _r then
  65. rspamd_logger.errx('cannot process %s: %s', opts['config'], err)
  66. os.exit(1)
  67. end
  68. end
  69. local function spf_handler(opts)
  70. local rspamd_spf = require "rspamd_spf"
  71. local rspamd_task = require "rspamd_task"
  72. local rspamd_ip = require "rspamd_ip"
  73. local task = rspamd_task:create(rspamd_config, rspamadm_ev_base)
  74. task:set_session(rspamadm_session)
  75. task:set_resolver(rspamadm_dns_resolver)
  76. if opts.ip then
  77. opts.ip = rspamd_ip.fromstring(opts.ip)
  78. task:set_from_ip(opts.ip)
  79. else
  80. opts.all = true
  81. end
  82. if opts.from then
  83. local rspamd_parsers = require "rspamd_parsers"
  84. local addr_parsed = rspamd_parsers.parse_mail_address(opts.from)
  85. if addr_parsed then
  86. task:set_from('smtp', addr_parsed[1])
  87. else
  88. io.stderr:write('Invalid from addr\n')
  89. os.exit(1)
  90. end
  91. elseif opts.domain then
  92. task:set_from('smtp', { user = 'user', domain = opts.domain })
  93. else
  94. io.stderr:write('Neither domain nor from specified\n')
  95. os.exit(1)
  96. end
  97. local function flag_to_str(fl)
  98. if bit.band(fl, rspamd_spf.flags.temp_fail) ~= 0 then
  99. return "temporary failure"
  100. elseif bit.band(fl, rspamd_spf.flags.perm_fail) ~= 0 then
  101. return "permanent failure"
  102. elseif bit.band(fl, rspamd_spf.flags.na) ~= 0 then
  103. return "no spf record"
  104. end
  105. return "unknown flag: " .. tostring(fl)
  106. end
  107. local function display_spf_results(elt, colored)
  108. local dec = function(e)
  109. return e
  110. end
  111. local policy_decode = function(e)
  112. if e == rspamd_spf.policy.fail then
  113. return 'reject'
  114. elseif e == rspamd_spf.policy.pass then
  115. return 'pass'
  116. elseif e == rspamd_spf.policy.soft_fail then
  117. return 'soft fail'
  118. elseif e == rspamd_spf.policy.neutral then
  119. return 'neutral'
  120. end
  121. return 'unknown'
  122. end
  123. if colored then
  124. dec = function(e)
  125. return highlight(e)
  126. end
  127. if elt.result == rspamd_spf.policy.pass then
  128. dec = function(e)
  129. return green(e)
  130. end
  131. elseif elt.result == rspamd_spf.policy.fail then
  132. dec = function(e)
  133. return red(e)
  134. end
  135. end
  136. end
  137. printf('%s: %s', highlight('Policy'), dec(policy_decode(elt.result)))
  138. printf('%s: %s', highlight('Network'), dec(elt.addr))
  139. if elt.str then
  140. printf('%s: %s', highlight('Original'), elt.str)
  141. end
  142. end
  143. local function cb(record, flags, err)
  144. if record then
  145. local result, flag_or_policy, error_or_addr
  146. if opts.ip then
  147. result, flag_or_policy, error_or_addr = record:check_ip(opts.ip)
  148. elseif opts.all then
  149. result = true
  150. end
  151. if opts.ip and not opts.all then
  152. if result then
  153. display_spf_results(error_or_addr, true)
  154. else
  155. printf('Not matched: %s', error_or_addr)
  156. end
  157. os.exit(0)
  158. end
  159. if result then
  160. printf('SPF record for %s; digest: %s',
  161. highlight(opts.domain or opts.from), highlight(record:get_digest()))
  162. for _, elt in ipairs(record:get_elts()) do
  163. if result and error_or_addr and elt.str and elt.str == error_or_addr.str then
  164. printf("%s", highlight('*** Matched ***'))
  165. display_spf_results(elt, true)
  166. printf('------')
  167. else
  168. display_spf_results(elt, false)
  169. printf('------')
  170. end
  171. end
  172. else
  173. printf('Error getting SPF record: %s (%s flag)', err,
  174. flag_to_str(flag_or_policy or flags))
  175. end
  176. else
  177. printf('Cannot get SPF record: %s', err)
  178. end
  179. end
  180. rspamd_spf.resolve(task, cb)
  181. end
  182. local function handler(args)
  183. local opts = parser:parse(args)
  184. load_config(opts)
  185. local command = opts.command
  186. if command == 'spf' then
  187. spf_handler(opts)
  188. else
  189. parser:error('command %s is not implemented', command)
  190. end
  191. end
  192. return {
  193. name = 'dnstool',
  194. aliases = { 'dns', 'dns_tool' },
  195. handler = handler,
  196. description = parser._description
  197. }