Merge pull request #253 from pi-hole/FTLDNS-resolve

Internal name resolving functionality
This commit is contained in:
DL6ER
2018-04-13 18:00:31 +02:00
committed by GitHub
9 changed files with 207 additions and 12 deletions
+4
View File
@@ -159,12 +159,16 @@ typedef struct {
int count;
int failed;
char *ip;
char *name;
bool new;
} forwardedDataStruct;
typedef struct {
unsigned char magic;
int count;
char *ip;
char *name;
bool new;
} clientsDataStruct;
typedef struct {
+1 -1
View File
@@ -14,7 +14,7 @@ DNSMASQOPTS = -DHAVE_DNSSEC -DHAVE_DNSSEC_STATIC -DNO_FORK
# Flags for compiling with libidn2: -DHAVE_LIBIDN2 -DIDN2_VERSION_NUMBER=0x02000003
FTLDEPS = FTL.h routines.h version.h api.h dnsmasq_interface.h
FTLOBJ = main.o memory.o log.o daemon.o datastructure.o signals.o socket.o request.o grep.o setupVars.o args.o threads.o gc.o config.o database.o msgpack.o api.o dnsmasq_interface.o
FTLOBJ = main.o memory.o log.o daemon.o datastructure.o signals.o socket.o request.o grep.o setupVars.o args.o threads.o gc.o config.o database.o msgpack.o api.o dnsmasq_interface.o resolve.o
DNSMASQDEPS = config.h dhcp-protocol.h dns-protocol.h radv-protocol.h dhcp6-protocol.h dnsmasq.h ip6addr.h
DNSMASQOBJ = 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 loop.o radv.o tables.o bpf.o dhcp-common.o helper.o netlink.o rfc1035.o tftp.o cache.o dnsmasq.o inotify.o network.o rfc2131.o util.o conntrack.o dnssec.o ipset.o option.o rfc3315.o crypto.o
+44 -11
View File
@@ -380,20 +380,28 @@ void getTopClients(char *client_message, int *sock)
validate_access("clients", j, true, __LINE__, __FUNCTION__, __FILE__);
// Skip this client if there is a filter on it
if(excludeclients != NULL && insetupVarsArray(clients[j].ip))
if(excludeclients != NULL &&
(insetupVarsArray(clients[j].ip) || insetupVarsArray(clients[j].name)))
continue;
// Hidden domain, probably due to privacy level. Skip this in the top lists
// Hidden client, probably due to privacy level. Skip this in the top lists
if(strcmp(clients[j].ip, "0.0.0.0") == 0)
continue;
// Only return name if available
char *name;
if(clients[j].name != NULL)
name = clients[j].name;
else
name = "";
// Return this client if either
// - "withzero" option is set, and/or
// - the client made at least one query within the most recent 24 hours
if(includezeroclients || clients[j].count > 0)
{
if(istelnet[*sock])
ssend(*sock,"%i %i %s\n",n,clients[j].count,clients[j].ip);
ssend(*sock,"%i %i %s %s\n",n,clients[j].count,clients[j].ip,name);
else
{
if(!pack_str32(*sock, "") || !pack_str32(*sock, clients[j].ip))
@@ -437,7 +445,8 @@ void getForwardDestinations(char *client_message, int *sock)
}
}
if(sort) {
if(sort)
{
// Add "local " forward destination
temparray[counters.forwarded][0] = counters.forwarded;
temparray[counters.forwarded][1] = counters.cached + counters.blocked;
@@ -451,7 +460,7 @@ void getForwardDestinations(char *client_message, int *sock)
// Loop over available forward destinations
for(i=0; i < min(counters.forwarded+1, 10); i++)
{
char *ip;
char *ip, *name;
float percentage = 0.0f;
// Get sorted indices
@@ -465,6 +474,7 @@ void getForwardDestinations(char *client_message, int *sock)
if(j == counters.forwarded)
{
ip = strdup("local");
name = ip;
if(totalqueries > 0)
// Whats the percentage of (cached + blocked) queries on the total amount of queries?
@@ -477,6 +487,12 @@ void getForwardDestinations(char *client_message, int *sock)
validate_access("forwarded", j, true, __LINE__, __FUNCTION__, __FILE__);
ip = forwarded[j].ip;
// Only return name if available
if(forwarded[j].name != NULL)
name = forwarded[j].name;
else
name = "";
// Math explanation:
// A single query may result in requests being forwarded to multiple destinations
// Hence, in order to be able to give percentages here, we have to normalize the
@@ -503,7 +519,7 @@ void getForwardDestinations(char *client_message, int *sock)
if(percentage > 0.0f)
{
if(istelnet[*sock])
ssend(*sock, "%i %.2f %s\n", i, percentage, ip);
ssend(*sock, "%i %.2f %s %s\n", i, percentage, ip, name);
else
{
if(!pack_str32(*sock, "") || !pack_str32(*sock, ip))
@@ -515,7 +531,10 @@ void getForwardDestinations(char *client_message, int *sock)
// Free previously allocated memory only if we allocated it
if(allocated)
{
free(ip);
//free(name); // This is just the same as ip
}
}
if(debugclients)
@@ -681,12 +700,18 @@ void getAllQueries(char *client_message, int *sock)
if(filterclientname)
{
// Skip if client name and IP are not identical with what the user wants to see
if(strcmp(clients[queries[i].clientID].ip, clientname) != 0)
if(strcmp(clients[queries[i].clientID].ip, clientname) != 0 &&
strcmp(clients[queries[i].clientID].name, clientname) != 0)
continue;
}
char *domain = domains[queries[i].domainID].domain;
char *client = clients[queries[i].clientID].ip;
char *client;
if(clients[queries[i].clientID].name != NULL &&
strlen(clients[queries[i].clientID].name) > 0)
client = clients[queries[i].clientID].name;
else
client = clients[queries[i].clientID].ip;
unsigned long delay = queries[i].response;
// Check if received (delay should be smaller than 30min)
@@ -967,7 +992,8 @@ void getClientsOverTime(int *sock)
{
validate_access("clients", i, true, __LINE__, __FUNCTION__, __FILE__);
// Check if this client should be skipped
if(insetupVarsArray(clients[i].ip))
if(insetupVarsArray(clients[i].ip) ||
insetupVarsArray(clients[i].name))
skipclient[i] = true;
}
}
@@ -1039,7 +1065,8 @@ void getClientNames(int *sock)
{
validate_access("clients", i, true, __LINE__, __FUNCTION__, __FILE__);
// Check if this client should be skipped
if(insetupVarsArray(clients[i].ip))
if(insetupVarsArray(clients[i].ip) ||
insetupVarsArray(clients[i].name))
skipclient[i] = true;
}
}
@@ -1051,8 +1078,14 @@ void getClientNames(int *sock)
if(skipclient[i])
continue;
char *client;
if(clients[i].name != NULL && strlen(clients[i].name) > 0)
client = clients[i].name;
else
client = clients[i].ip;
if(istelnet[*sock])
ssend(*sock, "%i %i %s\n", i, clients[i].count, clients[i].ip);
ssend(*sock, "%i %i %s\n", i, clients[i].count, client);
else {
if(!pack_str32(*sock, "") || !pack_str32(*sock, clients[i].ip))
return;
+4
View File
@@ -555,6 +555,10 @@ void *DB_thread(void *val)
// Update lastDBsave timer
lastDBsave = time(NULL) - time(NULL)%config.DBinterval;
// This has to be run outside of the thread locks
// to prevent locking the resolver
resolveNewClients();
// Lock FTL's data structure, since it is
// likely that it will be changed here
enable_thread_lock();
+12
View File
@@ -111,6 +111,12 @@ int findForwardID(const char * forward, bool count)
forwarded[forwardID].ip = strdup(forward);
memory.forwardedips += (strlen(forward) + 1) * sizeof(char);
forwarded[forwardID].failed = 0;
// Initialize forward hostname
// Due to the nature of us being the resolver,
// the actual resolving of the host name has
// to be done separately to be non-blocking
forwarded[forwardID].new = true;
forwarded[forwardID].name = NULL;
// Increase counter by one
counters.forwarded++;
@@ -191,6 +197,12 @@ int findClientID(const char *client)
// Store client IP - no need to check for NULL here as it doesn't harm
clients[clientID].ip = strdup(client);
memory.clientips += (strlen(client) + 1) * sizeof(char);
// Initialize client hostname
// Due to the nature of us being the resolver,
// the actual resolving of the host name has
// to be done separately to be non-blocking
clients[clientID].new = true;
clients[clientID].name = NULL;
// Increase counter by one
counters.clients++;
+5
View File
@@ -166,6 +166,11 @@ void *GC_thread(void *val)
// Release thread lock
disable_thread_lock();
// Reresolve client hostnames to account for changes
// Have to this outside of the thread lock
// to prevent locking of the resolver
reresolveHostnames();
}
sleepms(100);
}
+128
View File
@@ -0,0 +1,128 @@
/* 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
* DNS Client Implementation
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
#include "FTL.h"
char *resolveHostname(const char *addr)
{
// Get host name
struct hostent *he = NULL;
char *hostname = NULL;;
bool IPv6 = false;
// Check if this is a hidden client
// if so, return "hidden" as hostname
if(strcmp(addr, "0.0.0.0") == 0)
{
hostname = strdup("hidden");
//if(hostname == NULL) return NULL;
return hostname;
}
// Test if we want to resolve an IPv6 address
if(strstr(addr,":") != NULL)
{
IPv6 = true;
}
if(IPv6 && config.resolveIPv6) // Resolve IPv6 address only if requested
{
struct in6_addr ipaddr;
inet_pton(AF_INET6, addr, &ipaddr);
he = gethostbyaddr(&ipaddr, sizeof ipaddr, AF_INET6);
}
else if(!IPv6 && config.resolveIPv4) // Resolve IPv4 address only if requested
{
struct in_addr ipaddr;
inet_pton(AF_INET, addr, &ipaddr);
he = gethostbyaddr(&ipaddr, sizeof ipaddr, AF_INET);
}
if(he == NULL)
{
// No hostname found
hostname = strdup("");
//if(hostname == NULL) return NULL;
}
else
{
// Return hostname copied to new memory location
hostname = strdup(he->h_name);
if(hostname == NULL) return NULL;
// Convert hostname to lower case
strtolower(hostname);
}
return hostname;
}
// This routine is run *after* garbage cleaning (default interval is once per hour)
// to account for possibly updated hostnames
void reresolveHostnames(void)
{
int clientID;
for(clientID = 0; clientID < counters.clients; clientID++)
{
// Memory validation
validate_access("clients", clientID, true, __LINE__, __FUNCTION__, __FILE__);
// Process this client only if it has at least one active query in the log
if(clients[clientID].count < 1)
continue;
// Get client hostname
char *hostname = resolveHostname(clients[clientID].ip);
if(strlen(hostname) > 0)
{
// Delete possibly already existing hostname pointer before storing new data
if(clients[clientID].name != NULL)
{
free(clients[clientID].name);
clients[clientID].name = NULL;
}
// Store client hostname
clients[clientID].name = strdup(hostname);
}
free(hostname);
}
}
// This routine is run *before* saving to the database (default interval is once per minute)
// to account for new clients (and forward destinations)
void resolveNewClients(void)
{
int i;
for(i = 0; i < counters.clients; i++)
{
// Memory validation
validate_access("clients", i, true, __LINE__, __FUNCTION__, __FILE__);
// Only try to resolve new clients
// Note that it can happen that we are not able to find hostnames but we don't
// want to try to resolve them every minute in this case.
if(clients[i].new)
{
clients[i].name = resolveHostname(clients[i].ip);
clients[i].new = false;
}
}
for(i = 0; i < counters.forwarded; i++)
{
// Memory validation
validate_access("forwarded", i, true, __LINE__, __FUNCTION__, __FILE__);
// Only try to resolve new forward destinations
if(forwarded[i].new)
{
forwarded[i].name = resolveHostname(forwarded[i].ip);
forwarded[i].new = false;
}
}
}
+4
View File
@@ -100,3 +100,7 @@ int main_dnsmasq(int argc, char **argv);
// signals.c
void handle_signals(void);
// resolve.c
void resolveNewClients(void);
void reresolveHostnames(void);
+5
View File
@@ -165,6 +165,11 @@ void clearSetupVarsArray(void)
bool insetupVarsArray(char * str)
{
int i;
// Check for possible NULL pointer
// (this is valid input, e.g. if clients[i].name is unspecified)
if(str == NULL)
return false;
// Loop over all entries in setupVarsArray
for (i = 0; i < setupVarsElements; ++i)
if(setupVarsArray[i][0] == '*')