From 43124f71e6fca2f02f0c020cbe22de1da380ee90 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 18 May 2020 22:56:55 +0200 Subject: [PATCH] Try to resolve empty host names in the network_addresses table when re-resolving host names (typically once per hour). Do this only for fairly recent IP addresses (hard-coded 24h as we're speaking) to avoid unnecessary noice leading to inaccurate data. Signed-off-by: DL6ER --- src/daemon.c | 2 + src/daemon.h | 2 + src/dnsmasq_interface.c | 3 + src/resolve.c | 139 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 2 deletions(-) diff --git a/src/daemon.c b/src/daemon.c index a8e1bd21..5981a957 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -16,6 +16,8 @@ // sleepms() #include "timers.h" +bool resolver_ready = false; + void go_daemon(void) { // Create child process diff --git a/src/daemon.h b/src/daemon.h index d94f4cf5..79f6b204 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -16,4 +16,6 @@ char * getUserName(void); void removepid(void); void delay_startup(void); +extern bool resolver_ready; + #endif //DAEMON_H diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c index 9bc016fc..4f8176a9 100644 --- a/src/dnsmasq_interface.c +++ b/src/dnsmasq_interface.c @@ -834,6 +834,9 @@ void FTL_dnsmasq_reload(void) // Print current set of capabilities if requested via debug flag if(config.debug & DEBUG_CAPS) check_capabilities(); + + // Set resolver as ready + resolver_ready = true; } void _FTL_reply(const unsigned short flags, const char *name, const union all_addr *addr, const int id, diff --git a/src/resolve.c b/src/resolve.c index b02ae411..25ad84d5 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -22,6 +22,10 @@ #include "database/network-table.h" // struct _res #include +// FTL_db +#include "database/common.h" +// resolver_ready +#include "daemon.h" static bool res_initialized = false; @@ -397,15 +401,143 @@ void resolveForwardDestinations(const bool onlynew) } } +// Resolve unknown names of recently seen IP addresses in network table +static void resolveNetworkTableNames(void) +{ + // Open database file + if(!dbopen()) + { + logg("resolveNetworkTableNames() - Failed to open DB"); + 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); + dbclose(); + 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 (name IS NULL OR " + "name = '') AND " + "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); + dbclose(); + 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); + + // Try to obtain host name + char* newname = resolveHostname(ip); + + if(config.debug & DEBUG_RESOLVER) + logg("Resolving database IP %s -> %s", ip, newname); + + // Store new host name in database if not empty + if(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; + } + 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); + dbclose(); + return; + } + + // Close and unlock database connection + sqlite3_finalize(table_stmt); + dbclose(); +} + void *DNSclient_thread(void *val) { // Set thread name prctl(PR_SET_NAME, "DNS client", 0, 0, 0); + // Initial delay until we first try to resolve anything + sleepms(2000); + while(!killed) { // Run every minute to resolve only new clients and upstream servers - if(time(NULL) % RESOLVE_INTERVAL == 0) + if(resolver_ready && time(NULL) % RESOLVE_INTERVAL == 0) { // Try to resolve new client host names (onlynew=true) resolveClients(true); @@ -416,12 +548,15 @@ void *DNSclient_thread(void *val) } // Run every hour to update possibly changed client host names - if(time(NULL) % RERESOLVE_INTERVAL == 0) + if(resolver_ready && time(NULL) % RERESOLVE_INTERVAL == 0) { // Try to resolve all client host names (onlynew=false) resolveClients(false); // Try to resolve all upstream destination host names (onlynew=false) resolveForwardDestinations(false); + // Try to resolve host names from clients in the network table + // which have empty/undefined host names + resolveNetworkTableNames(); // Prevent immediate re-run of this routine sleepms(500); }