Skip to content

Commit

Permalink
Merge branch 'development-v6' into new/validator
Browse files Browse the repository at this point in the history
Signed-off-by: DL6ER <[email protected]>
  • Loading branch information
DL6ER committed Feb 11, 2024
2 parents 3b9badd + 9e3ccd9 commit 6009a1a
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 94 deletions.
22 changes: 6 additions & 16 deletions src/api/docs/content/specs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -239,17 +239,10 @@ components:
type: integer
optimizer:
type: integer
revServer:
type: object
properties:
active:
type: boolean
cidr:
type: string
target:
type: string
domain:
type: string
revServers:
type: array
items:
type: string
blocking:
type: object
properties:
Expand Down Expand Up @@ -623,11 +616,8 @@ components:
cache:
size: 10000
optimizer: 3600
revServer:
active: false
cidr: "192.168.0.0/24"
target: "192.168.0.1"
domain: "lan"
revServers:
- "true,192.168.0.0/24,192.168.0.1,lan"
blocking:
active: true
mode: 'NULL'
Expand Down
40 changes: 8 additions & 32 deletions src/config/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,14 @@ void initConfig(struct config *conf)
conf->dns.blocking.mode.d.blocking_mode = MODE_NULL;
conf->dns.blocking.mode.c = validate_stub; // Only type-based checking

conf->dns.revServers.k = "dns.revServers";
conf->dns.revServers.h = "Reverse server (former also called \"conditional forwarding\") feature\n Array of reverse servers each one in one of the following forms: \"<enabled>,<ip-address>[/<prefix-len>],<server>[#<port>],<domain>\"\n\n Individual components:\n\n <enabled>: either \"true\" or \"false\"\n\n <ip-address>[/<prefix-len>]: Address range for the reverse server feature in CIDR notation. If the prefix length is omitted, either 32 (IPv4) or 128 (IPv6) are substituted (exact address match). This is almost certainly not what you want here.\n Example: \"192.168.0.0/24\" for the range 192.168.0.1 - 192.168.0.255\n\n <server>[#<port>]: Target server to be used for the reverse server feature\n Example: \"192.168.0.1#53\"\n\n <domain>: Domain used for the reverse server feature (e.g., \"fritz.box\")\n Example: \"fritz.box\"";
conf->dns.revServers.a = cJSON_CreateStringReference("array of reverse servers each one in one of the following forms: \"<enabled>,<ip-address>[/<prefix-len>],<server>[#<port>],<domain>\", e.g., \"true,192.168.0.0/24,192.168.0.1,fritz.box\"");
conf->dns.revServers.t = CONF_JSON_STRING_ARRAY;
conf->dns.revServers.d.json = cJSON_CreateArray();
conf->dns.revServers.c = validate_stub; // Only type-based checking
conf->dns.revServers.f = FLAG_RESTART_FTL;

// sub-struct dns.rate_limit
conf->dns.rateLimit.count.k = "dns.rateLimit.count";
conf->dns.rateLimit.count.h = "Rate-limited queries are answered with a REFUSED reply and not further processed by FTL.\n The default settings for FTL's rate-limiting are to permit no more than 1000 queries in 60 seconds. Both numbers can be customized independently. It is important to note that rate-limiting is happening on a per-client basis. Other clients can continue to use FTL while rate-limited clients are short-circuited at the same time.\n For this setting, both numbers, the maximum number of queries within a given time, and the length of the time interval (seconds) have to be specified. For instance, if you want to set a rate limit of 1 query per hour, the option should look like RATE_LIMIT=1/3600. The time interval is relative to when FTL has finished starting (start of the daemon + possible delay by DELAY_STARTUP) then it will advance in steps of the rate-limiting interval. If a client reaches the maximum number of queries it will be blocked until the end of the current interval. This will be logged to /var/log/pihole/FTL.log, e.g. Rate-limiting 10.0.1.39 for at least 44 seconds. If the client continues to send queries while being blocked already and this number of queries during the blocking exceeds the limit the client will continue to be blocked until the end of the next interval (FTL.log will contain lines like Still rate-limiting 10.0.1.39 as it made additional 5007 queries). As soon as the client requests less than the set limit, it will be unblocked (Ending rate-limitation of 10.0.1.39).\n Rate-limiting may be disabled altogether by setting both values to zero (this results in the same behavior as before FTL v5.7).\n How many queries are permitted...";
Expand Down Expand Up @@ -701,38 +709,6 @@ void initConfig(struct config *conf)
memset(&conf->dns.reply.blocking.v6.d.in6_addr, 0, sizeof(struct in6_addr));
conf->dns.reply.blocking.v6.c = validate_stub; // Only type-based checking

