Remove globally defined queries array.

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2019-03-06 16:26:54 +01:00
parent b13c77b492
commit 810e36bef8
9 changed files with 301 additions and 243 deletions
+4 -1
View File
@@ -261,7 +261,6 @@ extern FTLFileNamesStruct FTLfiles;
extern countersStruct *counters;
extern ConfigStruct config;
extern queriesDataStruct *queries;
extern forwardedDataStruct *forwarded;
extern clientsDataStruct *clients;
extern domainsDataStruct *domains;
@@ -315,3 +314,7 @@ extern pthread_t socket_listenthread;
extern pthread_t DBthread;
extern pthread_t GCthread;
extern pthread_t DNSclientthread;
// Pointer getter functions
#define getQuery(queryID) _getQuery(queryID, __LINE__, __FUNCTION__, __FILE__)
queriesDataStruct* _getQuery(int queryID, int line, const char * function, const char * file);
+42 -41
View File
@@ -745,53 +745,53 @@ void getAllQueries(char *client_message, int *sock)
int i;
for(i=ibeg; i < counters->queries; i++)
{
validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__);
queriesDataStruct* query = getQuery(i);
// Check if this query has been create while in maximum privacy mode
if(queries[i].privacylevel >= PRIVACY_MAXIMUM) continue;
if(query->privacylevel >= PRIVACY_MAXIMUM) continue;
validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__);
validate_access("clients", queries[i].clientID, true, __LINE__, __FUNCTION__, __FILE__);
validate_access("domains", query->domainID, true, __LINE__, __FUNCTION__, __FILE__);
validate_access("clients", query->clientID, true, __LINE__, __FUNCTION__, __FILE__);
char *qtype = querytypes[queries[i].type - TYPE_A];
char *qtype = querytypes[query->type - TYPE_A];
// 1 = gravity.list, 4 = wildcard, 5 = black.list
if((queries[i].status == QUERY_GRAVITY ||
queries[i].status == QUERY_WILDCARD ||
queries[i].status == QUERY_BLACKLIST) && !showblocked)
if((query->status == QUERY_GRAVITY ||
query->status == QUERY_WILDCARD ||
query->status == QUERY_BLACKLIST) && !showblocked)
continue;
// 2 = forwarded, 3 = cached
if((queries[i].status == QUERY_FORWARDED ||
queries[i].status == QUERY_CACHE) && !showpermitted)
if((query->status == QUERY_FORWARDED ||
query->status == QUERY_CACHE) && !showpermitted)
continue;
// Skip those entries which so not meet the requested timeframe
if((from > queries[i].timestamp && from != 0) || (queries[i].timestamp > until && until != 0))
if((from > query->timestamp && from != 0) || (query->timestamp > until && until != 0))
continue;
// Skip if domain is not identical with what the user wants to see
if(filterdomainname && queries[i].domainID != domainid)
if(filterdomainname && query->domainID != domainid)
continue;
// Skip if client name and IP are not identical with what the user wants to see
if(filterclientname && queries[i].clientID != clientid)
if(filterclientname && query->clientID != clientid)
continue;
// Skip if query type is not identical with what the user wants to see
if(querytype != 0 && querytype != queries[i].type)
if(querytype != 0 && querytype != query->type)
continue;
if(filterforwarddest)
{
// Does the user want to see queries answered from blocking lists?
if(forwarddestid == -2 && queries[i].status != QUERY_GRAVITY
&& queries[i].status != QUERY_WILDCARD
&& queries[i].status != QUERY_BLACKLIST)
if(forwarddestid == -2 && query->status != QUERY_GRAVITY
&& query->status != QUERY_WILDCARD
&& query->status != QUERY_BLACKLIST)
continue;
// Does the user want to see queries answered from local cache?
else if(forwarddestid == -1 && queries[i].status != QUERY_CACHE)
else if(forwarddestid == -1 && query->status != QUERY_CACHE)
continue;
// Does the user want to see queries answered by an upstream server?
else if(forwarddestid >= 0 && forwarddestid != queries[i].forwardID)
else if(forwarddestid >= 0 && forwarddestid != query->forwardID)
continue;
}
@@ -800,23 +800,23 @@ void getAllQueries(char *client_message, int *sock)
char *domain = getDomainString(i);
// Similarly for the client
char *client;
if(strlen(getstr(clients[queries[i].clientID].namepos)) > 0)
if(strlen(getstr(clients[query->clientID].namepos)) > 0)
client = getClientNameString(i);
else
client = getClientIPString(i);
unsigned long delay = queries[i].response;
unsigned long delay = query->response;
// Check if received (delay should be smaller than 30min)
if(delay > 1.8e7)
delay = 0;
if(istelnet[*sock])
{
ssend(*sock,"%i %s %s %s %i %i %i %lu\n",queries[i].timestamp,qtype,domain,client,queries[i].status,queries[i].dnssec,queries[i].reply,delay);
ssend(*sock,"%i %s %s %s %i %i %i %lu\n",query->timestamp,qtype,domain,client,query->status,query->dnssec,query->reply,delay);
}
else
{
pack_int32(*sock, queries[i].timestamp);
pack_int32(*sock, query->timestamp);
// Use a fixstr because the length of qtype is always 4 (max is 31 for fixstr)
if(!pack_fixstr(*sock, qtype))
@@ -826,8 +826,8 @@ void getAllQueries(char *client_message, int *sock)
if(!pack_str32(*sock, domain) || !pack_str32(*sock, client))
return;
pack_uint8(*sock, queries[i].status);
pack_uint8(*sock, queries[i].dnssec);
pack_uint8(*sock, query->status);
pack_uint8(*sock, query->dnssec);
}
}
@@ -857,11 +857,11 @@ void getRecentBlocked(char *client_message, int *sock)
int found = 0;
for(i = counters->queries - 1; i > 0 ; i--)
{
validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__);
queriesDataStruct* query = getQuery(i);
if(queries[i].status == QUERY_GRAVITY ||
queries[i].status == QUERY_WILDCARD ||
queries[i].status == QUERY_BLACKLIST)
if(query->status == QUERY_GRAVITY ||
query->status == QUERY_WILDCARD ||
query->status == QUERY_BLACKLIST)
{
found++;
@@ -1160,11 +1160,12 @@ void getUnknownQueries(int *sock)
int i;
for(i=0; i < counters->queries; i++)
{
validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__);
if(queries[i].status != QUERY_UNKNOWN && queries[i].complete) continue;
queriesDataStruct* query = getQuery(i);
if(query->status != QUERY_UNKNOWN && query->complete) continue;
char type[5];
if(queries[i].type == TYPE_A)
if(query->type == TYPE_A)
{
strcpy(type,"IPv4");
}
@@ -1173,28 +1174,28 @@ void getUnknownQueries(int *sock)
strcpy(type,"IPv6");
}
validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__);
validate_access("clients", queries[i].clientID, true, __LINE__, __FUNCTION__, __FILE__);
validate_access("domains", query->domainID, true, __LINE__, __FUNCTION__, __FILE__);
validate_access("clients", query->clientID, true, __LINE__, __FUNCTION__, __FILE__);
char *client = getstr(clients[queries[i].clientID].ippos);
char *client = getstr(clients[query->clientID].ippos);
if(istelnet[*sock])
ssend(*sock, "%i %i %i %s %s %s %i %s\n", queries[i].timestamp, i, queries[i].id, type, getstr(domains[queries[i].domainID].domainpos), client, queries[i].status, queries[i].complete ? "true" : "false");
ssend(*sock, "%i %i %i %s %s %s %i %s\n", query->timestamp, i, query->id, type, getstr(domains[query->domainID].domainpos), client, query->status, query->complete ? "true" : "false");
else {
pack_int32(*sock, queries[i].timestamp);
pack_int32(*sock, queries[i].id);
pack_int32(*sock, query->timestamp);
pack_int32(*sock, query->id);
// Use a fixstr because the length of qtype is always 4 (max is 31 for fixstr)
if(!pack_fixstr(*sock, type))
return;
// Use str32 for domain and client because we have no idea how long they will be (max is 4294967295 for str32)
if(!pack_str32(*sock, getstr(domains[queries[i].domainID].domainpos)) || !pack_str32(*sock, client))
if(!pack_str32(*sock, getstr(domains[query->domainID].domainpos)) || !pack_str32(*sock, client))
return;
pack_uint8(*sock, queries[i].status);
pack_bool(*sock, queries[i].complete);
pack_uint8(*sock, query->status);
pack_bool(*sock, query->complete);
}
}
}
+34 -34
View File
@@ -456,14 +456,14 @@ void save_to_DB(void)
time_t newlasttimestamp = 0;
for(i = MAX(0, lastdbindex); i < counters->queries; i++)
{
validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__);
if(queries[i].db != 0)
queriesDataStruct* query = getQuery(i);
if(query->db != 0)
{
// Skip, already saved in database
continue;
}
if(!queries[i].complete && queries[i].timestamp > currenttimestamp-2)
if(!query->complete && query->timestamp > currenttimestamp-2)
{
// Break if a brand new query (age < 2 seconds) is not yet completed
// giving it a chance to be stored next time
@@ -473,7 +473,7 @@ void save_to_DB(void)
// Memory checks
validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__);
if(queries[i].privacylevel >= PRIVACY_MAXIMUM)
if(query->privacylevel >= PRIVACY_MAXIMUM)
{
// Skip, we never store nor count queries recorded
// while have been in maximum privacy mode in the database
@@ -481,13 +481,13 @@ void save_to_DB(void)
}
// TIMESTAMP
sqlite3_bind_int(stmt, 1, queries[i].timestamp);
sqlite3_bind_int(stmt, 1, query->timestamp);
// TYPE
sqlite3_bind_int(stmt, 2, queries[i].type);
sqlite3_bind_int(stmt, 2, query->type);
// STATUS
sqlite3_bind_int(stmt, 3, queries[i].status);
sqlite3_bind_int(stmt, 3, query->status);
// DOMAIN
char *domain = getDomainString(i);
@@ -498,10 +498,10 @@ void save_to_DB(void)
sqlite3_bind_text(stmt, 5, client, -1, SQLITE_TRANSIENT);
// FORWARD
if(queries[i].status == QUERY_FORWARDED && queries[i].forwardID > -1)
if(query->status == QUERY_FORWARDED && query->forwardID > -1)
{
validate_access("forwarded", queries[i].forwardID, true, __LINE__, __FUNCTION__, __FILE__);
sqlite3_bind_text(stmt, 6, getstr(forwarded[queries[i].forwardID].ippos), -1, SQLITE_TRANSIENT);
validate_access("forwarded", query->forwardID, true, __LINE__, __FUNCTION__, __FILE__);
sqlite3_bind_text(stmt, 6, getstr(forwarded[query->forwardID].ippos), -1, SQLITE_TRANSIENT);
}
else
{
@@ -531,19 +531,19 @@ void save_to_DB(void)
saved++;
// Mark this query as saved in the database by setting the corresponding ID
queries[i].db = ++lastID;
query->db = ++lastID;
// Total counter information (delta computation)
total++;
if(queries[i].status == QUERY_GRAVITY ||
queries[i].status == QUERY_BLACKLIST ||
queries[i].status == QUERY_WILDCARD ||
queries[i].status == QUERY_EXTERNAL_BLOCKED)
if(query->status == QUERY_GRAVITY ||
query->status == QUERY_BLACKLIST ||
query->status == QUERY_WILDCARD ||
query->status == QUERY_EXTERNAL_BLOCKED)
blocked++;
// Update lasttimestamp variable with timestamp of the latest stored query
if(queries[i].timestamp > newlasttimestamp)
newlasttimestamp = queries[i].timestamp;
if(query->timestamp > newlasttimestamp)
newlasttimestamp = query->timestamp;
}
// Finish prepared statement
@@ -777,25 +777,25 @@ void read_data_from_DB(void)
int queryIndex = counters->queries;
// Store this query in memory
validate_access("queries", queryIndex, false, __LINE__, __FUNCTION__, __FILE__);
validate_access("clients", clientID, true, __LINE__, __FUNCTION__, __FILE__);
queries[queryIndex].magic = MAGICBYTE;
queries[queryIndex].timestamp = queryTimeStamp;
queries[queryIndex].type = type;
queries[queryIndex].status = status;
queries[queryIndex].domainID = domainID;
queries[queryIndex].clientID = clientID;
queries[queryIndex].forwardID = forwardID;
queries[queryIndex].timeidx = timeidx;
queries[queryIndex].db = dbid;
queries[queryIndex].id = 0;
queries[queryIndex].complete = true; // Mark as all information is available
queries[queryIndex].response = 0;
queries[queryIndex].AD = false;
queries[queryIndex].dnssec = DNSSEC_UNKNOWN;
queries[queryIndex].reply = REPLY_UNKNOWN;
queriesDataStruct* query = getQuery(queryIndex);
query->magic = MAGICBYTE;
query->timestamp = queryTimeStamp;
query->type = type;
query->status = status;
query->domainID = domainID;
query->clientID = clientID;
query->forwardID = forwardID;
query->timeidx = timeidx;
query->db = dbid;
query->id = 0;
query->complete = true; // Mark as all information is available
query->response = 0;
query->AD = false;
query->dnssec = DNSSEC_UNKNOWN;
query->reply = REPLY_UNKNOWN;
// Set lastQuery timer and add one query for network table
validate_access("clients", clientID, true, __LINE__, __FUNCTION__, __FILE__);
clients[clientID].lastQuery = queryTimeStamp;
clients[clientID].numQueriesARP++;
+12 -9
View File
@@ -184,10 +184,11 @@ bool isValidIPv6(const char *addr)
// only when appropriate for the requested query
char *getDomainString(int queryID)
{
if(queries[queryID].privacylevel < PRIVACY_HIDE_DOMAINS)
queriesDataStruct* query = getQuery(queryID);
if(query->privacylevel < PRIVACY_HIDE_DOMAINS)
{
validate_access("domains", queries[queryID].domainID, true, __LINE__, __FUNCTION__, __FILE__);
return getstr(domains[queries[queryID].domainID].domainpos);
validate_access("domains", query->domainID, true, __LINE__, __FUNCTION__, __FILE__);
return getstr(domains[query->domainID].domainpos);
}
else
return HIDDEN_DOMAIN;
@@ -197,10 +198,11 @@ char *getDomainString(int queryID)
// only when appropriate for the requested query
char *getClientIPString(int queryID)
{
if(queries[queryID].privacylevel < PRIVACY_HIDE_DOMAINS_CLIENTS)
queriesDataStruct* query = getQuery(queryID);
if(query->privacylevel < PRIVACY_HIDE_DOMAINS_CLIENTS)
{
validate_access("clients", queries[queryID].clientID, true, __LINE__, __FUNCTION__, __FILE__);
return getstr(clients[queries[queryID].clientID].ippos);
validate_access("clients", query->clientID, true, __LINE__, __FUNCTION__, __FILE__);
return getstr(clients[query->clientID].ippos);
}
else
return HIDDEN_CLIENT;
@@ -210,10 +212,11 @@ char *getClientIPString(int queryID)
// only when appropriate for the requested query
char *getClientNameString(int queryID)
{
if(queries[queryID].privacylevel < PRIVACY_HIDE_DOMAINS_CLIENTS)
queriesDataStruct* query = getQuery(queryID);
if(query->privacylevel < PRIVACY_HIDE_DOMAINS_CLIENTS)
{
validate_access("clients", queries[queryID].clientID, true, __LINE__, __FUNCTION__, __FILE__);
return getstr(clients[queries[queryID].clientID].namepos);
validate_access("clients", query->clientID, true, __LINE__, __FUNCTION__, __FILE__);
return getstr(clients[query->clientID].namepos);
}
else
return HIDDEN_CLIENT;
+110 -78
View File
@@ -140,31 +140,31 @@ void _FTL_new_query(unsigned int flags, char *name, struct all_addr *addr, char
int clientID = findClientID(client, true);
// Save everything
validate_access("queries", queryID, false, __LINE__, __FUNCTION__, __FILE__);
queries[queryID].magic = MAGICBYTE;
queries[queryID].timestamp = querytimestamp;
queries[queryID].type = querytype;
queries[queryID].status = QUERY_UNKNOWN;
queries[queryID].domainID = domainID;
queries[queryID].clientID = clientID;
queries[queryID].timeidx = timeidx;
queriesDataStruct* query = getQuery(queryID);
query->magic = MAGICBYTE;
query->timestamp = querytimestamp;
query->type = querytype;
query->status = QUERY_UNKNOWN;
query->domainID = domainID;
query->clientID = clientID;
query->timeidx = timeidx;
// Initialize database rowID with zero, will be set when the query is stored in the long-term DB
queries[queryID].db = 0;
queries[queryID].id = id;
queries[queryID].complete = false;
queries[queryID].response = converttimeval(request);
query->db = 0;
query->id = id;
query->complete = false;
query->response = converttimeval(request);
// Initialize reply type
queries[queryID].reply = REPLY_UNKNOWN;
query->reply = REPLY_UNKNOWN;
// Store DNSSEC result for this domain
queries[queryID].dnssec = DNSSEC_UNSPECIFIED;
query->dnssec = DNSSEC_UNSPECIFIED;
// AD has not yet been received for this query
queries[queryID].AD = false;
query->AD = false;
// Check and apply possible privacy level rules
// The currently set privacy level (at the time the query is
// generated) is stored in the queries structure
get_privacy_level(NULL);
queries[queryID].privacylevel = config.privacylevel;
query->privacylevel = config.privacylevel;
// Increase DNS queries counter
counters->queries++;
@@ -227,16 +227,16 @@ static int findQueryID(int id)
// We iterate from the most recent query down to at most MAXITER queries in the past to avoid
// iterating through the entire array of queries
// MAX(0, a) is used to return 0 in case a is negative (negative array indices are harmful)
// Validate access only once for the maximum index (all lower will work)
int until = MAX(0, counters->queries-MAXITER);
int start = MAX(0, counters->queries-1);
validate_access("queries", until, false, __LINE__, __FUNCTION__, __FILE__);
// Check UUIDs of queries
for(int i = start; i >= until; i--)
if(queries[i].id == id)
{
queriesDataStruct* query = getQuery(i);
if(query->id == id)
return i;
}
// If not found
return -1;
@@ -275,13 +275,16 @@ void _FTL_forwarded(unsigned int flags, char *name, struct all_addr *addr, int i
return;
}
// Get query pointer
queriesDataStruct* query = getQuery(i);
// Proceed only if
// - current query has not been marked as replied to so far
// (it could be that answers from multiple forward
// destinations are coming in for the same query)
// - the query was formally known as cached but had to be forwarded
// (this is a special case further described below)
if(queries[i].complete && queries[i].status != QUERY_CACHE)
if(query->complete && query->status != QUERY_CACHE)
{
free(forward);
unlock_shm();
@@ -291,11 +294,11 @@ void _FTL_forwarded(unsigned int flags, char *name, struct all_addr *addr, int i
// Get ID of forward destination, create new forward destination record
// if not found in current data structure
int forwardID = findForwardID(forward, true);
queries[i].forwardID = forwardID;
query->forwardID = forwardID;
unsigned int timeidx = queries[i].timeidx;
unsigned int timeidx = query->timeidx;
if(queries[i].status == QUERY_CACHE)
if(query->status == QUERY_CACHE)
{
// Detect if we cached the <CNAME> but need to ask the upstream
// servers for the actual IPs now, we remove this query from the
@@ -322,7 +325,7 @@ void _FTL_forwarded(unsigned int flags, char *name, struct all_addr *addr, int i
gettimeofday(&response, 0);
// Reset timer, shift slightly into the past to acknowledge the time
// FTLDNS needed to look up the CNAME in its cache
queries[i].response = converttimeval(response) - queries[i].response;
query->response = converttimeval(response) - query->response;
}
else
{
@@ -330,14 +333,14 @@ void _FTL_forwarded(unsigned int flags, char *name, struct all_addr *addr, int i
// Query is no longer unknown
counters->unknown--;
// Hereby, this query is now fully determined
queries[i].complete = true;
query->complete = true;
}
// Set query status to forwarded only after the
// if(queries[i].status == QUERY_CACHE) { ... }
// if(query->status == QUERY_CACHE) { ... }
// from above as otherwise this check will always
// be negative
queries[i].status = QUERY_FORWARDED;
query->status = QUERY_FORWARDED;
// Update overTime data
overTime[timeidx].forwarded++;
@@ -424,7 +427,10 @@ void _FTL_reply(unsigned short flags, char *name, struct all_addr *addr, int id,
return;
}
if(queries[i].reply != REPLY_UNKNOWN)
// Get query pointer
queriesDataStruct* query = getQuery(i);
if(query->reply != REPLY_UNKNOWN)
{
// Nothing to be done here
unlock_shm();
@@ -432,18 +438,18 @@ void _FTL_reply(unsigned short flags, char *name, struct all_addr *addr, int id,
}
// Determine if this reply is an exact match for the queried domain
int domainID = queries[i].domainID;
int domainID = query->domainID;
validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__);
bool isExactMatch = (name != NULL && strcmp(getstr(domains[domainID].domainpos), name) == 0);
if((flags & F_CONFIG) && isExactMatch && !queries[i].complete)
if((flags & F_CONFIG) && isExactMatch && !query->complete)
{
// Answered from local configuration, might be a wildcard or user-provided
// This query is no longer unknown
counters->unknown--;
// Get time index
unsigned int timeidx = queries[i].timeidx;
unsigned int timeidx = query->timeidx;
if(strcmp(answer, "(NXDOMAIN)") == 0 ||
strcmp(answer, "0.0.0.0") == 0 ||
@@ -453,13 +459,13 @@ void _FTL_reply(unsigned short flags, char *name, struct all_addr *addr, int id,
counters->blocked++;
overTime[timeidx].blocked++;
validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__);
domains[queries[i].domainID].blockedcount++;
validate_access("domains", query->domainID, true, __LINE__, __FUNCTION__, __FILE__);
domains[query->domainID].blockedcount++;
validate_access("clients", queries[i].clientID, true, __LINE__, __FUNCTION__, __FILE__);
clients[queries[i].clientID].blockedcount++;
validate_access("clients", query->clientID, true, __LINE__, __FUNCTION__, __FILE__);
clients[query->clientID].blockedcount++;
queries[i].status = QUERY_WILDCARD;
query->status = QUERY_WILDCARD;
}
else
{
@@ -467,14 +473,14 @@ void _FTL_reply(unsigned short flags, char *name, struct all_addr *addr, int id,
counters->cached++;
overTime[timeidx].cached++;
queries[i].status = QUERY_CACHE;
query->status = QUERY_CACHE;
}
// Save reply type and update individual reply counters
save_reply_type(flags, i, response);
// Hereby, this query is now fully determined
queries[i].complete = true;
query->complete = true;
}
else if((flags & F_FORWARD) && isExactMatch)
{
@@ -482,7 +488,7 @@ void _FTL_reply(unsigned short flags, char *name, struct all_addr *addr, int id,
save_reply_type(flags, i, response);
// If received NXDOMAIN and AD bit is set, Quad9 may have blocked this query
if(flags & F_NXDOMAIN && queries[i].AD)
if(flags & F_NXDOMAIN && query->AD)
{
query_externally_blocked(i);
}
@@ -504,7 +510,7 @@ void _FTL_reply(unsigned short flags, char *name, struct all_addr *addr, int id,
// Save reply type and update individual reply counters
save_reply_type(flags, i, response);
}
else if(isExactMatch && !queries[i].complete)
else if(isExactMatch && !query->complete)
{
logg("*************************** unknown REPLY ***************************");
print_flags(flags);
@@ -568,26 +574,30 @@ static void detect_blocked_IP(unsigned short flags, char* answer, int queryID)
static void query_externally_blocked(int i)
{
unsigned int timeidx = queries[i].timeidx;
// Get query pointer
queriesDataStruct* query = getQuery(i);
// Get time index
unsigned int timeidx = query->timeidx;
// Correct counters if necessary ...
if(queries[i].status == QUERY_FORWARDED)
if(query->status == QUERY_FORWARDED)
{
counters->forwardedqueries--;
overTime[timeidx].forwarded--;
validate_access("forwarded", queries[i].forwardID, true, __LINE__, __FUNCTION__, __FILE__);
forwarded[queries[i].forwardID].count--;
validate_access("forwarded", query->forwardID, true, __LINE__, __FUNCTION__, __FILE__);
forwarded[query->forwardID].count--;
}
// ... but as blocked
counters->blocked++;
overTime[timeidx].blocked++;
validate_access("domains", queries[i].domainID, true, __LINE__, __FUNCTION__, __FILE__);
domains[queries[i].domainID].blockedcount++;
validate_access("clients", queries[i].clientID, true, __LINE__, __FUNCTION__, __FILE__);
clients[queries[i].clientID].blockedcount++;
validate_access("domains", query->domainID, true, __LINE__, __FUNCTION__, __FILE__);
domains[query->domainID].blockedcount++;
validate_access("clients", query->clientID, true, __LINE__, __FUNCTION__, __FILE__);
clients[query->clientID].blockedcount++;
queries[i].status = QUERY_EXTERNAL_BLOCKED;
query->status = QUERY_EXTERNAL_BLOCKED;
}
void _FTL_cache(unsigned int flags, char *name, struct all_addr *addr, char *arg, int id, const char* file, const int line)
@@ -669,10 +679,20 @@ void _FTL_cache(unsigned int flags, char *name, struct all_addr *addr, char *arg
}
int i = findQueryID(id);
if(i < 0 || queries[i].complete)
if(i < 0)
{
// This may happen e.g. if the original query was a PTR query or "pi.hole"
// as we ignore them altogether or if the query is already complete
// as we ignore them altogether
unlock_shm();
return;
}
// Get query pointer
queriesDataStruct* query = getQuery(i);
if(query->complete)
{
// Skip query if already complete
unlock_shm();
return;
}
@@ -681,25 +701,25 @@ void _FTL_cache(unsigned int flags, char *name, struct all_addr *addr, char *arg
counters->unknown--;
// Get time index
unsigned int timeidx = queries[i].timeidx;
unsigned int timeidx = query->timeidx;
int domainID = queries[i].domainID;
int domainID = query->domainID;
validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__);
int clientID = queries[i].clientID;
int clientID = query->clientID;
validate_access("clients", clientID, true, __LINE__, __FUNCTION__, __FILE__);
// Mark this query as blocked if domain was matched by a regex
if(domains[domainID].regexmatch == REGEX_BLOCKED)
requesttype = QUERY_WILDCARD;
queries[i].status = requesttype;
query->status = requesttype;
// Detect if returned IP indicates that this query was blocked
detect_blocked_IP(flags, dest, i);
// Re-read requesttype as detect_blocked_IP() might have changed it
requesttype = queries[i].status;
requesttype = query->status;
// Handle counters accordingly
switch(requesttype)
@@ -726,7 +746,7 @@ void _FTL_cache(unsigned int flags, char *name, struct all_addr *addr, char *arg
save_reply_type(flags, i, response);
// Hereby, this query is now fully determined
queries[i].complete = true;
query->complete = true;
}
else
{
@@ -753,21 +773,24 @@ void _FTL_dnssec(int status, int id, const char* file, const int line)
return;
}
// Get query pointer
queriesDataStruct* query = getQuery(i);
// Debug logging
if(config.debug & DEBUG_QUERIES)
{
int domainID = queries[i].domainID;
int domainID = query->domainID;
validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__);
logg("**** got DNSSEC details for %s: %i (ID %i, %s:%i)", getstr(domains[domainID].domainpos), status, id, file, line);
}
// Iterate through possible values
if(status == STAT_SECURE)
queries[i].dnssec = DNSSEC_SECURE;
query->dnssec = DNSSEC_SECURE;
else if(status == STAT_INSECURE)
queries[i].dnssec = DNSSEC_INSECURE;
query->dnssec = DNSSEC_INSECURE;
else
queries[i].dnssec = DNSSEC_BOGUS;
query->dnssec = DNSSEC_BOGUS;
unlock_shm();
}
@@ -792,6 +815,10 @@ void _FTL_upstream_error(unsigned int rcode, int id, const char* file, const int
unlock_shm();
return;
}
// Get query pointer
queriesDataStruct* query = getQuery(i);
// Translate dnsmasq's rcode into something we can use
char *rcodestr = NULL;
bool alloc = false;
@@ -799,27 +826,27 @@ void _FTL_upstream_error(unsigned int rcode, int id, const char* file, const int
{
case SERVFAIL:
rcodestr = "SERVFAIL";
queries[i].reply = REPLY_SERVFAIL;
query->reply = REPLY_SERVFAIL;
break;
case REFUSED:
rcodestr = "REFUSED";
queries[i].reply = REPLY_REFUSED;
query->reply = REPLY_REFUSED;
break;
case NOTIMP:
rcodestr = "NOT IMPLEMENTED";
queries[i].reply = REPLY_NOTIMP;
query->reply = REPLY_NOTIMP;
break;
default:
if(asprintf(&rcodestr, "Unknown error type (%u)", rcode) > -1)
alloc = true;
queries[i].reply = REPLY_OTHER;
query->reply = REPLY_OTHER;
break;
}
// Debug logging
if(config.debug & DEBUG_QUERIES)
{
int domainID = queries[i].domainID;
int domainID = query->domainID;
validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__);
logg("**** got error report for %s: %s (ID %i, %s:%i)", getstr(domains[domainID].domainpos), rcodestr, id, file, line);
}
@@ -855,15 +882,18 @@ void _FTL_header_ADbit(unsigned char header4, unsigned int rcode, int id, const
return;
}
// Get query pointer
queriesDataStruct* query = getQuery(i);
if(config.debug & DEBUG_QUERIES)
{
int domainID = queries[i].domainID;
int domainID = query->domainID;
validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__);
logg("**** AD bit set for %s (ID %i, RCODE %u, %s:%i)", getstr(domains[domainID].domainpos), id, rcode, file, line);
}
// Store AD bit in query data
queries[i].AD = true;
query->AD = true;
// If the response code (rcode) is NXDOMAIN, we may be seeing a response from
// an externally blocked query. As they are not always accompany a necessary
@@ -907,50 +937,52 @@ void print_flags(unsigned int flags)
void save_reply_type(unsigned int flags, int queryID, struct timeval response)
{
// Get query pointer
queriesDataStruct* query = getQuery(queryID);
// Iterate through possible values
validate_access("queries", queryID, false, __LINE__, __FUNCTION__, __FILE__);
if(flags & F_NEG)
{
if(flags & F_NXDOMAIN)
{
// NXDOMAIN
queries[queryID].reply = REPLY_NXDOMAIN;
query->reply = REPLY_NXDOMAIN;
counters->reply_NXDOMAIN++;
}
else
{
// NODATA(-IPv6)
queries[queryID].reply = REPLY_NODATA;
query->reply = REPLY_NODATA;
counters->reply_NODATA++;
}
}
else if(flags & F_CNAME)
{
// <CNAME>
queries[queryID].reply = REPLY_CNAME;
query->reply = REPLY_CNAME;
counters->reply_CNAME++;
}
else if(flags & F_REVERSE)
{
// reserve lookup
queries[queryID].reply = REPLY_DOMAIN;
query->reply = REPLY_DOMAIN;
counters->reply_domain++;
}
else if(flags & F_RRNAME)
{
// TXT query
queries[queryID].reply = REPLY_RRNAME;
query->reply = REPLY_RRNAME;
}
else
{
// Valid IP
queries[queryID].reply = REPLY_IP;
query->reply = REPLY_IP;
counters->reply_IP++;
}
// Save response time (relative time)
queries[queryID].response = converttimeval(response) -
queries[queryID].response;
query->response = converttimeval(response) -
query->response;
}
pthread_t telnet_listenthreadv4;
+14 -14
View File
@@ -51,29 +51,29 @@ void *GC_thread(void *val)
// Process all queries
for(i=0; i < counters->queries; i++)
{
validate_access("queries", i, true, __LINE__, __FUNCTION__, __FILE__);
queriesDataStruct* query = getQuery(i);
// Test if this query is too new
if(queries[i].timestamp > mintime)
if(query->timestamp > mintime)
break;
// Adjust client counter
int clientID = queries[i].clientID;
int clientID = query->clientID;
validate_access("clients", clientID, true, __LINE__, __FUNCTION__, __FILE__);
clients[clientID].count--;
// Adjust total counters and total over time data
int timeidx = queries[i].timeidx;
int timeidx = query->timeidx;
overTime[timeidx].total--;
// Adjust corresponding overTime counters
clients[clientID].overTime[timeidx]--;
// Adjust domain counter (no overTime information)
int domainID = queries[i].domainID;
int domainID = query->domainID;
validate_access("domains", domainID, true, __LINE__, __FUNCTION__, __FILE__);
domains[domainID].count--;
// Change other counters according to status of this query
switch(queries[i].status)
switch(query->status)
{
case QUERY_UNKNOWN:
// Unknown (?)
@@ -82,8 +82,8 @@ void *GC_thread(void *val)
case QUERY_FORWARDED:
// Forwarded to an upstream DNS server
counters->forwardedqueries--;
validate_access("forwarded", queries[i].forwardID, true, __LINE__, __FUNCTION__, __FILE__);
forwarded[queries[i].forwardID].count--;
validate_access("forwarded", query->forwardID, true, __LINE__, __FUNCTION__, __FILE__);
forwarded[query->forwardID].count--;
overTime[timeidx].forwarded--;
break;
case QUERY_CACHE:
@@ -106,7 +106,7 @@ void *GC_thread(void *val)
}
// Update reply counters
switch(queries[i].reply)
switch(query->reply)
{
case REPLY_NODATA: // NODATA(-IPv6)
counters->reply_NODATA--;
@@ -133,10 +133,10 @@ void *GC_thread(void *val)
}
// Update type counters
if(queries[i].type >= TYPE_A && queries[i].type < TYPE_MAX)
if(query->type >= TYPE_A && query->type < TYPE_MAX)
{
counters->querytype[queries[i].type-1]--;
overTime[timeidx].querytypedata[queries[i].type-1]--;
counters->querytype[query->type-1]--;
overTime[timeidx].querytypedata[query->type-1]--;
}
// Count removed queries
@@ -149,7 +149,7 @@ void *GC_thread(void *val)
// Example: (I = now invalid, X = still valid queries, F = free space)
// Before: IIIIIIXXXXFF
// After: XXXXFFFFFFFF
memmove(&queries[0], &queries[removed], (counters->queries - removed)*sizeof(*queries));
memmove(getQuery(0), getQuery(removed), (counters->queries - removed)*sizeof(queriesDataStruct));
// Update queries counter
counters->queries -= removed;
@@ -157,7 +157,7 @@ void *GC_thread(void *val)
lastdbindex -= removed;
// Zero out remaining memory (marked as "F" in the above example)
memset(&queries[counters->queries], 0, (counters->queries_MAX - counters->queries)*sizeof(*queries));
memset(getQuery(counters->queries), 0, (counters->queries_MAX - counters->queries)*sizeof(queriesDataStruct));
// Determine if overTime memory needs to get moved
moveOverTimeMemory(mintime);
-63
View File
@@ -38,78 +38,16 @@ countersStruct *counters = NULL;
ConfigStruct config;
// Variable size array structs
queriesDataStruct *queries = NULL;
forwardedDataStruct *forwarded = NULL;
clientsDataStruct *clients = NULL;
domainsDataStruct *domains = NULL;
overTimeDataStruct *overTime = NULL;
void memory_check(int which)
{
switch(which)
{
case QUERIES:
if(counters->queries >= counters->queries_MAX-1)
{
// Have to reallocate shared memory
queries = enlarge_shmem_struct(QUERIES);
if(queries == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
case FORWARDED:
if(counters->forwarded >= counters->forwarded_MAX-1)
{
// Have to reallocate shared memory
forwarded = enlarge_shmem_struct(FORWARDED);
if(forwarded == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
case CLIENTS:
if(counters->clients >= counters->clients_MAX-1)
{
// Have to reallocate shared memory
clients = enlarge_shmem_struct(CLIENTS);
if(clients == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
case DOMAINS:
if(counters->domains >= counters->domains_MAX-1)
{
// Have to reallocate shared memory
domains = enlarge_shmem_struct(DOMAINS);
if(domains == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
default:
/* That cannot happen */
logg("Fatal error in memory_check(%i)", which);
exit(EXIT_FAILURE);
break;
}
}
void validate_access(const char * name, int pos, bool testmagic, int line, const char * function, const char * file)
{
int limit = 0;
if(name[0] == 'c') limit = counters->clients_MAX;
else if(name[0] == 'd') limit = counters->domains_MAX;
else if(name[0] == 'q') limit = counters->queries_MAX;
else if(name[0] == 'f') limit = counters->forwarded_MAX;
else { logg("Validator error (range)"); killed = 1; }
@@ -124,7 +62,6 @@ void validate_access(const char * name, int pos, bool testmagic, int line, const
unsigned char magic = 0x00;
if(name[0] == 'c') magic = clients[pos].magic;
else if(name[0] == 'd') magic = domains[pos].magic;
else if(name[0] == 'q') magic = queries[pos].magic;
else if(name[0] == 'f') magic = forwarded[pos].magic;
else { logg("Validator error (magic byte)"); killed = 1; }
if(magic != MAGICBYTE)
+5 -3
View File
@@ -125,16 +125,18 @@ void moveOverTimeMemory(time_t mintime)
// Correct time indices of queries. This is necessary because we just moved the slot this index points to
for(int queryID = 0; queryID < counters->queries; queryID++)
{
// Get query pointer
queriesDataStruct* query = getQuery(queryID);
// Check if the index would become negative if we adjusted it
if(((int)queries[queryID].timeidx - (int)moveOverTime) < 0)
if(((int)query->timeidx - (int)moveOverTime) < 0)
{
// This should never happen, but we print a warning if it still happens
// We don't do anything in this case
logg("WARN: moveOverTimeMemory(): overTime time index correction failed (%i: %u / %u)", queryID, queries[queryID].timeidx, moveOverTime);
logg("WARN: moveOverTimeMemory(): overTime time index correction failed (%i: %u / %u)", queryID, query->timeidx, moveOverTime);
}
else
{
queries[queryID].timeidx -= moveOverTime;
query->timeidx -= moveOverTime;
}
}
+80
View File
@@ -36,6 +36,9 @@ static SharedMemory shm_forwarded = { 0 };
static SharedMemory shm_overTime = { 0 };
static SharedMemory shm_settings = { 0 };
// Variable size array structs
static queriesDataStruct *queries = NULL;
typedef struct {
pthread_mutex_t lock;
bool waitingForLock;
@@ -511,3 +514,80 @@ static size_t get_optimal_object_size(size_t objsize, unsigned int minsize)
return optsize;
}
}
void memory_check(int which)
{
switch(which)
{
case QUERIES:
if(counters->queries >= counters->queries_MAX-1)
{
// Have to reallocate shared memory
queries = enlarge_shmem_struct(QUERIES);
if(queries == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
case FORWARDED:
if(counters->forwarded >= counters->forwarded_MAX-1)
{
// Have to reallocate shared memory
forwarded = enlarge_shmem_struct(FORWARDED);
if(forwarded == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
case CLIENTS:
if(counters->clients >= counters->clients_MAX-1)
{
// Have to reallocate shared memory
clients = enlarge_shmem_struct(CLIENTS);
if(clients == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
case DOMAINS:
if(counters->domains >= counters->domains_MAX-1)
{
// Have to reallocate shared memory
domains = enlarge_shmem_struct(DOMAINS);
if(domains == NULL)
{
logg("FATAL: Memory allocation failed! Exiting");
exit(EXIT_FAILURE);
}
}
break;
default:
/* That cannot happen */
logg("Fatal error in memory_check(%i)", which);
exit(EXIT_FAILURE);
break;
}
}
queriesDataStruct* _getQuery(int queryID, int line, const char * function, const char * file)
{
if(queryID < 0 || queryID > counters->queries_MAX)
{
logg("FATAL: Trying to access query ID %i, but maximum is %i", queryID, counters->queries_MAX);
logg(" found in %s() (%s:%i)", function, file, line);
return NULL;
}
if(queries[queryID].magic != MAGICBYTE)
{
logg("FATAL: Trying to access query ID %i, but magic byte is %x", queryID, queries[queryID].magic);
logg(" found in %s() (%s:%i)", function, file, line);
return NULL;
}
return &queries[queryID];
}