1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780 |
- /*
- * Copyright 2024 Vsevolod Stakhov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "lua_common.h"
- #include "libmime/message.h"
- #include "libutil/expression.h"
- #include "src/libserver/composites/composites.h"
- #include "libserver/cfg_file_private.h"
- #include "libmime/lang_detection.h"
- #include "lua/lua_map.h"
- #include "lua/lua_thread_pool.h"
- #include "utlist.h"
- #include <math.h>
-
- /***
- * This module is used to configure rspamd and is normally available as global
- * variable named `rspamd_config`. Unlike other modules, it is not necessary to
- * require it before usage.
- * @module rspamd_config
- * @example
- -- Register some callback symbol
- local function foo(task)
- -- do something
- end
- rspamd_config:register_symbol('SYMBOL', 1.0, foo)
-
- -- Get configuration
- local tab = rspamd_config:get_all_opt('module') -- get table for module's options
- local opts = rspamd_config:get_key('options') -- get content of the specified key in rspamd configuration
- */
-
- /* Config file methods */
- /***
- * @method rspamd_config:get_module_opt(mname, optname)
- * Returns value of specified option `optname` for a module `mname`,
- * @param {string} mname name of module
- * @param {string} optname option to get
- * @return {string or table} value of the option or `nil` if option is not found
- */
- LUA_FUNCTION_DEF(config, get_module_opt);
- /***
- * @method rspamd_config:get_all_opt(mname)
- * Returns value of all options for a module `mname`, flattening values into a single table consisting
- * of all sections with such a name.
- * @param {string} mname name of module
- * @return {table} table of all options for `mname` or `nil` if a module's configuration is not found
- */
- LUA_FUNCTION_DEF(config, get_all_opt);
-
- /***
- * @method rspamd_config:get_ucl()
- * Returns full configuration as a native Lua object (ucl to lua conversion).
- * This method uses caching if possible.
- * @return {table} table of all options in the configuration
- */
- LUA_FUNCTION_DEF(config, get_ucl);
- /***
- * @method rspamd_config:get_mempool()
- * Returns static configuration memory pool.
- * @return {mempool} [memory pool](mempool.md) object
- */
- LUA_FUNCTION_DEF(config, get_mempool);
- /***
- * @method rspamd_config:get_resolver()
- * Returns DNS resolver.
- * @return {dns_resolver} opaque DNS resolver pointer if any
- */
- LUA_FUNCTION_DEF(config, get_resolver);
- /***
- * @method rspamd_config:add_radix_map(mapline[, description])
- * Creates new dynamic map of IP/mask addresses.
- * @param {string} mapline URL for a map
- * @param {string} description optional map description
- * @return {map} radix tree object
- * @example
- local ip_map = rspamd_config:add_radix_map ('file:///path/to/file', 'my radix map')
- ...
- local function foo(task)
- local ip = task:get_from_ip()
- if ip_map:get_key(ip) then
- return true
- end
- return false
- end
- */
-
- /***
- * @method rspamd_config:radix_from_config(mname, optname)
- * Creates new embedded map of IP/mask addresses from config.
- * @param {string} mname name of module
- * @param {string} optname option to get
- * @return {map} radix tree object
- * @example
- local ip_map = rspamd_config:radix_from_config ('mymodule', 'ips')
- ...
- local function foo(task)
- local ip = task:get_from_ip()
- if ip_map:get_key(ip) then
- return true
- end
- return false
- end
- */
- /***
- * @method rspamd_config:radix_from_ucl(obj)
- * Creates new embedded map of IP/mask addresses from object.
- * @param {ucl} obj object
- * @return {map} radix tree object
- */
- /***
- * @method rspamd_config:add_hash_map(mapline[, description])
- * Creates new dynamic map string objects.
- * @param {string} mapline URL for a map
- * @param {string} description optional map description
- * @return {map} hash set object
- * @example
- local hash_map = rspamd_config:add_hash_map ('file:///path/to/file', 'my hash map')
- ...
- local function foo(task)
- local from = task:get_from()
- if hash_map:get_key(from['user']) then
- return true
- end
- return false
- end
- */
- /***
- * @method rspamd_config:add_kv_map(mapline[, description])
- * Creates new dynamic map of key/values associations.
- * @param {string} mapline URL for a map
- * @param {string} description optional map description
- * @return {map} hash table object
- * @example
- local kv_map = rspamd_config:add_kv_map ('file:///path/to/file', 'my kv map')
- ...
- local function foo(task)
- local from = task:get_from()
- if from then
- local value = kv_map:get_key(from['user'])
- if value then
- return true,value
- end
- end
- return false
- end
- */
- /***
- * @method rspamd_config:add_map({args})
- * Creates new dynamic map according to the attributes passed.
- *
- * - `type`: type of map to be created, can be one of the following set:
- * + `set`: set of strings
- * + `radix`: map of IP addresses to strings
- * + `map`: map of strings to strings
- * + `regexp`: map of regexps to strings
- * + `callback`: map processed by lua callback
- * - `url`: url to load map from
- * - `description`: map's description
- * - `callback`: lua callback for the map
- *
- * @return {map} `true` if map has been added
- * @example
-
- local str = ''
- local function process_map(in)
- str = in
- end
-
- rspamd_config:add_map('http://example.com/map', "settings map", process_map)
- */
- /***
- * @method rspamd_config:get_maps()
- * Get all maps defined as an array of rspamd{map} objects
- *
- * @return {table|rspamd{map}}
- */
- /***
- * @method rspamd_config:get_classifier(name)
- * Returns classifier config.
- * @param {string} name name of classifier (e.g. `bayes`)
- * @return {classifier} classifier object or `nil`
- */
- LUA_FUNCTION_DEF(config, get_classifier);
- /***
- * @method rspamd_config:register_symbol(table)
- * Register symbol of a specified type in rspamd. This function accepts table of arguments:
- *
- * - `name`: name of symbol (can be missing for callback symbols)
- * - `callback`: function to be called for symbol's check (can be absent for virtual symbols)
- * - `weight`: weight of symbol (should normally be 1 or missing)
- * - `priority`: priority of symbol (normally 0 or missing)
- * - `type`: type of symbol:
- * + `normal`: executed after prefilters, according to dependency graph or in undefined order
- * + `callback`: a check that merely inserts virtual symbols
- * + `connfilter`: executed early; before message body is available
- * + `idempotent`: cannot change result in any way; executed last
- * + `postfilter`: executed after most other checks
- * + `prefilter`: executed before most other checks
- * + `virtual`: a symbol inserted by its parent check
- * - `flags`: various flags split by commas or spaces:
- * + `nice` if symbol can produce negative score;
- * + `empty` if symbol can be called for empty messages
- * + `skip` if symbol should be skipped now
- * + `nostat` if symbol should be excluded from stat tokens
- * + `trivial` symbol is trivial (e.g. no network requests)
- * + `explicit_disable` requires explicit disabling (e.g. via settings)
- * + `ignore_passthrough` executed even if passthrough result has been set
- * - `parent`: id of parent symbol (useful for virtual symbols)
- *
- * @return {number} id of symbol registered
- */
- LUA_FUNCTION_DEF(config, register_symbol);
- /***
- * @method rspamd_config:register_symbols(callback, [weight], callback_name, [, symbol, ...])
- * Register callback function to be called for a set of symbols with initial weight.
- * @param {function} callback callback function to be called for a specified symbol
- * @param {number} weight initial weight of symbol (can be less than zero to specify non-spam symbols)
- * @param {string} callback_name symbolic name of callback
- * @param {list of strings} symbol list of symbols registered by this function
- */
- LUA_FUNCTION_DEF(config, register_symbols);
- /***
- * @method rspamd_config:register_virtual_symbol(name, weight,)
- * Register virtual symbol that is not associated with any callback.
- *
- * **This method is deprecated and should not be used in newly written code **
- * @param {string} virtual name symbol's name
- * @param {number} weight initial weight of symbol (can be less than zero to specify non-spam symbols)
- */
- LUA_FUNCTION_DEF(config, register_virtual_symbol);
- /***
- * @method rspamd_config:register_callback_symbol(name, weight, callback)
- * Register callback function to be called for a specified symbol with initial weight. Symbol itself is
- * not registered in the metric and is not intended to be visible by a user.
- *
- * **This method is deprecated and should not be used in newly written code **
- * @param {string} name symbol's name (just for unique id purposes)
- * @param {number} weight initial weight of symbol (can be less than zero to specify non-spam symbols)
- * @param {function} callback callback function to be called for a specified symbol
- */
- LUA_FUNCTION_DEF(config, register_callback_symbol);
- LUA_FUNCTION_DEF(config, register_callback_symbol_priority);
-
- /***
- * @method rspamd_config:register_dependency(id|name, depname)
- * Create a dependency on symbol identified by name for symbol identified by ID or name.
- * This affects order of checks only (a symbol is still checked if its dependencies are disabled).
- * @param {number|string} id id or name of source (numeric id is returned by all register_*_symbol)
- * @param {string} depname dependency name
- * @example
- local function cb(task)
- ...
- end
-
- local id = rspamd_config:register_symbol('SYM', 1.0, cb)
- rspamd_config:register_dependency(id, 'OTHER_SYM')
- -- Alternative form
- -- Symbol MY_RULE needs result from SPF_CHECK
- rspamd_config:register_dependency('MY_RULE', 'SPF_CHECK')
- */
- LUA_FUNCTION_DEF(config, register_dependency);
-
- /***
- * @method rspamd_config:get_symbol_flags(name)
- * Returns symbol flags
- * @param {string} name symbols's name
- * @return {table|string} list of flags for symbol or nil
- */
- LUA_FUNCTION_DEF(config, get_symbol_flags);
-
- /***
- * @method rspamd_config:add_symbol_flags(name, flags)
- * Adds flags to a symbol
- * @param {string} name symbols's name
- * @param {table|string} flags flags to add
- * @return {table|string} new set of flags
- */
- LUA_FUNCTION_DEF(config, add_symbol_flags);
-
- /**
- * @method rspamd_config:register_re_selector(name, selector_str, [delimiter, [flatten]])
- * Registers selector with the specific name to use in regular expressions in form
- * name=/re/$ or name=/re/{selector}
- * @param {string} name name of the selector
- * @param {string} selector_str selector definition
- * @param {string} delimiter delimiter to use when joining strings if flatten is false
- * @param {bool} flatten if true then selector will return a table of captures instead of a single string
- * @return true if selector has been registered
- */
- LUA_FUNCTION_DEF(config, register_re_selector);
-
- /**
- * @method rspamd_config:set_symbol({table})
- * Sets the value of a specified symbol in a metric. This function accepts table with the following elements:
- *
- * - `name`: name of symbol (string)
- * - `score`: score for symbol (number)
- * - `metric`: name of metric (string, optional)
- * - `description`: description of symbol (string, optional)
- * - `group`: name of group for symbol (string, optional)
- * - `one_shot`: turn off multiple hits for a symbol (boolean, optional)
- * - `one_param`: turn off multiple options for a symbol (boolean, optional)
- * - `flags`: comma separated string of flags:
- * + `ignore`: do not strictly check validity of symbol and corresponding rule
- * + `one_shot`: turn off multiple hits for a symbol
- * + `one_param`: allow only one parameter for a symbol
- * - `priority`: priority of symbol's definition
- */
- LUA_FUNCTION_DEF(config, set_metric_symbol);
-
- /**
- * @method rspamd_config:set_action({table})
- * Sets the score of a specified action in a metric. This function accepts table with the following elements:
- *
- * - `action`: name of action (string)
- * - `score`: score for action (number)
- * - `metric`: name of metric (string, optional)
- * - `priority`: priority of action's definition
- */
- LUA_FUNCTION_DEF(config, set_metric_action);
-
- /**
- * @method rspamd_config:get_action(name)
- * Gets data for a specific action in config. This function returns number representing action's score
- *
- * @param {string} name name of action
- * @return {number} action's score or nil in case of undefined score or action
- */
- LUA_FUNCTION_DEF(config, get_metric_action);
-
- /**
- * @method rspamd_config:get_all_actions()
- * Gets data for all action in config
- * @return {table|str->num} action's score or nil in case of undefined score or action
- */
- LUA_FUNCTION_DEF(config, get_all_actions);
-
- /**
- * @method rspamd_config:add_composite(name, expression)
- * @param {string} name name of composite symbol
- * @param {string} expression symbolic expression of the composite rule
- * @return {bool} true if a composite has been added successfully
- */
- LUA_FUNCTION_DEF(config, add_composite);
- /***
- * @method rspamd_config:register_pre_filter(callback[, order])
- * Register function to be called prior to symbols processing.
- * @param {function} callback callback function
- * @param {number} order filters are called from lower orders to higher orders, order is equal to 0 by default
- * @example
- local function check_function(task)
- -- It is possible to manipulate the task object here: set settings, set pre-action and so on
- ...
- end
-
- rspamd_config:register_pre_filter(check_function)
- */
- LUA_FUNCTION_DEF(config, register_pre_filter);
- /***
- * @method rspamd_config:register_post_filter(callback[, order])
- * Register function to be called after symbols are processed.
- *
- * @param {function} callback callback function
- * @param {number} order filters are called from lower orders to higher orders, order is equal to 0 by default
- */
- LUA_FUNCTION_DEF(config, register_post_filter);
- /* XXX: obsoleted */
- LUA_FUNCTION_DEF(config, register_module_option);
- /* XXX: not needed now */
- LUA_FUNCTION_DEF(config, get_api_version);
- /***
- * @method rspamd_config:get_key(name)
- * Returns configuration section with the specified `name`.
- * @param {string} name name of config section
- * @return {variant} specific value of section
- * @example
-
- local set_section = rspamd_config:get_key("settings")
- if type(set_section) == "string" then
- -- Just a map of ucl
- if rspamd_config:add_map(set_section, "settings map", process_settings_map) then
- rspamd_config:register_pre_filter(check_settings)
- end
- elseif type(set_section) == "table" then
- if process_settings_table(set_section) then
- rspamd_config:register_pre_filter(check_settings)
- end
- end
- */
- LUA_FUNCTION_DEF(config, get_key);
-
- /***
- * @method rspamd_config:add_condition(symbol, condition)
- * Adds condition callback for specified symbol
- * @param {string} symbol symbol's name
- * @param {function} condition condition callback
- * @return {boolean} true if condition has been added
- * @example
-
- local condition_map = rspamd_config:add_map{
- type = "hash",
- urls = ['file:///path/to/file'],
- description = 'SMTP from map that allows FUZZY_DENIED skip for the listed addresses'
- }
- rspamd_config:add_condition('FUZZY_DENIED', function(task)
- local E = {}
- -- Check for the smtp from address adding fail safe checks
- if condition_map:find_key(((task:get_from('smtp') or E)[1] or E).addr) then
- return false
- end
- -- Allow execution otherwise
- return true
- end)
- */
- LUA_FUNCTION_DEF(config, add_condition);
-
- /***
- * @method rspamd_config:enable_symbol(symbol)
- * Enables execution for the specified symbol
- * @param {string} symbol symbol's name
- */
- LUA_FUNCTION_DEF(config, enable_symbol);
-
- /***
- * @method rspamd_config:disable_symbol(symbol, [disable_parent=true])
- * Disables execution for the specified symbol
- * @param {string} symbol symbol's name
- * @param {boolean} disable_parent if true then disable parent execution in case of a virtual symbol
- */
- LUA_FUNCTION_DEF(config, disable_symbol);
-
- /***
- * @method rspamd_config:get_symbol_parent(symbol)
- * Returns a parent symbol for specific symbol (or symbol itself if top level)
- * @param {string} symbol symbol's name
- */
- LUA_FUNCTION_DEF(config, get_symbol_parent);
-
- /***
- * @method rspamd_config:get_group_symbols(group)
- * Returns list of symbols for a specific group
- * @param {string} group group's name
- * @available 2.0+
- * @return {list|string} list of all symbols in a specific group
- */
- LUA_FUNCTION_DEF(config, get_group_symbols);
-
- /***
- * @method rspamd_config:get_groups([need_private])
- * Returns list of all groups defined
- * @param {boolean} need_private optional flag to include private groups
- * @available 2.3+
- * @return {list|table} list of all groups
- */
- LUA_FUNCTION_DEF(config, get_groups);
-
- /***
- * @method rspamd_config:register_settings_id(name, symbols_enabled, symbols_disabled)
- * Register new static settings id in config
- * @param {string} name id name (not numeric!)
- * @param {map|string->string} symbols_enabled map from symbol's name to boolean (currently)
- * @param {map|string->string} symbols_disabled map from symbol's name to boolean (currently)
- * @available 2.0+
- */
- LUA_FUNCTION_DEF(config, register_settings_id);
-
- /***
- * @method rspamd_config:__newindex(name, callback)
- * This metamethod is called if new indices are added to the `rspamd_config` object.
- * Technically, it is the equivalent of @see rspamd_config:register_symbol where `weight` is 1.0.
- * There is also table form invocation that allows to control more things:
- *
- * - `callback`: has the same meaning and acts as function of task
- * - `score`: default score for a symbol
- * - `group`: default group for a symbol
- * - `description`: default symbol's description
- * - `priority`: additional priority value
- * - `one_shot`: default value for one shot attribute
- * - `condition`: function of task that can enable or disable this specific rule's execution
- * @param {string} name index name
- * @param {function/table} callback callback to be called
- * @return {number} id of the new symbol added
- * @example
- rspamd_config.R_EMPTY_IMAGE = function (task)
- parts = task:get_text_parts()
- if parts then
- for _,part in ipairs(parts) do
- if part:is_empty() then
- images = task:get_images()
- if images then
- -- Symbol `R_EMPTY_IMAGE` is inserted
- return true
- end
- return false
- end
- end
- end
- return false
- end
-
- rspamd_config.SYMBOL = {
- callback = function(task)
- ...
- end,
- score = 5.1,
- description = 'sample symbol',
- group = 'sample symbols',
- condition = function(task)
- if task:get_from()[1]['addr'] == 'user@example.com' then
- return false
- end
- return true
- end
- }
- */
- LUA_FUNCTION_DEF(config, newindex);
-
- /***
- * @method rspamd_config:register_regexp(params)
- * Registers new re for further cached usage
- * Params is the table with the following fields (mandatory fields are marked with `*`):
- * - `re`* : regular expression object
- * - `type`*: type of regular expression:
- * + `mime`: mime regexp
- * + `rawmime`: raw mime regexp
- * + `header`: header regexp
- * + `rawheader`: raw header expression
- * + `body`: raw body regexp
- * + `url`: url regexp
- * - `header`: for header and rawheader regexp means the name of header
- * - `pcre_only`: flag regexp as pcre only regexp
- */
- LUA_FUNCTION_DEF(config, register_regexp);
-
- /***
- * @method rspamd_config:replace_regexp(params)
- * Replaces regexp with a new one
- * Params is the table with the following fields (mandatory fields are marked with `*`):
- * - `old_re`* : old regular expression object (must be in the cache)
- * - `new_re`* : old regular expression object (must not be in the cache)
- */
- LUA_FUNCTION_DEF(config, replace_regexp);
-
- /***
- * @method rspamd_config:register_worker_script(worker_type, script)
- * Registers the following script for workers of a specified type. The exact type
- * of script function depends on worker type
- * @param {string} worker_type worker type (e.g. "normal")
- * @param {function} script script for a worker
- * @return {boolean} `true` if a script has been registered
- */
- LUA_FUNCTION_DEF(config, register_worker_script);
-
- /***
- * @method rspamd_config:add_on_load(function(cfg, ev_base, worker) ... end)
- * Registers the following script to be executed when configuration is completely loaded
- * and the worker is already started (forked)
- * @param {function} script function to be executed
- * @example
- rspamd_config:add_on_load(function(cfg, ev_base, worker)
- rspamd_config:add_periodic(ev_base, 1.0, function(cfg, ev_base)
- local logger = require "rspamd_logger"
- logger.infox(cfg, "periodic function in worker %s", worker:get_name())
- return true
- end)
- end)
- */
- LUA_FUNCTION_DEF(config, add_on_load);
-
- /***
- * @method rspamd_config:add_periodic(event_base, timeout, function(cfg, ev_base) ... end, [jitter = false])
- * Registers function to be periodically executed by Rspamd
- * @param {ev_base} event_base event base that is needed for async events
- * @param {number} timeout time in seconds (could be fractional)
- * @param {function} script function to be executed
- * @param {boolean} jitter `true` if timeout jittering is needed
- * @example
- rspamd_config:add_on_load(function(cfg, ev_base)
- rspamd_config:add_periodic(ev_base, 1.0, function(cfg, ev_base)
- local logger = require "rspamd_logger"
- logger.infox(cfg, "periodic function")
- return true -- if return numeric, a new interval is set. if return false, then the periodic event is removed
- end)
- end)
- */
- LUA_FUNCTION_DEF(config, add_periodic);
-
- /***
- * @method rspamd_config:add_post_init(function(cfg) ... end)
- * Registers the following script to be executed when configuration is completely loaded
- * @available 2.0+
- * @param {function} script function to be executed
- */
- LUA_FUNCTION_DEF(config, add_post_init);
-
- /***
- * @method rspamd_config:add_config_unload(function(cfg) ... end)
- * Registers the following script to be executed when configuration is unloaded
- * @available 2.0+
- * @param {function} script function to be executed
- */
- LUA_FUNCTION_DEF(config, add_config_unload);
-
- /***
- * @method rspamd_config:get_symbols_count()
- * Returns number of symbols registered in rspamd configuration
- * @return {number} number of symbols registered in the configuration
- */
- LUA_FUNCTION_DEF(config, get_symbols_count);
-
- /***
- * @method rspamd_config:get_symbols_cksum()
- * Returns checksum for all symbols in the cache
- * @return {int64} boxed value of the 64 bit checksum
- */
- LUA_FUNCTION_DEF(config, get_symbols_cksum);
-
- /***
- * @method rspamd_config:get_symbols_counters()
- * Returns table of all counters in the cache (weights, frequencies etc)
- * @return {table|tables} all symbols indexed by name
- */
- LUA_FUNCTION_DEF(config, get_symbols_counters);
-
- /***
- * @method rspamd_config:get_symbols()
- * Returns table of all scores defined in config. From version 2.0 returns table:
- * - name
- * - score
- * - flags (e.g. `ignore` or `oneparam`)
- * - nshots (== maxhits)
- * - group - main group
- * - groups - array of all groups
- * @available 2.0+
- * @return {table|tables} all symbols indexed by name
- */
- LUA_FUNCTION_DEF(config, get_symbols);
-
- /***
- * @method rspamd_config:get_symbol(sym_name)
- * Returns table for a specific symbol getting data from the static config:
- * - name
- * - score
- * - flags (e.g. `ignore` or `oneparam`)
- * - nshots (== maxhits)
- * - group - main group
- * - groups - array of all groups
- * @available 3.3+
- * @return {table} symbol data (or nil)
- */
- LUA_FUNCTION_DEF(config, get_symbol);
-
- /***
- * @method rspamd_config:get_symbol_callback(name)
- * Returns callback function for the specified symbol if it is a lua registered callback
- * @return {function} callback function or nil
- */
- LUA_FUNCTION_DEF(config, get_symbol_callback);
-
- /***
- * @method rspamd_config:get_symbol_stat(name)
- * Returns table with statistics for a specific symbol:
- * - `frequency`: frequency for symbol's hits
- * - `stddev`: standard deviation of `frequency`
- * - `time`: average time in seconds (floating point)
- * - `count`: total number of hits
- * @return {table} symbol stats
- */
- LUA_FUNCTION_DEF(config, get_symbol_stat);
-
- /***
- * @method rspamd_config:set_symbol_callback(name, callback)
- * Sets callback for the specified symbol
- * @return {boolean} true if function has been replaced
- */
- LUA_FUNCTION_DEF(config, set_symbol_callback);
-
- /***
- * @method rspamd_config:register_finish_script(callback)
- * Adds new callback that is called on worker process termination when all
- * tasks pending are processed
- *
- * @param callback {function} a function with one argument (rspamd_task)
- */
- LUA_FUNCTION_DEF(config, register_finish_script);
-
- /***
- * @method rspamd_config:register_monitored(url, type, [{params}])
- * Registers monitored resource to watch its availability. Supported types:
- *
- * - `dns`: DNS monitored object
- *
- * Params are optional table specific for each type. For DNS it supports the
- * following options:
- *
- * - `prefix`: prefix to add before making request
- * - `type`: type of request (e.g. 'a' or 'txt')
- * - `ipnet`: array of ip/networks to expect on reply
- * - `rcode`: expected return code (e.g. `nxdomain`)
- *
- * Returned object has the following methods:
- *
- * - `alive`: returns `true` if monitored resource is alive
- * - `offline`: returns number of seconds of the current offline period (or 0 if alive)
- * - `total_offline`: returns number of seconds of the overall offline
- * - `latency`: returns the current average latency in seconds (or 0 if offline)
- *
- * @param {string} url resource to monitor
- * @param {string} type type of monitoring
- * @param {table} opts optional parameters
- * @return {rspamd_monitored} rspamd monitored object
- */
- LUA_FUNCTION_DEF(config, register_monitored);
-
- /***
- * @method rspamd_config:add_doc(path, option, doc_string, [{params}])
- * Adds new documentation string for an option `option` at path `path`
- * Options defines optional params, such as:
- *
- * - `default`: default option value
- * - `type`: type of an option (`string`, `number`, `object`, `array` etc)
- * - `required`: if an option is required
- *
- * @param {string} path documentation path (e.g. module name)
- * @param {string} option name of the option
- * @param {string} doc_string documentation string
- * @param {table} params optional parameters
- */
- LUA_FUNCTION_DEF(config, add_doc);
-
- /***
- * @method rspamd_config:add_example(path, option, doc_string, example)
- * Adds new documentation
- *
- * @param {string} path documentation path (e.g. module name or nil for top)
- * @param {string} option name of the option
- * @param {string} doc_string documentation string
- * @param {string} example example in ucl format, comments are also parsed
- */
- LUA_FUNCTION_DEF(config, add_example);
-
- /***
- * @method rspamd_config:set_peak_cb(function)
- * Sets a function that will be called when frequency of some symbol goes out of
- * stddev * 2 over the last period of refreshment.
- *
- * @example
- rspamd_config:set_peak_cb(function(ev_base, sym, mean, stddev, value, error)
- -- ev_base: event base for async events (e.g. redis)
- -- sym: symbol's name
- -- mean: mean frequency value
- -- stddev: standard deviation of frequency
- -- value: current frequency value
- -- error: squared error
- local logger = require "rspamd_logger"
- logger.infox(rspamd_config, "symbol %s has changed frequency significantly: %s(%s) over %s(%s)",
- sym, value, error, mean, stddev)
- end)
- */
- LUA_FUNCTION_DEF(config, set_peak_cb);
- /***
- * @method rspamd_config:get_cpu_flags()
- * Returns architecture dependent flags supported by the CPU
- * Currently, only x86 flags are supported:
- * - 'ssse3'
- * - 'sse42'
- * - 'avx'
- * - 'avx2'
- * @return {table} flag -> true table
- */
- LUA_FUNCTION_DEF(config, get_cpu_flags);
-
- /***
- * @method rspamd_config:has_torch()
- * Returns true if Rspamd is compiled with torch support and the runtime CPU
- * supports sse4.2 required for torch.
- * @return {boolean} true if torch is compiled and supported
- */
- LUA_FUNCTION_DEF(config, has_torch);
-
- /***
- * @method rspamd_config:experimental_enabled()
- * Returns true if experimental plugins are enabled
- * @return {boolean} true if experimental plugins are enabled
- */
- LUA_FUNCTION_DEF(config, experimental_enabled);
-
- /***
- * @method rspamd_config:load_ucl(filename[, include_trace])
- * Loads config from the UCL file (but does not perform parsing using rcl)
- * @param {string} filename file to load
- * @return true or false + error message
- */
- LUA_FUNCTION_DEF(config, load_ucl);
-
- /***
- * @method rspamd_config:parse_rcl([skip_sections])
- * Parses RCL using loaded ucl file
- * @param {table|string} sections to skip
- * @return true or false + error message
- */
- LUA_FUNCTION_DEF(config, parse_rcl);
-
- /***
- * @method rspamd_config:init_modules()
- * Initialize lua and internal modules
- * @return true or false
- */
- LUA_FUNCTION_DEF(config, init_modules);
-
- /***
- * @method rspamd_config:init_subsystem(str)
- * Initialize config subsystem from a comma separated list:
- * - `modules` - init modules
- * - `langdet` - language detector
- * - `dns` - DNS resolver
- * - TODO: add more
- */
- LUA_FUNCTION_DEF(config, init_subsystem);
-
- /***
- * @method rspamd_config:get_tld_path()
- * Returns path to TLD file
- * @return {string} path to tld file
- */
- LUA_FUNCTION_DEF(config, get_tld_path);
-
- /***
- * @method rspamd_config:get_dns_max_requests()
- * Returns limit of DNS requests per task
- * @return {number} number of dns requests allowed
- */
- LUA_FUNCTION_DEF(config, get_dns_max_requests);
-
- /***
- * @method rspamd_config:get_dns_timeout()
- * Returns timeout for a DNS request
- * @return {number} DNS timeout in second or 0 if not defined
- */
- LUA_FUNCTION_DEF(config, get_dns_timeout);
-
- static const struct luaL_reg configlib_m[] = {
- LUA_INTERFACE_DEF(config, get_module_opt),
- LUA_INTERFACE_DEF(config, get_mempool),
- LUA_INTERFACE_DEF(config, get_resolver),
- LUA_INTERFACE_DEF(config, get_all_opt),
- LUA_INTERFACE_DEF(config, get_ucl),
- LUA_INTERFACE_DEF(config, add_radix_map),
- LUA_INTERFACE_DEF(config, radix_from_config),
- LUA_INTERFACE_DEF(config, radix_from_ucl),
- LUA_INTERFACE_DEF(config, add_hash_map),
- LUA_INTERFACE_DEF(config, add_kv_map),
- LUA_INTERFACE_DEF(config, add_map),
- LUA_INTERFACE_DEF(config, get_maps),
- LUA_INTERFACE_DEF(config, get_classifier),
- LUA_INTERFACE_DEF(config, register_symbol),
- LUA_INTERFACE_DEF(config, register_symbols),
- LUA_INTERFACE_DEF(config, register_virtual_symbol),
- LUA_INTERFACE_DEF(config, register_callback_symbol),
- LUA_INTERFACE_DEF(config, register_callback_symbol_priority),
- LUA_INTERFACE_DEF(config, register_dependency),
- LUA_INTERFACE_DEF(config, register_settings_id),
- LUA_INTERFACE_DEF(config, get_symbol_flags),
- LUA_INTERFACE_DEF(config, set_metric_symbol),
- {"set_symbol", lua_config_set_metric_symbol},
- LUA_INTERFACE_DEF(config, set_metric_action),
- {"set_action", lua_config_set_metric_action},
- {"get_metric_symbol", lua_config_get_symbol},
- LUA_INTERFACE_DEF(config, get_metric_action),
- {"get_action", lua_config_get_metric_action},
- LUA_INTERFACE_DEF(config, get_all_actions),
- LUA_INTERFACE_DEF(config, add_composite),
- LUA_INTERFACE_DEF(config, register_module_option),
- LUA_INTERFACE_DEF(config, register_pre_filter),
- LUA_INTERFACE_DEF(config, register_post_filter),
- LUA_INTERFACE_DEF(config, get_api_version),
- LUA_INTERFACE_DEF(config, get_key),
- LUA_INTERFACE_DEF(config, add_condition),
- LUA_INTERFACE_DEF(config, enable_symbol),
- LUA_INTERFACE_DEF(config, disable_symbol),
- LUA_INTERFACE_DEF(config, register_regexp),
- LUA_INTERFACE_DEF(config, replace_regexp),
- LUA_INTERFACE_DEF(config, register_worker_script),
- LUA_INTERFACE_DEF(config, register_re_selector),
- LUA_INTERFACE_DEF(config, add_on_load),
- LUA_INTERFACE_DEF(config, add_periodic),
- LUA_INTERFACE_DEF(config, add_post_init),
- LUA_INTERFACE_DEF(config, add_config_unload),
- LUA_INTERFACE_DEF(config, get_symbols_count),
- LUA_INTERFACE_DEF(config, get_symbols_cksum),
- LUA_INTERFACE_DEF(config, get_symbols_counters),
- {"get_symbols_scores", lua_config_get_symbols},
- LUA_INTERFACE_DEF(config, get_symbols),
- LUA_INTERFACE_DEF(config, get_symbol),
- LUA_INTERFACE_DEF(config, get_groups),
- LUA_INTERFACE_DEF(config, get_symbol_callback),
- LUA_INTERFACE_DEF(config, set_symbol_callback),
- LUA_INTERFACE_DEF(config, get_symbol_stat),
- LUA_INTERFACE_DEF(config, get_symbol_parent),
- LUA_INTERFACE_DEF(config, get_group_symbols),
- LUA_INTERFACE_DEF(config, register_finish_script),
- LUA_INTERFACE_DEF(config, register_monitored),
- LUA_INTERFACE_DEF(config, add_doc),
- LUA_INTERFACE_DEF(config, add_example),
- LUA_INTERFACE_DEF(config, set_peak_cb),
- LUA_INTERFACE_DEF(config, get_cpu_flags),
- LUA_INTERFACE_DEF(config, has_torch),
- LUA_INTERFACE_DEF(config, experimental_enabled),
- LUA_INTERFACE_DEF(config, load_ucl),
- LUA_INTERFACE_DEF(config, parse_rcl),
- LUA_INTERFACE_DEF(config, init_modules),
- LUA_INTERFACE_DEF(config, init_subsystem),
- LUA_INTERFACE_DEF(config, get_tld_path),
- LUA_INTERFACE_DEF(config, get_dns_max_requests),
- LUA_INTERFACE_DEF(config, get_dns_timeout),
- {"__tostring", rspamd_lua_class_tostring},
- {"__newindex", lua_config_newindex},
- {NULL, NULL}};
-
- LUA_FUNCTION_DEF(monitored, alive);
- LUA_FUNCTION_DEF(monitored, latency);
- LUA_FUNCTION_DEF(monitored, offline);
- LUA_FUNCTION_DEF(monitored, total_offline);
-
- static const struct luaL_reg monitoredlib_m[] = {
- LUA_INTERFACE_DEF(monitored, alive),
- LUA_INTERFACE_DEF(monitored, latency),
- LUA_INTERFACE_DEF(monitored, offline),
- LUA_INTERFACE_DEF(monitored, total_offline),
- {"__tostring", rspamd_lua_class_tostring},
- {NULL, NULL}};
-
- static const guint64 rspamd_lua_callback_magic = 0x32c118af1e3263c7ULL;
-
- struct rspamd_config *
- lua_check_config(lua_State *L, gint pos)
- {
- void *ud = rspamd_lua_check_udata(L, pos, "rspamd{config}");
- luaL_argcheck(L, ud != NULL, pos, "'config' expected");
- return ud ? *((struct rspamd_config **) ud) : NULL;
- }
-
- static struct rspamd_monitored *
- lua_check_monitored(lua_State *L, gint pos)
- {
- void *ud = rspamd_lua_check_udata(L, pos, "rspamd{monitored}");
- luaL_argcheck(L, ud != NULL, pos, "'monitored' expected");
- return ud ? *((struct rspamd_monitored **) ud) : NULL;
- }
-
- /*** Config functions ***/
- static gint
- lua_config_get_api_version(lua_State *L)
- {
- msg_warn("get_api_version is deprecated, do not use it");
- lua_pushnumber(L, 100);
-
- return 1;
- }
-
- static gint
- lua_config_get_module_opt(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *mname, *optname;
- const ucl_object_t *obj;
-
- if (cfg) {
- mname = luaL_checkstring(L, 2);
- optname = luaL_checkstring(L, 3);
-
- if (mname && optname) {
- obj = rspamd_config_get_module_opt(cfg, mname, optname);
- if (obj) {
- return ucl_object_push_lua(L, obj, TRUE);
- }
- }
- }
- lua_pushnil(L);
- return 1;
- }
-
- static int
- lua_config_get_mempool(lua_State *L)
- {
- LUA_TRACE_POINT;
- rspamd_mempool_t **ppool;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL) {
- ppool = lua_newuserdata(L, sizeof(rspamd_mempool_t *));
- rspamd_lua_setclass(L, "rspamd{mempool}", -1);
- *ppool = cfg->cfg_pool;
- }
- else {
- lua_pushnil(L);
- }
- return 1;
- }
-
- static int
- lua_config_get_resolver(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_dns_resolver **pres;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL && cfg->dns_resolver) {
- pres = lua_newuserdata(L, sizeof(*pres));
- rspamd_lua_setclass(L, "rspamd{resolver}", -1);
- *pres = cfg->dns_resolver;
- }
- else {
- lua_pushnil(L);
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_all_opt(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *mname;
- const ucl_object_t *obj, *cur, *cur_elt;
- ucl_object_iter_t it = NULL;
- gint i;
-
- if (cfg) {
- mname = luaL_checkstring(L, 2);
-
- if (mname) {
- obj = ucl_obj_get_key(cfg->cfg_ucl_obj, mname);
- /* Flatten object */
- if (obj != NULL && (ucl_object_type(obj) == UCL_OBJECT ||
- ucl_object_type(obj) == UCL_ARRAY)) {
-
- lua_newtable(L);
- it = ucl_object_iterate_new(obj);
-
- LL_FOREACH(obj, cur)
- {
- it = ucl_object_iterate_reset(it, cur);
-
- while ((cur_elt = ucl_object_iterate_safe(it, true))) {
- lua_pushstring(L, ucl_object_key(cur_elt));
- ucl_object_push_lua(L, cur_elt, true);
- lua_settable(L, -3);
- }
- }
-
- ucl_object_iterate_free(it);
-
- return 1;
- }
- else if (obj != NULL) {
- lua_newtable(L);
- i = 1;
-
- LL_FOREACH(obj, cur)
- {
- lua_pushinteger(L, i++);
- ucl_object_push_lua(L, cur, true);
- lua_settable(L, -3);
- }
-
- return 1;
- }
- }
- }
- lua_pushnil(L);
-
- return 1;
- }
-
- struct rspamd_lua_cached_config {
- lua_State *L;
- gint ref;
- };
-
- static void
- lua_config_ucl_dtor(gpointer p)
- {
- struct rspamd_lua_cached_config *cached = p;
-
- luaL_unref(cached->L, LUA_REGISTRYINDEX, cached->ref);
- }
-
- static gint
- lua_config_get_ucl(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_lua_cached_config *cached;
-
- if (cfg) {
- cached = rspamd_mempool_get_variable(cfg->cfg_pool, "ucl_cached");
-
- if (cached) {
- lua_rawgeti(L, LUA_REGISTRYINDEX, cached->ref);
- }
- else {
- if (cfg->cfg_ucl_obj) {
- ucl_object_push_lua(L, cfg->cfg_ucl_obj, true);
- lua_pushvalue(L, -1);
- cached = rspamd_mempool_alloc(cfg->cfg_pool, sizeof(*cached));
- cached->L = L;
- cached->ref = luaL_ref(L, LUA_REGISTRYINDEX);
- rspamd_mempool_set_variable(cfg->cfg_pool, "ucl_cached",
- cached, lua_config_ucl_dtor);
- }
- else {
- lua_pushnil(L);
- }
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
-
- static gint
- lua_config_get_classifier(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_classifier_config *clc = NULL, **pclc = NULL;
- const gchar *name;
- GList *cur;
-
- if (cfg) {
- name = luaL_checkstring(L, 2);
-
- cur = g_list_first(cfg->classifiers);
- while (cur) {
- clc = cur->data;
- if (g_ascii_strcasecmp(clc->name, name) == 0) {
- pclc = &clc;
- break;
- }
- cur = g_list_next(cur);
- }
- if (pclc) {
- pclc = lua_newuserdata(L,
- sizeof(struct rspamd_classifier_config *));
- rspamd_lua_setclass(L, "rspamd{classifier}", -1);
- *pclc = clc;
- return 1;
- }
- }
-
- lua_pushnil(L);
- return 1;
- }
-
- struct lua_callback_data {
- guint64 magic;
- lua_State *L;
- gchar *symbol;
-
- union {
- gchar *name;
- gint ref;
- } callback;
- gboolean cb_is_ref;
-
- /* Dynamic data */
- gint stack_level;
- gint order;
- struct rspamd_symcache_dynamic_item *item;
- };
-
- /*
- * Unref symbol if it is local reference
- */
- static void
- lua_destroy_cfg_symbol(gpointer ud)
- {
- struct lua_callback_data *cd = ud;
-
- /* Unref callback */
- if (cd->cb_is_ref) {
- luaL_unref(cd->L, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- }
-
- static gint
- lua_config_register_module_option(lua_State *L)
- {
- return 0;
- }
-
- static gint
- rspamd_compare_order_func(gconstpointer a, gconstpointer b)
- {
- const struct lua_callback_data *cb1 = a, *cb2 = b;
-
- /* order of call goes from lower to higher */
- return cb2->order - cb1->order;
- }
-
- static void
- lua_metric_symbol_callback(struct rspamd_task *task,
- struct rspamd_symcache_dynamic_item *item,
- gpointer ud)
- {
- struct lua_callback_data *cd = ud;
- struct rspamd_task **ptask;
- gint level = lua_gettop(cd->L), nresults, err_idx, ret;
- lua_State *L = cd->L;
- struct rspamd_symbol_result *s;
-
- cd->item = item;
- rspamd_symcache_item_async_inc(task, item, "lua symbol");
- lua_pushcfunction(L, &rspamd_lua_traceback);
- err_idx = lua_gettop(L);
-
- level++;
-
- if (cd->cb_is_ref) {
- lua_rawgeti(L, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- else {
- lua_getglobal(L, cd->callback.name);
- }
-
- ptask = lua_newuserdata(L, sizeof(struct rspamd_task *));
- rspamd_lua_setclass(L, rspamd_task_classname, -1);
- *ptask = task;
-
- if ((ret = lua_pcall(L, 1, LUA_MULTRET, err_idx)) != 0) {
- msg_err_task("call to (%s) failed (%d): %s", cd->symbol, ret,
- lua_tostring(L, -1));
- lua_settop(L, err_idx); /* Not -1 here, as err_func is popped below */
- }
- else {
- nresults = lua_gettop(L) - level;
-
- if (nresults >= 1) {
- /* Function returned boolean, so maybe we need to insert result? */
- gint res = 0;
- gint i;
- gdouble flag = 1.0;
- gint type;
-
- type = lua_type(cd->L, level + 1);
-
- if (type == LUA_TBOOLEAN) {
- res = lua_toboolean(L, level + 1);
- }
- else if (type == LUA_TNUMBER) {
- res = lua_tonumber(L, level + 1);
- }
- else if (type == LUA_TNIL) {
- /* Can happen sometimes... */
- res = FALSE;
- }
- else {
- /* Something bogus has been returned, so we should log it */
- msg_err_task("invalid return value for %s: %s",
- cd->symbol, lua_typename(L, type));
- res = FALSE;
- }
-
- if (res) {
- gint first_opt = 2;
-
- if (lua_type(L, level + 2) == LUA_TNUMBER) {
- flag = lua_tonumber(L, level + 2);
- /* Shift opt index */
- first_opt = 3;
- }
- else {
- flag = res;
- }
-
- s = rspamd_task_insert_result(task, cd->symbol, flag, NULL);
-
- if (s) {
- guint last_pos = lua_gettop(L);
-
- for (i = level + first_opt; i <= last_pos; i++) {
- if (lua_type(L, i) == LUA_TSTRING) {
- gsize optlen;
- const char *opt = lua_tolstring(L, i, &optlen);
-
- rspamd_task_add_result_option(task, s, opt, optlen);
- }
- else if (lua_type(L, i) == LUA_TUSERDATA) {
- struct rspamd_lua_text *t = lua_check_text(L, i);
-
- if (t) {
- rspamd_task_add_result_option(task, s, t->start,
- t->len);
- }
- }
- else if (lua_type(L, i) == LUA_TTABLE) {
- gsize objlen = rspamd_lua_table_size(L, i);
-
- for (guint j = 1; j <= objlen; j++) {
- lua_rawgeti(L, i, j);
-
- if (lua_type(L, -1) == LUA_TSTRING) {
- gsize optlen;
- const char *opt = lua_tolstring(L, -1, &optlen);
-
- rspamd_task_add_result_option(task, s, opt, optlen);
- }
- else if (lua_type(L, -1) == LUA_TUSERDATA) {
- struct rspamd_lua_text *t = lua_check_text(L, -1);
-
- if (t) {
- rspamd_task_add_result_option(task, s, t->start,
- t->len);
- }
- }
-
- lua_pop(L, 1);
- }
- }
- }
- }
- }
-
- lua_pop(L, nresults);
- }
- }
-
- lua_pop(L, 1); /* Error function */
- rspamd_symcache_item_async_dec_check(task, cd->item, "lua symbol");
- g_assert(lua_gettop(L) == level - 1);
- }
-
- static void lua_metric_symbol_callback_return(struct thread_entry *thread_entry,
- int ret);
-
- static void lua_metric_symbol_callback_error(struct thread_entry *thread_entry,
- int ret,
- const char *msg);
-
- static void
- lua_metric_symbol_callback_coro(struct rspamd_task *task,
- struct rspamd_symcache_dynamic_item *item,
- gpointer ud)
- {
- struct lua_callback_data *cd = ud;
- struct rspamd_task **ptask;
- struct thread_entry *thread_entry;
-
- cd->item = item;
- rspamd_symcache_item_async_inc(task, item, "lua coro symbol");
- thread_entry = lua_thread_pool_get_for_task(task);
-
- g_assert(thread_entry->cd == NULL);
- thread_entry->cd = cd;
-
- lua_State *thread = thread_entry->lua_state;
- cd->stack_level = lua_gettop(thread);
-
- if (cd->cb_is_ref) {
- lua_rawgeti(thread, LUA_REGISTRYINDEX, cd->callback.ref);
- }
- else {
- lua_getglobal(thread, cd->callback.name);
- }
-
- ptask = lua_newuserdata(thread, sizeof(struct rspamd_task *));
- rspamd_lua_setclass(thread, rspamd_task_classname, -1);
- *ptask = task;
-
- thread_entry->finish_callback = lua_metric_symbol_callback_return;
- thread_entry->error_callback = lua_metric_symbol_callback_error;
-
- lua_thread_call(thread_entry, 1);
- }
-
- static void
- lua_metric_symbol_callback_error(struct thread_entry *thread_entry,
- int ret,
- const char *msg)
- {
- struct lua_callback_data *cd = thread_entry->cd;
- struct rspamd_task *task = thread_entry->task;
- msg_err_task("call to coroutine (%s) failed (%d): %s", cd->symbol, ret, msg);
-
- rspamd_symcache_item_async_dec_check(task, cd->item, "lua coro symbol");
- }
-
- static void
- lua_metric_symbol_callback_return(struct thread_entry *thread_entry, int ret)
- {
- struct lua_callback_data *cd = thread_entry->cd;
- struct rspamd_task *task = thread_entry->task;
- int nresults;
- struct rspamd_symbol_result *s;
-
- (void) ret;
-
- lua_State *L = thread_entry->lua_state;
-
- nresults = lua_gettop(L) - cd->stack_level;
-
- if (nresults >= 1) {
- /* Function returned boolean, so maybe we need to insert result? */
- gint res = 0;
- gint i;
- gdouble flag = 1.0;
- gint type;
-
- type = lua_type(L, cd->stack_level + 1);
-
- if (type == LUA_TBOOLEAN) {
- res = lua_toboolean(L, cd->stack_level + 1);
- }
- else if (type == LUA_TFUNCTION) {
- g_assert_not_reached();
- }
- else {
- res = lua_tonumber(L, cd->stack_level + 1);
- }
-
- if (res) {
- gint first_opt = 2;
-
- if (lua_type(L, cd->stack_level + 2) == LUA_TNUMBER) {
- flag = lua_tonumber(L, cd->stack_level + 2);
- /* Shift opt index */
- first_opt = 3;
- }
- else {
- flag = res;
- }
-
- s = rspamd_task_insert_result(task, cd->symbol, flag, NULL);
-
- if (s) {
- guint last_pos = lua_gettop(L);
-
- for (i = cd->stack_level + first_opt; i <= last_pos; i++) {
- if (lua_type(L, i) == LUA_TSTRING) {
- gsize optlen;
- const char *opt = lua_tolstring(L, i, &optlen);
-
- rspamd_task_add_result_option(task, s, opt, optlen);
- }
- else if (lua_type(L, i) == LUA_TUSERDATA) {
- struct rspamd_lua_text *t = lua_check_text(L, i);
-
- if (t) {
- rspamd_task_add_result_option(task, s, t->start,
- t->len);
- }
- }
- else if (lua_type(L, i) == LUA_TTABLE) {
- gsize objlen = rspamd_lua_table_size(L, i);
-
- for (guint j = 1; j <= objlen; j++) {
- lua_rawgeti(L, i, j);
-
- if (lua_type(L, -1) == LUA_TSTRING) {
- gsize optlen;
- const char *opt = lua_tolstring(L, -1, &optlen);
-
- rspamd_task_add_result_option(task, s, opt, optlen);
- }
- else if (lua_type(L, -1) == LUA_TUSERDATA) {
- struct rspamd_lua_text *t = lua_check_text(L, -1);
-
- if (t) {
- rspamd_task_add_result_option(task, s, t->start,
- t->len);
- }
- }
-
- lua_pop(L, 1);
- }
- }
- }
- }
- }
-
- lua_pop(L, nresults);
- }
-
- g_assert(lua_gettop(L) == cd->stack_level); /* we properly cleaned up the stack */
-
- cd->stack_level = 0;
- rspamd_symcache_item_async_dec_check(task, cd->item, "lua coro symbol");
- }
-
- static GArray *
- rspamd_process_id_list(const gchar *entries)
- {
- gchar **sym_elts;
- GArray *ret;
-
- sym_elts = g_strsplit_set(entries, ",;", -1);
- guint nids = g_strv_length(sym_elts);
- ret = g_array_sized_new(FALSE, FALSE, sizeof(guint32), nids);
-
- for (guint i = 0; i < nids; i++) {
- guint32 v = rspamd_config_name_to_id(sym_elts[i], strlen(sym_elts[i]));
- g_array_append_val(ret, v);
- }
-
- g_strfreev(sym_elts);
-
- return ret;
- }
-
- static gint
- rspamd_register_symbol_fromlua(lua_State *L,
- struct rspamd_config *cfg,
- const gchar *name,
- gint ref,
- gdouble weight,
- gint priority,
- enum rspamd_symbol_type type,
- gint parent,
- GArray *allowed_ids,
- GArray *forbidden_ids,
- gboolean optional)
- {
- struct lua_callback_data *cd;
- gint ret = -1;
-
- if (priority == 0 && weight < 0) {
- priority = 1;
- }
-
- if ((ret = rspamd_symcache_find_symbol(cfg->cache, name)) != -1) {
- if (optional) {
- msg_debug_config("duplicate symbol: %s, skip registering", name);
-
- return ret;
- }
- else {
- msg_err_config("duplicate symbol: %s, skip registering", name);
-
- return -1;
- }
- }
-
- if (allowed_ids && !(type & SYMBOL_TYPE_EXPLICIT_DISABLE)) {
- /* Mark symbol as explicit allow */
- msg_info_config("mark symbol %s as explicit enable as its execution is"
- "allowed merely on specific settings ids",
- name);
- type |= SYMBOL_TYPE_EXPLICIT_ENABLE;
- }
-
- if (ref != -1) {
- cd = rspamd_mempool_alloc0(cfg->cfg_pool,
- sizeof(struct lua_callback_data));
- cd->magic = rspamd_lua_callback_magic;
- cd->cb_is_ref = TRUE;
- cd->callback.ref = ref;
- cd->L = L;
-
- if (name) {
- cd->symbol = rspamd_mempool_strdup(cfg->cfg_pool, name);
- }
-
- if (type & SYMBOL_TYPE_USE_CORO) {
- ret = rspamd_symcache_add_symbol(cfg->cache,
- name,
- priority,
- lua_metric_symbol_callback_coro,
- cd,
- type,
- parent);
- }
- else {
- ret = rspamd_symcache_add_symbol(cfg->cache,
- name,
- priority,
- lua_metric_symbol_callback,
- cd,
- type,
- parent);
- }
- rspamd_mempool_add_destructor(cfg->cfg_pool,
- (rspamd_mempool_destruct_t) lua_destroy_cfg_symbol,
- cd);
- }
- else {
- /* No callback */
- ret = rspamd_symcache_add_symbol(cfg->cache,
- name,
- priority,
- NULL,
- NULL,
- type,
- parent);
- }
-
- if (allowed_ids) {
- rspamd_symcache_set_allowed_settings_ids(cfg->cache, name,
- &g_array_index(allowed_ids, guint32, 0), allowed_ids->len);
- }
-
- if (forbidden_ids) {
- rspamd_symcache_set_forbidden_settings_ids(cfg->cache, name,
- &g_array_index(forbidden_ids, guint32, 0), forbidden_ids->len);
- }
-
- return ret;
- }
-
- static gint
- lua_config_register_post_filter(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- gint order = 0, cbref, ret;
-
- if (cfg) {
- if (lua_type(L, 3) == LUA_TNUMBER) {
- order = lua_tonumber(L, 3);
- }
-
- if (lua_type(L, 2) == LUA_TFUNCTION) {
- lua_pushvalue(L, 2);
- /* Get a reference */
- cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- }
- else {
- return luaL_error(L, "invalid type for callback: %s",
- lua_typename(L, lua_type(L, 2)));
- }
-
- msg_warn_config("register_post_filter function is deprecated, "
- "use register_symbol instead");
-
- ret = rspamd_register_symbol_fromlua(L,
- cfg,
- NULL,
- cbref,
- 1.0,
- order,
- SYMBOL_TYPE_POSTFILTER | SYMBOL_TYPE_CALLBACK,
- -1,
- NULL, NULL,
- FALSE);
-
- lua_pushboolean(L, ret);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_register_pre_filter(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- gint order = 0, cbref, ret;
-
- if (cfg) {
- if (lua_type(L, 3) == LUA_TNUMBER) {
- order = lua_tonumber(L, 3);
- }
-
- if (lua_type(L, 2) == LUA_TFUNCTION) {
- lua_pushvalue(L, 2);
- /* Get a reference */
- cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- }
- else {
- return luaL_error(L, "invalid type for callback: %s",
- lua_typename(L, lua_type(L, 2)));
- }
-
- msg_warn_config("register_pre_filter function is deprecated, "
- "use register_symbol instead");
-
- ret = rspamd_register_symbol_fromlua(L,
- cfg,
- NULL,
- cbref,
- 1.0,
- order,
- SYMBOL_TYPE_PREFILTER | SYMBOL_TYPE_CALLBACK,
- -1,
- NULL, NULL,
- FALSE);
-
- lua_pushboolean(L, ret);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_key(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name;
- size_t namelen;
- const ucl_object_t *val;
-
- name = luaL_checklstring(L, 2, &namelen);
- if (name && cfg) {
- val = ucl_object_lookup_len(cfg->cfg_ucl_obj, name, namelen);
- if (val != NULL) {
- ucl_object_push_lua(L, val, val->type != UCL_ARRAY);
- }
- else {
- lua_pushnil(L);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static guint
- lua_parse_symbol_flags(const gchar *str)
- {
- guint ret = 0;
-
- if (str) {
- if (strstr(str, "fine") != NULL) {
- ret |= SYMBOL_TYPE_FINE;
- }
- if (strstr(str, "nice") != NULL) {
- ret |= SYMBOL_TYPE_FINE;
- }
- if (strstr(str, "empty") != NULL) {
- ret |= SYMBOL_TYPE_EMPTY;
- }
- if (strstr(str, "skip") != NULL) {
- ret |= SYMBOL_TYPE_SKIPPED;
- }
- if (strstr(str, "nostat") != NULL) {
- ret |= SYMBOL_TYPE_NOSTAT;
- }
- if (strstr(str, "idempotent") != NULL) {
- ret |= SYMBOL_TYPE_IDEMPOTENT;
- }
- if (strstr(str, "trivial") != NULL) {
- ret |= SYMBOL_TYPE_TRIVIAL;
- }
- if (strstr(str, "ghost") != NULL) {
- ret |= SYMBOL_TYPE_GHOST;
- }
- if (strstr(str, "mime") != NULL) {
- ret |= SYMBOL_TYPE_MIME_ONLY;
- }
- if (strstr(str, "ignore_passthrough") != NULL) {
- ret |= SYMBOL_TYPE_IGNORE_PASSTHROUGH;
- }
- if (strstr(str, "explicit_disable") != NULL) {
- ret |= SYMBOL_TYPE_EXPLICIT_DISABLE;
- }
- if (strstr(str, "explicit_enable") != NULL) {
- ret |= SYMBOL_TYPE_EXPLICIT_ENABLE;
- }
- if (strstr(str, "coro") != NULL) {
- ret |= SYMBOL_TYPE_USE_CORO;
- }
- }
-
- return ret;
- }
-
- static guint
- lua_parse_symbol_type(const gchar *str)
- {
- guint ret = SYMBOL_TYPE_NORMAL;
- gchar **vec;
- guint i, l;
-
- if (str) {
- vec = g_strsplit_set(str, ",;", -1);
-
- if (vec) {
- l = g_strv_length(vec);
-
- for (i = 0; i < l; i++) {
- str = vec[i];
-
- /* TODO: total shit, rework some day */
- if (g_ascii_strcasecmp(str, "virtual") == 0) {
- ret |= SYMBOL_TYPE_VIRTUAL;
- ret &= ~SYMBOL_TYPE_NORMAL;
- ret &= ~SYMBOL_TYPE_CALLBACK;
- }
- else if (g_ascii_strcasecmp(str, "callback") == 0) {
- ret |= SYMBOL_TYPE_CALLBACK;
- ret &= ~SYMBOL_TYPE_NORMAL;
- ret &= ~SYMBOL_TYPE_VIRTUAL;
- }
- else if (g_ascii_strcasecmp(str, "normal") == 0) {
- ret |= SYMBOL_TYPE_NORMAL;
- ret &= ~SYMBOL_TYPE_CALLBACK;
- ret &= ~SYMBOL_TYPE_VIRTUAL;
- }
- else if (g_ascii_strcasecmp(str, "prefilter") == 0) {
- ret |= SYMBOL_TYPE_PREFILTER | SYMBOL_TYPE_GHOST;
- }
- else if (g_ascii_strcasecmp(str, "postfilter") == 0) {
- ret |= SYMBOL_TYPE_POSTFILTER | SYMBOL_TYPE_GHOST;
- }
- else if (g_ascii_strcasecmp(str, "connfilter") == 0 ||
- g_ascii_strcasecmp(str, "conn_filter") == 0) {
- ret |= SYMBOL_TYPE_CONNFILTER | SYMBOL_TYPE_GHOST;
- }
- else if (g_ascii_strcasecmp(str, "idempotent") == 0) {
- ret |= SYMBOL_TYPE_GHOST |
- SYMBOL_TYPE_IDEMPOTENT | SYMBOL_TYPE_CALLBACK;
- }
- else {
- gint fl = 0;
-
- fl = lua_parse_symbol_flags(str);
-
- if (fl == 0) {
- msg_warn("bad type: %s", str);
- }
- else {
- ret |= fl;
- }
- }
- }
-
- g_strfreev(vec);
- }
- }
-
- return ret;
- }
-
- enum lua_push_symbol_flags_opts {
- LUA_SYMOPT_FLAG_CREATE_ARRAY = 1u << 0u,
- LUA_SYMOPT_FLAG_CREATE_MAP = 1u << 1u,
- LUA_SYMOPT_FLAG_USE_MAP = 1u << 2u,
- LUA_SYMOPT_FLAG_USE_ARRAY = 1u << 3u,
- };
-
- #define LUA_SYMOPT_IS_ARRAY(f) ((f) & (LUA_SYMOPT_FLAG_CREATE_ARRAY | LUA_SYMOPT_FLAG_USE_ARRAY))
- #define LUA_SYMOPT_IS_CREATE(f) ((f) & (LUA_SYMOPT_FLAG_CREATE_ARRAY | LUA_SYMOPT_FLAG_CREATE_MAP))
- #define LUA_OPTION_PUSH(nm) \
- do { \
- if (LUA_SYMOPT_IS_ARRAY(fl)) { \
- lua_pushstring(L, #nm); \
- lua_rawseti(L, -2, i++); \
- } \
- else { \
- lua_pushboolean(L, true); \
- lua_setfield(L, -2, #nm); \
- } \
- } while (0)
-
- static void
- lua_push_symbol_flags(lua_State *L, guint flags, enum lua_push_symbol_flags_opts fl)
- {
- guint i = 1;
-
- if (LUA_SYMOPT_IS_CREATE(fl)) {
- lua_newtable(L);
- }
-
- if (flags & SYMBOL_TYPE_FINE) {
- LUA_OPTION_PUSH(fine);
- }
-
- if (flags & SYMBOL_TYPE_EMPTY) {
- LUA_OPTION_PUSH(empty);
- }
-
- if (flags & SYMBOL_TYPE_EXPLICIT_DISABLE) {
- LUA_OPTION_PUSH(explicit_disable);
- }
-
- if (flags & SYMBOL_TYPE_EXPLICIT_ENABLE) {
- LUA_OPTION_PUSH(explicit_enable);
- }
-
- if (flags & SYMBOL_TYPE_IGNORE_PASSTHROUGH) {
- LUA_OPTION_PUSH(ignore_passthrough);
- }
-
- if (flags & SYMBOL_TYPE_NOSTAT) {
- LUA_OPTION_PUSH(nostat);
- }
-
- if (flags & SYMBOL_TYPE_IDEMPOTENT) {
- LUA_OPTION_PUSH(idempotent);
- }
-
- if (flags & SYMBOL_TYPE_MIME_ONLY) {
- LUA_OPTION_PUSH(mime);
- }
-
- if (flags & SYMBOL_TYPE_TRIVIAL) {
- LUA_OPTION_PUSH(trivial);
- }
-
- if (flags & SYMBOL_TYPE_SKIPPED) {
- LUA_OPTION_PUSH(skip);
- }
-
- if (flags & SYMBOL_TYPE_COMPOSITE) {
- LUA_OPTION_PUSH(composite);
- }
- }
-
- static gint
- lua_config_get_symbol_flags(lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name = luaL_checkstring(L, 2);
- guint flags;
-
- if (cfg && name) {
- flags = rspamd_symcache_get_symbol_flags(cfg->cache,
- name);
-
- if (flags != 0) {
- lua_push_symbol_flags(L, flags, LUA_SYMOPT_FLAG_CREATE_ARRAY);
- }
- else {
- lua_pushnil(L);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_register_symbol(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name = NULL, *type_str = NULL,
- *description = NULL, *group = NULL;
- double weight = 0, score = NAN, parent_float = NAN;
- gboolean one_shot = FALSE;
- gint ret = -1, cbref = -1;
- guint type = 0, flags = 0;
- gint64 parent = 0, priority = 0, nshots = 0;
- GArray *allowed_ids = NULL, *forbidden_ids = NULL;
- GError *err = NULL;
- int prev_top = lua_gettop(L);
-
- if (cfg) {
- if (!rspamd_lua_parse_table_arguments(L, 2, &err,
- RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
- "name=S;weight=N;callback=F;type=S;priority=I;parent=D;"
- "score=D;description=S;group=S;one_shot=B;nshots=I",
- &name, &weight, &cbref, &type_str,
- &priority, &parent_float,
- &score, &description, &group, &one_shot, &nshots)) {
- msg_err_config("bad arguments: %e", err);
- g_error_free(err);
- lua_settop(L, prev_top);
-
- return luaL_error(L, "invalid arguments");
- }
-
- /* Deal with flags and ids */
- lua_pushstring(L, "flags");
- lua_gettable(L, 2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- flags = lua_parse_symbol_flags(lua_tostring(L, -1));
- }
- else if (lua_type(L, -1) == LUA_TTABLE) {
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- flags |= lua_parse_symbol_flags(lua_tostring(L, -1));
- }
- }
- lua_pop(L, 1); /* Clean flags */
-
- lua_pushstring(L, "allowed_ids");
- lua_gettable(L, 2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- allowed_ids = rspamd_process_id_list(lua_tostring(L, -1));
- }
- else if (lua_type(L, -1) == LUA_TTABLE) {
- allowed_ids = g_array_sized_new(FALSE, FALSE, sizeof(guint32),
- rspamd_lua_table_size(L, -1));
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- guint32 v = lua_tointeger(L, -1);
- g_array_append_val(allowed_ids, v);
- }
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "forbidden_ids");
- lua_gettable(L, 2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- forbidden_ids = rspamd_process_id_list(lua_tostring(L, -1));
- }
- else if (lua_type(L, -1) == LUA_TTABLE) {
- forbidden_ids = g_array_sized_new(FALSE, FALSE, sizeof(guint32),
- rspamd_lua_table_size(L, -1));
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- guint32 v = lua_tointeger(L, -1);
- g_array_append_val(forbidden_ids, v);
- }
- }
- lua_pop(L, 1);
-
- if (nshots == 0) {
- nshots = cfg->default_max_shots;
- }
-
- type = lua_parse_symbol_type(type_str);
-
- if (!name && !(type & SYMBOL_TYPE_CALLBACK)) {
- lua_settop(L, prev_top);
- return luaL_error(L, "no symbol name but type is not callback");
- }
- else if (!(type & SYMBOL_TYPE_VIRTUAL) && cbref == -1) {
- lua_settop(L, prev_top);
- return luaL_error(L, "no callback for symbol %s", name);
- }
-
- if (isnan(parent_float)) {
- parent = -1;
- }
- else {
- parent = parent_float;
- }
-
- ret = rspamd_register_symbol_fromlua(L,
- cfg,
- name,
- cbref,
- weight == 0 ? 1.0 : weight,
- priority,
- type | flags,
- parent,
- allowed_ids, forbidden_ids,
- FALSE);
-
- if (allowed_ids) {
- g_array_free(allowed_ids, TRUE);
- }
-
- if (forbidden_ids) {
- g_array_free(forbidden_ids, TRUE);
- }
-
- if (ret != -1) {
- if (!isnan(score) || group) {
- if (one_shot) {
- nshots = 1;
- }
-
- rspamd_config_add_symbol(cfg, name,
- score, description, group, flags,
- 0, nshots);
-
- lua_pushstring(L, "groups");
- lua_gettable(L, 2);
-
- if (lua_istable(L, -1)) {
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- if (lua_isstring(L, -1)) {
- rspamd_config_add_symbol_group(cfg, name,
- lua_tostring(L, -1));
- }
- else {
- lua_settop(L, prev_top);
- return luaL_error(L, "invalid groups element");
- }
- }
- }
-
- lua_pop(L, 1);
- }
-
- lua_pushstring(L, "augmentations");
- lua_gettable(L, 2);
-
- if (lua_type(L, -1) == LUA_TTABLE) {
- int tbl_idx = lua_gettop(L);
- for (lua_pushnil(L); lua_next(L, tbl_idx); lua_pop(L, 1)) {
- size_t len;
- const char *augmentation = lua_tolstring(L, -1, &len), *eqsign_pos;
-
- /* Find `=` symbol and use it as a separator */
- eqsign_pos = memchr(augmentation, '=', len);
- if (eqsign_pos != NULL && eqsign_pos + 1 < augmentation + len) {
- rspamd_ftok_t tok;
-
- tok.begin = augmentation;
- tok.len = eqsign_pos - augmentation;
- char *augentation_name = rspamd_ftokdup(&tok);
-
- tok.begin = eqsign_pos + 1;
- tok.len = (augmentation + len) - tok.begin;
-
- char *augmentation_value = rspamd_ftokdup(&tok);
-
- if (!rspamd_symcache_add_symbol_augmentation(cfg->cache, ret,
- augentation_name, augmentation_value)) {
- lua_settop(L, prev_top);
- g_free(augmentation_value);
- g_free(augentation_name);
-
- return luaL_error(L, "unknown or invalid augmentation %s in symbol %s",
- augmentation, name);
- }
-
- g_free(augmentation_value);
- g_free(augentation_name);
- }
- else {
- /* Just a value */
- if (!rspamd_symcache_add_symbol_augmentation(cfg->cache, ret,
- augmentation, NULL)) {
- lua_settop(L, prev_top);
-
- return luaL_error(L, "unknown augmentation %s in symbol %s",
- augmentation, name);
- }
- }
- }
- }
- }
- }
- else {
- lua_settop(L, prev_top);
-
- return luaL_error(L, "invalid arguments");
- }
-
- lua_settop(L, prev_top);
- lua_pushinteger(L, ret);
-
- return 1;
- }
-
- static gint
- lua_config_register_symbols(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- gint i, top, idx, ret = -1;
- const gchar *sym;
- gdouble weight = 1.0;
-
- if (lua_gettop(L) < 3) {
- if (cfg) {
- msg_err_config("not enough arguments to register a function");
- }
-
- lua_error(L);
-
- return 0;
- }
- if (cfg) {
- if (lua_type(L, 2) == LUA_TSTRING) {
- lua_getglobal(L, luaL_checkstring(L, 2));
- }
- else {
- lua_pushvalue(L, 2);
- }
- idx = luaL_ref(L, LUA_REGISTRYINDEX);
-
- if (lua_type(L, 3) == LUA_TNUMBER) {
- weight = lua_tonumber(L, 3);
- top = 4;
- }
- else {
- top = 3;
- }
- sym = luaL_checkstring(L, top++);
- ret = rspamd_register_symbol_fromlua(L,
- cfg,
- sym,
- idx,
- weight,
- 0,
- SYMBOL_TYPE_CALLBACK,
- -1,
- NULL, NULL,
- FALSE);
-
- for (i = top; i <= lua_gettop(L); i++) {
- if (lua_type(L, i) == LUA_TTABLE) {
- lua_pushvalue(L, i);
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- lua_pushvalue(L, -2);
- sym = luaL_checkstring(L, -2);
- rspamd_symcache_add_symbol(cfg->cache, sym,
- 0, NULL, NULL,
- SYMBOL_TYPE_VIRTUAL, ret);
- lua_pop(L, 2);
- }
- lua_pop(L, 1);
- }
- else if (lua_type(L, i) == LUA_TSTRING) {
- sym = luaL_checkstring(L, i);
- rspamd_symcache_add_symbol(cfg->cache, sym,
- 0, NULL, NULL,
- SYMBOL_TYPE_VIRTUAL, ret);
- }
- }
- }
-
- lua_pushinteger(L, ret);
-
- return 1;
- }
-
- static gint
- lua_config_register_virtual_symbol(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name;
- double weight;
- gint ret = -1, parent = -1;
-
- if (cfg) {
- name = luaL_checkstring(L, 2);
- weight = luaL_checknumber(L, 3);
-
- if (lua_gettop(L) > 3) {
- parent = lua_tonumber(L, 4);
- }
-
- if (name) {
- ret = rspamd_symcache_add_symbol(cfg->cache, name,
- weight > 0 ? 0 : -1, NULL, NULL,
- SYMBOL_TYPE_VIRTUAL, parent);
- }
- }
-
- lua_pushinteger(L, ret);
-
- return 1;
- }
-
- static gint
- lua_config_register_callback_symbol(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name = NULL;
- double weight;
- gint ret = -1, top = 2;
-
- if (cfg) {
- if (lua_type(L, 2) == LUA_TSTRING) {
- /* Legacy syntax */
- name = luaL_checkstring(L, 2);
- top++;
- }
-
- weight = luaL_checknumber(L, top);
-
- if (lua_type(L, top + 1) == LUA_TSTRING) {
- lua_getglobal(L, luaL_checkstring(L, top + 1));
- }
- else {
- lua_pushvalue(L, top + 1);
- }
- ret = rspamd_register_symbol_fromlua(L,
- cfg,
- name,
- luaL_ref(L, LUA_REGISTRYINDEX),
- weight,
- 0,
- SYMBOL_TYPE_CALLBACK,
- -1,
- NULL, NULL,
- FALSE);
- }
-
- lua_pushinteger(L, ret);
-
- return 1;
- }
-
- static gint
- lua_config_register_callback_symbol_priority(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name = NULL;
- double weight;
- gint priority, ret = -1, top = 2;
-
- if (cfg) {
- if (lua_type(L, 2) == LUA_TSTRING) {
- /* Legacy syntax */
- name = luaL_checkstring(L, 2);
- top++;
- }
-
- weight = luaL_checknumber(L, top);
- priority = luaL_checknumber(L, top + 1);
-
- if (lua_type(L, top + 2) == LUA_TSTRING) {
- lua_getglobal(L, luaL_checkstring(L, top + 2));
- }
- else {
- lua_pushvalue(L, top + 2);
- }
-
- ret = rspamd_register_symbol_fromlua(L,
- cfg,
- name,
- luaL_ref(L, LUA_REGISTRYINDEX),
- weight,
- priority,
- SYMBOL_TYPE_CALLBACK,
- -1,
- NULL, NULL,
- FALSE);
- }
-
- lua_pushinteger(L, ret);
-
- return 1;
- }
-
-
- static gint
- lua_config_register_dependency(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *parent = NULL, *child = NULL;
- gint child_id;
-
- if (cfg == NULL) {
- lua_error(L);
- return 0;
- }
-
- if (lua_type(L, 2) == LUA_TNUMBER) {
- child_id = luaL_checknumber(L, 2);
- parent = luaL_checkstring(L, 3);
-
- return luaL_error(L, "calling for obsolete method to register deps for symbol %d->%s",
- child_id, parent);
- }
- else {
- child = luaL_checkstring(L, 2);
- parent = luaL_checkstring(L, 3);
-
- if (child != NULL && parent != NULL) {
- rspamd_symcache_add_delayed_dependency(cfg->cache, child,
- parent);
- }
- }
-
- return 0;
- }
-
- static gint
- lua_config_set_metric_symbol(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *description = NULL,
- *group = NULL, *name = NULL, *flags_str = NULL;
- double score;
- gboolean one_shot = FALSE, one_param = FALSE;
- GError *err = NULL;
- gdouble priority = 0.0;
- guint flags = 0;
- gint64 nshots = 0;
-
- if (cfg) {
-
- if (lua_type(L, 2) == LUA_TTABLE) {
- if (!rspamd_lua_parse_table_arguments(L, 2, &err,
- RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
- "*name=S;score=N;description=S;"
- "group=S;one_shot=B;one_param=B;priority=N;flags=S;"
- "nshots=I",
- &name, &score, &description,
- &group, &one_shot, &one_param,
- &priority, &flags_str, &nshots)) {
- msg_err_config("bad arguments: %e", err);
- g_error_free(err);
-
- return 0;
- }
- }
- else {
- name = luaL_checkstring(L, 2);
- score = luaL_checknumber(L, 3);
-
- if (lua_gettop(L) > 3 && lua_type(L, 4) == LUA_TSTRING) {
- description = luaL_checkstring(L, 4);
- }
- if (lua_gettop(L) > 4 && lua_type(L, 5) == LUA_TSTRING) {
- /* XXX: metrics */
- }
- if (lua_gettop(L) > 5 && lua_type(L, 6) == LUA_TSTRING) {
- group = luaL_checkstring(L, 6);
- }
- if (lua_gettop(L) > 6 && lua_type(L, 7) == LUA_TBOOLEAN) {
- one_shot = lua_toboolean(L, 7);
- }
- }
-
- if (nshots == 0) {
- nshots = cfg->default_max_shots;
- }
-
- if (one_shot) {
- nshots = 1;
- }
- if (one_param) {
- flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM;
- }
-
- if (flags_str) {
- if (strstr(flags_str, "one_shot") != NULL) {
- nshots = 1;
- }
- if (strstr(flags_str, "ignore") != NULL) {
- flags |= RSPAMD_SYMBOL_FLAG_IGNORE_METRIC;
- }
- if (strstr(flags_str, "one_param") != NULL) {
- flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM;
- }
- }
-
- rspamd_config_add_symbol(cfg, name,
- score, description, group, flags, (guint) priority, nshots);
-
-
- if (lua_type(L, 2) == LUA_TTABLE) {
- lua_pushstring(L, "groups");
- lua_gettable(L, 2);
-
- if (lua_istable(L, -1)) {
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- if (lua_isstring(L, -1)) {
- rspamd_config_add_symbol_group(cfg, name,
- lua_tostring(L, -1));
- }
- else {
- return luaL_error(L, "invalid groups element");
- }
- }
- }
-
- lua_pop(L, 1);
- }
- }
- else {
- return luaL_error(L, "invalid arguments, rspamd_config expected");
- }
-
- return 0;
- }
-
- static gint
- lua_config_set_metric_action(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name = NULL;
- double threshold = NAN;
- GError *err = NULL;
- gdouble priority = 0.0;
- ucl_object_t *obj_tbl = NULL;
-
- if (cfg) {
-
- if (lua_type(L, 2) == LUA_TTABLE) {
- if (!rspamd_lua_parse_table_arguments(L, 2, &err,
- RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
- "*action=S;score=N;"
- "priority=N",
- &name, &threshold,
- &priority)) {
- msg_err_config("bad arguments: %e", err);
- g_error_free(err);
-
- return 0;
- }
- }
- else if (lua_type(L, 2) == LUA_TSTRING && lua_type(L, 3) == LUA_TTABLE) {
- name = lua_tostring(L, 2);
- obj_tbl = ucl_object_lua_import(L, 3);
-
- if (obj_tbl) {
- if (name) {
- rspamd_config_set_action_score(cfg, name, obj_tbl);
- ucl_object_unref(obj_tbl);
- }
- else {
- ucl_object_unref(obj_tbl);
- return luaL_error(L, "invalid first argument, action name expected");
- }
- }
- else {
- return luaL_error(L, "invalid second argument, table expected");
- }
- }
- else {
- return luaL_error(L, "invalid arguments, table expected");
- }
-
- if (name != NULL && !isnan(threshold) && threshold != 0) {
- obj_tbl = ucl_object_typed_new(UCL_OBJECT);
- ucl_object_insert_key(obj_tbl, ucl_object_fromdouble(threshold),
- "score", 0, false);
- ucl_object_insert_key(obj_tbl, ucl_object_fromdouble(priority),
- "priority", 0, false);
- rspamd_config_set_action_score(cfg, name, obj_tbl);
- ucl_object_unref(obj_tbl);
- }
- }
- else {
- return luaL_error(L, "invalid arguments, rspamd_config expected");
- }
-
- return 0;
- }
-
- static gint
- lua_config_get_metric_action(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *act_name = luaL_checkstring(L, 2);
- struct rspamd_action *act;
-
- if (cfg && act_name) {
- act = rspamd_config_get_action(cfg, act_name);
-
- if (act) {
- if (!isnan(act->threshold)) {
- lua_pushnumber(L, act->threshold);
- }
- else {
- lua_pushnil(L);
- }
- }
- else {
- lua_pushnil(L);
- }
- }
- else {
- return luaL_error(L, "invalid arguments, rspamd_config expected");
- }
-
- return 1;
- }
-
- static void
- lua_config_actions_cb(struct rspamd_action *act, void *cbd)
- {
- lua_State *L = (lua_State *) cbd;
-
- if (!isnan(act->threshold)) {
- lua_pushstring(L, act->name);
- lua_pushnumber(L, act->threshold);
- lua_settable(L, -3);
- }
- }
-
- static gint
- lua_config_get_all_actions(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg) {
- lua_createtable(L, 0, rspamd_config_actions_size(cfg));
- rspamd_config_actions_foreach(cfg, lua_config_actions_cb, L);
- }
- else {
- return luaL_error(L, "invalid arguments, rspamd_config expected");
- }
-
- return 1;
- }
-
- static gint
- lua_config_add_composite(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- gchar *name;
- const gchar *expr_str;
- struct rspamd_composite *composite;
- gboolean ret = FALSE;
-
- if (cfg) {
- name = rspamd_mempool_strdup(cfg->cfg_pool, luaL_checkstring(L, 2));
- expr_str = luaL_checkstring(L, 3);
-
- if (name && expr_str) {
- composite = rspamd_composites_manager_add_from_string(cfg->composites_manager,
- name, expr_str);
-
- if (composite) {
- rspamd_symcache_add_symbol(cfg->cache, name,
- 0, NULL, composite, SYMBOL_TYPE_COMPOSITE, -1);
- ret = TRUE;
- }
- }
- }
-
- lua_pushboolean(L, ret);
-
- return 1;
- }
-
- static gint
- lua_config_newindex(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name;
- GArray *allowed_ids = NULL, *forbidden_ids = NULL;
- gint id, nshots;
- guint flags = 0;
- gboolean optional = FALSE;
-
- name = luaL_checkstring(L, 2);
-
- if (cfg != NULL && name != NULL && lua_gettop(L) == 3) {
-
- if (lua_type(L, 3) == LUA_TFUNCTION) {
- /* Normal symbol from just a function */
- lua_pushvalue(L, 3);
- rspamd_register_symbol_fromlua(L,
- cfg,
- name,
- luaL_ref(L, LUA_REGISTRYINDEX),
- 1.0,
- 0,
- SYMBOL_TYPE_NORMAL,
- -1,
- NULL, NULL,
- FALSE);
- }
- else if (lua_type(L, 3) == LUA_TTABLE) {
- guint type = SYMBOL_TYPE_NORMAL, priority = 0;
- gint idx;
- gdouble weight = 1.0, score = NAN;
- const char *type_str, *group = NULL, *description = NULL;
-
- /*
- * Table can have the following attributes:
- * "callback" - should be a callback function
- * "weight" - optional weight
- * "priority" - optional priority
- * "type" - optional type (normal, virtual, callback)
- * "flags" - optional flags
- * -- Metric options
- * "score" - optional default score (overridden by metric)
- * "group" - optional default group
- * "one_shot" - optional one shot mode
- * "description" - optional description
- */
- lua_pushvalue(L, 3);
- lua_pushstring(L, "callback");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) != LUA_TFUNCTION) {
- lua_pop(L, 2);
- msg_info_config("cannot find callback definition for %s",
- name);
- return 0;
- }
- idx = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* Optional fields */
- lua_pushstring(L, "weight");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TNUMBER) {
- weight = lua_tonumber(L, -1);
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "priority");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TNUMBER) {
- priority = lua_tointeger(L, -1);
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "optional");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TBOOLEAN) {
- optional = lua_toboolean(L, -1);
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "type");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TSTRING) {
- type_str = lua_tostring(L, -1);
- type = lua_parse_symbol_type(type_str);
- }
- lua_pop(L, 1);
-
- /* Deal with flags and ids */
- lua_pushstring(L, "flags");
- lua_gettable(L, -2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- flags = lua_parse_symbol_flags(lua_tostring(L, -1));
- }
- else if (lua_type(L, -1) == LUA_TTABLE) {
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- flags |= lua_parse_symbol_flags(lua_tostring(L, -1));
- }
- }
- lua_pop(L, 1); /* Clean flags */
-
- lua_pushstring(L, "allowed_ids");
- lua_gettable(L, -2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- allowed_ids = rspamd_process_id_list(lua_tostring(L, -1));
- }
- else if (lua_type(L, -1) == LUA_TTABLE) {
- allowed_ids = g_array_sized_new(FALSE, FALSE, sizeof(guint32),
- rspamd_lua_table_size(L, -1));
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- guint32 v = lua_tointeger(L, -1);
- g_array_append_val(allowed_ids, v);
- }
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "forbidden_ids");
- lua_gettable(L, -2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- forbidden_ids = rspamd_process_id_list(lua_tostring(L, -1));
- }
- else if (lua_type(L, -1) == LUA_TTABLE) {
- forbidden_ids = g_array_sized_new(FALSE, FALSE, sizeof(guint32),
- rspamd_lua_table_size(L, -1));
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- guint32 v = lua_tointeger(L, -1);
- g_array_append_val(forbidden_ids, v);
- }
- }
- lua_pop(L, 1);
-
- id = rspamd_register_symbol_fromlua(L,
- cfg,
- name,
- idx,
- weight,
- priority,
- type | flags,
- -1,
- allowed_ids, forbidden_ids,
- optional);
-
- if (allowed_ids) {
- g_array_free(allowed_ids, TRUE);
- }
-
- if (forbidden_ids) {
- g_array_free(forbidden_ids, TRUE);
- }
-
- if (id != -1) {
- /* Check for condition */
- lua_pushstring(L, "condition");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TFUNCTION) {
- gint condref;
-
- /* Here we pop function from the stack, so no lua_pop is required */
- condref = luaL_ref(L, LUA_REGISTRYINDEX);
- g_assert(name != NULL);
- rspamd_symcache_add_condition_delayed(cfg->cache,
- name, L, condref);
- }
- else {
- lua_pop(L, 1);
- }
-
- /* Check for augmentations */
- lua_pushstring(L, "augmentations");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TTABLE) {
-
- int tbl_idx = lua_gettop(L);
- for (lua_pushnil(L); lua_next(L, tbl_idx); lua_pop(L, 1)) {
- rspamd_symcache_add_symbol_augmentation(cfg->cache, id,
- lua_tostring(L, -1), NULL);
- }
- }
-
- lua_pop(L, 1);
- }
-
- /*
- * Now check if a symbol has not been registered in any metric and
- * insert default value if applicable
- */
- struct rspamd_symbol *sym = g_hash_table_lookup(cfg->symbols, name);
- if (sym == NULL || (sym->flags & RSPAMD_SYMBOL_FLAG_UNSCORED)) {
- nshots = cfg->default_max_shots;
-
- lua_pushstring(L, "score");
- lua_gettable(L, -2);
- if (lua_type(L, -1) == LUA_TNUMBER) {
- score = lua_tonumber(L, -1);
-
- if (sym) {
- /* Reset unscored flag */
- sym->flags &= ~RSPAMD_SYMBOL_FLAG_UNSCORED;
- }
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "group");
- lua_gettable(L, -2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- group = lua_tostring(L, -1);
- }
- lua_pop(L, 1);
-
- if (!isnan(score) || group != NULL) {
- lua_pushstring(L, "description");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TSTRING) {
- description = lua_tostring(L, -1);
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "one_shot");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TBOOLEAN) {
- if (lua_toboolean(L, -1)) {
- nshots = 1;
- }
- }
- lua_pop(L, 1);
-
- lua_pushstring(L, "one_param");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TBOOLEAN) {
- if (lua_toboolean(L, -1)) {
- flags |= RSPAMD_SYMBOL_FLAG_ONEPARAM;
- }
- }
- lua_pop(L, 1);
-
- /*
- * Do not override the existing symbols (using zero priority),
- * since we are defining default values here
- */
- if (!isnan(score)) {
- rspamd_config_add_symbol(cfg, name, score,
- description, group, flags, 0, nshots);
- }
- else if (group) {
- /* Add with zero score */
- rspamd_config_add_symbol(cfg, name, NAN,
- description, group, flags, 0, nshots);
- }
-
- lua_pushstring(L, "groups");
- lua_gettable(L, -2);
-
- if (lua_istable(L, -1)) {
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- if (lua_isstring(L, -1)) {
- rspamd_config_add_symbol_group(cfg, name,
- lua_tostring(L, -1));
- }
- else {
- return luaL_error(L, "invalid groups element");
- }
- }
- }
-
- lua_pop(L, 1);
- }
- }
- else {
- /* Fill in missing fields from lua definition if they are not set */
- if (sym->description == NULL) {
- lua_pushstring(L, "description");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) == LUA_TSTRING) {
- description = lua_tostring(L, -1);
- }
- lua_pop(L, 1);
-
- if (description) {
- sym->description = rspamd_mempool_strdup(cfg->cfg_pool, description);
- }
- }
-
- /* If ungrouped and there is a group defined in lua, change the primary group
- * Otherwise, add to the list of groups for this symbol. */
- lua_pushstring(L, "group");
- lua_gettable(L, -2);
- if (lua_type(L, -1) == LUA_TSTRING) {
- group = lua_tostring(L, -1);
- }
- lua_pop(L, 1);
- if (group) {
- if (sym->flags & RSPAMD_SYMBOL_FLAG_UNGROUPED) {
- /* Unset the "ungrouped" group */
- sym->gr = NULL;
- }
- /* Add the group. If the symbol was ungrouped, this will
- * clear RSPAMD_SYMBOL_FLAG_UNGROUPED from the flags. */
- rspamd_config_add_symbol_group(cfg, name, group);
- }
- }
-
- /* Remove table from stack */
- lua_pop(L, 1);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 0;
- }
-
- static gint
- lua_config_add_condition(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *sym = luaL_checkstring(L, 2);
- gboolean ret = FALSE;
- gint condref;
-
- if (cfg && sym && lua_type(L, 3) == LUA_TFUNCTION) {
- lua_pushvalue(L, 3);
- condref = luaL_ref(L, LUA_REGISTRYINDEX);
-
- ret = rspamd_symcache_add_condition_delayed(cfg->cache, sym, L,
- condref);
-
- if (!ret) {
- luaL_unref(L, LUA_REGISTRYINDEX, condref);
- }
- }
-
- lua_pushboolean(L, ret);
- return 1;
- }
-
- static gint
- lua_config_set_peak_cb(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- gint condref;
-
- if (cfg && lua_type(L, 2) == LUA_TFUNCTION) {
- lua_pushvalue(L, 2);
- condref = luaL_ref(L, LUA_REGISTRYINDEX);
- rspamd_symcache_set_peak_callback(cfg->cache,
- condref);
- }
-
- return 0;
- }
-
- static gint
- lua_config_enable_symbol(lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const char *sym = luaL_checkstring(L, 2);
-
- if (!sym || !cfg) {
- return luaL_error(L, "invalid arguments");
- }
-
- rspamd_symcache_enable_symbol_static(cfg->cache, sym);
-
- return 0;
- }
-
- static gint
- lua_config_disable_symbol(lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const char *sym = luaL_checkstring(L, 2);
-
- if (!sym || !cfg) {
- return luaL_error(L, "invalid arguments");
- }
-
- rspamd_symcache_disable_symbol_static(cfg->cache, sym);
-
- return 0;
- }
-
- static gint
- lua_config_register_regexp(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_lua_regexp *re = NULL;
- rspamd_regexp_t *cache_re;
- const gchar *type_str = NULL, *header_str = NULL;
- gsize header_len = 0;
- GError *err = NULL;
- enum rspamd_re_type type = RSPAMD_RE_BODY;
- gboolean pcre_only = FALSE;
-
- /*
- * - `re`* : regular expression object
- * - `type`*: type of regular expression:
- * + `mime`: mime regexp
- * + `rawmime`: raw mime regexp
- * + `header`: header regexp
- * + `rawheader`: raw header expression
- * + `body`: raw body regexp
- * + `url`: url regexp
- * - `header`: for header and rawheader regexp means the name of header
- * - `pcre_only`: allow merely pcre for this regexp
- */
- if (cfg != NULL) {
- if (!rspamd_lua_parse_table_arguments(L, 2, &err,
- RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
- "*re=U{regexp};*type=S;header=S;pcre_only=B",
- &re, &type_str, &header_str, &pcre_only)) {
- msg_err_config("cannot get parameters list: %e", err);
-
- if (err) {
- g_error_free(err);
- }
- }
- else {
- type = rspamd_re_cache_type_from_string(type_str);
-
- if ((type == RSPAMD_RE_HEADER ||
- type == RSPAMD_RE_RAWHEADER ||
- type == RSPAMD_RE_MIMEHEADER) &&
- header_str == NULL) {
- msg_err_config(
- "header argument is mandatory for header/rawheader regexps");
- }
- else {
- if (pcre_only) {
- rspamd_regexp_set_flags(re->re,
- rspamd_regexp_get_flags(re->re) | RSPAMD_REGEXP_FLAG_PCRE_ONLY);
- }
-
- if (header_str != NULL) {
- /* Include the last \0 */
- header_len = strlen(header_str) + 1;
- }
-
- cache_re = rspamd_re_cache_add(cfg->re_cache, re->re, type,
- (gpointer) header_str, header_len, -1);
-
- /*
- * XXX: here are dragons!
- * Actually, lua regexp contains internal rspamd_regexp_t
- * and it owns it.
- * However, after this operation we have some OTHER regexp,
- * which we really would like to use.
- * So we do the following:
- * 1) Remove old re and unref it
- * 2) Replace the internal re with cached one
- * 3) Increase its refcount to share ownership between cache and
- * lua object
- */
- if (cache_re != re->re) {
- rspamd_regexp_unref(re->re);
- re->re = rspamd_regexp_ref(cache_re);
-
- if (pcre_only) {
- rspamd_regexp_set_flags(re->re,
- rspamd_regexp_get_flags(re->re) | RSPAMD_REGEXP_FLAG_PCRE_ONLY);
- }
- }
- }
- }
- }
-
- return 0;
- }
-
- static gint
- lua_config_replace_regexp(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_lua_regexp *old_re = NULL, *new_re = NULL;
- gboolean pcre_only = FALSE;
- GError *err = NULL;
-
- if (cfg != NULL) {
- if (!rspamd_lua_parse_table_arguments(L, 2, &err,
- RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
- "*old_re=U{regexp};*new_re=U{regexp};pcre_only=B",
- &old_re, &new_re, &pcre_only)) {
- gint ret = luaL_error(L, "cannot get parameters list: %s",
- err ? err->message : "invalid arguments");
-
- if (err) {
- g_error_free(err);
- }
-
- return ret;
- }
- else {
-
- if (pcre_only) {
- rspamd_regexp_set_flags(new_re->re,
- rspamd_regexp_get_flags(new_re->re) | RSPAMD_REGEXP_FLAG_PCRE_ONLY);
- }
-
- rspamd_re_cache_replace(cfg->re_cache, old_re->re, new_re->re);
- }
- }
-
- return 0;
- }
-
- static gint
- lua_config_register_worker_script(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *worker_type = luaL_checkstring(L, 2), *wtype;
- struct rspamd_worker_conf *cf;
- GList *cur;
- struct rspamd_worker_lua_script *sc;
- gboolean found = FALSE;
-
- if (cfg == NULL || worker_type == NULL || lua_type(L, 3) != LUA_TFUNCTION) {
- return luaL_error(L, "invalid arguments");
- }
-
- for (cur = g_list_first(cfg->workers); cur != NULL; cur = g_list_next(cur)) {
- cf = cur->data;
- wtype = g_quark_to_string(cf->type);
-
- if (g_ascii_strcasecmp(wtype, worker_type) == 0) {
- sc = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*sc));
- lua_pushvalue(L, 3);
- sc->cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- DL_APPEND(cf->scripts, sc);
- found = TRUE;
- }
- }
-
- lua_pushboolean(L, found);
-
- return 1;
- }
-
- static gint
- lua_config_add_on_load(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_config_cfg_lua_script *sc;
-
- if (cfg == NULL || lua_type(L, 2) != LUA_TFUNCTION) {
- return luaL_error(L, "invalid arguments");
- }
-
- sc = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*sc));
- lua_pushvalue(L, 2);
- sc->cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- DL_APPEND(cfg->on_load_scripts, sc);
-
- return 0;
- }
-
- static inline int
- rspamd_post_init_sc_sort(const struct rspamd_config_cfg_lua_script *pra,
- const struct rspamd_config_cfg_lua_script *prb)
- {
- /* Inverse sort */
- return prb->priority - pra->priority;
- }
-
- static gint
- lua_config_add_post_init(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_config_cfg_lua_script *sc;
- guint priority = 0;
- lua_Debug d;
- gchar tmp[256], *p;
-
- if (cfg == NULL || lua_type(L, 2) != LUA_TFUNCTION) {
- return luaL_error(L, "invalid arguments");
- }
-
- if (lua_type(L, 3) == LUA_TNUMBER) {
- priority = lua_tointeger(L, 3);
- }
-
- if (lua_getstack(L, 1, &d) == 1) {
- (void) lua_getinfo(L, "Sl", &d);
- if ((p = strrchr(d.short_src, '/')) == NULL) {
- p = d.short_src;
- }
- else {
- p++;
- }
-
- if (strlen(p) > 200) {
- rspamd_snprintf(tmp, sizeof(tmp), "%10s...]:%d", p,
- d.currentline);
- }
- else {
- rspamd_snprintf(tmp, sizeof(tmp), "%s:%d", p,
- d.currentline);
- }
- }
-
- sc = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*sc));
- lua_pushvalue(L, 2);
- sc->cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- sc->priority = priority;
- sc->lua_src_pos = rspamd_mempool_strdup(cfg->cfg_pool, tmp);
- DL_APPEND(cfg->post_init_scripts, sc);
- DL_SORT(cfg->post_init_scripts, rspamd_post_init_sc_sort);
-
- return 0;
- }
-
- static gint
- lua_config_add_config_unload(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_config_cfg_lua_script *sc;
- lua_Debug d;
- gchar tmp[256], *p;
-
- if (cfg == NULL || lua_type(L, 2) != LUA_TFUNCTION) {
- return luaL_error(L, "invalid arguments");
- }
-
- if (lua_getstack(L, 1, &d) == 1) {
- (void) lua_getinfo(L, "Sl", &d);
- if ((p = strrchr(d.short_src, '/')) == NULL) {
- p = d.short_src;
- }
- else {
- p++;
- }
-
- if (strlen(p) > 20) {
- rspamd_snprintf(tmp, sizeof(tmp), "%10s...]:%d", p,
- d.currentline);
- }
- else {
- rspamd_snprintf(tmp, sizeof(tmp), "%s:%d", p,
- d.currentline);
- }
- }
-
- sc = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*sc));
- lua_pushvalue(L, 2);
- sc->cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- sc->lua_src_pos = rspamd_mempool_strdup(cfg->cfg_pool, tmp);
- DL_APPEND(cfg->config_unload_scripts, sc);
-
- return 0;
- }
-
-
- static void lua_periodic_callback_finish(struct thread_entry *thread, int ret);
- static void lua_periodic_callback_error(struct thread_entry *thread, int ret, const char *msg);
-
- struct rspamd_lua_periodic {
- struct ev_loop *event_loop;
- struct rspamd_config *cfg;
- gchar *lua_src_pos;
- lua_State *L;
- gdouble timeout;
- ev_timer ev;
- gint cbref;
- gboolean need_jitter;
- ref_entry_t ref;
- };
-
- static void
- lua_periodic_dtor(struct rspamd_lua_periodic *periodic)
- {
- luaL_unref(periodic->L, LUA_REGISTRYINDEX, periodic->cbref);
- ev_timer_stop(periodic->event_loop, &periodic->ev);
- }
-
- static void
- lua_periodic_fin(gpointer p)
- {
- struct rspamd_lua_periodic *periodic = (struct rspamd_lua_periodic *) p;
-
- REF_RELEASE(periodic);
- }
-
- static void
- lua_periodic_callback(struct ev_loop *loop, ev_timer *w, int revents)
- {
- struct rspamd_lua_periodic *periodic = (struct rspamd_lua_periodic *) w->data;
- struct rspamd_config **pcfg, *cfg;
- struct ev_loop **pev_base;
- struct thread_entry *thread;
- lua_State *L;
-
- REF_RETAIN(periodic);
- thread = lua_thread_pool_get_for_config(periodic->cfg);
- thread->cd = periodic;
- thread->finish_callback = lua_periodic_callback_finish;
- thread->error_callback = lua_periodic_callback_error;
-
- L = thread->lua_state;
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, periodic->cbref);
- pcfg = lua_newuserdata(L, sizeof(*pcfg));
- rspamd_lua_setclass(L, "rspamd{config}", -1);
- cfg = periodic->cfg;
- *pcfg = cfg;
- pev_base = lua_newuserdata(L, sizeof(*pev_base));
- rspamd_lua_setclass(L, "rspamd{ev_base}", -1);
- *pev_base = periodic->event_loop;
- lua_pushnumber(L, ev_now(periodic->event_loop));
-
- lua_thread_call(thread, 3);
- }
-
- static void
- lua_periodic_callback_finish(struct thread_entry *thread, int ret)
- {
- lua_State *L;
- struct rspamd_lua_periodic *periodic = thread->cd;
- gboolean plan_more = FALSE;
- gdouble timeout = 0.0;
-
- L = thread->lua_state;
-
- ev_now_update(periodic->event_loop);
-
- if (ret == 0) {
- if (lua_type(L, -1) == LUA_TBOOLEAN) {
- plan_more = lua_toboolean(L, -1);
- timeout = periodic->timeout;
- }
- else if (lua_type(L, -1) == LUA_TNUMBER) {
- timeout = lua_tonumber(L, -1);
- plan_more = timeout > 0 ? TRUE : FALSE;
- }
-
- lua_pop(L, 1); /* Return value */
- }
-
- if (periodic->cfg->cur_worker) {
- if (periodic->cfg->cur_worker->state != rspamd_worker_state_running) {
- /* We are terminating, no more periodics */
- plan_more = FALSE;
- }
- }
-
- if (plan_more) {
- if (periodic->need_jitter) {
- timeout = rspamd_time_jitter(timeout, 0.0);
- }
-
- periodic->ev.repeat = timeout;
- ev_timer_again(periodic->event_loop, &periodic->ev);
- }
- else {
- ev_timer_stop(periodic->event_loop, &periodic->ev);
- }
-
- REF_RELEASE(periodic);
- }
-
- static void
- lua_periodic_callback_error(struct thread_entry *thread, int ret, const char *msg)
- {
- struct rspamd_config *cfg;
- struct rspamd_lua_periodic *periodic = thread->cd;
- cfg = periodic->cfg;
-
- msg_err_config("call to periodic script (registered at %s) failed: %s",
- periodic->lua_src_pos, msg);
-
- lua_periodic_callback_finish(thread, ret);
- }
-
-
- static gint
- lua_config_add_periodic(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct ev_loop *ev_base = lua_check_ev_base(L, 2);
- gdouble timeout = lua_tonumber(L, 3);
- struct rspamd_lua_periodic *periodic;
- gboolean need_jitter = FALSE;
- lua_Debug d;
- gchar tmp[256], *p;
-
- if (cfg == NULL || timeout < 0 || lua_type(L, 4) != LUA_TFUNCTION) {
- return luaL_error(L, "invalid arguments");
- }
-
- if (lua_type(L, 5) == LUA_TBOOLEAN) {
- need_jitter = lua_toboolean(L, 5);
- }
-
- if (lua_getstack(L, 1, &d) == 1) {
- (void) lua_getinfo(L, "Sl", &d);
- if ((p = strrchr(d.short_src, '/')) == NULL) {
- p = d.short_src;
- }
- else {
- p++;
- }
-
- if (strlen(p) > 20) {
- rspamd_snprintf(tmp, sizeof(tmp), "%10s...]:%d", p,
- d.currentline);
- }
- else {
- rspamd_snprintf(tmp, sizeof(tmp), "%s:%d", p,
- d.currentline);
- }
- }
-
- periodic = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*periodic));
- periodic->timeout = timeout;
- periodic->L = L;
- periodic->cfg = cfg;
- periodic->event_loop = ev_base;
- periodic->need_jitter = need_jitter;
- periodic->lua_src_pos = rspamd_mempool_strdup(cfg->cfg_pool, tmp);
- lua_pushvalue(L, 4);
- periodic->cbref = luaL_ref(L, LUA_REGISTRYINDEX);
-
- if (need_jitter) {
- timeout = rspamd_time_jitter(timeout, 0.0);
- }
-
- ev_timer_init(&periodic->ev, lua_periodic_callback, timeout, 0.0);
- periodic->ev.data = periodic;
- ev_timer_start(ev_base, &periodic->ev);
- REF_INIT_RETAIN(periodic, lua_periodic_dtor);
-
- rspamd_mempool_add_destructor(cfg->cfg_pool, lua_periodic_fin,
- periodic);
-
- return 0;
- }
-
- static gint
- lua_config_get_symbols_count(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- guint res = 0;
-
- if (cfg != NULL) {
- res = rspamd_symcache_stats_symbols_count(cfg->cache);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- lua_pushinteger(L, res);
-
- return 1;
- }
-
- static gint
- lua_config_get_symbols_cksum(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- guint64 res = 0, *pres;
-
- if (cfg != NULL) {
- res = rspamd_symcache_get_cksum(cfg->cache);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- pres = lua_newuserdata(L, sizeof(res));
- *pres = res;
- rspamd_lua_setclass(L, "rspamd{int64}", -1);
-
- return 1;
- }
-
- static gint
- lua_config_get_symbols_counters(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- ucl_object_t *counters;
-
- if (cfg != NULL) {
- counters = rspamd_symcache_counters(cfg->cache);
- ucl_object_push_lua(L, counters, true);
- ucl_object_unref(counters);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- struct lua_metric_symbols_cbdata {
- lua_State *L;
- struct rspamd_config *cfg;
- bool is_table;
- };
-
- static void
- lua_metric_symbol_inserter(gpointer k, gpointer v, gpointer ud)
- {
- struct lua_metric_symbols_cbdata *cbd = (struct lua_metric_symbols_cbdata *) ud;
- lua_State *L;
- const gchar *sym = k;
- struct rspamd_symbol *s = (struct rspamd_symbol *) v;
- struct rspamd_symbols_group *gr;
- gint i;
-
- L = cbd->L;
-
- if (cbd->is_table) {
- lua_pushstring(L, sym); /* Symbol name */
- }
-
- lua_createtable(L, 0, 6);
- lua_pushstring(L, "score");
- lua_pushnumber(L, s->score);
- lua_settable(L, -3);
- lua_pushstring(L, "description");
- lua_pushstring(L, s->description);
- lua_settable(L, -3);
-
- lua_pushstring(L, "flags");
- lua_createtable(L, 0, 3);
-
- if (s->flags & RSPAMD_SYMBOL_FLAG_IGNORE_METRIC) {
- lua_pushstring(L, "ignore");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (s->flags & RSPAMD_SYMBOL_FLAG_ONEPARAM) {
- lua_pushstring(L, "oneparam");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (s->flags & RSPAMD_SYMBOL_FLAG_UNGROUPED) {
- lua_pushstring(L, "ungrouped");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (s->flags & RSPAMD_SYMBOL_FLAG_DISABLED) {
- lua_pushstring(L, "disabled");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
-
- if (s->cache_item) {
- guint sflags = rspamd_symcache_get_symbol_flags(cbd->cfg->cache, sym);
-
- lua_push_symbol_flags(L, sflags, LUA_SYMOPT_FLAG_USE_MAP);
-
- guint nids;
- const guint *allowed_ids = rspamd_symcache_get_allowed_settings_ids(cbd->cfg->cache,
- sym, &nids);
-
- if (allowed_ids && nids > 0) {
- lua_createtable(L, nids, 0);
-
- for (i = 0; i < nids; i++) {
- lua_pushinteger(L, allowed_ids[i]);
- lua_rawseti(L, -2, i + 1);
- }
-
- lua_setfield(L, -2, "allowed_ids");
- }
-
- const guint *forbidden_ids = rspamd_symcache_get_forbidden_settings_ids(
- cbd->cfg->cache,
- sym, &nids);
-
- if (forbidden_ids && nids > 0) {
- lua_createtable(L, nids, 0);
-
- for (i = 0; i < nids; i++) {
- lua_pushinteger(L, forbidden_ids[i]);
- lua_rawseti(L, -2, i + 1);
- }
-
- lua_setfield(L, -2, "forbidden_ids");
- }
- }
-
- lua_settable(L, -3); /* Flags -> flags_table */
-
- lua_pushstring(L, "nshots");
- lua_pushinteger(L, s->nshots);
- lua_settable(L, -3);
-
- if (s->gr) {
- lua_pushstring(L, "group");
- lua_pushstring(L, s->gr->name);
- lua_settable(L, -3);
- }
-
- if (s->groups && s->groups->len > 0) {
- lua_pushstring(L, "groups");
- lua_createtable(L, s->groups->len, 0);
-
- PTR_ARRAY_FOREACH(s->groups, i, gr)
- {
- lua_pushstring(L, gr->name);
- lua_rawseti(L, -2, i + 1); /* Groups[i + 1] = group_name */
- }
-
- lua_settable(L, -3); /* Groups -> groups_table */
- }
- else {
- lua_createtable(L, 0, 0);
- lua_setfield(L, -2, "groups");
- }
-
- if (cbd->is_table) {
- lua_settable(L, -3); /* Symname -> table */
- }
- }
-
- static gint
- lua_config_get_symbols(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL) {
- struct lua_metric_symbols_cbdata cbd;
-
- cbd.L = L;
- cbd.cfg = cfg;
- cbd.is_table = true;
-
- lua_createtable(L, 0, g_hash_table_size(cfg->symbols));
- g_hash_table_foreach(cfg->symbols,
- lua_metric_symbol_inserter,
- &cbd);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_symbol(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *sym_name = luaL_checkstring(L, 2);
-
- if (cfg != NULL && sym_name != NULL) {
- struct lua_metric_symbols_cbdata cbd;
- struct rspamd_symbol *s = g_hash_table_lookup(cfg->symbols, sym_name);
-
- if (s) {
- cbd.L = L;
- cbd.cfg = cfg;
- cbd.is_table = false;
- lua_metric_symbol_inserter((void *) sym_name, s, &cbd);
- }
- else {
- /* No config for a symbol */
- lua_pushnil(L);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_symbol_callback(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *sym = luaL_checkstring(L, 2);
- struct rspamd_abstract_callback_data *abs_cbdata;
- struct lua_callback_data *cbd;
-
- if (cfg != NULL && sym != NULL) {
- abs_cbdata = rspamd_symcache_get_cbdata(cfg->cache, sym);
-
- if (abs_cbdata == NULL || abs_cbdata->magic != rspamd_lua_callback_magic) {
- lua_pushnil(L);
- }
- else {
- cbd = (struct lua_callback_data *) abs_cbdata;
-
- if (cbd->cb_is_ref) {
- lua_rawgeti(L, LUA_REGISTRYINDEX, cbd->callback.ref);
- }
- else {
- lua_getglobal(L, cbd->callback.name);
- }
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_set_symbol_callback(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *sym = luaL_checkstring(L, 2);
- struct rspamd_abstract_callback_data *abs_cbdata;
- struct lua_callback_data *cbd;
-
- if (cfg != NULL && sym != NULL && lua_type(L, 3) == LUA_TFUNCTION) {
- abs_cbdata = rspamd_symcache_get_cbdata(cfg->cache, sym);
-
- if (abs_cbdata == NULL || abs_cbdata->magic != rspamd_lua_callback_magic) {
- lua_pushboolean(L, FALSE);
- }
- else {
- cbd = (struct lua_callback_data *) abs_cbdata;
-
- if (cbd->cb_is_ref) {
- luaL_unref(L, LUA_REGISTRYINDEX, cbd->callback.ref);
- }
- else {
- cbd->cb_is_ref = TRUE;
- }
-
- lua_pushvalue(L, 3);
- cbd->callback.ref = luaL_ref(L, LUA_REGISTRYINDEX);
- lua_pushboolean(L, TRUE);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_symbol_stat(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *sym = luaL_checkstring(L, 2);
- gdouble freq, stddev, tm;
- guint hits;
-
- if (cfg != NULL && sym != NULL) {
- if (!rspamd_symcache_stat_symbol(cfg->cache, sym, &freq,
- &stddev, &tm, &hits)) {
- lua_pushnil(L);
- }
- else {
- lua_createtable(L, 0, 4);
- lua_pushstring(L, "frequency");
- lua_pushnumber(L, freq);
- lua_settable(L, -3);
- lua_pushstring(L, "sttdev");
- lua_pushnumber(L, stddev);
- lua_settable(L, -3);
- lua_pushstring(L, "time");
- lua_pushnumber(L, tm);
- lua_settable(L, -3);
- lua_pushstring(L, "hits");
- lua_pushinteger(L, hits);
- lua_settable(L, -3);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_symbol_parent(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *sym = luaL_checkstring(L, 2), *parent;
-
- if (cfg != NULL && sym != NULL) {
- parent = rspamd_symcache_get_parent(cfg->cache, sym);
-
- if (parent) {
- lua_pushstring(L, parent);
- }
- else {
- lua_pushnil(L);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_group_symbols(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *gr_name = luaL_checkstring(L, 2);
-
- if (cfg != NULL && gr_name != NULL) {
- struct rspamd_symbols_group *group;
-
- group = g_hash_table_lookup(cfg->groups, gr_name);
-
- if (group == NULL) {
- lua_pushnil(L);
- }
- else {
- guint i = 1;
- gpointer k, v;
- GHashTableIter it;
-
- lua_createtable(L, g_hash_table_size(group->symbols), 0);
- g_hash_table_iter_init(&it, group->symbols);
-
- while (g_hash_table_iter_next(&it, &k, &v)) {
- lua_pushstring(L, k);
- lua_rawseti(L, -2, i);
- i++;
- }
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_groups(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- gboolean need_private;
- struct rspamd_symbols_group *gr;
- GHashTableIter it;
- gpointer k, v;
-
- if (cfg) {
- if (lua_isboolean(L, 2)) {
- need_private = lua_toboolean(L, 2);
- }
- else {
- need_private = !(cfg->public_groups_only);
- }
-
- lua_createtable(L, 0, g_hash_table_size(cfg->groups));
- g_hash_table_iter_init(&it, cfg->groups);
-
- while (g_hash_table_iter_next(&it, &k, &v)) {
- gr = (struct rspamd_symbols_group *) v;
-
- if (need_private || (gr->flags & RSPAMD_SYMBOL_GROUP_PUBLIC)) {
- lua_createtable(L, 0, 4);
-
- lua_pushstring(L, gr->description);
- lua_setfield(L, -2, "description");
- lua_pushnumber(L, gr->max_score);
- lua_setfield(L, -2, "max_score");
- lua_pushboolean(L, (gr->flags & RSPAMD_SYMBOL_GROUP_PUBLIC) != 0);
- lua_setfield(L, -2, "is_public");
- /* TODO: maybe push symbols as well */
-
- /* Parent table indexed by group name */
- lua_setfield(L, -2, gr->name);
- }
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_register_finish_script(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_config_cfg_lua_script *sc;
-
- if (cfg != NULL && lua_type(L, 2) == LUA_TFUNCTION) {
- sc = rspamd_mempool_alloc0(cfg->cfg_pool, sizeof(*sc));
- lua_pushvalue(L, 2);
- sc->cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- DL_APPEND(cfg->on_term_scripts, sc);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 0;
- }
-
- static inline bool
- rspamd_lua_config_check_settings_symbols_object(const ucl_object_t *obj)
- {
- if (obj == NULL) {
- /* Semantically valid */
- return true;
- }
-
- if (ucl_object_type(obj) == UCL_OBJECT) {
- /* Key-value mapping - should be okay */
- return true;
- }
-
- if (ucl_object_type(obj) == UCL_ARRAY) {
- /* Okay if empty */
- if (obj->len == 0) {
- return true;
- }
- }
-
- /* Everything else not okay */
- return false;
- }
-
- static gint
- lua_config_register_settings_id(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *settings_name = luaL_checkstring(L, 2);
-
- if (cfg != NULL && settings_name) {
- ucl_object_t *sym_enabled, *sym_disabled;
- enum rspamd_config_settings_policy policy = RSPAMD_SETTINGS_POLICY_DEFAULT;
-
- sym_enabled = ucl_object_lua_import(L, 3);
-
- if (!rspamd_lua_config_check_settings_symbols_object(sym_enabled)) {
- ucl_object_unref(sym_enabled);
-
- return luaL_error(L, "invalid symbols enabled");
- }
-
- sym_disabled = ucl_object_lua_import(L, 4);
-
- if (!rspamd_lua_config_check_settings_symbols_object(sym_disabled)) {
- ucl_object_unref(sym_enabled);
- ucl_object_unref(sym_disabled);
-
- return luaL_error(L, "invalid symbols enabled");
- }
-
- /* Check policy */
- if (lua_isstring(L, 5)) {
- const gchar *policy_str = lua_tostring(L, 5);
-
- if (strcmp(policy_str, "default") == 0) {
- policy = RSPAMD_SETTINGS_POLICY_DEFAULT;
- }
- else if (strcmp(policy_str, "implicit_allow") == 0) {
- policy = RSPAMD_SETTINGS_POLICY_IMPLICIT_ALLOW;
- }
- else if (strcmp(policy_str, "implicit_deny") == 0) {
- policy = RSPAMD_SETTINGS_POLICY_IMPLICIT_DENY;
- }
- else {
- return luaL_error(L, "invalid settings policy: %s", policy_str);
- }
- }
- else {
- /* Apply heuristic */
- if (!sym_enabled) {
- policy = RSPAMD_SETTINGS_POLICY_IMPLICIT_ALLOW;
- }
- }
-
- rspamd_config_register_settings_id(cfg, settings_name, sym_enabled,
- sym_disabled, policy);
-
- if (sym_enabled) {
- ucl_object_unref(sym_enabled);
- }
-
- if (sym_disabled) {
- ucl_object_unref(sym_disabled);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 0;
- }
-
- static gint
- lua_config_register_monitored(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_monitored *m, **pm;
- const gchar *url, *type;
- ucl_object_t *params = NULL;
-
- url = lua_tostring(L, 2);
- type = lua_tostring(L, 3);
-
- if (cfg != NULL && url != NULL && type != NULL) {
- if (g_ascii_strcasecmp(type, "dns") == 0) {
- lua_Debug ar;
-
- if (lua_type(L, 4) == LUA_TTABLE) {
- params = ucl_object_lua_import(L, 4);
- }
-
- /* Get lua line and source */
- lua_getstack(L, 1, &ar);
- lua_getinfo(L, "nSl", &ar);
-
- m = rspamd_monitored_create_(cfg->monitored_ctx, url,
- RSPAMD_MONITORED_DNS, RSPAMD_MONITORED_DEFAULT,
- params, ar.short_src);
-
- if (m) {
- pm = lua_newuserdata(L, sizeof(*pm));
- *pm = m;
- rspamd_lua_setclass(L, "rspamd{monitored}", -1);
- }
- else {
- lua_pushnil(L);
- }
-
- if (params) {
- ucl_object_unref(params);
- }
- }
- else {
- return luaL_error(L, "invalid monitored type: %s", type);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_add_doc(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg;
- const gchar *path = NULL, *option, *doc_string;
- const gchar *type_str = NULL, *default_value = NULL;
- ucl_type_t type = UCL_NULL;
- gboolean required = FALSE;
- GError *err = NULL;
-
- cfg = lua_check_config(L, 1);
-
- if (lua_type(L, 2) == LUA_TSTRING) {
- path = luaL_checkstring(L, 2);
- }
-
- option = luaL_checkstring(L, 3);
- doc_string = luaL_checkstring(L, 4);
-
- if (cfg && option && doc_string) {
- if (lua_type(L, 5) == LUA_TTABLE) {
- if (!rspamd_lua_parse_table_arguments(L, 5, &err,
- RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
- "type=S;default=S;required=B",
- &type_str, &default_value, &required)) {
- msg_err_config("cannot get parameters list: %e", err);
-
- if (err) {
- g_error_free(err);
- }
-
- if (type_str) {
- if (!ucl_object_string_to_type(type_str, &type)) {
- msg_err_config("invalid type: %s", type_str);
- }
- }
- }
- }
-
- rspamd_rcl_add_doc_by_path(cfg, path, doc_string, option,
- type, NULL, 0, default_value, required);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 0;
- }
-
- static gint
- lua_config_add_example(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg;
- const gchar *path = NULL, *option, *doc_string, *example;
- gsize example_len;
-
- cfg = lua_check_config(L, 1);
-
- if (lua_type(L, 2) == LUA_TSTRING) {
- path = luaL_checkstring(L, 2);
- }
-
- option = luaL_checkstring(L, 3);
- doc_string = luaL_checkstring(L, 4);
- example = luaL_checklstring(L, 5, &example_len);
-
- if (cfg && option && doc_string && example) {
-
- rspamd_rcl_add_doc_by_example(cfg, path, doc_string, option,
- example, example_len);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 0;
- }
-
- static gint
- lua_config_get_cpu_flags(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- struct rspamd_cryptobox_library_ctx *crypto_ctx;
-
- if (cfg != NULL) {
- crypto_ctx = cfg->libs_ctx->crypto_ctx;
- lua_newtable(L);
-
- if (crypto_ctx->cpu_config & CPUID_SSSE3) {
- lua_pushstring(L, "ssse3");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (crypto_ctx->cpu_config & CPUID_SSE41) {
- lua_pushstring(L, "sse41");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (crypto_ctx->cpu_config & CPUID_SSE42) {
- lua_pushstring(L, "sse42");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (crypto_ctx->cpu_config & CPUID_SSE2) {
- lua_pushstring(L, "sse2");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (crypto_ctx->cpu_config & CPUID_SSE3) {
- lua_pushstring(L, "sse3");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (crypto_ctx->cpu_config & CPUID_AVX) {
- lua_pushstring(L, "avx");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- if (crypto_ctx->cpu_config & CPUID_AVX2) {
- lua_pushstring(L, "avx2");
- lua_pushboolean(L, true);
- lua_settable(L, -3);
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_has_torch(lua_State *L)
- {
- msg_warn("use of the obsoleted `has_torch` function");
- lua_pushboolean(L, false);
-
- return 1;
- }
-
- static gint
- lua_config_experimental_enabled(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL) {
- lua_pushboolean(L, cfg->enable_experimental);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- struct rspamd_lua_include_trace_cbdata {
- lua_State *L;
- gint cbref;
- };
-
- static void
- lua_include_trace_cb(struct ucl_parser *parser,
- const ucl_object_t *parent,
- const ucl_object_t *args,
- const char *path,
- size_t pathlen,
- void *user_data)
- {
- struct rspamd_lua_include_trace_cbdata *cbdata =
- (struct rspamd_lua_include_trace_cbdata *) user_data;
- gint err_idx;
- lua_State *L;
-
- L = cbdata->L;
- lua_pushcfunction(L, &rspamd_lua_traceback);
- err_idx = lua_gettop(L);
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, cbdata->cbref);
- /* Current filename */
- lua_pushstring(L, ucl_parser_get_cur_file(parser));
- /* Included filename */
- lua_pushlstring(L, path, pathlen);
- /* Params */
- if (args) {
- ucl_object_push_lua(L, args, true);
- }
- else {
- lua_newtable(L);
- }
- /* Parent */
- if (parent) {
- lua_pushstring(L, ucl_object_key(parent));
- }
- else {
- lua_pushnil(L);
- }
-
- if (lua_pcall(L, 4, 0, err_idx) != 0) {
- msg_err("lua call to local include trace failed: %s", lua_tostring(L, -1));
- }
-
- lua_settop(L, err_idx - 1);
- }
-
- #define LUA_TABLE_TO_HASH(htb, idx) \
- do { \
- lua_pushstring(L, (idx)); \
- lua_gettable(L, -2); \
- if (lua_isstring(L, -1)) { \
- g_hash_table_insert((htb), (idx), g_strdup(lua_tostring(L, -1))); \
- } \
- lua_pop(L, 1); \
- } while (0)
-
- static gint
- lua_config_load_ucl(lua_State *L)
- {
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *filename;
- GHashTable *paths = g_hash_table_new_full(rspamd_str_hash, rspamd_str_equal,
- NULL, g_free);
- GError *err = NULL;
-
- if (cfg) {
- if (lua_isstring(L, 2)) {
- filename = lua_tostring(L, 2);
- }
- else {
- filename = RSPAMD_CONFDIR "/rspamd.conf";
- }
-
- /* Convert rspamd_paths */
- lua_getglobal(L, "rspamd_paths");
-
- if (lua_istable(L, -1)) {
- LUA_TABLE_TO_HASH(paths, RSPAMD_CONFDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_LOCAL_CONFDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_RUNDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_DBDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_LOGDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_WWWDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_PLUGINSDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_RULESDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_LUALIBDIR_INDEX);
- LUA_TABLE_TO_HASH(paths, RSPAMD_PREFIX_INDEX);
- }
-
- lua_pop(L, 1);
-
- if (lua_isfunction(L, 3)) {
- struct rspamd_lua_include_trace_cbdata cbd;
-
- lua_pushvalue(L, 3);
- cbd.cbref = luaL_ref(L, LUA_REGISTRYINDEX);
- cbd.L = L;
-
- if (!rspamd_config_parse_ucl(cfg, filename, paths,
- lua_include_trace_cb, &cbd, lua_toboolean(L, 4), &err)) {
- luaL_unref(L, LUA_REGISTRYINDEX, cbd.cbref);
- lua_pushboolean(L, false);
- lua_pushfstring(L, "failed to load config: %s", err->message);
- g_error_free(err);
- g_hash_table_unref(paths);
-
- return 2;
- }
-
- luaL_unref(L, LUA_REGISTRYINDEX, cbd.cbref);
- }
- else {
- if (!rspamd_config_parse_ucl(cfg, filename, paths, NULL, NULL,
- lua_toboolean(L, 3), &err)) {
- lua_pushboolean(L, false);
- lua_pushfstring(L, "failed to load config: %s", err->message);
- g_error_free(err);
- g_hash_table_unref(paths);
-
- return 2;
- }
- }
-
- rspamd_rcl_maybe_apply_lua_transform(cfg);
- rspamd_config_calculate_cksum(cfg);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- g_hash_table_unref(paths);
- lua_pushboolean(L, true);
-
- return 1;
- }
-
- #undef IDX_TO_HASH
-
- static gint
- lua_config_parse_rcl(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- GHashTable *excluded = g_hash_table_new_full(rspamd_str_hash, rspamd_str_equal,
- g_free, NULL);
- GError *err = NULL;
- struct rspamd_rcl_sections_map *top;
-
- if (cfg) {
- if (lua_istable(L, 2)) {
- lua_pushvalue(L, 2);
-
- for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
- g_hash_table_insert(excluded, g_strdup(lua_tostring(L, -1)),
- GINT_TO_POINTER(-1));
- }
-
- lua_pop(L, 1);
- }
-
- top = rspamd_rcl_config_init(cfg, excluded);
-
- if (!rspamd_rcl_parse(top, cfg, cfg, cfg->cfg_pool, cfg->cfg_ucl_obj, &err)) {
- lua_pushboolean(L, false);
- lua_pushfstring(L, "failed to load config: %s", err->message);
- g_error_free(err);
- g_hash_table_unref(excluded);
- rspamd_rcl_sections_free(top);
-
- return 2;
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- g_hash_table_unref(excluded);
- rspamd_rcl_sections_free(top);
- lua_pushboolean(L, true);
-
- return 1;
- }
-
- static gint
- lua_config_init_modules(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL) {
- rspamd_lua_post_load_config(cfg);
- lua_pushboolean(L, rspamd_init_filters(cfg, false, false));
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_init_subsystem(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *subsystem = luaL_checkstring(L, 2);
- gchar **parts;
- guint nparts, i;
-
- if (cfg != NULL && subsystem != NULL) {
- parts = g_strsplit_set(subsystem, ";,", -1);
- nparts = g_strv_length(parts);
-
- for (i = 0; i < nparts; i++) {
- if (strcmp(parts[i], "filters") == 0) {
- rspamd_lua_post_load_config(cfg);
- rspamd_init_filters(cfg, false, false);
- }
- else if (strcmp(parts[i], "langdet") == 0) {
- if (!cfg->lang_det) {
- cfg->lang_det = rspamd_language_detector_init(cfg);
- rspamd_mempool_add_destructor(cfg->cfg_pool,
- (rspamd_mempool_destruct_t) rspamd_language_detector_unref,
- cfg->lang_det);
- }
- }
- else if (strcmp(parts[i], "stat") == 0) {
- rspamd_stat_init(cfg, NULL);
- }
- else if (strcmp(parts[i], "dns") == 0) {
- struct ev_loop *ev_base = lua_check_ev_base(L, 3);
-
- if (ev_base) {
- cfg->dns_resolver = rspamd_dns_resolver_init(rspamd_log_default_logger(),
- ev_base,
- cfg);
- }
- else {
- g_strfreev(parts);
-
- return luaL_error(L, "no event base specified");
- }
- }
- else if (strcmp(parts[i], "symcache") == 0) {
- rspamd_symcache_init(cfg->cache);
- }
- else {
- int ret = luaL_error(L, "invalid param: %s", parts[i]);
- g_strfreev(parts);
-
- return ret;
- }
- }
-
- g_strfreev(parts);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 0;
- }
-
- static gint
- lua_config_register_re_selector(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
- const gchar *name = luaL_checkstring(L, 2);
- const gchar *selector_str = luaL_checkstring(L, 3);
- const gchar *delimiter = "";
- bool flatten = false;
- gint top = lua_gettop(L);
- bool res = false;
-
- if (cfg && name && selector_str) {
- if (lua_gettop(L) >= 4) {
- delimiter = luaL_checkstring(L, 4);
-
- if (lua_isboolean(L, 5)) {
- flatten = lua_toboolean(L, 5);
- }
- }
-
- if (luaL_dostring(L, "return require \"lua_selectors\"") != 0) {
- msg_warn_config("cannot require lua_selectors: %s",
- lua_tostring(L, -1));
- }
- else {
- if (lua_type(L, -1) != LUA_TTABLE) {
- msg_warn_config("lua selectors must return "
- "table and not %s",
- lua_typename(L, lua_type(L, -1)));
- }
- else {
- lua_pushstring(L, "create_selector_closure");
- lua_gettable(L, -2);
-
- if (lua_type(L, -1) != LUA_TFUNCTION) {
- msg_warn_config("create_selector_closure must return "
- "function and not %s",
- lua_typename(L, lua_type(L, -1)));
- }
- else {
- gint err_idx, ret;
- struct rspamd_config **pcfg;
-
- lua_pushcfunction(L, &rspamd_lua_traceback);
- err_idx = lua_gettop(L);
-
- /* Push function */
- lua_pushvalue(L, -2);
-
- pcfg = lua_newuserdata(L, sizeof(*pcfg));
- rspamd_lua_setclass(L, "rspamd{config}", -1);
- *pcfg = cfg;
- lua_pushstring(L, selector_str);
- lua_pushstring(L, delimiter);
- lua_pushboolean(L, flatten);
-
- if ((ret = lua_pcall(L, 4, 1, err_idx)) != 0) {
- msg_err_config("call to create_selector_closure lua "
- "script failed (%d): %s",
- ret,
- lua_tostring(L, -1));
- }
- else {
- if (lua_type(L, -1) != LUA_TFUNCTION) {
- msg_warn_config("create_selector_closure "
- "invocation must return "
- "function and not %s",
- lua_typename(L, lua_type(L, -1)));
- }
- else {
- ret = luaL_ref(L, LUA_REGISTRYINDEX);
- rspamd_re_cache_add_selector(cfg->re_cache,
- name, ret);
- res = true;
- }
- }
- }
- }
- }
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- lua_settop(L, top);
- lua_pushboolean(L, res);
-
- if (res) {
- msg_info_config("registered regexp selector %s", name);
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_tld_path(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL) {
- lua_pushstring(L, cfg->tld_file);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_dns_max_requests(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL) {
- lua_pushinteger(L, cfg->dns_max_requests);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_config_get_dns_timeout(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_config *cfg = lua_check_config(L, 1);
-
- if (cfg != NULL) {
- lua_pushnumber(L, cfg->dns_timeout);
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_monitored_alive(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_monitored *m = lua_check_monitored(L, 1);
-
- if (m) {
- lua_pushboolean(L, rspamd_monitored_alive(m));
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_monitored_offline(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_monitored *m = lua_check_monitored(L, 1);
-
- if (m) {
- lua_pushnumber(L, rspamd_monitored_offline_time(m));
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_monitored_total_offline(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_monitored *m = lua_check_monitored(L, 1);
-
- if (m) {
- lua_pushnumber(L, rspamd_monitored_total_offline_time(m));
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- static gint
- lua_monitored_latency(lua_State *L)
- {
- LUA_TRACE_POINT;
- struct rspamd_monitored *m = lua_check_monitored(L, 1);
-
- if (m) {
- lua_pushnumber(L, rspamd_monitored_latency(m));
- }
- else {
- return luaL_error(L, "invalid arguments");
- }
-
- return 1;
- }
-
- void luaopen_config(lua_State *L)
- {
- rspamd_lua_new_class(L, "rspamd{config}", configlib_m);
-
- lua_pop(L, 1);
-
- rspamd_lua_new_class(L, "rspamd{monitored}", monitoredlib_m);
-
- lua_pop(L, 1);
- }
-
- void lua_call_finish_script(struct rspamd_config_cfg_lua_script *sc,
- struct rspamd_task *task)
- {
-
- struct rspamd_task **ptask;
- struct thread_entry *thread;
-
- thread = lua_thread_pool_get_for_task(task);
- thread->task = task;
-
- lua_State *L = thread->lua_state;
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, sc->cbref);
-
- ptask = lua_newuserdata(L, sizeof(struct rspamd_task *));
- rspamd_lua_setclass(L, rspamd_task_classname, -1);
- *ptask = task;
-
- lua_thread_call(thread, 1);
- }
|