// sub-struct revServer
conf->dns.revServer.active.k = "dns.revServer.active";
conf->dns.revServer.active.h = "Is the reverse server (former also called \"conditional forwarding\") feature enabled?";
conf->dns.revServer.active.t = CONF_BOOL;
conf->dns.revServer.active.d.b = false;
conf->dns.revServer.active.f = FLAG_RESTART_FTL;
conf->dns.revServer.active.c = validate_stub; // Only type-based checking

conf->dns.revServer.cidr.k = "dns.revServer.cidr";
conf->dns.revServer.cidr.h = "Address range for the reverse server feature in CIDR notation. If the prefix length is omitted, either 32 (IPv4) or 128 (IPv6) are substitutet (exact address match). This is almost certainly not what you want here.";
conf->dns.revServer.cidr.a = cJSON_CreateStringReference("<ip-address>[/<prefix-len>], e.g., \"192.168.0.0/24\" for the range 192.168.0.1 - 192.168.0.255");
conf->dns.revServer.cidr.t = CONF_STRING;
conf->dns.revServer.cidr.d.s = (char*)"";
conf->dns.revServer.cidr.f = FLAG_RESTART_FTL;
conf->dns.revServer.cidr.c = validate_cidr;

conf->dns.revServer.target.k = "dns.revServer.target";
conf->dns.revServer.target.h = "Target server tp be used for the reverse server feature";
conf->dns.revServer.target.a = cJSON_CreateStringReference("<server>[#<port>], e.g., \"192.168.0.1\"");
conf->dns.revServer.target.t = CONF_STRING;
conf->dns.revServer.target.d.s = (char*)"";
conf->dns.revServer.target.f = FLAG_RESTART_FTL;
conf->dns.revServer.target.c = validate_ip_port;

conf->dns.revServer.domain.k = "dns.revServer.domain";
conf->dns.revServer.domain.h = "Domain used for the reverse server feature (e.g., \"fritz.box\")";
conf->dns.revServer.domain.a = cJSON_CreateStringReference("<valid domain>");
conf->dns.revServer.domain.t = CONF_STRING;
conf->dns.revServer.domain.d.s = (char*)"";
conf->dns.revServer.domain.f = FLAG_RESTART_FTL;
conf->dns.revServer.domain.c = validate_domain;

