Merge pull request #836 from pi-hole/release/v5.1

Release/v5.1 -> development
This commit is contained in:
DL6ER
2020-07-17 09:49:13 +02:00
committed by GitHub
33 changed files with 459 additions and 320 deletions
+1
View File
@@ -114,6 +114,7 @@ set(sources
datastructure.h
dnsmasq_interface.c
dnsmasq_interface.h
enums.h
files.c
files.h
FTL.h
-11
View File
@@ -103,17 +103,6 @@
// Default: 1000 (one second)
#define DATABASE_BUSY_TIMEOUT 1000
// FTLDNS enums
enum { QUERIES, UPSTREAMS, CLIENTS, DOMAINS, OVERTIME, WILDCARD, DNS_CACHE };
enum { DNSSEC_UNSPECIFIED, DNSSEC_SECURE, DNSSEC_INSECURE, DNSSEC_BOGUS, DNSSEC_ABANDONED };
enum { QUERY_UNKNOWN, QUERY_GRAVITY, QUERY_FORWARDED, QUERY_CACHE, QUERY_REGEX, QUERY_BLACKLIST, \
QUERY_EXTERNAL_BLOCKED_IP, QUERY_EXTERNAL_BLOCKED_NULL, QUERY_EXTERNAL_BLOCKED_NXRA, \
QUERY_GRAVITY_CNAME, QUERY_REGEX_CNAME, QUERY_BLACKLIST_CNAME, QUERY_STATUS_MAX };
enum { REPLY_UNKNOWN, REPLY_NODATA, REPLY_NXDOMAIN, REPLY_CNAME, REPLY_IP, REPLY_DOMAIN, REPLY_RRNAME, REPLY_SERVFAIL, REPLY_REFUSED, REPLY_NOTIMP, REPLY_OTHER };
enum { PRIVACY_SHOW_ALL = 0, PRIVACY_HIDE_DOMAINS, PRIVACY_HIDE_DOMAINS_CLIENTS, PRIVACY_MAXIMUM, PRIVACY_NOSTATS };
enum { MODE_IP, MODE_NX, MODE_NULL, MODE_IP_NODATA_AAAA, MODE_NODATA };
enum { REGEX_BLACKLIST, REGEX_WHITELIST };
// Use out own memory handling functions that will detect possible errors
// and report accordingly in the log. This will make debugging FTL crashs
// caused by insufficient memory or by code bugs (not properly dealing
+7 -3
View File
@@ -9,6 +9,7 @@
* Please see LICENSE file for your rights under this license. */
#include "FTL.h"
#include "enums.h"
#include "memory.h"
#include "shmem.h"
#include "datastructure.h"
@@ -1368,15 +1369,18 @@ void getDomainDetails(const char *client_message, const int *sock)
case UNKNOWN_BLOCKED:
str = "unknown";
break;
case BLACKLIST_BLOCKED:
str = "blacklisted";
break;
case GRAVITY_BLOCKED:
str = "gravity";
break;
case BLACKLIST_BLOCKED:
str = "blacklisted";
break;
case REGEX_BLOCKED:
str = "regex";
break;
case WHITELISTED:
str = "whitelisted";
break;
case NOT_BLOCKED:
str = "not blocked";
break;
+40 -69
View File
@@ -29,27 +29,11 @@
#define BACKLOG 5
// File descriptors
int socketfd, telnetfd4 = 0, telnetfd6 = 0;
int socketfd = 0, telnetfd4 = 0, telnetfd6 = 0;
bool dualstack = false;
bool ipv4telnet = false, ipv6telnet = false;
bool sock_avail = false;
bool ipv4telnet = false, ipv6telnet = false, sock_avail = false;
bool istelnet[MAXCONNS];
static void saveport(void)
{
FILE *f;
if((f = fopen(FTLfiles.port, "w+")) == NULL)
{
logg("WARNING: Unable to write used port to file.");
logg(" Continuing anyway (API might not find the port).");
}
else
{
fprintf(f, "%i", config.port);
fclose(f);
}
}
static bool bind_to_telnet_port_IPv4(int *socketdescriptor)
{
// IPv4 socket
@@ -161,15 +145,14 @@ static bool bind_to_telnet_port_IPv6(int *socketdescriptor)
return true;
}
static void bind_to_unix_socket(int *socketdescriptor)
static bool bind_to_unix_socket(int *socketdescriptor)
{
*socketdescriptor = socket(AF_LOCAL, SOCK_STREAM, 0);
if(*socketdescriptor < 0)
{
logg("WARNING: Error opening Unix socket.");
logg(" Continuing anyway.");
return;
return false;
}
// Make sure unix socket file handle does not exist, if it exists, remove it
@@ -190,32 +173,18 @@ static void bind_to_unix_socket(int *socketdescriptor)
if(bind(*socketdescriptor, (struct sockaddr *) &address, sizeof (address)) != 0)
{
logg("WARNING: Cannot bind on Unix socket %s: %s (%i)", FTLfiles.socketfile, strerror(errno), errno);
logg(" Continuing anyway.");
return;
return false;
}
// The listen system call allows the process to listen on the Unix socket for connections
if(listen(*socketdescriptor, BACKLOG) == -1)
{
logg("WARNING: Cannot listen on Unix socket: %s (%i)", strerror(errno), errno);
logg(" Continuing anyway.");
return;
return false;
}
logg("Listening on Unix socket");
sock_avail = true;
}
// Called from main() at graceful shutdown
static void removeport(void)
{
FILE *f;
if((f = fopen(FTLfiles.port, "w+")) == NULL)
{
logg("WARNING: Unable to empty port file");
return;
}
fclose(f);
return true;
}
void seom(const int sock)
@@ -295,7 +264,6 @@ static int listener(const int sockfd, const char type)
void close_telnet_socket(void)
{
removeport();
// Using global variable here
if(telnetfd4)
close(telnetfd4);
@@ -303,12 +271,17 @@ void close_telnet_socket(void)
close(telnetfd6);
}
void close_unix_socket(void)
void close_unix_socket(bool unlink_file)
{
// The process has to take care of unlinking the socket file description on exit
unlink(FTLfiles.socketfile);
if(unlink_file)
{
// The process has to take care of unlinking the socket file description on exit
unlink(FTLfiles.socketfile);
}
// Using global variable here
close(socketfd);
if(sock_avail)
close(socketfd);
}
static void *telnet_connection_handler_thread(void *socket_desc)
@@ -413,24 +386,6 @@ static void *socket_connection_handler_thread(void *socket_desc)
return false;
}
void bind_sockets(void)
{
// Initialize IPv4 telnet socket
if(bind_to_telnet_port_IPv4(&telnetfd4))
ipv4telnet = true;
// Initialize IPv6 telnet socket
// only if IPv6 interfaces are available
if(ipv6_available())
if(bind_to_telnet_port_IPv6(&telnetfd6))
ipv6telnet = true;
saveport();
// Initialize Unix socket
bind_to_unix_socket(&socketfd);
}
void *telnet_listening_thread_IPv4(void *args)
{
// We will use the attributes object later to start all threads in detached mode
@@ -444,6 +399,11 @@ void *telnet_listening_thread_IPv4(void *args)
// Set thread name
prctl(PR_SET_NAME,"telnet-IPv4",0,0,0);
// Initialize IPv4 telnet socket
ipv4telnet = bind_to_telnet_port_IPv4(&telnetfd4);
if(!ipv4telnet)
return NULL;
// Listen as long as FTL is not killed
while(!killed)
{
@@ -466,7 +426,7 @@ void *telnet_listening_thread_IPv4(void *args)
if(pthread_create( &telnet_connection_thread, &attr, telnet_connection_handler_thread, (void*) newsock ) != 0)
{
// Log the error code description
logg("WARNING: Unable to open telnet processing thread, error: %s", strerror(errno));
logg("WARNING: Unable to open telnet processing thread: %s", strerror(errno));
}
}
return false;
@@ -485,6 +445,14 @@ void *telnet_listening_thread_IPv6(void *args)
// Set thread name
prctl(PR_SET_NAME,"telnet-IPv6",0,0,0);
// Initialize IPv6 telnet socket but only if IPv6 interfaces are available
if(!ipv6_available())
return NULL;
ipv6telnet = bind_to_telnet_port_IPv6(&telnetfd6);
if(!ipv6telnet)
return NULL;
// Listen as long as FTL is not killed
while(!killed)
{
@@ -507,7 +475,7 @@ void *telnet_listening_thread_IPv6(void *args)
if(pthread_create( &telnet_connection_thread, &attr, telnet_connection_handler_thread, (void*) newsock ) != 0)
{
// Log the error code description
logg("WARNING: Unable to open telnet processing thread, error: %s", strerror(errno));
logg("WARNING: Unable to open telnet processing thread: %s", strerror(errno));
}
}
return false;
@@ -527,7 +495,8 @@ void *socket_listening_thread(void *args)
prctl(PR_SET_NAME,"socket listener",0,0,0);
// Return early to avoid CPU spinning if Unix socket is not available
if(!sock_avail)
sock_avail = bind_to_unix_socket(&socketfd);
if(sock_avail)
return NULL;
// Listen as long as FTL is not killed
@@ -535,7 +504,8 @@ void *socket_listening_thread(void *args)
{
// Look for new clients that want to connect
const int csck = listener(socketfd, 0);
if(csck < 0) continue;
if(csck < 0)
continue;
// Allocate memory used to transport client socket ID to client listening thread
int *newsock;
@@ -548,7 +518,7 @@ void *socket_listening_thread(void *args)
if(pthread_create( &socket_connection_thread, &attr, socket_connection_handler_thread, (void*) newsock ) != 0)
{
// Log the error code description
logg("WARNING: Unable to open socket processing thread, error: %s", strerror(errno));
logg("WARNING: Unable to open socket processing thread: %s", strerror(errno));
}
}
return false;
@@ -557,6 +527,7 @@ void *socket_listening_thread(void *args)
bool ipv6_available(void)
{
struct ifaddrs *allInterfaces;
enum { IPv4, IPv6 };
int iface[2] = { 0 };
// Get all interfaces
@@ -572,7 +543,7 @@ bool ipv6_available(void)
// Check only for up and running IPv4, IPv6 interfaces
if ((flags & (IFF_UP|IFF_RUNNING)) && addr != NULL)
{
iface[addr->sa_family == AF_INET6 ? 1 : 0]++;
iface[addr->sa_family == AF_INET6 ? IPv6 : IPv4]++;
if(config.debug & DEBUG_NETWORKING)
logg("Interface %s is %s", interface->ifa_name, addr->sa_family == AF_INET6 ? "IPv6" : "IPv4");
@@ -583,8 +554,8 @@ bool ipv6_available(void)
if(config.debug & DEBUG_NETWORKING)
{
logg("Found %i IPv4 and %i IPv6 capable interfaces", iface[0], iface[1]);
logg("Found %i IPv4 and %i IPv6 capable interfaces", iface[IPv4], iface[IPv6]);
}
return (iface[1] > 0);
return (iface[IPv6] > 0);
}
+1 -1
View File
@@ -11,7 +11,7 @@
#define SOCKET_H
void close_telnet_socket(void);
void close_unix_socket(void);
void close_unix_socket(bool unlink_file);
void seom(const int sock);
void ssend(const int sock, const char *format, ...) __attribute__ ((format (gnu_printf, 2, 3)));
void swrite(const int sock, const void* value, const size_t size);
+1 -5
View File
@@ -29,7 +29,6 @@ FTLFileNamesStruct FTLfiles = {
NULL,
NULL,
NULL,
NULL,
NULL
};
@@ -301,9 +300,6 @@ void read_FTLconf(void)
// PIDFILE
getpath(fp, "PIDFILE", "/run/pihole-FTL.pid", &FTLfiles.pid);
// PORTFILE
getpath(fp, "PORTFILE", "/run/pihole-FTL.port", &FTLfiles.port);
// SOCKETFILE
getpath(fp, "SOCKETFILE", "/run/pihole/FTL.sock", &FTLfiles.socketfile);
@@ -512,7 +508,7 @@ void get_privacy_level(FILE *fp)
{
// Check for change and validity of privacy level (set in FTL.h)
if(value >= PRIVACY_SHOW_ALL &&
value <= PRIVACY_NOSTATS &&
value <= PRIVACY_MAXIMUM &&
value > config.privacylevel)
{
logg("Notice: Increasing privacy level from %i to %i", config.privacylevel, value);
+5 -22
View File
@@ -10,6 +10,9 @@
#ifndef CONFIG_H
#define CONFIG_H
// enum privacy_level
#include "enums.h"
// typedef int16_t
#include <sys/types.h>
@@ -27,8 +30,8 @@ typedef struct {
int dns_port;
unsigned int delay_startup;
int16_t debug;
unsigned char privacylevel;
unsigned char blockingmode;
enum privacy_level privacylevel;
enum blocking_mode blockingmode;
bool socket_listenlocal;
bool analyze_AAAA;
bool resolveIPv6;
@@ -47,7 +50,6 @@ typedef struct {
const char* snapConf;
char* log;
char* pid;
char* port;
char* socketfile;
char* FTL_db;
char* gravity_db;
@@ -59,23 +61,4 @@ typedef struct {
extern ConfigStruct config;
extern FTLFileNamesStruct FTLfiles;
enum {
DEBUG_DATABASE = (1 << 0), /* 00000000 00000001 */
DEBUG_NETWORKING = (1 << 1), /* 00000000 00000010 */
DEBUG_LOCKS = (1 << 2), /* 00000000 00000100 */
DEBUG_QUERIES = (1 << 3), /* 00000000 00001000 */
DEBUG_FLAGS = (1 << 4), /* 00000000 00010000 */
DEBUG_SHMEM = (1 << 5), /* 00000000 00100000 */
DEBUG_GC = (1 << 6), /* 00000000 01000000 */
DEBUG_ARP = (1 << 7), /* 00000000 10000000 */
DEBUG_REGEX = (1 << 8), /* 00000001 00000000 */
DEBUG_API = (1 << 9), /* 00000010 00000000 */
DEBUG_OVERTIME = (1 << 10), /* 00000100 00000000 */
DEBUG_EXTBLOCKED = (1 << 11), /* 00001000 00000000 */
DEBUG_CAPS = (1 << 12), /* 00010000 00000000 */
DEBUG_DNSMASQ_LINES = (1 << 13), /* 00100000 00000000 */
DEBUG_VECTORS = (1 << 14), /* 01000000 00000000 */
DEBUG_RESOLVER = (1 << 15), /* 10000000 00000000 */
};
#endif //CONFIG_H
+16
View File
@@ -141,3 +141,19 @@ void delay_startup(void)
sleep(config.delay_startup);
logg("Done sleeping, continuing startup of resolver...\n");
}
// Is this a fork?
bool __attribute__ ((const)) is_fork(const pid_t mpid, const pid_t pid)
{
return mpid > -1 && mpid != pid;
}
pid_t FTL_gettid(void)
{
#ifdef SYS_gettid
return (pid_t)syscall(SYS_gettid);
#else
#warning SYS_gettid is not available on this system
return -1;
#endif // SYS_gettid
}
+17
View File
@@ -15,5 +15,22 @@ void savepid(void);
char * getUserName(void);
void removepid(void);
void delay_startup(void);
bool is_fork(const pid_t mpid, const pid_t pid) __attribute__ ((const));
#include <sys/syscall.h>
#include <unistd.h>
// Get ID of current thread (incorrectly shown as "PID" in, e.g., htop)
// We define this wrapper ourselves as the GNU C Library only added it
// in 2019 meaning that, while we're writing this, it will not be widely
// available. It was only added even later (end of 2019) to musl libc.
// https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=1d0fc213824eaa2a8f8c4385daaa698ee8fb7c92
// https://www.openwall.com/lists/musl/2019/08/01/11
// To avoid any conflicts, also in the future, we use our own macro for this
#if !defined(SYS_gettid) && defined(__NR_gettid)
#define SYS_gettid __NR_gettid
#endif // !SYS_gettid && __NR_gettid
pid_t FTL_gettid(void);
#define gettid FTL_gettid
#endif //DAEMON_H
+3 -3
View File
@@ -377,7 +377,7 @@ void db_init(void)
logg("Database successfully initialized");
}
int db_get_FTL_property(const unsigned int ID)
int db_get_FTL_property(const enum ftl_table_props ID)
{
if(!database || FTL_db == NULL)
{
@@ -400,7 +400,7 @@ int db_get_FTL_property(const unsigned int ID)
return value;
}
bool db_set_FTL_property(const unsigned int ID, const int value)
bool db_set_FTL_property(const enum ftl_table_props ID, const int value)
{
if(!database || FTL_db == NULL)
{
@@ -410,7 +410,7 @@ bool db_set_FTL_property(const unsigned int ID, const int value)
return dbquery("INSERT OR REPLACE INTO ftl (id, value) VALUES ( %u, %i );", ID, value) == SQLITE_OK;
}
bool db_set_counter(const unsigned int ID, const int value)
bool db_set_counter(const enum counters_table_props ID, const int value)
{
if(!database || FTL_db == NULL)
{
+16 -8
View File
@@ -12,9 +12,22 @@
#include "sqlite3.h"
// Database table "ftl"
enum ftl_table_props {
DB_VERSION,
DB_LASTTIMESTAMP,
DB_FIRSTCOUNTERTIMESTAMP
} __attribute__ ((packed));
// Database table "counters"
enum counters_table_props {
DB_TOTALQUERIES,
DB_BLOCKEDQUERIES
} __attribute__ ((packed));
void db_init(void);
int db_get_FTL_property(const unsigned int ID);
bool db_set_FTL_property(const unsigned int ID, const int value);
int db_get_FTL_property(const enum ftl_table_props ID);
bool db_set_FTL_property(const enum ftl_table_props ID, const int value);
/// Execute a formatted SQL query and get the return code
int dbquery(const char *format, ...);
@@ -26,7 +39,7 @@ int db_query_int(const char*);
long get_lastID(void);
void SQLite3LogCallback(void *pArg, int iErrCode, const char *zMsg);
long int get_max_query_ID(void);
bool db_set_counter(const unsigned int ID, const int value);
bool db_set_counter(const enum counters_table_props ID, const int value);
bool db_update_counters(const int total, const int blocked);
const char *get_sqlite3_version(void);
bool use_database(void) __attribute__ ((pure));
@@ -59,9 +72,4 @@ extern bool DBdeleteoldqueries;
}\
}
// Database table "ftl"
enum { DB_VERSION, DB_LASTTIMESTAMP, DB_FIRSTCOUNTERTIMESTAMP };
// Database table "counters"
enum { DB_TOTALQUERIES, DB_BLOCKEDQUERIES };
#endif //DATABASE_COMMON_H
+31 -69
View File
@@ -34,39 +34,16 @@ static sqlite3 *gravity_db = NULL;
static sqlite3_stmt* table_stmt = NULL;
static sqlite3_stmt* auditlist_stmt = NULL;
bool gravityDB_opened = false;
static pid_t main_process = 0, this_process = 0;
// Table names corresponding to the enum defined in gravity-db.h
static const char* tablename[] = { "vw_gravity", "vw_blacklist", "vw_whitelist", "vw_regex_blacklist", "vw_regex_whitelist" , ""};
static const char* tablename[] = { "vw_gravity", "vw_blacklist", "vw_whitelist", "vw_regex_blacklist", "vw_regex_whitelist" , "" };
// Prototypes from functions in dnsmasq's source
void rehash(int size);
// Initialize gravity subroutines
static void gravityDB_check_fork(void)
void gravityDB_forked(void)
{
// Memorize main process PID on first call of this funtion (guaranteed to be
// the main dnsmasq thread)
if(main_process == 0)
{
main_process = getpid();
this_process = main_process;
}
if(this_process == getpid())
return;
// If we reach this point, FTL forked to handle TCP connections with
// dedicated (forked) workers SQLite3's mentions that carrying an open
// database connection across a fork() can lead to all kinds of locking
// problems as SQLite3 was not intended to work under such circumstances.
// Doing so may easily lead to ending up with a corrupted database.
logg("Note: FTL forked to handle TCP requests");
// Memorize PID of this thread to avoid re-opening the gravity database
// connection multiple times for the same fork
this_process = getpid();
// Pretend that we did not open the database so far so it needs to be
// re-opened, also pretend we have not yet prepared the list statements
gravityDB_opened = false;
@@ -546,9 +523,6 @@ void gravityDB_close(void)
// blocking domains from a table which is specified when calling this function
bool gravityDB_getTable(const unsigned char list)
{
// First check if FTL forked to handle TCP connections
gravityDB_check_fork();
if(!gravityDB_opened && !gravityDB_open())
{
logg("gravityDB_getTable(%u): Gravity database not available", list);
@@ -637,7 +611,7 @@ void gravityDB_finalizeTable(void)
// Get number of domains in a specified table of the gravity database
// We return the constant DB_FAILED and log to pihole-FTL.log if we
// encounter any error
int gravityDB_count(const unsigned char list)
int gravityDB_count(const enum gravity_tables list)
{
if(!gravityDB_opened && !gravityDB_open())
{
@@ -645,31 +619,37 @@ int gravityDB_count(const unsigned char list)
return DB_FAILED;
}
// Checking for smaller than GRAVITY_LIST is omitted due to list being unsigned
if(list >= UNKNOWN_TABLE)
const char *querystr = NULL;
// Build query string to be used depending on list to be read
switch (list)
{
logg("gravityDB_getTable(%u): Requested list is not known!", list);
return false;
}
char *querystr = NULL;
// Build correct query string to be used depending on list to be read
if(list != GRAVITY_TABLE && asprintf(&querystr, "SELECT COUNT(DISTINCT domain) FROM %s", tablename[list]) < 18)
{
logg("readGravity(%u) - asprintf() error", list);
return false;
}
// We get the number of unique gravity domains as counted and stored by gravity. Counting the number
// of distinct domains in vw_gravity may take up to several minutes for very large blocking lists on
// very low-end devices such as the Raspierry Pi Zero
else if(list == GRAVITY_TABLE && asprintf(&querystr, "SELECT value FROM info WHERE property = 'gravity_count';") < 18)
{
logg("readGravity(%u) - asprintf() error", list);
return false;
case GRAVITY_TABLE:
// We get the number of unique gravity domains as counted and stored by gravity. Counting the number
// of distinct domains in vw_gravity may take up to several minutes for very large blocking lists on
// very low-end devices such as the Raspierry Pi Zero
querystr = "SELECT value FROM info WHERE property = 'gravity_count';";
break;
case EXACT_BLACKLIST_TABLE:
querystr = "SELECT COUNT(DISTINCT domain) FROM vw_blacklist";
break;
case EXACT_WHITELIST_TABLE:
querystr = "SELECT COUNT(DISTINCT domain) FROM vw_whitelist";
break;
case REGEX_BLACKLIST_TABLE:
querystr = "SELECT COUNT(DISTINCT domain) FROM vw_regex_blacklist";
break;
case REGEX_WHITELIST_TABLE:
querystr = "SELECT COUNT(DISTINCT domain) FROM vw_regex_whitelist";
break;
case UNKNOWN_TABLE:
logg("Error: List type %u unknown!", list);
gravityDB_close();
return DB_FAILED;
}
if(config.debug & DEBUG_DATABASE)
logg("Querying count of distinct domains in gravity database table %s", tablename[list]);
logg("Querying count of distinct domains in gravity database table %s: %s",
tablename[list], querystr);
// Prepare query
int rc = sqlite3_prepare_v2(gravity_db, querystr, -1, &table_stmt, NULL);
@@ -677,7 +657,6 @@ int gravityDB_count(const unsigned char list)
logg("gravityDB_count(%s) - SQL error prepare %s", querystr, sqlite3_errstr(rc));
gravityDB_finalizeTable();
gravityDB_close();
free(querystr);
return DB_FAILED;
}
@@ -691,7 +670,6 @@ int gravityDB_count(const unsigned char list)
}
gravityDB_finalizeTable();
gravityDB_close();
free(querystr);
return DB_FAILED;
}
@@ -701,8 +679,7 @@ int gravityDB_count(const unsigned char list)
// Finalize statement
gravityDB_finalizeTable();
// Free allocated memory and return result
free(querystr);
// Return result
return result;
}
@@ -777,9 +754,6 @@ static bool domain_in_list(const char *domain, sqlite3_stmt* stmt, const char* l
bool in_whitelist(const char *domain, const int clientID, clientsData* client)
{
// First check if FTL forked to handle TCP connections
gravityDB_check_fork();
// 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
if(whitelist_stmt == NULL)
@@ -814,9 +788,6 @@ bool in_whitelist(const char *domain, const int clientID, clientsData* client)
bool in_gravity(const char *domain, const int clientID, clientsData* client)
{
// First check if FTL forked to handle TCP connections
gravityDB_check_fork();
// 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
if(gravity_stmt == NULL)
@@ -844,9 +815,6 @@ bool in_gravity(const char *domain, const int clientID, clientsData* client)
inline bool in_blacklist(const char *domain, const int clientID, clientsData* client)
{
// First check if FTL forked to handle TCP connections
gravityDB_check_fork();
// 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
if(blacklist_stmt == NULL)
@@ -874,9 +842,6 @@ inline bool in_blacklist(const char *domain, const int clientID, clientsData* cl
bool in_auditlist(const char *domain)
{
// First check if FTL forked to handle TCP connections
gravityDB_check_fork();
// If audit list statement is not ready and cannot be initialized (e.g. no access
// to the database), we return false (not in audit list) to prevent an FTL crash
if(auditlist_stmt == NULL)
@@ -889,9 +854,6 @@ bool in_auditlist(const char *domain)
bool gravityDB_get_regex_client_groups(clientsData* client, const int numregex, const int *regexid,
const unsigned char type, const char* table, const int clientID)
{
// First check if FTL forked to handle TCP connections
gravityDB_check_fork();
char *querystr = NULL;
if(!client->found_group && !get_client_groupids(client))
return false;
+3 -2
View File
@@ -16,8 +16,9 @@
#include "datastructure.h"
// Table indices
enum { GRAVITY_TABLE, EXACT_BLACKLIST_TABLE, EXACT_WHITELIST_TABLE, REGEX_BLACKLIST_TABLE, REGEX_WHITELIST_TABLE, UNKNOWN_TABLE };
enum gravity_tables { GRAVITY_TABLE, EXACT_BLACKLIST_TABLE, EXACT_WHITELIST_TABLE, REGEX_BLACKLIST_TABLE, REGEX_WHITELIST_TABLE, UNKNOWN_TABLE } __attribute__ ((packed));
void gravityDB_forked(void);
bool gravityDB_open(void);
bool gravityDB_prepare_client_statements(const int clientID, clientsData* client);
void gravityDB_close(void);
@@ -25,7 +26,7 @@ bool gravityDB_getTable(unsigned char list);
const char* gravityDB_getDomain(int *rowid);
char* get_group_names(const char *group_ids) __attribute__ ((malloc));
void gravityDB_finalizeTable(void);
int gravityDB_count(unsigned char list);
int gravityDB_count(const enum gravity_tables list);
bool in_auditlist(const char *domain);
bool in_gravity(const char *domain, const int clientID, clientsData* client);
-8
View File
@@ -46,10 +46,6 @@ int get_number_of_queries_in_DB(void)
void DB_save_queries(void)
{
// Don't save anything to the database if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Start database timer
if(config.debug & DEBUG_DATABASE)
timer_start(DATABASE_WRITE_TIMER);
@@ -296,10 +292,6 @@ void delete_old_queries_in_DB(void)
// Get most recent 24 hours data from long-term database
void DB_read_queries(void)
{
// Don't try to load anything to the database if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Open database file
if(!dbopen())
{
+9 -9
View File
@@ -13,6 +13,9 @@
// Definition of sqlite3_stmt
#include "database/sqlite3.h"
// enum privacy_level
#include "enums.h"
void strtolower(char *str);
int findUpstreamID(const char * upstream, const bool count);
int findDomainID(const char *domain, const bool count);
@@ -24,16 +27,13 @@ bool isValidIPv6(const char *addr);
void FTL_reload_all_domainlists(void);
void FTL_reset_per_client_domain_data(void);
enum { TYPE_A = 1, TYPE_AAAA, TYPE_ANY, TYPE_SRV, TYPE_SOA, TYPE_PTR, TYPE_TXT, TYPE_NAPTR,
TYPE_MX, TYPE_DS, TYPE_RRSIG, TYPE_DNSKEY, TYPE_OTHER, TYPE_MAX };
typedef struct {
unsigned char magic;
unsigned char status;
unsigned char type;
unsigned char privacylevel;
unsigned char reply;
unsigned char dnssec;
enum query_status status;
enum query_types type;
enum privacy_level privacylevel;
enum reply_type reply;
enum dnssec_status dnssec;
time_t timestamp;
int domainID;
int clientID;
@@ -79,7 +79,7 @@ typedef struct {
typedef struct {
unsigned char magic;
unsigned char blocking_status;
enum domain_client_status blocking_status;
unsigned char force_reply;
int domainID;
int clientID;
+9 -5
View File
@@ -1249,7 +1249,7 @@ static void sig_handler(int sig)
{
/*** Pi-hole modification ***/
// TCP workers ignore all signals except SIGALRM
FTL_TCP_worker_terminating();
FTL_TCP_worker_terminating(false);
/*** Pi-hole modification ***/
_exit(0);
}
@@ -1957,8 +1957,16 @@ static void check_dns_listeners(time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
/******* Pi-hole modification *******/
FTL_TCP_worker_created();
/************************************/
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
/******* Pi-hole modification *******/
FTL_TCP_worker_terminating(true);
/************************************/
shutdown(confd, SHUT_RDWR);
close(confd);
@@ -1974,10 +1982,6 @@ static void check_dns_listeners(time_t now)
if (!option_bool(OPT_DEBUG))
{
/*** Pi-hole modification ***/
// TCP workers ignore all signals except SIGALRM
FTL_TCP_worker_terminating();
/****************************/
close(daemon->pipe_to_parent);
flush_log();
_exit(0);
+49 -50
View File
@@ -12,6 +12,7 @@
#include "dnsmasq/dnsmasq.h"
#undef __USE_XOPEN
#include "FTL.h"
#include "enums.h"
#include "dnsmasq_interface.h"
#include "shmem.h"
#include "overTime.h"
@@ -302,10 +303,6 @@ static bool _FTL_check_blocking(int queryID, int domainID, int clientID, const c
bool _FTL_CNAME(const char *domain, const struct crec *cpp, const int id, const char* file, const int line)
{
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return false;
// Does the user want to skip deep CNAME inspection?
if(!config.cname_inspection)
{
@@ -423,10 +420,6 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
{
// Create new query in data structure
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return false;
// Get timestamp
const time_t querytimestamp = time(NULL);
@@ -692,10 +685,6 @@ void _FTL_forwarded(const unsigned int flags, const char *name, const union all_
{
// Save that this query got forwarded to an upstream server
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Lock shared memory
lock_shm();
@@ -810,7 +799,6 @@ void FTL_dnsmasq_reload(void)
{
// This function is called by the dnsmasq code on receive of SIGHUP
// *before* clearing the cache and rereading the lists
// This is the only hook that is not skipped in PRIVACY_NOSTATS mode
logg("Reloading DNS cache");
@@ -844,10 +832,6 @@ void FTL_dnsmasq_reload(void)
void _FTL_reply(const unsigned short flags, const char *name, const union all_addr *addr, const int id,
const char* file, const int line)
{
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Lock shared memory
lock_shm();
@@ -968,9 +952,9 @@ void _FTL_reply(const unsigned short flags, const char *name, const union all_ad
{
// Only proceed if query is not already known
// to have been blocked by Quad9
if(query->reply != QUERY_EXTERNAL_BLOCKED_IP &&
query->reply != QUERY_EXTERNAL_BLOCKED_NULL &&
query->reply != QUERY_EXTERNAL_BLOCKED_NXRA)
if(query->status != QUERY_EXTERNAL_BLOCKED_IP &&
query->status != QUERY_EXTERNAL_BLOCKED_NULL &&
query->status != QUERY_EXTERNAL_BLOCKED_NXRA)
{
// Save reply type and update individual reply counters
save_reply_type(flags, addr, query, response);
@@ -1129,7 +1113,7 @@ static void detect_blocked_IP(const unsigned short flags, const union all_addr *
}
}
static void query_externally_blocked(const int queryID, const unsigned char status)
static void query_externally_blocked(const int queryID, const enum query_status status)
{
// Get query pointer
queriesData* query = getQuery(queryID, true);
@@ -1172,10 +1156,6 @@ void _FTL_cache(const unsigned int flags, const char *name, const union all_addr
{
// Save that this query got answered from cache
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// If domain is "pi.hole", we skip this query
// We compare case-insensitive here
if(strcasecmp(name, "pi.hole") == 0)
@@ -1339,10 +1319,6 @@ void _FTL_dnssec(const int status, const int id, const char* file, const int lin
{
// Process DNSSEC result for a domain
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Lock shared memory
lock_shm();
@@ -1393,10 +1369,6 @@ void _FTL_upstream_error(const unsigned int rcode, const int id, const char* fil
// Queries with error are those where the RCODE
// in the DNS header is neither NOERROR nor NXDOMAIN.
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Lock shared memory
lock_shm();
@@ -1469,10 +1441,6 @@ void _FTL_header_analysis(const unsigned char header4, const unsigned int rcode,
{
// Analyze DNS header bits
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Check if RA bit is unset in DNS header and rcode is NXDOMAIN
// If the response code (rcode) is NXDOMAIN, we may be seeing a response from
// an externally blocked query. As they are not always accompany a necessary
@@ -1649,18 +1617,15 @@ void FTL_fork_and_bind_sockets(struct passwd *ent_pw)
// join with the terminated thread
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// Bind to sockets
bind_sockets();
// Start TELNET IPv4 thread
if(ipv4telnet && pthread_create( &telnet_listenthreadv4, &attr, telnet_listening_thread_IPv4, NULL ) != 0)
if(pthread_create( &telnet_listenthreadv4, &attr, telnet_listening_thread_IPv4, NULL ) != 0)
{
logg("Unable to open IPv4 telnet listening thread. Exiting...");
exit(EXIT_FAILURE);
}
// Start TELNET IPv6 thread
if(ipv6telnet && pthread_create( &telnet_listenthreadv6, &attr, telnet_listening_thread_IPv6, NULL ) != 0)
if(pthread_create( &telnet_listenthreadv6, &attr, telnet_listening_thread_IPv6, NULL ) != 0)
{
logg("Unable to open IPv6 telnet listening thread. Exiting...");
exit(EXIT_FAILURE);
@@ -1735,10 +1700,6 @@ void _FTL_forwarding_failed(const struct server *server, const char* file, const
{
// Forwarding to upstream server failed
// Don't analyze anything if in PRIVACY_NOSTATS mode
if(config.privacylevel >= PRIVACY_NOSTATS)
return;
// Lock shared memory
lock_shm();
@@ -1824,14 +1785,52 @@ static void prepare_blocking_metadata(void)
// Called when a (forked) TCP worker is terminated by receiving SIGALRM
// We close the dedicated database connection this client had opened
// to avoid dangling database locks
void FTL_TCP_worker_terminating(void)
void FTL_TCP_worker_terminating(bool finished)
{
if(config.debug & DEBUG_DATABASE)
if(config.debug != 0)
{
logg("TCP worker terminating, "
"closing gravity database connection");
const char *reason = finished ? "client disconnected" : "timeout";
logg("TCP worker terminating (%s)", reason);
}
if(main_pid() == getpid())
{
// If this is not really a fork (e.g. in debug mode), we don't
// actually close gravity here
return;
}
// Close dedicated database connection of this fork
gravityDB_close();
}
// Called when a (forked) TCP worker is created
// FTL forked to handle TCP connections with dedicated (forked) workers
// SQLite3's mentions that carrying an open database connection across a
// fork() can lead to all kinds of locking problems as SQLite3 was not
// intended to work under such circumstances. Doing so may easily lead
// to ending up with a corrupted database.
void FTL_TCP_worker_created(void)
{
if(config.debug != 0)
{
// Print this if any debug setting is enabled
logg("TCP worker forked");
}
if(main_pid() == getpid())
{
// If this is not really a fork (e.g. in debug mode), we don't
// actually re-open gravity or close sockets here
return;
}
// Reopen gravity database handle in this fork as the main process's
// handle isn't valid here
gravityDB_forked();
// Children inherit file descriptors from their parents
// We don't need them in the forks, so we clean them up
close_telnet_socket();
close_unix_socket(false);
}
+2 -1
View File
@@ -51,7 +51,8 @@ bool _FTL_CNAME(const char *domain, const struct crec *cpp, const int id, const
void FTL_dnsmasq_reload(void);
void FTL_fork_and_bind_sockets(struct passwd *ent_pw);
void FTL_TCP_worker_terminating(void);
void FTL_TCP_worker_created(void);
void FTL_TCP_worker_terminating(bool finished);
void set_debug_dnsmasq_lines(char enabled);
extern char debug_dnsmasq_lines;
+132
View File
@@ -0,0 +1,132 @@
/* Pi-hole: A black hole for Internet advertisements
* (c) 2020 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* FTL Engine
* Global enums
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
#ifndef ENUMS_H
#define ENUMS_H
enum memory_type {
QUERIES,
UPSTREAMS,
CLIENTS,
DOMAINS,
OVERTIME,
DNS_CACHE
} __attribute__ ((packed));
enum dnssec_status {
DNSSEC_UNSPECIFIED,
DNSSEC_SECURE,
DNSSEC_INSECURE,
DNSSEC_BOGUS,
DNSSEC_ABANDONED
} __attribute__ ((packed));
enum query_status {
QUERY_UNKNOWN,
QUERY_GRAVITY,
QUERY_FORWARDED,
QUERY_CACHE,
QUERY_REGEX,
QUERY_BLACKLIST,
QUERY_EXTERNAL_BLOCKED_IP,
QUERY_EXTERNAL_BLOCKED_NULL,
QUERY_EXTERNAL_BLOCKED_NXRA,
QUERY_GRAVITY_CNAME,
QUERY_REGEX_CNAME,
QUERY_BLACKLIST_CNAME,
QUERY_STATUS_MAX
} __attribute__ ((packed));
enum reply_type {
REPLY_UNKNOWN,
REPLY_NODATA,
REPLY_NXDOMAIN,
REPLY_CNAME,
REPLY_IP,
REPLY_DOMAIN,
REPLY_RRNAME,
REPLY_SERVFAIL,
REPLY_REFUSED,
REPLY_NOTIMP,
REPLY_OTHER
} __attribute__ ((packed));
enum privacy_level {
PRIVACY_SHOW_ALL = 0,
PRIVACY_HIDE_DOMAINS,
PRIVACY_HIDE_DOMAINS_CLIENTS,
PRIVACY_MAXIMUM
} __attribute__ ((packed));
enum blocking_mode {
MODE_IP,
MODE_NX,
MODE_NULL,
MODE_IP_NODATA_AAAA,
MODE_NODATA
} __attribute__ ((packed));
enum regex_id {
REGEX_BLACKLIST,
REGEX_WHITELIST
} __attribute__ ((packed));
enum query_types {
TYPE_A = 1,
TYPE_AAAA,
TYPE_ANY,
TYPE_SRV,
TYPE_SOA,
TYPE_PTR,
TYPE_TXT,
TYPE_NAPTR,
TYPE_MX,
TYPE_DS,
TYPE_RRSIG,
TYPE_DNSKEY,
TYPE_OTHER,
TYPE_MAX
} __attribute__ ((packed));
enum blocking_status {
BLOCKING_DISABLED,
BLOCKING_ENABLED,
BLOCKING_UNKNOWN
} __attribute__ ((packed));
// Blocking status constants used by the dns_cache->blocking_status vector
enum domain_client_status {
UNKNOWN_BLOCKED = 0,
GRAVITY_BLOCKED,
BLACKLIST_BLOCKED,
REGEX_BLOCKED,
WHITELISTED,
NOT_BLOCKED
} __attribute__ ((packed));
enum debug_mode {
DEBUG_DATABASE = (1 << 0), /* 00000000 00000001 */
DEBUG_NETWORKING = (1 << 1), /* 00000000 00000010 */
DEBUG_LOCKS = (1 << 2), /* 00000000 00000100 */
DEBUG_QUERIES = (1 << 3), /* 00000000 00001000 */
DEBUG_FLAGS = (1 << 4), /* 00000000 00010000 */
DEBUG_SHMEM = (1 << 5), /* 00000000 00100000 */
DEBUG_GC = (1 << 6), /* 00000000 01000000 */
DEBUG_ARP = (1 << 7), /* 00000000 10000000 */
DEBUG_REGEX = (1 << 8), /* 00000001 00000000 */
DEBUG_API = (1 << 9), /* 00000010 00000000 */
DEBUG_OVERTIME = (1 << 10), /* 00000100 00000000 */
DEBUG_EXTBLOCKED = (1 << 11), /* 00001000 00000000 */
DEBUG_CAPS = (1 << 12), /* 00010000 00000000 */
DEBUG_DNSMASQ_LINES = (1 << 13), /* 00100000 00000000 */
DEBUG_VECTORS = (1 << 14), /* 01000000 00000000 */
DEBUG_RESOLVER = (1 << 15), /* 10000000 00000000 */
} __attribute__ ((packed));
#endif // ENUMS_H
+19 -12
View File
@@ -129,6 +129,7 @@ void *GC_thread(void *val)
if(client != NULL)
client->blockedcount--;
break;
case QUERY_STATUS_MAX: // fall through
default:
/* That cannot happen */
break;
@@ -138,27 +139,33 @@ void *GC_thread(void *val)
switch(query->reply)
{
case REPLY_NODATA: // NODATA(-IPv6)
counters->reply_NODATA--;
break;
counters->reply_NODATA--;
break;
case REPLY_NXDOMAIN: // NXDOMAIN
counters->reply_NXDOMAIN--;
break;
counters->reply_NXDOMAIN--;
break;
case REPLY_CNAME: // <CNAME>
counters->reply_CNAME--;
break;
counters->reply_CNAME--;
break;
case REPLY_IP: // valid IP
counters->reply_IP--;
break;
counters->reply_IP--;
break;
case REPLY_DOMAIN: // reverse lookup
counters->reply_domain--;
break;
counters->reply_domain--;
break;
default: // Incomplete query or TXT, do nothing
break;
case REPLY_RRNAME: // fall through
case REPLY_SERVFAIL: // fall through
case REPLY_REFUSED: // fall through
case REPLY_NOTIMP: // fall through
case REPLY_OTHER: // fall through
case REPLY_UNKNOWN: // fall through
default:
break;
}
// Update type counters
+25 -3
View File
@@ -11,6 +11,7 @@
#include "FTL.h"
#include "version.h"
#include "memory.h"
// is_fork()
#include "daemon.h"
#include "config.h"
#include "log.h"
@@ -20,6 +21,8 @@
#include "args.h"
// global counters variable
#include "shmem.h"
// main_pid()
#include "signals.h"
static pthread_mutex_t lock;
static FILE *logfile = NULL;
@@ -83,12 +86,31 @@ void __attribute__ ((format (gnu_printf, 1, 2))) logg(const char *format, ...)
// Get and log PID of current process to avoid ambiguities when more than one
// pihole-FTL instance is logging into the same file
const long pid = (long)getpid();
char idstr[42];
const int pid = getpid(); // Get the process ID of the calling process
const int mpid = main_pid(); // Get the process ID of the main FTL process
const int tid = gettid(); // Get the thread ID of the callig process
// There are four cases we have to differentiate here:
if(pid == tid)
if(is_fork(mpid, pid))
// Fork of the main process
snprintf(idstr, sizeof(idstr)-1, "%i/F%i", pid, mpid);
else
// Main process
snprintf(idstr, sizeof(idstr)-1, "%iM", pid);
else
if(is_fork(mpid, pid))
// Thread of a fork of the main process
snprintf(idstr, sizeof(idstr)-1, "%i/F%i/T%i", pid, mpid, tid);
else
// Thread of the main process
snprintf(idstr, sizeof(idstr)-1, "%i/T%i", pid, tid);
// Print to stdout before writing to file
if(!daemonmode)
{
printf("[%s %ld] ", timestring, pid);
printf("[%s %s] ", timestring, idstr);
va_start(args, format);
vprintf(format, args);
va_end(args);
@@ -101,7 +123,7 @@ void __attribute__ ((format (gnu_printf, 1, 2))) logg(const char *format, ...)
// Write to log file
if(logfile != NULL)
{
fprintf(logfile, "[%s %ld] ", timestring, pid);
fprintf(logfile, "[%s %s] ", timestring, idstr);
va_start(args, format);
vfprintf(logfile, format, args);
va_end(args);
+2 -2
View File
@@ -108,9 +108,9 @@ int main (int argc, char* argv[])
logg("Finished final database update");
}
// Close sockets
// Close sockets and delete Unix socket file handle
close_telnet_socket();
close_unix_socket();
close_unix_socket(true);
// Close gravity database connection
gravityDB_close();
+2 -1
View File
@@ -10,7 +10,8 @@
#ifndef MEMORY_H
#define MEMORY_H
void memory_check(const int which);
#include "enums.h"
char *FTLstrdup(const char *src, const char *file, const char *function, const int line) __attribute__((malloc));
void *FTLcalloc(size_t nmemb, size_t size, const char *file, const char *function, const int line) __attribute__((malloc)) __attribute__((alloc_size(1,2)));
void *FTLrealloc(void *ptr_in, size_t size, const char *file, const char *function, const int line) __attribute__((alloc_size(2)));
+4 -4
View File
@@ -194,10 +194,10 @@ void allocate_regex_client_enabled(clientsData *client, const int clientID)
}
}
static void read_regex_table(const unsigned char regexid)
static void read_regex_table(const enum regex_id regexid)
{
// Get table ID
unsigned char tableID = (regexid == REGEX_BLACKLIST) ? REGEX_BLACKLIST_TABLE : REGEX_WHITELIST_TABLE;
const enum gravity_tables tableID = (regexid == REGEX_BLACKLIST) ? REGEX_BLACKLIST_TABLE : REGEX_WHITELIST_TABLE;
// Get number of lines in the regex table
counters->num_regex[regexid] = gravityDB_count(tableID);
@@ -293,7 +293,7 @@ void read_regex_from_database(void)
}
// Print message to FTL's log after reloading regex filters
logg("Compiled %i whitelist and %i blacklist regex filters in %.1f msec",
logg("Compiled %i whitelist and %i blacklist regex filters for %i clients in %.1f msec",
counters->num_regex[REGEX_WHITELIST], counters->num_regex[REGEX_BLACKLIST],
timer_elapsed_msec(REGEX_TIMER));
counters->clients, timer_elapsed_msec(REGEX_TIMER));
}
-5
View File
@@ -19,9 +19,4 @@ int match_regex(const char *input, const int clientID, const unsigned char regex
void allocate_regex_client_enabled(clientsData *client, const int clientID);
void read_regex_from_database(void);
// Blocking status constants used by the domain->clientstatus vector
// We explicitly force UNKNOWN_BLOCKED to zero on all platforms as this is the
// default value set initially with calloc
enum { UNKNOWN_BLOCKED = 0, GRAVITY_BLOCKED, BLACKLIST_BLOCKED, REGEX_BLOCKED, WHITELISTED, NOT_BLOCKED };
#endif //REGEX_H
+1 -1
View File
@@ -232,7 +232,7 @@ bool __attribute__((pure)) getSetupVarsBool(const char * input)
}
// Global variable showing current blocking status
unsigned char blockingstatus = BLOCKING_UNKNOWN;
enum blocking_status blockingstatus = BLOCKING_UNKNOWN;
void check_blocking_status(void)
{
-2
View File
@@ -22,6 +22,4 @@ void check_blocking_status(void);
extern unsigned char blockingstatus;
enum { BLOCKING_DISABLED, BLOCKING_ENABLED, BLOCKING_UNKNOWN };
#endif //SETUPVARS_H
+8 -7
View File
@@ -608,7 +608,7 @@ static size_t get_optimal_object_size(const size_t objsize, const size_t minsize
}
}
void memory_check(int which)
void memory_check(const enum memory_type which)
{
switch(which)
{
@@ -623,7 +623,7 @@ void memory_check(int which)
exit(EXIT_FAILURE);
}
}
break;
break;
case UPSTREAMS:
if(counters->upstreams >= counters->upstreams_MAX-1)
{
@@ -635,7 +635,7 @@ void memory_check(int which)
exit(EXIT_FAILURE);
}
}
break;
break;
case CLIENTS:
if(counters->clients >= counters->clients_MAX-1)
{
@@ -647,7 +647,7 @@ void memory_check(int which)
exit(EXIT_FAILURE);
}
}
break;
break;
case DOMAINS:
if(counters->domains >= counters->domains_MAX-1)
{
@@ -659,7 +659,7 @@ void memory_check(int which)
exit(EXIT_FAILURE);
}
}
break;
break;
case DNS_CACHE:
if(counters->dns_cache_size >= counters->dns_cache_MAX-1)
{
@@ -671,12 +671,13 @@ void memory_check(int which)
exit(EXIT_FAILURE);
}
}
break;
break;
case OVERTIME: // fall through
default:
/* That cannot happen */
logg("Fatal error in memory_check(%i)", which);
exit(EXIT_FAILURE);
break;
break;
}
}
+2
View File
@@ -114,4 +114,6 @@ void reset_per_client_regex(const int clientID);
bool get_per_client_regex(const int clientID, const int regexID);
void set_per_client_regex(const int clientID, const int regexID, const bool value);
void memory_check(const enum memory_type which);
#endif //SHARED_MEMORY_SERVER_H
+40 -12
View File
@@ -20,14 +20,24 @@
// FTL_reload_all_domainlists()
#include "datastructure.h"
#include "config.h"
// gettid()
#include "daemon.h"
#define BINARY_NAME "pihole-FTL"
volatile sig_atomic_t killed = 0;
static volatile pid_t pid = 0;
static volatile pid_t mpid = -1;
static time_t FTLstarttime = 0;
extern volatile int exit_code;
// Return the (null-terminated) name of the calling thread
// The name is stored in the buffer as well as returned for convenience
static char * __attribute__ ((nonnull (1))) getthread_name(char buffer[16])
{
prctl(PR_GET_NAME, buffer, 0, 0, 0);
return buffer;
}
#if defined(__GLIBC__)
static void print_addr2line(const char *symbol, const void *address, const int j, const void *offset)
{
@@ -57,8 +67,15 @@ static void print_addr2line(const char *symbol, const void *address, const int j
// Strip possible newline at the end of the addr2line output
if ((pos=strchr(linebuffer, '\n')) != NULL)
*pos = '\0';
logg("L[%04i]: %s", j, linebuffer);
}
else
{
snprintf(linebuffer, sizeof(linebuffer), "N/A (%p)", addr);
}
// Log result
logg("L[%04i]: %s", j, linebuffer);
// Close pipe
pclose(addr2line);
}
#endif
@@ -76,17 +93,22 @@ static void __attribute__((noreturn)) SIGSEGV_handler(int sig, siginfo_t *si, vo
logg("FTL has been running for %li seconds", time(NULL)-FTLstarttime);
}
log_FTL_version(true);
char namebuf[16];
logg("Process details: MID: %i",mpid);
logg(" PID: %i", getpid());
logg(" TID: %i", gettid());
logg(" Name: %s", getthread_name(namebuf));
logg("Received signal: %s", strsignal(sig));
logg(" at address: %p", si->si_addr);
switch (si->si_code)
{
case SEGV_MAPERR: logg(" with code: SEGV_MAPERR (Address not mapped to object)"); break;
case SEGV_ACCERR: logg(" with code: SEGV_ACCERR (Invalid permissions for mapped object)"); break;
case SEGV_MAPERR: logg(" with code: SEGV_MAPERR (Address not mapped to object)"); break;
case SEGV_ACCERR: logg(" with code: SEGV_ACCERR (Invalid permissions for mapped object)"); break;
#if defined(SEGV_BNDERR)
case SEGV_BNDERR: logg(" with code: SEGV_BNDERR (Failed address bound checks)"); break;
case SEGV_BNDERR: logg(" with code: SEGV_BNDERR (Failed address bound checks)"); break;
#endif
default: logg(" with code: Unknown (%i)", si->si_code); break;
default: logg(" with code: Unknown (%i)", si->si_code); break;
}
// Check GLIBC availability as MUSL does not support live backtrace generation
@@ -114,7 +136,7 @@ static void __attribute__((noreturn)) SIGSEGV_handler(int sig, siginfo_t *si, vo
for(int j = 0; j < calls; j++)
{
logg("B[%04i]: %p, %s", j, buffer[j],
logg("B[%04i]: %s", j,
bcktrace != NULL ? bcktrace[j] : "---");
if(bcktrace != NULL)
@@ -132,11 +154,11 @@ static void __attribute__((noreturn)) SIGSEGV_handler(int sig, siginfo_t *si, vo
logg("Thank you for helping us to improve our FTL engine!");
// Terminate main process if crash happened in a TCP worker
if(pid != getpid())
if(mpid != getpid())
{
// This is a forked process
logg("Asking parent pihole-FTL (PID %i) to shut down", (int)pid);
kill(pid, SIGRTMIN+2);
logg("Asking parent pihole-FTL (PID %i) to shut down", (int)mpid);
kill(mpid, SIGRTMIN+2);
logg("FTL fork terminated!");
}
else
@@ -152,7 +174,7 @@ static void __attribute__((noreturn)) SIGSEGV_handler(int sig, siginfo_t *si, vo
static void SIGRT_handler(int signum, siginfo_t *si, void *unused)
{
// Ignore real-time signals outside of the main process (TCP forks)
if(pid != getpid())
if(mpid != getpid())
return;
int rtsig = signum - SIGRTMIN;
@@ -207,7 +229,7 @@ void handle_realtime_signals(void)
{
// This function is only called once (after forking), store the PID of
// the main process
pid = getpid();
mpid = getpid();
// Catch first five real-time signals
for(unsigned int i = 0; i < 5; i++)
@@ -220,3 +242,9 @@ void handle_realtime_signals(void)
sigaction(SIGRTMIN + i, &SIGACTION, NULL);
}
}
// Return PID of the main FTL process
pid_t main_pid(void)
{
return mpid;
}
+1
View File
@@ -12,6 +12,7 @@
void handle_SIGSEGV(void);
void handle_realtime_signals(void);
pid_t main_pid(void);
extern volatile sig_atomic_t killed;
+2 -2
View File
@@ -15,7 +15,7 @@
struct timeval t0[NUMTIMERS];
void timer_start(const int i)
void timer_start(enum timers i)
{
if(i >= NUMTIMERS)
{
@@ -25,7 +25,7 @@ void timer_start(const int i)
gettimeofday(&t0[i], 0);
}
double timer_elapsed_msec(const int i)
double timer_elapsed_msec(enum timers i)
{
if(i >= NUMTIMERS)
{
+11 -3
View File
@@ -11,12 +11,20 @@
#define TIMERS_H
// Timer enumeration
enum { DATABASE_WRITE_TIMER, EXIT_TIMER, GC_TIMER, LISTS_TIMER, REGEX_TIMER, ARP_TIMER, LAST_TIMER };
enum timers {
DATABASE_WRITE_TIMER,
EXIT_TIMER,
GC_TIMER,
LISTS_TIMER,
REGEX_TIMER,
ARP_TIMER,
LAST_TIMER
} __attribute__ ((packed));
#define NUMTIMERS LAST_TIMER
void timer_start(const int i);
double timer_elapsed_msec(const int i);
void timer_start(const enum timers i);
double timer_elapsed_msec(const enum timers i);
void sleepms(const int milliseconds);
#endif //TIMERS_H