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

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