#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) {
std::string exec = argv[0];
- std::string filetrace = exec.substr(exec.find_last_of("/") + 1) + ".trace";
+ 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::string msg = "Usage: "; msg += exec;
- msg += " <dictionaries> <input file> [--ignore-flags: non-strict validation]\n\n";
- msg += " dictionaries: list of comma-separated xml dictionaries (one or more can be provided).\n";
- msg += " Input file: normally a pcap file, but hexadecimal content (colons allowed) can also be decoded (use '.hex' extension).";
+ msg += " <stacks> <input file> [--no-validation] [--ignore-flags] [--debug]\n\n";
+ msg += " stacks: <id1,dictionary1#id2,dictionary2#...#idN,dictionaryN>\n";
+ msg += " This is a list of #-separated stacks defined by a comma-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 += " --no-validation: no validation is performed.\n";
+ msg += " --ignore-flags: wrong flags regarding dictionary are ignored in xml representation.\n";
+ msg += " --debug: activates debug level traces (warning by default).";
_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 ignoreFlags = ((argc == 4) && (optional == "--ignore-flags"));
- std::cout << "Dictionary(ies) provided: " << dictionaries << std::endl;
- std::cout << "Input file provided: " << inputFile << std::endl;
- std::cout << "Validation kindness: "
- << (ignoreFlags ? "non strict" : "strict") << std::endl;
- // Logger and engines:
- Logger::setLevel(Logger::Debug);
- Logger::initialize("pcapDecoder", new TraceWriter(filetrace.c_str(), 2048000));
- anna::diameter::codec::Engine *codecEngine =
- new anna::diameter::codec::Engine();
+ 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 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());
}
- 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");
- 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);
+ std::ofstream out(outputFile.c_str(), std::ifstream::out);
out << G_codecMsg.asXMLString();
// Close output file:
out.close();
- std::string msg = "Open 'file.trace' in order to see process traces.\n";
+ 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);
}
// Print payloads //////////////////////////////////////////////////////////////////////////////////////////////
// Open output file:
outputFile += ".report";
- std::ofstream out(outputFile, std::ifstream::out);
+ std::ofstream out(outputFile.c_str(), std::ifstream::out);
for(payloads_it it = G_payloads.begin(); it != G_payloads.end(); it++) {
LOGDEBUG(
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) {
- _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();
}
// Close output file:
out.close();
- std::string msg = "Open 'file.trace' in order to see process traces.\n";
+ 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);
}