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:
DL6ER
2023-02-14 23:21:28 +01:00
parent e938e27c2e
commit 8794b1684d
7 changed files with 156 additions and 33 deletions
+1 -1
View File
@@ -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",
+14
View File
@@ -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);
+1
View File
@@ -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;
+92 -1
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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]} == "" ]]
}