From 2317c8998f68df73b2fcb25debec39c2e7a9fb75 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sat, 7 Mar 2020 10:58:19 +0100 Subject: [PATCH] Add all clients FTL knowns about to the network table. This requires a yet to be done modification to the web interface to hide the mock hardware addresses we generate for these devices. Signed-off-by: DL6ER --- src/database/network-table.c | 141 +++++++++++++++++++++++++++++------ src/database/query-table.c | 3 +- 2 files changed, 119 insertions(+), 25 deletions(-) diff --git a/src/database/network-table.c b/src/database/network-table.c index 03bdb572..2f1cb4e8 100644 --- a/src/database/network-table.c +++ b/src/database/network-table.c @@ -9,8 +9,8 @@ * Please see LICENSE file for your rights under this license. */ #include "FTL.h" -#include "network-table.h" -#include "common.h" +#include "database/network-table.h" +#include "database/common.h" #include "shmem.h" #include "memory.h" #include "log.h" @@ -31,7 +31,7 @@ bool create_network_table(void) "name TEXT, " \ "firstSeen INTEGER NOT NULL, " \ "lastQuery INTEGER NOT NULL, " \ - "numQueries INTEGER NOT NULL," \ + "numQueries INTEGER NOT NULL, " \ "macVendor TEXT);"); // Update database version to 3 @@ -132,9 +132,8 @@ void parse_neighbor_cache(void) // Prepare buffers char * linebuffer = NULL; - size_t linebuffersize = 0; - char ip[100], hwaddr[100], iface[100]; - unsigned int entries = 0; + size_t linebuffersize = 0u; + unsigned int entries = 0u, additional_entries = 0u; time_t now = time(NULL); // Start collecting database commands @@ -152,9 +151,16 @@ void parse_neighbor_cache(void) return; } + bool ARP_client[counters->clients]; + for(int i = 0; i < counters->clients; i++) + { + ARP_client[i] = false; + } + // Read ARP cache line by line while(getline(&linebuffer, &linebuffersize, arpfp) != -1) { + char ip[100], hwaddr[100], iface[100]; int num = sscanf(linebuffer, "%99s dev %99s lladdr %99s", ip, iface, hwaddr); @@ -177,7 +183,7 @@ void parse_neighbor_cache(void) ret = asprintf(&querystr, "SELECT id FROM network WHERE hwaddr = \'%s\';", hwaddr); if(querystr == NULL || ret < 0) { - logg("Memory allocation failed in parse_arp_cache(): %i", ret); + logg("Memory allocation failed in parse_arp_cache() [1]: %i", ret); break; } @@ -206,6 +212,7 @@ void parse_neighbor_cache(void) // findClientID() returned a non-negative index if(clientID >= 0) { + ARP_client[clientID] = true; client = getClient(clientID, true); hostname = getstr(client->namepos); } @@ -248,7 +255,7 @@ void parse_neighbor_cache(void) client->numQueriesARP = 0; // Store hostname if available - if(strlen(hostname) > 0) + if(hostname != NULL && strlen(hostname) > 0) { // Store host name dbquery("UPDATE network "\ @@ -265,31 +272,119 @@ void parse_neighbor_cache(void) // this pair already exists, the UNIQUE(network_id,ip) trigger // becomes active and the line is instead REPLACEd, causing the // lastQuery timestamp to be updated - dbquery("INSERT OR REPLACE INTO network_addresses "\ + dbquery("INSERT OR IGNORE INTO network_addresses "\ "(network_id,ip) VALUES(%i,\'%s\');", dbID, ip); // Count number of processed ARP cache entries entries++; } - // Actually update the database - if(dbquery("COMMIT") != SQLITE_OK) { - logg("ERROR: parse_neighbor_cache() failed!"); - unlock_shm(); - return; + // Close file handle + pclose(arpfp); + + // Finally, loop over all clients known to FTL and ensure we add them + // all to the database + for(int clientID = 0; clientID < counters->clients; clientID++) + { + // Skip if already handled above + if(ARP_client[clientID]) + continue; + + // Get client pointer + clientsData* client = getClient(clientID, true); + if(client == NULL) + continue; + + // Get hostname and IP address of this client + const char *hostname, *ipaddr; + ipaddr = getstr(client->ippos); + hostname = getstr(client->namepos); + + // Get device with mock-hardware address (ip-) + char* querystr = NULL; + ret = asprintf(&querystr, "SELECT id FROM network WHERE hwaddr = \'ip-%s\';", ipaddr); + if(querystr == NULL || ret < 0) + { + logg("Memory allocation failed in parse_arp_cache() [2]: %i", ret); + break; + } + + // Perform SQL query + int dbID = db_query_int(querystr); + free(querystr); + + if(dbID == DB_FAILED) + { + // SQLite error + break; + } + + // Device not in database, add new entry + if(dbID == DB_NODATA) + { + dbquery("INSERT INTO network "\ + "(hwaddr,interface,firstSeen,lastQuery,numQueries,name,macVendor) "\ + "VALUES (\'ip-%s\',\'N/A\',%lu, %ld, %u, \'%s\', \'N/A\');",\ + ipaddr, now, client->lastQuery, client->numQueriesARP, hostname); + + // Obtain ID which was given to this new entry + dbID = get_lastID(); + } + // Device already in database + else + { + // Update lastQuery. Only use new value if larger + // client->lastQuery may be zero if this + // client is only known from a database entry but has + // not been seen since then + dbquery("UPDATE network "\ + "SET lastQuery = MAX(lastQuery, %ld) "\ + "WHERE id = %i;",\ + client->lastQuery, dbID); + + // Update numQueries. Add queries seen since last update + // and reset counter afterwards + dbquery("UPDATE network "\ + "SET numQueries = numQueries + %u "\ + "WHERE id = %i;",\ + client->numQueriesARP, dbID); + client->numQueriesARP = 0; + + // Store hostname if available + if(hostname != NULL && strlen(hostname) > 0) + { + // Store host name + dbquery("UPDATE network "\ + "SET name = \'%s\' "\ + "WHERE id = %i;",\ + hostname, dbID); + } + } + + // Add IP/mock-MAC pair to address database + dbquery("INSERT OR IGNORE INTO network_addresses "\ + "(network_id,ip) VALUES(%i,\'%s\');", dbID, ipaddr); + + // Add to number of processed ARP cache entries + additional_entries++; } + // Actually update the database + if(dbquery("COMMIT") != SQLITE_OK) + logg("ERROR: parse_neighbor_cache() failed!"); + + // Close database connection + // We opened the connection in this function + dbclose(); + unlock_shm(); // Debug logging if(config.debug & DEBUG_ARP) - logg("ARP table processing (%i entries) took %.1f ms", entries, timer_elapsed_msec(ARP_TIMER)); - - // Close file handle - pclose(arpfp); - - // Close database connection - dbclose(); + { + logg("ARP table processing (%i entries from ARP, %i from FTL's cache) took %.1f ms", + entries, additional_entries, timer_elapsed_msec(ARP_TIMER)); + } } // Loop over all entries in network table and unify entries by their hwaddr @@ -374,9 +469,9 @@ static char* getMACVendor(const char* hwaddr) logg("getMACVenor(%s): %s does not exist", hwaddr, FTLfiles.macvendor_db); return strdup(""); } - else if(strlen(hwaddr) != 17) + else if(strlen(hwaddr) != 17 || strstr(hwaddr, "ip-") != NULL) { - // MAC address is incomplete + // MAC address is incomplete or mock address (for distant clients) if(config.debug & DEBUG_ARP) logg("getMACVenor(%s): MAC invalid (length %zu)", hwaddr, strlen(hwaddr)); return strdup(""); diff --git a/src/database/query-table.c b/src/database/query-table.c index 32a0de5e..83eebf41 100644 --- a/src/database/query-table.c +++ b/src/database/query-table.c @@ -376,10 +376,9 @@ void DB_read_queries(void) query->reply = REPLY_UNKNOWN; query->CNAME_domainID = -1; - // Set lastQuery timer and add one query for network table + // Set lastQuery timer for network table clientsData* client = getClient(clientID, true); client->lastQuery = queryTimeStamp; - client->numQueriesARP++; // Handle type counters if(type >= TYPE_A && type < TYPE_MAX)