// sub-struct dhcp
conf->dhcp.active.k = "dhcp.active";
conf->dhcp.active.h = "Is the embedded DHCP server enabled?";
Expand Down
8 changes: 1 addition & 7 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ struct config {
struct conf_item queryLogging;
struct conf_item cnameRecords;
struct conf_item port;
struct conf_item revServers;
struct {
struct conf_item size;
struct conf_item optimizer;
Expand Down Expand Up @@ -178,13 +179,6 @@ struct config {
struct conf_item count;
struct conf_item interval;
} rateLimit;

struct {
struct conf_item active;
struct conf_item cidr;
struct conf_item target;
struct conf_item domain;
} revServer;
} dns;

struct {
Expand Down
48 changes: 38 additions & 10 deletions src/config/dnsmasq_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,24 +449,52 @@ bool __attribute__((const)) write_dnsmasq_config(struct config *conf, bool test_
}
fputs("\n", pihole_conf);

if(conf->dns.revServer.active.v.b)
{
fputs("# Reverse server setting\n", pihole_conf);
fprintf(pihole_conf, "rev-server=%s,%s\n",
conf->dns.revServer.cidr.v.s, conf->dns.revServer.target.v.s);
const unsigned int revServers = cJSON_GetArraySize(conf->dns.revServers.v.json);
for(unsigned int i = 0; i < revServers; i++)
{
cJSON *revServer = cJSON_GetArrayItem(conf->dns.revServers.v.json, i);

// Split comma-separated string into its components
char *copy = strdup(revServer->valuestring);
char *active = strtok(copy, ",");
char *cidr = strtok(NULL, ",");
char *target = strtok(NULL, ",");
char *domain = strtok(NULL, ",");

// Skip inactive reverse servers
if(active != NULL &&
strcmp(active, "true") != 0 &&
strcmp(active, "1") != 0)
{
log_debug(DEBUG_CONFIG, "Skipping inactive reverse server: %s", revServer->valuestring);
free(copy);
continue;
}

if(active == NULL || cidr == NULL || target == NULL || domain == NULL)
{
log_err("Invalid reverse server string: %s", revServer->valuestring);
free(copy);
continue;
}

fprintf(pihole_conf, "# Reverse server setting (%u%s server)\n",
i+1, get_ordinal_suffix(i+1));
fprintf(pihole_conf, "rev-server=%s,%s\n", cidr, target);

// If we have a reverse domain, we forward all queries to this domain to
// the same destination
if(strlen(conf->dns.revServer.domain.v.s) > 0)
fprintf(pihole_conf, "server=/%s/%s\n",
conf->dns.revServer.domain.v.s, conf->dns.revServer.target.v.s);
if(strlen(domain) > 0)
fprintf(pihole_conf, "server=/%s/%s\n", domain, target);

// Forward unqualified names to the target only when the "never forward
// non-FQDN" option is NOT ticked
if(!conf->dns.domainNeeded.v.b)
fprintf(pihole_conf, "server=//%s\n",
conf->dns.revServer.target.v.s);
fprintf(pihole_conf, "server=//%s\n", target);
fputs("\n", pihole_conf);

// Free copy of string
free(copy);
}

// When there is a Pi-hole domain set and "Never forward non-FQDNs" is
Expand Down
82 changes: 78 additions & 4 deletions src/config/setupVars.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,83 @@ static void get_conf_bool_from_setupVars(const char *key, struct conf_item *conf
key, conf_item->k, conf_item->v.b ? "true" : "false");
}

static void get_revServer_from_setupVars(void)
{
bool active = false;
char *cidr = NULL;
char *target = NULL;
char *domain = NULL;
const char *active_str = read_setupVarsconf("REV_SERVER");
if(active_str == NULL)
{
// Do not change default value, this value is not set in setupVars.conf
log_debug(DEBUG_CONFIG, "setupVars.conf:REV_SERVER -> Not set");

// Free memory, harmless to call if read_setupVarsconf() didn't return a result
clearSetupVarsArray();
return;
}
else
{
// Parameter present in setupVars.conf
active = getSetupVarsBool(active_str);
}

// Free memory, harmless to call if read_setupVarsconf() didn't return a result
clearSetupVarsArray();

char *cidr_str = read_setupVarsconf("REV_SERVER_CIDR");
if(cidr_str != NULL)
{
cidr = strdup(cidr_str);
trim_whitespace(cidr);
}

// Free memory, harmless to call if read_setupVarsconf() didn't return a result
clearSetupVarsArray();

char *target_str = read_setupVarsconf("REV_SERVER_TARGET");
if(target_str != NULL)
{
target = strdup(target_str);
trim_whitespace(target);
}

// Free memory, harmless to call if read_setupVarsconf() didn't return a result
clearSetupVarsArray();

char *domain_str = read_setupVarsconf("REV_SERVER_DOMAIN");
if(domain_str != NULL)
{
domain = strdup(domain_str);
trim_whitespace(domain);
}

// Free memory, harmless to call if read_setupVarsconf() didn't return a result
clearSetupVarsArray();

if(active && cidr != NULL && target != NULL && domain != NULL)
{
// Build comma-separated string of all values
char *old = calloc(strlen(active_str) + strlen(cidr) + strlen(target) + strlen(domain) + 4, sizeof(char));
if(old)
{
// Add to new config
sprintf(old, "%s,%s,%s,%s", active_str, cidr, target, domain);
cJSON_AddItemToArray(config.dns.revServers.v.json, cJSON_CreateString(old));
free(old);
}
}

// Free memory
if(cidr != NULL)
free(cidr);
if(target != NULL)
free(target);
if(domain != NULL)
free(domain);
}

static void get_conf_string_array_from_setupVars_regex(const char *key, struct conf_item *conf_item)
{
// Verify we are allowed to use this function
Expand Down Expand Up @@ -463,10 +540,7 @@ void importsetupVarsConf(void)
get_conf_listeningMode_from_setupVars();

// Try to obtain REV_SERVER settings
get_conf_bool_from_setupVars("REV_SERVER", &config.dns.revServer.active);
get_conf_string_from_setupVars("REV_SERVER_CIDR", &config.dns.revServer.cidr);
get_conf_string_from_setupVars("REV_SERVER_TARGET", &config.dns.revServer.target);
get_conf_string_from_setupVars("REV_SERVER_DOMAIN", &config.dns.revServer.domain);
get_revServer_from_setupVars();

// Try to obtain DHCP settings
get_conf_bool_from_setupVars("DHCP_ACTIVE", &config.dhcp.active);
Expand Down
46 changes: 46 additions & 0 deletions src/config/toml_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,48 @@
static toml_table_t *parseTOML(const unsigned int version);
static void reportDebugFlags(void);

// Migrate config from old to new, returns true if a restart is required
static bool migrate_config(toml_table_t *toml, struct config *newconf)
{
bool restart = false;
toml_table_t *dns = toml_table_in(toml, "dns");
if(dns)
{
toml_table_t *revServer = toml_table_in(dns, "revServer");
if(revServer)
{
// Read old config
toml_datum_t active = toml_bool_in(revServer, "active");
toml_datum_t cidr = toml_string_in(revServer, "cidr");
toml_datum_t target = toml_string_in(revServer, "target");
toml_datum_t domain = toml_string_in(revServer, "domain");

// Necessary condition: all values must exist and CIDR and target must not be empty
if(active.ok && cidr.ok && target.ok && domain.ok && strlen(cidr.u.s) > 0 && strlen(target.u.s))
{
// Build comma-separated string of all values
char *old = calloc((active.u.b ? 4 : 5) + strlen(cidr.u.s) + strlen(target.u.s) + strlen(domain.u.s) + 4, sizeof(char));
if(old)
{
// Add to new config
sprintf(old, "%s,%s,%s,%s", active.u.s ? "true" : "false", cidr.u.s, target.u.s, domain.u.s);
log_debug(DEBUG_CONFIG, "Config setting dns.revServer MIGRATED: %s", old);
cJSON_AddItemToArray(newconf->dns.revServers.v.json, cJSON_CreateString(old));
restart = true;
}
}
else
log_warn("Config setting dns.revServer INVALID - ignoring: %s %s %s %s", active.ok ? active.u.s : "NULL", cidr.ok ? cidr.u.s : "NULL", target.ok ? target.u.s : "NULL", domain.ok ? domain.u.s : "NULL");
}
else
log_info("dns.revServer DOES NOT EXIST");
}
else
log_info("dns DOES NOT EXIST");

return restart;
}

bool readFTLtoml(struct config *oldconf, struct config *newconf,
toml_table_t *toml, const bool verbose, bool *restart,
const unsigned int version)
Expand Down Expand Up @@ -126,6 +168,10 @@ bool readFTLtoml(struct config *oldconf, struct config *newconf,
}
}

// Migrate config from old to new
if(migrate_config(toml, newconf) && restart != NULL)
*restart = true;

// Report debug config if enabled
set_debug_flags(newconf);
if(verbose)
Expand Down
47 changes: 22 additions & 25 deletions test/pihole.toml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,28 @@
# Port used by the DNS server
port = 53

# Reverse server (former also called "conditional forwarding") feature
# Array of reverse servers each one in one of the following forms:
# "<enabled>,<ip-address>[/<prefix-len>],<server>[#<port>],<domain>"
#
# Individual components:
#
# <enabled>: either "true" or "false"
#
# <ip-address>[/<prefix-len>]: Address range for the reverse server feature in CIDR
# notation. If the prefix length is omitted, either 32 (IPv4) or 128 (IPv6) are
# substituted (exact address match). This is almost certainly not what you want here.
# Example: "192.168.0.0/24" for the range 192.168.0.1 - 192.168.0.255
#
# <server>[#<port>]: Target server to be used for the reverse server feature
# Example: "192.168.0.1#53"
#
# <domain>: Domain used for the reverse server feature (e.g., "fritz.box")
# Example: "fritz.box"
#
# A valid line could look like this: "true,192.168.0.0/24,192.168.0.1,fritz.box"
revServers = []

[dns.cache]
# Cache size of the DNS server. Note that expiring cache entries naturally make room
# for new insertions over time. Setting this number too high will have an adverse
Expand Down Expand Up @@ -348,31 +370,6 @@
# ... in the set interval before rate-limiting?
interval = 0 ### CHANGED, default = 60

[dns.revServer]
# Is the reverse server (former also called "conditional forwarding") feature enabled?
active = false

# Address range for the reverse server feature in CIDR notation. If the prefix length
# is omitted, either 32 (IPv4) or 128 (IPv6) are substitutet (exact address match).
# This is almost certainly not what you want here.
#
# Possible values are:
# <ip-address>[/<prefix-len>], e.g., "192.168.0.0/24" for the range 192.168.0.1 -
# 192.168.0.255
cidr = ""

# Target server tp be used for the reverse server feature
#
# Possible values are:
# <server>[#<port>], e.g., "192.168.0.1"
target = ""

# Domain used for the reverse server feature
#
# Possible values are:
# <valid domain> (e.g., "fritz.box")
domain = ""

[dhcp]
# Is the embedded DHCP server enabled?
active = false
Expand Down

0 comments on commit 6009a1a

Please sign in to comment.