Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

snf_HeaderFinder.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // snf_HeaderFinder.cpp
  2. // Copyright (C) 2007 - 2009 ARM Research Labs, LLC.
  3. // See www.armresearch.com for the copyright terms.
  4. //
  5. // See snf_HeaderFinder.hpp for details
  6. #include "snf_HeaderFinder.hpp"
  7. #include "snfLOGmgr.hpp"
  8. #include "snfCFGmgr.hpp"
  9. const int NumberOfByteValues = 256; // Number of possible byte values.
  10. HeaderFinder::HeaderFinder( // To construct one of these:
  11. snfScanData* EngineScanData, // -- Scanner control data ptr.
  12. const HeaderDirectiveSet& Patterns, // -- this is the set of patterns.
  13. const unsigned char* MessageBuffer, // -- this is the message buffer.
  14. const int MessageLength // -- this is the length of the buffer.
  15. ) :
  16. ScanData(EngineScanData), // Grab the scan control block.
  17. HeaderDirectives(Patterns), // Grab the Directives and
  18. Bfr(MessageBuffer), // the message buffer.
  19. Len(MessageLength),
  20. ImpossibleBytes(NumberOfByteValues, false), // Clear the impossible bytes cache.
  21. Directives(0) { // Zero the composite result.
  22. UnfoldHeaders(); // Unfold the headers.
  23. }
  24. IP4Address extractIPFromSourceHeader(string& Header) { // Return first IP found in header.
  25. const string Digits = "0123456789";
  26. unsigned int EndOfName = Header.find_first_of(":");
  27. unsigned int StartOfIP = Header.find_first_of(Digits, EndOfName);
  28. const string IPCharacters = ".0123456789";
  29. unsigned int EndOfIP = Header.find_first_not_of(IPCharacters, StartOfIP);
  30. bool NoExtraCharactersAfterIP = (string::npos == EndOfIP);
  31. if(NoExtraCharactersAfterIP) EndOfIP = Header.length();
  32. unsigned int IPLength = EndOfIP - StartOfIP;
  33. IP4Address ExtractedIP = Header.substr(StartOfIP, IPLength);
  34. return ExtractedIP;
  35. }
  36. void HeaderFinder::CheckContent(string& Header, const HeaderFinderPattern& P) { // Check for a match in the header.
  37. bool HeaderContainsFinderPattern = (
  38. string::npos != Header.find(P.Contains, P.Header.length())
  39. );
  40. if(HeaderContainsFinderPattern) {
  41. switch(P.Directive) {
  42. case HeaderDirectiveBypass:
  43. case HeaderDirectiveWhite: {
  44. Directives |= P.Directive; // Add the flags to our output.
  45. break;
  46. }
  47. case HeaderDirectiveDrillDown: {
  48. ScanData->drillPastOrdinal(P.Ordinal); // Mark the IP DrillDown flag.
  49. Directives |= P.Directive; // Add the flags to our output.
  50. break;
  51. }
  52. case HeaderDirectiveContext: {
  53. ActivatedContexts.insert(P.Context); // Activate the context.
  54. Directives |= P.Directive; // Add the flags to our output.
  55. break;
  56. }
  57. case HeaderDirectiveSource: {
  58. bool HeaderDirectiveSourceIPNotSet = (
  59. 0UL == ScanData->HeaderDirectiveSourceIP()
  60. );
  61. bool SourceContextActive = (
  62. ActivatedContexts.end() != ActivatedContexts.find(P.Context)
  63. );
  64. if(HeaderDirectiveSourceIPNotSet && SourceContextActive) {
  65. ScanData->HeaderDirectiveSourceIP(
  66. extractIPFromSourceHeader(Header)
  67. );
  68. Directives |= P.Directive; // Add the flags to our output.
  69. }
  70. break;
  71. }
  72. }
  73. }
  74. }
  75. void HeaderFinder::MatchHeaders(string& Header) { // Check that the header matches.
  76. if(0 >= Header.length()) return; // If there's nothing to look at, done!
  77. HeaderFinderPattern Key; // We will need a handy key.
  78. Key.Header.push_back(Header.at(0)); // Set up a minimal header string.
  79. HeaderDirectiveIterator iK = HeaderDirectives.lower_bound(Key); // Locate the lower bound.
  80. // At this point we have found a reasonable starting place for the
  81. // header directives that might match this header. We will scan through
  82. // them looking for a match. Since all matches should be grouped together
  83. // in the set we will set a flag so that on the first non-match after that
  84. // we can stop looking.
  85. int CurrentOrdinal = 0; // Keep the current ordinal in scope.
  86. bool FoundFirstMatch = false; // Have we found our first match?
  87. for(;iK != HeaderDirectives.end();iK++) { // Scan through the directives.
  88. const HeaderFinderPattern& P = (*iK); // Make a handy handle.
  89. if(0 == Header.compare(0, P.Header.length(), P.Header)) { // Check for a matching header.
  90. if(false == FoundFirstMatch) { // If this is our first match
  91. FoundFirstMatch = true; // then set our first match flag
  92. CurrentOrdinal = Ordinals[P.Header]; // and get the Ordinal. Then increment
  93. Ordinals[P.Header] = CurrentOrdinal + 1; // the Ordinal for next time.
  94. }
  95. if(CurrentOrdinal == P.Ordinal) { // If the Ordinal matches our Directive
  96. CheckContent(Header, P); // then check the content of the header.
  97. } else
  98. if(CurrentOrdinal < P.Ordinal) { // If we're into Directives bigger than
  99. return; // our Ordinal then we're done.
  100. }
  101. } else { // If the header doesn't match and we
  102. if(FoundFirstMatch) return; // were matching before then we're done.
  103. if(Header.at(0)!=P.Header.at(0)) return; // If first bytes don't match, so done!
  104. }
  105. } // Move on to the next directive.
  106. }
  107. bool HeaderFinder::ByteIsImpossible(unsigned char b) { // Is b not first byte of any pattern?
  108. if(ImpossibleBytes[b]) return true; // Don't look if we already know.
  109. HeaderFinderPattern Key; // We will need a handy key.
  110. Key.Header.push_back(b); // Set up a minimal header string.
  111. HeaderDirectiveIterator iK = HeaderDirectives.lower_bound(Key); // Locate the lower bound.
  112. if(iK == HeaderDirectives.end()) return (ImpossibleBytes[b] = true); // If we find nothing or the first byte
  113. if((*iK).Header.at(0) != b) return (ImpossibleBytes[b] = true); // byte doesn't match it's impossible.
  114. return false; // Otherwise we might find it ;-)
  115. }
  116. bool TrimToNextHeader(int& Pos, const unsigned char* Bfr, const int Len) { // Move Pos & check for EOH.
  117. for(;(Pos < (Len-2));Pos++) { // Scan through the Bfr (stay in range).
  118. switch(Bfr[Pos]) { // React to the byte at hand:
  119. case '\t':
  120. case '\r':
  121. case ' ': { // Ordinary spaces and \r we skip.
  122. break;
  123. }
  124. case '\n': { // On Newlines we check to see if
  125. if( // this is the end of the headers.
  126. ('\r' == Bfr[Pos+1] && '\n' == Bfr[Pos+2]) || // Either \n\r\n or
  127. ('\n' == Bfr[Pos+1] ) // \n\n means EOH.
  128. ) {
  129. return false; // If EOH, no more headers, send false.
  130. }
  131. break; // If not EOH then keep going.
  132. }
  133. default: { // Any other byte and we are done.
  134. return true; // We have another header, send true.
  135. }
  136. }
  137. } // If we run out of bytes then we
  138. return false; // are also out of headers, send false.
  139. }
  140. void eatThisHeader(int& Pos, const unsigned char* Bfr, const int Len) { // Eat up to the next header.
  141. for(;(Pos < (Len-1));Pos++) { // Scan through this header.
  142. if('\n' == Bfr[Pos]) { // When we get to a new line check
  143. if(' ' == Bfr[Pos+1] || '\t' == Bfr[Pos+1]) continue; // for and skip any folding. Anything
  144. return; // other than folding and we're done.
  145. }
  146. }
  147. }
  148. void eatOrdinarySpace(int& Pos, const unsigned char* Bfr, const int Len) { // Eat all spaces (dedup, unfold, etc)
  149. for(;Pos < Len;Pos++) { // Scan through the buffer.
  150. switch(Bfr[Pos]) { // React to each byte.
  151. case ' ': // Simply skip all ordinary spaces
  152. case '\t': { // or tabs.
  153. break;
  154. }
  155. default: { // At the first other byte
  156. return; // we are done.
  157. }
  158. }
  159. }
  160. }
  161. void captureThisHeader( // Capture the header and move pos.
  162. string& Output, // Here is the output string.
  163. int& Pos, // Here is the current position.
  164. const unsigned char* Bfr, // Here is the buffer pointer.
  165. const int Len // Here is the length of the buffer.
  166. ) {
  167. Output.clear(); // Clear the output.
  168. for(;(Pos < (Len-1)); Pos++) { // Scan through the header.
  169. switch(Bfr[Pos]) { // React to each byte.
  170. case '\r': { // If we find a <cr> ignore it.
  171. break;
  172. }
  173. case '\n': { // If we find a <nl> check for folding.
  174. if(' ' == Bfr[Pos+1] || '\t' == Bfr[Pos+1]) { // If we find folding then
  175. ++Pos; // move to the space
  176. eatOrdinarySpace(Pos, Bfr, Len); // and gobble it up.
  177. Output.push_back(' '); // output a single ordinary space
  178. --Pos; // and drop back one for the loop's ++.
  179. } else { // If the <nl> wasn't part of a fold
  180. return; // then we are done with this header.
  181. }
  182. break; // Skip the rest of the switch.
  183. }
  184. case '\t': // When we come across a tab or
  185. case ' ': { // a space then we will eat them
  186. eatOrdinarySpace(Pos, Bfr, Len); // and any extras so they are converted
  187. Output.push_back(' '); // into a single ordinary space.
  188. --Pos; // Drop back one for the loop's ++.
  189. break;
  190. }
  191. default: { // For all ordinary bytes we simply
  192. Output.push_back(Bfr[Pos]); // add the byte to the string.
  193. break;
  194. }
  195. }
  196. }
  197. }
  198. void HeaderFinder::UnfoldHeaders() { // Unfold and check headers.
  199. if(0 >= HeaderDirectives.size()) return; // Skip this if we have no patterns.
  200. if(0 >= Len) return; // Skip if we have no message.
  201. string TestHeader; // The header under test.
  202. int Position = 0; // Position in Bfr.
  203. for(;;) { // Scan through all of the headers.
  204. // Skip any leading or leftover whitespace. Be sure to exit when we
  205. // reach a blank new line. The capture routine later on will not eat
  206. // the white space - that way we can check for the EOH in this one spot.
  207. if(false == TrimToNextHeader(Position, Bfr, Len)) return; // If no more headers then we're done.
  208. // Skip Impossible Headers -- no such first character.
  209. if(ByteIsImpossible(Bfr[Position])) { // If we have no patterns for this
  210. eatThisHeader(Position, Bfr, Len); // header then skip it and continue on
  211. continue; // to the next one.
  212. }
  213. // Capture and unfold the header to test.
  214. captureThisHeader(TestHeader, Position, Bfr, Len); // Unfold the header into TestHeader.
  215. // Test the header.
  216. MatchHeaders(TestHeader); // Match and activate header directives.
  217. }
  218. }