From 810e36bef8a68a06edb8f28eda5f7d9146dfa249 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 6 Mar 2019 16:26:54 +0100 Subject: [PATCH] Remove globally defined queries array. Signed-off-by: DL6ER --- FTL.h | 5 +- api.c | 83 +++++++++---------- database.c | 68 ++++++++-------- datastructure.c | 21 ++--- dnsmasq_interface.c | 188 ++++++++++++++++++++++++++------------------ gc.c | 28 +++---- memory.c | 63 --------------- overTime.c | 8 +- shmem.c | 80 +++++++++++++++++++ 9 files changed, 301 insertions(+), 243 deletions(-) diff --git a/FTL.h b/FTL.h index 1378ae79..5de1a71b 100644 --- a/FTL.h +++ b/FTL.h @@ -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); diff --git a/api.c b/api.c index b5e87f03..2364e1e5 100644 --- a/api.c +++ b/api.c @@ -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); } } } diff --git a/database.c b/database.c index 7488b2b8..95a7c78a 100644 --- a/database.c +++ b/database.c @@ -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++; diff --git a/datastructure.c b/datastructure.c index b0a20dc7..e762d049 100644 --- a/datastructure.c +++ b/datastructure.c @@ -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; diff --git a/dnsmasq_interface.c b/dnsmasq_interface.c index d11d1de9..8b0153b1 100644 --- a/dnsmasq_interface.c +++ b/dnsmasq_interface.c @@ -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 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) { // - 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; diff --git a/gc.c b/gc.c index b9857f97..6c0ead66 100644 --- a/gc.c +++ b/gc.c @@ -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); diff --git a/memory.c b/memory.c index b57dccef..676b4c0b 100644 --- a/memory.c +++ b/memory.c @@ -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) diff --git a/overTime.c b/overTime.c index 29ab2ee6..3d7a14ff 100644 --- a/overTime.c +++ b/overTime.c @@ -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; } } diff --git a/shmem.c b/shmem.c index 9896273d..69fac85f 100644 --- a/shmem.c +++ b/shmem.c @@ -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]; +}