diff --git a/src/args.c b/src/args.c index fc23c657..35f47d59 100644 --- a/src/args.c +++ b/src/args.c @@ -32,6 +32,7 @@ static inline bool strEndsWith(const char *input, const char *end){ void parse_args(int argc, char* argv[]) { + bool quiet = false; // Regardless of any arguments, we always pass "-k" (nofork) to dnsmasq argc_dnsmasq = 2; argv_dnsmasq = calloc(argc_dnsmasq, sizeof(char*)); @@ -155,15 +156,22 @@ void parse_args(int argc, char* argv[]) ok = true; } + // Quiet mode + if(strcmp(argv[i], "-q") == 0) + { + quiet = true; + ok = true; + } + // Regex test mode if(strcmp(argv[i], "regex-test") == 0) { // Enable stdout printing cli_mode = true; if(argc == i + 2) - exit(regex_test(debug, argv[i + 1], NULL)); + exit(regex_test(debug, quiet, argv[i + 1], NULL)); else if(argc == i + 3) - exit(regex_test(debug, argv[i + 1], argv[i + 2])); + exit(regex_test(debug, quiet, argv[i + 1], argv[i + 2])); else { printf("pihole-FTL: invalid option -- '%s' need either one or two parameters\nTry '%s --help' for more information\n", argv[i], argv[0]); @@ -257,10 +265,10 @@ const char __attribute__ ((const)) *cli_cross(void) return is_term() ? "["COL_RED"✗"COL_NC"]" : "[✗]"; } -// Returns [!] +// Returns [i] const char __attribute__ ((const)) *cli_info(void) { - return "[i]"; + return is_term() ? COL_BOLD"[i]"COL_NC : "[i]"; } // Returns [?] diff --git a/src/regex.c b/src/regex.c index 11ce3d22..fd9ae75d 100644 --- a/src/regex.c +++ b/src/regex.c @@ -139,20 +139,20 @@ int match_regex(const char *input, const int clientID, const enum regex_type reg if(regextest && regexid == REGEX_CLI) { // CLI provided regular expression - logg(" %s%s%s matches", + logg(" %s%s%s matches", cli_bold(), regexbuffer[regexid][index], cli_normal()); } else if(regextest && regexid == REGEX_BLACKLIST) { // Database-sourced regular expression - logg(" %s%s%s matches (regex blacklist, DB ID %i)", + logg(" %s%s%s matches (regex blacklist, DB ID %i)", cli_bold(), regexbuffer[regexid][index], cli_normal(), regex_id[regexid][index]); } else if(regextest && regexid == REGEX_WHITELIST) { // Database-sourced regular expression - logg(" %s%s%s matches (regex whitelist, DB ID %i)", + logg(" %s%s%s matches (regex whitelist, DB ID %i)", cli_bold(), regexbuffer[regexid][index], cli_normal(), regex_id[regexid][index]); } @@ -351,7 +351,7 @@ void read_regex_from_database(void) counters->clients, timer_elapsed_msec(REGEX_TIMER)); } -int regex_test(const bool debug_mode, const char *domainin, const char *regexin) +int regex_test(const bool debug_mode, const bool quiet, const char *domainin, const char *regexin) { // Prepare counters and regex memories counters = calloc(1, sizeof(countersStruct)); @@ -370,19 +370,48 @@ int regex_test(const bool debug_mode, const char *domainin, const char *regexin) if(regexin == NULL) { // Read and compile regex lists from database + if(!quiet) + { + logg("%s Loading regex filters from database...", cli_info()); + timer_start(REGEX_TIMER); + } read_regex_table(REGEX_BLACKLIST); read_regex_table(REGEX_WHITELIST); + if(!quiet) + { + logg(" Compiled %i black- and %i whitelist regex filters in %.3f msec\n", + counters->num_regex[REGEX_BLACKLIST], + counters->num_regex[REGEX_WHITELIST], + timer_elapsed_msec(REGEX_TIMER)); + } // Check user-provided domain against all loaded regular blacklist expressions - matchidx = match_regex(domainin, -1, REGEX_BLACKLIST, true); + if(!quiet) + { + logg("%s Checking domain against blacklist...", cli_info()); + timer_start(REGEX_TIMER); + } + int matchidx1 = match_regex(domainin, -1, REGEX_BLACKLIST, true); + if(!quiet) + logg(" Time: %.3f msec", timer_elapsed_msec(REGEX_TIMER)); // Check user-provided domain against all loaded regular whitelist expressions - matchidx = match_regex(domainin, -1, REGEX_WHITELIST, true); + if(!quiet) + { + logg("%s Checking domain against whitelist...", cli_info()); + timer_start(REGEX_TIMER); + } + int matchidx2 = match_regex(domainin, -1, REGEX_WHITELIST, true); + if(!quiet) + logg(" Time: %.3f msec", timer_elapsed_msec(REGEX_TIMER)); + matchidx = MAX(matchidx1, matchidx2); } else { // Compile CLI regex + if(!quiet) + logg("%s Compiling regex filter...", cli_info()); counters->num_regex[REGEX_BLACKLIST] = counters->num_regex[REGEX_WHITELIST] = 0; counters->num_regex[REGEX_CLI] = 1; @@ -393,14 +422,28 @@ int regex_test(const bool debug_mode, const char *domainin, const char *regexin) regexbuffer[REGEX_CLI] = calloc(counters->num_regex[REGEX_CLI], sizeof(char*)); // Compile CLI regex - timer_start(REGEX_TIMER); + if(!quiet) + timer_start(REGEX_TIMER); if(compile_regex(regexin, 0, REGEX_CLI, -1)) regex_available[REGEX_CLI][0] = true; else return EXIT_FAILURE; + if(!quiet) + logg(" Compiled regex filter in %.3f msec\n", timer_elapsed_msec(REGEX_TIMER)); // Check user-provided domain against user-provided regular expression + if(!quiet) + { + logg("Checking domain..."); + timer_start(REGEX_TIMER); + } matchidx = match_regex(domainin, -1, REGEX_CLI, true); + if(!quiet) + { + if(matchidx == -1) + logg(" NO MATCH!"); + logg(" Time: %.3f msec", timer_elapsed_msec(REGEX_TIMER)); + } } // Return status 0 = MATCH, 1 = ERROR, 2 = NO MATCH diff --git a/src/regex_r.h b/src/regex_r.h index 8c1591df..97d608c8 100644 --- a/src/regex_r.h +++ b/src/regex_r.h @@ -19,6 +19,6 @@ int match_regex(const char *input, const int clientID, const enum regex_type, co void allocate_regex_client_enabled(clientsData *client, const int clientID); void read_regex_from_database(void); -int regex_test(const bool debug_mode, const char *domainin, const char *regexin); +int regex_test(const bool debug_mode, const bool quiet, const char *domainin, const char *regexin); #endif //REGEX_H diff --git a/test/test_suite.bats b/test/test_suite.bats index 9bc697ac..39276c75 100644 --- a/test/test_suite.bats +++ b/test/test_suite.bats @@ -404,161 +404,138 @@ @test "Regex Test 1: \"regex7.test.pi-hole.net\" vs. [database regex]: MATCH" { run bash -c './pihole-FTL regex-test "regex7.test.pi-hole.net"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 2: \"a\" vs. \"a\": MATCH" { run bash -c './pihole-FTL regex-test "a" "a"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 3: \"aa\" vs. \"^[a-z]{1,3}$\": MATCH" { run bash -c './pihole-FTL regex-test "aa" "^[a-z]{1,3}$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 4: \"aaaa\" vs. \"^[a-z]{1,3}$\": NO MATCH" { run bash -c './pihole-FTL regex-test "aaaa" "^[a-z]{1,3}$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✗]"* ]] [[ $status == 2 ]] } @test "Regex Test 5: \"aa\" vs. \"^a(?#some comment)a$\": MATCH (comments)" { run bash -c './pihole-FTL regex-test "aa" "^a(?#some comment)a$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 6: \"abc.abc\" vs. \"([a-z]*)\.\1\": MATCH" { run bash -c './pihole-FTL regex-test "abc.abc" "([a-z]*)\.\1"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 7: Complex character set: MATCH" { run bash -c './pihole-FTL regex-test "__abc#LMN012$x%yz789*" "[[:digit:]a-z#$%]+"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 8: Range expression: MATCH" { run bash -c './pihole-FTL regex-test "!ABC-./XYZ~" "[--Z]+"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 9: Back reference: \"aabc\" vs. \"(a)\1{1,2}\": MATCH" { run bash -c './pihole-FTL regex-test "aabc" "(a)\1{1,2}"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 10: Back reference: \"foo\" vs. \"(.)\1$\": MATCH" { run bash -c './pihole-FTL regex-test "foo" "(.)\1$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 11: Back reference: \"foox\" vs. \"(.)\1$\": NO MATCH" { run bash -c './pihole-FTL regex-test "foox" "(.)\1$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✗]"* ]] [[ $status == 2 ]] } @test "Regex Test 12: Back reference: \"1234512345\" vs. \"([0-9]{5})\1\": MATCH" { run bash -c './pihole-FTL regex-test "1234512345" "([0-9]{5})\1"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 13: Back reference: \"12345\" vs. \"([0-9]{5})\1\": NO MATCH" { run bash -c './pihole-FTL regex-test "12345" "([0-9]{5})\1"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✗]"* ]] [[ $status == 2 ]] } @test "Regex Test 14: Complex back reference: MATCH" { run bash -c './pihole-FTL regex-test "cat.foo.dog---cat%dog!foo" "(cat)\.(foo)\.(dog)---\1%\3!\2"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 15: Approximate matching, 0 errors: MATCH" { run bash -c './pihole-FTL regex-test "foobarzap" "foo(bar){~1}zap"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 16: Approximate matching, 1 error (inside fault-tolerant area): MATCH" { run bash -c './pihole-FTL regex-test "foobrzap" "foo(bar){~1}zap"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 17: Approximate matching, 1 error (outside fault-tolert area): NO MATCH" { run bash -c './pihole-FTL regex-test "foxbrazap" "foo(bar){~1}zap"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✗]"* ]] [[ $status == 2 ]] } @test "Regex Test 18: Approximate matching, 0 global errors: MATCH" { run bash -c './pihole-FTL regex-test "foobar" "^(foobar){~1}$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 19: Approximate matching, 1 global error: MATCH" { run bash -c './pihole-FTL regex-test "cfoobar" "^(foobar){~1}$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 20: Approximate matching, 2 global errors: NO MATCH" { run bash -c './pihole-FTL regex-test "ccfoobar" "^(foobar){~1}$"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✗]"* ]] [[ $status == 2 ]] } @test "Regex Test 21: Approximate matching, insert + substitute: MATCH" { run bash -c './pihole-FTL regex-test "oobargoobaploowap" "(foobar){+2#2~2}"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 22: Approximate matching, insert + delete: MATCH" { run bash -c './pihole-FTL regex-test "3oifaowefbaoraofuiebofasebfaobfaorfeoaro" "(foobar){+1 -2}"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✓]"* ]] [[ $status == 0 ]] } @test "Regex Test 23: Approximate matching, insert + delete (insufficient): NO MATCH" { run bash -c './pihole-FTL regex-test "3oifaowefbaoraofuiebofasebfaobfaorfeoaro" "(foobar){+1 -1}"' printf "%s\n" "${lines[@]}" - [[ ${lines[4]} == "[✗]"* ]] [[ $status == 2 ]] } @@ -632,6 +609,13 @@ [[ $status == 1 ]] } +@test "Regex Test 34: Quiet mode gives only one line as result" { + run bash -c './pihole-FTL -q regex-test "fbcdn.net" "f"' + printf "%s\n" "${lines[@]}" + [[ ${lines[0]} == " f matches" ]] + [[ $status == 0 ]] +} + # 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.