mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
Add the ability to whitelist regex blocked. This significantly improves the flexibility of whitelisting and implements full wildcard whitelisting support.
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
@@ -209,6 +209,11 @@ typedef struct {
|
||||
int querytypedata;
|
||||
} memoryStruct;
|
||||
|
||||
typedef struct {
|
||||
int count;
|
||||
char **domains;
|
||||
} whitelistStruct;
|
||||
|
||||
// Prepare timers, used mainly for debugging purposes
|
||||
#define NUMTIMERS 5
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
static int num_regex;
|
||||
static regex_t *regex;
|
||||
static bool *regexconfigured;
|
||||
static whitelistStruct whitelist = { 0, NULL };
|
||||
|
||||
static void log_regex_error(char *where, int errcode, int index)
|
||||
{
|
||||
@@ -40,6 +41,28 @@ static bool init_regex(char *regexin, int index)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool in_whitelist(char *domain)
|
||||
{
|
||||
bool found = false;
|
||||
for(int i=0; i < whitelist.count; i++)
|
||||
{
|
||||
// strcasecmp() compares two strings ignoring case
|
||||
if(strcasecmp(whitelist.domains[i], domain) == 0)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static void free_whitelist_domains(void)
|
||||
{
|
||||
for(int i=0; i < whitelist.count; i++)
|
||||
free(whitelist.domains[i]);
|
||||
whitelist.count = 0;
|
||||
}
|
||||
|
||||
bool match_regex(char *input)
|
||||
{
|
||||
int index;
|
||||
@@ -68,6 +91,15 @@ bool match_regex(char *input)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If a regex filter matched, we additionally compare the domain
|
||||
// against all known whitelisted domains to possibly prevent blocking
|
||||
// of a specific domain. The login herein is:
|
||||
// If matched, then compare against whitelist
|
||||
// If in whitelist, negate matched so this function returns: not-to-be-blocked
|
||||
if(matched)
|
||||
matched = !in_whitelist(input);
|
||||
|
||||
logg("Regex evaluation took %.3f msec", timer_elapsed_msec(REGEX_TIMER));
|
||||
// No match, no error, return false
|
||||
return matched;
|
||||
@@ -101,6 +133,59 @@ void free_regex(void)
|
||||
{
|
||||
domains[i].regexmatch = REGEX_UNKNOWN;
|
||||
}
|
||||
|
||||
// Also free array of whitelisted domains
|
||||
free_whitelist_domains();
|
||||
}
|
||||
|
||||
static void read_whitelist_from_file(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char *buffer = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
// Start timer for regex compilation analysis
|
||||
timer_start(REGEX_TIMER);
|
||||
|
||||
// Get number of lines in the regex file
|
||||
whitelist.count = countlines(files.whitelist);
|
||||
|
||||
if(whitelist.count < 0)
|
||||
{
|
||||
logg("INFO: No whitelist file found");
|
||||
return;
|
||||
}
|
||||
|
||||
if((fp = fopen(files.whitelist, "r")) == NULL) {
|
||||
logg("WARN: Cannot access whitelist (%s)",files.whitelist);
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate memory for regex
|
||||
whitelist.domains = calloc(whitelist.count, sizeof(char*));
|
||||
|
||||
// Search through file
|
||||
// getline reads a string from the specified file up to either a
|
||||
// newline character or EOF
|
||||
for(int i=0; getline(&buffer, &size, fp) != -1; i++)
|
||||
{
|
||||
// Strip potential newline character at the end of line we just read
|
||||
if(buffer[strlen(buffer)-1] == '\n')
|
||||
buffer[strlen(buffer)-1] = '\0';
|
||||
|
||||
// Copy this whitelist domain into memory
|
||||
whitelist.domains[i] = strdup(buffer);
|
||||
}
|
||||
|
||||
// Free allocated memory
|
||||
if(buffer != NULL)
|
||||
{
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
}
|
||||
|
||||
// Close the file
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void read_regex_from_file(void)
|
||||
@@ -155,5 +240,8 @@ void read_regex_from_file(void)
|
||||
// Close the file
|
||||
fclose(fp);
|
||||
|
||||
logg("Compiled %i Regex filters in %.1f msec (%i errors)", num_regex, timer_elapsed_msec(REGEX_TIMER), errors);
|
||||
// Read whitelisted domains from file
|
||||
read_whitelist_from_file();
|
||||
|
||||
logg("Compiled %i Regex filters and %i whitelisted domains in %.1f msec (%i errors)", num_regex, whitelist.count, timer_elapsed_msec(REGEX_TIMER), errors);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user