Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pi-hole FTL v6.0.2 #2232

Merged
merged 15 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ set(CMAKE_C_STANDARD 17)

project(PIHOLE_FTL C)

set(DNSMASQ_VERSION pi-hole-v2.91rc4)
set(DNSMASQ_VERSION pi-hole-v2.91rc5)

add_subdirectory(src)
53 changes: 22 additions & 31 deletions src/config/dnsmasq_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
#include "log.h"
// get_blocking_mode_str()
#include "datastructure.h"
// flock(), LOCK_SH
#include <sys/file.h>
// struct config
#include "config/config.h"
// JSON array functions
Expand Down Expand Up @@ -116,11 +114,21 @@ static bool test_dnsmasq_config(char errbuf[ERRBUF_SIZE])
// We can ignore EINTR as it just means that the wait
// was interrupted, so we just try again. All other
// errors are fatal and we break out of the loop
if(err != EINTR)
if(err != EINTR && err != EAGAIN && err != ECHILD)
{
log_err("Cannot wait for dnsmasq test: %s", strerror(err));
break;
}

// Check if the child exited too quickly for waitpid to
// catch it. We cannot get the return code in this case
// and have to check the pipe content instead
if(errno == ECHILD)
{
log_debug(DEBUG_CONFIG, "dnsmasq test exited too quickly for waitpid");
code = strstr(errbuf, "syntax check OK") != NULL ? EXIT_SUCCESS : EXIT_FAILURE;
goto check_return;
}
}

// Get return code if child exited normally
Expand All @@ -136,11 +144,12 @@ static bool test_dnsmasq_config(char errbuf[ERRBUF_SIZE])
WCOREDUMP(status) ? "(core dumped)" : "");
}

