Compare commits

...
Author SHA1 Message Date
Simon Kelley 14e81b6976 Additional sanity check in filter_servers(). 2025-06-06 23:33:25 +01:00
Simon Kelley 6ce7f2d55a Fix regression in 9e67099ce7
Logging queries lost the RRtype.

Revert to e.g. query[A] example.com
2025-06-06 23:29:31 +01:00
Simon Kelley 287d6bc88d Fix 5846f749e5
Not sure how that bug got in there. Very (un)lucky choice
of test data, or last-minute "it'll be fine" modification I guess.

It was late, I can't remember.

Thanks to Dominik Derrigs for spotting the problem.
2025-06-03 22:16:50 +01:00
Simon Kelley c378d2c1de Fix crash in filter_servers().
The bug occurs when we ask lookup_domain() for a server for a domain
which is not a general upstream server, by setting F_DOMAINSRV in the flags.

If there are no possible servers, because there are no upstream servers
defined (for instance, at startup) then the code steps off the end of an
array and SEGVs.

The bug has been latent for some time, but
3e659bd4ec added a new call to lookup_domain()
which can actually trigger the bug if DNSSEC is enabled and a certain
amount of bad luck ensues.

Thanks to the testers extraordinaire at PiHole for reporting this.
2025-06-02 22:37:08 +01:00
Simon Kelley 5846f749e5 Rewrite chunks of inotify.c to remove a memory leak.
The code is much easier to follow now, this shouldn't
happen again.
2025-05-29 22:44:15 +01:00
Matthias Andree c9a4240ec4 Unbreak compilation on non-Linux systems (FreeBSD)
and put the void cast of netlink_warn under the same preprocessor
condition as its definition, #ifdef HAVE_LINUX_NETWORK.
2025-05-25 21:15:41 +01:00
Simon Kelley e7b87dee85 Tftp code tweaks. 2025-05-24 21:15:02 +01:00
5 changed files with 88 additions and 65 deletions

No files matched your search

