Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b258b43
utilize a cached file descriptor for logging & own dnsmasq.log
darkexplosiveqwx Jul 15, 2026
c74e0d1
We don't implement dnsmasq's logging to stderr
darkexplosiveqwx Jul 23, 2026
b52313e
log.c: apply O_CLOEXEC to avoid leaking file descriptors
darkexplosiveqwx Jul 24, 2026
e43c734
move dnsmasq_diagnosis_warning() into FTL_dnsmasq_log()
darkexplosiveqwx Jul 25, 2026
1d334dd
make the timestamp more clear for dnsmasaq log
darkexplosiveqwx Jul 25, 2026
6269ce8
keep dnsmasq's echo_stderr for --test
darkexplosiveqwx Jul 28, 2026
aa56104
weblog: route errors to FTL.log if webserver.log is unavailible, with a
darkexplosiveqwx Jul 31, 2026
eb5a4b0
log: reopen failed log files on SIGUSR2 and guard fds under the lock
darkexplosiveqwx Aug 3, 2026
898b60a
log: make the dnsmasq log timestamp locale-independent
darkexplosiveqwx Aug 3, 2026
0ccaa96
log: warn when pihole.log cannot be opened
darkexplosiveqwx Aug 3, 2026
bb9ace4
log: make the per-file log mutexes fork-safe
darkexplosiveqwx Aug 3, 2026
559990c
dnsmasq: chown webserver.log and pihole.log when dropping privileges
darkexplosiveqwx Aug 3, 2026
601919b
dnsmasq config: drop the dead log-async option
darkexplosiveqwx Aug 3, 2026
53baebc
log: use ASCII hyphens in the new comments
darkexplosiveqwx Aug 3, 2026
190bacf
log: clamp the line offset before using it as an offset
darkexplosiveqwx Aug 3, 2026
266bd72
log: mention misc.hide_dnsmasq_warn in the pihole.log warning
darkexplosiveqwx Aug 3, 2026
91c3ed2
address review feedback
darkexplosiveqwx Aug 18, 2026
8e30813
log: restore __attribute__((pure)) on is_log_fd() and fix ctime_r const
darkexplosiveqwx Aug 19, 2026
be5b4c7
log: guard free(NULL) in set_log_path()
darkexplosiveqwx Aug 19, 2026
6dc9399
avoid file descriptor leak
darkexplosiveqwx Aug 19, 2026
b8c1697
Fix ctime_r() fallback to include weekday prefix
darkexplosiveqwx Aug 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/config/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ void initConfig(struct config *conf)
conf->files.log.dnsmasq.t = CONF_STRING;
conf->files.log.dnsmasq.f = FLAG_RESTART_FTL;
conf->files.log.dnsmasq.d.s = (char*)"/var/log/pihole/pihole.log";
conf->files.log.dnsmasq.c = validate_filepath_dash;
conf->files.log.dnsmasq.c = validate_filepath;

conf->files.log.webserver.k = "files.log.webserver";
conf->files.log.webserver.h = "The log file used by the webserver";
Expand Down Expand Up @@ -1924,6 +1924,13 @@ bool readFTLconf(struct config *conf, const bool rewrite)
// First, read the environment
getEnvVars();

// Open pihole.log and webserver.log now (with default or ENV paths)
// so that any log output during write_dnsmasq_config() below is not
// silently lost. open_log_fds(false) will be called again after the
// config parse in main() to pick up any path overrides from the TOML
// file or legacy config.
open_log_fds(false);

