Browse Source

Wildcard ignore match & C++ < 11

master
Jon Foster 2 years ago
parent
commit
e63d932ab8
2 changed files with 73 additions and 81 deletions
  1. +9
    -1
      Makefile
  2. +64
    -80
      iptraffic.cpp

+ 9
- 1
Makefile View File

@@ -3,4 +3,12 @@ run: iptraffic
./iptraffic 2> log # 2>&1 | head -n 20 ./iptraffic 2> log # 2>&1 | head -n 20


iptraffic: iptraffic.cpp iptraffic: iptraffic.cpp
j++ -o $@ $@.cpp
g++ -o $@ $@.cpp



.PHONY: clean distclean
clean:
rm *.o || true
distclean: clean
rm iptraffic || true

+ 64
- 80
iptraffic.cpp View File

@@ -6,12 +6,18 @@
// The idea is to analyze iptables LOG entries in combination with // The idea is to analyze iptables LOG entries in combination with
// DNSmasq's query log entries and combine them to list the hosts // DNSmasq's query log entries and combine them to list the hosts
// that were accessed. The main reasons for not just inspecting HTTP // that were accessed. The main reasons for not just inspecting HTTP
// packets through a netfilter socket is due to httpS hiding the
// packets through a netfilter socket is due to HTTPS hiding the
// "host" field. So I'm deducing based on DNS query timing. // "host" field. So I'm deducing based on DNS query timing.
//
// NOTE: its assumed that the log being processed is in chronological
// order. This is the usual way things get logged. ;-)
//
// 2021-05-14 <ChipMaster@YeOlPiShack.net>
// Dumbed down for C++ < 11.
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// AAdditional Router setup:
// Additional Router setup:
// //
// ipset -N evilhosts iphash // ipset -N evilhosts iphash
// ipset -N evilnets nethash // ipset -N evilnets nethash
@@ -23,10 +29,10 @@
// 10.10.10.1 -> 134.215.160.1 ICMP[8] // 10.10.10.1 -> 134.215.160.1 ICMP[8]
// //
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// TODO: wildcard for name matching
// TODO: map names according to time and host. time is probably automatic // TODO: map names according to time and host. time is probably automatic


#include <string.h> #include <string.h>
#include <stdlib.h>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@@ -41,6 +47,7 @@ using namespace std;
// Splits: a util class to devide a line into space sep pieces // Splits: a util class to devide a line into space sep pieces
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// TODO: implement begin() + end() to make "for( : )" work // TODO: implement begin() + end() to make "for( : )" work
// TODO: implement field enclosing & escaping chars


