Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to obtain host names from another address of the same device when nothing else is available #879

Merged
merged 5 commits into from
Sep 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/database/gravity-db.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,9 @@ static bool get_client_groupids(clientsData* client)
{
free(hwaddr);
hwaddr = NULL;
logg("Skipping mock-device hardware address lookup");

if(config.debug & DEBUG_CLIENTS)
logg("Skipping mock-device hardware address lookup");
}

// MAC address fallback: Try to synthesize MAC address from internal buffer
Expand All @@ -348,7 +350,9 @@ static bool get_client_groupids(clientsData* client)
snprintf(hwaddr, strlen, "%02X:%02X:%02X:%02X:%02X:%02X",
client->hwaddr[0], client->hwaddr[1], client->hwaddr[2],
client->hwaddr[3], client->hwaddr[4], client->hwaddr[5]);
logg("--> Obtained %s from internal ARP cache", hwaddr);

if(config.debug & DEBUG_CLIENTS)
logg("--> Obtained %s from internal ARP cache", hwaddr);
}
}

Expand Down Expand Up @@ -432,7 +436,8 @@ static bool get_client_groupids(clientsData* client)
{
free(hostname);
hostname = NULL;
logg("Skipping empty host name lookup");
if(config.debug & DEBUG_CLIENTS)
logg("Skipping empty host name lookup");
}
}

Expand Down Expand Up @@ -517,7 +522,8 @@ static bool get_client_groupids(clientsData* client)
{
free(interface);
interface = 0;
logg("Skipping empty interface lookup");
if(config.debug & DEBUG_CLIENTS)
logg("Skipping empty interface lookup");
}
}

Expand Down
124 changes: 51 additions & 73 deletions src/database/network-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -1581,103 +1581,87 @@ void updateMACVendorRecords(void)
dbclose();
}

char *__attribute__((malloc)) getDatabaseHostname(const char *ipaddr)
// Get hardware address of device identified by IP address
char *__attribute__((malloc)) getMACfromIP(const char *ipaddr)
Comment on lines -1584 to +1585
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct, git screwed up the diff. I removed the getDatabaseHostname() function altogether as (almost) the same is done by getNameFromIP() below.

