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.

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