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.

dns_tool.lua 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. --[[
  2. Copyright (c) 2019, 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 argparse = require "argparse"
  14. local rspamd_logger = require "rspamd_logger"
  15. local lua_util = require "lua_util"
  16. local ansicolors = require "ansicolors"
  17. local parser = argparse()
  18. :name "rspamadm dns_tool"
  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. parser: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 lua_spf = require("lua_ffi").spf
  71. local rspamd_task = require "rspamd_task"
  72. local task = rspamd_task:create(rspamd_config, rspamadm_ev_base)
  73. task:set_session(rspamadm_session)
  74. task:set_resolver(rspamadm_dns_resolver)
  75. if opts.ip then
  76. task:set_from_ip(opts.ip)
  77. end
  78. if opts.from then
  79. task:set_from('smtp', {addr = opts.from})
  80. elseif opts.domain then
  81. task:set_from('smtp', {user = 'user', domain = opts.domain})
  82. else
  83. io.stderr:write('Neither domain nor from specified\n')
  84. os.exit(1)
  85. end
  86. local function display_spf_results(elt, colored)
  87. local dec = function(e) return e end
  88. if colored then
  89. dec = function(e) return highlight(e) end
  90. if elt.res == 'pass' then
  91. dec = function(e) return green(e) end
  92. elseif elt.res == 'fail' then
  93. dec = function(e) return red(e) end
  94. end
  95. end
  96. printf('%s: %s', highlight('Result'), dec(elt.res))
  97. printf('%s: %s', highlight('Network'), dec(elt.ipnet))
  98. if elt.spf_str then
  99. printf('%s: %s', highlight('Original'), elt.spf_str)
  100. end
  101. end
  102. local function cb(success, res, matched)
  103. if success then
  104. if opts.ip and not opts.all then
  105. if matched then
  106. display_spf_results(matched, true)
  107. else
  108. printf('Not matched')
  109. end
  110. os.exit(0)
  111. end
  112. printf('SPF record for %s; digest: %s',
  113. highlight(opts.domain or opts.from), highlight(res.digest))
  114. for _,elt in ipairs(res.addrs) do
  115. if lua_util.table_cmp(elt, matched) then
  116. printf("%s", highlight('*** Matched ***'))
  117. display_spf_results(elt, true)
  118. printf('------')
  119. else
  120. display_spf_results(elt, false)
  121. printf('------')
  122. end
  123. end
  124. else
  125. printf('Cannot get SPF record: %s', res)
  126. end
  127. end
  128. lua_spf.spf_resolve(task, cb)
  129. end
  130. local function handler(args)
  131. local opts = parser:parse(args)
  132. load_config(opts)
  133. local command = opts.command
  134. if command == 'spf' then
  135. spf_handler(opts)
  136. else
  137. parser:error('command %s is not implemented', command)
  138. end
  139. end
  140. return {
  141. name = 'dnstool',
  142. aliases = {'dns', 'dns_tool'},
  143. handler = handler,
  144. description = parser._description
  145. }