#include #include #include #include #include #include #include "Port.hh" #include "PcapLayer.hh" #include "loggers.hh" PcapLayer::PcapLayer(const std::string & type, const std::string & param) : PcapLayer() { loggers::loggers::log(">>> PcapLayer::PcapLayer: %s, %s", type.c_str(), param.c_str()); // Setup parameters Params::convert(_params, param); _params.log(); // Prepare capture processing char error_buffer[PCAP_ERRBUF_SIZE]; std::map::const_iterator it = _params.find(std::string("nic")); if ((it != _params.end()) && !it->second.empty()) { // Use online capture // Fetch the network address and network mask /*bpf_u_int32 mask; // subnet mask bpf_u_int32 net; // ip address if (pcap_lookupnet(_params["nic"].c_str(), &net, &mask, error_buffer) != 0) { loggers::loggers::error("PcapLayer::PcapLayer: PcapLayer::PcapLayer: Failed to fetch newtork address for device %s", _params["nic"].c_str()); } loggers::loggers::log("PcapLayer::PcapLayer: Device %s Network address: %d", _params["nic"].c_str(), net);*/ // Open the device _device = pcap_open_live(_params["nic"].c_str(), 65536, 1, 1000, error_buffer); // TODO Replace hard coded values by PcapLayer:: if (_device == NULL) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to open device %s", _params["nic"].c_str()); } // else, continue // Set non-blocking flag for the polling procedure if (pcap_setnonblock(_device, 1, error_buffer) != 0) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to set blocking mode: %s", error_buffer); } // Retrieve the device file handler _pcap_h = pcap_get_selectable_fd(_device); if (_pcap_h == -1) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to get device handler"); } } else { // Check file name it = _params.find(std::string("file")); if ((it != _params.end()) && !it->second.empty()) { // Use offline capture struct stat s = {0}; if ((stat(_params["file"].c_str(), &s) != 0) || !S_ISREG(s.st_mode)) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to acces PCAP file %s", _params["file"].c_str()); } // File exist, open it _device = pcap_open_offline(_params["file"].c_str(), error_buffer); if (_device == NULL) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to open PCAP file %s", error_buffer); } // else, continue } else { loggers::loggers::error("PcapLayer::PcapLayer: Failed to open PCAP file %s", error_buffer); } } // Setup filter std::string filter; it = _params.find(std::string("filter")); if ((it != _params.end()) && !it->second.empty()) { filter = _params["filter"]; } // else nothing to do loggers::loggers::log("PcapLayer::PcapLayer: Filter: %s", filter.c_str()); if (!filter.empty()) { struct bpf_program f = {0}; if (pcap_compile(_device, &f, filter.c_str(), 1, PCAP_NETMASK_UNKNOWN) != 0) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to compile PCAP filter"); } if (pcap_setfilter(_device, &f) != 0) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to set PCAP filter"); } pcap_freecode(&f); } // Pass the device file handler to the polling procedure if (_pcap_h != -1) { Handler_Add_Fd_Read(_pcap_h); } else { // Create a pipe if (pipe2(_fd, O_NONBLOCK) == -1) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to create a pipe: %s", ::strerror(errno)); } // Pass the pipe handler to the polling procedure loggers::loggers::log("PcapLayer::PcapLayer: Call handler with descriptor %d", _fd[0]); Handler_Add_Fd_Read(_fd[0]); if (pthread_create(&_thread_id, NULL, &PcapLayer::run, (void *)this) != 0) { loggers::loggers::error("PcapLayer::PcapLayer: Failed to compile PCAP filter"); } // Start a working thread to dispatch packet to a pipe while (_running == FALSE) { std::this_thread::sleep_for(std::chrono::seconds(1)); } loggers::loggers::log("<<< PcapLayer::PcapLayer"); } } // End of ctor PcapLayer::~PcapLayer() { loggers::loggers::log(">>> PcapLayer::~PcapLayer"); if (_device != NULL) { if (_fd[0] != -1) { // TODO To be refined :-( _running = FALSE; // Wait for the working thread to terminate pthread_join(_thread_id, NULL); loggers::loggers::log("PcapLayer::~PcapLayer: Thread were stops"); // Cleanup close(_fd[0]); close(_fd[1]); } pcap_close(_device); } } // End of dtor void * PcapLayer::run(void *p_this) { loggers::loggers::log(">>> PcapLayer::run: Class pointer: %p", p_this); PcapLayer& p = *static_cast(p_this); p._running = TRUE; p._resume = TRUE; while (p._running) { if (p._resume == TRUE) { write(p._fd[1], "\n", 1); p._resume = FALSE; } std::this_thread::sleep_for(std::chrono::milliseconds(200)); } loggers::loggers::log("<<< PcapLayer::run"); return NULL; } void PcapLayer::sendData(const OCTETSTRING& data, const Params& params) { loggers::loggers::log_msg(">>> PcapLayer::sendData: ", data); } void PcapLayer::receiveData(const OCTETSTRING& data, const Params& params) { //loggers::loggers::log(">>> PcapLayer::receiveData: Received %d bytes", data.lengthof()); //loggers::loggers::log_to_hexa("Packet dump", data); // Pass the packet to the upper layers toAllUpperLayers(data, params); } void PcapLayer::Handle_Fd_Event_Readable(int fd) { //loggers::loggers::log(">>> PcapLayer::Handle_Fd_Event_Readable: %d", fd); struct pcap_pkthdr *pkt_header; const u_char *pkt_data; int result = pcap_next_ex(_device, &pkt_header, &pkt_data); if (result == 1) { // Succeed if (pkt_header->caplen > 14) { // Reject too small packet //loggers::loggers::log("PcapLayer::Handle_Fd_Event_Readable: %.6d - %d", pkt_header->ts.tv_usec, pkt_header->len); // Fill parameters from PCAP layer Params params; params.insert(std::pair(std::string("timestamp"), std::to_string(pkt_header->ts.tv_usec))); // Process the packet at this layer this->receiveData(OCTETSTRING(pkt_header->len, pkt_data), params); } } // else, skip the packet // Specific to offline mode if (_fd[0] != -1) { // Check if offline mode is used //loggers::loggers::log("PcapLayer::Handle_Fd_Event_Readable: Read pipe"); char c[2]; read(_fd[0], &c, 1); if (result == -2) { // End of file, therminate worker thread _running = FALSE; } else { // Get next packet loggers::loggers::log("PcapLayer::Handle_Fd_Event_Readable: pcap_next_ex failed: result=%d", result); _resume = TRUE; } } // else, nothing to do } class PcapFactory: public LayerFactory { static PcapFactory _f; public: PcapFactory(); virtual Layer * createLayer(const std::string & type, const std::string & param); }; PcapFactory::PcapFactory() { // register factory loggers::loggers::log(">>> PcapFactory::PcapFactory"); LayerStackBuilder::RegisterLayerFactory("PCAP", this); } Layer * PcapFactory::createLayer(const std::string & type, const std::string & param) { return new PcapLayer(type, param); } PcapFactory PcapFactory::_f;