Merge pull request #1293 from pi-hole/new/force_ip46

Deprecate REPLY_ADDR4/6 in favor of more fine-grained setting
This commit is contained in:
Adam Warner
2022-02-03 18:16:22 +00:00
committed by GitHub
5 changed files with 189 additions and 81 deletions
+108 -22
View File
@@ -502,43 +502,129 @@ void read_FTLconf(void)
else
logg(" RATE_LIMIT: Disabled");
// REPLY_ADDR4
// LOCAL_IPV4
// Use a specific IP address instead of automatically detecting the
// IPv4 interface address a query arrived on
// IPv4 interface address a query arrived on for A hostname queries
// defaults to: not set
config.reply_addr.overwrite_v4 = false;
config.reply_addr.v4.s_addr = 0;
buffer = parse_FTLconf(fp, "REPLY_ADDR4");
if(buffer != NULL && inet_pton(AF_INET, buffer, &config.reply_addr.v4))
config.reply_addr.overwrite_v4 = true;
config.reply_addr.own_host.overwrite_v4 = false;
config.reply_addr.own_host.v4.s_addr = 0;
buffer = parse_FTLconf(fp, "LOCAL_IPV4");
if(buffer != NULL && inet_pton(AF_INET, buffer, &config.reply_addr.own_host.v4))
config.reply_addr.own_host.overwrite_v4 = true;
if(config.reply_addr.overwrite_v4)
if(config.reply_addr.own_host.overwrite_v4)
{
char addr[INET_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET, &config.reply_addr.v4, addr, INET_ADDRSTRLEN);
logg(" REPLY_ADDR4: Using IPv4 address %s in IP blocking mode", addr);
inet_ntop(AF_INET, &config.reply_addr.own_host.v4, addr, INET_ADDRSTRLEN);
logg(" LOCAL_IPV4: Using IPv4 address %s for pi.hole and hostname", addr);
}
else
logg(" REPLY_ADDR4: Automatic interface-dependent detection of address");
logg(" LOCAL_IPV4: Automatic interface-dependent detection of address");
// REPLY_ADDR6
// LOCAL_IPV6
// Use a specific IP address instead of automatically detecting the
// IPv6 interface address a query arrived on
// IPv6 interface address a query arrived on for AAAA hostname queries
// defaults to: not set
config.reply_addr.overwrite_v6 = false;
memset(&config.reply_addr.v6, 0, sizeof(config.reply_addr.v6));
buffer = parse_FTLconf(fp, "REPLY_ADDR6");
if(buffer != NULL && inet_pton(AF_INET6, buffer, &config.reply_addr.v6))
config.reply_addr.overwrite_v6 = true;
config.reply_addr.own_host.overwrite_v6 = false;
memset(&config.reply_addr.own_host.v6, 0, sizeof(config.reply_addr.own_host.v6));
buffer = parse_FTLconf(fp, "LOCAL_IPV6");
if(buffer != NULL && inet_pton(AF_INET6, buffer, &config.reply_addr.own_host.v6))
config.reply_addr.own_host.overwrite_v6 = true;
if(config.reply_addr.overwrite_v6)
if(config.reply_addr.own_host.overwrite_v6)
{
char addr[INET6_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET6, &config.reply_addr.v6, addr, INET6_ADDRSTRLEN);
logg(" REPLY_ADDR6: Using IPv6 address %s in IP blocking mode", addr);
inet_ntop(AF_INET6, &config.reply_addr.own_host.v6, addr, INET6_ADDRSTRLEN);
logg(" LOCAL_IPV6: Using IPv6 address %s for pi.hole and hostname", addr);
}
else
logg(" REPLY_ADDR6: Automatic interface-dependent detection of address");
logg(" LOCAL_IPV6: Automatic interface-dependent detection of address");
// BLOCK_IPV4
// Use a specific IPv4 address for IP blocking mode replies
// defaults to: REPLY_ADDR4 setting
config.reply_addr.ip_blocking.overwrite_v4 = false;
config.reply_addr.ip_blocking.v4.s_addr = 0;
buffer = parse_FTLconf(fp, "BLOCK_IPV4");
if(buffer != NULL && inet_pton(AF_INET, buffer, &config.reply_addr.ip_blocking.v4))
config.reply_addr.ip_blocking.overwrite_v4 = true;
if(config.reply_addr.ip_blocking.overwrite_v4)
{
char addr[INET_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET, &config.reply_addr.ip_blocking.v4, addr, INET_ADDRSTRLEN);
logg(" BLOCK_IPV4: Using IPv4 address %s in IP blocking mode", addr);
}
else
logg(" BLOCK_IPV4: Automatic interface-dependent detection of address");
// BLOCK_IPV6
// Use a specific IPv6 address for IP blocking mode replies
// defaults to: REPLY_ADDR6 setting
config.reply_addr.ip_blocking.overwrite_v6 = false;
memset(&config.reply_addr.ip_blocking.v6, 0, sizeof(config.reply_addr.own_host.v6));
buffer = parse_FTLconf(fp, "BLOCK_IPV6");
if(buffer != NULL && inet_pton(AF_INET6, buffer, &config.reply_addr.ip_blocking.v6))
config.reply_addr.ip_blocking.overwrite_v6 = true;
if(config.reply_addr.ip_blocking.overwrite_v6)
{
char addr[INET6_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET6, &config.reply_addr.ip_blocking.v6, addr, INET6_ADDRSTRLEN);
logg(" BLOCK_IPV6: Using IPv6 address %s in IP blocking mode", addr);
}
else
logg(" BLOCK_IPV6: Automatic interface-dependent detection of address");
// REPLY_ADDR4 (deprecated setting)
// Use a specific IP address instead of automatically detecting the
// IPv4 interface address a query arrived on A hostname and IP blocked queries
// defaults to: not set
struct in_addr reply_addr4;
buffer = parse_FTLconf(fp, "REPLY_ADDR4");
if(buffer != NULL && inet_pton(AF_INET, buffer, &reply_addr4))
{
if(config.reply_addr.own_host.overwrite_v4 || config.reply_addr.ip_blocking.overwrite_v4)
{
logg(" WARNING: Ignoring REPLY_ADDR4 as LOCAL_IPV4 or BLOCK_IPV4 has been specified.");
}
else
{
config.reply_addr.own_host.overwrite_v4 = true;
memcpy(&config.reply_addr.own_host.v4, &reply_addr4, sizeof(reply_addr4));
config.reply_addr.ip_blocking.overwrite_v4 = true;
memcpy(&config.reply_addr.ip_blocking.v4, &reply_addr4, sizeof(reply_addr4));
char addr[INET_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET, &reply_addr4, addr, INET_ADDRSTRLEN);
logg(" REPLY_ADDR4: Using IPv4 address %s instead of automatically determined IP address", addr);
}
}
// REPLY_ADDR6 (deprecated setting)
// Use a specific IP address instead of automatically detecting the
// IPv4 interface address a query arrived on A hostname and IP blocked queries
// defaults to: not set
struct in6_addr reply_addr6;
buffer = parse_FTLconf(fp, "REPLY_ADDR6");
if(buffer != NULL && inet_pton(AF_INET, buffer, &reply_addr6))
{
if(config.reply_addr.own_host.overwrite_v6 || config.reply_addr.ip_blocking.overwrite_v6)
{
logg(" WARNING: Ignoring REPLY_ADDR6 as LOCAL_IPV6 or BLOCK_IPV6 has been specified.");
}
else
{
config.reply_addr.own_host.overwrite_v6 = true;
memcpy(&config.reply_addr.own_host.v6, &reply_addr6, sizeof(reply_addr6));
config.reply_addr.ip_blocking.overwrite_v6 = true;
memcpy(&config.reply_addr.ip_blocking.v6, &reply_addr6, sizeof(reply_addr6));
char addr[INET6_ADDRSTRLEN] = { 0 };
inet_ntop(AF_INET6, &reply_addr6, addr, INET6_ADDRSTRLEN);
logg(" REPLY_ADDR6: Using IPv6 address %s instead of automatically determined IP address", addr);
}
}
// SHOW_DNSSEC
// Should FTL analyze and include automatically generated DNSSEC queries in the Query Log?
+13 -5
View File
@@ -77,13 +77,21 @@ typedef struct {
enum debug_flags debug;
time_t DBinterval;
struct {
bool overwrite_v4 :1;
bool overwrite_v6 :1;
struct in_addr v4;
struct in6_addr v6;
struct {
bool overwrite_v4 :1;
bool overwrite_v6 :1;
struct in_addr v4;
struct in6_addr v6;
} own_host;
struct {
bool overwrite_v4 :1;
bool overwrite_v6 :1;
struct in_addr v4;
struct in6_addr v6;
} ip_blocking;
} reply_addr;
} ConfigStruct;
ASSERT_SIZEOF(ConfigStruct, 88, 80, 80);
ASSERT_SIZEOF(ConfigStruct, 112, 104, 104);
typedef struct {
const char* conf;
+34 -54
View File
@@ -73,7 +73,6 @@ static char *get_ptrname(struct in_addr *addr);
// Static blocking metadata
static const char *blockingreason = "";
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;
@@ -322,21 +321,28 @@ 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 = &null_addrp;
union all_addr addr = {{ 0 }};
// Overwrite with IP address if requested
if(redirecting)
addr = &redirect_addr4;
memcpy(&addr, &redirect_addr4, sizeof(addr));
else if(config.blockingmode == MODE_IP ||
config.blockingmode == MODE_IP_NODATA_AAAA ||
forced_ip)
addr = &next_iface.addr4;
{
if(hostname && config.reply_addr.own_host.overwrite_v4)
memcpy(&addr, &config.reply_addr.own_host.v4, sizeof(addr));
else if(!hostname && config.reply_addr.ip_blocking.overwrite_v4)
memcpy(&addr, &config.reply_addr.ip_blocking.v4, sizeof(addr));
else
memcpy(&addr, &next_iface.addr4, sizeof(addr));
}
// Debug logging
if(config.debug & DEBUG_QUERIES)
{
char ip[ADDRSTRLEN+1] = { 0 };
alladdr_extract_ip(addr, AF_INET, ip);
alladdr_extract_ip(&addr, AF_INET, ip);
logg(" Adding RR: \"%s A %s\"", name, ip);
}
@@ -344,27 +350,34 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
header->ancount = htons(ntohs(header->ancount) + 1);
if(add_resource_record(header, limit, &trunc, sizeof(struct dns_header),
&p, hostname ? daemon->local_ttl : config.block_ttl,
NULL, T_A, C_IN, (char*)"4", &addr->addr4))
log_query(flags & ~F_IPV6, name, addr, (char*)blockingreason, 0);
NULL, T_A, C_IN, (char*)"4", &addr.addr4))
log_query(flags & ~F_IPV6, name, &addr, (char*)blockingreason, 0);
}
// Add AAAA answer record if requested
if(flags & F_IPV6)
{
union all_addr *addr = &null_addrp;
union all_addr addr = {{ 0 }};
// Overwrite with IP address if requested
if(redirecting)
addr = &redirect_addr6;
memcpy(&addr, &redirect_addr6, sizeof(addr));
else if(config.blockingmode == MODE_IP ||
forced_ip)
addr = &next_iface.addr6;
{
if(hostname && config.reply_addr.own_host.overwrite_v6)
memcpy(&addr, &config.reply_addr.own_host.v6, sizeof(addr));
else if(!hostname && config.reply_addr.ip_blocking.overwrite_v6)
memcpy(&addr, &config.reply_addr.ip_blocking.v6, sizeof(addr));
else
memcpy(&addr, &next_iface.addr6, sizeof(addr));
}
// Debug logging
if(config.debug & DEBUG_QUERIES)
{
char ip[ADDRSTRLEN+1] = { 0 };
alladdr_extract_ip(addr, AF_INET6, ip);
alladdr_extract_ip(&addr, AF_INET6, ip);
logg(" Adding RR: \"%s AAAA %s\"", name, ip);
}
@@ -372,8 +385,8 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
header->ancount = htons(ntohs(header->ancount) + 1);
if(add_resource_record(header, limit, &trunc, sizeof(struct dns_header),
&p, hostname ? daemon->local_ttl : config.block_ttl,
NULL, T_AAAA, C_IN, (char*)"6", &addr->addr6))
log_query(flags & ~F_IPV4, name, addr, (char*)blockingreason, 0);
NULL, T_AAAA, C_IN, (char*)"6", &addr.addr6))
log_query(flags & ~F_IPV4, name, &addr, (char*)blockingreason, 0);
}
// Log empty replies
@@ -507,8 +520,12 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
// Send NODATA when the current interface doesn't have
// the requested IP address, for instance AAAA on an
// virtual interface that has only an IPv4 address
if((querytype == TYPE_A && !next_iface.haveIPv4) ||
(querytype == TYPE_AAAA && !next_iface.haveIPv6))
if((querytype == TYPE_A &&
!next_iface.haveIPv4 &&
!config.reply_addr.own_host.overwrite_v4) ||
(querytype == TYPE_AAAA &&
!next_iface.haveIPv6 &&
!config.reply_addr.own_host.overwrite_v6))
force_next_DNS_reply = REPLY_NODATA;
else
force_next_DNS_reply = REPLY_IP;
@@ -820,40 +837,14 @@ void _FTL_iface(struct irec *recviface, const union all_addr *addr, const sa_fam
if(config.debug & DEBUG_NETWORKING)
logg("Interfaces: Called from %s:%d", short_path(file), line);
// Copy overwrite addresses if configured via REPLY_ADDR4 and/or REPLY_ADDR6 settings
if(config.reply_addr.overwrite_v4)
{
memcpy(&next_iface.addr4, &config.reply_addr.v4, sizeof(config.reply_addr.v4));
next_iface.haveIPv4 = true;
if(config.debug & DEBUG_NETWORKING)
{
char buffer[ADDRSTRLEN+1] = { 0 };
inet_ntop(AF_INET, &next_iface.addr4, buffer, ADDRSTRLEN);
logg("Configuration overwrites IPv4 address: %s", buffer);
}
}
if(config.reply_addr.overwrite_v6)
{
memcpy(&next_iface.addr6, &config.reply_addr.v6, sizeof(config.reply_addr.v6));
next_iface.haveIPv6 = true;
if(config.debug & DEBUG_NETWORKING)
{
char buffer[ADDRSTRLEN+1] = { 0 };
inet_ntop(AF_INET6, &next_iface.addr6, buffer, ADDRSTRLEN);
logg("Configuration overwrites IPv6 address: %s", buffer);
}
}
// Use dummy when interface record is not available
next_iface.name[0] = '-';
next_iface.name[1] = '\0';
// Check if we need to identify the receving interface by its address
if(!recviface && addr &&
((addrfamily == AF_INET && addr->addr4.s_addr != 0) ||
(addrfamily == AF_INET6 && addr->addr6.s6_addr[0] != 0)))
((addrfamily == AF_INET && addr->addr4.s_addr != INADDR_ANY) ||
(addrfamily == AF_INET6 && !IN6_IS_ADDR_UNSPECIFIED(&addr->addr6))))
{
if(config.debug & DEBUG_NETWORKING)
{
@@ -953,17 +944,6 @@ void _FTL_iface(struct irec *recviface, const union all_addr *addr, const sa_fam
strncpy(next_iface.name, iname, sizeof(next_iface.name)-1);
next_iface.name[sizeof(next_iface.name)-1] = '\0';
// Check if this family type is overwritten by config settings
// We logged this above
if((config.reply_addr.overwrite_v4 && family == AF_INET) ||
(config.reply_addr.overwrite_v6 && family == AF_INET6))
{
if(config.debug & DEBUG_NETWORKING)
logg(" - SKIP IPv%d interface %s: REPLY_ADDR%d used",
family == AF_INET ? 4 : 6, iname, family == AF_INET ? 4 : 6);
continue;
}
bool isULA = false, isGUA = false, isLL = false;
// Check if this address is different from 0000:0000:0000:0000:0000:0000:0000:0000
if(family == AF_INET6 && memcmp(&next_iface.addr6.addr6, &iface->addr.in6.sin6_addr, sizeof(iface->addr.in6.sin6_addr)) != 0)
+4
View File
@@ -2,3 +2,7 @@ DEBUG_ALL=true
RESOLVE_IPV4=no
RESOLVE_IPV6=no
CHECK_LOAD=false
LOCAL_IPV4=10.100.0.10
LOCAL_IPV6=fe80::10
BLOCK_IPV4=10.100.0.11
BLOCK_IPV6=fe80::11
+30
View File
@@ -1279,3 +1279,33 @@
printf "%s\n" "${lines[@]}"
[[ "${lines[0]}" == "" ]]
}
@test "Pi-hole uses LOCAL_IPV4/6 for pi.hole" {
run bash -c "dig A pi.hole +short @127.0.0.1"
printf "%s\n" "${lines[@]}"
[[ "${lines[0]}" == "10.100.0.10" ]]
run bash -c "dig AAAA pi.hole +short @127.0.0.1"
printf "%s\n" "${lines[@]}"
[[ "${lines[0]}" == "fe80::10" ]]
}
@test "Pi-hole uses LOCAL_IPV4/6 for hostname" {
run bash -c "dig A $(hostname) +short @127.0.0.1"
printf "%s\n" "${lines[@]}"
[[ "${lines[0]}" == "10.100.0.10" ]]
run bash -c "dig AAAA $(hostname) +short @127.0.0.1"
printf "%s\n" "${lines[@]}"
[[ "${lines[0]}" == "fe80::10" ]]
}
@test "Pi-hole uses BLOCK_IPV4/6 for blocked domain" {
echo "BLOCKINGMODE=IP" >> /etc/pihole/pihole-FTL.conf
run bash -c "kill -HUP $(cat /run/pihole-FTL.pid)"
sleep 2
run bash -c "dig A blacklisted.ftl +short @127.0.0.1"
printf "%s\n" "${lines[@]}"
[[ "${lines[0]}" == "10.100.0.11" ]]
run bash -c "dig AAAA blacklisted.ftl +short @127.0.0.1"
printf "%s\n" "${lines[@]}"
[[ "${lines[0]}" == "fe80::11" ]]
}