// Try to read TOML config file
// If we cannot parse /etc/pihole.toml (due to missing or invalid syntax),
// we try to read the rotated files in /etc/pihole/config_backup starting at
Expand Down
13 changes: 2 additions & 11 deletions src/config/dnsmasq_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,27 +423,18 @@ bool __attribute__((nonnull(1,3))) write_dnsmasq_config(struct config *conf, boo
if(conf->dns.queryLogging.v.b)
{
fputs("# Enable query logging\n", pihole_conf);
// FTL writes pihole.log synchronously via a cached descriptor, so
// dnsmasq's log-async queue is never used
if(conf->misc.extraLogging.v.b)
fputs("log-queries=proto\n", pihole_conf);
else
fputs("log-queries\n", pihole_conf);
fputs("log-async\n", pihole_conf);
fputs("\n", pihole_conf);
}
else
{
fputs("# Disable query logging\n", pihole_conf);
fputs("#log-queries\n", pihole_conf);
fputs("#log-async\n", pihole_conf);
fputs("\n", pihole_conf);
}

if(strlen(conf->files.log.dnsmasq.v.s) > 0)
{
fputs("# Specify the log file to use\n", pihole_conf);
fputs("# We set this even if logging is disabled to store warnings\n", pihole_conf);
fputs("# and errors in this file. This is useful for debugging.\n", pihole_conf);
fprintf(pihole_conf, "log-facility=%s\n", conf->files.log.dnsmasq.v.s);
fputs("\n", pihole_conf);
}

Expand Down
11 changes: 0 additions & 11 deletions src/config/validator.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,17 +339,6 @@ bool validate_filepath_empty(union conf_value *val, const char *key, char err[VA
return validate_filepath(val, key, err);
}

// Validate file path (dash allowed), used by files.log.dnsmasq
bool validate_filepath_dash(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN])
{
// Dash is allowed, this enabled printing to stderr
if(strlen(val->s) == 1 && val->s[0] == '-')
return true;

// else:
return validate_filepath(val, key, err);
}

// Validate the web server log file path. In addition to the regular file-path
// checks, reject a path inside webserver.paths.webroot: a log file served from
// the web server's document root can be read - and, if the path matches the
Expand Down
1 change: 0 additions & 1 deletion src/config/validator.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ bool validate_domain(union conf_value *val, const char *key, char err[VALIDATOR_
bool validate_filepath(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_filepath_two_slash(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_filepath_empty(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_filepath_dash(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_webserver_logfile(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_regex_array(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
bool validate_dns_revServers(union conf_value *val, const char *key, char err[VALIDATOR_ERRBUF_LEN]);
Expand Down
4 changes: 2 additions & 2 deletions src/database/message-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -1456,9 +1456,9 @@ void logg_rate_limit_message(const char *clientIP, const unsigned int rate_limit

}

void logg_warn_dnsmasq_message(char *message)
void logg_warn_dnsmasq_message(const char *message)
{
// Create message
// Create message (dnsmasq limits is message length to 1KiB to conform with RFC 3164; See MAX_MESSAGE in dnsmasq/log.c), account for our 'dnsmasq: ' prefix
char buf[2048];
format_dnsmasq_warn_message(buf, sizeof(buf), NULL, 0, message);

Expand Down
2 changes: 1 addition & 1 deletion src/database/message-table.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void logg_subnet_warning(const char *ip, const int matching_count, const char *m
void log_hostname_warning(const char *ip, const char *name, const unsigned int pos);
void logg_fatal_dnsmasq_message(const char *message);
void logg_rate_limit_message(const char *clientIP, const unsigned int rate_limit_count);
void logg_warn_dnsmasq_message(char *message);
void logg_warn_dnsmasq_message(const char *message);
void log_resource_shortage(const double load, const int nprocs, const int shmem, const int disk, const char *path, const char *msg);
void logg_inaccessible_adlist(const int dbindex, const char *address);
void log_certificate_domain_mismatch(const char *certfile, const char *domain);
Expand Down
23 changes: 8 additions & 15 deletions src/dnsmasq/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,13 @@ void my_syslog(int priority, const char *format, ...)
va_start(ap, format);
len = vsnprintf(buffer, MAX_MESSAGE, format, ap) + 1u; /* include zero-terminator */
va_end(ap);
FTL_dnsmasq_log(buffer, priority, len > MAX_MESSAGE ? MAX_MESSAGE : len);
/*******************************************************************************/
FTL_dnsmasq_log(buffer, priority, func, len > MAX_MESSAGE ? MAX_MESSAGE : len);

if (echo_stderr)
/* Pi-hole: FTL owns pihole.log. Bypass dnsmasq's file-write path
and syslog fallback entirely.
Keep echo_stderr so dnsmasq --test errors reach stderr (captured
by test_dnsmasq_config() in src/config/dnsmasq_config.c). */
if (echo_stderr)
{
fprintf(stderr, "dnsmasq%s: ", func);
va_start(ap, format);
Expand All @@ -339,18 +342,8 @@ void my_syslog(int priority, const char *format, ...)
fputc('\n', stderr);
}

/* Pi-hole diagnosis system */
if(priority == LOG_WARNING)
{
char *message;
va_start(ap, format);
if(vasprintf(&message, format, ap))
{
dnsmasq_diagnosis_warning(message);
free(message);
}
va_end(ap);
}
return;
/*******************************************************************************/

if (log_fd == -1)
{
Expand Down
3 changes: 2 additions & 1 deletion src/dnsmasq/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

/****** Pi-hole modification ******/
extern int is_shm_fd(const int fd);
extern int is_log_fd(const int fd);
/**********************************/

/* SURF random number generator */
Expand Down Expand Up @@ -881,7 +882,7 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
continue;

/****** Pi-hole modification ******/
if(is_shm_fd(fd))
if(is_shm_fd(fd) || is_log_fd(fd))
continue;
/**********************************/

Expand Down
20 changes: 19 additions & 1 deletion src/dnsmasq_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -3764,6 +3764,14 @@ void FTL_fork_and_bind_sockets(struct passwd *ent_pw, bool dnsmasq_start)
// Configured FTL log file
chown_pihole(config.files.log.ftl.v.s, ent_pw);

// Configured webserver log file
if(config.files.log.webserver.v.s != NULL)
chown_pihole(config.files.log.webserver.v.s, ent_pw);

// Configured dnsmasq log file (pihole.log)
if(config.files.log.dnsmasq.v.s != NULL)
chown_pihole(config.files.log.dnsmasq.v.s, ent_pw);

// Configured FTL database file
chown_pihole(config.files.database.v.s, ent_pw);

Expand Down Expand Up @@ -4261,7 +4269,7 @@ static void _query_set_dnssec(queriesData *query, const enum dnssec_status dnsse
}

// Add dnsmasq log line to internal FIFO buffer (can be queried via the API)
void FTL_dnsmasq_log(const char *payload, const int priority, const int length)
void FTL_dnsmasq_log(const char *payload, const int priority, const char *func, const int length)
{
// Lock SHM
lock_shm();
Expand All @@ -4273,6 +4281,16 @@ void FTL_dnsmasq_log(const char *payload, const int priority, const int length)

// Unlock SHM
unlock_shm();

// Write to pihole.log via shared writer (FTL owns this file now).
// If pihole.log is unavailable, fall back to syslog for warnings and
// errors so they are not silently lost for the lifetime of the process.
if(!FTL_write_dnsmasq_log(payload, func) && priority <= LOG_WARNING)
syslog(priority, "%s", payload);

/* Pi-hole diagnosis system */
if(priority == LOG_WARNING)
dnsmasq_diagnosis_warning(payload);
}

static const char *check_dnsmasq_name(const char *name)
Expand Down
2 changes: 1 addition & 1 deletion src/dnsmasq_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ bool get_dnsmasq_debug(void) __attribute__ ((pure));
// defined in src/dnsmasq/cache.c
extern char *querystr(char *desc, unsigned short type);

extern void FTL_dnsmasq_log(const char *payload, const int priority, const int length);
extern void FTL_dnsmasq_log(const char *payload, const int priority, const char *func, const int length);

#endif // DNSMASQ_INTERFACE_H
Loading
Loading