You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

map.c 71KB

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