Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247
  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 <contrib/librdns/rdns.h>
  17. #include "config.h"
  18. #include "dns.h"
  19. #include "spf.h"
  20. #include "rspamd.h"
  21. #include "message.h"
  22. #include "utlist.h"
  23. #include "libserver/mempool_vars_internal.h"
  24. #define SPF_VER1_STR "v=spf1"
  25. #define SPF_VER2_STR "spf2."
  26. #define SPF_SCOPE_PRA "pra"
  27. #define SPF_SCOPE_MFROM "mfrom"
  28. #define SPF_ALL "all"
  29. #define SPF_A "a"
  30. #define SPF_IP4 "ip4"
  31. #define SPF_IP6 "ip6"
  32. #define SPF_PTR "ptr"
  33. #define SPF_MX "mx"
  34. #define SPF_EXISTS "exists"
  35. #define SPF_INCLUDE "include"
  36. #define SPF_REDIRECT "redirect"
  37. #define SPF_EXP "exp"
  38. /** SPF limits for avoiding abuse **/
  39. #define SPF_MAX_NESTING 10
  40. #define SPF_MAX_DNS_REQUESTS 30
  41. struct spf_resolved_element {
  42. GPtrArray *elts;
  43. gchar *cur_domain;
  44. gboolean redirected; /* Ingnore level, it's redirected */
  45. };
  46. struct spf_record {
  47. gint nested;
  48. gint dns_requests;
  49. gint requests_inflight;
  50. guint ttl;
  51. GPtrArray *resolved;
  52. /* Array of struct spf_resolved_element */
  53. const gchar *sender;
  54. const gchar *sender_domain;
  55. gchar *local_part;
  56. struct rspamd_task *task;
  57. spf_cb_t callback;
  58. gpointer cbdata;
  59. gboolean done;
  60. };
  61. /**
  62. * BNF for SPF record:
  63. *
  64. * spf_mech ::= +|-|~|?
  65. *
  66. * spf_body ::= spf=v1 <spf_command> [<spf_command>]
  67. * spf_command ::= [spf_mech]all|a|<ip4>|<ip6>|ptr|mx|<exists>|<include>|<redirect>
  68. *
  69. * spf_domain ::= [:domain][/mask]
  70. * spf_ip4 ::= ip[/mask]
  71. * ip4 ::= ip4:<spf_ip4>
  72. * mx ::= mx<spf_domain>
  73. * a ::= a<spf_domain>
  74. * ptr ::= ptr[:domain]
  75. * exists ::= exists:domain
  76. * include ::= include:domain
  77. * redirect ::= redirect:domain
  78. * exp ::= exp:domain
  79. *
  80. */
  81. #undef SPF_DEBUG
  82. #define msg_err_spf(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
  83. "spf", rec->task->task_pool->tag.uid, \
  84. G_STRFUNC, \
  85. __VA_ARGS__)
  86. #define msg_warn_spf(...) rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
  87. "spf", rec->task->task_pool->tag.uid, \
  88. G_STRFUNC, \
  89. __VA_ARGS__)
  90. #define msg_info_spf(...) rspamd_default_log_function (G_LOG_LEVEL_INFO, \
  91. "spf", rec->task->task_pool->tag.uid, \
  92. G_STRFUNC, \
  93. __VA_ARGS__)
  94. #define msg_debug_spf(...) rspamd_conditional_debug_fast (NULL, rec->task->from_addr, \
  95. rspamd_spf_log_id, "spf", rec->task->task_pool->tag.uid, \
  96. G_STRFUNC, \
  97. __VA_ARGS__)
  98. INIT_LOG_MODULE(spf)
  99. struct spf_dns_cb {
  100. struct spf_record *rec;
  101. struct spf_addr *addr;
  102. struct spf_resolved_element *resolved;
  103. const gchar *ptr_host;
  104. spf_action_t cur_action;
  105. gboolean in_include;
  106. };
  107. #define CHECK_REC(rec) \
  108. do { \
  109. if ((rec)->nested > SPF_MAX_NESTING || \
  110. (rec)->dns_requests > SPF_MAX_DNS_REQUESTS) { \
  111. msg_info_spf ("<%s> spf recursion limit %d is reached, domain: %s", \
  112. (rec)->task->message_id, (rec)->dns_requests, \
  113. (rec)->sender_domain); \
  114. return FALSE; \
  115. } \
  116. } while (0) \
  117. static gboolean start_spf_parse (struct spf_record *rec,
  118. struct spf_resolved_element *resolved, gchar *begin);
  119. /* Determine spf mech */
  120. static spf_mech_t
  121. check_spf_mech (const gchar *elt, gboolean *need_shift)
  122. {
  123. g_assert (elt != NULL);
  124. *need_shift = TRUE;
  125. switch (*elt) {
  126. case '-':
  127. return SPF_FAIL;
  128. case '~':
  129. return SPF_SOFT_FAIL;
  130. case '+':
  131. return SPF_PASS;
  132. case '?':
  133. return SPF_NEUTRAL;
  134. default:
  135. *need_shift = FALSE;
  136. return SPF_PASS;
  137. }
  138. }
  139. static const gchar *
  140. rspamd_spf_dns_action_to_str (spf_action_t act)
  141. {
  142. const char *ret = "unknown";
  143. switch (act) {
  144. case SPF_RESOLVE_MX:
  145. ret = "MX";
  146. break;
  147. case SPF_RESOLVE_A:
  148. ret = "A";
  149. break;
  150. case SPF_RESOLVE_PTR:
  151. ret = "PTR";
  152. break;
  153. case SPF_RESOLVE_AAA:
  154. ret = "AAAA";
  155. break;
  156. case SPF_RESOLVE_REDIRECT:
  157. ret = "REDIRECT";
  158. break;
  159. case SPF_RESOLVE_INCLUDE:
  160. ret = "INCLUDE";
  161. break;
  162. case SPF_RESOLVE_EXISTS:
  163. ret = "EXISTS";
  164. break;
  165. case SPF_RESOLVE_EXP:
  166. ret = "EXP";
  167. break;
  168. }
  169. return ret;
  170. }
  171. static struct spf_addr *
  172. rspamd_spf_new_addr (struct spf_record *rec,
  173. struct spf_resolved_element *resolved, const gchar *elt)
  174. {
  175. gboolean need_shift = FALSE;
  176. struct spf_addr *naddr;
  177. naddr = g_malloc0 (sizeof (*naddr));
  178. naddr->mech = check_spf_mech (elt, &need_shift);
  179. if (need_shift) {
  180. naddr->spf_string = g_strdup (elt + 1);
  181. }
  182. else {
  183. naddr->spf_string = g_strdup (elt);
  184. }
  185. g_ptr_array_add (resolved->elts, naddr);
  186. naddr->prev = naddr;
  187. naddr->next = NULL;
  188. return naddr;
  189. }
  190. static void
  191. rspamd_spf_free_addr (gpointer a)
  192. {
  193. struct spf_addr *addr = a, *tmp, *cur;
  194. if (addr) {
  195. g_free (addr->spf_string);
  196. DL_FOREACH_SAFE (addr, cur, tmp) {
  197. g_free (cur);
  198. }
  199. }
  200. }
  201. static struct spf_resolved_element *
  202. rspamd_spf_new_addr_list (struct spf_record *rec, const gchar *domain)
  203. {
  204. struct spf_resolved_element *resolved;
  205. resolved = g_malloc0 (sizeof (*resolved));
  206. resolved->redirected = FALSE;
  207. resolved->cur_domain = g_strdup (domain);
  208. resolved->elts = g_ptr_array_new_full (8, rspamd_spf_free_addr);
  209. g_ptr_array_add (rec->resolved, resolved);
  210. return g_ptr_array_index (rec->resolved, rec->resolved->len - 1);
  211. }
  212. /*
  213. * Destructor for spf record
  214. */
  215. static void
  216. spf_record_destructor (gpointer r)
  217. {
  218. struct spf_record *rec = r;
  219. struct spf_resolved_element *elt;
  220. guint i;
  221. if (rec) {
  222. for (i = 0; i < rec->resolved->len; i++) {
  223. elt = g_ptr_array_index (rec->resolved, i);
  224. g_ptr_array_free (elt->elts, TRUE);
  225. g_free (elt->cur_domain);
  226. g_free (elt);
  227. }
  228. g_ptr_array_free (rec->resolved, TRUE);
  229. }
  230. }
  231. static void
  232. rspamd_flatten_record_dtor (struct spf_resolved *r)
  233. {
  234. struct spf_addr *addr;
  235. guint i;
  236. for (i = 0; i < r->elts->len; i++) {
  237. addr = &g_array_index (r->elts, struct spf_addr, i);
  238. g_free (addr->spf_string);
  239. }
  240. g_free (r->domain);
  241. g_array_free (r->elts, TRUE);
  242. g_free (r);
  243. }
  244. static void
  245. rspamd_spf_process_reference (struct spf_resolved *target,
  246. struct spf_addr *addr, struct spf_record *rec, gboolean top)
  247. {
  248. struct spf_resolved_element *elt, *relt;
  249. struct spf_addr *cur = NULL, taddr, *cur_addr;
  250. guint i;
  251. if (addr) {
  252. g_assert (addr->m.idx < rec->resolved->len);
  253. elt = g_ptr_array_index (rec->resolved, addr->m.idx);
  254. }
  255. else {
  256. elt = g_ptr_array_index (rec->resolved, 0);
  257. }
  258. if (rec->ttl < target->ttl) {
  259. msg_debug_spf ("reducing ttl from %d to %d after subrecord processing %s",
  260. target->ttl, rec->ttl, rec->sender_domain);
  261. target->ttl = rec->ttl;
  262. }
  263. if (elt->redirected) {
  264. g_assert (elt->elts->len > 0);
  265. for (i = 0; i < elt->elts->len; i++) {
  266. cur = g_ptr_array_index (elt->elts, i);
  267. if (cur->flags & RSPAMD_SPF_FLAG_REDIRECT) {
  268. break;
  269. }
  270. }
  271. g_assert (cur != NULL);
  272. if (!(cur->flags & (RSPAMD_SPF_FLAG_PARSED|RSPAMD_SPF_FLAG_RESOLVED))) {
  273. /* Unresolved redirect */
  274. msg_info_spf ("redirect to %s cannot be resolved", cur->spf_string);
  275. }
  276. else {
  277. g_assert (cur->flags & RSPAMD_SPF_FLAG_REFERENCE);
  278. g_assert (cur->m.idx < rec->resolved->len);
  279. relt = g_ptr_array_index (rec->resolved, cur->m.idx);
  280. msg_debug_spf ("domain %s is redirected to %s", elt->cur_domain,
  281. relt->cur_domain);
  282. }
  283. }
  284. for (i = 0; i < elt->elts->len; i++) {
  285. cur = g_ptr_array_index (elt->elts, i);
  286. if (cur->flags & RSPAMD_SPF_FLAG_TEMPFAIL) {
  287. target->temp_failed = TRUE;
  288. continue;
  289. }
  290. if (cur->flags & RSPAMD_SPF_FLAG_PERMFAIL) {
  291. target->perm_failed = TRUE;
  292. continue;
  293. }
  294. if (cur->flags & RSPAMD_SPF_FLAG_NA) {
  295. target->na = TRUE;
  296. continue;
  297. }
  298. if (cur->flags & RSPAMD_SPF_FLAG_INVALID) {
  299. /* Ignore invalid elements */
  300. continue;
  301. }
  302. if ((cur->flags & (RSPAMD_SPF_FLAG_PARSED|RSPAMD_SPF_FLAG_RESOLVED)) !=
  303. (RSPAMD_SPF_FLAG_RESOLVED|RSPAMD_SPF_FLAG_PARSED)) {
  304. /* Ignore unparsed addrs */
  305. continue;
  306. }
  307. if (cur->flags & RSPAMD_SPF_FLAG_REFERENCE) {
  308. /* Process reference */
  309. if (cur->flags & RSPAMD_SPF_FLAG_REDIRECT) {
  310. /* Stop on redirected domain */
  311. rspamd_spf_process_reference (target, cur, rec, top);
  312. break;
  313. }
  314. else {
  315. rspamd_spf_process_reference (target, cur, rec, FALSE);
  316. }
  317. }
  318. else {
  319. if ((cur->flags & RSPAMD_SPF_FLAG_ANY) && !top) {
  320. /* Ignore wide policies in includes */
  321. continue;
  322. }
  323. DL_FOREACH (cur, cur_addr) {
  324. memcpy (&taddr, cur_addr, sizeof (taddr));
  325. taddr.spf_string = g_strdup (cur_addr->spf_string);
  326. g_array_append_val (target->elts, taddr);
  327. }
  328. }
  329. }
  330. }
  331. /*
  332. * Parse record and flatten it to a simple structure
  333. */
  334. static struct spf_resolved *
  335. rspamd_spf_record_flatten (struct spf_record *rec)
  336. {
  337. struct spf_resolved *res;
  338. g_assert (rec != NULL);
  339. if (rec->resolved) {
  340. res = g_malloc0 (sizeof (*res));
  341. res->elts = g_array_sized_new (FALSE, FALSE, sizeof (struct spf_addr),
  342. rec->resolved->len);
  343. res->domain = g_strdup (rec->sender_domain);
  344. res->ttl = rec->ttl;
  345. REF_INIT_RETAIN (res, rspamd_flatten_record_dtor);
  346. if (rec->resolved->len > 0) {
  347. rspamd_spf_process_reference (res, NULL, rec, TRUE);
  348. }
  349. }
  350. else {
  351. res = g_malloc0 (sizeof (*res));
  352. res->elts = g_array_new (FALSE, FALSE, sizeof (struct spf_addr));
  353. res->domain = g_strdup (rec->sender_domain);
  354. res->ttl = rec->ttl;
  355. REF_INIT_RETAIN (res, rspamd_flatten_record_dtor);
  356. }
  357. return res;
  358. }
  359. static void
  360. rspamd_spf_maybe_return (struct spf_record *rec)
  361. {
  362. struct spf_resolved *flat;
  363. if (rec->requests_inflight == 0 && !rec->done) {
  364. flat = rspamd_spf_record_flatten (rec);
  365. rec->callback (flat, rec->task, rec->cbdata);
  366. REF_RELEASE (flat);
  367. rec->done = TRUE;
  368. }
  369. }
  370. static gboolean
  371. spf_check_ptr_host (struct spf_dns_cb *cb, const char *name)
  372. {
  373. const char *dend, *nend, *dstart, *nstart;
  374. struct spf_record *rec = cb->rec;
  375. if (cb->ptr_host != NULL) {
  376. dstart = cb->ptr_host;
  377. }
  378. else {
  379. dstart = cb->resolved->cur_domain;
  380. }
  381. if (name == NULL || dstart == NULL) {
  382. return FALSE;
  383. }
  384. msg_debug_spf ("check ptr %s vs %s", name, dstart);
  385. /* We need to check whether `cur_domain` is a subdomain for `name` */
  386. dend = dstart + strlen (dstart) - 1;
  387. nstart = name;
  388. nend = nstart + strlen (nstart) - 1;
  389. if (nend <= nstart || dend <= dstart) {
  390. return FALSE;
  391. }
  392. /* Strip last '.' from names */
  393. if (*nend == '.') {
  394. nend--;
  395. }
  396. if (*dend == '.') {
  397. dend--;
  398. }
  399. if (nend <= nstart || dend <= dstart) {
  400. return FALSE;
  401. }
  402. /* Now compare from end to start */
  403. for (;;) {
  404. if (g_ascii_tolower (*dend) != g_ascii_tolower (*nend)) {
  405. msg_debug_spf ("ptr records mismatch: %s and %s", dend, nend);
  406. return FALSE;
  407. }
  408. if (dend == dstart) {
  409. break;
  410. }
  411. if (nend == nstart) {
  412. /* Name is shorter than cur_domain */
  413. return FALSE;
  414. }
  415. nend--;
  416. dend--;
  417. }
  418. if (nend > nstart && *(nend - 1) != '.') {
  419. /* Not a subdomain */
  420. return FALSE;
  421. }
  422. return TRUE;
  423. }
  424. static void
  425. spf_record_process_addr (struct spf_record *rec, struct spf_addr *addr, struct
  426. rdns_reply_entry *reply)
  427. {
  428. struct spf_addr *naddr;
  429. if (!(addr->flags & RSPAMD_SPF_FLAG_PROCESSED)) {
  430. /* That's the first address */
  431. if (reply->type == RDNS_REQUEST_AAAA) {
  432. memcpy (addr->addr6,
  433. &reply->content.aaa.addr,
  434. sizeof (addr->addr6));
  435. addr->flags |= RSPAMD_SPF_FLAG_IPV6;
  436. }
  437. else if (reply->type == RDNS_REQUEST_A) {
  438. memcpy (addr->addr4, &reply->content.a.addr, sizeof (addr->addr4));
  439. addr->flags |= RSPAMD_SPF_FLAG_IPV4;
  440. }
  441. else {
  442. msg_err_spf (
  443. "internal error, bad DNS reply is treated as address: %s",
  444. rdns_strtype (reply->type));
  445. }
  446. addr->flags |= RSPAMD_SPF_FLAG_PROCESSED;
  447. }
  448. else {
  449. /* We need to create a new address */
  450. naddr = g_malloc0 (sizeof (*naddr));
  451. memcpy (naddr, addr, sizeof (*naddr));
  452. naddr->next = NULL;
  453. naddr->prev = NULL;
  454. if (reply->type == RDNS_REQUEST_AAAA) {
  455. memcpy (naddr->addr6,
  456. &reply->content.aaa.addr,
  457. sizeof (addr->addr6));
  458. naddr->flags |= RSPAMD_SPF_FLAG_IPV6;
  459. }
  460. else if (reply->type == RDNS_REQUEST_A) {
  461. memcpy (naddr->addr4, &reply->content.a.addr, sizeof (addr->addr4));
  462. naddr->flags |= RSPAMD_SPF_FLAG_IPV4;
  463. }
  464. else {
  465. msg_err_spf (
  466. "internal error, bad DNS reply is treated as address: %s",
  467. rdns_strtype (reply->type));
  468. }
  469. DL_APPEND (addr, naddr);
  470. }
  471. }
  472. static void
  473. spf_record_addr_set (struct spf_addr *addr, gboolean allow_any)
  474. {
  475. guchar fill;
  476. if (!(addr->flags & RSPAMD_SPF_FLAG_PROCESSED)) {
  477. if (allow_any) {
  478. fill = 0;
  479. addr->m.dual.mask_v4 = 0;
  480. addr->m.dual.mask_v6 = 0;
  481. }
  482. else {
  483. fill = 0xff;
  484. }
  485. memset (addr->addr4, fill, sizeof (addr->addr4));
  486. memset (addr->addr6, fill, sizeof (addr->addr6));
  487. addr->flags |= RSPAMD_SPF_FLAG_IPV4;
  488. addr->flags |= RSPAMD_SPF_FLAG_IPV6;
  489. }
  490. }
  491. static gboolean
  492. spf_process_txt_record (struct spf_record *rec, struct spf_resolved_element *resolved,
  493. struct rdns_reply *reply)
  494. {
  495. struct rdns_reply_entry *elt, *selected = NULL;
  496. gboolean ret = FALSE;
  497. /*
  498. * We prefer spf version 1 as other records are mostly likely garbadge
  499. * or incorrect records (e.g. spf2 records)
  500. */
  501. LL_FOREACH (reply->entries, elt) {
  502. if (strncmp (elt->content.txt.data, "v=spf1", sizeof ("v=spf1") - 1)
  503. == 0) {
  504. selected = elt;
  505. rspamd_mempool_set_variable (rec->task->task_pool,
  506. RSPAMD_MEMPOOL_SPF_RECORD,
  507. rspamd_mempool_strdup (rec->task->task_pool,
  508. elt->content.txt.data), NULL);
  509. break;
  510. }
  511. }
  512. if (!selected) {
  513. LL_FOREACH (reply->entries, elt) {
  514. if (start_spf_parse (rec, resolved, elt->content.txt.data)) {
  515. ret = TRUE;
  516. rspamd_mempool_set_variable (rec->task->task_pool,
  517. RSPAMD_MEMPOOL_SPF_RECORD,
  518. rspamd_mempool_strdup (rec->task->task_pool,
  519. elt->content.txt.data), NULL);
  520. break;
  521. }
  522. }
  523. }
  524. else {
  525. ret = start_spf_parse (rec, resolved, selected->content.txt.data);
  526. }
  527. return ret;
  528. }
  529. static void
  530. spf_record_dns_callback (struct rdns_reply *reply, gpointer arg)
  531. {
  532. struct spf_dns_cb *cb = arg;
  533. struct rdns_reply_entry *elt_data;
  534. struct rspamd_task *task;
  535. struct spf_addr *addr;
  536. struct spf_record *rec;
  537. const struct rdns_request_name *req_name;
  538. rec = cb->rec;
  539. task = rec->task;
  540. cb->rec->requests_inflight--;
  541. addr = cb->addr;
  542. if (reply->code == RDNS_RC_NOERROR) {
  543. req_name = rdns_request_get_name (reply->request, NULL);
  544. LL_FOREACH (reply->entries, elt_data) {
  545. /* Adjust ttl if a resolved record has lower ttl than spf record itself */
  546. if ((guint)elt_data->ttl < rec->ttl) {
  547. msg_debug_spf ("reducing ttl from %d to %d after DNS resolving",
  548. rec->ttl, elt_data->ttl);
  549. rec->ttl = elt_data->ttl;
  550. }
  551. switch (cb->cur_action) {
  552. case SPF_RESOLVE_MX:
  553. if (elt_data->type == RDNS_REQUEST_MX) {
  554. /* Now resolve A record for this MX */
  555. msg_debug_spf ("resolve %s after resolving of MX",
  556. elt_data->content.mx.name);
  557. if (make_dns_request_task_forced (task,
  558. spf_record_dns_callback, (void *) cb,
  559. RDNS_REQUEST_A,
  560. elt_data->content.mx.name)) {
  561. cb->rec->requests_inflight++;
  562. }
  563. if (make_dns_request_task_forced (task,
  564. spf_record_dns_callback, (void *) cb,
  565. RDNS_REQUEST_AAAA,
  566. elt_data->content.mx.name)) {
  567. cb->rec->requests_inflight++;
  568. }
  569. }
  570. else {
  571. cb->addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
  572. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PERMFAIL;
  573. spf_record_process_addr (rec, addr, elt_data);
  574. }
  575. break;
  576. case SPF_RESOLVE_A:
  577. case SPF_RESOLVE_AAA:
  578. cb->addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
  579. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PERMFAIL;
  580. spf_record_process_addr (rec, addr, elt_data);
  581. break;
  582. case SPF_RESOLVE_PTR:
  583. if (elt_data->type == RDNS_REQUEST_PTR) {
  584. /* Validate returned records prior to making A requests */
  585. if (spf_check_ptr_host (cb,
  586. elt_data->content.ptr.name)) {
  587. msg_debug_spf ("resolve %s after resolving of PTR",
  588. elt_data->content.ptr.name);
  589. if (make_dns_request_task_forced (task,
  590. spf_record_dns_callback, (void *) cb,
  591. RDNS_REQUEST_A,
  592. elt_data->content.ptr.name)) {
  593. cb->rec->requests_inflight++;
  594. }
  595. if (make_dns_request_task_forced (task,
  596. spf_record_dns_callback, (void *) cb,
  597. RDNS_REQUEST_AAAA,
  598. elt_data->content.ptr.name)) {
  599. cb->rec->requests_inflight++;
  600. }
  601. }
  602. else {
  603. cb->addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
  604. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PERMFAIL;
  605. }
  606. }
  607. else {
  608. cb->addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
  609. cb->addr->flags &= ~RSPAMD_SPF_FLAG_PERMFAIL;
  610. spf_record_process_addr (rec, addr, elt_data);
  611. }
  612. break;
  613. case SPF_RESOLVE_REDIRECT:
  614. if (elt_data->type == RDNS_REQUEST_TXT) {
  615. cb->addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
  616. if (reply->entries) {
  617. msg_debug_spf ("got redirection record for %s: '%s'",
  618. req_name->name,
  619. reply->entries[0].content.txt.data);
  620. }
  621. if (!spf_process_txt_record (rec, cb->resolved, reply)) {
  622. cb->addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  623. }
  624. }
  625. goto end;
  626. break;
  627. case SPF_RESOLVE_INCLUDE:
  628. if (elt_data->type == RDNS_REQUEST_TXT) {
  629. if (reply->entries) {
  630. msg_debug_spf ("got include record for %s: '%s'",
  631. req_name->name,
  632. reply->entries[0].content.txt.data);
  633. }
  634. cb->addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
  635. spf_process_txt_record (rec, cb->resolved, reply);
  636. }
  637. goto end;
  638. break;
  639. case SPF_RESOLVE_EXP:
  640. break;
  641. case SPF_RESOLVE_EXISTS:
  642. if (elt_data->type == RDNS_REQUEST_A ||
  643. elt_data->type == RDNS_REQUEST_AAAA) {
  644. /*
  645. * If specified address resolves, we can accept
  646. * connection from every IP
  647. */
  648. addr->flags |= RSPAMD_SPF_FLAG_RESOLVED;
  649. spf_record_addr_set (addr, TRUE);
  650. }
  651. break;
  652. }
  653. }
  654. }
  655. else if (reply->code == RDNS_RC_NXDOMAIN || reply->code == RDNS_RC_NOREC) {
  656. switch (cb->cur_action) {
  657. case SPF_RESOLVE_MX:
  658. if (!(cb->addr->flags & RSPAMD_SPF_FLAG_RESOLVED)) {
  659. cb->addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  660. msg_debug_spf (
  661. "<%s>: spf error for domain %s: cannot find MX"
  662. " record for %s: %s",
  663. task->message_id,
  664. cb->rec->sender_domain,
  665. cb->resolved->cur_domain,
  666. rdns_strerror (reply->code));
  667. spf_record_addr_set (addr, FALSE);
  668. }
  669. break;
  670. case SPF_RESOLVE_A:
  671. if (!(cb->addr->flags & RSPAMD_SPF_FLAG_RESOLVED)) {
  672. cb->addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  673. msg_debug_spf (
  674. "<%s>: spf error for domain %s: cannot resolve A"
  675. " record for %s: %s",
  676. task->message_id,
  677. cb->rec->sender_domain,
  678. cb->resolved->cur_domain,
  679. rdns_strerror (reply->code));
  680. if (rdns_request_has_type (reply->request, RDNS_REQUEST_A)) {
  681. spf_record_addr_set (addr, FALSE);
  682. }
  683. }
  684. break;
  685. case SPF_RESOLVE_AAA:
  686. if (!(cb->addr->flags & RSPAMD_SPF_FLAG_RESOLVED)) {
  687. cb->addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  688. msg_debug_spf (
  689. "<%s>: spf error for domain %s: cannot resolve AAAA"
  690. " record for %s: %s",
  691. task->message_id,
  692. cb->rec->sender_domain,
  693. cb->resolved->cur_domain,
  694. rdns_strerror (reply->code));
  695. if (rdns_request_has_type (reply->request, RDNS_REQUEST_AAAA)) {
  696. spf_record_addr_set (addr, FALSE);
  697. }
  698. }
  699. break;
  700. case SPF_RESOLVE_PTR:
  701. if (!(cb->addr->flags & RSPAMD_SPF_FLAG_RESOLVED)) {
  702. msg_debug_spf (
  703. "<%s>: spf error for domain %s: cannot resolve PTR"
  704. " record for %s: %s",
  705. task->message_id,
  706. cb->rec->sender_domain,
  707. cb->resolved->cur_domain,
  708. rdns_strerror (reply->code));
  709. cb->addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  710. spf_record_addr_set (addr, FALSE);
  711. }
  712. break;
  713. case SPF_RESOLVE_REDIRECT:
  714. if (!(cb->addr->flags & RSPAMD_SPF_FLAG_RESOLVED)) {
  715. cb->addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  716. msg_debug_spf (
  717. "<%s>: spf error for domain %s: cannot resolve REDIRECT"
  718. " record for %s: %s",
  719. task->message_id,
  720. cb->rec->sender_domain,
  721. cb->resolved->cur_domain,
  722. rdns_strerror (reply->code));
  723. }
  724. break;
  725. case SPF_RESOLVE_INCLUDE:
  726. if (!(cb->addr->flags & RSPAMD_SPF_FLAG_RESOLVED)) {
  727. msg_debug_spf (
  728. "<%s>: spf error for domain %s: cannot resolve INCLUDE"
  729. " record for %s: %s",
  730. task->message_id,
  731. cb->rec->sender_domain,
  732. cb->resolved->cur_domain,
  733. rdns_strerror (reply->code));
  734. cb->addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  735. }
  736. break;
  737. case SPF_RESOLVE_EXP:
  738. break;
  739. case SPF_RESOLVE_EXISTS:
  740. if (!(cb->addr->flags & RSPAMD_SPF_FLAG_RESOLVED)) {
  741. msg_debug_spf (
  742. "<%s>: spf error for domain %s: cannot resolve EXISTS"
  743. " record for %s: %s",
  744. task->message_id,
  745. cb->rec->sender_domain,
  746. cb->resolved->cur_domain,
  747. rdns_strerror (reply->code));
  748. spf_record_addr_set (addr, FALSE);
  749. }
  750. break;
  751. }
  752. }
  753. else {
  754. cb->addr->flags |= RSPAMD_SPF_FLAG_TEMPFAIL;
  755. msg_info_spf (
  756. "<%s>: spf error for domain %s: cannot resolve %s DNS record for"
  757. " %s: %s",
  758. task->message_id,
  759. cb->rec->sender_domain,
  760. rspamd_spf_dns_action_to_str (cb->cur_action),
  761. cb->ptr_host,
  762. rdns_strerror (reply->code));
  763. }
  764. end:
  765. rspamd_spf_maybe_return (cb->rec);
  766. }
  767. /*
  768. * The syntax defined by the following BNF:
  769. * [ ":" domain-spec ] [ dual-cidr-length ]
  770. * ip4-cidr-length = "/" 1*DIGIT
  771. * ip6-cidr-length = "/" 1*DIGIT
  772. * dual-cidr-length = [ ip4-cidr-length ] [ "/" ip6-cidr-length ]
  773. */
  774. static const gchar *
  775. parse_spf_domain_mask (struct spf_record *rec, struct spf_addr *addr,
  776. struct spf_resolved_element *resolved,
  777. gboolean allow_mask)
  778. {
  779. struct rspamd_task *task = rec->task;
  780. enum {
  781. parse_spf_elt = 0,
  782. parse_semicolon,
  783. parse_domain,
  784. parse_slash,
  785. parse_ipv4_mask,
  786. parse_second_slash,
  787. parse_ipv6_mask,
  788. skip_garbadge
  789. } state = 0;
  790. const gchar *p = addr->spf_string, *host, *c;
  791. gchar *hostbuf;
  792. gchar t;
  793. guint16 cur_mask = 0;
  794. host = resolved->cur_domain;
  795. c = p;
  796. while (*p) {
  797. t = *p;
  798. switch (state) {
  799. case parse_spf_elt:
  800. if (t == ':') {
  801. state = parse_semicolon;
  802. }
  803. else if (t == '/') {
  804. /* No domain but mask */
  805. state = parse_slash;
  806. }
  807. p++;
  808. break;
  809. case parse_semicolon:
  810. if (t == '/') {
  811. /* Empty domain, technically an error */
  812. state = parse_slash;
  813. }
  814. else {
  815. c = p;
  816. state = parse_domain;
  817. }
  818. break;
  819. case parse_domain:
  820. if (t == '/') {
  821. hostbuf = rspamd_mempool_alloc (task->task_pool, p - c + 1);
  822. rspamd_strlcpy (hostbuf, c, p - c + 1);
  823. host = hostbuf;
  824. state = parse_slash;
  825. }
  826. p++;
  827. break;
  828. case parse_slash:
  829. c = p;
  830. if (allow_mask) {
  831. state = parse_ipv4_mask;
  832. }
  833. else {
  834. state = skip_garbadge;
  835. }
  836. cur_mask = 0;
  837. break;
  838. case parse_ipv4_mask:
  839. if (g_ascii_isdigit (t)) {
  840. /* Ignore errors here */
  841. cur_mask = cur_mask * 10 + (t - '0');
  842. }
  843. else if (t == '/') {
  844. if (cur_mask <= 32) {
  845. addr->m.dual.mask_v4 = cur_mask;
  846. }
  847. else {
  848. msg_info_spf ("bad ipv4 mask: %d", cur_mask);
  849. }
  850. state = parse_second_slash;
  851. }
  852. p++;
  853. break;
  854. case parse_second_slash:
  855. c = p;
  856. state = parse_ipv6_mask;
  857. cur_mask = 0;
  858. break;
  859. case parse_ipv6_mask:
  860. if (g_ascii_isdigit (t)) {
  861. /* Ignore errors here */
  862. cur_mask = cur_mask * 10 + (t - '0');
  863. }
  864. p++;
  865. break;
  866. case skip_garbadge:
  867. p++;
  868. break;
  869. }
  870. }
  871. /* Process end states */
  872. if (state == parse_ipv4_mask) {
  873. if (cur_mask <= 32) {
  874. addr->m.dual.mask_v4 = cur_mask;
  875. }
  876. else {
  877. msg_info_spf ("bad ipv4 mask: %d", cur_mask);
  878. }
  879. }
  880. else if (state == parse_ipv6_mask) {
  881. if (cur_mask <= 128) {
  882. addr->m.dual.mask_v6 = cur_mask;
  883. }
  884. else {
  885. msg_info_spf ("bad ipv6 mask: %d", cur_mask);
  886. }
  887. }
  888. else if (state == parse_domain && p - c > 0) {
  889. hostbuf = rspamd_mempool_alloc (task->task_pool, p - c + 1);
  890. rspamd_strlcpy (hostbuf, c, p - c + 1);
  891. host = hostbuf;
  892. }
  893. if (cur_mask == 0) {
  894. addr->m.dual.mask_v4 = 32;
  895. addr->m.dual.mask_v6 = 64;
  896. }
  897. return host;
  898. }
  899. static gboolean
  900. parse_spf_a (struct spf_record *rec,
  901. struct spf_resolved_element *resolved, struct spf_addr *addr)
  902. {
  903. struct spf_dns_cb *cb;
  904. const gchar *host = NULL;
  905. struct rspamd_task *task = rec->task;
  906. CHECK_REC (rec);
  907. host = parse_spf_domain_mask (rec, addr, resolved, TRUE);
  908. if (host == NULL) {
  909. return FALSE;
  910. }
  911. rec->dns_requests++;
  912. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  913. cb->rec = rec;
  914. cb->ptr_host = host;
  915. cb->addr = addr;
  916. cb->cur_action = SPF_RESOLVE_A;
  917. cb->resolved = resolved;
  918. msg_debug_spf ("resolve a %s", host);
  919. if (make_dns_request_task_forced (task,
  920. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_A, host)) {
  921. rec->requests_inflight++;
  922. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  923. cb->rec = rec;
  924. cb->ptr_host = host;
  925. cb->addr = addr;
  926. cb->cur_action = SPF_RESOLVE_AAA;
  927. cb->resolved = resolved;
  928. msg_debug_spf ("resolve aaa %s", host);
  929. if (make_dns_request_task_forced (task,
  930. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_AAAA, host)) {
  931. rec->requests_inflight++;
  932. }
  933. return TRUE;
  934. }
  935. return FALSE;
  936. }
  937. static gboolean
  938. parse_spf_ptr (struct spf_record *rec,
  939. struct spf_resolved_element *resolved, struct spf_addr *addr)
  940. {
  941. struct spf_dns_cb *cb;
  942. const gchar *host;
  943. gchar *ptr;
  944. struct rspamd_task *task = rec->task;
  945. CHECK_REC (rec);
  946. host = parse_spf_domain_mask (rec, addr, resolved, FALSE);
  947. rec->dns_requests++;
  948. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  949. cb->rec = rec;
  950. cb->addr = addr;
  951. cb->cur_action = SPF_RESOLVE_PTR;
  952. cb->resolved = resolved;
  953. cb->ptr_host = rspamd_mempool_strdup (task->task_pool, host);
  954. ptr =
  955. rdns_generate_ptr_from_str (rspamd_inet_address_to_string (
  956. task->from_addr));
  957. if (ptr == NULL) {
  958. return FALSE;
  959. }
  960. rspamd_mempool_add_destructor (task->task_pool, free, ptr);
  961. msg_debug_spf ("resolve ptr %s for %s", ptr, host);
  962. rec->ttl = 0;
  963. msg_debug_spf ("disable SPF caching as there is PTR expansion");
  964. if (make_dns_request_task_forced (task,
  965. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_PTR, ptr)) {
  966. rec->requests_inflight++;
  967. return TRUE;
  968. }
  969. return FALSE;
  970. }
  971. static gboolean
  972. parse_spf_mx (struct spf_record *rec,
  973. struct spf_resolved_element *resolved, struct spf_addr *addr)
  974. {
  975. struct spf_dns_cb *cb;
  976. const gchar *host;
  977. struct rspamd_task *task = rec->task;
  978. CHECK_REC (rec);
  979. host = parse_spf_domain_mask (rec, addr, resolved, TRUE);
  980. if (host == NULL) {
  981. return FALSE;
  982. }
  983. rec->dns_requests++;
  984. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  985. cb->rec = rec;
  986. cb->addr = addr;
  987. cb->cur_action = SPF_RESOLVE_MX;
  988. cb->ptr_host = host;
  989. cb->resolved = resolved;
  990. msg_debug_spf ("resolve mx for %s", host);
  991. if (make_dns_request_task_forced (task,
  992. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_MX, host)) {
  993. rec->requests_inflight++;
  994. return TRUE;
  995. }
  996. return FALSE;
  997. }
  998. static gboolean
  999. parse_spf_all (struct spf_record *rec, struct spf_addr *addr)
  1000. {
  1001. /* All is 0/0 */
  1002. memset (&addr->addr4, 0, sizeof (addr->addr4));
  1003. memset (&addr->addr6, 0, sizeof (addr->addr6));
  1004. /* Here we set all masks to 0 */
  1005. addr->m.idx = 0;
  1006. addr->flags |= RSPAMD_SPF_FLAG_ANY|RSPAMD_SPF_FLAG_RESOLVED;
  1007. msg_debug_spf ("parsed all elt");
  1008. /* Disallow +all */
  1009. if (addr->mech == SPF_PASS) {
  1010. addr->flags |= RSPAMD_SPF_FLAG_INVALID;
  1011. msg_info_spf ("allow any SPF record for %s, ignore it",
  1012. rec->sender_domain);
  1013. }
  1014. return TRUE;
  1015. }
  1016. static gboolean
  1017. parse_spf_ip4 (struct spf_record *rec, struct spf_addr *addr)
  1018. {
  1019. /* ip4:addr[/mask] */
  1020. const gchar *semicolon, *slash;
  1021. gsize len;
  1022. gchar ipbuf[INET_ADDRSTRLEN + 1];
  1023. guint32 mask;
  1024. static const guint32 min_valid_mask = 8;
  1025. semicolon = strchr (addr->spf_string, ':');
  1026. if (semicolon == NULL) {
  1027. return FALSE;
  1028. }
  1029. semicolon++;
  1030. slash = strchr (semicolon, '/');
  1031. if (slash) {
  1032. len = slash - semicolon;
  1033. }
  1034. else {
  1035. len = strlen (semicolon);
  1036. }
  1037. rspamd_strlcpy (ipbuf, semicolon, MIN (len + 1, sizeof (ipbuf)));
  1038. if (inet_pton (AF_INET, ipbuf, addr->addr4) != 1) {
  1039. return FALSE;
  1040. }
  1041. if (slash) {
  1042. mask = strtoul (slash + 1, NULL, 10);
  1043. if (mask > 32) {
  1044. return FALSE;
  1045. }
  1046. addr->m.dual.mask_v4 = mask;
  1047. if (mask < min_valid_mask) {
  1048. addr->flags |= RSPAMD_SPF_FLAG_INVALID;
  1049. msg_info_spf ("too wide SPF record for %s: %s/%d",
  1050. rec->sender_domain,
  1051. ipbuf, addr->m.dual.mask_v4);
  1052. }
  1053. }
  1054. else {
  1055. addr->m.dual.mask_v4 = 32;
  1056. }
  1057. addr->flags |= RSPAMD_SPF_FLAG_IPV4|RSPAMD_SPF_FLAG_RESOLVED;
  1058. msg_debug_spf ("parsed ipv4 record %s/%d", ipbuf, addr->m.dual.mask_v4);
  1059. return TRUE;
  1060. }
  1061. static gboolean
  1062. parse_spf_ip6 (struct spf_record *rec, struct spf_addr *addr)
  1063. {
  1064. /* ip6:addr[/mask] */
  1065. const gchar *semicolon, *slash;
  1066. gsize len;
  1067. gchar ipbuf[INET6_ADDRSTRLEN + 1];
  1068. guint32 mask;
  1069. static const guint32 min_valid_mask = 8;
  1070. semicolon = strchr (addr->spf_string, ':');
  1071. if (semicolon == NULL) {
  1072. return FALSE;
  1073. }
  1074. semicolon++;
  1075. slash = strchr (semicolon, '/');
  1076. if (slash) {
  1077. len = slash - semicolon;
  1078. }
  1079. else {
  1080. len = strlen (semicolon);
  1081. }
  1082. rspamd_strlcpy (ipbuf, semicolon, MIN (len + 1, sizeof (ipbuf)));
  1083. if (inet_pton (AF_INET6, ipbuf, addr->addr6) != 1) {
  1084. return FALSE;
  1085. }
  1086. if (slash) {
  1087. mask = strtoul (slash + 1, NULL, 10);
  1088. if (mask > 128) {
  1089. return FALSE;
  1090. }
  1091. addr->m.dual.mask_v6 = mask;
  1092. if (mask < min_valid_mask) {
  1093. addr->flags |= RSPAMD_SPF_FLAG_INVALID;
  1094. msg_info_spf ("too wide SPF record for %s: %s/%d",
  1095. rec->sender_domain,
  1096. ipbuf, addr->m.dual.mask_v6);
  1097. }
  1098. }
  1099. else {
  1100. addr->m.dual.mask_v6 = 128;
  1101. }
  1102. addr->flags |= RSPAMD_SPF_FLAG_IPV6|RSPAMD_SPF_FLAG_RESOLVED;
  1103. msg_debug_spf ("parsed ipv6 record %s/%d", ipbuf, addr->m.dual.mask_v6);
  1104. return TRUE;
  1105. }
  1106. static gboolean
  1107. parse_spf_include (struct spf_record *rec, struct spf_addr *addr)
  1108. {
  1109. struct spf_dns_cb *cb;
  1110. const gchar *domain;
  1111. struct rspamd_task *task = rec->task;
  1112. CHECK_REC (rec);
  1113. domain = strchr (addr->spf_string, ':');
  1114. if (domain == NULL) {
  1115. return FALSE;
  1116. }
  1117. domain++;
  1118. rec->dns_requests++;
  1119. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  1120. cb->rec = rec;
  1121. cb->addr = addr;
  1122. cb->cur_action = SPF_RESOLVE_INCLUDE;
  1123. addr->m.idx = rec->resolved->len;
  1124. cb->resolved = rspamd_spf_new_addr_list (rec, domain);
  1125. cb->ptr_host = domain;
  1126. /* Set reference */
  1127. addr->flags |= RSPAMD_SPF_FLAG_REFERENCE;
  1128. msg_debug_spf ("resolve include %s", domain);
  1129. if (make_dns_request_task_forced (task,
  1130. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_TXT, domain)) {
  1131. rec->requests_inflight++;
  1132. return TRUE;
  1133. }
  1134. return FALSE;
  1135. }
  1136. static gboolean
  1137. parse_spf_exp (struct spf_record *rec, struct spf_addr *addr)
  1138. {
  1139. msg_info_spf ("exp record is ignored");
  1140. return TRUE;
  1141. }
  1142. static gboolean
  1143. parse_spf_redirect (struct spf_record *rec,
  1144. struct spf_resolved_element *resolved, struct spf_addr *addr)
  1145. {
  1146. struct spf_dns_cb *cb;
  1147. const gchar *domain;
  1148. struct rspamd_task *task = rec->task;
  1149. CHECK_REC (rec);
  1150. domain = strchr (addr->spf_string, '=');
  1151. if (domain == NULL) {
  1152. return FALSE;
  1153. }
  1154. domain++;
  1155. rec->dns_requests++;
  1156. resolved->redirected = TRUE;
  1157. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  1158. /* Set reference */
  1159. addr->flags |= RSPAMD_SPF_FLAG_REFERENCE | RSPAMD_SPF_FLAG_REDIRECT;
  1160. addr->m.idx = rec->resolved->len;
  1161. cb->rec = rec;
  1162. cb->addr = addr;
  1163. cb->cur_action = SPF_RESOLVE_REDIRECT;
  1164. cb->resolved = rspamd_spf_new_addr_list (rec, domain);
  1165. cb->ptr_host = domain;
  1166. msg_debug_spf ("resolve redirect %s", domain);
  1167. if (make_dns_request_task_forced (task,
  1168. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_TXT, domain)) {
  1169. rec->requests_inflight++;
  1170. return TRUE;
  1171. }
  1172. return FALSE;
  1173. }
  1174. static gboolean
  1175. parse_spf_exists (struct spf_record *rec, struct spf_addr *addr)
  1176. {
  1177. struct spf_dns_cb *cb;
  1178. const gchar *host;
  1179. struct rspamd_task *task = rec->task;
  1180. struct spf_resolved_element *resolved;
  1181. resolved = g_ptr_array_index (rec->resolved, rec->resolved->len - 1);
  1182. CHECK_REC (rec);
  1183. host = strchr (addr->spf_string, ':');
  1184. if (host == NULL) {
  1185. msg_info_spf ("bad SPF exist record: %s", addr->spf_string);
  1186. return FALSE;
  1187. }
  1188. host++;
  1189. rec->dns_requests++;
  1190. cb = rspamd_mempool_alloc (task->task_pool, sizeof (struct spf_dns_cb));
  1191. cb->rec = rec;
  1192. cb->addr = addr;
  1193. cb->cur_action = SPF_RESOLVE_EXISTS;
  1194. cb->resolved = resolved;
  1195. cb->ptr_host = host;
  1196. msg_debug_spf ("resolve exists %s", host);
  1197. if (make_dns_request_task_forced (task,
  1198. spf_record_dns_callback, (void *) cb, RDNS_REQUEST_A, host)) {
  1199. rec->requests_inflight++;
  1200. return TRUE;
  1201. }
  1202. return FALSE;
  1203. }
  1204. static gsize
  1205. rspamd_spf_split_elt (const gchar *val, gsize len, gint *pos,
  1206. gsize poslen, gchar delim)
  1207. {
  1208. const gchar *p, *end;
  1209. guint cur_pos = 0, cur_st = 0, nsub = 0;
  1210. p = val;
  1211. end = val + len;
  1212. while (p < end && cur_pos + 2 < poslen) {
  1213. if (*p == delim) {
  1214. if (p - val > cur_st) {
  1215. pos[cur_pos] = cur_st;
  1216. pos[cur_pos + 1] = p - val;
  1217. cur_st = p - val + 1;
  1218. cur_pos += 2;
  1219. nsub ++;
  1220. }
  1221. p ++;
  1222. }
  1223. else {
  1224. p ++;
  1225. }
  1226. }
  1227. if (cur_pos + 2 < poslen) {
  1228. if (end - val > cur_st) {
  1229. pos[cur_pos] = cur_st;
  1230. pos[cur_pos + 1] = end - val;
  1231. nsub ++;
  1232. }
  1233. }
  1234. else {
  1235. pos[cur_pos] = p - val;
  1236. pos[cur_pos + 1] = end - val;
  1237. nsub ++;
  1238. }
  1239. return nsub;
  1240. }
  1241. static gsize
  1242. rspamd_spf_process_substitution (const gchar *macro_value,
  1243. gsize macro_len, guint ndelim, gchar delim, gboolean reversed,
  1244. gchar *dest)
  1245. {
  1246. gchar *d = dest;
  1247. const gchar canon_delim = '.';
  1248. guint vlen, i;
  1249. gint pos[49 * 2], tlen;
  1250. if (!reversed && ndelim == 0 && delim == canon_delim) {
  1251. /* Trivial case */
  1252. memcpy (dest, macro_value, macro_len);
  1253. return macro_len;
  1254. }
  1255. vlen = rspamd_spf_split_elt (macro_value, macro_len,
  1256. pos, G_N_ELEMENTS (pos), delim);
  1257. if (vlen > 0) {
  1258. if (reversed) {
  1259. for (i = vlen - 1; ; i--) {
  1260. tlen = pos[i * 2 + 1] - pos[i * 2];
  1261. if (i != 0) {
  1262. memcpy (d, &macro_value[pos[i * 2]], tlen);
  1263. d += tlen;
  1264. *d++ = canon_delim;
  1265. }
  1266. else {
  1267. memcpy (d, &macro_value[pos[i * 2]], tlen);
  1268. d += tlen;
  1269. break;
  1270. }
  1271. }
  1272. }
  1273. else {
  1274. for (i = 0; i < vlen; i++) {
  1275. tlen = pos[i * 2 + 1] - pos[i * 2];
  1276. if (i != vlen - 1) {
  1277. memcpy (d, &macro_value[pos[i * 2]], tlen);
  1278. d += tlen;
  1279. *d++ = canon_delim;
  1280. }
  1281. else {
  1282. memcpy (d, &macro_value[pos[i * 2]], tlen);
  1283. d += tlen;
  1284. }
  1285. }
  1286. }
  1287. }
  1288. else {
  1289. /* Trivial case */
  1290. memcpy (dest, macro_value, macro_len);
  1291. return macro_len;
  1292. }
  1293. return (d - dest);
  1294. }
  1295. static const gchar *
  1296. expand_spf_macro (struct spf_record *rec, struct spf_resolved_element *resolved,
  1297. const gchar *begin)
  1298. {
  1299. const gchar *p, *macro_value = NULL;
  1300. gchar *c, *new, *tmp, delim = '.';
  1301. gsize len = 0, slen = 0, macro_len = 0;
  1302. gint state = 0, ndelim = 0;
  1303. gchar ip_buf[INET6_ADDRSTRLEN + 1];
  1304. gboolean need_expand = FALSE, reversed;
  1305. struct rspamd_task *task;
  1306. g_assert (rec != NULL);
  1307. g_assert (begin != NULL);
  1308. task = rec->task;
  1309. p = begin;
  1310. /* Calculate length */
  1311. while (*p) {
  1312. switch (state) {
  1313. case 0:
  1314. /* Skip any character and wait for % in input */
  1315. if (*p == '%') {
  1316. state = 1;
  1317. }
  1318. else {
  1319. len++;
  1320. }
  1321. slen++;
  1322. p++;
  1323. break;
  1324. case 1:
  1325. /* We got % sign, so we should whether wait for { or for - or for _ or for % */
  1326. if (*p == '%' || *p == '_') {
  1327. /* Just a single % sign or space */
  1328. len++;
  1329. state = 0;
  1330. }
  1331. else if (*p == '-') {
  1332. /* %20 */
  1333. len += sizeof ("%20") - 1;
  1334. state = 0;
  1335. }
  1336. else if (*p == '{') {
  1337. state = 2;
  1338. }
  1339. else {
  1340. /* Something unknown */
  1341. msg_info_spf (
  1342. "<%s>: spf error for domain %s: unknown spf element",
  1343. task->message_id, rec->sender_domain);
  1344. return begin;
  1345. }
  1346. p++;
  1347. slen++;
  1348. break;
  1349. case 2:
  1350. /* Read macro name */
  1351. switch (g_ascii_tolower (*p)) {
  1352. case 'i':
  1353. len += INET6_ADDRSTRLEN - 1;
  1354. break;
  1355. case 's':
  1356. len += strlen (rec->sender);
  1357. break;
  1358. case 'l':
  1359. len += strlen (rec->local_part);
  1360. break;
  1361. case 'o':
  1362. len += strlen (rec->sender_domain);
  1363. break;
  1364. case 'd':
  1365. len += strlen (resolved->cur_domain);
  1366. break;
  1367. case 'v':
  1368. len += sizeof ("in-addr") - 1;
  1369. break;
  1370. case 'h':
  1371. if (task->helo) {
  1372. len += strlen (task->helo);
  1373. }
  1374. break;
  1375. default:
  1376. msg_info_spf (
  1377. "<%s>: spf error for domain %s: unknown or "
  1378. "unsupported spf macro %c in %s",
  1379. task->message_id,
  1380. rec->sender_domain,
  1381. *p,
  1382. begin);
  1383. return begin;
  1384. }
  1385. p++;
  1386. slen++;
  1387. state = 3;
  1388. break;
  1389. case 3:
  1390. /* Read modifier */
  1391. if (*p == '}') {
  1392. state = 0;
  1393. need_expand = TRUE;
  1394. }
  1395. p++;
  1396. slen++;
  1397. break;
  1398. default:
  1399. g_assert_not_reached ();
  1400. }
  1401. }
  1402. if (!need_expand) {
  1403. /* No expansion needed */
  1404. return begin;
  1405. }
  1406. new = rspamd_mempool_alloc (task->task_pool, len + 1);
  1407. /* Reduce TTL to avoid caching of records with macros */
  1408. if (rec->ttl != 0) {
  1409. rec->ttl = 0;
  1410. msg_debug_spf ("disable SPF caching as there is macro expansion");
  1411. }
  1412. c = new;
  1413. p = begin;
  1414. state = 0;
  1415. /* Begin macro expansion */
  1416. while (*p) {
  1417. switch (state) {
  1418. case 0:
  1419. /* Skip any character and wait for % in input */
  1420. if (*p == '%') {
  1421. state = 1;
  1422. }
  1423. else {
  1424. *c = *p;
  1425. c++;
  1426. }
  1427. p++;
  1428. break;
  1429. case 1:
  1430. /* We got % sign, so we should whether wait for { or for - or for _ or for % */
  1431. if (*p == '%') {
  1432. /* Just a single % sign or space */
  1433. *c++ = '%';
  1434. state = 0;
  1435. }
  1436. else if (*p == '_') {
  1437. *c++ = ' ';
  1438. state = 0;
  1439. }
  1440. else if (*p == '-') {
  1441. /* %20 */
  1442. *c++ = '%';
  1443. *c++ = '2';
  1444. *c++ = '0';
  1445. state = 0;
  1446. }
  1447. else if (*p == '{') {
  1448. state = 2;
  1449. }
  1450. else {
  1451. /* Something unknown */
  1452. msg_info_spf (
  1453. "<%s>: spf error for domain %s: unknown spf element",
  1454. task->message_id, rec->sender_domain);
  1455. return begin;
  1456. }
  1457. p++;
  1458. break;
  1459. case 2:
  1460. /* Read macro name */
  1461. switch (g_ascii_tolower (*p)) {
  1462. case 'i':
  1463. if (task->from_addr) {
  1464. macro_len = rspamd_strlcpy (ip_buf,
  1465. rspamd_inet_address_to_string (task->from_addr),
  1466. sizeof (ip_buf));
  1467. macro_value = ip_buf;
  1468. }
  1469. else {
  1470. macro_len = rspamd_snprintf (ip_buf, sizeof (ip_buf),
  1471. "127.0.0.1");
  1472. macro_value = ip_buf;
  1473. }
  1474. break;
  1475. case 's':
  1476. if (rec->sender) {
  1477. macro_len = strlen (rec->sender);
  1478. macro_value = rec->sender;
  1479. }
  1480. else {
  1481. macro_len = sizeof ("unknown") - 1;
  1482. macro_value = "unknown";
  1483. }
  1484. break;
  1485. case 'l':
  1486. if (rec->local_part) {
  1487. macro_len = strlen (rec->local_part);
  1488. macro_value = rec->local_part;
  1489. }
  1490. else {
  1491. macro_len = sizeof ("unknown") - 1;
  1492. macro_value = "unknown";
  1493. }
  1494. break;
  1495. case 'o':
  1496. if (rec->sender_domain) {
  1497. macro_len = strlen (rec->sender_domain);
  1498. macro_value = rec->sender_domain;
  1499. }
  1500. else {
  1501. macro_len = sizeof ("unknown") - 1;
  1502. macro_value = "unknown";
  1503. }
  1504. break;
  1505. case 'd':
  1506. if (resolved && resolved->cur_domain) {
  1507. macro_len = strlen (resolved->cur_domain);
  1508. macro_value = resolved->cur_domain;
  1509. }
  1510. else {
  1511. macro_len = sizeof ("unknown") - 1;
  1512. macro_value = "unknown";
  1513. }
  1514. break;
  1515. case 'v':
  1516. if (task->from_addr) {
  1517. if (rspamd_inet_address_get_af (task->from_addr) == AF_INET) {
  1518. macro_len = sizeof ("in-addr") - 1;
  1519. macro_value = "in-addr";
  1520. } else {
  1521. macro_len = sizeof ("ip6") - 1;
  1522. macro_value = "ip6";
  1523. }
  1524. }
  1525. else {
  1526. macro_len = sizeof ("in-addr") - 1;
  1527. macro_value = "in-addr";
  1528. }
  1529. break;
  1530. case 'h':
  1531. if (task->helo) {
  1532. tmp = strchr (task->helo, '@');
  1533. if (tmp) {
  1534. macro_len = strlen (tmp + 1);
  1535. macro_value = tmp + 1;
  1536. }
  1537. else {
  1538. macro_len = strlen (task->helo);
  1539. macro_value = task->helo;
  1540. }
  1541. }
  1542. else {
  1543. macro_len = sizeof ("unknown") - 1;
  1544. macro_value = "unknown";
  1545. }
  1546. break;
  1547. default:
  1548. msg_info_spf (
  1549. "<%s>: spf error for domain %s: unknown or "
  1550. "unsupported spf macro %c in %s",
  1551. task->message_id,
  1552. rec->sender_domain,
  1553. *p,
  1554. begin);
  1555. return begin;
  1556. }
  1557. p++;
  1558. state = 3;
  1559. ndelim = 0;
  1560. delim = '.';
  1561. reversed = FALSE;
  1562. break;
  1563. case 3:
  1564. /* Read modifier */
  1565. if (*p == '}') {
  1566. state = 0;
  1567. len = rspamd_spf_process_substitution (macro_value,
  1568. macro_len, ndelim, delim, reversed, c);
  1569. c += len;
  1570. }
  1571. else if (*p == 'r' && len != 0) {
  1572. reversed = TRUE;
  1573. }
  1574. else if (g_ascii_isdigit (*p)) {
  1575. ndelim = strtoul (p, &tmp, 10);
  1576. if (tmp == NULL || tmp == p) {
  1577. p ++;
  1578. }
  1579. else {
  1580. p = tmp;
  1581. continue;
  1582. }
  1583. }
  1584. else if (*p == '+' || *p == '-' ||
  1585. *p == '.' || *p == ',' || *p == '/' || *p == '_' ||
  1586. *p == '=') {
  1587. delim = *p;
  1588. }
  1589. else {
  1590. msg_info_spf (
  1591. "<%s>: spf error for domain %s: unknown or "
  1592. "unsupported spf macro %c in %s",
  1593. task->message_id,
  1594. rec->sender_domain,
  1595. *p,
  1596. begin);
  1597. return begin;
  1598. }
  1599. p++;
  1600. break;
  1601. }
  1602. }
  1603. /* Null terminate */
  1604. *c = '\0';
  1605. return new;
  1606. }
  1607. /* Read current element and try to parse record */
  1608. static gboolean
  1609. parse_spf_record (struct spf_record *rec, struct spf_resolved_element *resolved,
  1610. const gchar *elt)
  1611. {
  1612. struct spf_addr *addr = NULL;
  1613. gboolean res = FALSE;
  1614. const gchar *begin;
  1615. struct rspamd_task *task;
  1616. gchar t;
  1617. g_assert (elt != NULL);
  1618. g_assert (rec != NULL);
  1619. if (*elt == '\0' || resolved->redirected) {
  1620. return TRUE;
  1621. }
  1622. task = rec->task;
  1623. begin = expand_spf_macro (rec, resolved, elt);
  1624. addr = rspamd_spf_new_addr (rec, resolved, begin);
  1625. g_assert (addr != NULL);
  1626. t = g_ascii_tolower (addr->spf_string[0]);
  1627. begin = addr->spf_string;
  1628. /* Now check what we have */
  1629. switch (t) {
  1630. case 'a':
  1631. /* all or a */
  1632. if (g_ascii_strncasecmp (begin, SPF_ALL,
  1633. sizeof (SPF_ALL) - 1) == 0) {
  1634. res = parse_spf_all (rec, addr);
  1635. }
  1636. else if (g_ascii_strncasecmp (begin, SPF_A,
  1637. sizeof (SPF_A) - 1) == 0) {
  1638. res = parse_spf_a (rec, resolved, addr);
  1639. }
  1640. else {
  1641. msg_info_spf (
  1642. "<%s>: spf error for domain %s: bad spf command %s",
  1643. task->message_id, rec->sender_domain, begin);
  1644. }
  1645. break;
  1646. case 'i':
  1647. /* include or ip4 */
  1648. if (g_ascii_strncasecmp (begin, SPF_IP4,
  1649. sizeof (SPF_IP4) - 1) == 0) {
  1650. res = parse_spf_ip4 (rec, addr);
  1651. }
  1652. else if (g_ascii_strncasecmp (begin, SPF_INCLUDE,
  1653. sizeof (SPF_INCLUDE) - 1) == 0) {
  1654. res = parse_spf_include (rec, addr);
  1655. }
  1656. else if (g_ascii_strncasecmp (begin, SPF_IP6, sizeof (SPF_IP6) -
  1657. 1) == 0) {
  1658. res = parse_spf_ip6 (rec, addr);
  1659. }
  1660. else {
  1661. msg_info_spf (
  1662. "<%s>: spf error for domain %s: bad spf command %s",
  1663. task->message_id, rec->sender_domain, begin);
  1664. }
  1665. break;
  1666. case 'm':
  1667. /* mx */
  1668. if (g_ascii_strncasecmp (begin, SPF_MX, sizeof (SPF_MX) - 1) == 0) {
  1669. res = parse_spf_mx (rec, resolved, addr);
  1670. }
  1671. else {
  1672. msg_info_spf (
  1673. "<%s>: spf error for domain %s: bad spf command %s",
  1674. task->message_id, rec->sender_domain, begin);
  1675. }
  1676. break;
  1677. case 'p':
  1678. /* ptr */
  1679. if (g_ascii_strncasecmp (begin, SPF_PTR,
  1680. sizeof (SPF_PTR) - 1) == 0) {
  1681. res = parse_spf_ptr (rec, resolved, addr);
  1682. }
  1683. else {
  1684. msg_info_spf (
  1685. "<%s>: spf error for domain %s: bad spf command %s",
  1686. task->message_id, rec->sender_domain, begin);
  1687. }
  1688. break;
  1689. case 'e':
  1690. /* exp or exists */
  1691. if (g_ascii_strncasecmp (begin, SPF_EXP,
  1692. sizeof (SPF_EXP) - 1) == 0) {
  1693. res = parse_spf_exp (rec, addr);
  1694. }
  1695. else if (g_ascii_strncasecmp (begin, SPF_EXISTS,
  1696. sizeof (SPF_EXISTS) - 1) == 0) {
  1697. res = parse_spf_exists (rec, addr);
  1698. }
  1699. else {
  1700. msg_info_spf (
  1701. "<%s>: spf error for domain %s: bad spf command %s",
  1702. task->message_id, rec->sender_domain, begin);
  1703. }
  1704. break;
  1705. case 'r':
  1706. /* redirect */
  1707. if (g_ascii_strncasecmp (begin, SPF_REDIRECT,
  1708. sizeof (SPF_REDIRECT) - 1) == 0) {
  1709. res = parse_spf_redirect (rec, resolved, addr);
  1710. }
  1711. else {
  1712. msg_info_spf (
  1713. "<%s>: spf error for domain %s: bad spf command %s",
  1714. task->message_id, rec->sender_domain, begin);
  1715. }
  1716. break;
  1717. case 'v':
  1718. if (g_ascii_strncasecmp (begin, "v=spf",
  1719. sizeof ("v=spf") - 1) == 0) {
  1720. /* Skip this element till the end of record */
  1721. while (*begin && !g_ascii_isspace (*begin)) {
  1722. begin++;
  1723. }
  1724. }
  1725. break;
  1726. default:
  1727. msg_info_spf ("<%s>: spf error for domain %s: bad spf command %s",
  1728. task->message_id, rec->sender_domain, begin);
  1729. break;
  1730. }
  1731. if (res) {
  1732. addr->flags |= RSPAMD_SPF_FLAG_PARSED;
  1733. }
  1734. return res;
  1735. }
  1736. static void
  1737. parse_spf_scopes (struct spf_record *rec, gchar **begin)
  1738. {
  1739. for (; ;) {
  1740. if (g_ascii_strncasecmp (*begin, SPF_SCOPE_PRA, sizeof (SPF_SCOPE_PRA) -
  1741. 1) == 0) {
  1742. *begin += sizeof (SPF_SCOPE_PRA) - 1;
  1743. /* XXX: Implement actual PRA check */
  1744. /* extract_pra_info (rec); */
  1745. continue;
  1746. }
  1747. else if (g_ascii_strncasecmp (*begin, SPF_SCOPE_MFROM,
  1748. sizeof (SPF_SCOPE_MFROM) - 1) == 0) {
  1749. /* mfrom is standard spf1 check */
  1750. *begin += sizeof (SPF_SCOPE_MFROM) - 1;
  1751. continue;
  1752. }
  1753. else if (**begin != ',') {
  1754. break;
  1755. }
  1756. (*begin)++;
  1757. }
  1758. }
  1759. static gboolean
  1760. start_spf_parse (struct spf_record *rec, struct spf_resolved_element *resolved,
  1761. gchar *begin)
  1762. {
  1763. gchar **elts, **cur_elt;
  1764. gsize len;
  1765. /* Skip spaces */
  1766. while (g_ascii_isspace (*begin)) {
  1767. begin++;
  1768. }
  1769. len = strlen (begin);
  1770. if (g_ascii_strncasecmp (begin, SPF_VER1_STR, sizeof (SPF_VER1_STR) - 1) ==
  1771. 0) {
  1772. begin += sizeof (SPF_VER1_STR) - 1;
  1773. while (g_ascii_isspace (*begin) && *begin) {
  1774. begin++;
  1775. }
  1776. }
  1777. else if (g_ascii_strncasecmp (begin, SPF_VER2_STR, sizeof (SPF_VER2_STR) -
  1778. 1) == 0) {
  1779. /* Skip one number of record, so no we are here spf2.0/ */
  1780. begin += sizeof (SPF_VER2_STR);
  1781. if (*begin != '/') {
  1782. msg_info_spf ("<%s>: spf error for domain %s: sender id is invalid",
  1783. rec->task->message_id, rec->sender_domain);
  1784. }
  1785. else {
  1786. begin++;
  1787. parse_spf_scopes (rec, &begin);
  1788. }
  1789. /* Now common spf record */
  1790. }
  1791. else {
  1792. msg_debug_spf (
  1793. "<%s>: spf error for domain %s: bad spf record start: %*s",
  1794. rec->task->message_id,
  1795. rec->sender_domain,
  1796. (gint)len,
  1797. begin);
  1798. return FALSE;
  1799. }
  1800. while (g_ascii_isspace (*begin) && *begin) {
  1801. begin++;
  1802. }
  1803. elts = g_strsplit_set (begin, " ", 0);
  1804. if (elts) {
  1805. cur_elt = elts;
  1806. while (*cur_elt) {
  1807. parse_spf_record (rec, resolved, *cur_elt);
  1808. cur_elt++;
  1809. }
  1810. g_strfreev (elts);
  1811. }
  1812. rspamd_spf_maybe_return (rec);
  1813. return TRUE;
  1814. }
  1815. static void
  1816. spf_dns_callback (struct rdns_reply *reply, gpointer arg)
  1817. {
  1818. struct spf_record *rec = arg;
  1819. struct spf_resolved_element *resolved = NULL;
  1820. struct spf_addr *addr;
  1821. rec->requests_inflight--;
  1822. if (reply->code == RDNS_RC_NOERROR) {
  1823. resolved = rspamd_spf_new_addr_list (rec, rec->sender_domain);
  1824. if (rec->resolved->len == 1) {
  1825. /* Top level resolved element */
  1826. rec->ttl = reply->entries->ttl;
  1827. }
  1828. }
  1829. else if ((reply->code == RDNS_RC_NOREC || reply->code == RDNS_RC_NXDOMAIN)
  1830. && rec->dns_requests == 0) {
  1831. resolved = rspamd_spf_new_addr_list (rec, rec->sender_domain);
  1832. addr = g_malloc0 (sizeof(*addr));
  1833. addr->flags = 0;
  1834. addr->flags |= RSPAMD_SPF_FLAG_NA;
  1835. g_ptr_array_insert (resolved->elts, 0, addr);
  1836. }
  1837. else if (reply->code != RDNS_RC_NOREC && reply->code != RDNS_RC_NXDOMAIN
  1838. && rec->dns_requests == 0) {
  1839. resolved = rspamd_spf_new_addr_list (rec, rec->sender_domain);
  1840. addr = g_malloc0 (sizeof(*addr));
  1841. addr->flags = 0;
  1842. addr->flags |= RSPAMD_SPF_FLAG_TEMPFAIL;
  1843. g_ptr_array_insert (resolved->elts, 0, addr);
  1844. }
  1845. if (resolved) {
  1846. if (!spf_process_txt_record (rec, resolved, reply)) {
  1847. resolved = g_ptr_array_index(rec->resolved, 0);
  1848. if (rec->resolved->len > 1) {
  1849. addr = g_ptr_array_index(resolved->elts, 0);
  1850. if ((reply->code == RDNS_RC_NOREC || reply->code == RDNS_RC_NXDOMAIN)
  1851. && (addr->flags & RSPAMD_SPF_FLAG_REDIRECT)) {
  1852. addr->flags |= RSPAMD_SPF_FLAG_PERMFAIL;
  1853. } else {
  1854. addr->flags |= RSPAMD_SPF_FLAG_TEMPFAIL;
  1855. }
  1856. }
  1857. else {
  1858. addr = g_malloc0 (sizeof(*addr));
  1859. addr->flags = 0;
  1860. if (reply->code == RDNS_RC_NOREC || reply->code == RDNS_RC_NXDOMAIN
  1861. || reply->code == RDNS_RC_NOERROR) {
  1862. addr->flags |= RSPAMD_SPF_FLAG_NA;
  1863. }
  1864. else {
  1865. addr->flags |= RSPAMD_SPF_FLAG_TEMPFAIL;
  1866. }
  1867. g_ptr_array_insert (resolved->elts, 0, addr);
  1868. }
  1869. }
  1870. }
  1871. rspamd_spf_maybe_return (rec);
  1872. }
  1873. struct rspamd_spf_cred {
  1874. gchar *local_part;
  1875. gchar *domain;
  1876. gchar *sender;
  1877. };
  1878. struct rspamd_spf_cred *
  1879. rspamd_spf_cache_domain (struct rspamd_task *task)
  1880. {
  1881. struct rspamd_email_address *addr;
  1882. struct rspamd_spf_cred *cred = NULL;
  1883. addr = rspamd_task_get_sender (task);
  1884. if (!addr || (addr->flags & RSPAMD_EMAIL_ADDR_EMPTY)) {
  1885. /* Get domain from helo */
  1886. if (task->helo) {
  1887. GString *fs = g_string_new ("");
  1888. cred = rspamd_mempool_alloc (task->task_pool, sizeof (*cred));
  1889. cred->domain = task->helo;
  1890. cred->local_part = "postmaster";
  1891. rspamd_printf_gstring (fs, "postmaster@%s", cred->domain);
  1892. cred->sender = fs->str;
  1893. rspamd_mempool_add_destructor (task->task_pool,
  1894. rspamd_gstring_free_hard, fs);
  1895. }
  1896. }
  1897. else {
  1898. rspamd_ftok_t tok;
  1899. cred = rspamd_mempool_alloc (task->task_pool, sizeof (*cred));
  1900. tok.begin = addr->domain;
  1901. tok.len = addr->domain_len;
  1902. cred->domain = rspamd_mempool_ftokdup (task->task_pool, &tok);
  1903. tok.begin = addr->user;
  1904. tok.len = addr->user_len;
  1905. cred->local_part = rspamd_mempool_ftokdup (task->task_pool, &tok);
  1906. tok.begin = addr->addr;
  1907. tok.len = addr->addr_len;
  1908. cred->sender = rspamd_mempool_ftokdup (task->task_pool, &tok);
  1909. }
  1910. if (cred) {
  1911. rspamd_mempool_set_variable (task->task_pool, RSPAMD_MEMPOOL_SPF_DOMAIN,
  1912. cred, NULL);
  1913. }
  1914. return cred;
  1915. }
  1916. const gchar *
  1917. rspamd_spf_get_domain (struct rspamd_task *task)
  1918. {
  1919. gchar *domain = NULL;
  1920. struct rspamd_spf_cred *cred;
  1921. cred = rspamd_mempool_get_variable (task->task_pool,
  1922. RSPAMD_MEMPOOL_SPF_DOMAIN);
  1923. if (!cred) {
  1924. cred = rspamd_spf_cache_domain (task);
  1925. }
  1926. if (cred) {
  1927. domain = cred->domain;
  1928. }
  1929. return domain;
  1930. }
  1931. gboolean
  1932. rspamd_spf_resolve (struct rspamd_task *task, spf_cb_t callback,
  1933. gpointer cbdata)
  1934. {
  1935. struct spf_record *rec;
  1936. struct rspamd_spf_cred *cred;
  1937. cred = rspamd_mempool_get_variable (task->task_pool,
  1938. RSPAMD_MEMPOOL_SPF_DOMAIN);
  1939. if (!cred) {
  1940. cred = rspamd_spf_cache_domain (task);
  1941. }
  1942. if (!cred || !cred->domain) {
  1943. return FALSE;
  1944. }
  1945. rec = rspamd_mempool_alloc0 (task->task_pool, sizeof (struct spf_record));
  1946. rec->task = task;
  1947. rec->callback = callback;
  1948. rec->cbdata = cbdata;
  1949. rec->resolved = g_ptr_array_sized_new (8);
  1950. /* Add destructor */
  1951. rspamd_mempool_add_destructor (task->task_pool,
  1952. (rspamd_mempool_destruct_t) spf_record_destructor,
  1953. rec);
  1954. /* Extract from data */
  1955. rec->sender = cred->sender;
  1956. rec->local_part = cred->local_part;
  1957. rec->sender_domain = cred->domain;
  1958. if (make_dns_request_task_forced (task,
  1959. spf_dns_callback,
  1960. (void *) rec, RDNS_REQUEST_TXT, rec->sender_domain)) {
  1961. rec->requests_inflight++;
  1962. return TRUE;
  1963. }
  1964. return FALSE;
  1965. }
  1966. struct spf_resolved *
  1967. spf_record_ref (struct spf_resolved *rec)
  1968. {
  1969. REF_RETAIN (rec);
  1970. return rec;
  1971. }
  1972. void
  1973. spf_record_unref (struct spf_resolved *rec)
  1974. {
  1975. REF_RELEASE (rec);
  1976. }