Implement support for custom redirection targets in regex extension, e.g., "someregex;reply=1.2.3.4;reply=fe80::1234"

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2021-09-11 12:10:41 +02:00
parent 8bc00f2613
commit 42a7948754
3 changed files with 162 additions and 22 deletions
+35 -12
View File
@@ -75,9 +75,10 @@ static void _query_set_dnssec(queriesData *query, const enum dnssec_status dnsse
static const char *blockingreason = NULL;
static union all_addr null_addrp = {{ 0 }};
static enum reply_type force_next_DNS_reply = REPLY_UNKNOWN;
static int last_regex_idx = -1;
static struct ptr_record *pihole_ptr = NULL;
// Fork-private copy of the interface name the most recent query came from
// Fork-private copy of the interface data the most recent query came from
static struct {
char name[IFNAMSIZ];
union all_addr addr4;
@@ -264,6 +265,20 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
}
}
// Check for regex redirecting
bool redirecting = false;
union all_addr redirect_addr4 = {{ 0 }}, redirect_addr6 = {{ 0 }};
if(last_regex_idx > -1)
{
redirecting = regex_get_redirect(last_regex_idx, &redirect_addr4.addr4, &redirect_addr6.addr6);
// Reset regex redirection forcing
last_regex_idx = -1;
// Debug logging
if(config.debug & DEBUG_FLAGS)
logg("Regex match is %sredirected", redirecting ? "" : "NOT ");
}
// Debug logging
if(config.debug & DEBUG_FLAGS)
print_flags(flags);
@@ -285,13 +300,15 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
// Add A answer record if requested
if(flags & F_IPV4)
{
union all_addr *addr;
if(config.blockingmode == MODE_IP ||
config.blockingmode == MODE_IP_NODATA_AAAA ||
forced_ip)
union all_addr *addr = &null_addrp;
// Overwrite with IP address if requested
if(redirecting)
addr = &redirect_addr4;
else if(config.blockingmode == MODE_IP ||
config.blockingmode == MODE_IP_NODATA_AAAA ||
forced_ip)
addr = &next_iface.addr4;
else
addr = &null_addrp;
// Debug logging
if(config.debug & DEBUG_QUERIES)
@@ -312,12 +329,14 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
// Add AAAA answer record if requested
if(flags & F_IPV6)
{
union all_addr *addr;
if(config.blockingmode == MODE_IP ||
forced_ip)
union all_addr *addr = &null_addrp;
// Overwrite with IP address if requested
if(redirecting)
addr = &redirect_addr6;
else if(config.blockingmode == MODE_IP ||
forced_ip)
addr = &next_iface.addr6;
else
addr = &null_addrp;
// Debug logging
if(config.debug & DEBUG_QUERIES)
@@ -968,6 +987,9 @@ static bool check_domain_blocked(const char *domain, const int clientID,
if(dns_cache->force_reply != REPLY_UNKNOWN)
force_next_DNS_reply = dns_cache->force_reply;
// Store ID of this regex (fork-private)
last_regex_idx = regex_idx;
// We block this domain
return true;
}
@@ -1104,6 +1126,7 @@ static bool _FTL_check_blocking(int queryID, int domainID, int clientID, const c
if(!query->flags.whitelisted)
{
force_next_DNS_reply = dns_cache->force_reply;
last_regex_idx = dns_cache->black_regex_idx;
query_blocked(query, domain, client, QUERY_REGEX);
return true;
}
+118 -9
View File
@@ -77,6 +77,46 @@ static inline void free_regex_ptr(const enum regex_type regexid)
}
}
static __attribute__ ((pure)) regexData *get_regex_ptr_from_id(unsigned int regexID)
{
unsigned int maxi;
enum regex_type regex_type;
if(regexID < num_regex[REGEX_BLACKLIST])
{
// Regex blacklist
regex_type = REGEX_BLACKLIST;
maxi = num_regex[REGEX_BLACKLIST];
}
else
{
// Subtract regex blacklist
regexID -= num_regex[REGEX_BLACKLIST];
// Check for regex whitelist
if(regexID < num_regex[REGEX_WHITELIST])
{
// Regex whitelist
regex_type = REGEX_WHITELIST;
maxi = num_regex[REGEX_WHITELIST];
}
else
{
// Subtract regex whitelist
regexID -= num_regex[REGEX_WHITELIST];
// CLI regex
regex_type = REGEX_CLI;
maxi = num_regex[REGEX_CLI];
}
}
regexData *regex = get_regex_ptr(regex_type);
if(regex != NULL && regexID < maxi)
return &(regex[regexID]);
return NULL;
}
unsigned int __attribute__((pure)) get_num_regex(const enum regex_type regexid)
{
// count number of all available reges
@@ -172,12 +212,6 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co
// 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)
@@ -200,6 +234,20 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co
type = "IP";
regex[index].ext.reply = REPLY_IP;
}
else if(inet_pton(AF_INET, extra, &regex[index].ext.addr4) == 1)
{
// Custom IPv4 target
type = extra;
regex[index].ext.reply = REPLY_IP;
regex[index].ext.custom_ip4 = true;
}
else if(inet_pton(AF_INET6, extra, &regex[index].ext.addr6) == 1)
{
// Custom IPv6 target
type = extra;
regex[index].ext.reply = REPLY_IP;
regex[index].ext.custom_ip6 = true;
}
else if(strcasecmp(extra, "NONE") == 0)
{
type = "NONE";
@@ -208,7 +256,7 @@ static bool compile_regex(const char *regexin, const enum regex_type regexid, co
else
{
char msg[64] = { 0 };
snprintf(msg, sizeof(msg)-1, "Unknown reply \"%s\"", extra);
snprintf(msg, sizeof(msg)-1, "Unknown reply type \"%s\"", extra);
logg_regex_warning(regextype[regexid], msg, dbidx, regexin);
}
@@ -398,7 +446,7 @@ int match_regex(const char *input, DNSCacheData* dns_cache, const int clientID,
}
}
// No match, no error, return false
// Return match_idx (-1 if there was no match)
return match_idx;
}
@@ -691,4 +739,65 @@ int regex_test(const bool debug_mode, const bool quiet, const char *domainin, co
// Return status 0 = MATCH, 1 = ERROR, 2 = NO MATCH
return matchidx > -1 ? EXIT_SUCCESS : 2;
}
}
// Get internal ID of regex with this database ID
static int __attribute__ ((pure)) regex_id_from_database_id(const int dbID)
{
// Get number of defined regular expressions
unsigned int sum_regex = 0;
for(unsigned int i = 0; i < REGEX_MAX; i++)
sum_regex += num_regex[i];
// Find internal ID of regular expression with this database ID
for(unsigned int i = 0; i < sum_regex; i++)
{
regexData *regex = get_regex_ptr_from_id(i);
if(regex == NULL)
continue;
if(regex->database_id == dbID)
return i;
}
return -1;
}
// Return redirection addresses for a given blacklist regex (if specified)
bool regex_get_redirect(const int dbID, struct in_addr *addr4, struct in6_addr *addr6)
{
// Check dbID for validity, return early if negative
if(dbID < 0)
return false;
// Get internal regex ID from database regex ID
const int regexID = regex_id_from_database_id(dbID);
if(config.debug & DEBUG_REGEX)
logg("Regex: %d (database) -> %d (internal)", dbID, regexID);
// Check internal regex ID for validity, return early if negative
if(regexID < 0)
return false;
// Get regex from regexID
regexData *regex = get_regex_ptr_from_id(regexID);
if(regex == NULL)
return false;
bool custom_addr = false;
// Check for IPv4 redirect
if(regex->ext.custom_ip4 && addr4 != NULL)
{
memcpy(addr4, &(regex->ext.addr4), sizeof(*addr4));
custom_addr = true;
}
// Check for IPv6 redirect
if(regex->ext.custom_ip6 && addr6 != NULL)
{
memcpy(addr6, &(regex->ext.addr6), sizeof(*addr6));
custom_addr = true;
}
return custom_addr;
}
+9 -1
View File
@@ -27,19 +27,26 @@ extern const char *regextype[];
// assert_sizeof
#include "static_assert.h"
#include <netinet/in.h>
typedef struct {
bool available :1;
struct {
bool inverted :1;
bool query_type_inverted :1;
bool custom_ip4 :1;
bool custom_ip6 :1;
enum query_types query_type;
enum reply_type reply;
struct in_addr addr4;
struct in6_addr addr6;
} ext;
int database_id;
char *string;
regex_t regex;
} regexData;
ASSERT_SIZEOF(regexData, 32, 20, 20);
ASSERT_SIZEOF(regexData, 56, 44, 44);
unsigned int get_num_regex(const enum regex_type regexid) __attribute__((pure));
int match_regex(const char *input, DNSCacheData* dns_cache, const int clientID,
@@ -47,6 +54,7 @@ int match_regex(const char *input, DNSCacheData* dns_cache, const int clientID,
void allocate_regex_client_enabled(clientsData *client, const int clientID);
void reload_per_client_regex(clientsData *client);
void read_regex_from_database(void);
bool regex_get_redirect(const int regexID, struct in_addr *addr4, struct in6_addr *addr6);
int regex_test(const bool debug_mode, const bool quiet, const char *domainin, const char *regexin);