{
// Test if this is an IPv6 address
bool IPv6 = false;
if(ipaddr != NULL && strstr(ipaddr,":") != NULL)
{
IPv6 = true;
}

// Do we want to resolve IPv4/IPv6 names at all?
if( (IPv6 && !config.resolveIPv6) ||
(!IPv6 && !config.resolveIPv4))
{
if(config.debug & DEBUG_RESOLVER)
{
logg(" ---> \"\" (configured to not resolve %s host names)",
IPv6 ? "IPv6" : "IPv4");
}
return strdup("");
}

// Open pihole-FTL.db database file if needed
const bool db_already_open = FTL_DB_avail();
if(!db_already_open && !dbopen())
{
logg("getDatabaseHostname(\"%s\") - Failed to open DB", ipaddr);
logg("getMACfromIP(\"%s\") - Failed to open DB", ipaddr);
return NULL;
}

// Prepare SQLite statement
// We request the most recent IP entry in case there an IP appears
// multiple times in the network_addresses table
sqlite3_stmt *stmt = NULL;
const char *querystr = "SELECT name FROM network_addresses "
"WHERE name IS NOT NULL AND ip = ?;";
const char *querystr = "SELECT hwaddr FROM network WHERE id = "
"(SELECT network_id FROM network_addresses "
"WHERE ip = ? GROUP BY ip HAVING max(lastSeen));";
int rc = sqlite3_prepare_v2(FTL_db, querystr, -1, &stmt, NULL);
if( rc != SQLITE_OK ){
logg("getDatabaseHostname(\"%s\") - SQL error prepare: %s",
logg("getMACfromIP(\"%s\") - SQL error prepare: %s",
ipaddr, sqlite3_errstr(rc));
if(!db_already_open)
dbclose();
return strdup("");
return NULL;
}

// Bind ipaddr to prepared statement
if((rc = sqlite3_bind_text(stmt, 1, ipaddr, -1, SQLITE_STATIC)) != SQLITE_OK)
{
logg("getDatabaseHostname(\"%s\"): Failed to bind ip: %s",
logg("getMACfromIP(\"%s\"): Failed to bind ip: %s",
ipaddr, sqlite3_errstr(rc));
sqlite3_reset(stmt);
sqlite3_finalize(stmt);
if(!db_already_open)
dbclose();
return strdup("");
return NULL;
}

char *hostname = NULL;
char *hwaddr = NULL;
rc = sqlite3_step(stmt);
if(rc == SQLITE_ROW)
{
// Database record found (result might be empty)
hostname = strdup((char*)sqlite3_column_text(stmt, 0));
hwaddr = strdup((char*)sqlite3_column_text(stmt, 0));
}
else
{
// Not found or error (will be logged automatically through our SQLite3 hook)
hostname = strdup("");
hwaddr = NULL;
}

if(config.debug & DEBUG_DATABASE && hwaddr != NULL)
logg("Found database hardware address %s -> %s", ipaddr, hwaddr);

// Finalize statement and close database handle
sqlite3_reset(stmt);
sqlite3_finalize(stmt);
if(!db_already_open)
dbclose();

return hostname;
return hwaddr;
}

// Get hardware address of device identified by IP address
char *__attribute__((malloc)) getMACfromIP(const char *ipaddr)
// Get host name of device identified by IP address
char *__attribute__((malloc)) getNameFromIP(const char *ipaddr)
{
// Open pihole-FTL.db database file if needed
const bool db_already_open = FTL_DB_avail();
if(!db_already_open && !dbopen())
{
logg("getMACfromIP(\"%s\") - Failed to open DB", ipaddr);
logg("getNameFromIP(\"%s\") - Failed to open DB", ipaddr);
return NULL;
}

// Prepare SQLite statement
// We request the most recent IP entry in case there an IP appears
// multiple times in the network_addresses table
// Check for a host name associated with the same IP address
sqlite3_stmt *stmt = NULL;
const char *querystr = "SELECT hwaddr FROM network WHERE id = "
"(SELECT network_id FROM network_addresses "
"WHERE ip = ? GROUP BY ip HAVING max(lastSeen));";
const char *querystr = "SELECT name FROM network_addresses WHERE name IS NOT NULL AND ip = ?;";
int rc = sqlite3_prepare_v2(FTL_db, querystr, -1, &stmt, NULL);
if( rc != SQLITE_OK ){
logg("getMACfromIP(\"%s\") - SQL error prepare: %s",
logg("getNameFromIP(\"%s\") - SQL error prepare: %s",
ipaddr, sqlite3_errstr(rc));
if(!db_already_open)
dbclose();
Expand All @@ -1687,7 +1671,7 @@ char *__attribute__((malloc)) getMACfromIP(const char *ipaddr)
// Bind ipaddr to prepared statement
if((rc = sqlite3_bind_text(stmt, 1, ipaddr, -1, SQLITE_STATIC)) != SQLITE_OK)
{
logg("getMACfromIP(\"%s\"): Failed to bind ip: %s",
logg("getNameFromIP(\"%s\"): Failed to bind ip: %s",
ipaddr, sqlite3_errstr(rc));
sqlite3_reset(stmt);
sqlite3_finalize(stmt);
Expand All @@ -1696,49 +1680,45 @@ char *__attribute__((malloc)) getMACfromIP(const char *ipaddr)
return NULL;
}

char *hwaddr = NULL;
char *name = NULL;
rc = sqlite3_step(stmt);
if(rc == SQLITE_ROW)
{
// Database record found (result might be empty)
hwaddr = strdup((char*)sqlite3_column_text(stmt, 0));
name = strdup((char*)sqlite3_column_text(stmt, 0));

if(config.debug & DEBUG_DATABASE)
logg("Found database host name (same address) %s -> %s", ipaddr, name);
}
else
{
// Not found or error (will be logged automatically through our SQLite3 hook)
hwaddr = NULL;
}

if(config.debug & DEBUG_DATABASE && hwaddr != NULL)
logg("Found database hardware address %s -> %s", ipaddr, hwaddr);

// Finalize statement and close database handle
// Finalize statement
sqlite3_reset(stmt);
sqlite3_finalize(stmt);
if(!db_already_open)
dbclose();

return hwaddr;
}

// Get host name of device identified by IP address
char *__attribute__((malloc)) getNameFromIP(const char *ipaddr)
{
// Open pihole-FTL.db database file if needed
const bool db_already_open = FTL_DB_avail();
if(!db_already_open && !dbopen())
// Return here if we found the name
if(name != NULL)
{
logg("getNameFromIP(\"%s\") - Failed to open DB", ipaddr);
return NULL;
if(!db_already_open)
dbclose();

return name;
}

// Prepare SQLite statement
sqlite3_stmt *stmt = NULL;
const char *querystr = "SELECT name FROM network_addresses WHERE name IS NOT NULL AND ip = ?;";
int rc = sqlite3_prepare_v2(FTL_db, querystr, -1, &stmt, NULL);
// Nothing found for the exact IP address
// Check for a host name associated with the same device (but another IP address)
querystr = "SELECT name FROM network_addresses "
"WHERE name IS NOT NULL AND "
"network_id = (SELECT network_id FROM network_addresses "
"WHERE ip = ?) "
"ORDER BY lastSeen DESC LIMIT 1";
rc = sqlite3_prepare_v2(FTL_db, querystr, -1, &stmt, NULL);
if( rc != SQLITE_OK ){
logg("getNameFromIP(\"%s\") - SQL error prepare: %s",
ipaddr, sqlite3_errstr(rc));
ipaddr, sqlite3_errstr(rc));
if(!db_already_open)
dbclose();
return NULL;
Expand All @@ -1748,30 +1728,28 @@ char *__attribute__((malloc)) getNameFromIP(const char *ipaddr)
if((rc = sqlite3_bind_text(stmt, 1, ipaddr, -1, SQLITE_STATIC)) != SQLITE_OK)
{
logg("getNameFromIP(\"%s\"): Failed to bind ip: %s",
ipaddr, sqlite3_errstr(rc));
ipaddr, sqlite3_errstr(rc));
sqlite3_reset(stmt);
sqlite3_finalize(stmt);
if(!db_already_open)
dbclose();
return NULL;
}

char *name = NULL;
rc = sqlite3_step(stmt);
if(rc == SQLITE_ROW)
{
// Database record found (result might be empty)
name = strdup((char*)sqlite3_column_text(stmt, 0));

if(config.debug & DEBUG_DATABASE)
logg("Found database host name (same device) %s -> %s", ipaddr, name);
}
else
{
// Not found or error (will be logged automatically through our SQLite3 hook)
name = NULL;
}

if(config.debug & DEBUG_DATABASE && name != NULL)
logg("Found database host name %s -> %s", ipaddr, name);

// Finalize statement and close database handle
sqlite3_reset(stmt);
sqlite3_finalize(stmt);
Expand Down
7 changes: 3 additions & 4 deletions src/database/network-table.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ bool create_network_addresses_with_names_table(void);
void parse_neighbor_cache(void);
void updateMACVendorRecords(void);
bool unify_hwaddr(void);
char* getDatabaseHostname(const char* ipaddr) __attribute__((malloc));
char* __attribute__((malloc)) getMACfromIP(const char* ipaddr);
char* __attribute__((malloc)) getNameFromIP(const char* ipaddr);
char* __attribute__((malloc)) getIfaceFromIP(const char* ipaddr);
char *getMACfromIP(const char* ipaddr) __attribute__((malloc));
char *getNameFromIP(const char* ipaddr) __attribute__((malloc));
char *getIfaceFromIP(const char* ipaddr) __attribute__((malloc));
void resolveNetworkTableNames(void);

#endif //NETWORKTABLE_H
34 changes: 21 additions & 13 deletions src/resolve.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,6 @@ char *resolveHostname(const char *addr)
IPv6 = true;
}

if( (IPv6 && !config.resolveIPv6) ||
(!IPv6 && !config.resolveIPv4))
{
if(config.debug & DEBUG_RESOLVER)
{
logg(" ---> \"\" (configured to not resolve %s host names)",
IPv6 ? "IPv6" : "IPv4");
}
return strdup("");
}

// 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
// address(es). If no server is given, the local host is tried. If no domain
Expand Down Expand Up @@ -285,6 +274,24 @@ 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))
{
if(config.debug & DEBUG_RESOLVER)
{
logg(" ---> \"\" (configured to not resolve %s host names)",
IPv6 ? "IPv6" : "IPv4");
}
return 0;
}

// Important: Don't hold a lock while resolving as the main thread
// (dnsmasq) needs to be operable during the call to resolveHostname()
char* newname = resolveHostname(ipaddr);
Expand All @@ -294,7 +301,7 @@ static size_t resolveAndAddHostname(size_t ippos, size_t oldnamepos)
if(strlen(newname) == 0 && config.names_from_netdb)
{
free(newname);
newname = getDatabaseHostname(ipaddr);
newname = getNameFromIP(ipaddr);
}

// Only store new newname if it is valid and differs from oldname
Expand All @@ -318,7 +325,8 @@ static size_t resolveAndAddHostname(size_t ippos, size_t oldnamepos)
logg("Not adding \"%s\" to buffer (unchanged)", oldname);
}

free(newname);
if(newname != NULL)
free(newname);
free(ipaddr);
free(oldname);

Expand Down