diff --git a/src/api/api.h b/src/api/api.h index 97907b2c..e8e57964 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -15,6 +15,8 @@ // type cJSON #include "webserver/cJSON/cJSON.h" #include "webserver/http-common.h" +// regex_t +#include "regex_r.h" // Common definitions #define LOCALHOSTv4 "127.0.0.1" @@ -43,6 +45,7 @@ int api_history_database_clients(struct ftl_conn *api); // Query methods int api_queries(struct ftl_conn *api); int api_queries_suggestions(struct ftl_conn *api); +bool compile_filter_regex(struct ftl_conn *api, const char *path, cJSON *json, regex_t **regex, unsigned int *N_regex); // Statistics methods (database) int api_stats_database_top_items(struct ftl_conn *api); diff --git a/src/api/queries.c b/src/api/queries.c index c4d6bf45..c7ceedb3 100644 --- a/src/api/queries.c +++ b/src/api/queries.c @@ -19,7 +19,6 @@ #include "database/aliasclients.h" // get_memdb() #include "database/query-table.h" -#include "regex.h" // dbopen(false, ), dbclose() #include "database/common.h" @@ -444,103 +443,19 @@ int api_queries(struct ftl_conn *api) bool filtering = false; // Regex filtering? - const int N_regex_domains = cJSON_GetArraySize(config.webserver.api.excludeDomains.v.json); regex_t *regex_domains = NULL; - if(N_regex_domains > 0) - { - // Allocate memory for regex array - regex_domains = calloc(N_regex_domains, sizeof(regex_t)); - if(regex_domains == NULL) - { - return send_json_error(api, 500, - "internal_error", - "Internal server error, failed to allocate memory for domain regex array", - NULL); - } - - // Compile regexes - unsigned int i = 0; - cJSON *filter = NULL; - cJSON_ArrayForEach(filter, config.webserver.api.excludeDomains.v.json) - { - // Skip non-string, invalid and empty values - if(!cJSON_IsString(filter) || filter->valuestring == NULL || strlen(filter->valuestring) == 0) - { - log_warn("Skipping invalid regex at webserver.api.excludeDomains.%u", i); - continue; - } - - // Compile regex - int rc = regcomp(®ex_domains[i], filter->valuestring, REG_EXTENDED); - if(rc != 0) - { - // Failed to compile regex - char errbuf[1024] = { 0 }; - regerror(rc, ®ex_domains[i], errbuf, sizeof(errbuf)); - log_err("Failed to compile domain regex \"%s\": %s", - filter->valuestring, errbuf); - return send_json_error(api, 400, - "bad_request", - "Failed to compile domain regex", - filter->valuestring); - } - - i++; - } - - // We are filtering, so we have to continue to step over the - // remaining rows to get the correct number of total records + unsigned int N_regex_domains = 0; + if(compile_filter_regex(api, "webserver.api.excludeDomains", + config.webserver.api.excludeDomains.v.json, + ®ex_domains, &N_regex_domains)) filtering = true; - } - const int N_regex_clients = cJSON_GetArraySize(config.webserver.api.excludeClients.v.json); regex_t *regex_clients = NULL; - if(N_regex_clients > 0) - { - // Allocate memory for regex array - regex_clients = calloc(N_regex_clients, sizeof(regex_t)); - if(regex_clients == NULL) - { - return send_json_error(api, 500, - "internal_error", - "Internal server error, failed to allocate memory for client regex array", - NULL); - } - - // Compile regexes - unsigned int i = 0; - cJSON *filter = NULL; - cJSON_ArrayForEach(filter, config.webserver.api.excludeClients.v.json) - { - // Skip non-string, invalid and empty values - if(!cJSON_IsString(filter) || filter->valuestring == NULL || strlen(filter->valuestring) == 0) - { - log_warn("Skipping invalid regex at webserver.api.excludeClients.%u", i); - continue; - } - - // Compile regex - int rc = regcomp(®ex_clients[i], filter->valuestring, REG_EXTENDED); - if(rc != 0) - { - // Failed to compile regex - char errbuf[1024] = { 0 }; - regerror(rc, ®ex_clients[i], errbuf, sizeof(errbuf)); - log_err("Failed to compile client regex \"%s\": %s", - filter->valuestring, errbuf); - return send_json_error(api, 400, - "bad_request", - "Failed to compile client regex", - filter->valuestring); - } - - i++; - } - - // We are filtering, so we have to continue to step over the - // remaining rows to get the correct number of total records + unsigned int N_regex_clients = 0; + if(compile_filter_regex(api, "webserver.api.excludeClients", + config.webserver.api.excludeClients.v.json, + ®ex_clients, &N_regex_clients)) filtering = true; - } // Finish preparing query string querystr_finish(querystr, sort_col, sort_dir); @@ -824,7 +739,7 @@ int api_queries(struct ftl_conn *api) { bool match = false; // Iterate over all regex filters - for(int i = 0; i < N_regex_domains; i++) + for(unsigned int i = 0; i < N_regex_domains; i++) { // Check if the domain matches the regex if(regexec(®ex_domains[i], domain, 0, NULL, 0) == 0) @@ -853,7 +768,7 @@ int api_queries(struct ftl_conn *api) { bool match = false; // Iterate over all regex filters - for(int i = 0; i < N_regex_clients; i++) + for(unsigned int i = 0; i < N_regex_clients; i++) { // Check if the domain matches the regex if(regexec(®ex_clients[i], client_ip, 0, NULL, 0) == 0) @@ -1049,7 +964,7 @@ int api_queries(struct ftl_conn *api) if(N_regex_domains > 0) { // Free individual regexes - for(int i = 0; i < N_regex_domains; i++) + for(unsigned int i = 0; i < N_regex_domains; i++) regfree(®ex_domains[i]); // Free array of regex pointers @@ -1058,12 +973,67 @@ int api_queries(struct ftl_conn *api) if(N_regex_clients > 0) { // Free individual regexes - for(int i = 0; i < N_regex_clients; i++) + for(unsigned int i = 0; i < N_regex_clients; i++) regfree(®ex_clients[i]); - // Free array of regex pointers + // Free array of regex po^inters free(regex_clients); } JSON_SEND_OBJECT(json); } + +bool compile_filter_regex(struct ftl_conn *api, const char *path, cJSON *json, regex_t **regex, unsigned int *N_regex) +{ + + const int N = cJSON_GetArraySize(json); + if(N < 1) + return false; + + // Set number of regexes (positive = unsigned integer) + *N_regex = N; + + // Allocate memory for regex array + *regex = calloc(N, sizeof(regex_t)); + if(*regex == NULL) + { + return send_json_error(api, 500, + "internal_error", + "Internal server error, failed to allocate memory for regex array", + NULL); + } + + // Compile regexes + unsigned int i = 0; + cJSON *filter = NULL; + cJSON_ArrayForEach(filter, json) + { + // Skip non-string, invalid and empty values + if(!cJSON_IsString(filter) || filter->valuestring == NULL || strlen(filter->valuestring) == 0) + { + log_warn("Skipping invalid regex at %s.%u", path, i); + continue; + } + + // Compile regex + int rc = regcomp(regex[i], filter->valuestring, REG_EXTENDED); + if(rc != 0) + { + // Failed to compile regex + char errbuf[1024] = { 0 }; + regerror(rc, regex[i], errbuf, sizeof(errbuf)); + log_err("Failed to compile regex \"%s\": %s", + filter->valuestring, errbuf); + return send_json_error(api, 400, + "bad_request", + "Failed to compile regex", + filter->valuestring); + } + + i++; + } + + // We are filtering, so we have to continue to step over the + // remaining rows to get the correct number of total records + return true; +} \ No newline at end of file diff --git a/src/api/stats.c b/src/api/stats.c index ff1618f1..339fb72e 100644 --- a/src/api/stats.c +++ b/src/api/stats.c @@ -216,50 +216,11 @@ int api_stats_top_domains(struct ftl_conn *api) clearSetupVarsArray(); // Get domains which the user doesn't want to see - const int N_regex_domains = cJSON_GetArraySize(config.webserver.api.excludeDomains.v.json); regex_t *regex_domains = NULL; - if(N_regex_domains > 0) - { - // Allocate memory for regex array - regex_domains = calloc(N_regex_domains, sizeof(regex_t)); - if(regex_domains == NULL) - { - return send_json_error(api, 500, - "internal_error", - "Internal server error, failed to allocate memory for client regex array", - NULL); - } - - // Compile regexes - unsigned int i = 0; - cJSON *filter = NULL; - cJSON_ArrayForEach(filter, config.webserver.api.excludeDomains.v.json) - { - // Skip non-string, invalid and empty values - if(!cJSON_IsString(filter) || filter->valuestring == NULL || strlen(filter->valuestring) == 0) - { - log_warn("Skipping invalid regex at webserver.api.excludeDomains.%u", i); - continue; - } - - // Compile regex - int rc = regcomp(®ex_domains[i], filter->valuestring, REG_EXTENDED); - if(rc != 0) - { - // Failed to compile regex - char errbuf[1024] = { 0 }; - regerror(rc, ®ex_domains[i], errbuf, sizeof(errbuf)); - log_err("Failed to compile domain regex \"%s\": %s", - filter->valuestring, errbuf); - return send_json_error(api, 400, - "bad_request", - "Failed to compile domain regex", - filter->valuestring); - } - - i++; - } - } + unsigned int N_regex_domains = 0; + compile_filter_regex(api, "webserver.api.excludeDomains", + config.webserver.api.excludeDomains.v.json, + ®ex_domains, &N_regex_domains); int n = 0; cJSON *top_domains = JSON_NEW_ARRAY(); @@ -284,7 +245,7 @@ int api_stats_top_domains(struct ftl_conn *api) if(N_regex_domains > 0) { // Iterate over all regex filters - for(int j = 0; j < N_regex_domains; j++) + for(unsigned int j = 0; j < N_regex_domains; j++) { // Check if the domain matches the regex if(regexec(®ex_domains[j], domain_name, 0, NULL, 0) == 0) @@ -328,7 +289,7 @@ int api_stats_top_domains(struct ftl_conn *api) if(N_regex_domains > 0) { // Free individual regexes - for(int i = 0; i < N_regex_domains; i++) + for(unsigned int i = 0; i < N_regex_domains; i++) regfree(®ex_domains[i]); // Free array of regex pointers @@ -403,50 +364,11 @@ int api_stats_top_clients(struct ftl_conn *api) qsort(temparray, clients, sizeof(int[2]), cmpdesc); // Get clients which the user doesn't want to see - const int N_regex_clients = cJSON_GetArraySize(config.webserver.api.excludeClients.v.json); regex_t *regex_clients = NULL; - if(N_regex_clients > 0) - { - // Allocate memory for regex array - regex_clients = calloc(N_regex_clients, sizeof(regex_t)); - if(regex_clients == NULL) - { - return send_json_error(api, 500, - "internal_error", - "Internal server error, failed to allocate memory for client regex array", - NULL); - } - - // Compile regexes - unsigned int i = 0; - cJSON *filter = NULL; - cJSON_ArrayForEach(filter, config.webserver.api.excludeClients.v.json) - { - // Skip non-string, invalid and empty values - if(!cJSON_IsString(filter) || filter->valuestring == NULL || strlen(filter->valuestring) == 0) - { - log_warn("Skipping invalid regex at webserver.api.excludeClients.%u", i); - continue; - } - - // Compile regex - int rc = regcomp(®ex_clients[i], filter->valuestring, REG_EXTENDED); - if(rc != 0) - { - // Failed to compile regex - char errbuf[1024] = { 0 }; - regerror(rc, ®ex_clients[i], errbuf, sizeof(errbuf)); - log_err("Failed to compile client regex \"%s\": %s", - filter->valuestring, errbuf); - return send_json_error(api, 400, - "bad_request", - "Failed to compile client regex", - filter->valuestring); - } - - i++; - } - } + unsigned int N_regex_clients = 0; + compile_filter_regex(api, "webserver.api.excludeClients", + config.webserver.api.excludeClients.v.json, + ®ex_clients, &N_regex_clients); int n = 0; cJSON *top_clients = JSON_NEW_ARRAY(); @@ -473,7 +395,7 @@ int api_stats_top_clients(struct ftl_conn *api) if(N_regex_clients > 0) { // Iterate over all regex filters - for(int j = 0; j < N_regex_clients; j++) + for(unsigned int j = 0; j < N_regex_clients; j++) { // Check if the domain matches the regex if(regexec(®ex_clients[j], client_ip, 0, NULL, 0) == 0) @@ -516,7 +438,7 @@ int api_stats_top_clients(struct ftl_conn *api) if(N_regex_clients > 0) { // Free individual regexes - for(int i = 0; i < N_regex_clients; i++) + for(unsigned int i = 0; i < N_regex_clients; i++) regfree(®ex_clients[i]); // Free array of regex pointers