Explicitly log which config item failed to validate. This is useful when a user tries to set multiple values at once (e.g. via the web UI)

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2024-01-21 20:25:15 +01:00
parent ef4e592ea9
commit 164434541b
5 changed files with 60 additions and 60 deletions
+2 -2
View File
@@ -768,7 +768,7 @@ static int api_config_patch(struct ftl_conn *api)
// Validate new value (if validation function is defined)
char errbuf[VALIDATOR_ERRBUF_LEN] = { 0 };
if(!conf_item->c(&new_item->v, errbuf))
if(!conf_item->c(&new_item->v, new_item->k, errbuf))
{
free_config(&newconf);
return send_json_error(api, 400,
@@ -965,7 +965,7 @@ static int api_config_put_delete(struct ftl_conn *api)
if(api->method == HTTP_PUT)
{
char errbuf[VALIDATOR_ERRBUF_LEN] = { 0 };
if(!new_item->c(&new_item->v, errbuf))
if(!new_item->c(&new_item->v, new_item->k, errbuf))
{
free_config(&newconf);
return send_json_error(api, 400,
+1 -1
View File
@@ -442,7 +442,7 @@ int set_config_from_CLI(const char *key, const char *value)
if(new_item->c != NULL)
{
char errbuf[VALIDATOR_ERRBUF_LEN] = { 0 };
if(!new_item->c(&new_item->v, errbuf))
if(!new_item->c(&new_item->v, new_item->k, errbuf))
{
free_config(&newconf);
log_err("Invalid value: %s", errbuf);
+1 -1
View File
@@ -111,7 +111,7 @@ struct conf_item {
uint8_t f; // additional Flags
union conf_value v; // current Value
union conf_value d; // Default value
bool (*c)(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]); // Function pointer to validate the value
bool (*c)(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]); // Function pointer to validate the value
};
struct enum_options {
+47 -47
View File
@@ -17,31 +17,31 @@
// Stub validator for config types that need to dedicated validation as they can
// be tested by their type only (e.g., integers, strings, booleans, enums, etc.)
bool __attribute__((const)) validate_stub(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool __attribute__((const)) validate_stub(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
return true;
}
// Validate the dns.hosts array
// Each entry needs to be a string in form "IP HOSTNAME"
bool validate_dns_hosts(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_dns_hosts(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
if(!cJSON_IsArray(val->json))
{
strncat(err, "Not an array", VALIDATOR_ERRBUF_LEN);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not an array", key);
return false;
}
for(int i = 1; i <= cJSON_GetArraySize(val->json); i++)
for(int i = 0; i < cJSON_GetArraySize(val->json); i++)
{
// Get array item
cJSON *item = cJSON_GetArrayItem(val->json, i-1);
cJSON *item = cJSON_GetArrayItem(val->json, i);
// Check if it's a string
if(!cJSON_IsString(item))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element is not a string",
i, get_ordinal_suffix(i));
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: not a string",
key, i);
return false;
}
@@ -52,8 +52,8 @@ bool validate_dns_hosts(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
if(!ip || !*ip)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element does not have an IP address (\"%s\")",
i, get_ordinal_suffix(i), item->valuestring);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: not an IP address (\"%s\")",
key, i, item->valuestring);
free(str);
return false;
}
@@ -63,8 +63,8 @@ bool validate_dns_hosts(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
struct in6_addr addr6;
if(inet_pton(AF_INET, ip, &addr) != 1 && inet_pton(AF_INET6, ip, &addr6) != 1)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element is neither a valid IPv4 nor IPv6 address (\"%s\")",
i, get_ordinal_suffix(i), ip);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: neither a valid IPv4 nor IPv6 address (\"%s\")",
key, i, ip);
free(str);
return false;
}
@@ -78,8 +78,8 @@ bool validate_dns_hosts(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
{
if(!valid_domain(host, strlen(host), false))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element has an invalid hostname (\"%s\")",
i, get_ordinal_suffix(i), host);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: invalid hostname (\"%s\")",
key, i, host);
free(str);
return false;
}
@@ -89,8 +89,8 @@ bool validate_dns_hosts(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
// Check if there is at least one hostname in this record
if(hosts < 1)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element does not have at least one hostname (\"%s\")",
i, get_ordinal_suffix(i), item->valuestring);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: entry does not have at least one hostname (\"%s\")",
key, i, item->valuestring);
free(str);
return false;
}
@@ -103,23 +103,23 @@ bool validate_dns_hosts(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
// Validate the dns.cnames array
// Each entry needs to be a string in form "<cname>,[<cname>,]<target>[,<TTL>]"
bool validate_dns_cnames(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_dns_cnames(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
if(!cJSON_IsArray(val->json))
{
strncat(err, "Not an array", VALIDATOR_ERRBUF_LEN);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not an array", key);
return false;
}
for(int i = 1; i <= cJSON_GetArraySize(val->json); i++)
for(int i = 0; i < cJSON_GetArraySize(val->json); i++)
{
// Get array item
cJSON *item = cJSON_GetArrayItem(val->json, i-1);
cJSON *item = cJSON_GetArrayItem(val->json, i);
// Check if it's a string
if(!cJSON_IsString(item))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element is not a string", i, get_ordinal_suffix(i));
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: not a string", key, i);
return false;
}
@@ -141,7 +141,7 @@ bool validate_dns_cnames(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
if(strlen(s) == 0)
{
// Contains an empty string
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element contains an empty string at position %u", i, get_ordinal_suffix(i), j);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: contains an empty string at position %u", key, i, j);
free(str);
return false;
}
@@ -153,7 +153,7 @@ bool validate_dns_cnames(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
// Check if there are at least one cname and a target
if(j < 2)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element is not a valid CNAME definition", i, get_ordinal_suffix(i));
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d] element is not a valid CNAME definition", key, i);
return false;
}
}
@@ -162,7 +162,7 @@ bool validate_dns_cnames(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
}
// Validate IPs in CIDR notation
bool validate_cidr(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_cidr(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
// Check if it's a valid CIDR
char *str = strdup(val->s);
@@ -174,7 +174,7 @@ bool validate_cidr(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
// Check if there is an IP and no tail
if(!ip || !*ip || tail)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid IP in CIDR notation (\"%s\")", val->s);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid IP in CIDR notation (\"%s\")", key, val->s);
free(str);
return false;
}
@@ -185,7 +185,7 @@ bool validate_cidr(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
int ip4 = 0, ip6 = 0;
if((ip4 = inet_pton(AF_INET, ip, &addr) != 1) && (ip6 = inet_pton(AF_INET6, ip, &addr6)) != 1)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid IPv4 nor IPv6 address (\"%s\")", ip);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid IPv4 nor IPv6 address (\"%s\")", key, ip);
free(str);
return false;
}
@@ -195,20 +195,20 @@ bool validate_cidr(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
{
if(strlen(cidr) == 0)
{
strncat(err, "Empty CIDR value", VALIDATOR_ERRBUF_LEN);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: empty CIDR value", key);
free(str);
return false;
}
int cidr_int = atoi(cidr);
if(ip4 && (cidr_int < 0 || cidr_int > 32))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid IPv4 CIDR (\"%s\")", cidr);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid IPv4 CIDR (\"%s\")", key, cidr);
free(str);
return false;
}
else if(ip6 && (cidr_int < 0 || cidr_int > 128))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid IPv6 CIDR (\"%s\")", cidr);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid IPv6 CIDR (\"%s\")", key, cidr);
free(str);
return false;
}
@@ -219,7 +219,7 @@ bool validate_cidr(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
}
// Validate IP address optionally followed by a port (separator is "#")
bool validate_ip_port(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_ip_port(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
// Check if it's a valid IP
char *str = strdup(val->s);
@@ -231,7 +231,7 @@ bool validate_ip_port(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
// Check if there is an IP and no tail
if(!ip || !*ip || tail)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid IP (\"%s\")", val->s);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid IP (\"%s\")", key, val->s);
free(str);
return false;
}
@@ -242,7 +242,7 @@ bool validate_ip_port(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
int ip4 = 0, ip6 = 0;
if((ip4 = inet_pton(AF_INET, ip, &addr) != 1) && (ip6 = inet_pton(AF_INET6, ip, &addr6)) != 1)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid IPv4 nor IPv6 address (\"%s\")", ip);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid IPv4 nor IPv6 address (\"%s\")", key, ip);
free(str);
return false;
}
@@ -252,14 +252,14 @@ bool validate_ip_port(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
{
if(strlen(port) == 0)
{
strncat(err, "Empty port value", VALIDATOR_ERRBUF_LEN);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: empty port value", key);
free(str);
return false;
}
int port_int = atoi(port);
if(port_int < 0 || port_int > 65535)
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid port (\"%s\")", port);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid port (\"%s\")", key, port);
free(str);
return false;
}
@@ -270,12 +270,12 @@ bool validate_ip_port(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
}
// Validate domain
bool validate_domain(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_domain(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
// Check if domain is valid
if(!valid_domain(val->s, strlen(val->s), false))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid domain (\"%s\")", val->s);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid domain (\"%s\")", key, val->s);
return false;
}
@@ -283,14 +283,14 @@ bool validate_domain(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
}
// Validate file path
bool validate_filepath(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_filepath(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
// Check if the path contains only valid characters
for(unsigned int i = 0; i < strlen(val->s); i++)
{
if(!isalnum(val->s[i]) && val->s[i] != '/' && val->s[i] != '.' && val->s[i] != '-' && val->s[i] != '_' && val->s[i] != ' ')
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "Not a valid file path (\"%s\")", val->s);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s: not a valid file path (\"%s\")", key, val->s);
return false;
}
}
@@ -299,14 +299,14 @@ bool validate_filepath(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
}
// Validate file path (empty allowed)
bool validate_filepath_empty(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_filepath_empty(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
// Empty paths are allowed, e.g., to disable a feature like PCAP
if(strlen(val->s) == 0)
return true;
// else:
return validate_filepath(val, err);
return validate_filepath(val, key, err);
}
// Validate a single regular expression
@@ -329,24 +329,24 @@ static bool validate_regex(const char *regex, char err[VALIDATOR_ERRBUF_LEN])
}
// Validate array of regexes
bool validate_regex_array(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
bool validate_regex_array(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
if(val == NULL || !cJSON_IsArray(val->json))
{
strncat(err, "Not an array", VALIDATOR_ERRBUF_LEN);
strncat(err, "%s: not an array", VALIDATOR_ERRBUF_LEN);
return false;
}
for(int i = 1; i <= cJSON_GetArraySize(val->json); i++)
for(int i = 0; i < cJSON_GetArraySize(val->json); i++)
{
// Get array item
cJSON *item = cJSON_GetArrayItem(val->json, i-1);
cJSON *item = cJSON_GetArrayItem(val->json, i);
// Check if it's a string
if(!cJSON_IsString(item))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element is not a string",
i, get_ordinal_suffix(i));
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: not a string",
key, i);
return false;
}
@@ -354,8 +354,8 @@ bool validate_regex_array(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN])
char errbuf[VALIDATOR_ERRBUF_LEN] = { 0 };
if(!validate_regex(item->valuestring, errbuf))
{
snprintf(err, VALIDATOR_ERRBUF_LEN, "%d%s element is not a valid regex (\"%s\"): %s",
i, get_ordinal_suffix(i), item->valuestring, errbuf);
snprintf(err, VALIDATOR_ERRBUF_LEN, "%s[%d]: not a valid regex (\"%s\"): %s",
key, i, item->valuestring, errbuf);
return false;
}
}
+9 -9
View File
@@ -14,14 +14,14 @@
#include "FTL.h"
#include "config/config.h"
bool validate_stub(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]) __attribute__((const));
bool validate_dns_hosts(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_dns_cnames(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_cidr(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_ip_port(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_domain(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_filepath(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_filepath_empty(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_regex_array(union conf_value *val, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_stub(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]) __attribute__((const));
bool validate_dns_hosts(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_dns_cnames(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_cidr(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_ip_port(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_domain(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_filepath(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_filepath_empty(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_regex_array(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
#endif // CONFIG_VALIDATOR_H