statistics.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. // Aidmar
  2. #include <iostream>
  3. #include <fstream>
  4. #include <vector>
  5. #include <math.h>
  6. #include <algorithm>
  7. #include "statistics.h"
  8. #include <sstream>
  9. #include <SQLiteCpp/SQLiteCpp.h>
  10. #include "statistics_db.h"
  11. // Aidmar
  12. /**
  13. * Get closest index for element in vector.
  14. * @param v vector
  15. * @param refElem element that we search for or for closest element
  16. */
  17. int getClosestIndex(std::vector<std::chrono::microseconds> v, std::chrono::microseconds refElem)
  18. {
  19. auto i = min_element(begin(v), end(v), [=] (std::chrono::microseconds x, std::chrono::microseconds y)
  20. {
  21. return std::abs((x - refElem).count()) < std::abs((y - refElem).count());
  22. });
  23. return std::distance(begin(v), i);
  24. }
  25. // Aidmar
  26. /**
  27. * Calculate entropy of source and destination IPs for last time interval and write results to a ip_entropy_interval.csv file.
  28. * @param intervalStartTimestamp The timstamp where the interval starts.
  29. */
  30. void statistics::calculateLastIntervalIPsEntropy(std::string filePath, std::chrono::microseconds intervalStartTimestamp){
  31. std::vector <int> IPsSrcPktsCounts;
  32. std::vector <int> IPsDstPktsCounts;
  33. std::vector <float> IPsSrcProb;
  34. std::vector <float> IPsDstProb;
  35. int pktsSent = 0, pktsReceived = 0;
  36. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  37. int indexStartSent = getClosestIndex(i->second.pktsSentTimestamp, intervalStartTimestamp);
  38. int IPsSrcPktsCount = i->second.pktsSentTimestamp.size() - indexStartSent;
  39. IPsSrcPktsCounts.push_back(IPsSrcPktsCount);
  40. pktsSent += IPsSrcPktsCount;
  41. //std::cout<<"IP:"<<i->first<<", indexStartSent:"<<indexStartSent<<", value:"<<i->second.pktsSentTimestamp[indexStartSent].count()<<", IPsSrcPktsCount:"<<IPsSrcPktsCount<<", total_pktsSent:"<<pktsSent<<"\n";
  42. int indexStartReceived = getClosestIndex(i->second.pktsReceivedTimestamp, intervalStartTimestamp);
  43. int IPsDstPktsCount = i->second.pktsReceivedTimestamp.size() - indexStartReceived;
  44. IPsDstPktsCounts.push_back(IPsDstPktsCount);
  45. pktsReceived += IPsDstPktsCount;
  46. }
  47. for (auto i = IPsSrcPktsCounts.begin(); i != IPsSrcPktsCounts.end(); i++) {
  48. IPsSrcProb.push_back((float)*i/pktsSent);
  49. //std::cout<<"IpSrcProb:"<<(float)*i/pktsSent<<"\n";
  50. }
  51. for (auto i = IPsDstPktsCounts.begin(); i != IPsDstPktsCounts.end(); i++) {
  52. IPsDstProb.push_back((float)*i/pktsReceived);
  53. //std::cout<<"IpDstProb:"<<(float)*i/pktsReceived<<"\n";
  54. }
  55. // Calculate IP source entropy
  56. float IPsSrcEntropy = 0;
  57. for(unsigned i=0; i < IPsSrcProb.size();i++){
  58. if (IPsSrcProb[i] > 0)
  59. IPsSrcEntropy += - IPsSrcProb[i]*log2(IPsSrcProb[i]);
  60. }
  61. // Calculate IP destination entropy
  62. float IPsDstEntropy = 0;
  63. for(unsigned i=0; i < IPsDstProb.size();i++){
  64. if (IPsDstProb[i] > 0)
  65. IPsDstEntropy += - IPsDstProb[i]*log2(IPsDstProb[i]);
  66. }
  67. // Replace pcap filename with 'filename_ip_entropy'
  68. std::string new_filepath = filePath;
  69. const std::string &newExt = "_ip_entropy_interval.csv";
  70. std::string::size_type h = new_filepath.rfind('.', new_filepath.length());
  71. if (h != std::string::npos) {
  72. new_filepath.replace(h, newExt.length(), newExt);
  73. } else {
  74. new_filepath.append(newExt);
  75. }
  76. // Write stats to file
  77. std::ofstream file;
  78. file.open (new_filepath,std::ios_base::app);
  79. file << intervalStartTimestamp.count() << "," << IPsSrcEntropy << "," << IPsDstEntropy << "\n";
  80. file.close();
  81. }
  82. // Aidmar - incomplete
  83. /**
  84. * Calculate entropy for time intervals. After finishing statistics collecting, this method goes through
  85. * all stored timestamps and calculate entropy of IP source and destination.
  86. * Big time overhead!! better to calculate it on fly, while we are processing packets.
  87. * @param
  88. */
  89. /*
  90. void statistics::calculateIntervalIPsEntropy(std::chrono::microseconds interval){
  91. std::vector <std::string> IPsSrc;
  92. std::vector <std::string> IPsDst;
  93. std::vector <int> pkts_sent;
  94. std::vector <int> pkts_received;
  95. std::vector <float> IPsSrcProb;
  96. std::vector <float> IPsDstProb;
  97. time_t t = (timestamp_lastPacket.seconds() - timestamp_firstPacket.seconds());
  98. time_t ms = (timestamp_lastPacket.microseconds() - timestamp_firstPacket.microseconds());
  99. intervalNum = t/interval;
  100. for(int j=0;j<intervalNum;j++){
  101. intStart = j*interval;
  102. intEnd = intStart + interval;
  103. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  104. for(int x = 0; x<i->second.pktsSentTimestamp.size();x++){ // could have a prob loop on pktsSent, and inside we have pktsReceived..
  105. if(i->second.pktsSentTimestamp[x]>intStart && i->second.pktsSentTimestamp[x]<intEnd){
  106. IPsSrc.push_back(i->first);
  107. }
  108. if(i->second.pktsReceivedTimestamp[x]>intStart && i->second.pktsReceivedTimestamp[x]<intEnd){
  109. IPsDst.push_back(i->first);
  110. }
  111. }
  112. }
  113. //IPsSrcProb.push_back((float)i->second.pkts_sent/packetCount);
  114. //IPsDstProb.push_back((float)i->second.pkts_received/packetCount);
  115. }
  116. }*/
  117. // Aidmar
  118. /**
  119. * Calculate cumulative entropy of source and destination IPs; the entropy for packets from the beginning of the pcap file.
  120. */
  121. void statistics::addIPEntropy(std::string filePath){
  122. std::vector <std::string> IPs;
  123. std::vector <float> IPsSrcProb;
  124. std::vector <float> IPsDstProb;
  125. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  126. IPs.push_back(i->first);
  127. IPsSrcProb.push_back((float)i->second.pkts_sent/packetCount);
  128. IPsDstProb.push_back((float)i->second.pkts_received/packetCount);
  129. /*std::cout << i->first << ":" << i->second.pkts_sent << ":" << i->second.pkts_received << ":"
  130. << i->second.firstAppearAsSenderPktCount << ":" << i->second.firstAppearAsReceiverPktCount << ":"
  131. << packetCount << "\n";*/
  132. }
  133. // Calculate IP source entropy
  134. float IPsSrcEntropy = 0;
  135. for(unsigned i=0; i < IPsSrcProb.size();i++){
  136. if (IPsSrcProb[i] > 0)
  137. IPsSrcEntropy += - IPsSrcProb[i]*log2(IPsSrcProb[i]);
  138. }
  139. std::cout << packetCount << ": SrcEnt: " << IPsSrcEntropy << "\n";
  140. // Calculate IP destination entropy
  141. float IPsDstEntropy = 0;
  142. for(unsigned i=0; i < IPsDstProb.size();i++){
  143. if (IPsDstProb[i] > 0)
  144. IPsDstEntropy += - IPsDstProb[i]*log2(IPsDstProb[i]);
  145. }
  146. std::cout << packetCount << ": DstEnt: " << IPsDstEntropy << "\n";
  147. // Write stats to file
  148. std::ofstream file;
  149. // Replace pcap filename with 'filename_ip_entropy'
  150. std::string new_filepath = filePath;
  151. const std::string &newExt = "_ip_entropy.csv";
  152. std::string::size_type h = new_filepath.rfind('.', new_filepath.length());
  153. if (h != std::string::npos) {
  154. new_filepath.replace(h, newExt.length(), newExt);
  155. } else {
  156. new_filepath.append(newExt);
  157. }
  158. file.open (new_filepath,std::ios_base::app);
  159. file << packetCount << "," << IPsSrcEntropy << "," << IPsDstEntropy << "\n";
  160. file.close();
  161. }
  162. // Aidmar
  163. /**
  164. * Increments the packet counter for the given flow.
  165. * @param ipAddressSender The sender IP address.
  166. * @param sport The source port.
  167. * @param ipAddressReceiver The receiver IP address.
  168. * @param dport The destination port.
  169. * @param timestamp The timestamp of the packet.
  170. */
  171. void statistics::addFlowStat(std::string ipAddressSender,int sport,std::string ipAddressReceiver,int dport, std::chrono::microseconds timestamp){
  172. flow f1 = {ipAddressReceiver, dport, ipAddressSender, sport};
  173. flow f2 = {ipAddressSender, sport, ipAddressReceiver, dport};
  174. // if already exist A(ipAddressReceiver, dport), B(ipAddressSender, sport)
  175. if (flow_statistics.count(f1)>0){
  176. flow_statistics[f1].pkts_B_A++;
  177. flow_statistics[f1].pkts_B_A_timestamp.push_back(timestamp);
  178. if(flow_statistics[f1].pkts_A_B_timestamp.size()>0){
  179. flow_statistics[f1].pkts_delay.push_back(std::chrono::duration_cast<std::chrono::microseconds> (timestamp - flow_statistics[f1].pkts_A_B_timestamp[flow_statistics[f1].pkts_A_B_timestamp.size()-1]));
  180. }
  181. //std::cout<<timestamp.count()<<"::"<<ipAddressReceiver<<":"<<dport<<","<<ipAddressSender<<":"<<sport<<"\n";
  182. //std::cout<<flow_statistics[f1].pkts_A_B<<"\n";
  183. //std::cout<<flow_statistics[f1].pkts_B_A<<"\n";
  184. }
  185. else{
  186. flow_statistics[f2].pkts_A_B++;
  187. flow_statistics[f2].pkts_A_B_timestamp.push_back(timestamp);
  188. if(flow_statistics[f2].pkts_B_A_timestamp.size()>0){
  189. flow_statistics[f2].pkts_delay.push_back(std::chrono::duration_cast<std::chrono::microseconds> (timestamp - flow_statistics[f2].pkts_B_A_timestamp[flow_statistics[f2].pkts_B_A_timestamp.size()-1]));
  190. }
  191. //std::cout<<timestamp.count()<<"::"<<ipAddressSender<<":"<<sport<<","<<ipAddressReceiver<<":"<<dport<<"\n";
  192. //std::cout<<flow_statistics[f2].pkts_A_B<<"\n";
  193. //std::cout<<flow_statistics[f2].pkts_B_A<<"\n";
  194. }
  195. }
  196. // Aidmar
  197. /**
  198. * Increments the packet counter for the given IP address and MSS value.
  199. * @param ipAddress The IP address whose MSS packet counter should be incremented.
  200. * @param mssValue The MSS value of the packet.
  201. */
  202. void statistics::incrementMSScount(std::string ipAddress, int mssValue) {
  203. mss_distribution[{ipAddress, mssValue}]++;
  204. }
  205. // Aidmar
  206. /**
  207. * Increments the packet counter for the given IP address and window size.
  208. * @param ipAddress The IP address whose window size packet counter should be incremented.
  209. * @param winSize The window size of the packet.
  210. */
  211. void statistics::incrementWinCount(std::string ipAddress, int winSize) {
  212. win_distribution[{ipAddress, winSize}]++;
  213. }
  214. /**
  215. * Increments the packet counter for the given IP address and TTL value.
  216. * @param ipAddress The IP address whose TTL packet counter should be incremented.
  217. * @param ttlValue The TTL value of the packet.
  218. */
  219. void statistics::incrementTTLcount(std::string ipAddress, int ttlValue) {
  220. ttl_distribution[{ipAddress, ttlValue}]++;
  221. }
  222. /**
  223. * Increments the protocol counter for the given IP address and protocol.
  224. * @param ipAddress The IP address whose protocol packet counter should be incremented.
  225. * @param protocol The protocol of the packet.
  226. */
  227. void statistics::incrementProtocolCount(std::string ipAddress, std::string protocol) {
  228. protocol_distribution[{ipAddress, protocol}]++;
  229. }
  230. /**
  231. * Returns the number of packets seen for the given IP address and protocol.
  232. * @param ipAddress The IP address whose packet count is wanted.
  233. * @param protocol The protocol whose packet count is wanted.
  234. * @return an integer: the number of packets
  235. */
  236. int statistics::getProtocolCount(std::string ipAddress, std::string protocol) {
  237. return protocol_distribution[{ipAddress, protocol}];
  238. }
  239. /**
  240. * Increments the packet counter for
  241. * - the given sender IP address with outgoing port and
  242. * - the given receiver IP address with incoming port.
  243. * @param ipAddressSender The IP address of the packet sender.
  244. * @param outgoingPort The port used by the sender.
  245. * @param ipAddressReceiver The IP address of the packet receiver.
  246. * @param incomingPort The port used by the receiver.
  247. */
  248. void statistics::incrementPortCount(std::string ipAddressSender, int outgoingPort, std::string ipAddressReceiver,
  249. int incomingPort) {
  250. ip_ports[{ipAddressSender, "out", outgoingPort}]++;
  251. ip_ports[{ipAddressReceiver, "in", incomingPort}]++;
  252. }
  253. /**
  254. * Creates a new statistics object.
  255. */
  256. statistics::statistics(void) {
  257. }
  258. /**
  259. * Stores the assignment IP address -> MAC address.
  260. * @param ipAddress The IP address belonging to the given MAC address.
  261. * @param macAddress The MAC address belonging to the given IP address.
  262. */
  263. void statistics::assignMacAddress(std::string ipAddress, std::string macAddress) {
  264. ip_mac_mapping[ipAddress] = macAddress;
  265. }
  266. /**
  267. * Registers statistical data for a sent packet. Increments the counter packets_sent for the sender and
  268. * packets_received for the receiver. Adds the bytes as kbytes_sent (sender) and kybtes_received (receiver).
  269. * @param ipAddressSender The IP address of the packet sender.
  270. * @param ipAddressReceiver The IP address of the packet receiver.
  271. * @param bytesSent The packet's size.
  272. */
  273. void statistics::addIpStat_packetSent(std::string filePath, std::string ipAddressSender, std::string ipAddressReceiver, long bytesSent, std::chrono::microseconds timestamp) {
  274. // Aidmar - Adding IP as a sender for first time
  275. if(ip_statistics[ipAddressSender].pkts_sent==0){
  276. // Caculate Mahoney anomaly score for ip.src
  277. float ipSrc_Mahoney_score = 0;
  278. // s_r: The number of IP sources (the different values)
  279. // n: The number of the total instances
  280. // s_t: The "time" since last anomalous (novel) IP was appeared
  281. int s_t = 0, n = 0, s_r = 0;
  282. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  283. if (i->second.pkts_sent > 0)
  284. s_r++;
  285. }
  286. if(s_r > 0){
  287. // The number of the total instances
  288. n = packetCount;
  289. // The packet count when the last novel IP was added as a sender
  290. int pktCntNvlSndr = 0;
  291. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  292. if (pktCntNvlSndr < i->second.firstAppearAsSenderPktCount)
  293. pktCntNvlSndr = i->second.firstAppearAsSenderPktCount;
  294. }
  295. // The "time" since last anomalous (novel) IP was appeared
  296. s_t = packetCount - pktCntNvlSndr + 1;
  297. ipSrc_Mahoney_score = (float)s_t*n/s_r;
  298. }
  299. // Replace pcap filename with 'filename_ip_entropy'
  300. std::string new_filepath = filePath;
  301. const std::string &newExt = "_ip_src_anomaly_score.csv";
  302. std::string::size_type h = new_filepath.rfind('.', new_filepath.length());
  303. if (h != std::string::npos) {
  304. new_filepath.replace(h, newExt.length(), newExt);
  305. } else {
  306. new_filepath.append(newExt);
  307. }
  308. // Write stats to file
  309. std::ofstream file;
  310. file.open (new_filepath,std::ios_base::app);
  311. file << ipAddressSender << ","<< s_t << "," << n << "," << s_r << "," << ipSrc_Mahoney_score << "\n";
  312. file.close();
  313. ip_statistics[ipAddressSender].firstAppearAsSenderPktCount = packetCount;
  314. ip_statistics[ipAddressSender].sourceAnomalyScore = ipSrc_Mahoney_score;
  315. }
  316. // Aidmar - Adding IP as a receiver for first time
  317. if(ip_statistics[ipAddressReceiver].pkts_received==0){
  318. // Caculate Mahoney anomaly score for ip.dst
  319. float ipDst_Mahoney_score = 0;
  320. // s_r: The number of IP sources (the different values)
  321. // n: The number of the total instances
  322. // s_t: The "time" since last anomalous (novel) IP was appeared
  323. int s_t = 0, n = 0, s_r = 0;
  324. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  325. if (i->second.pkts_received > 0)
  326. s_r++;
  327. }
  328. if(s_r > 0){
  329. // The number of the total instances
  330. n = packetCount;
  331. // The packet count when the last novel IP was added as a sender
  332. int pktCntNvlRcvr = 0;
  333. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  334. if (pktCntNvlRcvr < i->second.firstAppearAsReceiverPktCount)
  335. pktCntNvlRcvr = i->second.firstAppearAsReceiverPktCount;
  336. }
  337. // The "time" since last anomalous (novel) IP was appeared
  338. s_t = packetCount - pktCntNvlRcvr + 1;
  339. ipDst_Mahoney_score = (float)s_t*n/s_r;
  340. }
  341. // Replace pcap filename with 'filename_ip_entropy'
  342. std::string new_filepath = filePath;
  343. const std::string &newExt = "_ip_dst_anomaly_score.csv";
  344. std::string::size_type h = new_filepath.rfind('.', new_filepath.length());
  345. if (h != std::string::npos) {
  346. new_filepath.replace(h, newExt.length(), newExt);
  347. } else {
  348. new_filepath.append(newExt);
  349. }
  350. // Write stats to file
  351. std::ofstream file;
  352. file.open (new_filepath,std::ios_base::app);
  353. file << ipAddressReceiver << ","<< s_t << "," << n << "," << s_r << "," << ipDst_Mahoney_score << "\n";
  354. file.close();
  355. ip_statistics[ipAddressReceiver].firstAppearAsReceiverPktCount = packetCount;
  356. ip_statistics[ipAddressReceiver].destinationAnomalyScore = ipDst_Mahoney_score;
  357. }
  358. // Update stats for packet sender
  359. ip_statistics[ipAddressSender].kbytes_sent += (float(bytesSent) / 1024);
  360. ip_statistics[ipAddressSender].pkts_sent++;
  361. // Aidmar
  362. ip_statistics[ipAddressSender].pktsSentTimestamp.push_back(timestamp);
  363. // Update stats for packet receiver
  364. ip_statistics[ipAddressReceiver].kbytes_received += (float(bytesSent) / 1024);
  365. ip_statistics[ipAddressReceiver].pkts_received++;
  366. // Aidmar
  367. ip_statistics[ipAddressReceiver].pktsReceivedTimestamp.push_back(timestamp);
  368. }
  369. /**
  370. * Registers a value of the TCP option Maximum Segment Size (MSS).
  371. * @param ipAddress The IP address which sent the TCP packet.
  372. * @param MSSvalue The MSS value found.
  373. */
  374. void statistics::addMSS(std::string ipAddress, int MSSvalue) {
  375. ip_sumMss[ipAddress] += MSSvalue;
  376. }
  377. /**
  378. * Setter for the timestamp_firstPacket field.
  379. * @param ts The timestamp of the first packet in the PCAP file.
  380. */
  381. void statistics::setTimestampFirstPacket(Tins::Timestamp ts) {
  382. timestamp_firstPacket = ts;
  383. }
  384. /**
  385. * Setter for the timestamp_lastPacket field.
  386. * @param ts The timestamp of the last packet in the PCAP file.
  387. */
  388. void statistics::setTimestampLastPacket(Tins::Timestamp ts) {
  389. timestamp_lastPacket = ts;
  390. }
  391. // Aidmar
  392. /**
  393. * Getter for the timestamp_firstPacket field.
  394. */
  395. Tins::Timestamp statistics::getTimestampFirstPacket() {
  396. return timestamp_firstPacket;
  397. }
  398. /**
  399. * Getter for the timestamp_lastPacket field.
  400. */
  401. Tins::Timestamp statistics::getTimestampLastPacket() {
  402. return timestamp_lastPacket;
  403. }
  404. /**
  405. * Calculates the capture duration.
  406. * @return a formatted string HH:MM:SS.mmmmmm with
  407. * HH: hour, MM: minute, SS: second, mmmmmm: microseconds
  408. */
  409. std::string statistics::getCaptureDurationTimestamp() const {
  410. // Calculate duration
  411. time_t t = (timestamp_lastPacket.seconds() - timestamp_firstPacket.seconds());
  412. time_t ms = (timestamp_lastPacket.microseconds() - timestamp_firstPacket.microseconds());
  413. long int hour = t / 3600;
  414. long int remainder = (t - hour * 3600);
  415. long int minute = remainder / 60;
  416. long int second = (remainder - minute * 60) % 60;
  417. long int microseconds = ms;
  418. // Build desired output format: YYYY-mm-dd hh:mm:ss
  419. char out[64];
  420. sprintf(out, "%02ld:%02ld:%02ld.%06ld ", hour, minute, second, microseconds);
  421. return std::string(out);
  422. }
  423. /**
  424. * Calculates the capture duration.
  425. * @return a formatted string SS.mmmmmm with
  426. * S: seconds (UNIX time), mmmmmm: microseconds
  427. */
  428. float statistics::getCaptureDurationSeconds() const {
  429. timeval d;
  430. d.tv_sec = timestamp_lastPacket.seconds() - timestamp_firstPacket.seconds();
  431. d.tv_usec = timestamp_lastPacket.microseconds() - timestamp_firstPacket.microseconds();
  432. char tmbuf[64], buf[64];
  433. auto nowtm = localtime(&(d.tv_sec));
  434. strftime(tmbuf, sizeof(tmbuf), "%S", nowtm);
  435. snprintf(buf, sizeof(buf), "%s.%06u", tmbuf, (uint) d.tv_usec);
  436. return std::stof(std::string(buf));
  437. }
  438. /**
  439. * Creates a timestamp based on a time_t seconds (UNIX time format) and microseconds.
  440. * @param seconds
  441. * @param microseconds
  442. * @return a formatted string Y-m-d H:M:S.m with
  443. * Y: year, m: month, d: day, H: hour, M: minute, S: second, m: microseconds
  444. */
  445. std::string statistics::getFormattedTimestamp(time_t seconds, suseconds_t microseconds) const {
  446. timeval tv;
  447. tv.tv_sec = seconds;
  448. tv.tv_usec = microseconds;
  449. char tmbuf[64], buf[64];
  450. auto nowtm = localtime(&(tv.tv_sec));
  451. strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%d %H:%M:%S", nowtm);
  452. snprintf(buf, sizeof(buf), "%s.%06u", tmbuf, (uint) tv.tv_usec);
  453. return std::string(buf);
  454. }
  455. /**
  456. * Calculates the statistics for a given IP address.
  457. * @param ipAddress The IP address whose statistics should be calculated.
  458. * @return a ip_stats struct containing statistical data derived by the statistical data collected.
  459. */
  460. ip_stats statistics::getStatsForIP(std::string ipAddress) {
  461. float duration = getCaptureDurationSeconds();
  462. entry_ipStat ipStatEntry = ip_statistics[ipAddress];
  463. ip_stats s;
  464. s.bandwidthKBitsIn = (ipStatEntry.kbytes_received / duration) * 8;
  465. s.bandwidthKBitsOut = (ipStatEntry.kbytes_sent / duration) * 8;
  466. s.packetPerSecondIn = (ipStatEntry.pkts_received / duration);
  467. s.packetPerSecondOut = (ipStatEntry.pkts_sent / duration);
  468. s.AvgPacketSizeSent = (ipStatEntry.kbytes_sent / ipStatEntry.pkts_sent);
  469. s.AvgPacketSizeRecv = (ipStatEntry.kbytes_received / ipStatEntry.pkts_received);
  470. int sumMSS = ip_sumMss[ipAddress];
  471. int tcpPacketsSent = getProtocolCount(ipAddress, "TCP");
  472. s.AvgMaxSegmentSizeTCP = ((sumMSS > 0 && tcpPacketsSent > 0) ? (sumMSS / tcpPacketsSent) : 0);
  473. return s;
  474. }
  475. /**
  476. * Increments the packet counter.
  477. */
  478. void statistics::incrementPacketCount() {
  479. packetCount++;
  480. }
  481. /**
  482. * Prints the statistics of the PCAP and IP specific statistics for the given IP address.
  483. * @param ipAddress The IP address whose statistics should be printed. Can be empty "" to print only general file statistics.
  484. */
  485. void statistics::printStats(std::string ipAddress) {
  486. std::stringstream ss;
  487. ss << std::endl;
  488. ss << "Capture duration: " << getCaptureDurationSeconds() << " seconds" << std::endl;
  489. ss << "Capture duration (HH:MM:SS.mmmmmm): " << getCaptureDurationTimestamp() << std::endl;
  490. ss << "#Packets: " << packetCount << std::endl;
  491. ss << std::endl;
  492. // Print IP address specific statistics only if IP address was given
  493. if (ipAddress != "") {
  494. entry_ipStat e = ip_statistics[ipAddress];
  495. ss << "\n----- STATS FOR IP ADDRESS [" << ipAddress << "] -------" << std::endl;
  496. ss << std::endl << "KBytes sent: " << e.kbytes_sent << std::endl;
  497. ss << "KBytes received: " << e.kbytes_received << std::endl;
  498. ss << "Packets sent: " << e.pkts_sent << std::endl;
  499. ss << "Packets received: " << e.pkts_received << "\n\n";
  500. ip_stats is = getStatsForIP(ipAddress);
  501. ss << "Bandwidth IN: " << is.bandwidthKBitsIn << " kbit/s" << std::endl;
  502. ss << "Bandwidth OUT: " << is.bandwidthKBitsOut << " kbit/s" << std::endl;
  503. ss << "Packets per second IN: " << is.packetPerSecondIn << std::endl;
  504. ss << "Packets per second OUT: " << is.packetPerSecondOut << std::endl;
  505. ss << "Avg Packet Size Sent: " << is.AvgPacketSizeSent << " kbytes" << std::endl;
  506. ss << "Avg Packet Size Received: " << is.AvgPacketSizeRecv << " kbytes" << std::endl;
  507. ss << "Avg MSS: " << is.AvgMaxSegmentSizeTCP << " bytes" << std::endl;
  508. }
  509. std::cout << ss.str();
  510. }
  511. /**
  512. * Derives general PCAP file statistics from the collected statistical data and
  513. * writes all data into a SQLite database, located at database_path.
  514. * @param database_path The path of the SQLite database file ending with .sqlite3.
  515. */
  516. void statistics::writeToDatabase(std::string database_path) {
  517. // Generate general file statistics
  518. float duration = getCaptureDurationSeconds();
  519. long sumPacketsSent = 0, senderCountIP = 0;
  520. float sumBandwidthIn = 0.0, sumBandwidthOut = 0.0;
  521. for (auto i = ip_statistics.begin(); i != ip_statistics.end(); i++) {
  522. sumPacketsSent += i->second.pkts_sent;
  523. // Consumed bandwith (bytes) for sending packets
  524. sumBandwidthIn += (i->second.kbytes_received / duration);
  525. sumBandwidthOut += (i->second.kbytes_sent / duration);
  526. senderCountIP++;
  527. }
  528. float avgPacketRate = (packetCount / duration);
  529. long avgPacketSize = getAvgPacketSize();
  530. long avgPacketsSentPerHost = (sumPacketsSent / senderCountIP);
  531. float avgBandwidthInKBits = (sumBandwidthIn / senderCountIP) * 8;
  532. float avgBandwidthOutInKBits = (sumBandwidthOut / senderCountIP) * 8;
  533. // Create database and write information
  534. statistics_db db(database_path);
  535. db.writeStatisticsFile(packetCount, getCaptureDurationSeconds(),
  536. getFormattedTimestamp(timestamp_firstPacket.seconds(), timestamp_firstPacket.microseconds()),
  537. getFormattedTimestamp(timestamp_lastPacket.seconds(), timestamp_lastPacket.microseconds()),
  538. avgPacketRate, avgPacketSize, avgPacketsSentPerHost, avgBandwidthInKBits,
  539. avgBandwidthOutInKBits);
  540. db.writeStatisticsIP(ip_statistics);
  541. db.writeStatisticsTTL(ttl_distribution);
  542. db.writeStatisticsIpMac(ip_mac_mapping);
  543. db.writeStatisticsMss(ip_sumMss);
  544. db.writeStatisticsPorts(ip_ports);
  545. db.writeStatisticsProtocols(protocol_distribution);
  546. // Aidmar
  547. db.writeStatisticsMss_dist(mss_distribution);
  548. db.writeStatisticsWin(win_distribution);
  549. db.writeStatisticsFlow(flow_statistics);
  550. }
  551. /**
  552. * Returns the average packet size.
  553. * @return a float indicating the average packet size in kbytes.
  554. */
  555. float statistics::getAvgPacketSize() const {
  556. // AvgPktSize = (Sum of all packet sizes / #Packets)
  557. return (sumPacketSize / packetCount) / 1024;
  558. }
  559. /**
  560. * Adds the size of a packet (to be used to calculate the avg. packet size).
  561. * @param packetSize The size of the current packet in bytes.
  562. */
  563. void statistics::addPacketSize(uint32_t packetSize) {
  564. sumPacketSize += ((float) packetSize);
  565. }