struct Splits { struct Splits {


@@ -106,20 +113,28 @@ struct TSV: public Splits {




////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Subclass to match a list of prefixes against a string
// Function to match a list of prefixes against a string
// //
// This is not a subclass per-se since I don't know how to expose the
// inherited { } list based constructor and I just want to knock this
// out. So this is Q&D: typedef + operator.
// Since C++ < 11 doesn't support constant vector initialization we'll
// do this the old fashioned way with a null terminated char*[].
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////


typedef vector<string> PreMatch;
bool operator==(const PreMatch &list, const string &s) {
for(auto p: list) if(s.substr(0, p.size())==p) return true;
bool pre_match(char **list, const string &s) {
const char *p = s.c_str();
for(; *list; list++)
if(!strncmp(*list, p, strlen(*list))) return true;
return false; return false;
} }
inline bool operator!=(const PreMatch &list, const string &s) { return !(list==s); }

/* And because I think this may be useful in the future I'll hang on to it.
bool pre_match(const vector<string> &list, const string &s) {
for(
vector<string>::const_iterator p=list.begin();
p!=list.end();
p++
)
if(s.substr(0, p->size())==*p) return true;
return false;
}*/




////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@@ -184,21 +199,25 @@ struct Conn {


// TODO: does < > have any actual meaning in this context? // TODO: does < > have any actual meaning in this context?
int cmp(const Conn &gtr) const { int cmp(const Conn &gtr) const {
if(us<gtr.us) return -1;
if(us>gtr.us) return 1;
if(us!="*" && gtr.us!="*") {
if(us<gtr.us) return -1;
if(us>gtr.us) return 1;
}
// TODO: auto-wildcard port based on in? // TODO: auto-wildcard port based on in?
if(us_port && gtr.us_port) { // 0 = no comparison wildcard if(us_port && gtr.us_port) { // 0 = no comparison wildcard
if(us_port<gtr.us_port) return -1; if(us_port<gtr.us_port) return -1;
if(us_port>gtr.us_port) return 1; if(us_port>gtr.us_port) return 1;
} }
if(them<gtr.them) return -1;
if(them>gtr.them) return 1;
if(them!="*" && gtr.them!="*") {
if(them<gtr.them) return -1;
if(them>gtr.them) return 1;
}
if(them_port && gtr.them_port) { // 0 = no comparison wildcard if(them_port && gtr.them_port) { // 0 = no comparison wildcard
if(them_port<gtr.them_port) return -1; if(them_port<gtr.them_port) return -1;
if(them_port>gtr.them_port) return 1; if(them_port>gtr.them_port) return 1;
} }
// TODO: do we want to consider the name? // TODO: do we want to consider the name?
if(name!="") {
if(name!="*" && gtr.name!="*") {
if(name<gtr.name) return -1; if(name<gtr.name) return -1;
if(name>gtr.name) return 1; if(name>gtr.name) return 1;
} }
@@ -264,10 +283,10 @@ struct ConnList: public vector<Conn> {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////


struct LiveBug { struct LiveBug {
string seq = "-\\|/";
char pre = '\r';
int p;
LiveBug(): p(0) {}
string seq;
char pre;
int p;
LiveBug(): seq("-\\|/"), pre('\r'), p(0) {}
inline char next() { if(p>=seq.size()) p=0; return seq[p++]; } inline char next() { if(p>=seq.size()) p=0; return seq[p++]; }
}; };
ostream &operator<<(ostream &o, LiveBug &bug) { ostream &operator<<(ostream &o, LiveBug &bug) {
@@ -283,16 +302,17 @@ ostream &operator<<(ostream &o, LiveBug &bug) {


typedef map<string,string> NameVal; typedef map<string,string> NameVal;


const PreMatch us = { "10.10.10.", "192.168.255.", "2001:470:a:169:" };
const PreMatch dns_ignore = { "v=spf1", "https:" };
const PreMatch dns_del = { "NODATA-", "NXDOMAIN-" };
// TODO: define us[] in conf file
char *us[] = { (char *)"10.10.10.", (char *)"192.168.255.", (char *)"2001:470:a:169:", 0 };
char *dns_ignore[] = { (char *)"v=spf1", (char *)"https:", 0 };
char *dns_del[] = { (char *)"NODATA-", (char *)"NXDOMAIN-", 0 };
#define PATH "/srv/backups/iptraffic" #define PATH "/srv/backups/iptraffic"
ifstream log(PATH "/test.log"); ifstream log(PATH "/test.log");
ofstream out(PATH "/processed.log"); ofstream out(PATH "/processed.log");
Splits ln; Splits ln;
int lnno = 0, ict = 0; int lnno = 0, ict = 0;
LiveBug bug; LiveBug bug;
NameVal rdns, queries;
NameVal rdns;
NameVal::iterator nvp; NameVal::iterator nvp;
string name, address, s; string name, address, s;
Conn conn; Conn conn;
@@ -302,13 +322,19 @@ ConnList ignores;




void dlog(const string msg) { void dlog(const string msg) {
#ifdef DEBUG
cerr << "\r" << lnno << ": " << msg << endl; cerr << "\r" << lnno << ": " << msg << endl;
#endif
} }






int main(int argc, char **argv) { int main(int argc, char **argv) {


/// Load lists ///



/// Read in ignore list /// /// Read in ignore list ///


{ {
@@ -332,60 +358,21 @@ int main(int argc, char **argv) {


// TODO: need to get more specific on tying us + them + time to DNS // TODO: need to get more specific on tying us + them + time to DNS
if(ln.count>8 && strncmp(ln.fields[4], "dnsmasq[", 8)==0) { if(ln.count>8 && strncmp(ln.fields[4], "dnsmasq[", 8)==0) {

/// Query send ///

if(strncmp(ln.fields[5], "query[", 6)==0) {
s=ln[5].substr(6, ln[5].size()-7);
if(s!="A" && s!="AAAA") continue; // we're only concerned with addresses.
name = ln[6];
address = ln[8];
dlog("Query["+s+"] '"+name+"' for "+address);
name+=':'+s;
if(queries.find(name)==queries.end())
queries[name]=address;
else
dlog("WARN: Query already exists!");

/// Query reply ///

} else if(ln[5]=="reply") {
if(ln[5]=="reply") {
name = ln[6]; name = ln[6];
address = ln[8]; address = ln[8];
// Hmm... is this reply an address? // Hmm... is this reply an address?
if(dns_ignore==address) continue; // nope
if(dns_del==address) {
// "no exist" reply so just drop them.
if(*(address.end()-1)=='4') name+=":A";
else if(*(address.end()-1)=='6') name+=":AAAA";
else continue;
dlog("drop query '"+name+"'");
if((nvp=queries.find(name))!=queries.end()) queries.erase(nvp);
continue;
if(pre_match(dns_ignore, address)) continue; // nope
if(pre_match(dns_del, address)) continue; // does not exist reply
if((nvp=rdns.find(address))!=rdns.end()) {
if(nvp->second==name) continue;
dlog("WARN: DNS address overlap "+address+": "+nvp->second+" : "+name);
} }
// IPv6 or v4 query?
if(address.find(':')==name.npos)
s=name+":AAAA";
else
s=name+":A";
// now make source dest couplet
if((nvp=queries.find(s))!=queries.end()) {
address+=':'+nvp->second;
//queries.erase(nvp); // remove from active query list
if((nvp=rdns.find(address))!=rdns.end()) {
if(nvp->second==name) continue;
rdns[address] = name;
dlog("Added "+address+" = "+name);
#ifdef DEBUG #ifdef DEBUG
dlog("WARN: DNS address overlap "+address+": "+rdnsp->second+" : "+name);
cout << '\r' << lnno << ": " << name << endl;
#endif #endif
}
rdns[address] = name;
dlog("Added "+address+" = "+name);
#ifdef DEBUG
cout '\r' << lnno << ": " << name << endl;
#endif
continue;
}
dlog("WARN: reply '"+name+"' skipped due to lack of matching query");
continue; continue;
} }
} }
@@ -397,19 +384,16 @@ int main(int argc, char **argv) {
&& ln[5]=="ACCEPT" && ln[5]=="ACCEPT"
) { ) {
conn = ln; conn = ln;
if(us!=conn.us) conn.swap();
if((nvp=rdns.find(conn.them+':'+conn.us))!=rdns.end())
if(!pre_match(us, conn.us)) conn.swap();
if((nvp=rdns.find(conn.them))!=rdns.end())
conn.name = nvp->second; conn.name = nvp->second;
if(ignores.find(conn)<0) if(ignores.find(conn)<0)
out << conn << "\n";
out << ln[0] << " " << ln[1] << " " << ln[2] << " " << conn << "\n";
else else
ict++; ict++;
} }
} }
cout << "\nIgnored: " << ict << endl; cout << "\nIgnored: " << ict << endl;

#ifdef DEBUG
cout << "\n\n" << "Total rDNS: " << rdns.size() << "\n";
#endif
cout << "Total rDNS: " << rdns.size() << "\n";
return 0; return 0;
} }

Loading…
Cancel
Save