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.

spf.lua 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. --[[[
  14. -- @module lua_ffi/spf
  15. -- This module contains ffi interfaces to SPF
  16. --]]
  17. local ffi = require 'ffi'
  18. ffi.cdef[[
  19. enum spf_mech_e {
  20. SPF_FAIL,
  21. SPF_SOFT_FAIL,
  22. SPF_PASS,
  23. SPF_NEUTRAL
  24. };
  25. static const unsigned RSPAMD_SPF_FLAG_IPV6 = (1 << 0);
  26. static const unsigned RSPAMD_SPF_FLAG_IPV4 = (1 << 1);
  27. static const unsigned RSPAMD_SPF_FLAG_ANY = (1 << 3);
  28. struct spf_addr {
  29. unsigned char addr6[16];
  30. unsigned char addr4[4];
  31. union {
  32. struct {
  33. uint16_t mask_v4;
  34. uint16_t mask_v6;
  35. } dual;
  36. uint32_t idx;
  37. } m;
  38. unsigned flags;
  39. enum spf_mech_e mech;
  40. char *spf_string;
  41. struct spf_addr *prev, *next;
  42. };
  43. struct spf_resolved {
  44. char *domain;
  45. unsigned ttl;
  46. int temp_failed;
  47. int na;
  48. int perm_failed;
  49. uint64_t digest;
  50. struct GArray *elts;
  51. struct ref_entry_s ref;
  52. };
  53. typedef void (*spf_cb_t)(struct spf_resolved *record,
  54. struct rspamd_task *task, void *data);
  55. struct rspamd_task;
  56. int rspamd_spf_resolve(struct rspamd_task *task, spf_cb_t callback,
  57. void *cbdata);
  58. const char * rspamd_spf_get_domain (struct rspamd_task *task);
  59. struct spf_resolved * spf_record_ref (struct spf_resolved *rec);
  60. void spf_record_unref (struct spf_resolved *rec);
  61. char * spf_addr_mask_to_string (struct spf_addr *addr);
  62. struct spf_addr * spf_addr_match_task (struct rspamd_task *task, struct spf_resolved *rec);
  63. ]]
  64. local function convert_mech(mech)
  65. if mech == ffi.C.SPF_FAIL then
  66. return 'fail'
  67. elseif mech == ffi.C.SPF_SOFT_FAIL then
  68. return 'softfail'
  69. elseif mech == ffi.C.SPF_PASS then
  70. return 'pass'
  71. elseif mech == ffi.C.SPF_NEUTRAL then
  72. return 'neutral'
  73. end
  74. end
  75. local NULL = ffi.new 'void*'
  76. local function spf_addr_tolua(ffi_spf_addr)
  77. local ipstr = ffi.C.spf_addr_mask_to_string(ffi_spf_addr)
  78. local ret = {
  79. res = convert_mech(ffi_spf_addr.mech),
  80. ipnet = ffi.string(ipstr),
  81. }
  82. if ffi_spf_addr.spf_string ~= NULL then
  83. ret.spf_str = ffi.string(ffi_spf_addr.spf_string)
  84. end
  85. ffi.C.g_free(ipstr)
  86. return ret
  87. end
  88. local function spf_resolve(task, cb)
  89. local function spf_cb(rec, _, _)
  90. if not rec then
  91. cb(false, 'record is empty')
  92. else
  93. local nelts = rec.elts.len
  94. local elts = ffi.cast("struct spf_addr *", rec.elts.data)
  95. local res = {
  96. addrs = {}
  97. }
  98. local digstr = ffi.new("char[64]")
  99. ffi.C.rspamd_snprintf(digstr, 64, "0x%xuL", rec.digest)
  100. res.digest = ffi.string(digstr)
  101. for i = 1,nelts do
  102. res.addrs[i] = spf_addr_tolua(elts[i - 1])
  103. end
  104. local matched = ffi.C.spf_addr_match_task(task:topointer(), rec)
  105. if matched ~= NULL then
  106. cb(true, res, spf_addr_tolua(matched))
  107. else
  108. cb(true, res, nil)
  109. end
  110. end
  111. end
  112. local ret = ffi.C.rspamd_spf_resolve(task:topointer(), spf_cb, nil)
  113. if not ret then
  114. cb(false, 'cannot perform resolving')
  115. end
  116. end
  117. local function spf_unref(rec)
  118. ffi.C.spf_record_unref(rec)
  119. end
  120. return {
  121. spf_resolve = spf_resolve,
  122. spf_unref = spf_unref
  123. }