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

SNFMulti.cpp 142KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319
  1. // SNFMulti.cpp
  2. //
  3. // (C) Copyright 2006 - 2020 ARM Research Labs, LLC
  4. // See www.armresearch.com for the copyright terms.
  5. //
  6. // 20060121_M
  7. //
  8. // See SNFMulti.hpp for history and detailed notes.
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <ctime>
  12. #include <cstring>
  13. #include <cstdlib>
  14. #include <sstream>
  15. #include "SNFMulti.hpp"
  16. #include "snf_saccades.hpp"
  17. #include "../CodeDweller/timing.hpp"
  18. //#include "../nvwa-0.6/nvwa/debug_new.h"
  19. namespace cd = codedweller;
  20. //// Version Info
  21. const char* SNF_ENGINE_VERSION = "SNFMulti Engine Version 3.2.1 Build: " __DATE__ " " __TIME__;
  22. //// Script Caller Methods
  23. const cd::ThreadType ScriptCaller::Type("Script Caller"); // Script caller thread type mnemonic.
  24. const cd::ThreadState ScriptCaller::CallingSystem("In system()"); // Script caller "CallingSystem" state.
  25. const cd::ThreadState ScriptCaller::PendingGuardTime("Guard Time"); // Script caller "GuardTime" state.
  26. const cd::ThreadState ScriptCaller::StandingBy("Standby"); // Script caller "Standby" state.
  27. const cd::ThreadState ScriptCaller::Disabled("Disabled"); // State when unable to run.
  28. const int ScriptGuardDefault = 180000; // 3 Minute Default Guard Time.
  29. ScriptCaller::ScriptCaller(std::string S) : // Script caller constructor (with name).
  30. Thread(ScriptCaller::Type, S), // Set up the thread type and name.
  31. GuardTimer(ScriptGuardDefault), // Initialize the guard time.
  32. GoFlag(false), // Not ready to go yet.
  33. DieFlag(false), // Not ready to die yet.
  34. myLastResult(0) { // No last result yet.
  35. run(); // Launch the thread.
  36. }
  37. ScriptCaller::~ScriptCaller() { // Destructor.
  38. DieFlag = true; // Set the die flag.
  39. cd::Sleeper WaitATic(1000); // One second sleeper.
  40. for(int x = 10; x > 0; x--) { // We don't join, we might get stuck.
  41. if(false == isRunning()) break; // If we're still running then wait
  42. WaitATic(); // up to 10 seconds, then just exit.
  43. } // If the thread is stuck it will
  44. } // just get closed.
  45. std::string ScriptCaller::ScriptToRun() { // Safely grab the SystemCallText.
  46. cd::ScopeMutex Freeze(MyMutex); // Protect the string.
  47. return SystemCallText; // Grab a copy of the text.
  48. }
  49. bool ScriptCaller::hasGuardExpired() { // True if guard time has expired.
  50. cd::ScopeMutex Freeze(MyMutex); // Protect the timer.
  51. return GuardTimer.isExpired(); // If it has expired we're true.
  52. }
  53. void ScriptCaller::SystemCall(std::string S) { // Set the SystemCall text.
  54. cd::ScopeMutex Freeze(MyMutex); // Protect the string object.
  55. SystemCallText = S; // Set it's data.
  56. }
  57. const int MinimumGuardTime = 60000; // Minimum Guard Time 1 minute.
  58. void ScriptCaller::GuardTime(int T) { // Set the Guard Time.
  59. if(MinimumGuardTime > T) T = MinimumGuardTime; // Enforce our lower limit.
  60. cd::ScopeMutex Freeze(MyMutex); // Protect the Guard Timer.
  61. GuardTimer.setDuration(T); // Set the duration.
  62. GuardTimer.restart(); // Restart the timer.
  63. }
  64. void ScriptCaller::trigger() { // Trigger the system() call.
  65. GoFlag = true; // Set the flag.
  66. }
  67. int ScriptCaller::LastResult() { // Return the result code from
  68. return myLastResult; // the last system() call.
  69. }
  70. void ScriptCaller::myTask() { // Safely call system() when triggered.
  71. cd::Sleeper WaitATic(1000); // One second sleeper.
  72. while(false == DieFlag) { // While it's not time to die:
  73. WaitATic(); // Pause for 1 sec each round.
  74. std::string ScriptThisRound = ScriptToRun(); // Grab the current script.
  75. if(0 < ScriptToRun().length()) { // If script text is defined and
  76. if(true == GoFlag) { // If GoFlag is triggered and
  77. if(hasGuardExpired()) { // Guard time is expired:
  78. CurrentThreadState(CallingSystem); // Publish our state.
  79. myLastResult = system(ScriptThisRound.c_str()); // Make the system call.
  80. GoFlag = false; // Done with that trigger.
  81. GuardTimer.restart(); // Restart our Guard Time.
  82. } else { // If we're waiting for Guard Time:
  83. CurrentThreadState(PendingGuardTime); // publish that state and hold down
  84. GoFlag = false; // the trigger signal (no stale go).
  85. }
  86. } else { // If nothing is triggered yet then
  87. CurrentThreadState(StandingBy); // we are standing by.
  88. }
  89. } else { // If we have no script to run then
  90. CurrentThreadState(Disabled); // we are disabled.
  91. }
  92. }
  93. }
  94. //// Rulebase Reloader Methods
  95. // How to get timestamps on critical files.
  96. time_t getFileTimestamp(std::string FileName) {
  97. struct stat FileNameStat; // First we need a stat buffer.
  98. if(0 != stat(FileName.c_str(), &FileNameStat)) { // If we can't get the stat we
  99. return 0; // will return 0;
  100. } // If all goes well we return
  101. return FileNameStat.st_mtime; // the last modified time_t.
  102. }
  103. void snf_Reloader::captureFileStats() { // Get stats for later comparison.
  104. snfCFGData& C = *(MyRulebase.MyCFGmgr.ActiveConfiguration()); // Reference the active config.
  105. RulebaseFileCheckName = C.RuleFilePath; // Build/Get Rulebase File Name.
  106. ConfigFileCheckName = C.ConfigFilePath; // Build/Get Configuration File Name.
  107. IgnoreListCheckFileName = C.paths_workspace_path; // Build/Get Ignore File Name.
  108. IgnoreListCheckFileName.append("GBUdbIgnoreList.txt");
  109. RulebaseFileTimestamp = getFileTimestamp(RulebaseFileCheckName); // Timestamps to check for
  110. ConfigurationTimestamp = getFileTimestamp(ConfigFileCheckName); // changes in configuration data
  111. IgnoreListTimestamp = getFileTimestamp(IgnoreListCheckFileName); // or rulebase files.
  112. }
  113. bool snf_Reloader::StatsAreDifferent() { // Check file stats for changes.
  114. return ( // Return true if any of the
  115. RulebaseFileTimestamp != getFileTimestamp(RulebaseFileCheckName) || // Rulebase File, or the
  116. ConfigurationTimestamp != getFileTimestamp(ConfigFileCheckName) || // Configuration File, or the
  117. IgnoreListTimestamp != getFileTimestamp(IgnoreListCheckFileName) // Ignore List File have changed.
  118. );
  119. }
  120. const int MSPerSec = 1000; // 1000 milliseconds per second.
  121. void snf_Reloader::captureGetterConfig() { // Update RulebaseGetter config.
  122. snfCFGData& C = *(MyRulebase.MyCFGmgr.ActiveConfiguration()); // Reference the active config.
  123. RulebaseGetterIsTurnedOn = ( // Is the script caller on or off?
  124. true == C.update_script_on_off && // We're on if the bit is set and
  125. 0 < C.update_script_call.length() // we have a non-empty script to call.
  126. );
  127. if(RulebaseGetterIsTurnedOn) { // If it is turned on:
  128. RulebaseGetter.SystemCall(C.update_script_call); // Set the script call and
  129. RulebaseGetter.GuardTime(C.update_script_guard_time * MSPerSec); // the cycle guard time.
  130. }
  131. else { // If the scripter is turned off:
  132. RulebaseGetter.SystemCall(""); // Set the script to nothing.
  133. }
  134. }
  135. const std::string snfReloadContext = "--RELOADING--"; // Context for info and error logs.
  136. void snf_Reloader::myTask() { // How do we do this refresh thing?
  137. cd::Sleeper WaitATic(1000); // Wait a second between checks.
  138. while(!TimeToStop) { // While it's not time to stop:
  139. if(
  140. RulebaseGetterIsTurnedOn && // If our rulebase getter is enabled
  141. MyRulebase.MyLOGmgr.isUpdateAvailable() // and a new rulebase is availalbe:
  142. ) {
  143. RulebaseGetter.trigger(); // Trigger the update script (if any).
  144. }
  145. if(StatsAreDifferent()) { // Check the stats. If different:
  146. try { // safely attempt a reload.
  147. WaitATic(); // Wait a tic to let things stabilize
  148. MyRulebase.refresh(); // then call refresh on the handler.
  149. captureFileStats(); // If it works, capture the new stats.
  150. captureGetterConfig(); // Also update the RulebaseGetter.
  151. MyRulebase.logThisInfo( // Log our success.
  152. snfReloadContext, snf_SUCCESS, "Success");
  153. }
  154. catch(const snf_RulebaseHandler::IgnoreListError&) { // If we get an IgnoreListError - say so.
  155. MyRulebase.logThisError(
  156. snfReloadContext, snf_ERROR_RULE_FILE, "IgnoreListError");
  157. }
  158. catch(const snf_RulebaseHandler::ConfigurationError&) { // If we get a ConfigurationError - say so.
  159. MyRulebase.logThisError(
  160. snfReloadContext, snf_ERROR_RULE_FILE, "ConfigurationError");
  161. }
  162. catch(const snf_RulebaseHandler::FileError&) { // If we get a FileError - say so.
  163. MyRulebase.logThisError(
  164. snfReloadContext, snf_ERROR_RULE_FILE, "FileError");
  165. }
  166. catch(const snf_RulebaseHandler::AuthenticationError&) { // If we get a Auth Error - say so.
  167. MyRulebase.logThisError(
  168. snfReloadContext, snf_ERROR_RULE_AUTH, "AuthError");
  169. }
  170. catch(const snf_RulebaseHandler::Busy&) { // If we get a Busy Exception - say so.
  171. MyRulebase.logThisError(
  172. snfReloadContext, snf_ERROR_UNKNOWN, "BusyError");
  173. }
  174. catch(const snf_RulebaseHandler::Panic&) { // If we get a Panic - say so.
  175. MyRulebase.logThisError(
  176. snfReloadContext, snf_ERROR_UNKNOWN, "PanicError");
  177. }
  178. catch(...) { // If we get some other error - shout!
  179. MyRulebase.logThisError(
  180. snfReloadContext, snf_ERROR_UNKNOWN, "UnhandledError");
  181. }
  182. }
  183. WaitATic(); // Wait before the next loop.
  184. }
  185. }
  186. const cd::ThreadType snf_Reloader::Type("snf_Reloader"); // The thread's type.
  187. snf_Reloader::snf_Reloader(snf_RulebaseHandler& R) : // When we are created, we
  188. Thread(snf_Reloader::Type, "Reloader"), // brand and name our thread.
  189. MyRulebase(R), // Capture the rulebase handler.
  190. TimeToStop(false), // It's not time to stop yet.
  191. RulebaseGetter("RulebaseGetter"), // Setup our ScriptCaller thread.
  192. RulebaseGetterIsTurnedOn(false) { // Rulebase getter is off at first.
  193. captureFileStats(); // Set up the initial stats.
  194. captureGetterConfig(); // Set up RulebaseGetter config.
  195. run(); // Run our maintenenace thread.
  196. }
  197. snf_Reloader::~snf_Reloader() { // When we are destroyed we
  198. TimeToStop = true; // set our time to stop bit
  199. join(); // and wait for the thread.
  200. }
  201. //// snfCFGPacket Methods
  202. snfCFGPacket::snfCFGPacket(snf_RulebaseHandler* R) : // When we are created:
  203. MyRulebase(R), // Capture our rulebase handler and
  204. MyTokenMatrix(NULL), // ready our token matrix and
  205. MyCFGData(NULL) { // cfg pointers.
  206. if(MyRulebase) { MyRulebase->grab(*this); } // Safely grab our rulebase.
  207. }
  208. snfCFGPacket::~snfCFGPacket() { if(MyRulebase) MyRulebase->drop(*this); } // Safely drop our rulebase when we die.
  209. TokenMatrix* snfCFGPacket::Tokens() { return MyTokenMatrix; } // Consumers read the Token Matrix and
  210. snfCFGData* snfCFGPacket::Config() { return MyCFGData; } // the snfCFGData.
  211. bool snfCFGPacket::bad() { // If anything is missing it's not good.
  212. return (NULL == MyTokenMatrix || NULL == MyCFGData); // True if any of these aren NULL.
  213. }
  214. bool snfCFGPacket::isRulePanic(int R) { // Test for a rule panic.
  215. return(RulePanics.end() != RulePanics.find(R)); // Find it in the list, it's a panic.
  216. }
  217. //// Rulebase Handler Methods
  218. snf_RulebaseHandler::~snf_RulebaseHandler(){ // Destruct the handler.
  219. close(); // Close before we go.
  220. }
  221. bool snf_RulebaseHandler::isReady(){ // Is the object ready?
  222. return (NULL!=Rulebase); // Have Rulebase? We're ready.
  223. }
  224. bool snf_RulebaseHandler::isBusy(){ // Is a refresh/open in progress or
  225. return (RefreshInProgress || 0<RetiringCount); // an older rulebase is not yet retired.
  226. }
  227. int snf_RulebaseHandler::getReferenceCount(){ // How many Engines using this handler.
  228. return ReferenceCount; // Tell them the count bob.
  229. }
  230. int snf_RulebaseHandler::getCurrentCount(){ // How many Engines active in the current rb.
  231. return CurrentCount; // Tell them what it is bob.
  232. }
  233. int snf_RulebaseHandler::getRetiringCount(){ // How many Engines active in the old rb.
  234. return RetiringCount; // Tell them what it is bob.
  235. }
  236. // FileUTC(FileName) - utility function for tagging the active rulebase
  237. cd::RuntimeCheck FileUTCGoodTimestampLength("SNFMulti.cpp:FileUTC snprintf(...) == CorrectTimestampLength");
  238. std::string FileUTC(std::string FileName) { // Gets a files UTC.
  239. struct stat FileNameStat; // First we need a stat buffer.
  240. std::string t; // We also need a Timestamp holder.
  241. if(0 != stat(FileName.c_str(), &FileNameStat)) { // If we can't get the stat we
  242. t.append("00000000000000"); return t; // will return all zeroz to
  243. } // make sure we should get the file.
  244. struct tm FileNameTime; // Allocate a time structure.
  245. FileNameTime = *(gmtime(&FileNameStat.st_mtime)); // Copy the file time to it as UTC.
  246. char TimestampBfr[16]; // Timestamp buffer.
  247. size_t l = snprintf( // Format yyyymmddhhmmss
  248. TimestampBfr, sizeof(TimestampBfr),
  249. "%04d%02d%02d%02d%02d%02d",
  250. FileNameTime.tm_year+1900,
  251. FileNameTime.tm_mon+1,
  252. FileNameTime.tm_mday,
  253. FileNameTime.tm_hour,
  254. FileNameTime.tm_min,
  255. FileNameTime.tm_sec
  256. );
  257. const size_t CorrectTimestampLength = 4+2+2+2+2+2;
  258. FileUTCGoodTimestampLength(l == CorrectTimestampLength);
  259. t.append(TimestampBfr); // Append the timestamp to t
  260. return t; // and return it to the caller.
  261. }
  262. // Auto Reload Controls
  263. bool snf_RulebaseHandler::AutoRefresh(bool On) { // Turn on/off auto refresh.
  264. if(On) { // If they want Reload On:
  265. if(!AutoRefresh()) { // and it isn't already on:
  266. try { MyReloader = new snf_Reloader(*this); } // try to set up a Reloader.
  267. catch(...) { MyReloader = 0; } // If that fails we don't
  268. } // have one. If it's already
  269. } // on do nothing.
  270. else { // If they want Reload Off:
  271. if(AutoRefresh()) { // and it is turned on:
  272. delete MyReloader; // destroy the reloader and
  273. MyReloader = 0; // zero it's pointer.
  274. }
  275. }
  276. return AutoRefresh(); // Return the truth (on/off)
  277. }
  278. bool snf_RulebaseHandler::AutoRefresh() { // True if AutoRefresh is on.
  279. return (0 != MyReloader); // If we have one, it's on.
  280. }
  281. // _snf_LoadNewRulebase()
  282. // This is actually a common sub-funtion. It expects that the object is in the "RefreshInProgress" state,
  283. // and that everything is in place and safe for a new rulebase to be loaded into the object. Once it's
  284. // done it will reset from the "RefreshInProgress" state and along the way will throw any errors that
  285. // are appropriate. The other functions can count on this one to polish off the various forms of rulebase
  286. // load activity.
  287. const cd::LogicCheck SaneRefreshProcessCheck("snf_RulebaseHandler::_snf_LoadNewRulebase():SaneRefreshProcessCheck(RefreshInProgress)");
  288. void snf_RulebaseHandler::_snf_LoadNewRulebase(){ // Common internal load/check routine.
  289. SaneRefreshProcessCheck(RefreshInProgress); // We only get called when this flag is set.
  290. try { MyCFGmgr.load(); } // Load a fresh copy of the configuration.
  291. catch(...) { // If something goes wrong:
  292. RefreshInProgress = false; // we are no longer "in refresh"
  293. throw ConfigurationError("_snf_LoadNewRulebase() MyCFGmgr.load() failed"); // throw the Configuration exception.
  294. }
  295. std::string RuleFilePath = MyCFGmgr.RuleFilePath(); // Get our rulebase file path and our
  296. std::string SecurityKey = MyCFGmgr.SecurityKey(); // security key from the CFG manager.
  297. if(0>=RuleFilePath.length()) { // If we don't have a path, we're hosed.
  298. RefreshInProgress = false; // We are no longer "in refresh"
  299. throw FileError("_snf_LoadNewRulebase() Zero length RuleFilePath"); // Can't load a RB file with no path!
  300. }
  301. if(0>=SecurityKey.length()) { // No security string? toast!
  302. RefreshInProgress = false; // We are no longer "in refresh"
  303. throw AuthenticationError("snf_LoadNewRulebase() Zero length SecurityKey"); // Can't authenticate without a key!
  304. }
  305. // Notify sub modules of the new configuration data.
  306. MyGeneration++; // Increment the generation number.
  307. snfCFGData& CFGData = (*(MyCFGmgr.ActiveConfiguration())); // Capture the active config...
  308. CFGData.Generation = MyGeneration; // Tag the configuration data.
  309. MyLOGmgr.configure(CFGData); // Update the LOGmgr's configuration.
  310. MyNETmgr.configure(CFGData); // Update the NETmgr's configuration.
  311. MyGBUdbmgr.configure(CFGData); // Update the GBUdbmgr's configuration.
  312. // Load the new rulebase locally (on stack) and see if it authenticates.
  313. TokenMatrix* TryThis = NULL; // We need our candidate to remain in scope.
  314. try { // This try block decodes the problem.
  315. try { // This try block does cleanup work.
  316. TryThis = new TokenMatrix(); // Grab a new Token Matrix
  317. TryThis->Load(RuleFilePath); // Load it from the provided file path
  318. TryThis->Validate(SecurityKey); // Validate it with the provided security key
  319. TryThis->Verify(SecurityKey); // Verify that it is not corrupt.
  320. }
  321. catch(...) { // Clean up after any exceptions.
  322. RefreshInProgress = false; // We're not refreshing now.
  323. if(TryThis) { // If we allocated a TokenMatrix then
  324. delete TryThis; // we need to reclaim the memory
  325. TryThis = 0; // and erase the pointer.
  326. } // With everything nice and clean we can
  327. throw; // rethrow he exception for decoding.
  328. }
  329. } // If nothing threw, we're golden!
  330. catch (const TokenMatrix::BadFile&) { // BadFile translates to FileError
  331. throw FileError("_snf_LoadNewRulebase() TokenMatrix::BadFile");
  332. }
  333. catch (const TokenMatrix::BadMatrix&) { // BadMatrix translates to AuthenticationError
  334. throw AuthenticationError("_snf_LoadNewRulebase() TokenMatrix::BadMatrix");
  335. }
  336. catch (const TokenMatrix::BadAllocation&) { // BadAllocation translates to AllocationError
  337. throw AllocationError("_snf_LoadNewRulebase() TokenMatrix::BadAllocation");
  338. }
  339. catch (const TokenMatrix::OutOfRange&) { // OutOfRange should never happen so PANIC!
  340. throw Panic("_snf_LoadNewRulebase() TokenMatrix::OutOfRange");
  341. }
  342. catch (...) { // Something unpredicted happens? PANIC!
  343. throw Panic("_snf_LoadNewRulebase() TokenMatrix.load() ???");
  344. }
  345. // At this point the rulebase looks good. If we need to go big-endian do it!
  346. #ifdef __BIG_ENDIAN__
  347. TryThis->FlipEndian(); // Flip tokens to big-endian format.
  348. #endif
  349. MyLOGmgr.updateActiveUTC(FileUTC(RuleFilePath)); // Update the Active Rulebase UTC.
  350. MyMutex.lock(); // Lock the mutex while changing state.
  351. OldRulebase = Rulebase; // Move the current rulebase and count to
  352. RetiringCount = CurrentCount; // the retiring slot.
  353. if(0>=RetiringCount && NULL!=OldRulebase) { // If nobody cares about the old rulebase
  354. delete OldRulebase; // then delete it, and wipe everything
  355. OldRulebase = NULL; // clean for the next retiree.
  356. RetiringCount = 0;
  357. }
  358. CurrentCount = 0; // Set the current count to zero (it's fresh!)
  359. Rulebase = TryThis; // Copy our new rulebase into production.
  360. MyMutex.unlock(); // Release the hounds!!!
  361. // If there is a GBUdb Ignore List, refresh with it (This might go elsewhere).
  362. // Failure to read the GBUdbIgnoreList if all else went well does not cause
  363. // the rulebase update (if any) to fail.
  364. /**** This section needs work ****/
  365. try {
  366. std::string IgnoreListPath = CFGData.paths_workspace_path;
  367. IgnoreListPath.append("GBUdbIgnoreList.txt");
  368. if(0 == MyGBUdb.readIgnoreList(IgnoreListPath.c_str())) // We must have at least 1 IP listed.
  369. throw ConfigurationError(
  370. "_snf_LoadNewRulebase() GBUdbIgnoreList min 1 entry!");
  371. }
  372. catch(...) { // Ignore list read might fail.
  373. RefreshInProgress = false; // If so, don't keep things hung.
  374. throw IgnoreListError("_snf_LoadNewRulebase() readIgnoreList() ???"); // If it does, throw FileError.
  375. }
  376. RefreshInProgress = false; // Done with the refresh process.
  377. return; // Our work is done here.
  378. }
  379. // open()
  380. // This loads a new rulebase (usually the first one only) into the handler. This is the first of two loading
  381. // methods on this object. This one checks for isBusy() because it is highly invasive. If it is called after
  382. // the object has been running it is important that it not run while anything in the object is active. This
  383. // is because it is likely in this case we would be loading an entirely new rulebase that would lead to odd
  384. // results if some scanner instances were activily using a different one.
  385. void snf_RulebaseHandler::open(const char* path, const char* licenseid, const char* authentication){
  386. MyMutex.lock(); // Lock the mutex while changing state.
  387. if(isBusy()) { // Be sure we're not busy.
  388. MyMutex.unlock(); throw Busy("snf_RulebaseHandler::open() busy"); // If we are then throw.
  389. }
  390. RefreshInProgress = true; // Set RefreshInProgress.
  391. MyMutex.unlock(); // Unlock the mutex and
  392. MyCFGmgr.initialize(path, licenseid, authentication); // Initialize our configuration.
  393. _snf_LoadNewRulebase(); // get on with loading the rulebase.
  394. MyGBUdbmgr.load(); // Load the GBUdb as configured.
  395. AutoRefresh(true); // Turn on Refresh by default.
  396. logThisInfo("--INITIALIZING--", 0, "Success"); // Log the happy event.
  397. return;
  398. }
  399. // refresh()
  400. // This loads a fresh copy of the current rulebase. This is the second loading method on the object. It is
  401. // specifically designed to work without stopping scanning activities. This one checks for isBusy() because
  402. // there may be an old rulebase that is not yet completely retired --- that is, some scanners may be using it.
  403. // If there is still an old rulebase on it's way out then we can't shove it aside without breaking something,
  404. // so we have to throw.
  405. //
  406. // Under normal circumstances, this call will cause a new rulebase to be loaded without disturbing any scans
  407. // underway on the current rulebase. The current rulebase will be put into retirement while any active scans
  408. // are completed, and then it will quietly go away when the last has finished. The new rulebase will take it's
  409. // place and will be handed out to all new grab() requests.
  410. void snf_RulebaseHandler::refresh(){ // Reloads the rulebase.
  411. MyMutex.lock(); // Lock the mutex while changing states.
  412. if(isBusy()) { // If we're busy then throw.
  413. MyMutex.unlock(); throw Busy("snf_RulebaseHandler::refresh() busy");
  414. }
  415. RefreshInProgress = true; // Set RefreshInProgress and
  416. MyMutex.unlock(); // unlock the mutex. Then get on with
  417. _snf_LoadNewRulebase(); // loading a fresh copy of the rulebase
  418. return;
  419. }
  420. void snf_RulebaseHandler::close(){ // Closes this handler.
  421. try {
  422. AutoRefresh(false); // Stop AutoRefresh if it's on.
  423. }
  424. catch(const std::exception& e) { throw e; } // Rethrow good exceptions.
  425. catch(...) { throw Panic("snf_RulebaseHandler::close() AutoRefresh(false) panic!"); } // Panic blank exceptions.
  426. try {
  427. MyXCImgr.stop(); // Stop the XCI manager.
  428. }
  429. catch(const std::exception& e) { throw e; } // Rethrow good exceptions.
  430. catch(...) { throw Panic("snf_RulebaseHandler::close() MyXCImgr.stop() panic!"); } // Panic blank exceptions.
  431. if(isBusy() || 0<CurrentCount || 0<ReferenceCount) { // Check that there is no activity.
  432. throw Busy("snf_RulebaseHandler::close() busy"); // With XCI stopped we should not
  433. } // be busy.
  434. try {
  435. MyLOGmgr.stop(); // Stop the LOG manager.
  436. }
  437. catch(const std::exception& e) { throw e; } // Rethrow good exceptions.
  438. catch(...) { throw Panic("snf_RulebaseHandler::close() MyLOGmgr.stop() panic!"); } // Panic blank exceptions.
  439. try {
  440. MyNETmgr.stop(); // Stop the NET manager.
  441. }
  442. catch(const std::exception& e) { throw e; } // Rethrow good exceptions.
  443. catch(...) { throw Panic("snf_RulebaseHandler::close() MyNETmgr.stop() panic!"); } // Panic blank exceptions.
  444. try {
  445. MyGBUdbmgr.stop(); // Stop the GBUdb manager.
  446. }
  447. catch(const std::exception& e) { throw e; } // Rethrow good exceptions.
  448. catch(...) { throw Panic("snf_RulebaseHandler::close() MyGBUdbmgr.stop() panic!"); } // Panic blank exceptions.
  449. try {
  450. if(NULL!=Rulebase) {delete Rulebase; Rulebase=NULL;} // If we have a Rulebase destroy it.
  451. }
  452. catch(const std::exception& e) { throw e; } // Rethrow good exceptions.
  453. catch(...) { throw Panic("snf_RulebaseHandler::close() delete Rulebase panic!"); } // Panic blank exceptions.
  454. try {
  455. if(NULL!=OldRulebase) {delete OldRulebase; OldRulebase=NULL;} // Shouldn't happen, but just in case.
  456. }
  457. catch(const std::exception& e) { throw e; } // Rethrow good exceptions.
  458. catch(...) { throw Panic("snf_RulebaseHandler::close() delete OldRulebase panic!"); } // Panic blank exceptions.
  459. }
  460. void snf_RulebaseHandler::use(){ // Make use of this Rulebase Handler.
  461. MyMutex.lock(); // Lock the object
  462. ReferenceCount++; // Boost the count
  463. MyMutex.unlock(); // Unlock the object
  464. }
  465. void snf_RulebaseHandler::unuse(){ // Finish with this Rulebase Handler.
  466. MyMutex.lock(); // Lock the object
  467. ReferenceCount--; // Reduce the count
  468. MyMutex.unlock(); // Unlock the object
  469. }
  470. // A word about Generation... In practice whenever the configuration or rulebase
  471. // changes the entire thing is reloaded. The Generation() function gives other
  472. // modules a way to know if they need to update their interpretation of the
  473. // configuration. They can keep track of the last Generation value they got and
  474. // compare it to the latest Generation. If the two are different then they need
  475. // to update their configuration - just in case it has changed.
  476. int snf_RulebaseHandler::Generation() { return MyGeneration; } // Returns the generation number.
  477. // A word about autopanics.
  478. // The first time throgh this we outsmarted ourselves with an ellaborate
  479. // wait-to-insert scheme. That led to the possibilty of a deadlock. Now we
  480. // copy the (usually empty or very short) set of rule panics to the
  481. // configuration packet when it is grabbed and only use the one mutext to hold
  482. // the configuration steady while doing so. All queries are made to the local
  483. // copy of the panic list and all writes are made, under mutex, to the active
  484. // configuration. Simpler, no significant penalty, and no more deadlocks.
  485. // A word about configuration packets.
  486. // Along the way we simplified things by making the snfCFGPacket do it's own
  487. // grab and drop upon construction and destruction. This way we don't have to
  488. // remember to handle all possible cases during a scan or other opertion -- once
  489. // the operation goes out of scope the configuration packet drop()s with it.
  490. void snf_RulebaseHandler::grab(snfCFGPacket& CP) { // Activate this Rulebase.
  491. cd::ScopeMutex HoldStillPlease(MyMutex); // Lock the rulebase until we're done.
  492. CurrentCount++; // Boost the count for myself.
  493. CP.MyTokenMatrix = Rulebase; // Grab the current rulebase.
  494. CP.MyCFGData = MyCFGmgr.ActiveConfiguration(); // Grab the active configuration.
  495. CP.RulePanics = MyCFGmgr.ActiveConfiguration()->RulePanicHandler.IntegerSet; // Copy the RulePanic set.
  496. }
  497. void snf_RulebaseHandler::drop(snfCFGPacket& CP) { // Deactiveate this Rulebase.
  498. const TokenMatrix* t = CP.MyTokenMatrix; // Grab the token matrix pointer.
  499. CP.MyCFGData = NULL; // Null the configuration pointer.
  500. cd::ScopeMutex HoldStillPlease(MyMutex); // Lock the rulebase until we're done.
  501. if(t==Rulebase) { // If we're dropping the current rulebase
  502. CurrentCount--; // then reduce the current count.
  503. } else // If not that then...
  504. if(t==OldRulebase) { // If we're dropping the old rulebase
  505. RetiringCount--; // reduce the retiring count and check...
  506. if(0>=RetiringCount) { // to see if it is completely retired.
  507. if(NULL!=OldRulebase) delete OldRulebase; // If it is then delete it and
  508. OldRulebase = NULL; RetiringCount = 0; // reset it's pointer and counter.
  509. }
  510. } else { // If we're dropping something else,
  511. throw Panic("snf_RulebaseHandler::drop() panic"); // it is time to panic, so, then PANIC!
  512. }
  513. }
  514. // When adding a rule panic entry the rulebase and configuration state cannot
  515. // be changed, nor grabbed by an snfCFGPacket. This ensures that the IntegerSet
  516. // is only adjusted by one thread at a time and that any threads using the set
  517. // will have a consistent result based on their last grab().
  518. void snf_RulebaseHandler::addRulePanic(int RuleID) { // Add a rule panic id dynamically.
  519. cd::ScopeMutex JustMe(MyMutex); // Freeze the rulebase while we adjust
  520. MyCFGmgr.ActiveConfiguration() // the active configuration to
  521. ->RulePanicHandler.IntegerSet.insert(RuleID); // insert the new rule panic ruleid.
  522. } // When we're done, unlock and move on.
  523. IPTestRecord& snf_RulebaseHandler::performIPTest(IPTestRecord& I) { // Perform an IP test.
  524. snfCFGPacket MyCFGPacket(this); // We need a CFG packet.
  525. try { // Safely process the IP.
  526. if(false == MyCFGPacket.bad()) { // If we've got a good packet:
  527. I.G = MyGBUdb.getRecord(I.IP); // Lookup the IP in GBUdb.
  528. I.R = MyCFGPacket.Config()->RangeEvaluation(I.G); // Evaluate it's statistics.
  529. // Convert the RangeEvaluation into the configured Code
  530. switch(I.R) {
  531. case Unknown: // Unknown - not defined.
  532. case Normal: // Benefit of the doubt.
  533. case New: { // It is new to us.
  534. I.Code = 0; // Zero is the default - no code.
  535. break;
  536. }
  537. case White: { // This is a good guy.
  538. I.Code = MyCFGPacket.Config()->WhiteRangeHandler.Symbol;
  539. break;
  540. }
  541. case Caution: { // This is suspicious.
  542. I.Code = MyCFGPacket.Config()->CautionRangeHandler.Symbol;
  543. break;
  544. }
  545. case Black: { // This is bad.
  546. I.Code = MyCFGPacket.Config()->BlackRangeHandler.Symbol;
  547. break;
  548. }
  549. case Truncate: { // Don't even bother looking.
  550. I.Code = MyCFGPacket.Config()
  551. ->gbudb_regions_black_truncate_symbol;
  552. break;
  553. }
  554. }
  555. } // If something is broken we punt.
  556. } catch (...) {} // Ignore exceptions (none expected)
  557. return I; // Return the processed record.
  558. }
  559. void snf_RulebaseHandler::logThisIPTest(IPTestRecord& I, std::string Action) { // Log an IP test result & action.
  560. MyLOGmgr.logThisIPTest(I, Action);
  561. }
  562. void snf_RulebaseHandler::logThisError( // Log an error message.
  563. std::string ContextName, int Code, std::string Text
  564. ) {
  565. MyLOGmgr.logThisError(ContextName, Code, Text);
  566. }
  567. void snf_RulebaseHandler::logThisInfo( // Log an informational message.
  568. std::string ContextName, int Code, std::string Text
  569. ) {
  570. MyLOGmgr.logThisInfo(ContextName, Code, Text);
  571. }
  572. std::string snf_RulebaseHandler::PlatformVersion(std::string NewPlatformVersion) { // Set platform version info.
  573. return MyLOGmgr.PlatformVersion(NewPlatformVersion);
  574. }
  575. std::string snf_RulebaseHandler::PlatformVersion() { // Get platform version info.
  576. return MyLOGmgr.PlatformVersion();
  577. }
  578. std::string snf_RulebaseHandler::PlatformConfiguration() { // Get platform configuration.
  579. cd::ScopeMutex LockAndGrab(MyMutex); // Freeze things for a moment and
  580. return MyCFGmgr.ActiveConfiguration()->PlatformElementContents; // copy the platform configuration.
  581. }
  582. std::string snf_RulebaseHandler::EngineVersion() { // Get engine version info.
  583. return MyLOGmgr.EngineVersion();
  584. }
  585. void snf_RulebaseHandler::
  586. XCIServerCommandHandler(snfXCIServerCommandHandler& XCH) { // Registers a new XCI Srvr Cmd handler.
  587. cd::ScopeMutex ThereCanBeOnlyOne(XCIServerCommandMutex); // Serialize access to this resource.
  588. myXCIServerCommandHandler = &XCH; // Assign the new handler as provided.
  589. }
  590. std::string snf_RulebaseHandler::processXCIServerCommandRequest(snf_xci& X) { // Handle a parsed XCI Srvr Cmd request.
  591. cd::ScopeMutex ThereCanBeOnlyOne(XCIServerCommandMutex); // Serialize access to this resource.
  592. if(0 == myXCIServerCommandHandler) { // If we don't have a handler then
  593. snfXCIServerCommandHandler H; // create a base handler and
  594. return H.processXCIRequest(X); // return it's default response.
  595. } // If we do have a handler then pass
  596. return myXCIServerCommandHandler->processXCIRequest(X); // on the request and return the
  597. } // response.
  598. //// snf_IPTestEngine Methods
  599. snf_IPTestEngine::snf_IPTestEngine() : // The constructor is simple - it
  600. Lookup(NULL), ScanData(NULL) { // sets up our internal references.
  601. } // Before use these must be set.
  602. void snf_IPTestEngine::setGBUdb(GBUdb& G) { // Here's how we set the GBUdb.
  603. Lookup = &G;
  604. }
  605. void snf_IPTestEngine::setScanData(snfScanData& S) { // Here's how we set the ScanData object.
  606. ScanData = &S;
  607. }
  608. void snf_IPTestEngine::setCFGData(snfCFGData& C) { // Here's how we set the CFGData.
  609. CFGData = &C;
  610. }
  611. void snf_IPTestEngine::setLOGmgr(snfLOGmgr& L) { // Here's how we set the LOGmgr.
  612. LOGmgr = &L;
  613. }
  614. // 20090127 _M Added special handling for forced IP sources. First, they are
  615. // always considered the source and second if they are in the GBUdb ignore list
  616. // then GBUdb training bypass is established.
  617. std::string& snf_IPTestEngine::test(std::string& input, std::string& output) { // Perform IP lookups and put IPs into ScanData.
  618. if(NULL == Lookup || NULL == ScanData) { // If we are not set up properly then we
  619. output = "{IPTest Config Error}"; // will return an error string.
  620. return output;
  621. }
  622. try { // If we're out of IP records, no analysis.
  623. IPScanRecord& I = ScanData->newIPScanRecord(); // Grab a new IP scan record and
  624. cd::IP4Address IP = input; // Convert the string to an IP.
  625. // Identify forced Source IP addresses
  626. bool ThisSourceIsForced = ( // This IP is a forced source IP if:
  627. (0 == I.Ordinal) && ( // we are looking at the first IP and
  628. (0UL != ScanData->CallerForcedSourceIP()) || // either the Caller forced the IP or
  629. (0UL != ScanData->HeaderDirectiveSourceIP()) // the IP was forced by a header directive.
  630. )
  631. );
  632. // Bad IPs are possible, especially if the source was forced. In that
  633. // case forced source IP is meaningless so we want to ignore it and
  634. // we want to make the case visible in the logs. An ordinary IP that
  635. // is invalid has no consequence so we simply skip those.
  636. // Note that a source IP that has it's ignore flag set causes an
  637. // implied training bypass inside the scan function. Setting the bad
  638. // IP as the source and setting it's ignore flag will have the desired
  639. // effect.
  640. if(0UL == IP) { // If we got a 0 or a bad conversion then
  641. output = "{0.0.0.0 Is Not A Usable IP}"; // we won't be testing this IP.
  642. if(ThisSourceIsForced) { // If this ip is a forced source then
  643. I.GBUdbData.Flag(Ignore); // we will force a training bypass,
  644. ScanData->SourceIPRecord(I); // we will record it as the source,
  645. ScanData->SourceIPEvaluation = output; // and capture the error output.
  646. }
  647. return output;
  648. }
  649. if(0xFFFFFFFF == IP) { // If we got a 255.255.255.255 then
  650. output = "{255.255.255.255 Is Not A Usable IP}"; // we won't be testing this IP.
  651. if(ThisSourceIsForced) { // If this ip is a forced source then
  652. I.GBUdbData.Flag(Ignore); // we will force a training bypass,
  653. ScanData->SourceIPRecord(I); // we will record it as the source,
  654. ScanData->SourceIPEvaluation = output; // and capture the error output.
  655. }
  656. return output;
  657. }
  658. GBUdbRecord R = Lookup->getRecord(IP); // Get the GBUdb record for it.
  659. I.IP = IP; // store the IP and the
  660. I.GBUdbData = R; // GBUdb record we retrieved.
  661. output = "{"; // Next we start to build our IP data insert.
  662. std::ostringstream S; // We will use a string stream for formatting.
  663. switch(R.Flag()) { // Identify the flag data for this IP.
  664. case Good: S << "Good "; break;
  665. case Bad: S << "Bad "; break;
  666. case Ugly: S << "Ugly "; break;
  667. case Ignore: S << "Ignore "; break;
  668. }
  669. S << "c=" << R.Confidence() << " " // Include the Confidence and
  670. << "p=" << R.Probability(); // Probability.
  671. // Process ordinary Source IP addresses
  672. if( // The message source IP address is the
  673. (false == ScanData->FoundSourceIP()) && // first IP we find that is either forced
  674. (ThisSourceIsForced || (Ignore != R.Flag())) // OR is NOT part of our infrastructure.
  675. ) { // When we find the correct source IP:
  676. if( // Check to see if we're drilling down.
  677. (false == ThisSourceIsForced) && // We drill when the source is NOT forced
  678. (ScanData->isDrillDownSource(I)) // AND we have a matching drilldown.
  679. ) {
  680. Lookup->setIgnore(IP); // If we're drilling down ignore this IP.
  681. }
  682. else { // If not drilling down this is the source:
  683. ScanData->SourceIPRecord(I); // we log it in as the source
  684. S << " Source"; // and report our findings in our tag.
  685. // Since we are dealing with our source IP
  686. // this is a good place to evaluate our truncate feature.
  687. snfIPRange IPR =
  688. ScanData->SourceIPRange(CFGData->RangeEvaluation(R)); // Establish the IP range for this scan.
  689. // We will also emit a range identifier for pattern matches that might use it.
  690. switch(IPR) {
  691. case Unknown: { S << " Unknown"; break; } // Unknown - not defined.
  692. case White: { S << " White"; break; } // This is a good guy.
  693. case Normal: { S << " Normal"; break; } // Benefit of the doubt.
  694. case New: { S << " New"; break; } // It is new to us.
  695. case Caution: { S << " Caution"; break; } // This is suspicious.
  696. case Black: { S << " Black"; break; } // This is bad.
  697. case Truncate: { S << " Truncate"; break; } // Don't even bother looking.
  698. }
  699. ScanData->SourceIPEvaluation = S.str(); // Capture the source IP eval.
  700. // The RangeEvaluation() call above settles a lot of questions for us.
  701. // The Truncate return code only happens when the IP is either Bad w/
  702. // truncate turned on, or the statistics place the IP in the Truncate
  703. // range. If the Good flag is set the function always returns White so
  704. // here we only have to check for the Truncate flag.
  705. if(Truncate == IPR) { // If all of the conditions are met
  706. ScanData->GBUdbTruncateTriggered = true; // then Truncate has been triggered.
  707. ScanData->GBUdbPeekTriggered = LOGmgr->OkToPeek( // Since truncate was triggered, see if
  708. CFGData->gbudb_regions_black_truncate_peek_one_in); // we would also trigger a peek.
  709. // The reason we check the truncate on_off flag here is that the
  710. // IP range _may_ return a Truncate result if no Flags are set on
  711. // the IP and the IP is far enough into the black to reach the
  712. // Truncate threshold.
  713. if(CFGData->gbudb_regions_black_truncate_on_off) { // If truncate is on either peek or truncate.
  714. if(ScanData->GBUdbPeekTriggered) { // If a peek has been triggered then
  715. ScanData->GBUdbPeekExecuted = true; // mark the event and don't truncate.
  716. } else { // If a peek was not triggered then
  717. ScanData->GBUdbTruncateExecuted = true; // Record our trucnate action.
  718. output = ""; // Set up the truncate signal (empty string)
  719. return output; // and return it! We're done!
  720. }
  721. }
  722. }
  723. }
  724. }
  725. // If we're not truncating then we're going to return our IP evaulation tag
  726. // to the filter chain function module so it can emit it into the stream.
  727. output.append(S.str());
  728. output.append("}");
  729. }
  730. catch(snfScanData::NoFreeIPScanRecords) {
  731. output = "{too_many}";
  732. }
  733. catch(...) {
  734. output = "{fault}";
  735. }
  736. return output;
  737. }
  738. //// Engine Handler Methods
  739. snf_EngineHandler::~snf_EngineHandler(){ // Shutdown clenas up and checks for safety.
  740. if(isReady()) close(); // If we're live, close on our way out.
  741. }
  742. void snf_EngineHandler::open(snf_RulebaseHandler* Handler){ // Light up the engine.
  743. MyMutex.lock(); // Serialize this...
  744. if(isReady()) { // If we're already open then we need to
  745. MyMutex.unlock(); // unlock this object and let them know
  746. throw Busy("snf_EngineHandler::open() busy"); // we are busy.
  747. } // If we're not busy, then let's light it up.
  748. MyRulebase=Handler; // Install our rulebase handler.
  749. MyRulebase->use(); // Up the use count to let it know we're here.
  750. MyIPTestEngine.setGBUdb(MyRulebase->MyGBUdb); // Set up the IPTester's GBUdb.
  751. MyIPTestEngine.setScanData(MyScanData); // Set up the IPTester's ScanData reference.
  752. MyIPTestEngine.setLOGmgr(MyRulebase->MyLOGmgr); // Set up the IPTester's LOGmgr.
  753. MyMutex.unlock(); // Unlock our mutex, then...
  754. return; // our work is done.
  755. }
  756. bool snf_EngineHandler::isReady(){ // Is the Engine good to go?
  757. return (NULL!=MyRulebase); // Have rulebase will travel.
  758. }
  759. void snf_EngineHandler::close(){ // Close down the engine.
  760. MyMutex.lock(); // Serialize this...
  761. if(!isReady()){ // If we're not already open we can't close.
  762. MyMutex.unlock(); // Something is seriously wrong, so unlock
  763. throw Panic("snf_EngineHandler::close() !isReady panic"); // and hit the panic button!
  764. } // But, if everything is ok then we can
  765. MyRulebase->unuse(); // unuse our rulebase and quietly forget
  766. MyRulebase = NULL; // about it.
  767. if(NULL!=CurrentMatrix) { // If we have a leftover evaluation matrix
  768. delete CurrentMatrix; // we can let that go and forget about
  769. CurrentMatrix = NULL; // it as well.
  770. }
  771. MyMutex.unlock(); // Finally, we unlock our mutex and...
  772. return; // Our work is done here.
  773. }
  774. enum PatternResultTypes { // To train GBUdb we need a generalized
  775. NoPattern, // way to evaluate the results from the
  776. WhitePattern, // snf pattern matching scan.
  777. BlackPattern,
  778. IPPattern,
  779. AboveBandPattern
  780. };
  781. // In order to optimize message file reads when header injection is not activated
  782. // we need to look ahead to see if header injection is likely to be turned on when
  783. // we do the scan. This is a short term fix. The better fix might be to perform
  784. // the configuration load prior to scanning the message -- but that is a much larger
  785. // refactoring that ties up configuration and rulebase resources for a longer time.
  786. // Instead we're going to take an optimistic route and just peek at the configuration.
  787. // If the configuration changes while we're loading the file to be scanned then
  788. // we have two cases. If we go from XHDRInject off to XHDRInject on then we will
  789. // miss adding headers to the message - not a bad outcome. If we go from XHDRInject
  790. // on to XHDRInject off then we might emit headers for an extra message - also not
  791. // a bad outcome.
  792. bool snf_RulebaseHandler::testXHDRInjectOn() {
  793. cd::ScopeMutex HoldStillPlease(MyMutex); // Lock the rulebase until we're done.
  794. snfCFGData* myCFG = MyCFGmgr.ActiveConfiguration(); // Grab the active configuration.
  795. bool myXHDRInjectOnFlag = (LogOutputMode_Inject == myCFG->XHDROutput_Mode); // True if output mode is inject.
  796. return myXHDRInjectOnFlag; // return the result.
  797. }
  798. int snf_EngineHandler::scanMessageFile( // Scan this message file.
  799. const std::string MessageFilePath, // -- this is the file path (and id)
  800. const int MessageSetupTime, // -- setup time already used.
  801. const cd::IP4Address MessageSource // -- message source IP (for injection).
  802. ) {
  803. cd::Timer AdditionalSetupTime;
  804. cd::ScopeMutex DoingAFileScan(FileScan); // Protect MyScanData @ this entry.
  805. // Preliminary setup. Clearing the ScanData resets the ReadyToClear flag
  806. // and allows us to set some data for more accurate tracking and so that if
  807. // something goes wrong the ScanData will be helpful in determining the
  808. // state of the engine.
  809. MyScanData.clear(); // Clear the scan data.
  810. MyScanData.StartOfJobUTC = MyRulebase->MyLOGmgr.Timestamp(); // Set the job start timestamp.
  811. MyScanData.ScanName = MessageFilePath;
  812. // Now that the preliminaries are established we can begin our work.
  813. int MessageFileSize = 0; // Here will be the size of it.
  814. std::ifstream MessageFile; // Here will be our input file.
  815. MessageFile.exceptions( // It will throw exceptions for
  816. std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit // these unwanted events.
  817. );
  818. try { // Try opening the message file.
  819. MessageFile.open(MessageFilePath.c_str(),
  820. std::ios::in | std::ios::binary); // Open the file, binary mode.
  821. MessageFile.seekg(0, std::ios::end); // Find the end of the file,
  822. MessageFileSize = MessageFile.tellg(); // read that position as the size,
  823. MessageFile.seekg(0, std::ios::beg); // then go back to the beginning.
  824. MyScanData.ScanSize = MessageFileSize; // Capture the message file size.
  825. }
  826. catch(...) { // Trouble? Throw FileError.
  827. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  828. MyScanData, "scanMessageFile().open",
  829. snf_ERROR_MSG_FILE, "ERROR_MSG_FILE"
  830. );
  831. throw FileError("snf_EngineHandler::scanMessageFile() Open/Seek");
  832. }
  833. if(0 >= MessageFileSize) { // Handle zero length files.
  834. MessageFile.close(); // No need to keep this open.
  835. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  836. MyScanData, "scanMessageFile().isFileEmpty?",
  837. snf_ERROR_MSG_FILE, "ERROR_MSG_FILE"
  838. );
  839. throw FileError("snf_EngineHandler::scanMessageFile() FileEmpty!");
  840. }
  841. bool isXHeaderInjectionOn = MyRulebase->testXHDRInjectOn();
  842. bool noNeedToReadFullFile = (false == isXHeaderInjectionOn);
  843. if(noNeedToReadFullFile) {
  844. MessageFileSize = std::min(MessageFileSize, snf_ScanHorizon);
  845. }
  846. std::vector<unsigned char> MessageBuffer; // Allocate a buffer and size
  847. try { MessageBuffer.resize(MessageFileSize, 0); } // it to fit the message.
  848. catch(...) { // Trouble? Throw AllocationError.
  849. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  850. MyScanData, "scanMessageFile().alloc",
  851. snf_ERROR_MSG_FILE, "ERROR_MSG_ALLOC"
  852. );
  853. throw AllocationError("snf_EngineHandler::scanMessageFile() Alloc");
  854. }
  855. try { MessageFile.read((char*) &MessageBuffer[0], MessageFileSize); } // Read the file into the buffer.
  856. catch(...) {
  857. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  858. MyScanData, "scanMessageFile().read",
  859. snf_ERROR_MSG_FILE, "ERROR_MSG_READ"
  860. );
  861. throw FileError("snf_EngineHandler::scanMessageFile() Read");
  862. }
  863. MessageFile.close(); // Close the file.
  864. // Additional Setup Time will be captured as the call is made.
  865. int ScanResultCode = scanMessage( // Scan the message we've loaded.
  866. &MessageBuffer[0], // Here is the buffer pointer,
  867. MessageBuffer.size(), // here is the size of the message,
  868. MessageFilePath, // the path is the identifier,
  869. (AdditionalSetupTime.getElapsedTime() + MessageSetupTime), // and this is our setup time total.
  870. MessageSource // Pass on the source if provided.
  871. );
  872. // Inject headers if required.
  873. if(isXHeaderInjectionOn) { // If we are to inject headers:
  874. const char* XHDRInjStage = "Begin"; // Keep track of what we're doing.
  875. try {
  876. // The insertion point will be at the end of the existing headers.
  877. // We pick that point to be right between the two <cr><lf> so that
  878. // the first blank line will appear at the end of our headers.
  879. // We accommodate either <cr><lf> or <lf> line endings.
  880. // We are careful not to search past the end of unreasonably short
  881. // message files.
  882. unsigned int InsertPoint = 0; // Find the insertion point.
  883. bool UseLFOnly = false; // Use \n line endings in files?
  884. bool CRLFPresent = false; // Detected \r\n pairs?
  885. unsigned int BiggestPatternSize = 4; // How far we look ahead.
  886. bool BigEnoughMessage = BiggestPatternSize < MessageBuffer.size();
  887. if(BigEnoughMessage){
  888. unsigned int Limit = MessageBuffer.size() - BiggestPatternSize;
  889. bool DataWasSkipped = MessageBuffer.size() > MyScanData.ScanSize;
  890. unsigned int i = 0;
  891. if(DataWasSkipped) { // If our scanner skipped data at
  892. i = MessageBuffer.size() - MyScanData.ScanSize; // the top of the message buffer then
  893. } // we will skip it too.
  894. for(; i < Limit; i++) { // Search for the first blank line.
  895. if( // Detect CRLF pairs if present.
  896. false == CRLFPresent &&
  897. '\r' == MessageBuffer.at(i) &&
  898. '\n' == MessageBuffer.at(i + 1)
  899. ) CRLFPresent = true;
  900. if( // In a properly formatted RFC822
  901. '\r' == MessageBuffer.at(i) && // message that looks like
  902. '\n' == MessageBuffer.at(i + 1) && // <cr><lf><cr><lf>
  903. '\r' == MessageBuffer.at(i + 2) &&
  904. '\n' == MessageBuffer.at(i + 3)
  905. ) {
  906. InsertPoint = i + 2;
  907. break;
  908. } else
  909. if( // In some bizarre cases it might
  910. '\n' == MessageBuffer.at(i) && // look like <lf><lf>.
  911. '\n' == MessageBuffer.at(i + 1)
  912. ) {
  913. InsertPoint = i + 1;
  914. UseLFOnly = true; // We have to strip <CR> from our
  915. break; // injected header line ends.
  916. }
  917. }
  918. }
  919. // Here we must interpret the results of our search. Do we know where
  920. // our insert point is or do we punt and use the top of the message?
  921. if(0 == InsertPoint) { // No blank line? We need to punt.
  922. if(false == CRLFPresent) { // What kind of line ends do we use?
  923. UseLFOnly = true; // If no CRLF found use LF only.
  924. } // Either way we will be inserting
  925. } // our headers at the top of the msg.
  926. // At this point we know where to split the message and insert
  927. // our X Headers.
  928. XHDRInjStage = "Open Temp File"; // Update our process monitor.
  929. std::string TempFileName = MessageFilePath; // Prepare a temp file name
  930. TempFileName.append(".tmp"); // based on the message file.
  931. std::ofstream TempFile; // Here will be our temp file.
  932. TempFile.exceptions(std::ofstream::failbit | std::ofstream::badbit); // It will throw these exceptions.
  933. TempFile.open(TempFileName.c_str(),
  934. std::ios::binary | std::ios::trunc); // Open and truncate the file.
  935. // If our insert point is the top of the message we'll skip this.
  936. if(0 < InsertPoint) { // If we have an insert point:
  937. XHDRInjStage = "Write Temp File.1"; // Update our process monitor.
  938. TempFile.write( // Write the message file up
  939. reinterpret_cast<char*>(&MessageBuffer[0]), // to our split.
  940. InsertPoint
  941. );
  942. }
  943. // If our file has \n line ends we need to strip the \r from our
  944. // rfc822 \r\n line ends.
  945. XHDRInjStage = "XHDR <CR><LF> to <LF>";
  946. if(true == UseLFOnly) { // If we are using <LF> only:
  947. std::string ReworkedHeaders = ""; // Make a new string and rework
  948. for( // our headers.
  949. std::string::iterator iS = MyScanData.XHDRsText.begin(); // Run through the headers one
  950. iS != MyScanData.XHDRsText.end(); iS++ // byte at a time.
  951. ) {
  952. if('\r' != (*iS)) ReworkedHeaders.push_back(*iS); // Strip out any <CR> chars.
  953. }
  954. MyScanData.XHDRsText.swap(ReworkedHeaders); // Swap in our reworked headers.
  955. }
  956. // Now we are ready to inject our headers.
  957. XHDRInjStage = "Write Temp File.2"; // Update our process monitor.
  958. TempFile.write( // Inject our headers.
  959. MyScanData.XHDRsText.c_str(),
  960. MyScanData.XHDRsText.length()
  961. );
  962. XHDRInjStage = "Write Temp File.3"; // Update our process monitor.
  963. TempFile.write( // Write the rest of the message.
  964. reinterpret_cast<char*>(&MessageBuffer[InsertPoint]),
  965. MessageBuffer.size() - InsertPoint
  966. );
  967. XHDRInjStage = "Close Temp File"; // Update our process monitor.
  968. TempFile.close(); // Close the file (flushing it).
  969. cd::Sleeper PauseBeforeRetry(300); // Delay to use between retries.
  970. XHDRInjStage = "Drop Msg"; // Update our process monitor.
  971. if(remove(MessageFilePath.c_str())) { // Remove the old message file
  972. PauseBeforeRetry(); // If it fails, pause and retry.
  973. if(remove(MessageFilePath.c_str())) { // If that fails,
  974. PauseBeforeRetry(); // pause, then try once more.
  975. if(remove(MessageFilePath.c_str())) { // If that fails, throw.
  976. throw XHDRError("XHDR injector can't remove original!");
  977. }
  978. }
  979. }
  980. XHDRInjStage = "Rename Temp -> Msg"; // Update our process monitor.
  981. if(rename(TempFileName.c_str(), MessageFilePath.c_str())) { // Make Temp our new message file.
  982. PauseBeforeRetry(); // If it fails, pause and retry.
  983. if(rename(TempFileName.c_str(), MessageFilePath.c_str())) { // If that fails,
  984. PauseBeforeRetry(); // pause then try once more.
  985. if(rename(TempFileName.c_str(), MessageFilePath.c_str())) { // If that fails, throw.
  986. throw XHDRError("XHDR injector can't rename tmp file!");
  987. }
  988. }
  989. }
  990. }
  991. catch(XHDRError& e) { // For full XHDRError exceptions.
  992. std::string ERROR_MSG_XHDRi = "ERROR_MSG_XHDRi: "; // Format the XHDRInj error msg.
  993. ERROR_MSG_XHDRi.append(XHDRInjStage);
  994. ERROR_MSG_XHDRi.append(" ");
  995. ERROR_MSG_XHDRi.append(e.what());
  996. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  997. MyScanData, "scanMessageFile().xhdr.inject",
  998. snf_ERROR_MSG_FILE, ERROR_MSG_XHDRi
  999. );
  1000. throw; // Rethrow any XHDRError exceptions.
  1001. }
  1002. catch(const std::exception& e) { // For ordinary runtime exceptions.
  1003. std::string ERROR_MSG_XHDRi = "ERROR_MSG_XHDRi: "; // Format the XHDRInj error msg.
  1004. ERROR_MSG_XHDRi.append(XHDRInjStage);
  1005. ERROR_MSG_XHDRi.append(" ");
  1006. ERROR_MSG_XHDRi.append(e.what());
  1007. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1008. MyScanData, "scanMessageFile().xhdr.inject",
  1009. snf_ERROR_MSG_FILE, ERROR_MSG_XHDRi
  1010. );
  1011. throw XHDRError(ERROR_MSG_XHDRi); // Rethrow as XHDRError exceptions.
  1012. }
  1013. catch(...) { // If we encounter a problem then
  1014. std::string ERROR_MSG_XHDRi = "ERROR_MSG_XHDRi: "; // Format the XHDRInj error msg.
  1015. ERROR_MSG_XHDRi.append(XHDRInjStage);
  1016. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1017. MyScanData, "scanMessageFile().xhdr.inject",
  1018. snf_ERROR_MSG_FILE, ERROR_MSG_XHDRi
  1019. );
  1020. std::string XHDRError_msg = "Message Rewrite Failed: "; // Format our throw message with
  1021. XHDRError_msg.append(XHDRInjStage); // our detailed stage data and
  1022. throw XHDRError(XHDRError_msg); // throw our special exception.
  1023. }
  1024. }
  1025. // Create an .xhdr file if required.
  1026. if(MyScanData.XHeaderFileOn) {
  1027. try {
  1028. std::ofstream XHDRFile; // Output file will be XHDRFile.
  1029. XHDRFile.exceptions(std::ofstream::failbit | std::ofstream::badbit); // These events will throw exceptions.
  1030. std::string XHDRFileName = MessageFilePath; // Build the XHDR file name by adding
  1031. XHDRFileName.append(".xhdr"); // .xhdr to the message file name.
  1032. XHDRFile.open(XHDRFileName.c_str(),
  1033. std::ios::binary | std::ios::trunc); // Open (and truncate) the file.
  1034. XHDRFile << MyScanData.XHDRsText; // Spit out the XHDRs.
  1035. XHDRFile.close(); // All done.
  1036. }
  1037. catch(...) { // If we encounter a problem then
  1038. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1039. MyScanData, "scanMessageFile().xhdr.file",
  1040. snf_ERROR_MSG_FILE, "ERROR_MSG_XHDRf"
  1041. );
  1042. throw XHDRError(".xhdr file write failed"); // throw our special exception.
  1043. }
  1044. }
  1045. return ScanResultCode; // Return the actual result, of course.
  1046. }
  1047. std::string snf_EngineHandler::extractMessageID( // Find and return the first Message-ID
  1048. const unsigned char* Msg, // Input the Message buffer to search
  1049. const int Len // and the length of the buffer.
  1050. ) {
  1051. std::string ExtractedID = ""; // Start with an empty string.
  1052. bool FoundID = false; // Haven't found it yet.
  1053. int C = 0; // Cursor position.
  1054. while(!FoundID && (C < (Len - 12))) { // Loop through the Msg looking for
  1055. if( // the Message-ID: header.
  1056. ('\n' == Msg[C]) && // Starting at the new line find
  1057. ('M' == Msg[C + 1] || 'm' == Msg[C + 1]) && // Message-ID: (per RFC822)
  1058. ('e' == Msg[C + 2] || 'E' == Msg[C + 2]) &&
  1059. ('s' == Msg[C + 3] || 'S' == Msg[C + 3]) && // We use an unrolled comparison
  1060. ('s' == Msg[C + 4] || 'S' == Msg[C + 4]) && // loop here for raw speed and
  1061. ('a' == Msg[C + 5] || 'A' == Msg[C + 5]) && // optimization. Note that we
  1062. ('g' == Msg[C + 6] || 'G' == Msg[C + 6]) && // compare the most likely characters
  1063. ('e' == Msg[C + 7] || 'E' == Msg[C + 7]) && // first in each case, and we don't
  1064. ('-' == Msg[C + 8]) && // need to go through a buffer length
  1065. ('I' == Msg[C + 9] || 'i' == Msg[C + 9]) && // check at each byte for partial
  1066. ('D' == Msg[C + 10] || 'd' == Msg[C + 10]) && // matches.
  1067. (':' == Msg[C + 11]) &&
  1068. (' ' == Msg[C + 12] || '\t' == Msg[C + 12])
  1069. ) {
  1070. C = C + 13; // Starting just after the space
  1071. while(C < Len) { // and staying within bounds
  1072. unsigned char X = Msg[C]; // grab each character in the ID.
  1073. if(isprint(X)) { // If it is printable,
  1074. if(' ' == X) X = '_'; // massage out the spaces as _ and
  1075. if(127 < X) X = '|'; // high characters as | and
  1076. if('\'' == X || '\"' == X) X = '`'; // ' or " to ` in order to make the
  1077. ExtractedID.push_back(X); // ID safe for logging, then push
  1078. } else // the result into our string. When
  1079. if('\r' == X || '\n' == X) break; /* leave copy loop */ // we reach the end we're done.
  1080. ++C; // else get ready for the next byte.
  1081. }
  1082. FoundID = true; // Set the flag: we found Message-ID:
  1083. break; /* leave search loop */ // We got what we came for. Break!
  1084. } else { // When we don't find the Message-ID:
  1085. if( // we check for end of headers.
  1086. ('\n' == Msg[C] && '\n' == Msg[C+1]) || // Either <LF><LF> or
  1087. ('\r' == Msg[C] && '\n' == Msg[C+1] && // <CR><LF><CF><LF>
  1088. '\r' == Msg[C+2] && '\n' == Msg[C+3])
  1089. ) { // If we've found the end of headers
  1090. break; // we're done looking. If we did not
  1091. } // find the end of headers then
  1092. ++C; // we move to the next position.
  1093. }
  1094. }
  1095. // At this point we either have the Extracted ID, or we need a substitute.
  1096. if(0 == ExtractedID.length()) { // If we need a substitute ID then
  1097. MyRulebase->MyLOGmgr.SerialNumber(ExtractedID); // use the next available serial number.
  1098. }
  1099. return ExtractedID; // Return the extracted id or substitute.
  1100. }
  1101. const cd::LogicFault FaultBadMessageBuffer1("snf_EngineHandler::scanMessage():FaultBadMessageBuffer1(NULL == inputMessageBuffer)");
  1102. const cd::LogicFault FaultBadMessageBuffer2("snf_EngineHandler::scanMessage():FaultBadMessageBuffer2(0 >= inputMessageLength)");
  1103. const char Unknown_SNFMatchFlag = '-';
  1104. const char Panic_SNFMatchFlag = 'p';
  1105. const char Match_SNFMatchFlag = 'm';
  1106. const char White_SNFMatchFlag = 'w';
  1107. const char Final_SNFMatchFlag = 'f';
  1108. void captureMatchRecord(snf_match& M, MatchRecord* R) {
  1109. M.flag = Unknown_SNFMatchFlag;
  1110. M.ruleid = R->RuleId();
  1111. M.symbol = R->RuleGroup();
  1112. M.index = R->MatchStartPosition;
  1113. M.endex = R->MatchEndPosition;
  1114. }
  1115. void snf_SaccadesHandler::applySaccades(EvaluationMatrix* Scanner, std::vector<unsigned char>& Data) {
  1116. if(NULL == Scanner) return;
  1117. bool isTimeToPeek = (0 >= TimeToPeekCounter);
  1118. if(isTimeToPeek) {
  1119. TimeToPeekCounter = TimeToPeekReset;
  1120. return;
  1121. } else {
  1122. --TimeToPeekCounter;
  1123. }
  1124. std::vector<saccade> Saccades = grabSaccades();
  1125. for(std::vector<saccade>::iterator i = Saccades.begin(); i != Saccades.end(); i++) {
  1126. const saccade& s = (*i);
  1127. if(s.start >= Data.size()) break;
  1128. Scanner->evaluateSegment(Data, s.start, s.finish);
  1129. }
  1130. }
  1131. bool isLearnableMatch(MatchRecord* m) {
  1132. bool isGoodSymbol = (0 <= m->RuleGroup() && 64 > m->RuleGroup());
  1133. bool isBeyondAlwaysScan = (snf_SaccadesHandler::AlwaysScanLength < m->MatchEndPosition);
  1134. return (isGoodSymbol && isBeyondAlwaysScan);
  1135. }
  1136. void snf_SaccadesHandler::learnMatches(MatchRecord* Matches) {
  1137. if(NULL == Matches) return;
  1138. std::vector<saccade> MatchesToLearn;
  1139. saccade WatchForHeaderWhiteRules(0, AlwaysScanLength);
  1140. MatchesToLearn.push_back(WatchForHeaderWhiteRules);
  1141. for(MatchRecord* m = Matches; NULL != m; m = m->NextMatchRecord) {
  1142. if(isLearnableMatch(m)) {
  1143. MatchesToLearn.push_back(
  1144. saccade(
  1145. m->MatchStartPosition,
  1146. m->MatchEndPosition)
  1147. );
  1148. }
  1149. }
  1150. if(0 < MatchesToLearn.size()) {
  1151. lockAndLearn(MatchesToLearn);
  1152. }
  1153. }
  1154. static snf_SaccadesHandler SaccadeBrain;
  1155. static snf_IPStrangerList StrangersList;
  1156. int snf_EngineHandler::scanMessage( // Scan this message (in buffer).
  1157. const unsigned char* inputMessageBuffer, // -- this is the message buffer.
  1158. const int inputMessageLength, // -- this is the length of the buffer.
  1159. const std::string MessageName, // -- this is the message identifier.
  1160. const int MessageSetupTime, // -- setup time used (for logging).
  1161. const cd::IP4Address MessageSource // -- message source IP (for injection).
  1162. ) {
  1163. cd::ScopeTimer ScanTimeCapture(MyScanData.ScanTime); // Start the scan time clock.
  1164. unsigned char* MessageBuffer = NULL; // Explicitly initialize these two
  1165. int MessageLength = 0; // so the compiler will be happy.
  1166. FaultBadMessageBuffer1(NULL == inputMessageBuffer); // Fault on null message buffer.
  1167. FaultBadMessageBuffer2(0 >= inputMessageLength); // Fault on bad message bfr length.
  1168. // Protect this engine - only one scan at a time per EngineHandler ;-)
  1169. cd::ScopeMutex ScannerIsBusy(MyMutex); // Serialize this...
  1170. // Preliminary job setup.
  1171. // In our pre-processing we may adjust our input buffer so we capture the
  1172. // originals and then use the captured values. For example if we are scanning
  1173. // Communigate message files we will want to skip the communigate headers.
  1174. MessageBuffer = const_cast<unsigned char*>(inputMessageBuffer); // Capture the input buffer.
  1175. MessageLength = inputMessageLength; // Capture the input length.
  1176. MyScanData.clear(); // Clear the scan data.
  1177. MyScanData.ScanSize = MessageLength; // Grab the message length.
  1178. MyScanData.SetupTime = MessageSetupTime; // Capture the setup time.
  1179. if(0 == MyScanData.StartOfJobUTC) { // If the job timestamp is not
  1180. MyScanData.StartOfJobUTC = MyRulebase->MyLOGmgr.Timestamp(); // yet set then set it.
  1181. }
  1182. MyScanData.CallerForcedSourceIP(MessageSource); // Capture the MessageSource if any.
  1183. // Special note about exceptions here...
  1184. // Setting up the filter chain can throw an exception. It can't go in it's own try block or it will
  1185. // be out of scope for the remainder of the function... SO, I've wrapped everything inside of the
  1186. // Lock() in a try block ... and there's a nested one also for scanning the content. The result is
  1187. // that I can put all of the unlock work in the "outer" try block and re-throw anything that's
  1188. // needed.
  1189. snfCFGPacket MyCFGPacket(MyRulebase); // We need this to stay in scope.
  1190. // Set up the filter chain, configure the scanner, and scan the message.
  1191. try {
  1192. if(MyCFGPacket.bad()) { // If it's not there it's a big problem.
  1193. throw Panic("snf_EngineHandler::scanMessage() MyCFGPacket.bad()");
  1194. }
  1195. // Adapt to CGP message files - skip the CGP headers
  1196. MyScanData.MessageFileTypeCGPOn = // Find out if we are expecting
  1197. MyCFGPacket.Config()->MessageFileTypeCGP_on_off; // Communigate message files.
  1198. if(MyScanData.MessageFileTypeCGPOn) { // If we are scanning CGP files:
  1199. while(4 < MessageLength) { // Skip over the CGP headers.
  1200. if( // On Winx systems look for the first
  1201. '\r' == MessageBuffer[0] && // blank line encoded as CRLF CRLF.
  1202. '\n' == MessageBuffer[1] &&
  1203. '\r' == MessageBuffer[2] &&
  1204. '\n' == MessageBuffer[3]
  1205. ) { // If we find it then skip past
  1206. MessageBuffer += 4; // the new line and break out
  1207. MessageLength -= 4; // of the loop.
  1208. break;
  1209. } else // On *nix systems look for the first
  1210. if( // blank line encoded as LF LF.
  1211. '\n' == MessageBuffer[0] &&
  1212. '\n' == MessageBuffer[1]
  1213. ) { // If we find it then skip past
  1214. MessageBuffer += 2; // the blank line and break out
  1215. MessageLength -= 2; // of the loop.
  1216. break;
  1217. }
  1218. else { // If we don't find it then
  1219. ++MessageBuffer; // eat one byte from the buffer
  1220. --MessageLength; // and keep going.
  1221. }
  1222. }
  1223. // At this point our MessagBuffer contains just the message we
  1224. // want to scan.
  1225. MyScanData.ScanSize = MessageLength; // Reset the scan size.
  1226. }
  1227. // Identify this message.
  1228. if( // How do we identify this scan?
  1229. 0 == MessageName.length() || // If no name was provided or
  1230. true == MyCFGPacket.Config()->Scan_Identifier_Force_Message_Id // we are forcing RFC822 IDs then
  1231. ) { // extract the Message-ID from the
  1232. MyScanData.ScanName = extractMessageID(MessageBuffer, MessageLength); // message and use that.
  1233. } else { // If a name was provided and we
  1234. MyScanData.ScanName = MessageName; // are not forcing RFC822 IDs then
  1235. } // use the name provided to us.
  1236. // Set up our filter chain.
  1237. std::stringstream PrependedHeaders; // Use this to prepend X-Headers.
  1238. FilterChainCBFR IU(MessageBuffer, MessageLength, PrependedHeaders); // Set up the filter chain.
  1239. FilterChainHeaderAnalysis IV(&IU, MyIPTestEngine); // Include header analysis.
  1240. FilterChainBase64 IW(&IV); // Include Base64 decoding.
  1241. FilterChainQuotedPrintable IX(&IW); // Include Quoted Printable decoding.
  1242. FilterChainUrlDecode IY(&IX); // Include URL decoder.
  1243. FilterChainDefunker IZ(&IY); // Include Defunking.
  1244. // Now we set up our scanner and grab the current token matrix.
  1245. if(NULL!=CurrentMatrix) { delete CurrentMatrix; CurrentMatrix=NULL; } // If we have old results, delete them.
  1246. try {
  1247. CurrentMatrix = new EvaluationMatrix(MyCFGPacket.Tokens()); // Allocate a new matrix for this scan.
  1248. } catch(...) { // Check that the allocation worked.
  1249. throw AllocationError("new EvaluationMatrix() ???");
  1250. }
  1251. // Here we get down to it and start scanning the message.
  1252. const char* DebugInfo = "scanMessage() Begin Message Scan"; // If we panic, here we are.
  1253. try {
  1254. // The IPTestEngine has the ability to truncate the message in the filter
  1255. // chain under certain conditions. In order to configure those conditions
  1256. // the IPTestEngine needs to have the configuration data being used for
  1257. // the current scan.
  1258. DebugInfo = "scanMessage() setCFGData()"; // If we panic, here we are.
  1259. MyIPTestEngine.setCFGData(*(MyCFGPacket.Config())); // Setup the CFG data to use.
  1260. // Check processed headers for header directive rules. One of these might
  1261. // include a directive to get the message source IP from a header. If so
  1262. // then MyScanData will have been modified. Also if there are drill-down
  1263. // directives then MyScanData will have been modified to mark any headers
  1264. // that should be ignored -- in this case the IP test used in the filter
  1265. // chain will take appropriate action as it comes across the Received
  1266. // headers that have been marked.
  1267. DebugInfo = "scanMessage() Get Header Directives";
  1268. MyScanData.HeaderDirectiveFlags = 0x00000000; // Clear the header directive flags.
  1269. if(0 < MyCFGPacket.Config()-> // Check to see if we have any
  1270. HeaderDirectivesHandler.HeaderDirectives.size()) { // header directive rules and if we do:
  1271. HeaderFinder HeaderDirectivesParser( // Parse the headers in the message
  1272. &MyScanData, // and update the ScanData using the
  1273. MyCFGPacket.Config()->HeaderDirectivesHandler.HeaderDirectives, // directives in our configuration packet.
  1274. MessageBuffer, // Pass the message as a pointer with
  1275. MessageLength // a specific buffer length.
  1276. );
  1277. MyScanData.HeaderDirectiveFlags = HeaderDirectivesParser(); // Capture the parsed results.
  1278. }
  1279. // Message header rules in earlier versions occasionally failed because there was not
  1280. // a new-line character in front of the very first header. So, now we insert one :-)
  1281. // This allows all header rules to start off with a ^ indicating the start of the line.
  1282. // 20070719_M Added \n to X-snfScanSize: synthetic header.
  1283. // 20070120_M There are some messages where the size is a specific part of
  1284. // the pattern so we will now be emitting this data into the engine. A later
  1285. // version of the engine should handle this kind of thing using a special
  1286. // filter chain module.
  1287. DebugInfo = "scanMessage() ^X-snfScanSize"; // If we panic here we are.
  1288. // Build the scan size info
  1289. PrependedHeaders << "X-snfScanSize: " << MyScanData.ScanSize << "\n"; // and format as an X- header.
  1290. // Add a phantom received header to the top IF the message source has been
  1291. // forced by the caller or by a header directive. After that the normal
  1292. // scanning and header analysis process should pick up the IP as the
  1293. // source of the message. (It will not if the IP is ignored in the GBUdb!)
  1294. DebugInfo = "scanMessage() PhantomReceived"; // If we panic we are here.
  1295. if(0UL != MyScanData.CallerForcedSourceIP()) { // If the caller forced the source IP:
  1296. PrependedHeaders // Make a phantom Received header
  1297. << "Received: Caller.Forced.Source.IP [" // showing that the caller forced
  1298. << (std::string) MyScanData.CallerForcedSourceIP() << "]\n"; // the source IP.
  1299. } else
  1300. // If not forced by the caller but a
  1301. if(0UL != MyScanData.HeaderDirectiveSourceIP()) { // header directive forced the source IP:
  1302. PrependedHeaders // Make a phantom Received header
  1303. << "Received: Header.Directive.Source.IP [" // showing that a header directive
  1304. << (std::string) MyScanData.HeaderDirectiveSourceIP() << "]\n"; // established the source IP.
  1305. }
  1306. // Most of the time we will extract the source IP the normal way.
  1307. // If there are other prepended headers to add they should go here.
  1308. /** Add other prepended headers **/
  1309. // 20070719_M Reworked the engine to handle the filter-chain section in
  1310. // a tight loop separately from the scanning section. This should allow
  1311. // for tighter optimization in some cases (less cache thrashing) and also
  1312. // provides for later development of parallel analysis of the pre-filtered
  1313. // data, as well as the ability to output the pre-filtered data for use in
  1314. // rule development and debugging.
  1315. DebugInfo = "scanMessage() IZ.GetByte() ==> FilteredData"; // If we panic we are here.
  1316. unsigned char xb=0;
  1317. MyScanData.FilteredData.clear(); // Clear the FilteredData buffer.
  1318. try { // Watch for exceptions and scan
  1319. for(int a = 0; a < snf_ScanHorizon; a++) // the message through the filter
  1320. MyScanData.FilteredData.push_back(xb=IZ.GetByte()); // chain into the FilteredData buffer.
  1321. } // When we run out of data we will
  1322. catch(const FilterChain::Empty&) {} // get the Empty exception and stop.
  1323. // Scan each byte in the file up to the horizon or the end of the message.
  1324. // If something goes wrong, an exception will be thrown.
  1325. DebugInfo = "scanMessage() EvaluateThis(FilteredData)"; // If we panic, here we are.
  1326. if(false == MyScanData.GBUdbTruncateExecuted) { // If we haven't already truncated:
  1327. //for(int a = 0, b = MyScanData.FilteredData.size(); a < b; a++) // Scan through the filtered data one
  1328. // CurrentMatrix->EvaluateThis(MyScanData.FilteredData[a]); // byte at a time.
  1329. /** 20200618_M Experiment stripping out saccades to check performance hit
  1330. unsigned int fullLength = MyScanData.FilteredData.size();
  1331. SaccadeBrain.applySaccades(CurrentMatrix, MyScanData.FilteredData);
  1332. bool messageNotRecognized = (NULL == CurrentMatrix->ResultList);
  1333. if(messageNotRecognized) {
  1334. CurrentMatrix->evaluateSegment(MyScanData.FilteredData, 0, fullLength);
  1335. SaccadeBrain.learnMatches(CurrentMatrix->ResultList);
  1336. }
  1337. **/
  1338. size_t fullLength = MyScanData.FilteredData.size();
  1339. CurrentMatrix->evaluateSegment(MyScanData.FilteredData, 0, fullLength); // Only do a full scan -- see comment above
  1340. }
  1341. DebugInfo = "scanMessage() Scan Data Complete"; // If we panic, here we are.
  1342. }
  1343. catch(const EvaluationMatrix::BadAllocation&) { // Check for bad allocation during scan.
  1344. throw AllocationError("EvaluationMatrix::BadAllocation");
  1345. }
  1346. catch(const EvaluationMatrix::MaxEvalsExceeded&) { // Check for too many evaluators.
  1347. throw MaxEvals("EvaluationMatrix::MaxEvalsExceeded");
  1348. }
  1349. catch(const EvaluationMatrix::OutOfRange&) { // Check for out of range of (bad) matrix.
  1350. throw BadMatrix("EvaluationMatrix::OutOfRange");
  1351. }
  1352. catch(...){ // In order to prevent thread craziness
  1353. throw Panic(DebugInfo); // throw a Panic.
  1354. } // The mutex will unlock in the outer try.
  1355. }
  1356. // Here is the end of the outer try block. We can catch and rethrow whatever happend
  1357. // and we can also keep our mutex properly managed.
  1358. catch(AllocationError& e) { // Allocation Errors pass through.
  1359. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1360. MyScanData, "scanMessage()",
  1361. snf_ERROR_ALLOCATION, "ERROR_ALLOCATION"
  1362. );
  1363. throw;
  1364. }
  1365. catch(MaxEvals& e) { // MaxEvals == Panic, with a log.
  1366. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1367. MyScanData, "scanMessage()",
  1368. snf_ERROR_MAX_EVALS, "ERROR_MAX_EVALS"
  1369. );
  1370. throw;
  1371. }
  1372. catch(BadMatrix& e) { // BadMatrix == Panic, with a log.
  1373. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1374. MyScanData, "scanMessage()",
  1375. snf_ERROR_BAD_MATRIX, "ERROR_BAD_MATRIX"
  1376. );
  1377. throw;
  1378. }
  1379. catch(Panic& e) { // Panic is panic.
  1380. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1381. MyScanData, "scanMessage()",
  1382. snf_ERROR_BAD_MATRIX, "ERROR_PANIC"
  1383. );
  1384. throw;
  1385. }
  1386. catch(const std::exception& e) { // Other exceptions.
  1387. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1388. MyScanData, "scanMessage()",
  1389. snf_ERROR_UNKNOWN, "ERROR_EXCEPTION"
  1390. );
  1391. throw;
  1392. }
  1393. catch(...) { // Anything else == Panic.
  1394. MyRulebase->MyLOGmgr.logThisError( // Log the error.
  1395. MyScanData, "scanMessage()",
  1396. snf_ERROR_UNKNOWN, "ERROR_UNKNOWN"
  1397. );
  1398. throw Panic("snf_EngineHandler::scanMessage() ERROR_UNKNOWN!");
  1399. }
  1400. // At this point, we've completed our scan and we're ready to evaluate our results to find the correct symbol to return.
  1401. ResultsCount = 0; // Reset the count,
  1402. ResultsRemaining = 0; // Remaining count,
  1403. FinalResult = NULL; // Final Result marker,
  1404. ResultCursor = CurrentMatrix -> ResultList; // And cursor position for our results.
  1405. // Now that our result processing gadgets are reset, let's process the results list.
  1406. int const CLEAN_RESULT = 0; // CLEAN means no matches or white.
  1407. int const NO_SYMBOL = 999; // NO_SYMBOL is higher than any SYMBOL
  1408. int S = NO_SYMBOL; // so we start there and work down.
  1409. snf_match TmpSNFMatch; // We'll need a buffer for our matches.
  1410. while(NULL!=ResultCursor) { // While we have records to process...
  1411. captureMatchRecord(TmpSNFMatch, ResultCursor); // grab the next record and evaluate it.
  1412. // Mitigate short-match rulebase events to prevent false positives.
  1413. const size_t minimumPatternLength = 5; // Establish a minimum match length.
  1414. size_t matchSpan = (TmpSNFMatch.endex - TmpSNFMatch.index); // Determine the length of this match.
  1415. bool isShortMatchEvent = (minimumPatternLength > matchSpan); // Identify short-match events.
  1416. bool isPanickedRule = ( // In addition to rule IDs that are
  1417. MyCFGPacket.isRulePanic(TmpSNFMatch.ruleid) || // in the rule-panic list also treat
  1418. isShortMatchEvent // short match events as panic rules.
  1419. );
  1420. bool isVotingCandidate = (false == isPanickedRule); // Panic rules can't vote.
  1421. bool isWhiteRule = (
  1422. MyCFGPacket.Config()->TrainingWhiteRuleHandler.isListed(TmpSNFMatch.ruleid) ||
  1423. 0 == TmpSNFMatch.symbol
  1424. );
  1425. bool isBestResultCode = (TmpSNFMatch.symbol < S);
  1426. // Set an appropriate flag.
  1427. if(isPanickedRule) TmpSNFMatch.flag = Panic_SNFMatchFlag;
  1428. else if(isWhiteRule) TmpSNFMatch.flag = White_SNFMatchFlag;
  1429. else TmpSNFMatch.flag = Match_SNFMatchFlag;
  1430. // Vote for best rule match.
  1431. if(isVotingCandidate && isBestResultCode) {
  1432. FinalResult = ResultCursor;
  1433. S = TmpSNFMatch.symbol;
  1434. }
  1435. // Record this MatchRecord and mMove on to next result.
  1436. MyScanData.MatchRecords.push_back(TmpSNFMatch);
  1437. ResultsCount++;
  1438. ResultCursor=ResultCursor->NextMatchRecord;
  1439. }
  1440. if(NO_SYMBOL != S) { // If a pattern match was detected then
  1441. MyScanData.PatternWasFound = true; // trip the flag and record the
  1442. MyScanData.PatternID = FinalResult->RuleId(); // Rule ID and the
  1443. MyScanData.PatternSymbol = FinalResult->RuleGroup(); // Symbol.
  1444. }
  1445. //// GBUdb Integration ///////////////////////////////////////////////////////
  1446. // To integrate GBUdb we need to generalize the result from the pattern scan.
  1447. PatternResultTypes ScanResultType = NoPattern; // What kind of result have we here?
  1448. if(0 < (MyScanData.HeaderDirectiveFlags & HeaderDirectiveWhite)) { // If a white header directive matched
  1449. ScanResultType = WhitePattern; // then we have a "WhitePattern'.
  1450. } else
  1451. if(MyCFGPacket.Config()->TrainingWhiteRuleHandler.isListed(S)) { // If the pattern was mapped to a white
  1452. ScanResultType = WhitePattern; // rule group then we have a 'WhitePattern'.
  1453. } else
  1454. if(CLEAN_RESULT == S) { // If there was a standard white rule
  1455. ScanResultType = WhitePattern; // result then we have a 'WhitePattern'.
  1456. } else
  1457. if(NO_SYMBOL == S) { // If there was no pattern match then
  1458. ScanResultType = NoPattern; // we have 'NoPattern'.
  1459. } else
  1460. if(63 == S) { // If the pattern was a standard IP rule
  1461. ScanResultType = IPPattern; // then we have an 'IPPattern'.
  1462. } else
  1463. if(62 >= S) { // In general, other nonzer rule groups
  1464. ScanResultType = BlackPattern; // indicate we have a 'BlackPatter'.
  1465. } else
  1466. if(63 < S) { // Any pattern number > 63 is special.
  1467. ScanResultType = AboveBandPattern; // Any of these are an 'AboveBandPattern'
  1468. }
  1469. if(MyScanData.FoundSourceIP()) { // We need an identified IP source.
  1470. // Train the GBUdb based on our pattern matching results.
  1471. // Evaluate our training conditions.
  1472. bool TrainingIsTurnedOn = MyCFGPacket.Config()->GBUdbTrainingOn_Off;
  1473. bool MessageWasNotTruncated = (false == MyScanData.GBUdbTruncateExecuted);
  1474. bool ThereIsNoBypassHeaderDirective = (0 == (MyScanData.HeaderDirectiveFlags & HeaderDirectiveBypass));
  1475. bool ThereIsNoBypassResultCodeRule = (false == MyCFGPacket.Config()->TrainingBypassRuleHandler.isListed(S));
  1476. bool ThereIsNoImpliedBypassDirective = (Ignore != (MyScanData.SourceIPRecord().GBUdbData.Flag()));
  1477. // If these conditions are favorable then train the GBUdb.
  1478. if( // Check to see if training is enabled.
  1479. TrainingIsTurnedOn && // If it is turned on AND
  1480. MessageWasNotTruncated && // The message was not truncated AND
  1481. ThereIsNoBypassHeaderDirective && // There is NO Bypass header directive AND
  1482. ThereIsNoBypassResultCodeRule && // There is NO Bypass result code rule AND
  1483. ThereIsNoImpliedBypassDirective // There is NO Implied bypass directive:
  1484. ) {
  1485. // GBUdb training is enabled.
  1486. bool discoveredNewIP = false;
  1487. cd::IP4Address theSourceIP = MyScanData.SourceIPRecord().IP;
  1488. switch(ScanResultType) { // Evaluate the scan result.
  1489. case NoPattern: // On no pattern (benefit of doubt) or
  1490. case WhitePattern: { // a white pattern:
  1491. GBUdbRecord thisRecord = // Grab the GBUdb record for later
  1492. MyRulebase->MyGBUdb.addGood( // then add a good count to the
  1493. theSourceIP); // source IP.
  1494. discoveredNewIP = (0 == thisRecord.Bad() && 1 == thisRecord.Good());
  1495. if(discoveredNewIP) { // New IPs are strangers.
  1496. StrangersList.addStranger(theSourceIP); // Add them to the list
  1497. thisRecord.Bad(thisRecord.Good()); // and set their reputation
  1498. MyRulebase->MyGBUdb.setRecord(theSourceIP, thisRecord); // to 50/50 at best.
  1499. } else
  1500. if( // Known IPs that are getting
  1501. thisRecord.Good() > thisRecord.Bad() && // an advantage but are on the
  1502. StrangersList.isStranger(theSourceIP) // strangers list get put back
  1503. ) { // to a 50/50 reputation.
  1504. unsigned int equalizationValue = thisRecord.Good();
  1505. if(1 < equalizationValue) equalizationValue = equalizationValue / 2;
  1506. thisRecord.Bad(equalizationValue);
  1507. thisRecord.Good(equalizationValue);
  1508. MyRulebase->MyGBUdb.setRecord(theSourceIP, thisRecord);
  1509. }
  1510. break;
  1511. }
  1512. case BlackPattern: { // On a black pattern:
  1513. GBUdbRecord thisRecord = // Grab the GBUdb record for later
  1514. MyRulebase->MyGBUdb.addBad( // Add a bad count to the source IP
  1515. MyScanData.SourceIPRecord().IP); // in the GBUdb.
  1516. discoveredNewIP = (1 == thisRecord.Bad() && 0 == thisRecord.Good());
  1517. if(discoveredNewIP) StrangersList.addStranger(theSourceIP);
  1518. break;
  1519. }
  1520. default: break; // In all other cases, don't train.
  1521. }
  1522. }
  1523. // GBUdb Training Is Complete
  1524. // At this point our SourceIPRange tells us exactly how to evaluate
  1525. // the source IP for this message.
  1526. switch(MyScanData.SourceIPRange()) {
  1527. case White: { // If the IP was in the white zone
  1528. MyScanData.GBUdbWhiteTriggered = true; // mark that down.
  1529. if(MyCFGPacket.Config()->WhiteRangeHandler.On_Off) { // If we're also turned on then
  1530. if( // do we need to force the symbol?
  1531. BlackPattern == ScanResultType || // We do if the pattern scan resulted
  1532. IPPattern == ScanResultType // in a black or IPblack match.
  1533. ) { // If we must force a white result:
  1534. S = MyCFGPacket.Config()->WhiteRangeHandler.Symbol; // force the symbol and
  1535. MyScanData.GBUdbWhiteSymbolForced = true; // record that it was done.
  1536. }
  1537. // AutoPanic
  1538. int AutoPanicRangeLowerBound = // Calculate the current lower bound
  1539. MyRulebase->MyLOGmgr.LatestRuleID() - // for rule id's that are eligible to
  1540. MyCFGPacket.Config()->gbudb_regions_white_panic_rule_range; // trigger auto-panics.
  1541. if(BlackPattern == ScanResultType || IPPattern == ScanResultType) { // Was there a pattern/source conflict?
  1542. MyScanData.GBUdbPatternSourceConflict = true; // Record the event.
  1543. if(MyScanData.PatternID > AutoPanicRangeLowerBound) { // If the pattern ID is in range then
  1544. MyScanData.GBUdbAutoPanicTriggered = true; // record that the AutoPanic triggered.
  1545. if(MyCFGPacket.Config()->gbudb_regions_white_panic_on_off) { // If rule panics are turned on then
  1546. MyScanData.GBUdbAutoPanicExecuted = true; // indicate we are executing an autopanic.
  1547. MyRulebase->addRulePanic(MyScanData.PatternID); // Add the rule panic.
  1548. }
  1549. }
  1550. }
  1551. }
  1552. break;
  1553. }
  1554. case Normal: { // If the IP is normal...
  1555. MyScanData.GBUdbNormalTriggered = true; // Count the event.
  1556. break; // That's all.
  1557. }
  1558. case New: {
  1559. break;
  1560. }
  1561. case Caution: { // If the IP is in the caution range.
  1562. MyScanData.GBUdbCautionTriggered = true; // Track that this range fired.
  1563. if(
  1564. MyCFGPacket.Config()->CautionRangeHandler.On_Off && // If we're also turned on and there
  1565. NoPattern == ScanResultType // is no pattern match then
  1566. ) { // we will override the scan result:
  1567. S = MyCFGPacket.Config()->CautionRangeHandler.Symbol; // set the symbol as configured and
  1568. MyScanData.GBUdbCautionSymbolForced = true; // record that it was done.
  1569. }
  1570. break;
  1571. }
  1572. // Truncate is a kind of uber-black, so we do some weirdness here.
  1573. // If Truncate happens, then black was triggered by definition. In
  1574. // peek cases or if Truncate is turned off then Truncate might not
  1575. // execute-- when that happens we need to fall back to Black behavior.
  1576. case Truncate: // If the IP was in the truncate range
  1577. case Black: { // and/or If the IP is in the black range
  1578. MyScanData.GBUdbBlackTriggered = true; // mark that down.
  1579. if(MyScanData.GBUdbTruncateExecuted) { // If the truncate action was executed
  1580. S = MyCFGPacket.Config()->gbudb_regions_black_truncate_symbol; // we set the output symbol accordingly.
  1581. } else // Truncate overrides black.. but if
  1582. if( // Black is in charge do this...
  1583. MyCFGPacket.Config()->BlackRangeHandler.On_Off && // If black action is turned on and there
  1584. NoPattern == ScanResultType // is no pattern match then
  1585. ) { // we will override the scan data:
  1586. S = MyCFGPacket.Config()->BlackRangeHandler.Symbol; // set the symbol as configured and
  1587. MyScanData.GBUdbBlackSymbolForced = true; // record that it was done.
  1588. }
  1589. // Now that all of the overrides have been handled we can handle
  1590. // sampling. When a black IP is detected and a pattern match is not
  1591. // then we may sample the data.
  1592. int BlackSampleRate = // Grab the sample rate to make the
  1593. MyCFGPacket.Config()->gbudb_regions_black_sample_grab_one_in; // logic clearer.
  1594. bool SampleThresholdReached = // Check the spam probability of the
  1595. (MyCFGPacket.Config()->gbudb_regions_black_sample_probability <= // source IP against the configuration
  1596. MyScanData.SourceIPRecord().GBUdbData.Probability()); // to see if this IP is a candidate.
  1597. if( // Should we sample?
  1598. false == MyScanData.GBUdbTruncateExecuted && // If this was not a truncation and
  1599. NoPattern == ScanResultType && // No pattern match was found and
  1600. SampleThresholdReached && // We reached out sample threshold and
  1601. MyRulebase->MyLOGmgr.OkToSample(BlackSampleRate) // It's ok for us to sample this round
  1602. ) { // then our sampling mechanism is triggerd.
  1603. MyScanData.GBUdbSampleTriggered = true; // Mark down that event.
  1604. if(MyCFGPacket.Config()->gbudb_regions_black_sample_on_off) { // If sampling is turned on then
  1605. MyScanData.GBUdbSampleExecuted = true; // we will be sampling this data.
  1606. if(MyCFGPacket.Config()->gbudb_regions_black_sample_passthrough) { // If sampling by passthrough then
  1607. S = MyCFGPacket.Config()-> // Force the symbol value to passthrough
  1608. gbudb_regions_black_sample_passthrough_symbol; // (usually 0 - same as CLEAN).
  1609. } else { // If sampling internally then
  1610. MyRulebase->MyNETmgr.sendSample( // send this message as a sample.
  1611. (*(MyCFGPacket.Config())), // Pass our current config info,
  1612. MyScanData, // our scan data,
  1613. MessageBuffer, // and the message itself.
  1614. MessageLength
  1615. );
  1616. }
  1617. }
  1618. }
  1619. break;
  1620. }
  1621. case Unknown: // Unknown - most likely we couldn't
  1622. default: { // find a usable source.
  1623. break; // Do nothing.
  1624. }
  1625. }
  1626. } // End of IP source depended work (GBUdbOverrides)
  1627. // At this point we know the final result of our scan
  1628. // and the number of results we have. It's time to set up our result
  1629. // processing widgets for further query and return the result of this scan.
  1630. ResultCursor = CurrentMatrix -> ResultList; // Starting at the top of the list
  1631. ResultsRemaining = ResultsCount; // with all of the results ahead of us.
  1632. if(NO_SYMBOL==S) S = CLEAN_RESULT; // When there were no results, CLEAN
  1633. MyScanData.CompositeFinalResult = S; // Record what we will return.
  1634. if( // Prepare our final result.
  1635. CLEAN_RESULT == S && // If we have a clean result code
  1636. ScanResultType != WhitePattern && // and it wasn't forced by a white
  1637. false == MyScanData.GBUdbWhiteSymbolForced) { // rule or white GBUdb then we mark
  1638. TmpSNFMatch.flag = 'c'; // the final record Clean.
  1639. } else { // Otherwise we mark the final record
  1640. TmpSNFMatch.flag = 'f'; // as Final - meaning deliberately zero.
  1641. }
  1642. TmpSNFMatch.index = 0; // Our index is charater zero.
  1643. TmpSNFMatch.endex = CurrentMatrix->CountOfCharacters - 1; // Our endex is the end of the message.
  1644. TmpSNFMatch.symbol = MyScanData.CompositeFinalResult; // Our symbol is in CompositeFinal.
  1645. // The rule id is dependent on what's happened...
  1646. if( // If the symbol has been forced...
  1647. MyScanData.GBUdbTruncateExecuted || // Was it a Truncate-IP scan?
  1648. MyScanData.GBUdbWhiteSymbolForced || // Was it a White-IP scan?
  1649. MyScanData.GBUdbBlackSymbolForced || // Was it a Black-IP scan?
  1650. MyScanData.GBUdbCautionSymbolForced || // Was it a Caution-IP scan?
  1651. NULL == FinalResult // OR there was no valid match
  1652. ) { // then our rule id will be
  1653. TmpSNFMatch.ruleid = 0; // ZERO.
  1654. } else { // Normally the rule id will be
  1655. TmpSNFMatch.ruleid = FinalResult->RuleId(); // that of the winning pattern match.
  1656. }
  1657. MyScanData.MatchRecords.push_back(TmpSNFMatch); // Push our final entry onto the list.
  1658. MyScanData.MatchRecordsCursor = MyScanData.MatchRecords.begin(); // Reset the delivery system to the
  1659. MyScanData.MatchRecordsDelivered = 0; // beginning of the results list.
  1660. MyScanData.ScanDepth = CurrentMatrix->MaximumCountOfEvaluators; // Capture the scan depth.
  1661. MyScanData.ScanTime.stop(); // Stop the scan time clock.
  1662. MyRulebase->MyLOGmgr.logThisScan((*(MyCFGPacket.Config())), MyScanData); // Log the data from this scan.
  1663. // Since V2-9rc19 of this engine, the Engine mutex and snfCFGPacket handle
  1664. // their own cleanup when this call goes out of scope. ScannerIsBusy(MyMutex)
  1665. // will unlock() on destruction and snfCFGPacket will MyRulebase->drop().
  1666. return S; // Return the final scan result.
  1667. }
  1668. int snf_EngineHandler::getResults(snf_match* MatchBuffer){ // Get the next match buffer.
  1669. cd::ScopeMutex SerializeThis(MyMutex); // Serialize this...
  1670. if(NULL == MatchBuffer) { // If we were given the reset signal
  1671. MyScanData.MatchRecordsCursor = MyScanData.MatchRecords.begin(); // Move the cursor to the beginning
  1672. MyScanData.MatchRecordsDelivered = 0; // and reset the delivered count.
  1673. } else { // If we are in delivery mode and
  1674. if(MyScanData.MatchRecords.end() != MyScanData.MatchRecordsCursor) { // there are more to deliver then
  1675. (*MatchBuffer) = (*MyScanData.MatchRecordsCursor); // deliver the current match and
  1676. ++MyScanData.MatchRecordsCursor; // move on to the next. Be sure to
  1677. ++MyScanData.MatchRecordsDelivered; // count this one as delivered.
  1678. }
  1679. }
  1680. return MyScanData.MatchRecords.size() - MyScanData.MatchRecordsDelivered; // Return a count of unseen records.
  1681. }
  1682. int snf_EngineHandler::getDepth(){ // Get the scan depth.
  1683. cd::ScopeMutex SerializeThis(MyMutex); // Protect our reading.
  1684. return MyScanData.ScanDepth; // Return the latest scan depth.
  1685. }
  1686. const std::string snf_EngineHandler::getClassicLog() { // Get classic log entries for last scan.
  1687. cd::ScopeMutex SerializeThis(MyMutex); // Serialize this...
  1688. return MyScanData.ClassicLogText; // Return the log text.
  1689. }
  1690. const std::string snf_EngineHandler::getXMLLog() { // Get XML log entries or last scan.
  1691. cd::ScopeMutex SerializeThis(MyMutex); // Serialize this...
  1692. return MyScanData.XMLLogText; // Return the log text.
  1693. }
  1694. const std::string snf_EngineHandler::getXHDRs() { // Get XHDRs for last scan.
  1695. cd::ScopeMutex SerializeThis(MyMutex); // Serialize this...
  1696. return MyScanData.XHDRsText; // Return the XHeaders text.
  1697. }
  1698. //// Multi Engine Handler Methods
  1699. // snf_RoundRulebaseCursor()
  1700. // Returns the next rulebase slot id wrapping around to zero.
  1701. int snf_MultiEngineHandler::RoundRulebaseCursor(){ // Return the next Rulebase handle
  1702. RulebaseCursor++; // Increase the cursor.
  1703. if(snf_MAX_RULEBASES<=RulebaseCursor) // If we've reached the end of the array
  1704. RulebaseCursor=0; // then we start back at zero.
  1705. return RulebaseCursor; // Return the new handle candidate.
  1706. }
  1707. // snf_RoundEngineCursor()
  1708. // Returns the next engine slot id wrapping around to zero.
  1709. int snf_MultiEngineHandler::RoundEngineCursor(){ // Return the next Engine handle candidate.
  1710. EngineCursor++; // Increase the cursor.
  1711. if(snf_MAX_SCANNERS<=EngineCursor) // If we've reached the end of the array
  1712. EngineCursor=0; // then we start back at zero.
  1713. return EngineCursor; // Return the new handle candidate.
  1714. }
  1715. snf_MultiEngineHandler::~snf_MultiEngineHandler(){ // Clean up, safety check, shut down.
  1716. RulebaseScan.lock(); // Lock both the rulebase and
  1717. EngineScan.lock(); // engine scan rulebases.
  1718. RulebaseCursor = EngineCursor = SHUTDOWN; // Set the cursors to the FINISHED value.
  1719. // The handlers in the arrays will all get closed by their destructors.
  1720. // The SHUTDOWN value in the cursors will force any errant threads to get no love.
  1721. RulebaseScan.unlock();
  1722. EngineScan.unlock();
  1723. }
  1724. // snf_OpenRulebase()
  1725. // Grab the first available rulebse handler and light it up.
  1726. int snf_MultiEngineHandler::OpenRulebase(const char* path, const char* licenseid, const char* authentication){
  1727. RulebaseScan.lock(); // Serialize this.
  1728. if(SHUTDOWN==RulebaseCursor) { // Not ok to open after shutdown.
  1729. RulebaseScan.unlock();
  1730. throw Panic("snf_MultiEngineHandler::OpenRulebase() No open after shutdown");
  1731. }
  1732. int Handle = RoundRulebaseCursor(); // Grab the next hanlder on the list.
  1733. if(RulebaseHandlers[Handle].isReady()) { // Check to see if it's already in use. If so,
  1734. int wherewasi = Handle; // keep track of where we started.
  1735. while(RulebaseHandlers[(Handle=RoundRulebaseCursor())].isReady()){ // Loop to find an free handler.
  1736. if(wherewasi==Handle) { // If we get back where we started
  1737. RulebaseScan.unlock(); // Unlock the Rulebase Scanning process
  1738. throw TooMany("snf_MultiEngineHandler::OpenRulebase() Too Many Open"); // and tell the caller Too Many are open.
  1739. }
  1740. }
  1741. }
  1742. // Now we have a Handle to a free RulebaseHandler. Time to open it up.
  1743. try {
  1744. RulebaseHandlers[Handle].open(path,licenseid,authentication); // Try to open the handler.
  1745. } // If an exception is thrown...
  1746. catch(snf_RulebaseHandler::AuthenticationError& e) // Catch and re-throw the appropriate
  1747. { RulebaseScan.unlock(); throw AuthenticationError(e.what()); } // exception.
  1748. catch(snf_RulebaseHandler::AllocationError& e)
  1749. { RulebaseScan.unlock(); throw AllocationError(e.what()); }
  1750. catch(snf_RulebaseHandler::FileError& e)
  1751. { RulebaseScan.unlock(); throw FileError(e.what()); }
  1752. catch(snf_RulebaseHandler::Busy& e)
  1753. { RulebaseScan.unlock(); throw Panic(e.what()); } // Wasn't busy above!! Shoudn't be here!!!
  1754. catch(const std::exception& e)
  1755. { RulebaseScan.unlock(); throw e; }
  1756. catch(...) {
  1757. RulebaseScan.unlock();
  1758. throw Panic("snf_MultiEngineHandler::OpenRulebase() ???");
  1759. }
  1760. RulebaseScan.unlock(); // If everything went well then UnLock
  1761. return Handle; // and return the happy new handle.
  1762. }
  1763. // snf_RefreshRulebase()
  1764. // Reload the rulebase associated with the handler.
  1765. void snf_MultiEngineHandler::RefreshRulebase(int RulebaseHandle){ // Refreshing a rulebase (Not Serialized)
  1766. try {
  1767. RulebaseHandlers[RulebaseHandle].refresh(); // Try to refresh the rulebase.
  1768. } // Catch and rethrow any exceptions.
  1769. catch(snf_RulebaseHandler::AuthenticationError& e) {
  1770. throw AuthenticationError(e.what());
  1771. }
  1772. catch(snf_RulebaseHandler::AllocationError& e) {
  1773. throw AllocationError(e.what());
  1774. }
  1775. catch(snf_RulebaseHandler::FileError& e) {
  1776. throw FileError(e.what());
  1777. }
  1778. catch(snf_RulebaseHandler::Busy& e) {
  1779. throw Busy(e.what());
  1780. }
  1781. catch(const std::exception& e) {
  1782. throw e;
  1783. }
  1784. catch(...) {
  1785. throw Panic("snf_MultiEngineHandler::RefreshRulebase() ???");
  1786. }
  1787. }
  1788. // snf_CloseRulebase()
  1789. // Shut down this Rulebase handler.
  1790. void snf_MultiEngineHandler::CloseRulebase(int RulebaseHandle){ // Closing a rulebase handler
  1791. RulebaseScan.lock(); // Serialize this - the handler changes state.
  1792. try { // Try to close the handler.
  1793. RulebaseHandlers[RulebaseHandle].close();
  1794. }
  1795. catch(snf_RulebaseHandler::Busy& e) { // A busy throw we can understand.
  1796. RulebaseScan.unlock(); throw Busy(e.what());
  1797. }
  1798. catch(const std::exception& e) { // Other exceptions? rethrow.
  1799. RulebaseScan.unlock(); throw e;
  1800. }
  1801. catch(...) { // Any other throw is big trouble.
  1802. RulebaseScan.unlock();
  1803. throw Panic("snf_MultiEngineHandler::CloseRulebase() ???");
  1804. }
  1805. RulebaseScan.unlock(); // When done, unlock the Rulebase Scan process.
  1806. }
  1807. // snf_OpenEngine()
  1808. // Grab the first available Engine handler and light it up
  1809. int snf_MultiEngineHandler::OpenEngine(int RulebaseHandle){
  1810. EngineScan.lock(); // Serialize this.
  1811. if(SHUTDOWN==EngineCursor) { // Not ok to open after shutdown.
  1812. EngineScan.unlock();
  1813. throw Panic("snf_MultiEngineHandler::OpenEngine() No open after shutdwon");
  1814. }
  1815. int Handle = RoundEngineCursor(); // Grab the next hanlder on the list.
  1816. if(EngineHandlers[Handle].isReady()) { // Check to see if it's already in use. If so,
  1817. int wherewasi = Handle; // keep track of where we started.
  1818. while(EngineHandlers[(Handle=RoundEngineCursor())].isReady()){ // Loop to find an free handler.
  1819. if(wherewasi==Handle) { // If we get back where we started
  1820. EngineScan.unlock(); // Unlock the Rulebase Scanning process
  1821. throw TooMany("snf_MultiEngineHandler::OpenEngine() too many open"); // and tell the caller Too Many are open.
  1822. }
  1823. }
  1824. }
  1825. // Now we have a Handle to a free RulebaseHandler. Time to open it up.
  1826. try {
  1827. EngineHandlers[Handle].open(&RulebaseHandlers[RulebaseHandle]); // Try to open the handler.
  1828. } // If an exception is thrown...
  1829. catch(snf_EngineHandler::AllocationError& e) // Catch and rethrow as appropriate.
  1830. { EngineScan.unlock(); throw AllocationError(e.what()); }
  1831. catch(snf_EngineHandler::Busy& e)
  1832. { EngineScan.unlock(); throw Panic(e.what()); } // Not busy above should not be busy now!!!
  1833. catch(const std::exception& e) {
  1834. EngineScan.unlock();
  1835. throw e;
  1836. }
  1837. catch(...) {
  1838. EngineScan.unlock();
  1839. throw Panic("snf_MultiEngineHandler::OpenEngine() ???");
  1840. }
  1841. EngineScan.unlock(); // If everything went well then UnLock
  1842. return Handle; // and return the happy new handle.
  1843. }
  1844. // snf_CloseEngine()
  1845. // Shut down this Engine handler.
  1846. void snf_MultiEngineHandler::CloseEngine(int EngineHandle){ // Closing an engine handler.
  1847. EngineScan.lock(); // Serialize this, the object changes states.
  1848. try {
  1849. EngineHandlers[EngineHandle].close(); // Try closing the handler.
  1850. }
  1851. catch(snf_EngineHandler::AllocationError& e) // Catch and throw any exceptions as needed.
  1852. { EngineScan.unlock(); throw AllocationError(e.what()); }
  1853. catch(snf_EngineHandler::Busy& e)
  1854. { EngineScan.unlock(); throw Busy(e.what()); }
  1855. catch(const std::exception& e) {
  1856. EngineScan.unlock();
  1857. throw e;
  1858. }
  1859. catch(...) {
  1860. EngineScan.unlock();
  1861. throw Panic("snf_MultiEngineHandler::CloseEngine() ???");
  1862. }
  1863. EngineScan.unlock(); // Unlock when we're closed.
  1864. }
  1865. // snf_Scan()
  1866. // Scan the MessageBuffer with this Engine.
  1867. int snf_MultiEngineHandler::Scan(int EngineHandle, const unsigned char* MessageBuffer, int MessageLength){
  1868. // NOT serialized. Many scans at once, presumably one scan engine per thread.
  1869. int ScanResult; // ScanResult stays in scope.
  1870. try {
  1871. ScanResult=EngineHandlers[EngineHandle]
  1872. .scanMessage(MessageBuffer,MessageLength); // Try the scan on the given engine.
  1873. }
  1874. catch(snf_EngineHandler::AllocationError& e) { // Re-throw any exceptions as needed.
  1875. throw AllocationError(e.what());
  1876. }
  1877. catch(snf_EngineHandler::Busy& e) { throw Busy(e.what()); }
  1878. catch(const std::exception& e) { throw e; }
  1879. catch(...) { throw Panic("snf_MultiEngineHandler::Scan() ???"); }
  1880. return ScanResult; // Return the results.
  1881. }
  1882. // The Engine prvides detailed match results through this function.
  1883. int snf_MultiEngineHandler::getResults(int EngineHandle, snf_match* matchbfr){
  1884. // NOT serialized. Many scans at once, presumably one scan engine per thread.
  1885. int ResultCount; // ResultCount stays in scope.
  1886. try {
  1887. ResultCount=EngineHandlers[EngineHandle].getResults(matchbfr); // Try the scan on the given engine.
  1888. }
  1889. catch(snf_EngineHandler::AllocationError& e) { // Re-throw any exceptions as needed.
  1890. throw AllocationError(e.what());
  1891. }
  1892. catch(snf_EngineHandler::Busy& e) { throw Busy(e.what()); }
  1893. catch(const std::exception& e) { throw e; }
  1894. catch(...) { throw Panic("snf_MultiEngineHandler::getResults() ???"); }
  1895. return ResultCount; // Return the results.
  1896. }
  1897. // The Engine provies the scan depth through this function.
  1898. int snf_MultiEngineHandler::getDepth(int EngineHandle){
  1899. // NOT serialized. Many scans at once, presumably one scan engine per thread.
  1900. int DepthResult; // ScanResult stays in scope.
  1901. try {
  1902. DepthResult=EngineHandlers[EngineHandle].getDepth(); // Try the scan on the given engine.
  1903. }
  1904. catch(snf_EngineHandler::AllocationError& e) { // Re-throw any exceptions as needed.
  1905. throw AllocationError(e.what());
  1906. }
  1907. catch(snf_EngineHandler::Busy& e) { throw Busy(e.what()); }
  1908. catch(const std::exception& e) { throw e; }
  1909. catch(...) { throw Panic("snf_MultiEngineHandler::getDepth() ???"); }
  1910. return DepthResult; // Return the results.
  1911. }