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: 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
// DNSmasq's query log entries and combine them to list the hosts
// 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.
//
// 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 evilnets nethash
@@ -23,10 +29,10 @@
// 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

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

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;
}
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?
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?
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(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) return -1;
if(them_port>gtr.them_port) return 1;
}
// 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;
}
@@ -264,10 +283,10 @@ struct ConnList: public vector<Conn> {
//////////////////////////////////////////////////////////////////////

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++]; }
};
ostream &operator<<(ostream &o, LiveBug &bug) {
@@ -283,16 +302,17 @@ ostream &operator<<(ostream &o, LiveBug &bug) {

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"
ifstream log(PATH "/test.log");
ofstream out(PATH "/processed.log");
Splits ln;
int lnno = 0, ict = 0;
LiveBug bug;
NameVal rdns, queries;
NameVal rdns;
NameVal::iterator nvp;
string name, address, s;
Conn conn;
@@ -302,13 +322,19 @@ ConnList ignores;


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



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

/// Load lists ///



/// 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
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];
address = ln[8];
// 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
dlog("WARN: DNS address overlap "+address+": "+rdnsp->second+" : "+name);
cout << '\r' << lnno << ": " << name << endl;
#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;
}
}
@@ -397,19 +384,16 @@ int main(int argc, char **argv) {
&& ln[5]=="ACCEPT"
) {
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;
if(ignores.find(conn)<0)
out << conn << "\n";
out << ln[0] << " " << ln[1] << " " << ln[2] << " " << conn << "\n";
else
ict++;
}
}
cout << "\nIgnored: " << ict << endl;

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

Loading…
Cancel
Save