mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
Add ABP format blocking support for gravity. Note that the option needs to be switched on by setting GRAVITY_ABP_STYLE=true in pihole-FTL.conf to avoid running this computationally expensive task on the vast majority of user databases only fed from properly formatted HOSTS lists. Gravity can enable the setting when it detects ABP format automatically.
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "FTL x86_64 Build Env",
|
||||
"image": "ghcr.io/pi-hole/ftl-build:x86_64",
|
||||
"image": "ghcr.io/pi-hole/ftl-build:x86_64-musl",
|
||||
"extensions": [
|
||||
"jetmartin.bats",
|
||||
"ms-vscode.cpptools",
|
||||
|
||||
@@ -770,6 +770,20 @@ void read_FTLconf(void)
|
||||
|
||||
logg(" CHECK_DISK: Warning if certain disk usage exceeds %d%%", config.check.disk);
|
||||
|
||||
// GRAVITY_ABP_STYLE
|
||||
// Should FTL check for ABP-style domain entries in the gravity database?
|
||||
// This option should only be enabled if you are using ABP-style entries
|
||||
// in your gravity database as it adds a significant overhead to the
|
||||
// database query.
|
||||
// defaults to: false
|
||||
buffer = parse_FTLconf(fp, "GRAVITY_ABP_STYLE");
|
||||
config.gravityABP = read_bool(buffer, false);
|
||||
|
||||
if(config.gravityABP)
|
||||
logg(" GRAVITY_ABP_STYLE: Enabled");
|
||||
else
|
||||
logg(" GRAVITY_ABP_STYLE: Disabled");
|
||||
|
||||
// Read DEBUG_... setting from pihole-FTL.conf
|
||||
read_debuging_settings(fp);
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef struct {
|
||||
bool edns0_ecs :1;
|
||||
bool show_dnssec :1;
|
||||
bool addr2line :1;
|
||||
bool gravityABP:1;
|
||||
struct {
|
||||
bool mozilla_canary :1;
|
||||
bool icloud_private_relay :1;
|
||||
|
||||
@@ -1290,7 +1290,98 @@ enum db_result in_gravity(const char *domain, clientsData *client)
|
||||
if(stmt == NULL)
|
||||
stmt = gravity_stmt->get(gravity_stmt, client->id);
|
||||
|
||||
return domain_in_list(domain, stmt, "gravity", NULL);
|
||||
// Check if domain is exactly in gravity list
|
||||
const bool exact_match = domain_in_list(domain, stmt, "gravity", NULL);
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
logg("Checking if \"%s\" is in gravity: %s", domain, exact_match ? "yes" : "no");
|
||||
if(exact_match)
|
||||
return FOUND;
|
||||
|
||||
// Return early if we are not supposed to check for ABP-style regex
|
||||
// matches. This needs to be enabled in the config file as it is
|
||||
// computationally expensive and not needed in most cases (HOSTS lists).
|
||||
if(!config.gravityABP)
|
||||
return NOT_FOUND;
|
||||
|
||||
// Make a copy of the domain we will slowly truncate
|
||||
// while extracting the individual components below
|
||||
char *domainBuf = strdup(domain);
|
||||
|
||||
// Buffer to hold the constructed (sub)domain in ABP format
|
||||
char *abpDomain = calloc(strlen(domain) + 4, sizeof(char));
|
||||
// Prime abp matcher with minimal content
|
||||
strcpy(abpDomain, "||^");
|
||||
|
||||
// Get number of domain parts (equals the number of dots + 1)
|
||||
unsigned int N = 1u;
|
||||
for(const char *p = domain; *p != '\0'; p++)
|
||||
if(*p == '.')
|
||||
N++;
|
||||
|
||||
// Loop over domain parts, building matcher from the TLD
|
||||
// going down into domain and subdomains one by one
|
||||
while(N-- > 0)
|
||||
{
|
||||
// Get domain to the *last* occurence of '.'
|
||||
char *ptr = strrchr(domainBuf, '.');
|
||||
|
||||
// If there are no '.' left in the domain buffer, we use the
|
||||
// remainder which is the left-most domain component
|
||||
if(ptr == NULL)
|
||||
ptr = domainBuf;
|
||||
|
||||
// Get size of this component...
|
||||
const size_t component_size = strlen(ptr);
|
||||
// ... and use it to create a "gap" of the right size in our ABP
|
||||
// format buffer
|
||||
// Insert the domain component into the gap
|
||||
if(ptr[0] == '.')
|
||||
{
|
||||
// If the component starts with a dot, we need
|
||||
// to skip it when copying it into the ABP buffer
|
||||
// Move excluding initial "||" but including final \0 (strlen-2+1 = strlen-1)
|
||||
memmove(abpDomain+2+component_size-1, abpDomain+2, strlen(abpDomain)-1);
|
||||
// Copy component bytes (excl. trailling null-byte)
|
||||
memcpy(abpDomain+2, ptr+1, component_size-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, we copy the component as-is
|
||||
memmove(abpDomain+2+component_size, abpDomain+2, strlen(abpDomain)-1);
|
||||
// Copy component bytes (excl. trailling null-byte)
|
||||
memcpy(abpDomain+2, ptr, component_size);
|
||||
}
|
||||
// Check if the constructed ABP-style domain is in the gravity list
|
||||
const bool abp_match = domain_in_list(abpDomain, stmt, "gravity", NULL);
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
logg("Checking if \"%s\" is in gravity: %s", abpDomain, abp_match ? "yes" : "no");
|
||||
if(abp_match)
|
||||
{
|
||||
free(domainBuf);
|
||||
free(abpDomain);
|
||||
return FOUND;
|
||||
}
|
||||
// Truncate the domain buffer to the left of the
|
||||
// last dot, effectively removing the last component
|
||||
const ssize_t truncate_pos = strlen(domainBuf)-component_size;
|
||||
if(truncate_pos < 1)
|
||||
// This was already the last iteration
|
||||
break;
|
||||
|
||||
// Put a null-byte at the truncation position
|
||||
domainBuf[truncate_pos] = '\0';
|
||||
|
||||
// Move the ABP buffer to the right by one byte ...
|
||||
memmove(abpDomain+3, abpDomain+2, strlen(abpDomain));
|
||||
// ... and insert '.' for the next iteration
|
||||
abpDomain[2] = '.';
|
||||
}
|
||||
|
||||
free(domainBuf);
|
||||
free(abpDomain);
|
||||
|
||||
// Domain not found in gravity list
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
enum db_result in_blacklist(const char *domain, DNSCacheData *dns_cache, clientsData *client)
|
||||
|
||||
+2
-1
@@ -220,7 +220,8 @@ INSERT INTO gravity VALUES('whitelisted.ftl',1);
|
||||
INSERT INTO gravity VALUES('gravity.ftl',1);
|
||||
INSERT INTO gravity VALUES('gravity-aaaa.ftl',1);
|
||||
INSERT INTO gravity VALUES('gravity-whitelisted.ftl',1);
|
||||
INSERT INTO info VALUES('gravity_count',4);
|
||||
INSERT INTO gravity VALUES('||special.gravity.ftl^',1);
|
||||
INSERT INTO info VALUES('gravity_count',5);
|
||||
|
||||
INSERT INTO "group" VALUES(1,0,'Test group',1559928803,1559928803,'A disabled test group');
|
||||
INSERT INTO domainlist_by_group VALUES(15,1);
|
||||
|
||||
@@ -7,3 +7,4 @@ LOCAL_IPV4=10.100.0.10
|
||||
LOCAL_IPV6=fe80::10
|
||||
BLOCK_IPV4=10.100.0.11
|
||||
BLOCK_IPV6=fe80::11
|
||||
GRAVITY_ABP_STYLE=true
|
||||
|
||||
+45
-30
@@ -426,14 +426,25 @@
|
||||
[[ ${lines[@]} == *"status: SERVFAIL"* ]]
|
||||
}
|
||||
|
||||
@test "ABP-style matching working as expected" {
|
||||
run bash -c "dig A special.gravity.ftl @127.0.0.1 +short"
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[0]} == "0.0.0.0" ]]
|
||||
[[ ${lines[1]} == "" ]]
|
||||
run bash -c "dig A a.b.c.d.special.gravity.ftl @127.0.0.1 +short"
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[0]} == "0.0.0.0" ]]
|
||||
[[ ${lines[1]} == "" ]]
|
||||
}
|
||||
|
||||
@test "Statistics as expected" {
|
||||
run bash -c 'echo ">stats >quit" | nc -v 127.0.0.1 4711'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[1]} == "domains_being_blocked 4" ]]
|
||||
[[ ${lines[2]} == "dns_queries_today 52" ]]
|
||||
[[ ${lines[3]} == "ads_blocked_today 13" ]]
|
||||
[[ ${lines[1]} == "domains_being_blocked 5" ]]
|
||||
[[ ${lines[2]} == "dns_queries_today 54" ]]
|
||||
[[ ${lines[3]} == "ads_blocked_today 15" ]]
|
||||
#[[ ${lines[4]} == "ads_percentage_today 7.792208" ]]
|
||||
[[ ${lines[5]} == "unique_domains 37" ]]
|
||||
[[ ${lines[5]} == "unique_domains 39" ]]
|
||||
[[ ${lines[6]} == "queries_forwarded 27" ]]
|
||||
[[ ${lines[7]} == "queries_cached 12" ]]
|
||||
# Clients ever seen is commented out as the CI may have
|
||||
@@ -441,12 +452,12 @@
|
||||
# number of clients may not work in all cases
|
||||
#[[ ${lines[8]} == "clients_ever_seen 8" ]]
|
||||
#[[ ${lines[9]} == "unique_clients 8" ]]
|
||||
[[ ${lines[10]} == "dns_queries_all_types 52" ]]
|
||||
[[ ${lines[10]} == "dns_queries_all_types 54" ]]
|
||||
[[ ${lines[11]} == "reply_UNKNOWN 0" ]]
|
||||
[[ ${lines[12]} == "reply_NODATA 0" ]]
|
||||
[[ ${lines[13]} == "reply_NXDOMAIN 1" ]]
|
||||
[[ ${lines[14]} == "reply_CNAME 7" ]]
|
||||
[[ ${lines[15]} == "reply_IP 23" ]]
|
||||
[[ ${lines[15]} == "reply_IP 25" ]]
|
||||
[[ ${lines[16]} == "reply_DOMAIN 0" ]]
|
||||
[[ ${lines[17]} == "reply_RRNAME 5" ]]
|
||||
[[ ${lines[18]} == "reply_SERVFAIL 0" ]]
|
||||
@@ -456,7 +467,7 @@
|
||||
[[ ${lines[22]} == "reply_DNSSEC 6" ]]
|
||||
[[ ${lines[23]} == "reply_NONE 0" ]]
|
||||
[[ ${lines[24]} == "reply_BLOB 10" ]]
|
||||
[[ ${lines[25]} == "dns_queries_all_replies 52" ]]
|
||||
[[ ${lines[25]} == "dns_queries_all_replies 54" ]]
|
||||
[[ ${lines[26]} == "privacy_level 0" ]]
|
||||
[[ ${lines[27]} == "status enabled" ]]
|
||||
[[ ${lines[28]} == "" ]]
|
||||
@@ -471,7 +482,7 @@
|
||||
@test "Top Clients" {
|
||||
run bash -c 'echo ">top-clients >quit" | nc -v 127.0.0.1 4711'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[1]} == "0 36 127.0.0.1 "* ]]
|
||||
[[ ${lines[1]} == "0 38 127.0.0.1 "* ]]
|
||||
[[ ${lines[2]} == "1 6 :: "* ]]
|
||||
[[ ${lines[3]} == "2 4 127.0.0.3 "* ]]
|
||||
[[ ${lines[4]} == "3 3 127.0.0.2 "* ]]
|
||||
@@ -519,12 +530,14 @@
|
||||
[[ "${lines[@]}" == *" 2 gravity-aaaa.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 blacklisted.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 whitelisted.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 special.gravity.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 a.b.c.d.special.gravity.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 regex5.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 regex1.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 cname-1.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 cname-7.ftl"* ]]
|
||||
[[ "${lines[@]}" == *" 1 use-application-dns.net"* ]]
|
||||
[[ ${lines[12]} == "" ]]
|
||||
[[ ${lines[14]} == "" ]]
|
||||
}
|
||||
|
||||
@test "Domain auditing, approved domains are not shown" {
|
||||
@@ -542,33 +555,33 @@
|
||||
@test "Upstream Destinations reported correctly" {
|
||||
run bash -c 'echo ">forward-dest >quit" | nc -v 127.0.0.1 4711'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[1]} == "-3 25.00 blocked blocked" ]]
|
||||
[[ ${lines[2]} == "-2 23.08 cached cached" ]]
|
||||
[[ ${lines[1]} == "-3 27.78 blocked blocked" ]]
|
||||
[[ ${lines[2]} == "-2 22.22 cached cached" ]]
|
||||
[[ ${lines[3]} == "-1 0.00 other other" ]]
|
||||
[[ ${lines[4]} == "0 48.08 127.0.0.1#5555 127.0.0.1#5555" ]]
|
||||
[[ ${lines[5]} == "1 3.85 127.0.0.1#5554 127.0.0.1#5554" ]]
|
||||
[[ ${lines[4]} == "0 46.30 127.0.0.1#5555 127.0.0.1#5555" ]]
|
||||
[[ ${lines[5]} == "1 3.70 127.0.0.1#5554 127.0.0.1#5554" ]]
|
||||
[[ ${lines[6]} == "" ]]
|
||||
}
|
||||
|
||||
@test "Query Types reported correctly" {
|
||||
run bash -c 'echo ">querytypes >quit" | nc -v 127.0.0.1 4711'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[1]} == "A (IPv4): 50.00" ]]
|
||||
[[ ${lines[2]} == "AAAA (IPv6): 7.69" ]]
|
||||
[[ ${lines[3]} == "ANY: 1.92" ]]
|
||||
[[ ${lines[4]} == "SRV: 1.92" ]]
|
||||
[[ ${lines[5]} == "SOA: 1.92" ]]
|
||||
[[ ${lines[6]} == "PTR: 1.92" ]]
|
||||
[[ ${lines[7]} == "TXT: 11.54" ]]
|
||||
[[ ${lines[8]} == "NAPTR: 1.92" ]]
|
||||
[[ ${lines[9]} == "MX: 1.92" ]]
|
||||
[[ ${lines[10]} == "DS: 5.77" ]]
|
||||
[[ ${lines[1]} == "A (IPv4): 51.85" ]]
|
||||
[[ ${lines[2]} == "AAAA (IPv6): 7.41" ]]
|
||||
[[ ${lines[3]} == "ANY: 1.85" ]]
|
||||
[[ ${lines[4]} == "SRV: 1.85" ]]
|
||||
[[ ${lines[5]} == "SOA: 1.85" ]]
|
||||
[[ ${lines[6]} == "PTR: 1.85" ]]
|
||||
[[ ${lines[7]} == "TXT: 11.11" ]]
|
||||
[[ ${lines[8]} == "NAPTR: 1.85" ]]
|
||||
[[ ${lines[9]} == "MX: 1.85" ]]
|
||||
[[ ${lines[10]} == "DS: 5.56" ]]
|
||||
[[ ${lines[11]} == "RRSIG: 0.00" ]]
|
||||
[[ ${lines[12]} == "DNSKEY: 5.77" ]]
|
||||
[[ ${lines[13]} == "NS: 1.92" ]]
|
||||
[[ ${lines[14]} == "OTHER: 1.92" ]]
|
||||
[[ ${lines[15]} == "SVCB: 1.92" ]]
|
||||
[[ ${lines[16]} == "HTTPS: 1.92" ]]
|
||||
[[ ${lines[12]} == "DNSKEY: 5.56" ]]
|
||||
[[ ${lines[13]} == "NS: 1.85" ]]
|
||||
[[ ${lines[14]} == "OTHER: 1.85" ]]
|
||||
[[ ${lines[15]} == "SVCB: 1.85" ]]
|
||||
[[ ${lines[16]} == "HTTPS: 1.85" ]]
|
||||
[[ ${lines[17]} == "" ]]
|
||||
}
|
||||
|
||||
@@ -629,7 +642,9 @@
|
||||
[[ ${lines[50]} == *" DNSKEY dnssec.works :: 2 1 11 "*" N/A -1 127.0.0.1#5555 \"\" \"49\""* ]]
|
||||
[[ ${lines[51]} == *" A fail01.dnssec.works 127.0.0.1 2 3 4 "*" N/A -1 127.0.0.1#5555 \"RRSIG missing\" \"50\""* ]]
|
||||
[[ ${lines[52]} == *" DS fail01.dnssec.works :: 2 1 11 "*" N/A -1 127.0.0.1#5555 \"\" \"51\""* ]]
|
||||
[[ ${lines[53]} == "" ]]
|
||||
[[ ${lines[53]} == *" A special.gravity.ftl 127.0.0.1 1 2 4 "*" N/A -1 N/A#0 \"\" \"52\""* ]]
|
||||
[[ ${lines[54]} == *" A a.b.c.d.special.gravity.ftl 127.0.0.1 1 2 4 "*" N/A -1 N/A#0 \"\" \"53\""* ]]
|
||||
[[ ${lines[55]} == "" ]]
|
||||
}
|
||||
|
||||
@test "Get all queries (domain filtered) shows expected content" {
|
||||
@@ -642,7 +657,7 @@
|
||||
@test "Recent blocked shows expected content" {
|
||||
run bash -c 'echo ">recentBlocked >quit" | nc -v 127.0.0.1 4711'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[1]} == "aaaa-cname.ftl" ]]
|
||||
[[ ${lines[1]} == "a.b.c.d.special.gravity.ftl" ]]
|
||||
[[ ${lines[2]} == "" ]]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user