X-Git-Url: https://git.teslayout.com/public/public/public/?a=blobdiff_plain;f=example%2Fdiameter%2FpcapDecoder%2Fmain.cpp;h=69c4f19ddf4b53b7cae498b870e5ab0c7fc1f1a1;hb=c2d9954484b92913d1289160efa6a9055cb9bdf1;hp=8e3e86614ecfc3824137250e55c0ef88ffd37629;hpb=0ce74f51388826845727411a7d37d841111ede84;p=anna.git diff --git a/example/diameter/pcapDecoder/main.cpp b/example/diameter/pcapDecoder/main.cpp index 8e3e866..69c4f19 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 //////////////////////////////////////////////////////////////////////////////////// @@ -289,77 +293,164 @@ void my_callback(u_char *useless, const struct pcap_pkthdr* pkthdr, count++; } +bool getDataBlockFromHexFile(const std::string &pathfile, anna::DataBlock &db) throw() { + // Get hex string + static char buffer[8192]; + std::ifstream infile(pathfile.c_str(), std::ifstream::in); + + if(infile.is_open()) { + infile >> buffer; + std::string hexString(buffer, strlen(buffer)); + // Allow colon separator in hex string: we have to remove them before processing with 'fromHexString': + hexString.erase(std::remove(hexString.begin(), hexString.end(), ':'), hexString.end()); + LOGDEBUG( + std::string msg = "Hex string (remove colons if exists): "; + msg += hexString; + anna::Logger::debug(msg, ANNA_FILE_LOCATION); + ); + anna::functions::fromHexString(hexString, db); + // Close file + infile.close(); + return true; + } + + return false; +} + + +void _exit(const std::string &message, int resultCode = 1) { + if(resultCode) + std::cerr << message << std::endl << std::endl; + else + std::cout << message << std::endl << std::endl; + + 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) { std::string exec = argv[0]; + std::string execBN = exec.substr(exec.find_last_of("/") + 1); + std::string filetrace = execBN + ".trace"; std::cout << std::endl; //check command line arguments if(argc < 3) { - std::cout << "Usage: " << exec - << " [--ignore-flags: non-strict validation]" - << std::endl << std::endl; - return 1; + std::string msg = "Usage: "; msg += exec; + msg += " [--no-validation] [--ignore-flags]\n\n"; + msg += " stacks: \n"; + msg += " This is a list of #-separated stacks defined by a comma-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 += " --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 pcapFile = argv[2]; - std::string optional = argv[3] ? argv[3] : ""; - bool ignoreFlags = ((argc == 4) && (optional == "--ignore-flags")); - std::cout << "Dictionary(ies) provided: " << dictionaries << std::endl; - std::cout << "Pcap file provided: " << pcapFile << std::endl; - std::cout << "Validation kindness: " - << (ignoreFlags ? "non strict" : "strict") << std::endl; - // Logger and engines: - Logger::setLevel(Logger::Debug); - Logger::initialize("pcapDecoder", new TraceWriter("file.trace", 2048000)); - anna::diameter::codec::Engine *codecEngine = - new anna::diameter::codec::Engine(); + 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 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); + bool debug = (optionals.find("--debug") != std::string::npos); + Logger::setLevel(debug ? Logger::Debug:Logger::Warning); + Logger::initialize(execBN.c_str(), new TraceWriter(filetrace.c_str(), 2048000)); + 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 '" << 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) { - std::cerr << ex.asString() << std::endl << std::endl; - return 1; + _exit(ex.asString()); } - codecEngine->ignoreFlagsOnValidation(ignoreFlags); + // Validation kindness + G_codecEngine->setValidationDepth(anna::diameter::codec::EngineImpl::ValidationDepth::Complete); // complete validation for better reports + 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"); + + // Decode datablock: + decodeDataBlock(db_aux, detectedApplicationId); + // Open output file: + outputFile += ".as.xml"; + std::ofstream out(outputFile.c_str(), std::ifstream::out); + out << G_codecMsg.asXMLString(); + // Close output file: + out.close(); + std::string msg = "Open '"; msg += filetrace; msg += "' in order to see process traces.\n"; + msg += "Open '"; msg += outputFile; msg += "' to see decoding results."; + _exit(msg, 0); + } + + // Normal input: pcap file: // SNIFFING //////////////////////////////////////////////////////////////////////////////////////////////7 //temporary packet buffers struct pcap_pkthdr header; // The header that pcap gives us @@ -368,12 +459,9 @@ int main(int argc, char **argv) { //open the pcap file pcap_t *handle; char errbuf[PCAP_ERRBUF_SIZE]; //not sure what to do with this, oh well - handle = pcap_open_offline(pcapFile.c_str(), errbuf); //call pcap library function + handle = pcap_open_offline(inputFile.c_str(), errbuf); //call pcap library function - if(handle == NULL) { - std::cerr << errbuf << std::endl << std::endl; - return 2; - } + if(handle == NULL) _exit(errbuf, 2); //begin processing the packets in this particular file int packets = -1; @@ -382,20 +470,14 @@ int main(int argc, char **argv) { while(packets != 0) packets = pcap_dispatch(handle, -1, (pcap_handler) my_callback, NULL); } catch(RuntimeException &ex) { - std::cerr << ex.asString() << std::endl << std::endl; - return 1; + _exit(ex.asString()); } pcap_close(handle); //close the pcap file // Print payloads ////////////////////////////////////////////////////////////////////////////////////////////// // Open output file: - std::string output = pcapFile; - output += ".report"; - std::ofstream out(output, std::ifstream::out); - std::string xmlStr; - anna::DataBlock db_aux(true); - - //out.write(str.c_str(), str.size()); + outputFile += ".report"; + std::ofstream out(outputFile.c_str(), std::ifstream::out); for(payloads_it it = G_payloads.begin(); it != G_payloads.end(); it++) { LOGDEBUG( @@ -408,31 +490,26 @@ int main(int argc, char **argv) { out << "===================================================================================================" << std::endl; - 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 << "Date: " << ts_str << std::endl; + out << "Timestamp: " << anna::functions::asString((int)ts) << "." + << anna::functions::asString((int)tsu) << 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) { - std::cerr << ex.asString() << std::endl << std::endl; - return 1; - } - + // 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(); } // Close output file: out.close(); - std::cout << "Open 'file.trace' in order to see process traces." << std::endl; - std::cout << "Open '" << output << "' to see conversion results." - << std::endl; - std::cout << std::endl; - return 0; + std::string msg = "Open '"; msg += filetrace; msg += "' in order to see process traces.\n"; + msg += "Open '"; msg += outputFile; msg += "' to see decoding results."; + _exit(msg, 0); }