statistics.cpp 28 KB

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