From 1a7a2591d75aef76173a0e8f80bf0183b3b72e82 Mon Sep 17 00:00:00 2001 From: Eduardo Ramos Testillano Date: Mon, 6 Apr 2015 16:41:00 +0200 Subject: [PATCH] Fix enum bug (was on dictionary even when no data). PcapDecoder can load multiple stacks, selected with the incoming application-id --- example/diameter/pcapDecoder/main.cpp | 143 ++++++++++++++----------- include/anna/diameter/stack/Engine.hpp | 16 +-- source/diameter/stack/Avp.cpp | 4 +- source/diameter/stack/Engine.cpp | 24 +++-- 4 files changed, 107 insertions(+), 80 deletions(-) diff --git a/example/diameter/pcapDecoder/main.cpp b/example/diameter/pcapDecoder/main.cpp index 80278e4..d296a40 100644 --- a/example/diameter/pcapDecoder/main.cpp +++ b/example/diameter/pcapDecoder/main.cpp @@ -55,6 +55,9 @@ #include #include #include +//#include // typedef unsigned int ApplicationId; +#include // ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException); + using namespace anna; using namespace anna::diameter; @@ -147,6 +150,7 @@ typedef std::map < int /* frame */, Payload > payloads_t; typedef std::map < int /* frame */, Payload >::const_iterator payloads_it; payloads_t G_payloads; anna::diameter::codec::Message G_codecMsg; +anna::diameter::codec::Engine *G_codecEngine; // Sniffing structures //////////////////////////////////////////////////////////////////////////////////// @@ -323,6 +327,17 @@ void _exit(const std::string &message, int resultCode = 1) { exit(resultCode); } +// Decodes a diameter message coming from a datablock +void decodeDataBlock(const anna::DataBlock &db, unsigned int & detectedApplicationId) throw() { + try { + detectedApplicationId = anna::diameter::codec::functions::getApplicationId(db); + G_codecEngine->setDictionary(detectedApplicationId); + G_codecMsg.decode(db); + } catch(RuntimeException &ex) { + _exit(ex.asString()); + } +} + //------------------------------------------------------------------- int main(int argc, char **argv) { @@ -334,88 +349,94 @@ int main(int argc, char **argv) { //check command line arguments if(argc < 3) { std::string msg = "Usage: "; msg += exec; - msg += " [--non-strict-validation]\n\n"; - msg += " dictionaries: list of comma-separated xml dictionaries (one or more can be provided).\n"; + msg += " [--no-validation] [--ignore-flags]\n\n"; + msg += " stacks: \n"; + msg += " This is a list of comma-separated stacks defined by a #-separated pair \n"; + msg += " If only one stack is provided, application-id could be omitted and then, all the messages will be decoded with the\n"; + msg += " dictionary regardless the value of the application-id (the stack will be registered with id=0).\n"; msg += " Input file: normally a pcap file, but hexadecimal content (colons allowed) can also be decoded (use '.hex' extension).\n"; - msg += " --non-strict-validation: no validation is performed, and wrong flags regarding dictionary are ignored in xml representation."; + msg += " --no-validation: no validation is performed.\n"; + msg += " --ignore-flags: wrong flags regarding dictionary are ignored in xml representation."; _exit(msg); } // Command-line parameters: - std::string dictionaries = argv[1]; + std::string stacks = argv[1]; std::string inputFile = argv[2]; bool isHex = (inputFile.substr(inputFile.find_last_of(".") + 1) == "hex"); std::string outputFile = inputFile; // extension will be added later - std::string optional = argv[3] ? argv[3] : ""; - bool non_strict_validation = ((argc == 4) && (optional == "--non-strict-validation")); - std::cout << "Dictionary(ies) provided: " << dictionaries << std::endl; - std::cout << "Input file provided: " << inputFile << std::endl; - std::cout << "Validation kindness: " << (non_strict_validation ? "non strict" : "strict") << std::endl; - // Logger and engines: + std::string optionals; + int indx = 3; + + while(indx < argc) { optionals += " "; optionals += argv[indx]; indx++; } + + bool no_validation = (optionals.find("--no-validation") != std::string::npos); + bool ignore_flags = (optionals.find("--ignore-flags") != std::string::npos); Logger::setLevel(Logger::Debug); Logger::initialize(execBN.c_str(), new TraceWriter(filetrace.c_str(), 2048000)); - anna::diameter::codec::Engine *codecEngine = - new anna::diameter::codec::Engine(); + G_codecEngine = new anna::diameter::codec::Engine(); anna::diameter::stack::Engine &stackEngine = anna::diameter::stack::Engine::instantiate(); + // Register stacks: try { - anna::diameter::stack::Dictionary * d = stackEngine.createDictionary( - 0 /* stack id */); - // Analyze comma-separated list: - anna::Tokenizer lst; - lst.apply(dictionaries, ","); - - if(lst.size() >= 1) { // always true (at least one, because -dictionary is mandatory) - anna::Tokenizer::const_iterator tok_min(lst.begin()); - anna::Tokenizer::const_iterator tok_max(lst.end()); - anna::Tokenizer::const_iterator tok_iter; - std::string pathFile; - d->allowUpdates(); - - for(tok_iter = tok_min; tok_iter != tok_max; tok_iter++) { - pathFile = anna::Tokenizer::data(tok_iter); - d->load(pathFile); + anna::Tokenizer stacksTok; + stacksTok.apply(stacks, ","); + anna::Tokenizer::const_iterator stacks_it, stack_it; + + for(stacks_it = stacksTok.begin(); stacks_it != stacksTok.end(); stacks_it++) { + std::string stack = anna::Tokenizer::data(stacks_it); + anna::Tokenizer stackTok; + stackTok.apply(stack, "#"); + + if(stackTok.size() == 1) { + if(stacksTok.size() != 1) + throw anna::RuntimeException("Application Id value is mandatory when more than one stack is going to be configured", ANNA_FILE_LOCATION); + + anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(0 /* no matter */, stack); // the stack is the dictionary + G_codecEngine->setDictionary(d); + break; } - } - codecEngine->setDictionary(d); - //LOGDEBUG(anna::Logger::debug(codecEngine->asString(), ANNA_FILE_LOCATION)); - - if(lst.size() > 1) { - std::string all_in_one = "./dictionary-all-in-one.xml"; - std::ofstream out(all_in_one, std::ifstream::out); - std::string buffer = d->asXMLString(); - out.write(buffer.c_str(), buffer.size()); - out.close(); - std::cout << "Written accumulated '" << all_in_one - << "' (provide it next time to be more comfortable)." << std::endl; + if(stackTok.size() != 2) + throw anna::RuntimeException("Each stack must be in the form '#'", ANNA_FILE_LOCATION); + + stack_it = stackTok.begin(); + unsigned int stackId = atoll(anna::Tokenizer::data(stack_it)); + stack_it++; + std::string file = anna::Tokenizer::data(stack_it); + anna::diameter::stack::Dictionary * d = stackEngine.createDictionary(stackId, file); } + + std::cout << "Stacks provided: " << std::endl; + std::cout << anna::functions::tab(stackEngine.asString(false /* light */)); + std::cout << std::endl; + std::cout << "Input file provided: " << inputFile << std::endl; + std::cout << "Validation: " << (!no_validation ? "yes" : "no") << std::endl; + std::cout << "Ignore Flags: " << (ignore_flags ? "yes" : "no") << std::endl; + std::cout << std::endl; } catch(anna::RuntimeException &ex) { _exit(ex.asString()); } - if(non_strict_validation) { - codecEngine->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never); - codecEngine->ignoreFlagsOnValidation(true); - } + // Validation kindness + if(no_validation) G_codecEngine->setValidationMode(anna::diameter::codec::EngineImpl::ValidationMode::Never); + + if(ignore_flags) G_codecEngine->ignoreFlagsOnValidation(true); // Tracing: //if (cl.exists("trace")) // anna::Logger::setLevel(anna::Logger::asLevel(cl.getValue("trace"))); // Check hex content input file (look extension): anna::DataBlock db_aux(true); + unsigned int detectedApplicationId; if(isHex) { if(!getDataBlockFromHexFile(inputFile, db_aux)) _exit("Error reading hex file provided"); - try { - G_codecMsg.decode(db_aux); - } catch(RuntimeException &ex) { - _exit(ex.asString()); - } - + // Decode datablock: + decodeDataBlock(db_aux, detectedApplicationId); // Open output file: outputFile += ".as.xml"; std::ofstream out(outputFile, std::ifstream::out); @@ -467,21 +488,19 @@ int main(int argc, char **argv) { out << "===================================================================================================" << std::endl; - out << "Date: " << ts_str << std::endl; - out << "Timestamp: " << std::to_string(ts) << "." + out << "Date: " << ts_str << std::endl; + out << "Timestamp: " << std::to_string(ts) << "." << std::to_string(tsu) << std::endl; - out << "Origin IP: " << (it->second).getSourceIP() << std::endl; - out << "Destination IP: " << (it->second).getDestinationIP() << std::endl; - out << std::endl; + out << "Origin IP: " << (it->second).getSourceIP() << std::endl; + out << "Destination IP: " << (it->second).getDestinationIP() << std::endl; // decode hex string: anna::functions::fromHexString((it->second).getDataAsHex(), db_aux); - - try { - G_codecMsg.decode(db_aux); - } catch(RuntimeException &ex) { - _exit(ex.asString()); - } - + // Decode datablock: + decodeDataBlock(db_aux, detectedApplicationId); + // Stack identification: + //out << "Application Id: " << detectedApplicationId << std::endl; + out << "Dictionary used: " << G_codecEngine->getDictionary()->getName() << std::endl; + out << std::endl; out << G_codecMsg.asXMLString(); } diff --git a/include/anna/diameter/stack/Engine.hpp b/include/anna/diameter/stack/Engine.hpp index ca3f758..5dcb440 100644 --- a/include/anna/diameter/stack/Engine.hpp +++ b/include/anna/diameter/stack/Engine.hpp @@ -71,7 +71,7 @@ class Engine : public anna::Singleton { public: - typedef std::map stack_container; + typedef std::map stack_container; typedef stack_container::const_iterator const_stack_iterator; typedef stack_container::iterator stack_iterator; @@ -84,7 +84,7 @@ public: * @param stackId Stack identifier. * @return Dictionary reference, NULL if no stack found */ - const Dictionary * getDictionary(int stackId) const throw(); + const Dictionary * getDictionary(unsigned int stackId) const throw(); /** Beginning stack iterator */ const_stack_iterator stack_begin() const throw() { return a_stacks.begin(); } @@ -104,9 +104,11 @@ public: /** * Class string representation * + * @param all Complete engine information versus only stacks list with its ids and dictionary names + * * @return String with class content */ - std::string asString(void) const throw(); + std::string asString(bool all = true) const throw(); // set @@ -143,7 +145,7 @@ public: * * @return Dictionary registered. When exception happen, dictionary can be accessed by #getDictionary */ - Dictionary * createDictionary(int stackId, const std::string & xmlPathFile = "") throw(anna::RuntimeException); + Dictionary * createDictionary(unsigned int stackId, const std::string & xmlPathFile = "") throw(anna::RuntimeException); /** * Register a externally created Dictionary or a derived class from Dictionary @@ -154,7 +156,7 @@ public: * * @return Dictionary registered. When exception happen, dictionary can be accessed by #getDictionary */ - Dictionary * registerDictionary(int stackId, Dictionary *dictionary) throw(anna::RuntimeException); + Dictionary * registerDictionary(unsigned int stackId, Dictionary *dictionary) throw(anna::RuntimeException); /** * Loads an XML dictionary document over the diameter stack identifiers (one or more stack id's). @@ -164,7 +166,7 @@ public: * @param stacks Stacks identifiers over which the dictionary will be load. * @param xmlPathFile Path file to the xml document which represents the diameter dictionary. */ - void loadDictionary(const std::vector & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException); + void loadDictionary(const std::vector & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException); /** * Loads an XML dictionary document over all the diameter engine registered stacks. When more than one stack id is @@ -185,7 +187,7 @@ public: * * @param stackId Stack identifier for created dictionary */ - void removeStack(int stackId) throw(); + void removeStack(unsigned int stackId) throw(); private: diff --git a/source/diameter/stack/Avp.cpp b/source/diameter/stack/Avp.cpp index d3d971d..252e816 100644 --- a/source/diameter/stack/Avp.cpp +++ b/source/diameter/stack/Avp.cpp @@ -294,7 +294,9 @@ anna::xml::Node* anna::diameter::stack::Avp::asXML(anna::xml::Node* parent) cons single->createAttribute("format-name", a_formatName); if(format->isEnumerated()) { - single->createAttribute("enum", getEnums()); + std::string enums = getEnums(); + + if(enums != "") single->createAttribute("enum", enums); } if(hasAliases()) { diff --git a/source/diameter/stack/Engine.cpp b/source/diameter/stack/Engine.cpp index 07daa79..bb46cbe 100644 --- a/source/diameter/stack/Engine.cpp +++ b/source/diameter/stack/Engine.cpp @@ -163,7 +163,7 @@ anna::diameter::stack::Engine::Engine(void) { //------------------------------------------------------------------------------ //------------------------------------------------------ Engine::getDictionary() //------------------------------------------------------------------------------ -const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDictionary(int stackId) const throw() { +const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDictionary(unsigned int stackId) const throw() { const Dictionary * result = NULL; const_stack_iterator it = a_stacks.find(stackId); @@ -176,12 +176,12 @@ const anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::getDict //------------------------------------------------------------------------------ //----------------------------------------------------------- Engine::asString() //------------------------------------------------------------------------------ -std::string anna::diameter::stack::Engine::asString(void) const throw() { +std::string anna::diameter::stack::Engine::asString(bool all) const throw() { std::string trace; - int stackId; + unsigned int stackId; if(isEmpty()) { - trace = "No diameter dictionaries found"; + trace = "No diameter stacks found"; } else { int numberOfStacks = stack_size(); trace = ((numberOfStacks > 1) ? "Multi-stack " : "Mono-stack "); @@ -194,7 +194,11 @@ std::string anna::diameter::stack::Engine::asString(void) const throw() { std::string title = "Diameter stack id = "; title += anna::functions::asString((*it).first); trace += anna::functions::highlightJustify(title); - trace += (*it).second->asString(); trace += "\n"; + + if(all) trace += (*it).second->asString(); + else trace += (*it).second->getName(); + + trace += "\n"; } } @@ -206,7 +210,7 @@ std::string anna::diameter::stack::Engine::asString(void) const throw() { //------------------------------------------------------------------------------ //------------------------------------------------- Engine::registerDictionary() //------------------------------------------------------------------------------ -anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::registerDictionary(int stackId, Dictionary *dictionary) throw(anna::RuntimeException) { +anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::registerDictionary(unsigned int stackId, Dictionary *dictionary) throw(anna::RuntimeException) { Dictionary * result = const_cast(getDictionary(stackId)); if(!dictionary) @@ -227,7 +231,7 @@ anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::registerDicti //------------------------------------------------------------------------------ //--------------------------------------------------- Engine::createDictionary() //------------------------------------------------------------------------------ -anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::createDictionary(int stackId, const std::string & xmlPathFile) throw(anna::RuntimeException) { +anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::createDictionary(unsigned int stackId, const std::string & xmlPathFile) throw(anna::RuntimeException) { Dictionary * result = const_cast(getDictionary(stackId)); if(result) // if exists, launch exception @@ -249,8 +253,8 @@ anna::diameter::stack::Dictionary * anna::diameter::stack::Engine::createDictio } -void anna::diameter::stack::Engine::loadDictionary(const std::vector & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) { - std::vector::const_iterator it; +void anna::diameter::stack::Engine::loadDictionary(const std::vector & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) { + std::vector::const_iterator it; Dictionary *d; if(xmlPathFile == "") @@ -289,7 +293,7 @@ void anna::diameter::stack::Engine::loadDictionary(const std::string & xmlPathFi //------------------------------------------------------------------------------ //-------------------------------------------------------- Engine::removeStack() //------------------------------------------------------------------------------ -void anna::diameter::stack::Engine::removeStack(int stackId) throw() { +void anna::diameter::stack::Engine::removeStack(unsigned int stackId) throw() { stack_iterator it = a_stacks.find(stackId); if(it != stack_end()) { // if exists, clear -- 2.20.1