The Poor Man's (or Woman's) Intrusion Detection System
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

iptraffic.cpp 4.4 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. //////////////////////////////////////////////////////////////////////
  2. // IP traffic analyzer
  3. // Written by Jonathan A. Foster <ChipMaster@YeOlPiShack.net>
  4. // Started April 23rd, 2021
  5. //
  6. // The idea is to analyze iptables LOG entries in combination with
  7. // DNSmasq's query log entries and combine them to list the hosts
  8. // that were accessed. The main reasons for not just inspecting HTTP
  9. // packets through a netfilter socket is due to HTTPS hiding the
  10. // "host" field. So I'm deducing based on DNS query timing.
  11. //
  12. // NOTE: its assumed that the log being processed is in chronological
  13. // order. This is the usual way things get logged. ;-)
  14. //
  15. // 2021-05-14 <ChipMaster@YeOlPiShack.net>
  16. // Dumbed down for < C++11.
  17. // Split into modules
  18. //
  19. // 2021-06-18 <ChipMaster@YeOlPiShack.net>
  20. // Wrapped in application object and added command line handling.
  21. // This includes:
  22. // - Getting config file name from CLI args
  23. // - Getting input and output filenams from CLI args
  24. // - Reading and writing from STDIN & STDOUT
  25. // - Send all non-data output to stderr
  26. //
  27. // 2021-08-11 <ChipMaster@YeOlPiShack.net>
  28. // Move main data colation routine into its own class to be shared
  29. // with multiple tools.
  30. //////////////////////////////////////////////////////////////////////
  31. #include <string.h>
  32. #include <string>
  33. #include <iostream>
  34. #include <fstream>
  35. #include <stdexcept>
  36. #include <vector>
  37. #include <map>
  38. #include "cli.h"
  39. #include "strutil.h"
  40. #include "data.h"
  41. #include "config.h"
  42. using namespace std;
  43. //////////////////////////////////////////////////////////////////////
  44. // Application class to process files.
  45. //////////////////////////////////////////////////////////////////////
  46. //#define DEBUG
  47. struct IPtraffic: public cBaseApp {
  48. Config config;
  49. LogAnalyzer analyze;
  50. istream *log;
  51. ostream *out;
  52. LiveBug bug;
  53. int line_no;
  54. IPtraffic(): out(&cout), log(0)
  55. { // I'd rather this initialization be static...
  56. analyze.us = &(config.us);
  57. }
  58. ~IPtraffic() { if(log && log!=&cin) delete(log); }
  59. void dlog(const string msg) {
  60. #ifdef DEBUG
  61. cerr << line_no << ": " << msg << endl;
  62. #endif
  63. }
  64. // TODO: elaborate
  65. void help() {
  66. cerr <<
  67. "\n"
  68. "iptraffic -c {config file} [-o {output file}] [{input file} [...]]\n";
  69. ExitCode = 1;
  70. }
  71. unsigned do_switch(const char *sw) {
  72. if((sw[0]=='c' || sw[0]=='o') && sw[1]==0) return 1;
  73. throw CLIerror("Unrecognized Switch");
  74. }
  75. void do_switch_arg(const char *sw, const std::string &val) {
  76. switch(*sw) {
  77. case 'c':
  78. config.load(val);
  79. if(!config.us.size()) throw CLIerror(
  80. "The configuration files MUST contain an [us] section with "
  81. "appropriate values"
  82. );
  83. break;
  84. case 'o':
  85. if(out!=&cout)
  86. throw CLIerror("Output file has already been specified");
  87. out = new ofstream(val.c_str()); // c_str(), really?!?!
  88. }
  89. }
  90. void do_arg(const char *fname) {
  91. if(log && log!=&cin) delete(log);
  92. log = 0;
  93. log = new ifstream(fname);
  94. ExitCode = do_log();
  95. }
  96. // NOTE: the return values isn't really used yet but the channel is here if
  97. // it can be of use.
  98. int do_log() {
  99. int ict=0; // ignored netfilter lines
  100. std::string l;
  101. /// parse log file ///
  102. if(!config.us.size()) throw CLIerror(
  103. "A configuration file must be specified before input files."
  104. );
  105. line_no=0;
  106. while(std::getline(*log, l)) {
  107. line_no++;
  108. cerr << bug << ' ' << line_no << '\r' << flush;
  109. /// process connections ///
  110. if(analyze.line(l)) {
  111. if(config.ignores.find(analyze.conn)<0)
  112. *out << analyze.ln[0] << " " << analyze.ln[1] << " " << analyze.ln[2]
  113. << " " << analyze.conn << "\n";
  114. else
  115. ict++;
  116. }
  117. }
  118. *out << flush; // make sure all data gets written.
  119. cerr << "\nLines: " << line_no
  120. << "\nIgnored: " << ict
  121. << "\nTotal rDNS: " << analyze.rdns.size() << endl;
  122. return 0;
  123. }
  124. int main() {
  125. try {
  126. cBaseApp::main();
  127. if(!log) {
  128. // no inputs were specified run stdin.
  129. log = &cin;
  130. ExitCode = do_log();
  131. }
  132. } catch(const CLIerror &e) {
  133. cerr << "ERROR: " << e.what() << "\n";
  134. help();
  135. }
  136. return ExitCode;
  137. }
  138. };
  139. //////////////////////////////////////////////////////////////////////
  140. // Run it
  141. //////////////////////////////////////////////////////////////////////
  142. MAIN(IPtraffic)