Merge branch 'master' into new/http
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
commit
56f0e56b1f
|
@ -11,6 +11,6 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(PIHOLE_FTL C)
|
||||
|
||||
set(DNSMASQ_VERSION pi-hole-2.83)
|
||||
set(DNSMASQ_VERSION pi-hole-2.84)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
|
|
@ -135,6 +135,8 @@ set(sources
|
|||
main.h
|
||||
overTime.c
|
||||
overTime.h
|
||||
procps.c
|
||||
procps.h
|
||||
regex.c
|
||||
regex_r.h
|
||||
resolve.c
|
||||
|
|
|
@ -194,7 +194,7 @@ int check_client_auth(struct ftl_conn *api)
|
|||
if(config.debug & DEBUG_API)
|
||||
{
|
||||
char timestr[128];
|
||||
get_timestr(timestr, auth_data[user_id].valid_until);
|
||||
get_timestr(timestr, auth_data[user_id].valid_until, false);
|
||||
logg("API: Recognized known user: user_id %i valid_until: %s remote_addr %s",
|
||||
user_id, timestr, auth_data[user_id].remote_addr);
|
||||
}
|
||||
|
@ -516,7 +516,7 @@ int api_auth(struct ftl_conn *api)
|
|||
if(config.debug & DEBUG_API && user_id > API_AUTH_UNAUTHORIZED)
|
||||
{
|
||||
char timestr[128];
|
||||
get_timestr(timestr, auth_data[user_id].valid_until);
|
||||
get_timestr(timestr, auth_data[user_id].valid_until, false);
|
||||
logg("API: Registered new user: user_id %i valid_until: %s remote_addr %s (accepted due to %s)",
|
||||
user_id, timestr, auth_data[user_id].remote_addr,
|
||||
response_correct ? "correct response" : "empty password");
|
||||
|
|
21
src/config.c
21
src/config.c
|
@ -536,6 +536,25 @@ void read_FTLconf(void)
|
|||
// WEBDOMAIN
|
||||
getpath(fp, "WEBDOMAIN", "pi.hole", &httpsettings.webdomain);
|
||||
|
||||
// RATE_LIMIT
|
||||
// defaults to: 1000 queries / 60 seconds
|
||||
config.rate_limit.count = 1000;
|
||||
config.rate_limit.interval = 60;
|
||||
buffer = parse_FTLconf(fp, "RATE_LIMIT");
|
||||
|
||||
unsigned int count = 0, interval = 0;
|
||||
if(buffer != NULL && sscanf(buffer, "%u/%u", &count, &interval) == 2)
|
||||
{
|
||||
config.rate_limit.count = count;
|
||||
config.rate_limit.interval = interval;
|
||||
}
|
||||
|
||||
if(config.rate_limit.count > 0)
|
||||
logg(" RATE_LIMIT: Rate-limiting client making more than %u queries in %u second%s",
|
||||
config.rate_limit.count, config.rate_limit.interval, config.rate_limit.interval == 1 ? "" : "s");
|
||||
else
|
||||
logg(" RATE_LIMIT: Disabled");
|
||||
|
||||
// Read DEBUG_... setting from pihole-FTL.conf
|
||||
// This option should be the last one as it causes
|
||||
// some rather verbose output into the log when
|
||||
|
@ -601,7 +620,7 @@ static char *parse_FTLconf(FILE *fp, const char * key)
|
|||
|
||||
// Go to beginning of file
|
||||
fseek(fp, 0L, SEEK_SET);
|
||||
|
||||
|
||||
if(config.debug & DEBUG_EXTRA)
|
||||
logg("initial: conflinebuffer = %p, keystr = %p, size = %zu", conflinebuffer, keystr, size);
|
||||
|
||||
|
|
|
@ -53,10 +53,14 @@ typedef struct {
|
|||
int dns_port;
|
||||
unsigned int delay_startup;
|
||||
unsigned int network_expire;
|
||||
struct {
|
||||
unsigned int count;
|
||||
unsigned int interval;
|
||||
} rate_limit;
|
||||
enum debug_flags debug;
|
||||
time_t DBinterval;
|
||||
} ConfigStruct;
|
||||
ASSERT_SIZEOF(ConfigStruct, 56, 48, 48);
|
||||
ASSERT_SIZEOF(ConfigStruct, 64, 56, 56);
|
||||
|
||||
typedef struct {
|
||||
const char* conf;
|
||||
|
|
|
@ -359,12 +359,13 @@ void DB_read_queries(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
const int status = sqlite3_column_int(stmt, 3);
|
||||
if(status < QUERY_UNKNOWN || status >= QUERY_STATUS_MAX)
|
||||
const int status_int = sqlite3_column_int(stmt, 3);
|
||||
if(status_int < QUERY_UNKNOWN || status_int >= QUERY_STATUS_MAX)
|
||||
{
|
||||
logg("FTL_db warn: STATUS should be within [%i,%i] but is %i", QUERY_UNKNOWN, QUERY_STATUS_MAX-1, status);
|
||||
logg("FTL_db warn: STATUS should be within [%i,%i] but is %i", QUERY_UNKNOWN, QUERY_STATUS_MAX-1, status_int);
|
||||
continue;
|
||||
}
|
||||
const enum query_status status = status_int;
|
||||
|
||||
const char * domainname = (const char *)sqlite3_column_text(stmt, 4);
|
||||
if(domainname == NULL)
|
||||
|
@ -387,12 +388,11 @@ void DB_read_queries(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
const char *upstream = NULL;
|
||||
const char *buffer = NULL;
|
||||
int upstreamID = -1; // Default if not forwarded
|
||||
// Determine upstreamID only when status == 2 (forwarded) as the
|
||||
// field need not to be filled for other query status types
|
||||
// Try to extract the upstream from the "forward" column if non-empty
|
||||
if(sqlite3_column_bytes(stmt, 6) > 0 &&
|
||||
(upstream = (const char *)sqlite3_column_text(stmt, 6)) != NULL)
|
||||
(buffer = (const char *)sqlite3_column_text(stmt, 6)) != NULL)
|
||||
{
|
||||
// Get IP address and port of upstream destination
|
||||
char serv_addr[INET6_ADDRSTRLEN] = { 0 };
|
||||
|
@ -400,9 +400,9 @@ void DB_read_queries(void)
|
|||
// We limit the number of bytes written into the serv_addr buffer
|
||||
// to prevent buffer overflows. If there is no port available in
|
||||
// the database, we skip extracting them and use the default port
|
||||
sscanf(upstream, "%"xstr(INET6_ADDRSTRLEN)"[^#]#%u", serv_addr, &serv_port);
|
||||
sscanf(buffer, "%"xstr(INET6_ADDRSTRLEN)"[^#]#%u", serv_addr, &serv_port);
|
||||
serv_addr[INET6_ADDRSTRLEN-1] = '\0';
|
||||
upstreamID = findUpstreamID(serv_addr, (in_port_t)serv_port, true);
|
||||
upstreamID = findUpstreamID(serv_addr, (in_port_t)serv_port);
|
||||
}
|
||||
|
||||
// Obtain IDs only after filtering which queries we want to keep
|
||||
|
@ -522,7 +522,15 @@ void DB_read_queries(void)
|
|||
break;
|
||||
|
||||
case QUERY_FORWARDED: // Forwarded
|
||||
case QUERY_RETRIED: // (fall through)
|
||||
case QUERY_RETRIED_DNSSEC: // (fall through)
|
||||
counters->forwarded++;
|
||||
upstreamsData *upstream = getUpstream(upstreamID, true);
|
||||
if(upstream != NULL)
|
||||
{
|
||||
upstream->count++;
|
||||
upstream->lastQuery = queryTimeStamp;
|
||||
}
|
||||
// Update overTime data structure
|
||||
overTime[timeidx].forwarded++;
|
||||
break;
|
||||
|
@ -533,11 +541,11 @@ void DB_read_queries(void)
|
|||
overTime[timeidx].cached++;
|
||||
break;
|
||||
|
||||
case QUERY_RETRIED: // Retried query
|
||||
case QUERY_RETRIED_DNSSEC: // fall through
|
||||
case QUERY_IN_PROGRESS:
|
||||
// Nothing to be done here
|
||||
break;
|
||||
|
||||
case QUERY_STATUS_MAX:
|
||||
default:
|
||||
logg("Warning: Found unknown status %i in long term database!", status);
|
||||
break;
|
||||
|
|
|
@ -65,7 +65,7 @@ int findQueryID(const int id)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int findUpstreamID(const char * upstreamString, const in_port_t port, const bool count)
|
||||
int findUpstreamID(const char * upstreamString, const in_port_t port)
|
||||
{
|
||||
// Go through already knows upstream servers and see if we used one of those
|
||||
for(int upstreamID=0; upstreamID < counters->upstreams; upstreamID++)
|
||||
|
@ -78,13 +78,7 @@ int findUpstreamID(const char * upstreamString, const in_port_t port, const bool
|
|||
continue;
|
||||
|
||||
if(strcmp(getstr(upstream->ippos), upstreamString) == 0 && upstream->port == port)
|
||||
{
|
||||
if(count)
|
||||
{
|
||||
upstream->count++;
|
||||
}
|
||||
return upstreamID;
|
||||
}
|
||||
}
|
||||
// This upstream server is not known
|
||||
// Store ID
|
||||
|
@ -105,10 +99,7 @@ int findUpstreamID(const char * upstreamString, const in_port_t port, const bool
|
|||
// Set magic byte
|
||||
upstream->magic = MAGICBYTE;
|
||||
// Initialize its counter
|
||||
if(count)
|
||||
upstream->count = 1;
|
||||
else
|
||||
upstream->count = 0;
|
||||
upstream->count = 0;
|
||||
// Save upstream destination IP address
|
||||
upstream->ippos = addstr(upstreamString);
|
||||
upstream->failed = 0;
|
||||
|
@ -591,6 +582,8 @@ const char * __attribute__ ((pure)) get_query_status_str(const queriesData *quer
|
|||
return "RETRIED";
|
||||
case QUERY_RETRIED_DNSSEC:
|
||||
return "RETRIED_DNSSEC";
|
||||
case QUERY_IN_PROGRESS:
|
||||
return "IN_PROGRESS";
|
||||
case QUERY_STATUS_MAX:
|
||||
default:
|
||||
return "STATUS_MAX";
|
||||
|
|
|
@ -84,6 +84,7 @@ typedef struct {
|
|||
int blockedcount;
|
||||
int aliasclient_id;
|
||||
unsigned int id;
|
||||
unsigned int rate_limit;
|
||||
unsigned int numQueriesARP;
|
||||
int overTime[OVERTIME_SLOTS];
|
||||
size_t groupspos;
|
||||
|
@ -95,7 +96,7 @@ typedef struct {
|
|||
} clientsData;
|
||||
|
||||
// ARM needs alignment to 8-byte boundary
|
||||
ASSERT_SIZEOF(clientsData, 688, 668, 672);
|
||||
ASSERT_SIZEOF(clientsData, 696, 668, 668);
|
||||
|
||||
typedef struct {
|
||||
unsigned char magic;
|
||||
|
@ -118,7 +119,7 @@ ASSERT_SIZEOF(DNSCacheData, 16, 16, 16);
|
|||
|
||||
void strtolower(char *str);
|
||||
int findQueryID(const int id);
|
||||
int findUpstreamID(const char * upstream, const in_port_t port, const bool count);
|
||||
int findUpstreamID(const char * upstream, const in_port_t port);
|
||||
int findDomainID(const char *domain, const bool count);
|
||||
int findClientID(const char *client, const bool count, const bool aliasclient);
|
||||
int findCacheID(int domainID, int clientID, enum query_types query_type);
|
||||
|
|
|
@ -134,7 +134,7 @@ static int get_hardware_address(const int sock, const char *interface_name, unsi
|
|||
logg_sameline("Hardware address of this interface: ");
|
||||
for (uint8_t i = 0; i < 6; ++i)
|
||||
logg_sameline("%02x%s", mac[i], i < 5 ? ":" : "");
|
||||
logg("");
|
||||
logg(" ");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
@ -201,14 +201,8 @@ static bool send_dhcp_discover(const int sock, const uint32_t xid, const char *i
|
|||
discover_packet.options[5] = '\x01'; // DHCP message option length in bytes
|
||||
discover_packet.options[6] = 1; // DHCP message type code for DHCPDISCOVER
|
||||
|
||||
// Request a lease with validity of 1 second
|
||||
discover_packet.options[7] = 51; // Lease time type option identifier
|
||||
discover_packet.options[8] = '\x04'; // DHCP message option length in bytes
|
||||
const uint32_t lease_time = htonl(1);
|
||||
memcpy(&discover_packet.options[9], &lease_time, sizeof(lease_time));
|
||||
|
||||
// Place end option at the end of the options
|
||||
discover_packet.options[13] = 255;
|
||||
discover_packet.options[7] = 255;
|
||||
|
||||
// send the DHCPDISCOVER packet to the specified address
|
||||
struct sockaddr_in target;
|
||||
|
@ -452,12 +446,12 @@ static bool get_dhcp_offer(const int sock, const uint32_t xid, const char *iface
|
|||
|
||||
if(!receive_dhcp_packet(&offer_packet, sizeof(offer_packet), iface, sock, start_time, &source))
|
||||
continue;
|
||||
#if DEBUG
|
||||
#ifdef DEBUG
|
||||
else
|
||||
responses++;
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#ifdef DEBUG
|
||||
logg(" DHCPOFFER XID: %lu (0x%X)", (unsigned long) ntohl(offer_packet.xid), ntohl(offer_packet.xid));
|
||||
#endif
|
||||
|
||||
|
@ -555,19 +549,20 @@ static void *dhcp_discover_iface(void *args)
|
|||
srand(time(NULL));
|
||||
const uint32_t xid = random();
|
||||
|
||||
#ifdef PROBE_LOCAL
|
||||
// Probe a local server listining on this interface
|
||||
// send DHCPDISCOVER packet to interface address
|
||||
struct sockaddr_in ifaddr = { 0 };
|
||||
memcpy(&ifaddr, ((struct ifaddrs*)args)->ifa_addr, sizeof(ifaddr));
|
||||
send_dhcp_discover(dhcp_socket, xid, iface, ifaddr.sin_addr.s_addr);
|
||||
#endif
|
||||
|
||||
#ifdef PROBE_BCAST
|
||||
// Probe distant servers
|
||||
// send DHCPDISCOVER packet to broadcast address
|
||||
send_dhcp_discover(dhcp_socket, xid, iface, mac, INADDR_BROADCAST);
|
||||
#endif
|
||||
if(strcmp(iface, "lo") == 0)
|
||||
{
|
||||
// Probe a local server listening on this interface
|
||||
// Send DHCPDISCOVER packet to interface address
|
||||
struct sockaddr_in ifaddr = { 0 };
|
||||
memcpy(&ifaddr, ((struct ifaddrs*)args)->ifa_addr, sizeof(ifaddr));
|
||||
send_dhcp_discover(dhcp_socket, xid, iface, mac, ifaddr.sin_addr.s_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Probe distant servers
|
||||
// Send DHCPDISCOVER packet to broadcast address
|
||||
send_dhcp_discover(dhcp_socket, xid, iface, mac, INADDR_BROADCAST);
|
||||
}
|
||||
|
||||
// wait for a DHCPOFFER packet
|
||||
get_dhcp_offer(dhcp_socket, xid, iface, mac);
|
||||
|
@ -615,13 +610,8 @@ int run_dhcp_discover(void)
|
|||
int tid = 0;
|
||||
while(tmp != NULL && tid < MAXTHREADS)
|
||||
{
|
||||
#ifdef PROBE_LOCAL
|
||||
// Create a thread for interfaces of type AF_INET (IPv4 sockets)
|
||||
if(tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET)
|
||||
#else
|
||||
// Create a thread for interfaces of type AF_PACKET
|
||||
if(tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_PACKET)
|
||||
#endif
|
||||
{
|
||||
if(pthread_create(&scanthread[tid], &attr, dhcp_discover_iface, tmp ) != 0)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -122,8 +122,8 @@ HAVE_AUTH
|
|||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
HAVE_NETTLEHASH
|
||||
include just hash function from nettle, but no DNSSEC.
|
||||
HAVE_CRYPTOHASH
|
||||
include just hash function from crypto library, but no DNSSEC.
|
||||
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
@ -192,7 +192,7 @@ RESOLVFILE
|
|||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_LIBIDN2 */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
/* #define HAVE_NETTLEHASH */
|
||||
/* #define HAVE_CRYPTOHASH */
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
|
||||
|
@ -426,10 +426,10 @@ static char *compile_opts =
|
|||
"no-"
|
||||
#endif
|
||||
"auth "
|
||||
#if !defined(HAVE_NETTLEHASH) && !defined(HAVE_DNSSEC)
|
||||
#if !defined(HAVE_CRYPTOHASH) && !defined(HAVE_DNSSEC)
|
||||
"no-"
|
||||
#endif
|
||||
"nettlehash "
|
||||
"cryptohash "
|
||||
#ifndef HAVE_DNSSEC
|
||||
"no-"
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -27,7 +27,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -392,8 +392,8 @@ int main_dnsmasq (int argc, char **argv)
|
|||
if (daemon->port != 0)
|
||||
{
|
||||
cache_init();
|
||||
|
||||
blockdata_init();
|
||||
hash_questions_init();
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,7 +14,7 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (c) 2000-2020 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2021 Simon Kelley"
|
||||
|
||||
/* We do defines that influence behavior of stdio.h, so complain
|
||||
if included too early. */
|
||||
|
@ -157,7 +157,11 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
|||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
/* Backwards compat with 2.83 */
|
||||
#if defined(HAVE_NETTLEHASH)
|
||||
# define HAVE_CRYPTOHASH
|
||||
#endif
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
|
@ -666,6 +670,7 @@ struct frec {
|
|||
union mysockaddr source;
|
||||
union all_addr dest;
|
||||
unsigned int iface, log_id;
|
||||
int fd;
|
||||
unsigned short orig_id;
|
||||
struct frec_src *next;
|
||||
} frec_src;
|
||||
|
@ -673,7 +678,7 @@ struct frec {
|
|||
struct randfd *rfd4;
|
||||
struct randfd *rfd6;
|
||||
unsigned short new_id;
|
||||
int fd, forwardall, flags;
|
||||
int forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
@ -1265,6 +1270,7 @@ size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
|||
int setup_timestamp(void);
|
||||
|
||||
/* hash_questions.c */
|
||||
void hash_questions_init(void);
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
|
||||
/* crypto.c */
|
||||
|
|
|
@ -334,37 +334,64 @@ static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
|
|||
if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
|
||||
return rrsetidx; /* short packet */
|
||||
state2.end = state2.ip + rdlen2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int ok1, ok2;
|
||||
|
||||
ok1 = get_rdata(header, plen, &state1);
|
||||
ok2 = get_rdata(header, plen, &state2);
|
||||
|
||||
if (!ok1 && !ok2)
|
||||
/* If the RR has no names in it then canonicalisation
|
||||
is the identity function and we can compare
|
||||
the RRs directly. If not we compare the
|
||||
canonicalised RRs one byte at a time. */
|
||||
if (*rr_desc == (u16)-1)
|
||||
{
|
||||
int rdmin = rdlen1 > rdlen2 ? rdlen2 : rdlen1;
|
||||
int cmp = memcmp(state1.ip, state2.ip, rdmin);
|
||||
|
||||
if (cmp > 0 || (cmp == 0 && rdlen1 > rdmin))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = 1;
|
||||
}
|
||||
else if (cmp == 0 && (rdlen1 == rdlen2))
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
else if (ok1 && (!ok2 || *state1.op > *state2.op))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = 1;
|
||||
break;
|
||||
}
|
||||
else if (ok2 && (!ok1 || *state2.op > *state1.op))
|
||||
break;
|
||||
|
||||
/* arrive here when bytes are equal, go round the loop again
|
||||
and compare the next ones. */
|
||||
}
|
||||
else
|
||||
/* Comparing canonicalised RRs, byte-at-a-time. */
|
||||
while (1)
|
||||
{
|
||||
int ok1, ok2;
|
||||
|
||||
ok1 = get_rdata(header, plen, &state1);
|
||||
ok2 = get_rdata(header, plen, &state2);
|
||||
|
||||
if (!ok1 && !ok2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
else if (ok1 && (!ok2 || *state1.op > *state2.op))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = 1;
|
||||
break;
|
||||
}
|
||||
else if (ok2 && (!ok1 || *state2.op > *state1.op))
|
||||
break;
|
||||
|
||||
/* arrive here when bytes are equal, go round the loop again
|
||||
and compare the next ones. */
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -391,8 +391,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||
new->dest = *dst_addr;
|
||||
new->log_id = daemon->log_id;
|
||||
new->iface = dst_iface;
|
||||
new->fd = udpfd;
|
||||
}
|
||||
|
||||
// Pi-hole modification
|
||||
FTL_query_in_progress(daemon->log_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -415,8 +419,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||
forward->frec_src.dest = *dst_addr;
|
||||
forward->frec_src.iface = dst_iface;
|
||||
forward->frec_src.next = NULL;
|
||||
forward->frec_src.fd = udpfd;
|
||||
forward->new_id = get_id();
|
||||
forward->fd = udpfd;
|
||||
memcpy(forward->hash, hash, HASH_SIZE);
|
||||
forward->forwardall = 0;
|
||||
forward->flags = fwd_flags;
|
||||
|
@ -1329,6 +1333,9 @@ void reply_query(int fd, int family, time_t now)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Pi-hole modification
|
||||
int first_ID = -1;
|
||||
|
||||
for (src = &forward->frec_src; src; src = src->next)
|
||||
{
|
||||
header->id = htons(src->orig_id);
|
||||
|
@ -1337,7 +1344,7 @@ void reply_query(int fd, int family, time_t now)
|
|||
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
|
||||
#endif
|
||||
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
send_from(src->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&src->source, &src->dest, src->iface);
|
||||
|
||||
if (option_bool(OPT_EXTRALOG) && src != &forward->frec_src)
|
||||
|
@ -1346,6 +1353,8 @@ void reply_query(int fd, int family, time_t now)
|
|||
daemon->log_source_addr = &src->source;
|
||||
log_query(F_UPSTREAM, "query", NULL, "duplicate");
|
||||
}
|
||||
/* Pi-hole modification */
|
||||
FTL_duplicate_reply(src->log_id, &first_ID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1700,6 +1709,10 @@ void receive_query(struct listener *listen, time_t now)
|
|||
FTL_get_blocking_metadata(&addrp, &flags);
|
||||
log_query(flags, daemon->namebuff, addrp, (char*)blockingreason);
|
||||
n = setup_reply(header, n, addrp, flags, daemon->local_ttl);
|
||||
// The pseudoheader may contain important information such as EDNS0 version important for
|
||||
// some DNS resolvers (such as systemd-resolved) to work properly. We should not discard them.
|
||||
if (have_pseudoheader)
|
||||
n = add_pseudoheader(header, n, ((unsigned char *) header) + PACKETSZ, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, n, (union mysockaddr*)&source_addr, &dst_addr, if_index);
|
||||
return;
|
||||
}
|
||||
|
@ -2091,6 +2104,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||
FTL_get_blocking_metadata(&addrp, &flags);
|
||||
log_query(flags, daemon->namebuff, addrp, (char*)blockingreason);
|
||||
m = setup_reply(header, size, addrp, flags, daemon->local_ttl);
|
||||
// The pseudoheader may contain important information such as EDNS0 version important for
|
||||
// some DNS resolvers (such as systemd-resolved) to work properly. We should not discard them.
|
||||
if (have_pseudoheader)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -28,28 +28,28 @@
|
|||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_NETTLEHASH)
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||
|
||||
static const struct nettle_hash *hash;
|
||||
static void *ctx;
|
||||
static unsigned char *digest;
|
||||
|
||||
void hash_questions_init(void)
|
||||
{
|
||||
if (!(hash = hash_find("sha256")))
|
||||
die(_("Failed to create SHA-256 hash object"), NULL, EC_MISC);
|
||||
|
||||
ctx = safe_malloc(hash->context_size);
|
||||
digest = safe_malloc(hash->digest_size);
|
||||
}
|
||||
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
const struct nettle_hash *hash;
|
||||
void *ctx;
|
||||
unsigned char *digest;
|
||||
|
||||
if (!(hash = hash_find("sha256")) || !hash_init(hash, &ctx, &digest))
|
||||
{
|
||||
/* don't think this can ever happen. */
|
||||
static unsigned char dummy[HASH_SIZE];
|
||||
static int warned = 0;
|
||||
|
||||
if (!warned)
|
||||
my_syslog(LOG_ERR, _("Failed to create SHA-256 hash object"));
|
||||
warned = 1;
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
char *cp, c;
|
||||
|
@ -74,7 +74,7 @@ unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name
|
|||
return digest;
|
||||
}
|
||||
|
||||
#else /* HAVE_DNSSEC */
|
||||
#else /* HAVE_DNSSEC || HAVE_CRYPTOHASH */
|
||||
|
||||
#define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest
|
||||
typedef unsigned char BYTE; // 8-bit byte
|
||||
|
@ -91,6 +91,9 @@ static void sha256_init(SHA256_CTX *ctx);
|
|||
static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
|
||||
static void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
|
||||
|
||||
void hash_questions_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,7 +20,7 @@
|
|||
#include <setjmp.h>
|
||||
|
||||
/* Pi-hole modification */
|
||||
extern char *get_FTL_version(void);
|
||||
#include "../log.h"
|
||||
/************************/
|
||||
|
||||
static volatile int mem_recover = 0;
|
||||
|
@ -5059,7 +5059,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||
/************************/
|
||||
#endif
|
||||
/******** Pi-hole modification ********/
|
||||
add_txt("version.FTL", get_FTL_version(), 0 );
|
||||
add_txt("version.FTL", (char*)get_FTL_version(), 0 );
|
||||
/**************************************/
|
||||
|
||||
while (1)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
|
|
@ -191,8 +191,8 @@ static bool _FTL_check_blocking(int queryID, int domainID, int clientID, const c
|
|||
// as something along the CNAME path hit the whitelist
|
||||
if(!query->flags.whitelisted)
|
||||
{
|
||||
query_blocked(query, domain, client, QUERY_BLACKLIST);
|
||||
force_next_DNS_reply = dns_cache->force_reply;
|
||||
query_blocked(query, domain, client, QUERY_BLACKLIST);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -211,8 +211,8 @@ static bool _FTL_check_blocking(int queryID, int domainID, int clientID, const c
|
|||
// as sometving along the CNAME path hit the whitelist
|
||||
if(!query->flags.whitelisted)
|
||||
{
|
||||
query_blocked(query, domain, client, QUERY_GRAVITY);
|
||||
force_next_DNS_reply = dns_cache->force_reply;
|
||||
query_blocked(query, domain, client, QUERY_GRAVITY);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -533,19 +533,9 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
// Ensure we have enough space in the queries struct
|
||||
memory_check(QUERIES);
|
||||
const int queryID = counters->queries;
|
||||
|
||||
// If domain is "pi.hole" we skip this query
|
||||
if(strcasecmp(name, "pi.hole") == 0)
|
||||
{
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert domain to lower case
|
||||
char *domainString = strdup(name);
|
||||
|
@ -575,10 +565,50 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
|
|||
(strcmp(clientIP, "127.0.0.1") == 0 || strcmp(clientIP, "::1") == 0))
|
||||
{
|
||||
free(domainString);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
// Find client IP
|
||||
const int clientID = findClientID(clientIP, true, false);
|
||||
|
||||
// Get client pointer
|
||||
clientsData* client = getClient(clientID, true);
|
||||
if(client == NULL)
|
||||
{
|
||||
// Encountered memory error, skip query
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check rate-limit for this client
|
||||
if(config.rate_limit.count > 0 &&
|
||||
++client->rate_limit > config.rate_limit.count)
|
||||
{
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
logg("Rate-limiting %s %s query \"%s\" from %s:%s",
|
||||
proto == TCP ? "TCP" : "UDP",
|
||||
types, domainString, next_iface, clientIP);
|
||||
}
|
||||
|
||||
// Block this query
|
||||
force_next_DNS_reply = REFUSED;
|
||||
|
||||
// Do not further process this query, Pi-hole has never seen it
|
||||
unlock_shm();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ensure we have enough space in the queries struct
|
||||
memory_check(QUERIES);
|
||||
const int queryID = counters->queries;
|
||||
|
||||
// Log new query if in debug mode
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
|
@ -608,9 +638,6 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
|
|||
// Go through already knows domains and see if it is one of them
|
||||
const int domainID = findDomainID(domainString, true);
|
||||
|
||||
// Go through already knows clients and see if it is one of them
|
||||
const int clientID = findClientID(clientIP, true, false);
|
||||
|
||||
// Save everything
|
||||
queriesData* query = getQuery(queryID, false);
|
||||
if(query == NULL)
|
||||
|
@ -664,19 +691,6 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
|
|||
// Update overTime data
|
||||
overTime[timeidx].total++;
|
||||
|
||||
// Get client pointer
|
||||
clientsData* client = getClient(clientID, true);
|
||||
if(client == NULL)
|
||||
{
|
||||
// Encountered memory error, skip query
|
||||
logg("WARN: No memory available, skipping query analysis");
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update overTime data structure with the new client
|
||||
change_clientcount(client, 0, 0, timeidx, 1);
|
||||
|
||||
|
@ -763,8 +777,8 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
|
|||
void _FTL_get_blocking_metadata(union all_addr **addrp, unsigned int *flags, const char* file, const int line)
|
||||
{
|
||||
// Check first if we need to force our reply to something different than the
|
||||
// default/configured blocking mode For instance, we need to force NXDOMAIN
|
||||
// for intercepted _esni.* queries
|
||||
// default/configured blocking mode. For instance, we need to force NXDOMAIN
|
||||
// for intercepted _esni.* queries.
|
||||
if(force_next_DNS_reply == NXDOMAIN)
|
||||
{
|
||||
*flags = F_NXDOMAIN;
|
||||
|
@ -772,6 +786,14 @@ void _FTL_get_blocking_metadata(union all_addr **addrp, unsigned int *flags, con
|
|||
force_next_DNS_reply = 0u;
|
||||
return;
|
||||
}
|
||||
else if(force_next_DNS_reply == REFUSED)
|
||||
{
|
||||
// Empty flags result in REFUSED
|
||||
*flags = 0;
|
||||
// Reset DNS reply forcing
|
||||
force_next_DNS_reply = 0u;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add flags according to current blocking mode
|
||||
// We bit-add here as flags already contains either F_IPV4 or F_IPV6
|
||||
|
@ -869,12 +891,18 @@ void _FTL_forwarded(const unsigned int flags, const char *name, const struct ser
|
|||
|
||||
// Get ID of upstream destination, create new upstream record
|
||||
// if not found in current data structure
|
||||
const int upstreamID = findUpstreamID(upstreamIP, upstreamPort, true);
|
||||
const int upstreamID = findUpstreamID(upstreamIP, upstreamPort);
|
||||
query->upstreamID = upstreamID;
|
||||
|
||||
upstreamsData *upstream = getUpstream(upstreamID, true);
|
||||
if(upstream != NULL)
|
||||
{
|
||||
upstream->count++;
|
||||
upstream->lastQuery = double_time();
|
||||
}
|
||||
|
||||
// Update counter for forwarded queries
|
||||
counters->forwarded++;
|
||||
|
||||
// Get time index for this query
|
||||
const unsigned int timeidx = query->timeidx;
|
||||
|
@ -926,9 +954,6 @@ void _FTL_forwarded(const unsigned int flags, const char *name, const struct ser
|
|||
// Update overTime data
|
||||
overTime[timeidx].forwarded++;
|
||||
|
||||
// Update counter for forwarded queries
|
||||
counters->forwarded++;
|
||||
|
||||
struct timeval request;
|
||||
gettimeofday(&request, 0);
|
||||
query->forwardresponse = converttimeval(request);
|
||||
|
@ -1275,9 +1300,6 @@ static void query_externally_blocked(const int queryID, const enum query_status
|
|||
return;
|
||||
}
|
||||
|
||||
// Get time index
|
||||
const unsigned int timeidx = query->timeidx;
|
||||
|
||||
// If query is already known to be externally blocked,
|
||||
// then we have nothing to do here
|
||||
if(query->status == QUERY_EXTERNAL_BLOCKED_IP ||
|
||||
|
@ -1285,18 +1307,6 @@ static void query_externally_blocked(const int queryID, const enum query_status
|
|||
query->status == QUERY_EXTERNAL_BLOCKED_NXRA)
|
||||
return;
|
||||
|
||||
// Correct counters if necessary ...
|
||||
if(query->status == QUERY_FORWARDED)
|
||||
{
|
||||
counters->forwarded--;
|
||||
overTime[timeidx].forwarded--;
|
||||
|
||||
// Get forward pointer
|
||||
upstreamsData* upstream = getUpstream(query->upstreamID, true);
|
||||
if(upstream != NULL)
|
||||
upstream->count--;
|
||||
}
|
||||
|
||||
// Mark query as blocked
|
||||
domainsData* domain = getDomain(query->domainID, true);
|
||||
clientsData* client = getClient(query->clientID, true);
|
||||
|
@ -1444,6 +1454,12 @@ static void query_blocked(queriesData* query, domainsData* domain, clientsData*
|
|||
else if(query->status == QUERY_FORWARDED)
|
||||
{
|
||||
counters->forwarded--;
|
||||
overTime[query->timeidx].forwarded--;
|
||||
|
||||
// Get forward pointer
|
||||
upstreamsData* upstream = getUpstream(query->upstreamID, true);
|
||||
if(upstream != NULL)
|
||||
upstream->count--;
|
||||
}
|
||||
else if(query->status == QUERY_CACHE)
|
||||
{
|
||||
|
@ -1679,7 +1695,7 @@ static void save_reply_type(const unsigned int flags, const union all_addr *addr
|
|||
queriesData* query, const struct timeval response)
|
||||
{
|
||||
// Iterate through possible values
|
||||
if(flags & F_NEG)
|
||||
if(flags & F_NEG || force_next_DNS_reply == NXDOMAIN)
|
||||
{
|
||||
if(flags & F_NXDOMAIN)
|
||||
{
|
||||
|
@ -1711,15 +1727,15 @@ static void save_reply_type(const unsigned int flags, const union all_addr *addr
|
|||
// TXT query
|
||||
query->reply = REPLY_RRNAME;
|
||||
}
|
||||
else if(flags & F_RCODE && addr != NULL)
|
||||
else if((flags & F_RCODE && addr != NULL) || force_next_DNS_reply == REFUSED)
|
||||
{
|
||||
const unsigned int rcode = addr->log.rcode;
|
||||
if(rcode == REFUSED)
|
||||
if((addr != NULL && addr->log.rcode == REFUSED)
|
||||
|| force_next_DNS_reply == REFUSED )
|
||||
{
|
||||
// REFUSED query
|
||||
query->reply = REPLY_REFUSED;
|
||||
}
|
||||
else if(rcode == SERVFAIL)
|
||||
else if(addr != NULL && addr->log.rcode == SERVFAIL)
|
||||
{
|
||||
// SERVFAIL query
|
||||
query->reply = REPLY_SERVFAIL;
|
||||
|
@ -1890,7 +1906,7 @@ void FTL_forwarding_retried(const struct server *serv, const int oldID, const in
|
|||
strtolower(upstreamIP);
|
||||
|
||||
// Get upstream ID
|
||||
const int upstreamID = findUpstreamID(upstreamIP, upstreamPort, false);
|
||||
const int upstreamID = findUpstreamID(upstreamIP, upstreamPort);
|
||||
|
||||
// Possible debugging information
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
|
@ -1908,7 +1924,7 @@ void FTL_forwarding_retried(const struct server *serv, const int oldID, const in
|
|||
|
||||
// Search for corresponding query identified by ID
|
||||
// Retried DNSSEC queries are ignored, we have to flag themselves (newID)
|
||||
// Retried normal queries take over, we have to flat the original query (oldID)
|
||||
// Retried normal queries take over, we have to flag the original query (oldID)
|
||||
const int queryID = findQueryID(dnssec ? newID : oldID);
|
||||
if(queryID >= 0)
|
||||
{
|
||||
|
@ -2188,3 +2204,110 @@ bool FTL_unlink_DHCP_lease(const char *ipaddr)
|
|||
return true;
|
||||
|
||||
}
|
||||
|
||||
void FTL_query_in_progress(const int id)
|
||||
{
|
||||
// Query (possibly from new source), but the same query may be in
|
||||
// progress from another source.
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
// Search for corresponding query identified by ID
|
||||
const int queryID = findQueryID(id);
|
||||
if(queryID < 0)
|
||||
{
|
||||
// This may happen e.g. if the original query was an unhandled query type
|
||||
unlock_shm();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get query pointer
|
||||
queriesData* query = getQuery(queryID, true);
|
||||
if(query == NULL)
|
||||
{
|
||||
// Memory error, skip this DNSSEC details
|
||||
unlock_shm();
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
// Get domain pointer
|
||||
const domainsData* domain = getDomain(query->domainID, true);
|
||||
if(domain != NULL)
|
||||
{
|
||||
logg("**** query for %s is already in progress (ID %i)", getstr(domain->domainpos), id);
|
||||
}
|
||||
}
|
||||
|
||||
// Store status
|
||||
query->status = QUERY_IN_PROGRESS;
|
||||
|
||||
// Unlock shared memory
|
||||
unlock_shm();
|
||||
}
|
||||
|
||||
void FTL_duplicate_reply(const int id, int *firstID)
|
||||
{
|
||||
// Reply to duplicated query
|
||||
|
||||
// Check if we can process thes duplicated queries at all
|
||||
if(*firstID == -2)
|
||||
return;
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
// Search for corresponding query identified by ID
|
||||
const int queryID = findQueryID(id);
|
||||
if(queryID < 0)
|
||||
{
|
||||
// This may happen e.g. if the original query was an unhandled query type
|
||||
unlock_shm();
|
||||
*firstID = -2;
|
||||
return;
|
||||
}
|
||||
|
||||
if(*firstID == -1)
|
||||
{
|
||||
// This is not yet a duplicate, we just store the ID
|
||||
// of the successful reply here so we can get it quicker
|
||||
// during the next loop iterations
|
||||
unlock_shm();
|
||||
*firstID = queryID;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get query pointer of duplicate reply
|
||||
queriesData* duplicated_query = getQuery(queryID, true);
|
||||
const queriesData* source_query = getQuery(*firstID, true);
|
||||
|
||||
if(duplicated_query == NULL || source_query == NULL)
|
||||
{
|
||||
// Memory error, skip this duplicate
|
||||
unlock_shm();
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug logging
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
logg("**** query %d is duplicate of %d", queryID, *firstID);
|
||||
}
|
||||
|
||||
// Copy relevant information over
|
||||
duplicated_query->reply = source_query->reply;
|
||||
duplicated_query->dnssec = source_query->dnssec;
|
||||
duplicated_query->flags.complete = true;
|
||||
|
||||
// The original query may have been blocked during CNAME inspection,
|
||||
// correct status in this case
|
||||
if(source_query->status != QUERY_FORWARDED)
|
||||
duplicated_query->status = source_query->status;
|
||||
duplicated_query->CNAME_domainID = source_query->CNAME_domainID;
|
||||
|
||||
// Unlock shared memory
|
||||
unlock_shm();
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ void _FTL_get_blocking_metadata(union all_addr **addrp, unsigned int *flags, con
|
|||
bool _FTL_CNAME(const char *domain, const struct crec *cpp, const int id, const char* file, const int line);
|
||||
|
||||
unsigned int FTL_extract_question_flags(struct dns_header *header, const size_t qlen);
|
||||
void FTL_query_in_progress(const int id);
|
||||
void FTL_duplicate_reply(const int id, int *firstID);
|
||||
|
||||
void FTL_dnsmasq_reload(void);
|
||||
void FTL_fork_and_bind_sockets(struct passwd *ent_pw);
|
||||
|
|
|
@ -42,6 +42,7 @@ enum query_status {
|
|||
QUERY_BLACKLIST_CNAME,
|
||||
QUERY_RETRIED,
|
||||
QUERY_RETRIED_DNSSEC,
|
||||
QUERY_IN_PROGRESS,
|
||||
QUERY_STATUS_MAX
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
|
38
src/gc.c
38
src/gc.c
|
@ -23,29 +23,46 @@
|
|||
|
||||
bool doGC = false;
|
||||
|
||||
time_t lastGCrun = 0;
|
||||
static void reset_rate_limiting(void)
|
||||
{
|
||||
for(int clientID = 0; clientID < counters->clients; clientID++)
|
||||
{
|
||||
clientsData *client = getClient(clientID, true);
|
||||
if(client != NULL)
|
||||
client->rate_limit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *GC_thread(void *val)
|
||||
{
|
||||
// Set thread name
|
||||
prctl(PR_SET_NAME,"housekeeper",0,0,0);
|
||||
|
||||
// Save timestamp as we do not want to store immediately
|
||||
// to the database
|
||||
lastGCrun = time(NULL) - time(NULL)%GCinterval;
|
||||
// Remember when we last ran the actions
|
||||
time_t lastGCrun = time(NULL) - time(NULL)%GCinterval;
|
||||
time_t lastRateLimitCleaner = time(NULL);
|
||||
while(!killed)
|
||||
{
|
||||
if(time(NULL) - GCdelay - lastGCrun >= GCinterval || doGC)
|
||||
const time_t now = time(NULL);
|
||||
if((unsigned int)(now - lastRateLimitCleaner) >= config.rate_limit.interval)
|
||||
{
|
||||
lastRateLimitCleaner = now;
|
||||
lock_shm();
|
||||
reset_rate_limiting();
|
||||
unlock_shm();
|
||||
}
|
||||
if(now - GCdelay - lastGCrun >= GCinterval || doGC)
|
||||
{
|
||||
doGC = false;
|
||||
// Update lastGCrun timer
|
||||
lastGCrun = time(NULL) - GCdelay - (time(NULL) - GCdelay)%GCinterval;
|
||||
lastGCrun = now - GCdelay - (now - GCdelay)%GCinterval;
|
||||
|
||||
// Lock FTL's data structure, since it is likely that it will be changed here
|
||||
// Requests should not be processed/answered when data is about to change
|
||||
lock_shm();
|
||||
|
||||
// Get minimum time stamp to keep
|
||||
time_t mintime = (time(NULL) - GCdelay) - MAXLOGAGE*3600;
|
||||
time_t mintime = (now - GCdelay) - MAXLOGAGE*3600;
|
||||
|
||||
// Align to the start of the next hour. This will also align with
|
||||
// the oldest overTime interval after GC is done.
|
||||
|
@ -56,7 +73,7 @@ void *GC_thread(void *val)
|
|||
{
|
||||
timer_start(GC_TIMER);
|
||||
char timestring[84] = "";
|
||||
get_timestr(timestring, mintime);
|
||||
get_timestr(timestring, mintime, false);
|
||||
logg("GC starting, mintime: %s (%llu)", timestring, (long long)mintime);
|
||||
}
|
||||
|
||||
|
@ -128,6 +145,11 @@ void *GC_thread(void *val)
|
|||
if(client != NULL)
|
||||
change_clientcount(client, 0, -1, -1, 0);
|
||||
break;
|
||||
case QUERY_IN_PROGRESS:
|
||||
// Nothing to be done here, this was a duplicated query. It
|
||||
// wasn't forwarded on its own to save some traffic (and
|
||||
// reduce the attack surface for cache spoofing)
|
||||
break;
|
||||
case QUERY_STATUS_MAX: // fall through
|
||||
default:
|
||||
/* That cannot happen */
|
||||
|
|
27
src/log.c
27
src/log.c
|
@ -112,18 +112,27 @@ double double_time(void)
|
|||
|
||||
// The size of 84 bytes has been carefully selected for all possible timestamps
|
||||
// to always fit into the available space without buffer overflows
|
||||
void get_timestr(char * const timestring, const time_t timein)
|
||||
void get_timestr(char * const timestring, const time_t timein, const bool millis)
|
||||
{
|
||||
struct tm tm;
|
||||
localtime_r(&timein, &tm);
|
||||
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
const int millisec = tv.tv_usec/1000;
|
||||
if(millis)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
const int millisec = tv.tv_usec/1000;
|
||||
|
||||
sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d.%03i",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, millisec);
|
||||
sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d.%03i",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec, millisec);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d",
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
}
|
||||
}
|
||||
|
||||
void _FTL_log(const bool newline, const char *func, const char *file, const int line, const char *format, ...)
|
||||
|
@ -142,7 +151,7 @@ void _FTL_log(const bool newline, const char *func, const char *file, const int
|
|||
pthread_mutex_lock(&FTL_log_lock);
|
||||
|
||||
// Get human-readable time
|
||||
get_timestr(timestring, time(NULL));
|
||||
get_timestr(timestring, time(NULL), true);
|
||||
|
||||
// Get and log PID of current process to avoid ambiguities when more than one
|
||||
// pihole-FTL instance is logging into the same file
|
||||
|
@ -241,7 +250,7 @@ void __attribute__ ((format (gnu_printf, 2, 3))) logg_web(enum web_code code, co
|
|||
pthread_mutex_lock(&web_log_lock);
|
||||
|
||||
// Get human-readable time
|
||||
get_timestr(timestring, time(NULL));
|
||||
get_timestr(timestring, time(NULL), true);
|
||||
|
||||
// Get and log PID of current process to avoid ambiguities when more than one
|
||||
// pihole-FTL instance is logging into the same file
|
||||
|
|
|
@ -23,7 +23,7 @@ void format_time(char buffer[42], unsigned long seconds, double milliseconds);
|
|||
const char *get_FTL_version(void) __attribute__ ((malloc));
|
||||
void log_FTL_version(bool crashreport);
|
||||
double double_time(void);
|
||||
void get_timestr(char * const timestring, const time_t timein);
|
||||
void get_timestr(char * const timestring, const time_t timein, const bool millis);
|
||||
void logg_web(enum web_code code, const char* format, ...) __attribute__ ((format (gnu_printf, 2, 3)));
|
||||
const char *get_ordinal_suffix(unsigned int number) __attribute__ ((const));
|
||||
|
||||
|
|
10
src/main.c
10
src/main.c
|
@ -25,6 +25,7 @@
|
|||
#include "timers.h"
|
||||
// http_terminate()
|
||||
#include "webserver/webserver.h"
|
||||
#include "procps.h"
|
||||
|
||||
char * username;
|
||||
bool needGC = false;
|
||||
|
@ -56,16 +57,17 @@ int main (int argc, char* argv[])
|
|||
// We handle real-time signals later (after dnsmasq has forked)
|
||||
handle_SIGSEGV();
|
||||
|
||||
// Process pihole-FTL.conf
|
||||
read_FTLconf();
|
||||
|
||||
// Initialize shared memory - replace possibly existing files
|
||||
// Initialize shared memory
|
||||
if(!init_shmem(true))
|
||||
{
|
||||
logg("Initialization of shared memory failed.");
|
||||
check_running_FTL();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Process pihole-FTL.conf
|
||||
read_FTLconf();
|
||||
|
||||
// pihole-FTL should really be run as user "pihole" to not mess up with file permissions
|
||||
// print warning otherwise
|
||||
if(strcmp(username, "pihole") != 0)
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2021 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* FTL Engine
|
||||
* /proc system subroutines
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
#include "FTL.h"
|
||||
#include "procps.h"
|
||||
#include "log.h"
|
||||
#include <dirent.h>
|
||||
// getpid()
|
||||
#include <unistd.h>
|
||||
|
||||
#define PROCESS_NAME "pihole-FTL"
|
||||
|
||||
static bool get_process_name(const pid_t pid, char name[128])
|
||||
{
|
||||
if(pid == 0)
|
||||
{
|
||||
strcpy(name, "init");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to open comm file
|
||||
char filename[sizeof("/proc/%u/task/%u/comm") + sizeof(int)*3 * 2];
|
||||
snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
|
||||
FILE *f = fopen(filename, "r");
|
||||
if(f == NULL)
|
||||
return false;
|
||||
|
||||
// Read name from opened file
|
||||
if(fscanf(f, "%128s", name) != 1)
|
||||
false;
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool get_process_ppid(const pid_t pid, pid_t *ppid)
|
||||
{
|
||||
// Try to open status file
|
||||
char filename[sizeof("/proc/%u/task/%u/comm") + sizeof(int)*3 * 2];
|
||||
snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
|
||||
FILE *f = fopen(filename, "r");
|
||||
if(f == NULL)
|
||||
return false;
|
||||
|
||||
// Read comm from opened file
|
||||
char buffer[128];
|
||||
while(fgets(buffer, sizeof(buffer), f) != NULL)
|
||||
{
|
||||
if(sscanf(buffer, "PPid: %d\n", ppid) == 1)
|
||||
break;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_process_creation_time(const pid_t pid, char timestr[84])
|
||||
{
|
||||
// Try to open comm file
|
||||
char filename[sizeof("/proc/%u/task/%u/comm") + sizeof(int)*3 * 2];
|
||||
snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
|
||||
struct stat st;
|
||||
if(stat(filename, &st) < 0)
|
||||
return false;
|
||||
get_timestr(timestr, st.st_ctim.tv_sec, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void check_running_FTL(void)
|
||||
{
|
||||
//pid_t pid;
|
||||
DIR *dirPos;
|
||||
struct dirent *entry;
|
||||
|
||||
// Open /proc
|
||||
errno = 0;
|
||||
if ((dirPos = opendir("/proc")) == NULL)
|
||||
{
|
||||
logg("Dailed to access /proc: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop over entries in /proc
|
||||
// This is much more efficient than iterating over all possible PIDs
|
||||
while ((entry = readdir(dirPos)) != NULL)
|
||||
{
|
||||
// We are only interested in subdirectories of /proc
|
||||
if(entry->d_type != DT_DIR)
|
||||
continue;
|
||||
// We are only interested in PID subdirectories
|
||||
if(entry->d_name[0] < '0' || entry->d_name[0] > '9')
|
||||
continue;
|
||||
|
||||
// Extract PID
|
||||
const pid_t pid = strtol(entry->d_name, NULL, 10);
|
||||
|
||||
// Skip our own process
|
||||
if(pid == getpid())
|
||||
continue;
|
||||
|
||||
// Get process name
|
||||
char name[128] = { 0 };
|
||||
if(!get_process_name(pid, name))
|
||||
continue;
|
||||
|
||||
// Get parent process ID (PPID)
|
||||
pid_t ppid;
|
||||
if(!get_process_ppid(pid, &ppid))
|
||||
continue;
|
||||
char ppid_name[128] = { 0 };
|
||||
if(!get_process_name(ppid, ppid_name))
|
||||
continue;
|
||||
|
||||
char timestr[84] = { 0 };
|
||||
get_process_creation_time(pid, timestr);
|
||||
|
||||
// Log this process if it is a duplicate of us
|
||||
if(strcasecmp(name, PROCESS_NAME) == 0)
|
||||
logg("---> %s is already running as PID %d (started %s, child of PID %i (%s))",
|
||||
PROCESS_NAME, pid, timestr, ppid, ppid_name);
|
||||
}
|
||||
|
||||
closedir(dirPos);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2021 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* FTL Engine
|
||||
* /proc system prototypes
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
#ifndef PROCPS_H
|
||||
#define PROCPS_H
|
||||
void check_running_FTL(void);
|
||||
|
||||
#endif // POCPS_H
|
45
src/shmem.c
45
src/shmem.c
|
@ -81,6 +81,7 @@ static ShmSettings *shmSettings = NULL;
|
|||
|
||||
static int pagesize;
|
||||
static unsigned int local_shm_counter = 0;
|
||||
static size_t used_shmem = 0u;
|
||||
static size_t get_optimal_object_size(const size_t objsize, const size_t minsize);
|
||||
|
||||
static int get_dev_shm_usage(char buffer[64])
|
||||
|
@ -106,13 +107,19 @@ static int get_dev_shm_usage(char buffer[64])
|
|||
double formated_size = 0.0;
|
||||
format_memory_size(prefix_size, size, &formated_size);
|
||||
|
||||
// Generate human-readable used size
|
||||
// Generate human-readable "total used" size
|
||||
char prefix_used[2] = { 0 };
|
||||
double formated_used = 0.0;
|
||||
format_memory_size(prefix_used, used, &formated_used);
|
||||
|
||||
// Generate human-readable "used by FTL" size
|
||||
char prefix_FTL[2] = { 0 };
|
||||
double formated_FTL = 0.0;
|
||||
format_memory_size(prefix_FTL, used_shmem, &formated_FTL);
|
||||
|
||||
// Print result into buffer passed to this subroutine
|
||||
snprintf(buffer, 64, SHMEM_PATH": %.1f%sB used, %.1f%sB total", formated_used, prefix_used, formated_size, prefix_size);
|
||||
snprintf(buffer, 64, SHMEM_PATH": %.1f%sB used, %.1f%sB total, FTL uses %.1f%sB",
|
||||
formated_used, prefix_used, formated_size, prefix_size, formated_FTL, prefix_FTL);
|
||||
|
||||
// Return percentage of used shared memory
|
||||
// Adding 1 avoids FPE if the size turns out to be zero
|
||||
|
@ -595,28 +602,14 @@ SharedMemory create_shm(const char *name, const size_t size, bool create_new)
|
|||
};
|
||||
|
||||
// O_RDWR: Open the object for read-write access (we need to be able to modify the locks)
|
||||
int shm_oflags = O_RDWR;
|
||||
if(create_new)
|
||||
{
|
||||
// Try unlinking the shared memory object before creating a new one.
|
||||
// If the object is still existing, e.g., due to a past unclean exit
|
||||
// of FTL, shm_open() would fail with error "File exists"
|
||||
int ret = shm_unlink(name);
|
||||
// Check return code. shm_unlink() returns -1 on error and sets errno
|
||||
// We specifically ignore ENOENT (No such file or directory) as this is not an
|
||||
// error in our use case (we only want the file to be deleted when existing)
|
||||
if(ret != 0 && errno != ENOENT)
|
||||
logg("create_shm(): shm_unlink(\"%s\") failed: %s (%i)", name, strerror(errno), errno);
|
||||
|
||||
// Replace shm_oflags
|
||||
// O_CREAT: Create the shared memory object if it does not exist.
|
||||
// O_EXCL: Return an error if a shared memory object with the given name already exists.
|
||||
// O_TRUNC: If the shared memory object already exists, truncate it to zero bytes.
|
||||
shm_oflags |= O_CREAT | O_EXCL | O_TRUNC;
|
||||
}
|
||||
// When creating a new shared memory object, we add to this
|
||||
// - O_CREAT: Create the shared memory object if it does not exist.
|
||||
// - O_EXCL: Return an error if a shared memory object with the given name already exists.
|
||||
const int shm_oflags = create_new ? O_RDWR | O_CREAT | O_EXCL : O_RDWR;
|
||||
|
||||
// Create the shared memory file in read/write mode with 600 permissions
|
||||
int fd = shm_open(sharedMemory.name, shm_oflags, S_IRUSR | S_IWUSR);
|
||||
errno = 0;
|
||||
const int fd = shm_open(sharedMemory.name, shm_oflags, S_IRUSR | S_IWUSR);
|
||||
|
||||
// Check for `shm_open` error
|
||||
if(fd == -1)
|
||||
|
@ -638,6 +631,10 @@ SharedMemory create_shm(const char *name, const size_t size, bool create_new)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Update how much memory FTL uses
|
||||
// We only add here as this is a new file
|
||||
used_shmem += size;
|
||||
|
||||
// Create shared memory mapping
|
||||
void *shm = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
|
@ -783,6 +780,10 @@ bool realloc_shm(SharedMemory *sharedMemory, const size_t size1, const size_t si
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Update how much memory FTL uses
|
||||
// We add the difference between updated and previous size
|
||||
used_shmem += (size - sharedMemory->size);
|
||||
|
||||
sharedMemory->ptr = new_ptr;
|
||||
sharedMemory->size = size;
|
||||
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#!./test/libs/bats/bin/bats
|
||||
|
||||
@test "Running a second instance is detected and prevented" {
|
||||
run bash -c 'su pihole -s /bin/sh -c "/home/pihole/pihole-FTL -f"'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[9]} == *"Initialization of shared memory failed." ]]
|
||||
[[ ${lines[10]} == *"--> pihole-FTL is already running as PID "* ]]
|
||||
}
|
||||
|
||||
@test "Starting tests without prior history" {
|
||||
run bash -c 'grep -c "Total DNS queries: 0" /var/log/pihole-FTL.log'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
|
@ -297,8 +304,8 @@
|
|||
[[ ${lines[0]} == "0" ]]
|
||||
}
|
||||
|
||||
@test "No FATAL messages in pihole-FTL.log" {
|
||||
run bash -c 'grep -c "FATAL:" /var/log/pihole-FTL.log'
|
||||
@test "No FATAL messages in pihole-FTL.log (besides error due to starting FTL more than once)" {
|
||||
run bash -c 'grep "FATAL:" /var/log/pihole-FTL.log | grep -c -v "FATAL: create_shm(): Failed to create shared memory object \"FTL-lock\": File exists"'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[0]} == "0" ]]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue