diff --git a/Makefile b/Makefile index 0826caa5..bcaad190 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,8 @@ FTL_DEPS = *.h database/*.h api/*.h version.h FTL_DB_OBJ = database/common.o database/query-table.o database/network-table.o database/gravity-db.o database/database-thread.o \ database/sqlite3-ext.o database/message-table.o FTL_API_OBJ = api/http-common.o api/routes.o api/ftl.o api/stats.o api/dns.o api/version.o api/auth.o api/settings.o api/stats_database.o -FTL_OBJ = $(FTL_DB_OBJ) $(FTL_API_OBJ) main.o memory.o log.o daemon.o datastructure.o signals.o files.o setupVars.o args.o gc.o config.o dnsmasq_interface.o resolve.o regex.o shmem.o capabilities.o overTime.o timers.o vector.o +FTL_OBJ = $(FTL_DB_OBJ) $(FTL_API_OBJ) main.o memory.o log.o daemon.o datastructure.o signals.o files.o setupVars.o args.o gc.o config.o \ + dnsmasq_interface.o resolve.o regex.o shmem.o capabilities.o overTime.o timers.o vector.o math.o DNSMASQ_DEPS = config.h dhcp-protocol.h dns-protocol.h radv-protocol.h dhcp6-protocol.h dnsmasq.h ip6addr.h metrics.h ../dnsmasq_interface.h DNSMASQ_OBJ = arp.o dbus.o domain.o lease.o outpacket.o rrfilter.o auth.o dhcp6.o edns0.o log.o poll.o slaac.o blockdata.o dhcp.o forward.o \ diff --git a/src/api/stats.c b/src/api/stats.c index 717a9a99..017b98a8 100644 --- a/src/api/stats.c +++ b/src/api/stats.c @@ -26,6 +26,8 @@ #include "overTime.h" // enum REGEX #include "regex_r.h" +// my_sqrt() +#include "../math.h" /* qsort comparision function (count field), sort ASC static int __attribute__((pure)) cmpasc(const void *a, const void *b) @@ -471,6 +473,7 @@ int api_stats_upstreams(struct mg_connection *conn) { int count = 0; const char* ip, *name; + double responsetime = 0.0, uncertainty = 0.0; if(i == -2) { @@ -503,6 +506,20 @@ int api_stats_upstreams(struct mg_connection *conn) // Get percentage count = forward->count; + + // Compute average response time and uncertainty (unit: seconds) + if(forward->responses > 0) + { + // Wehave to multiply runcertainty by 1e-4 to get seconds + responsetime = 1e-4 * forward->rtime / forward->responses; + } + if(forward->responses > 1) + { + // The actual value will be somewhere in a neighborhood around the mean value. + // This neighborhood of values is the uncertainty in the mean. + // Wehave to multiply runcertainty by (1e-4)^2 to get seconds + uncertainty = my_sqrt(1e-8 * forward->rtuncertainty / forward->responses / (forward->responses-1)); + } } // Send data: @@ -514,6 +531,8 @@ int api_stats_upstreams(struct mg_connection *conn) JSON_OBJ_REF_STR(upstream, "name", name); JSON_OBJ_REF_STR(upstream, "ip", ip); JSON_OBJ_ADD_NUMBER(upstream, "count", count); + JSON_OBJ_ADD_NUMBER(upstream, "responsetime", responsetime); + JSON_OBJ_ADD_NUMBER(upstream, "uncertainty", uncertainty); JSON_ARRAY_ADD_ITEM(upstreams, upstream); } } diff --git a/src/datastructure.c b/src/datastructure.c index eb3adf08..c3f8afa5 100644 --- a/src/datastructure.c +++ b/src/datastructure.c @@ -76,6 +76,10 @@ int findUpstreamID(const char * upstreamString, const bool count) // to be done separately to be non-blocking upstream->new = true; upstream->namepos = 0; // 0 -> string with length zero + // Initialize response time values + upstream->rtime = 0u; + upstream->rtuncertainty = 0u; + upstream->responses = 0u; // Increase counter by one counters->upstreams++; diff --git a/src/datastructure.h b/src/datastructure.h index b573f4b5..4deebb07 100644 --- a/src/datastructure.h +++ b/src/datastructure.h @@ -47,6 +47,9 @@ typedef struct { typedef struct { unsigned char magic; bool new; + unsigned long rtime; + unsigned long rtuncertainty; + unsigned int responses; int count; int failed; size_t ippos; diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c index 165b34e5..d829562b 100644 --- a/src/dnsmasq_interface.c +++ b/src/dnsmasq_interface.c @@ -961,6 +961,14 @@ void _FTL_reply(const unsigned short flags, const char *name, const union all_ad } else if((flags & F_FORWARD) && isExactMatch) { + // Save query response time + upstreamsData *upstream = getUpstream(query->upstreamID, true); + upstream->responses++; + unsigned long rtime = converttimeval(response) - query->response; + upstream->rtime += rtime; + unsigned long mean = upstream->rtime / upstream->responses; + upstream->rtuncertainty += (mean - rtime)*(mean - rtime); + // Only proceed if query is not already known // to have been blocked by Quad9 if(query->reply != QUERY_EXTERNAL_BLOCKED_IP && diff --git a/src/math.c b/src/math.c new file mode 100644 index 00000000..d0a66be6 --- /dev/null +++ b/src/math.c @@ -0,0 +1,52 @@ +/* Pi-hole: A black hole for Internet advertisements +* (c) 2019 Pi-hole, LLC (https://pi-hole.net) +* Network-wide ad blocking via your own hardware. +* +* FTL Engine +* Math Implementation +* +* This file is copyright under the latest version of the EUPL. +* Please see LICENSE file for your rights under this license. */ + +#include "math.h" + +// Recursive function that returns square root +// of a number with precision upto 5 decimal places +double Square(double n, double i, double j) +{ + double mid = (i + j) / 2; + double mul = mid * mid; + + if ((mul - n)*(mul - n) < (SQRT_PRECISION * SQRT_PRECISION)) + { + return mid; + } + else if (mul < n) + { + return Square(n, mid, j); + } + else + { + return Square(n, i, mid); + } +} + + // Function to find the square root of n +double my_sqrt(double n) +{ + // While the square root is not found + for(double i = 1.0; true; i++) + { + if ((i - n)*(i - n) < (SQRT_PRECISION * SQRT_PRECISION)) + { + // If n is a perfect square + return i; + } + else if (i * i > n) + { + // Square root will lie in the interval i-1 and i + return Square(n, i - 1, i); + } + i++; + } +} \ No newline at end of file diff --git a/src/math.h b/src/math.h new file mode 100644 index 00000000..ec59b48e --- /dev/null +++ b/src/math.h @@ -0,0 +1,25 @@ +/* Pi-hole: A black hole for Internet advertisements +* (c) 2019 Pi-hole, LLC (https://pi-hole.net) +* Network-wide ad blocking via your own hardware. +* +* FTL Engine +* Math Prototypes +* +* This file is copyright under the latest version of the EUPL. +* Please see LICENSE file for your rights under this license. */ + +#ifndef MATH_H +#define MATH_H + +#include +#include + +#define SQRT_PRECISION 1e-5 + +// Recursive function that returns square root +double Square(double n, double i, double j); + +// Function to find the square root of n +double my_sqrt(double n); + +#endif //MATH_H \ No newline at end of file