// snf_HeaderFinder.cpp | // snf_HeaderFinder.cpp | ||||
// Copyright (C) 2007 - 2009 ARM Research Labs, LLC. | |||||
// Copyright (C) 2007 - 2020 ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | // See www.armresearch.com for the copyright terms. | ||||
// | // | ||||
// See snf_HeaderFinder.hpp for details | // See snf_HeaderFinder.hpp for details | ||||
#include "snfLOGmgr.hpp" | #include "snfLOGmgr.hpp" | ||||
#include "snfCFGmgr.hpp" | #include "snfCFGmgr.hpp" | ||||
namespace cd = codedweller; | |||||
const int NumberOfByteValues = 256; // Number of possible byte values. | const int NumberOfByteValues = 256; // Number of possible byte values. | ||||
const bool HeaderFinderPattern::operator<(const HeaderFinderPattern& R) const { // Comparator for set<> living. | |||||
if(Header < R.Header) { // If the Header name is < then true! | |||||
return true; | |||||
} else | |||||
if(Header == R.Header) { // If the Header name is == then | |||||
if(Ordinal < R.Ordinal) { // check the Ordinal. If it's < then | |||||
return true; // true! | |||||
} else | |||||
if(Ordinal == R.Ordinal) { // If the Ordinal == then | |||||
if(Contains < R.Contains) { // check the Contains. If it is < then | |||||
return true; // true! | |||||
} else | |||||
if(Context < R.Context) { | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
return false; // In all other cases this is not < R | |||||
} | |||||
HeaderFinderPattern::HeaderFinderPattern(const HeaderFinderPattern& P) { // Copy constructor. | |||||
Header = P.Header; | |||||
Ordinal = P.Ordinal; | |||||
Context = P.Context; | |||||
Directive = P.Directive; | |||||
Contains = P.Contains; | |||||
} | |||||
void HeaderFinderPattern::clear() { // Do this to make fresh and clean. | |||||
Header.clear(); | |||||
Ordinal = Context = Directive = 0; | |||||
Contains.clear(); | |||||
} | |||||
HeaderFinderPattern& | |||||
HeaderFinderPattern::operator=(const HeaderFinderPattern& R) { // Assignment operator. | |||||
Header = R.Header; | |||||
Ordinal = R.Ordinal; | |||||
Context = R.Context; | |||||
Directive = R.Directive; | |||||
Contains = R.Contains; | |||||
return *this; | |||||
} | |||||
const unsigned long int HeaderFinder::operator()() const { // Return the Directives. | |||||
return Directives; | |||||
} | |||||
HeaderFinder::HeaderFinder( // To construct one of these: | HeaderFinder::HeaderFinder( // To construct one of these: | ||||
snfScanData* EngineScanData, // -- Scanner control data ptr. | snfScanData* EngineScanData, // -- Scanner control data ptr. | ||||
const HeaderDirectiveSet& Patterns, // -- this is the set of patterns. | const HeaderDirectiveSet& Patterns, // -- this is the set of patterns. | ||||
HeaderDirectives(Patterns), // Grab the Directives and | HeaderDirectives(Patterns), // Grab the Directives and | ||||
Bfr(MessageBuffer), // the message buffer. | Bfr(MessageBuffer), // the message buffer. | ||||
Len(MessageLength), | Len(MessageLength), | ||||
ImpossibleBytes(NumberOfByteValues, false), // Clear the impossible bytes cache. | |||||
ImpossibleBytes(NumberOfByteValues, false), // Clear the impossible bytes cache. | |||||
Directives(0) { // Zero the composite result. | Directives(0) { // Zero the composite result. | ||||
UnfoldHeaders(); // Unfold the headers. | UnfoldHeaders(); // Unfold the headers. | ||||
} | } | ||||
IP4Address extractIPFromSourceHeader(string& Header) { // Return first IP found in header. | |||||
const string Digits = "0123456789"; | |||||
unsigned int EndOfName = Header.find_first_of(":"); | |||||
unsigned int StartOfIP = Header.find_first_of(Digits, EndOfName); | |||||
const string IPCharacters = ".0123456789"; | |||||
unsigned int EndOfIP = Header.find_first_not_of(IPCharacters, StartOfIP); | |||||
bool NoExtraCharactersAfterIP = (string::npos == EndOfIP); | |||||
if(NoExtraCharactersAfterIP) EndOfIP = Header.length(); | |||||
unsigned int IPLength = EndOfIP - StartOfIP; | |||||
IP4Address ExtractedIP = Header.substr(StartOfIP, IPLength); | |||||
return ExtractedIP; | |||||
} | |||||
void HeaderFinder::CheckContent(string& Header, const HeaderFinderPattern& P) { // Check for a match in the header. | |||||
bool HeaderContainsFinderPattern = ( | |||||
string::npos != Header.find(P.Contains, P.Header.length()) | |||||
cd::IP4Address extractIPFromSourceHeader(string& Header) { // Return first IP found in header. | |||||
const string Digits = "0123456789"; | |||||
unsigned int EndOfName = Header.find_first_of(":"); | |||||
unsigned int StartOfIP = Header.find_first_of(Digits, EndOfName); | |||||
const string IPCharacters = ".0123456789"; | |||||
unsigned int EndOfIP = Header.find_first_not_of(IPCharacters, StartOfIP); | |||||
bool NoExtraCharactersAfterIP = (string::npos == EndOfIP); | |||||
if(NoExtraCharactersAfterIP) EndOfIP = Header.length(); | |||||
unsigned int IPLength = EndOfIP - StartOfIP; | |||||
cd::IP4Address ExtractedIP = Header.substr(StartOfIP, IPLength); | |||||
return ExtractedIP; | |||||
} | |||||
void HeaderFinder::CheckContent(string& Header, const HeaderFinderPattern& P) { // Check for a match in the header. | |||||
bool HeaderContainsFinderPattern = ( | |||||
string::npos != Header.find(P.Contains, P.Header.length()) | |||||
); | ); | ||||
if(HeaderContainsFinderPattern) { | if(HeaderContainsFinderPattern) { | ||||
switch(P.Directive) { | |||||
case HeaderDirectiveBypass: | |||||
case HeaderDirectiveWhite: { | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
break; | |||||
} | |||||
case HeaderDirectiveDrillDown: { | |||||
ScanData->drillPastOrdinal(P.Ordinal); // Mark the IP DrillDown flag. | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
break; | |||||
} | |||||
case HeaderDirectiveContext: { | |||||
ActivatedContexts.insert(P.Context); // Activate the context. | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
break; | |||||
} | |||||
case HeaderDirectiveSource: { | |||||
bool HeaderDirectiveSourceIPNotSet = ( | |||||
0UL == ScanData->HeaderDirectiveSourceIP() | |||||
); | |||||
bool SourceContextActive = ( | |||||
ActivatedContexts.end() != ActivatedContexts.find(P.Context) | |||||
); | |||||
if(HeaderDirectiveSourceIPNotSet && SourceContextActive) { | |||||
ScanData->HeaderDirectiveSourceIP( | |||||
extractIPFromSourceHeader(Header) | |||||
); | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
switch(P.Directive) { | |||||
case HeaderDirectiveBypass: | |||||
case HeaderDirectiveWhite: { | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
break; | |||||
} | |||||
case HeaderDirectiveDrillDown: { | |||||
ScanData->drillPastOrdinal(P.Ordinal); // Mark the IP DrillDown flag. | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
break; | |||||
} | |||||
case HeaderDirectiveContext: { | |||||
ActivatedContexts.insert(P.Context); // Activate the context. | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
break; | |||||
} | |||||
case HeaderDirectiveSource: { | |||||
bool HeaderDirectiveSourceIPNotSet = ( | |||||
0UL == ScanData->HeaderDirectiveSourceIP() | |||||
); | |||||
bool SourceContextActive = ( | |||||
ActivatedContexts.end() != ActivatedContexts.find(P.Context) | |||||
); | |||||
if(HeaderDirectiveSourceIPNotSet && SourceContextActive) { | |||||
ScanData->HeaderDirectiveSourceIP( | |||||
extractIPFromSourceHeader(Header) | |||||
); | |||||
Directives |= P.Directive; // Add the flags to our output. | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
// snf_HeaderFinder.hpp | // snf_HeaderFinder.hpp | ||||
// Copyright (C) 2007 - 2009 ARM Research Labs, LLC. | |||||
// Copyright (C) 2007 - 2020 ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | // See www.armresearch.com for the copyright terms. | ||||
// | // | ||||
// SNF Header Finder used for identifying headers in a message. A header match | // SNF Header Finder used for identifying headers in a message. A header match | ||||
// | // | ||||
// The evaluation of the status flag is defined by the application. | // The evaluation of the status flag is defined by the application. | ||||
#ifndef snf_HeaderFinder_included | |||||
#define snf_HeaderFinder_included | |||||
#pragma once | |||||
#include <string> | #include <string> | ||||
#include <set> | #include <set> | ||||
#include <map> | #include <map> | ||||
#include <vector> | #include <vector> | ||||
using namespace std; | |||||
struct HeaderFinderPattern { // Input pattern for header finder. | struct HeaderFinderPattern { // Input pattern for header finder. | ||||
string Header; // Header name to match. | |||||
std::string Header; // Header name to match. | |||||
int Ordinal; // Which instance to match. | int Ordinal; // Which instance to match. | ||||
int Context; // Context link (for pairing patterns). | int Context; // Context link (for pairing patterns). | ||||
string Contains; // What to find in the header. | |||||
std::string Contains; // What to find in the header. | |||||
unsigned long int Directive; // What directive to present. | unsigned long int Directive; // What directive to present. | ||||
HeaderFinderPattern(): // When constructing a finder parttern | HeaderFinderPattern(): // When constructing a finder parttern | ||||
const bool operator<(const HeaderFinderPattern& R) const; // Comparator for set<> living. | const bool operator<(const HeaderFinderPattern& R) const; // Comparator for set<> living. | ||||
}; | }; | ||||
typedef set<HeaderFinderPattern> HeaderDirectiveSet; // Convenient set typedef. | |||||
typedef set<HeaderFinderPattern>::iterator HeaderDirectiveIterator; // Convenient iterator typedef. | |||||
typedef std::set<HeaderFinderPattern> HeaderDirectiveSet; // Convenient set typedef. | |||||
typedef std::set<HeaderFinderPattern>::iterator HeaderDirectiveIterator; // Convenient iterator typedef. | |||||
typedef map<const string, int> NameOrdinalMap; // Header Ordinal Count Map. | |||||
typedef std::map<const std::string, int> NameOrdinalMap; // Header Ordinal Count Map. | |||||
// Upon construction the HeaderFinder scans the headers for matching directives | // Upon construction the HeaderFinder scans the headers for matching directives | ||||
// and leaves the composite results ready for inspection via the () operator. | // and leaves the composite results ready for inspection via the () operator. | ||||
class HeaderFinder { // Header Finder Object. | class HeaderFinder { // Header Finder Object. | ||||
private: | private: | ||||
snfScanData* ScanData; // Scanner control data. | |||||
snfScanData* ScanData; // Scanner control data. | |||||
const HeaderDirectiveSet& HeaderDirectives; // Handle for the directives/patterns. | const HeaderDirectiveSet& HeaderDirectives; // Handle for the directives/patterns. | ||||
const unsigned char* Bfr; // Message buffer. | |||||
const int Len; // Message length. | |||||
vector<bool> ImpossibleBytes; // Cache of known impossible bytes. | |||||
const unsigned char* Bfr; // Message buffer. | |||||
const int Len; // Message length. | |||||
std::vector<bool> ImpossibleBytes; // Cache of known impossible bytes. | |||||
unsigned long int Directives; // Composite result given this message. | unsigned long int Directives; // Composite result given this message. | ||||
set<int> ActivatedContexts; // Set of activated contexts. | |||||
std::set<int> ActivatedContexts; // Set of activated contexts. | |||||
NameOrdinalMap Ordinals; // Map of current header ordinals. | NameOrdinalMap Ordinals; // Map of current header ordinals. | ||||
void CheckContent(string& Header, const HeaderFinderPattern& P); // Check for a match in the header. | |||||
void MatchHeaders(string& Header); // Check that the header matches. | |||||
void CheckContent(std::string& Header, const HeaderFinderPattern& P); // Check for a match in the header. | |||||
void MatchHeaders(std::string& Header); // Check that the header matches. | |||||
bool ByteIsImpossible(unsigned char b); // Is b not first byte of any pattern? | bool ByteIsImpossible(unsigned char b); // Is b not first byte of any pattern? | ||||
void UnfoldHeaders(); // Unfold and check headers. | void UnfoldHeaders(); // Unfold and check headers. | ||||
); | ); | ||||
const unsigned long int operator()() const; // How to read the composite directives. | const unsigned long int operator()() const; // How to read the composite directives. | ||||
string EstablishedSourceIP; // Source IP from directive if any. | |||||
std::string EstablishedSourceIP; // Source IP from directive if any. | |||||
}; | }; | ||||
#include "snf_HeaderFinder.inline.hpp" | |||||
#endif |
// snf_HeaderFinder.inline.hpp | |||||
// Copyright (C) 2007 - 2009 ARM Research Labs, LLC. | |||||
// See www.armresearch.com for the copyright terms. | |||||
// Inline methods. | |||||
inline const bool HeaderFinderPattern::operator<(const HeaderFinderPattern& R) const { // Comparator for set<> living. | |||||
if(Header < R.Header) { // If the Header name is < then true! | |||||
return true; | |||||
} else | |||||
if(Header == R.Header) { // If the Header name is == then | |||||
if(Ordinal < R.Ordinal) { // check the Ordinal. If it's < then | |||||
return true; // true! | |||||
} else | |||||
if(Ordinal == R.Ordinal) { // If the Ordinal == then | |||||
if(Contains < R.Contains) { // check the Contains. If it is < then | |||||
return true; // true! | |||||
} else | |||||
if(Context < R.Context) { | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
return false; // In all other cases this is not < R | |||||
} | |||||
inline HeaderFinderPattern::HeaderFinderPattern(const HeaderFinderPattern& P) { // Copy constructor. | |||||
Header = P.Header; | |||||
Ordinal = P.Ordinal; | |||||
Context = P.Context; | |||||
Directive = P.Directive; | |||||
Contains = P.Contains; | |||||
} | |||||
inline void HeaderFinderPattern::clear() { // Do this to make fresh and clean. | |||||
Header.clear(); | |||||
Ordinal = Context = Directive = 0; | |||||
Contains.clear(); | |||||
} | |||||
inline HeaderFinderPattern& | |||||
HeaderFinderPattern::operator=(const HeaderFinderPattern& R) { // Assignment operator. | |||||
Header = R.Header; | |||||
Ordinal = R.Ordinal; | |||||
Context = R.Context; | |||||
Directive = R.Directive; | |||||
Contains = R.Contains; | |||||
return *this; | |||||
} | |||||
inline const unsigned long int HeaderFinder::operator()() const { // Return the Directives. | |||||
return Directives; | |||||
} |