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 74KB

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