check_return:
// Check if the error message contains a line number. If so, we
// can append the offending line to the error message
if(code != EXIT_SUCCESS)
{
int lineno = get_lineno_from_string(errbuf);
const int lineno = get_lineno_from_string(errbuf);
if(lineno > 0)
{
const size_t errbuf_size = strlen(errbuf);
Expand Down Expand Up @@ -314,12 +323,7 @@ bool __attribute__((const)) write_dnsmasq_config(struct config *conf, bool test_
}

// Lock file, may block if the file is currently opened
if(flock(fileno(pihole_conf), LOCK_EX) != 0)
{
log_err("Cannot open "DNSMASQ_TEMP_CONF" in exclusive mode: %s", strerror(errno));
fclose(pihole_conf);
return false;
}
const bool locked = lock_file(pihole_conf, DNSMASQ_TEMP_CONF);

write_config_header(pihole_conf, "Dnsmasq config for Pi-hole's FTLDNS");
fputs("hostsdir="DNSMASQ_HOSTSDIR"\n", pihole_conf);
Expand Down Expand Up @@ -500,9 +504,9 @@ bool __attribute__((const)) write_dnsmasq_config(struct config *conf, bool test_
continue;
}

if(active == NULL || cidr == NULL || target == NULL || domain == NULL)
if(active == NULL || cidr == NULL || target == NULL)
{
log_err("Skipped invalid dns.revServers[%u]: %s", i, revServer->valuestring);
log_err("Skipped invalid dns.revServers[%u]: %s (not fully defined)", i, revServer->valuestring);
free(copy);
continue;
}
Expand All @@ -513,7 +517,7 @@ bool __attribute__((const)) write_dnsmasq_config(struct config *conf, bool test_

// If we have a reverse domain, we forward all queries to this domain to
// the same destination
if(strlen(domain) > 0)
if(domain != NULL && strlen(domain) > 0)
{
fprintf(pihole_conf, "server=/%s/%s\n", domain, target);

Expand Down Expand Up @@ -757,12 +761,8 @@ bool __attribute__((const)) write_dnsmasq_config(struct config *conf, bool test_
fflush(pihole_conf);

// Unlock file
if(flock(fileno(pihole_conf), LOCK_UN) != 0)
{
log_err("Cannot release lock on dnsmasq config file: %s", strerror(errno));
fclose(pihole_conf);
return false;
}
if(locked)
unlock_file(pihole_conf, DNSMASQ_TEMP_CONF);

// Close file
if(fclose(pihole_conf) != 0)
Expand Down Expand Up @@ -1026,12 +1026,7 @@ bool write_custom_list(void)
}

// Lock file, may block if the file is currently opened
if(flock(fileno(custom_list), LOCK_EX) != 0)
{
log_err("Cannot open "DNSMASQ_CUSTOM_LIST_LEGACY".tmp in exclusive mode: %s", strerror(errno));
fclose(custom_list);
return false;
}
const bool locked = lock_file(custom_list, DNSMASQ_CUSTOM_LIST_LEGACY".tmp");

write_config_header(custom_list, "Custom DNS entries (HOSTS file)");
fputc('\n', custom_list);
Expand All @@ -1056,12 +1051,8 @@ bool write_custom_list(void)
fputs("\n# There are currently no entries in this file\n", custom_list);

// Unlock file
if(flock(fileno(custom_list), LOCK_UN) != 0)
{
log_err("Cannot release lock on custom.list: %s", strerror(errno));
fclose(custom_list);
return false;
}
if(locked)
unlock_file(custom_list, DNSMASQ_CUSTOM_LIST_LEGACY".tmp");

// Close file
if(fclose(custom_list) != 0)
Expand Down
7 changes: 4 additions & 3 deletions src/config/env.c
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,9 @@ cJSON *read_forced_vars(const unsigned int version)
cJSON *env_vars = cJSON_CreateArray();

// Try to open default config file. Use fallback if not found
FILE *fp;
if((fp = openFTLtoml("r", version)) == NULL)
bool locked = false;
FILE *fp = openFTLtoml("r", version, &locked);
if(fp == NULL)
{
// Return empty cJSON array
return env_vars;
Expand Down Expand Up @@ -672,7 +673,7 @@ cJSON *read_forced_vars(const unsigned int version)
}

// Close file and release exclusive lock
closeFTLtoml(fp);
closeFTLtoml(fp, locked);

// Return cJSON array
return env_vars;
Expand Down
22 changes: 6 additions & 16 deletions src/config/toml_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
#include "config/config.h"
// get_refresh_hostnames_str()
#include "datastructure.h"
// flock(), LOCK_SH
#include <sys/file.h>
// fcntl(), O_ACCMODE, O_RDONLY
#include <fcntl.h>
// rotate_files()
Expand All @@ -29,7 +27,7 @@
#include "files.h"

// Open the TOML file for reading or writing
FILE * __attribute((malloc)) __attribute((nonnull(1))) openFTLtoml(const char *mode, const unsigned int version)
FILE * __attribute((malloc)) __attribute((nonnull(1))) openFTLtoml(const char *mode, const unsigned int version, bool *locked)
{
// This should not happen, install a safeguard anyway to unveil
// possible future coding issues early on
Expand Down Expand Up @@ -69,15 +67,7 @@ FILE * __attribute((malloc)) __attribute((nonnull(1))) openFTLtoml(const char *m
}

// Lock file, may block if the file is currently opened
if(flock(fileno(fp), LOCK_EX) != 0)
{
const int _e = errno;
log_err("Cannot open config file %s in exclusive mode (%s): %s",
filename, mode, strerror(errno));
fclose(fp);
errno = _e;
return NULL;
}
*locked = lock_file(fp, filename);

// Log if we are using a backup file
if(version > 0)
Expand All @@ -88,14 +78,14 @@ FILE * __attribute((malloc)) __attribute((nonnull(1))) openFTLtoml(const char *m
}

// Open the TOML file for reading or writing
void closeFTLtoml(FILE *fp)
void closeFTLtoml(FILE *fp, const bool locked)
{
// Release file lock
const int fn = fileno(fp);
if(flock(fn, LOCK_UN) != 0)
log_err("Cannot release lock on FTL's config file: %s", strerror(errno));
if(locked)
unlock_file(fp, NULL);

// Get access mode
const int fn = fileno(fp);
const int mode = fcntl(fn, F_GETFL);
if (mode == -1)
log_err("Cannot get access mode for FTL's config file: %s", strerror(errno));
Expand Down
4 changes: 2 additions & 2 deletions src/config/toml_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
#include "tomlc99/toml.h"

void indentTOML(FILE *fp, const unsigned int indent);
FILE *openFTLtoml(const char *mode, const unsigned int version) __attribute((malloc)) __attribute((nonnull(1)));
void closeFTLtoml(FILE *fp);
FILE *openFTLtoml(const char *mode, const unsigned int version, bool *locked) __attribute((malloc)) __attribute((nonnull(1)));
void closeFTLtoml(FILE *fp, const bool locked);
void print_comment(FILE *fp, const char *str, const char *intro, const unsigned int width, const unsigned int indent);
void print_toml_allowed_values(cJSON *allowed_values, FILE *fp, const unsigned int width, const unsigned int indent);
void writeTOMLvalue(FILE * fp, const int indent, const enum conf_type t, union conf_value *v);
Expand Down
7 changes: 4 additions & 3 deletions src/config/toml_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,17 @@ bool readFTLtoml(struct config *oldconf, struct config *newconf,
static toml_table_t *parseTOML(const unsigned int version)
{
// Try to open default config file. Use fallback if not found
FILE *fp;
if((fp = openFTLtoml("r", version)) == NULL)
bool locked = false;
FILE *fp = openFTLtoml("r", version, &locked);
if(fp == NULL)
return NULL;

// Parse lines in the config file
char errbuf[200];
toml_table_t *conf = toml_parse_file(fp, errbuf, sizeof(errbuf));

// Close file and release exclusive lock
closeFTLtoml(fp);
closeFTLtoml(fp, locked);

// Check for errors
if(conf == NULL)
Expand Down
7 changes: 4 additions & 3 deletions src/config/toml_writer.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ bool writeFTLtoml(const bool verbose)
}

// Try to open a temporary config file for writing
FILE *fp;
if((fp = openFTLtoml("w", 0)) == NULL)
bool locked = false;
FILE *fp = openFTLtoml("w", 0, &locked);
if(fp == NULL)
return false;

// Write header
Expand Down Expand Up @@ -163,7 +164,7 @@ bool writeFTLtoml(const bool verbose)
cJSON_Delete(env_vars);

// Close file and release exclusive lock
closeFTLtoml(fp);
closeFTLtoml(fp, locked);

// Move temporary file to the final location if it is different
// We skip the first 8 lines as they contain the header and will always
Expand Down
49 changes: 21 additions & 28 deletions src/dnsmasq/forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,9 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,

if (gobig && !bitvector)
{
casediff = (i/BITS_IN_INT) + 1; /* length of array */
if ((bitvector = whine_malloc(casediff)))
casediff = ((i - 1)/BITS_IN_INT) + 1; /* length of array */
/* whine_malloc() zeros memory */
if ((bitvector = whine_malloc(casediff * sizeof(unsigned int))))
goto big_redo;
}
}
Expand Down Expand Up @@ -402,6 +403,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
header->id = ntohs(forward->new_id);

forward->frec_src.encode_bitmap = option_bool(OPT_NO_0x20) ? 0 : rand32();
forward->frec_src.encode_bigmap = NULL;
p = (unsigned char *)(header+1);
if (!extract_name(header, plen, &p, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
goto reply;
Expand Down Expand Up @@ -721,7 +723,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
unsigned int rcode = RCODE(header);
size_t plen;
/******** Pi-hole modification ********/
unsigned char *pheader_copy = NULL;
unsigned char ede_data[MAX_EDE_DATA] = { 0 };
size_t ede_len = 0;
/**************************************/
Expand Down Expand Up @@ -874,16 +875,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
if(rc == 99)
{
cache_secure = 0;
// Make a private copy of the pheader to ensure
// we are not accidentially rewriting what is in
// the pheader when we're creating a crafted reply
// further below (when a query is to be blocked)
if (pheader)
{
pheader_copy = calloc(1, plen);
memcpy(pheader_copy, pheader, plen);
}

// Generate DNS packet for reply, a possibly existing pseudo header
// will be restored later inside resize_packet()
n = FTL_make_answer(header, ((char *) header) + 65536, n, ede_data, &ede_len);
Expand Down Expand Up @@ -919,22 +910,17 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server

/* the code above can elide sections of the packet. Find the new length here
and put back pseudoheader if it was removed. */
n = resize_packet(header, n, pheader_copy ? pheader_copy : pheader, plen);
n = resize_packet(header, n, pheader, plen);
/******** Pi-hole modification ********/
// The line above was modified to use
// pheader_copy instead of pheader
if(pheader_copy)
free(pheader_copy);

if (pheader && (ede != EDE_UNSET || ede_len > 0))
{
if (ede_len > 0)
n = add_pseudoheader(header, n, limit, EDNS0_OPTION_EDE, ede_data, ede_len, do_bit, 1);
else
{
u16 swap = htons((u16)ede);
n = add_pseudoheader(header, n, limit, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
}
n = add_pseudoheader(header, n, limit, EDNS0_OPTION_EDE, ede_data, ede_len, do_bit, 1);
else
{
u16 swap = htons((u16)ede);
n = add_pseudoheader(header, n, limit, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
}
}
/**************************************/

Expand Down Expand Up @@ -1100,6 +1086,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
new->flags |= flags;
new->forwardall = 0;
new->frec_src.encode_bitmap = 0;
new->frec_src.encode_bigmap = NULL;

forward->next_dependent = NULL;
new->dependent = forward; /* to find query awaiting new one. */
Expand Down Expand Up @@ -1555,13 +1542,13 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
int first_ID = -1;

/* This gets the name back to the state it was in when we started. */
flip_queryname(header, nn, prev, &forward->frec_src);
flip_queryname(header, new, prev, &forward->frec_src);

for (src = &forward->frec_src, prev = NULL; src; prev = src, src = src->next)
{
/* If you didn't undertand this above, you won't understand it here either. */
if (prev)
flip_queryname(header, nn, prev, src);
flip_queryname(header, new, prev, src);

if (src->fd != -1 && nn > src->udp_pkt_size)
{
Expand Down Expand Up @@ -3200,7 +3187,7 @@ static void free_frec(struct frec *f)
struct frec_src *last;

/* add back to freelist if not the record builtin to every frec,
also free any bigmaps they's been decorated with. */
also free any bigmaps they've been decorated with. */
for (last = f->frec_src.next; last && last->next; last = last->next)
if (last->encode_bigmap)
{
Expand All @@ -3210,6 +3197,12 @@ static void free_frec(struct frec *f)

if (last)
{
/* final link in the chain loses bigmap too. */
if (last->encode_bigmap)
{
free(last->encode_bigmap);
last->encode_bigmap = NULL;
}
last->next = daemon->free_frec_src;
daemon->free_frec_src = f->frec_src.next;
}
Expand Down
Loading
Loading