mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
Add regex extension ";reply=NXDOMAIN,NODATA,REFUSED,IP,NONE"
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
@@ -1223,7 +1223,7 @@ static void gravityDB_client_check_again(clientsData* client)
|
||||
}
|
||||
}
|
||||
|
||||
enum db_result in_whitelist(const char *domain, const DNSCacheData *dns_cache, clientsData* client)
|
||||
enum db_result in_whitelist(const char *domain, DNSCacheData *dns_cache, clientsData* client)
|
||||
{
|
||||
// If list statement is not ready and cannot be initialized (e.g. no
|
||||
// access to the database), we return false to prevent an FTL crash
|
||||
|
||||
@@ -32,7 +32,7 @@ int gravityDB_count(const enum gravity_tables list);
|
||||
|
||||
enum db_result in_gravity(const char *domain, clientsData *client);
|
||||
enum db_result in_blacklist(const char *domain, clientsData *client);
|
||||
enum db_result in_whitelist(const char *domain, const DNSCacheData *dns_cache, clientsData *client);
|
||||
enum db_result in_whitelist(const char *domain, DNSCacheData *dns_cache, clientsData *client);
|
||||
bool in_auditlist(const char *domain);
|
||||
|
||||
bool gravityDB_get_regex_client_groups(clientsData* client, const unsigned int numregex, const regexData *regex,
|
||||
|
||||
@@ -133,6 +133,8 @@ const char *getClientNameString(const queriesData* query);
|
||||
|
||||
void change_clientcount(clientsData *client, int total, int blocked, int overTimeIdx, int overTimeMod);
|
||||
|
||||
const char *get_query_reply_str(const enum reply_type query) __attribute__ ((const));
|
||||
|
||||
// Pointer getter functions
|
||||
#define getQuery(queryID, checkMagic) _getQuery(queryID, checkMagic, __LINE__, __FUNCTION__, __FILE__)
|
||||
queriesData* _getQuery(int queryID, bool checkMagic, int line, const char * function, const char * file);
|
||||
|
||||
+23
-3
@@ -50,6 +50,7 @@
|
||||
#include "database/message-table.h"
|
||||
|
||||
// Private prototypes
|
||||
static const char *reply_status_str[QUERY_REPLY_MAX+1];
|
||||
static void print_flags(const unsigned int flags);
|
||||
#define query_set_reply(flags, addr, query, response) _query_set_reply(flags, addr, query, response, __FILE__, __LINE__)
|
||||
static void _query_set_reply(const unsigned int flags, const union all_addr *addr, queriesData* query, const struct timeval response,
|
||||
@@ -192,6 +193,16 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
|
||||
if(config.debug & DEBUG_FLAGS)
|
||||
logg("Forced DNS reply to NXDOMAIN");
|
||||
}
|
||||
else if(force_next_DNS_reply == REPLY_NODATA)
|
||||
{
|
||||
flags = F_NOERR;
|
||||
// Reset DNS reply forcing
|
||||
force_next_DNS_reply = REPLY_UNKNOWN;
|
||||
|
||||
// Debug logging
|
||||
if(config.debug & DEBUG_FLAGS)
|
||||
logg("Forced DNS reply to NODATA");
|
||||
}
|
||||
else if(force_next_DNS_reply == REPLY_REFUSED)
|
||||
{
|
||||
// Empty flags result in REFUSED
|
||||
@@ -237,7 +248,7 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
|
||||
{
|
||||
// If we block in NXDOMAIN mode, we add the NEGATIVE response
|
||||
// and the NXDOMAIN flags
|
||||
flags = F_NEG | F_NXDOMAIN;
|
||||
flags = F_NXDOMAIN;
|
||||
if(config.debug & DEBUG_FLAGS)
|
||||
logg("Configured blocking mode is NXDOMAIN");
|
||||
}
|
||||
@@ -953,6 +964,10 @@ static bool check_domain_blocked(const char *domain, const int clientID,
|
||||
set_dnscache_blockingstatus(dns_cache, client, REGEX_BLOCKED, domain);
|
||||
dns_cache->black_regex_idx = regex_idx;
|
||||
|
||||
// Regex may be overwriting reply type for this domain
|
||||
if(dns_cache->force_reply != REPLY_UNKNOWN)
|
||||
force_next_DNS_reply = dns_cache->force_reply;
|
||||
|
||||
// We block this domain
|
||||
return true;
|
||||
}
|
||||
@@ -1207,6 +1222,9 @@ static bool _FTL_check_blocking(int queryID, int domainID, int clientID, const c
|
||||
// Debug output
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
logg("Blocking %s as %s is %s", domainstr, blockedDomain, blockingreason);
|
||||
|
||||
if(force_next_DNS_reply != 0)
|
||||
logg("Forcing next reply to %s", reply_status_str[force_next_DNS_reply]);
|
||||
}
|
||||
else if(db_okay)
|
||||
{
|
||||
@@ -2276,8 +2294,10 @@ static void _query_set_reply(const unsigned int flags, const union all_addr *add
|
||||
const char *file, const int line)
|
||||
{
|
||||
// Iterate through possible values
|
||||
if(flags & F_NEG || force_next_DNS_reply == REPLY_NXDOMAIN ||
|
||||
(flags & F_NOERR && !(flags & (F_IPV4 | F_IPV6)))) // <-- FTL_make_answer() when no A or AAAA is added
|
||||
if(flags & F_NEG ||
|
||||
(flags & F_NOERR && !(flags & (F_IPV4 | F_IPV6))) || // <-- FTL_make_answer() when no A or AAAA is added
|
||||
force_next_DNS_reply == REPLY_NXDOMAIN ||
|
||||
force_next_DNS_reply == REPLY_NODATA)
|
||||
{
|
||||
if(flags & F_NXDOMAIN || force_next_DNS_reply == REPLY_NXDOMAIN)
|
||||
// NXDOMAIN
|
||||
|
||||
+71
-18
@@ -119,7 +119,7 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co
|
||||
if(sscanf(part, "querytype=%16s", extra))
|
||||
{
|
||||
// Warn if specified more than one querytype option
|
||||
if(regex[index].query_type != 0)
|
||||
if(regex[index].ext.query_type != 0)
|
||||
logg_regex_warning(regextype[regexid],
|
||||
"Overwriting previous querytype setting",
|
||||
dbidx, regexin);
|
||||
@@ -130,35 +130,38 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co
|
||||
// Check for querytype
|
||||
if(strcasecmp(extra, querytypes[type]) == 0)
|
||||
{
|
||||
regex[index].query_type = type;
|
||||
regex[index].query_type_inverted = false;
|
||||
regex[index].ext.query_type = type;
|
||||
regex[index].ext.query_type_inverted = false;
|
||||
break;
|
||||
}
|
||||
// Check for INVERTED querytype
|
||||
else if(extra[0] == '!' && strcasecmp(extra + 1u, querytypes[type]) == 0)
|
||||
{
|
||||
regex[index].query_type = type;
|
||||
regex[index].query_type_inverted = true;
|
||||
regex[index].ext.query_type = type;
|
||||
regex[index].ext.query_type_inverted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Nothing found
|
||||
if(regex[index].query_type == 0)
|
||||
logg_regex_warning(regextype[regexid], "Unknown querytype",
|
||||
dbidx, regexin);
|
||||
if(regex[index].ext.query_type == 0)
|
||||
{
|
||||
char msg[64] = { 0 };
|
||||
snprintf(msg, sizeof(msg), "Unknown querytype \"%s\"", extra);
|
||||
logg_regex_warning(regextype[regexid], msg, dbidx, regexin);
|
||||
}
|
||||
|
||||
// Debug output
|
||||
else if(config.debug & DEBUG_REGEX)
|
||||
{
|
||||
logg(" This regex will %s match query type %s",
|
||||
regex[index].query_type_inverted ? "NOT" : "ONLY",
|
||||
querytypes[regex[index].query_type]);
|
||||
regex[index].ext.query_type_inverted ? "NOT" : "ONLY",
|
||||
querytypes[regex[index].ext.query_type]);
|
||||
}
|
||||
}
|
||||
// option: ";invert"
|
||||
else if(strcasecmp(part, "invert") == 0)
|
||||
{
|
||||
regex[index].inverted = true;
|
||||
regex[index].ext.inverted = true;
|
||||
|
||||
// Debug output
|
||||
if(config.debug & DEBUG_REGEX)
|
||||
@@ -166,6 +169,53 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co
|
||||
logg(" This regex will match in inverted mode.");
|
||||
}
|
||||
}
|
||||
// options ";reply=NXDOMAIN", etc.
|
||||
else if(sscanf(part, "reply=%16s", extra))
|
||||
{
|
||||
// Warn if specified more than one repl option
|
||||
if(regex[index].ext.reply != 0)
|
||||
logg_regex_warning(regextype[regexid],
|
||||
"Overwriting previous replytype setting",
|
||||
dbidx, regexin);
|
||||
|
||||
// Test input string against all implemented reply types
|
||||
const char *type = "";
|
||||
if(strcasecmp(extra, "NODATA") == 0)
|
||||
{
|
||||
type = "NODATA";
|
||||
regex[index].ext.reply = REPLY_NODATA;
|
||||
}
|
||||
else if(strcasecmp(extra, "NXDOMAIN") == 0)
|
||||
{
|
||||
type = "NXDOMAIN";
|
||||
regex[index].ext.reply = REPLY_NXDOMAIN;
|
||||
}
|
||||
else if(strcasecmp(extra, "REFUSED") == 0)
|
||||
{
|
||||
type = "REFUSED";
|
||||
regex[index].ext.reply = REPLY_REFUSED;
|
||||
}
|
||||
else if(strcasecmp(extra, "IP") == 0)
|
||||
{
|
||||
type = "IP";
|
||||
regex[index].ext.reply = REPLY_IP;
|
||||
}
|
||||
else if(strcasecmp(extra, "NONE") == 0)
|
||||
{
|
||||
type = "NONE";
|
||||
regex[index].ext.reply = REPLY_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
char msg[64] = { 0 };
|
||||
snprintf(msg, sizeof(msg)-1, "Unknown reply \"%s\"", extra);
|
||||
logg_regex_warning(regextype[regexid], msg, dbidx, regexin);
|
||||
}
|
||||
|
||||
// Debug output
|
||||
if(config.debug & DEBUG_REGEX && regex[index].ext.reply != REPLY_UNKNOWN)
|
||||
logg(" This regex will result in a custom reply: %s", type);
|
||||
}
|
||||
else
|
||||
{
|
||||
char hint[40 + strlen(part)];
|
||||
@@ -204,7 +254,7 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co
|
||||
return true;
|
||||
}
|
||||
|
||||
int match_regex(const char *input, const DNSCacheData* dns_cache, const int clientID,
|
||||
int match_regex(const char *input, DNSCacheData* dns_cache, const int clientID,
|
||||
const enum regex_type regexid, const bool regextest)
|
||||
{
|
||||
int match_idx = -1;
|
||||
@@ -273,28 +323,31 @@ int match_regex(const char *input, const DNSCacheData* dns_cache, const int clie
|
||||
int retval = regexec(®ex[index].regex, input, 0, NULL, 0);
|
||||
#endif
|
||||
// regexec() returns REG_OK for a successful match or REG_NOMATCH for failure.
|
||||
if ((retval == REG_OK && !regex[index].inverted) ||
|
||||
(retval == REG_NOMATCH && regex[index].inverted))
|
||||
if ((retval == REG_OK && !regex[index].ext.inverted) ||
|
||||
(retval == REG_NOMATCH && regex[index].ext.inverted))
|
||||
{
|
||||
// Check possible additional regex settings
|
||||
if(dns_cache != NULL)
|
||||
{
|
||||
// Check query type filtering
|
||||
if(regex[index].query_type != 0)
|
||||
if(regex[index].ext.query_type != 0)
|
||||
{
|
||||
if((!regex[index].query_type_inverted && regex[index].query_type != dns_cache->query_type) ||
|
||||
(regex[index].query_type_inverted && regex[index].query_type == dns_cache->query_type))
|
||||
if((!regex[index].ext.query_type_inverted && regex[index].ext.query_type != dns_cache->query_type) ||
|
||||
(regex[index].ext.query_type_inverted && regex[index].ext.query_type == dns_cache->query_type))
|
||||
{
|
||||
if(config.debug & DEBUG_REGEX)
|
||||
{
|
||||
logg("Regex %s (%u, DB ID %i) NO match: \"%s\" vs. \"%s\""
|
||||
" (skipped because of query type %smatch)",
|
||||
regextype[regexid], index, regex[index].database_id,
|
||||
input, regex[index].string, regex[index].query_type_inverted ? "inversion " : "mis");
|
||||
input, regex[index].string, regex[index].ext.query_type_inverted ? "inversion " : "mis");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Set special reply type if configured for this regex
|
||||
if(regex[index].ext.reply != REPLY_UNKNOWN)
|
||||
dns_cache->force_reply = regex[index].ext.reply;
|
||||
}
|
||||
|
||||
// Match, return true
|
||||
|
||||
+8
-5
@@ -28,10 +28,13 @@ extern const char *regextype[];
|
||||
#include "static_assert.h"
|
||||
|
||||
typedef struct {
|
||||
bool available;
|
||||
bool inverted;
|
||||
bool query_type_inverted;
|
||||
enum query_types query_type;
|
||||
bool available :1;
|
||||
struct {
|
||||
bool inverted :1;
|
||||
bool query_type_inverted :1;
|
||||
enum query_types query_type;
|
||||
enum reply_type reply;
|
||||
} ext;
|
||||
int database_id;
|
||||
char *string;
|
||||
regex_t regex;
|
||||
@@ -39,7 +42,7 @@ typedef struct {
|
||||
ASSERT_SIZEOF(regexData, 32, 20, 20);
|
||||
|
||||
unsigned int get_num_regex(const enum regex_type regexid) __attribute__((pure));
|
||||
int match_regex(const char *input, const DNSCacheData* dns_cache, const int clientID,
|
||||
int match_regex(const char *input, DNSCacheData* dns_cache, const int clientID,
|
||||
const enum regex_type regexid, const bool regextest);
|
||||
void allocate_regex_client_enabled(clientsData *client, const int clientID);
|
||||
void reload_per_client_regex(clientsData *client);
|
||||
|
||||
Reference in New Issue
Block a user