mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
Merge branch 'development' into update/dnsmasq-v2.86
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
+2
-1
@@ -27,7 +27,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
# SQLITE_DEFAULT_FOREIGN_KEYS=1: This macro determines whether enforcement of foreign key constraints is enabled or disabled by default for new database connections.
|
||||
# SQLITE_DQS=0: This setting disables the double-quoted string literal misfeature.
|
||||
# SQLITE_ENABLE_DBPAGE_VTAB: Enables the SQLITE_DBPAGE virtual table. Warning: writing to the SQLITE_DBPAGE virtual table can very easily cause unrecoverably database corruption.
|
||||
set(SQLITE_DEFINES "-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_DEFAULT_FOREIGN_KEYS=1 -DSQLITE_DQS=0 -DSQLITE_ENABLE_DBPAGE_VTAB")
|
||||
# SQLITE_OMIT_DESERIALIZE: This option causes the the sqlite3_serialize() and sqlite3_deserialize() interfaces to be omitted from the build (was the default before 3.36.0)
|
||||
set(SQLITE_DEFINES "-DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_DEFAULT_FOREIGN_KEYS=1 -DSQLITE_DQS=0 -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_OMIT_DESERIALIZE")
|
||||
|
||||
# Code hardening and debugging improvements
|
||||
# -fstack-protector-strong: The program will be resistant to having its stack overflowed
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "database/common.h"
|
||||
// destroy_shmem()
|
||||
#include "shmem.h"
|
||||
// uname()
|
||||
#include <sys/utsname.h>
|
||||
// killed
|
||||
#include "signals.h"
|
||||
|
||||
@@ -141,6 +143,30 @@ char *getUserName(void)
|
||||
return name;
|
||||
}
|
||||
|
||||
// "man 7 hostname" says:
|
||||
//
|
||||
// Each element of the hostname must be from 1 to 63 characters long and the
|
||||
// entire hostname, including the dots, can be at most 253 characters long.
|
||||
//
|
||||
// Valid characters for hostnames are ASCII(7) letters from a to z, the
|
||||
// digits from 0 to 9, and the hyphen (-). A hostname may not start with a
|
||||
// hyphen.
|
||||
#define HOSTNAMESIZE 256
|
||||
static char nodename[HOSTNAMESIZE] = { 0 };
|
||||
const char *hostname(void)
|
||||
{
|
||||
// Ask kernel for node name if not known
|
||||
// This is equivalent to "uname -n"
|
||||
if(nodename[0] == '\0')
|
||||
{
|
||||
struct utsname buf;
|
||||
if(uname(&buf) == 0)
|
||||
strncpy(nodename, buf.nodename, HOSTNAMESIZE);
|
||||
nodename[HOSTNAMESIZE-1] = '\0';
|
||||
}
|
||||
return nodename;
|
||||
}
|
||||
|
||||
void delay_startup(void)
|
||||
{
|
||||
// Exit early if not sleeping
|
||||
|
||||
@@ -16,6 +16,7 @@ extern pthread_t threads[THREADS_MAX];
|
||||
void go_daemon(void);
|
||||
void savepid(void);
|
||||
char *getUserName(void);
|
||||
const char *hostname(void);
|
||||
void delay_startup(void);
|
||||
bool is_fork(const pid_t mpid, const pid_t pid) __attribute__ ((const));
|
||||
void cleanup(const int ret);
|
||||
|
||||
+895
-61
File diff suppressed because it is too large
Load Diff
+4237
-2949
File diff suppressed because it is too large
Load Diff
+111
-22
@@ -123,9 +123,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.35.4"
|
||||
#define SQLITE_VERSION_NUMBER 3035004
|
||||
#define SQLITE_SOURCE_ID "2021-04-02 15:20:15 5d4c65779dab868b285519b19e4cf9d451d50c6048f06f653aa701ec212df45e"
|
||||
#define SQLITE_VERSION "3.36.0"
|
||||
#define SQLITE_VERSION_NUMBER 3036000
|
||||
#define SQLITE_SOURCE_ID "2021-06-18 18:36:39 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@@ -1128,6 +1128,23 @@ struct sqlite3_io_methods {
|
||||
** file to the database file, but before the *-shm file is updated to
|
||||
** record the fact that the pages have been checkpointed.
|
||||
** </ul>
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
|
||||
** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
|
||||
** whether or not there is a database client in another process with a wal-mode
|
||||
** transaction open on the database or not. It is only available on unix.The
|
||||
** (void*) argument passed with this file-control should be a pointer to a
|
||||
** value of type (int). The integer value is set to 1 if the database is a wal
|
||||
** mode database and there exists at least one client in another process that
|
||||
** currently has an SQL transaction open on the database. It is set to 0 if
|
||||
** the database is not a wal-mode db, or if there is no such connection in any
|
||||
** other process. This opcode cannot be used to detect transactions opened
|
||||
** by clients within the current process, only within other processes.
|
||||
** </ul>
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
|
||||
** Used by the cksmvfs VFS module only.
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_FCNTL_GET_LOCKPROXYFILE 2
|
||||
@@ -1167,6 +1184,8 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_CKPT_DONE 37
|
||||
#define SQLITE_FCNTL_RESERVE_BYTES 38
|
||||
#define SQLITE_FCNTL_CKPT_START 39
|
||||
#define SQLITE_FCNTL_EXTERNAL_READER 40
|
||||
#define SQLITE_FCNTL_CKSM_FILE 41
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -4179,6 +4198,15 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
||||
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
|
||||
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
|
||||
** sqlite3_stmt_readonly() returns false for those commands.
|
||||
**
|
||||
** ^This routine returns false if there is any possibility that the
|
||||
** statement might change the database file. ^A false return does
|
||||
** not guarantee that the statement will change the database file.
|
||||
** ^For example, an UPDATE statement might have a WHERE clause that
|
||||
** makes it a no-op, but the sqlite3_stmt_readonly() result would still
|
||||
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
|
||||
** read-only no-op if the table already exists, but
|
||||
** sqlite3_stmt_readonly() still returns false for such a statement.
|
||||
*/
|
||||
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||
|
||||
@@ -4348,18 +4376,22 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** contain embedded NULs. The result of expressions involving strings
|
||||
** with embedded NULs is undefined.
|
||||
**
|
||||
** ^The fifth argument to the BLOB and string binding interfaces
|
||||
** is a destructor used to dispose of the BLOB or
|
||||
** string after SQLite has finished with it. ^The destructor is called
|
||||
** to dispose of the BLOB or string even if the call to the bind API fails,
|
||||
** except the destructor is not called if the third parameter is a NULL
|
||||
** pointer or the fourth parameter is negative.
|
||||
** ^If the fifth argument is
|
||||
** the special value [SQLITE_STATIC], then SQLite assumes that the
|
||||
** information is in static, unmanaged space and does not need to be freed.
|
||||
** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
|
||||
** SQLite makes its own private copy of the data immediately, before
|
||||
** the sqlite3_bind_*() routine returns.
|
||||
** ^The fifth argument to the BLOB and string binding interfaces controls
|
||||
** or indicates the lifetime of the object referenced by the third parameter.
|
||||
** These three options exist:
|
||||
** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished
|
||||
** with it may be passed. ^It is called to dispose of the BLOB or string even
|
||||
** if the call to the bind API fails, except the destructor is not called if
|
||||
** the third parameter is a NULL pointer or the fourth parameter is negative.
|
||||
** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
|
||||
** the application remains responsible for disposing of the object. ^In this
|
||||
** case, the object and the provided pointer to it must remain valid until
|
||||
** either the prepared statement is finalized or the same SQL parameter is
|
||||
** bound to something else, whichever occurs sooner.
|
||||
** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the
|
||||
** object is to be copied prior to the return from sqlite3_bind_*(). ^The
|
||||
** object and pointer to it must remain valid until then. ^SQLite will then
|
||||
** manage the lifetime of its private copy.
|
||||
**
|
||||
** ^The sixth argument to sqlite3_bind_text64() must be one of
|
||||
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
|
||||
@@ -5101,7 +5133,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
|
||||
** index expressions, or the WHERE clause of partial indexes.
|
||||
**
|
||||
** <span style="background-color:#ffff90;">
|
||||
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
|
||||
** all application-defined SQL functions that do not need to be
|
||||
** used inside of triggers, view, CHECK constraints, or other elements of
|
||||
@@ -5111,7 +5142,6 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** a database file to include invocations of the function with parameters
|
||||
** chosen by the attacker, which the application will then execute when
|
||||
** the database file is opened and read.
|
||||
** </span>
|
||||
**
|
||||
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
|
||||
** function can gain access to this pointer using [sqlite3_user_data()].)^
|
||||
@@ -7779,7 +7809,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
|
||||
#define SQLITE_TESTCTRL_SEEK_COUNT 30
|
||||
#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
||||
#define SQLITE_TESTCTRL_LAST 31 /* Largest TESTCTRL */
|
||||
#define SQLITE_TESTCTRL_TUNE 32
|
||||
#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Keyword Checking
|
||||
@@ -9531,6 +9562,15 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
||||
** triggers; or 2 for changes resulting from triggers called by top-level
|
||||
** triggers; and so forth.
|
||||
**
|
||||
** When the [sqlite3_blob_write()] API is used to update a blob column,
|
||||
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
|
||||
** in this case the new values are not available. In this case, when a
|
||||
** callback made with op==SQLITE_DELETE is actuall a write using the
|
||||
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
|
||||
** the index of the column being written. In other cases, where the
|
||||
** pre-update hook is being invoked for some other reason, including a
|
||||
** regular DELETE, sqlite3_preupdate_blobwrite() returns -1.
|
||||
**
|
||||
** See also: [sqlite3_update_hook()]
|
||||
*/
|
||||
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
||||
@@ -9551,6 +9591,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
|
||||
SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
|
||||
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
|
||||
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
|
||||
SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -9789,8 +9830,8 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
|
||||
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
|
||||
** allocation error occurs.
|
||||
**
|
||||
** This interface is only available if SQLite is compiled with the
|
||||
** [SQLITE_ENABLE_DESERIALIZE] option.
|
||||
** This interface is omitted if SQLite is compiled with the
|
||||
** [SQLITE_OMIT_DESERIALIZE] option.
|
||||
*/
|
||||
SQLITE_API unsigned char *sqlite3_serialize(
|
||||
sqlite3 *db, /* The database connection */
|
||||
@@ -9841,8 +9882,8 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
||||
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
|
||||
** [sqlite3_free()] is invoked on argument P prior to returning.
|
||||
**
|
||||
** This interface is only available if SQLite is compiled with the
|
||||
** [SQLITE_ENABLE_DESERIALIZE] option.
|
||||
** This interface is omitted if SQLite is compiled with the
|
||||
** [SQLITE_OMIT_DESERIALIZE] option.
|
||||
*/
|
||||
SQLITE_API int sqlite3_deserialize(
|
||||
sqlite3 *db, /* The database connection */
|
||||
@@ -10091,6 +10132,38 @@ SQLITE_API int sqlite3session_create(
|
||||
*/
|
||||
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
|
||||
|
||||
/*
|
||||
** CAPIREF: Conigure a Session Object
|
||||
** METHOD: sqlite3_session
|
||||
**
|
||||
** This method is used to configure a session object after it has been
|
||||
** created. At present the only valid value for the second parameter is
|
||||
** [SQLITE_SESSION_OBJCONFIG_SIZE].
|
||||
**
|
||||
** Arguments for sqlite3session_object_config()
|
||||
**
|
||||
** The following values may passed as the the 4th parameter to
|
||||
** sqlite3session_object_config().
|
||||
**
|
||||
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
|
||||
** This option is used to set, clear or query the flag that enables
|
||||
** the [sqlite3session_changeset_size()] API. Because it imposes some
|
||||
** computational overhead, this API is disabled by default. Argument
|
||||
** pArg must point to a value of type (int). If the value is initially
|
||||
** 0, then the sqlite3session_changeset_size() API is disabled. If it
|
||||
** is greater than 0, then the same API is enabled. Or, if the initial
|
||||
** value is less than zero, no change is made. In all cases the (int)
|
||||
** variable is set to 1 if the sqlite3session_changeset_size() API is
|
||||
** enabled following the current call, or 0 otherwise.
|
||||
**
|
||||
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
|
||||
** the first table has been attached to the session object.
|
||||
*/
|
||||
SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
|
||||
|
||||
/*
|
||||
*/
|
||||
#define SQLITE_SESSION_OBJCONFIG_SIZE 1
|
||||
|
||||
/*
|
||||
** CAPI3REF: Enable Or Disable A Session Object
|
||||
@@ -10335,6 +10408,22 @@ SQLITE_API int sqlite3session_changeset(
|
||||
void **ppChangeset /* OUT: Buffer containing changeset */
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Return An Upper-limit For The Size Of The Changeset
|
||||
** METHOD: sqlite3_session
|
||||
**
|
||||
** By default, this function always returns 0. For it to return
|
||||
** a useful result, the sqlite3_session object must have been configured
|
||||
** to enable this API using sqlite3session_object_config() with the
|
||||
** SQLITE_SESSION_OBJCONFIG_SIZE verb.
|
||||
**
|
||||
** When enabled, this function returns an upper limit, in bytes, for the size
|
||||
** of the changeset that might be produced if sqlite3session_changeset() were
|
||||
** called. The final changeset size might be equal to or smaller than the
|
||||
** size in bytes returned by this function.
|
||||
*/
|
||||
SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Load The Difference Between Tables Into A Session
|
||||
** METHOD: sqlite3_session
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ ASSERT_SIZEOF(domainsData, 24, 16, 16);
|
||||
typedef struct {
|
||||
unsigned char magic;
|
||||
enum domain_client_status blocking_status;
|
||||
unsigned char force_reply;
|
||||
enum reply_type force_reply;
|
||||
enum query_types query_type;
|
||||
int domainID;
|
||||
int clientID;
|
||||
|
||||
+381
-345
@@ -50,6 +50,8 @@ static void print_flags(const unsigned int flags);
|
||||
#define query_set_reply(flags, addr, query, response) _query_set_reply(flags, addr, query, response, __FILE__, __LINE__)
|
||||
static void _query_set_reply(const unsigned int flags, const union all_addr *addr, queriesData* query, const struct timeval response,
|
||||
const char *file, const int line);
|
||||
#define FTL_check_blocking(queryID, domainID, clientID) _FTL_check_blocking(queryID, domainID, clientID, __FILE__, __LINE__)
|
||||
static bool _FTL_check_blocking(int queryID, int domainID, int clientID, const char* file, const int line);
|
||||
static unsigned long converttimeval(const struct timeval time) __attribute__((const));
|
||||
static enum query_status detect_blocked_IP(const unsigned short flags, const union all_addr *addr, const queriesData *query, const domainsData *domain);
|
||||
static void query_blocked(queriesData* query, domainsData* domain, clientsData* client, const unsigned char new_status);
|
||||
@@ -61,7 +63,7 @@ static void FTL_dnssec(const char *result, const int id, const char* file, const
|
||||
// Static blocking metadata
|
||||
static const char *blockingreason = NULL;
|
||||
static union all_addr null_addrp = {{ 0 }};
|
||||
static unsigned char force_next_DNS_reply = 0u;
|
||||
static enum reply_type force_next_DNS_reply = REPLY_UNKNOWN;
|
||||
|
||||
// Adds debug information to the regular pihole.log file
|
||||
char debug_dnsmasq_lines = 0;
|
||||
@@ -218,7 +220,9 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
|
||||
if(flags & F_IPV4)
|
||||
{
|
||||
union all_addr *addr;
|
||||
if(config.blockingmode == MODE_IP || config.blockingmode == MODE_IP_NODATA_AAAA)
|
||||
if(config.blockingmode == MODE_IP ||
|
||||
config.blockingmode == MODE_IP_NODATA_AAAA ||
|
||||
force_next_DNS_reply == REPLY_IP)
|
||||
addr = &next_iface.addr4;
|
||||
else
|
||||
addr = &null_addrp;
|
||||
@@ -235,7 +239,8 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
|
||||
if(flags & F_IPV6)
|
||||
{
|
||||
union all_addr *addr;
|
||||
if(config.blockingmode == MODE_IP)
|
||||
if(config.blockingmode == MODE_IP ||
|
||||
force_next_DNS_reply == REPLY_IP)
|
||||
addr = &next_iface.addr6;
|
||||
else
|
||||
addr = &null_addrp;
|
||||
@@ -255,6 +260,345 @@ size_t _FTL_make_answer(struct dns_header *header, char *limit, const size_t len
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
bool _FTL_new_query(const unsigned int flags, const char *name,
|
||||
union mysockaddr *addr, const char *types,
|
||||
const unsigned short qtype, const int id,
|
||||
const ednsData *edns, const enum protocol proto,
|
||||
const char* file, const int line)
|
||||
{
|
||||
// Create new query in data structure
|
||||
|
||||
// Get timestamp
|
||||
const time_t querytimestamp = time(NULL);
|
||||
|
||||
// Save request time
|
||||
struct timeval request;
|
||||
gettimeofday(&request, 0);
|
||||
|
||||
// Determine query type
|
||||
enum query_types querytype;
|
||||
switch(qtype)
|
||||
{
|
||||
case T_A:
|
||||
querytype = TYPE_A;
|
||||
break;
|
||||
case T_AAAA:
|
||||
querytype = TYPE_AAAA;
|
||||
break;
|
||||
case T_ANY:
|
||||
querytype = TYPE_ANY;
|
||||
break;
|
||||
case T_SRV:
|
||||
querytype = TYPE_SRV;
|
||||
break;
|
||||
case T_SOA:
|
||||
querytype = TYPE_SOA;
|
||||
break;
|
||||
case T_PTR:
|
||||
querytype = TYPE_PTR;
|
||||
break;
|
||||
case T_TXT:
|
||||
querytype = TYPE_TXT;
|
||||
break;
|
||||
case T_NAPTR:
|
||||
querytype = TYPE_NAPTR;
|
||||
break;
|
||||
case T_MX:
|
||||
querytype = TYPE_MX;
|
||||
break;
|
||||
case T_DS:
|
||||
querytype = TYPE_DS;
|
||||
break;
|
||||
case T_RRSIG:
|
||||
querytype = TYPE_RRSIG;
|
||||
break;
|
||||
case T_DNSKEY:
|
||||
querytype = TYPE_DNSKEY;
|
||||
break;
|
||||
case T_NS:
|
||||
querytype = TYPE_NS;
|
||||
break;
|
||||
case 64: // Scn. 2 of https://datatracker.ietf.org/doc/draft-ietf-dnsop-svcb-https/
|
||||
querytype = TYPE_SVCB;
|
||||
break;
|
||||
case 65: // Scn. 2 of https://datatracker.ietf.org/doc/draft-ietf-dnsop-svcb-https/
|
||||
querytype = TYPE_HTTPS;
|
||||
break;
|
||||
default:
|
||||
querytype = TYPE_OTHER;
|
||||
break;
|
||||
}
|
||||
|
||||
// If domain is "pi.hole" or the local hostname we skip analyzing this query
|
||||
// and, instead, immediately reply with the IP address - these queries are not further analyzed
|
||||
if(strcasecmp(name, "pi.hole") == 0 || strcasecmp(name, hostname()) == 0)
|
||||
{
|
||||
if(querytype == TYPE_A || querytype == TYPE_AAAA || querytype == TYPE_ANY)
|
||||
{
|
||||
// "Block" this query by sending the interface IP address
|
||||
force_next_DNS_reply = REPLY_IP;
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
logg("Replying to %s with interface-local IP address", name);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't block this query
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip AAAA queries if user doesn't want to have them analyzed
|
||||
if(!config.analyze_AAAA && querytype == TYPE_AAAA)
|
||||
{
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
logg("Not analyzing AAAA query");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert domain to lower case
|
||||
char *domainString = strdup(name);
|
||||
strtolower(domainString);
|
||||
|
||||
// Get client IP address
|
||||
// The requestor's IP address can be rewritten using EDNS(0) client
|
||||
// subnet (ECS) data), however, we do not rewrite the IPs ::1 and
|
||||
// 127.0.0.1 to avoid queries originating from localhost of the
|
||||
// *distant* machine as queries coming from the *local* machine
|
||||
const sa_family_t family = addr ? addr->sa.sa_family : AF_INET;
|
||||
bool internal_query = false;
|
||||
char clientIP[ADDRSTRLEN+1] = { 0 };
|
||||
if(config.edns0_ecs && edns && edns->client_set)
|
||||
{
|
||||
// Use ECS provided client
|
||||
strncpy(clientIP, edns->client, ADDRSTRLEN);
|
||||
clientIP[ADDRSTRLEN] = '\0';
|
||||
}
|
||||
else if(addr)
|
||||
{
|
||||
// Use original requestor
|
||||
inet_ntop(family,
|
||||
family == AF_INET ?
|
||||
(union alladdr*)&addr->in.sin_addr :
|
||||
(union alladdr*)&addr->in6.sin6_addr,
|
||||
clientIP, ADDRSTRLEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No client address available, this is an automatically generated (e.g.
|
||||
// DNSSEC) query
|
||||
internal_query = true;
|
||||
strcpy(clientIP, "::");
|
||||
}
|
||||
|
||||
// Check if user wants to skip queries coming from localhost
|
||||
if(config.ignore_localhost &&
|
||||
(strcmp(clientIP, "127.0.0.1") == 0 || strcmp(clientIP, "::1") == 0))
|
||||
{
|
||||
free(domainString);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
const int queryID = counters->queries;
|
||||
|
||||
// Find client IP
|
||||
const int clientID = findClientID(clientIP, true, false);
|
||||
|
||||
// Get client pointer
|
||||
clientsData* client = getClient(clientID, true);
|
||||
if(client == NULL)
|
||||
{
|
||||
// Encountered memory error, skip query
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Interface name is only available for regular queries, not for
|
||||
// automatically generated DNSSEC queries
|
||||
const char *interface = internal_query ? "-" : next_iface.name;
|
||||
|
||||
// Check rate-limit for this client
|
||||
if(!internal_query && config.rate_limit.count > 0 &&
|
||||
++client->rate_limit > config.rate_limit.count)
|
||||
{
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
logg("Rate-limiting %sIPv%d %s query \"%s\" from %s:%s",
|
||||
proto == TCP ? "TCP " : proto == UDP ? "UDP " : "",
|
||||
family == AF_INET ? 4 : 6, types, domainString, interface, clientIP);
|
||||
}
|
||||
|
||||
// Block this query
|
||||
force_next_DNS_reply = REPLY_REFUSED;
|
||||
|
||||
// Do not further process this query, Pi-hole has never seen it
|
||||
unlock_shm();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Log new query if in debug mode
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
logg("**** new %sIPv%d %s query \"%s\" from %s:%s (ID %i, FTL %i, %s:%i)",
|
||||
proto == TCP ? "TCP " : proto == UDP ? "UDP " : "",
|
||||
family == AF_INET ? 4 : 6, types, domainString, interface,
|
||||
internal_query ? "<internal>" : clientIP, id, queryID, short_path(file), line);
|
||||
}
|
||||
|
||||
// Update counters
|
||||
counters->querytype[querytype-1]++;
|
||||
|
||||
// Update overTime
|
||||
const unsigned int timeidx = getOverTimeID(querytimestamp);
|
||||
|
||||
// Skip rest of the analysis if this query is not of type A or AAAA
|
||||
// but user wants to see only A and AAAA queries (pre-v4.1 behavior)
|
||||
if(config.analyze_only_A_AAAA && querytype != TYPE_A && querytype != TYPE_AAAA)
|
||||
{
|
||||
// Don't process this query further here, we already counted it
|
||||
if(config.debug & DEBUG_QUERIES) logg("Notice: Skipping new query: %s (%i)", types, id);
|
||||
free(domainString);
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Go through already knows domains and see if it is one of them
|
||||
const int domainID = findDomainID(domainString, true);
|
||||
|
||||
// Save everything
|
||||
queriesData* query = getQuery(queryID, false);
|
||||
if(query == NULL)
|
||||
{
|
||||
// Encountered memory error, skip query
|
||||
logg("WARN: No memory available, skipping query analysis");
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill query object with available data
|
||||
query->magic = MAGICBYTE;
|
||||
query->timestamp = querytimestamp;
|
||||
query->type = querytype;
|
||||
query->qtype = qtype;
|
||||
query->id = id; // Has to be set before calling query_set_status()
|
||||
|
||||
// This query is unknown as long as no reply has been found and analyzed
|
||||
counters->status[QUERY_UNKNOWN]++;
|
||||
query_set_status(query, QUERY_UNKNOWN);
|
||||
query->domainID = domainID;
|
||||
query->clientID = clientID;
|
||||
query->timeidx = timeidx;
|
||||
// Initialize database rowID with zero, will be set when the query is stored in the long-term DB
|
||||
query->db = 0;
|
||||
query->flags.complete = false;
|
||||
query->response = converttimeval(request);
|
||||
// Initialize reply type
|
||||
query->reply = REPLY_UNKNOWN;
|
||||
// Store DNSSEC result for this domain
|
||||
query->dnssec = DNSSEC_UNSPECIFIED;
|
||||
query->CNAME_domainID = -1;
|
||||
// This query is not yet known ad forwarded or blocked
|
||||
query->flags.blocked = false;
|
||||
query->flags.whitelisted = false;
|
||||
|
||||
// Indicator that this query was not forwarded so far
|
||||
query->upstreamID = -1;
|
||||
|
||||
// Check and apply possible privacy level rules
|
||||
// The currently set privacy level (at the time the query is
|
||||
// generated) is stored in the queries structure
|
||||
query->privacylevel = config.privacylevel;
|
||||
|
||||
// Increase DNS queries counter
|
||||
counters->queries++;
|
||||
|
||||
// Update overTime data
|
||||
overTime[timeidx].total++;
|
||||
|
||||
// Update overTime data structure with the new client
|
||||
change_clientcount(client, 0, 0, timeidx, 1);
|
||||
|
||||
// Set lastQuery timer and add one query for network table
|
||||
client->lastQuery = querytimestamp;
|
||||
client->numQueriesARP++;
|
||||
|
||||
// Process interface information of client (if available)
|
||||
// Skip interface name length 1 to skip "-". No real interface should
|
||||
// have a name with a length of 1...
|
||||
if(!internal_query && strlen(interface) > 1)
|
||||
{
|
||||
if(client->ifacepos == 0u)
|
||||
{
|
||||
// Store in the client data if unknown so far
|
||||
client->ifacepos = addstr(interface);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if this is still the same interface or
|
||||
// if the client moved to another interface
|
||||
// (may require group re-processing)
|
||||
const char *oldiface = getstr(client->ifacepos);
|
||||
if(strcasecmp(oldiface, interface) != 0)
|
||||
{
|
||||
if(config.debug & DEBUG_CLIENTS)
|
||||
{
|
||||
const char *clientName = getstr(client->namepos);
|
||||
logg("Client %s (%s) changed interface: %s -> %s",
|
||||
clientIP, clientName, oldiface, interface);
|
||||
}
|
||||
|
||||
gravityDB_reload_groups(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set client MAC address from EDNS(0) information (if available)
|
||||
if(config.edns0_ecs && edns->mac_set)
|
||||
{
|
||||
memcpy(client->hwaddr, edns->mac_byte, 6);
|
||||
client->hwlen = 6;
|
||||
}
|
||||
|
||||
// Try to obtain MAC address from dnsmasq's cache (also asks the kernel)
|
||||
if(client->hwlen < 1)
|
||||
{
|
||||
client->hwlen = find_mac(addr, client->hwaddr, 1, time(NULL));
|
||||
if(config.debug & DEBUG_ARP)
|
||||
{
|
||||
if(client->hwlen == 6)
|
||||
logg("find_mac(\"%s\") returned hardware address "
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X", clientIP,
|
||||
client->hwaddr[0], client->hwaddr[1], client->hwaddr[2],
|
||||
client->hwaddr[3], client->hwaddr[4], client->hwaddr[5]);
|
||||
else
|
||||
logg("find_mac(\"%s\") returned %i bytes of data",
|
||||
clientIP, client->hwlen);
|
||||
}
|
||||
}
|
||||
|
||||
bool blockDomain = false;
|
||||
// Check if this should be blocked only for active queries
|
||||
// (skipped for internally generated ones, e.g., DNSSEC)
|
||||
if(!internal_query)
|
||||
blockDomain = FTL_check_blocking(queryID, domainID, clientID);
|
||||
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
|
||||
return blockDomain;
|
||||
}
|
||||
|
||||
void FTL_iface(const int ifidx, const struct irec *ifaces)
|
||||
{
|
||||
// Invalidate data we have from the last interface/query
|
||||
@@ -264,10 +608,28 @@ void FTL_iface(const int ifidx, const struct irec *ifaces)
|
||||
|
||||
// Copy overwrite addresses if configured via REPLY_ADDR4 and/or REPLY_ADDR6 settings
|
||||
if(config.reply_addr.overwrite_v4)
|
||||
{
|
||||
memcpy(&next_iface.addr4, &config.reply_addr.v4, sizeof(config.reply_addr.v4));
|
||||
|
||||
if(config.debug & DEBUG_NETWORKING)
|
||||
{
|
||||
char buffer[ADDRSTRLEN+1] = { 0 };
|
||||
inet_ntop(AF_INET, &next_iface.addr4, buffer, ADDRSTRLEN);
|
||||
logg("Interface (%d) %s OVERWRITES IPv4 address %s", ifidx, next_iface.name, buffer);
|
||||
}
|
||||
}
|
||||
if(config.reply_addr.overwrite_v6)
|
||||
{
|
||||
memcpy(&next_iface.addr6, &config.reply_addr.v6, sizeof(config.reply_addr.v6));
|
||||
|
||||
if(config.debug & DEBUG_NETWORKING)
|
||||
{
|
||||
char buffer[ADDRSTRLEN+1] = { 0 };
|
||||
inet_ntop(AF_INET6, &next_iface.addr6, buffer, ADDRSTRLEN);
|
||||
logg("Interface (%d) %s OVERWRITES IPv6 address %s", ifidx, next_iface.name, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Use dummy when interface record is not available
|
||||
next_iface.name[0] = '-';
|
||||
next_iface.name[1] = '\0';
|
||||
@@ -357,7 +719,6 @@ void FTL_iface(const int ifidx, const struct irec *ifaces)
|
||||
}
|
||||
}
|
||||
|
||||
#define FTL_check_blocking(queryID, domainID, clientID) _FTL_check_blocking(queryID, domainID, clientID, __FILE__, __LINE__)
|
||||
static bool check_domain_blocked(const char *domain, const int clientID,
|
||||
clientsData *client, queriesData *query, DNSCacheData *dns_cache,
|
||||
unsigned char *new_status)
|
||||
@@ -581,8 +942,8 @@ static bool _FTL_check_blocking(int queryID, int domainID, int clientID, const c
|
||||
// Truncate "_esni." from queried domain if the parenting domain was the reason for blocking this query
|
||||
blockedDomain = domainstr + 6u;
|
||||
// Force next DNS reply to be NXDOMAIN for _esni.* queries
|
||||
force_next_DNS_reply = NXDOMAIN;
|
||||
dns_cache->force_reply = NXDOMAIN;
|
||||
force_next_DNS_reply = REPLY_NXDOMAIN;
|
||||
dns_cache->force_reply = REPLY_NXDOMAIN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,331 +1100,6 @@ bool _FTL_CNAME(const char *domain, const struct crec *cpp, const int id, const
|
||||
return block;
|
||||
}
|
||||
|
||||
|
||||
bool _FTL_new_query(const unsigned int flags, const char *name,
|
||||
union mysockaddr *addr, const char *types,
|
||||
const unsigned short qtype, const int id,
|
||||
const ednsData *edns, const enum protocol proto,
|
||||
const char* file, const int line)
|
||||
{
|
||||
// Create new query in data structure
|
||||
|
||||
// Get timestamp
|
||||
const time_t querytimestamp = time(NULL);
|
||||
|
||||
// Save request time
|
||||
struct timeval request;
|
||||
gettimeofday(&request, 0);
|
||||
|
||||
// If domain is "pi.hole" we skip this query
|
||||
if(strcasecmp(name, "pi.hole") == 0)
|
||||
return false;
|
||||
|
||||
// Determine query type
|
||||
enum query_types querytype;
|
||||
switch(qtype)
|
||||
{
|
||||
case T_A:
|
||||
querytype = TYPE_A;
|
||||
break;
|
||||
case T_AAAA:
|
||||
querytype = TYPE_AAAA;
|
||||
break;
|
||||
case T_ANY:
|
||||
querytype = TYPE_ANY;
|
||||
break;
|
||||
case T_SRV:
|
||||
querytype = TYPE_SRV;
|
||||
break;
|
||||
case T_SOA:
|
||||
querytype = TYPE_SOA;
|
||||
break;
|
||||
case T_PTR:
|
||||
querytype = TYPE_PTR;
|
||||
break;
|
||||
case T_TXT:
|
||||
querytype = TYPE_TXT;
|
||||
break;
|
||||
case T_NAPTR:
|
||||
querytype = TYPE_NAPTR;
|
||||
break;
|
||||
case T_MX:
|
||||
querytype = TYPE_MX;
|
||||
break;
|
||||
case T_DS:
|
||||
querytype = TYPE_DS;
|
||||
break;
|
||||
case T_RRSIG:
|
||||
querytype = TYPE_RRSIG;
|
||||
break;
|
||||
case T_DNSKEY:
|
||||
querytype = TYPE_DNSKEY;
|
||||
break;
|
||||
case T_NS:
|
||||
querytype = TYPE_NS;
|
||||
break;
|
||||
case 64: // Scn. 2 of https://datatracker.ietf.org/doc/draft-ietf-dnsop-svcb-https/
|
||||
querytype = TYPE_SVCB;
|
||||
break;
|
||||
case 65: // Scn. 2 of https://datatracker.ietf.org/doc/draft-ietf-dnsop-svcb-https/
|
||||
querytype = TYPE_HTTPS;
|
||||
break;
|
||||
default:
|
||||
querytype = TYPE_OTHER;
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip AAAA queries if user doesn't want to have them analyzed
|
||||
if(!config.analyze_AAAA && querytype == TYPE_AAAA)
|
||||
{
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
logg("Not analyzing AAAA query");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert domain to lower case
|
||||
char *domainString = strdup(name);
|
||||
strtolower(domainString);
|
||||
|
||||
// Get client IP address
|
||||
// The requestor's IP address can be rewritten using EDNS(0) client
|
||||
// subnet (ECS) data), however, we do not rewrite the IPs ::1 and
|
||||
// 127.0.0.1 to avoid queries originating from localhost of the
|
||||
// *distant* machine as queries coming from the *local* machine
|
||||
const sa_family_t family = addr ? addr->sa.sa_family : AF_INET;
|
||||
bool internal_query = false;
|
||||
char clientIP[ADDRSTRLEN+1] = { 0 };
|
||||
if(config.edns0_ecs && edns && edns->client_set)
|
||||
{
|
||||
// Use ECS provided client
|
||||
strncpy(clientIP, edns->client, ADDRSTRLEN);
|
||||
clientIP[ADDRSTRLEN] = '\0';
|
||||
}
|
||||
else if(addr)
|
||||
{
|
||||
// Use original requestor
|
||||
inet_ntop(family,
|
||||
family == AF_INET ?
|
||||
(union alladdr*)&addr->in.sin_addr :
|
||||
(union alladdr*)&addr->in6.sin6_addr,
|
||||
clientIP, ADDRSTRLEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No client address available, this is an automatically generated (e.g.
|
||||
// DNSSEC) query
|
||||
internal_query = true;
|
||||
strcpy(clientIP, "::");
|
||||
}
|
||||
|
||||
// Check if user wants to skip queries coming from localhost
|
||||
if(config.ignore_localhost &&
|
||||
(strcmp(clientIP, "127.0.0.1") == 0 || strcmp(clientIP, "::1") == 0))
|
||||
{
|
||||
free(domainString);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
const int queryID = counters->queries;
|
||||
|
||||
// Find client IP
|
||||
const int clientID = findClientID(clientIP, true, false);
|
||||
|
||||
// Get client pointer
|
||||
clientsData* client = getClient(clientID, true);
|
||||
if(client == NULL)
|
||||
{
|
||||
// Encountered memory error, skip query
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Interface name is only available for regular queries, not for
|
||||
// automatically generated DNSSEC queries
|
||||
const char *interface = internal_query ? "-" : next_iface.name;
|
||||
|
||||
// Check rate-limit for this client
|
||||
if(!internal_query && config.rate_limit.count > 0 &&
|
||||
++client->rate_limit > config.rate_limit.count)
|
||||
{
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
logg("Rate-limiting %sIPv%d %s query \"%s\" from %s:%s",
|
||||
proto == TCP ? "TCP " : proto == UDP ? "UDP " : "",
|
||||
family == AF_INET ? 4 : 6, types, domainString, interface, clientIP);
|
||||
}
|
||||
|
||||
// Block this query
|
||||
force_next_DNS_reply = REFUSED;
|
||||
|
||||
// Do not further process this query, Pi-hole has never seen it
|
||||
unlock_shm();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Log new query if in debug mode
|
||||
if(config.debug & DEBUG_QUERIES)
|
||||
{
|
||||
logg("**** new %sIPv%d %s query \"%s\" from %s:%s (ID %i, FTL %i, %s:%i)",
|
||||
proto == TCP ? "TCP " : proto == UDP ? "UDP " : "",
|
||||
family == AF_INET ? 4 : 6, types, domainString, interface,
|
||||
internal_query ? "<internal>" : clientIP, id, queryID, short_path(file), line);
|
||||
}
|
||||
|
||||
// Update counters
|
||||
counters->querytype[querytype-1]++;
|
||||
|
||||
// Update overTime
|
||||
const unsigned int timeidx = getOverTimeID(querytimestamp);
|
||||
|
||||
// Skip rest of the analysis if this query is not of type A or AAAA
|
||||
// but user wants to see only A and AAAA queries (pre-v4.1 behavior)
|
||||
if(config.analyze_only_A_AAAA && querytype != TYPE_A && querytype != TYPE_AAAA)
|
||||
{
|
||||
// Don't process this query further here, we already counted it
|
||||
if(config.debug & DEBUG_QUERIES) logg("Notice: Skipping new query: %s (%i)", types, id);
|
||||
free(domainString);
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Go through already knows domains and see if it is one of them
|
||||
const int domainID = findDomainID(domainString, true);
|
||||
|
||||
// Save everything
|
||||
queriesData* query = getQuery(queryID, false);
|
||||
if(query == NULL)
|
||||
{
|
||||
// Encountered memory error, skip query
|
||||
logg("WARN: No memory available, skipping query analysis");
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill query object with available data
|
||||
query->magic = MAGICBYTE;
|
||||
query->timestamp = querytimestamp;
|
||||
query->type = querytype;
|
||||
query->qtype = qtype;
|
||||
query->id = id; // Has to be set before calling query_set_status()
|
||||
|
||||
// This query is unknown as long as no reply has been found and analyzed
|
||||
counters->status[QUERY_UNKNOWN]++;
|
||||
query_set_status(query, QUERY_UNKNOWN);
|
||||
query->domainID = domainID;
|
||||
query->clientID = clientID;
|
||||
query->timeidx = timeidx;
|
||||
// Initialize database rowID with zero, will be set when the query is stored in the long-term DB
|
||||
query->db = 0;
|
||||
query->flags.complete = false;
|
||||
query->response = converttimeval(request);
|
||||
// Initialize reply type
|
||||
query->reply = REPLY_UNKNOWN;
|
||||
// Store DNSSEC result for this domain
|
||||
query->dnssec = DNSSEC_UNSPECIFIED;
|
||||
query->CNAME_domainID = -1;
|
||||
// This query is not yet known ad forwarded or blocked
|
||||
query->flags.blocked = false;
|
||||
query->flags.whitelisted = false;
|
||||
|
||||
// Indicator that this query was not forwarded so far
|
||||
query->upstreamID = -1;
|
||||
|
||||
// Check and apply possible privacy level rules
|
||||
// The currently set privacy level (at the time the query is
|
||||
// generated) is stored in the queries structure
|
||||
query->privacylevel = config.privacylevel;
|
||||
|
||||
// Increase DNS queries counter
|
||||
counters->queries++;
|
||||
|
||||
// Update overTime data
|
||||
overTime[timeidx].total++;
|
||||
|
||||
// Update overTime data structure with the new client
|
||||
change_clientcount(client, 0, 0, timeidx, 1);
|
||||
|
||||
// Set lastQuery timer and add one query for network table
|
||||
client->lastQuery = querytimestamp;
|
||||
client->numQueriesARP++;
|
||||
|
||||
// Process interface information of client (if available)
|
||||
// Skip interface name length 1 to skip "-". No real interface should
|
||||
// have a name with a length of 1...
|
||||
if(!internal_query && strlen(interface) > 1)
|
||||
{
|
||||
if(client->ifacepos == 0u)
|
||||
{
|
||||
// Store in the client data if unknown so far
|
||||
client->ifacepos = addstr(interface);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if this is still the same interface or
|
||||
// if the client moved to another interface
|
||||
// (may require group re-processing)
|
||||
const char *oldiface = getstr(client->ifacepos);
|
||||
if(strcasecmp(oldiface, interface) != 0)
|
||||
{
|
||||
if(config.debug & DEBUG_CLIENTS)
|
||||
{
|
||||
const char *clientName = getstr(client->namepos);
|
||||
logg("Client %s (%s) changed interface: %s -> %s",
|
||||
clientIP, clientName, oldiface, interface);
|
||||
}
|
||||
|
||||
gravityDB_reload_groups(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set client MAC address from EDNS(0) information (if available)
|
||||
if(config.edns0_ecs && edns->mac_set)
|
||||
{
|
||||
memcpy(client->hwaddr, edns->mac_byte, 6);
|
||||
client->hwlen = 6;
|
||||
}
|
||||
|
||||
// Try to obtain MAC address from dnsmasq's cache (also asks the kernel)
|
||||
if(client->hwlen < 1)
|
||||
{
|
||||
client->hwlen = find_mac(addr, client->hwaddr, 1, time(NULL));
|
||||
if(config.debug & DEBUG_ARP)
|
||||
{
|
||||
if(client->hwlen == 6)
|
||||
logg("find_mac(\"%s\") returned hardware address "
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X", clientIP,
|
||||
client->hwaddr[0], client->hwaddr[1], client->hwaddr[2],
|
||||
client->hwaddr[3], client->hwaddr[4], client->hwaddr[5]);
|
||||
else
|
||||
logg("find_mac(\"%s\") returned %i bytes of data",
|
||||
clientIP, client->hwlen);
|
||||
}
|
||||
}
|
||||
|
||||
bool blockDomain = false;
|
||||
// Check if this should be blocked only for active queries
|
||||
// (skipped for internally generated ones, e.g., DNSSEC)
|
||||
if(!internal_query)
|
||||
blockDomain = FTL_check_blocking(queryID, domainID, clientID);
|
||||
|
||||
// Free allocated memory
|
||||
free(domainString);
|
||||
|
||||
// Release thread lock
|
||||
unlock_shm();
|
||||
|
||||
return blockDomain;
|
||||
}
|
||||
|
||||
static void FTL_forwarded(const unsigned int flags, const char *name, const union all_addr *addr,
|
||||
const int id, const char* file, const int line)
|
||||
{
|
||||
@@ -1243,6 +1279,16 @@ static void FTL_reply(const unsigned int flags, const char *name, const union al
|
||||
// Lock shared memory
|
||||
lock_shm();
|
||||
|
||||
// Save status in corresponding query identified by dnsmasq's ID
|
||||
const int queryID = findQueryID(id);
|
||||
if(queryID < 0)
|
||||
{
|
||||
// This may happen e.g. if the original query was "pi.hole"
|
||||
if(config.debug & DEBUG_QUERIES) logg("FTL_reply(): Query %i has not been found", id);
|
||||
unlock_shm();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this reply came from our local cache
|
||||
bool cached = false;
|
||||
if(!(flags & F_UPSTREAM))
|
||||
@@ -1308,18 +1354,8 @@ static void FTL_reply(const unsigned int flags, const char *name, const union al
|
||||
struct timeval response;
|
||||
gettimeofday(&response, 0);
|
||||
|
||||
// Save status in corresponding query identified by dnsmasq's ID
|
||||
const int i = findQueryID(id);
|
||||
if(i < 0)
|
||||
{
|
||||
// This may happen e.g. if the original query was "pi.hole"
|
||||
if(config.debug & DEBUG_QUERIES) logg("FTL_reply(): Query %i has not been found", id);
|
||||
unlock_shm();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get query pointer
|
||||
queriesData* query = getQuery(i, true);
|
||||
queriesData* query = getQuery(queryID, true);
|
||||
|
||||
// Check if reply time is still unknown
|
||||
// We only process the first reply in here
|
||||
@@ -1815,7 +1851,7 @@ static void _query_set_reply(const unsigned int flags, const union all_addr *add
|
||||
const char *file, const int line)
|
||||
{
|
||||
// Iterate through possible values
|
||||
if(flags & F_NEG || force_next_DNS_reply == NXDOMAIN)
|
||||
if(flags & F_NEG || force_next_DNS_reply == REPLY_NXDOMAIN)
|
||||
{
|
||||
if(flags & F_NXDOMAIN)
|
||||
// NXDOMAIN
|
||||
@@ -1833,10 +1869,10 @@ static void _query_set_reply(const unsigned int flags, const union all_addr *add
|
||||
else if(flags & F_RRNAME)
|
||||
// TXT query
|
||||
query->reply = REPLY_RRNAME;
|
||||
else if((flags & F_RCODE && addr != NULL) || force_next_DNS_reply == REFUSED)
|
||||
else if((flags & F_RCODE && addr != NULL) || force_next_DNS_reply == REPLY_REFUSED)
|
||||
{
|
||||
if((addr != NULL && addr->log.rcode == REFUSED)
|
||||
|| force_next_DNS_reply == REFUSED )
|
||||
|| force_next_DNS_reply == REPLY_REFUSED )
|
||||
{
|
||||
// REFUSED query
|
||||
query->reply = REPLY_REFUSED;
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ int main (int argc, char* argv[])
|
||||
// Try to open FTL log
|
||||
init_FTL_log();
|
||||
timer_start(EXIT_TIMER);
|
||||
logg("########## FTL started! ##########");
|
||||
logg("########## FTL started on %s! ##########", hostname());
|
||||
log_FTL_version(false);
|
||||
|
||||
// Catch signals not handled by dnsmasq
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
|
||||
int main_dnsmasq(int argc, const char ** argv);
|
||||
|
||||
extern char * username;
|
||||
extern char *username;
|
||||
extern bool startup;
|
||||
|
||||
#endif //MAIN_H
|
||||
|
||||
Reference in New Issue
Block a user