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

map.c 68KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833
  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. /*
  17. * Implementation of map files handling
  18. */
  19. #include "config.h"
  20. #include "map.h"
  21. #include "map_private.h"
  22. #include "http_connection.h"
  23. #include "http_private.h"
  24. #include "rspamd.h"
  25. #include "contrib/zstd/zstd.h"
  26. #include "contrib/libev/ev.h"
  27. #undef MAP_DEBUG_REFS
  28. #ifdef MAP_DEBUG_REFS
  29. #define MAP_RETAIN(x, t) do { \
  30. msg_err (G_GNUC_PRETTY_FUNCTION ": " t ": retain ref %p, refcount: %d -> %d", (x), (x)->ref.refcount, (x)->ref.refcount + 1); \
  31. REF_RETAIN(x); \
  32. } while (0)
  33. #define MAP_RELEASE(x, t) do { \
  34. msg_err (G_GNUC_PRETTY_FUNCTION ": " t ": release ref %p, refcount: %d -> %d", (x), (x)->ref.refcount, (x)->ref.refcount - 1); \
  35. REF_RELEASE(x); \
  36. } while (0)
  37. #else
  38. #define MAP_RETAIN(x, t) REF_RETAIN(x)
  39. #define MAP_RELEASE(x, t) REF_RELEASE(x)
  40. #endif
  41. static void free_http_cbdata_common (struct http_callback_data *cbd,
  42. gboolean plan_new);
  43. static void free_http_cbdata_dtor (gpointer p);
  44. static void free_http_cbdata (struct http_callback_data *cbd);
  45. static void rspamd_map_process_periodic (struct map_periodic_cbdata *cbd);
  46. static void rspamd_map_schedule_periodic (struct rspamd_map *map, gboolean locked,
  47. gboolean initial, gboolean errored);
  48. static gboolean read_map_file_chunks (struct rspamd_map *map,
  49. struct map_cb_data *cbdata,
  50. const gchar *fname,
  51. gsize len,
  52. goffset off);
  53. static gboolean rspamd_map_save_http_cached_file (struct rspamd_map *map,
  54. struct rspamd_map_backend *bk,
  55. struct http_map_data *htdata,
  56. const guchar *data,
  57. gsize len);
  58. guint rspamd_map_log_id = (guint)-1;
  59. RSPAMD_CONSTRUCTOR(rspamd_map_log_init)
  60. {
  61. rspamd_map_log_id = rspamd_logger_add_debug_module("map");
  62. }
  63. /**
  64. * Write HTTP request
  65. */
  66. static void
  67. write_http_request (struct http_callback_data *cbd)
  68. {
  69. gchar datebuf[128];
  70. struct rspamd_http_message *msg;
  71. struct rspamd_map *map;
  72. map = cbd->map;
  73. msg = rspamd_http_new_message (HTTP_REQUEST);
  74. if (cbd->bk->protocol == MAP_PROTO_HTTPS) {
  75. msg->flags |= RSPAMD_HTTP_FLAG_SSL;
  76. }
  77. if (cbd->check) {
  78. msg->method = HTTP_HEAD;
  79. }
  80. if (cbd->stage == map_load_file) {
  81. msg->url = rspamd_fstring_append (msg->url,
  82. cbd->data->path, strlen (cbd->data->path));
  83. if (cbd->check && cbd->stage == map_load_file) {
  84. if (cbd->data->last_modified != 0) {
  85. rspamd_http_date_format (datebuf, sizeof (datebuf),
  86. cbd->data->last_modified);
  87. rspamd_http_message_add_header (msg, "If-Modified-Since",
  88. datebuf);
  89. }
  90. if (cbd->data->etag) {
  91. rspamd_http_message_add_header_len (msg, "If-None-Match",
  92. cbd->data->etag->str, cbd->data->etag->len);
  93. }
  94. }
  95. }
  96. else if (cbd->stage == map_load_pubkey) {
  97. msg->url = rspamd_fstring_append (msg->url,
  98. cbd->data->path, strlen (cbd->data->path));
  99. msg->url = rspamd_fstring_append (msg->url, ".pub", 4);
  100. }
  101. else if (cbd->stage == map_load_signature) {
  102. msg->url = rspamd_fstring_append (msg->url,
  103. cbd->data->path, strlen (cbd->data->path));
  104. msg->url = rspamd_fstring_append (msg->url, ".sig", 4);
  105. }
  106. else {
  107. g_assert_not_reached ();
  108. }
  109. msg->url = rspamd_fstring_append (msg->url, cbd->data->rest,
  110. strlen (cbd->data->rest));
  111. if (cbd->data->userinfo) {
  112. rspamd_http_message_add_header (msg, "Authorization",
  113. cbd->data->userinfo);
  114. }
  115. MAP_RETAIN (cbd, "http_callback_data");
  116. rspamd_http_connection_write_message (cbd->conn,
  117. msg,
  118. cbd->data->host,
  119. NULL,
  120. cbd,
  121. cbd->timeout);
  122. }
  123. static gboolean
  124. rspamd_map_check_sig_pk_mem (const guchar *sig,
  125. gsize siglen,
  126. struct rspamd_map *map,
  127. const guchar *input,
  128. gsize inlen,
  129. struct rspamd_cryptobox_pubkey *pk)
  130. {
  131. GString *b32_key;
  132. gboolean ret = TRUE;
  133. if (siglen != rspamd_cryptobox_signature_bytes (RSPAMD_CRYPTOBOX_MODE_25519)) {
  134. msg_err_map ("can't open signature for %s: invalid size: %z", map->name, siglen);
  135. ret = FALSE;
  136. }
  137. if (ret && !rspamd_cryptobox_verify (sig, siglen, input, inlen,
  138. rspamd_pubkey_get_pk (pk, NULL), RSPAMD_CRYPTOBOX_MODE_25519)) {
  139. msg_err_map ("can't verify signature for %s: incorrect signature", map->name);
  140. ret = FALSE;
  141. }
  142. if (ret) {
  143. b32_key = rspamd_pubkey_print (pk,
  144. RSPAMD_KEYPAIR_BASE32|RSPAMD_KEYPAIR_PUBKEY);
  145. msg_info_map ("verified signature for %s using trusted key %v",
  146. map->name, b32_key);
  147. g_string_free (b32_key, TRUE);
  148. }
  149. return ret;
  150. }
  151. static gboolean
  152. rspamd_map_check_file_sig (const char *fname,
  153. struct rspamd_map *map,
  154. struct rspamd_map_backend *bk,
  155. const guchar *input,
  156. gsize inlen)
  157. {
  158. guchar *data;
  159. struct rspamd_cryptobox_pubkey *pk = NULL;
  160. GString *b32_key;
  161. gboolean ret = TRUE;
  162. gsize len = 0;
  163. gchar fpath[PATH_MAX];
  164. if (bk->trusted_pubkey == NULL) {
  165. /* Try to load and check pubkey */
  166. rspamd_snprintf (fpath, sizeof (fpath), "%s.pub", fname);
  167. data = rspamd_file_xmap (fpath, PROT_READ, &len, TRUE);
  168. if (data == NULL) {
  169. msg_err_map ("can't open pubkey %s: %s", fpath, strerror (errno));
  170. return FALSE;
  171. }
  172. pk = rspamd_pubkey_from_base32 (data, len, RSPAMD_KEYPAIR_SIGN,
  173. RSPAMD_CRYPTOBOX_MODE_25519);
  174. munmap (data, len);
  175. if (pk == NULL) {
  176. msg_err_map ("can't load pubkey %s", fpath);
  177. return FALSE;
  178. }
  179. /* We just check pk against the trusted db of keys */
  180. b32_key = rspamd_pubkey_print (pk,
  181. RSPAMD_KEYPAIR_BASE32|RSPAMD_KEYPAIR_PUBKEY);
  182. g_assert (b32_key != NULL);
  183. if (g_hash_table_lookup (map->cfg->trusted_keys, b32_key->str) == NULL) {
  184. msg_err_map ("pubkey loaded from %s is untrusted: %v", fpath,
  185. b32_key);
  186. g_string_free (b32_key, TRUE);
  187. rspamd_pubkey_unref (pk);
  188. return FALSE;
  189. }
  190. g_string_free (b32_key, TRUE);
  191. }
  192. else {
  193. pk = rspamd_pubkey_ref (bk->trusted_pubkey);
  194. }
  195. rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", fname);
  196. data = rspamd_shmem_xmap (fpath, PROT_READ, &len);
  197. if (data == NULL) {
  198. msg_err_map ("can't open signature %s: %s", fpath, strerror (errno));
  199. ret = FALSE;
  200. }
  201. if (ret) {
  202. ret = rspamd_map_check_sig_pk_mem (data, len, map, input, inlen, pk);
  203. munmap (data, len);
  204. }
  205. rspamd_pubkey_unref (pk);
  206. return ret;
  207. }
  208. /**
  209. * Callback for destroying HTTP callback data
  210. */
  211. static void
  212. free_http_cbdata_common (struct http_callback_data *cbd, gboolean plan_new)
  213. {
  214. struct map_periodic_cbdata *periodic = cbd->periodic;
  215. if (cbd->shmem_sig) {
  216. rspamd_http_message_shmem_unref (cbd->shmem_sig);
  217. }
  218. if (cbd->shmem_pubkey) {
  219. rspamd_http_message_shmem_unref (cbd->shmem_pubkey);
  220. }
  221. if (cbd->shmem_data) {
  222. rspamd_http_message_shmem_unref (cbd->shmem_data);
  223. }
  224. if (cbd->pk) {
  225. rspamd_pubkey_unref (cbd->pk);
  226. }
  227. if (cbd->conn) {
  228. rspamd_http_connection_unref (cbd->conn);
  229. cbd->conn = NULL;
  230. }
  231. if (cbd->addr) {
  232. rspamd_inet_address_free (cbd->addr);
  233. }
  234. MAP_RELEASE (cbd->bk, "rspamd_map_backend");
  235. if (periodic) {
  236. /* Detached in case of HTTP error */
  237. MAP_RELEASE (periodic, "periodic");
  238. }
  239. g_free (cbd);
  240. }
  241. static void
  242. free_http_cbdata (struct http_callback_data *cbd)
  243. {
  244. cbd->map->tmp_dtor = NULL;
  245. cbd->map->tmp_dtor_data = NULL;
  246. free_http_cbdata_common (cbd, TRUE);
  247. }
  248. static void
  249. free_http_cbdata_dtor (gpointer p)
  250. {
  251. struct http_callback_data *cbd = p;
  252. struct rspamd_map *map;
  253. map = cbd->map;
  254. if (cbd->stage >= map_load_file) {
  255. REF_RELEASE (cbd);
  256. }
  257. else {
  258. /* We cannot terminate DNS requests sent */
  259. cbd->stage = map_finished;
  260. }
  261. msg_warn_map ("%s: "
  262. "connection with http server is terminated: worker is stopping",
  263. map->name);
  264. }
  265. /*
  266. * HTTP callbacks
  267. */
  268. static void
  269. http_map_error (struct rspamd_http_connection *conn,
  270. GError *err)
  271. {
  272. struct http_callback_data *cbd = conn->ud;
  273. struct rspamd_map *map;
  274. map = cbd->map;
  275. cbd->periodic->errored = TRUE;
  276. msg_err_map ("error reading %s(%s): "
  277. "connection with http server terminated incorrectly: %e",
  278. cbd->bk->uri,
  279. cbd->addr ? rspamd_inet_address_to_string_pretty (cbd->addr) : "",
  280. err);
  281. MAP_RETAIN (cbd->periodic, "periodic");
  282. rspamd_map_process_periodic (cbd->periodic);
  283. MAP_RELEASE (cbd->periodic, "periodic");
  284. /* Detach periodic as rspamd_map_process_periodic will destroy it */
  285. cbd->periodic = NULL;
  286. MAP_RELEASE (cbd, "http_callback_data");
  287. }
  288. static void
  289. rspamd_map_cache_cb (struct ev_loop *loop, ev_timer *w, int revents)
  290. {
  291. struct rspamd_http_map_cached_cbdata *cache_cbd = (struct rspamd_http_map_cached_cbdata *)
  292. w->data;
  293. struct rspamd_map *map;
  294. struct http_map_data *data;
  295. map = cache_cbd->map;
  296. data = cache_cbd->data;
  297. if (cache_cbd->gen != cache_cbd->data->gen) {
  298. /* We have another update, so this cache element is obviously expired */
  299. /*
  300. * Important!: we do not set cache availability to zero here, as there
  301. * might be fresh cache
  302. */
  303. msg_info_map ("cached data is now expired (gen mismatch %L != %L) for %s",
  304. cache_cbd->gen, cache_cbd->data->gen, map->name);
  305. MAP_RELEASE (cache_cbd->shm, "rspamd_http_map_cached_cbdata");
  306. ev_timer_stop (loop, &cache_cbd->timeout);
  307. g_free (cache_cbd);
  308. }
  309. else if (cache_cbd->data->last_checked >= cache_cbd->last_checked) {
  310. /*
  311. * We checked map but we have not found anything more recent,
  312. * reschedule cache check
  313. */
  314. if (cache_cbd->map->poll_timeout >
  315. ev_now (loop) - cache_cbd->data->last_checked) {
  316. w->repeat = cache_cbd->map->poll_timeout -
  317. (ev_now (loop) - cache_cbd->data->last_checked);
  318. }
  319. else {
  320. w->repeat = cache_cbd->map->poll_timeout;
  321. }
  322. cache_cbd->last_checked = cache_cbd->data->last_checked;
  323. msg_debug_map ("cached data is up to date for %s", map->name);
  324. ev_timer_again (loop, &cache_cbd->timeout);
  325. }
  326. else {
  327. data->cur_cache_cbd = NULL;
  328. g_atomic_int_set (&data->cache->available, 0);
  329. MAP_RELEASE (cache_cbd->shm, "rspamd_http_map_cached_cbdata");
  330. msg_info_map ("cached data is now expired for %s", map->name);
  331. ev_timer_stop (loop, &cache_cbd->timeout);
  332. g_free (cache_cbd);
  333. }
  334. }
  335. static gboolean
  336. rspamd_http_check_pubkey (struct http_callback_data *cbd,
  337. struct rspamd_http_message *msg)
  338. {
  339. const rspamd_ftok_t *pubkey_hdr;
  340. pubkey_hdr = rspamd_http_message_find_header (msg, "Pubkey");
  341. if (pubkey_hdr) {
  342. cbd->pk = rspamd_pubkey_from_base32 (pubkey_hdr->begin,
  343. pubkey_hdr->len,
  344. RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519);
  345. return cbd->pk != NULL;
  346. }
  347. return FALSE;
  348. }
  349. static gboolean
  350. rspamd_http_check_signature (struct rspamd_map *map,
  351. struct http_callback_data *cbd,
  352. struct rspamd_http_message *msg)
  353. {
  354. const rspamd_ftok_t *sig_hdr;
  355. guchar *in;
  356. size_t dlen;
  357. sig_hdr = rspamd_http_message_find_header (msg, "Signature");
  358. if (sig_hdr && cbd->pk) {
  359. in = rspamd_shmem_xmap (cbd->shmem_data->shm_name, PROT_READ, &dlen);
  360. if (in == NULL) {
  361. msg_err_map ("cannot read tempfile %s: %s",
  362. cbd->shmem_data->shm_name,
  363. strerror (errno));
  364. return FALSE;
  365. }
  366. if (!rspamd_map_check_sig_pk_mem (sig_hdr->begin, sig_hdr->len,
  367. map, in,
  368. cbd->data_len, cbd->pk)) {
  369. munmap (in, dlen);
  370. return FALSE;
  371. }
  372. munmap (in, dlen);
  373. return TRUE;
  374. }
  375. return FALSE;
  376. }
  377. static int
  378. http_map_finish (struct rspamd_http_connection *conn,
  379. struct rspamd_http_message *msg)
  380. {
  381. struct http_callback_data *cbd = conn->ud;
  382. struct rspamd_map *map;
  383. struct rspamd_map_backend *bk;
  384. struct http_map_data *data;
  385. struct rspamd_http_map_cached_cbdata *cache_cbd;
  386. const rspamd_ftok_t *expires_hdr, *etag_hdr;
  387. char next_check_date[128];
  388. guchar *aux_data, *in = NULL;
  389. gsize inlen = 0, dlen = 0;
  390. map = cbd->map;
  391. bk = cbd->bk;
  392. data = bk->data.hd;
  393. if (msg->code == 200) {
  394. if (cbd->check) {
  395. cbd->periodic->need_modify = TRUE;
  396. /* Reset the whole chain */
  397. cbd->periodic->cur_backend = 0;
  398. /* Reset cache, old cached data will be cleaned on timeout */
  399. g_atomic_int_set (&data->cache->available, 0);
  400. data->cur_cache_cbd = NULL;
  401. rspamd_map_process_periodic (cbd->periodic);
  402. MAP_RELEASE (cbd, "http_callback_data");
  403. return 0;
  404. }
  405. if (cbd->stage == map_load_file) {
  406. cbd->data->last_checked = msg->date;
  407. if (msg->last_modified) {
  408. cbd->data->last_modified = msg->last_modified;
  409. }
  410. else {
  411. cbd->data->last_modified = msg->date;
  412. }
  413. /* Maybe we need to check signature ? */
  414. if (bk->is_signed) {
  415. cbd->shmem_data = rspamd_http_message_shmem_ref (msg);
  416. cbd->data_len = msg->body_buf.len;
  417. if (bk->trusted_pubkey) {
  418. /* No need to load key */
  419. cbd->pk = rspamd_pubkey_ref (bk->trusted_pubkey);
  420. cbd->stage = map_load_signature;
  421. }
  422. else {
  423. if (!rspamd_http_check_pubkey (cbd, msg)) {
  424. cbd->stage = map_load_pubkey;
  425. }
  426. else {
  427. cbd->stage = map_load_signature;
  428. }
  429. }
  430. if (cbd->stage == map_load_signature) {
  431. /* Try HTTP header */
  432. if (rspamd_http_check_signature (map, cbd, msg)) {
  433. goto read_data;
  434. }
  435. }
  436. rspamd_http_connection_unref (cbd->conn);
  437. cbd->conn = rspamd_http_connection_new_client (NULL,
  438. NULL,
  439. http_map_error,
  440. http_map_finish,
  441. RSPAMD_HTTP_CLIENT_SIMPLE|RSPAMD_HTTP_CLIENT_SHARED,
  442. cbd->addr);
  443. write_http_request (cbd);
  444. MAP_RELEASE (cbd, "http_callback_data");
  445. return 0;
  446. }
  447. else {
  448. /* Unsigned version - just open file */
  449. cbd->shmem_data = rspamd_http_message_shmem_ref (msg);
  450. cbd->data_len = msg->body_buf.len;
  451. goto read_data;
  452. }
  453. }
  454. else if (cbd->stage == map_load_pubkey) {
  455. /* We now can load pubkey */
  456. cbd->shmem_pubkey = rspamd_http_message_shmem_ref (msg);
  457. cbd->pubkey_len = msg->body_buf.len;
  458. aux_data = rspamd_shmem_xmap (cbd->shmem_pubkey->shm_name,
  459. PROT_READ, &inlen);
  460. if (aux_data == NULL) {
  461. msg_err_map ("cannot map pubkey file %s: %s",
  462. cbd->shmem_pubkey->shm_name, strerror (errno));
  463. goto err;
  464. }
  465. if (inlen < cbd->pubkey_len) {
  466. msg_err_map ("cannot map pubkey file %s: %s",
  467. cbd->shmem_pubkey->shm_name, strerror (errno));
  468. munmap (aux_data, inlen);
  469. goto err;
  470. }
  471. cbd->pk = rspamd_pubkey_from_base32 (aux_data, cbd->pubkey_len,
  472. RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519);
  473. munmap (aux_data, inlen);
  474. if (cbd->pk == NULL) {
  475. msg_err_map ("cannot load pubkey file %s: bad pubkey",
  476. cbd->shmem_pubkey->shm_name);
  477. goto err;
  478. }
  479. cbd->stage = map_load_signature;
  480. rspamd_http_connection_unref (cbd->conn);
  481. cbd->conn = rspamd_http_connection_new_client (NULL,
  482. NULL,
  483. http_map_error,
  484. http_map_finish,
  485. RSPAMD_HTTP_CLIENT_SIMPLE|RSPAMD_HTTP_CLIENT_SHARED,
  486. cbd->addr);
  487. write_http_request (cbd);
  488. MAP_RELEASE (cbd, "http_callback_data");
  489. return 0;
  490. }
  491. else if (cbd->stage == map_load_signature) {
  492. /* We can now check signature */
  493. cbd->shmem_sig = rspamd_http_message_shmem_ref (msg);
  494. cbd->sig_len = msg->body_buf.len;
  495. aux_data = rspamd_shmem_xmap (cbd->shmem_sig->shm_name,
  496. PROT_READ, &inlen);
  497. if (aux_data == NULL) {
  498. msg_err_map ("cannot map signature file %s: %s",
  499. cbd->shmem_sig->shm_name, strerror (errno));
  500. goto err;
  501. }
  502. if (inlen < cbd->sig_len) {
  503. msg_err_map ("cannot map pubkey file %s: %s",
  504. cbd->shmem_pubkey->shm_name, strerror (errno));
  505. munmap (aux_data, inlen);
  506. goto err;
  507. }
  508. in = rspamd_shmem_xmap (cbd->shmem_data->shm_name, PROT_READ, &dlen);
  509. if (in == NULL) {
  510. msg_err_map ("cannot read tempfile %s: %s",
  511. cbd->shmem_data->shm_name,
  512. strerror (errno));
  513. munmap (aux_data, inlen);
  514. goto err;
  515. }
  516. if (!rspamd_map_check_sig_pk_mem (aux_data, cbd->sig_len, map, in,
  517. cbd->data_len, cbd->pk)) {
  518. munmap (aux_data, inlen);
  519. munmap (in, dlen);
  520. goto err;
  521. }
  522. munmap (in, dlen);
  523. }
  524. read_data:
  525. if (cbd->data_len == 0) {
  526. msg_err_map ("cannot read empty map");
  527. goto err;
  528. }
  529. g_assert (cbd->shmem_data != NULL);
  530. in = rspamd_shmem_xmap (cbd->shmem_data->shm_name, PROT_READ, &dlen);
  531. if (in == NULL) {
  532. msg_err_map ("cannot read tempfile %s: %s",
  533. cbd->shmem_data->shm_name,
  534. strerror (errno));
  535. goto err;
  536. }
  537. /* Check for expires */
  538. double cached_timeout = map->poll_timeout * 2;
  539. expires_hdr = rspamd_http_message_find_header (msg, "Expires");
  540. if (expires_hdr) {
  541. time_t hdate;
  542. hdate = rspamd_http_parse_date (expires_hdr->begin, expires_hdr->len);
  543. if (hdate != (time_t)-1 && hdate > msg->date) {
  544. if (map->next_check) {
  545. /* If we have multiple backends */
  546. hdate = MIN (map->next_check, hdate);
  547. }
  548. cached_timeout = map->next_check - msg->date +
  549. map->poll_timeout * 2;
  550. map->next_check = hdate;
  551. }
  552. }
  553. /* Check for etag */
  554. etag_hdr = rspamd_http_message_find_header (msg, "ETag");
  555. if (etag_hdr) {
  556. if (cbd->data->etag) {
  557. /* Remove old etag */
  558. rspamd_fstring_free (cbd->data->etag);
  559. }
  560. cbd->data->etag = rspamd_fstring_new_init (etag_hdr->begin,
  561. etag_hdr->len);
  562. }
  563. else {
  564. if (cbd->data->etag) {
  565. /* Remove and clear old etag */
  566. rspamd_fstring_free (cbd->data->etag);
  567. cbd->data->etag = NULL;
  568. }
  569. }
  570. MAP_RETAIN (cbd->shmem_data, "shmem_data");
  571. cbd->data->gen ++;
  572. /*
  573. * We know that a map is in the locked state
  574. */
  575. g_atomic_int_set (&data->cache->available, 1);
  576. /* Store cached data */
  577. rspamd_strlcpy (data->cache->shmem_name, cbd->shmem_data->shm_name,
  578. sizeof (data->cache->shmem_name));
  579. data->cache->len = cbd->data_len;
  580. data->cache->last_modified = cbd->data->last_modified;
  581. cache_cbd = g_malloc0 (sizeof (*cache_cbd));
  582. cache_cbd->shm = cbd->shmem_data;
  583. cache_cbd->event_loop = cbd->event_loop;
  584. cache_cbd->map = map;
  585. cache_cbd->data = cbd->data;
  586. cache_cbd->last_checked = cbd->data->last_checked;
  587. cache_cbd->gen = cbd->data->gen;
  588. MAP_RETAIN (cache_cbd->shm, "shmem_data");
  589. ev_timer_init (&cache_cbd->timeout, rspamd_map_cache_cb, cached_timeout,
  590. 0.0);
  591. ev_timer_start (cbd->event_loop, &cache_cbd->timeout);
  592. cache_cbd->timeout.data = cache_cbd;
  593. data->cur_cache_cbd = cache_cbd;
  594. if (map->next_check) {
  595. rspamd_http_date_format (next_check_date, sizeof (next_check_date),
  596. map->next_check);
  597. }
  598. else {
  599. rspamd_http_date_format (next_check_date, sizeof (next_check_date),
  600. ev_now (cbd->event_loop) + map->poll_timeout);
  601. }
  602. if (cbd->bk->is_compressed) {
  603. ZSTD_DStream *zstream;
  604. ZSTD_inBuffer zin;
  605. ZSTD_outBuffer zout;
  606. guchar *out;
  607. gsize outlen, r;
  608. zstream = ZSTD_createDStream ();
  609. ZSTD_initDStream (zstream);
  610. zin.pos = 0;
  611. zin.src = in;
  612. zin.size = dlen;
  613. if ((outlen = ZSTD_getDecompressedSize (zin.src, zin.size)) == 0) {
  614. outlen = ZSTD_DStreamOutSize ();
  615. }
  616. out = g_malloc (outlen);
  617. zout.dst = out;
  618. zout.pos = 0;
  619. zout.size = outlen;
  620. while (zin.pos < zin.size) {
  621. r = ZSTD_decompressStream (zstream, &zout, &zin);
  622. if (ZSTD_isError (r)) {
  623. msg_err_map ("%s(%s): cannot decompress data: %s",
  624. cbd->bk->uri,
  625. rspamd_inet_address_to_string_pretty (cbd->addr),
  626. ZSTD_getErrorName (r));
  627. ZSTD_freeDStream (zstream);
  628. g_free (out);
  629. MAP_RELEASE (cbd->shmem_data, "shmem_data");
  630. goto err;
  631. }
  632. if (zout.pos == zout.size) {
  633. /* We need to extend output buffer */
  634. zout.size = zout.size * 1.5 + 1.0;
  635. out = g_realloc (zout.dst, zout.size);
  636. zout.dst = out;
  637. }
  638. }
  639. ZSTD_freeDStream (zstream);
  640. msg_info_map ("%s(%s): read map data %z bytes compressed, "
  641. "%z uncompressed, next check at %s",
  642. cbd->bk->uri,
  643. rspamd_inet_address_to_string_pretty (cbd->addr),
  644. dlen, zout.pos, next_check_date);
  645. map->read_callback (out, zout.pos, &cbd->periodic->cbdata, TRUE);
  646. rspamd_map_save_http_cached_file (map, bk, cbd->data, out, zout.pos);
  647. g_free (out);
  648. }
  649. else {
  650. msg_info_map ("%s(%s): read map data %z bytes, next check at %s",
  651. cbd->bk->uri,
  652. rspamd_inet_address_to_string_pretty (cbd->addr),
  653. dlen, next_check_date);
  654. rspamd_map_save_http_cached_file (map, bk, cbd->data, in, cbd->data_len);
  655. map->read_callback (in, cbd->data_len, &cbd->periodic->cbdata, TRUE);
  656. }
  657. MAP_RELEASE (cbd->shmem_data, "shmem_data");
  658. cbd->periodic->cur_backend ++;
  659. munmap (in, dlen);
  660. rspamd_map_process_periodic (cbd->periodic);
  661. }
  662. else if (msg->code == 304 && (cbd->check && cbd->stage == map_load_file)) {
  663. cbd->data->last_checked = msg->date;
  664. if (msg->last_modified) {
  665. cbd->data->last_modified = msg->last_modified;
  666. }
  667. else {
  668. cbd->data->last_modified = msg->date;
  669. }
  670. expires_hdr = rspamd_http_message_find_header (msg, "Expires");
  671. if (expires_hdr) {
  672. time_t hdate;
  673. hdate = rspamd_http_parse_date (expires_hdr->begin, expires_hdr->len);
  674. if (hdate != (time_t)-1 && hdate > msg->date) {
  675. if (map->next_check) {
  676. /* If we have multiple backends */
  677. hdate = MIN (map->next_check, hdate);
  678. }
  679. map->next_check = hdate;
  680. }
  681. }
  682. etag_hdr = rspamd_http_message_find_header (msg, "ETag");
  683. if (etag_hdr) {
  684. if (cbd->data->etag) {
  685. /* Remove old etag */
  686. rspamd_fstring_free (cbd->data->etag);
  687. cbd->data->etag = rspamd_fstring_new_init (etag_hdr->begin,
  688. etag_hdr->len);
  689. }
  690. }
  691. if (map->next_check) {
  692. rspamd_http_date_format (next_check_date, sizeof (next_check_date),
  693. map->next_check);
  694. }
  695. else {
  696. rspamd_http_date_format (next_check_date, sizeof (next_check_date),
  697. ev_now (cbd->event_loop) + map->poll_timeout);
  698. }
  699. msg_info_map ("data is not modified for server %s, next check at %s",
  700. cbd->data->host, next_check_date);
  701. cbd->periodic->cur_backend ++;
  702. rspamd_map_process_periodic (cbd->periodic);
  703. }
  704. else {
  705. msg_info_map ("cannot load map %s from %s: HTTP error %d",
  706. bk->uri, cbd->data->host, msg->code);
  707. goto err;
  708. }
  709. MAP_RELEASE (cbd, "http_callback_data");
  710. return 0;
  711. err:
  712. cbd->periodic->errored = 1;
  713. rspamd_map_process_periodic (cbd->periodic);
  714. MAP_RELEASE (cbd, "http_callback_data");
  715. return 0;
  716. }
  717. static gboolean
  718. read_map_file_chunks (struct rspamd_map *map, struct map_cb_data *cbdata,
  719. const gchar *fname, gsize len, goffset off)
  720. {
  721. gint fd;
  722. gssize r, avail;
  723. gsize buflen = 1024 * 1024;
  724. gchar *pos, *bytes;
  725. fd = rspamd_file_xopen (fname, O_RDONLY, 0, TRUE);
  726. if (fd == -1) {
  727. msg_err_map ("can't open map for buffered reading %s: %s",
  728. fname, strerror (errno));
  729. return FALSE;
  730. }
  731. if (lseek (fd, off, SEEK_SET) == -1) {
  732. msg_err_map ("can't seek in map to pos %d for buffered reading %s: %s",
  733. (gint)off, fname, strerror (errno));
  734. return FALSE;
  735. }
  736. buflen = MIN (len, buflen);
  737. bytes = g_malloc (buflen);
  738. avail = buflen;
  739. pos = bytes;
  740. while ((r = read (fd, pos, avail)) > 0) {
  741. gchar *end = bytes + (pos - bytes) + r;
  742. msg_info_map ("%s: read map chunk, %z bytes", fname,
  743. r);
  744. pos = map->read_callback (bytes, end - bytes, cbdata, r == len);
  745. if (pos && pos > bytes && pos < end) {
  746. guint remain = end - pos;
  747. memmove (bytes, pos, remain);
  748. pos = bytes + remain;
  749. /* Need to preserve the remain */
  750. avail = ((gssize)buflen) - remain;
  751. if (avail <= 0) {
  752. /* Try realloc, too large element */
  753. g_assert (buflen >= remain);
  754. bytes = g_realloc (bytes, buflen * 2);
  755. pos = bytes + remain; /* Adjust */
  756. avail += buflen;
  757. buflen *= 2;
  758. }
  759. }
  760. else {
  761. avail = buflen;
  762. pos = bytes;
  763. }
  764. len -= r;
  765. }
  766. if (r == -1) {
  767. msg_err_map ("can't read from map %s: %s", fname, strerror (errno));
  768. close (fd);
  769. g_free (bytes);
  770. return FALSE;
  771. }
  772. close (fd);
  773. g_free (bytes);
  774. return TRUE;
  775. }
  776. /**
  777. * Callback for reading data from file
  778. */
  779. static gboolean
  780. read_map_file (struct rspamd_map *map, struct file_map_data *data,
  781. struct rspamd_map_backend *bk, struct map_periodic_cbdata *periodic)
  782. {
  783. gchar *bytes;
  784. gsize len;
  785. struct stat st;
  786. if (map->read_callback == NULL || map->fin_callback == NULL) {
  787. msg_err_map ("%s: bad callback for reading map file",
  788. data->filename);
  789. return FALSE;
  790. }
  791. if (stat (data->filename, &st) == -1) {
  792. /* File does not exist, skipping */
  793. if (errno != ENOENT) {
  794. msg_err_map ("%s: map file is unavailable for reading: %s",
  795. data->filename, strerror (errno));
  796. return FALSE;
  797. }
  798. else {
  799. msg_info_map ("%s: map file is not found; "
  800. "it will be read automatically if created",
  801. data->filename);
  802. return TRUE;
  803. }
  804. }
  805. ev_stat_stat (map->event_loop, &data->st_ev);
  806. len = st.st_size;
  807. if (bk->is_signed) {
  808. bytes = rspamd_file_xmap (data->filename, PROT_READ, &len, TRUE);
  809. if (bytes == NULL) {
  810. msg_err_map ("can't open map %s: %s", data->filename, strerror (errno));
  811. return FALSE;
  812. }
  813. if (!rspamd_map_check_file_sig (data->filename, map, bk, bytes, len)) {
  814. munmap (bytes, len);
  815. return FALSE;
  816. }
  817. munmap (bytes, len);
  818. }
  819. if (len > 0) {
  820. if (bk->is_compressed) {
  821. bytes = rspamd_file_xmap (data->filename, PROT_READ, &len, TRUE);
  822. if (bytes == NULL) {
  823. msg_err_map ("can't open map %s: %s", data->filename, strerror (errno));
  824. return FALSE;
  825. }
  826. ZSTD_DStream *zstream;
  827. ZSTD_inBuffer zin;
  828. ZSTD_outBuffer zout;
  829. guchar *out;
  830. gsize outlen, r;
  831. zstream = ZSTD_createDStream ();
  832. ZSTD_initDStream (zstream);
  833. zin.pos = 0;
  834. zin.src = bytes;
  835. zin.size = len;
  836. if ((outlen = ZSTD_getDecompressedSize (zin.src, zin.size)) == 0) {
  837. outlen = ZSTD_DStreamOutSize ();
  838. }
  839. out = g_malloc (outlen);
  840. zout.dst = out;
  841. zout.pos = 0;
  842. zout.size = outlen;
  843. while (zin.pos < zin.size) {
  844. r = ZSTD_decompressStream (zstream, &zout, &zin);
  845. if (ZSTD_isError (r)) {
  846. msg_err_map ("%s: cannot decompress data: %s",
  847. data->filename,
  848. ZSTD_getErrorName (r));
  849. ZSTD_freeDStream (zstream);
  850. g_free (out);
  851. munmap (bytes, len);
  852. return FALSE;
  853. }
  854. if (zout.pos == zout.size) {
  855. /* We need to extend output buffer */
  856. zout.size = zout.size * 1.5 + 1.0;
  857. out = g_realloc (zout.dst, zout.size);
  858. zout.dst = out;
  859. }
  860. }
  861. ZSTD_freeDStream (zstream);
  862. msg_info_map ("%s: read map data, %z bytes compressed, "
  863. "%z uncompressed)", data->filename,
  864. len, zout.pos);
  865. map->read_callback (out, zout.pos, &periodic->cbdata, TRUE);
  866. g_free (out);
  867. munmap (bytes, len);
  868. }
  869. else {
  870. /* Perform buffered read: fail-safe */
  871. if (!read_map_file_chunks (map, &periodic->cbdata, data->filename,
  872. len, 0)) {
  873. return FALSE;
  874. }
  875. }
  876. }
  877. else {
  878. /* Empty map */
  879. map->read_callback (NULL, 0, &periodic->cbdata, TRUE);
  880. }
  881. return TRUE;
  882. }
  883. static gboolean
  884. read_map_static (struct rspamd_map *map, struct static_map_data *data,
  885. struct rspamd_map_backend *bk, struct map_periodic_cbdata *periodic)
  886. {
  887. guchar *bytes;
  888. gsize len;
  889. if (map->read_callback == NULL || map->fin_callback == NULL) {
  890. msg_err_map ("%s: bad callback for reading map file", map->name);
  891. data->processed = TRUE;
  892. return FALSE;
  893. }
  894. bytes = data->data;
  895. len = data->len;
  896. if (len > 0) {
  897. if (bk->is_compressed) {
  898. ZSTD_DStream *zstream;
  899. ZSTD_inBuffer zin;
  900. ZSTD_outBuffer zout;
  901. guchar *out;
  902. gsize outlen, r;
  903. zstream = ZSTD_createDStream ();
  904. ZSTD_initDStream (zstream);
  905. zin.pos = 0;
  906. zin.src = bytes;
  907. zin.size = len;
  908. if ((outlen = ZSTD_getDecompressedSize (zin.src, zin.size)) == 0) {
  909. outlen = ZSTD_DStreamOutSize ();
  910. }
  911. out = g_malloc (outlen);
  912. zout.dst = out;
  913. zout.pos = 0;
  914. zout.size = outlen;
  915. while (zin.pos < zin.size) {
  916. r = ZSTD_decompressStream (zstream, &zout, &zin);
  917. if (ZSTD_isError (r)) {
  918. msg_err_map ("%s: cannot decompress data: %s",
  919. map->name,
  920. ZSTD_getErrorName (r));
  921. ZSTD_freeDStream (zstream);
  922. g_free (out);
  923. return FALSE;
  924. }
  925. if (zout.pos == zout.size) {
  926. /* We need to extend output buffer */
  927. zout.size = zout.size * 1.5 + 1.0;
  928. out = g_realloc (zout.dst, zout.size);
  929. zout.dst = out;
  930. }
  931. }
  932. ZSTD_freeDStream (zstream);
  933. msg_info_map ("%s: read map data, %z bytes compressed, "
  934. "%z uncompressed)",
  935. map->name,
  936. len, zout.pos);
  937. map->read_callback (out, zout.pos, &periodic->cbdata, TRUE);
  938. g_free (out);
  939. }
  940. else {
  941. msg_info_map ("%s: read map data, %z bytes",
  942. map->name, len);
  943. map->read_callback (bytes, len, &periodic->cbdata, TRUE);
  944. }
  945. }
  946. else {
  947. map->read_callback (NULL, 0, &periodic->cbdata, TRUE);
  948. }
  949. data->processed = TRUE;
  950. return TRUE;
  951. }
  952. static void
  953. rspamd_map_periodic_dtor (struct map_periodic_cbdata *periodic)
  954. {
  955. struct rspamd_map *map;
  956. map = periodic->map;
  957. msg_debug_map ("periodic dtor %p", periodic);
  958. if (periodic->need_modify) {
  959. /* We are done */
  960. periodic->map->fin_callback (&periodic->cbdata, periodic->map->user_data);
  961. }
  962. else {
  963. /* Not modified */
  964. }
  965. if (periodic->locked) {
  966. rspamd_map_schedule_periodic (periodic->map, FALSE, FALSE, FALSE);
  967. g_atomic_int_set (periodic->map->locked, 0);
  968. msg_debug_map ("unlocked map");
  969. }
  970. g_free (periodic);
  971. }
  972. /* Called on timer execution */
  973. static void
  974. rspamd_map_periodic_callback (struct ev_loop *loop, ev_timer *w, int revents)
  975. {
  976. struct map_periodic_cbdata *cbd = (struct map_periodic_cbdata *)w->data;
  977. ev_timer_stop (loop, w);
  978. rspamd_map_process_periodic (cbd);
  979. }
  980. static void
  981. rspamd_map_schedule_periodic (struct rspamd_map *map,
  982. gboolean locked, gboolean initial, gboolean errored)
  983. {
  984. const gdouble error_mult = 20.0, lock_mult = 0.1;
  985. gdouble jittered_sec;
  986. gdouble timeout;
  987. struct map_periodic_cbdata *cbd;
  988. if (map->scheduled_check || (map->wrk && map->wrk->wanna_die)) {
  989. /* Do not schedule check if some check is already scheduled */
  990. return;
  991. }
  992. if (map->next_check != 0) {
  993. timeout = map->next_check - rspamd_get_calendar_ticks ();
  994. if (timeout < map->poll_timeout) {
  995. timeout = map->poll_timeout;
  996. if (errored) {
  997. timeout = map->poll_timeout * error_mult;
  998. }
  999. else if (locked) {
  1000. timeout = map->poll_timeout * lock_mult;
  1001. }
  1002. jittered_sec = rspamd_time_jitter (timeout, 0);
  1003. }
  1004. else {
  1005. jittered_sec = rspamd_time_jitter (timeout, map->poll_timeout);
  1006. }
  1007. /* Reset till the next usage */
  1008. map->next_check = 0;
  1009. }
  1010. else {
  1011. timeout = map->poll_timeout;
  1012. if (initial) {
  1013. timeout = 0.0;
  1014. } else {
  1015. if (errored) {
  1016. timeout = map->poll_timeout * error_mult;
  1017. }
  1018. else if (locked) {
  1019. timeout = map->poll_timeout * lock_mult;
  1020. }
  1021. }
  1022. jittered_sec = rspamd_time_jitter (timeout, 0);
  1023. }
  1024. cbd = g_malloc0 (sizeof (*cbd));
  1025. cbd->cbdata.state = 0;
  1026. cbd->cbdata.prev_data = *map->user_data;
  1027. cbd->cbdata.cur_data = NULL;
  1028. cbd->cbdata.map = map;
  1029. cbd->map = map;
  1030. map->scheduled_check = cbd;
  1031. REF_INIT_RETAIN (cbd, rspamd_map_periodic_dtor);
  1032. cbd->ev.data = cbd;
  1033. ev_timer_init (&cbd->ev, rspamd_map_periodic_callback, jittered_sec, 0.0);
  1034. ev_timer_start (map->event_loop, &cbd->ev);
  1035. msg_debug_map ("schedule new periodic event %p in %.2f seconds",
  1036. cbd, jittered_sec);
  1037. }
  1038. static void
  1039. rspamd_map_dns_callback (struct rdns_reply *reply, void *arg)
  1040. {
  1041. struct http_callback_data *cbd = arg;
  1042. struct rspamd_map *map;
  1043. guint flags = RSPAMD_HTTP_CLIENT_SIMPLE|RSPAMD_HTTP_CLIENT_SHARED;
  1044. map = cbd->map;
  1045. if (cbd->stage == map_finished) {
  1046. MAP_RELEASE (cbd, "http_callback_data");
  1047. return;
  1048. }
  1049. if (reply->code == RDNS_RC_NOERROR) {
  1050. /*
  1051. * We just get the first address hoping that a resolver performs
  1052. * round-robin rotation well
  1053. */
  1054. if (cbd->addr == NULL) {
  1055. cbd->addr = rspamd_inet_address_from_rnds (reply->entries);
  1056. if (cbd->addr != NULL) {
  1057. rspamd_inet_address_set_port (cbd->addr, cbd->data->port);
  1058. cbd->conn = rspamd_http_connection_new_client (NULL,
  1059. NULL,
  1060. http_map_error,
  1061. http_map_finish,
  1062. flags,
  1063. cbd->addr);
  1064. if (cbd->conn != NULL) {
  1065. cbd->stage = map_load_file;
  1066. write_http_request (cbd);
  1067. }
  1068. else {
  1069. rspamd_inet_address_free (cbd->addr);
  1070. cbd->addr = NULL;
  1071. }
  1072. }
  1073. }
  1074. }
  1075. else if (cbd->stage < map_load_file) {
  1076. if (cbd->stage == map_resolve_host2) {
  1077. /* We have still one request pending */
  1078. cbd->stage = map_resolve_host1;
  1079. }
  1080. else {
  1081. /* We could not resolve host, so cowardly fail here */
  1082. msg_err_map ("cannot resolve %s: %s", cbd->data->host,
  1083. rdns_strerror (reply->code));
  1084. cbd->periodic->errored = 1;
  1085. rspamd_map_process_periodic (cbd->periodic);
  1086. }
  1087. }
  1088. MAP_RELEASE (cbd, "http_callback_data");
  1089. }
  1090. static gboolean
  1091. rspamd_map_read_cached (struct rspamd_map *map, struct rspamd_map_backend *bk,
  1092. struct map_periodic_cbdata *periodic, const gchar *host)
  1093. {
  1094. gsize len;
  1095. gpointer in;
  1096. struct http_map_data *data;
  1097. data = bk->data.hd;
  1098. in = rspamd_shmem_xmap (data->cache->shmem_name, PROT_READ, &len);
  1099. if (in == NULL) {
  1100. msg_err ("cannot map cache from %s: %s", data->cache->shmem_name,
  1101. strerror (errno));
  1102. return FALSE;
  1103. }
  1104. if (len < data->cache->len) {
  1105. msg_err ("cannot map cache from %s: bad length %z, %z expected",
  1106. data->cache->shmem_name,
  1107. len, data->cache->len);
  1108. munmap (in, len);
  1109. return FALSE;
  1110. }
  1111. if (bk->is_compressed) {
  1112. ZSTD_DStream *zstream;
  1113. ZSTD_inBuffer zin;
  1114. ZSTD_outBuffer zout;
  1115. guchar *out;
  1116. gsize outlen, r;
  1117. zstream = ZSTD_createDStream ();
  1118. ZSTD_initDStream (zstream);
  1119. zin.pos = 0;
  1120. zin.src = in;
  1121. zin.size = len;
  1122. if ((outlen = ZSTD_getDecompressedSize (zin.src, zin.size)) == 0) {
  1123. outlen = ZSTD_DStreamOutSize ();
  1124. }
  1125. out = g_malloc (outlen);
  1126. zout.dst = out;
  1127. zout.pos = 0;
  1128. zout.size = outlen;
  1129. while (zin.pos < zin.size) {
  1130. r = ZSTD_decompressStream (zstream, &zout, &zin);
  1131. if (ZSTD_isError (r)) {
  1132. msg_err_map ("%s: cannot decompress data: %s",
  1133. bk->uri,
  1134. ZSTD_getErrorName (r));
  1135. ZSTD_freeDStream (zstream);
  1136. g_free (out);
  1137. munmap (in, len);
  1138. return FALSE;
  1139. }
  1140. if (zout.pos == zout.size) {
  1141. /* We need to extend output buffer */
  1142. zout.size = zout.size * 1.5 + 1.0;
  1143. out = g_realloc (zout.dst, zout.size);
  1144. zout.dst = out;
  1145. }
  1146. }
  1147. ZSTD_freeDStream (zstream);
  1148. msg_info_map ("%s: read map data cached %z bytes compressed, "
  1149. "%z uncompressed", bk->uri,
  1150. len, zout.pos);
  1151. map->read_callback (out, zout.pos, &periodic->cbdata, TRUE);
  1152. g_free (out);
  1153. }
  1154. else {
  1155. msg_info_map ("%s: read map data cached %z bytes", bk->uri,
  1156. len);
  1157. map->read_callback (in, len, &periodic->cbdata, TRUE);
  1158. }
  1159. munmap (in, len);
  1160. return TRUE;
  1161. }
  1162. static gboolean
  1163. rspamd_map_has_http_cached_file (struct rspamd_map *map,
  1164. struct rspamd_map_backend *bk)
  1165. {
  1166. gchar path[PATH_MAX];
  1167. guchar digest[rspamd_cryptobox_HASHBYTES];
  1168. struct rspamd_config *cfg = map->cfg;
  1169. struct stat st;
  1170. if (cfg->maps_cache_dir == NULL || cfg->maps_cache_dir[0] == '\0') {
  1171. return FALSE;
  1172. }
  1173. rspamd_cryptobox_hash (digest, bk->uri, strlen (bk->uri), NULL, 0);
  1174. rspamd_snprintf (path, sizeof (path), "%s%c%*xs.map", cfg->maps_cache_dir,
  1175. G_DIR_SEPARATOR, 20, digest);
  1176. if (stat (path, &st) != -1 && st.st_size >
  1177. sizeof (struct rspamd_http_file_data)) {
  1178. return TRUE;
  1179. }
  1180. return FALSE;
  1181. }
  1182. static gboolean
  1183. rspamd_map_save_http_cached_file (struct rspamd_map *map,
  1184. struct rspamd_map_backend *bk,
  1185. struct http_map_data *htdata,
  1186. const guchar *data,
  1187. gsize len)
  1188. {
  1189. gchar path[PATH_MAX];
  1190. guchar digest[rspamd_cryptobox_HASHBYTES];
  1191. struct rspamd_config *cfg = map->cfg;
  1192. gint fd;
  1193. struct rspamd_http_file_data header;
  1194. if (cfg->maps_cache_dir == NULL || cfg->maps_cache_dir[0] == '\0') {
  1195. return FALSE;
  1196. }
  1197. rspamd_cryptobox_hash (digest, bk->uri, strlen (bk->uri), NULL, 0);
  1198. rspamd_snprintf (path, sizeof (path), "%s%c%*xs.map", cfg->maps_cache_dir,
  1199. G_DIR_SEPARATOR, 20, digest);
  1200. fd = rspamd_file_xopen (path, O_WRONLY | O_TRUNC | O_CREAT,
  1201. 00600, FALSE);
  1202. if (fd == -1) {
  1203. return FALSE;
  1204. }
  1205. if (!rspamd_file_lock (fd, FALSE)) {
  1206. msg_err_map ("cannot lock file %s: %s", path, strerror (errno));
  1207. close (fd);
  1208. return FALSE;
  1209. }
  1210. memcpy (header.magic, rspamd_http_file_magic, sizeof (rspamd_http_file_magic));
  1211. header.mtime = htdata->last_modified;
  1212. header.next_check = map->next_check;
  1213. header.data_off = sizeof (header);
  1214. if (write (fd, &header, sizeof (header)) != sizeof (header)) {
  1215. msg_err_map ("cannot write file %s: %s", path, strerror (errno));
  1216. rspamd_file_unlock (fd, FALSE);
  1217. close (fd);
  1218. return FALSE;
  1219. }
  1220. /* Now write the rest */
  1221. if (write (fd, data, len) != len) {
  1222. msg_err_map ("cannot write file %s: %s", path, strerror (errno));
  1223. rspamd_file_unlock (fd, FALSE);
  1224. close (fd);
  1225. return FALSE;
  1226. }
  1227. rspamd_file_unlock (fd, FALSE);
  1228. close (fd);
  1229. msg_info_map ("saved data from %s in %s, %uz bytes", bk->uri, path, len);
  1230. return TRUE;
  1231. }
  1232. static gboolean
  1233. rspamd_map_read_http_cached_file (struct rspamd_map *map,
  1234. struct rspamd_map_backend *bk,
  1235. struct http_map_data *htdata,
  1236. struct map_cb_data *cbdata)
  1237. {
  1238. gchar path[PATH_MAX];
  1239. guchar digest[rspamd_cryptobox_HASHBYTES];
  1240. struct rspamd_config *cfg = map->cfg;
  1241. gint fd;
  1242. struct stat st;
  1243. struct rspamd_http_file_data header;
  1244. if (cfg->maps_cache_dir == NULL || cfg->maps_cache_dir[0] == '\0') {
  1245. return FALSE;
  1246. }
  1247. rspamd_cryptobox_hash (digest, bk->uri, strlen (bk->uri), NULL, 0);
  1248. rspamd_snprintf (path, sizeof (path), "%s%c%*xs.map", cfg->maps_cache_dir,
  1249. G_DIR_SEPARATOR, 20, digest);
  1250. fd = rspamd_file_xopen (path, O_RDONLY, 00600, FALSE);
  1251. if (fd == -1) {
  1252. return FALSE;
  1253. }
  1254. if (!rspamd_file_lock (fd, FALSE)) {
  1255. msg_err_map ("cannot lock file %s: %s", path, strerror (errno));
  1256. close (fd);
  1257. return FALSE;
  1258. }
  1259. (void)fstat (fd, &st);
  1260. if (read (fd, &header, sizeof (header)) != sizeof (header)) {
  1261. msg_err_map ("cannot read file %s: %s", path, strerror (errno));
  1262. rspamd_file_unlock (fd, FALSE);
  1263. close (fd);
  1264. return FALSE;
  1265. }
  1266. if (memcmp (header.magic, rspamd_http_file_magic,
  1267. sizeof (rspamd_http_file_magic)) != 0) {
  1268. msg_err_map ("invalid magic in file %s: %s", path, strerror (errno));
  1269. rspamd_file_unlock (fd, FALSE);
  1270. close (fd);
  1271. return FALSE;
  1272. }
  1273. rspamd_file_unlock (fd, FALSE);
  1274. close (fd);
  1275. map->next_check = header.next_check;
  1276. htdata->last_modified = header.mtime;
  1277. /* Now read file data */
  1278. /* Perform buffered read: fail-safe */
  1279. if (!read_map_file_chunks (map, cbdata, path,
  1280. st.st_size - header.data_off, header.data_off)) {
  1281. return FALSE;
  1282. }
  1283. msg_info_map ("read cached data for %s from %s, %uz bytes", bk->uri, path,
  1284. st.st_size - header.data_off);
  1285. return TRUE;
  1286. }
  1287. /**
  1288. * Async HTTP callback
  1289. */
  1290. static void
  1291. rspamd_map_common_http_callback (struct rspamd_map *map,
  1292. struct rspamd_map_backend *bk,
  1293. struct map_periodic_cbdata *periodic,
  1294. gboolean check)
  1295. {
  1296. struct http_map_data *data;
  1297. struct http_callback_data *cbd;
  1298. guint flags = RSPAMD_HTTP_CLIENT_SIMPLE|RSPAMD_HTTP_CLIENT_SHARED;
  1299. data = bk->data.hd;
  1300. if (g_atomic_int_get (&data->cache->available) == 1) {
  1301. /* Read cached data */
  1302. if (check) {
  1303. if (data->last_modified < data->cache->last_modified) {
  1304. periodic->need_modify = TRUE;
  1305. /* Reset the whole chain */
  1306. periodic->cur_backend = 0;
  1307. rspamd_map_process_periodic (periodic);
  1308. }
  1309. else {
  1310. if (map->active_http) {
  1311. /* Check even if there is a cached version */
  1312. goto check;
  1313. }
  1314. else {
  1315. /* Switch to the next backend */
  1316. periodic->cur_backend++;
  1317. rspamd_map_process_periodic (periodic);
  1318. }
  1319. }
  1320. return;
  1321. }
  1322. else {
  1323. if (map->active_http &&
  1324. data->last_modified > data->cache->last_modified) {
  1325. goto check;
  1326. }
  1327. else if (rspamd_map_read_cached (map, bk, periodic, data->host)) {
  1328. /* Switch to the next backend */
  1329. periodic->cur_backend++;
  1330. data->last_modified = data->cache->last_modified;
  1331. rspamd_map_process_periodic (periodic);
  1332. return;
  1333. }
  1334. }
  1335. }
  1336. else if (!map->active_http) {
  1337. /* Switch to the next backend */
  1338. periodic->cur_backend ++;
  1339. rspamd_map_process_periodic (periodic);
  1340. return;
  1341. }
  1342. check:
  1343. cbd = g_malloc0 (sizeof (struct http_callback_data));
  1344. cbd->event_loop = map->event_loop;
  1345. cbd->map = map;
  1346. cbd->data = data;
  1347. cbd->check = check;
  1348. cbd->periodic = periodic;
  1349. MAP_RETAIN (periodic, "periodic");
  1350. cbd->bk = bk;
  1351. MAP_RETAIN (bk, "rspamd_map_backend");
  1352. cbd->stage = map_resolve_host2;
  1353. REF_INIT_RETAIN (cbd, free_http_cbdata);
  1354. msg_debug_map ("%s map data from %s", check ? "checking" : "reading",
  1355. data->host);
  1356. /* Send both A and AAAA requests */
  1357. if (rspamd_parse_inet_address (&cbd->addr, data->host, strlen (data->host))) {
  1358. rspamd_inet_address_set_port (cbd->addr, cbd->data->port);
  1359. cbd->conn = rspamd_http_connection_new_client (
  1360. NULL,
  1361. NULL,
  1362. http_map_error,
  1363. http_map_finish,
  1364. flags,
  1365. cbd->addr);
  1366. if (cbd->conn != NULL) {
  1367. cbd->stage = map_load_file;
  1368. write_http_request (cbd);
  1369. MAP_RELEASE (cbd, "http_callback_data");
  1370. }
  1371. else {
  1372. msg_warn_map ("cannot load map: cannot connect to %s: %s",
  1373. data->host, strerror (errno));
  1374. rspamd_inet_address_free (cbd->addr);
  1375. cbd->addr = NULL;
  1376. MAP_RELEASE (cbd, "http_callback_data");
  1377. }
  1378. return;
  1379. }
  1380. else if (map->r->r) {
  1381. if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd,
  1382. map->cfg->dns_timeout, map->cfg->dns_retransmits, 1,
  1383. data->host, RDNS_REQUEST_A)) {
  1384. MAP_RETAIN (cbd, "http_callback_data");
  1385. }
  1386. if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd,
  1387. map->cfg->dns_timeout, map->cfg->dns_retransmits, 1,
  1388. data->host, RDNS_REQUEST_AAAA)) {
  1389. MAP_RETAIN (cbd, "http_callback_data");
  1390. }
  1391. map->tmp_dtor = free_http_cbdata_dtor;
  1392. map->tmp_dtor_data = cbd;
  1393. }
  1394. else {
  1395. msg_warn_map ("cannot load map: DNS resolver is not initialized");
  1396. cbd->periodic->errored = TRUE;
  1397. }
  1398. MAP_RELEASE (cbd, "http_callback_data");
  1399. }
  1400. static void
  1401. rspamd_map_http_check_callback (struct map_periodic_cbdata *cbd)
  1402. {
  1403. struct rspamd_map *map;
  1404. struct rspamd_map_backend *bk;
  1405. map = cbd->map;
  1406. bk = g_ptr_array_index (cbd->map->backends, cbd->cur_backend);
  1407. rspamd_map_common_http_callback (map, bk, cbd, TRUE);
  1408. }
  1409. static void
  1410. rspamd_map_http_read_callback (struct map_periodic_cbdata *cbd)
  1411. {
  1412. struct rspamd_map *map;
  1413. struct rspamd_map_backend *bk;
  1414. map = cbd->map;
  1415. bk = g_ptr_array_index (cbd->map->backends, cbd->cur_backend);
  1416. rspamd_map_common_http_callback (map, bk, cbd, FALSE);
  1417. }
  1418. static void
  1419. rspamd_map_file_check_callback (struct map_periodic_cbdata *periodic)
  1420. {
  1421. struct rspamd_map *map;
  1422. struct file_map_data *data;
  1423. struct rspamd_map_backend *bk;
  1424. map = periodic->map;
  1425. bk = g_ptr_array_index (map->backends, periodic->cur_backend);
  1426. data = bk->data.fd;
  1427. if (data->need_modify) {
  1428. periodic->need_modify = TRUE;
  1429. periodic->cur_backend = 0;
  1430. data->need_modify = FALSE;
  1431. rspamd_map_process_periodic (periodic);
  1432. return;
  1433. }
  1434. map = periodic->map;
  1435. /* Switch to the next backend as the rest is handled by ev_stat */
  1436. periodic->cur_backend ++;
  1437. rspamd_map_process_periodic (periodic);
  1438. }
  1439. static void
  1440. rspamd_map_static_check_callback (struct map_periodic_cbdata *periodic)
  1441. {
  1442. struct rspamd_map *map;
  1443. struct static_map_data *data;
  1444. struct rspamd_map_backend *bk;
  1445. map = periodic->map;
  1446. bk = g_ptr_array_index (map->backends, periodic->cur_backend);
  1447. data = bk->data.sd;
  1448. if (!data->processed) {
  1449. periodic->need_modify = TRUE;
  1450. periodic->cur_backend = 0;
  1451. rspamd_map_process_periodic (periodic);
  1452. return;
  1453. }
  1454. /* Switch to the next backend */
  1455. periodic->cur_backend ++;
  1456. rspamd_map_process_periodic (periodic);
  1457. }
  1458. static void
  1459. rspamd_map_file_read_callback (struct map_periodic_cbdata *periodic)
  1460. {
  1461. struct rspamd_map *map;
  1462. struct file_map_data *data;
  1463. struct rspamd_map_backend *bk;
  1464. map = periodic->map;
  1465. bk = g_ptr_array_index (map->backends, periodic->cur_backend);
  1466. data = bk->data.fd;
  1467. msg_info_map ("rereading map file %s", data->filename);
  1468. if (!read_map_file (map, data, bk, periodic)) {
  1469. periodic->errored = TRUE;
  1470. }
  1471. /* Switch to the next backend */
  1472. periodic->cur_backend ++;
  1473. rspamd_map_process_periodic (periodic);
  1474. }
  1475. static void
  1476. rspamd_map_static_read_callback (struct map_periodic_cbdata *periodic)
  1477. {
  1478. struct rspamd_map *map;
  1479. struct static_map_data *data;
  1480. struct rspamd_map_backend *bk;
  1481. map = periodic->map;
  1482. bk = g_ptr_array_index (map->backends, periodic->cur_backend);
  1483. data = bk->data.sd;
  1484. msg_info_map ("rereading static map");
  1485. if (!read_map_static (map, data, bk, periodic)) {
  1486. periodic->errored = TRUE;
  1487. }
  1488. /* Switch to the next backend */
  1489. periodic->cur_backend ++;
  1490. rspamd_map_process_periodic (periodic);
  1491. }
  1492. static void
  1493. rspamd_map_process_periodic (struct map_periodic_cbdata *cbd)
  1494. {
  1495. struct rspamd_map_backend *bk;
  1496. struct rspamd_map *map;
  1497. map = cbd->map;
  1498. map->scheduled_check = NULL;
  1499. if (!cbd->locked) {
  1500. if (!g_atomic_int_compare_and_exchange (cbd->map->locked, 0, 1)) {
  1501. msg_debug_map (
  1502. "don't try to reread map as it is locked by other process, "
  1503. "will reread it later");
  1504. rspamd_map_schedule_periodic (map, TRUE, FALSE, FALSE);
  1505. MAP_RELEASE (cbd, "periodic");
  1506. return;
  1507. }
  1508. else {
  1509. msg_debug_map ("locked map");
  1510. cbd->locked = TRUE;
  1511. }
  1512. }
  1513. if (cbd->errored) {
  1514. /* We should not check other backends if some backend has failed */
  1515. rspamd_map_schedule_periodic (cbd->map, FALSE, FALSE, TRUE);
  1516. if (cbd->locked) {
  1517. g_atomic_int_set (cbd->map->locked, 0);
  1518. }
  1519. msg_debug_map ("unlocked map");
  1520. MAP_RELEASE (cbd, "periodic");
  1521. return;
  1522. }
  1523. /* For each backend we need to check for modifications */
  1524. if (cbd->cur_backend >= cbd->map->backends->len) {
  1525. /* Last backend */
  1526. msg_debug_map ("finished map: %d of %d", cbd->cur_backend,
  1527. cbd->map->backends->len);
  1528. MAP_RELEASE (cbd, "periodic");
  1529. return;
  1530. }
  1531. if (!(cbd->map->wrk && cbd->map->wrk->wanna_die)) {
  1532. bk = g_ptr_array_index (cbd->map->backends, cbd->cur_backend);
  1533. g_assert (bk != NULL);
  1534. if (cbd->need_modify) {
  1535. /* Load data from the next backend */
  1536. switch (bk->protocol) {
  1537. case MAP_PROTO_HTTP:
  1538. case MAP_PROTO_HTTPS:
  1539. rspamd_map_http_read_callback (cbd);
  1540. break;
  1541. case MAP_PROTO_FILE:
  1542. rspamd_map_file_read_callback (cbd);
  1543. break;
  1544. case MAP_PROTO_STATIC:
  1545. rspamd_map_static_read_callback (cbd);
  1546. break;
  1547. }
  1548. } else {
  1549. /* Check the next backend */
  1550. switch (bk->protocol) {
  1551. case MAP_PROTO_HTTP:
  1552. case MAP_PROTO_HTTPS:
  1553. rspamd_map_http_check_callback (cbd);
  1554. break;
  1555. case MAP_PROTO_FILE:
  1556. rspamd_map_file_check_callback (cbd);
  1557. break;
  1558. case MAP_PROTO_STATIC:
  1559. rspamd_map_static_check_callback (cbd);
  1560. break;
  1561. }
  1562. }
  1563. }
  1564. }
  1565. static void
  1566. rspamd_map_on_stat (struct ev_loop *loop, ev_stat *w, int revents)
  1567. {
  1568. struct rspamd_map *map = (struct rspamd_map *)w->data;
  1569. if (w->attr.st_nlink > 0) {
  1570. if (w->attr.st_mtime > w->prev.st_mtime) {
  1571. msg_info_map ("old mtime is %t, new mtime is %t for map file %s",
  1572. w->prev.st_mtime, w->attr.st_mtime, w->path);
  1573. /* Fire need modify flag */
  1574. struct rspamd_map_backend *bk;
  1575. guint i;
  1576. PTR_ARRAY_FOREACH (map->backends, i, bk) {
  1577. if (bk->protocol == MAP_PROTO_FILE) {
  1578. bk->data.fd->need_modify = TRUE;
  1579. }
  1580. }
  1581. map->next_check = 0;
  1582. if (map->scheduled_check) {
  1583. ev_timer_stop (map->event_loop, &map->scheduled_check->ev);
  1584. MAP_RELEASE (map->scheduled_check, "rspamd_map_on_stat");
  1585. map->scheduled_check = NULL;
  1586. }
  1587. rspamd_map_schedule_periodic (map, FALSE, TRUE, FALSE);
  1588. }
  1589. }
  1590. }
  1591. /* Start watching event for all maps */
  1592. void
  1593. rspamd_map_watch (struct rspamd_config *cfg,
  1594. struct ev_loop *event_loop,
  1595. struct rspamd_dns_resolver *resolver,
  1596. struct rspamd_worker *worker,
  1597. gboolean active_http)
  1598. {
  1599. GList *cur = cfg->maps;
  1600. struct rspamd_map *map;
  1601. struct rspamd_map_backend *bk;
  1602. guint i;
  1603. /* First of all do synced read of data */
  1604. while (cur) {
  1605. map = cur->data;
  1606. map->event_loop = event_loop;
  1607. map->r = resolver;
  1608. map->wrk = worker;
  1609. if (active_http) {
  1610. map->active_http = active_http;
  1611. }
  1612. if (!map->active_http) {
  1613. /* Check cached version more frequently as it is cheap */
  1614. if (map->poll_timeout >= cfg->map_timeout &&
  1615. cfg->map_file_watch_multiplier < 1.0) {
  1616. map->poll_timeout =
  1617. map->poll_timeout * cfg->map_file_watch_multiplier;
  1618. }
  1619. }
  1620. PTR_ARRAY_FOREACH (map->backends, i, bk) {
  1621. bk->event_loop = event_loop;
  1622. if (bk->protocol == MAP_PROTO_FILE) {
  1623. struct file_map_data *data;
  1624. data = bk->data.fd;
  1625. ev_stat_init (&data->st_ev, rspamd_map_on_stat,
  1626. data->filename, map->poll_timeout * cfg->map_file_watch_multiplier);
  1627. data->st_ev.data = map;
  1628. ev_stat_start (event_loop, &data->st_ev);
  1629. }
  1630. }
  1631. rspamd_map_schedule_periodic (map, FALSE, TRUE, FALSE);
  1632. cur = g_list_next (cur);
  1633. }
  1634. }
  1635. void
  1636. rspamd_map_preload (struct rspamd_config *cfg)
  1637. {
  1638. GList *cur = cfg->maps;
  1639. struct rspamd_map *map;
  1640. struct rspamd_map_backend *bk;
  1641. guint i;
  1642. gboolean map_ok;
  1643. /* First of all do synced read of data */
  1644. while (cur) {
  1645. map = cur->data;
  1646. map_ok = TRUE;
  1647. PTR_ARRAY_FOREACH (map->backends, i, bk) {
  1648. if (!(bk->protocol == MAP_PROTO_FILE ||
  1649. bk->protocol == MAP_PROTO_STATIC)) {
  1650. if (bk->protocol == MAP_PROTO_HTTP ||
  1651. bk->protocol == MAP_PROTO_HTTPS) {
  1652. if (!rspamd_map_has_http_cached_file (map, bk)) {
  1653. if (!map->fallback_backend) {
  1654. map_ok = FALSE;
  1655. }
  1656. break;
  1657. }
  1658. else {
  1659. continue; /* We are yet fine */
  1660. }
  1661. }
  1662. map_ok = FALSE;
  1663. break;
  1664. }
  1665. }
  1666. if (map_ok) {
  1667. struct map_periodic_cbdata fake_cbd;
  1668. gboolean succeed = TRUE;
  1669. memset (&fake_cbd, 0, sizeof (fake_cbd));
  1670. fake_cbd.cbdata.state = 0;
  1671. fake_cbd.cbdata.prev_data = *map->user_data;
  1672. fake_cbd.cbdata.cur_data = NULL;
  1673. fake_cbd.cbdata.map = map;
  1674. fake_cbd.map = map;
  1675. PTR_ARRAY_FOREACH (map->backends, i, bk) {
  1676. fake_cbd.cur_backend = i;
  1677. if (bk->protocol == MAP_PROTO_FILE) {
  1678. if (!read_map_file (map, bk->data.fd, bk, &fake_cbd)) {
  1679. succeed = FALSE;
  1680. break;
  1681. }
  1682. }
  1683. else if (bk->protocol == MAP_PROTO_STATIC) {
  1684. if (!read_map_static (map, bk->data.sd, bk, &fake_cbd)) {
  1685. succeed = FALSE;
  1686. break;
  1687. }
  1688. }
  1689. else if (bk->protocol == MAP_PROTO_HTTP ||
  1690. bk->protocol == MAP_PROTO_HTTPS) {
  1691. if (!rspamd_map_read_http_cached_file (map, bk, bk->data.hd,
  1692. &fake_cbd.cbdata)) {
  1693. if (map->fallback_backend) {
  1694. /* Try fallback */
  1695. g_assert (map->fallback_backend->protocol ==
  1696. MAP_PROTO_FILE);
  1697. if (!read_map_file (map,
  1698. map->fallback_backend->data.fd,
  1699. map->fallback_backend, &fake_cbd)) {
  1700. succeed = FALSE;
  1701. break;
  1702. }
  1703. }
  1704. else {
  1705. succeed = FALSE;
  1706. break;
  1707. }
  1708. }
  1709. }
  1710. else {
  1711. g_assert_not_reached ();
  1712. }
  1713. }
  1714. if (succeed) {
  1715. map->fin_callback (&fake_cbd.cbdata, map->user_data);
  1716. }
  1717. else {
  1718. msg_info_map ("preload of %s failed", map->name);
  1719. }
  1720. }
  1721. cur = g_list_next (cur);
  1722. }
  1723. }
  1724. void
  1725. rspamd_map_remove_all (struct rspamd_config *cfg)
  1726. {
  1727. struct rspamd_map *map;
  1728. GList *cur;
  1729. struct rspamd_map_backend *bk;
  1730. struct map_cb_data cbdata;
  1731. guint i;
  1732. for (cur = cfg->maps; cur != NULL; cur = g_list_next (cur)) {
  1733. map = cur->data;
  1734. if (map->tmp_dtor) {
  1735. map->tmp_dtor (map->tmp_dtor_data);
  1736. }
  1737. if (map->dtor) {
  1738. cbdata.prev_data = NULL;
  1739. cbdata.map = map;
  1740. cbdata.cur_data = *map->user_data;
  1741. map->dtor (&cbdata);
  1742. *map->user_data = NULL;
  1743. }
  1744. for (i = 0; i < map->backends->len; i ++) {
  1745. bk = g_ptr_array_index (map->backends, i);
  1746. MAP_RELEASE (bk, "rspamd_map_backend");
  1747. }
  1748. if (map->fallback_backend) {
  1749. MAP_RELEASE (map->fallback_backend, "rspamd_map_backend");
  1750. }
  1751. }
  1752. g_list_free (cfg->maps);
  1753. cfg->maps = NULL;
  1754. }
  1755. static const gchar *
  1756. rspamd_map_check_proto (struct rspamd_config *cfg,
  1757. const gchar *map_line, struct rspamd_map_backend *bk)
  1758. {
  1759. const gchar *pos = map_line, *end, *end_key;
  1760. g_assert (bk != NULL);
  1761. g_assert (pos != NULL);
  1762. end = pos + strlen (pos);
  1763. /* Static check */
  1764. if (g_ascii_strcasecmp (pos, "static") == 0) {
  1765. bk->protocol = MAP_PROTO_STATIC;
  1766. bk->uri = g_strdup (pos);
  1767. return pos;
  1768. }
  1769. else if (g_ascii_strcasecmp (pos, "zst+static") == 0) {
  1770. bk->protocol = MAP_PROTO_STATIC;
  1771. bk->uri = g_strdup (pos + 4);
  1772. bk->is_compressed = TRUE;
  1773. return pos + 4;
  1774. }
  1775. for (;;) {
  1776. if (g_ascii_strncasecmp (pos, "sign+", sizeof ("sign+") - 1) == 0) {
  1777. bk->is_signed = TRUE;
  1778. pos += sizeof ("sign+") - 1;
  1779. }
  1780. else if (g_ascii_strncasecmp (pos, "fallback+", sizeof ("fallback+") - 1) == 0) {
  1781. bk->is_fallback = TRUE;
  1782. pos += sizeof ("fallback+") - 1;
  1783. }
  1784. else if (g_ascii_strncasecmp (pos, "key=", sizeof ("key=") - 1) == 0) {
  1785. pos += sizeof ("key=") - 1;
  1786. end_key = memchr (pos, '+', end - pos);
  1787. if (end_key != NULL) {
  1788. bk->trusted_pubkey = rspamd_pubkey_from_base32 (pos, end_key - pos,
  1789. RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519);
  1790. if (bk->trusted_pubkey == NULL) {
  1791. msg_err_config ("cannot read pubkey from map: %s",
  1792. map_line);
  1793. return NULL;
  1794. }
  1795. pos = end_key + 1;
  1796. } else if (end - pos > 64) {
  1797. /* Try hex encoding */
  1798. bk->trusted_pubkey = rspamd_pubkey_from_hex (pos, 64,
  1799. RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519);
  1800. if (bk->trusted_pubkey == NULL) {
  1801. msg_err_config ("cannot read pubkey from map: %s",
  1802. map_line);
  1803. return NULL;
  1804. }
  1805. pos += 64;
  1806. } else {
  1807. msg_err_config ("cannot read pubkey from map: %s",
  1808. map_line);
  1809. return NULL;
  1810. }
  1811. if (*pos == '+' || *pos == ':') {
  1812. pos++;
  1813. }
  1814. }
  1815. else {
  1816. /* No known flags */
  1817. break;
  1818. }
  1819. }
  1820. bk->protocol = MAP_PROTO_FILE;
  1821. if (g_ascii_strncasecmp (pos, "http://", sizeof ("http://") - 1) == 0) {
  1822. bk->protocol = MAP_PROTO_HTTP;
  1823. /* Include http:// */
  1824. bk->uri = g_strdup (pos);
  1825. pos += sizeof ("http://") - 1;
  1826. }
  1827. else if (g_ascii_strncasecmp (pos, "https://", sizeof ("https://") - 1) == 0) {
  1828. bk->protocol = MAP_PROTO_HTTPS;
  1829. /* Include https:// */
  1830. bk->uri = g_strdup (pos);
  1831. pos += sizeof ("https://") - 1;
  1832. }
  1833. else if (g_ascii_strncasecmp (pos, "file://", sizeof ("file://") - 1) == 0) {
  1834. pos += sizeof ("file://") - 1;
  1835. /* Exclude file:// */
  1836. bk->uri = g_strdup (pos);
  1837. }
  1838. else if (*pos == '/') {
  1839. /* Trivial file case */
  1840. bk->uri = g_strdup (pos);
  1841. }
  1842. else {
  1843. msg_err_config ("invalid map fetching protocol: %s", map_line);
  1844. return NULL;
  1845. }
  1846. return pos;
  1847. }
  1848. gboolean
  1849. rspamd_map_is_map (const gchar *map_line)
  1850. {
  1851. gboolean ret = FALSE;
  1852. g_assert (map_line != NULL);
  1853. if (map_line[0] == '/') {
  1854. ret = TRUE;
  1855. }
  1856. else if (g_ascii_strncasecmp (map_line, "sign+", sizeof ("sign+") - 1) == 0) {
  1857. ret = TRUE;
  1858. }
  1859. else if (g_ascii_strncasecmp (map_line, "fallback+", sizeof ("fallback+") - 1) == 0) {
  1860. ret = TRUE;
  1861. }
  1862. else if (g_ascii_strncasecmp (map_line, "file://", sizeof ("file://") - 1) == 0) {
  1863. ret = TRUE;
  1864. }
  1865. else if (g_ascii_strncasecmp (map_line, "http://", sizeof ("http://") - 1) == 0) {
  1866. ret = TRUE;
  1867. }
  1868. else if (g_ascii_strncasecmp (map_line, "https://", sizeof ("https://") - 1) == 0) {
  1869. ret = TRUE;
  1870. }
  1871. return ret;
  1872. }
  1873. static void
  1874. rspamd_map_backend_dtor (struct rspamd_map_backend *bk)
  1875. {
  1876. g_free (bk->uri);
  1877. switch (bk->protocol) {
  1878. case MAP_PROTO_FILE:
  1879. if (bk->data.fd) {
  1880. ev_stat_stop (bk->event_loop, &bk->data.fd->st_ev);
  1881. g_free (bk->data.fd->filename);
  1882. g_free (bk->data.fd);
  1883. }
  1884. break;
  1885. case MAP_PROTO_STATIC:
  1886. if (bk->data.sd) {
  1887. if (bk->data.sd->data) {
  1888. g_free (bk->data.sd->data);
  1889. }
  1890. g_free (bk->data.sd);
  1891. }
  1892. break;
  1893. case MAP_PROTO_HTTP:
  1894. case MAP_PROTO_HTTPS:
  1895. if (bk->data.hd) {
  1896. struct http_map_data *data = bk->data.hd;
  1897. g_free (data->host);
  1898. g_free (data->path);
  1899. g_free (data->rest);
  1900. if (data->userinfo) {
  1901. g_free (data->userinfo);
  1902. }
  1903. if (data->etag) {
  1904. rspamd_fstring_free (data->etag);
  1905. }
  1906. if (g_atomic_int_compare_and_exchange (&data->cache->available, 1, 0)) {
  1907. if (data->cur_cache_cbd) {
  1908. MAP_RELEASE (data->cur_cache_cbd->shm,
  1909. "rspamd_http_map_cached_cbdata");
  1910. ev_timer_stop (data->cur_cache_cbd->event_loop,
  1911. &data->cur_cache_cbd->timeout);
  1912. g_free (data->cur_cache_cbd);
  1913. data->cur_cache_cbd = NULL;
  1914. }
  1915. unlink (data->cache->shmem_name);
  1916. }
  1917. g_free (bk->data.hd);
  1918. }
  1919. break;
  1920. }
  1921. if (bk->trusted_pubkey) {
  1922. rspamd_pubkey_unref (bk->trusted_pubkey);
  1923. }
  1924. g_free (bk);
  1925. }
  1926. static struct rspamd_map_backend *
  1927. rspamd_map_parse_backend (struct rspamd_config *cfg, const gchar *map_line)
  1928. {
  1929. struct rspamd_map_backend *bk;
  1930. struct file_map_data *fdata = NULL;
  1931. struct http_map_data *hdata = NULL;
  1932. struct static_map_data *sdata = NULL;
  1933. struct http_parser_url up;
  1934. const gchar *end, *p;
  1935. rspamd_ftok_t tok;
  1936. bk = g_malloc0 (sizeof (*bk));
  1937. REF_INIT_RETAIN (bk, rspamd_map_backend_dtor);
  1938. if (!rspamd_map_check_proto (cfg, map_line, bk)) {
  1939. goto err;
  1940. }
  1941. if (bk->is_fallback && bk->protocol != MAP_PROTO_FILE) {
  1942. msg_err_config ("fallback backend must be file for %s", bk->uri);
  1943. goto err;
  1944. }
  1945. end = map_line + strlen (map_line);
  1946. if (end - map_line > 5) {
  1947. p = end - 5;
  1948. if (g_ascii_strcasecmp (p, ".zstd") == 0) {
  1949. bk->is_compressed = TRUE;
  1950. }
  1951. p = end - 4;
  1952. if (g_ascii_strcasecmp (p, ".zst") == 0) {
  1953. bk->is_compressed = TRUE;
  1954. }
  1955. }
  1956. /* Now check for each proto separately */
  1957. if (bk->protocol == MAP_PROTO_FILE) {
  1958. fdata = g_malloc0 (sizeof (struct file_map_data));
  1959. if (access (bk->uri, R_OK) == -1) {
  1960. if (errno != ENOENT) {
  1961. msg_err_config ("cannot open file '%s': %s", bk->uri, strerror (errno));
  1962. goto err;
  1963. }
  1964. msg_info_config (
  1965. "map '%s' is not found, but it can be loaded automatically later",
  1966. bk->uri);
  1967. }
  1968. fdata->filename = g_strdup (bk->uri);
  1969. bk->data.fd = fdata;
  1970. }
  1971. else if (bk->protocol == MAP_PROTO_HTTP || bk->protocol == MAP_PROTO_HTTPS) {
  1972. hdata = g_malloc0 (sizeof (struct http_map_data));
  1973. memset (&up, 0, sizeof (up));
  1974. if (http_parser_parse_url (bk->uri, strlen (bk->uri), FALSE,
  1975. &up) != 0) {
  1976. msg_err_config ("cannot parse HTTP url: %s", bk->uri);
  1977. goto err;
  1978. }
  1979. else {
  1980. if (!(up.field_set & 1u << UF_HOST)) {
  1981. msg_err_config ("cannot parse HTTP url: %s: no host", bk->uri);
  1982. goto err;
  1983. }
  1984. tok.begin = bk->uri + up.field_data[UF_HOST].off;
  1985. tok.len = up.field_data[UF_HOST].len;
  1986. hdata->host = rspamd_ftokdup (&tok);
  1987. if (up.field_set & (1u << UF_PORT)) {
  1988. hdata->port = up.port;
  1989. }
  1990. else {
  1991. if (bk->protocol == MAP_PROTO_HTTP) {
  1992. hdata->port = 80;
  1993. }
  1994. else {
  1995. hdata->port = 443;
  1996. }
  1997. }
  1998. if (up.field_set & (1u << UF_PATH)) {
  1999. tok.begin = bk->uri + up.field_data[UF_PATH].off;
  2000. tok.len = up.field_data[UF_PATH].len;
  2001. hdata->path = rspamd_ftokdup (&tok);
  2002. /* We also need to check query + fragment */
  2003. if (up.field_set & ((1u << UF_QUERY) | (1u << UF_FRAGMENT))) {
  2004. tok.begin = bk->uri + up.field_data[UF_PATH].off +
  2005. up.field_data[UF_PATH].len;
  2006. tok.len = strlen (tok.begin);
  2007. hdata->rest = rspamd_ftokdup (&tok);
  2008. }
  2009. else {
  2010. hdata->rest = g_strdup ("");
  2011. }
  2012. }
  2013. if (up.field_set & (1u << UF_USERINFO)) {
  2014. /* Create authorisation header for basic auth */
  2015. guint len = sizeof ("Basic ") +
  2016. up.field_data[UF_USERINFO].len * 8 / 5 + 4;
  2017. hdata->userinfo = g_malloc (len);
  2018. rspamd_snprintf (hdata->userinfo, len, "Basic %*Bs",
  2019. (int)up.field_data[UF_USERINFO].len,
  2020. bk->uri + up.field_data[UF_USERINFO].off);
  2021. }
  2022. }
  2023. hdata->cache = rspamd_mempool_alloc0_shared (cfg->cfg_pool,
  2024. sizeof (*hdata->cache));
  2025. bk->data.hd = hdata;
  2026. }
  2027. else if (bk->protocol == MAP_PROTO_STATIC) {
  2028. sdata = g_malloc0 (sizeof (*sdata));
  2029. bk->data.sd = sdata;
  2030. }
  2031. bk->id = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_T1HA,
  2032. bk->uri, strlen (bk->uri), 0xdeadbabe);
  2033. return bk;
  2034. err:
  2035. MAP_RELEASE (bk, "rspamd_map_backend");
  2036. if (hdata) {
  2037. g_free (hdata);
  2038. }
  2039. return NULL;
  2040. }
  2041. static void
  2042. rspamd_map_calculate_hash (struct rspamd_map *map)
  2043. {
  2044. struct rspamd_map_backend *bk;
  2045. guint i;
  2046. rspamd_cryptobox_hash_state_t st;
  2047. gchar *cksum_encoded, cksum[rspamd_cryptobox_HASHBYTES];
  2048. rspamd_cryptobox_hash_init (&st, NULL, 0);
  2049. for (i = 0; i < map->backends->len; i ++) {
  2050. bk = g_ptr_array_index (map->backends, i);
  2051. rspamd_cryptobox_hash_update (&st, bk->uri, strlen (bk->uri));
  2052. }
  2053. rspamd_cryptobox_hash_final (&st, cksum);
  2054. cksum_encoded = rspamd_encode_base32 (cksum, sizeof (cksum));
  2055. rspamd_strlcpy (map->tag, cksum_encoded, sizeof (map->tag));
  2056. g_free (cksum_encoded);
  2057. }
  2058. static gboolean
  2059. rspamd_map_add_static_string (struct rspamd_config *cfg,
  2060. const ucl_object_t *elt,
  2061. GString *target)
  2062. {
  2063. gsize sz;
  2064. const gchar *dline;
  2065. if (ucl_object_type (elt) != UCL_STRING) {
  2066. msg_err_config ("map has static backend but `data` is "
  2067. "not string like: %s",
  2068. ucl_object_type_to_string (elt->type));
  2069. return FALSE;
  2070. }
  2071. /* Otherwise, we copy data to the backend */
  2072. dline = ucl_object_tolstring (elt, &sz);
  2073. if (sz == 0) {
  2074. msg_err_config ("map has static backend but empty no data");
  2075. return FALSE;
  2076. }
  2077. g_string_append_len (target, dline, sz);
  2078. g_string_append_c (target, '\n');
  2079. return TRUE;
  2080. }
  2081. struct rspamd_map *
  2082. rspamd_map_add (struct rspamd_config *cfg,
  2083. const gchar *map_line,
  2084. const gchar *description,
  2085. map_cb_t read_callback,
  2086. map_fin_cb_t fin_callback,
  2087. map_dtor_t dtor,
  2088. void **user_data)
  2089. {
  2090. struct rspamd_map *map;
  2091. struct rspamd_map_backend *bk;
  2092. bk = rspamd_map_parse_backend (cfg, map_line);
  2093. if (bk == NULL) {
  2094. return NULL;
  2095. }
  2096. if (bk->is_fallback) {
  2097. msg_err_config ("cannot add map with fallback only backend: %s", bk->uri);
  2098. REF_RELEASE (bk);
  2099. return NULL;
  2100. }
  2101. map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_map));
  2102. map->read_callback = read_callback;
  2103. map->fin_callback = fin_callback;
  2104. map->dtor = dtor;
  2105. map->user_data = user_data;
  2106. map->cfg = cfg;
  2107. map->id = rspamd_random_uint64_fast ();
  2108. map->locked =
  2109. rspamd_mempool_alloc0_shared (cfg->cfg_pool, sizeof (gint));
  2110. map->backends = g_ptr_array_sized_new (1);
  2111. rspamd_mempool_add_destructor (cfg->cfg_pool, rspamd_ptr_array_free_hard,
  2112. map->backends);
  2113. g_ptr_array_add (map->backends, bk);
  2114. map->name = rspamd_mempool_strdup (cfg->cfg_pool, map_line);
  2115. if (bk->protocol == MAP_PROTO_FILE) {
  2116. map->poll_timeout = (cfg->map_timeout * cfg->map_file_watch_multiplier);
  2117. } else {
  2118. map->poll_timeout = cfg->map_timeout;
  2119. }
  2120. if (description != NULL) {
  2121. map->description = rspamd_mempool_strdup (cfg->cfg_pool, description);
  2122. }
  2123. rspamd_map_calculate_hash (map);
  2124. msg_info_map ("added map %s", bk->uri);
  2125. cfg->maps = g_list_prepend (cfg->maps, map);
  2126. return map;
  2127. }
  2128. static inline void
  2129. rspamd_map_add_backend (struct rspamd_map *map, struct rspamd_map_backend *bk)
  2130. {
  2131. if (bk->is_fallback) {
  2132. if (map->fallback_backend) {
  2133. msg_warn_map ("redefining fallback backend from %s to %s",
  2134. map->fallback_backend->uri, bk->uri);
  2135. }
  2136. map->fallback_backend = bk;
  2137. }
  2138. else {
  2139. g_ptr_array_add (map->backends, bk);
  2140. }
  2141. }
  2142. struct rspamd_map*
  2143. rspamd_map_add_from_ucl (struct rspamd_config *cfg,
  2144. const ucl_object_t *obj,
  2145. const gchar *description,
  2146. map_cb_t read_callback,
  2147. map_fin_cb_t fin_callback,
  2148. map_dtor_t dtor,
  2149. void **user_data)
  2150. {
  2151. ucl_object_iter_t it = NULL;
  2152. const ucl_object_t *cur, *elt;
  2153. struct rspamd_map *map;
  2154. struct rspamd_map_backend *bk;
  2155. guint i;
  2156. g_assert (obj != NULL);
  2157. if (ucl_object_type (obj) == UCL_STRING) {
  2158. /* Just a plain string */
  2159. return rspamd_map_add (cfg, ucl_object_tostring (obj), description,
  2160. read_callback, fin_callback, dtor, user_data);
  2161. }
  2162. map = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_map));
  2163. map->read_callback = read_callback;
  2164. map->fin_callback = fin_callback;
  2165. map->dtor = dtor;
  2166. map->user_data = user_data;
  2167. map->cfg = cfg;
  2168. map->id = rspamd_random_uint64_fast ();
  2169. map->locked =
  2170. rspamd_mempool_alloc0_shared (cfg->cfg_pool, sizeof (gint));
  2171. map->backends = g_ptr_array_new ();
  2172. rspamd_mempool_add_destructor (cfg->cfg_pool, rspamd_ptr_array_free_hard,
  2173. map->backends);
  2174. map->poll_timeout = cfg->map_timeout;
  2175. if (description) {
  2176. map->description = rspamd_mempool_strdup (cfg->cfg_pool, description);
  2177. }
  2178. if (ucl_object_type (obj) == UCL_ARRAY) {
  2179. /* Add array of maps as multiple backends */
  2180. while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
  2181. if (ucl_object_type (cur) == UCL_STRING) {
  2182. bk = rspamd_map_parse_backend (cfg, ucl_object_tostring (cur));
  2183. if (bk != NULL) {
  2184. rspamd_map_add_backend (map, bk);
  2185. if (!map->name) {
  2186. map->name = rspamd_mempool_strdup (cfg->cfg_pool,
  2187. ucl_object_tostring (cur));
  2188. }
  2189. }
  2190. }
  2191. else {
  2192. msg_err_config ("bad map element type: %s",
  2193. ucl_object_type_to_string (ucl_object_type (cur)));
  2194. }
  2195. }
  2196. if (map->backends->len == 0) {
  2197. msg_err_config ("map has no urls to be loaded: empty list");
  2198. goto err;
  2199. }
  2200. }
  2201. else if (ucl_object_type (obj) == UCL_OBJECT) {
  2202. elt = ucl_object_lookup (obj, "name");
  2203. if (elt && ucl_object_type (elt) == UCL_STRING) {
  2204. map->name = rspamd_mempool_strdup (cfg->cfg_pool,
  2205. ucl_object_tostring (elt));
  2206. }
  2207. elt = ucl_object_lookup (obj, "description");
  2208. if (elt && ucl_object_type (elt) == UCL_STRING) {
  2209. map->description = rspamd_mempool_strdup (cfg->cfg_pool,
  2210. ucl_object_tostring (elt));
  2211. }
  2212. elt = ucl_object_lookup_any (obj, "timeout", "poll", "poll_time",
  2213. "watch_interval", NULL);
  2214. if (elt) {
  2215. map->poll_timeout = ucl_object_todouble (elt);
  2216. }
  2217. elt = ucl_object_lookup_any (obj, "upstreams", "url", "urls", NULL);
  2218. if (elt == NULL) {
  2219. msg_err_config ("map has no urls to be loaded: no elt");
  2220. goto err;
  2221. }
  2222. if (ucl_object_type (elt) == UCL_ARRAY) {
  2223. /* Add array of maps as multiple backends */
  2224. it = ucl_object_iterate_new (elt);
  2225. while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
  2226. if (ucl_object_type (cur) == UCL_STRING) {
  2227. bk = rspamd_map_parse_backend (cfg, ucl_object_tostring (cur));
  2228. if (bk != NULL) {
  2229. rspamd_map_add_backend (map, bk);
  2230. if (!map->name) {
  2231. map->name = rspamd_mempool_strdup (cfg->cfg_pool,
  2232. ucl_object_tostring (cur));
  2233. }
  2234. }
  2235. }
  2236. else {
  2237. msg_err_config ("bad map element type: %s",
  2238. ucl_object_type_to_string (ucl_object_type (cur)));
  2239. ucl_object_iterate_free (it);
  2240. goto err;
  2241. }
  2242. }
  2243. ucl_object_iterate_free (it);
  2244. if (map->backends->len == 0) {
  2245. msg_err_config ("map has no urls to be loaded: empty object list");
  2246. goto err;
  2247. }
  2248. }
  2249. else if (ucl_object_type (elt) == UCL_STRING) {
  2250. bk = rspamd_map_parse_backend (cfg, ucl_object_tostring (elt));
  2251. if (bk != NULL) {
  2252. rspamd_map_add_backend (map, bk);
  2253. if (!map->name) {
  2254. map->name = rspamd_mempool_strdup (cfg->cfg_pool,
  2255. ucl_object_tostring (elt));
  2256. }
  2257. }
  2258. }
  2259. if (!map->backends || map->backends->len == 0) {
  2260. msg_err_config ("map has no urls to be loaded: no valid backends");
  2261. goto err;
  2262. }
  2263. }
  2264. else {
  2265. msg_err_config ("map has invalid type for value: %s",
  2266. ucl_object_type_to_string (ucl_object_type (obj)));
  2267. goto err;
  2268. }
  2269. gboolean all_local = TRUE;
  2270. PTR_ARRAY_FOREACH (map->backends, i, bk) {
  2271. if (bk->protocol == MAP_PROTO_STATIC) {
  2272. GString *map_data;
  2273. /* We need data field in ucl */
  2274. elt = ucl_object_lookup (obj, "data");
  2275. if (elt == NULL) {
  2276. msg_err_config ("map has static backend but no `data` field");
  2277. goto err;
  2278. }
  2279. if (ucl_object_type (elt) == UCL_STRING) {
  2280. map_data = g_string_sized_new (32);
  2281. if (rspamd_map_add_static_string (cfg, elt, map_data)) {
  2282. bk->data.sd->data = map_data->str;
  2283. bk->data.sd->len = map_data->len;
  2284. g_string_free (map_data, FALSE);
  2285. }
  2286. else {
  2287. g_string_free (map_data, TRUE);
  2288. msg_err_config ("map has static backend with invalid `data` field");
  2289. goto err;
  2290. }
  2291. }
  2292. else if (ucl_object_type (elt) == UCL_ARRAY) {
  2293. map_data = g_string_sized_new (32);
  2294. it = ucl_object_iterate_new (elt);
  2295. while ((cur = ucl_object_iterate_safe (it, true))) {
  2296. if (!rspamd_map_add_static_string (cfg, cur, map_data)) {
  2297. g_string_free (map_data, TRUE);
  2298. msg_err_config ("map has static backend with invalid "
  2299. "`data` field");
  2300. ucl_object_iterate_free (it);
  2301. goto err;
  2302. }
  2303. }
  2304. ucl_object_iterate_free (it);
  2305. bk->data.sd->data = map_data->str;
  2306. bk->data.sd->len = map_data->len;
  2307. g_string_free (map_data, FALSE);
  2308. }
  2309. }
  2310. else if (bk->protocol != MAP_PROTO_FILE) {
  2311. all_local = FALSE;
  2312. }
  2313. }
  2314. if (all_local) {
  2315. map->poll_timeout = (map->poll_timeout *
  2316. cfg->map_file_watch_multiplier);
  2317. }
  2318. rspamd_map_calculate_hash (map);
  2319. msg_debug_map ("added map from ucl");
  2320. cfg->maps = g_list_prepend (cfg->maps, map);
  2321. return map;
  2322. err:
  2323. if (map) {
  2324. PTR_ARRAY_FOREACH (map->backends, i, bk) {
  2325. MAP_RELEASE (bk, "rspamd_map_backend");
  2326. }
  2327. }
  2328. return NULL;
  2329. }
  2330. rspamd_map_traverse_function
  2331. rspamd_map_get_traverse_function (struct rspamd_map *map)
  2332. {
  2333. if (map) {
  2334. return map->traverse_function;
  2335. }
  2336. return NULL;
  2337. }
  2338. void
  2339. rspamd_map_traverse (struct rspamd_map *map, rspamd_map_traverse_cb cb,
  2340. gpointer cbdata, gboolean reset_hits)
  2341. {
  2342. if (*map->user_data && map->traverse_function) {
  2343. map->traverse_function (*map->user_data, cb, cbdata, reset_hits);
  2344. }
  2345. }