diff --git a/src/api/docs/content/specs/stats.yaml b/src/api/docs/content/specs/stats.yaml index 60fa3f69..b2dfba01 100644 --- a/src/api/docs/content/specs/stats.yaml +++ b/src/api/docs/content/specs/stats.yaml @@ -406,6 +406,82 @@ components: type: integer description: Queries of remaining types example: 845 + status: + type: object + description: Number of individual queries (by status) + properties: + UNKNOWN: + type: integer + description: Type UNKNOWN queries + example: 3 + GRAVITY: + type: integer + description: Type GRAVITY queries + example: 72 + FORWARDED: + type: integer + description: Type FORWARDED queries + example: 533 + CACHE: + type: integer + description: Type CACHE queries + example: 32 + REGEX: + type: integer + description: Type REGEX queries + example: 84 + DENYLIST: + type: integer + description: Type DENYLIST queries + example: 31 + EXTERNAL_BLOCKED_IP: + type: integer + description: Type EXTERNAL_BLOCKED_IP queries + example: 0 + EXTERNAL_BLOCKED_NULL: + type: integer + description: Type EXTERNAL_BLOCKED_NULL queries + example: 0 + EXTERNAL_BLOCKED_NXRA: + type: integer + description: Type EXTERNAL_BLOCKED_NXRA queries + example: 0 + GRAVITY_CNAME: + type: integer + description: Type GRAVITY_CNAME queries + example: 0 + REGEX_CNAME: + type: integer + description: Type REGEX_CNAME queries + example: 0 + DENYLIST_CNAME: + type: integer + description: Type DENYLIST_CNAME queries + example: 0 + RETRIED: + type: integer + description: Type RETRIED queries + example: 0 + RETRIED_DNSSEC: + type: integer + description: Type RETRIED_DNSSEC queries + example: 0 + IN_PROGRESS: + type: integer + description: Type IN_PROGRESS queries + example: 0 + DBBUSY: + type: integer + description: Type DBBUSY queries + example: 0 + SPECIAL_DOMAIN: + type: integer + description: Type SPECIAL_DOMAIN queries + example: 0 + CACHE_STALE: + type: integer + description: Type CACHE_STALE queries + example: 0 replies: type: object description: Number of individual replies diff --git a/src/api/stats.c b/src/api/stats.c index 0c06b1f7..a9874750 100644 --- a/src/api/stats.c +++ b/src/api/stats.c @@ -100,6 +100,10 @@ int api_stats_summary(struct ftl_conn *api) return ret; JSON_ADD_ITEM_TO_OBJECT(queries, "types", types); + cJSON *statuses = JSON_NEW_OBJECT(); + for(enum query_status status = 0; status < QUERY_STATUS_MAX; status++) + JSON_ADD_NUMBER_TO_OBJECT(statuses, get_query_status_str(status), counters->status[status]); + JSON_ADD_ITEM_TO_OBJECT(queries, "status", statuses); cJSON *replies = JSON_NEW_OBJECT(); for(enum reply_type reply = 0; reply type = TYPE_OTHER; query->qtype = type - 100; } + counters->querytype[query->type]++; // Status is set below query->domainID = domainID; @@ -1084,13 +1085,9 @@ void DB_read_queries(void) clientsData *client = getClient(clientID, true); client->lastQuery = queryTimeStamp; - // Handle type counters - if(type >= TYPE_A && type < TYPE_MAX) - counters->querytype[type]++; - // Update overTime data overTime[timeidx].total++; - // Update overTime data structure with the new client + // Update client's overTime data structure change_clientcount(client, 0, 0, timeidx, 1); // Increase DNS queries counter @@ -1126,12 +1123,8 @@ void DB_read_queries(void) cache->domainlist_id = sqlite3_column_int(stmt, 7); } - // Increment status counters, we first have to add one to the count of - // unknown queries because query_set_status() will subtract from there - // when setting a different status - if(status != QUERY_UNKNOWN) - counters->status[QUERY_UNKNOWN]++; - query_set_status(query, status); + // Increment status counters + query_set_status_init(query, status); // Do further processing based on the query status we read from the database switch(status) diff --git a/src/datastructure.c b/src/datastructure.c index 7998d99b..78c9add4 100644 --- a/src/datastructure.c +++ b/src/datastructure.c @@ -926,19 +926,27 @@ static const char* __attribute__ ((const)) query_status_str(const enum query_sta return NULL; } -void _query_set_status(queriesData *query, const enum query_status new_status, const char *func, const int line, const char *file) +void _query_set_status(queriesData *query, const enum query_status new_status, const bool init, + const char *func, const int line, const char *file) { // Debug logging if(config.debug.status.v.b) { - const char *oldstr = query->status < QUERY_STATUS_MAX ? query_status_str(query->status) : "INVALID"; - if(query->status == new_status) + if(init) { + const char *newstr = new_status < QUERY_STATUS_MAX ? query_status_str(new_status) : "INVALID"; + log_debug(DEBUG_STATUS, "Query %i: status initialized: %s (%d) in %s() (%s:%i)", + query->id, newstr, new_status, func, short_path(file), line); + } + else if(query->status == new_status) + { + const char *oldstr = query->status < QUERY_STATUS_MAX ? query_status_str(query->status) : "INVALID"; log_debug(DEBUG_STATUS, "Query %i: status unchanged: %s (%d) in %s() (%s:%i)", query->id, oldstr, query->status, func, short_path(file), line); } else { + const char *oldstr = query->status < QUERY_STATUS_MAX ? query_status_str(query->status) : "INVALID"; const char *newstr = new_status < QUERY_STATUS_MAX ? query_status_str(new_status) : "INVALID"; log_debug(DEBUG_STATUS, "Query %i: status changed: %s (%d) -> %s (%d) in %s() (%s:%i)", query->id, oldstr, query->status, newstr, new_status, func, short_path(file), line); @@ -949,30 +957,36 @@ void _query_set_status(queriesData *query, const enum query_status new_status, c if(new_status >= QUERY_STATUS_MAX) return; - // Update counters - if(query->status != new_status) + const enum query_status old_status = query->status; + if(old_status == new_status && !init) { - counters->status[query->status]--; - counters->status[new_status]++; - - const int timeidx = getOverTimeID(query->timestamp); - if(is_blocked(query->status)) - overTime[timeidx].blocked--; - if(is_blocked(new_status)) - overTime[timeidx].blocked++; - - if(query->status == QUERY_CACHE) - overTime[timeidx].cached--; - if(new_status == QUERY_CACHE) - overTime[timeidx].cached++; - - if(query->status == QUERY_FORWARDED) - overTime[timeidx].forwarded--; - if(new_status == QUERY_FORWARDED) - overTime[timeidx].forwarded++; + // Nothing to do + return; } - // Update status + // else: update global counters, ... + if(!init) + counters->status[old_status]--; + counters->status[new_status]++; + + // ... update overTime counters, ... + const int timeidx = getOverTimeID(query->timestamp); + if(is_blocked(old_status) && !init) + overTime[timeidx].blocked--; + if(is_blocked(new_status)) + overTime[timeidx].blocked++; + + if(old_status == QUERY_CACHE && !init) + overTime[timeidx].cached--; + if(new_status == QUERY_CACHE) + overTime[timeidx].cached++; + + if(old_status == QUERY_FORWARDED && !init) + overTime[timeidx].forwarded--; + if(new_status == QUERY_FORWARDED) + overTime[timeidx].forwarded++; + + // ... and set new status query->status = new_status; } diff --git a/src/datastructure.h b/src/datastructure.h index c115064e..66da308f 100644 --- a/src/datastructure.h +++ b/src/datastructure.h @@ -134,8 +134,9 @@ const char *get_cached_statuslist(void) __attribute__ ((pure)); int get_blocked_count(void) __attribute__ ((pure)); int get_forwarded_count(void) __attribute__ ((pure)); int get_cached_count(void) __attribute__ ((pure)); -#define query_set_status(query, new_status) _query_set_status(query, new_status, __FUNCTION__, __LINE__, __FILE__) -void _query_set_status(queriesData *query, const enum query_status new_status, const char *func, const int line, const char *file); +#define query_set_status(query, new_status) _query_set_status(query, new_status, false, __FUNCTION__, __LINE__, __FILE__) +#define query_set_status_init(query, new_status) _query_set_status(query, new_status, true, __FUNCTION__, __LINE__, __FILE__) +void _query_set_status(queriesData *query, const enum query_status new_status, const bool init, const char *func, const int line, const char *file); void FTL_reload_all_domainlists(void); void FTL_reset_per_client_domain_data(void); diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c index 0211afa8..5987a991 100644 --- a/src/dnsmasq_interface.c +++ b/src/dnsmasq_interface.c @@ -746,12 +746,12 @@ bool _FTL_new_query(const unsigned int flags, const char *name, query->magic = MAGICBYTE; query->timestamp = querytimestamp; query->type = querytype; + counters->querytype[querytype]++; query->qtype = qtype; query->id = id; // Has to be set before calling query_set_status() // This query is unknown as long as no reply has been found and analyzed - counters->status[QUERY_UNKNOWN]++; - query_set_status(query, QUERY_UNKNOWN); + query_set_status_init(query, QUERY_UNKNOWN); query->domainID = domainID; query->clientID = clientID; // Initialize database field, will be set when the query is stored in the long-term DB @@ -797,9 +797,6 @@ bool _FTL_new_query(const unsigned int flags, const char *name, client->lastQuery = querytimestamp; client->numQueriesARP++; - // Update counters - counters->querytype[querytype]++; - // Process interface information of client (if available) // Skip interface name length 1 to skip "-". No real interface should // have a name with a length of 1... @@ -2528,7 +2525,6 @@ static void FTL_upstream_error(const union all_addr *addr, const unsigned int fl if(query->reply == REPLY_OTHER) log_debug(DEBUG_QUERIES, " Unknown rcode = %i", addr->log.rcode); - if(addr->log.ede != EDE_UNSET) log_debug(DEBUG_QUERIES, " EDE: %s (1/%d)", edestr(addr->log.ede), addr->log.ede); @@ -3364,7 +3360,10 @@ void FTL_multiple_replies(const int id, int *firstID) log_debug(DEBUG_QUERIES, "**** sending reply %d also to %d", *firstID, queryID); // Copy relevant information over + counters->reply[duplicated_query->reply]--; duplicated_query->reply = source_query->reply; + counters->reply[duplicated_query->reply]++; + duplicated_query->dnssec = source_query->dnssec; duplicated_query->flags.complete = true; duplicated_query->CNAME_domainID = source_query->CNAME_domainID; diff --git a/src/gc.c b/src/gc.c index 322a92ab..dbb73ffe 100644 --- a/src/gc.c +++ b/src/gc.c @@ -189,7 +189,6 @@ void runGC(const time_t now, time_t *lastGCrun, const bool flush) case QUERY_RETRIED: // (fall through) case QUERY_RETRIED_DNSSEC: // Forwarded to an upstream DNS server - // Adjusting counters is done below in moveOverTimeMemory() break; case QUERY_CACHE: case QUERY_CACHE_STALE: @@ -206,7 +205,6 @@ void runGC(const time_t now, time_t *lastGCrun, const bool flush) case QUERY_DENYLIST_CNAME: // Exactly denied domain in CNAME chain (fall through) case QUERY_DBBUSY: // Blocked because gravity database was busy case QUERY_SPECIAL_DOMAIN: // Blocked by special domain handling - //counters->blocked--; overTime[timeidx].blocked--; if(domain != NULL) domain->blockedcount--; @@ -220,16 +218,15 @@ void runGC(const time_t now, time_t *lastGCrun, const bool flush) break; } - // Update reply countersthread_running[GC] = false; + // Update reply counters counters->reply[query->reply]--; // Update type counters - if(query->type >= TYPE_A && query->type < TYPE_MAX) - counters->querytype[query->type]--; + counters->querytype[query->type]--; // Subtract UNKNOWN from the counters before - // setting the status if different. This ensure - // we are not counting them at all. + // setting the status if different. + // Minus one here and plus one below = net zero if(query->status != QUERY_UNKNOWN) counters->status[QUERY_UNKNOWN]--; diff --git a/src/overTime.c b/src/overTime.c index d29f6ed9..5148b908 100644 --- a/src/overTime.c +++ b/src/overTime.c @@ -190,15 +190,6 @@ void moveOverTimeMemory(const time_t mintime) &overTime[moveOverTime], remainingSlots*sizeof(*overTime)); - // 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 - queriesData* query = getQuery(queryID, true); - if(query == NULL) - continue; - } - // Move client-specific overTime memory for(int clientID = 0; clientID < counters->clients; clientID++) {