Changeset View
Changeset View
Standalone View
Standalone View
plugins/process/network/helper/Capture.cpp
Show All 25 Lines | |||||
26 | 26 | | |||
27 | #include <pcap/pcap.h> | 27 | #include <pcap/pcap.h> | ||
28 | 28 | | |||
29 | #include "Packet.h" | 29 | #include "Packet.h" | ||
30 | #include "TimeStamps.h" | 30 | #include "TimeStamps.h" | ||
31 | 31 | | |||
32 | using namespace std::string_literals; | 32 | using namespace std::string_literals; | ||
33 | 33 | | |||
34 | // Limit the amount of entries waiting in the queue to this size, to prevent | ||||
35 | // the queue from getting too full. | ||||
36 | static const int MaximumQueueSize = 1000; | ||||
37 | | ||||
34 | void pcapDispatchCallback(uint8_t *user, const struct pcap_pkthdr *h, const uint8_t *bytes) | 38 | void pcapDispatchCallback(uint8_t *user, const struct pcap_pkthdr *h, const uint8_t *bytes) | ||
35 | { | 39 | { | ||
36 | reinterpret_cast<Capture *>(user)->handlePacket(h, bytes); | 40 | reinterpret_cast<Capture *>(user)->handlePacket(h, bytes); | ||
37 | } | 41 | } | ||
38 | 42 | | |||
39 | Capture::Capture(const std::string &interface) | 43 | Capture::Capture(const std::string &interface) | ||
40 | { | 44 | { | ||
41 | m_interface = interface; | 45 | m_interface = interface; | ||
42 | } | 46 | } | ||
43 | 47 | | |||
44 | Capture::~Capture() | 48 | Capture::~Capture() | ||
45 | { | 49 | { | ||
46 | if (m_pcap) { | 50 | if (m_pcap) { | ||
47 | if (m_active) { | | |||
48 | stop(); | 51 | stop(); | ||
49 | } | 52 | } | ||
50 | | ||||
51 | pcap_close(m_pcap); | | |||
52 | } | | |||
53 | } | 53 | } | ||
54 | 54 | | |||
55 | bool Capture::start() | 55 | bool Capture::start() | ||
56 | { | 56 | { | ||
57 | auto device = m_interface.empty() ? (const char *)nullptr : m_interface.c_str(); | 57 | auto device = m_interface.empty() ? (const char *)nullptr : m_interface.c_str(); | ||
58 | 58 | | |||
59 | char errorBuffer[PCAP_ERRBUF_SIZE]; | 59 | char errorBuffer[PCAP_ERRBUF_SIZE]; | ||
60 | m_pcap = pcap_create(device, errorBuffer); | 60 | m_pcap = pcap_create(device, errorBuffer); | ||
61 | if (!m_pcap) { | 61 | if (!m_pcap) { | ||
62 | m_error = std::string(errorBuffer, PCAP_ERRBUF_SIZE); | 62 | m_error = std::string(errorBuffer, PCAP_ERRBUF_SIZE); | ||
63 | return false; | 63 | return false; | ||
64 | } | 64 | } | ||
65 | 65 | | |||
66 | pcap_set_timeout(m_pcap, 500); | 66 | pcap_set_timeout(m_pcap, 500); | ||
67 | pcap_set_snaplen(m_pcap, 100); | 67 | pcap_set_snaplen(m_pcap, 100); | ||
68 | pcap_set_promisc(m_pcap, 0); | 68 | pcap_set_promisc(m_pcap, 0); | ||
69 | pcap_set_datalink(m_pcap, DLT_LINUX_SLL); | 69 | pcap_set_datalink(m_pcap, DLT_LINUX_SLL); | ||
70 | 70 | | |||
71 | if (checkError(pcap_activate(m_pcap))) | 71 | if (checkError(pcap_activate(m_pcap))) { | ||
72 | return false; | 72 | return false; | ||
73 | } | ||||
73 | 74 | | |||
74 | struct bpf_program filter; | 75 | struct bpf_program filter; | ||
75 | if (checkError(pcap_compile(m_pcap, &filter, "tcp or udp", 1, PCAP_NETMASK_UNKNOWN))) { | 76 | if (checkError(pcap_compile(m_pcap, &filter, "tcp or udp", 1, PCAP_NETMASK_UNKNOWN))) { | ||
76 | pcap_freecode(&filter); | | |||
77 | return false; | 77 | return false; | ||
78 | } | 78 | } | ||
79 | 79 | | |||
80 | if (checkError(pcap_setfilter(m_pcap, &filter))) { | 80 | if (checkError(pcap_setfilter(m_pcap, &filter))) { | ||
81 | pcap_freecode(&filter); | 81 | pcap_freecode(&filter); | ||
82 | return false; | 82 | return false; | ||
83 | } | 83 | } | ||
84 | 84 | | |||
85 | pcap_freecode(&filter); | 85 | pcap_freecode(&filter); | ||
86 | 86 | | |||
87 | m_thread = std::thread { &Capture::loop, this }; | 87 | m_thread = std::thread { &Capture::loop, this }; | ||
88 | 88 | | |||
89 | return true; | 89 | return true; | ||
90 | } | 90 | } | ||
91 | 91 | | |||
92 | void Capture::stop() | 92 | void Capture::stop() | ||
93 | { | 93 | { | ||
94 | pcap_breakloop(m_pcap); | 94 | pcap_breakloop(m_pcap); | ||
95 | if (m_thread.joinable()) { | 95 | if (m_thread.joinable()) { | ||
96 | m_thread.join(); | 96 | m_thread.join(); | ||
97 | } | 97 | } | ||
98 | pcap_close(m_pcap); | ||||
99 | m_pcap = nullptr; | ||||
98 | } | 100 | } | ||
99 | 101 | | |||
100 | std::string Capture::lastError() const | 102 | std::string Capture::lastError() const | ||
101 | { | 103 | { | ||
102 | return m_error; | 104 | return m_error; | ||
103 | } | 105 | } | ||
104 | 106 | | |||
105 | void Capture::reportStatistics() | 107 | void Capture::reportStatistics() | ||
106 | { | 108 | { | ||
107 | pcap_stat stats; | 109 | pcap_stat stats; | ||
108 | pcap_stats(m_pcap, &stats); | 110 | pcap_stats(m_pcap, &stats); | ||
109 | 111 | | |||
110 | std::cout << "Packet Statistics: " << std::endl; | 112 | std::cout << "Packet Statistics: " << std::endl; | ||
111 | std::cout << " " << stats.ps_recv << " received" << std::endl; | 113 | std::cout << " " << stats.ps_recv << " received" << std::endl; | ||
112 | std::cout << " " << stats.ps_drop << " dropped (full)" << std::endl; | 114 | std::cout << " " << stats.ps_drop << " dropped (full)" << std::endl; | ||
113 | std::cout << " " << stats.ps_ifdrop << " dropped (iface)" << std::endl; | 115 | std::cout << " " << stats.ps_ifdrop << " dropped (iface)" << std::endl; | ||
114 | std::cout << " " << m_packetCount << " processed" << std::endl; | 116 | std::cout << " " << m_packetCount << " processed" << std::endl; | ||
117 | std::cout << " " << m_droppedPackets << " dropped (capture)" << std::endl; | ||||
115 | } | 118 | } | ||
116 | 119 | | |||
117 | Packet Capture::nextPacket() | 120 | Packet Capture::nextPacket() | ||
118 | { | 121 | { | ||
119 | std::unique_lock<std::mutex> lock(m_mutex); | 122 | std::unique_lock<std::mutex> lock(m_mutex); | ||
120 | m_condition.wait(lock, [this]() { return m_queue.size() > 0; }); | 123 | m_condition.wait(lock, [this]() { return m_queue.size() > 0; }); | ||
121 | 124 | | |||
122 | auto packet = std::move(m_queue.front()); | 125 | auto packet = std::move(m_queue.front()); | ||
Show All 34 Lines | 136 | { | |||
157 | 160 | | |||
158 | return false; | 161 | return false; | ||
159 | } | 162 | } | ||
160 | 163 | | |||
161 | void Capture::handlePacket(const struct pcap_pkthdr *header, const uint8_t *data) | 164 | void Capture::handlePacket(const struct pcap_pkthdr *header, const uint8_t *data) | ||
162 | { | 165 | { | ||
163 | auto timeStamp = std::chrono::time_point_cast<TimeStamp::MicroSeconds::duration>(std::chrono::system_clock::from_time_t(header->ts.tv_sec) + std::chrono::microseconds { header->ts.tv_usec }); | 166 | auto timeStamp = std::chrono::time_point_cast<TimeStamp::MicroSeconds::duration>(std::chrono::system_clock::from_time_t(header->ts.tv_sec) + std::chrono::microseconds { header->ts.tv_usec }); | ||
164 | 167 | | |||
165 | m_packetCount++; | | |||
166 | { | 168 | { | ||
167 | std::lock_guard<std::mutex> lock { m_mutex }; | 169 | std::lock_guard<std::mutex> lock { m_mutex }; | ||
170 | | ||||
171 | m_packetCount++; | ||||
172 | if (m_queue.size() < MaximumQueueSize) { | ||||
168 | m_queue.emplace_back(timeStamp, data, header->caplen, header->len); | 173 | m_queue.emplace_back(timeStamp, data, header->caplen, header->len); | ||
174 | } else { | ||||
175 | m_droppedPackets++; | ||||
176 | } | ||||
169 | } | 177 | } | ||
170 | 178 | | |||
171 | m_condition.notify_all(); | 179 | m_condition.notify_all(); | ||
172 | } | 180 | } |