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.c 41KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  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. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "dns.h"
  18. #include "spf.h"
  19. #include "rspamd.h"
  20. #include "message.h"
  21. #include "filter.h"
  22. #include "utlist.h"
  23. #define SPF_VER1_STR "v=spf1"
  24. #define SPF_VER2_STR "spf2."
  25. #define SPF_SCOPE_PRA "pra"
  26. #define SPF_SCOPE_MFROM "mfrom"
  27. #define SPF_ALL "all"
  28. #define SPF_A "a"
  29. #define SPF_IP4 "ip4"
  30. #define SPF_IP6 "ip6"
  31. #define SPF_PTR "ptr"
  32. #define SPF_MX "mx"
  33. #define SPF_EXISTS "exists"
  34. #define SPF_INCLUDE "include"
  35. #define SPF_REDIRECT "redirect"
  36. #define SPF_EXP "exp"
  37. /** SPF limits for avoiding abuse **/
  38. #define SPF_MAX_NESTING 10
  39. #define SPF_MAX_DNS_REQUESTS 30
  40. struct spf_resolved_element {
  41. GPtrArray *elts;
  42. gchar *cur_domain;
  43. gboolean redirected; /* Ingnore level, it's redirected */
  44. };
  45. struct spf_record {
  46. gint nested;
  47. gint dns_requests;
  48. gint requests_inflight;
  49. guint ttl;
  50. GPtrArray *resolved;
  51. /* Array of struct spf_resolved_element */
  52. const gchar *sender;
  53. const gchar *sender_domain;
  54. gchar *local_part;
  55. struct rspamd_task *task;
  56. spf_cb_t callback;
  57. gboolean done;
  58. };
  59. /**
  60. * BNF for SPF record:
  61. *
  62. * spf_mech ::= +|-|~|?
  63. *
  64. * spf_body ::= spf=v1 <spf_command> [<spf_command>]
  65. * spf_command ::= [spf_mech]all|a|<ip4>|<ip6>|ptr|mx|<exists>|<include>|<redirect>
  66. *
  67. * spf_domain ::= [:domain][/mask]
  68. * spf_ip4 ::= ip[/mask]
  69. * ip4 ::= ip4:<spf_ip4>
  70. * mx ::= mx<spf_domain>
  71. * a ::= a<spf_domain>
  72. * ptr ::= ptr[:domain]
  73. * exists ::= exists:domain
  74. * include ::= include:domain
  75. * redirect ::= redirect:domain
  76. * exp ::= exp:domain
  77. *
  78. */
  79. #undef SPF_DEBUG
  80. #define msg_err_spf(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
  81. "spf", rec->task->task_pool->tag.uid, \
  82. G_STRFUNC, \
  83. __VA_ARGS__)
  84. #define msg_warn_spf(...) rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
  85. "spf", rec->task->task_pool->tag.uid, \
  86. G_STRFUNC, \
  87. __VA_ARGS__)
  88. #define msg_info_spf(...) rspamd_default_log_function (G_LOG_LEVEL_INFO, \
  89. "spf", rec->task->task_pool->tag.uid, \
  90. G_STRFUNC, \
  91. __VA_ARGS__)
  92. #define msg_debug_spf(...) rspamd_default_log_function (G_LOG_LEVEL_DEBUG, \
  93. "spf", rec->task->task_pool->tag.uid, \
  94. G_STRFUNC, \
  95. __VA_ARGS__)
  96. struct spf_dns_cb {
  97. struct spf_record *rec;
  98. struct spf_addr *addr;
  99. struct spf_resolved_element *resolved;
  100. gchar *ptr_host;
  101. spf_action_t cur_action;
  102. gboolean in_include;
  103. };
  104. #define CHECK_REC(rec) \
  105. do { \
  106. if ((rec)->nested > SPF_MAX_NESTING || \
  107. (rec)->dns_requests > SPF_MAX_DNS_REQUESTS) { \
  108. msg_info_spf ("<%s> spf recursion limit %d is reached, domain: %s", \
  109. (rec)->task->message_id, (rec)->dns_requests, \
  110. (rec)->sender_domain); \
  111. return FALSE; \
  112. } \
  113. } while (0) \
  114. static gboolean start_spf_parse (struct spf_record *rec,
  115. struct spf_resolved_element *resolved, gchar *begin);
  116. /* Determine spf mech */
  117. static spf_mech_t
  118. check_spf_mech (const gchar *elt, gboolean *need_shift)
  119. {
  120. g_assert (elt != NULL);
  121. *need_shift = TRUE;
  122. switch (*elt) {
  123. case '-':
  124. return SPF_FAIL;
  125. case '~':
  126. return SPF_SOFT_FAIL;
  127. case '+':
  128. return SPF_PASS;
  129. case '?':
  130. return SPF_NEUTRAL;
  131. default:
  132. *need_shift = FALSE;
  133. return SPF_PASS;
  134. }
  135. }
  136. static struct spf_addr *
  137. rspamd_spf_new_addr (struct spf_record *rec,
  138. struct spf_resolved_element *resolved, const gchar *elt)
  139. {
  140. gboolean need_shift = FALSE;
  141. struct spf_addr *naddr;
  142. naddr = g_slice_alloc0 (sizeof (*naddr));
  143. naddr->mech = check_spf_mech (elt, &need_shift);
  144. if (need_shift) {
  145. naddr->spf_string = g_strdup (elt + 1);
  146. }
  147. else {
  148. naddr->spf_string = g_strdup (elt);
  149. }
  150. g_ptr_array_add (resolved->elts, naddr);
  151. naddr->prev = naddr;
  152. naddr->next = NULL;
  153. return naddr;
  154. }
  155. static void
  156. rspamd_spf_free_addr (gpointer a)
  157. {
  158. struct spf_addr *addr = a, *tmp, *cur;
  159. if (addr) {
  160. g_free (addr->spf_string);
  161. DL_FOREACH_SAFE (addr, cur, tmp) {
  162. g_slice_free1 (sizeof (*cur), cur);
  163. }
  164. }
  165. }
  166. static struct spf_resolved_element *
  167. rspamd_spf_new_addr_list (struct spf_record *rec, const gchar *domain)
  168. {
  169. struct spf_resolved_element *resolved;
  170. resolved = g_slice_alloc (sizeof (*resolved));
  171. resolved->redirected = FALSE;
  172. resolved->cur_domain = g_strdup (domain);
  173. resolved->elts = g_ptr_array_new_full (8, rspamd_spf_free_addr);
  174. g_ptr_array_add (rec->resolved, resolved);
  175. return g_ptr_array_index (rec->resolved, rec->resolved->len - 1);
  176. }
  177. /*
  178. * Destructor for spf record
  179. */
  180. static void
  181. spf_record_destructor (gpointer r)
  182. {
  183. struct spf_record *rec = r;
  184. struct spf_resolved_element *elt;
  185. guint i;
  186. if (rec) {
  187. for (i = 0; i < rec->resolved->len; i++) {
  188. elt = g_ptr_array_index (rec->resolved, i);
  189. g_ptr_array_free (elt->elts, TRUE);
  190. g_free (elt->cur_domain);
  191. g_slice_free1 (sizeof (*elt), elt);
  192. }
  193. g_ptr_array_free (rec->resolved, TRUE);
  194. }
  195. }
  196. static void
  197. rspamd_flatten_record_dtor (struct spf_resolved *r)
  198. {
  199. struct spf_addr *addr;
  200. guint i;
  201. for (i = 0; i < r->elts->len; i++) {
  202. addr = &g_array_index (r->elts, struct spf_addr, i);
  203. g_free (addr->spf_string);
  204. }
  205. g_free (r->domain);
  206. g_array_free (r->elts, TRUE);
  207. g_slice_free1 (sizeof (*r), r);
  208. }
  209. static void
  210. rspamd_spf_process_reference (struct spf_resolved *target,
  211. struct spf_addr *addr, struct spf_record *rec, gboolean top)
  212. {
  213. struct spf_resolved_element *elt, *relt;
  214. struct spf_addr *cur = NULL, taddr, *cur_addr;
  215. guint i;
  216. if (addr) {
  217. g_assert (addr->m.idx < rec->resolved->len);
  218. elt = g_ptr_array_index (rec->resolved, addr->m.idx);
  219. }
  220. else {
  221. elt = g_ptr_array_index (rec->resolved, 0);
  222. }
  223. if (rec->ttl < target->ttl) {
  224. msg_debug_spf ("reducing ttl from %d to %d after subrecord processing %s",
  225. target->ttl, rec->ttl, rec->sender_domain);
  226. target->ttl = rec->ttl;
  227. }
  228. if (elt->redirected) {
  229. g_assert (elt->elts->len > 0);
  230. for (i = 0; i < elt->elts->len; i++) {
  231. cur = g_ptr_array_index (elt->elts, i);
  232. if (cur->flags & RSPAMD_SPF_FLAG_REDIRECT) {
  233. break;
  234. }
  235. }
  236. g_assert (cur != NULL);
  237. if (!(cur->flags & RSPAMD_SPF_FLAG_PARSED)) {
  238. /* Unresolved redirect */
  239. msg_info_spf ("redirect to %s cannot be resolved", cur->spf_string);
  240. return;
  241. }
  242. g_assert (cur->flags & RSPAMD_SPF_FLAG_REFRENCE);
  243. g_assert (cur->m.idx < rec->resolved->len);
  244. relt = g_ptr_array_index (rec->resolved, cur->m.idx);
  245. msg_debug_spf ("domain %s is redirected to %s", elt->cur_domain,
  246. relt->cur_domain);
  247. }
  248. for (i = 0; i < elt->elts->len; i++) {
  249. cur = g_ptr_array_index (elt->elts, i);
  250. if (cur->flags & RSPAMD_SPF_FLAG_TEMPFAIL) {
  251. target->failed = TRUE;
  252. continue;
  253. }
  254. else if (!(cur->flags & RSPAMD_SPF_FLAG_PARSED)) {
  255. /* Ignore unparsed addrs */
  256. continue;
  257. }
  258. else if (cur->flags & RSPAMD_SPF_FLAG_REFRENCE) {
  259. /* Process reference */
  260. rspamd_spf_process_reference (target, cur, rec, FALSE);
  261. if (cur->flags & RSPAMD_SPF_FLAG_REDIRECT) {
  262. /* Stop on redirected domain */
  263. break;
  264. }
  265. }
  266. else {
  267. if ((cur->flags & RSPAMD_SPF_FLAG_ANY) && !top) {
  268. /* Ignore wide policies in includes */
  269. continue;
  270. }
  271. DL_FOREACH (cur, cur_addr) {
  272. memcpy (&taddr, cur_addr, sizeof (taddr));
  273. taddr.spf_string = g_strdup (cur_addr->spf_string);
  274. g_array_append_val (target->elts, taddr);
  275. }
  276. }
  277. }
  278. }
  279. /*
  280. * Parse record and flatten it to a simple structure
  281. */
  282. static struct spf_resolved *
  283. rspamd_spf_record_flatten (struct spf_record *rec)
  284. {
  285. struct spf_resolved *res;
  286. g_assert (rec != NULL);
  287. res = g_slice_alloc0 (sizeof (*res));
  288. res->elts = g_array_sized_new (FALSE, FALSE, sizeof (struct spf_addr),
  289. rec->resolved->len);
  290. res->domain = g_strdup (rec->sender_domain);
  291. res->ttl = rec->ttl;
  292. REF_INIT_RETAIN (res, rspamd_flatten_record_dtor);
  293. if (rec->resolved->len > 0) {
  294. rspamd_spf_process_reference (res, NULL, rec, TRUE);
  295. }
  296. return res;
  297. }
  298. static void
  299. rspamd_spf_maybe_return (struct spf_record *rec)
  300. {
  301. struct spf_resolved *flat;
  302. if (rec->requests_inflight == 0 && !rec->done) {
  303. flat = rspamd_spf_record_flatten (rec);
  304. rec->callback (flat, rec->task);
  305. REF_RELEASE (flat);
  306. rec->done = TRUE;
  307. }
  308. }
  309. static gboolean
  310. spf_check_ptr_host (struct spf_dns_cb *cb, const char *name)
  311. {
  312. const char *dend, *nend, *dstart, *nstart;
  313. struct spf_record *rec = cb->rec;
  314. if (name == NULL) {
  315. return FALSE;
  316. }
  317. if (cb->ptr_host != NULL) {
  318. dstart = cb->ptr_host;
  319. }
  320. else {
  321. dstart = cb->resolved->cur_domain;
  322. }
  323. msg_debug_spf ("check ptr %s vs %s", name, dstart);
  324. /* We need to check whether `cur_domain` is a subdomain for `name` */
  325. dend = dstart + strlen (dstart) - 1;
  326. nstart = name;
  327. nend = nstart + strlen (nstart) - 1;
  328. if (nend == nstart || dend == dstart) {
  329. return FALSE;
  330. }
  331. /* Strip last '.' from names */
  332. if (*nend == '.') {
  333. nend--;
  334. }
  335. if (*dend == '.') {
  336. dend--;
  337. }
  338. /* Now compare from end to start */
  339. for (;;) {
  340. if (g_ascii_tolower (*dend) != g_ascii_tolower (*nend)) {
  341. msg_debug_spf ("ptr records mismatch: %s and %s", dend, nend);
  342. return FALSE;
  343. }
  344. if (dend == dstart) {
  345. break;
  346. }
  347. if (nend == nstart) {
  348. /* Name is shorter than cur_domain */
  349. return FALSE;
  350. }
  351. nend--;
  352. dend--;
  353. }
  354. if (nend != nstart && *(nend - 1) != '.') {
  355. /* Not a subdomain */
  356. return FALSE;
  357. }
  358. return TRUE;
  359. }
  360. static void
  361. spf_record_process_addr (struct spf_record *rec, struct spf_addr *addr, struct
  362. rdns_reply_entry *reply)
  363. {
  364. struct spf_addr *naddr;
  365. if (!(addr->flags & RSPAMD_SPF_FLAG_PROCESSED)) {
  366. /* That's the first address */
  367. if (reply->type == RDNS_REQUEST_AAAA) {
  368. memcpy (addr->addr6,
  369. &reply->content.aaa.addr,
  370. sizeof (addr->addr6));
  371. addr->flags |= RSPAMD_SPF_FLAG_IPV6;
  372. }
  373. else if (reply->type == RDNS_REQUEST_A) {
  374. memcpy (addr->addr4, &reply->content.a.addr, sizeof (addr->addr4));
  375. addr->flags |= RSPAMD_SPF_FLAG_IPV4;
  376. }
  377. else {
  378. msg_err_spf (
  379. "internal error, bad DNS reply is treated as address: %s",
  380. rdns_strtype (reply->type));
  381. }
  382. addr->flags |= RSPAMD_SPF_FLAG_PROCESSED;
  383. }
  384. else {
  385. /* We need to create a new address */
  386. naddr = g_slice_alloc0 (sizeof (*naddr));
  387. memcpy (naddr, addr, sizeof (*naddr));
  388. naddr->next = NULL;
  389. naddr->prev = NULL;
  390. if (reply->type == RDNS_REQUEST_AAAA) {
  391. memcpy (naddr->addr6,
  392. &reply->content.aaa.addr,
  393. sizeof (addr->addr6));
  394. naddr->flags |= RSPAMD_SPF_FLAG_IPV6;
  395. }
  396. else if (reply->type == RDNS_REQUEST_A) {
  397. memcpy (naddr->addr4, &reply->content.a.addr, sizeof (addr->addr4));
  398. naddr->flags |= RSPAMD_SPF_FLAG_IPV4;
  399. }
  400. else {
  401. msg_err_spf (
  402. "internal error, bad DNS reply is treated as address: %s",
  403. rdns_strtype (reply->type));
  404. }
  405. DL_APPEND (addr, naddr);
  406. }
  407. }
  408. static void
  409. spf_record_addr_set (struct spf_addr *addr, gboolean allow_any)
  410. {
  411. guchar fill;
  412. if (!(addr->flags & RSPAMD_SPF_FLAG_PROCESSED)) {
  413. if (allow_any) {
  414. fill = 0;
  415. addr->m.dual.mask_v4 = 0;
  416. addr->m.dual.mask_v6 = 0;
  417. }
  418. else {
  419. fill = 0xff;
  420. }
  421. memset (addr->addr4, fill, sizeof (addr->addr4));
  422. memset (addr->addr6, fill, sizeof (addr->addr6));
  423. addr->flags |= RSPAMD_SPF_FLAG_IPV4;
  424. addr->flags |= RSPAMD_SPF_FLAG_IPV6;
  425. }
  426. }
  427. static gboolean
  428. spf_process_txt_record (struct spf_record *rec, struct spf_resolved_element *resolved,
  429. struct rdns_reply *reply)
  430. {
  431. struct rdns_reply_entry *elt, *selected = NULL;
  432. gboolean ret = FALSE;
  433. /*
  434. * We prefer spf version 1 as other records are mostly likely garbadge
  435. * or incorrect records (e.g. spf2 records)
  436. */
  437. LL_FOREACH (reply->entries, elt) {
  438. if (strncmp (elt->content.txt.data, "v=spf1", sizeof ("v=spf1") - 1)
  439. == 0) {
  440. selected = elt;
  441. break;
  442. }
  443. }
  444. if (!selected) {
  445. LL_FOREACH (reply->entries, elt) {
  446. if (start_spf_parse (rec, resolved, elt->content.txt.data)) {
  447. ret = TRUE;
  448. break;
  449. }
  450. }
  451. }
  452. else {
  453. ret = start_spf_parse (rec, resolved, selected->content.txt.data);
  454. }
  455. return ret;
  456. }
  457. static void
  458. spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
  459. {
  460. struct spf_dns_cb *cb = arg;
  461. struct rdns_reply_entry *elt_data;
  462. struct rspamd_task *task;
  463. struct spf_addr *addr;
  464. struct spf_record *rec;
  465. rec = cb->rec;
  466. task = rec->task;
  467. cb->rec->requests_inflight--;
  468. addr = cb->addr;
  469. if (reply->code == RDNS_RC_NOERROR) {
  470. LL_FOREACH (reply->entries, elt_data) {
  471. /* Adjust ttl if a resolved record has lower ttl than spf record itself */
  472. if ((guint)elt_data->ttl < rec->ttl) {
  473. msg_debug_spf ("reducing ttl from %d to %d after DNS resolving",
  474. rec->ttl, elt_data->ttl);
  475. rec->ttl = elt_data->ttl;
  476. }
  477. switch (cb->cur_action) {
  478. case SPF_RESOLVE_MX:
  479. if (elt_data->type == RDNS_REQUEST_MX) {
  480. /* Now resolve A record for this MX */
  481. msg_debug_spf ("resolve %s after resolving of MX",
  482. elt_data->content.mx.name);
  483. if (make_dns_request_task (task,
  484. spf_record_dns_callback, (void *) cb,
  485. RDNS_REQUEST_A,
  486. elt_data->content.mx.name)) {
  487. cb->rec->requests_inflight++;
  488. }
  489. if (make_dns_request_task (task,
  490. spf_record_dns_callback, (void *) cb,
  491. RDNS_REQUEST_AAAA,
  492. elt_data->content.mx.name)) {
  493. cb->rec->requests_inflight++;
  494. }
  495. }
  496. else {
  497. spf_record_process_addr (rec, addr, elt_data);
  498. }
  499. break;
  500. case SPF_RESOLVE_A:
  501. case SPF_RESOLVE_AAA:
  502. spf_record_process_addr (rec, addr, elt_data);
  503. break;
  504. case SPF_RESOLVE_PTR:
  505. if (elt_data->type == RDNS_REQUEST_PTR) {
  506. /* Validate returned records prior to making A requests */
  507. if (spf_check_ptr_host (cb,
  508. elt_data->content.ptr.name)) {
  509. msg_debug_spf ("resolve %s after resolving of PTR",
  510. elt_data->content.ptr.name);
  511. if (make_dns_request_task (task,
  512. spf_record_dns_callback, (void *) cb,
  513. RDNS_REQUEST_A,
  514. elt_data->content.ptr.name)) {
  515. cb->rec->requests_inflight++;
  516. }
  517. if (make_dns_request_task (task,
  518. spf_record_dns_callback, (void *) cb,
  519. RDNS_REQUEST_AAAA,
  520. elt_data->content.ptr.name)) {
  521. cb->rec->requests_inflight++;
  522. }
  523. }
  524. }
  525. else {
  526. spf_record_process_addr (rec, addr, elt_data);
  527. }
  528. break;
  529. case SPF_RESOLVE_REDIRECT:
  530. if (elt_data->type == RDNS_REQUEST_TXT) {
  531. if (spf_process_txt_record (rec, cb->resolved, reply)) {
  532. cb->addr->flags |= RSPAMD_SPF_FLAG_PARSED;
  533. }
  534. else {
  535. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PARSED;
  536. }
  537. }
  538. break;
  539. case SPF_RESOLVE_INCLUDE:
  540. if (elt_data->type == RDNS_REQUEST_TXT) {
  541. if (spf_process_txt_record (rec, cb->resolved, reply)) {
  542. cb->addr->flags |= RSPAMD_SPF_FLAG_PARSED;
  543. }
  544. else {
  545. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PARSED;
  546. }
  547. }
  548. break;
  549. case SPF_RESOLVE_EXP:
  550. break;
  551. case SPF_RESOLVE_EXISTS:
  552. if (elt_data->type == RDNS_REQUEST_A ||
  553. elt_data->type == RDNS_REQUEST_AAAA) {
  554. /* If specified address resolves, we can accept connection from every IP */
  555. spf_record_addr_set (addr, TRUE);
  556. }
  557. break;
  558. }
  559. }
  560. }
  561. else if (reply->code == RDNS_RC_NXDOMAIN || reply->code == RDNS_RC_NOREC) {
  562. switch (cb->cur_action) {
  563. case SPF_RESOLVE_MX:
  564. if (rdns_request_has_type (reply->request, RDNS_REQUEST_MX)) {
  565. msg_debug_spf (
  566. "<%s>: spf error for domain %s: cannot find MX record for %s",
  567. task->message_id,
  568. cb->rec->sender_domain,
  569. cb->resolved->cur_domain);
  570. spf_record_addr_set (addr, FALSE);
  571. }
  572. else {
  573. msg_debug_spf (
  574. "<%s>: spf error for domain %s: cannot resolve MX record for %s",
  575. task->message_id,
  576. cb->rec->sender_domain,
  577. cb->resolved->cur_domain);
  578. spf_record_addr_set (addr, FALSE);
  579. }
  580. break;
  581. case SPF_RESOLVE_A:
  582. if (rdns_request_has_type (reply->request, RDNS_REQUEST_A)) {
  583. spf_record_addr_set (addr, FALSE);
  584. }
  585. break;
  586. case SPF_RESOLVE_AAA:
  587. if (rdns_request_has_type (reply->request, RDNS_REQUEST_AAAA)) {
  588. spf_record_addr_set (addr, FALSE);
  589. }
  590. break;
  591. case SPF_RESOLVE_PTR:
  592. spf_record_addr_set (addr, FALSE);
  593. break;
  594. case SPF_RESOLVE_REDIRECT:
  595. msg_debug_spf (
  596. "<%s>: spf error for domain %s: cannot resolve TXT record for %s",
  597. task->message_id,
  598. cb->rec->sender_domain,
  599. cb->resolved->cur_domain);
  600. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PARSED;
  601. break;
  602. case SPF_RESOLVE_INCLUDE:
  603. msg_debug_spf (
  604. "<%s>: spf error for domain %s: cannot resolve TXT record for %s",
  605. task->message_id,
  606. cb->rec->sender_domain,
  607. cb->resolved->cur_domain);
  608. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PARSED;
  609. break;
  610. case SPF_RESOLVE_EXP:
  611. break;
  612. case SPF_RESOLVE_EXISTS:
  613. spf_record_addr_set (addr, FALSE);
  614. break;
  615. }
  616. }
  617. else if ((cb->cur_action == SPF_RESOLVE_INCLUDE ||
  618. cb->cur_action == SPF_RESOLVE_REDIRECT) ||
  619. reply->code == RDNS_RC_TIMEOUT) {
  620. cb->addr->flags |= RSPAMD_SPF_FLAG_TEMPFAIL;
  621. msg_info_spf (
  622. "<%s>: spf error for domain %s: cannot resolve DNS record for"
  623. " %s: %s",
  624. task->message_id,
  625. cb->rec->sender_domain,
  626. cb->resolved->cur_domain,
  627. rdns_strerror (reply->code));
  628. }
  629. rspamd_spf_maybe_return (cb->rec);
  630. }
  631. /*
  632. * The syntax defined by the following BNF:
  633. * [ ":" domain-spec ] [ dual-cidr-length ]
  634. * ip4-cidr-length = "/" 1*DIGIT
  635. * ip6-cidr-length = "/" 1*DIGIT
  636. * dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
  637. */
  638. static const gchar *
  639. parse_spf_domain_mask (struct spf_record *rec, struct spf_addr *addr,
  640. struct spf_resolved_element *resolved,
  641. gboolean allow_mask)
  642. {
  643. struct rspamd_task *task = rec->task;
  644. enum {
  645. parse_spf_elt = 0,
  646. parse_semicolon,
  647. parse_domain,
  648. parse_slash,
  649. parse_ipv4_mask,
  650. parse_second_slash,
  651. parse_ipv6_mask,
  652. skip_garbadge
  653. } state = 0;
  654. const gchar *p = addr->spf_string, *host, *c;
  655. gchar *hostbuf;
  656. gchar t;
  657. guint16 cur_mask = 0;
  658. host = resolved->cur_domain;
  659. c = p;
  660. while (*p) {
  661. t = *p;
  662. switch (state) {
  663. case parse_spf_elt:
  664. if (t == ':') {
  665. state = parse_semicolon;
  666. }
  667. else if (t == '/') {
  668. /* No domain but mask */
  669. state = parse_slash;
  670. }
  671. p++;
  672. break;
  673. case parse_semicolon:
  674. if (t == '/') {
  675. /* Empty domain, technically an error */
  676. state = parse_slash;
  677. }
  678. c = p;
  679. state = parse_domain;
  680. break;
  681. case parse_domain:
  682. if (t == '/') {
  683. hostbuf = rspamd_mempool_alloc (task->task_pool, p - c + 1);
  684. rspamd_strlcpy (hostbuf, c, p - c + 1);
  685. host = hostbuf;
  686. state = parse_slash;
  687. }
  688. p++;
  689. break;
  690. case parse_slash:
  691. c = p;
  692. if (allow_mask) {
  693. state = parse_ipv4_mask;
  694. }
  695. else {
  696. state = skip_garbadge;
  697. }
  698. cur_mask = 0;
  699. break;
  700. case parse_ipv4_mask:
  701. if (g_ascii_isdigit (t)) {
  702. /* Ignore errors here */
  703. cur_mask = cur_mask * 10 + (t - '0');
  704. }
  705. else if (t == '/') {
  706. if (cur_mask <= 32) {
  707. addr->m.dual.mask_v4 = cur_mask;
  708. }
  709. else {
  710. msg_info_spf ("bad ipv4 mask: %d", cur_mask);
  711. }
  712. state = parse_second_slash;
  713. }
  714. p++;
  715. break;
  716. case parse_second_slash:
  717. c = p;
  718. state = parse_ipv6_mask;
  719. cur_mask = 0;
  720. break;
  721. case parse_ipv6_mask:
  722. if (g_ascii_isdigit (t)) {
  723. /* Ignore errors here */
  724. cur_mask = cur_mask * 10 + (t - '0');
  725. }
  726. p++;
  727. break;
  728. case skip_garbadge:
  729. p++;
  730. break;
  731. }
  732. }
  733. /* Process end states */
  734. if (state == parse_ipv4_mask) {
  735. if (cur_mask <= 32) {
  736. addr->m.dual.mask_v4 = cur_mask;
  737. }
  738. else {
  739. msg_info_spf ("bad ipv4 mask: %d", cur_mask);
  740. }
  741. }
  742. else if (state == parse_ipv6_mask) {
  743. if (cur_mask <= 128) {
  744. addr->m.dual.mask_v6 = cur_mask;
  745. }
  746. else {
  747. msg_info_spf ("bad ipv6 mask: %d", cur_mask);
  748. }
  749. }
  750. else if (state == parse_domain && p - c > 0) {
  751. hostbuf = rspamd_mempool_alloc (task->task_pool, p - c + 1);
  752. rspamd_strlcpy (hostbuf, c, p - c + 1);
  753. host = hostbuf;
  754. }
  755. if (cur_mask == 0) {
  756. addr->m.dual.mask_v4 = 32;
  757. addr->m.dual.mask_v6 = 64;
  758. }
  759. return host;
  760. }
  761. static gboolean
  762. parse_spf_a (struct spf_record *rec,
  763. struct spf_resolved_element *resolved, struct spf_addr *addr)
  764. {
  765. struct spf_dns_cb *cb;
  766. const gchar *host = NULL;
  767. struct rspamd_task *task = rec->task;
  768. CHECK_REC (rec);
  769. host = parse_spf_domain_mask (rec, addr, resolved, TRUE);
  770. if (host == NULL) {
  771. return FALSE;
  772. }
  773. rec->dns_requests++;
  774. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  775. cb->rec = rec;
  776. cb->addr = addr;
  777. cb->cur_action = SPF_RESOLVE_A;
  778. cb->resolved = resolved;
  779. msg_debug_spf ("resolve a %s", host);
  780. if (make_dns_request_task (task,
  781. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_A, host)) {
  782. rec->requests_inflight++;
  783. if (make_dns_request_task (task,
  784. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_AAAA, host)) {
  785. rec->requests_inflight++;
  786. }
  787. return TRUE;
  788. }
  789. return FALSE;
  790. }
  791. static gboolean
  792. parse_spf_ptr (struct spf_record *rec,
  793. struct spf_resolved_element *resolved, struct spf_addr *addr)
  794. {
  795. struct spf_dns_cb *cb;
  796. const gchar *host;
  797. gchar *ptr;
  798. struct rspamd_task *task = rec->task;
  799. CHECK_REC (rec);
  800. host = parse_spf_domain_mask (rec, addr, resolved, FALSE);
  801. rec->dns_requests++;
  802. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  803. cb->rec = rec;
  804. cb->addr = addr;
  805. cb->cur_action = SPF_RESOLVE_PTR;
  806. cb->resolved = resolved;
  807. cb->ptr_host = rspamd_mempool_strdup (task->task_pool, host);
  808. ptr =
  809. rdns_generate_ptr_from_str (rspamd_inet_address_to_string (
  810. task->from_addr));
  811. if (ptr == NULL) {
  812. return FALSE;
  813. }
  814. rspamd_mempool_add_destructor (task->task_pool, free, ptr);
  815. msg_debug_spf ("resolve ptr %s for %s", ptr, host);
  816. if (make_dns_request_task (task,
  817. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_PTR, ptr)) {
  818. rec->requests_inflight++;
  819. return TRUE;
  820. }
  821. return FALSE;
  822. }
  823. static gboolean
  824. parse_spf_mx (struct spf_record *rec,
  825. struct spf_resolved_element *resolved, struct spf_addr *addr)
  826. {
  827. struct spf_dns_cb *cb;
  828. const gchar *host;
  829. struct rspamd_task *task = rec->task;
  830. CHECK_REC (rec);
  831. host = parse_spf_domain_mask (rec, addr, resolved, TRUE);
  832. if (host == NULL) {
  833. return FALSE;
  834. }
  835. rec->dns_requests++;
  836. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  837. cb->rec = rec;
  838. cb->addr = addr;
  839. cb->cur_action = SPF_RESOLVE_MX;
  840. cb->resolved = resolved;
  841. msg_debug_spf ("resolve mx for %s", host);
  842. if (make_dns_request_task (task,
  843. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_MX, host)) {
  844. rec->requests_inflight++;
  845. return TRUE;
  846. }
  847. return FALSE;
  848. }
  849. static gboolean
  850. parse_spf_all (struct spf_record *rec, struct spf_addr *addr)
  851. {
  852. /* All is 0/0 */
  853. memset (&addr->addr4, 0, sizeof (addr->addr4));
  854. memset (&addr->addr6, 0, sizeof (addr->addr6));
  855. /* Here we set all masks to 0 */
  856. addr->m.idx = 0;
  857. addr->flags |= RSPAMD_SPF_FLAG_ANY;
  858. msg_debug_spf ("parsed all elt");
  859. return TRUE;
  860. }
  861. static gboolean
  862. parse_spf_ip4 (struct spf_record *rec, struct spf_addr *addr)
  863. {
  864. /* ip4:addr[/mask] */
  865. const gchar *semicolon, *slash;
  866. gsize len;
  867. gchar ipbuf[INET_ADDRSTRLEN + 1];
  868. guint32 mask;
  869. CHECK_REC (rec);
  870. semicolon = strchr (addr->spf_string, ':');
  871. if (semicolon == NULL) {
  872. return FALSE;
  873. }
  874. semicolon++;
  875. slash = strchr (semicolon, '/');
  876. if (slash) {
  877. len = slash - semicolon;
  878. }
  879. else {
  880. len = strlen (semicolon);
  881. }
  882. rspamd_strlcpy (ipbuf, semicolon, MIN (len + 1, sizeof (ipbuf)));
  883. if (inet_pton (AF_INET, ipbuf, addr->addr4) != 1) {
  884. return FALSE;
  885. }
  886. if (slash) {
  887. mask = strtoul (slash + 1, NULL, 10);
  888. if (mask > 32) {
  889. return FALSE;
  890. }
  891. addr->m.dual.mask_v4 = mask;
  892. }
  893. else {
  894. addr->m.dual.mask_v4 = 32;
  895. }
  896. addr->flags |= RSPAMD_SPF_FLAG_IPV4;
  897. msg_debug_spf ("parsed ipv4 record %s/%d", ipbuf, addr->m.dual.mask_v4);
  898. return TRUE;
  899. }
  900. static gboolean
  901. parse_spf_ip6 (struct spf_record *rec, struct spf_addr *addr)
  902. {
  903. /* ip6:addr[/mask] */
  904. const gchar *semicolon, *slash;
  905. gsize len;
  906. gchar ipbuf[INET6_ADDRSTRLEN + 1];
  907. guint32 mask;
  908. CHECK_REC (rec);
  909. semicolon = strchr (addr->spf_string, ':');
  910. if (semicolon == NULL) {
  911. return FALSE;
  912. }
  913. semicolon++;
  914. slash = strchr (semicolon, '/');
  915. if (slash) {
  916. len = slash - semicolon;
  917. }
  918. else {
  919. len = strlen (semicolon);
  920. }
  921. rspamd_strlcpy (ipbuf, semicolon, MIN (len + 1, sizeof (ipbuf)));
  922. if (inet_pton (AF_INET6, ipbuf, addr->addr6) != 1) {
  923. return FALSE;
  924. }
  925. if (slash) {
  926. mask = strtoul (slash + 1, NULL, 10);
  927. if (mask > 128) {
  928. return FALSE;
  929. }
  930. addr->m.dual.mask_v6 = mask;
  931. }
  932. else {
  933. addr->m.dual.mask_v6 = 128;
  934. }
  935. addr->flags |= RSPAMD_SPF_FLAG_IPV6;
  936. msg_debug_spf ("parsed ipv6 record %s/%d", ipbuf, addr->m.dual.mask_v6);
  937. return TRUE;
  938. }
  939. static gboolean
  940. parse_spf_include (struct spf_record *rec, struct spf_addr *addr)
  941. {
  942. struct spf_dns_cb *cb;
  943. const gchar *domain;
  944. struct rspamd_task *task = rec->task;
  945. CHECK_REC (rec);
  946. domain = strchr (addr->spf_string, ':');
  947. if (domain == NULL) {
  948. return FALSE;
  949. }
  950. domain++;
  951. rec->dns_requests++;
  952. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  953. cb->rec = rec;
  954. cb->addr = addr;
  955. cb->cur_action = SPF_RESOLVE_INCLUDE;
  956. addr->m.idx = rec->resolved->len;
  957. cb->resolved = rspamd_spf_new_addr_list (rec, domain);
  958. /* Set reference */
  959. addr->flags |= RSPAMD_SPF_FLAG_REFRENCE;
  960. msg_debug_spf ("resolve include %s", domain);
  961. if (make_dns_request_task (task,
  962. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_TXT, domain)) {
  963. rec->requests_inflight++;
  964. return TRUE;
  965. }
  966. return FALSE;
  967. }
  968. static gboolean
  969. parse_spf_exp (struct spf_record *rec, struct spf_addr *addr)
  970. {
  971. CHECK_REC (rec);
  972. msg_info_spf ("exp record is ignored");
  973. return TRUE;
  974. }
  975. static gboolean
  976. parse_spf_redirect (struct spf_record *rec,
  977. struct spf_resolved_element *resolved, struct spf_addr *addr)
  978. {
  979. struct spf_dns_cb *cb;
  980. const gchar *domain;
  981. struct rspamd_task *task = rec->task;
  982. CHECK_REC (rec);
  983. domain = strchr (addr->spf_string, '=');
  984. if (domain == NULL) {
  985. return FALSE;
  986. }
  987. domain++;
  988. rec->dns_requests++;
  989. resolved->redirected = TRUE;
  990. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  991. /* Set reference */
  992. addr->flags |= RSPAMD_SPF_FLAG_REFRENCE | RSPAMD_SPF_FLAG_REDIRECT;
  993. addr->m.idx = rec->resolved->len;
  994. cb->rec = rec;
  995. cb->addr = addr;
  996. cb->cur_action = SPF_RESOLVE_REDIRECT;
  997. cb->resolved = rspamd_spf_new_addr_list (rec, domain);
  998. msg_debug_spf ("resolve redirect %s", domain);
  999. if (make_dns_request_task (task,
  1000. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_TXT, domain)) {
  1001. rec->requests_inflight++;
  1002. return TRUE;
  1003. }
  1004. return FALSE;
  1005. }
  1006. static gboolean
  1007. parse_spf_exists (struct spf_record *rec, struct spf_addr *addr)
  1008. {
  1009. struct spf_dns_cb *cb;
  1010. const gchar *host;
  1011. struct rspamd_task *task = rec->task;
  1012. struct spf_resolved_element *resolved;
  1013. resolved = g_ptr_array_index (rec->resolved, rec->resolved->len - 1);
  1014. CHECK_REC (rec);
  1015. host = strchr (addr->spf_string, ':');
  1016. if (host == NULL) {
  1017. msg_info_spf ("bad SPF exist record: %s", addr->spf_string);
  1018. return FALSE;
  1019. }
  1020. host++;
  1021. rec->dns_requests++;
  1022. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  1023. cb->rec = rec;
  1024. cb->addr = addr;
  1025. cb->cur_action = SPF_RESOLVE_EXISTS;
  1026. cb->resolved = resolved;
  1027. msg_debug_spf ("resolve exists %s", host);
  1028. if (make_dns_request_task (task,
  1029. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_A, host)) {
  1030. rec->requests_inflight++;
  1031. return TRUE;
  1032. }
  1033. return FALSE;
  1034. }
  1035. static void
  1036. reverse_spf_ip (gchar *ip, gint len)
  1037. {
  1038. gchar ipbuf[sizeof ("255.255.255.255") - 1], *p, *c;
  1039. gint t = 0, l = len;
  1040. if (len > (gint) sizeof (ipbuf)) {
  1041. msg_info ("cannot reverse string of length %d", len);
  1042. return;
  1043. }
  1044. p = ipbuf + len;
  1045. c = ip;
  1046. while (--l) {
  1047. if (*c == '.') {
  1048. memcpy (p, c - t, t);
  1049. *--p = '.';
  1050. c++;
  1051. t = 0;
  1052. continue;
  1053. }
  1054. t++;
  1055. c++;
  1056. p--;
  1057. }
  1058. memcpy (p - 1, c - t, t + 1);
  1059. memcpy (ip, ipbuf, len);
  1060. }
  1061. static const gchar *
  1062. expand_spf_macro (struct spf_record *rec,
  1063. const gchar *begin)
  1064. {
  1065. const gchar *p;
  1066. gchar *c, *new, *tmp;
  1067. gsize len = 0, slen = 0;
  1068. gint state = 0;
  1069. gchar ip_buf[INET6_ADDRSTRLEN];
  1070. gboolean need_expand = FALSE;
  1071. struct rspamd_task *task;
  1072. struct spf_resolved_element *resolved;
  1073. g_assert (rec != NULL);
  1074. g_assert (begin != NULL);
  1075. task = rec->task;
  1076. resolved = g_ptr_array_index (rec->resolved, rec->resolved->len - 1);
  1077. p = begin;
  1078. /* Calculate length */
  1079. while (*p) {
  1080. switch (state) {
  1081. case 0:
  1082. /* Skip any character and wait for % in input */
  1083. if (*p == '%') {
  1084. state = 1;
  1085. }
  1086. else {
  1087. len++;
  1088. }
  1089. slen++;
  1090. p++;
  1091. break;
  1092. case 1:
  1093. /* We got % sign, so we should whether wait for { or for - or for _ or for % */
  1094. if (*p == '%' || *p == '_') {
  1095. /* Just a single % sign or space */
  1096. len++;
  1097. state = 0;
  1098. }
  1099. else if (*p == '-') {
  1100. /* %20 */
  1101. len += sizeof ("%20") - 1;
  1102. state = 0;
  1103. }
  1104. else if (*p == '{') {
  1105. state = 2;
  1106. }
  1107. else {
  1108. /* Something unknown */
  1109. msg_info_spf (
  1110. "<%s>: spf error for domain %s: unknown spf element",
  1111. task->message_id, rec->sender_domain);
  1112. return begin;
  1113. }
  1114. p++;
  1115. slen++;
  1116. break;
  1117. case 2:
  1118. /* Read macro name */
  1119. switch (g_ascii_tolower (*p)) {
  1120. case 'i':
  1121. len += INET6_ADDRSTRLEN - 1;
  1122. break;
  1123. case 's':
  1124. len += strlen (rec->sender);
  1125. break;
  1126. case 'l':
  1127. len += strlen (rec->local_part);
  1128. break;
  1129. case 'o':
  1130. len += strlen (rec->sender_domain);
  1131. break;
  1132. case 'd':
  1133. len += strlen (resolved->cur_domain);
  1134. break;
  1135. case 'v':
  1136. len += sizeof ("in-addr") - 1;
  1137. break;
  1138. case 'h':
  1139. if (task->helo) {
  1140. len += strlen (task->helo);
  1141. }
  1142. break;
  1143. default:
  1144. msg_info_spf (
  1145. "<%s>: spf error for domain %s: unknown or unsupported spf macro %c in %s",
  1146. task->message_id,
  1147. rec->sender_domain,
  1148. *p,
  1149. begin);
  1150. return begin;
  1151. }
  1152. p++;
  1153. slen++;
  1154. state = 3;
  1155. break;
  1156. case 3:
  1157. /* Read modifier */
  1158. if (*p == '}') {
  1159. state = 0;
  1160. need_expand = TRUE;
  1161. }
  1162. else if (*p != 'r' && !g_ascii_isdigit (*p)) {
  1163. msg_info_spf (
  1164. "<%s>: spf error for domain %s: unknown or unsupported spf modifier %c in %s",
  1165. task->message_id,
  1166. rec->sender_domain,
  1167. *p,
  1168. begin);
  1169. return begin;
  1170. }
  1171. p++;
  1172. slen++;
  1173. break;
  1174. default:
  1175. assert (0);
  1176. }
  1177. }
  1178. if (!need_expand) {
  1179. /* No expansion needed */
  1180. return begin;
  1181. }
  1182. new = rspamd_mempool_alloc (task->task_pool, len + 1);
  1183. c = new;
  1184. p = begin;
  1185. state = 0;
  1186. /* Begin macro expansion */
  1187. while (*p) {
  1188. switch (state) {
  1189. case 0:
  1190. /* Skip any character and wait for % in input */
  1191. if (*p == '%') {
  1192. state = 1;
  1193. }
  1194. else {
  1195. *c = *p;
  1196. c++;
  1197. }
  1198. p++;
  1199. break;
  1200. case 1:
  1201. /* We got % sign, so we should whether wait for { or for - or for _ or for % */
  1202. if (*p == '%') {
  1203. /* Just a single % sign or space */
  1204. *c++ = '%';
  1205. state = 0;
  1206. }
  1207. else if (*p == '_') {
  1208. *c++ = ' ';
  1209. state = 0;
  1210. }
  1211. else if (*p == '-') {
  1212. /* %20 */
  1213. *c++ = '%';
  1214. *c++ = '2';
  1215. *c++ = '0';
  1216. state = 0;
  1217. }
  1218. else if (*p == '{') {
  1219. state = 2;
  1220. }
  1221. else {
  1222. /* Something unknown */
  1223. msg_info_spf (
  1224. "<%s>: spf error for domain %s: unknown spf element",
  1225. task->message_id, rec->sender_domain);
  1226. return begin;
  1227. }
  1228. p++;
  1229. break;
  1230. case 2:
  1231. /* Read macro name */
  1232. switch (g_ascii_tolower (*p)) {
  1233. case 'i':
  1234. len = rspamd_strlcpy (ip_buf,
  1235. rspamd_inet_address_to_string (task->from_addr),
  1236. sizeof (ip_buf));
  1237. memcpy (c, ip_buf, len);
  1238. c += len;
  1239. break;
  1240. case 's':
  1241. len = strlen (rec->sender);
  1242. memcpy (c, rec->sender, len);
  1243. c += len;
  1244. break;
  1245. case 'l':
  1246. len = strlen (rec->local_part);
  1247. memcpy (c, rec->local_part, len);
  1248. c += len;
  1249. break;
  1250. case 'o':
  1251. len = strlen (rec->sender_domain);
  1252. memcpy (c, rec->sender_domain, len);
  1253. c += len;
  1254. break;
  1255. case 'd':
  1256. len = strlen (resolved->cur_domain);
  1257. memcpy (c, resolved->cur_domain, len);
  1258. c += len;
  1259. break;
  1260. case 'v':
  1261. len = sizeof ("in-addr") - 1;
  1262. memcpy (c, "in-addr", len);
  1263. c += len;
  1264. break;
  1265. case 'h':
  1266. if (task->helo) {
  1267. tmp = strchr (task->helo, '@');
  1268. if (tmp) {
  1269. len = strlen (tmp + 1);
  1270. memcpy (c, tmp + 1, len);
  1271. c += len;
  1272. }
  1273. }
  1274. break;
  1275. default:
  1276. msg_info_spf (
  1277. "<%s>: spf error for domain %s: unknown or unsupported spf macro %c in %s",
  1278. task->message_id,
  1279. rec->sender_domain,
  1280. *p,
  1281. begin);
  1282. return begin;
  1283. }
  1284. p++;
  1285. state = 3;
  1286. break;
  1287. case 3:
  1288. /* Read modifier */
  1289. if (*p == '}') {
  1290. state = 0;
  1291. }
  1292. else if (*p == 'r' && len != 0) {
  1293. reverse_spf_ip (c - len, len);
  1294. len = 0;
  1295. }
  1296. else if (g_ascii_isdigit (*p)) {
  1297. /*XXX: try to implement domain trimming */
  1298. }
  1299. else {
  1300. msg_info_spf (
  1301. "<%s>: spf error for domain %s: unknown or unsupported spf macro %c in %s",
  1302. task->message_id,
  1303. rec->sender_domain,
  1304. *p,
  1305. begin);
  1306. return begin;
  1307. }
  1308. p++;
  1309. break;
  1310. }
  1311. }
  1312. /* Null terminate */
  1313. *c = '\0';
  1314. return new;
  1315. }
  1316. /* Read current element and try to parse record */
  1317. static gboolean
  1318. parse_spf_record (struct spf_record *rec, struct spf_resolved_element *resolved,
  1319. const gchar *elt)
  1320. {
  1321. struct spf_addr *addr = NULL;
  1322. gboolean res = FALSE;
  1323. const gchar *begin;
  1324. struct rspamd_task *task;
  1325. gchar t;
  1326. g_assert (elt != NULL);
  1327. g_assert (rec != NULL);
  1328. if (*elt == '\0' || resolved->redirected) {
  1329. return TRUE;
  1330. }
  1331. task = rec->task;
  1332. begin = expand_spf_macro (rec, elt);
  1333. addr = rspamd_spf_new_addr (rec, resolved, begin);
  1334. g_assert (addr != NULL);
  1335. t = g_ascii_tolower (addr->spf_string[0]);
  1336. begin = addr->spf_string;
  1337. /* Now check what we have */
  1338. switch (t) {
  1339. case 'a':
  1340. /* all or a */
  1341. if (g_ascii_strncasecmp (begin, SPF_ALL,
  1342. sizeof (SPF_ALL) - 1) == 0) {
  1343. res = parse_spf_all (rec, addr);
  1344. }
  1345. else if (g_ascii_strncasecmp (begin, SPF_A,
  1346. sizeof (SPF_A) - 1) == 0) {
  1347. res = parse_spf_a (rec, resolved, addr);
  1348. }
  1349. else {
  1350. msg_info_spf (
  1351. "<%s>: spf error for domain %s: bad spf command %s",
  1352. task->message_id, rec->sender_domain, begin);
  1353. }
  1354. break;
  1355. case 'i':
  1356. /* include or ip4 */
  1357. if (g_ascii_strncasecmp (begin, SPF_IP4,
  1358. sizeof (SPF_IP4) - 1) == 0) {
  1359. res = parse_spf_ip4 (rec, addr);
  1360. }
  1361. else if (g_ascii_strncasecmp (begin, SPF_INCLUDE,
  1362. sizeof (SPF_INCLUDE) - 1) == 0) {
  1363. res = parse_spf_include (rec, addr);
  1364. }
  1365. else if (g_ascii_strncasecmp (begin, SPF_IP6, sizeof (SPF_IP6) -
  1366. 1) == 0) {
  1367. res = parse_spf_ip6 (rec, addr);
  1368. }
  1369. else {
  1370. msg_info_spf (
  1371. "<%s>: spf error for domain %s: bad spf command %s",
  1372. task->message_id, rec->sender_domain, begin);
  1373. }
  1374. break;
  1375. case 'm':
  1376. /* mx */
  1377. if (g_ascii_strncasecmp (begin, SPF_MX, sizeof (SPF_MX) - 1) == 0) {
  1378. res = parse_spf_mx (rec, resolved, addr);
  1379. }
  1380. else {
  1381. msg_info_spf (
  1382. "<%s>: spf error for domain %s: bad spf command %s",
  1383. task->message_id, rec->sender_domain, begin);
  1384. }
  1385. break;
  1386. case 'p':
  1387. /* ptr */
  1388. if (g_ascii_strncasecmp (begin, SPF_PTR,
  1389. sizeof (SPF_PTR) - 1) == 0) {
  1390. res = parse_spf_ptr (rec, resolved, addr);
  1391. }
  1392. else {
  1393. msg_info_spf (
  1394. "<%s>: spf error for domain %s: bad spf command %s",
  1395. task->message_id, rec->sender_domain, begin);
  1396. }
  1397. break;
  1398. case 'e':
  1399. /* exp or exists */
  1400. if (g_ascii_strncasecmp (begin, SPF_EXP,
  1401. sizeof (SPF_EXP) - 1) == 0) {
  1402. res = parse_spf_exp (rec, addr);
  1403. }
  1404. else if (g_ascii_strncasecmp (begin, SPF_EXISTS,
  1405. sizeof (SPF_EXISTS) - 1) == 0) {
  1406. res = parse_spf_exists (rec, addr);
  1407. }
  1408. else {
  1409. msg_info_spf (
  1410. "<%s>: spf error for domain %s: bad spf command %s",
  1411. task->message_id, rec->sender_domain, begin);
  1412. }
  1413. break;
  1414. case 'r':
  1415. /* redirect */
  1416. if (g_ascii_strncasecmp (begin, SPF_REDIRECT,
  1417. sizeof (SPF_REDIRECT) - 1) == 0) {
  1418. res = parse_spf_redirect (rec, resolved, addr);
  1419. }
  1420. else {
  1421. msg_info_spf (
  1422. "<%s>: spf error for domain %s: bad spf command %s",
  1423. task->message_id, rec->sender_domain, begin);
  1424. }
  1425. break;
  1426. case 'v':
  1427. if (g_ascii_strncasecmp (begin, "v=spf",
  1428. sizeof ("v=spf") - 1) == 0) {
  1429. /* Skip this element till the end of record */
  1430. while (*begin && !g_ascii_isspace (*begin)) {
  1431. begin++;
  1432. }
  1433. }
  1434. break;
  1435. default:
  1436. msg_info_spf ("<%s>: spf error for domain %s: bad spf command %s",
  1437. task->message_id, rec->sender_domain, begin);
  1438. break;
  1439. }
  1440. if (res) {
  1441. addr->flags |= RSPAMD_SPF_FLAG_PARSED;
  1442. }
  1443. return res;
  1444. }
  1445. static void
  1446. parse_spf_scopes (struct spf_record *rec, gchar **begin)
  1447. {
  1448. for (; ;) {
  1449. if (g_ascii_strncasecmp (*begin, SPF_SCOPE_PRA, sizeof (SPF_SCOPE_PRA) -
  1450. 1) == 0) {
  1451. *begin += sizeof (SPF_SCOPE_PRA) - 1;
  1452. /* XXX: Implement actual PRA check */
  1453. /* extract_pra_info (rec); */
  1454. continue;
  1455. }
  1456. else if (g_ascii_strncasecmp (*begin, SPF_SCOPE_MFROM,
  1457. sizeof (SPF_SCOPE_MFROM) - 1) == 0) {
  1458. /* mfrom is standart spf1 check */
  1459. *begin += sizeof (SPF_SCOPE_MFROM) - 1;
  1460. continue;
  1461. }
  1462. else if (**begin != ',') {
  1463. break;
  1464. }
  1465. (*begin)++;
  1466. }
  1467. }
  1468. static gboolean
  1469. start_spf_parse (struct spf_record *rec, struct spf_resolved_element *resolved,
  1470. gchar *begin)
  1471. {
  1472. gchar **elts, **cur_elt;
  1473. /* Skip spaces */
  1474. while (g_ascii_isspace (*begin)) {
  1475. begin++;
  1476. }
  1477. if (g_ascii_strncasecmp (begin, SPF_VER1_STR, sizeof (SPF_VER1_STR) - 1) ==
  1478. 0) {
  1479. begin += sizeof (SPF_VER1_STR) - 1;
  1480. while (g_ascii_isspace (*begin) && *begin) {
  1481. begin++;
  1482. }
  1483. }
  1484. else if (g_ascii_strncasecmp (begin, SPF_VER2_STR, sizeof (SPF_VER2_STR) -
  1485. 1) == 0) {
  1486. /* Skip one number of record, so no we are here spf2.0/ */
  1487. begin += sizeof (SPF_VER2_STR);
  1488. if (*begin != '/') {
  1489. msg_info_spf ("<%s>: spf error for domain %s: sender id is invalid",
  1490. rec->task->message_id, rec->sender_domain);
  1491. }
  1492. else {
  1493. begin++;
  1494. parse_spf_scopes (rec, &begin);
  1495. }
  1496. /* Now common spf record */
  1497. }
  1498. else {
  1499. msg_debug_spf (
  1500. "<%s>: spf error for domain %s: bad spf record start: %*s",
  1501. rec->task->message_id,
  1502. rec->sender_domain,
  1503. (gint)sizeof (SPF_VER1_STR) - 1,
  1504. begin);
  1505. return FALSE;
  1506. }
  1507. while (g_ascii_isspace (*begin) && *begin) {
  1508. begin++;
  1509. }
  1510. elts = g_strsplit_set (begin, " ", 0);
  1511. if (elts) {
  1512. cur_elt = elts;
  1513. while (*cur_elt) {
  1514. parse_spf_record (rec, resolved, *cur_elt);
  1515. cur_elt++;
  1516. }
  1517. g_strfreev (elts);
  1518. }
  1519. rspamd_spf_maybe_return (rec);
  1520. return TRUE;
  1521. }
  1522. static void
  1523. spf_dns_callback (struct rdns_reply *reply, gpointer arg)
  1524. {
  1525. struct spf_record *rec = arg;
  1526. struct spf_resolved_element *resolved;
  1527. rec->requests_inflight--;
  1528. if (reply->code == RDNS_RC_NOERROR) {
  1529. resolved = rspamd_spf_new_addr_list (rec, rec->sender_domain);
  1530. if (rec->resolved->len == 1) {
  1531. /* Top level resolved element */
  1532. rec->ttl = reply->entries->ttl;
  1533. }
  1534. spf_process_txt_record (rec, resolved, reply);
  1535. }
  1536. rspamd_spf_maybe_return (rec);
  1537. }
  1538. const gchar *
  1539. get_spf_domain (struct rspamd_task *task)
  1540. {
  1541. const gchar *domain, *res = NULL;
  1542. const gchar *sender;
  1543. sender = rspamd_task_get_sender (task);
  1544. if (sender != NULL) {
  1545. domain = strchr (sender, '@');
  1546. if (domain) {
  1547. res = domain + 1;
  1548. }
  1549. }
  1550. return res;
  1551. }
  1552. gboolean
  1553. resolve_spf (struct rspamd_task *task, spf_cb_t callback)
  1554. {
  1555. struct spf_record *rec;
  1556. gchar *domain;
  1557. const gchar *sender;
  1558. sender = rspamd_task_get_sender (task);
  1559. rec = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct spf_record));
  1560. rec->task = task;
  1561. rec->callback = callback;
  1562. rec->resolved = g_ptr_array_sized_new (8);
  1563. /* Add destructor */
  1564. rspamd_mempool_add_destructor (task->task_pool,
  1565. (rspamd_mempool_destruct_t) spf_record_destructor,
  1566. rec);
  1567. /* Extract from data */
  1568. if (sender != NULL && (domain = strchr (sender, '@')) != NULL) {
  1569. rec->sender = sender;
  1570. rec->local_part = rspamd_mempool_alloc (task->task_pool,
  1571. domain - sender);
  1572. rspamd_strlcpy (rec->local_part, sender, domain - sender);
  1573. rec->sender_domain = domain + 1;
  1574. }
  1575. else if (task->helo != NULL && strchr (task->helo, '.') != NULL) {
  1576. /* For notifies we can check HELO identity and check SPF accordingly */
  1577. /* XXX: very poor check */
  1578. rec->local_part = rspamd_mempool_strdup (task->task_pool, "postmaster");
  1579. rec->sender_domain = task->helo;
  1580. }
  1581. else {
  1582. return FALSE;
  1583. }
  1584. if (make_dns_request_task (task,
  1585. spf_dns_callback,
  1586. (void *) rec, RDNS_REQUEST_TXT, rec->sender_domain)) {
  1587. rec->requests_inflight++;
  1588. return TRUE;
  1589. }
  1590. return FALSE;
  1591. }
  1592. struct spf_resolved *
  1593. spf_record_ref (struct spf_resolved *rec)
  1594. {
  1595. REF_RETAIN (rec);
  1596. return rec;
  1597. }
  1598. void
  1599. spf_record_unref (struct spf_resolved *rec)
  1600. {
  1601. REF_RELEASE (rec);
  1602. }