mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
+1
-1
@@ -11,6 +11,6 @@
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(PIHOLE_FTL C)
|
||||
|
||||
set(DNSMASQ_VERSION pi-hole-2.81)
|
||||
set(DNSMASQ_VERSION pi-hole-2.82)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
+2
-2
@@ -131,8 +131,6 @@ set(sources
|
||||
log.h
|
||||
main.c
|
||||
main.h
|
||||
memory.c
|
||||
memory.h
|
||||
overTime.c
|
||||
overTime.h
|
||||
regex.c
|
||||
@@ -174,6 +172,7 @@ add_executable(pihole-FTL
|
||||
$<TARGET_OBJECTS:sqlite3>
|
||||
$<TARGET_OBJECTS:lua>
|
||||
$<TARGET_OBJECTS:tre-regex>
|
||||
$<TARGET_OBJECTS:syscalls>
|
||||
)
|
||||
if(STATIC STREQUAL "true")
|
||||
set_target_properties(pihole-FTL PROPERTIES LINK_SEARCH_START_STATIC ON)
|
||||
@@ -228,3 +227,4 @@ add_subdirectory(database)
|
||||
add_subdirectory(dnsmasq)
|
||||
add_subdirectory(lua)
|
||||
add_subdirectory(tre-regex)
|
||||
add_subdirectory(syscalls)
|
||||
|
||||
@@ -79,10 +79,6 @@
|
||||
// can be 24 hours + 59 minutes
|
||||
#define OVERTIME_SLOTS ((MAXLOGAGE+1)*3600/OVERTIME_INTERVAL)
|
||||
|
||||
// Interval for resolving NEW client and upstream server host names [seconds]
|
||||
// Default: 60 (once every minute)
|
||||
#define RESOLVE_INTERVAL 60
|
||||
|
||||
// Interval for re-resolving ALL known host names [seconds]
|
||||
// Default: 3600 (once every hour)
|
||||
#define RERESOLVE_INTERVAL 3600
|
||||
@@ -114,16 +110,35 @@
|
||||
// Important: This number has to be smaller than 256 for this mechanism to work
|
||||
#define NUM_RECHECKS 3
|
||||
|
||||
// Use out own memory handling functions that will detect possible errors
|
||||
// Use out own syscalls 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
|
||||
// with NULL pointers) much easier.
|
||||
#undef strdup // strdup() is a macro in itself, it needs special handling
|
||||
#define free(ptr) FTLfree(ptr, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define lib_strdup() strdup()
|
||||
#undef strdup
|
||||
#define strdup(str_in) FTLstrdup(str_in, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define calloc(numer_of_elements, element_size) FTLcalloc(numer_of_elements, element_size, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define realloc(ptr, new_size) FTLrealloc(ptr, new_size, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define printf(format, ...) FTLfprintf(stdout, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
|
||||
#define fprintf(stream, format, ...) FTLfprintf(stream, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__)
|
||||
#define vprintf(format, args) FTLvfprintf(stdout, __FILE__, __FUNCTION__, __LINE__, format, args)
|
||||
#define vfprintf(stream, format, args) FTLvfprintf(stream, __FILE__, __FUNCTION__, __LINE__, format, args)
|
||||
#define sprintf(buffer, format, ...) FTLsprintf(__FILE__, __FUNCTION__, __LINE__, buffer, format, ##__VA_ARGS__)
|
||||
#define vsprintf(buffer, format, args) FTLvsprintf(__FILE__, __FUNCTION__, __LINE__, buffer, format, args)
|
||||
#define asprintf(buffer, format, ...) FTLasprintf(__FILE__, __FUNCTION__, __LINE__, buffer, format, ##__VA_ARGS__)
|
||||
#define vasprintf(buffer, format, args) FTLvasprintf(__FILE__, __FUNCTION__, __LINE__, buffer, format, args)
|
||||
#define snprintf(buffer, maxlen, format, ...) FTLsnprintf(__FILE__, __FUNCTION__, __LINE__, buffer, maxlen, format, ##__VA_ARGS__)
|
||||
#define vsnprintf(buffer, maxlen, format, args) FTLvsnprintf(__FILE__, __FUNCTION__, __LINE__, buffer, maxlen, format, args)
|
||||
#define write(fd, buf, n) FTLwrite(fd, buf, n, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define accept(sockfd, addr, addrlen) FTLaccept(sockfd, addr, addrlen, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define recv(sockfd, buf, len, flags) FTLrecv(sockfd, buf, len, flags, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define recvfrom(sockfd, buf, len, flags, src_addr, addrlen) FTLrecvfrom(sockfd, buf, len, flags, src_addr, addrlen, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define sendto(sockfd, buf, len, flags, dest_addr, addrlen) FTLsendto(sockfd, buf, len, flags, dest_addr, addrlen, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define select(nfds, readfds, writefds, exceptfds, timeout) FTLselect(nfds, readfds, writefds, exceptfds, timeout, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define pthread_mutex_lock(mutex) FTLpthread_mutex_lock(mutex, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define fopen(pathname, mode) FTLfopen(pathname, mode, __FILE__, __FUNCTION__, __LINE__)
|
||||
#define ftlallocate(fd, offset, len) FTLfallocate(fd, offset, len, __FILE__, __FUNCTION__, __LINE__)
|
||||
#include "syscalls/syscalls.h"
|
||||
|
||||
// Preprocessor help functions
|
||||
#define str(x) # x
|
||||
|
||||
+11
-11
@@ -16,12 +16,12 @@
|
||||
void pack_eom(const int sock) {
|
||||
// This byte is explicitly never used in the MessagePack spec, so it is perfect to use as an EOM for this API.
|
||||
uint8_t eom = 0xc1;
|
||||
swrite(sock, &eom, sizeof(eom));
|
||||
write(sock, &eom, sizeof(eom));
|
||||
}
|
||||
|
||||
static void pack_basic(const int sock, const uint8_t format, const void *value, const size_t size) {
|
||||
swrite(sock, &format, sizeof(format));
|
||||
swrite(sock, value, size);
|
||||
write(sock, &format, sizeof(format));
|
||||
write(sock, value, size);
|
||||
}
|
||||
|
||||
static uint64_t __attribute__((const)) leToBe64(const uint64_t value) {
|
||||
@@ -42,7 +42,7 @@ static uint64_t __attribute__((const)) leToBe64(const uint64_t value) {
|
||||
|
||||
void pack_bool(const int sock, const bool value) {
|
||||
uint8_t packed = (uint8_t) (value ? 0xc3 : 0xc2);
|
||||
swrite(sock, &packed, sizeof(packed));
|
||||
write(sock, &packed, sizeof(packed));
|
||||
}
|
||||
|
||||
void pack_uint8(const int sock, const uint8_t value) {
|
||||
@@ -87,8 +87,8 @@ bool pack_fixstr(const int sock, const char *string) {
|
||||
}
|
||||
|
||||
const uint8_t format = (uint8_t) (0xA0 | length);
|
||||
swrite(sock, &format, sizeof(format));
|
||||
swrite(sock, string, length);
|
||||
write(sock, &format, sizeof(format));
|
||||
write(sock, string, length);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -104,17 +104,17 @@ bool pack_str32(const int sock, const char *string) {
|
||||
}
|
||||
|
||||
const uint8_t format = 0xdb;
|
||||
swrite(sock, &format, sizeof(format));
|
||||
write(sock, &format, sizeof(format));
|
||||
const uint32_t bigELength = htonl((uint32_t) length);
|
||||
swrite(sock, &bigELength, sizeof(bigELength));
|
||||
swrite(sock, string, length);
|
||||
write(sock, &bigELength, sizeof(bigELength));
|
||||
write(sock, string, length);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void pack_map16_start(const int sock, const uint16_t length) {
|
||||
const uint8_t format = 0xde;
|
||||
swrite(sock, &format, sizeof(format));
|
||||
write(sock, &format, sizeof(format));
|
||||
const uint16_t bigELength = htons(length);
|
||||
swrite(sock, &bigELength, sizeof(bigELength));
|
||||
write(sock, &bigELength, sizeof(bigELength));
|
||||
}
|
||||
|
||||
+10
-14
@@ -10,13 +10,12 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "api.h"
|
||||
#include "log.h"
|
||||
#include "../log.h"
|
||||
#include "socket.h"
|
||||
#include "request.h"
|
||||
#include "config.h"
|
||||
#include "memory.h"
|
||||
#include "../config.h"
|
||||
// global variable killed
|
||||
#include "signals.h"
|
||||
#include "../signals.h"
|
||||
|
||||
// The backlog argument defines the maximum length
|
||||
// to which the queue of pending connections for
|
||||
@@ -223,21 +222,15 @@ void __attribute__ ((format (gnu_printf, 2, 3))) ssend(const int sock, const cha
|
||||
char *buffer;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vasprintf(&buffer, format, args);
|
||||
int bytes = vasprintf(&buffer, format, args);
|
||||
va_end(args);
|
||||
if(ret > 0)
|
||||
if(bytes > 0 && buffer != NULL)
|
||||
{
|
||||
if(!write(sock, buffer, strlen(buffer)))
|
||||
logg("WARNING: Socket write returned error %s (%i)", strerror(errno), errno);
|
||||
write(sock, buffer, bytes);
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void swrite(const int sock, const void *value, size_t size) {
|
||||
if(write(sock, value, size) == -1)
|
||||
logg("WARNING: Socket write returned error code %i", errno);
|
||||
}
|
||||
|
||||
static inline int checkClientLimit(const int socket) {
|
||||
if(socket < MAXCONNS)
|
||||
{
|
||||
@@ -519,8 +512,11 @@ void *socket_listening_thread(void *args)
|
||||
|
||||
// Return early to avoid CPU spinning if Unix socket is not available
|
||||
sock_avail = bind_to_unix_socket(&socketfd);
|
||||
if(sock_avail)
|
||||
if(!sock_avail)
|
||||
{
|
||||
logg("INFO: Unix socket will not be available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Listen as long as FTL is not killed
|
||||
while(!killed)
|
||||
|
||||
@@ -15,7 +15,6 @@ void close_telnet_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);
|
||||
void *telnet_listening_thread_IPv4(void *args);
|
||||
void *telnet_listening_thread_IPv6(void *args);
|
||||
void *socket_listening_thread(void *args);
|
||||
|
||||
+29
-72
@@ -16,7 +16,6 @@
|
||||
#include "FTL.h"
|
||||
#include "args.h"
|
||||
#include "version.h"
|
||||
#include "memory.h"
|
||||
#include "main.h"
|
||||
#include "log.h"
|
||||
// global variable killed
|
||||
@@ -27,8 +26,6 @@
|
||||
#include "shmem.h"
|
||||
// LUA dependencies
|
||||
#include "lua/ftl_lua.h"
|
||||
#include <readline/history.h>
|
||||
#include <wordexp.h>
|
||||
// run_dhcp_discover()
|
||||
#include "dhcp-discover.h"
|
||||
// defined in dnsmasq.c
|
||||
@@ -58,11 +55,31 @@ void parse_args(int argc, char* argv[])
|
||||
if(strEndsWith(argv[0], "dnsmasq"))
|
||||
consume_for_dnsmasq = true;
|
||||
|
||||
if(strEndsWith(argv[0], "lua"))
|
||||
exit(run_lua_interpreter(argc, argv, false));
|
||||
|
||||
if(strEndsWith(argv[0], "luac"))
|
||||
exit(run_luac(argc, argv));
|
||||
|
||||
// start from 1, as argv[0] is the executable name
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// Expose internal lua interpreter
|
||||
if(strcmp(argv[i], "lua") == 0 ||
|
||||
strcmp(argv[i], "--lua") == 0)
|
||||
{
|
||||
exit(run_lua_interpreter(argc - i, &argv[i], dnsmasq_debug));
|
||||
}
|
||||
|
||||
// Expose internal lua compiler
|
||||
if(strcmp(argv[i], "luac") == 0 ||
|
||||
strcmp(argv[i], "--luac") == 0)
|
||||
{
|
||||
exit(luac_main(argc - i, &argv[i]));
|
||||
}
|
||||
|
||||
// Implement dnsmasq's test function, no need to prepare the entire FTL
|
||||
// environment (initialize shared memory, lead queries from long-term
|
||||
// database, ...) when the task is a simple (dnsmasq) syntax check
|
||||
@@ -279,78 +296,18 @@ void parse_args(int argc, char* argv[])
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Expose internal lua interpreter
|
||||
if(strcmp(argv[i], "lua") == 0 ||
|
||||
strcmp(argv[i], "--lua") == 0)
|
||||
{
|
||||
if(argc == i + 1) // No arguments after this one
|
||||
printf("Pi-hole FTL %s\n", get_FTL_version());
|
||||
#if defined(LUA_USE_READLINE)
|
||||
wordexp_t word;
|
||||
wordexp(LUA_HISTORY_FILE, &word, WRDE_NOCMD);
|
||||
const char *history_file = NULL;
|
||||
if(word.we_wordc == 1)
|
||||
{
|
||||
history_file = word.we_wordv[0];
|
||||
const int ret_r = read_history(history_file);
|
||||
if(dnsmasq_debug)
|
||||
{
|
||||
printf("Reading history ... ");
|
||||
if(ret_r == 0)
|
||||
printf("success\n");
|
||||
else
|
||||
printf("error - %s: %s\n", history_file, strerror(ret_r));
|
||||
}
|
||||
|
||||
// The history file may not exist, try to create an empty one in this case
|
||||
if(ret_r == ENOENT)
|
||||
{
|
||||
if(dnsmasq_debug)
|
||||
{
|
||||
printf("Creating new history file: %s\n", history_file);
|
||||
}
|
||||
FILE *history = fopen(history_file, "w");
|
||||
if(history != NULL)
|
||||
fclose(history);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(dnsmasq_debug)
|
||||
printf("No readline available!\n");
|
||||
#endif
|
||||
const int ret = lua_main(argc - i, &argv[i]);
|
||||
#if defined(LUA_USE_READLINE)
|
||||
if(history_file != NULL)
|
||||
{
|
||||
const int ret_w = write_history(history_file);
|
||||
if(dnsmasq_debug)
|
||||
{
|
||||
printf("Writing history ... ");
|
||||
if(ret_w == 0)
|
||||
printf("success\n");
|
||||
else
|
||||
printf("error - %s: %s\n", history_file, strerror(ret_w));
|
||||
}
|
||||
|
||||
wordfree(&word);
|
||||
}
|
||||
#endif
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
// Expose internal lua compiler
|
||||
if(strcmp(argv[i], "luac") == 0 ||
|
||||
strcmp(argv[i], "--luac") == 0)
|
||||
{
|
||||
if(argc == i + 1) // No arguments after this one
|
||||
printf("Pi-hole FTL %s\n", get_FTL_version());
|
||||
exit(luac_main(argc - i, &argv[i]));
|
||||
}
|
||||
|
||||
// Complain if invalid options have been found
|
||||
if(!ok)
|
||||
{
|
||||
printf("pihole-FTL: invalid option -- '%s'\nTry '%s --help' for more information\n", argv[i], argv[0]);
|
||||
printf("pihole-FTL: invalid option -- '%s'\n", argv[i]);
|
||||
printf("Command: '");
|
||||
for(int j = 0; j < argc; j++)
|
||||
{
|
||||
printf("%s", argv[j]);
|
||||
if(j < argc - 1)
|
||||
printf(" ");
|
||||
}
|
||||
printf("'\nTry '%s --help' for more information\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#undef __USE_XOPEN
|
||||
#include "FTL.h"
|
||||
#include "capabilities.h"
|
||||
#include "memory.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
+21
-3
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "config.h"
|
||||
#include "memory.h"
|
||||
#include "setupVars.h"
|
||||
#include "log.h"
|
||||
// nice()
|
||||
@@ -438,6 +437,11 @@ void read_FTLconf(void)
|
||||
config.refresh_hostnames = REFRESH_NONE;
|
||||
logg(" REFRESH_HOSTNAMES: Not periodically refreshing names");
|
||||
}
|
||||
else if(buffer != NULL && strcasecmp(buffer, "UNKNOWN") == 0)
|
||||
{
|
||||
config.refresh_hostnames = REFRESH_UNKNOWN;
|
||||
logg(" REFRESH_HOSTNAMES: Only refreshing recently active clients with unknown hostnames");
|
||||
}
|
||||
else
|
||||
{
|
||||
config.refresh_hostnames = REFRESH_IPV4_ONLY;
|
||||
@@ -496,7 +500,7 @@ static char *parse_FTLconf(FILE *fp, const char * key)
|
||||
if(fp == NULL)
|
||||
return NULL;
|
||||
|
||||
char * keystr = calloc(strlen(key)+2,sizeof(char));
|
||||
char *keystr = calloc(strlen(key)+2, sizeof(char));
|
||||
if(keystr == NULL)
|
||||
{
|
||||
logg("WARN: parse_FTLconf failed: could not allocate memory for keystr");
|
||||
@@ -506,10 +510,18 @@ 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);
|
||||
|
||||
errno = 0;
|
||||
while(getline(&conflinebuffer, &size, fp) != -1)
|
||||
{
|
||||
if(config.debug & DEBUG_EXTRA)
|
||||
{
|
||||
logg("conflinebuffer = %p, keystr = %p, size = %zu", conflinebuffer, keystr, size);
|
||||
logg(" while reading line \"%s\" looking for \"%s\"", conflinebuffer, keystr);
|
||||
}
|
||||
// Check if memory allocation failed
|
||||
if(conflinebuffer == NULL)
|
||||
break;
|
||||
@@ -526,7 +538,7 @@ static char *parse_FTLconf(FILE *fp, const char * key)
|
||||
free(keystr);
|
||||
// Note: value is still a pointer into the conflinebuffer
|
||||
// its memory will get released in release_config_memory()
|
||||
char* value = find_equals(conflinebuffer) + 1;
|
||||
char *value = find_equals(conflinebuffer) + 1;
|
||||
// Trim whitespace at beginning and end, this function
|
||||
// modifies the string inplace
|
||||
trim_whitespace(value);
|
||||
@@ -548,6 +560,7 @@ void release_config_memory(void)
|
||||
{
|
||||
free(conflinebuffer);
|
||||
conflinebuffer = NULL;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,6 +764,10 @@ void read_debuging_settings(FILE *fp)
|
||||
// defaults to: false
|
||||
setDebugOption(fp, "DEBUG_HELPER", DEBUG_HELPER);
|
||||
|
||||
// DEBUG_EXTRA
|
||||
// defaults to: false
|
||||
setDebugOption(fp, "DEBUG_EXTRA", DEBUG_EXTRA);
|
||||
|
||||
if(config.debug)
|
||||
{
|
||||
logg("*****************************");
|
||||
@@ -776,6 +793,7 @@ void read_debuging_settings(FILE *fp)
|
||||
logg("* DEBUG_ALIASCLIENTS %s *", (config.debug & DEBUG_ALIASCLIENTS)? "YES":"NO ");
|
||||
logg("* DEBUG_EVENTS %s *", (config.debug & DEBUG_EVENTS)? "YES":"NO ");
|
||||
logg("* DEBUG_HELPER %s *", (config.debug & DEBUG_HELPER)? "YES":"NO ");
|
||||
logg("* DEBUG_EXTRA %s *", (config.debug & DEBUG_EXTRA)? "YES":"NO ");
|
||||
logg("*****************************");
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "daemon.h"
|
||||
#include "memory.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
// sleepms()
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#include "../config.h"
|
||||
// logg()
|
||||
#include "../log.h"
|
||||
// calloc()
|
||||
#include "../memory.h"
|
||||
// getAliasclientIDfromIP()
|
||||
#include "network-table.h"
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "network-table.h"
|
||||
#include "message-table.h"
|
||||
#include "../shmem.h"
|
||||
#include "../memory.h"
|
||||
// struct config
|
||||
#include "../config.h"
|
||||
// logg()
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
// reset_aliasclient()
|
||||
#include "aliasclients.h"
|
||||
|
||||
// Definition of struct regex_data
|
||||
#include "../regex_r.h"
|
||||
|
||||
// Prefix of interface names in the client table
|
||||
#define INTERFACE_SEP ":"
|
||||
|
||||
@@ -1087,6 +1090,12 @@ int gravityDB_count(const enum gravity_tables list)
|
||||
// Finalize statement
|
||||
gravityDB_finalizeTable();
|
||||
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
{
|
||||
logg("gravityDB_count(%d): %i entries in %s",
|
||||
list, result, tablename[list]);
|
||||
}
|
||||
|
||||
// Return result
|
||||
return result;
|
||||
}
|
||||
@@ -1294,6 +1303,9 @@ bool in_auditlist(const char *domain)
|
||||
bool gravityDB_get_regex_client_groups(clientsData* client, const unsigned int numregex, const regex_data *regex,
|
||||
const unsigned char type, const char* table, const int clientID)
|
||||
{
|
||||
if(config.debug & DEBUG_REGEX)
|
||||
logg("Getting regex client groups for client with ID %i", clientID);
|
||||
|
||||
char *querystr = NULL;
|
||||
if(!client->found_group && !get_client_groupids(client))
|
||||
return false;
|
||||
@@ -1328,7 +1340,7 @@ bool gravityDB_get_regex_client_groups(clientsData* client, const unsigned int n
|
||||
{
|
||||
// Regular expressions are stored in one array
|
||||
if(type == REGEX_WHITELIST)
|
||||
regexID += counters->num_regex[REGEX_BLACKLIST];
|
||||
regexID += get_num_regex(REGEX_BLACKLIST);
|
||||
set_per_client_regex(clientID, regexID, true);
|
||||
|
||||
if(config.debug & DEBUG_REGEX)
|
||||
|
||||
@@ -10,12 +10,9 @@
|
||||
#ifndef GRAVITY_H
|
||||
#define GRAVITY_H
|
||||
|
||||
// global variable counters
|
||||
#include "memory.h"
|
||||
// clients data structure
|
||||
#include "datastructure.h"
|
||||
|
||||
// Definition of struct regex_data
|
||||
// clientsData
|
||||
#include "../datastructure.h"
|
||||
// regex_data
|
||||
#include "../regex_r.h"
|
||||
|
||||
// Table indices
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include "network-table.h"
|
||||
#include "common.h"
|
||||
#include "../shmem.h"
|
||||
// strdup()
|
||||
#include "../memory.h"
|
||||
#include "../log.h"
|
||||
// timer_elapsed_msec()
|
||||
#include "../timers.h"
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
#include "../config.h"
|
||||
// getstr()
|
||||
#include "../shmem.h"
|
||||
// free()
|
||||
#include "../memory.h"
|
||||
|
||||
static bool saving_failed_before = false;
|
||||
|
||||
|
||||
+11
-2
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "datastructure.h"
|
||||
#include "memory.h"
|
||||
#include "shmem.h"
|
||||
#include "log.h"
|
||||
// enum REGEX
|
||||
@@ -25,6 +24,10 @@
|
||||
#include "database/aliasclients.h"
|
||||
// piholeFTLDB_reopen()
|
||||
#include "database/common.h"
|
||||
// config struct
|
||||
#include "config.h"
|
||||
// set_event(RESOLVE_NEW_HOSTNAMES)
|
||||
#include "events.h"
|
||||
|
||||
const char *querytypes[TYPE_MAX] = {"UNKNOWN", "A", "AAAA", "ANY", "SRV", "SOA", "PTR", "TXT",
|
||||
"NAPTR", "MX", "DS", "RRSIG", "DNSKEY", "NS", "OTHER"};
|
||||
@@ -119,6 +122,7 @@ int findUpstreamID(const char * upstreamString, const in_port_t port, const bool
|
||||
// to be done separately to be non-blocking
|
||||
upstream->new = true;
|
||||
upstream->namepos = 0; // 0 -> string with length zero
|
||||
set_event(RESOLVE_NEW_HOSTNAMES);
|
||||
// This is a new upstream server
|
||||
upstream->lastQuery = time(NULL);
|
||||
// Store port
|
||||
@@ -242,6 +246,7 @@ int findClientID(const char *clientIP, const bool count, const bool aliasclient)
|
||||
// to be done separately to be non-blocking
|
||||
client->new = true;
|
||||
client->namepos = 0;
|
||||
set_event(RESOLVE_NEW_HOSTNAMES);
|
||||
// No query seen so far
|
||||
client->lastQuery = 0;
|
||||
client->numQueriesARP = client->count;
|
||||
@@ -453,13 +458,17 @@ const char *getClientNameString(const queriesData* query)
|
||||
|
||||
void FTL_reset_per_client_domain_data(void)
|
||||
{
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
logg("Resetting per-client DNS cache, size is %i", counters->dns_cache_size);
|
||||
|
||||
for(int cacheID = 0; cacheID < counters->dns_cache_size; cacheID++)
|
||||
{
|
||||
// Reset all blocking yes/no fields for all domains and clients
|
||||
// This forces a reprocessing of all available filters for any
|
||||
// given domain and client the next time they are seen
|
||||
DNSCacheData *dns_cache = getDNSCache(cacheID, true);
|
||||
dns_cache->blocking_status = UNKNOWN_BLOCKED;
|
||||
if(dns_cache != NULL)
|
||||
dns_cache->blocking_status = UNKNOWN_BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -506,6 +506,18 @@ static bool get_dhcp_offer(const int sock, const uint32_t xid, const char *iface
|
||||
else
|
||||
logg("N/A");
|
||||
|
||||
logg_sameline(" BOOTP server: ");
|
||||
if(offer_packet.sname[0] != 0)
|
||||
logg("%s", offer_packet.sname);
|
||||
else
|
||||
logg("(empty)");
|
||||
|
||||
logg_sameline(" BOOTP file: ");
|
||||
if(offer_packet.file[0] != 0)
|
||||
logg("%s", offer_packet.file);
|
||||
else
|
||||
logg("(empty)");
|
||||
|
||||
logg(" DHCP options:");
|
||||
print_dhcp_offer(source.sin_addr, &offer_packet);
|
||||
pthread_mutex_unlock(&lock);
|
||||
|
||||
@@ -692,7 +692,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
a.log.rcode = rcode;
|
||||
FTL_upstream_error(rcode, daemon->log_display_id);
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
||||
FTL_upstream_error(rcode, daemon->log_display_id);
|
||||
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
}
|
||||
@@ -735,8 +734,13 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
int ret = extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache, cache_secure, &doctored);
|
||||
if (ret == 2)
|
||||
{
|
||||
munged = 1;
|
||||
cache_secure = 0;
|
||||
union all_addr *addrp = NULL;
|
||||
// Extract IPv4/IPv6 information from the original question in the DNS
|
||||
// header
|
||||
unsigned int flags = FTL_extract_question_flags(header, n);
|
||||
FTL_get_blocking_metadata(&addrp, &flags);
|
||||
n = setup_reply(header, n, addrp, flags, daemon->local_ttl);
|
||||
}
|
||||
else if(ret)
|
||||
{
|
||||
@@ -1627,16 +1631,13 @@ void receive_query(struct listener *listen, time_t now)
|
||||
/************ Pi-hole modification ************/
|
||||
if(piholeblocked)
|
||||
{
|
||||
size_t plen = n;
|
||||
union all_addr *addrp = NULL;
|
||||
// DNS resource record type for AAAA is 28 (decimal) following RFC 3596, section 2.1
|
||||
unsigned int flags = (type == 28u) ? F_IPV6 : F_IPV4;
|
||||
FTL_get_blocking_metadata(&addrp, &flags);
|
||||
log_query(flags, daemon->namebuff, addrp, (char*)blockingreason);
|
||||
plen = setup_reply(header, n, addrp, flags, daemon->local_ttl);
|
||||
if (find_pseudoheader(header, plen, NULL, NULL, NULL, NULL))
|
||||
plen = add_pseudoheader(header, plen, ((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, plen, (union mysockaddr*)&source_addr, &dst_addr, if_index);
|
||||
n = setup_reply(header, n, addrp, flags, daemon->local_ttl);
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, n, (union mysockaddr*)&source_addr, &dst_addr, if_index);
|
||||
return;
|
||||
}
|
||||
/**********************************************/
|
||||
@@ -2027,8 +2028,6 @@ 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);
|
||||
if (have_pseudoheader)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+54
-3
@@ -16,7 +16,6 @@
|
||||
#include "dnsmasq_interface.h"
|
||||
#include "shmem.h"
|
||||
#include "overTime.h"
|
||||
#include "memory.h"
|
||||
#include "database/common.h"
|
||||
#include "database/database-thread.h"
|
||||
#include "datastructure.h"
|
||||
@@ -1023,7 +1022,7 @@ void _FTL_reply(const unsigned int flags, const char *name, const union all_addr
|
||||
}
|
||||
|
||||
// Check if this domain matches exactly
|
||||
const bool isExactMatch = (name != NULL && strcasecmp(getstr(domain->domainpos), name) == 0);
|
||||
const bool isExactMatch = strcmp_escaped(name, getstr(domain->domainpos));
|
||||
|
||||
if((flags & F_CONFIG) && isExactMatch && !query->complete)
|
||||
{
|
||||
@@ -1775,7 +1774,9 @@ void FTL_fork_and_bind_sockets(struct passwd *ent_pw)
|
||||
// option states to run as a different user/group (e.g. "nobody")
|
||||
if(getuid() == 0)
|
||||
{
|
||||
if(ent_pw != NULL)
|
||||
// Only print this and change ownership of shmem objects when
|
||||
// we're actually dropping root (user/group my be set to root)
|
||||
if(ent_pw != NULL && ent_pw->pw_uid != 0)
|
||||
{
|
||||
logg("INFO: FTL is going to drop from root to user %s (UID %d)",
|
||||
ent_pw->pw_name, (int)ent_pw->pw_uid);
|
||||
@@ -1956,6 +1957,56 @@ static void prepare_blocking_metadata(void)
|
||||
clearSetupVarsArray();
|
||||
}
|
||||
|
||||
unsigned int FTL_extract_question_flags(struct dns_header *header, const size_t qlen)
|
||||
{
|
||||
// Create working pointer
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
uint16_t qtype, qclass;
|
||||
|
||||
// Go through the questions
|
||||
for (uint16_t i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
// Prime dnsmasq flags
|
||||
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
|
||||
// Extract name from this question
|
||||
char name[MAXDNAME];
|
||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||
break; // bad packet, go to fallback solution
|
||||
|
||||
// Extract query type
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
// Only further analyze IN questions here (not CHAOS, etc.)
|
||||
if (qclass != C_IN)
|
||||
continue;
|
||||
|
||||
// Very simple decision: If the question is AAAA, the reply
|
||||
// should be IPv6. We use IPv4 in all other cases
|
||||
if(qtype == T_AAAA)
|
||||
flags |= F_IPV6;
|
||||
else
|
||||
flags |= F_IPV4;
|
||||
|
||||
// Debug logging if enabled
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
char *qtype_str = querystr(NULL, qtype);
|
||||
logg("CNAME header: Question was <IN> %s %s", qtype_str, name);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
// Fall back to IPv4 (type A) when for the unlikely event that we cannot
|
||||
// find any questions in this header
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
logg("CNAME header: No valid IN question found in header");
|
||||
|
||||
return F_IPV4;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -52,6 +52,8 @@ void _FTL_get_blocking_metadata(union all_addr **addrp, unsigned int *flags, con
|
||||
#define FTL_CNAME(domain, cpp, id) _FTL_CNAME(domain, cpp, id, __FILE__, __LINE__)
|
||||
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_dnsmasq_reload(void);
|
||||
void FTL_fork_and_bind_sockets(struct passwd *ent_pw);
|
||||
void FTL_TCP_worker_created(const int confd, const char *iface_name);
|
||||
|
||||
@@ -139,12 +139,15 @@ enum debug_flags {
|
||||
DEBUG_ALIASCLIENTS = (1 << 18), /* 00000000 00000100 00000000 00000000 */
|
||||
DEBUG_EVENTS = (1 << 19), /* 00000000 00001000 00000000 00000000 */
|
||||
DEBUG_HELPER = (1 << 20), /* 00000000 00010000 00000000 00000000 */
|
||||
DEBUG_EXTRA = (1 << 21), /* 00000000 00100000 00000000 00000000 */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum events {
|
||||
RELOAD_GRAVITY,
|
||||
RELOAD_PRIVACY_LEVEL,
|
||||
RESOLVE_NEW_HOSTNAMES,
|
||||
RERESOLVE_HOSTNAMES,
|
||||
RERESOLVE_HOSTNAMES_FORCE,
|
||||
REIMPORT_ALIASCLIENTS,
|
||||
PARSE_NEIGHBOR_CACHE,
|
||||
EVENTS_MAX
|
||||
@@ -153,6 +156,7 @@ enum events {
|
||||
enum refresh_hostnames {
|
||||
REFRESH_ALL,
|
||||
REFRESH_IPV4_ONLY,
|
||||
REFRESH_UNKNOWN,
|
||||
REFRESH_NONE
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
@@ -92,10 +92,14 @@ static const char *eventtext(const enum events event)
|
||||
return "RELOAD_PRIVACY_LEVEL";
|
||||
case RERESOLVE_HOSTNAMES:
|
||||
return "RERESOLVE_HOSTNAMES";
|
||||
case RERESOLVE_HOSTNAMES_FORCE:
|
||||
return "RERESOLVE_HOSTNAMES_FORCE";
|
||||
case REIMPORT_ALIASCLIENTS:
|
||||
return "REIMPORT_ALIASCLIENTS";
|
||||
case PARSE_NEIGHBOR_CACHE:
|
||||
return "PARSE_NEIGHBOR_CACHE";
|
||||
case RESOLVE_NEW_HOSTNAMES:
|
||||
return "RESOLVE_NEW_HOSTNAMES";
|
||||
case EVENTS_MAX: // fall through
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "files.h"
|
||||
#include "memory.h"
|
||||
#include "config.h"
|
||||
#include "setupVars.h"
|
||||
#include "log.h"
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#include "overTime.h"
|
||||
#include "database/common.h"
|
||||
#include "log.h"
|
||||
// global variable counters
|
||||
#include "memory.h"
|
||||
// global variable killed
|
||||
#include "signals.h"
|
||||
// data getter functions
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "version.h"
|
||||
#include "memory.h"
|
||||
// is_fork()
|
||||
#include "daemon.h"
|
||||
#include "config.h"
|
||||
@@ -28,6 +27,7 @@
|
||||
|
||||
static pthread_mutex_t lock;
|
||||
static FILE *logfile = NULL;
|
||||
static bool FTL_log_ready = false;
|
||||
static bool print_log = true, print_stdout = true;
|
||||
|
||||
void log_ctrl(bool plog, bool pstdout)
|
||||
@@ -42,27 +42,25 @@ static void close_FTL_log(void)
|
||||
fclose(logfile);
|
||||
}
|
||||
|
||||
void init_FTL_log(void)
|
||||
void open_FTL_log(const bool init)
|
||||
{
|
||||
if (pthread_mutex_init(&lock, NULL) != 0)
|
||||
if(init)
|
||||
{
|
||||
printf("FATAL: Log mutex init failed\n");
|
||||
// Return failure
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
// Initialize logging mutex
|
||||
if (pthread_mutex_init(&lock, NULL) != 0)
|
||||
{
|
||||
printf("FATAL: Log mutex init failed\n");
|
||||
// Return failure
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void open_FTL_log(const bool test)
|
||||
{
|
||||
if(test)
|
||||
{
|
||||
// Obtain log file location
|
||||
getLogFilePath();
|
||||
}
|
||||
|
||||
// Open the log file in append/create mode
|
||||
logfile = fopen(FTLfiles.log, "a+");
|
||||
if((logfile == NULL) && test){
|
||||
if((logfile == NULL) && init){
|
||||
syslog(LOG_ERR, "Opening of FTL\'s log file failed!");
|
||||
printf("FATAL: Opening of FTL log (%s) failed!\n",FTLfiles.log);
|
||||
printf(" Make sure it exists and is writeable by user %s\n", username);
|
||||
@@ -70,7 +68,10 @@ void open_FTL_log(const bool test)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(test)
|
||||
// Set log as ready (we were able to open it)
|
||||
FTL_log_ready = true;
|
||||
|
||||
if(init)
|
||||
{
|
||||
close_FTL_log();
|
||||
}
|
||||
@@ -141,7 +142,7 @@ void _FTL_log(const bool newline, const char *format, ...)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if(print_log)
|
||||
if(print_log && FTL_log_ready)
|
||||
{
|
||||
// Open log file
|
||||
open_FTL_log(false);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <time.h>
|
||||
|
||||
void init_FTL_log(void);
|
||||
void open_FTL_log(const bool test);
|
||||
void open_FTL_log(const bool init);
|
||||
void log_counter_info(void);
|
||||
void format_memory_size(char * const prefix, unsigned long long int bytes,
|
||||
double * const formated);
|
||||
|
||||
@@ -14,6 +14,72 @@
|
||||
#include "lauxlib.h"
|
||||
// get_FTL_version()
|
||||
#include "../log.h"
|
||||
#include <readline/history.h>
|
||||
#include <wordexp.h>
|
||||
|
||||
int run_lua_interpreter(const int argc, char **argv, bool dnsmasq_debug)
|
||||
{
|
||||
if(argc == 1) // No arguments after this one
|
||||
printf("Pi-hole FTL %s\n", get_FTL_version());
|
||||
#if defined(LUA_USE_READLINE)
|
||||
wordexp_t word;
|
||||
wordexp(LUA_HISTORY_FILE, &word, WRDE_NOCMD);
|
||||
const char *history_file = NULL;
|
||||
if(word.we_wordc == 1)
|
||||
{
|
||||
history_file = word.we_wordv[0];
|
||||
const int ret_r = read_history(history_file);
|
||||
if(dnsmasq_debug)
|
||||
{
|
||||
printf("Reading history ... ");
|
||||
if(ret_r == 0)
|
||||
printf("success\n");
|
||||
else
|
||||
printf("error - %s: %s\n", history_file, strerror(ret_r));
|
||||
}
|
||||
|
||||
// The history file may not exist, try to create an empty one in this case
|
||||
if(ret_r == ENOENT)
|
||||
{
|
||||
if(dnsmasq_debug)
|
||||
{
|
||||
printf("Creating new history file: %s\n", history_file);
|
||||
}
|
||||
FILE *history = fopen(history_file, "w");
|
||||
if(history != NULL)
|
||||
fclose(history);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(dnsmasq_debug)
|
||||
printf("No readline available!\n");
|
||||
#endif
|
||||
const int ret = lua_main(argc, argv);
|
||||
#if defined(LUA_USE_READLINE)
|
||||
if(history_file != NULL)
|
||||
{
|
||||
const int ret_w = write_history(history_file);
|
||||
if(dnsmasq_debug)
|
||||
{
|
||||
printf("Writing history ... ");
|
||||
if(ret_w == 0)
|
||||
printf("success\n");
|
||||
else
|
||||
printf("error - %s: %s\n", history_file, strerror(ret_w));
|
||||
}
|
||||
|
||||
wordfree(&word);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int run_luac(const int argc, char **argv)
|
||||
{
|
||||
if(argc == 1) // No arguments after this one
|
||||
printf("Pi-hole FTL %s\n", get_FTL_version());
|
||||
return luac_main(argc, argv);
|
||||
}
|
||||
|
||||
// pihole.ftl_version()
|
||||
static int pihole_ftl_version(lua_State *L) {
|
||||
|
||||
@@ -11,9 +11,13 @@
|
||||
#define FTL_LUA_H
|
||||
|
||||
#include "lua.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define LUA_HISTORY_FILE "~/.pihole_lua_history"
|
||||
|
||||
int run_lua_interpreter(const int argc, char **argv, bool dnsmasq_debug);
|
||||
int run_luac(const int argc, char **argv);
|
||||
|
||||
int lua_main (int argc, char **argv);
|
||||
int luac_main (int argc, char **argv);
|
||||
|
||||
|
||||
@@ -39,12 +39,6 @@ int main (int argc, char* argv[])
|
||||
// it if needed
|
||||
username = getUserName();
|
||||
|
||||
// This only prepares the log file lock, we
|
||||
// do not want to log already here (parsing
|
||||
// args may bring up something we want to do
|
||||
// separated from the log in foreground)
|
||||
init_FTL_log();
|
||||
|
||||
// Parse arguments
|
||||
// We run this also for no direct arguments
|
||||
// to have arg{c,v}_dnsmasq initialized
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* FTL Engine
|
||||
* Global variable definitions and memory reallocation handling
|
||||
*
|
||||
* 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 "shmem.h"
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
|
||||
// The special memory handling routines have to be the last ones in this source file
|
||||
// as we restore the original definition of the strdup, free, calloc, and realloc
|
||||
// functions in here, i.e. if anything extra would come below these lines, it would
|
||||
// not be protected by our (error logging) functions!
|
||||
|
||||
#undef strdup
|
||||
char* __attribute__((malloc)) FTLstrdup(const char *src, const char * file, const char * function, const int line)
|
||||
{
|
||||
// The FTLstrdup() function returns a pointer to a new string which is a
|
||||
// duplicate of the string s. Memory for the new string is obtained with
|
||||
// calloc(3), and can be freed with free(3).
|
||||
if(src == NULL)
|
||||
{
|
||||
logg("WARN: Trying to copy a NULL string in %s() (%s:%i)", function, file, line);
|
||||
return NULL;
|
||||
}
|
||||
const size_t len = strlen(src);
|
||||
char *dest = calloc(len+1, sizeof(char));
|
||||
if(dest == NULL)
|
||||
{
|
||||
logg("FATAL: Memory allocation failed in %s() (%s:%i)", function, file, line);
|
||||
return NULL;
|
||||
}
|
||||
// Use memcpy as memory areas cannot overlap
|
||||
memcpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
#undef calloc
|
||||
void* __attribute__((malloc)) __attribute__((alloc_size(1,2))) FTLcalloc(const size_t nmemb, const size_t size, const char * file, const char * function, const int line)
|
||||
{
|
||||
// The FTLcalloc() function allocates memory for an array of nmemb elements
|
||||
// of size bytes each and returns a pointer to the allocated memory. The
|
||||
// memory is set to zero. If nmemb or size is 0, then calloc() returns
|
||||
// either NULL, or a unique pointer value that can later be successfully
|
||||
// passed to free().
|
||||
void *ptr = calloc(nmemb, size);
|
||||
if(ptr == NULL)
|
||||
logg("FATAL: Memory allocation (%zu x %zu) failed in %s() (%s:%i)",
|
||||
nmemb, size, function, file, line);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
#undef realloc
|
||||
void __attribute__((alloc_size(2))) *FTLrealloc(void *ptr_in, const size_t size, const char * file, const char * function, const int line)
|
||||
{
|
||||
// The FTLrealloc() function changes the size of the memory block pointed to
|
||||
// by ptr to size bytes. The contents will be unchanged in the range from
|
||||
// the start of the region up to the minimum of the old and new sizes. If
|
||||
// the new size is larger than the old size, the added memory will not be
|
||||
// initialized. If ptr is NULL, then the call is equivalent to malloc(size),
|
||||
// for all values of size; if size is equal to zero, and ptr is
|
||||
// not NULL, then the call is equivalent to free(ptr). Unless ptr is
|
||||
// NULL, it must have been returned by an earlier call to malloc(), cal‐
|
||||
// loc() or realloc(). If the area pointed to was moved, a free(ptr) is
|
||||
// done.
|
||||
void *ptr_out = realloc(ptr_in, size);
|
||||
if(ptr_out == NULL)
|
||||
logg("FATAL: Memory reallocation (%p -> %zu) failed in %s() (%s:%i)",
|
||||
ptr_in, size, function, file, line);
|
||||
|
||||
return ptr_out;
|
||||
}
|
||||
|
||||
#undef free
|
||||
void FTLfree(void *ptr, const char * file, const char * function, const int line)
|
||||
{
|
||||
// The free() function frees the memory space pointed to by ptr, which
|
||||
// must have been returned by a previous call to malloc(), calloc(), or
|
||||
// realloc(). Otherwise, or if free(ptr) has already been called before,
|
||||
// undefined behavior occurs. If ptr is NULL, no operation is performed.
|
||||
if(ptr == NULL)
|
||||
logg("FATAL: Trying to free NULL pointer in %s() (%s:%i)", function, file, line);
|
||||
|
||||
// We intentionally run free() nevertheless to see the crash in the debugger
|
||||
free(ptr);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2019 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* FTL Engine
|
||||
* Memory prototypes
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include "enums.h"
|
||||
|
||||
char *FTLstrdup(const char *src, const char *file, const char *function, const int line) __attribute__((malloc));
|
||||
void *FTLcalloc(size_t n, 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)));
|
||||
void FTLfree(void *ptr, const char* file, const char *function, const int line);
|
||||
|
||||
#endif //MEMORY_H
|
||||
+1
-3
@@ -13,8 +13,6 @@
|
||||
#include "shmem.h"
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
// global variable counters
|
||||
#include "memory.h"
|
||||
// data getter functions
|
||||
#include "datastructure.h"
|
||||
|
||||
@@ -125,7 +123,7 @@ unsigned int getOverTimeID(time_t timestamp)
|
||||
void moveOverTimeMemory(const time_t mintime)
|
||||
{
|
||||
const time_t oldestOverTimeIS = overTime[0].timestamp;
|
||||
// Shift SHOULD timestemp into the future by the amount GC is running earlier
|
||||
// Shift SHOULD timestamp into the future by the amount GC is running earlier
|
||||
time_t oldestOverTimeSHOULD = mintime;
|
||||
|
||||
// Center in interval
|
||||
|
||||
+127
-35
@@ -11,7 +11,6 @@
|
||||
#include "FTL.h"
|
||||
#include "regex_r.h"
|
||||
#include "timers.h"
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
// data getter functions
|
||||
@@ -32,9 +31,10 @@ const char *regextype[REGEX_MAX] = { "blacklist", "whitelist", "CLI" };
|
||||
static regex_data *white_regex = NULL;
|
||||
static regex_data *black_regex = NULL;
|
||||
static regex_data *cli_regex = NULL;
|
||||
static unsigned int num_regex[REGEX_MAX] = { 0 };
|
||||
unsigned int regex_change = 0;
|
||||
|
||||
regex_data *get_regex_from_type(const enum regex_type regexid);
|
||||
inline regex_data *get_regex_from_type(const enum regex_type regexid)
|
||||
static inline regex_data *get_regex_ptr(const enum regex_type regexid)
|
||||
{
|
||||
switch (regexid)
|
||||
{
|
||||
@@ -50,13 +50,59 @@ inline regex_data *get_regex_from_type(const enum regex_type regexid)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void free_regex_ptr(const enum regex_type regexid)
|
||||
{
|
||||
regex_data **regex;
|
||||
switch (regexid)
|
||||
{
|
||||
case REGEX_BLACKLIST:
|
||||
regex = &black_regex;
|
||||
break;
|
||||
case REGEX_WHITELIST:
|
||||
regex = &white_regex;
|
||||
break;
|
||||
case REGEX_CLI:
|
||||
regex = &cli_regex;
|
||||
break;
|
||||
case REGEX_MAX: // Fall through
|
||||
default: // This is not possible
|
||||
return;
|
||||
}
|
||||
|
||||
// Free pointer (if not already NULL)
|
||||
if(*regex != NULL)
|
||||
{
|
||||
free(*regex);
|
||||
*regex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int __attribute__((pure)) get_num_regex(const enum regex_type regexid)
|
||||
{
|
||||
// count number of all available reges
|
||||
if(regexid == REGEX_MAX)
|
||||
{
|
||||
unsigned int num = 0;
|
||||
for(unsigned int i = 0; i < REGEX_MAX; i++)
|
||||
num += num_regex[i];
|
||||
return num;
|
||||
}
|
||||
|
||||
// else: specific regex type
|
||||
return num_regex[regexid];
|
||||
}
|
||||
|
||||
#define FTL_REGEX_SEP ";"
|
||||
/* Compile regular expressions into data structures that can be used with
|
||||
regexec() to match against a string */
|
||||
static bool compile_regex(const char *regexin, const enum regex_type regexid)
|
||||
{
|
||||
regex_data *regex = get_regex_from_type(regexid);
|
||||
int index = counters->num_regex[regexid]++;
|
||||
regex_data *regex = get_regex_ptr(regexid);
|
||||
int index = num_regex[regexid]++;
|
||||
|
||||
// Update global counter from private counter
|
||||
// This is safe her because we're (fork-wide) locked
|
||||
num_regex[regexid] = num_regex[regexid];
|
||||
|
||||
// Extract possible Pi-hole extensions
|
||||
char rgxbuf[strlen(regexin) + 1u];
|
||||
@@ -163,13 +209,25 @@ int match_regex(const char *input, const DNSCacheData* dns_cache, const int clie
|
||||
const enum regex_type regexid, const bool regextest)
|
||||
{
|
||||
int match_idx = -1;
|
||||
regex_data *regex = get_regex_from_type(regexid);
|
||||
regex_data *regex = get_regex_ptr(regexid);
|
||||
#ifdef USE_TRE_REGEX
|
||||
regmatch_t match = { 0 }; // This also disables any sub-matching
|
||||
#endif
|
||||
|
||||
// Check if we need to recompile regex because they were changed in
|
||||
// another fork. If this is the case, reload everything (regex
|
||||
// themselves as well as per-client enabled/disabled state)
|
||||
if(regex_change != counters->regex_change)
|
||||
{
|
||||
logg("Reloading externally changed regular expressions");
|
||||
read_regex_from_database();
|
||||
// Update regex pointer as it will have changed (free_regex has
|
||||
// been called)
|
||||
regex = get_regex_ptr(regexid);
|
||||
}
|
||||
|
||||
// Loop over all configured regex filters of this type
|
||||
for(unsigned int index = 0; index < counters->num_regex[regexid]; index++)
|
||||
for(unsigned int index = 0; index < num_regex[regexid]; index++)
|
||||
{
|
||||
// Only check regex which have been successfully compiled ...
|
||||
if(!regex[index].available)
|
||||
@@ -185,10 +243,10 @@ int match_regex(const char *input, const DNSCacheData* dns_cache, const int clie
|
||||
// ... and are enabled for this client
|
||||
int regexID = index;
|
||||
if(regexid == REGEX_WHITELIST)
|
||||
regexID += counters->num_regex[REGEX_BLACKLIST];
|
||||
regexID += num_regex[REGEX_BLACKLIST];
|
||||
else if(regexid == REGEX_CLI)
|
||||
regexID += counters->num_regex[REGEX_BLACKLIST] +
|
||||
counters->num_regex[REGEX_WHITELIST];
|
||||
regexID += num_regex[REGEX_BLACKLIST] +
|
||||
num_regex[REGEX_WHITELIST];
|
||||
|
||||
// Only use regular expressions enabled for this client
|
||||
// We allow clientID = -1 to get all regex (for testing)
|
||||
@@ -208,6 +266,9 @@ int match_regex(const char *input, const DNSCacheData* dns_cache, const int clie
|
||||
}
|
||||
|
||||
// Try to match the compiled regular expression against input
|
||||
if(config.debug & DEBUG_REGEX)
|
||||
logg("Executing: index = %d, preg = %p, str = \"%s\", pmatch = %p", index, ®ex[index].regex, input, &match);
|
||||
sync();
|
||||
#ifdef USE_TRE_REGEX
|
||||
int retval = tre_regexec(®ex[index].regex, input, 0, &match, 0);
|
||||
#else
|
||||
@@ -292,16 +353,19 @@ int match_regex(const char *input, const DNSCacheData* dns_cache, const int clie
|
||||
|
||||
static void free_regex(void)
|
||||
{
|
||||
// Reset FTL's DNS cache
|
||||
FTL_reset_per_client_domain_data();
|
||||
|
||||
// Return early if we don't use any regex filters
|
||||
if(white_regex == NULL &&
|
||||
black_regex == NULL &&
|
||||
cli_regex == NULL)
|
||||
{
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
logg("Not using any regex filters, nothing to free or reset");
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset client configuration
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
logg("Resetting per-client regex settings");
|
||||
for(int clientID = 0; clientID < counters->clients; clientID++)
|
||||
{
|
||||
reset_per_client_regex(clientID);
|
||||
@@ -309,11 +373,26 @@ static void free_regex(void)
|
||||
|
||||
// Free regex datastructure
|
||||
// Loop over regex types
|
||||
for(unsigned char regexid = 0; regexid < REGEX_MAX; regexid++)
|
||||
for(enum regex_type regexid = REGEX_BLACKLIST; regexid < REGEX_MAX; regexid++)
|
||||
{
|
||||
regex_data *regex = get_regex_from_type(regexid);
|
||||
regex_data *regex = get_regex_ptr(regexid);
|
||||
|
||||
// Reset counter for number of regex
|
||||
const unsigned int oldcount = num_regex[regexid];
|
||||
num_regex[regexid] = 0;
|
||||
|
||||
// Exit early if the regex has already been freed (or has never been used)
|
||||
if(regex == NULL)
|
||||
continue;
|
||||
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
{
|
||||
logg("Going to free %i entries in %s regex struct",
|
||||
oldcount, regextype[regexid]);
|
||||
}
|
||||
|
||||
// Loop over entries with this regex type
|
||||
for(unsigned int index = 0; index < counters->num_regex[regexid]; index++)
|
||||
for(unsigned int index = 0; index < oldcount; index++)
|
||||
{
|
||||
if(!regex[index].available)
|
||||
continue;
|
||||
@@ -328,15 +407,13 @@ static void free_regex(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Free array with regex datastructure
|
||||
if(regex != NULL)
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
{
|
||||
free(regex);
|
||||
regex = NULL;
|
||||
logg("Loop done, freeing regex pointer (%p)", regex);
|
||||
}
|
||||
|
||||
// Reset counter for number of regex
|
||||
counters->num_regex[regexid] = 0;
|
||||
// Free array with regex datastructure
|
||||
free_regex_ptr(regexid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,18 +426,18 @@ void reload_per_client_regex(const int clientID, clientsData *client)
|
||||
// Ensure there is enough memory in the shared memory object
|
||||
add_per_client_regex(clientID);
|
||||
|
||||
// Zero-initialize(or wipe previous) regex
|
||||
// Zero-initialize (or wipe previous) regex
|
||||
reset_per_client_regex(clientID);
|
||||
|
||||
// Load regex per-group regex blacklist for this client
|
||||
if(counters->num_regex[REGEX_BLACKLIST] > 0)
|
||||
gravityDB_get_regex_client_groups(client, counters->num_regex[REGEX_BLACKLIST],
|
||||
if(num_regex[REGEX_BLACKLIST] > 0)
|
||||
gravityDB_get_regex_client_groups(client, num_regex[REGEX_BLACKLIST],
|
||||
black_regex, REGEX_BLACKLIST,
|
||||
"vw_regex_blacklist", clientID);
|
||||
|
||||
// Load regex per-group regex whitelist for this client
|
||||
if(counters->num_regex[REGEX_WHITELIST] > 0)
|
||||
gravityDB_get_regex_client_groups(client, counters->num_regex[REGEX_WHITELIST],
|
||||
if(num_regex[REGEX_WHITELIST] > 0)
|
||||
gravityDB_get_regex_client_groups(client, num_regex[REGEX_WHITELIST],
|
||||
white_regex, REGEX_WHITELIST,
|
||||
"vw_regex_whitelist", clientID);
|
||||
}
|
||||
@@ -370,8 +447,11 @@ static void read_regex_table(const enum regex_type regexid)
|
||||
// Get table ID
|
||||
const enum gravity_tables tableID = (regexid == REGEX_BLACKLIST) ? REGEX_BLACKLIST_TABLE : REGEX_WHITELIST_TABLE;
|
||||
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
logg("Reading regex %s from database", regextype[regexid]);
|
||||
|
||||
// Get number of lines in the regex table
|
||||
counters->num_regex[regexid] = 0;
|
||||
num_regex[regexid] = 0;
|
||||
int count = gravityDB_count(tableID);
|
||||
|
||||
if(count == 0)
|
||||
@@ -412,10 +492,10 @@ static void read_regex_table(const enum regex_type regexid)
|
||||
{
|
||||
// Avoid buffer overflow if database table changed
|
||||
// since we counted its entries
|
||||
if(counters->num_regex[regexid] >= (unsigned int)count)
|
||||
if(num_regex[regexid] >= (unsigned int)count)
|
||||
{
|
||||
logg("INFO: read_regex_table(%s) exiting early to avoid overflow (%d/%d).",
|
||||
regextype[regexid], counters->num_regex[regexid], count);
|
||||
regextype[regexid], num_regex[regexid], count);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -432,15 +512,25 @@ static void read_regex_table(const enum regex_type regexid)
|
||||
if(config.debug & DEBUG_REGEX)
|
||||
{
|
||||
logg("Compiling %s regex %i (DB ID %i): %s",
|
||||
regextype[regexid], counters->num_regex[regexid], rowid, domain);
|
||||
regextype[regexid], num_regex[regexid], rowid, domain);
|
||||
}
|
||||
|
||||
compile_regex(domain, regexid);
|
||||
regex[counters->num_regex[regexid]-1].database_id = rowid;
|
||||
regex[num_regex[regexid]-1].database_id = rowid;
|
||||
|
||||
// Signal other forks that the regex data has changed and should be updated
|
||||
regex_change = ++counters->regex_change;
|
||||
}
|
||||
|
||||
// Finalize statement and close gravity database handle
|
||||
gravityDB_finalizeTable();
|
||||
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
{
|
||||
logg("Read %i %s regex entries",
|
||||
num_regex[regexid],
|
||||
regextype[regexid]);
|
||||
}
|
||||
}
|
||||
|
||||
void read_regex_from_database(void)
|
||||
@@ -462,6 +552,8 @@ void read_regex_from_database(void)
|
||||
// Loop over all clients and ensure we have enough space and load
|
||||
// per-client regex data, not all of the regex read and compiled above
|
||||
// will also be used by all clients
|
||||
if(config.debug & DEBUG_DATABASE)
|
||||
logg("Loading per-client regex data");
|
||||
for(int clientID = 0; clientID < counters->clients; clientID++)
|
||||
{
|
||||
// Get client pointer
|
||||
@@ -475,7 +567,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 for %i clients in %.1f msec",
|
||||
counters->num_regex[REGEX_WHITELIST], counters->num_regex[REGEX_BLACKLIST],
|
||||
num_regex[REGEX_WHITELIST], num_regex[REGEX_BLACKLIST],
|
||||
counters->clients, timer_elapsed_msec(REGEX_TIMER));
|
||||
}
|
||||
|
||||
@@ -505,8 +597,8 @@ int regex_test(const bool debug_mode, const bool quiet, const char *domainin, co
|
||||
read_regex_table(REGEX_WHITELIST);
|
||||
log_ctrl(false, !quiet); // Re-apply quiet option after compilation
|
||||
logg(" Compiled %i black- and %i whitelist regex filters in %.3f msec\n",
|
||||
counters->num_regex[REGEX_BLACKLIST],
|
||||
counters->num_regex[REGEX_WHITELIST],
|
||||
num_regex[REGEX_BLACKLIST],
|
||||
num_regex[REGEX_WHITELIST],
|
||||
timer_elapsed_msec(REGEX_TIMER));
|
||||
|
||||
// Check user-provided domain against all loaded regular blacklist expressions
|
||||
|
||||
@@ -38,6 +38,7 @@ struct query_details {
|
||||
enum query_types query_type;
|
||||
};
|
||||
|
||||
unsigned int get_num_regex(const enum regex_type regexid) __attribute__((pure));
|
||||
int match_regex(const char *input, const DNSCacheData* dns_cache, const int clientID,
|
||||
const enum regex_type regexid, const bool regextest);
|
||||
void allocate_regex_client_enabled(clientsData *client, const int clientID);
|
||||
|
||||
+63
-23
@@ -11,7 +11,6 @@
|
||||
#include "FTL.h"
|
||||
#include "resolve.h"
|
||||
#include "shmem.h"
|
||||
#include "memory.h"
|
||||
// struct config
|
||||
#include "config.h"
|
||||
// sleepms()
|
||||
@@ -350,7 +349,7 @@ static size_t resolveAndAddHostname(size_t ippos, size_t oldnamepos)
|
||||
}
|
||||
|
||||
// Resolve client host names
|
||||
static void resolveClients(const bool onlynew)
|
||||
static void resolveClients(const bool onlynew, const bool force_refreshing)
|
||||
{
|
||||
const time_t now = time(NULL);
|
||||
// Lock counter access here, we use a copy in the following loop
|
||||
@@ -386,7 +385,7 @@ static void resolveClients(const bool onlynew)
|
||||
|
||||
// Only try to resolve host names of clients which were recently active if we are re-resolving
|
||||
// Limit for a "recently active" client is two hours ago
|
||||
if(onlynew == false && client->lastQuery < now - 2*60*60)
|
||||
if(!force_refreshing && !onlynew && client->lastQuery < now - 2*60*60)
|
||||
{
|
||||
if(config.debug & DEBUG_RESOLVER)
|
||||
{
|
||||
@@ -401,7 +400,7 @@ static void resolveClients(const bool onlynew)
|
||||
|
||||
// If onlynew flag is set, we will only resolve new clients
|
||||
// If not, we will try to re-resolve all known clients
|
||||
if(onlynew && !newflag)
|
||||
if(!force_refreshing && onlynew && !newflag)
|
||||
{
|
||||
if(config.debug & DEBUG_RESOLVER)
|
||||
{
|
||||
@@ -419,17 +418,35 @@ static void resolveClients(const bool onlynew)
|
||||
IPv6 = true;
|
||||
|
||||
// If we're in refreshing mode (onlynew == false), we skip clients if
|
||||
// either IPv4-only or none is selected
|
||||
// 1. We should not refresh any hostnames
|
||||
// 2. We should only refresh IPv4 client, but this client is IPv6
|
||||
// 3. We should only refresh unknown hostnames, but leave
|
||||
// existing ones as they are
|
||||
if(onlynew == false &&
|
||||
(config.refresh_hostnames == REFRESH_NONE ||
|
||||
(config.refresh_hostnames == REFRESH_IPV4_ONLY && IPv6)))
|
||||
(config.refresh_hostnames == REFRESH_NONE ||
|
||||
(config.refresh_hostnames == REFRESH_IPV4_ONLY && IPv6) ||
|
||||
(config.refresh_hostnames == REFRESH_UNKNOWN && oldnamepos != 0)))
|
||||
{
|
||||
if(config.debug & DEBUG_RESOLVER)
|
||||
{
|
||||
logg("Skipping client %s (%s) because it should not be refreshed",
|
||||
getstr(ippos), getstr(oldnamepos));
|
||||
const char *reason = "N/A";
|
||||
if(config.refresh_hostnames == REFRESH_NONE)
|
||||
reason = "Not refreshing any hostnames";
|
||||
else if(config.refresh_hostnames == REFRESH_IPV4_ONLY)
|
||||
reason = "Only refreshing IPv4 names";
|
||||
else if(config.refresh_hostnames == REFRESH_UNKNOWN)
|
||||
reason = "Looking only for unknown hostnames";
|
||||
|
||||
logg("Skipping client %s (%s) because it should not be refreshed: %s",
|
||||
getstr(ippos), getstr(oldnamepos), reason);
|
||||
}
|
||||
skipped++;
|
||||
if(config.debug & DEBUG_RESOLVER)
|
||||
{
|
||||
lock_shm();
|
||||
logg("Client %s -> \"%s\" already known", getstr(ippos), getstr(oldnamepos));
|
||||
unlock_shm();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -454,6 +471,10 @@ static void resolveClients(const bool onlynew)
|
||||
client->namepos = newnamepos;
|
||||
// Mark entry as not new
|
||||
client->new = false;
|
||||
|
||||
if(config.debug & DEBUG_RESOLVER)
|
||||
logg("Client %s -> \"%s\" is new", getstr(ippos), getstr(newnamepos));
|
||||
|
||||
unlock_shm();
|
||||
}
|
||||
|
||||
@@ -511,6 +532,12 @@ static void resolveUpstreams(const bool onlynew)
|
||||
if(onlynew && !newflag)
|
||||
{
|
||||
skipped++;
|
||||
if(config.debug & DEBUG_RESOLVER)
|
||||
{
|
||||
lock_shm();
|
||||
logg("Upstream %s -> \"%s\" already known", getstr(ippos), getstr(oldnamepos));
|
||||
unlock_shm();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -535,6 +562,10 @@ static void resolveUpstreams(const bool onlynew)
|
||||
upstream->namepos = newnamepos;
|
||||
// Mark entry as not new
|
||||
upstream->new = false;
|
||||
|
||||
if(config.debug & DEBUG_RESOLVER)
|
||||
logg("Upstream %s -> \"%s\" is new", getstr(ippos), getstr(newnamepos));
|
||||
|
||||
unlock_shm();
|
||||
}
|
||||
|
||||
@@ -555,15 +586,17 @@ void *DNSclient_thread(void *val)
|
||||
|
||||
while(!killed)
|
||||
{
|
||||
// Run every minute to resolve only new clients and upstream servers
|
||||
if(resolver_ready && (time(NULL) % RESOLVE_INTERVAL == 0))
|
||||
// Run whenever necessary to resolve only new clients and
|
||||
// upstream servers
|
||||
if(resolver_ready && get_and_clear_event(RESOLVE_NEW_HOSTNAMES))
|
||||
{
|
||||
// Try to resolve new client host names (onlynew=true)
|
||||
resolveClients(true);
|
||||
// Try to resolve new upstream destination host names (onlynew=true)
|
||||
// Try to resolve new client host names
|
||||
// (onlynew=true)
|
||||
// We're not forcing refreshing here
|
||||
resolveClients(true, false);
|
||||
// Try to resolve new upstream destination host names
|
||||
// (onlynew=true)
|
||||
resolveUpstreams(true);
|
||||
// Prevent immediate re-run of this routine
|
||||
sleepms(500);
|
||||
}
|
||||
|
||||
// Run every hour to update possibly changed client host names
|
||||
@@ -572,19 +605,26 @@ void *DNSclient_thread(void *val)
|
||||
set_event(RERESOLVE_HOSTNAMES); // done below
|
||||
}
|
||||
|
||||
bool force_refreshing = false;
|
||||
if(get_and_clear_event(RERESOLVE_HOSTNAMES_FORCE))
|
||||
{
|
||||
set_event(RERESOLVE_HOSTNAMES); // done below
|
||||
force_refreshing = true;
|
||||
}
|
||||
|
||||
// Process resolver related event queue elements
|
||||
if(get_and_clear_event(RERESOLVE_HOSTNAMES))
|
||||
{
|
||||
// Try to resolve all client host names (onlynew=false)
|
||||
resolveClients(false);
|
||||
// Try to resolve all upstream destination host names (onlynew=false)
|
||||
// Try to resolve all client host names
|
||||
// (onlynew=false)
|
||||
resolveClients(false, force_refreshing);
|
||||
// Try to resolve all upstream destination host names
|
||||
// (onlynew=false)
|
||||
resolveUpstreams(false);
|
||||
// Prevent immediate re-run of this routine
|
||||
sleepms(500);
|
||||
}
|
||||
|
||||
// Idle for 0.1 sec before checking again the time criteria
|
||||
sleepms(100);
|
||||
// Idle for 1 sec before checking again the time criteria
|
||||
sleepms(1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "config.h"
|
||||
#include "setupVars.h"
|
||||
|
||||
|
||||
+86
-18
@@ -12,12 +12,13 @@
|
||||
#include "shmem.h"
|
||||
#include "overTime.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "config.h"
|
||||
// data getter functions
|
||||
#include "datastructure.h"
|
||||
// statvfs()
|
||||
#include <sys/statvfs.h>
|
||||
// get_num_regex()
|
||||
#include "regex_r.h"
|
||||
|
||||
/// The version of shared memory used
|
||||
#define SHARED_MEMORY_VERSION 10
|
||||
@@ -150,22 +151,81 @@ void chown_all_shmem(struct passwd *ent_pw)
|
||||
chown_shmem(&shm_per_client_regex, ent_pw);
|
||||
}
|
||||
|
||||
size_t addstr(const char *str)
|
||||
// A function that duplicates a string and replaces all characters "s" by "r"
|
||||
static char *__attribute__ ((malloc)) str_replace(const char *input,
|
||||
const char s,
|
||||
const char r,
|
||||
unsigned int *N)
|
||||
{
|
||||
if(str == NULL)
|
||||
// Duplicate string
|
||||
char *copy = strdup(input);
|
||||
if(copy == NULL)
|
||||
return NULL;
|
||||
|
||||
// Woring pointer
|
||||
char *ix = copy;
|
||||
// Loop over string until there are no further "s" chars in the string
|
||||
while((ix = strchr(ix, s)) != NULL)
|
||||
{
|
||||
*ix++ = r;
|
||||
(*N)++;
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
char *str_escape(const char *input, unsigned int *N)
|
||||
{
|
||||
// If no escaping is done, this routine returns the original pointer
|
||||
// and N stays 0
|
||||
*N = 0;
|
||||
char *out = (char *)input;
|
||||
if(strchr(input, ' ') != NULL)
|
||||
{
|
||||
// Replace any spaces by ~ if we find them in the domain name
|
||||
// This is necessary as our telnet API uses space delimiters
|
||||
out = str_replace(out, ' ', '~', N);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool strcmp_escaped(const char *a, const char *b)
|
||||
{
|
||||
if(a == NULL || b == NULL)
|
||||
return false;
|
||||
|
||||
unsigned int Na, Nb;
|
||||
char *aa = str_escape(a, &Na);
|
||||
char *bb = str_escape(b, &Nb);
|
||||
|
||||
const char result = strcasecmp(aa, bb) == 0;
|
||||
|
||||
if(Na > 0)
|
||||
free(aa);
|
||||
if(Nb > 0)
|
||||
free(bb);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
size_t addstr(const char *input)
|
||||
{
|
||||
if(input == NULL)
|
||||
{
|
||||
logg("WARN: Called addstr() with NULL pointer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get string length, add terminating character
|
||||
size_t len = strlen(str) + 1;
|
||||
size_t len = strlen(input) + 1;
|
||||
|
||||
// If this is an empty string (only the terminating character is present),
|
||||
// use the shared memory string at position zero instead of creating a new
|
||||
// entry here. We also ensure that the given string is not too long to
|
||||
// prevent possible memory corruption caused by strncpy() further down
|
||||
if(len == 1) {
|
||||
if(len == 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if(len > (size_t)(pagesize-1))
|
||||
@@ -174,6 +234,12 @@ size_t addstr(const char *str)
|
||||
len = pagesize;
|
||||
}
|
||||
|
||||
unsigned int N = 0;
|
||||
char *str = str_escape(input, &N);
|
||||
|
||||
if(N > 0)
|
||||
logg("INFO: FTL escaped %ui characters in \"%s\"", N, str);
|
||||
|
||||
// Debugging output
|
||||
if(config.debug & DEBUG_SHMEM)
|
||||
logg("Adding \"%s\" (len %zu) to buffer. next_str_pos is %u", str, len, shmSettings->next_str_pos);
|
||||
@@ -181,7 +247,11 @@ size_t addstr(const char *str)
|
||||
// Reserve additional memory if necessary
|
||||
if(shmSettings->next_str_pos + len > shm_strings.size &&
|
||||
!realloc_shm(&shm_strings, shm_strings.size + pagesize, sizeof(char), true))
|
||||
{
|
||||
if(N > 0)
|
||||
free(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Store new string buffer size in corresponding counters entry
|
||||
// for re-using when we need to re-map shared memory objects
|
||||
@@ -189,6 +259,8 @@ size_t addstr(const char *str)
|
||||
|
||||
// Copy the C string pointed by str into the shared string buffer
|
||||
strncpy(&((char*)shm_strings.ptr)[shmSettings->next_str_pos], str, len);
|
||||
if(N > 0)
|
||||
free(str);
|
||||
|
||||
// Increment string length counter
|
||||
shmSettings->next_str_pos += len;
|
||||
@@ -508,10 +580,10 @@ SharedMemory create_shm(const char *name, const size_t size, bool create_new)
|
||||
}
|
||||
|
||||
// Allocate shared memory object to specified size
|
||||
// Using fallocate() will ensure that there's actually space for
|
||||
// Using f[tl]allocate() will ensure that there's actually space for
|
||||
// this file. Otherwise we end up with a sparse file that can give
|
||||
// SIGBUS if we run out of space while writing to it.
|
||||
const int ret = fallocate(fd, 0, 0U, size);
|
||||
const int ret = ftlallocate(fd, 0U, size);
|
||||
if(ret != 0)
|
||||
{
|
||||
logg("FATAL: create_shm(): Failed to resize \"%s\" (%i) to %zu: %s (%i)",
|
||||
@@ -632,10 +704,10 @@ bool realloc_shm(SharedMemory *sharedMemory, const size_t size1, const size_t si
|
||||
}
|
||||
|
||||
// Allocate shared memory object to specified size
|
||||
// Using fallocate() will ensure that there's actually space for
|
||||
// Using f[tl]allocate() will ensure that there's actually space for
|
||||
// this file. Otherwise we end up with a sparse file that can give
|
||||
// SIGBUS if we run out of space while writing to it.
|
||||
const int ret = fallocate(fd, 0, 0U, size);
|
||||
const int ret = ftlallocate(fd, 0U, size);
|
||||
if(ret != 0)
|
||||
{
|
||||
logg("FATAL: realloc_shm(): Failed to resize \"%s\" (%i) to %zu: %s (%i)",
|
||||
@@ -644,7 +716,7 @@ bool realloc_shm(SharedMemory *sharedMemory, const size_t size1, const size_t si
|
||||
}
|
||||
|
||||
// Close shared memory object file descriptor as it is no longer
|
||||
// needed after having called fallocate()
|
||||
// needed after having called f[tl]allocate()
|
||||
close(fd);
|
||||
|
||||
// Update shm counters to indicate that at least one shared memory object changed
|
||||
@@ -817,8 +889,7 @@ void memory_check(const enum memory_type which)
|
||||
|
||||
void reset_per_client_regex(const int clientID)
|
||||
{
|
||||
const unsigned int num_regex_tot = counters->num_regex[REGEX_BLACKLIST] +
|
||||
counters->num_regex[REGEX_WHITELIST];
|
||||
const unsigned int num_regex_tot = get_num_regex(REGEX_MAX); // total number
|
||||
for(unsigned int i = 0u; i < num_regex_tot; i++)
|
||||
{
|
||||
// Zero-initialize/reset (= false) all regex (white + black)
|
||||
@@ -828,8 +899,7 @@ void reset_per_client_regex(const int clientID)
|
||||
|
||||
void add_per_client_regex(unsigned int clientID)
|
||||
{
|
||||
const unsigned int num_regex_tot = counters->num_regex[REGEX_BLACKLIST] +
|
||||
counters->num_regex[REGEX_WHITELIST];
|
||||
const unsigned int num_regex_tot = get_num_regex(REGEX_MAX); // total number
|
||||
const size_t size = counters->clients * num_regex_tot;
|
||||
if(size > shm_per_client_regex.size &&
|
||||
realloc_shm(&shm_per_client_regex, counters->clients, num_regex_tot, true))
|
||||
@@ -840,8 +910,7 @@ void add_per_client_regex(unsigned int clientID)
|
||||
|
||||
bool get_per_client_regex(const int clientID, const int regexID)
|
||||
{
|
||||
const unsigned int num_regex_tot = counters->num_regex[REGEX_BLACKLIST] +
|
||||
counters->num_regex[REGEX_WHITELIST];
|
||||
const unsigned int num_regex_tot = get_num_regex(REGEX_MAX); // total number
|
||||
const unsigned int id = clientID * num_regex_tot + regexID;
|
||||
const size_t maxval = shm_per_client_regex.size / sizeof(bool);
|
||||
if(id > maxval)
|
||||
@@ -856,8 +925,7 @@ 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)
|
||||
{
|
||||
const unsigned int num_regex_tot = counters->num_regex[REGEX_BLACKLIST] +
|
||||
counters->num_regex[REGEX_WHITELIST];
|
||||
const unsigned int num_regex_tot = get_num_regex(REGEX_MAX); // total number
|
||||
const unsigned int id = clientID * num_regex_tot + regexID;
|
||||
const size_t maxval = shm_per_client_regex.size / sizeof(bool);
|
||||
if(id > maxval)
|
||||
|
||||
+11
-1
@@ -53,7 +53,7 @@ typedef struct {
|
||||
int reply_domain;
|
||||
int dns_cache_size;
|
||||
int dns_cache_MAX;
|
||||
unsigned int num_regex[REGEX_MAX];
|
||||
unsigned int regex_change;
|
||||
} countersStruct;
|
||||
|
||||
extern countersStruct *counters;
|
||||
@@ -95,6 +95,16 @@ size_t addstr(const char *str);
|
||||
const char *getstr(const size_t pos);
|
||||
void *enlarge_shmem_struct(const char type);
|
||||
|
||||
/**
|
||||
* Escapes a string by replacing special characters, such as spaces
|
||||
*/
|
||||
char *str_escape(const char *input, unsigned int *N);
|
||||
|
||||
/**
|
||||
* Compare two strings. Escape them if needed
|
||||
*/
|
||||
bool strcmp_escaped(const char *a, const char *b);
|
||||
|
||||
/**
|
||||
* Create a new overTime client shared memory block.
|
||||
* This also updates `overTimeClientData`.
|
||||
|
||||
+14
-4
@@ -15,8 +15,6 @@
|
||||
#include "signals.h"
|
||||
// logg()
|
||||
#include "log.h"
|
||||
// free()
|
||||
#include "memory.h"
|
||||
// ls_dir()
|
||||
#include "files.h"
|
||||
// gettid()
|
||||
@@ -247,10 +245,17 @@ static void __attribute__((noreturn)) signal_handler(int sig, siginfo_t *si, voi
|
||||
}
|
||||
|
||||
static void SIGRT_handler(int signum, siginfo_t *si, void *unused)
|
||||
{
|
||||
{
|
||||
// Backup errno
|
||||
const int _errno = errno;
|
||||
|
||||
// Ignore real-time signals outside of the main process (TCP forks)
|
||||
if(mpid != getpid())
|
||||
{
|
||||
// Restore errno before returning
|
||||
errno = _errno;
|
||||
return;
|
||||
}
|
||||
|
||||
int rtsig = signum - SIGRTMIN;
|
||||
logg("Received: %s (%d -> %d)", strsignal(signum), signum, rtsig);
|
||||
@@ -283,13 +288,18 @@ static void SIGRT_handler(int signum, siginfo_t *si, void *unused)
|
||||
else if(rtsig == 4)
|
||||
{
|
||||
// Re-resolve all clients and forward destinations
|
||||
set_event(RERESOLVE_HOSTNAMES);
|
||||
// Force refreshing hostnames according to
|
||||
// REFRESH_HOSTNAMES config option
|
||||
set_event(RERESOLVE_HOSTNAMES_FORCE);
|
||||
}
|
||||
else if(rtsig == 5)
|
||||
{
|
||||
// Parse neighbor cache
|
||||
set_event(PARSE_NEIGHBOR_CACHE);
|
||||
}
|
||||
|
||||
// Restore errno before returning back to previous context
|
||||
errno = _errno;
|
||||
}
|
||||
|
||||
// Register SIGSEGV handler
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# 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
|
||||
# /src/syscalls/CMakeList.txt
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
set(sources
|
||||
accept.c
|
||||
asprintf.c
|
||||
calloc.c
|
||||
ftlallocate.c
|
||||
fopen.c
|
||||
fprintf.c
|
||||
free.c
|
||||
pthread_mutex_lock.c
|
||||
realloc.c
|
||||
recv.c
|
||||
recvfrom.c
|
||||
select.c
|
||||
sendto.c
|
||||
snprintf.c
|
||||
sprintf.c
|
||||
strdup.c
|
||||
syscalls.h
|
||||
vasprintf.c
|
||||
vfprintf.c
|
||||
vsnprintf.c
|
||||
vsprintf.c
|
||||
write.c
|
||||
)
|
||||
|
||||
add_library(syscalls OBJECT ${sources})
|
||||
target_compile_options(syscalls PRIVATE ${EXTRAWARN})
|
||||
@@ -0,0 +1,36 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for accept
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef accept
|
||||
int FTLaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, const char *file, const char *func, const int line)
|
||||
{
|
||||
int ret = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = accept(sockfd, addr, addrlen);
|
||||
}
|
||||
// Try again if the last accept() call failed due to an interruption by an
|
||||
// incoming signal
|
||||
while(ret < 0 && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(ret < 0)
|
||||
logg("WARN: Could not accept() in %s() (%s:%i): %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for asprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
int FTLasprintf(const char *file, const char *func, const int line, char **buffer, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int length = FTLvasprintf(file, func, line, buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for calloc
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef calloc
|
||||
void* __attribute__((malloc)) __attribute__((alloc_size(1,2))) FTLcalloc(const size_t nmemb, const size_t size, const char *file, const char *func, const int line)
|
||||
{
|
||||
// The FTLcalloc() func allocates memory for an array of nmemb elements
|
||||
// of size bytes each and returns a pointer to the allocated memory. The
|
||||
// memory is set to zero. If nmemb or size is 0, then calloc() returns
|
||||
// either NULL, or a unique pointer value that can later be successfully
|
||||
// passed to free().
|
||||
void *ptr = NULL;
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
ptr = calloc(nmemb, size);
|
||||
}
|
||||
// Try again to allocate memory if this failed due to an interruption by
|
||||
// an incoming signal
|
||||
while(ptr == NULL && errno == EINTR);
|
||||
|
||||
// Handle other errors than EINTR
|
||||
if(ptr == NULL)
|
||||
logg("FATAL: Memory allocation (%zu x %zu) failed in %s() (%s:%i)",
|
||||
nmemb, size, func, file, line);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for fopen
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef fopen
|
||||
FILE *FTLfopen(const char *pathname, const char *mode, const char *file, const char *func, const int line)
|
||||
{
|
||||
FILE *file_ptr = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
file_ptr = fopen(pathname, mode);
|
||||
}
|
||||
// Try again if the last accept() call failed due to an interruption by an
|
||||
// incoming signal
|
||||
while(file_ptr == NULL && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(file_ptr == NULL)
|
||||
logg("WARN: Could not fopen(\"%s\", \"%s\") in %s() (%s:%i): %s",
|
||||
pathname, mode, func, file, line, strerror(errno));
|
||||
|
||||
return file_ptr;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for fprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
int FTLfprintf(FILE *stream, const char *file, const char *func, const int line, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int length = FTLvfprintf(stream, file, func, line, format, args);
|
||||
va_end(args);
|
||||
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for free
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef free
|
||||
void FTLfree(void *ptr, const char *file, const char *func, const int line)
|
||||
{
|
||||
// The free() function frees the memory space pointed to by ptr, which
|
||||
// must have been returned by a previous call to malloc(), calloc(), or
|
||||
// realloc(). Otherwise, or if free(ptr) has already been called before,
|
||||
// undefined behavior occurs. If ptr is NULL, no operation is performed.
|
||||
if(ptr == NULL)
|
||||
{
|
||||
logg("WARN: Trying to free NULL pointer in %s() (%s:%i)", func, file, line);
|
||||
return;
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for fallocate
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
#include <fcntl.h>
|
||||
|
||||
// off_t is automatically set as off64_t when this is a 64bit system
|
||||
int FTLfallocate(const int fd, const off_t offset, const off_t len, const char *file, const char *func, const int line)
|
||||
{
|
||||
int ret = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = posix_fallocate(fd, offset, len);
|
||||
}
|
||||
// Try again if the last posix_fallocate() call failed due to an
|
||||
// interruption by an incoming signal
|
||||
while(ret < 0 && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(ret < 0)
|
||||
logg("WARN: Could not fallocate() in %s() (%s:%i): %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for pthread_mutex_lock
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#undef pthread_mutex_lock
|
||||
int FTLpthread_mutex_lock(pthread_mutex_t *__mutex, const char *file, const char *func, const int line)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = pthread_mutex_lock(__mutex);
|
||||
}
|
||||
// Try again if the last accept() call failed due to an interruption by an
|
||||
// incoming signal
|
||||
while(ret < 0 && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(ret < 0)
|
||||
logg("WARN: Could not pthread_mutex_lock() in %s() (%s:%i): %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for realloc
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef realloc
|
||||
void __attribute__((alloc_size(2))) *FTLrealloc(void *ptr_in, const size_t size, const char * file, const char * func, const int line)
|
||||
{
|
||||
// The FTLrealloc() function changes the size of the memory block pointed to
|
||||
// by ptr to size bytes. The contents will be unchanged in the range from
|
||||
// the start of the region up to the minimum of the old and new sizes. If
|
||||
// the new size is larger than the old size, the added memory will not be
|
||||
// initialized. If ptr is NULL, then the call is equivalent to malloc(size),
|
||||
// for all values of size; if size is equal to zero, and ptr is not NULL,
|
||||
// then the call is equivalent to free(ptr). Unless ptr is NULL, it must
|
||||
// have been returned by an earlier call to malloc(), calloc() or realloc().
|
||||
// If the area pointed to was moved, a free(ptr) is done implicitly.
|
||||
void *ptr_out = NULL;
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
ptr_out = realloc(ptr_in, size);
|
||||
}
|
||||
// Try again to allocate memory if this failed due to an interruption by
|
||||
// an incoming signal
|
||||
while(ptr_out == NULL && errno == EINTR);
|
||||
|
||||
// Handle other errors than EINTR
|
||||
if(ptr_out == NULL)
|
||||
logg("FATAL: Memory reallocation (%p -> %zu) failed in %s() (%s:%i)",
|
||||
ptr_in, size, func, file, line);
|
||||
|
||||
return ptr_out;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for recv
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#undef recv
|
||||
ssize_t FTLrecv(int sockfd, void *buf, size_t len, int flags, const char *file, const char *func, const int line)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = recv(sockfd, buf, len, flags);
|
||||
}
|
||||
// Try again if the last accept() call failed due to an interruption by an
|
||||
// incoming signal
|
||||
while(ret < 0 && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(ret < 0)
|
||||
logg("WARN: Could not recv() in %s() (%s:%i): %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for recvfrom
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#undef recvfrom
|
||||
ssize_t FTLrecvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen, const char *file, const char *func, const int line)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
|
||||
}
|
||||
// Try again if the last accept() call failed due to an interruption by an
|
||||
// incoming signal
|
||||
while(ret < 0 && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(ret < 0)
|
||||
logg("WARN: Could not recvfrom() in %s() (%s:%i): %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for select
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
#undef select
|
||||
int FTLselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout, const char *file, const char *func, const int line)
|
||||
{
|
||||
int ret = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = select(nfds, readfds, writefds, exceptfds, timeout);
|
||||
}
|
||||
// Try again if the last accept() call failed due to an interruption by an
|
||||
// incoming signal
|
||||
while(ret < 0 && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(ret < 0)
|
||||
logg("WARN: Could not select() in %s() (%s:%i): %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for sendto
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#undef sendto
|
||||
ssize_t FTLsendto(int sockfd, void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen, const char *file, const char *func, const int line)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
|
||||
}
|
||||
// Try again if the last accept() call failed due to an interruption by an
|
||||
// incoming signal
|
||||
while(ret < 0 && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(ret < 0)
|
||||
logg("WARN: Could not sendto() in %s() (%s:%i): %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for snprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
int FTLsnprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const size_t maxlen, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int length = FTLvsnprintf(file, func, line, buffer, maxlen, format, args);
|
||||
va_end(args);
|
||||
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for sprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
int FTLsprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
const int length = FTLvsprintf(file, func, line, buffer, format, args);
|
||||
va_end(args);
|
||||
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for strdup
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
char* __attribute__((malloc)) FTLstrdup(const char *src, const char *file, const char *func, const int line)
|
||||
{
|
||||
// The FTLstrdup() function returns a pointer to a new string which is a
|
||||
// duplicate of the string s. Memory for the new string is obtained with
|
||||
// calloc(3), and can be freed with free(3).
|
||||
if(src == NULL)
|
||||
{
|
||||
logg("WARN: Trying to copy a NULL string in %s() (%s:%i)", func, file, line);
|
||||
return NULL;
|
||||
}
|
||||
const size_t len = strlen(src);
|
||||
char *dest = FTLcalloc(len+1, sizeof(char), file, func, line);
|
||||
|
||||
// Return early in case of an unrecoverable error, error reporting has
|
||||
// already been done in FTLcalloc()
|
||||
if(dest == NULL)
|
||||
return NULL;
|
||||
|
||||
// Use memcpy as memory areas cannot overlap
|
||||
memcpy(dest, src, len);
|
||||
dest[len] = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* 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
|
||||
* Syscall prototypes
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
#ifndef SYSCALLS_H
|
||||
#define SYSCALLS_H
|
||||
|
||||
// Interrupt-safe memory routines
|
||||
char *FTLstrdup(const char *src, const char *file, const char *func, const int line) __attribute__((malloc));
|
||||
void *FTLcalloc(size_t n, size_t size, const char *file, const char *func, const int line) __attribute__((malloc)) __attribute__((alloc_size(1,2)));
|
||||
void *FTLrealloc(void *ptr_in, size_t size, const char *file, const char *func, const int line) __attribute__((alloc_size(2)));
|
||||
void FTLfree(void *ptr, const char*file, const char *func, const int line);
|
||||
int FTLfallocate(const int fd, const off_t offset, const off_t len, const char *file, const char *func, const int line);
|
||||
|
||||
|
||||
// Interrupt-safe printing routines
|
||||
// printf() is derived from fprintf(stdout, ...)
|
||||
// vprintf() is derived from vfprintf(stdout, ...)
|
||||
int FTLfprintf(FILE *stream, const char*file, const char *func, const int line, const char *format, ...) __attribute__ ((format (gnu_printf, 5, 6)));
|
||||
int FTLvfprintf(FILE *stream, const char*file, const char *func, const int line, const char *format, va_list args) __attribute__ ((format (gnu_printf, 5, 0)));
|
||||
|
||||
int FTLsprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const char *format, ...) __attribute__ ((format (gnu_printf, 5, 6)));
|
||||
int FTLvsprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const char *format, va_list args) __attribute__ ((format (gnu_printf, 5, 0)));
|
||||
|
||||
int FTLasprintf(const char *file, const char *func, const int line, char **buffer, const char *format, ...) __attribute__ ((format (gnu_printf, 5, 6)));
|
||||
int FTLvasprintf(const char *file, const char *func, const int line, char **buffer, const char *format, va_list args) __attribute__ ((format (gnu_printf, 5, 0)));
|
||||
|
||||
int FTLsnprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const size_t maxlen, const char *format, ...) __attribute__ ((format (gnu_printf, 6, 7)));
|
||||
int FTLvsnprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const size_t maxlen, const char *format, va_list args) __attribute__ ((format (gnu_printf, 6, 0)));
|
||||
|
||||
// Interrupt-safe socket routines
|
||||
ssize_t FTLwrite(int fd, const void *buf, size_t total, const char *file, const char *func, const int line);
|
||||
int FTLaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen, const char *file, const char *func, const int line);
|
||||
ssize_t FTLrecv(int sockfd, void *buf, size_t len, int flags, const char *file, const char *func, const int line);
|
||||
ssize_t FTLrecvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen, const char *file, const char *func, const int line);
|
||||
int FTLselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout, const char *file, const char *func, const int line);
|
||||
ssize_t FTLsendto(int sockfd, void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen, const char *file, const char *func, const int line);
|
||||
|
||||
// Interrupt-safe thread routines
|
||||
int FTLpthread_mutex_lock(pthread_mutex_t *__mutex, const char *file, const char *func, const int line);
|
||||
|
||||
// Interrupt-safe file routines
|
||||
FILE *FTLfopen(const char *pathname, const char *mode, const char *file, const char *func, const int line);
|
||||
|
||||
// Syscall helpers
|
||||
void syscalls_report_error(const char *error, FILE *stream, const int _errno, const char *format, const char *func, const char *file, const int line);
|
||||
|
||||
#endif //SYSCALLS_H
|
||||
@@ -0,0 +1,59 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for vasprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef vasprintf
|
||||
int FTLvasprintf(const char *file, const char *func, const int line, char **buffer, const char *format, va_list args)
|
||||
{
|
||||
// Sanity check
|
||||
if(buffer == NULL)
|
||||
{
|
||||
syscalls_report_error("vasprintf() called with NULL buffer",
|
||||
stdout, 0, format, func, file, line);
|
||||
return 0;
|
||||
}
|
||||
// Print into dynamically allocated memory
|
||||
int _errno, length = 0;
|
||||
do
|
||||
{
|
||||
// The va_copy() macro copies the (previously initialized) variable
|
||||
// argument list args to the local _args. The behavior is as if
|
||||
// va_start() were applied to _args with the same last argument,
|
||||
// followed by the same number of va_arg() invocations that was used to
|
||||
// reach the current state of args. We do this to be able to reuse the
|
||||
// arguments in args when we need to redo the string preparation
|
||||
// procedure
|
||||
va_list _args;
|
||||
va_copy(_args, args);
|
||||
// Reset errno before trying to get the string
|
||||
errno = 0;
|
||||
// Do the actual string transformation
|
||||
length = vasprintf(buffer, format, _args);
|
||||
// Copy errno into buffer before calling va_end()
|
||||
_errno = errno;
|
||||
va_end(_args);
|
||||
}
|
||||
// Try again to allocate memory if this failed due to an interruption by
|
||||
// an incoming signal
|
||||
while(length < 0 && _errno == EINTR);
|
||||
|
||||
// Handle other errors than EINTR
|
||||
if(length < 0)
|
||||
{
|
||||
syscalls_report_error("vasprintf() failed to print into buffer",
|
||||
stdout, _errno, format, func, file, line);
|
||||
}
|
||||
|
||||
// Return number of written bytes
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for vfprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
// itoa implementation using only static memory
|
||||
// taken from Kernighan and Ritchie's "The C Programming Language"
|
||||
// see https://clc-wiki.net/wiki/K&R2_solutions:Chapter_3:Exercise_4
|
||||
// This implementation has its drawbacks, however, we only use it for
|
||||
// automated conversion of code line numbers to strings so we're not
|
||||
// interested in its performance outside the range of [1, 10'000]
|
||||
static void itoa(int n, char s[])
|
||||
{
|
||||
int i = 0, sign = n;
|
||||
|
||||
// Make n positive if negative
|
||||
if (sign < 0)
|
||||
n = -n;
|
||||
|
||||
// Generate digits in reverse order
|
||||
do
|
||||
{
|
||||
s[i++] = n % 10 + '0'; /* get next digit */
|
||||
} while ((n /= 10) > 0); /* delete it */
|
||||
|
||||
// Add sign (if needed)
|
||||
if (sign < 0)
|
||||
s[i++] = '-';
|
||||
|
||||
// Rero-terminate string
|
||||
s[i] = '\0';
|
||||
|
||||
// Reverse string s in place
|
||||
int j;
|
||||
char c;
|
||||
int len = strlen(s);
|
||||
for (i = 0, j = len-1; i<j; i++, j--) {
|
||||
c = s[i];
|
||||
s[i] = s[j];
|
||||
s[j] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// Variant of fputs that prints newline characters as "\n"
|
||||
static int fputs_convert_newline(const char *string, FILE *stream)
|
||||
{
|
||||
int pos = 0;
|
||||
while(string[pos] != '\0')
|
||||
{
|
||||
if(string[pos] == '\n')
|
||||
{
|
||||
fputc('\\', stream);
|
||||
fputc('n', stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
fputc(string[pos], stream);
|
||||
}
|
||||
|
||||
pos++;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Special error reporting for our own vfprintf()
|
||||
// Since we cannot rely on (heap) being available (allocation may have failed
|
||||
// earlier), we do the reporting entirely manually, writing one string at a time
|
||||
void syscalls_report_error(const char *error, FILE *stream, const int _errno, const char *format, const char *func, const char *file, const int line)
|
||||
{
|
||||
char linestr[16] = { 0 };
|
||||
itoa(line, linestr);
|
||||
|
||||
fputs("WARN: ", stream);
|
||||
fputs(error, stream);
|
||||
fputs(": ", stream);
|
||||
fputs(strerror(_errno), stream);
|
||||
fputs("\n Not processing string \"", stream);
|
||||
fputs_convert_newline(format, stream);
|
||||
fputs("\" in ", stream);
|
||||
fputs(func, stream);
|
||||
fputs("() [", stream);
|
||||
fputs(file, stream);
|
||||
fputs(":", stream);
|
||||
fputs(linestr, stream);
|
||||
fputs("]\n", stream);
|
||||
}
|
||||
|
||||
// The actual vfprintf() routine
|
||||
int FTLvfprintf(FILE *stream, const char *file, const char *func, const int line, const char *format, va_list args)
|
||||
{
|
||||
// Print into dynamically allocated memory
|
||||
char *buffer = NULL;
|
||||
int _errno, length = 0;
|
||||
do
|
||||
{
|
||||
// The va_copy() macro copies the (previously initialized) variable
|
||||
// argument list args to the local _args. The behavior is as if
|
||||
// va_start() were applied to _args with the same last argument,
|
||||
// followed by the same number of va_arg() invocations that was used to
|
||||
// reach the current state of args. We do this to be able to reuse the
|
||||
// arguments in args when we need to redo the string preparation
|
||||
// procedure
|
||||
va_list _args;
|
||||
va_copy(_args, args);
|
||||
// Reset errno before trying to get the string
|
||||
errno = 0;
|
||||
// Do the actual string transformation
|
||||
length = vasprintf(&buffer, format, _args);
|
||||
// Copy errno into buffer before calling va_end()
|
||||
_errno = errno;
|
||||
va_end(_args);
|
||||
}
|
||||
// Try again to allocate memory if this failed due to an interruption by
|
||||
// an incoming signal
|
||||
while(length < 0 && _errno == EINTR);
|
||||
|
||||
// Handle other errors than EINTR
|
||||
if(length < 0 || buffer == NULL)
|
||||
{
|
||||
syscalls_report_error("vfprintf() failed to allocate memory",
|
||||
stream, _errno, format, func, file, line);
|
||||
|
||||
// Free the buffer in case anything got allocated
|
||||
if(buffer != NULL)
|
||||
free(buffer);
|
||||
|
||||
// Return early, there isn't anything we can do here
|
||||
return length;
|
||||
}
|
||||
|
||||
// Actually write into the requested stream now
|
||||
char *_buffer = buffer;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
// Print buffer into stream and advance working pointer by number of
|
||||
// written bytes
|
||||
_buffer += fputs(_buffer, stream);
|
||||
}
|
||||
// Try to write the remaining content into the stream if this failed due
|
||||
// to an interruption by an incoming signal
|
||||
while(_buffer < buffer && errno == EINTR);
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(_buffer < buffer)
|
||||
{
|
||||
syscalls_report_error("vfprintf() did not print all characters",
|
||||
stream, errno, format, func, file, line);
|
||||
}
|
||||
|
||||
// Free allocated memory
|
||||
free(buffer);
|
||||
|
||||
// Return number of written bytes
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for vsnprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef vsnprintf
|
||||
int FTLvsnprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const size_t maxlen, const char *format, va_list args)
|
||||
{
|
||||
// Sanity check
|
||||
if(buffer == NULL)
|
||||
{
|
||||
syscalls_report_error("vsnprintf() called with NULL buffer",
|
||||
stdout, 0, format, func, file, line);
|
||||
return 0;
|
||||
}
|
||||
// Print into dynamically allocated memory
|
||||
int _errno, length = 0;
|
||||
do
|
||||
{
|
||||
// The va_copy() macro copies the (previously initialized) variable
|
||||
// argument list args to the local _args. The behavior is as if
|
||||
// va_start() were applied to _args with the same last argument,
|
||||
// followed by the same number of va_arg() invocations that was used to
|
||||
// reach the current state of args. We do this to be able to reuse the
|
||||
// arguments in args when we need to redo the string preparation
|
||||
// procedure
|
||||
va_list _args;
|
||||
va_copy(_args, args);
|
||||
// Reset errno before trying to get the string
|
||||
errno = 0;
|
||||
// Do the actual string transformation
|
||||
length = vsnprintf(buffer, maxlen, format, _args);
|
||||
// Copy errno into buffer before calling va_end()
|
||||
_errno = errno;
|
||||
va_end(_args);
|
||||
}
|
||||
// Try again to allocate memory if this failed due to an interruption by
|
||||
// an incoming signal
|
||||
while(length < 0 && _errno == EINTR);
|
||||
|
||||
// Handle other errors than EINTR
|
||||
if(length < 0)
|
||||
{
|
||||
syscalls_report_error("vsnprintf() failed to print into buffer",
|
||||
stdout, _errno, format, func, file, line);
|
||||
}
|
||||
|
||||
// Return number of written bytes
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for vsprintf
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef vsprintf
|
||||
int FTLvsprintf(const char *file, const char *func, const int line, char *__restrict__ buffer, const char *format, va_list args)
|
||||
{
|
||||
// Sanity check
|
||||
if(buffer == NULL)
|
||||
{
|
||||
syscalls_report_error("vsprintf() called with NULL buffer",
|
||||
stdout, 0, format, func, file, line);
|
||||
return 0;
|
||||
}
|
||||
// Print into dynamically allocated memory
|
||||
int _errno, length = 0;
|
||||
do
|
||||
{
|
||||
// The va_copy() macro copies the (previously initialized) variable
|
||||
// argument list args to the local _args. The behavior is as if
|
||||
// va_start() were applied to _args with the same last argument,
|
||||
// followed by the same number of va_arg() invocations that was used to
|
||||
// reach the current state of args. We do this to be able to reuse the
|
||||
// arguments in args when we need to redo the string preparation
|
||||
// procedure
|
||||
va_list _args;
|
||||
va_copy(_args, args);
|
||||
// Reset errno before trying to get the string
|
||||
errno = 0;
|
||||
// Do the actual string transformation
|
||||
length = vsprintf(buffer, format, _args);
|
||||
// Copy errno into buffer before calling va_end()
|
||||
_errno = errno;
|
||||
va_end(_args);
|
||||
}
|
||||
// Try again to allocate memory if this failed due to an interruption by
|
||||
// an incoming signal
|
||||
while(length < 0 && _errno == EINTR);
|
||||
|
||||
// Handle other errors than EINTR
|
||||
if(length < 0)
|
||||
{
|
||||
syscalls_report_error("vsprintf() failed to print into buffer",
|
||||
stdout, _errno, format, func, file, line);
|
||||
}
|
||||
|
||||
// Return number of written bytes
|
||||
return length;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* 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
|
||||
* Pi-hole syscall implementation for write
|
||||
*
|
||||
* 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 "syscalls.h" is implicitly done in FTL.h
|
||||
#include "../log.h"
|
||||
|
||||
#undef write
|
||||
ssize_t FTLwrite(int fd, const void *buf, size_t total, const char *file, const char *func, const int line)
|
||||
{
|
||||
if(buf == NULL)
|
||||
{
|
||||
logg("ERROR: Trying to write a NULL string in %s() (%s:%i)", func, file, line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t ret = 0;
|
||||
size_t written = 0;
|
||||
do
|
||||
{
|
||||
// Reset errno before trying to write
|
||||
errno = 0;
|
||||
ret = write(fd, buf, total);
|
||||
if(ret > 0)
|
||||
written += ret;
|
||||
}
|
||||
// Try to write the remaining content into the stream if
|
||||
// (a) we haven't written all the data, however, there was no other error
|
||||
// (b) the last write() call failed due to an interruption by an incoming signal
|
||||
while((written < total && errno == 0) || (ret < 0 && errno == EINTR));
|
||||
|
||||
// Final error checking (may have faild for some other reason then an
|
||||
// EINTR = interrupted system call)
|
||||
if(written < total)
|
||||
logg("WARN: Could not write() everything in %s() [%s:%i]: %s",
|
||||
func, file, line, strerror(errno));
|
||||
|
||||
return written;
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include "FTL.h"
|
||||
#include "timers.h"
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
|
||||
struct timespec t0[NUMTIMERS];
|
||||
|
||||
@@ -473,7 +473,8 @@
|
||||
run bash -c '/home/pihole/pihole-FTL abc'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
[[ ${lines[0]} == "pihole-FTL: invalid option -- 'abc'" ]]
|
||||
[[ ${lines[1]} == "Try '/home/pihole/pihole-FTL --help' for more information" ]]
|
||||
[[ ${lines[1]} == "Command: '/home/pihole/pihole-FTL abc'" ]]
|
||||
[[ ${lines[2]} == "Try '/home/pihole/pihole-FTL --help' for more information" ]]
|
||||
}
|
||||
|
||||
@test "Help CLI argument return help text" {
|
||||
|
||||
Reference in New Issue
Block a user