From c86e8d9f83aa86b5b98e77f08fba70a3f0a1685e Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 14:17:16 +0100 Subject: [PATCH 01/63] Extract dnsmasq's ID from the logged queries Signed-off-by: DL6ER --- FTL.h | 3 +++ parser.c | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/FTL.h b/FTL.h index a3c02bc6..18f389b6 100644 --- a/FTL.h +++ b/FTL.h @@ -137,6 +137,9 @@ typedef struct { int forwardID; bool valid; bool db; + // the ID is a (signed) in dnsmasq, so no need for a long int here + unsigned int id; + bool complete; } queriesDataStruct; typedef struct { diff --git a/parser.c b/parser.c index 2fea9c65..2a31f14f 100644 --- a/parser.c +++ b/parser.c @@ -200,7 +200,7 @@ void process_pihole_log(int file) } // Test if the read line is a query line - if(strstr(readbuffer,"]: query[A") != NULL) + if(strstr(readbuffer," query[A") != NULL) { // Check if this domain names contains only printable characters // if not: skip analysis of this log line @@ -216,7 +216,7 @@ void process_pihole_log(int file) continue; } - if(!config.analyze_AAAA && strstr(readbuffer,"]: query[AAAA]") != NULL) + if(!config.analyze_AAAA && strstr(readbuffer," query[AAAA]") != NULL) { if(debug) logg("Not analyzing AAAA query"); continue; @@ -304,6 +304,15 @@ void process_pihole_log(int file) continue; } + // Get query ID + // "Dec 20 21:16:22 dnsmasq[19372]: 4 10.8.0.2/34596 query[A] pi.hole from 10.8.0.2 + unsigned int dnsmasqID = 0; + if(!sscanf(readbuffer, "%*[^]]]: %u", &dnsmasqID)) + { + if(debug) logg("Error getting ID for query \"%s\" %u", readbuffer, dnsmasqID); + continue; + } + // Get domain // domainstart = pointer to | in "query[AAAA] |host.name from ww.xx.yy.zz\n" const char *domainstart = strstr(readbuffer, "] "); From 90494ec6496e397af20ecb4c412af7484be79997 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 14:23:59 +0100 Subject: [PATCH 02/63] Modify parser to understand "query" lines with IDs Signed-off-by: DL6ER --- parser.c | 156 ++++--------------------------------------------------- 1 file changed, 10 insertions(+), 146 deletions(-) diff --git a/parser.c b/parser.c index 2a31f14f..8eb93559 100644 --- a/parser.c +++ b/parser.c @@ -148,8 +148,7 @@ void process_pihole_log(int file) { int i; char *readbuffer = NULL; - char *readbuffer2 = NULL; - size_t size1 = 0, size2 = 0; + size_t size1 = 0; FILE *fp; if(file == 0) @@ -304,8 +303,8 @@ void process_pihole_log(int file) continue; } - // Get query ID - // "Dec 20 21:16:22 dnsmasq[19372]: 4 10.8.0.2/34596 query[A] pi.hole from 10.8.0.2 + // Get query ID from a string like + // "Dec 20 21:16:22 dnsmasq[19372]: 4 10.8.0.2/34596 query[A] pi.hole from 10.8.0.2" unsigned int dnsmasqID = 0; if(!sscanf(readbuffer, "%*[^]]]: %u", &dnsmasqID)) { @@ -405,95 +404,6 @@ void process_pihole_log(int file) overTime[timeidx].querytypedata[1]++; } - // Save current file pointer position - long int fpos = ftell(fp); - unsigned char status = 0; - - // Try to find either a matching - // - "gravity.list" + domain - // - "forwarded" + domain - // - "cached" + domain - // - "black.list" + domain - // in the following up to 200 lines - bool firsttime = true; - int forwardID = -1; - for(i=0; i<200; i++) - { - if(getline(&readbuffer2, &size2, fp) != -1) - { - // Process only matching lines - if(strstr(readbuffer2, domainwithspaces) != NULL) - { - // Blocked by gravity.list ? - if(strstr(readbuffer2,"gravity.list ") != NULL) - { - status = 1; - break; - } - // Forwarded to upstream server? - else if(strstr(readbuffer2,": forwarded ") != NULL) - { - status = 2; - // Get ID of forward destination, create new forward destination record - // if not found in current data structure - forwardID = getforwardID(readbuffer2, false); - if(forwardID == -2) - continue; - break; - } - // Answered by local cache? - else if((strstr(readbuffer2,"cached ") != NULL) || - (strstr(readbuffer2,"local.list") != NULL) || - (strstr(readbuffer2,"hostname.list") != NULL) || - (strstr(readbuffer2,"DHCP ") != NULL) || - (strstr(readbuffer2,"/etc/hosts") != NULL)) - { - status = 3; - break; - } - // wildcard blocking? - else if((strstr(readbuffer2,"config ") != NULL)) - { - status = detectStatus(domain); - break; - } - // Blocked by black.list ? - else if(strstr(readbuffer2,"black.list ") != NULL) - { - status = 5; - break; - } - } - } - else - { - if(firsttime) - { - // Reached EOF without finding the action - // wait 100msec and try again to read dnsmasq's response - i = 0; - fseek(fp, fpos, SEEK_SET); - firsttime = false; - sleepms(100); - } - else - { - // Failed second time - break; - } - } - } - - // Return to previous file pointer position - fseek(fp, fpos, SEEK_SET); - - // Free memory allocated by readline - if(readbuffer2 != NULL) - { - free(readbuffer2); - readbuffer2 = NULL; - } - // Go through already knows domains and see if it is one of them // Check struct size memory_check(DOMAINS); @@ -505,7 +415,7 @@ void process_pihole_log(int file) domainID = counters.domains; // // Debug output if(debug) - logg("New domain: %s (%i - %i/%i)", domain, status, domainID, counters.domains_MAX); + logg("New domain: %s (%i: %i/%i)", domain, dnsmasqID, domainID, counters.domains_MAX); validate_access("domains", domainID, false, __LINE__, __FUNCTION__, __FILE__); // Set magic byte domains[domainID].magic = MAGICBYTE; @@ -538,10 +448,10 @@ void process_pihole_log(int file) { // Convert hostname to lower case strtolower(hostname); - logg("New client: %s %s (%i/%i)", client, hostname, clientID, counters.clients_MAX); + logg("New client: %s %s (%i: %i/%i)", client, hostname, dnsmasqID, clientID, counters.clients_MAX); } else - logg("New client: %s (%i/%i)", client, clientID, counters.clients_MAX); + logg("New client: %s (%i: %i/%i)", client, dnsmasqID, clientID, counters.clients_MAX); validate_access("clients", clientID, false, __LINE__, __FUNCTION__, __FILE__); // Set magic byte @@ -564,13 +474,15 @@ void process_pihole_log(int file) queries[queryID].magic = MAGICBYTE; queries[queryID].timestamp = querytimestamp; queries[queryID].type = type; - queries[queryID].status = status; + // queries[queryID].status = status; queries[queryID].domainID = domainID; queries[queryID].clientID = clientID; queries[queryID].timeidx = timeidx; - queries[queryID].forwardID = forwardID; + // queries[queryID].forwardID = forwardID; queries[queryID].valid = true; queries[queryID].db = false; + queries[queryID].id = dnsmasqID; + queries[queryID].complete = false; // Increase DNS queries counter counters.queries++; @@ -579,54 +491,6 @@ void process_pihole_log(int file) validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); overTime[timeidx].total++; - // Decide what to increment depending on status - switch(status) - { - case 0: - // Unknown (?) - counters.unknown++; - break; - case 1: - // Blocked by Pi-hole's blocking lists - counters.blocked++; - validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); - overTime[timeidx].blocked++; - validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__); - domains[domainID].blockedcount++; - break; - case 2: - // Forwarded to an upstream DNS server - counters.forwardedqueries++; - break; - case 3: - // Answered from local cache _or_ local config - counters.cached++; - validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); - overTime[timeidx].cached++; - break; - case 4: - // Blocked due to a matching wildcard rule - counters.wildcardblocked++; - validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); - overTime[timeidx].blocked++; - validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__); - domains[domainID].blockedcount++; - domains[domainID].wildcard = true; - break; - case 5: - // Blocked by user's black list - counters.blocked++; - validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); - overTime[timeidx].blocked++; - validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__); - domains[domainID].blockedcount++; - break; - default: - /* That cannot happen */ - logg("Found unexpected status %i",status); - break; - } - // Determine if there is enough space for saving the current // clientID in the overTime data structure, allocate space otherwise validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); From 468da59bae135d0afed092c143df58cce409ba72 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 14:52:39 +0100 Subject: [PATCH 03/63] Added proper analysis for "cached" lines + outsourced the timestamp detection into its own subroutine to avoid large repitions of code. Signed-off-by: DL6ER --- FTL.h | 2 +- parser.c | 162 ++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 126 insertions(+), 38 deletions(-) diff --git a/FTL.h b/FTL.h index 18f389b6..ba81200e 100644 --- a/FTL.h +++ b/FTL.h @@ -138,7 +138,7 @@ typedef struct { bool valid; bool db; // the ID is a (signed) in dnsmasq, so no need for a long int here - unsigned int id; + int id; bool complete; } queriesDataStruct; diff --git a/parser.c b/parser.c index 8eb93559..f15dd6c7 100644 --- a/parser.c +++ b/parser.c @@ -49,6 +49,45 @@ long int checkLogForChanges(void) return difference; } +int getTimeIndex(char * readbuffer) +{ + int querytimestamp, overTimetimestamp, timeidx = -1, i; + extracttimestamp(readbuffer, &querytimestamp, &overTimetimestamp); + + bool found = false; + // Check struct size + memory_check(OVERTIME); + for(i=0; i < counters.overTime; i++) + { + validate_access("overTime", i, true, __LINE__, __FUNCTION__, __FILE__); + if(overTime[i].timestamp == overTimetimestamp) + { + found = true; + timeidx = i; + break; + } + } + if(!found) + { + timeidx = counters.overTime; + validate_access("overTime", timeidx, false, __LINE__, __FUNCTION__, __FILE__); + overTime[timeidx].magic = MAGICBYTE; + overTime[timeidx].timestamp = overTimetimestamp; + overTime[timeidx].total = 0; + overTime[timeidx].blocked = 0; + overTime[timeidx].cached = 0; + overTime[timeidx].forwardnum = 0; + overTime[timeidx].forwarddata = NULL; + overTime[timeidx].querytypedata = calloc(2, sizeof(int)); + overTime[timeidx].clientnum = 0; + overTime[timeidx].clientdata = NULL; + memory.querytypedata += 2*sizeof(int); + counters.overTime++; + } + + return timeidx; +} + void open_pihole_log(void) { FILE * fp; @@ -144,6 +183,18 @@ void *pihole_log_thread(void *val) return NULL; } +int getID(char * readbuffer) +{ + // Get query ID from a string like + // "Dec 20 21:16:22 dnsmasq[19372]: 4 10.8.0.2/34596 query[A] pi.hole from 10.8.0.2" + int dnsmasqID = -1; + if(!sscanf(readbuffer, "%*[^]]]: %i", &dnsmasqID)) + { + if(debug) logg("Error getting ID for query \"%s\" %u", readbuffer, dnsmasqID); + } + return dnsmasqID; +} + void process_pihole_log(int file) { int i; @@ -303,14 +354,8 @@ void process_pihole_log(int file) continue; } - // Get query ID from a string like - // "Dec 20 21:16:22 dnsmasq[19372]: 4 10.8.0.2/34596 query[A] pi.hole from 10.8.0.2" - unsigned int dnsmasqID = 0; - if(!sscanf(readbuffer, "%*[^]]]: %u", &dnsmasqID)) - { - if(debug) logg("Error getting ID for query \"%s\" %u", readbuffer, dnsmasqID); - continue; - } + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); // Get domain // domainstart = pointer to | in "query[AAAA] |host.name from ww.xx.yy.zz\n" @@ -517,7 +562,8 @@ void process_pihole_log(int file) free(domain); free(domainwithspaces); } - else if(strstr(readbuffer,": forwarded") != NULL) + // is this a "forwarded" line? + else if(strstr(readbuffer," forwarded ") != NULL && strstr(readbuffer," to ") != NULL) { // Check if this domain names contains only printable characters // if not: skip analysis of this log line @@ -532,46 +578,38 @@ void process_pihole_log(int file) if(strstr(readbuffer,"in-addr.arpa") != NULL) continue; + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); + // Get ID of forward destination, create new forward destination record // if not found in current data structure int forwardID = getforwardID(readbuffer, true); if(forwardID == -2) - continue; - - // Get timestamp - int querytimestamp, overTimetimestamp, timeidx = -1, i; - extracttimestamp(readbuffer, &querytimestamp, &overTimetimestamp); - - bool found = false; - // Check struct size - memory_check(OVERTIME); - for(i=0; i < counters.overTime; i++) { - validate_access("overTime", i, true, __LINE__, __FUNCTION__, __FILE__); - if(overTime[i].timestamp == overTimetimestamp) + if(debug) logg("Skipping malformated forwarded line"); + continue; + } + + // Save forwardID in corresponding query indentified by dnsmasq's ID + bool found = false; + for(i=0;i") != NULL) + { + if(debug) logg("Ignoring domain (cached)"); + continue; + } + + // Check if this is a PTR query + // if so: skip analysis of this log line + if(strstr(readbuffer,"in-addr.arpa") != NULL) + continue; + + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); + + // Save forwardID in corresponding query indentified by dnsmasq's ID + bool found = false; + for(i=0;i Date: Thu, 21 Dec 2017 14:54:14 +0100 Subject: [PATCH 04/63] Initialize query status with 0 (unknown) Signed-off-by: DL6ER --- parser.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/parser.c b/parser.c index f15dd6c7..de967658 100644 --- a/parser.c +++ b/parser.c @@ -519,11 +519,10 @@ void process_pihole_log(int file) queries[queryID].magic = MAGICBYTE; queries[queryID].timestamp = querytimestamp; queries[queryID].type = type; - // queries[queryID].status = status; + queries[queryID].status = 0; queries[queryID].domainID = domainID; queries[queryID].clientID = clientID; queries[queryID].timeidx = timeidx; - // queries[queryID].forwardID = forwardID; queries[queryID].valid = true; queries[queryID].db = false; queries[queryID].id = dnsmasqID; From 9c49155da62787869d6eb0c335e941d85b44d7ba Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 15:01:49 +0100 Subject: [PATCH 05/63] Change the logic FTL uses to treat the counters Signed-off-by: DL6ER --- parser.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/parser.c b/parser.c index de967658..a1d89d88 100644 --- a/parser.c +++ b/parser.c @@ -530,6 +530,9 @@ void process_pihole_log(int file) // Increase DNS queries counter counters.queries++; + // Count this query as unknown as long as no reply has + // been found and analyzed + counters.unknown++; // Update overTime data validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); @@ -595,6 +598,7 @@ void process_pihole_log(int file) { if(queries[i].id == dnsmasqID) { + queries[i].status = 2; queries[i].forwardID = forwardID; found = true; } @@ -629,6 +633,16 @@ void process_pihole_log(int file) // Update overTime data structure with the new forwarder validate_access_oTfd(timeidx, forwardID, __LINE__, __FUNCTION__, __FILE__); overTime[timeidx].forwarddata[forwardID]++; + + if(!queries[i].complete) + { + // This query is no longer unknown ... + counters.unknown--; + // ... but got forwarded + counters.forwardedqueries++; + // Hereby, this query is now fully determined + queries[i].complete = true; + } } // is this a "cached" line? else if((strstr(readbuffer," cached ") != NULL || \ @@ -672,8 +686,15 @@ void process_pihole_log(int file) } if(debug) logg("Cached: %i \"%s\"",dnsmasqID, readbuffer); - // Answered from local cache _or_ local config - counters.cached++; + if(!queries[i].complete) + { + // This query is no longer unknown ... + counters.unknown--; + // ... but answered from local cache _or_ local config + counters.cached++; + // Hereby, this query is now fully determined + queries[i].complete = true; + } // Get time index int timeidx = getTimeIndex(readbuffer); From 678e755e9500e5187087c35421fa27f9ac3c97c7 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 15:06:18 +0100 Subject: [PATCH 06/63] Properly update time index Signed-off-by: DL6ER --- parser.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/parser.c b/parser.c index a1d89d88..438ac96a 100644 --- a/parser.c +++ b/parser.c @@ -564,6 +564,60 @@ void process_pihole_log(int file) free(domain); free(domainwithspaces); } + // is this a "gravity.list" line? + else if(strstr(readbuffer," gravity.list ") != NULL && strstr(readbuffer," is ") != NULL) + { + // Check if this domain names contains only printable characters + // if not: skip analysis of this log line + if(strstr(readbuffer,"") != NULL) + { + if(debug) logg("Ignoring domain (cached)"); + continue; + } + + // Check if this is a PTR query + // if so: skip analysis of this log line + if(strstr(readbuffer,"in-addr.arpa") != NULL) + continue; + + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); + + // Save forwardID in corresponding query indentified by dnsmasq's ID + bool found = false; + for(i=0;i Date: Thu, 21 Dec 2017 15:09:43 +0100 Subject: [PATCH 07/63] List files like gravity.list, local.list, and hostname.list have to have a path + removed some debugging output Signed-off-by: DL6ER --- parser.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/parser.c b/parser.c index 438ac96a..8d5d6020 100644 --- a/parser.c +++ b/parser.c @@ -565,7 +565,7 @@ void process_pihole_log(int file) free(domainwithspaces); } // is this a "gravity.list" line? - else if(strstr(readbuffer," gravity.list ") != NULL && strstr(readbuffer," is ") != NULL) + else if(strstr(readbuffer,"/gravity.list ") != NULL && strstr(readbuffer," is ") != NULL) { // Check if this domain names contains only printable characters // if not: skip analysis of this log line @@ -599,7 +599,6 @@ void process_pihole_log(int file) // as we ignore them altogether continue; } - if(debug) logg("Gravity: %i \"%s\"",dnsmasqID, readbuffer); if(!queries[i].complete) { @@ -700,8 +699,8 @@ void process_pihole_log(int file) } // is this a "cached" line? else if((strstr(readbuffer," cached ") != NULL || \ - strstr(readbuffer," local.list ") != NULL || \ - strstr(readbuffer," hostname.list ") != NULL || \ + strstr(readbuffer,"/local.list ") != NULL || \ + strstr(readbuffer,"/hostname.list ") != NULL || \ strstr(readbuffer," DHCP ") != NULL || \ strstr(readbuffer," /etc/hosts ") != NULL) \ && strstr(readbuffer," is ") != NULL) @@ -738,7 +737,6 @@ void process_pihole_log(int file) // as we ignore them altogether continue; } - if(debug) logg("Cached: %i \"%s\"",dnsmasqID, readbuffer); if(!queries[i].complete) { From 538e5a315693c9db794177d07ea682fe52174c1c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 15:19:35 +0100 Subject: [PATCH 08/63] Handle wildcard blocked domains correctly Signed-off-by: DL6ER --- log.c | 4 +++- parser.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/log.c b/log.c index 5b5f1d1e..8b3b44f3 100644 --- a/log.c +++ b/log.c @@ -135,7 +135,9 @@ void log_counter_info(void) { logg(" -> Total DNS queries: %i", counters.queries); logg(" -> Cached DNS queries: %i", counters.cached); - logg(" -> Blocked DNS queries: %i", counters.blocked); + logg(" -> Forwarded DNS queries: %i", counters.forwarded); + logg(" -> Exactly blocked DNS queries: %i", counters.blocked); + logg(" -> Wildcard blocked DNS queries: %i", counters.wildcardblocked); logg(" -> Unknown DNS queries: %i", counters.unknown); logg(" -> Unique domains: %i", counters.domains); logg(" -> Unique clients: %i", counters.clients); diff --git a/parser.c b/parser.c index 8d5d6020..43e2eeb1 100644 --- a/parser.c +++ b/parser.c @@ -752,7 +752,75 @@ void process_pihole_log(int file) validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); overTime[timeidx].cached++; } + } + // is this a "wildcard" line? + else if(strstr(readbuffer," config ") != NULL && strstr(readbuffer," is ") != NULL) + { + // Check if this domain names contains only printable characters + // if not: skip analysis of this log line + if(strstr(readbuffer,"") != NULL) + { + if(debug) logg("Ignoring domain (cached)"); + continue; + } + // Check if this is a PTR query + // if so: skip analysis of this log line + if(strstr(readbuffer,"in-addr.arpa") != NULL) + continue; + + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); + + // Save forwardID in corresponding query indentified by dnsmasq's ID + bool found = false; + for(i=0;i Date: Thu, 21 Dec 2017 15:21:24 +0100 Subject: [PATCH 09/63] Handle exactly blocked queries (blocked by black.list) Signed-off-by: DL6ER --- parser.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/parser.c b/parser.c index 43e2eeb1..273bbf21 100644 --- a/parser.c +++ b/parser.c @@ -823,6 +823,60 @@ void process_pihole_log(int file) } } + // is this a "black.list" line? + else if(strstr(readbuffer,"/black.list ") != NULL && strstr(readbuffer," is ") != NULL) + { + // Check if this domain names contains only printable characters + // if not: skip analysis of this log line + if(strstr(readbuffer,"") != NULL) + { + if(debug) logg("Ignoring domain (cached)"); + continue; + } + + // Check if this is a PTR query + // if so: skip analysis of this log line + if(strstr(readbuffer,"in-addr.arpa") != NULL) + continue; + + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); + + // Save forwardID in corresponding query indentified by dnsmasq's ID + bool found = false; + for(i=0;i Date: Thu, 21 Dec 2017 15:37:28 +0100 Subject: [PATCH 10/63] Have to actually break out of the loops for i to be the queryID Signed-off-by: DL6ER --- parser.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/parser.c b/parser.c index 273bbf21..e7e65a18 100644 --- a/parser.c +++ b/parser.c @@ -591,6 +591,7 @@ void process_pihole_log(int file) { queries[i].status = 1; found = true; + break; } } if(!found) @@ -654,6 +655,7 @@ void process_pihole_log(int file) queries[i].status = 2; queries[i].forwardID = forwardID; found = true; + break; } } if(!found) @@ -729,6 +731,7 @@ void process_pihole_log(int file) { queries[i].status = 3; found = true; + break; } } if(!found) @@ -780,6 +783,7 @@ void process_pihole_log(int file) { queries[i].status = detectStatus(domains[queries[i].domainID].domain); found = true; + break; } } if(!found) @@ -796,14 +800,16 @@ void process_pihole_log(int file) // Hereby, this query is now fully determined queries[i].complete = true; + // Get time index int timeidx = getTimeIndex(readbuffer); // Decide what to do depening on the result of detectStatus() - if(queries[i].id == 4) + if(queries[i].status == 4) { // Blocked due to a matching wildcard rule counters.wildcardblocked++; + validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); overTime[timeidx].blocked++; validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__); @@ -815,8 +821,6 @@ void process_pihole_log(int file) // Answered from a custom (user provided) cache file counters.cached++; - // Get time index - int timeidx = getTimeIndex(readbuffer); validate_access("overTime", timeidx, true, __LINE__, __FUNCTION__, __FILE__); overTime[timeidx].cached++; } @@ -850,6 +854,7 @@ void process_pihole_log(int file) { queries[i].status = 5; found = true; + break; } } if(!found) From 541d86bc744c7f46a69738c27ad06faa6b7a0fb9 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 15:45:42 +0100 Subject: [PATCH 11/63] Add (undocumented) debugging command over telnet (display unknown queries) Signed-off-by: DL6ER --- parser.c | 1 - request.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/parser.c b/parser.c index e7e65a18..e5d9c3b0 100644 --- a/parser.c +++ b/parser.c @@ -800,7 +800,6 @@ void process_pihole_log(int file) // Hereby, this query is now fully determined queries[i].complete = true; - // Get time index int timeidx = getTimeIndex(readbuffer); diff --git a/request.c b/request.c index 196a413a..40670236 100644 --- a/request.c +++ b/request.c @@ -32,6 +32,7 @@ void getVersion(int *sock); void getDBstats(int *sock); void getClientsOverTime(int *sock); void getClientNames(int *sock); +void getUnknownQueries(int *sock); void process_request(char *client_message, int *sock) { @@ -125,6 +126,11 @@ void process_request(char *client_message, int *sock) processed = true; getClientNames(sock); } + else if(command(client_message, ">unknown")) + { + processed = true; + getUnknownQueries(sock); + } // Test only at the end if we want to quit or kill // so things can be processed before @@ -1184,3 +1190,45 @@ void getClientNames(int *sock) if(excludeclients != NULL) clearSetupVarsArray(); } + +void getUnknownQueries(int *sock) +{ + char server_message[SOCKETBUFFERLEN]; + + if(!debug) + { + sprintf(server_message,"For safety reasons, the command is only available in debugging mode!\n"); + swrite(server_message, *sock); + return; + } + + int i; + for(i=0; i < counters.queries; i++) + { + validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__); + // Check if this query has been removed due to garbage collection + if(queries[i].status != 0) continue; + + char type[5]; + if(queries[i].type == 1) + { + strcpy(type,"IPv4"); + } + else + { + strcpy(type,"IPv6"); + } + + validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__); + validate_access("clients", queries[i].clientID, true, __LINE__, __FUNCTION__, __FILE__); + + if(strlen(clients[queries[i].clientID].name) > 0) + sprintf(server_message,"%i %s %s %s %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status); + else + sprintf(server_message,"%i %s %s %s %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status); + swrite(server_message, *sock); + } + + if(debugclients) + logg("Sent unknown queries data to client, ID: %i", *sock); +} From 24e4f6f8a9d923be086c041bc85e000b8ab7b4ab Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 15:48:04 +0100 Subject: [PATCH 12/63] Display counter information after re-reading the log file (received SIGHUP) Signed-off-by: DL6ER --- main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main.c b/main.c index 28b18e62..025b37d0 100644 --- a/main.c +++ b/main.c @@ -145,6 +145,7 @@ int main (int argc, char* argv[]) { // Have to re-read gravity files rereadgravity = false; read_gravity_files(); + log_counter_info(); disable_thread_lock("pihole_main_thread"); } } From 478568e1eebff8ce19a1fa6831793d6a6211e9c6 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 15:54:52 +0100 Subject: [PATCH 13/63] Extend the new debug command a little bit Signed-off-by: DL6ER --- parser.c | 12 ++++++------ request.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/parser.c b/parser.c index e5d9c3b0..7d10e8be 100644 --- a/parser.c +++ b/parser.c @@ -585,7 +585,7 @@ void process_pihole_log(int file) // Save forwardID in corresponding query indentified by dnsmasq's ID bool found = false; - for(i=0;i 0) - sprintf(server_message,"%i %s %s %s %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status); + sprintf(server_message,"%i %i %i %s %s %s %i %s\n",queries[i].timestamp,i,queries[i].id,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status,queries[i].complete ?"true":"false"); else - sprintf(server_message,"%i %s %s %s %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status); + sprintf(server_message,"%i %i %i %s %s %s %i %s\n",queries[i].timestamp,i,queries[i].id,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status,queries[i].complete?"true":"false"); swrite(server_message, *sock); } From f935312de52df3fa514cf96ea2ff232767fab69b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 16:05:48 +0100 Subject: [PATCH 14/63] Don't reuse i as counting index where we need it as query ID Signed-off-by: DL6ER --- parser.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/parser.c b/parser.c index 7d10e8be..9c53d58f 100644 --- a/parser.c +++ b/parser.c @@ -676,9 +676,10 @@ void process_pihole_log(int file) // Reallocate more space for forwarddata overTime[timeidx].forwarddata = realloc(overTime[timeidx].forwarddata, (forwardID+1)*sizeof(*overTime[timeidx].forwarddata)); // Initialize new data fields with zeroes - for(i = overTime[timeidx].forwardnum; i <= forwardID; i++) + int j; + for(j = overTime[timeidx].forwardnum; j <= forwardID; j++) { - overTime[timeidx].forwarddata[i] = 0; + overTime[timeidx].forwarddata[j] = 0; memory.forwarddata++; } // Update counter From b61d035807c2ad5edc12abe76cafbe7a0060c578 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 16:15:34 +0100 Subject: [PATCH 15/63] Update tests with new log format Signed-off-by: DL6ER --- test/run.sh | 66 ++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/test/run.sh b/test/run.sh index 95459821..a4658026 100755 --- a/test/run.sh +++ b/test/run.sh @@ -8,39 +8,39 @@ dnsmasq_pre() { # Prepare FTL's files ts="$(dnsmasq_pre)" cat <> pihole.log -${ts} query[AAAA] raspberrypi from 127.0.0.1 -${ts} /etc/pihole/local.list raspberrypi is fda2:2001:5647:0:ba27:ebff:fe37:4205 -${ts} query[A] ChEcKiP.DyNdNs.OrG from 127.0.0.1 -${ts} forwarded ChEcKiP.DyNdNs.OrG to 2001:1608:10:25::9249:d69b -${ts} forwarded ChEcKiP.DyNdNs.OrG to 2001:1608:10:25::1c04:b12f -${ts} forwarded ChEcKiP.DyNdNs.OrG to 2620:0:ccd::2 -${ts} forwarded ChEcKiP.DyNdNs.OrG to 2620:0:ccc::2 -${ts} reply ChEcKiP.DyNdNs.OrG is -${ts} reply checkip.dyndns.com is 216.146.38.70 -${ts} reply checkip.dyndns.com is 216.146.43.71 -${ts} reply checkip.dyndns.com is 91.198.22.70 -${ts} reply checkip.dyndns.com is 216.146.43.70 -${ts} query[A] pi.hole from 10.8.0.2 -${ts} /etc/pihole/local.list pi.hole is 192.168.2.10 -${ts} query[A] example.com from 10.8.0.2 -${ts} /etc/pihole/local.list example.com is 192.168.2.10 -${ts} query[A] play.google.com from 192.168.2.208 -${ts} forwarded play.google.com to 2001:1608:10:25::9249:d69b -${ts} forwarded play.google.com to 2001:1608:10:25::1c04:b12f -${ts} forwarded play.google.com to 2620:0:ccd::2 -${ts} forwarded play.google.com to 2620:0:ccc::2 -${ts} reply play.google.com is -${ts} reply play.l.google.com is 216.58.208.110 -${ts} reply play.l.google.com is 216.58.208.110 -${ts} reply play.l.google.com is 216.58.208.110 -${ts} reply play.google.com is -${ts} query[AAAA] play.google.com from 192.168.2.208 -${ts} forwarded play.google.com to 2620:0:ccd::2 -${ts} reply play.l.google.com is 2a00:1450:4017:802::200e -${ts} query[A] blacklisted.com from 192.168.2.208 -${ts} /etc/pihole/black.list blacklisted.com is 1.2.3.4 -${ts} query[A] addomain.com from 192.168.2.208 -${ts} /etc/pihole/gravity.list addomain.com is 1.2.3.4 +${ts} 1 1270.0.01/1234 query[AAAA] raspberrypi from 127.0.0.1 +${ts} 1 1270.0.01/1234 /etc/pihole/local.list raspberrypi is fda2:2001:5647:0:ba27:ebff:fe37:4205 +${ts} 2 1270.0.01/1234 query[A] ChEcKiP.DyNdNs.OrG from 127.0.0.1 +${ts} 2 1270.0.01/1234 forwarded ChEcKiP.DyNdNs.OrG to 2001:1608:10:25::9249:d69b +${ts} 2 1270.0.01/1234 forwarded ChEcKiP.DyNdNs.OrG to 2001:1608:10:25::1c04:b12f +${ts} 2 1270.0.01/1234 forwarded ChEcKiP.DyNdNs.OrG to 2620:0:ccd::2 +${ts} 2 1270.0.01/1234 forwarded ChEcKiP.DyNdNs.OrG to 2620:0:ccc::2 +${ts} 2 1270.0.01/1234 reply ChEcKiP.DyNdNs.OrG is +${ts} 2 1270.0.01/1234 reply ChEcKiP.DyNdNs.OrG is 216.146.38.70 +${ts} 2 1270.0.01/1234 reply ChEcKiP.DyNdNs.OrG is 216.146.43.71 +${ts} 2 1270.0.01/1234 reply ChEcKiP.DyNdNs.OrG is 91.198.22.70 +${ts} 2 1270.0.01/1234 reply ChEcKiP.DyNdNs.OrG is 216.146.43.70 +${ts} 3 1270.0.01/1234 query[A] pi.hole from 10.8.0.2 +${ts} 3 1270.0.01/1234 /etc/pihole/local.list pi.hole is 192.168.2.10 +${ts} 4 1270.0.01/1234 query[A] example.com from 10.8.0.2 +${ts} 4 1270.0.01/1234 /etc/pihole/local.list example.com is 192.168.2.10 +${ts} 5 1270.0.01/1234 query[A] play.google.com from 192.168.2.208 +${ts} 5 1270.0.01/1234 forwarded play.google.com to 2001:1608:10:25::9249:d69b +${ts} 5 1270.0.01/1234 forwarded play.google.com to 2001:1608:10:25::1c04:b12f +${ts} 5 1270.0.01/1234 forwarded play.google.com to 2620:0:ccd::2 +${ts} 5 1270.0.01/1234 forwarded play.google.com to 2620:0:ccc::2 +${ts} 5 1270.0.01/1234 reply play.google.com is +${ts} 5 1270.0.01/1234 reply play.l.google.com is 216.58.208.110 +${ts} 5 1270.0.01/1234 reply play.l.google.com is 216.58.208.110 +${ts} 5 1270.0.01/1234 reply play.l.google.com is 216.58.208.110 +${ts} 5 1270.0.01/1234 reply play.google.com is +${ts} 6 1270.0.01/1234 query[AAAA] play.google.com from 192.168.2.208 +${ts} 6 1270.0.01/1234 forwarded play.google.com to 2620:0:ccd::2 +${ts} 6 1270.0.01/1234 reply play.l.google.com is 2a00:1450:4017:802::200e +${ts} 7 1270.0.01/1234 query[A] blacklisted.com from 192.168.2.208 +${ts} 7 1270.0.01/1234 /etc/pihole/black.list blacklisted.com is 1.2.3.4 +${ts} 8 1270.0.01/1234 query[A] addomain.com from 192.168.2.208 +${ts} 8 1270.0.01/1234 /etc/pihole/gravity.list addomain.com is 1.2.3.4 EOT touch "pihole-FTL.log" From 86393d50fe2a300c40dd2d9a60620a7b0220956a Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 16:21:12 +0100 Subject: [PATCH 16/63] Skip lines without UUID Signed-off-by: DL6ER --- parser.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/parser.c b/parser.c index 9c53d58f..2fe89184 100644 --- a/parser.c +++ b/parser.c @@ -356,6 +356,9 @@ void process_pihole_log(int file) // Get dnsmasq's ID for this transaction int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; // Get domain // domainstart = pointer to | in "query[AAAA] |host.name from ww.xx.yy.zz\n" @@ -582,6 +585,9 @@ void process_pihole_log(int file) // Get dnsmasq's ID for this transaction int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; // Save forwardID in corresponding query indentified by dnsmasq's ID bool found = false; @@ -636,6 +642,9 @@ void process_pihole_log(int file) // Get dnsmasq's ID for this transaction int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; // Get ID of forward destination, create new forward destination record // if not found in current data structure @@ -723,6 +732,9 @@ void process_pihole_log(int file) // Get dnsmasq's ID for this transaction int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; // Save forwardID in corresponding query indentified by dnsmasq's ID bool found = false; @@ -775,6 +787,9 @@ void process_pihole_log(int file) // Get dnsmasq's ID for this transaction int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; // Save forwardID in corresponding query indentified by dnsmasq's ID bool found = false; @@ -845,6 +860,9 @@ void process_pihole_log(int file) // Get dnsmasq's ID for this transaction int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; // Save forwardID in corresponding query indentified by dnsmasq's ID bool found = false; From f416fa5928b8b8119ca69500465b269d12590a6e Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 21 Dec 2017 16:33:05 +0100 Subject: [PATCH 17/63] Add the concept of log generations to account for UUIDs that are not very unique Signed-off-by: DL6ER --- FTL.h | 1 + parser.c | 27 ++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/FTL.h b/FTL.h index ba81200e..7284592f 100644 --- a/FTL.h +++ b/FTL.h @@ -140,6 +140,7 @@ typedef struct { // the ID is a (signed) in dnsmasq, so no need for a long int here int id; bool complete; + int generation; } queriesDataStruct; typedef struct { diff --git a/parser.c b/parser.c index 2fe89184..beff1250 100644 --- a/parser.c +++ b/parser.c @@ -23,6 +23,7 @@ long int lastpos = 0; int lastqueryID = 0; bool flush = false; char timestamp[16] = ""; +int loggeneration = 0; void initial_log_parsing(void) { @@ -530,6 +531,7 @@ void process_pihole_log(int file) queries[queryID].db = false; queries[queryID].id = dnsmasqID; queries[queryID].complete = false; + queries[queryID].generation = loggeneration; // Increase DNS queries counter counters.queries++; @@ -593,7 +595,8 @@ void process_pihole_log(int file) bool found = false; for(i=0; i Date: Thu, 21 Dec 2017 22:37:58 +0100 Subject: [PATCH 18/63] Fix README.md Signed-off-by: DL6ER --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1fd4bbac..70dabdd0 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,7 @@ unique_clients 3 2 10.0 5.6.7.8 some.other.dns.com ``` Variant: `>forward-dest unsorted` to show forward destinations in unsorted order (equivalent to using `>forward-names`) -``` + - `>querytypes` : get collected query types percentage ``` From 3d0fc44ed430ce07ae68b61635fa0ebddb27f63f Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 22 Dec 2017 12:16:33 +0100 Subject: [PATCH 19/63] Further reduction of code duplication in the parser routine Signed-off-by: DL6ER --- parser.c | 109 ++++++++++++++++++------------------------------------- 1 file changed, 35 insertions(+), 74 deletions(-) diff --git a/parser.c b/parser.c index beff1250..5cf2d9b1 100644 --- a/parser.c +++ b/parser.c @@ -196,6 +196,30 @@ int getID(char * readbuffer) return dnsmasqID; } +bool checkQuery(char * readbuffer, const char * type) +{ + // Check if this domain names contains only printable characters + // if not: skip analysis of this log line + if(strstr(readbuffer,"") != NULL) + { + if(debug) logg("Ignoring domain (%s)", type); + return false; + } + + // Check if this domain name contains quotes + if(strstr(readbuffer, "\"") != NULL) + { + if(debug) logg("Ignoring \" domain (%s)", type); + return false; + } + + // Check if this is a PTR query (we don't analyze them) + if(strstr(readbuffer,"in-addr.arpa") != NULL) + return false; + + return true; +} + void process_pihole_log(int file) { int i; @@ -253,19 +277,8 @@ void process_pihole_log(int file) // Test if the read line is a query line if(strstr(readbuffer," query[A") != NULL) { - // Check if this domain names contains only printable characters - // if not: skip analysis of this log line - if(strstr(readbuffer,"") != NULL) - { - if(debug) logg("Ignoring domain (query)"); + if(!checkQuery(readbuffer, "query")) continue; - } - - if(strstr(readbuffer, "\"") != NULL) - { - if(debug) logg("Ignoring \" domain (query)"); - continue; - } if(!config.analyze_AAAA && strstr(readbuffer," query[AAAA]") != NULL) { @@ -390,11 +403,8 @@ void process_pihole_log(int file) } char *domain = calloc(domainlen+1,sizeof(char)); - char *domainwithspaces = calloc(domainlen+3,sizeof(char)); // strncat() NULL-terminates the copied string (strncpy() doesn't!) strncat(domain,domainstart+2,domainlen); - // Copy string into buffer surrounded by spaces - sprintf(domainwithspaces," %s ",domain); // Convert domain to lower case strtolower(domain); @@ -403,7 +413,6 @@ void process_pihole_log(int file) // domain is "pi.hole", skip this query // free memory already allocated here free(domain); - free(domainwithspaces); continue; } @@ -416,7 +425,6 @@ void process_pihole_log(int file) logg("Notice: Skipping malformated log line (client end missing): %s", readbuffer); // Skip this line, free memory already allocated here free(domain); - free(domainwithspaces); continue; } @@ -426,7 +434,6 @@ void process_pihole_log(int file) logg("Notice: Skipping malformated log line (client length < 1): %s", readbuffer); // Skip this line, free memory already allocated here free(domain); - free(domainwithspaces); continue; } @@ -567,22 +574,12 @@ void process_pihole_log(int file) // Free allocated memory free(client); free(domain); - free(domainwithspaces); } // is this a "gravity.list" line? else if(strstr(readbuffer,"/gravity.list ") != NULL && strstr(readbuffer," is ") != NULL) { - // Check if this domain names contains only printable characters - // if not: skip analysis of this log line - if(strstr(readbuffer,"") != NULL) - { - if(debug) logg("Ignoring domain (cached)"); - continue; - } - - // Check if this is a PTR query - // if so: skip analysis of this log line - if(strstr(readbuffer,"in-addr.arpa") != NULL) + // Check query for invalid characters + if(!checkQuery(readbuffer, "gravity.list")) continue; // Get dnsmasq's ID for this transaction @@ -630,17 +627,8 @@ void process_pihole_log(int file) // is this a "forwarded" line? else if(strstr(readbuffer," forwarded ") != NULL && strstr(readbuffer," to ") != NULL) { - // Check if this domain names contains only printable characters - // if not: skip analysis of this log line - if(strstr(readbuffer,"") != NULL) - { - if(debug) logg("Ignoring domain (forwarded)"); - continue; - } - - // Check if this is a PTR query - // if so: skip analysis of this log line - if(strstr(readbuffer,"in-addr.arpa") != NULL) + // Check query for invalid characters + if(!checkQuery(readbuffer, "forwarded")) continue; // Get dnsmasq's ID for this transaction @@ -721,17 +709,8 @@ void process_pihole_log(int file) strstr(readbuffer," /etc/hosts ") != NULL) \ && strstr(readbuffer," is ") != NULL) { - // Check if this domain names contains only printable characters - // if not: skip analysis of this log line - if(strstr(readbuffer,"") != NULL) - { - if(debug) logg("Ignoring domain (cached)"); - continue; - } - - // Check if this is a PTR query - // if so: skip analysis of this log line - if(strstr(readbuffer,"in-addr.arpa") != NULL) + // Check query for invalid characters + if(!checkQuery(readbuffer, "cached")) continue; // Get dnsmasq's ID for this transaction @@ -777,17 +756,8 @@ void process_pihole_log(int file) // is this a "wildcard" line? else if(strstr(readbuffer," config ") != NULL && strstr(readbuffer," is ") != NULL) { - // Check if this domain names contains only printable characters - // if not: skip analysis of this log line - if(strstr(readbuffer,"") != NULL) - { - if(debug) logg("Ignoring domain (cached)"); - continue; - } - - // Check if this is a PTR query - // if so: skip analysis of this log line - if(strstr(readbuffer,"in-addr.arpa") != NULL) + // Check query for invalid characters + if(!checkQuery(readbuffer, "gravity.list")) continue; // Get dnsmasq's ID for this transaction @@ -851,17 +821,8 @@ void process_pihole_log(int file) // is this a "black.list" line? else if(strstr(readbuffer,"/black.list ") != NULL && strstr(readbuffer," is ") != NULL) { - // Check if this domain names contains only printable characters - // if not: skip analysis of this log line - if(strstr(readbuffer,"") != NULL) - { - if(debug) logg("Ignoring domain (cached)"); - continue; - } - - // Check if this is a PTR query - // if so: skip analysis of this log line - if(strstr(readbuffer,"in-addr.arpa") != NULL) + // Check query for invalid characters + if(!checkQuery(readbuffer, "black.list")) continue; // Get dnsmasq's ID for this transaction From 8035d9f5a4d81c96ad4f379fc2b3d27681aabdcd Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 22 Dec 2017 12:31:08 +0100 Subject: [PATCH 20/63] Save only complete queries into the database Signed-off-by: DL6ER --- database.c | 7 ++----- main.c | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/database.c b/database.c index 241fad97..a192e6b1 100644 --- a/database.c +++ b/database.c @@ -312,12 +312,9 @@ void save_to_DB(void) for(i = lastdbindex; i < counters.queries; i++) { validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__); - if(queries[i].timestamp <= lasttimestamp || queries[i].db == true) - { - // Already in database - // logg("Skipping %i",i); + if(queries[i].timestamp <= lasttimestamp || queries[i].db || !queries[i].complete) + // Already in database or not yet complete continue; - } // Memory checks validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__); diff --git a/main.c b/main.c index 025b37d0..ec4db0b3 100644 --- a/main.c +++ b/main.c @@ -150,7 +150,6 @@ int main (int argc, char* argv[]) { } } - logg("Shutting down..."); pthread_cancel(piholelogthread); pthread_cancel(socket_listenthread); From cdfa4d82d642c43b1e3e21fbbc18711f315d80f8 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 23 Dec 2017 11:59:41 +0100 Subject: [PATCH 21/63] Travis CI pulls on a tag basis, not by branch. Fix the returned branch if we find that the binary was build on "(no branch)" but is properly tagged. Signed-off-by: DL6ER --- args.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/args.c b/args.c index 3bb073fd..d09f38df 100644 --- a/args.c +++ b/args.c @@ -70,7 +70,7 @@ void parse_args(int argc, char* argv[]) if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "version") == 0) { - char version[] = GIT_VERSION; + const char * version = GIT_VERSION; // Check if version is of format vX.YY // '.' can never be part of a commit hash if(strstr(version, ".") != NULL) @@ -90,7 +90,15 @@ void parse_args(int argc, char* argv[]) if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "branch") == 0) { - printf("%s\n",GIT_BRANCH); + const char * branch = GIT_BRANCH; + const char * version = GIT_VERSION; + // Travis CI pulls on a tag basis, not by branch. + // Hence, it may happen that the master binary isn't aware of its branch. + // We check if this is the case and if there is a "vX.YY" like tag on the + // binary are print out branch "master" if we find that this is the case + if(strstr(branch, "(no branch)") != NULL && strstr(version, ".") != NULL) + branch = "master"; + printf("%s\n",branch); exit(EXIT_SUCCESS); } From 12a46e5ccfd2f846fe59e5e13b55d37427dfb4ce Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 23 Dec 2017 12:04:41 +0100 Subject: [PATCH 22/63] Apply the same idea in the telnet request Signed-off-by: DL6ER --- request.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/request.c b/request.c index 196a413a..f4814393 100644 --- a/request.c +++ b/request.c @@ -1038,11 +1038,19 @@ void getVersion(int *sock) { char server_message[SOCKETBUFFERLEN]; - char version[] = GIT_VERSION; + const char * version = GIT_VERSION; + const char * branch = GIT_BRANCH; + // Travis CI pulls on a tag basis, not by branch. + // Hence, it may happen that the master binary isn't aware of its branch. + // We check if this is the case and if there is a "vX.YY" like tag on the + // binary are print out branch "master" if we find that this is the case + if(strstr(branch, "(no branch)") != NULL && strstr(version, ".") != NULL) + branch = "master"; + if(strstr(version, ".") != NULL) - sprintf(server_message,"version %s\ntag %s\nbranch %s\ndate %s\n", GIT_VERSION, GIT_TAG, GIT_BRANCH, GIT_DATE); + sprintf(server_message,"version %s\ntag %s\nbranch %s\ndate %s\n", version, GIT_TAG, branch, GIT_DATE); else - sprintf(server_message,"version vDev-%s\ntag %s\nbranch %s\ndate %s\n", GIT_HASH, GIT_TAG, GIT_BRANCH, GIT_DATE); + sprintf(server_message,"version vDev-%s\ntag %s\nbranch %s\ndate %s\n", GIT_HASH, GIT_TAG, branch, GIT_DATE); swrite(server_message, *sock); if(debugclients) From 91047f97f1414763b5f1acf2b9215af86586e939 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 23 Dec 2017 21:54:40 +0100 Subject: [PATCH 23/63] Accept "*domain.tld" as wildcard audit entry Signed-off-by: DL6ER --- grep.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/grep.c b/grep.c index b862dd37..fa13f9c2 100644 --- a/grep.c +++ b/grep.c @@ -189,9 +189,24 @@ int countlineswith(const char* str, const char* fname) // Search through file // getline reads a string from the specified file up to either a newline character or EOF while(getline(&buffer, &size, fp) != -1) - if((strstr(buffer, str)) != NULL) + { + // Strip potential newline character at the end of line we just read + if(buffer[strlen(buffer)-1] == '\n') + buffer[strlen(buffer)-1] = '\0'; + + printf("Searching \"%s\" in \"%s\"\n",buffer,str); + // Search for exact match + if(strcmp(buffer, str) == 0) found++; + // If line starts with *, search for partial match + if(buffer[0] == '*') + { + if(strstr(str, buffer+1) != NULL) + found++; + } + } + // Free allocated memory if(buffer != NULL) { From a940e4089bf8dbf2343734fce991721a18bad940 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 23 Dec 2017 22:00:26 +0100 Subject: [PATCH 24/63] Use short circuit evolution to shorten statement Signed-off-by: DL6ER --- grep.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/grep.c b/grep.c index fa13f9c2..6ff4d1b3 100644 --- a/grep.c +++ b/grep.c @@ -199,12 +199,10 @@ int countlineswith(const char* str, const char* fname) if(strcmp(buffer, str) == 0) found++; - // If line starts with *, search for partial match - if(buffer[0] == '*') - { - if(strstr(str, buffer+1) != NULL) + // If line starts with *, search for partial match of + // needle "buffer+1" in haystack "str" + if(buffer[0] == '*' && strstr(str, buffer+1) != NULL) found++; - } } // Free allocated memory From fc942428c363278c7c80ae204387cbb5f32d8def Mon Sep 17 00:00:00 2001 From: Mcat12 Date: Sun, 24 Dec 2017 16:22:49 -0500 Subject: [PATCH 25/63] Add support for --help It's referenced in the usage, but was never actually added as an alias. Signed-off-by: Mcat12 --- args.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/args.c b/args.c index d09f38df..52385e02 100644 --- a/args.c +++ b/args.c @@ -131,8 +131,7 @@ void parse_args(int argc, char* argv[]) } // List of implemented arguments - if(strcmp(argv[i], "-h") == 0 || - strcmp(argv[i], "help") == 0) + if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "help") == 0 || strcmp(argv[i], "--help") == 0) { printf("pihole-FTL - The Pi-hole FTL engine\n\n"); printf("Usage: sudo service pihole-FTL \n"); From dac50b19a9d0c457f30f87094ac4503777a536ab Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 27 Dec 2017 00:20:25 +0100 Subject: [PATCH 26/63] Add parsing for "reply ... is ..." lines Signed-off-by: DL6ER --- FTL.h | 3 ++- parser.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/FTL.h b/FTL.h index 7284592f..5034091a 100644 --- a/FTL.h +++ b/FTL.h @@ -137,9 +137,10 @@ typedef struct { int forwardID; bool valid; bool db; - // the ID is a (signed) in dnsmasq, so no need for a long int here + // the ID is a (signed) int in dnsmasq, so no need for a long int here int id; bool complete; + unsigned char reply; int generation; } queriesDataStruct; diff --git a/parser.c b/parser.c index 5cf2d9b1..ed317b1e 100644 --- a/parser.c +++ b/parser.c @@ -538,6 +538,7 @@ void process_pihole_log(int file) queries[queryID].db = false; queries[queryID].id = dnsmasqID; queries[queryID].complete = false; + queries[queryID].reply = 0; queries[queryID].generation = loggeneration; // Increase DNS queries counter @@ -878,6 +879,42 @@ void process_pihole_log(int file) if(debug) logg("Detected restart of dnsmasq, increasing loggeneration to %i", loggeneration); } + // is this a "reply" line? + else if(strstr(readbuffer," reply ") != NULL && strstr(readbuffer," is ") != NULL) + { + // Check query for invalid characters + if(!checkQuery(readbuffer, "reply")) + continue; + + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; + + // Search for corresponding query indentified by dnsmasq's ID + bool found = false; + for(i=0; i Date: Wed, 27 Dec 2017 00:23:10 +0100 Subject: [PATCH 27/63] Remove debugging output Signed-off-by: DL6ER --- grep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/grep.c b/grep.c index 6ff4d1b3..41daf8a2 100644 --- a/grep.c +++ b/grep.c @@ -194,7 +194,6 @@ int countlineswith(const char* str, const char* fname) if(buffer[strlen(buffer)-1] == '\n') buffer[strlen(buffer)-1] = '\0'; - printf("Searching \"%s\" in \"%s\"\n",buffer,str); // Search for exact match if(strcmp(buffer, str) == 0) found++; From 7425c1d700b5bed2c02951dd4257ecc126521967 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 27 Dec 2017 00:23:37 +0100 Subject: [PATCH 28/63] Continue if exact match was found Signed-off-by: DL6ER --- grep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grep.c b/grep.c index 41daf8a2..9f197041 100644 --- a/grep.c +++ b/grep.c @@ -196,7 +196,10 @@ int countlineswith(const char* str, const char* fname) // Search for exact match if(strcmp(buffer, str) == 0) + { found++; + continue; + } // If line starts with *, search for partial match of // needle "buffer+1" in haystack "str" From bc3d1f1c2e8c836cdd31914998d5726500a0aea3 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 27 Dec 2017 00:30:43 +0100 Subject: [PATCH 29/63] Makes sure wildcard matching is unambigious Signed-off-by: DL6ER --- grep.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/grep.c b/grep.c index 9f197041..fb24b787 100644 --- a/grep.c +++ b/grep.c @@ -203,8 +203,20 @@ int countlineswith(const char* str, const char* fname) // If line starts with *, search for partial match of // needle "buffer+1" in haystack "str" - if(buffer[0] == '*' && strstr(str, buffer+1) != NULL) + if(buffer[0] == '*') + { + char * buf = strstr(str, buffer+1); + // The strstr() function finds the first occurrence of + // the substring buffer+1 in the string str. + // These functions return a pointer to the beginning of + // the located substring, or NULL if the substring is not + // found. Hence, we compare the length of the substring to + // the wildcard entry to determine if there is anything + // behind the wildcard. This avoids that given + // "*example.com" "example.com.xxxxx" would also match. + if(buf != NULL && strlen(buf) == strlen(str)) found++; + } } // Free allocated memory From 372dbca40a79cd62fca58ef549798385e70c6264 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 27 Dec 2017 00:35:38 +0100 Subject: [PATCH 30/63] Update comment and use correct string for strlen() Signed-off-by: DL6ER --- grep.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/grep.c b/grep.c index fb24b787..17e27fa4 100644 --- a/grep.c +++ b/grep.c @@ -187,7 +187,8 @@ int countlineswith(const char* str, const char* fname) } // Search through file - // getline reads a string from the specified file up to either a newline character or EOF + // getline reads a string from the specified file up to either a + // newline character or EOF while(getline(&buffer, &size, fp) != -1) { // Strip potential newline character at the end of line we just read @@ -211,10 +212,10 @@ int countlineswith(const char* str, const char* fname) // These functions return a pointer to the beginning of // the located substring, or NULL if the substring is not // found. Hence, we compare the length of the substring to - // the wildcard entry to determine if there is anything - // behind the wildcard. This avoids that given + // the wildcard entry to rule out the possiblity that + // there is anything behind the wildcard. This avoids that given // "*example.com" "example.com.xxxxx" would also match. - if(buf != NULL && strlen(buf) == strlen(str)) + if(buf != NULL && strlen(buf) == strlen(buffer+1)) found++; } } From 13b89c72afcabd043d02152d01af72f44adeeb8c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 27 Dec 2017 00:52:36 +0100 Subject: [PATCH 31/63] Save reply type in query struct (can be used somewhere later on) Signed-off-by: DL6ER --- parser.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/parser.c b/parser.c index ed317b1e..49f99061 100644 --- a/parser.c +++ b/parser.c @@ -911,8 +911,32 @@ void process_pihole_log(int file) continue; } - // Do something here - + // Iterate through possible values + if(strstr(readbuffer," is NODATA") != NULL) + { + // NODATA(-IPv6) + queries[i].reply = 1; + } + else if(strstr(readbuffer," is NXDOMAIN") != NULL) + { + // NXDOMAIN + queries[i].reply = 2; + } + else if(strstr(readbuffer," is ") != NULL) + { + // + queries[i].reply = 3; + } + else + { + // Valid IP + queries[i].reply = 4; + // const char * dest = strstr(readbuffer," is "); + // char * result; + // sscanf(dest, " is %ms", &result); + // printf("reply is IP: %s\n",result); + // free(result); + } } // Save file pointer position, because we might have to repeat From 7cbf68f0b643708d0118cf5c4be34196fd781a24 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 27 Dec 2017 13:24:44 +0100 Subject: [PATCH 32/63] Output correct counters in log_counter_info() (this has always been wrong but nobody noticed it) Signed-off-by: DL6ER --- log.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/log.c b/log.c index 8b3b44f3..23b8cc83 100644 --- a/log.c +++ b/log.c @@ -135,12 +135,13 @@ void log_counter_info(void) { logg(" -> Total DNS queries: %i", counters.queries); logg(" -> Cached DNS queries: %i", counters.cached); - logg(" -> Forwarded DNS queries: %i", counters.forwarded); + logg(" -> Forwarded DNS queries: %i", counters.forwardedqueries); logg(" -> Exactly blocked DNS queries: %i", counters.blocked); logg(" -> Wildcard blocked DNS queries: %i", counters.wildcardblocked); logg(" -> Unknown DNS queries: %i", counters.unknown); logg(" -> Unique domains: %i", counters.domains); logg(" -> Unique clients: %i", counters.clients); + logg(" -> Known forward destinations: %i", counters.forwarded); } void log_FTL_version(void) From 3346a84d1b277276b9db0fe699516e537d5f55a3 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 28 Dec 2017 20:43:47 +0100 Subject: [PATCH 33/63] Add global counters for types of replies (and properly GC them) Signed-off-by: DL6ER --- FTL.h | 4 ++++ gc.c | 22 ++++++++++++++++++++++ parser.c | 4 ++++ 3 files changed, 30 insertions(+) diff --git a/FTL.h b/FTL.h index 5034091a..0bd0b05f 100644 --- a/FTL.h +++ b/FTL.h @@ -110,6 +110,10 @@ typedef struct { int SRV; int wildcarddomains; int forwardedqueries; + int reply_NODATA; + int reply_NXDOMAIN; + int reply_CNAME; + int reply_IP; } countersStruct; typedef struct { diff --git a/gc.c b/gc.c index ecb4a400..7b19ca54 100644 --- a/gc.c +++ b/gc.c @@ -69,6 +69,28 @@ void *GC_thread(void *val) counters.forwardedqueries--; validate_access("forwarded", queries[i].forwardID, true, __LINE__, __FUNCTION__, __FILE__); forwarded[queries[i].forwardID].count--; + // Maybe we have to adjust total counters depending on the reply type + switch(queries[i].reply) + { + case 1: // NODATA(-IPv6) + counters.reply_NODATA--; + break; + + case 2: // NXDOMAIN + counters.reply_NXDOMAIN--; + break; + + case 3: // + counters.reply_CNAME--; + break; + + case 4: // valid IP + counters.reply_IP--; + break; + + default: // Incomplete query, do nothing + break; + } break; case 3: // Answered from local cache _or_ local config diff --git a/parser.c b/parser.c index 49f99061..fb662589 100644 --- a/parser.c +++ b/parser.c @@ -916,21 +916,25 @@ void process_pihole_log(int file) { // NODATA(-IPv6) queries[i].reply = 1; + counters.reply_NODATA++; } else if(strstr(readbuffer," is NXDOMAIN") != NULL) { // NXDOMAIN queries[i].reply = 2; + counters.reply_NXDOMAIN++; } else if(strstr(readbuffer," is ") != NULL) { // queries[i].reply = 3; + counters.reply_CNAME++; } else { // Valid IP queries[i].reply = 4; + counters.reply_IP++; // const char * dest = strstr(readbuffer," is "); // char * result; // sscanf(dest, " is %ms", &result); From dbc9457708b62c2e05b4f093005349ca5250397b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 28 Dec 2017 20:48:29 +0100 Subject: [PATCH 34/63] Worked on review comments Signed-off-by: DL6ER --- parser.c | 12 ++++++------ request.c | 7 ------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/parser.c b/parser.c index fb662589..8d416f39 100644 --- a/parser.c +++ b/parser.c @@ -589,7 +589,7 @@ void process_pihole_log(int file) if(dnsmasqID < 0) continue; - // Save forwardID in corresponding query indentified by dnsmasq's ID + // Save status in corresponding query indentified by dnsmasq's ID bool found = false; for(i=0; i Date: Thu, 28 Dec 2017 21:02:10 +0100 Subject: [PATCH 35/63] Compare age of query against current time to decide if we should give a query more time to get completed Signed-off-by: DL6ER --- database.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/database.c b/database.c index a192e6b1..6179affb 100644 --- a/database.c +++ b/database.c @@ -309,13 +309,21 @@ void save_to_DB(void) return; } + int currenttimestamp = time(NULL); for(i = lastdbindex; i < counters.queries; i++) { validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__); - if(queries[i].timestamp <= lasttimestamp || queries[i].db || !queries[i].complete) + if(queries[i].timestamp <= lasttimestamp || queries[i].db) // Already in database or not yet complete continue; + if(!queries[i].complete && queries[i].timestamp > currenttimestamp-2) + { + // Break if a brand new query (age < 2 seconds) is not yet completed + // giving it a chance to be stored next time + break; + } + // Memory checks validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__); validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__); From f026a885dda1cde855c8a3069ebeeb0723808acf Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 28 Dec 2017 23:46:41 +0100 Subject: [PATCH 36/63] Remove two int we are not using at all Signed-off-by: DL6ER --- FTL.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/FTL.h b/FTL.h index 0bd0b05f..ce6075b2 100644 --- a/FTL.h +++ b/FTL.h @@ -106,8 +106,6 @@ typedef struct { int overTime; int IPv4; int IPv6; - int PTR; - int SRV; int wildcarddomains; int forwardedqueries; int reply_NODATA; From 0b1175ec60b94e44b301c761c98bde80f9e16e29 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 29 Dec 2017 00:51:07 +0100 Subject: [PATCH 37/63] Skip this entry if we already found th reply for this forwarded query before Signed-off-by: DL6ER --- parser.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parser.c b/parser.c index 8d416f39..062a9772 100644 --- a/parser.c +++ b/parser.c @@ -911,6 +911,12 @@ void process_pihole_log(int file) continue; } + if(queries[i].reply != 0) + { + // Skip this entry if we already found the first result for this query before + continue; + } + // Iterate through possible values if(strstr(readbuffer," is NODATA") != NULL) { From d0968c68aadf8d4af691ae0d4f175a59a0a713ba Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 30 Dec 2017 22:34:20 +0100 Subject: [PATCH 38/63] Close database after initial check so we dont keep it open forever and hence lock it. Signed-off-by: DL6ER --- database.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/database.c b/database.c index 6179affb..25fdead8 100644 --- a/database.c +++ b/database.c @@ -169,6 +169,9 @@ void db_init(void) } } + // Close database to prevent having it opened all time + sqlite3_close(db); + if (pthread_mutex_init(&dblock, NULL) != 0) { logg("FATAL: DB mutex init failed\n"); From 90cf01bbc52e7ebb994cd34577bcefbf4d9550c1 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 00:54:21 +0100 Subject: [PATCH 39/63] Have to finalize all statements before sqlite3_close() can succeed. Also print some error message in the future if closeing the database failed. Signed-off-by: DL6ER --- database.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/database.c b/database.c index 25fdead8..f61c4a60 100644 --- a/database.c +++ b/database.c @@ -36,7 +36,12 @@ void check_database(int rc) void dbclose(void) { - sqlite3_close(db); + int rc = sqlite3_close(db); + // Report any error + if( rc ) + logg("dbclose() - SQL error (%i): %s", rc, sqlite3_errmsg(db)); + + // Unlock mutex on the database pthread_mutex_unlock(&dblock); } @@ -392,9 +397,9 @@ void save_to_DB(void) } // Finish prepared statement - ret = dbquery("END TRANSACTION"); - if(!ret){ dbclose(); return; } - sqlite3_finalize(stmt); + dbquery("END TRANSACTION"); + ret = sqlite3_finalize(stmt); + if(ret != SQLITE_OK){ dbclose(); return; } // Store index for next loop interation round and update last time stamp // in the database only if all queries have been saved successfully From 0aad3533e2f72aa392f2b536e22818817d5c2ad5 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 01:13:10 +0100 Subject: [PATCH 40/63] Check return values of both dbquery() and sqlite3_finalize() Signed-off-by: DL6ER --- database.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/database.c b/database.c index f61c4a60..5f9edc15 100644 --- a/database.c +++ b/database.c @@ -397,9 +397,9 @@ void save_to_DB(void) } // Finish prepared statement - dbquery("END TRANSACTION"); - ret = sqlite3_finalize(stmt); - if(ret != SQLITE_OK){ dbclose(); return; } + ret = dbquery("END TRANSACTION"); + int ret2 = sqlite3_finalize(stmt); + if(!ret || ret2 != SQLITE_OK){ dbclose(); return; } // Store index for next loop interation round and update last time stamp // in the database only if all queries have been saved successfully From 530a894bc53f076b17220da5430c425f1048413b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 15:13:30 +0100 Subject: [PATCH 41/63] Parse "validation" log lines Signed-off-by: DL6ER --- FTL.h | 1 + parser.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/FTL.h b/FTL.h index 0bd0b05f..fb869943 100644 --- a/FTL.h +++ b/FTL.h @@ -146,6 +146,7 @@ typedef struct { bool complete; unsigned char reply; int generation; + unsigned char dnssec; } queriesDataStruct; typedef struct { diff --git a/parser.c b/parser.c index 8d416f39..bcf82e78 100644 --- a/parser.c +++ b/parser.c @@ -540,6 +540,7 @@ void process_pihole_log(int file) queries[queryID].complete = false; queries[queryID].reply = 0; queries[queryID].generation = loggeneration; + queries[queryID].dnssec = 0; // Increase DNS queries counter counters.queries++; @@ -942,6 +943,59 @@ void process_pihole_log(int file) // free(result); } } + // is this a "validaton" line? -- DNSSEC + else if(strstr(readbuffer," validation ") != NULL && strstr(readbuffer," is ") != NULL) + { + // Check query for invalid characters + if(!checkQuery(readbuffer, "DNSSEC")) + continue; + + // Get dnsmasq's ID for this transaction + int dnsmasqID = getID(readbuffer); + // Skip invalid lines + if(dnsmasqID < 0) + continue; + + // Search for corresponding query indentified by dnsmasq's ID + bool found = false; + for(i=0; i Date: Sun, 31 Dec 2017 15:21:09 +0100 Subject: [PATCH 42/63] Return DNSSEC result in getAllQueries result Signed-off-by: DL6ER --- request.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/request.c b/request.c index 52d3e4ec..593ad411 100644 --- a/request.c +++ b/request.c @@ -811,13 +811,13 @@ void getAllQueries(char *client_message, int *sock) if(!privacymode) { if(strlen(clients[queries[i].clientID].name) > 0) - sprintf(server_message,"%i %s %s %s %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status); + sprintf(server_message,"%i %s %s %s %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status,queries[i].dnssec); else - sprintf(server_message,"%i %s %s %s %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status); + sprintf(server_message,"%i %s %s %s %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status,queries[i].dnssec); } else { - sprintf(server_message,"%i %s %s hidden %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,queries[i].status); + sprintf(server_message,"%i %s %s hidden %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,queries[i].status,queries[i].dnssec); } swrite(server_message, *sock); } From c9ee9f552ad5e36fe0063ddbe1315552030ae258 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 16:50:58 +0100 Subject: [PATCH 43/63] Store DNSSEC result per domain not per query Signed-off-by: DL6ER --- FTL.h | 2 +- parser.c | 12 +++++++----- request.c | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/FTL.h b/FTL.h index fb869943..23768a25 100644 --- a/FTL.h +++ b/FTL.h @@ -146,7 +146,6 @@ typedef struct { bool complete; unsigned char reply; int generation; - unsigned char dnssec; } queriesDataStruct; typedef struct { @@ -169,6 +168,7 @@ typedef struct { int blockedcount; char *domain; bool wildcard; + unsigned char dnssec; } domainsDataStruct; typedef struct { diff --git a/parser.c b/parser.c index bcf82e78..b38d5c8c 100644 --- a/parser.c +++ b/parser.c @@ -484,6 +484,8 @@ void process_pihole_log(int file) // Store domain name domains[domainID].domain = strdup(domain); memory.domainnames += (strlen(domain) + 1) * sizeof(char); + // Store DNSSEC result for this domain + domains[domainID].dnssec = 0; // Increase counter by one counters.domains++; } @@ -540,7 +542,6 @@ void process_pihole_log(int file) queries[queryID].complete = false; queries[queryID].reply = 0; queries[queryID].generation = loggeneration; - queries[queryID].dnssec = 0; // Increase DNS queries counter counters.queries++; @@ -975,23 +976,24 @@ void process_pihole_log(int file) continue; } + validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__); // Iterate through possible values if(strstr(readbuffer,"is SECURE") != NULL) { - queries[i].dnssec = 1; + domains[queries[i].domainID].dnssec = 1; } else if(strstr(readbuffer,"is INSECURE") != NULL) { - queries[i].dnssec = 2; + domains[queries[i].domainID].dnssec = 2; } else if(strstr(readbuffer,"is BOGUS") != NULL) { - queries[i].dnssec = 3; + domains[queries[i].domainID].dnssec = 3; } else { // Unknown - queries[i].dnssec = 4; + domains[queries[i].domainID].dnssec = 4; if(debug) logg("Unknown DNSSEC reply: %i\n\"%s\"",dnsmasqID,readbuffer); } } diff --git a/request.c b/request.c index 593ad411..71cb0550 100644 --- a/request.c +++ b/request.c @@ -811,13 +811,13 @@ void getAllQueries(char *client_message, int *sock) if(!privacymode) { if(strlen(clients[queries[i].clientID].name) > 0) - sprintf(server_message,"%i %s %s %s %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status,queries[i].dnssec); + sprintf(server_message,"%i %s %s %s %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].name,queries[i].status,domains[queries[i].domainID].dnssec); else - sprintf(server_message,"%i %s %s %s %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status,queries[i].dnssec); + sprintf(server_message,"%i %s %s %s %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,clients[queries[i].clientID].ip,queries[i].status,domains[queries[i].domainID].dnssec); } else { - sprintf(server_message,"%i %s %s hidden %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,queries[i].status,queries[i].dnssec); + sprintf(server_message,"%i %s %s hidden %i %i\n",queries[i].timestamp,type,domains[queries[i].domainID].domain,queries[i].status,domains[queries[i].domainID].dnssec); } swrite(server_message, *sock); } From 0c4cfce780be564ab77ad584a5bd4fb6fe2d5be8 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 17:04:11 +0100 Subject: [PATCH 44/63] Use enum for DNS states Signed-off-by: DL6ER --- FTL.h | 1 + parser.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/FTL.h b/FTL.h index 23768a25..cb05aca6 100644 --- a/FTL.h +++ b/FTL.h @@ -198,6 +198,7 @@ typedef struct { enum { QUERIES, FORWARDED, CLIENTS, DOMAINS, OVERTIME, WILDCARD }; enum { SOCKET }; +enum { DNSSEC_UNSPECIFIED, DNSSEC_SECURE, DNSSEC_INSECURE, DNSSEC_BOGUS, DNSSEC_UNKNOWN }; logFileNamesStruct files; FTLFileNamesStruct FTLfiles; diff --git a/parser.c b/parser.c index b38d5c8c..421a4592 100644 --- a/parser.c +++ b/parser.c @@ -485,7 +485,7 @@ void process_pihole_log(int file) domains[domainID].domain = strdup(domain); memory.domainnames += (strlen(domain) + 1) * sizeof(char); // Store DNSSEC result for this domain - domains[domainID].dnssec = 0; + domains[domainID].dnssec = DNSSEC_UNSPECIFIED; // Increase counter by one counters.domains++; } @@ -980,20 +980,20 @@ void process_pihole_log(int file) // Iterate through possible values if(strstr(readbuffer,"is SECURE") != NULL) { - domains[queries[i].domainID].dnssec = 1; + domains[queries[i].domainID].dnssec = DNSSEC_SECURE; } else if(strstr(readbuffer,"is INSECURE") != NULL) { - domains[queries[i].domainID].dnssec = 2; + domains[queries[i].domainID].dnssec = DNSSEC_INSECURE; } else if(strstr(readbuffer,"is BOGUS") != NULL) { - domains[queries[i].domainID].dnssec = 3; + domains[queries[i].domainID].dnssec = DNSSEC_BOGUS; } else { // Unknown - domains[queries[i].domainID].dnssec = 4; + domains[queries[i].domainID].dnssec = DNSSEC_UNKNOWN; if(debug) logg("Unknown DNSSEC reply: %i\n\"%s\"",dnsmasqID,readbuffer); } } From 804c2d9fd3bf37ef5d1fc3f3eb281e862ade2740 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 17:32:45 +0100 Subject: [PATCH 45/63] Add state ABANDONED which is very similar to BOGUS Signed-off-by: DL6ER --- FTL.h | 2 +- parser.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/FTL.h b/FTL.h index cb05aca6..245aed87 100644 --- a/FTL.h +++ b/FTL.h @@ -198,7 +198,7 @@ typedef struct { enum { QUERIES, FORWARDED, CLIENTS, DOMAINS, OVERTIME, WILDCARD }; enum { SOCKET }; -enum { DNSSEC_UNSPECIFIED, DNSSEC_SECURE, DNSSEC_INSECURE, DNSSEC_BOGUS, DNSSEC_UNKNOWN }; +enum { DNSSEC_UNSPECIFIED, DNSSEC_SECURE, DNSSEC_INSECURE, DNSSEC_BOGUS, DNSSEC_ABANDONED, DNSSEC_UNKNOWN }; logFileNamesStruct files; FTLFileNamesStruct FTLfiles; diff --git a/parser.c b/parser.c index 421a4592..62006511 100644 --- a/parser.c +++ b/parser.c @@ -990,6 +990,10 @@ void process_pihole_log(int file) { domains[queries[i].domainID].dnssec = DNSSEC_BOGUS; } + else if(strstr(readbuffer,"is ABANDONED") != NULL) + { + domains[queries[i].domainID].dnssec = DNSSEC_ABANDONED; + } else { // Unknown From e4cbe417a1d5c8aede78f5cf35c59e2342fcf9cf Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 22:25:27 +0100 Subject: [PATCH 46/63] Rename existing telnet socket functions to contain "telnet" in their names to avoid confusion when adding Unix sockets Signed-off-by: DL6ER --- Makefile | 2 +- main.c | 10 +++++----- routines.h | 4 ++-- socket.c => telnet.c | 22 +++++++++++----------- 4 files changed, 19 insertions(+), 19 deletions(-) rename socket.c => telnet.c (93%) diff --git a/Makefile b/Makefile index 5f38b5b7..8ea6d95b 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ # Please see LICENSE file for your rights under this license. DEPS = FTL.h routines.h version.h -OBJ = main.o structs.o log.o daemon.o parser.o signals.o socket.o request.o grep.o setupVars.o args.o flush.o threads.o gc.o config.o database.o +OBJ = main.o structs.o log.o daemon.o parser.o signals.o telnet.o request.o grep.o setupVars.o args.o flush.o threads.o gc.o config.o database.o # Get git commit version and date GIT_BRANCH := $(shell git branch | sed -n 's/^\* //p') diff --git a/main.c b/main.c index ec4db0b3..81767569 100644 --- a/main.c +++ b/main.c @@ -70,10 +70,10 @@ int main (int argc, char* argv[]) { killed = 1; } - pthread_t socket_listenthread; - if(pthread_create( &socket_listenthread, &attr, socket_listenting_thread, NULL ) != 0) + pthread_t telnet_listenthread; + if(pthread_create( &telnet_listenthread, &attr, telnet_listenting_thread, NULL ) != 0) { - logg("Unable to open socket listening thread. Exiting..."); + logg("Unable to open telnet listening thread. Exiting..."); killed = 1; } @@ -152,8 +152,8 @@ int main (int argc, char* argv[]) { logg("Shutting down..."); pthread_cancel(piholelogthread); - pthread_cancel(socket_listenthread); - close_socket(SOCKET); + pthread_cancel(telnet_listenthread); + close_telnet_socket(SOCKET); removepid(); logg("########## FTL terminated! ##########"); return 1; diff --git a/routines.h b/routines.h index 87489877..6b1a17f6 100644 --- a/routines.h +++ b/routines.h @@ -38,10 +38,10 @@ void pihole_log_flushed(bool message); void memory_check(int which); -void close_socket(char type); +void close_telnet_socket(char type); void seom(char server_message[], int sock); void swrite(char server_message[], int sock); -void *socket_listenting_thread(void *args); +void *telnet_listenting_thread(void *args); void process_request(char *client_message, int *sock); bool command(char *client_message, const char* cmd); diff --git a/socket.c b/telnet.c similarity index 93% rename from socket.c rename to telnet.c index 9a88c8c0..7073ba9c 100644 --- a/socket.c +++ b/telnet.c @@ -12,7 +12,7 @@ // The backlog argument defines the maximum length // to which the queue of pending connections for -// socketfd may grow. If a connection request arrives +// telnetfd may grow. If a connection request arrives // when the queue is full, the client may receive an // error with an indication of ECONNREFUSED or, if // the underlying protocol supports retransmission, @@ -21,7 +21,7 @@ #define BACKLOG 5 // File descriptors -int socketfd; +int telnetfd; void saveport(int port) { @@ -38,7 +38,7 @@ void saveport(int port) } } -void bind_to_port(char type, int *socketdescriptor) +void bind_to_telnet_port(char type, int *socketdescriptor) { *socketdescriptor = socket(AF_INET, SOCK_STREAM, 0); @@ -144,7 +144,7 @@ void swrite(char server_message[SOCKETBUFFERLEN], int sock) logg("WARNING: Socket write returned error code %i", errno); } -int listener(int sockfd) +int telnet_listener(int sockfd) { struct sockaddr_in cli_addr; // set all values in the buffer to zero @@ -158,14 +158,14 @@ int listener(int sockfd) return clientsocket; } -void close_socket(char type) +void close_telnet_socket(char type) { switch(type) { case SOCKET: removeport(); // Using global variable here - close(socketfd); + close(telnetfd); break; default: logg("Incompatible socket type %i, cannot close",(int)type); @@ -174,7 +174,7 @@ void close_socket(char type) } } -void *socket_connection_handler_thread(void *socket_desc) +void *telnet_connection_handler_thread(void *socket_desc) { //Get the socket descriptor int sock = *(int*)socket_desc; @@ -231,7 +231,7 @@ void *socket_connection_handler_thread(void *socket_desc) return 0; } -void *socket_listenting_thread(void *args) +void *telnet_listenting_thread(void *args) { int *newsock; // We will use the attributes object later to start all threads in detached mode @@ -246,13 +246,13 @@ void *socket_listenting_thread(void *args) prctl(PR_SET_NAME,"socket listener",0,0,0); // Initialize sockets only after initial log parsing in listenting_thread - bind_to_port(SOCKET, &socketfd); + bind_to_telnet_port(SOCKET, &telnetfd); // Listen as long as FTL is not killed while(!killed) { // Look for new clients that want to connect - int csck = listener(socketfd); + int csck = telnet_listener(telnetfd); // Allocate memory used to transport client socket ID to client listening thread newsock = calloc(1,sizeof(int)); @@ -260,7 +260,7 @@ void *socket_listenting_thread(void *args) pthread_t socket_connection_thread; // Create a new thread - if(pthread_create( &socket_connection_thread, &attr, socket_connection_handler_thread, (void*) newsock ) != 0) + if(pthread_create( &socket_connection_thread, &attr, telnet_connection_handler_thread, (void*) newsock ) != 0) { // Log the error code description logg("WARNING: Unable to open clients processing thread, error: %s", strerror(errno)); From 3c39cb1fd234aa59e406dfce954a09f9a320b438 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 22:44:08 +0100 Subject: [PATCH 47/63] Added Unix socket - it is listening! Signed-off-by: DL6ER --- FTL.h | 4 +++ Makefile | 2 +- main.c | 7 ++++ routines.h | 1 + telnet.c => socket.c | 81 ++++++++++++++++++++++++++++++++++++++++++-- structs.c | 3 +- 6 files changed, 93 insertions(+), 5 deletions(-) rename telnet.c => socket.c (75%) diff --git a/FTL.h b/FTL.h index a2ee5d45..8c5be723 100644 --- a/FTL.h +++ b/FTL.h @@ -40,6 +40,9 @@ #include "sqlite3.h" // tolower() #include +// Unix socket +#include + #include "routines.h" @@ -73,6 +76,7 @@ typedef struct { const char* pid; const char* port; char* db; + const char* socketfile; } FTLFileNamesStruct; typedef struct { diff --git a/Makefile b/Makefile index 8ea6d95b..5f38b5b7 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ # Please see LICENSE file for your rights under this license. DEPS = FTL.h routines.h version.h -OBJ = main.o structs.o log.o daemon.o parser.o signals.o telnet.o request.o grep.o setupVars.o args.o flush.o threads.o gc.o config.o database.o +OBJ = main.o structs.o log.o daemon.o parser.o signals.o socket.o request.o grep.o setupVars.o args.o flush.o threads.o gc.o config.o database.o # Get git commit version and date GIT_BRANCH := $(shell git branch | sed -n 's/^\* //p') diff --git a/main.c b/main.c index 81767569..45bf77d0 100644 --- a/main.c +++ b/main.c @@ -77,6 +77,13 @@ int main (int argc, char* argv[]) { killed = 1; } + pthread_t socket_listenthread; + if(pthread_create( &socket_listenthread, &attr, socket_listenting_thread, NULL ) != 0) + { + logg("Unable to open Unix socket listening thread. Exiting..."); + killed = 1; + } + while(!killed) { sleepms(100); diff --git a/routines.h b/routines.h index 6b1a17f6..d8807993 100644 --- a/routines.h +++ b/routines.h @@ -42,6 +42,7 @@ void close_telnet_socket(char type); void seom(char server_message[], int sock); void swrite(char server_message[], int sock); void *telnet_listenting_thread(void *args); +void *socket_listenting_thread(void *args); void process_request(char *client_message, int *sock); bool command(char *client_message, const char* cmd); diff --git a/telnet.c b/socket.c similarity index 75% rename from telnet.c rename to socket.c index 7073ba9c..ef5f1755 100644 --- a/telnet.c +++ b/socket.c @@ -21,7 +21,7 @@ #define BACKLOG 5 // File descriptors -int telnetfd; +int telnetfd, socketfd; void saveport(int port) { @@ -44,7 +44,7 @@ void bind_to_telnet_port(char type, int *socketdescriptor) if(*socketdescriptor < 0) { - logg("Error opening socket"); + logg("Error opening telnet socket"); exit(EXIT_FAILURE); } @@ -120,6 +120,43 @@ void bind_to_telnet_port(char type, int *socketdescriptor) logg("Listening on port %i for incoming connections", port); } + +void bind_to_unix_socket(int *socketdescriptor) +{ + *socketdescriptor = socket(AF_LOCAL, SOCK_STREAM, 0); + + if(*socketdescriptor < 0) + { + logg("Error opening unix socket"); + exit(EXIT_FAILURE); + } + + // Make sure unix socket file handle does not exist, if it exists, remove it + unlink(FTLfiles.socketfile); + + struct sockaddr_un address; + address.sun_family = AF_LOCAL; + strcpy(address.sun_path, FTLfiles.socketfile); + + // Bild to Unix socket handle + errno = 0; + if(bind(*socketdescriptor, (struct sockaddr *) &address, sizeof (address)) != 0) { + logg("Error on binding on unix socket %s", FTLfiles.socketfile); + logg("Reason: %s (%i)", strerror(errno), errno); + exit(EXIT_FAILURE); + } + + // The listen system call allows the process to listen on the Unix socket for connections + if(listen(*socketdescriptor, BACKLOG) == -1) + { + logg("Error on listening"); + exit(EXIT_FAILURE); + } + + logg("Listening on Unix socket"); +} + + // Called from main() at graceful shutdown void removeport(void) { @@ -243,7 +280,7 @@ void *telnet_listenting_thread(void *args) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // Set thread name - prctl(PR_SET_NAME,"socket listener",0,0,0); + prctl(PR_SET_NAME,"telnet listener",0,0,0); // Initialize sockets only after initial log parsing in listenting_thread bind_to_telnet_port(SOCKET, &telnetfd); @@ -268,3 +305,41 @@ void *telnet_listenting_thread(void *args) } return 0; } + +void *socket_listenting_thread(void *args) +{ + int *newsock; + // We will use the attributes object later to start all threads in detached mode + pthread_attr_t attr; + // Initialize thread attributes object with default attribute values + pthread_attr_init(&attr); + // When a detached thread terminates, its resources are automatically released back to + // the system without the need for another thread to join with the terminated thread + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + // Set thread name + prctl(PR_SET_NAME,"socket listener",0,0,0); + + // Initialize sockets only after initial log parsing in listenting_thread + bind_to_unix_socket(&socketfd); + + // Listen as long as FTL is not killed + while(!killed) + { + // Look for new clients that want to connect + int csck = telnet_listener(socketfd); + + // Allocate memory used to transport client socket ID to client listening thread + newsock = calloc(1,sizeof(int)); + *newsock = csck; + + pthread_t socket_connection_thread; + // Create a new thread + if(pthread_create( &socket_connection_thread, &attr, telnet_connection_handler_thread, (void*) newsock ) != 0) + { + // Log the error code description + logg("WARNING: Unable to open clients processing thread, error: %s", strerror(errno)); + } + } + return 0; +} diff --git a/structs.c b/structs.c index 2e7abcd8..dd5fe217 100644 --- a/structs.c +++ b/structs.c @@ -15,7 +15,8 @@ FTLFileNamesStruct FTLfiles = { "/var/log/pihole-FTL.log", "/var/run/pihole-FTL.pid", "/var/run/pihole-FTL.port", - NULL + NULL, + "/var/run/pihole/FTL.sock" }; logFileNamesStruct files = { From 0387304b4cfdbb8f9371c0f42c64716269bb4094 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 22:49:14 +0100 Subject: [PATCH 48/63] Answer Unix socket requests the exact same way we do already for the telnet interface Signed-off-by: DL6ER --- socket.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/socket.c b/socket.c index ef5f1755..5c7a4645 100644 --- a/socket.c +++ b/socket.c @@ -221,7 +221,7 @@ void *telnet_connection_handler_thread(void *socket_desc) // Set thread name char threadname[16]; - sprintf(threadname,"client-%i",sockID); + sprintf(threadname,"telnet-%i",sockID); prctl(PR_SET_NAME,threadname,0,0,0); //Receive from client ssize_t n; @@ -254,11 +254,67 @@ void *telnet_connection_handler_thread(void *socket_desc) else if(n == -1) { if(debugclients) - logg("Client connection interrupted, ID: %i", sockID); + logg("Telnet connection interrupted, ID: %i", sockID); } } if(debugclients) - logg("Client disconnected, ID: %i", sockID); + logg("Telnet disconnected, ID: %i", sockID); + + //Free the socket pointer + if(sock != 0) + close(sock); + free(socket_desc); + + return 0; +} + + +void *socket_connection_handler_thread(void *socket_desc) +{ + //Get the socket descriptor + int sock = *(int*)socket_desc; + // Store copy only for displaying the debug messages + int sockID = sock; + char client_message[SOCKETBUFFERLEN] = ""; + + // Set thread name + char threadname[16]; + sprintf(threadname,"socket-%i",sockID); + prctl(PR_SET_NAME,threadname,0,0,0); + //Receive from client + ssize_t n; + while((n = recv(sock,client_message,SOCKETBUFFERLEN-1, 0))) + { + if (n > 0) + { + char *message = calloc(strlen(client_message)+1,sizeof(char)); + strcpy(message, client_message); + + // Clear client message receive buffer + memset(client_message, 0, sizeof client_message); + + // Lock FTL data structure, since it is likely that it will be changed here + // Requests should not be processed/answered when data is about to change + enable_thread_lock(threadname); + + process_request(message, &sock); + free(message); + + // Release thread lock + disable_thread_lock(threadname); + + if(sock == 0) + { + // Socket connection interrupted by seding EOT or ">quit" + break; + } + } + else if(n == -1) + { + if(debug) logg("Socket connection interrupted, ID: %i", sockID); + } + } + if(debug) logg("Socket disconnected, ID: %i", sockID); //Free the socket pointer if(sock != 0) @@ -295,12 +351,12 @@ void *telnet_listenting_thread(void *args) newsock = calloc(1,sizeof(int)); *newsock = csck; - pthread_t socket_connection_thread; + pthread_t telnet_connection_thread; // Create a new thread - if(pthread_create( &socket_connection_thread, &attr, telnet_connection_handler_thread, (void*) newsock ) != 0) + if(pthread_create( &telnet_connection_thread, &attr, telnet_connection_handler_thread, (void*) newsock ) != 0) { // Log the error code description - logg("WARNING: Unable to open clients processing thread, error: %s", strerror(errno)); + logg("WARNING: Unable to open telnet processing thread, error: %s", strerror(errno)); } } return 0; @@ -335,10 +391,10 @@ void *socket_listenting_thread(void *args) pthread_t socket_connection_thread; // Create a new thread - if(pthread_create( &socket_connection_thread, &attr, telnet_connection_handler_thread, (void*) newsock ) != 0) + if(pthread_create( &socket_connection_thread, &attr, socket_connection_handler_thread, (void*) newsock ) != 0) { // Log the error code description - logg("WARNING: Unable to open clients processing thread, error: %s", strerror(errno)); + logg("WARNING: Unable to open socket processing thread, error: %s", strerror(errno)); } } return 0; From 300de477523ca837305df56782e2839b0807a5b1 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 23:00:55 +0100 Subject: [PATCH 49/63] Add simple Unix socket client test program Signed-off-by: DL6ER --- socket_client.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 socket_client.c diff --git a/socket_client.c b/socket_client.c new file mode 100644 index 00000000..67ad38b3 --- /dev/null +++ b/socket_client.c @@ -0,0 +1,70 @@ +/* uds_client.c */ +#include +/* Pi-hole: A black hole for Internet advertisements +* (c) 2017 Pi-hole, LLC (https://pi-hole.net) +* Network-wide ad blocking via your own hardware. +* +* FTL Engine +* Unix socket connection test program +* +* This file is copyright under the latest version of the EUPL. +* Please see LICENSE file for your rights under this license. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#define BUF 1024 +#define UDS_FILE "/var/run/pihole/FTL.sock" + +int main (int argc, char **argv) { + int socketfd; + char *buffer = malloc (BUF); + struct sockaddr_un address; + int size, ret; + + socketfd = socket(PF_LOCAL, SOCK_STREAM, 0); + if(socket <= 0) + { + printf("Error creating socket!\n"); + exit(EXIT_FAILURE); + } + printf ("Socket created\n"); + + address.sun_family = AF_LOCAL; + strcpy(address.sun_path, UDS_FILE); + ret = connect(socketfd, (struct sockaddr *) &address, sizeof (address)); + if (ret != 0) + { + printf("Error establishing connection!\n"); + exit(EXIT_FAILURE); + } + printf("Connection established\n"); + + sprintf(buffer, ">stats"); + send(socketfd, buffer, strlen (buffer), 0); + + // Receive message + size = recv(socketfd, buffer, BUF-1, 0); + + while (strstr(buffer, "--EOM--") != 0) + { + // Zero-terminate incoming message + if(size > 0) + buffer[size] = '\0'; + + printf("Message received: \"%s\"\n", buffer); + + // Receive message + size = recv(socketfd, buffer, BUF-1, 0); + } + + printf("Message received: \"%s\"\n", buffer); + + close (socketfd); + return EXIT_SUCCESS; + } From 3086d1b40d91305f55230e3de4ecc35d8a69231c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 23:02:34 +0100 Subject: [PATCH 50/63] Save socket file in home folder on Travis Signed-off-by: DL6ER --- args.c | 1 + 1 file changed, 1 insertion(+) diff --git a/args.c b/args.c index 52385e02..03c2562f 100644 --- a/args.c +++ b/args.c @@ -126,6 +126,7 @@ void parse_args(int argc, char* argv[]) FTLfiles.log = "pihole-FTL.log"; // FTLfiles.db will be set to "pihole-FTL.db" via config file on Travis FTLfiles.conf = "pihole-FTL.conf"; + FTLfiles.socketfile = "pihole-FTL.sock"; files.log = "pihole.log"; ok = true; } From eb431d1bd04d1c0fb8d3e410c46768e5187eeb5d Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 31 Dec 2017 23:37:35 +0100 Subject: [PATCH 51/63] Finish socket client test program Signed-off-by: DL6ER --- socket_client.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/socket_client.c b/socket_client.c index 67ad38b3..1a571272 100644 --- a/socket_client.c +++ b/socket_client.c @@ -50,17 +50,21 @@ int main (int argc, char **argv) { // Receive message size = recv(socketfd, buffer, BUF-1, 0); + // Zero-terminate incoming message + if(size > 0) + buffer[size] = '\0'; - while (strstr(buffer, "--EOM--") != 0) + while (strstr(buffer, "--EOM--") == NULL) { - // Zero-terminate incoming message - if(size > 0) - buffer[size] = '\0'; printf("Message received: \"%s\"\n", buffer); // Receive message size = recv(socketfd, buffer, BUF-1, 0); + + // Zero-terminate incoming message + if(size > 0) + buffer[size] = '\0'; } printf("Message received: \"%s\"\n", buffer); From 1f7dbaa403bb328d99ba93cd63e0227000575f76 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 00:56:39 +0100 Subject: [PATCH 52/63] :codacy: Signed-off-by: DL6ER --- socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/socket.c b/socket.c index 5c7a4645..d210616b 100644 --- a/socket.c +++ b/socket.c @@ -326,7 +326,6 @@ void *socket_connection_handler_thread(void *socket_desc) void *telnet_listenting_thread(void *args) { - int *newsock; // We will use the attributes object later to start all threads in detached mode pthread_attr_t attr; // Initialize thread attributes object with default attribute values @@ -348,6 +347,7 @@ void *telnet_listenting_thread(void *args) int csck = telnet_listener(telnetfd); // Allocate memory used to transport client socket ID to client listening thread + int *newsock; newsock = calloc(1,sizeof(int)); *newsock = csck; @@ -364,7 +364,6 @@ void *telnet_listenting_thread(void *args) void *socket_listenting_thread(void *args) { - int *newsock; // We will use the attributes object later to start all threads in detached mode pthread_attr_t attr; // Initialize thread attributes object with default attribute values @@ -386,6 +385,7 @@ void *socket_listenting_thread(void *args) int csck = telnet_listener(socketfd); // Allocate memory used to transport client socket ID to client listening thread + int *newsock; newsock = calloc(1,sizeof(int)); *newsock = csck; From 900a3fa5cbe4ce1ac9427ed1572d188e49080019 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 00:59:10 +0100 Subject: [PATCH 53/63] Add "socket-test" target in Makefile Signed-off-by: DL6ER --- Makefile | 5 ++++- socket_client.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5f38b5b7..35367075 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ _DEPS = $(patsubst %,$(IDIR)/%,$(DEPS)) _OBJ = $(patsubst %,$(ODIR)/%,$(OBJ)) -all: pihole-FTL +all: pihole-FTL socket-test $(ODIR)/%.o: %.c $(_DEPS) | $(ODIR) $(CC) -c -o $@ $< -g3 $(CCFLAGS) @@ -60,6 +60,9 @@ $(ODIR)/sqlite3.o: sqlite3.c pihole-FTL: $(_OBJ) $(ODIR)/sqlite3.o $(CC) -v $(CCFLAGS) -o $@ $^ $(LIBS) +socket-test: socket_client.c + $(CC) -o $@ $< $(CCFLAGS) + .PHONY: clean force install clean: diff --git a/socket_client.c b/socket_client.c index 1a571272..76c9a7aa 100644 --- a/socket_client.c +++ b/socket_client.c @@ -28,7 +28,7 @@ int main (int argc, char **argv) { int size, ret; socketfd = socket(PF_LOCAL, SOCK_STREAM, 0); - if(socket <= 0) + if(socketfd <= 0) { printf("Error creating socket!\n"); exit(EXIT_FAILURE); From e4e5b0d45e9f35b1a4aabac0f2a9df876a28ae19 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 01:02:54 +0100 Subject: [PATCH 54/63] Use special socket file on Travis Signed-off-by: DL6ER --- socket_client.c | 5 ++++- test/test_suite.sh | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/socket_client.c b/socket_client.c index 76c9a7aa..ab0415d9 100644 --- a/socket_client.c +++ b/socket_client.c @@ -36,7 +36,10 @@ int main (int argc, char **argv) { printf ("Socket created\n"); address.sun_family = AF_LOCAL; - strcpy(address.sun_path, UDS_FILE); + if(argc == 2 && strcmp(argv[1], "travis") == 0) + strcpy(address.sun_path,"pihole-FTL.sock"); + else + strcpy(address.sun_path,"/var/run/pihole/FTL.sock"); ret = connect(socketfd, (struct sockaddr *) &address, sizeof (address)); if (ret != 0) { diff --git a/test/test_suite.sh b/test/test_suite.sh index 69de9c31..a4907c1f 100644 --- a/test/test_suite.sh +++ b/test/test_suite.sh @@ -196,6 +196,12 @@ load 'libs/bats-support/load' [[ ${lines[0]} == "pihole-FTL - The Pi-hole FTL engine" ]] } +@test "Unix socket returning data" { + run bash -c './pihole-FTL help' + echo "output: ${lines[@]}" + [[ ${lines[0]} == "pihole-FTL - The Pi-hole FTL engine" ]] +} + @test "Final part of the tests: Killing pihole-FTL process" { run bash -c 'echo ">kill" | nc -v 127.0.0.1 4711' echo "output: ${lines[@]}" From 9e40d006eb966bc95edd683ce643c49ed3f9db92 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 01:05:17 +0100 Subject: [PATCH 55/63] Add Unix socket test Signed-off-by: DL6ER --- socket_client.c | 4 ++-- test/test_suite.sh | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/socket_client.c b/socket_client.c index ab0415d9..c6bb405c 100644 --- a/socket_client.c +++ b/socket_client.c @@ -60,7 +60,7 @@ int main (int argc, char **argv) { while (strstr(buffer, "--EOM--") == NULL) { - printf("Message received: \"%s\"\n", buffer); + printf("%s", buffer); // Receive message size = recv(socketfd, buffer, BUF-1, 0); @@ -70,7 +70,7 @@ int main (int argc, char **argv) { buffer[size] = '\0'; } - printf("Message received: \"%s\"\n", buffer); + printf("%s", buffer); close (socketfd); return EXIT_SUCCESS; diff --git a/test/test_suite.sh b/test/test_suite.sh index a4907c1f..4ca4ca29 100644 --- a/test/test_suite.sh +++ b/test/test_suite.sh @@ -197,9 +197,11 @@ load 'libs/bats-support/load' } @test "Unix socket returning data" { - run bash -c './pihole-FTL help' + run bash -c './socket-test travis' echo "output: ${lines[@]}" - [[ ${lines[0]} == "pihole-FTL - The Pi-hole FTL engine" ]] + [[ ${lines[0]} == "Socket created" ]] + [[ ${lines[1]} == "Connection established" ]] + [[ ${lines[2]} ~= "domains_being_blocked -1" ]] } @test "Final part of the tests: Killing pihole-FTL process" { From b28a52c2805e157cb399e7349720c72f54d602a7 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 02:56:19 +0100 Subject: [PATCH 56/63] Extend test Signed-off-by: DL6ER --- test/test_suite.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test/test_suite.sh b/test/test_suite.sh index 4ca4ca29..e94126db 100644 --- a/test/test_suite.sh +++ b/test/test_suite.sh @@ -201,7 +201,17 @@ load 'libs/bats-support/load' echo "output: ${lines[@]}" [[ ${lines[0]} == "Socket created" ]] [[ ${lines[1]} == "Connection established" ]] - [[ ${lines[2]} ~= "domains_being_blocked -1" ]] + [[ ${lines[2]} == "domains_being_blocked -1" ]] + [[ ${lines[3]} == "dns_queries_today 7" ]] + [[ ${lines[4]} == "ads_blocked_today 2" ]] + [[ ${lines[5]} == "ads_percentage_today 28.571428" ]] + [[ ${lines[6]} == "unique_domains 6" ]] + [[ ${lines[7]} == "queries_forwarded 3" ]] + [[ ${lines[8]} == "queries_cached 2" ]] + [[ ${lines[9]} == "clients_ever_seen 3" ]] + [[ ${lines[10]} == "unique_clients 3" ]] + [[ ${lines[11]} == "status unknown" ]] + [[ ${lines[12]} == "---EOM---" ]] } @test "Final part of the tests: Killing pihole-FTL process" { From 855a0762e427bf262a22de7f976220e1b93d0f48 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 03:06:49 +0100 Subject: [PATCH 57/63] Make all instead of ony target pihole-FTL Signed-off-by: DL6ER --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e8420e17..5d9d21ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ before_script: - mkdir -p "${DEST_DIR}" - make clean script: -- make pihole-FTL CC="${BUILD_CC}" CFLAGS="${CFLAGS}" +- make CC="${BUILD_CC}" CFLAGS="${CFLAGS}" - file pihole-FTL - if [[ "${BIN_NAME}" == "pihole-FTL-linux-x86_64" ]]; then test/run.sh; fi - mv pihole-FTL "${DEST_DIR}/${BIN_NAME}" From 7ad0c66b682bbed3a418f08f045d6bd000d9debc Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 11:32:31 +0100 Subject: [PATCH 58/63] Remove debug output Signed-off-by: DL6ER --- socket.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/socket.c b/socket.c index d210616b..74cc5a12 100644 --- a/socket.c +++ b/socket.c @@ -253,8 +253,8 @@ void *telnet_connection_handler_thread(void *socket_desc) } else if(n == -1) { - if(debugclients) - logg("Telnet connection interrupted, ID: %i", sockID); + if(debug) logg("Telnet connection interrupted (%s), ID: %i", strerror(errno), sockID); + break; } } if(debugclients) @@ -311,10 +311,11 @@ void *socket_connection_handler_thread(void *socket_desc) } else if(n == -1) { - if(debug) logg("Socket connection interrupted, ID: %i", sockID); + if(debug) logg("Unix socket connection interrupted (%s), ID: %i", strerror(errno), sockID); + break; } } - if(debug) logg("Socket disconnected, ID: %i", sockID); + if(debugclients) logg("Socket disconnected, ID: %i", sockID); //Free the socket pointer if(sock != 0) From c26ff3a23fed34d070e8c2cc4552955e49173113 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 11:44:22 +0100 Subject: [PATCH 59/63] Add more comments to socket_client.c so it is easier understandable in case users what to use it as template to code their own APIs etc. Signed-off-by: DL6ER --- socket_client.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/socket_client.c b/socket_client.c index c6bb405c..e534148e 100644 --- a/socket_client.c +++ b/socket_client.c @@ -19,7 +19,6 @@ #include #include #define BUF 1024 -#define UDS_FILE "/var/run/pihole/FTL.sock" int main (int argc, char **argv) { int socketfd; @@ -27,19 +26,25 @@ int main (int argc, char **argv) { struct sockaddr_un address; int size, ret; + // Create socket socketfd = socket(PF_LOCAL, SOCK_STREAM, 0); if(socketfd <= 0) { printf("Error creating socket!\n"); exit(EXIT_FAILURE); } - printf ("Socket created\n"); + printf("Socket created\n"); + // Set socket family to local socket (not an Internet socket) address.sun_family = AF_LOCAL; + + // Set socket file location (respect special location on the CI system Travis) if(argc == 2 && strcmp(argv[1], "travis") == 0) strcpy(address.sun_path,"pihole-FTL.sock"); else strcpy(address.sun_path,"/var/run/pihole/FTL.sock"); + + // Connect to the socket provided by pihole-FTL ret = connect(socketfd, (struct sockaddr *) &address, sizeof (address)); if (ret != 0) { @@ -48,21 +53,24 @@ int main (int argc, char **argv) { } printf("Connection established\n"); + // As an example, we query the current statistics from FTL through the socket here sprintf(buffer, ">stats"); send(socketfd, buffer, strlen (buffer), 0); // Receive message size = recv(socketfd, buffer, BUF-1, 0); + // Zero-terminate incoming message if(size > 0) buffer[size] = '\0'; - while (strstr(buffer, "--EOM--") == NULL) + // Try to receive data until either recv() fails or we see "--EOM--" + while(size > -1 && strstr(buffer, "--EOM--") == NULL) { - + // Print received data to stdout printf("%s", buffer); - // Receive message + // Receive potential new message size = recv(socketfd, buffer, BUF-1, 0); // Zero-terminate incoming message @@ -70,8 +78,10 @@ int main (int argc, char **argv) { buffer[size] = '\0'; } + // Print received data to stdout printf("%s", buffer); - close (socketfd); + // Close Unix socket connection + close(socketfd); return EXIT_SUCCESS; } From 54487db5cf783f63d0194345c1b510d9804649eb Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 11:59:43 +0100 Subject: [PATCH 60/63] Close unix socket and unlink file handle on exit of FTL Signed-off-by: DL6ER --- main.c | 4 +++- routines.h | 3 ++- socket.c | 26 +++++++++++++------------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/main.c b/main.c index 45bf77d0..9d8b2529 100644 --- a/main.c +++ b/main.c @@ -160,7 +160,9 @@ int main (int argc, char* argv[]) { logg("Shutting down..."); pthread_cancel(piholelogthread); pthread_cancel(telnet_listenthread); - close_telnet_socket(SOCKET); + pthread_cancel(socket_listenthread); + close_telnet_socket(); + close_unix_socket(); removepid(); logg("########## FTL terminated! ##########"); return 1; diff --git a/routines.h b/routines.h index d8807993..1f363ba6 100644 --- a/routines.h +++ b/routines.h @@ -38,7 +38,8 @@ void pihole_log_flushed(bool message); void memory_check(int which); -void close_telnet_socket(char type); +void close_telnet_socket(void); +void close_unix_socket(void); void seom(char server_message[], int sock); void swrite(char server_message[], int sock); void *telnet_listenting_thread(void *args); diff --git a/socket.c b/socket.c index 74cc5a12..2467e951 100644 --- a/socket.c +++ b/socket.c @@ -195,20 +195,20 @@ int telnet_listener(int sockfd) return clientsocket; } -void close_telnet_socket(char type) +void close_telnet_socket(void) { - switch(type) - { - case SOCKET: - removeport(); - // Using global variable here - close(telnetfd); - break; - default: - logg("Incompatible socket type %i, cannot close",(int)type); - exit(EXIT_FAILURE); - break; - } + removeport(); + // Using global variable here + close(telnetfd); +} + +void close_unix_socket(void) +{ + // According to "man unix" the process has to take care + // to unlink the socket file description on exit + unlink(FTLfiles.socketfile); + // Using global variable here + close(socketfd); } void *telnet_connection_handler_thread(void *socket_desc) From e67e5e45dec65cce6c7f6195e07692ed440a6347 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 14:28:29 +0100 Subject: [PATCH 61/63] Suppress connection interrupted messages for Telnet and Unix Socket Signed-off-by: DL6ER --- socket.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/socket.c b/socket.c index 2467e951..ce0116ce 100644 --- a/socket.c +++ b/socket.c @@ -204,8 +204,7 @@ void close_telnet_socket(void) void close_unix_socket(void) { - // According to "man unix" the process has to take care - // to unlink the socket file description on exit + // The process has to take care of unlinking the socket file description on exit unlink(FTLfiles.socketfile); // Using global variable here close(socketfd); @@ -253,7 +252,7 @@ void *telnet_connection_handler_thread(void *socket_desc) } else if(n == -1) { - if(debug) logg("Telnet connection interrupted (%s), ID: %i", strerror(errno), sockID); + if(debugclients) logg("Telnet connection interrupted (%s), ID: %i", strerror(errno), sockID); break; } } @@ -311,7 +310,7 @@ void *socket_connection_handler_thread(void *socket_desc) } else if(n == -1) { - if(debug) logg("Unix socket connection interrupted (%s), ID: %i", strerror(errno), sockID); + if(debugclients) logg("Unix socket connection interrupted (%s), ID: %i", strerror(errno), sockID); break; } } From 8a720b6f19e29767e342abea3ca84630845e8146 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 17:24:54 +0100 Subject: [PATCH 62/63] Fix spelling Signed-off-by: DL6ER --- main.c | 4 ++-- routines.h | 4 ++-- socket.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index 9d8b2529..a0b2694f 100644 --- a/main.c +++ b/main.c @@ -71,14 +71,14 @@ int main (int argc, char* argv[]) { } pthread_t telnet_listenthread; - if(pthread_create( &telnet_listenthread, &attr, telnet_listenting_thread, NULL ) != 0) + if(pthread_create( &telnet_listenthread, &attr, telnet_listening_thread, NULL ) != 0) { logg("Unable to open telnet listening thread. Exiting..."); killed = 1; } pthread_t socket_listenthread; - if(pthread_create( &socket_listenthread, &attr, socket_listenting_thread, NULL ) != 0) + if(pthread_create( &socket_listenthread, &attr, socket_listening_thread, NULL ) != 0) { logg("Unable to open Unix socket listening thread. Exiting..."); killed = 1; diff --git a/routines.h b/routines.h index 1f363ba6..f1d8de53 100644 --- a/routines.h +++ b/routines.h @@ -42,8 +42,8 @@ void close_telnet_socket(void); void close_unix_socket(void); void seom(char server_message[], int sock); void swrite(char server_message[], int sock); -void *telnet_listenting_thread(void *args); -void *socket_listenting_thread(void *args); +void *telnet_listening_thread(void *args); +void *socket_listening_thread(void *args); void process_request(char *client_message, int *sock); bool command(char *client_message, const char* cmd); diff --git a/socket.c b/socket.c index ce0116ce..9da83348 100644 --- a/socket.c +++ b/socket.c @@ -324,7 +324,7 @@ void *socket_connection_handler_thread(void *socket_desc) return 0; } -void *telnet_listenting_thread(void *args) +void *telnet_listening_thread(void *args) { // We will use the attributes object later to start all threads in detached mode pthread_attr_t attr; @@ -362,7 +362,7 @@ void *telnet_listenting_thread(void *args) return 0; } -void *socket_listenting_thread(void *args) +void *socket_listening_thread(void *args) { // We will use the attributes object later to start all threads in detached mode pthread_attr_t attr; From 7638d8cdb1ccffb357d4e7ebc308334680e389e6 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 1 Jan 2018 21:33:39 +0100 Subject: [PATCH 63/63] Improve socket client example + work on review comments Signed-off-by: DL6ER --- socket.c | 10 +++++----- socket_client.c | 32 +++++++++++--------------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/socket.c b/socket.c index 9da83348..f808b3ec 100644 --- a/socket.c +++ b/socket.c @@ -181,7 +181,7 @@ void swrite(char server_message[SOCKETBUFFERLEN], int sock) logg("WARNING: Socket write returned error code %i", errno); } -int telnet_listener(int sockfd) +int listener(int sockfd) { struct sockaddr_in cli_addr; // set all values in the buffer to zero @@ -246,7 +246,7 @@ void *telnet_connection_handler_thread(void *socket_desc) if(sock == 0) { - // Client disconnected by seding EOT or ">quit" + // Client disconnected by sending EOT or ">quit" break; } } @@ -304,7 +304,7 @@ void *socket_connection_handler_thread(void *socket_desc) if(sock == 0) { - // Socket connection interrupted by seding EOT or ">quit" + // Socket connection interrupted by sending EOT or ">quit" break; } } @@ -344,7 +344,7 @@ void *telnet_listening_thread(void *args) while(!killed) { // Look for new clients that want to connect - int csck = telnet_listener(telnetfd); + int csck = listener(telnetfd); // Allocate memory used to transport client socket ID to client listening thread int *newsock; @@ -382,7 +382,7 @@ void *socket_listening_thread(void *args) while(!killed) { // Look for new clients that want to connect - int csck = telnet_listener(socketfd); + int csck = listener(socketfd); // Allocate memory used to transport client socket ID to client listening thread int *newsock; diff --git a/socket_client.c b/socket_client.c index e534148e..080bf107 100644 --- a/socket_client.c +++ b/socket_client.c @@ -1,5 +1,3 @@ -/* uds_client.c */ -#include /* Pi-hole: A black hole for Internet advertisements * (c) 2017 Pi-hole, LLC (https://pi-hole.net) * Network-wide ad blocking via your own hardware. @@ -9,7 +7,7 @@ * * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ - +#include #include #include #include @@ -57,31 +55,23 @@ int main (int argc, char **argv) { sprintf(buffer, ">stats"); send(socketfd, buffer, strlen (buffer), 0); - // Receive message - size = recv(socketfd, buffer, BUF-1, 0); - - // Zero-terminate incoming message - if(size > 0) - buffer[size] = '\0'; - // Try to receive data until either recv() fails or we see "--EOM--" - while(size > -1 && strstr(buffer, "--EOM--") == NULL) + while((size = recv(socketfd, buffer, BUF-1, 0)) > -1) { - // Print received data to stdout - printf("%s", buffer); - - // Receive potential new message - size = recv(socketfd, buffer, BUF-1, 0); - // Zero-terminate incoming message if(size > 0) buffer[size] = '\0'; - } - // Print received data to stdout - printf("%s", buffer); + // Print received data to stdout + printf("%s", buffer); + + // Exit on End Of Message + if(strstr(buffer, "--EOM--") != NULL) + break; + + } // Close Unix socket connection close(socketfd); return EXIT_SUCCESS; - } +}