diff --git a/src/regex.c b/src/regex.c index ad0f5ea4..e938ff8c 100644 --- a/src/regex.c +++ b/src/regex.c @@ -159,9 +159,13 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co // Analyze FTL-specific parts while((part = strtok_r(NULL, FTL_REGEX_SEP, &saveptr)) != NULL) { - char extra[17] = { 0 }; - // options ";querytype=!AAAA" and ";querytype=AAAA" - if(sscanf(part, "querytype=%16s", extra)) + char extra[64] = { 0 }; + // options like + // - ";querytype=A" (only match type A queries) + // - ";querytype=!AAAA" (match everything but AAAA queries) + // - ";querytype=A,AAAA" (match only A and AAAA queries) + // - ";querytype=!A,AAAA" (match everything but A and AAAA queries) + if(sscanf(part, "querytype=%63s", extra)) { // Warn if specified more than one querytype option if(regex[index].ext.query_type != 0) @@ -169,6 +173,19 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co "Overwriting previous querytype setting", dbidx, regexin); + // Check if the first letter is a "!" + // This means that the query type matching is inverted + bool inverted = false; + if(extra[0] == '!') + { + // Set inverted mode (will be applied + // after parsing all query types) + inverted = true; + + // Remove the "!" from the string + memmove(extra, extra+1, strlen(extra)); + } + // Split input string into individual query types char *saveptr2 = NULL; char *token = strtok_r(extra, ",", &saveptr2); @@ -183,12 +200,6 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co regex[index].ext.query_type ^= 1 << type; break; } - // Check for INVERTED querytype - else if(token[0] == '!' && strcasecmp(token + 1u, querytypes[type]) == 0) - { - regex[index].ext.query_type ^= ~(1 << type); - break; - } } // Check if we found a valid query type if(regex[index].ext.query_type == 0) @@ -203,6 +214,11 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co // Get next token token = strtok_r(NULL, ",", &saveptr2); } + + // Invert query types if requested + if(inverted) + regex[index].ext.query_type = ~regex[index].ext.query_type; + if(regex[index].ext.query_type != 0 && config.debug & DEBUG_REGEX) { logg(" Hint: This regex matches only specific query types:"); diff --git a/test/gravity.db.sql b/test/gravity.db.sql index c317a2dc..22133c84 100644 --- a/test/gravity.db.sql +++ b/test/gravity.db.sql @@ -208,9 +208,11 @@ INSERT INTO domainlist VALUES(11,3,'^regex-REPLYv6$;reply=fe80::1234',1,15599288 INSERT INTO domainlist VALUES(12,3,'^regex-REPLYv46$;reply=1.2.3.4;reply=fe80::1234',1,1559928803,1559928803,''); INSERT INTO domainlist VALUES(13,3,'^regex-A$;querytype=A',1,1559928803,1559928803,''); INSERT INTO domainlist VALUES(14,3,'^regex-notA$;querytype=!A',1,1559928803,1559928803,''); +INSERT INTO domainlist VALUES(15,3,'^regex-multiple.ftl$;querytype=ANY,HTTPS,SVCB;reply=refused',1,1559928803,1559928803,''); +INSERT INTO domainlist VALUES(16,3,'^regex-notMultiple.ftl$;querytype=!ANY,HTTPS,SVCB;reply=refused',1,1559928803,1559928803,''); /* Other special domains */ -INSERT INTO domainlist VALUES(15,1,'blacklisted-group-disabled.com',1,1559928803,1559928803,'Entry disabled by a group'); +INSERT INTO domainlist VALUES(17,1,'blacklisted-group-disabled.com',1,1559928803,1559928803,'Entry disabled by a group'); INSERT INTO adlist VALUES(1,'https://hosts-file.net/ad_servers.txt',1,1559928803,1559928803,'Migrated from /etc/pihole/adlists.list',1559928803,2000,2,1); diff --git a/test/pdns/setup.sh b/test/pdns/setup.sh index ea53a51b..390b9073 100644 --- a/test/pdns/setup.sh +++ b/test/pdns/setup.sh @@ -98,9 +98,19 @@ pdnsutil add-record ftl. mx MX "50 ns1.ftl." # SVCB + HTTPS pdnsutil add-record ftl. svcb SVCB '1 port="80"' +pdnsutil add-record ftl. regex-multiple SVCB '1 port="80"' +pdnsutil add-record ftl. regex-notMultiple SVCB '1 port="80"' # HTTPS pdnsutil add-record ftl. https HTTPS '1 . alpn="h3,h2"' +pdnsutil add-record ftl. regex-multiple HTTPS '1 . alpn="h3,h2"' +pdnsutil add-record ftl. regex-notMultiple HTTPS '1 . alpn="h3,h2"' + +# ANY +pdnsutil add-record ftl. regex-multiple A 192.168.3.12 +pdnsutil add-record ftl. regex-multiple AAAA fe80::3f41 +pdnsutil add-record ftl. regex-notMultiple A 192.168.3.12 +pdnsutil add-record ftl. regex-notMultiple AAAA fe80::3f41 # Create reverse lookup zone pdnsutil create-zone arpa ns1.ftl diff --git a/test/test_suite.bats b/test/test_suite.bats index a899cf4d..e143633e 100644 --- a/test/test_suite.bats +++ b/test/test_suite.bats @@ -58,7 +58,7 @@ @test "Number of compiled regex filters as expected" { run bash -c 'grep "Compiled [0-9]* whitelist" /var/log/pihole/FTL.log' printf "%s\n" "${lines[@]}" - [[ ${lines[0]} == *"Compiled 2 whitelist and 9 blacklist regex filters"* ]] + [[ ${lines[0]} == *"Compiled 2 whitelist and 11 blacklist regex filters"* ]] } @test "Blacklisted domain is blocked" { @@ -196,7 +196,7 @@ [[ ${lines[0]} == "2" ]] run bash -c "grep -c 'Regex blacklist ([[:digit:]]*, DB ID [[:digit:]]*) .* NOT ENABLED for client 127.0.0.4' /var/log/pihole/FTL.log" printf "%s\n" "${lines[@]}" - [[ ${lines[0]} == "9" ]] + [[ ${lines[0]} == "11" ]] } @test "Client 5: Client is recognized by MAC address" { @@ -228,7 +228,7 @@ [[ ${lines[0]} == "2" ]] run bash -c "grep -c 'Regex blacklist ([[:digit:]]*, DB ID [[:digit:]]*) .* NOT ENABLED for client 127.0.0.5' /var/log/pihole/FTL.log" printf "%s\n" "${lines[@]}" - [[ ${lines[0]} == "9" ]] + [[ ${lines[0]} == "11" ]] } @test "Client 6: Client is recognized by interface name" { @@ -266,7 +266,7 @@ [[ ${lines[0]} == "2" ]] run bash -c "grep -c 'Regex blacklist ([[:digit:]]*, DB ID [[:digit:]]*) .* NOT ENABLED for client 127.0.0.6' /var/log/pihole/FTL.log" printf "%s\n" "${lines[@]}" - [[ ${lines[0]} == "9" ]] + [[ ${lines[0]} == "11" ]] } @test "Normal query (A) is not blocked" { @@ -1082,6 +1082,42 @@ [[ "${lines[@]}" == *"- HTTPS"* ]] } +@test "Regex Test 52: Option \";querytype=ANY,HTTPS,SVCB;reply=refused\" working as expected (ONLY matching ANY, HTTPS or SVCB queries)" { + run bash -c 'dig A regex-multiple.ftl @127.0.0.1' + printf "dig A: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: NOERROR"* ]] + run bash -c 'dig AAAA regex-multiple.ftl @127.0.0.1' + printf "dig AAAA: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: NOERROR"* ]] + run bash -c 'dig SVCB regex-multiple.ftl @127.0.0.1' + printf "dig SVCB: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: REFUSED"* ]] + run bash -c 'dig HTTPS regex-multiple.ftl @127.0.0.1' + printf "dig HTTPS: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: REFUSED"* ]] + run bash -c 'dig ANY regex-multiple.ftl @127.0.0.1' + printf "dig ANY: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: REFUSED"* ]] +} + +@test "Regex Test 53: Option \";querytype=!ANY,HTTPS,SVCB;reply=refused\" working as expected (NOT matching ANY, HTTPS or SVCB queries)" { + run bash -c 'dig A regex-notMultiple.ftl @127.0.0.1' + printf "dig A: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: REFUSED"* ]] + run bash -c 'dig AAAA regex-notMultiple.ftl @127.0.0.1' + printf "dig AAAA: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: REFUSED"* ]] + run bash -c 'dig SVCB regex-notMultiple.ftl @127.0.0.1' + printf "dig SVCB: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: NOERROR"* ]] + run bash -c 'dig HTTPS regex-notMultiple.ftl @127.0.0.1' + printf "dig HTTPS: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: NOERROR"* ]] + run bash -c 'dig ANY regex-notMultiple.ftl @127.0.0.1' + printf "dig ANY: %s\n" "${lines[@]}" + [[ "${lines[@]}" == *"status: NOERROR"* ]] +} + # x86_64-musl is built on busybox which has a slightly different # variant of ls displaying three, instead of one, spaces between the # user and group names.