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.
 
 

182 lines
4.4 KiB

  1. //////////////////////////////////////////////////////////////////////
  2. // IP traffic analyzer - data objects
  3. // Written by Jonathan A. Foster <ChipMaster@YeOlPiShack.net>
  4. // Started April 23rd, 2021
  5. // Copyright JF Possibilities, Inc. All rights reserved.
  6. //////////////////////////////////////////////////////////////////////
  7. #include <arpa/inet.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include <stdexcept>
  11. #include <iostream>
  12. #include "data.h"
  13. //////////////////////////////////////////////////////////////////////
  14. // Utils
  15. //////////////////////////////////////////////////////////////////////
  16. std::string ipv6opt(const std::string &addr) {
  17. in6_addr buf;
  18. char s[256];
  19. if(inet_pton(AF_INET6, addr.c_str(), &buf)<1) throw
  20. std::runtime_error("ipv6opt: inet_pton() says '"+addr+"' is not a valid IPv6 address");
  21. if(!inet_ntop(AF_INET6, &buf, s, 255)) throw // should never happen
  22. std::runtime_error("ipv6opt: inet_ntop() refused to convert the address back");
  23. return std::string(s);
  24. }
  25. int addr_wild_comp(const std::string &str1, const std::string &str2) {
  26. int spre1=0, spre2=0;
  27. if(str1=="*" || str2=="*") return 0;
  28. if(str1!="" && (str1.end()[-1]=='.' || str1.end()[-1]==':')) spre1=str1.size();
  29. if(str2!="" && (str2.end()[-1]=='.' || str2.end()[-1]==':')) spre2=str2.size();
  30. if(spre2>spre1) spre1=spre2;
  31. if(spre1) return strncmp(str1.c_str(), str2.c_str(), spre1);
  32. else if(str1<str2) return -1;
  33. else if(str1>str2) return 1;
  34. return 0;
  35. }
  36. //////////////////////////////////////////////////////////////////////
  37. // Conn
  38. //////////////////////////////////////////////////////////////////////
  39. void Conn::clear() {
  40. us = them = name = protocol = "";
  41. in=false;
  42. us_port = them_port = 0;
  43. }
  44. void Conn::compact() {
  45. if(us.find(':')!=us.npos) us=ipv6opt(us);
  46. if(them.find(':')!=us.npos) them=ipv6opt(them);
  47. }
  48. void Conn::swap() {
  49. std::string s;
  50. int x;
  51. s = us;
  52. us = them;
  53. them =s;
  54. x = us_port;
  55. us_port = them_port;
  56. them_port = x;
  57. in=!in;
  58. }
  59. Conn &Conn::operator=(const Splits &sp) {
  60. int x;
  61. clear();
  62. for(x=0; x<sp.count; x++) {
  63. if(!strncmp(sp.fields[x], "SRC=", 4)) {
  64. us = sp.fields[x]+4;
  65. continue;
  66. }
  67. if(!strncmp(sp.fields[x], "DST=", 4)) {
  68. them = sp.fields[x]+4;
  69. continue;
  70. }
  71. if(!strncmp(sp.fields[x], "SPT=", 4)) {
  72. us_port = atoi(sp.fields[x]+4);
  73. continue;
  74. }
  75. if(!strncmp(sp.fields[x], "DPT=", 4)) {
  76. them_port = atoi(sp.fields[x]+4);
  77. continue;
  78. }
  79. if(!strncmp(sp.fields[x], "TYPE=", 5) && protocol=="ICMP") {
  80. us_port = them_port = atoi(sp.fields[x]+5);
  81. continue;
  82. }
  83. if(!strncmp(sp.fields[x], "PROTO=", 6))
  84. protocol = sp.fields[x]+6;
  85. }
  86. }
  87. // TODO: does < > have any actual meaning in this context?
  88. int Conn::cmp(const Conn &gtr) const {
  89. int r;
  90. if(r = addr_wild_comp(us, gtr.us)) return r;
  91. // TODO: auto-wildcard port based on in?
  92. if(us_port && gtr.us_port) { // 0 = no comparison wildcard
  93. if(us_port<gtr.us_port) return -1;
  94. if(us_port>gtr.us_port) return 1;
  95. }
  96. if(r = addr_wild_comp(them, gtr.them)) return r;
  97. if(them_port && gtr.them_port) { // 0 = no comparison wildcard
  98. if(them_port<gtr.them_port) return -1;
  99. if(them_port>gtr.them_port) return 1;
  100. }
  101. // TODO: do we want to consider the name?
  102. if(name!="*" && gtr.name!="*") {
  103. if(name<gtr.name) return -1;
  104. if(name>gtr.name) return 1;
  105. }
  106. if(protocol<gtr.protocol) return -1;
  107. if(protocol>gtr.protocol) return 1;
  108. if(in<gtr.in) return -1;
  109. if(in>gtr.in) return 1;
  110. return 0;
  111. }
  112. std::ostream &operator<<(std::ostream &out, const Conn &c) {
  113. out << c.us
  114. << ( c.in ? " <- " : " -> " )
  115. << c.them
  116. << " " << c.protocol
  117. << "[" << ( c.in ? c.us_port : c.them_port ) << "] "
  118. << c.name;
  119. return out;
  120. }
  121. const Splits &operator>>(const Splits &tsv, Conn &conn) {
  122. if(tsv.count<7) throw std::runtime_error("Conn=TSV: too few columns");
  123. conn.clear();
  124. conn.us = tsv[0];
  125. conn.us_port = atoi(tsv.fields[1]);
  126. conn.them = tsv[2];
  127. conn.them_port = atoi(tsv.fields[3]);
  128. conn.name = tsv[4];
  129. conn.protocol = tsv[5];
  130. conn.in = tsv[6]=="1";
  131. return tsv;
  132. }
  133. //////////////////////////////////////////////////////////////////////
  134. // ConnList
  135. //////////////////////////////////////////////////////////////////////
  136. int ConnList::find(Conn &needle) {
  137. int r;
  138. for(r=0; r<size(); r++) if((*this)[r]==needle) return r;
  139. return -1;
  140. }