-// ANNA - Anna is Not Nothingness Anymore
-//
-// (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
-//
-// http://redmine.teslayout.com/projects/anna-suite
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions
-// are met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of the copyright holder nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: eduardo.ramos.testillano@gmail.com
-// cisco.tierra@gmail.com
-
-// Standard
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
#include <pcap.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <map>
#include <anna/core/DataBlock.hpp>
-#include <anna/core/util/Tokenizer.hpp>
#include <anna/core/functions.hpp>
#include <anna/core/tracing/Logger.hpp>
#include <anna/core/tracing/TraceWriter.hpp>
#include <anna/core/RuntimeException.hpp>
-#include <anna/xml/xml.hpp>
-#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;
// Payload and frame metadata /////////////////////////////////////////////////////////////////////////////
class Payload {
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 ////////////////////////////////////////////////////////////////////////////////////
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::cout << std::endl;
//check command line arguments
- if(argc < 3) {
+ if(argc < 2) {
std::string msg = "Usage: "; msg += exec;
- 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 #-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.";
+ msg += " <pcap file> [--write-hex: to write hex files] [--debug: activates debug level traces (warning by default)]\n\n";
_exit(msg);
}
// Command-line parameters:
- std::string stacks = argv[1];
- std::string inputFile = argv[2];
+ std::string inputFile = argv[1];
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;
-
+ int indx = 2;
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);
+ bool writeHex = (optionals.find("--write-hex") != 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::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;
- }
-
- 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());
- }
-
- // 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
if(handle == NULL) _exit(errbuf, 2);
+ // TODO: add filtering. At the moment, pcap must be previously filtered for diameter protocol ('tcp port 3868' or any other filter allowed)
+ /*
+ // Filtering:
+ std::string filter = ?????;
+ struct bpf_program _fp;
+ struct bpf_program *fp = &_fp;
+ bpf_u_int32 netmask = 4294967295; // FFFFFFFF
+
+ if (pcap_compile(handle, fp, (char*)(filter.c_str()), 1, netmask) == -1) {
+ std::cerr << "Couldn't compile the filter " << filter << std::endl;
+ return(2);
+ }
+
+ if (pcap_setfilter(handle, fp) == -1) {
+ std::cerr << "Couldn't set the filter " << filter << std::endl;
+ return(2);
+ }
+ */
+
//begin processing the packets in this particular file
int packets = -1;
}
pcap_close(handle); //close the pcap file
+
// Print payloads //////////////////////////////////////////////////////////////////////////////////////////////
// Open output file:
outputFile += ".report";
int tsu = (it->second).getTimestampU();
std::string ts_str = ctime(&ts);
ts_str.erase(ts_str.find("\n"));
- out << std::endl;
- out
- << "==================================================================================================="
- << std::endl;
+ out << "Frame: " << anna::functions::asString(it->first) << 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);
- // Decode datablock:
- decodeDataBlock(db_aux, detectedApplicationId);
- // Stack identification:
- //out << "Application Id: " << detectedApplicationId << std::endl;
- out << "Dictionary used: " << G_codecEngine->getDictionary()->getName() << std::endl;
+ out << "Destination IP: " << (it->second).getDestinationIP() << std::endl;
+ out << "Hex String: " << (it->second).getDataAsHex() << std::endl;
+
+ // Create hex file:
+ if (writeHex) {
+ std::string hexFile = anna::functions::asString(it->first) + ".hex";
+ std::ofstream hex(hexFile.c_str(), std::ifstream::out);
+ hex << (it->second).getDataAsHex();
+ hex.close();
+ }
+
out << std::endl;
- 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.";
+ msg += "Open '"; msg += outputFile; msg += "' to see decoding results.\n";
+ if (writeHex) msg += "Open '<frame number>.hex' to see specific frame data.";
_exit(msg, 0);
}