+4 -2
View File
@@ -2360,6 +2360,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "reply"; source = "reply";
else if (flags & F_AUTH) else if (flags & F_AUTH)
source = "auth"; source = "auth";
else if (flags & F_QUERY)
source = "query";
else if (flags & F_SECSTAT) else if (flags & F_SECSTAT)
{ {
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG)) if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
@@ -2400,8 +2402,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "non-query opcode"; source = "non-query opcode";
name = opcodestring; name = opcodestring;
} }
else if (!(flags & F_AUTH)) else if (type > 0)
source = "query"; source = querystr(source, type);
verb = "from"; verb = "from";
} }
+2
View File
@@ -81,7 +81,9 @@ int main (int argc, char **argv)
int tftp_prefix_missing = 0; int tftp_prefix_missing = 0;
#endif #endif
#ifdef HAVE_LINUX_NETWORK
(void)netlink_warn; (void)netlink_warn;
#endif
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR) #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
+1 -3
View File
@@ -343,10 +343,8 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
else else
{ {
/* If we want a server for a particular domain, and this one isn't, return nothing. */ /* If we want a server for a particular domain, and this one isn't, return nothing. */
if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0) if (nlow < daemon->serverarraysz && nlow != nhigh && (flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
nlow = nhigh; nlow = nhigh;
else
nlow = i;
} }
} }
} }
+72 -53
View File
@@ -133,29 +133,44 @@ void inotify_dnsmasq_init()
} }
} }
static struct hostsfile *dyndir_addhosts(struct dyndir *dd, char *path) static struct hostsfile *dyndir_addhosts(struct dyndir *dd, char *file)
{ {
/* Check if this file is already known in dd->files */ /* Check if this file is already known in dd->files */
struct hostsfile *ah = NULL; struct hostsfile *ah;
for(ah = dd->files; ah; ah = ah->next) size_t dirlen = strlen(dd->dname);
if(ah && ah->fname && strcmp(path, ah->fname) == 0)
/* ah->fname always starts with the string in dd->dname */
for (ah = dd->files; ah; ah = ah->next)
if (ah->fname[dirlen] == '/' &&
strcmp(&ah->fname[dirlen+1], file) == 0)
return ah; return ah;
/* Not known, create new hostsfile record for this dyndir */ /* Not known, create new hostsfile record for this dyndir */
struct hostsfile *newah = NULL; if ((ah = whine_malloc(sizeof(struct hostsfile))))
if(!(newah = whine_malloc(sizeof(struct hostsfile)))) {
char *path;
if (!(path = whine_malloc(dirlen + strlen(file) + 2)))
{
free(ah);
return NULL; return NULL;
}
strcpy(path, dd->dname);
strcat(path, "/");
strcat(path, file);
/* Add this file to the tip of the linked list */ /* Add this file to the tip of the linked list */
newah->next = dd->files; ah->next = dd->files;
dd->files = newah; dd->files = ah;
/* Copy flags, set index and the full file path */ /* Copy flags, set index and the full file path */
newah->flags = dd->flags; ah->flags = dd->flags;
newah->index = daemon->host_index++; ah->index = daemon->host_index++;
newah->fname = path; ah->fname = path;
}
return newah; return ah;
} }
@@ -204,9 +219,7 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
while ((ent = readdir(dir_stream))) while ((ent = readdir(dir_stream)))
{ {
size_t lendir = strlen(dd->dname);
size_t lenfile = strlen(ent->d_name); size_t lenfile = strlen(ent->d_name);
char *path;
/* ignore emacs backups and dotfiles */ /* ignore emacs backups and dotfiles */
if (lenfile == 0 || if (lenfile == 0 ||
@@ -215,32 +228,35 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
ent->d_name[0] == '.') ent->d_name[0] == '.')
continue; continue;
if ((path = whine_malloc(lendir + lenfile + 2))) if (dd->flags & AH_HOSTS)
{ {
struct hostsfile *ah; struct hostsfile *ah;
/* ignore non-regular files */
if ((ah = dyndir_addhosts(dd, ent->d_name)) &&
stat(ah->fname, &buf) != -1 && S_ISREG(buf.st_mode))
total_size = read_hostsfile(ah->fname, ah->index, total_size, rhash, revhashsz);
}
#ifdef HAVE_DHCP
else if (dd->flags & (AH_DHCP_HST | AH_DHCP_OPT))
{
char *path;
if ((path = whine_malloc(strlen(dd->dname) + lenfile + 2)))
{
strcpy(path, dd->dname); strcpy(path, dd->dname);
strcat(path, "/"); strcat(path, "/");
strcat(path, ent->d_name); strcat(path, ent->d_name);
if (!(ah = dyndir_addhosts(dd, path)))
{
free(path);
continue;
}
/* ignore non-regular files */ /* ignore non-regular files */
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode)) if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
{
if (dd->flags & AH_HOSTS)
total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz);
#ifdef HAVE_DHCP
else if (dd->flags & (AH_DHCP_HST | AH_DHCP_OPT))
option_read_dynfile(path, dd->flags); option_read_dynfile(path, dd->flags);
free(path);
}
}
#endif #endif
} }
}
}
closedir(dir_stream); closedir(dir_stream);
} }
@@ -285,34 +301,25 @@ int inotify_check(time_t now)
for (dd = daemon->dynamic_dirs; dd; dd = dd->next) for (dd = daemon->dynamic_dirs; dd; dd = dd->next)
if (dd->wd == in->wd) if (dd->wd == in->wd)
{ {
size_t lendir = strlen(dd->dname); if (dd->flags & AH_HOSTS)
char *path;
if ((path = whine_malloc(lendir + in->len + 2)))
{ {
struct hostsfile *ah = NULL; struct hostsfile *ah;
if ((ah = dyndir_addhosts(dd, in->name)))
strcpy(path, dd->dname); {
strcat(path, "/"); const unsigned int removed = cache_remove_uid(ah->index);
strcat(path, in->name);
/* Is this is a deletion event? */ /* Is this is a deletion event? */
if (in->mask & IN_DELETE) if (in->mask & IN_DELETE)
my_syslog(LOG_INFO, _("inotify: %s removed"), path); my_syslog(LOG_INFO, _("inotify: %s removed"), ah->fname);
else else
my_syslog(LOG_INFO, _("inotify: %s new or modified"), path); my_syslog(LOG_INFO, _("inotify: %s new or modified"), ah->fname);
if (dd->flags & AH_HOSTS)
{
if ((ah = dyndir_addhosts(dd, path)))
{
const unsigned int removed = cache_remove_uid(ah->index);
if (removed > 0) if (removed > 0)
my_syslog(LOG_INFO, _("inotify: flushed %u names read from %s"), removed, path); my_syslog(LOG_INFO, _("inotify: flushed %u names read from %s"), removed, ah->fname);
/* (Re-)load hostsfile only if this event isn't triggered by deletion */ /* (Re-)load hostsfile only if this event isn't triggered by deletion */
if (!(in->mask & IN_DELETE)) if (!(in->mask & IN_DELETE))
read_hostsfile(path, ah->index, 0, NULL, 0); read_hostsfile(ah->fname, ah->index, 0, NULL, 0);
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp || daemon->doing_dhcp6) if (daemon->dhcp || daemon->doing_dhcp6)
{ {
@@ -326,9 +333,19 @@ int inotify_check(time_t now)
} }
} }
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
else if (dd->flags & AH_DHCP_HST) else if (!(in->mask & IN_DELETE))
{ {
if (option_read_dynfile(path, AH_DHCP_HST)) char *path;
if ((path = whine_malloc(strlen(dd->dname) + in->len + 2)))
{
strcpy(path, dd->dname);
strcat(path, "/");
strcat(path, in->name);
my_syslog(LOG_INFO, _("inotify: %s new or modified"), path);
if ((dd->flags & AH_DHCP_HST) && option_read_dynfile(path, AH_DHCP_HST))
{ {
/* Propagate the consequences of loading a new dhcp-host */ /* Propagate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf); dhcp_update_configs(daemon->dhcp_conf);
@@ -336,17 +353,19 @@ int inotify_check(time_t now)
lease_update_file(now); lease_update_file(now);
lease_update_dns(1); lease_update_dns(1);
} }
}
else if (dd->flags & AH_DHCP_OPT)
option_read_dynfile(path, AH_DHCP_OPT);
#endif
if (!ah) if (dd->flags & AH_DHCP_OPT)
option_read_dynfile(path, AH_DHCP_OPT);
free(path); free(path);
} }
} }
#endif
} }
} }
}
return hit; return hit;
} }
+9 -7
View File
@@ -198,10 +198,10 @@ static void tftp_request(struct listener *listen, time_t now)
name = namebuff; name = namebuff;
addra.addr4 = addr.in.sin_addr;
if (family == AF_INET6) if (family == AF_INET6)
addra.addr6 = addr.in6.sin6_addr; addra.addr6 = addr.in6.sin6_addr;
else
addra.addr4 = addr.in.sin_addr;
if (daemon->tftp_interfaces) if (daemon->tftp_interfaces)
{ {
@@ -679,7 +679,6 @@ void check_tftp_listeners(time_t now)
/* Do transmission or re-transmission. When we get an ACK, the call to handle_tftp() /* Do transmission or re-transmission. When we get an ACK, the call to handle_tftp()
bumps transfer->lastack and trips the retransmit timer so that we send the next block(s) bumps transfer->lastack and trips the retransmit timer so that we send the next block(s)
here. */ here. */
unsigned int i, winsize;
ssize_t len; ssize_t len;
transfer->retransmit += transfer->timeout + (1<<(transfer->backoff/2)); transfer->retransmit += transfer->timeout + (1<<(transfer->backoff/2));
@@ -691,10 +690,7 @@ void check_tftp_listeners(time_t now)
else else
{ {
/* send a window'a worth of blocks unless we're retransmitting OACK */ /* send a window'a worth of blocks unless we're retransmitting OACK */
winsize = transfer->block ? transfer->windowsize : 1; unsigned int i, winsize = transfer->block ? transfer->windowsize : 1;
/* we overwrote the buffer... */
daemon->srv_save = NULL;
for (i = 0; i < winsize && !endcon; i++, transfer->block++) for (i = 0; i < winsize && !endcon; i++, transfer->block++)
{ {
@@ -861,6 +857,9 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *
} *mess = (struct errmess *)packet; } *mess = (struct errmess *)packet;
ssize_t len, ret = 4; ssize_t len, ret = 4;
/* we overwrote the buffer... */
daemon->srv_save = NULL;
memset(packet, 0, daemon->packet_buff_sz); memset(packet, 0, daemon->packet_buff_sz);
if (file) if (file)
sanitise(file); sanitise(file);
@@ -889,6 +888,9 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
{ {
memset(packet, 0, daemon->packet_buff_sz); memset(packet, 0, daemon->packet_buff_sz);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if (transfer->block == 0) if (transfer->block == 0)
{ {
/* send OACK */ /* send OACK */