#include <anna/diameter/stack/Engine.hpp>
#include <anna/diameter/codec/Engine.hpp>
#include <anna/diameter/codec/Message.hpp>
+//#include <anna/diameter/defines.hpp> // typedef unsigned int ApplicationId;
+#include <anna/diameter/codec/functions.hpp> // ApplicationId anna::diameter::codec::functions::getApplicationId(const anna::DataBlock &) throw(anna::RuntimeException);
+
using namespace anna;
using namespace anna::diameter;
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 ////////////////////////////////////////////////////////////////////////////////////
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) {
//check command line arguments
if(argc < 3) {
std::string msg = "Usage: "; msg += exec;
- msg += " <dictionaries> <input file> [--non-strict-validation]\n\n";
- msg += " dictionaries: list of comma-separated xml dictionaries (one or more can be provided).\n";
+ msg += " <stacks> <input file> [--no-validation] [--ignore-flags]\n\n";
+ msg += " stacks: <id1#dictionary1,id2#dictionary2,...,idN#dictionaryN>\n";
+ msg += " This is a list of comma-separated stacks defined by a #-separated pair <application-id#xml dictionary pathfile>\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 '<application-id>#<xml dictionary pathfile>'", 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);
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();
}
public:
- typedef std::map<int, Dictionary*> stack_container;
+ typedef std::map<unsigned int, Dictionary*> stack_container;
typedef stack_container::const_iterator const_stack_iterator;
typedef stack_container::iterator stack_iterator;
* @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(); }
/**
* 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
*
* @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
*
* @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).
* @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<int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException);
+ void loadDictionary(const std::vector<unsigned int> & 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
*
* @param stackId Stack identifier for created dictionary
*/
- void removeStack(int stackId) throw();
+ void removeStack(unsigned int stackId) throw();
private:
//------------------------------------------------------------------------------
//------------------------------------------------------ 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);
//------------------------------------------------------------------------------
//----------------------------------------------------------- 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 ");
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";
}
}
//------------------------------------------------------------------------------
//------------------------------------------------- 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<Dictionary *>(getDictionary(stackId));
if(!dictionary)
//------------------------------------------------------------------------------
//--------------------------------------------------- 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<Dictionary *>(getDictionary(stackId));
if(result) // if exists, launch exception
}
-void anna::diameter::stack::Engine::loadDictionary(const std::vector<int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) {
- std::vector<int>::const_iterator it;
+void anna::diameter::stack::Engine::loadDictionary(const std::vector<unsigned int> & stacks, const std::string & xmlPathFile) throw(anna::RuntimeException) {
+ std::vector<unsigned int>::const_iterator it;
Dictionary *d;
if(xmlPathFile == "")
//------------------------------------------------------------------------------
//-------------------------------------------------------- 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