mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
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:
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user