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.

fuzzy_storage.c 82KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * Rspamd fuzzy storage server
  18. */
  19. #include "config.h"
  20. #include "libserver/fuzzy_wire.h"
  21. #include "util.h"
  22. #include "rspamd.h"
  23. #include "map.h"
  24. #include "map_helpers.h"
  25. #include "fuzzy_wire.h"
  26. #include "fuzzy_backend.h"
  27. #include "ottery.h"
  28. #include "ref.h"
  29. #include "xxhash.h"
  30. #include "libserver/worker_util.h"
  31. #include "libserver/rspamd_control.h"
  32. #include "libcryptobox/cryptobox.h"
  33. #include "libcryptobox/keypairs_cache.h"
  34. #include "libcryptobox/keypair.h"
  35. #include "libserver/rspamd_control.h"
  36. #include "libutil/hash.h"
  37. #include "libutil/map_private.h"
  38. #include "libutil/http_private.h"
  39. #include "libutil/http_router.h"
  40. #include "unix-std.h"
  41. #include <math.h>
  42. /* Resync value in seconds */
  43. #define DEFAULT_SYNC_TIMEOUT 60.0
  44. #define DEFAULT_KEYPAIR_CACHE_SIZE 512
  45. #define DEFAULT_MASTER_TIMEOUT 10.0
  46. #define DEFAULT_UPDATES_MAXFAIL 3
  47. #define COOKIE_SIZE 128
  48. #define DEFAULT_MAX_BUCKETS 2000
  49. #define DEFAULT_BUCKET_TTL 3600
  50. #define DEFAULT_BUCKET_MASK 24
  51. static const gchar *local_db_name = "local";
  52. #define msg_err_fuzzy_update(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
  53. session->name, session->uid, \
  54. G_STRFUNC, \
  55. __VA_ARGS__)
  56. #define msg_warn_fuzzy_update(...) rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
  57. session->name, session->uid, \
  58. G_STRFUNC, \
  59. __VA_ARGS__)
  60. #define msg_info_fuzzy_update(...) rspamd_default_log_function (G_LOG_LEVEL_INFO, \
  61. session->name, session->uid, \
  62. G_STRFUNC, \
  63. __VA_ARGS__)
  64. #define msg_err_fuzzy_collection(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
  65. "fuzzy_collection", session->uid, \
  66. G_STRFUNC, \
  67. __VA_ARGS__)
  68. #define msg_warn_fuzzy_collection(...) rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
  69. "fuzzy_collection", session->uid, \
  70. G_STRFUNC, \
  71. __VA_ARGS__)
  72. #define msg_info_fuzzy_collection(...) rspamd_default_log_function (G_LOG_LEVEL_INFO, \
  73. "fuzzy_collection", session->uid, \
  74. G_STRFUNC, \
  75. __VA_ARGS__)
  76. /* Init functions */
  77. gpointer init_fuzzy (struct rspamd_config *cfg);
  78. void start_fuzzy (struct rspamd_worker *worker);
  79. worker_t fuzzy_worker = {
  80. "fuzzy", /* Name */
  81. init_fuzzy, /* Init function */
  82. start_fuzzy, /* Start function */
  83. RSPAMD_WORKER_HAS_SOCKET,
  84. RSPAMD_WORKER_SOCKET_UDP|RSPAMD_WORKER_SOCKET_TCP, /* Both socket */
  85. RSPAMD_WORKER_VER /* Version info */
  86. };
  87. struct fuzzy_global_stat {
  88. guint64 fuzzy_hashes;
  89. /**< number of fuzzy hashes stored */
  90. guint64 fuzzy_hashes_expired;
  91. /**< number of fuzzy hashes expired */
  92. guint64 fuzzy_hashes_checked[RSPAMD_FUZZY_EPOCH_MAX];
  93. /**< amount of check requests for each epoch */
  94. guint64 fuzzy_shingles_checked[RSPAMD_FUZZY_EPOCH_MAX];
  95. /**< amount of shingle check requests for each epoch */
  96. guint64 fuzzy_hashes_found[RSPAMD_FUZZY_EPOCH_MAX];
  97. /**< amount of hashes found by epoch */
  98. guint64 invalid_requests;
  99. };
  100. struct fuzzy_key_stat {
  101. guint64 checked;
  102. guint64 matched;
  103. guint64 added;
  104. guint64 deleted;
  105. guint64 errors;
  106. rspamd_lru_hash_t *last_ips;
  107. };
  108. struct rspamd_fuzzy_mirror {
  109. gchar *name;
  110. struct upstream_list *u;
  111. struct rspamd_cryptobox_pubkey *key;
  112. };
  113. struct rspamd_leaky_bucket_elt {
  114. rspamd_inet_addr_t *addr;
  115. gdouble last;
  116. gdouble cur;
  117. };
  118. static const guint64 rspamd_fuzzy_storage_magic = 0x291a3253eb1b3ea5ULL;
  119. struct rspamd_fuzzy_storage_ctx {
  120. guint64 magic;
  121. /* Events base */
  122. struct event_base *ev_base;
  123. /* DNS resolver */
  124. struct rspamd_dns_resolver *resolver;
  125. /* Config */
  126. struct rspamd_config *cfg;
  127. /* END OF COMMON PART */
  128. struct fuzzy_global_stat stat;
  129. gdouble expire;
  130. gdouble sync_timeout;
  131. struct rspamd_radix_map_helper *update_ips;
  132. struct rspamd_radix_map_helper *master_ips;
  133. struct rspamd_radix_map_helper *blocked_ips;
  134. struct rspamd_radix_map_helper *ratelimit_whitelist;
  135. struct rspamd_cryptobox_keypair *sync_keypair;
  136. struct rspamd_cryptobox_pubkey *master_key;
  137. struct timeval master_io_tv;
  138. gdouble master_timeout;
  139. GPtrArray *mirrors;
  140. const ucl_object_t *update_map;
  141. const ucl_object_t *masters_map;
  142. const ucl_object_t *blocked_map;
  143. const ucl_object_t *ratelimit_whitelist_map;
  144. GHashTable *master_flags;
  145. guint keypair_cache_size;
  146. gint peer_fd;
  147. struct event peer_ev;
  148. struct event stat_ev;
  149. struct timeval stat_tv;
  150. /* Local keypair */
  151. struct rspamd_cryptobox_keypair *default_keypair; /* Bad clash, need for parse keypair */
  152. struct fuzzy_key *default_key;
  153. GHashTable *keys;
  154. gboolean encrypted_only;
  155. gboolean collection_mode;
  156. gboolean read_only;
  157. struct rspamd_cryptobox_keypair *collection_keypair;
  158. struct rspamd_cryptobox_pubkey *collection_sign_key;
  159. gchar *collection_id_file;
  160. struct rspamd_http_context *http_ctx;
  161. struct rspamd_keypair_cache *keypair_cache;
  162. rspamd_lru_hash_t *errors_ips;
  163. rspamd_lru_hash_t *ratelimit_buckets;
  164. struct rspamd_fuzzy_backend *backend;
  165. GArray *updates_pending;
  166. guint updates_failed;
  167. guint updates_maxfail;
  168. guint32 collection_id;
  169. /* Ratelimits */
  170. guint leaky_bucket_ttl;
  171. guint leaky_bucket_mask;
  172. guint max_buckets;
  173. gboolean ratelimit_log_only;
  174. gdouble leaky_bucket_burst;
  175. gdouble leaky_bucket_rate;
  176. struct rspamd_worker *worker;
  177. struct rspamd_http_connection_router *collection_rt;
  178. const ucl_object_t *skip_map;
  179. struct rspamd_hash_map_helper *skip_hashes;
  180. guchar cookie[COOKIE_SIZE];
  181. };
  182. enum fuzzy_cmd_type {
  183. CMD_NORMAL,
  184. CMD_SHINGLE,
  185. CMD_ENCRYPTED_NORMAL,
  186. CMD_ENCRYPTED_SHINGLE
  187. };
  188. struct fuzzy_session {
  189. struct rspamd_worker *worker;
  190. rspamd_inet_addr_t *addr;
  191. struct rspamd_fuzzy_storage_ctx *ctx;
  192. union {
  193. struct rspamd_fuzzy_encrypted_shingle_cmd enc_shingle;
  194. struct rspamd_fuzzy_encrypted_cmd enc_normal;
  195. struct rspamd_fuzzy_cmd normal;
  196. struct rspamd_fuzzy_shingle_cmd shingle;
  197. } cmd;
  198. struct rspamd_fuzzy_encrypted_reply reply;
  199. struct fuzzy_key_stat *ip_stat;
  200. enum rspamd_fuzzy_epoch epoch;
  201. enum fuzzy_cmd_type cmd_type;
  202. gint fd;
  203. guint64 time;
  204. struct event io;
  205. ref_entry_t ref;
  206. struct fuzzy_key_stat *key_stat;
  207. guchar nm[rspamd_cryptobox_MAX_NMBYTES];
  208. };
  209. struct fuzzy_peer_request {
  210. struct event io_ev;
  211. struct fuzzy_peer_cmd cmd;
  212. };
  213. struct fuzzy_key {
  214. struct rspamd_cryptobox_keypair *key;
  215. struct rspamd_cryptobox_pubkey *pk;
  216. struct fuzzy_key_stat *stat;
  217. };
  218. struct fuzzy_master_update_session {
  219. const gchar *name;
  220. gchar uid[16];
  221. struct rspamd_http_connection *conn;
  222. struct rspamd_http_message *msg;
  223. struct rspamd_fuzzy_storage_ctx *ctx;
  224. const gchar *src;
  225. gchar *psrc;
  226. rspamd_inet_addr_t *addr;
  227. gboolean replied;
  228. gint sock;
  229. };
  230. static void rspamd_fuzzy_write_reply (struct fuzzy_session *session);
  231. static gboolean
  232. rspamd_fuzzy_check_ratelimit (struct fuzzy_session *session)
  233. {
  234. rspamd_inet_addr_t *masked;
  235. struct rspamd_leaky_bucket_elt *elt;
  236. struct timeval tv;
  237. gdouble now;
  238. if (session->ctx->ratelimit_whitelist != NULL) {
  239. if (rspamd_match_radix_map_addr (session->ctx->ratelimit_whitelist,
  240. session->addr) != NULL) {
  241. return TRUE;
  242. }
  243. }
  244. /*
  245. if (rspamd_inet_address_is_local (session->addr, TRUE)) {
  246. return TRUE;
  247. }
  248. */
  249. masked = rspamd_inet_address_copy (session->addr);
  250. if (rspamd_inet_address_get_af (masked) == AF_INET) {
  251. rspamd_inet_address_apply_mask (masked,
  252. MIN (session->ctx->leaky_bucket_mask, 32));
  253. }
  254. else {
  255. /* Must be at least /64 */
  256. rspamd_inet_address_apply_mask (masked,
  257. MIN (MAX (session->ctx->leaky_bucket_mask * 4, 64), 128));
  258. }
  259. #ifdef HAVE_EVENT_NO_CACHE_TIME_FUNC
  260. event_base_gettimeofday_cached (session->ctx->ev_base, &tv);
  261. #else
  262. gettimeofday (&tv, NULL);
  263. #endif
  264. now = tv_to_double (&tv);
  265. elt = rspamd_lru_hash_lookup (session->ctx->ratelimit_buckets, masked,
  266. tv.tv_sec);
  267. if (elt) {
  268. gboolean ratelimited = FALSE;
  269. if (isnan (elt->cur)) {
  270. /* Ratelimit exceeded, preserve it for the whole ttl */
  271. ratelimited = TRUE;
  272. }
  273. else {
  274. /* Update bucket */
  275. if (elt->last < now) {
  276. elt->cur -= session->ctx->leaky_bucket_rate * (now - elt->last);
  277. elt->last = now;
  278. if (elt->cur < 0) {
  279. elt->cur = 0;
  280. }
  281. }
  282. else {
  283. elt->last = now;
  284. }
  285. /* Check bucket */
  286. if (elt->cur >= session->ctx->leaky_bucket_burst) {
  287. msg_info ("ratelimiting %s (%s), %.1f max elts",
  288. rspamd_inet_address_to_string (session->addr),
  289. rspamd_inet_address_to_string (masked),
  290. session->ctx->leaky_bucket_burst);
  291. elt->cur = NAN;
  292. }
  293. else {
  294. elt->cur ++; /* Allow one more request */
  295. }
  296. }
  297. rspamd_inet_address_free (masked);
  298. return !ratelimited;
  299. }
  300. else {
  301. /* New bucket */
  302. elt = g_malloc (sizeof (*elt));
  303. elt->addr = masked; /* transfer ownership */
  304. elt->cur = 1;
  305. elt->last = now;
  306. rspamd_lru_hash_insert (session->ctx->ratelimit_buckets,
  307. masked,
  308. elt,
  309. tv.tv_sec,
  310. session->ctx->leaky_bucket_ttl);
  311. }
  312. return TRUE;
  313. }
  314. static gboolean
  315. rspamd_fuzzy_check_client (struct fuzzy_session *session, gboolean is_write)
  316. {
  317. if (session->ctx->blocked_ips != NULL) {
  318. if (rspamd_match_radix_map_addr (session->ctx->blocked_ips,
  319. session->addr) != NULL) {
  320. return FALSE;
  321. }
  322. }
  323. if (is_write) {
  324. if (session->ctx->read_only) {
  325. return FALSE;
  326. }
  327. if (session->ctx->update_ips != NULL) {
  328. if (rspamd_match_radix_map_addr (session->ctx->update_ips,
  329. session->addr) == NULL) {
  330. return FALSE;
  331. }
  332. else {
  333. return TRUE;
  334. }
  335. }
  336. return FALSE;
  337. }
  338. /* Non write */
  339. if (session->ctx->ratelimit_buckets) {
  340. if (session->ctx->ratelimit_log_only) {
  341. (void)rspamd_fuzzy_check_ratelimit (session); /* Check but ignore */
  342. }
  343. else {
  344. return rspamd_fuzzy_check_ratelimit (session);
  345. }
  346. }
  347. return TRUE;
  348. }
  349. static void
  350. fuzzy_key_stat_dtor (gpointer p)
  351. {
  352. struct fuzzy_key_stat *st = p;
  353. if (st->last_ips) {
  354. rspamd_lru_hash_destroy (st->last_ips);
  355. }
  356. }
  357. static void
  358. fuzzy_key_dtor (gpointer p)
  359. {
  360. struct fuzzy_key *key = p;
  361. if (key->stat) {
  362. fuzzy_key_stat_dtor (key->stat);
  363. }
  364. }
  365. static void
  366. fuzzy_count_callback (guint64 count, void *ud)
  367. {
  368. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  369. ctx->stat.fuzzy_hashes = count;
  370. }
  371. struct fuzzy_slave_connection {
  372. struct rspamd_cryptobox_keypair *local_key;
  373. struct rspamd_cryptobox_pubkey *remote_key;
  374. struct upstream *up;
  375. struct rspamd_http_connection *http_conn;
  376. struct rspamd_fuzzy_mirror *mirror;
  377. gint sock;
  378. };
  379. static void
  380. fuzzy_rl_bucket_free (gpointer p)
  381. {
  382. struct rspamd_leaky_bucket_elt *elt = (struct rspamd_leaky_bucket_elt *)p;
  383. rspamd_inet_address_free (elt->addr);
  384. g_free (elt);
  385. }
  386. static void
  387. fuzzy_mirror_close_connection (struct fuzzy_slave_connection *conn)
  388. {
  389. if (conn) {
  390. if (conn->http_conn) {
  391. rspamd_http_connection_reset (conn->http_conn);
  392. rspamd_http_connection_unref (conn->http_conn);
  393. }
  394. close (conn->sock);
  395. g_free (conn);
  396. }
  397. }
  398. struct rspamd_fuzzy_updates_cbdata {
  399. struct rspamd_fuzzy_storage_ctx *ctx;
  400. struct rspamd_http_message *msg;
  401. struct fuzzy_slave_connection *conn;
  402. struct rspamd_fuzzy_mirror *m;
  403. GArray *updates_pending;
  404. };
  405. static void
  406. fuzzy_mirror_updates_version_cb (guint64 rev64, void *ud)
  407. {
  408. struct rspamd_fuzzy_updates_cbdata *cbdata = ud;
  409. struct fuzzy_peer_cmd *io_cmd;
  410. guint32 rev32 = rev64, len;
  411. const gchar *p;
  412. rspamd_fstring_t *reply;
  413. struct fuzzy_slave_connection *conn;
  414. struct rspamd_fuzzy_storage_ctx *ctx;
  415. struct rspamd_http_message *msg;
  416. struct rspamd_fuzzy_mirror *m;
  417. struct timeval tv;
  418. guint i;
  419. conn = cbdata->conn;
  420. ctx = cbdata->ctx;
  421. msg = cbdata->msg;
  422. m = cbdata->m;
  423. rev32 = GUINT32_TO_LE (rev32);
  424. len = sizeof (guint32) * 2; /* revision + last chunk */
  425. for (i = 0; i < cbdata->updates_pending->len; i ++) {
  426. io_cmd = &g_array_index (cbdata->updates_pending,
  427. struct fuzzy_peer_cmd, i);
  428. if (io_cmd->is_shingle) {
  429. len += sizeof (guint32) + sizeof (guint32) +
  430. sizeof (struct rspamd_fuzzy_shingle_cmd);
  431. }
  432. else {
  433. len += sizeof (guint32) + sizeof (guint32) +
  434. sizeof (struct rspamd_fuzzy_cmd);
  435. }
  436. }
  437. reply = rspamd_fstring_sized_new (len);
  438. reply = rspamd_fstring_append (reply, (const char *)&rev32,
  439. sizeof (rev32));
  440. for (i = 0; i < cbdata->updates_pending->len; i ++) {
  441. io_cmd = &g_array_index (cbdata->updates_pending, struct fuzzy_peer_cmd, i);
  442. if (io_cmd->is_shingle) {
  443. len = sizeof (guint32) +
  444. sizeof (struct rspamd_fuzzy_shingle_cmd);
  445. }
  446. else {
  447. len = sizeof (guint32) +
  448. sizeof (struct rspamd_fuzzy_cmd);
  449. }
  450. p = (const char *)io_cmd;
  451. len = GUINT32_TO_LE (len);
  452. reply = rspamd_fstring_append (reply, (const char *)&len, sizeof (len));
  453. reply = rspamd_fstring_append (reply, p, len);
  454. }
  455. /* Last chunk */
  456. len = 0;
  457. reply = rspamd_fstring_append (reply, (const char *)&len, sizeof (len));
  458. rspamd_http_message_set_body_from_fstring_steal (msg, reply);
  459. double_to_tv (ctx->sync_timeout, &tv);
  460. rspamd_http_connection_write_message (conn->http_conn,
  461. msg, NULL, NULL, conn,
  462. &tv);
  463. msg_info ("send update request to %s", m->name);
  464. g_array_free (cbdata->updates_pending, TRUE);
  465. g_free (cbdata);
  466. }
  467. static void
  468. fuzzy_mirror_updates_to_http (struct rspamd_fuzzy_mirror *m,
  469. struct fuzzy_slave_connection *conn,
  470. struct rspamd_fuzzy_storage_ctx *ctx,
  471. struct rspamd_http_message *msg,
  472. GArray *updates)
  473. {
  474. struct rspamd_fuzzy_updates_cbdata *cbdata;
  475. cbdata = g_malloc (sizeof (*cbdata));
  476. cbdata->ctx = ctx;
  477. cbdata->msg = msg;
  478. cbdata->conn = conn;
  479. cbdata->m = m;
  480. /* Copy queue */
  481. cbdata->updates_pending = g_array_sized_new (FALSE, FALSE,
  482. sizeof (struct fuzzy_peer_cmd), updates->len);
  483. g_array_append_vals (cbdata->updates_pending, updates->data, updates->len);
  484. rspamd_fuzzy_backend_version (ctx->backend, local_db_name,
  485. fuzzy_mirror_updates_version_cb, cbdata);
  486. }
  487. static void
  488. fuzzy_mirror_error_handler (struct rspamd_http_connection *conn, GError *err)
  489. {
  490. struct fuzzy_slave_connection *bk_conn = conn->ud;
  491. msg_info ("abnormally closing connection from backend: %s:%s, "
  492. "error: %e",
  493. bk_conn->mirror->name,
  494. rspamd_inet_address_to_string (rspamd_upstream_addr_cur (bk_conn->up)),
  495. err);
  496. fuzzy_mirror_close_connection (bk_conn);
  497. }
  498. static gint
  499. fuzzy_mirror_finish_handler (struct rspamd_http_connection *conn,
  500. struct rspamd_http_message *msg)
  501. {
  502. struct fuzzy_slave_connection *bk_conn = conn->ud;
  503. msg_info ("finished mirror connection to %s", bk_conn->mirror->name);
  504. fuzzy_mirror_close_connection (bk_conn);
  505. return 0;
  506. }
  507. static void
  508. rspamd_fuzzy_send_update_mirror (struct rspamd_fuzzy_storage_ctx *ctx,
  509. struct rspamd_fuzzy_mirror *m, GArray *updates)
  510. {
  511. struct fuzzy_slave_connection *conn;
  512. struct rspamd_http_message *msg;
  513. conn = g_malloc0 (sizeof (*conn));
  514. conn->up = rspamd_upstream_get (m->u,
  515. RSPAMD_UPSTREAM_MASTER_SLAVE, NULL, 0);
  516. conn->mirror = m;
  517. if (conn->up == NULL) {
  518. g_free (conn);
  519. msg_err ("cannot select upstream for %s", m->name);
  520. return;
  521. }
  522. conn->sock = rspamd_inet_address_connect (
  523. rspamd_upstream_addr_next (conn->up),
  524. SOCK_STREAM, TRUE);
  525. if (conn->sock == -1) {
  526. g_free (conn);
  527. msg_err ("cannot connect upstream for %s", m->name);
  528. rspamd_upstream_fail (conn->up, TRUE);
  529. return;
  530. }
  531. msg = rspamd_http_new_message (HTTP_REQUEST);
  532. rspamd_printf_fstring (&msg->url, "/update_v1/%s", m->name);
  533. conn->http_conn = rspamd_http_connection_new_client_socket (
  534. ctx->http_ctx,
  535. NULL,
  536. fuzzy_mirror_error_handler,
  537. fuzzy_mirror_finish_handler,
  538. RSPAMD_HTTP_CLIENT_SIMPLE,
  539. conn->sock);
  540. rspamd_http_connection_set_key (conn->http_conn,
  541. ctx->sync_keypair);
  542. msg->peer_key = rspamd_pubkey_ref (m->key);
  543. fuzzy_mirror_updates_to_http (m, conn, ctx, msg, updates);
  544. }
  545. struct rspamd_updates_cbdata {
  546. GArray *updates_pending;
  547. struct rspamd_fuzzy_storage_ctx *ctx;
  548. gchar *source;
  549. };
  550. static void
  551. fuzzy_update_version_callback (guint64 ver, void *ud)
  552. {
  553. msg_info ("updated fuzzy storage from %s: version: %d",
  554. (const char *)ud, (gint)ver);
  555. g_free (ud);
  556. }
  557. static void
  558. fuzzy_stat_count_callback (guint64 count, void *ud)
  559. {
  560. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  561. event_add (&ctx->stat_ev, &ctx->stat_tv);
  562. ctx->stat.fuzzy_hashes = count;
  563. }
  564. static void
  565. rspamd_fuzzy_stat_callback (gint fd, gshort what, gpointer ud)
  566. {
  567. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  568. event_del (&ctx->stat_ev);
  569. rspamd_fuzzy_backend_count (ctx->backend, fuzzy_stat_count_callback, ctx);
  570. }
  571. static void
  572. rspamd_fuzzy_updates_cb (gboolean success,
  573. guint nadded,
  574. guint ndeleted,
  575. guint nextended,
  576. guint nignored,
  577. void *ud)
  578. {
  579. struct rspamd_updates_cbdata *cbdata = ud;
  580. struct rspamd_fuzzy_mirror *m;
  581. guint i;
  582. struct rspamd_fuzzy_storage_ctx *ctx;
  583. const gchar *source;
  584. ctx = cbdata->ctx;
  585. source = cbdata->source;
  586. if (success) {
  587. rspamd_fuzzy_backend_count (ctx->backend, fuzzy_count_callback, ctx);
  588. if (ctx->updates_pending->len > 0) {
  589. for (i = 0; i < ctx->mirrors->len; i ++) {
  590. m = g_ptr_array_index (ctx->mirrors, i);
  591. rspamd_fuzzy_send_update_mirror (ctx, m,
  592. cbdata->updates_pending);
  593. }
  594. }
  595. msg_info ("successfully updated fuzzy storage: %d updates in queue; "
  596. "%d pending currently; "
  597. "%d added, %d deleted, %d extended, %d duplicates",
  598. cbdata->updates_pending->len,
  599. ctx->updates_pending->len,
  600. nadded, ndeleted, nextended, nignored);
  601. rspamd_fuzzy_backend_version (ctx->backend, source,
  602. fuzzy_update_version_callback, g_strdup (source));
  603. ctx->updates_failed = 0;
  604. }
  605. else {
  606. if (++ctx->updates_failed > ctx->updates_maxfail) {
  607. msg_err ("cannot commit update transaction to fuzzy backend, discard "
  608. "%ud updates after %d retries",
  609. cbdata->updates_pending->len,
  610. ctx->updates_maxfail);
  611. ctx->updates_failed = 0;
  612. }
  613. else {
  614. msg_err ("cannot commit update transaction to fuzzy backend, "
  615. "%ud updates are still left; %ud currently pending;"
  616. " %d updates left",
  617. cbdata->updates_pending->len,
  618. ctx->updates_pending->len,
  619. ctx->updates_maxfail - ctx->updates_failed);
  620. /* Move the remaining updates to ctx queue */
  621. g_array_append_vals (ctx->updates_pending,
  622. cbdata->updates_pending->data,
  623. cbdata->updates_pending->len);
  624. }
  625. }
  626. if (ctx->worker->wanna_die) {
  627. /* Plan exit */
  628. struct timeval tv;
  629. tv.tv_sec = 0;
  630. tv.tv_usec = 0;
  631. event_base_loopexit (ctx->ev_base, &tv);
  632. }
  633. g_array_free (cbdata->updates_pending, TRUE);
  634. g_free (cbdata->source);
  635. g_free (cbdata);
  636. }
  637. static void
  638. rspamd_fuzzy_process_updates_queue (struct rspamd_fuzzy_storage_ctx *ctx,
  639. const gchar *source, gboolean forced)
  640. {
  641. struct rspamd_updates_cbdata *cbdata;
  642. if ((forced ||ctx->updates_pending->len > 0)) {
  643. cbdata = g_malloc (sizeof (*cbdata));
  644. cbdata->ctx = ctx;
  645. cbdata->updates_pending = ctx->updates_pending;
  646. ctx->updates_pending = g_array_sized_new (FALSE, FALSE,
  647. sizeof (struct fuzzy_peer_cmd),
  648. MAX (cbdata->updates_pending->len, 1024));
  649. cbdata->source = g_strdup (source);
  650. rspamd_fuzzy_backend_process_updates (ctx->backend,
  651. cbdata->updates_pending,
  652. source, rspamd_fuzzy_updates_cb, cbdata);
  653. }
  654. }
  655. static void
  656. rspamd_fuzzy_reply_io (gint fd, gshort what, gpointer d)
  657. {
  658. struct fuzzy_session *session = d;
  659. rspamd_fuzzy_write_reply (session);
  660. REF_RELEASE (session);
  661. }
  662. static void
  663. rspamd_fuzzy_write_reply (struct fuzzy_session *session)
  664. {
  665. gssize r;
  666. gsize len;
  667. gconstpointer data;
  668. if (session->cmd_type == CMD_ENCRYPTED_NORMAL ||
  669. session->cmd_type == CMD_ENCRYPTED_SHINGLE) {
  670. /* Encrypted reply */
  671. data = &session->reply;
  672. if (session->epoch > RSPAMD_FUZZY_EPOCH10) {
  673. len = sizeof (session->reply);
  674. }
  675. else {
  676. len = sizeof (session->reply.hdr) + sizeof (session->reply.rep.v1);
  677. }
  678. }
  679. else {
  680. data = &session->reply.rep;
  681. if (session->epoch > RSPAMD_FUZZY_EPOCH10) {
  682. len = sizeof (session->reply.rep);
  683. }
  684. else {
  685. len = sizeof (session->reply.rep.v1);
  686. }
  687. }
  688. r = rspamd_inet_address_sendto (session->fd, data, len, 0,
  689. session->addr);
  690. if (r == -1) {
  691. if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
  692. /* Grab reference to avoid early destruction */
  693. REF_RETAIN (session);
  694. event_set (&session->io, session->fd, EV_WRITE,
  695. rspamd_fuzzy_reply_io, session);
  696. event_base_set (session->ctx->ev_base, &session->io);
  697. event_add (&session->io, NULL);
  698. }
  699. else {
  700. msg_err ("error while writing reply: %s", strerror (errno));
  701. }
  702. }
  703. }
  704. static void
  705. fuzzy_peer_send_io (gint fd, gshort what, gpointer d)
  706. {
  707. struct fuzzy_peer_request *up_req = d;
  708. gssize r;
  709. r = write (fd, &up_req->cmd, sizeof (up_req->cmd));
  710. if (r != sizeof (up_req->cmd)) {
  711. msg_err ("cannot send update request to the peer: %s", strerror (errno));
  712. }
  713. event_del (&up_req->io_ev);
  714. g_free (up_req);
  715. }
  716. static void
  717. rspamd_fuzzy_update_stats (struct rspamd_fuzzy_storage_ctx *ctx,
  718. enum rspamd_fuzzy_epoch epoch,
  719. gboolean matched,
  720. gboolean is_shingle,
  721. struct fuzzy_key_stat *key_stat,
  722. struct fuzzy_key_stat *ip_stat,
  723. guint cmd, guint reply)
  724. {
  725. ctx->stat.fuzzy_hashes_checked[epoch] ++;
  726. if (matched) {
  727. ctx->stat.fuzzy_hashes_found[epoch]++;
  728. }
  729. if (is_shingle) {
  730. ctx->stat.fuzzy_shingles_checked[epoch]++;
  731. }
  732. if (key_stat) {
  733. if (!matched && reply != 0) {
  734. key_stat->errors ++;
  735. }
  736. else {
  737. if (cmd == FUZZY_CHECK) {
  738. key_stat->checked++;
  739. if (matched) {
  740. key_stat->matched ++;
  741. }
  742. }
  743. else if (cmd == FUZZY_WRITE) {
  744. key_stat->added++;
  745. }
  746. else if (cmd == FUZZY_DEL) {
  747. key_stat->deleted++;
  748. }
  749. }
  750. }
  751. if (ip_stat) {
  752. if (!matched && reply != 0) {
  753. ip_stat->errors++;
  754. }
  755. else {
  756. if (cmd == FUZZY_CHECK) {
  757. ip_stat->checked++;
  758. if (matched) {
  759. ip_stat->matched++;
  760. }
  761. }
  762. else if (cmd == FUZZY_WRITE) {
  763. ip_stat->added++;
  764. }
  765. else if (cmd == FUZZY_DEL) {
  766. ip_stat->deleted++;
  767. }
  768. }
  769. }
  770. }
  771. static void
  772. rspamd_fuzzy_make_reply (struct rspamd_fuzzy_cmd *cmd,
  773. struct rspamd_fuzzy_reply *result,
  774. struct fuzzy_session *session,
  775. gboolean encrypted, gboolean is_shingle)
  776. {
  777. gsize len;
  778. if (cmd) {
  779. result->v1.tag = cmd->tag;
  780. memcpy (&session->reply.rep, result, sizeof (*result));
  781. rspamd_fuzzy_update_stats (session->ctx,
  782. session->epoch,
  783. result->v1.prob > 0.5,
  784. is_shingle,
  785. session->key_stat,
  786. session->ip_stat,
  787. cmd->cmd,
  788. result->v1.value);
  789. if (encrypted) {
  790. /* We need also to encrypt reply */
  791. ottery_rand_bytes (session->reply.hdr.nonce,
  792. sizeof (session->reply.hdr.nonce));
  793. /*
  794. * For old replies we need to encrypt just old part, otherwise
  795. * decryption would fail due to mac verification mistake
  796. */
  797. if (session->epoch > RSPAMD_FUZZY_EPOCH10) {
  798. len = sizeof (session->reply.rep);
  799. }
  800. else {
  801. len = sizeof (session->reply.rep.v1);
  802. }
  803. rspamd_cryptobox_encrypt_nm_inplace ((guchar *)&session->reply.rep,
  804. len,
  805. session->reply.hdr.nonce,
  806. session->nm,
  807. session->reply.hdr.mac,
  808. RSPAMD_CRYPTOBOX_MODE_25519);
  809. }
  810. }
  811. rspamd_fuzzy_write_reply (session);
  812. }
  813. static void
  814. rspamd_fuzzy_check_callback (struct rspamd_fuzzy_reply *result, void *ud)
  815. {
  816. struct fuzzy_session *session = ud;
  817. gboolean encrypted = FALSE, is_shingle = FALSE;
  818. struct rspamd_fuzzy_cmd *cmd = NULL;
  819. const struct rspamd_shingle *shingle = NULL;
  820. struct rspamd_shingle sgl_cpy;
  821. switch (session->cmd_type) {
  822. case CMD_NORMAL:
  823. cmd = &session->cmd.normal;
  824. break;
  825. case CMD_SHINGLE:
  826. cmd = &session->cmd.shingle.basic;
  827. memcpy (&sgl_cpy, &session->cmd.shingle.sgl, sizeof (sgl_cpy));
  828. shingle = &sgl_cpy;
  829. is_shingle = TRUE;
  830. break;
  831. case CMD_ENCRYPTED_NORMAL:
  832. cmd = &session->cmd.enc_normal.cmd;
  833. encrypted = TRUE;
  834. break;
  835. case CMD_ENCRYPTED_SHINGLE:
  836. cmd = &session->cmd.enc_shingle.cmd.basic;
  837. memcpy (&sgl_cpy, &session->cmd.enc_shingle.cmd.sgl, sizeof (sgl_cpy));
  838. shingle = &sgl_cpy;
  839. encrypted = TRUE;
  840. is_shingle = TRUE;
  841. break;
  842. }
  843. rspamd_fuzzy_make_reply (cmd, result, session, encrypted, is_shingle);
  844. /* Refresh hash if found with strong confidence */
  845. if (result->v1.prob > 0.9 && !session->ctx->read_only) {
  846. struct fuzzy_peer_cmd up_cmd;
  847. struct fuzzy_peer_request *up_req;
  848. if (session->worker->index == 0 || session->ctx->peer_fd == -1) {
  849. /* Just add to the queue */
  850. memset (&up_cmd, 0, sizeof (up_cmd));
  851. up_cmd.is_shingle = is_shingle;
  852. memcpy (up_cmd.cmd.normal.digest, result->digest,
  853. sizeof (up_cmd.cmd.normal.digest));
  854. up_cmd.cmd.normal.flag = result->v1.flag;
  855. up_cmd.cmd.normal.cmd = FUZZY_REFRESH;
  856. up_cmd.cmd.normal.shingles_count = cmd->shingles_count;
  857. if (is_shingle && shingle) {
  858. memcpy (&up_cmd.cmd.shingle.sgl, shingle,
  859. sizeof (up_cmd.cmd.shingle.sgl));
  860. }
  861. g_array_append_val (session->ctx->updates_pending, up_cmd);
  862. }
  863. else {
  864. /* We need to send request to the peer */
  865. up_req = g_malloc0 (sizeof (*up_req));
  866. up_req->cmd.is_shingle = is_shingle;
  867. memcpy (up_req->cmd.cmd.normal.digest, result->digest,
  868. sizeof (up_req->cmd.cmd.normal.digest));
  869. up_req->cmd.cmd.normal.flag = result->v1.flag;
  870. up_req->cmd.cmd.normal.cmd = FUZZY_REFRESH;
  871. up_req->cmd.cmd.normal.shingles_count = cmd->shingles_count;
  872. if (is_shingle && shingle) {
  873. memcpy (&up_req->cmd.cmd.shingle.sgl, shingle,
  874. sizeof (up_req->cmd.cmd.shingle.sgl));
  875. }
  876. event_set (&up_req->io_ev, session->ctx->peer_fd, EV_WRITE,
  877. fuzzy_peer_send_io, up_req);
  878. event_base_set (session->ctx->ev_base, &up_req->io_ev);
  879. event_add (&up_req->io_ev, NULL);
  880. }
  881. }
  882. REF_RELEASE (session);
  883. }
  884. static void
  885. rspamd_fuzzy_process_command (struct fuzzy_session *session)
  886. {
  887. gboolean encrypted = FALSE, is_shingle = FALSE;
  888. struct rspamd_fuzzy_cmd *cmd = NULL;
  889. struct rspamd_fuzzy_reply result;
  890. struct fuzzy_peer_cmd up_cmd;
  891. struct fuzzy_peer_request *up_req;
  892. struct fuzzy_key_stat *ip_stat = NULL;
  893. gchar hexbuf[rspamd_cryptobox_HASHBYTES * 2 + 1];
  894. rspamd_inet_addr_t *naddr;
  895. gpointer ptr;
  896. gsize up_len = 0;
  897. switch (session->cmd_type) {
  898. case CMD_NORMAL:
  899. cmd = &session->cmd.normal;
  900. up_len = sizeof (session->cmd.normal);
  901. break;
  902. case CMD_SHINGLE:
  903. cmd = &session->cmd.shingle.basic;
  904. up_len = sizeof (session->cmd.shingle);
  905. is_shingle = TRUE;
  906. break;
  907. case CMD_ENCRYPTED_NORMAL:
  908. cmd = &session->cmd.enc_normal.cmd;
  909. up_len = sizeof (session->cmd.normal);
  910. encrypted = TRUE;
  911. break;
  912. case CMD_ENCRYPTED_SHINGLE:
  913. cmd = &session->cmd.enc_shingle.cmd.basic;
  914. up_len = sizeof (session->cmd.shingle);
  915. encrypted = TRUE;
  916. is_shingle = TRUE;
  917. break;
  918. default:
  919. msg_err ("invalid command type: %d", session->cmd_type);
  920. return;
  921. }
  922. memset (&result, 0, sizeof (result));
  923. memcpy (result.digest, cmd->digest, sizeof (result.digest));
  924. result.v1.flag = cmd->flag;
  925. result.v1.tag = cmd->tag;
  926. if (G_UNLIKELY (cmd == NULL || up_len == 0)) {
  927. result.v1.value = 500;
  928. result.v1.prob = 0.0;
  929. rspamd_fuzzy_make_reply (cmd, &result, session, encrypted, is_shingle);
  930. return;
  931. }
  932. if (session->ctx->encrypted_only && !encrypted) {
  933. /* Do not accept unencrypted commands */
  934. result.v1.value = 403;
  935. result.v1.prob = 0.0;
  936. rspamd_fuzzy_make_reply (cmd, &result, session, encrypted, is_shingle);
  937. return;
  938. }
  939. if (session->key_stat) {
  940. ip_stat = rspamd_lru_hash_lookup (session->key_stat->last_ips,
  941. session->addr, -1);
  942. if (ip_stat == NULL) {
  943. naddr = rspamd_inet_address_copy (session->addr);
  944. ip_stat = g_malloc0 (sizeof (*ip_stat));
  945. rspamd_lru_hash_insert (session->key_stat->last_ips,
  946. naddr, ip_stat, -1, 0);
  947. }
  948. session->ip_stat = ip_stat;
  949. }
  950. if (cmd->cmd == FUZZY_CHECK) {
  951. if (rspamd_fuzzy_check_client (session, FALSE)) {
  952. if (G_UNLIKELY (session->ctx->collection_mode)) {
  953. result.v1.prob = 0;
  954. result.v1.value = 500;
  955. result.v1.flag = 0;
  956. rspamd_fuzzy_make_reply (cmd, &result, session, encrypted,
  957. is_shingle);
  958. } else {
  959. REF_RETAIN (session);
  960. rspamd_fuzzy_backend_check (session->ctx->backend, cmd,
  961. rspamd_fuzzy_check_callback, session);
  962. }
  963. }
  964. else {
  965. result.v1.value = 403;
  966. result.v1.prob = 0.0;
  967. result.v1.flag = 0;
  968. rspamd_fuzzy_make_reply (cmd, &result, session, encrypted, is_shingle);
  969. }
  970. }
  971. else if (cmd->cmd == FUZZY_STAT) {
  972. if (G_UNLIKELY (session->ctx->collection_mode)) {
  973. result.v1.prob = 0;
  974. result.v1.value = 500;
  975. result.v1.flag = 0;
  976. rspamd_fuzzy_make_reply (cmd, &result, session, encrypted, is_shingle);
  977. }
  978. else {
  979. result.v1.prob = 1.0;
  980. result.v1.value = 0;
  981. result.v1.flag = session->ctx->stat.fuzzy_hashes;
  982. rspamd_fuzzy_make_reply (cmd, &result, session, encrypted, is_shingle);
  983. }
  984. }
  985. else {
  986. if (rspamd_fuzzy_check_client (session, TRUE)) {
  987. /* Check whitelist */
  988. if (session->ctx->skip_hashes && cmd->cmd == FUZZY_WRITE) {
  989. rspamd_encode_hex_buf (cmd->digest, sizeof (cmd->digest),
  990. hexbuf, sizeof (hexbuf) - 1);
  991. hexbuf[sizeof (hexbuf) - 1] = '\0';
  992. if (rspamd_match_hash_map (session->ctx->skip_hashes, hexbuf)) {
  993. result.v1.value = 401;
  994. result.v1.prob = 0.0;
  995. goto reply;
  996. }
  997. }
  998. if (session->worker->index == 0 || session->ctx->peer_fd == -1) {
  999. /* Just add to the queue */
  1000. up_cmd.is_shingle = is_shingle;
  1001. ptr = is_shingle ?
  1002. (gpointer)&up_cmd.cmd.shingle :
  1003. (gpointer)&up_cmd.cmd.normal;
  1004. memcpy (ptr, cmd, up_len);
  1005. g_array_append_val (session->ctx->updates_pending, up_cmd);
  1006. }
  1007. else {
  1008. /* We need to send request to the peer */
  1009. up_req = g_malloc0 (sizeof (*up_req));
  1010. up_req->cmd.is_shingle = is_shingle;
  1011. ptr = is_shingle ?
  1012. (gpointer)&up_req->cmd.cmd.shingle :
  1013. (gpointer)&up_req->cmd.cmd.normal;
  1014. memcpy (ptr, cmd, up_len);
  1015. event_set (&up_req->io_ev, session->ctx->peer_fd, EV_WRITE,
  1016. fuzzy_peer_send_io, up_req);
  1017. event_base_set (session->ctx->ev_base, &up_req->io_ev);
  1018. event_add (&up_req->io_ev, NULL);
  1019. }
  1020. result.v1.value = 0;
  1021. result.v1.prob = 1.0;
  1022. }
  1023. else {
  1024. result.v1.value = 403;
  1025. result.v1.prob = 0.0;
  1026. }
  1027. reply:
  1028. rspamd_fuzzy_make_reply (cmd, &result, session, encrypted, is_shingle);
  1029. }
  1030. }
  1031. static enum rspamd_fuzzy_epoch
  1032. rspamd_fuzzy_command_valid (struct rspamd_fuzzy_cmd *cmd, gint r)
  1033. {
  1034. enum rspamd_fuzzy_epoch ret = RSPAMD_FUZZY_EPOCH_MAX;
  1035. switch (cmd->version) {
  1036. case 4:
  1037. if (cmd->shingles_count > 0) {
  1038. if (r == sizeof (struct rspamd_fuzzy_shingle_cmd)) {
  1039. ret = RSPAMD_FUZZY_EPOCH11;
  1040. }
  1041. }
  1042. else {
  1043. if (r == sizeof (*cmd)) {
  1044. ret = RSPAMD_FUZZY_EPOCH11;
  1045. }
  1046. }
  1047. break;
  1048. case 3:
  1049. if (cmd->shingles_count > 0) {
  1050. if (r == sizeof (struct rspamd_fuzzy_shingle_cmd)) {
  1051. ret = RSPAMD_FUZZY_EPOCH10;
  1052. }
  1053. }
  1054. else {
  1055. if (r == sizeof (*cmd)) {
  1056. ret = RSPAMD_FUZZY_EPOCH10;
  1057. }
  1058. }
  1059. break;
  1060. case 2:
  1061. /*
  1062. * rspamd 0.8 has slightly different tokenizer then it might be not
  1063. * 100% compatible
  1064. */
  1065. if (cmd->shingles_count > 0) {
  1066. if (r == sizeof (struct rspamd_fuzzy_shingle_cmd)) {
  1067. ret = RSPAMD_FUZZY_EPOCH8;
  1068. }
  1069. }
  1070. else {
  1071. ret = RSPAMD_FUZZY_EPOCH8;
  1072. }
  1073. break;
  1074. default:
  1075. break;
  1076. }
  1077. return ret;
  1078. }
  1079. static gboolean
  1080. rspamd_fuzzy_decrypt_command (struct fuzzy_session *s)
  1081. {
  1082. struct rspamd_fuzzy_encrypted_req_hdr *hdr;
  1083. guchar *payload;
  1084. gsize payload_len;
  1085. struct rspamd_cryptobox_pubkey *rk;
  1086. struct fuzzy_key *key;
  1087. if (s->ctx->default_key == NULL) {
  1088. msg_warn ("received encrypted request when encryption is not enabled");
  1089. return FALSE;
  1090. }
  1091. if (s->cmd_type == CMD_ENCRYPTED_NORMAL) {
  1092. hdr = &s->cmd.enc_normal.hdr;
  1093. payload = (guchar *)&s->cmd.enc_normal.cmd;
  1094. payload_len = sizeof (s->cmd.enc_normal.cmd);
  1095. }
  1096. else {
  1097. hdr = &s->cmd.enc_shingle.hdr;
  1098. payload = (guchar *) &s->cmd.enc_shingle.cmd;
  1099. payload_len = sizeof (s->cmd.enc_shingle.cmd);
  1100. }
  1101. /* Compare magic */
  1102. if (memcmp (hdr->magic, fuzzy_encrypted_magic, sizeof (hdr->magic)) != 0) {
  1103. msg_debug ("invalid magic for the encrypted packet");
  1104. return FALSE;
  1105. }
  1106. /* Try to find the desired key */
  1107. key = g_hash_table_lookup (s->ctx->keys, hdr->key_id);
  1108. if (key == NULL) {
  1109. /* Unknown key, assume default one */
  1110. key = s->ctx->default_key;
  1111. }
  1112. s->key_stat = key->stat;
  1113. /* Now process keypair */
  1114. rk = rspamd_pubkey_from_bin (hdr->pubkey, sizeof (hdr->pubkey),
  1115. RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519);
  1116. if (rk == NULL) {
  1117. msg_err ("bad key");
  1118. return FALSE;
  1119. }
  1120. rspamd_keypair_cache_process (s->ctx->keypair_cache, key->key, rk);
  1121. /* Now decrypt request */
  1122. if (!rspamd_cryptobox_decrypt_nm_inplace (payload, payload_len, hdr->nonce,
  1123. rspamd_pubkey_get_nm (rk, key->key),
  1124. hdr->mac, RSPAMD_CRYPTOBOX_MODE_25519)) {
  1125. msg_err ("decryption failed");
  1126. rspamd_pubkey_unref (rk);
  1127. return FALSE;
  1128. }
  1129. memcpy (s->nm, rspamd_pubkey_get_nm (rk, key->key), sizeof (s->nm));
  1130. rspamd_pubkey_unref (rk);
  1131. return TRUE;
  1132. }
  1133. static gboolean
  1134. rspamd_fuzzy_cmd_from_wire (guchar *buf, guint buflen, struct fuzzy_session *s)
  1135. {
  1136. enum rspamd_fuzzy_epoch epoch;
  1137. /* For now, we assume that recvfrom returns a complete datagramm */
  1138. switch (buflen) {
  1139. case sizeof (struct rspamd_fuzzy_cmd):
  1140. s->cmd_type = CMD_NORMAL;
  1141. memcpy (&s->cmd.normal, buf, sizeof (s->cmd.normal));
  1142. epoch = rspamd_fuzzy_command_valid (&s->cmd.normal, buflen);
  1143. if (epoch == RSPAMD_FUZZY_EPOCH_MAX) {
  1144. msg_debug ("invalid fuzzy command of size %d received", buflen);
  1145. return FALSE;
  1146. }
  1147. s->epoch = epoch;
  1148. break;
  1149. case sizeof (struct rspamd_fuzzy_shingle_cmd):
  1150. s->cmd_type = CMD_SHINGLE;
  1151. memcpy (&s->cmd.shingle, buf, sizeof (s->cmd.shingle));
  1152. epoch = rspamd_fuzzy_command_valid (&s->cmd.shingle.basic, buflen);
  1153. if (epoch == RSPAMD_FUZZY_EPOCH_MAX) {
  1154. msg_debug ("invalid fuzzy command of size %d received", buflen);
  1155. return FALSE;
  1156. }
  1157. s->epoch = epoch;
  1158. break;
  1159. case sizeof (struct rspamd_fuzzy_encrypted_cmd):
  1160. s->cmd_type = CMD_ENCRYPTED_NORMAL;
  1161. memcpy (&s->cmd.enc_normal, buf, sizeof (s->cmd.enc_normal));
  1162. if (!rspamd_fuzzy_decrypt_command (s)) {
  1163. return FALSE;
  1164. }
  1165. epoch = rspamd_fuzzy_command_valid (&s->cmd.enc_normal.cmd,
  1166. sizeof (s->cmd.enc_normal.cmd));
  1167. if (epoch == RSPAMD_FUZZY_EPOCH_MAX) {
  1168. msg_debug ("invalid fuzzy command of size %d received", buflen);
  1169. return FALSE;
  1170. }
  1171. /* Encrypted is epoch 10 at least */
  1172. s->epoch = epoch;
  1173. break;
  1174. case sizeof (struct rspamd_fuzzy_encrypted_shingle_cmd):
  1175. s->cmd_type = CMD_ENCRYPTED_SHINGLE;
  1176. memcpy (&s->cmd.enc_shingle, buf, sizeof (s->cmd.enc_shingle));
  1177. if (!rspamd_fuzzy_decrypt_command (s)) {
  1178. return FALSE;
  1179. }
  1180. epoch = rspamd_fuzzy_command_valid (&s->cmd.enc_shingle.cmd.basic,
  1181. sizeof (s->cmd.enc_shingle.cmd));
  1182. if (epoch == RSPAMD_FUZZY_EPOCH_MAX) {
  1183. msg_debug ("invalid fuzzy command of size %d received", buflen);
  1184. return FALSE;
  1185. }
  1186. s->epoch = epoch;
  1187. break;
  1188. default:
  1189. msg_debug ("invalid fuzzy command of size %d received", buflen);
  1190. return FALSE;
  1191. }
  1192. return TRUE;
  1193. }
  1194. static void
  1195. rspamd_fuzzy_mirror_process_update (struct fuzzy_master_update_session *session,
  1196. struct rspamd_http_message *msg, guint our_rev)
  1197. {
  1198. const guchar *p;
  1199. gsize remain;
  1200. gint32 revision;
  1201. guint32 len = 0, cnt = 0;
  1202. struct fuzzy_peer_cmd cmd;
  1203. enum {
  1204. read_len = 0,
  1205. read_data,
  1206. finish_processing
  1207. } state = read_len;
  1208. gpointer flag_ptr;
  1209. /*
  1210. * Message format:
  1211. * <uint32_le> - revision
  1212. * <uint32_le> - size of the next element
  1213. * <data> - command data
  1214. * ...
  1215. * <0> - end of data
  1216. * ... - ignored
  1217. */
  1218. p = rspamd_http_message_get_body (msg, &remain);
  1219. if (p && remain >= sizeof (gint32) * 2) {
  1220. memcpy (&revision, p, sizeof (gint32));
  1221. revision = GINT32_TO_LE (revision);
  1222. if (revision <= our_rev) {
  1223. msg_err_fuzzy_update ("remote revision: %d is older than ours: %d, "
  1224. "refusing update",
  1225. revision, our_rev);
  1226. return;
  1227. }
  1228. else if (revision - our_rev > 1) {
  1229. msg_warn_fuzzy_update ("remote revision: %d is newer more than one revision "
  1230. "than ours: %d, cold sync is recommended",
  1231. revision, our_rev);
  1232. }
  1233. remain -= sizeof (gint32);
  1234. p += sizeof (gint32);
  1235. }
  1236. else {
  1237. msg_err_fuzzy_update ("short update message, not processing");
  1238. goto err;
  1239. }
  1240. while (remain > 0) {
  1241. switch (state) {
  1242. case read_len:
  1243. if (remain < sizeof (guint32)) {
  1244. msg_err_fuzzy_update ("short update message while reading "
  1245. "length, not processing");
  1246. goto err;
  1247. }
  1248. memcpy (&len, p, sizeof (guint32));
  1249. len = GUINT32_TO_LE (len);
  1250. remain -= sizeof (guint32);
  1251. p += sizeof (guint32);
  1252. if (len == 0) {
  1253. remain = 0;
  1254. state = finish_processing;
  1255. }
  1256. else {
  1257. state = read_data;
  1258. }
  1259. break;
  1260. case read_data:
  1261. if (remain < len) {
  1262. msg_err_fuzzy_update ("short update message while reading data, "
  1263. "not processing"
  1264. " (%zd is available, %d is required)", remain, len);
  1265. return;
  1266. }
  1267. if (len < sizeof (struct rspamd_fuzzy_cmd) + sizeof (guint32) ||
  1268. len > sizeof (cmd)) {
  1269. /* Bad size command */
  1270. msg_err_fuzzy_update ("incorrect element size: %d, at least "
  1271. "%d expected", len,
  1272. (gint)(sizeof (struct rspamd_fuzzy_cmd) + sizeof (guint32)));
  1273. goto err;
  1274. }
  1275. memcpy (&cmd, p, len);
  1276. if (cmd.is_shingle && len != sizeof (cmd)) {
  1277. /* Short command */
  1278. msg_err_fuzzy_update ("incorrect element size: %d, at least "
  1279. "%d expected", len,
  1280. (gint)(sizeof (cmd)));
  1281. goto err;
  1282. }
  1283. if (cmd.is_shingle) {
  1284. if ((flag_ptr = g_hash_table_lookup (session->ctx->master_flags,
  1285. GUINT_TO_POINTER (cmd.cmd.shingle.basic.flag))) != NULL) {
  1286. cmd.cmd.shingle.basic.flag = GPOINTER_TO_UINT (flag_ptr);
  1287. }
  1288. }
  1289. else {
  1290. if ((flag_ptr = g_hash_table_lookup (session->ctx->master_flags,
  1291. GUINT_TO_POINTER (cmd.cmd.normal.flag))) != NULL) {
  1292. cmd.cmd.normal.flag = GPOINTER_TO_UINT (flag_ptr);
  1293. }
  1294. }
  1295. g_array_append_val (session->ctx->updates_pending, cmd);
  1296. p += len;
  1297. remain -= len;
  1298. len = 0;
  1299. state = read_len;
  1300. cnt ++;
  1301. break;
  1302. case finish_processing:
  1303. /* Do nothing */
  1304. remain = 0;
  1305. break;
  1306. }
  1307. }
  1308. rspamd_fuzzy_process_updates_queue (session->ctx, session->src, TRUE);
  1309. msg_info_fuzzy_update ("processed updates from the master %s, "
  1310. "%ud operations processed,"
  1311. " revision: %d (local revision: %d)",
  1312. rspamd_inet_address_to_string (session->addr),
  1313. cnt, revision, our_rev);
  1314. err:
  1315. return;
  1316. }
  1317. static void
  1318. fuzzy_session_destroy (gpointer d)
  1319. {
  1320. struct fuzzy_session *session = d;
  1321. rspamd_inet_address_free (session->addr);
  1322. rspamd_explicit_memzero (session->nm, sizeof (session->nm));
  1323. session->worker->nconns--;
  1324. g_free (session);
  1325. }
  1326. static void
  1327. rspamd_fuzzy_mirror_session_destroy (struct fuzzy_master_update_session *session)
  1328. {
  1329. if (session) {
  1330. rspamd_http_connection_reset (session->conn);
  1331. rspamd_http_connection_unref (session->conn);
  1332. rspamd_inet_address_free (session->addr);
  1333. close (session->sock);
  1334. if (session->psrc) {
  1335. g_free (session->psrc);
  1336. }
  1337. g_free (session);
  1338. }
  1339. }
  1340. static void
  1341. rspamd_fuzzy_mirror_error_handler (struct rspamd_http_connection *conn, GError *err)
  1342. {
  1343. struct fuzzy_master_update_session *session = conn->ud;
  1344. msg_err_fuzzy_update ("abnormally closing connection from: %s, error: %e",
  1345. rspamd_inet_address_to_string (session->addr), err);
  1346. /* Terminate session immediately */
  1347. rspamd_fuzzy_mirror_session_destroy (session);
  1348. }
  1349. static void
  1350. rspamd_fuzzy_mirror_send_reply (struct fuzzy_master_update_session *session,
  1351. guint code, const gchar *str)
  1352. {
  1353. struct rspamd_http_message *msg;
  1354. msg = rspamd_http_new_message (HTTP_RESPONSE);
  1355. msg->url = rspamd_fstring_new_init (str, strlen (str));
  1356. msg->code = code;
  1357. session->replied = TRUE;
  1358. rspamd_http_connection_reset (session->conn);
  1359. rspamd_http_connection_write_message (session->conn, msg, NULL, "text/plain",
  1360. session, &session->ctx->master_io_tv);
  1361. }
  1362. static void
  1363. rspamd_fuzzy_update_version_callback (guint64 version, void *ud)
  1364. {
  1365. struct fuzzy_master_update_session *session = ud;
  1366. rspamd_fuzzy_mirror_process_update (session, session->msg, version);
  1367. rspamd_fuzzy_mirror_send_reply (session, 200, "OK");
  1368. }
  1369. static gint
  1370. rspamd_fuzzy_mirror_finish_handler (struct rspamd_http_connection *conn,
  1371. struct rspamd_http_message *msg)
  1372. {
  1373. struct fuzzy_master_update_session *session = conn->ud;
  1374. const struct rspamd_cryptobox_pubkey *rk;
  1375. const gchar *err_str = NULL;
  1376. gchar *psrc;
  1377. const gchar *src = NULL;
  1378. gsize remain;
  1379. if (session->replied) {
  1380. rspamd_fuzzy_mirror_session_destroy (session);
  1381. return 0;
  1382. }
  1383. /* Check key */
  1384. if (!rspamd_http_connection_is_encrypted (conn)) {
  1385. msg_err_fuzzy_update ("refuse unencrypted update from: %s",
  1386. rspamd_inet_address_to_string (session->addr));
  1387. err_str = "Unencrypted update is not allowed";
  1388. goto end;
  1389. }
  1390. else {
  1391. if (session->ctx->master_key) {
  1392. rk = rspamd_http_connection_get_peer_key (conn);
  1393. g_assert (rk != NULL);
  1394. if (!rspamd_pubkey_equal (rk, session->ctx->master_key)) {
  1395. msg_err_fuzzy_update ("refuse unknown pubkey update from: %s",
  1396. rspamd_inet_address_to_string (session->addr));
  1397. err_str = "Unknown pubkey";
  1398. goto end;
  1399. }
  1400. }
  1401. else {
  1402. msg_warn_fuzzy_update ("no trusted key specified, accept any update from %s",
  1403. rspamd_inet_address_to_string (session->addr));
  1404. }
  1405. if (!rspamd_http_message_get_body (msg, NULL) || !msg->url
  1406. || msg->url->len == 0) {
  1407. msg_err_fuzzy_update ("empty update message, not processing");
  1408. err_str = "Empty update";
  1409. goto end;
  1410. }
  1411. /* Detect source from url: /update_v1/<source>, so we look for the last '/' */
  1412. remain = msg->url->len;
  1413. psrc = rspamd_fstringdup (msg->url);
  1414. src = psrc;
  1415. while (remain--) {
  1416. if (src[remain] == '/') {
  1417. src = &src[remain + 1];
  1418. break;
  1419. }
  1420. }
  1421. session->src = src;
  1422. session->psrc = psrc;
  1423. session->msg = msg;
  1424. rspamd_fuzzy_backend_version (session->ctx->backend, src,
  1425. rspamd_fuzzy_update_version_callback, session);
  1426. return 0;
  1427. }
  1428. end:
  1429. rspamd_fuzzy_mirror_send_reply (session, 403, err_str);
  1430. return 0;
  1431. }
  1432. struct rspamd_fuzzy_collection_session {
  1433. struct rspamd_fuzzy_storage_ctx *ctx;
  1434. struct rspamd_worker *worker;
  1435. rspamd_inet_addr_t *from_addr;
  1436. guchar uid[16];
  1437. };
  1438. static void
  1439. rspamd_fuzzy_collection_error_handler (struct rspamd_http_connection_entry *conn_ent,
  1440. GError *err)
  1441. {
  1442. struct rspamd_fuzzy_collection_session *session = conn_ent->ud;
  1443. msg_err_fuzzy_collection ("http error occurred: %s", err->message);
  1444. }
  1445. static void
  1446. rspamd_fuzzy_collection_finish_handler (struct rspamd_http_connection_entry *conn_ent)
  1447. {
  1448. struct rspamd_fuzzy_collection_session *session = conn_ent->ud;
  1449. rspamd_inet_address_free (session->from_addr);
  1450. g_free (session);
  1451. }
  1452. void
  1453. rspamd_fuzzy_collection_send_error (struct rspamd_http_connection_entry *entry,
  1454. gint code, const gchar *error_msg, ...)
  1455. {
  1456. struct rspamd_http_message *msg;
  1457. va_list args;
  1458. rspamd_fstring_t *reply;
  1459. msg = rspamd_http_new_message (HTTP_RESPONSE);
  1460. va_start (args, error_msg);
  1461. msg->status = rspamd_fstring_new ();
  1462. rspamd_vprintf_fstring (&msg->status, error_msg, args);
  1463. va_end (args);
  1464. msg->date = time (NULL);
  1465. msg->code = code;
  1466. reply = rspamd_fstring_sized_new (msg->status->len + 16);
  1467. rspamd_printf_fstring (&reply, "%V", msg->status);
  1468. rspamd_http_message_set_body_from_fstring_steal (msg, reply);
  1469. rspamd_http_connection_reset (entry->conn);
  1470. rspamd_http_router_insert_headers (entry->rt, msg);
  1471. rspamd_http_connection_write_message (entry->conn,
  1472. msg,
  1473. NULL,
  1474. "text/plain",
  1475. entry,
  1476. entry->rt->ptv);
  1477. entry->is_reply = TRUE;
  1478. }
  1479. /*
  1480. * Note: this function steals fstring
  1481. */
  1482. void
  1483. rspamd_fuzzy_collection_send_fstring (struct rspamd_http_connection_entry *entry,
  1484. rspamd_fstring_t *fstr)
  1485. {
  1486. struct rspamd_http_message *msg;
  1487. msg = rspamd_http_new_message (HTTP_RESPONSE);
  1488. msg->status = rspamd_fstring_new_init ("OK", 2);
  1489. msg->date = time (NULL);
  1490. msg->code = 200;
  1491. rspamd_http_message_set_body_from_fstring_steal (msg, fstr);
  1492. rspamd_http_connection_reset (entry->conn);
  1493. rspamd_http_router_insert_headers (entry->rt, msg);
  1494. rspamd_http_connection_write_message (entry->conn,
  1495. msg,
  1496. NULL,
  1497. "application/octet-stream",
  1498. entry,
  1499. entry->rt->ptv);
  1500. entry->is_reply = TRUE;
  1501. }
  1502. static int
  1503. rspamd_fuzzy_collection_cookie (struct rspamd_http_connection_entry *conn_ent,
  1504. struct rspamd_http_message *msg)
  1505. {
  1506. struct rspamd_fuzzy_collection_session *session = conn_ent->ud;
  1507. rspamd_fstring_t *cookie;
  1508. cookie = rspamd_fstring_new_init (session->ctx->cookie,
  1509. sizeof (session->ctx->cookie));
  1510. rspamd_fuzzy_collection_send_fstring (conn_ent, cookie);
  1511. return 0;
  1512. }
  1513. static int
  1514. rspamd_fuzzy_collection_data (struct rspamd_http_connection_entry *conn_ent,
  1515. struct rspamd_http_message *msg)
  1516. {
  1517. struct rspamd_fuzzy_collection_session *session = conn_ent->ud;
  1518. const rspamd_ftok_t *sign_header;
  1519. struct rspamd_fuzzy_storage_ctx *ctx;
  1520. guint i;
  1521. struct fuzzy_peer_cmd *io_cmd;
  1522. rspamd_fstring_t *reply;
  1523. GError *err = NULL;
  1524. guchar *decoded_signature;
  1525. gsize dec_len;
  1526. guint32 cmdlen, nupdates = 0;
  1527. sign_header = rspamd_http_message_find_header (msg, "Signature");
  1528. if (sign_header == NULL) {
  1529. rspamd_fuzzy_collection_send_error (conn_ent, 403, "Missing signature");
  1530. return 0;
  1531. }
  1532. ctx = session->ctx;
  1533. if (ctx->collection_sign_key == NULL) {
  1534. rspamd_fuzzy_collection_send_error (conn_ent, 500, "Misconfigured signature key");
  1535. return 0;
  1536. }
  1537. decoded_signature = g_malloc (sign_header->len * 2 + 1);
  1538. dec_len = rspamd_decode_hex_buf (sign_header->begin, sign_header->len,
  1539. decoded_signature, sign_header->len * 2 + 1);
  1540. if (dec_len == -1 || !rspamd_keypair_verify (ctx->collection_sign_key,
  1541. ctx->cookie, sizeof (ctx->cookie),
  1542. decoded_signature, dec_len, &err)) {
  1543. if (err) {
  1544. rspamd_fuzzy_collection_send_error (conn_ent, 403, "Signature verification error: %e",
  1545. err);
  1546. g_error_free (err);
  1547. }
  1548. else {
  1549. rspamd_fuzzy_collection_send_error (conn_ent, 403, "Signature verification error");
  1550. }
  1551. g_free (decoded_signature);
  1552. return 0;
  1553. }
  1554. g_free (decoded_signature);
  1555. /* Generate new cookie */
  1556. ottery_rand_bytes (ctx->cookie, sizeof (ctx->cookie));
  1557. /* Send&Clear updates */
  1558. reply = rspamd_fstring_sized_new (8192);
  1559. /*
  1560. * Message format:
  1561. * <uint32_le> - revision
  1562. * <uint32_le> - size of the next element
  1563. * <data> - command data
  1564. * ...
  1565. * <0> - end of data
  1566. * ... - ignored
  1567. */
  1568. reply = rspamd_fstring_append (reply, (const gchar *)&ctx->collection_id,
  1569. sizeof (ctx->collection_id));
  1570. for (i = 0; i < ctx->updates_pending->len; i ++) {
  1571. io_cmd = &g_array_index (ctx->updates_pending, struct fuzzy_peer_cmd, i);
  1572. if (io_cmd->is_shingle) {
  1573. cmdlen = sizeof (io_cmd->cmd.shingle) + sizeof (guint32);
  1574. }
  1575. else {
  1576. cmdlen = sizeof (io_cmd->cmd.normal) + sizeof (guint32);
  1577. }
  1578. cmdlen = GUINT32_TO_LE (cmdlen);
  1579. reply = rspamd_fstring_append (reply, (const gchar *)&cmdlen,
  1580. sizeof (cmdlen));
  1581. reply = rspamd_fstring_append (reply, (const gchar *)io_cmd,
  1582. cmdlen);
  1583. nupdates ++;
  1584. }
  1585. msg_info_fuzzy_collection ("collection %d done, send %d updates",
  1586. ctx->collection_id, nupdates);
  1587. /* Last command */
  1588. cmdlen = 0;
  1589. reply = rspamd_fstring_append (reply, (const gchar *)&cmdlen,
  1590. sizeof (cmdlen));
  1591. ctx->updates_pending->len = 0;
  1592. /* Clear failed attempts counter */
  1593. ctx->updates_failed = 0;
  1594. ctx->collection_id ++;
  1595. rspamd_fuzzy_collection_send_fstring (conn_ent, reply);
  1596. return 0;
  1597. }
  1598. static void
  1599. accept_fuzzy_collection_socket (gint fd, short what, void *arg)
  1600. {
  1601. struct rspamd_worker *worker = (struct rspamd_worker *)arg;
  1602. rspamd_inet_addr_t *addr;
  1603. gint nfd;
  1604. struct rspamd_fuzzy_storage_ctx *ctx;
  1605. struct rspamd_fuzzy_collection_session *session;
  1606. if ((nfd =
  1607. rspamd_accept_from_socket (fd, &addr, worker->accept_events)) == -1) {
  1608. msg_warn ("accept failed: %s", strerror (errno));
  1609. return;
  1610. }
  1611. /* Check for EAGAIN */
  1612. if (nfd == 0) {
  1613. return;
  1614. }
  1615. ctx = worker->ctx;
  1616. if (!ctx->collection_keypair) {
  1617. msg_err ("deny request from %s, as no local keypair is specified",
  1618. rspamd_inet_address_to_string (addr));
  1619. rspamd_inet_address_free (addr);
  1620. close (nfd);
  1621. return;
  1622. }
  1623. session = g_malloc0 (sizeof (*session));
  1624. session->ctx = ctx;
  1625. session->worker = worker;
  1626. rspamd_random_hex (session->uid, sizeof (session->uid) - 1);
  1627. session->uid[sizeof (session->uid) - 1] = '\0';
  1628. session->from_addr = addr;
  1629. rspamd_http_router_handle_socket (ctx->collection_rt, nfd, session);
  1630. msg_info_fuzzy_collection ("accepted connection from %s port %d, session ptr: %p",
  1631. rspamd_inet_address_to_string (addr),
  1632. rspamd_inet_address_get_port (addr),
  1633. session);
  1634. }
  1635. static void
  1636. rspamd_fuzzy_collection_periodic (gint fd, gshort what, gpointer ud)
  1637. {
  1638. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  1639. if (++ctx->updates_failed > ctx->updates_maxfail) {
  1640. msg_err ("cannot store more data in workqueue, discard "
  1641. "%ud updates after %d missed collection points",
  1642. ctx->updates_pending->len,
  1643. ctx->updates_maxfail);
  1644. ctx->updates_failed = 0;
  1645. ctx->updates_pending->len = 0;
  1646. /* Regenerate cookie */
  1647. ottery_rand_bytes (ctx->cookie, sizeof (ctx->cookie));
  1648. }
  1649. else {
  1650. msg_err ("fuzzy data has not been collected in time, "
  1651. "%ud updates are still pending, %d updates left",
  1652. ctx->updates_pending->len,
  1653. ctx->updates_maxfail - ctx->updates_failed);
  1654. }
  1655. if (ctx->worker->wanna_die) {
  1656. /* Plan exit */
  1657. struct timeval tv;
  1658. tv.tv_sec = 0;
  1659. tv.tv_usec = 0;
  1660. event_base_loopexit (ctx->ev_base, &tv);
  1661. }
  1662. }
  1663. static void
  1664. accept_fuzzy_mirror_socket (gint fd, short what, void *arg)
  1665. {
  1666. struct rspamd_worker *worker = (struct rspamd_worker *)arg;
  1667. rspamd_inet_addr_t *addr;
  1668. gint nfd;
  1669. struct rspamd_http_connection *http_conn;
  1670. struct rspamd_fuzzy_storage_ctx *ctx;
  1671. struct fuzzy_master_update_session *session;
  1672. if ((nfd =
  1673. rspamd_accept_from_socket (fd, &addr, worker->accept_events)) == -1) {
  1674. msg_warn ("accept failed: %s", strerror (errno));
  1675. return;
  1676. }
  1677. /* Check for EAGAIN */
  1678. if (nfd == 0) {
  1679. return;
  1680. }
  1681. ctx = worker->ctx;
  1682. if (!ctx->master_ips) {
  1683. msg_err ("deny update request from %s as no masters defined",
  1684. rspamd_inet_address_to_string (addr));
  1685. rspamd_inet_address_free (addr);
  1686. close (nfd);
  1687. return;
  1688. }
  1689. else if (rspamd_match_radix_map_addr (ctx->master_ips, addr) == NULL) {
  1690. msg_err ("deny update request from %s",
  1691. rspamd_inet_address_to_string (addr));
  1692. rspamd_inet_address_free (addr);
  1693. close (nfd);
  1694. return;
  1695. }
  1696. if (!ctx->sync_keypair) {
  1697. msg_err ("deny update request from %s, as no local keypair is specified",
  1698. rspamd_inet_address_to_string (addr));
  1699. rspamd_inet_address_free (addr);
  1700. close (nfd);
  1701. return;
  1702. }
  1703. session = g_malloc0 (sizeof (*session));
  1704. session->name = rspamd_inet_address_to_string (addr);
  1705. rspamd_random_hex (session->uid, sizeof (session->uid) - 1);
  1706. session->uid[sizeof (session->uid) - 1] = '\0';
  1707. http_conn = rspamd_http_connection_new_server (
  1708. ctx->http_ctx,
  1709. nfd,
  1710. NULL,
  1711. rspamd_fuzzy_mirror_error_handler,
  1712. rspamd_fuzzy_mirror_finish_handler,
  1713. 0);
  1714. rspamd_http_connection_set_key (http_conn, ctx->sync_keypair);
  1715. session->ctx = ctx;
  1716. session->conn = http_conn;
  1717. session->addr = addr;
  1718. session->sock = nfd;
  1719. rspamd_http_connection_read_message (http_conn,
  1720. session,
  1721. &ctx->master_io_tv);
  1722. }
  1723. /*
  1724. * Accept new connection and construct task
  1725. */
  1726. static void
  1727. accept_fuzzy_socket (gint fd, short what, void *arg)
  1728. {
  1729. struct rspamd_worker *worker = (struct rspamd_worker *)arg;
  1730. struct fuzzy_session *session;
  1731. rspamd_inet_addr_t *addr;
  1732. gssize r;
  1733. guint8 buf[512];
  1734. guint64 *nerrors;
  1735. /* Got some data */
  1736. if (what == EV_READ) {
  1737. for (;;) {
  1738. worker->nconns++;
  1739. r = rspamd_inet_address_recvfrom (fd,
  1740. buf,
  1741. sizeof (buf),
  1742. 0,
  1743. &addr);
  1744. if (r == -1) {
  1745. if (errno == EINTR) {
  1746. continue;
  1747. }
  1748. else if (errno == EAGAIN || errno == EWOULDBLOCK) {
  1749. return;
  1750. }
  1751. msg_err ("got error while reading from socket: %d, %s",
  1752. errno,
  1753. strerror (errno));
  1754. return;
  1755. }
  1756. session = g_malloc0 (sizeof (*session));
  1757. REF_INIT_RETAIN (session, fuzzy_session_destroy);
  1758. session->worker = worker;
  1759. session->fd = fd;
  1760. session->ctx = worker->ctx;
  1761. session->time = (guint64) time (NULL);
  1762. session->addr = addr;
  1763. if (rspamd_fuzzy_cmd_from_wire (buf, r, session)) {
  1764. /* Check shingles count sanity */
  1765. rspamd_fuzzy_process_command (session);
  1766. }
  1767. else {
  1768. /* Discard input */
  1769. session->ctx->stat.invalid_requests ++;
  1770. msg_debug ("invalid fuzzy command of size %z received", r);
  1771. nerrors = rspamd_lru_hash_lookup (session->ctx->errors_ips,
  1772. addr, -1);
  1773. if (nerrors == NULL) {
  1774. nerrors = g_malloc (sizeof (*nerrors));
  1775. *nerrors = 1;
  1776. rspamd_lru_hash_insert (session->ctx->errors_ips,
  1777. rspamd_inet_address_copy (addr),
  1778. nerrors, -1, -1);
  1779. }
  1780. else {
  1781. *nerrors = *nerrors + 1;
  1782. }
  1783. }
  1784. REF_RELEASE (session);
  1785. }
  1786. }
  1787. }
  1788. static gboolean
  1789. rspamd_fuzzy_storage_periodic_callback (void *ud)
  1790. {
  1791. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  1792. if (ctx->updates_pending->len > 0) {
  1793. rspamd_fuzzy_process_updates_queue (ctx, local_db_name, FALSE);
  1794. return TRUE;
  1795. }
  1796. return FALSE;
  1797. }
  1798. static gboolean
  1799. rspamd_fuzzy_storage_sync (struct rspamd_main *rspamd_main,
  1800. struct rspamd_worker *worker, gint fd,
  1801. gint attached_fd,
  1802. struct rspamd_control_command *cmd,
  1803. gpointer ud)
  1804. {
  1805. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  1806. struct rspamd_control_reply rep;
  1807. rep.reply.fuzzy_sync.status = 0;
  1808. if (ctx->backend && worker->index == 0) {
  1809. rspamd_fuzzy_process_updates_queue (ctx, local_db_name, FALSE);
  1810. rspamd_fuzzy_backend_start_update (ctx->backend, ctx->sync_timeout,
  1811. rspamd_fuzzy_storage_periodic_callback, ctx);
  1812. }
  1813. if (write (fd, &rep, sizeof (rep)) != sizeof (rep)) {
  1814. msg_err ("cannot write reply to the control socket: %s",
  1815. strerror (errno));
  1816. }
  1817. return TRUE;
  1818. }
  1819. static gboolean
  1820. rspamd_fuzzy_storage_reload (struct rspamd_main *rspamd_main,
  1821. struct rspamd_worker *worker, gint fd,
  1822. gint attached_fd,
  1823. struct rspamd_control_command *cmd,
  1824. gpointer ud)
  1825. {
  1826. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  1827. GError *err = NULL;
  1828. struct rspamd_control_reply rep;
  1829. msg_info ("reloading fuzzy storage after receiving reload command");
  1830. if (ctx->backend) {
  1831. /* Close backend and reopen it one more time */
  1832. rspamd_fuzzy_backend_close (ctx->backend);
  1833. }
  1834. memset (&rep, 0, sizeof (rep));
  1835. rep.type = RSPAMD_CONTROL_RELOAD;
  1836. if ((ctx->backend = rspamd_fuzzy_backend_create (ctx->ev_base,
  1837. worker->cf->options, rspamd_main->cfg,
  1838. &err)) == NULL) {
  1839. msg_err ("cannot open backend after reload: %e", err);
  1840. g_error_free (err);
  1841. rep.reply.reload.status = err->code;
  1842. }
  1843. else {
  1844. rep.reply.reload.status = 0;
  1845. }
  1846. if (ctx->backend && worker->index == 0) {
  1847. rspamd_fuzzy_backend_start_update (ctx->backend, ctx->sync_timeout,
  1848. rspamd_fuzzy_storage_periodic_callback, ctx);
  1849. }
  1850. if (write (fd, &rep, sizeof (rep)) != sizeof (rep)) {
  1851. msg_err ("cannot write reply to the control socket: %s",
  1852. strerror (errno));
  1853. }
  1854. return TRUE;
  1855. }
  1856. static ucl_object_t *
  1857. rspamd_fuzzy_storage_stat_key (struct fuzzy_key_stat *key_stat)
  1858. {
  1859. ucl_object_t *res;
  1860. res = ucl_object_typed_new (UCL_OBJECT);
  1861. ucl_object_insert_key (res, ucl_object_fromint (key_stat->checked),
  1862. "checked", 0, false);
  1863. ucl_object_insert_key (res, ucl_object_fromint (key_stat->matched),
  1864. "matched", 0, false);
  1865. ucl_object_insert_key (res, ucl_object_fromint (key_stat->added),
  1866. "added", 0, false);
  1867. ucl_object_insert_key (res, ucl_object_fromint (key_stat->deleted),
  1868. "deleted", 0, false);
  1869. ucl_object_insert_key (res, ucl_object_fromint (key_stat->errors),
  1870. "errors", 0, false);
  1871. return res;
  1872. }
  1873. static ucl_object_t *
  1874. rspamd_fuzzy_stat_to_ucl (struct rspamd_fuzzy_storage_ctx *ctx, gboolean ip_stat)
  1875. {
  1876. struct fuzzy_key_stat *key_stat;
  1877. GHashTableIter it;
  1878. struct fuzzy_key *key;
  1879. ucl_object_t *obj, *keys_obj, *elt, *ip_elt, *ip_cur;
  1880. gpointer k, v;
  1881. gint i;
  1882. gchar keyname[17];
  1883. obj = ucl_object_typed_new (UCL_OBJECT);
  1884. keys_obj = ucl_object_typed_new (UCL_OBJECT);
  1885. g_hash_table_iter_init (&it, ctx->keys);
  1886. while (g_hash_table_iter_next (&it, &k, &v)) {
  1887. key = v;
  1888. key_stat = key->stat;
  1889. if (key_stat) {
  1890. rspamd_snprintf (keyname, sizeof (keyname), "%8bs", k);
  1891. elt = rspamd_fuzzy_storage_stat_key (key_stat);
  1892. if (key_stat->last_ips && ip_stat) {
  1893. i = 0;
  1894. ip_elt = ucl_object_typed_new (UCL_OBJECT);
  1895. while ((i = rspamd_lru_hash_foreach (key_stat->last_ips,
  1896. i, &k, &v)) != -1) {
  1897. ip_cur = rspamd_fuzzy_storage_stat_key (v);
  1898. ucl_object_insert_key (ip_elt, ip_cur,
  1899. rspamd_inet_address_to_string (k), 0, true);
  1900. }
  1901. ucl_object_insert_key (elt, ip_elt, "ips", 0, false);
  1902. }
  1903. ucl_object_insert_key (keys_obj, elt, keyname, 0, true);
  1904. }
  1905. }
  1906. ucl_object_insert_key (obj, keys_obj, "keys", 0, false);
  1907. /* Now generic stats */
  1908. ucl_object_insert_key (obj,
  1909. ucl_object_fromint (ctx->stat.fuzzy_hashes),
  1910. "fuzzy_stored",
  1911. 0,
  1912. false);
  1913. ucl_object_insert_key (obj,
  1914. ucl_object_fromint (ctx->stat.fuzzy_hashes_expired),
  1915. "fuzzy_expired",
  1916. 0,
  1917. false);
  1918. ucl_object_insert_key (obj,
  1919. ucl_object_fromint (ctx->stat.invalid_requests),
  1920. "invalid_requests",
  1921. 0,
  1922. false);
  1923. if (ctx->errors_ips && ip_stat) {
  1924. i = 0;
  1925. ip_elt = ucl_object_typed_new (UCL_OBJECT);
  1926. while ((i = rspamd_lru_hash_foreach (ctx->errors_ips, i, &k, &v)) != -1) {
  1927. ucl_object_insert_key (ip_elt,
  1928. ucl_object_fromint (*(guint64 *)v),
  1929. rspamd_inet_address_to_string (k), 0, true);
  1930. }
  1931. ucl_object_insert_key (obj,
  1932. ip_elt,
  1933. "errors_ips",
  1934. 0,
  1935. false);
  1936. }
  1937. /* Checked by epoch */
  1938. elt = ucl_object_typed_new (UCL_ARRAY);
  1939. for (i = RSPAMD_FUZZY_EPOCH6; i < RSPAMD_FUZZY_EPOCH_MAX; i++) {
  1940. ucl_array_append (elt,
  1941. ucl_object_fromint (ctx->stat.fuzzy_hashes_checked[i]));
  1942. }
  1943. ucl_object_insert_key (obj, elt, "fuzzy_checked", 0, false);
  1944. /* Shingles by epoch */
  1945. elt = ucl_object_typed_new (UCL_ARRAY);
  1946. for (i = RSPAMD_FUZZY_EPOCH6; i < RSPAMD_FUZZY_EPOCH_MAX; i++) {
  1947. ucl_array_append (elt,
  1948. ucl_object_fromint (ctx->stat.fuzzy_shingles_checked[i]));
  1949. }
  1950. ucl_object_insert_key (obj, elt, "fuzzy_shingles", 0, false);
  1951. /* Matched by epoch */
  1952. elt = ucl_object_typed_new (UCL_ARRAY);
  1953. for (i = RSPAMD_FUZZY_EPOCH6; i < RSPAMD_FUZZY_EPOCH_MAX; i++) {
  1954. ucl_array_append (elt,
  1955. ucl_object_fromint (ctx->stat.fuzzy_hashes_found[i]));
  1956. }
  1957. ucl_object_insert_key (obj, elt, "fuzzy_found", 0, false);
  1958. return obj;
  1959. }
  1960. static gboolean
  1961. rspamd_fuzzy_storage_stat (struct rspamd_main *rspamd_main,
  1962. struct rspamd_worker *worker, gint fd,
  1963. gint attached_fd,
  1964. struct rspamd_control_command *cmd,
  1965. gpointer ud)
  1966. {
  1967. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  1968. struct rspamd_control_reply rep;
  1969. ucl_object_t *obj;
  1970. struct ucl_emitter_functions *emit_subr;
  1971. guchar fdspace[CMSG_SPACE(sizeof (int))];
  1972. struct iovec iov;
  1973. struct msghdr msg;
  1974. struct cmsghdr *cmsg;
  1975. gint outfd = -1;
  1976. gchar tmppath[PATH_MAX];
  1977. memset (&rep, 0, sizeof (rep));
  1978. rep.type = RSPAMD_CONTROL_FUZZY_STAT;
  1979. rspamd_snprintf (tmppath, sizeof (tmppath), "%s%c%s-XXXXXXXXXX",
  1980. rspamd_main->cfg->temp_dir, G_DIR_SEPARATOR, "fuzzy-stat");
  1981. if ((outfd = mkstemp (tmppath)) == -1) {
  1982. rep.reply.fuzzy_stat.status = errno;
  1983. msg_info_main ("cannot make temporary stat file for fuzzy stat: %s",
  1984. strerror (errno));
  1985. }
  1986. else {
  1987. rep.reply.fuzzy_stat.status = 0;
  1988. memcpy (rep.reply.fuzzy_stat.storage_id,
  1989. rspamd_fuzzy_backend_id (ctx->backend),
  1990. sizeof (rep.reply.fuzzy_stat.storage_id));
  1991. obj = rspamd_fuzzy_stat_to_ucl (ctx, TRUE);
  1992. emit_subr = ucl_object_emit_fd_funcs (outfd);
  1993. ucl_object_emit_full (obj, UCL_EMIT_JSON_COMPACT, emit_subr, NULL);
  1994. ucl_object_emit_funcs_free (emit_subr);
  1995. ucl_object_unref (obj);
  1996. /* Rewind output file */
  1997. close (outfd);
  1998. outfd = open (tmppath, O_RDONLY);
  1999. unlink (tmppath);
  2000. }
  2001. /* Now we can send outfd and status message */
  2002. memset (&msg, 0, sizeof (msg));
  2003. /* Attach fd to the message */
  2004. if (outfd != -1) {
  2005. memset (fdspace, 0, sizeof (fdspace));
  2006. msg.msg_control = fdspace;
  2007. msg.msg_controllen = sizeof (fdspace);
  2008. cmsg = CMSG_FIRSTHDR (&msg);
  2009. if (cmsg) {
  2010. cmsg->cmsg_level = SOL_SOCKET;
  2011. cmsg->cmsg_type = SCM_RIGHTS;
  2012. cmsg->cmsg_len = CMSG_LEN (sizeof (int));
  2013. memcpy (CMSG_DATA (cmsg), &outfd, sizeof (int));
  2014. }
  2015. }
  2016. iov.iov_base = &rep;
  2017. iov.iov_len = sizeof (rep);
  2018. msg.msg_iov = &iov;
  2019. msg.msg_iovlen = 1;
  2020. if (sendmsg (fd, &msg, 0) == -1) {
  2021. msg_err_main ("cannot send fuzzy stat: %s", strerror (errno));
  2022. }
  2023. if (outfd != -1) {
  2024. close (outfd);
  2025. }
  2026. return TRUE;
  2027. }
  2028. static gboolean
  2029. fuzzy_storage_parse_mirror (rspamd_mempool_t *pool,
  2030. const ucl_object_t *obj,
  2031. gpointer ud,
  2032. struct rspamd_rcl_section *section,
  2033. GError **err)
  2034. {
  2035. const ucl_object_t *elt;
  2036. struct rspamd_fuzzy_mirror *up = NULL;
  2037. struct rspamd_rcl_struct_parser *pd = ud;
  2038. struct rspamd_fuzzy_storage_ctx *ctx;
  2039. ctx = pd->user_struct;
  2040. if (ucl_object_type (obj) != UCL_OBJECT) {
  2041. g_set_error (err, g_quark_try_string ("fuzzy"), 100,
  2042. "mirror/slave option must be an object");
  2043. return FALSE;
  2044. }
  2045. elt = ucl_object_lookup (obj, "name");
  2046. if (elt == NULL) {
  2047. g_set_error (err, g_quark_try_string ("fuzzy"), 100,
  2048. "mirror option must have some name definition");
  2049. return FALSE;
  2050. }
  2051. up = g_malloc0 (sizeof (*up));
  2052. up->name = g_strdup (ucl_object_tostring (elt));
  2053. elt = ucl_object_lookup (obj, "key");
  2054. if (elt != NULL) {
  2055. up->key = rspamd_pubkey_from_base32 (ucl_object_tostring (elt), 0,
  2056. RSPAMD_KEYPAIR_KEX, RSPAMD_CRYPTOBOX_MODE_25519);
  2057. }
  2058. if (up->key == NULL) {
  2059. g_set_error (err, g_quark_try_string ("fuzzy"), 100,
  2060. "cannot read mirror key");
  2061. goto err;
  2062. }
  2063. elt = ucl_object_lookup (obj, "hosts");
  2064. if (elt == NULL) {
  2065. g_set_error (err, g_quark_try_string ("fuzzy"), 100,
  2066. "mirror option must have some hosts definition");
  2067. goto err;
  2068. }
  2069. up->u = rspamd_upstreams_create (ctx->cfg->ups_ctx);
  2070. if (!rspamd_upstreams_from_ucl (up->u, elt, 11335, NULL)) {
  2071. g_set_error (err, g_quark_try_string ("fuzzy"), 100,
  2072. "mirror has bad hosts definition");
  2073. goto err;
  2074. }
  2075. g_ptr_array_add (ctx->mirrors, up);
  2076. return TRUE;
  2077. err:
  2078. g_free (up->name);
  2079. rspamd_upstreams_destroy (up->u);
  2080. if (up->key) {
  2081. rspamd_pubkey_unref (up->key);
  2082. }
  2083. g_free (up);
  2084. return FALSE;
  2085. }
  2086. static gboolean
  2087. fuzzy_storage_parse_master_flags (rspamd_mempool_t *pool,
  2088. const ucl_object_t *obj,
  2089. gpointer ud,
  2090. struct rspamd_rcl_section *section,
  2091. GError **err)
  2092. {
  2093. const ucl_object_t *cur;
  2094. struct rspamd_rcl_struct_parser *pd = ud;
  2095. struct rspamd_fuzzy_storage_ctx *ctx;
  2096. ucl_object_iter_t it = NULL;
  2097. gulong remote_flag;
  2098. gint64 local_flag;
  2099. ctx = pd->user_struct;
  2100. if (ucl_object_type (obj) != UCL_OBJECT) {
  2101. g_set_error (err, g_quark_try_string ("fuzzy"), 100,
  2102. "master_flags option must be an object");
  2103. return FALSE;
  2104. }
  2105. while ((cur = ucl_iterate_object (obj, &it, true)) != NULL) {
  2106. if (rspamd_strtoul (cur->key, cur->keylen, &remote_flag) &&
  2107. ucl_object_toint_safe (cur, (int64_t *)&local_flag)) {
  2108. g_hash_table_insert (ctx->master_flags, GUINT_TO_POINTER (remote_flag),
  2109. GUINT_TO_POINTER (local_flag));
  2110. }
  2111. }
  2112. return TRUE;
  2113. }
  2114. static gboolean
  2115. fuzzy_parse_keypair (rspamd_mempool_t *pool,
  2116. const ucl_object_t *obj,
  2117. gpointer ud,
  2118. struct rspamd_rcl_section *section,
  2119. GError **err)
  2120. {
  2121. struct rspamd_rcl_struct_parser *pd = ud;
  2122. struct rspamd_fuzzy_storage_ctx *ctx;
  2123. struct rspamd_cryptobox_keypair *kp;
  2124. struct fuzzy_key_stat *keystat;
  2125. struct fuzzy_key *key;
  2126. const ucl_object_t *cur;
  2127. const guchar *pk;
  2128. ucl_object_iter_t it = NULL;
  2129. gboolean ret;
  2130. ctx = pd->user_struct;
  2131. pd->offset = G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, default_keypair);
  2132. /*
  2133. * Single key
  2134. */
  2135. if (ucl_object_type (obj) == UCL_STRING || ucl_object_type (obj)
  2136. == UCL_OBJECT) {
  2137. ret = rspamd_rcl_parse_struct_keypair (pool, obj, pd, section, err);
  2138. if (!ret) {
  2139. return ret;
  2140. }
  2141. /* Insert key to the hash table */
  2142. kp = ctx->default_keypair;
  2143. if (kp == NULL) {
  2144. return FALSE;
  2145. }
  2146. if (rspamd_keypair_alg (kp) != RSPAMD_CRYPTOBOX_MODE_25519 ||
  2147. rspamd_keypair_type (kp) != RSPAMD_KEYPAIR_KEX) {
  2148. return FALSE;
  2149. }
  2150. key = rspamd_mempool_alloc0 (pool, sizeof (*key));
  2151. key->key = kp;
  2152. keystat = rspamd_mempool_alloc0 (pool, sizeof (*keystat));
  2153. /* Hash of ip -> fuzzy_key_stat */
  2154. keystat->last_ips = rspamd_lru_hash_new_full (1024,
  2155. (GDestroyNotify) rspamd_inet_address_free, fuzzy_key_stat_dtor,
  2156. rspamd_inet_address_hash, rspamd_inet_address_equal);
  2157. key->stat = keystat;
  2158. pk = rspamd_keypair_component (kp, RSPAMD_KEYPAIR_COMPONENT_PK,
  2159. NULL);
  2160. g_hash_table_insert (ctx->keys, (gpointer)pk, key);
  2161. ctx->default_key = key;
  2162. msg_info_pool ("loaded keypair %*xs", 8, pk);
  2163. }
  2164. else if (ucl_object_type (obj) == UCL_ARRAY) {
  2165. while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
  2166. if (!fuzzy_parse_keypair (pool, cur, pd, section, err)) {
  2167. msg_err_pool ("cannot parse keypair");
  2168. }
  2169. }
  2170. }
  2171. return TRUE;
  2172. }
  2173. static guint
  2174. fuzzy_kp_hash (gconstpointer p)
  2175. {
  2176. return *(guint *)p;
  2177. }
  2178. static gboolean
  2179. fuzzy_kp_equal (gconstpointer a, gconstpointer b)
  2180. {
  2181. const guchar *pa = a, *pb = b;
  2182. return (memcmp (pa, pb, RSPAMD_FUZZY_KEYLEN) == 0);
  2183. }
  2184. gpointer
  2185. init_fuzzy (struct rspamd_config *cfg)
  2186. {
  2187. struct rspamd_fuzzy_storage_ctx *ctx;
  2188. GQuark type;
  2189. type = g_quark_try_string ("fuzzy");
  2190. ctx = rspamd_mempool_alloc0 (cfg->cfg_pool,
  2191. sizeof (struct rspamd_fuzzy_storage_ctx));
  2192. ctx->magic = rspamd_fuzzy_storage_magic;
  2193. ctx->sync_timeout = DEFAULT_SYNC_TIMEOUT;
  2194. ctx->master_timeout = DEFAULT_MASTER_TIMEOUT;
  2195. ctx->keypair_cache_size = DEFAULT_KEYPAIR_CACHE_SIZE;
  2196. ctx->keys = g_hash_table_new_full (fuzzy_kp_hash, fuzzy_kp_equal,
  2197. NULL, fuzzy_key_dtor);
  2198. rspamd_mempool_add_destructor (cfg->cfg_pool,
  2199. (rspamd_mempool_destruct_t)g_hash_table_unref, ctx->keys);
  2200. ctx->master_flags = g_hash_table_new (g_direct_hash, g_direct_equal);
  2201. rspamd_mempool_add_destructor (cfg->cfg_pool,
  2202. (rspamd_mempool_destruct_t)g_hash_table_unref, ctx->master_flags);
  2203. ctx->errors_ips = rspamd_lru_hash_new_full (1024,
  2204. (GDestroyNotify) rspamd_inet_address_free, g_free,
  2205. rspamd_inet_address_hash, rspamd_inet_address_equal);
  2206. rspamd_mempool_add_destructor (cfg->cfg_pool,
  2207. (rspamd_mempool_destruct_t)rspamd_lru_hash_destroy, ctx->errors_ips);
  2208. ctx->cfg = cfg;
  2209. ctx->mirrors = g_ptr_array_new ();
  2210. rspamd_mempool_add_destructor (cfg->cfg_pool,
  2211. (rspamd_mempool_destruct_t)rspamd_ptr_array_free_hard, ctx->mirrors);
  2212. ctx->updates_maxfail = DEFAULT_UPDATES_MAXFAIL;
  2213. ctx->collection_id_file = RSPAMD_DBDIR "/fuzzy_collection.id";
  2214. ctx->leaky_bucket_mask = DEFAULT_BUCKET_MASK;
  2215. ctx->leaky_bucket_ttl = DEFAULT_BUCKET_TTL;
  2216. ctx->max_buckets = DEFAULT_MAX_BUCKETS;
  2217. ctx->leaky_bucket_burst = NAN;
  2218. ctx->leaky_bucket_rate = NAN;
  2219. rspamd_rcl_register_worker_option (cfg,
  2220. type,
  2221. "sync",
  2222. rspamd_rcl_parse_struct_time,
  2223. ctx,
  2224. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx,
  2225. sync_timeout),
  2226. RSPAMD_CL_FLAG_TIME_FLOAT,
  2227. "Time to perform database sync, default: "
  2228. G_STRINGIFY (DEFAULT_SYNC_TIMEOUT) " seconds");
  2229. rspamd_rcl_register_worker_option (cfg,
  2230. type,
  2231. "expire",
  2232. rspamd_rcl_parse_struct_time,
  2233. ctx,
  2234. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx,
  2235. expire),
  2236. RSPAMD_CL_FLAG_TIME_FLOAT,
  2237. "Default expire time for hashes, default: "
  2238. G_STRINGIFY (DEFAULT_EXPIRE) " seconds");
  2239. rspamd_rcl_register_worker_option (cfg,
  2240. type,
  2241. "allow_update",
  2242. rspamd_rcl_parse_struct_ucl,
  2243. ctx,
  2244. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, update_map),
  2245. 0,
  2246. "Allow modifications from the following IP addresses");
  2247. rspamd_rcl_register_worker_option (cfg,
  2248. type,
  2249. "keypair",
  2250. fuzzy_parse_keypair,
  2251. ctx,
  2252. 0,
  2253. RSPAMD_CL_FLAG_MULTIPLE,
  2254. "Encryption keypair (can be repeated for different keys)");
  2255. rspamd_rcl_register_worker_option (cfg,
  2256. type,
  2257. "keypair_cache_size",
  2258. rspamd_rcl_parse_struct_integer,
  2259. ctx,
  2260. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx,
  2261. keypair_cache_size),
  2262. RSPAMD_CL_FLAG_UINT,
  2263. "Size of keypairs cache, default: "
  2264. G_STRINGIFY (DEFAULT_KEYPAIR_CACHE_SIZE));
  2265. rspamd_rcl_register_worker_option (cfg,
  2266. type,
  2267. "encrypted_only",
  2268. rspamd_rcl_parse_struct_boolean,
  2269. ctx,
  2270. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, encrypted_only),
  2271. 0,
  2272. "Allow encrypted requests only (and forbid all unknown keys or plaintext requests)");
  2273. rspamd_rcl_register_worker_option (cfg,
  2274. type,
  2275. "read_only",
  2276. rspamd_rcl_parse_struct_boolean,
  2277. ctx,
  2278. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, read_only),
  2279. 0,
  2280. "Work in read only mode");
  2281. rspamd_rcl_register_worker_option (cfg,
  2282. type,
  2283. "master_timeout",
  2284. rspamd_rcl_parse_struct_time,
  2285. ctx,
  2286. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, master_timeout),
  2287. RSPAMD_CL_FLAG_TIME_FLOAT,
  2288. "Master protocol IO timeout");
  2289. rspamd_rcl_register_worker_option (cfg,
  2290. type,
  2291. "sync_keypair",
  2292. rspamd_rcl_parse_struct_keypair,
  2293. ctx,
  2294. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, sync_keypair),
  2295. 0,
  2296. "Encryption key for master/slave updates");
  2297. rspamd_rcl_register_worker_option (cfg,
  2298. type,
  2299. "masters",
  2300. rspamd_rcl_parse_struct_ucl,
  2301. ctx,
  2302. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, masters_map),
  2303. 0,
  2304. "Allow master/slave updates from the following IP addresses");
  2305. rspamd_rcl_register_worker_option (cfg,
  2306. type,
  2307. "blocked",
  2308. rspamd_rcl_parse_struct_ucl,
  2309. ctx,
  2310. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, blocked_map),
  2311. 0,
  2312. "Block requests from specific networks");
  2313. rspamd_rcl_register_worker_option (cfg,
  2314. type,
  2315. "master_key",
  2316. rspamd_rcl_parse_struct_pubkey,
  2317. ctx,
  2318. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, master_key),
  2319. 0,
  2320. "Allow master/slave updates merely using the specified key");
  2321. rspamd_rcl_register_worker_option (cfg,
  2322. type,
  2323. "mirror",
  2324. fuzzy_storage_parse_mirror,
  2325. ctx,
  2326. 0,
  2327. RSPAMD_CL_FLAG_MULTIPLE,
  2328. "List of slave hosts");
  2329. rspamd_rcl_register_worker_option (cfg,
  2330. type,
  2331. "slave",
  2332. fuzzy_storage_parse_mirror,
  2333. ctx,
  2334. 0,
  2335. RSPAMD_CL_FLAG_MULTIPLE,
  2336. "List of slave hosts");
  2337. rspamd_rcl_register_worker_option (cfg,
  2338. type,
  2339. "master_flags",
  2340. fuzzy_storage_parse_master_flags,
  2341. ctx,
  2342. 0,
  2343. 0,
  2344. "Map of flags in form master_flags = { master_flag = local_flag; ... }; ");
  2345. rspamd_rcl_register_worker_option (cfg,
  2346. type,
  2347. "updates_maxfail",
  2348. rspamd_rcl_parse_struct_integer,
  2349. ctx,
  2350. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, updates_maxfail),
  2351. RSPAMD_CL_FLAG_UINT,
  2352. "Maximum number of updates to be failed before discarding");
  2353. rspamd_rcl_register_worker_option (cfg,
  2354. type,
  2355. "collection_only",
  2356. rspamd_rcl_parse_struct_boolean,
  2357. ctx,
  2358. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, collection_mode),
  2359. 0,
  2360. "Start fuzzy in collection only mode");
  2361. rspamd_rcl_register_worker_option (cfg,
  2362. type,
  2363. "collection_signkey",
  2364. rspamd_rcl_parse_struct_pubkey,
  2365. ctx,
  2366. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, collection_sign_key),
  2367. RSPAMD_CL_FLAG_SIGNKEY,
  2368. "Accept only signed requests with the specified key");
  2369. rspamd_rcl_register_worker_option (cfg,
  2370. type,
  2371. "collection_keypair",
  2372. rspamd_rcl_parse_struct_keypair,
  2373. ctx,
  2374. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, collection_keypair),
  2375. 0,
  2376. "Use the specified keypair to encrypt collection protocol");
  2377. rspamd_rcl_register_worker_option (cfg,
  2378. type,
  2379. "collection_id_file",
  2380. rspamd_rcl_parse_struct_string,
  2381. ctx,
  2382. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, collection_id_file),
  2383. RSPAMD_CL_FLAG_STRING_PATH,
  2384. "Store collection epoch in the desired file");
  2385. rspamd_rcl_register_worker_option (cfg,
  2386. type,
  2387. "skip_hashes",
  2388. rspamd_rcl_parse_struct_ucl,
  2389. ctx,
  2390. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, skip_map),
  2391. 0,
  2392. "Skip specific hashes from the map");
  2393. /* Ratelimits */
  2394. rspamd_rcl_register_worker_option (cfg,
  2395. type,
  2396. "ratelimit_whitelist",
  2397. rspamd_rcl_parse_struct_ucl,
  2398. ctx,
  2399. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, ratelimit_whitelist_map),
  2400. 0,
  2401. "Skip specific addresses from rate limiting");
  2402. rspamd_rcl_register_worker_option (cfg,
  2403. type,
  2404. "ratelimit_max_buckets",
  2405. rspamd_rcl_parse_struct_integer,
  2406. ctx,
  2407. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, max_buckets),
  2408. RSPAMD_CL_FLAG_UINT,
  2409. "Maximum number of leaky buckets (default: " G_STRINGIFY(DEFAULT_MAX_BUCKETS) ")");
  2410. rspamd_rcl_register_worker_option (cfg,
  2411. type,
  2412. "ratelimit_network_mask",
  2413. rspamd_rcl_parse_struct_integer,
  2414. ctx,
  2415. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, leaky_bucket_mask),
  2416. RSPAMD_CL_FLAG_UINT,
  2417. "Network mask to apply for IPv4 rate addresses (default: " G_STRINGIFY(DEFAULT_BUCKET_MASK) ")");
  2418. rspamd_rcl_register_worker_option (cfg,
  2419. type,
  2420. "ratelimit_bucket_ttl",
  2421. rspamd_rcl_parse_struct_time,
  2422. ctx,
  2423. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, leaky_bucket_ttl),
  2424. RSPAMD_CL_FLAG_TIME_INTEGER,
  2425. "Time to live for ratelimit element (default: " G_STRINGIFY(DEFAULT_BUCKET_TTL) ")");
  2426. rspamd_rcl_register_worker_option (cfg,
  2427. type,
  2428. "ratelimit_rate",
  2429. rspamd_rcl_parse_struct_double,
  2430. ctx,
  2431. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, leaky_bucket_rate),
  2432. 0,
  2433. "Leak rate in requests per second");
  2434. rspamd_rcl_register_worker_option (cfg,
  2435. type,
  2436. "ratelimit_burst",
  2437. rspamd_rcl_parse_struct_double,
  2438. ctx,
  2439. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, leaky_bucket_burst),
  2440. 0,
  2441. "Peak value for ratelimit bucket");
  2442. rspamd_rcl_register_worker_option (cfg,
  2443. type,
  2444. "ratelimit_log_only",
  2445. rspamd_rcl_parse_struct_boolean,
  2446. ctx,
  2447. G_STRUCT_OFFSET (struct rspamd_fuzzy_storage_ctx, ratelimit_log_only),
  2448. 0,
  2449. "Don't really ban on ratelimit reaching, just log");
  2450. return ctx;
  2451. }
  2452. static void
  2453. rspamd_fuzzy_peer_io (gint fd, gshort what, gpointer d)
  2454. {
  2455. struct fuzzy_peer_cmd cmd;
  2456. struct rspamd_fuzzy_storage_ctx *ctx = d;
  2457. gssize r;
  2458. r = read (fd, &cmd, sizeof (cmd));
  2459. if (r != sizeof (cmd)) {
  2460. if (errno == EINTR) {
  2461. rspamd_fuzzy_peer_io (fd, what, d);
  2462. return;
  2463. }
  2464. if (errno != EAGAIN) {
  2465. msg_err ("cannot read command from peers: %s", strerror (errno));
  2466. }
  2467. }
  2468. else {
  2469. g_array_append_val (ctx->updates_pending, cmd);
  2470. }
  2471. }
  2472. static void
  2473. fuzzy_peer_rep (struct rspamd_worker *worker,
  2474. struct rspamd_srv_reply *rep, gint rep_fd,
  2475. gpointer ud)
  2476. {
  2477. struct rspamd_fuzzy_storage_ctx *ctx = ud;
  2478. GList *cur;
  2479. struct rspamd_worker_listen_socket *ls;
  2480. struct event *accept_events;
  2481. ctx->peer_fd = rep_fd;
  2482. if (rep_fd == -1) {
  2483. msg_err ("cannot receive peer fd from the main process");
  2484. exit (EXIT_FAILURE);
  2485. }
  2486. else {
  2487. rspamd_socket_nonblocking (rep_fd);
  2488. }
  2489. msg_info ("got peer fd reply from the main process");
  2490. /* Start listening */
  2491. cur = worker->cf->listen_socks;
  2492. while (cur) {
  2493. ls = cur->data;
  2494. if (ls->fd != -1) {
  2495. msg_info ("start listening on %s",
  2496. rspamd_inet_address_to_string_pretty (ls->addr));
  2497. if (ls->type == RSPAMD_WORKER_SOCKET_UDP) {
  2498. accept_events = g_malloc0 (sizeof (struct event) * 2);
  2499. event_set (&accept_events[0], ls->fd, EV_READ | EV_PERSIST,
  2500. accept_fuzzy_socket, worker);
  2501. event_base_set (ctx->ev_base, &accept_events[0]);
  2502. event_add (&accept_events[0], NULL);
  2503. worker->accept_events = g_list_prepend (worker->accept_events,
  2504. accept_events);
  2505. }
  2506. else if (worker->index == 0) {
  2507. /* We allow TCP listeners only for a update worker */
  2508. accept_events = g_malloc0 (sizeof (struct event) * 2);
  2509. if (ctx->collection_mode) {
  2510. event_set (&accept_events[0], ls->fd, EV_READ | EV_PERSIST,
  2511. accept_fuzzy_collection_socket, worker);
  2512. }
  2513. else {
  2514. event_set (&accept_events[0], ls->fd, EV_READ | EV_PERSIST,
  2515. accept_fuzzy_mirror_socket, worker);
  2516. }
  2517. event_base_set (ctx->ev_base, &accept_events[0]);
  2518. event_add (&accept_events[0], NULL);
  2519. worker->accept_events = g_list_prepend (worker->accept_events,
  2520. accept_events);
  2521. }
  2522. }
  2523. cur = g_list_next (cur);
  2524. }
  2525. if (worker->index == 0 && ctx->peer_fd != -1) {
  2526. /* Listen for peer requests */
  2527. event_set (&ctx->peer_ev, ctx->peer_fd, EV_READ | EV_PERSIST,
  2528. rspamd_fuzzy_peer_io, ctx);
  2529. event_base_set (ctx->ev_base, &ctx->peer_ev);
  2530. event_add (&ctx->peer_ev, NULL);
  2531. }
  2532. }
  2533. /*
  2534. * Start worker process
  2535. */
  2536. void
  2537. start_fuzzy (struct rspamd_worker *worker)
  2538. {
  2539. struct rspamd_fuzzy_storage_ctx *ctx = worker->ctx;
  2540. GError *err = NULL;
  2541. struct rspamd_srv_command srv_cmd;
  2542. struct rspamd_config *cfg = worker->srv->cfg;
  2543. ctx->ev_base = rspamd_prepare_worker (worker,
  2544. "fuzzy",
  2545. NULL);
  2546. ctx->peer_fd = -1;
  2547. ctx->worker = worker;
  2548. ctx->cfg = worker->srv->cfg;
  2549. double_to_tv (ctx->master_timeout, &ctx->master_io_tv);
  2550. ctx->resolver = rspamd_dns_resolver_init (worker->srv->logger,
  2551. ctx->ev_base,
  2552. worker->srv->cfg);
  2553. rspamd_upstreams_library_config (worker->srv->cfg, ctx->cfg->ups_ctx,
  2554. ctx->ev_base, ctx->resolver->r);
  2555. if (ctx->keypair_cache_size > 0) {
  2556. /* Create keypairs cache */
  2557. ctx->keypair_cache = rspamd_keypair_cache_new (ctx->keypair_cache_size);
  2558. }
  2559. ctx->http_ctx = rspamd_http_context_create (cfg, ctx->ev_base, ctx->cfg->ups_ctx);
  2560. if (!ctx->collection_mode) {
  2561. /*
  2562. * Open DB and perform VACUUM
  2563. */
  2564. if ((ctx->backend = rspamd_fuzzy_backend_create (ctx->ev_base,
  2565. worker->cf->options, cfg, &err)) == NULL) {
  2566. msg_err ("cannot open backend: %e", err);
  2567. if (err) {
  2568. g_error_free (err);
  2569. }
  2570. exit (EXIT_SUCCESS);
  2571. }
  2572. rspamd_fuzzy_backend_count (ctx->backend, fuzzy_count_callback, ctx);
  2573. if (worker->index == 0) {
  2574. ctx->updates_pending = g_array_sized_new (FALSE, FALSE,
  2575. sizeof (struct fuzzy_peer_cmd), 1024);
  2576. rspamd_fuzzy_backend_start_update (ctx->backend, ctx->sync_timeout,
  2577. rspamd_fuzzy_storage_periodic_callback, ctx);
  2578. }
  2579. double_to_tv (ctx->sync_timeout, &ctx->stat_tv);
  2580. event_set (&ctx->stat_ev, -1, EV_TIMEOUT, rspamd_fuzzy_stat_callback, ctx);
  2581. event_base_set (ctx->ev_base, &ctx->stat_ev);
  2582. event_add (&ctx->stat_ev, &ctx->stat_tv);
  2583. /* Register custom reload and stat commands for the control socket */
  2584. rspamd_control_worker_add_cmd_handler (worker, RSPAMD_CONTROL_RELOAD,
  2585. rspamd_fuzzy_storage_reload, ctx);
  2586. rspamd_control_worker_add_cmd_handler (worker, RSPAMD_CONTROL_FUZZY_STAT,
  2587. rspamd_fuzzy_storage_stat, ctx);
  2588. rspamd_control_worker_add_cmd_handler (worker, RSPAMD_CONTROL_FUZZY_SYNC,
  2589. rspamd_fuzzy_storage_sync, ctx);
  2590. }
  2591. else {
  2592. /*
  2593. * In collection mode we do a different thing:
  2594. * we collect fuzzy hashes in the updates queue and ignore all read commands
  2595. */
  2596. if (worker->index == 0) {
  2597. ctx->updates_pending = g_array_sized_new (FALSE, FALSE,
  2598. sizeof (struct fuzzy_peer_cmd), 1024);
  2599. double_to_tv (ctx->sync_timeout, &ctx->stat_tv);
  2600. event_set (&ctx->stat_ev, -1, EV_TIMEOUT|EV_PERSIST,
  2601. rspamd_fuzzy_collection_periodic, ctx);
  2602. event_base_set (ctx->ev_base, &ctx->stat_ev);
  2603. event_add (&ctx->stat_ev, &ctx->stat_tv);
  2604. ctx->collection_rt = rspamd_http_router_new (
  2605. rspamd_fuzzy_collection_error_handler,
  2606. rspamd_fuzzy_collection_finish_handler,
  2607. &ctx->stat_tv,
  2608. NULL,
  2609. ctx->http_ctx);
  2610. if (ctx->collection_keypair) {
  2611. rspamd_http_router_set_key (ctx->collection_rt,
  2612. ctx->collection_keypair);
  2613. }
  2614. /* Try to load collection id */
  2615. if (ctx->collection_id_file) {
  2616. gint fd;
  2617. fd = rspamd_file_xopen (ctx->collection_id_file, O_RDONLY, 0,
  2618. FALSE);
  2619. if (fd == -1) {
  2620. if (errno != ENOENT) {
  2621. msg_err ("cannot open collection id from %s: %s",
  2622. ctx->collection_id_file, strerror (errno));
  2623. }
  2624. ctx->collection_id = 0;
  2625. }
  2626. else {
  2627. if (read (fd, &ctx->collection_id,
  2628. sizeof (ctx->collection_id)) == -1) {
  2629. msg_err ("cannot read collection id from %s: %s",
  2630. ctx->collection_id_file, strerror (errno));
  2631. ctx->collection_id = 0;
  2632. }
  2633. close (fd);
  2634. }
  2635. }
  2636. /* Generate new cookie */
  2637. ottery_rand_bytes (ctx->cookie, sizeof (ctx->cookie));
  2638. /* Register paths */
  2639. rspamd_http_router_add_path (ctx->collection_rt,
  2640. "/cookie",
  2641. rspamd_fuzzy_collection_cookie);
  2642. rspamd_http_router_add_path (ctx->collection_rt,
  2643. "/data",
  2644. rspamd_fuzzy_collection_data);
  2645. }
  2646. }
  2647. if (ctx->mirrors && ctx->mirrors->len != 0) {
  2648. if (ctx->sync_keypair == NULL) {
  2649. GString *pk_str = NULL;
  2650. ctx->sync_keypair = rspamd_keypair_new (RSPAMD_KEYPAIR_KEX,
  2651. RSPAMD_CRYPTOBOX_MODE_25519);
  2652. pk_str = rspamd_keypair_print (ctx->sync_keypair,
  2653. RSPAMD_KEYPAIR_COMPONENT_PK|RSPAMD_KEYPAIR_BASE32);
  2654. msg_warn_config ("generating new temporary keypair for communicating"
  2655. " with slave hosts, pk is %s", pk_str->str);
  2656. g_string_free (pk_str, TRUE);
  2657. }
  2658. }
  2659. /* Create radix trees */
  2660. if (ctx->update_map != NULL) {
  2661. rspamd_config_radix_from_ucl (worker->srv->cfg, ctx->update_map,
  2662. "Allow fuzzy updates from specified addresses",
  2663. &ctx->update_ips, NULL);
  2664. }
  2665. if (ctx->masters_map != NULL) {
  2666. rspamd_config_radix_from_ucl (worker->srv->cfg, ctx->masters_map,
  2667. "Allow fuzzy master/slave updates from specified addresses",
  2668. &ctx->master_ips, NULL);
  2669. }
  2670. if (ctx->skip_map != NULL) {
  2671. struct rspamd_map *m;
  2672. if ((m = rspamd_map_add_from_ucl (cfg, ctx->skip_map,
  2673. "Skip hashes",
  2674. rspamd_kv_list_read,
  2675. rspamd_kv_list_fin,
  2676. rspamd_kv_list_dtor,
  2677. (void **)&ctx->skip_hashes)) == NULL) {
  2678. msg_warn_config ("cannot load hashes list from %s",
  2679. ucl_object_tostring (ctx->skip_map));
  2680. }
  2681. else {
  2682. m->active_http = TRUE;
  2683. }
  2684. }
  2685. if (ctx->blocked_map != NULL) {
  2686. rspamd_config_radix_from_ucl (worker->srv->cfg, ctx->blocked_map,
  2687. "Block fuzzy requests from the specific IPs",
  2688. &ctx->blocked_ips, NULL);
  2689. }
  2690. /* Create radix trees */
  2691. if (ctx->ratelimit_whitelist_map != NULL) {
  2692. rspamd_config_radix_from_ucl (worker->srv->cfg, ctx->ratelimit_whitelist_map,
  2693. "Skip ratelimits from specific ip addresses/networks",
  2694. &ctx->ratelimit_whitelist, NULL);
  2695. }
  2696. /* Ratelimits */
  2697. if (!isnan (ctx->leaky_bucket_rate) && !isnan (ctx->leaky_bucket_burst)) {
  2698. ctx->ratelimit_buckets = rspamd_lru_hash_new_full (ctx->max_buckets,
  2699. NULL, fuzzy_rl_bucket_free,
  2700. rspamd_inet_address_hash, rspamd_inet_address_equal);
  2701. }
  2702. /* Maps events */
  2703. ctx->resolver = rspamd_dns_resolver_init (worker->srv->logger,
  2704. ctx->ev_base,
  2705. worker->srv->cfg);
  2706. rspamd_map_watch (worker->srv->cfg, ctx->ev_base, ctx->resolver, worker, 0);
  2707. /* Get peer pipe */
  2708. memset (&srv_cmd, 0, sizeof (srv_cmd));
  2709. srv_cmd.type = RSPAMD_SRV_SOCKETPAIR;
  2710. srv_cmd.cmd.spair.af = SOCK_DGRAM;
  2711. srv_cmd.cmd.spair.pair_num = worker->index;
  2712. memset (srv_cmd.cmd.spair.pair_id, 0, sizeof (srv_cmd.cmd.spair.pair_id));
  2713. memcpy (srv_cmd.cmd.spair.pair_id, "fuzzy", sizeof ("fuzzy"));
  2714. rspamd_srv_send_command (worker, ctx->ev_base, &srv_cmd, -1,
  2715. fuzzy_peer_rep, ctx);
  2716. event_base_loop (ctx->ev_base, 0);
  2717. rspamd_worker_block_signals ();
  2718. if (worker->index == 0 && ctx->updates_pending->len > 0) {
  2719. if (!ctx->collection_mode) {
  2720. rspamd_fuzzy_process_updates_queue (ctx, local_db_name, FALSE);
  2721. event_base_loop (ctx->ev_base, 0);
  2722. }
  2723. }
  2724. if (!ctx->collection_mode) {
  2725. rspamd_fuzzy_backend_close (ctx->backend);
  2726. }
  2727. else if (worker->index == 0) {
  2728. gint fd;
  2729. rspamd_http_router_free (ctx->collection_rt);
  2730. /* Try to save collection id */
  2731. fd = rspamd_file_xopen (ctx->collection_id_file,
  2732. O_WRONLY | O_CREAT | O_TRUNC, 00644, 0);
  2733. if (fd == -1) {
  2734. msg_err ("cannot open collection id to store in %s: %s",
  2735. ctx->collection_id_file, strerror (errno));
  2736. }
  2737. else {
  2738. if (write (fd, &ctx->collection_id,
  2739. sizeof (ctx->collection_id)) == -1) {
  2740. msg_err ("cannot store collection id in %s: %s",
  2741. ctx->collection_id_file, strerror (errno));
  2742. }
  2743. close (fd);
  2744. }
  2745. }
  2746. if (worker->index == 0) {
  2747. g_array_free (ctx->updates_pending, TRUE);
  2748. }
  2749. if (ctx->peer_fd != -1) {
  2750. if (worker->index == 0) {
  2751. event_del (&ctx->peer_ev);
  2752. }
  2753. close (ctx->peer_fd);
  2754. }
  2755. if (ctx->keypair_cache) {
  2756. rspamd_keypair_cache_destroy (ctx->keypair_cache);
  2757. }
  2758. struct rspamd_http_context *http_ctx = ctx->http_ctx;
  2759. REF_RELEASE (ctx->cfg);
  2760. rspamd_http_context_free (http_ctx);
  2761. rspamd_log_close (worker->srv->logger, TRUE);
  2762. exit (EXIT_SUCCESS);
  2763. }