From 4492562c502cdc01ba6293e8667cbc08fd5de1be Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Sun, 29 Nov 2020 18:16:01 +0800 Subject: [PATCH 01/12] Fix compatibility with GCC 10. GCC 10 defaults to -fno-common, which requires "extern" when defining global variables in headers. Signed-off-by: DDoSolitary --- src/datastructure.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datastructure.h b/src/datastructure.h index e92adbe84..8592a7d9d 100644 --- a/src/datastructure.h +++ b/src/datastructure.h @@ -16,7 +16,7 @@ // enum privacy_level #include "enums.h" -const char *querytypes[TYPE_MAX]; +extern const char *querytypes[TYPE_MAX]; typedef struct { unsigned char magic; From d61ddc3925f0fad2680735f2ee017e277c8bfd90 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Sun, 29 Nov 2020 23:58:09 +0800 Subject: [PATCH 02/12] Add -fno-common to HARDENING_FLAGS. Signed-off-by: DDoSolitary --- src/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ba192761..b83dc8a78 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,7 +41,8 @@ set(SQLITE_DEFINES "-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_DEFAULT_MEMSTATUS=0 -D # -Wl,-z,defs: Detect and reject underlinking (phenomenon caused by missing shared library arguments when invoking the linked editor to produce another shared library) # -Wl,-z,now: Disable lazy binding # -Wl,-z,relro: Read-only segments after relocation -set(HARDENING_FLAGS "-fstack-protector-strong -Wp,-D_FORTIFY_SOURCE=2 -Wl,-z,relro,-z,now -fexceptions -funwind-tables -fasynchronous-unwind-tables -Wl,-z,defs -Wl,-z,now -Wl,-z,relro") +# -fno-common: Emit globals without explicit initializer from `.bss` to `.data`. This causes GCC to reject multiple definitions of global variables. This is the new default from GCC-10 on. +set(HARDENING_FLAGS "-fstack-protector-strong -Wp,-D_FORTIFY_SOURCE=2 -Wl,-z,relro,-z,now -fexceptions -funwind-tables -fasynchronous-unwind-tables -Wl,-z,defs -Wl,-z,now -Wl,-z,relro -fno-common") set(DEBUG_FLAGS "-rdynamic -fno-omit-frame-pointer") # -Wall: This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or modify to prevent the warning), even in conjunction with macros. This also enables some language-specific warnings described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options. From 4bfe4a4fde425e0f9f139a3cdc744d5b43a9671f Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 30 Nov 2020 13:32:18 +0100 Subject: [PATCH 03/12] Do not warn about query status 12 and 13 on import (retried queries) Signed-off-by: DL6ER --- src/database/query-table.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/database/query-table.c b/src/database/query-table.c index af5512758..3bd3ca93f 100644 --- a/src/database/query-table.c +++ b/src/database/query-table.c @@ -523,10 +523,13 @@ void DB_read_queries(void) overTime[timeidx].cached++; break; + case QUERY_RETRIED: // Retried query + case QUERY_RETRIED_DNSSEC: // fall through + // Nothing to be done here + break; + default: - logg("Error: Found unknown status %i in long term database!", status); - logg(" Timestamp: %lli", (long long)queryTimeStamp); - logg(" Continuing anyway..."); + logg("Warning: Found unknown status %i in long term database!", status); break; } } From ec2a0ae1a436bd3140d4f57814fc87a0b8f7317c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 30 Nov 2020 13:26:45 +0100 Subject: [PATCH 04/12] Catch all real-time signals, decide later which one we handle and which one we ignore. Signed-off-by: DL6ER --- src/signals.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/signals.c b/src/signals.c index d9b119703..b5ec061da 100644 --- a/src/signals.c +++ b/src/signals.c @@ -225,7 +225,7 @@ static void __attribute__((noreturn)) signal_handler(int sig, siginfo_t *si, voi // Print content of /dev/shm ls_dir("/dev/shm"); - + logg("Please also include some lines from above the !!!!!!!!! header."); logg("Thank you for helping us to improve our FTL engine!"); // Terminate main process if crash happened in a TCP worker @@ -246,7 +246,6 @@ static void __attribute__((noreturn)) signal_handler(int sig, siginfo_t *si, voi exit(EXIT_FAILURE); } -#define RTSIG_MAX 2 static void SIGRT_handler(int signum, siginfo_t *si, void *unused) { // Ignore real-time signals outside of the main process (TCP forks) @@ -358,15 +357,15 @@ void handle_realtime_signals(void) // the main process mpid = getpid(); - // Catch first five real-time signals - for(unsigned char i = 0; i < (RTSIG_MAX+1); i++) + // Catch all real-time signals + for(int signum = SIGRTMIN; signum <= SIGRTMAX; signum++) { struct sigaction SIGACTION; memset(&SIGACTION, 0, sizeof(struct sigaction)); SIGACTION.sa_flags = SA_SIGINFO; sigemptyset(&SIGACTION.sa_mask); SIGACTION.sa_sigaction = &SIGRT_handler; - sigaction(SIGRTMIN + i, &SIGACTION, NULL); + sigaction(signum, &SIGACTION, NULL); } } From dad2d6fc15807226671309b660a4ddad9c0544a6 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 30 Nov 2020 14:32:46 +0100 Subject: [PATCH 05/12] Check for memory allocation erros in parse_FTLconf() Signed-off-by: DL6ER --- src/config.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/config.c b/src/config.c index 4e3e67bfa..d7bcea656 100644 --- a/src/config.c +++ b/src/config.c @@ -490,6 +490,10 @@ static char *parse_FTLconf(FILE *fp, const char * key) errno = 0; while(getline(&conflinebuffer, &size, fp) != -1) { + // Check if memory allocation failed + if(conflinebuffer == NULL) + break; + // Skip comment lines if(conflinebuffer[0] == '#' || conflinebuffer[0] == ';') continue; @@ -512,7 +516,7 @@ static char *parse_FTLconf(FILE *fp, const char * key) if(errno == ENOMEM) logg("WARN: parse_FTLconf failed: could not allocate memory for getline"); - // Key not found -> return NULL + // Key not found or memory error -> return NULL free(keystr); return NULL; From d25f05d3398d661cbfa06331dcda12c8b68eacda Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 29 Nov 2020 13:21:24 +0100 Subject: [PATCH 06/12] Respect settings RESOLVE_IPV4 and RESOLVE_IPv6 also when trying to resolve host names from the database (network table) Signed-off-by: DL6ER --- src/database/network-table.c | 17 ++++++++++++ src/resolve.c | 53 ++++++++++++++++++++++++------------ src/resolve.h | 2 ++ 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/database/network-table.c b/src/database/network-table.c index eb8faa1dc..1fabb3ddc 100644 --- a/src/database/network-table.c +++ b/src/database/network-table.c @@ -1695,6 +1695,15 @@ char *__attribute__((malloc)) getNameFromIP(const char *ipaddr) return NULL; } + // Check if we want to resolve host names + if(!resolve_this_name(ipaddr)) + { + if(config.debug & DEBUG_DATABASE) + logg("getNameFromIP(\"%s\") - configured to not resolve host name", ipaddr); + + return NULL; + } + // Check for a host name associated with the same IP address sqlite3_stmt *stmt = NULL; const char *querystr = "SELECT name FROM network_addresses WHERE name IS NOT NULL AND ip = ?;"; @@ -1858,6 +1867,14 @@ void resolveNetworkTableNames(void) return; } + // Check if we want to resolve host names + if(!resolve_names()) + { + if(config.debug & DEBUG_DATABASE) + logg("resolveNetworkTableNames() - configured to not resolve host names"); + return; + } + const char sql[] = "BEGIN TRANSACTION IMMEDIATE"; int rc = dbquery(sql); if( rc != SQLITE_OK ) diff --git a/src/resolve.c b/src/resolve.c index f9776416a..f7c425bb4 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -112,12 +112,39 @@ static void print_used_resolvers(const char *message) } } +// Return if we want to resolve address to names at all +// (may be disabled due to config settings) +bool __attribute__((pure)) resolve_names(void) +{ + if(!config.resolveIPv4 && !config.resolveIPv6) + return false; + return true; +} + +// Return if we want to resolve this type of address to a name +bool __attribute__((pure)) resolve_this_name(const char *ipaddr) +{ + if(!config.resolveIPv4 || + (!config.resolveIPv6 && strstr(ipaddr,":") != NULL)) + return false; + return true; +} + char *resolveHostname(const char *addr) { // Get host name struct hostent *he = NULL; char *hostname = NULL; - bool IPv6 = false; + + // Check if we want to resolve host names + if(!resolve_this_name(addr)) + { + if(config.debug & DEBUG_RESOLVER) + logg("Configured to not resolve host name for %s", addr); + + // Return an empty host name + return strdup(""); + } if(config.debug & DEBUG_RESOLVER) logg("Trying to resolve %s", addr); @@ -133,10 +160,9 @@ char *resolveHostname(const char *addr) } // Test if we want to resolve an IPv6 address + bool IPv6 = false; if(strstr(addr,":") != NULL) - { IPv6 = true; - } // Initialize resolver subroutines if trying to resolve for the first time // res_init() reads resolv.conf to get the default domain name and name server @@ -248,7 +274,7 @@ char *resolveHostname(const char *addr) } else { - // No (he == NULL) or invalid (valid_hostname returned false) hostname found + // No hostname found (empty PTR) hostname = strdup(""); if(config.debug & DEBUG_RESOLVER) @@ -270,21 +296,14 @@ static size_t resolveAndAddHostname(size_t ippos, size_t oldnamepos) char* oldname = strdup(getstr(oldnamepos)); unlock_shm(); - // Test if we want to resolve an IPv6 address - bool IPv6 = false; - if(strstr(ipaddr,":") != NULL) - { - IPv6 = true; - } - - if( (IPv6 && !config.resolveIPv6) || - (!IPv6 && !config.resolveIPv4)) + // Test if we want to resolve host names, otherwise all calls to resolveHostname() + // and getNameFromIP() can be skipped as they will all return empty names (= no records) + if(!resolve_this_name(ipaddr)) { if(config.debug & DEBUG_RESOLVER) - { - logg(" ---> \"\" (configured to not resolve %s host names)", - IPv6 ? "IPv6" : "IPv4"); - } + logg(" ---> \"\" (configured to not resolve host name)"); + + // Return fixed position of empty string return 0; } diff --git a/src/resolve.h b/src/resolve.h index c8516bf92..6598faa9e 100644 --- a/src/resolve.h +++ b/src/resolve.h @@ -12,6 +12,8 @@ void *DNSclient_thread(void *val); char *resolveHostname(const char *addr); +bool resolve_names(void) __attribute__((pure)); +bool resolve_this_name(const char *ipaddr) __attribute__((pure)); // musl does not define MAXHOSTNAMELEN // If it is not defined, we set the value From 9751ae9efc27d3bea539a3a08aebfb6d9a5ba405 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 1 Dec 2020 14:09:50 +0100 Subject: [PATCH 07/12] Do not try to resolve IPs for records without hostnames in the network_addresses table. Signed-off-by: DL6ER --- src/database/database-thread.c | 5 -- src/database/network-table.c | 137 --------------------------------- src/enums.h | 1 - src/events.c | 2 - src/resolve.c | 1 - 5 files changed, 146 deletions(-) diff --git a/src/database/database-thread.c b/src/database/database-thread.c index 2b7ab049d..320ec3334 100644 --- a/src/database/database-thread.c +++ b/src/database/database-thread.c @@ -84,11 +84,6 @@ void *DB_thread(void *val) if(get_and_clear_event(RELOAD_PRIVACY_LEVEL)) get_privacy_level(NULL); - // Try to resolve host names from clients in the network table - // which have empty/undefined host names - if(get_and_clear_event(RERESOLVE_DATABASE_NAMES)) - resolveNetworkTableNames(); - // Import alias-clients if(get_and_clear_event(REIMPORT_ALIASCLIENTS)) { diff --git a/src/database/network-table.c b/src/database/network-table.c index 1fabb3ddc..bc045c523 100644 --- a/src/database/network-table.c +++ b/src/database/network-table.c @@ -19,7 +19,6 @@ #include "../timers.h" // struct config #include "../config.h" -//#include "../datastructure.h" // resolveHostname() #include "../resolve.h" @@ -1857,139 +1856,3 @@ char *__attribute__((malloc)) getIfaceFromIP(const char *ipaddr) return iface; } - -// Resolve unknown names of recently seen IP addresses in network table -void resolveNetworkTableNames(void) -{ - if(!FTL_DB_avail()) - { - logg("resolveNetworkTableNames() - Database not available"); - return; - } - - // Check if we want to resolve host names - if(!resolve_names()) - { - if(config.debug & DEBUG_DATABASE) - logg("resolveNetworkTableNames() - configured to not resolve host names"); - return; - } - - const char sql[] = "BEGIN TRANSACTION IMMEDIATE"; - int rc = dbquery(sql); - if( rc != SQLITE_OK ) - { - const char *text; - if( rc == SQLITE_BUSY ) - { - text = "WARNING"; - } - else - { - text = "ERROR"; - } - - // dbquery() above already logs the reson for why the query failed - logg("%s: Trying to resolve unknown network table host names (\"%s\") failed", text, sql); - - return; - } - - // Get IP addresses seen within the last 24 hours with empty or NULL host names - const char querystr[] = "SELECT ip FROM network_addresses " - "WHERE lastSeen > cast(strftime('%%s', 'now') as int)-86400;"; - - // Prepare query - sqlite3_stmt *table_stmt = NULL; - rc = sqlite3_prepare_v2(FTL_db, querystr, -1, &table_stmt, NULL); - if(rc != SQLITE_OK) - { - logg("resolveNetworkTableNames() - SQL error prepare: %s", - sqlite3_errstr(rc)); - sqlite3_finalize(table_stmt); - return; - } - - // Get data - while((rc = sqlite3_step(table_stmt)) == SQLITE_ROW) - { - // Get IP address from database - const char *ip = (const char*)sqlite3_column_text(table_stmt, 0); - - if(config.debug & DEBUG_DATABASE) - logg("Resolving database IP %s", ip); - - // Try to obtain host name - char *newname = resolveHostname(ip); - - if(config.debug & DEBUG_DATABASE) - logg("---> \"%s\"", newname); - - // Store new host name in database if not empty - if(newname != NULL && strlen(newname) > 0) - { - const char updatestr[] = "UPDATE network_addresses " - "SET name = ?1," - "nameUpdated = cast(strftime('%s', 'now') as int) " - "WHERE ip = ?2;"; - sqlite3_stmt *update_stmt = NULL; - int rc2 = sqlite3_prepare_v2(FTL_db, updatestr, -1, &update_stmt, NULL); - if(rc2 != SQLITE_OK){ - logg("resolveNetworkTableNames(%s -> \"%s\") - SQL error prepare: %s", - ip, newname, sqlite3_errstr(rc2)); - sqlite3_finalize(update_stmt); - break; - } - - // Bind newname to prepared statement - if((rc2 = sqlite3_bind_text(update_stmt, 1, newname, -1, SQLITE_STATIC)) != SQLITE_OK) - { - logg("resolveNetworkTableNames(%s -> \"%s\"): Failed to bind newname: %s", - ip, newname, sqlite3_errstr(rc2)); - sqlite3_finalize(update_stmt); - break; - } - - // Bind ip to prepared statement - if((rc2 = sqlite3_bind_text(update_stmt, 2, ip, -1, SQLITE_STATIC)) != SQLITE_OK) - { - logg("resolveNetworkTableNames(%s -> \"%s\"): Failed to bind ip: %s", - ip, newname, sqlite3_errstr(rc2)); - sqlite3_finalize(update_stmt); - break; - } - - if(config.debug & DEBUG_DATABASE) - logg("dbquery: \"%s\" with ?1 = \"%s\" and ?2 = \"%s\"", updatestr, newname, ip); - - rc2 = sqlite3_step(update_stmt); - if(rc2 != SQLITE_BUSY && rc2 != SQLITE_DONE) - { - // Any return code that is neither SQLITE_BUSY not SQLITE_ROW - // is a real error we should log - logg("resolveNetworkTableNames(%s -> \"%s\"): Failed to perform step: %s", - ip, newname, sqlite3_errstr(rc2)); - sqlite3_finalize(update_stmt); - break; - } - - // Finalize host name update statement - sqlite3_finalize(update_stmt); - } - free(newname); - } - - // Possible error handling and reporting - if(rc != SQLITE_DONE) - { - logg("resolveNetworkTableNames() - SQL error step: %s", - sqlite3_errstr(rc)); - sqlite3_finalize(table_stmt); - return; - } - - // Close and unlock database connection - sqlite3_finalize(table_stmt); - - dbquery("COMMIT"); -} diff --git a/src/enums.h b/src/enums.h index 7ac770031..78752b0c7 100644 --- a/src/enums.h +++ b/src/enums.h @@ -147,7 +147,6 @@ enum events { RERESOLVE_HOSTNAMES, REIMPORT_ALIASCLIENTS, PARSE_NEIGHBOR_CACHE, - RERESOLVE_DATABASE_NAMES, EVENTS_MAX } __attribute__ ((packed)); diff --git a/src/events.c b/src/events.c index 8cd3a7df9..845837026 100644 --- a/src/events.c +++ b/src/events.c @@ -96,8 +96,6 @@ static const char *eventtext(const enum events event) return "REIMPORT_ALIASCLIENTS"; case PARSE_NEIGHBOR_CACHE: return "PARSE_NEIGHBOR_CACHE"; - case RERESOLVE_DATABASE_NAMES: - return "RERESOLVE_DATABASE_NAMES"; case EVENTS_MAX: // fall through default: return "UNKNOWN"; diff --git a/src/resolve.c b/src/resolve.c index f7c425bb4..3508a7244 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -544,7 +544,6 @@ void *DNSclient_thread(void *val) if(resolver_ready && (time(NULL) % RERESOLVE_INTERVAL == 0)) { set_event(RERESOLVE_HOSTNAMES); // done below - set_event(RERESOLVE_DATABASE_NAMES); // done in database thread } // Process resolver related event queue elements From b833b73a4d14dff002f7028b153040fecf165d05 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 1 Dec 2020 14:18:44 +0100 Subject: [PATCH 08/12] Add new REFRESH_HOSTNAMES option Signed-off-by: DL6ER --- src/config.c | 20 ++++++++++++++++++++ src/config.h | 1 + src/enums.h | 6 ++++++ src/resolve.c | 15 +++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/src/config.c b/src/config.c index d7bcea656..0bae6280e 100644 --- a/src/config.c +++ b/src/config.c @@ -424,6 +424,26 @@ void read_FTLconf(void) else logg(" EDNS0_ECS: Don't use ECS information"); + // REFRESH_HOSTNAMES + // defaults to: IPV4 + buffer = parse_FTLconf(fp, "REFRESH_HOSTNAMES"); + + if(buffer != NULL && strcasecmp(buffer, "ALL") == 0) + { + config.refresh_hostnames = REFRESH_ALL; + logg(" REFRESH_HOSTNAMES: Periodically refreshing all names"); + } + else if(buffer != NULL && strcasecmp(buffer, "NONE") == 0) + { + config.refresh_hostnames = REFRESH_NONE; + logg(" REFRESH_HOSTNAMES: Not periodically refreshing names"); + } + else + { + config.refresh_hostnames = REFRESH_IPV4_ONLY; + logg(" REFRESH_HOSTNAMES: Periodically refreshing IPv4 names"); + } + // Read DEBUG_... setting from pihole-FTL.conf read_debuging_settings(fp); diff --git a/src/config.h b/src/config.h index c15cab68b..36c297146 100644 --- a/src/config.h +++ b/src/config.h @@ -34,6 +34,7 @@ typedef struct { unsigned int network_expire; enum privacy_level privacylevel; enum blocking_mode blockingmode; + enum refresh_hostnames refresh_hostnames; bool socket_listenlocal; bool analyze_AAAA; bool resolveIPv6; diff --git a/src/enums.h b/src/enums.h index 78752b0c7..35caf92c0 100644 --- a/src/enums.h +++ b/src/enums.h @@ -150,4 +150,10 @@ enum events { EVENTS_MAX } __attribute__ ((packed)); +enum refresh_hostnames { + REFRESH_ALL, + REFRESH_IPV4_ONLY, + REFRESH_NONE +} __attribute__ ((packed)); + #endif // ENUMS_H diff --git a/src/resolve.c b/src/resolve.c index 3508a7244..790964f12 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -407,6 +407,21 @@ static void resolveClients(const bool onlynew) continue; } + // Check if we want to resolve an IPv6 address + bool IPv6 = false; + const char *ipaddr = NULL; + if((ipaddr = getstr(ippos)) != NULL && strstr(ipaddr,":") != NULL) + IPv6 = true; + + // If we're in refreshing mode (onlynew == false), we skip clients if + // either IPv4-only or none is selected + if(config.refresh_hostnames == REFRESH_NONE || + (config.refresh_hostnames == REFRESH_IPV4_ONLY && IPv6)) + { + skipped++; + continue; + } + // Obtain/update hostname of this client size_t newnamepos = resolveAndAddHostname(ippos, oldnamepos); From 01c36ef9381b6708b38e2f4f6c6c4ea499921178 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 1 Dec 2020 22:00:35 +0100 Subject: [PATCH 09/12] Use case-insensitive comparison of MAC address to ensure capitilization does not play a role. Signed-off-by: DL6ER --- src/database/network-table.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/database/network-table.c b/src/database/network-table.c index 1fabb3ddc..1c84fe155 100644 --- a/src/database/network-table.c +++ b/src/database/network-table.c @@ -1161,17 +1161,7 @@ void parse_neighbor_cache(void) // only the changed to the database are collected for latter // commitment. Read-only access such as this SELECT command will be // executed immediately on the database. - char *querystr = NULL; - rc = asprintf(&querystr, "SELECT id FROM network WHERE hwaddr = \'%s\';", hwaddr); - if(querystr == NULL || rc < 0) - { - logg("Memory allocation failed in parse_arp_cache(): %i", rc); - break; - } - - // Perform SQL query - int dbID = db_query_int(querystr); - free(querystr); + int dbID = find_device_by_hwaddr(hwaddr); if(dbID == DB_FAILED) { @@ -1393,19 +1383,19 @@ bool unify_hwaddr(void) // Update firstSeen with lowest value across all rows with the same hwaddr dbquery("UPDATE network "\ - "SET firstSeen = (SELECT MIN(firstSeen) FROM network WHERE hwaddr = \'%s\') "\ + "SET firstSeen = (SELECT MIN(firstSeen) FROM network WHERE hwaddr = \'%s\' COLLATE NOCASE) "\ "WHERE id = %i;",\ hwaddr, id); // Update numQueries with sum of all rows with the same hwaddr dbquery("UPDATE network "\ - "SET numQueries = (SELECT SUM(numQueries) FROM network WHERE hwaddr = \'%s\') "\ + "SET numQueries = (SELECT SUM(numQueries) FROM network WHERE hwaddr = \'%s\' COLLATE NOCASE) "\ "WHERE id = %i;",\ hwaddr, id); // Remove all other lines with the same hwaddr but a different id dbquery("DELETE FROM network "\ - "WHERE hwaddr = \'%s\' "\ + "WHERE hwaddr = \'%s\' COLLATE NOCASE "\ "AND id != %i;",\ hwaddr, id); From 1bc9eb46a027326dcdc7622e2ad9874f5e9c4ab8 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 1 Dec 2020 22:17:33 +0100 Subject: [PATCH 10/12] Tweak code to restore compatibility with Gentoo gcc 10.2.0-r3 Signed-off-by: DL6ER --- src/dnsmasq_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c index 340aed1c8..c97b68d26 100644 --- a/src/dnsmasq_interface.c +++ b/src/dnsmasq_interface.c @@ -551,12 +551,12 @@ bool _FTL_new_query(const unsigned int flags, const char *name, // 127.0.0.1 to avoid queries originating from localhost of the // *distant* machine as queries coming from the *local* machine const sa_family_t family = (flags & F_IPV4) ? AF_INET : AF_INET6; - char clientIP[ADDRSTRLEN] = { 0 }; + char clientIP[ADDRSTRLEN+1] = { 0 }; if(config.edns0_ecs && edns->client_set) { // Use ECS provided client strncpy(clientIP, edns->client, ADDRSTRLEN); - clientIP[ADDRSTRLEN-1] = '\0'; + clientIP[ADDRSTRLEN] = '\0'; } else { From 5e8b6c4699e034402709f737642a52ddfa87ed9f Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 2 Dec 2020 21:19:20 +0100 Subject: [PATCH 11/12] Always try to resolve hostnames when seeing a client/upstream serer for the first time. Also when it wasn't recently active (may happen on re-import from database history). Signed-off-by: DL6ER --- src/resolve.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resolve.c b/src/resolve.c index 790964f12..64984c8e1 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -384,9 +384,9 @@ static void resolveClients(const bool onlynew) size_t ippos = client->ippos; size_t oldnamepos = client->namepos; - // Only try to resolve host names of clients which were recently active + // Only try to resolve host names of clients which were recently active if we are re-resolving // Limit for a "recently active" client is two hours ago - if(client->lastQuery < now - 2*60*60) + if(onlynew == false && client->lastQuery < now - 2*60*60) { if(config.debug & DEBUG_RESOLVER) { From 949a5d9f25e6a86778e24258bb5512ce70aa449b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 2 Dec 2020 21:44:57 +0100 Subject: [PATCH 12/12] Add more debugging output and ensure refreshing rules are really only used when refreshing Signed-off-by: DL6ER --- src/resolve.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/resolve.c b/src/resolve.c index 64984c8e1..cd71996ef 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -403,6 +403,11 @@ static void resolveClients(const bool onlynew) // If not, we will try to re-resolve all known clients if(onlynew && !newflag) { + if(config.debug & DEBUG_RESOLVER) + { + logg("Skipping client %s (%s) because it is not new", + getstr(ippos), getstr(oldnamepos)); + } skipped++; continue; } @@ -415,9 +420,15 @@ static void resolveClients(const bool onlynew) // If we're in refreshing mode (onlynew == false), we skip clients if // either IPv4-only or none is selected - if(config.refresh_hostnames == REFRESH_NONE || - (config.refresh_hostnames == REFRESH_IPV4_ONLY && IPv6)) + if(onlynew == false && + (config.refresh_hostnames == REFRESH_NONE || + (config.refresh_hostnames == REFRESH_IPV4_ONLY && IPv6))) { + if(config.debug & DEBUG_RESOLVER) + { + logg("Skipping client %s (%s) because it should not be refreshed", + getstr(ippos), getstr(oldnamepos)); + } skipped++; continue; }