Newer
Older
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <thread>
#include <chrono>
#include "Port.hh"
#include "PcapLayer.hh"
#include "loggers.hh"
PcapLayer::PcapLayer(const std::string & type, const std::string & param) : PcapLayer() {
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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<std::string, std::string>::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::<constants>
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) {
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
} 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<PcapLayer *>(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);
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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, std::string>(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 {
PcapFactory();
virtual Layer * createLayer(const std::string & type,
const std::string & param);
// register factory
loggers::loggers::log(">>> PcapFactory::PcapFactory");
LayerStackBuilder::RegisterLayerFactory("PCAP", this);
}
Layer * PcapFactory::createLayer(const std::string & type, const std::string & param) {