Compare commits

...
21 Commits
Author SHA1 Message Date
Simon Kelley bceb5287b9 Fix FTBFS on MacOS.
Fallout from 98189ff988

Thanks to Travis Rayan for the bug report.
2025-07-07 17:58:41 +01:00
Simon Kelley 84445dec26 Fix server selection for DS queries.
This was mainly done in 57e582492b
This commit extends the new behaviour to cases where DNSSEC
validation is not compiled-in or not enabled.
2025-07-07 17:16:32 +01:00
Rob Gill via Dnsmasq-discuss c70b92b2a4 Add CG-NAT range to non-globally routed IP space per RFC7793
The Shared address space (100.64.0.0/10) used by CG-NAT, defined in RFC6598 should
not have reverse DNS queries sent to global DNS infrastructure.

Confirmed in RFC7793 and listed on
https://www.iana.org/assignments/locally-served-dns-zones/locally-served-dns-zones.xhtml

Signed-off-by: Rob Gill <rrobgill@protonmail.com>
2025-06-26 13:10:48 +01:00
Simon Kelley 57e582492b Fix to 57f0489f38
When choosing a server to send a DS query to take
account of the need for DS records for a domain
to come from the parent of that domain.
2025-06-25 15:02:47 +01:00
Simon Kelley ec8f3e65c1 Tweak domain-specific servers and DNSSEC code to treat
servers for plain names (server=//1.2.3.4) as domain-specific.

This means that if we fail to get a DS record for such a query,
it gets given the benefit of the doubt.

Updates 57f0489f38
2025-06-23 21:48:29 +01:00
Simon Kelley 15841f187d Fix issue with fast file-descriptor close on *BSD.
This fixes a problem introduced in 8a5fe8ce6b

On BSD, fdescfs is normally mounted at /dev/fd. However
if it is NOT mounted, devfs creates a directory at /dev/fd
which contains (only) the file descriptors 0,1 and 2.

Under these conditions, opendir() will succeed, and
if we proceed we will fail to close extant
file descriptors which should be closed.

Check that there is a filesystem mounted at /dev/fd
by checking that the device changes between /dev/fd
and /dev. If if doesn't, fall back to the dumb path.

Thanks to Roman Bogorodskiy for spotting the problem
and helping with diagnosis.
2025-06-22 23:04:36 +01:00
Simon Kelley ade97495e6 Trvial formatting fix. 2025-06-20 17:12:32 +01:00
Simon Kelley 2b19285724 Fix breakage of ipset on *BSD.
Regression introduced in 98189ff988

Thanks to Harper Andrews for spotting this.
2025-06-20 15:48:47 +01:00
Simon Kelley a444715bf0 Fix FTBFS on Jurassic gcc versions. 2025-06-20 15:27:43 +01:00
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
Simon Kelley 90b248582c Remove compiler warnings for obscure combinations of build options. 2025-05-24 15:09:53 +01:00
Simon Kelley ebef27f321 Add TFTP options windowsize (RFC 7440) and timeout (RFC 2349). 2025-05-24 14:41:40 +01:00
Matthias Andree 1861a881eb Only define variable "a" if we HAVE_LINUX_NETWORK
Variable unsigned char a is defined unconditionally,
but it is only used if HAVE_LINUX_NETWORK is defined.
This triggers compiler warnings on, say, FreeBSD.

Fix by wrapping the definition in proper #ifdef.
2025-05-21 19:48:39 +01:00
Matthias Andree 96bdb42d40 Fix GCC's -Wunterminated-string-initialization warning in edns0.c.
GCC complains that writing the five-character "ODNS\0" string into
a four-element char magic[4] array truncates the NUL character.
The warning's rationale is that this is incompatible with C++, or
maybe non-intentional.

GCC 8 has added a nonstring variable attribute, clang 20.1 does
not yet support this, but clang's Git head does.

Add an ATTRIBUTE_NONSTRING macro, currently only defined on GCC >= 8
as __attribute__ ((nonstring)).  This successfully suppresses
the warning on Fedora Linux 42's default compiler.

The alternative would be to replace the "ODNS" literal by {0} and
instead memcpy(opt.magic, "ODNS", sizeof(opt.magic)); on the next line,
which is correct, C++ compatible, but also less concise.
2025-05-21 15:06:27 +01:00
Simon Kelley c7a909ad65 Add RRtypes HHIT and BRID to the table. 2025-05-21 15:03:51 +01:00
17 changed files with 510 additions and 310 deletions

No files matched your search

+2
View File
@@ -59,6 +59,8 @@ version 2.92
Fix failure to cache PTR RRs when a reply contains more than one answer.
Thanks to Dmitry for spotting this.
Add TFTP options windowsize (RFC 7440) and timeout (RFC 2349).
version 2.91
Fix spurious "resource limit exceeded messages". Thanks to
+6 -2
View File
@@ -102,6 +102,8 @@ static const struct {
{ 64, "SVCB" }, /* Service Binding [draft-ietf-dnsop-svcb-https-00] SVCB/svcb-completed-template 2020-06-30*/
{ 65, "HTTPS" }, /* HTTPS Binding [draft-ietf-dnsop-svcb-https-00] HTTPS/https-completed-template 2020-06-30*/
{ 66, "DSYNC" }, /* Endpoint discovery for delegation synchronization [draft-ietf-dnsop-generalized-notify-03] DSYNC/dsync-completed-template 2024-12-10 */
{ 67, "HHIT" }, /* [draft-ietf-drip-registries-28] */
{ 68, "BRID" }, /* [draft-ietf-drip-registries-28] */
{ 99, "SPF" }, /* [RFC7208] */
{ 100, "UINFO" }, /* [IANA-Reserved] */
{ 101, "UID" }, /* [IANA-Reserved] */
@@ -2358,6 +2360,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "reply";
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_QUERY)
source = "query";
else if (flags & F_SECSTAT)
{
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
@@ -2398,8 +2402,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "non-query opcode";
name = opcodestring;
}
else if (!(flags & F_AUTH))
source = "query";
else if (type > 0)
source = querystr(source, type);
verb = "from";
}
+13 -1
View File
@@ -52,6 +52,8 @@
#define CHUSER "nobody"
#define CHGRP "dip"
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define TFTP_MAX_WINDOW 32 /* max window size to negotiate */
#define TFTP_TRANSFER_TIME 120 /* Abandon TFTP transfers after this long. Two mins. */
#define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom"
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
@@ -288,6 +290,7 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#define HAVE_SOCKADDR_SA_LEN
#define NO_IPSET
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
/* Select the RFC_3542 version of the IPv6 socket API.
@@ -347,7 +350,6 @@ HAVE_SOCKADDR_SA_LEN
#endif
#if !defined(HAVE_LINUX_NETWORK)
#undef HAVE_IPSET
#undef HAVE_NFTSET
#endif
@@ -355,6 +357,16 @@ HAVE_SOCKADDR_SA_LEN
#undef HAVE_IPSET
#endif
#if defined(HAVE_IPSET)
# if defined(HAVE_LINUX_NETWORK)
# define HAVE_LINUX_IPSET
# elif defined(HAVE_BSD_NETWORK)
# define HAVE_BSD_IPSET
# else
# undef HAVE_IPSET
# endif
#endif
#ifdef NO_LOOP
#undef HAVE_LOOP
#endif
+14 -3
View File
@@ -30,7 +30,9 @@ static volatile pid_t pid = 0;
static volatile int pipewrite;
static void set_dns_listeners(void);
#ifdef HAVE_TFTP
static void set_tftp_listeners(void);
#endif
static void check_dns_listeners(time_t now);
static void do_tcp_connection(struct listener *listener, time_t now, int slot);
static void sig_handler(int sig);
@@ -62,14 +64,16 @@ int main (int argc, char **argv)
int need_cap_net_raw = 0;
int need_cap_net_bind_service = 0;
int have_cap_chown = 0;
# ifdef HAVE_DHCP
char *bound_device = NULL;
int did_bind = 0;
# endif
struct server *serv;
char *netlink_warn;
#else
int bind_fallback = 0;
#endif
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
#if defined(HAVE_DHCP)
struct dhcp_context *context;
struct dhcp_relay *relay;
#endif
@@ -77,6 +81,10 @@ int main (int argc, char **argv)
int tftp_prefix_missing = 0;
#endif
#ifdef HAVE_LINUX_NETWORK
(void)netlink_warn;
#endif
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
setlocale(LC_ALL, "");
#endif
@@ -1939,11 +1947,14 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
pid_t p;
union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr);
unsigned char a = 0, *buff;
unsigned char *buff;
struct server *s;
int flags, auth_dns;
struct in_addr netmask;
int pipefd[2];
#ifdef HAVE_LINUX_NETWORK
unsigned char a = 0;
#endif
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
@@ -2052,7 +2063,7 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
single byte comes back up the pipe, which
is sent by the child after it has closed the
netlink socket. */
read_write(pipefd[0], &a, 1, RW_READ);
#endif
+10 -6
View File
@@ -48,6 +48,12 @@
#define ATTRIBUTE_NORETURN
#endif
#if __GNUC__ + 0 >= 8 // clang 20.1.0 does not yet support this
#define ATTRIBUTE_NONSTRING __attribute__ ((nonstring))
#else
#define ATTRIBUTE_NONSTRING
#endif
/* get these before config.h for IPv6 stuff... */
#include <sys/types.h>
#include <sys/socket.h>
@@ -1111,14 +1117,13 @@ struct tftp_file {
struct tftp_transfer {
int sockfd;
time_t timeout;
int backoff;
unsigned int block, blocksize, expansion;
time_t retransmit, start;
unsigned int lastack, block, blocksize, windowsize, timeout, expansion;
off_t offset;
union mysockaddr peer;
union all_addr source;
int if_index;
char opt_blocksize, opt_transize, netascii, carrylf;
unsigned char opt_blocksize, opt_transize, opt_windowsize, opt_timeout, netascii, carrylf, backoff;
struct tftp_file *file;
struct tftp_transfer *next;
};
@@ -1762,7 +1767,6 @@ void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *p
/* tftp.c */
#ifdef HAVE_TFTP
void tftp_request(struct listener *listen, time_t now);
void check_tftp_listeners(time_t now);
int do_tftp_script_run(void);
#endif
@@ -1934,7 +1938,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
char *name, char *limit, int first, int last, int ede);
int server_samegroup(struct server *a, struct server *b);
#ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp);
int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp);
#endif
void mark_servers(int flag);
void cleanup_servers(void);
+24 -10
View File
@@ -95,6 +95,7 @@ void build_server_array(void)
A flag of F_SERVER returns an upstream server only.
A flag of F_DNSSECOK disables NODOTS servers from consideration.
A flag of F_DS returns parent domain server.
A flag of F_DOMAINSRV returns a domain-specific server only.
A flag of F_CONFIG returns anything that generates a local
reply of IPv4 or IPV6.
@@ -106,12 +107,23 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
ssize_t qlen;
int try, high, low = 0;
int nlow = 0, nhigh = 0;
char *cp, *qdomain = domain;
char *cp, *qdomain;
/* may be no configured servers. */
if (daemon->serverarraysz == 0)
return 0;
/* DS records should come from the parent domain. */
if (flags & F_DS)
{
if ((cp = strchr(domain, '.')))
domain = cp+1;
else
domain = "";
}
qdomain = domain;
/* find query length and presence of '.' */
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
if (*cp == '.')
@@ -244,7 +256,10 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
if (nodots &&
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
{
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
qlen = 0;
}
if (lowout)
*lowout = nlow;
@@ -343,10 +358,9 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
else
{
/* 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 && !(daemon->serverarray[nlow]->flags & SERV_FOR_NODOTS))
nlow = nhigh;
else
nlow = i;
}
}
}
@@ -401,7 +415,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
setup_reply(header, flags, ede);
gotname &= ~F_QUERY;
gotname &= ~(F_QUERY | F_DS);
if (flags & (F_NXDOMAIN | F_NOERR))
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
@@ -461,14 +475,14 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
}
#ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp)
{
int first, last, index;
/* Find server to send DNSSEC query to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK, &first, &last))
if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK | (is_ds ? F_DS : 0), &first, &last))
return -1;
for (index = first; index != last; index++)
+1 -1
View File
@@ -494,7 +494,7 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
#define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device)
struct umbrella_opt {
u8 magic[4];
u8 magic[4] ATTRIBUTE_NONSTRING;
u8 version;
u8 flags;
/* We have 4 possible fields since we'll never send both IPv4 and
+3 -3
View File
@@ -1024,7 +1024,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
/* Make sure we don't expire and free the orig frec during the
allocation of a new one: third arg of get_new_frec() does that. */
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, NULL, NULL)) != -1 &&
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, STAT_ISEQUAL(status, STAT_NEED_DS), NULL, NULL)) != -1 &&
(server = daemon->serverarray[serverind]) &&
(nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz,
daemon->keyname, forward->class, get_id(),
@@ -2199,7 +2199,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
first = start = server->arrayposn;
last = first + 1;
if (!STAT_ISEQUAL(status, STAT_OK) && (start = dnssec_server(server, name, &first, &last)) == -1)
if (!STAT_ISEQUAL(status, STAT_OK) && (start = dnssec_server(server, name, STAT_ISEQUAL(status, STAT_NEED_DS), &first, &last)) == -1)
new_status = STAT_ABANDONED;
else
{
@@ -2307,7 +2307,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0,
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
if ((start = dnssec_server(server, keyname, &first, &last)) == -1)
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1)
{
new_status = STAT_ABANDONED;
break;
+106 -85
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 */
struct hostsfile *ah = NULL;
for(ah = dd->files; ah; ah = ah->next)
if(ah && ah->fname && strcmp(path, ah->fname) == 0)
struct hostsfile *ah;
size_t dirlen = strlen(dd->dname);
/* 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;
/* Not known, create new hostsfile record for this dyndir */
struct hostsfile *newah = NULL;
if(!(newah = whine_malloc(sizeof(struct hostsfile))))
return NULL;
if ((ah = whine_malloc(sizeof(struct hostsfile))))
{
char *path;
/* Add this file to the tip of the linked list */
newah->next = dd->files;
dd->files = newah;
/* Copy flags, set index and the full file path */
newah->flags = dd->flags;
newah->index = daemon->host_index++;
newah->fname = path;
return newah;
if (!(path = whine_malloc(dirlen + strlen(file) + 2)))
{
free(ah);
return NULL;
}
strcpy(path, dd->dname);
strcat(path, "/");
strcat(path, file);
/* Add this file to the tip of the linked list */
ah->next = dd->files;
dd->files = ah;
/* Copy flags, set index and the full file path */
ah->flags = dd->flags;
ah->index = daemon->host_index++;
ah->fname = path;
}
return ah;
}
@@ -204,10 +219,8 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
while ((ent = readdir(dir_stream)))
{
size_t lendir = strlen(dd->dname);
size_t lenfile = strlen(ent->d_name);
char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
@@ -215,33 +228,36 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
ent->d_name[0] == '.')
continue;
if ((path = whine_malloc(lendir + lenfile + 2)))
if (dd->flags & AH_HOSTS)
{
struct hostsfile *ah;
strcpy(path, dd->dname);
strcat(path, "/");
strcat(path, ent->d_name);
if (!(ah = dyndir_addhosts(dd, path)))
{
free(path);
continue;
}
/* ignore non-regular files */
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);
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))
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);
strcat(path, "/");
strcat(path, ent->d_name);
/* ignore non-regular files */
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
option_read_dynfile(path, dd->flags);
#endif
free(path);
}
}
#endif
}
closedir(dir_stream);
}
}
@@ -251,6 +267,8 @@ int inotify_check(time_t now)
int hit = 0;
struct dyndir *dd;
(void)now;
while (1)
{
int rc;
@@ -283,50 +301,27 @@ int inotify_check(time_t now)
for (dd = daemon->dynamic_dirs; dd; dd = dd->next)
if (dd->wd == in->wd)
{
size_t lendir = strlen(dd->dname);
char *path;
if ((path = whine_malloc(lendir + in->len + 2)))
if (dd->flags & AH_HOSTS)
{
struct hostsfile *ah = NULL;
strcpy(path, dd->dname);
strcat(path, "/");
strcat(path, in->name);
/* Is this is a deletion event? */
if (in->mask & IN_DELETE)
my_syslog(LOG_INFO, _("inotify: %s removed"), path);
else
my_syslog(LOG_INFO, _("inotify: %s new or modified"), path);
if (dd->flags & AH_HOSTS)
struct hostsfile *ah;
if ((ah = dyndir_addhosts(dd, in->name)))
{
if ((ah = dyndir_addhosts(dd, path)))
{
const unsigned int removed = cache_remove_uid(ah->index);
if (removed > 0)
my_syslog(LOG_INFO, _("inotify: flushed %u names read from %s"), removed, path);
const unsigned int removed = cache_remove_uid(ah->index);
/* (Re-)load hostsfile only if this event isn't triggered by deletion */
if (!(in->mask & IN_DELETE))
read_hostsfile(path, ah->index, 0, NULL, 0);
/* Is this is a deletion event? */
if (in->mask & IN_DELETE)
my_syslog(LOG_INFO, _("inotify: %s removed"), ah->fname);
else
my_syslog(LOG_INFO, _("inotify: %s new or modified"), ah->fname);
if (removed > 0)
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 */
if (!(in->mask & IN_DELETE))
read_hostsfile(ah->fname, ah->index, 0, NULL, 0);
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->doing_dhcp6)
{
/* Propagate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns(1);
}
#endif
}
}
#ifdef HAVE_DHCP
else if (dd->flags & AH_DHCP_HST)
{
if (option_read_dynfile(path, AH_DHCP_HST))
if (daemon->dhcp || daemon->doing_dhcp6)
{
/* Propagate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
@@ -334,17 +329,43 @@ int inotify_check(time_t now)
lease_update_file(now);
lease_update_dns(1);
}
}
else if (dd->flags & AH_DHCP_OPT)
option_read_dynfile(path, AH_DHCP_OPT);
#endif
if (!ah)
free(path);
}
}
#ifdef HAVE_DHCP
else if (!(in->mask & IN_DELETE))
{
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 */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns(1);
}
if (dd->flags & AH_DHCP_OPT)
option_read_dynfile(path, AH_DHCP_OPT);
free(path);
}
}
#endif
}
}
}
return hit;
}
+1 -1
View File
@@ -16,7 +16,7 @@
#include "dnsmasq.h"
#if defined(HAVE_IPSET)
#if defined(HAVE_LINUX_IPSET)
#include <string.h>
#include <errno.h>
+5 -1
View File
@@ -1568,6 +1568,8 @@ void check_servers(int no_loop_check)
struct serverfd *sfd, *tmp, **up;
int port = 0, count;
int locals = 0;
(void)no_loop_check;
#ifdef HAVE_LOOP
if (!no_loop_check)
@@ -1775,8 +1777,10 @@ int reload_servers(char *fname)
/* Called when addresses are added or deleted from an interface */
void newaddress(time_t now)
{
#ifdef HAVE_DHCP
struct dhcp_relay *relay;
#endif
(void)now;
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
+7 -3
View File
@@ -2917,13 +2917,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break;
#ifdef HAVE_DHCP
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
# endif
case LOPT_LEASEQUERY:
set_option_bool(OPT_LEASEQUERY);
if (!arg)
break;
#pragma GCC diagnostic pop
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic pop
# endif
#endif
case 'B': /* --bogus-nxdomain */
case LOPT_IGNORE_ADDR: /* --ignore-address */
+3 -4
View File
@@ -415,6 +415,7 @@ int private_net(struct in_addr addr, int ban_localhost)
(((ip_addr & 0xFF000000) == 0x7F000000) && ban_localhost) /* 127.0.0.0/8 (loopback) */ ||
(((ip_addr & 0xFF000000) == 0x00000000) && ban_localhost) /* RFC 5735 section 3. "here" network */ ||
((ip_addr & 0xFF000000) == 0x0A000000) /* 10.0.0.0/8 (private) */ ||
((ip_addr & 0xFFC00000) == 0x64400000) /* 100.64.0.0/10 (CG-NAT) RFC6598/RFC7793*/ ||
((ip_addr & 0xFFF00000) == 0xAC100000) /* 172.16.0.0/12 (private) */ ||
((ip_addr & 0xFFFF0000) == 0xC0A80000) /* 192.168.0.0/16 (private) */ ||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ||
@@ -1244,12 +1245,10 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
return F_IPV4 | F_IPV6;
}
#ifdef HAVE_DNSSEC
/* Make the behaviour for DS and DNSKEY queries we forward the same
as for DS and DNSKEY queries we originate. */
if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DS || qtype == T_DNSKEY))
return F_DNSSECOK;
#endif
if (qtype == T_DS || qtype == T_DNSKEY)
return F_DNSSECOK | (qtype == T_DS ? F_DS : 0);
return F_QUERY;
}
+1 -1
View File
@@ -18,7 +18,7 @@
#include "dnsmasq.h"
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
#if defined(HAVE_BSD_IPSET)
#include <string.h>
+276 -185
View File
@@ -41,11 +41,11 @@ static void sanitise(char *buf);
#define ERR_ILL 4
#define ERR_TID 5
void tftp_request(struct listener *listen, time_t now)
static void tftp_request(struct listener *listen, time_t now)
{
ssize_t len;
char *packet = daemon->packet;
char *filename, *mode, *p, *end, *opt;
char *filename, *mode, *p, *end;
union mysockaddr addr, peer;
struct msghdr msg;
struct iovec iov;
@@ -198,11 +198,11 @@ void tftp_request(struct listener *listen, time_t now)
name = namebuff;
addra.addr4 = addr.in.sin_addr;
if (family == AF_INET6)
addra.addr6 = addr.in6.sin6_addr;
else
addra.addr4 = addr.in.sin_addr;
if (daemon->tftp_interfaces)
{
/* dedicated tftp interface list */
@@ -308,7 +308,9 @@ void tftp_request(struct listener *listen, time_t now)
/* May reuse struct transfer from abandoned transfer in single port mode. */
if (!transfer && !(transfer = whine_malloc(sizeof(struct tftp_transfer))))
return;
memset(transfer, 0, sizeof(struct tftp_transfer));
if (option_bool(OPT_SINGLE_PORT))
transfer->sockfd = listen->tftpfd;
else if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
@@ -320,15 +322,13 @@ void tftp_request(struct listener *listen, time_t now)
transfer->peer = peer;
transfer->source = addra;
transfer->if_index = if_index;
transfer->timeout = now + 2;
transfer->timeout = 2;
transfer->start = now;
transfer->backoff = 1;
transfer->block = 1;
transfer->blocksize = 512;
transfer->offset = 0;
transfer->file = NULL;
transfer->opt_blocksize = transfer->opt_transize = 0;
transfer->netascii = transfer->carrylf = 0;
transfer->windowsize = 1;
(void)prettyprint_addr(&peer, daemon->addrbuff);
/* if we have a nailed-down range, iterate until we find a free one. */
@@ -361,140 +361,167 @@ void tftp_request(struct listener *listen, time_t now)
p = packet + 2;
end = packet + len;
len = 0;
if (!(filename = next(&p, end)) ||
!(mode = next(&p, end)) ||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0) ||
ntohs(*((unsigned short *)packet)) != OP_RRQ)
if (ntohs(*((unsigned short *)packet)) == OP_WRQ)
len = tftp_err(ERR_ILL, packet, _("unsupported write request from %s"),daemon->addrbuff, NULL);
else if (ntohs(*((unsigned short *)packet)) == OP_RRQ)
{
if (!filename)
if (!(filename = next(&p, end)))
len = tftp_err(ERR_ILL, packet, _("empty filename in request from %s"), daemon->addrbuff, NULL);
else if (!(mode = next(&p, end)) || (strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"),daemon->addrbuff, NULL);
else
len = tftp_err(ERR_ILL, packet, _("unsupported %srequest from %s"),
(ntohs(*((unsigned short *)packet)) == OP_WRQ) ? _("write ") : "", daemon->addrbuff);
is_err = 1;
}
else
{
if (strcasecmp(mode, "netascii") == 0)
transfer->netascii = 1;
while ((opt = next(&p, end)))
{
if (strcasecmp(opt, "blksize") == 0)
char *opt, *arg;
if (strcasecmp(mode, "netascii") == 0)
transfer->netascii = 1;
while ((opt = next(&p, end)) && (arg = next(&p, end)))
{
if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
unsigned int val = atoi(arg);
if (strcasecmp(opt, "blksize") == 0 && !option_bool(OPT_TFTP_NOBLOCK))
{
/* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
int overhead = (family == AF_INET) ? 32 : 52;
transfer->blocksize = atoi(opt);
if (transfer->blocksize < 1)
transfer->blocksize = 1;
if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
if (mtu != 0 && transfer->blocksize > (unsigned)mtu - overhead)
transfer->blocksize = (unsigned)mtu - overhead;
if (val < 1)
val = 1;
if (val > (unsigned)daemon->packet_buff_sz - 4)
val = (unsigned)daemon->packet_buff_sz - 4;
if (mtu != 0 && val > (unsigned)mtu - overhead)
val = (unsigned)mtu - overhead;
transfer->blocksize = val;
transfer->opt_blocksize = 1;
transfer->block = 0;
}
}
else if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
{
transfer->opt_transize = 1;
transfer->block = 0;
}
}
/* cope with backslashes from windows boxen. */
for (p = filename; *p; p++)
if (*p == '\\')
*p = '/';
else if (option_bool(OPT_TFTP_LC))
*p = tolower((unsigned char)*p);
strcpy(daemon->namebuff, "/");
if (prefix)
{
if (prefix[0] == '/')
daemon->namebuff[0] = 0;
strncat(daemon->namebuff, prefix, (MAXDNAME-1) - strlen(daemon->namebuff));
if (prefix[strlen(prefix)-1] != '/')
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
if (option_bool(OPT_TFTP_APREF_IP))
{
size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf;
strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
/* remove unique-directory if it doesn't exist */
if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
daemon->namebuff[oldlen] = 0;
else if (strcasecmp(opt, "tsize") == 0 && !transfer->netascii)
{
transfer->opt_transize = 1;
transfer->block = 0;
}
else if (strcasecmp(opt, "timeout") == 0)
{
if (val > 255)
val = 255;
transfer->timeout = val;
transfer->opt_timeout = 1;
transfer->block = 0;
}
else if (strcasecmp(opt, "windowsize") == 0 && !transfer->netascii)
{
/* windowsize option only supported for binary transfers. */
if (val < 1)
val = 1;
if (val > TFTP_MAX_WINDOW)
val = TFTP_MAX_WINDOW;
transfer->windowsize = val;
transfer->opt_windowsize = 1;
transfer->block = 0;
}
}
if (option_bool(OPT_TFTP_APREF_MAC))
/* cope with backslashes from windows boxen. */
for (p = filename; *p; p++)
if (*p == '\\')
*p = '/';
else if (option_bool(OPT_TFTP_LC))
*p = tolower((unsigned char)*p);
strcpy(daemon->namebuff, "/");
if (prefix)
{
unsigned char *macaddr = NULL;
unsigned char macbuf[DHCP_CHADDR_MAX];
if (prefix[0] == '/')
daemon->namebuff[0] = 0;
strncat(daemon->namebuff, prefix, (MAXDNAME-1) - strlen(daemon->namebuff));
if (prefix[strlen(prefix)-1] != '/')
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
#ifdef HAVE_DHCP
if (daemon->dhcp && peer.sa.sa_family == AF_INET)
{
/* Check if the client IP is in our lease database */
struct dhcp_lease *lease = lease_find_by_addr(peer.in.sin_addr);
if (lease && lease->hwaddr_type == ARPHRD_ETHER && lease->hwaddr_len == ETHER_ADDR_LEN)
macaddr = lease->hwaddr;
}
#endif
/* If no luck, try to find in ARP table. This only works if client is in same (V)LAN */
if (!macaddr && find_mac(&peer, macbuf, 1, now) > 0)
macaddr = macbuf;
if (macaddr)
{
if (option_bool(OPT_TFTP_APREF_IP))
{
size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf;
snprintf(daemon->namebuff + oldlen, (MAXDNAME-1) - oldlen, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x/",
macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
/* remove unique-directory if it doesn't exist */
if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
daemon->namebuff[oldlen] = 0;
}
if (option_bool(OPT_TFTP_APREF_MAC))
{
unsigned char *macaddr = NULL;
unsigned char macbuf[DHCP_CHADDR_MAX];
#ifdef HAVE_DHCP
if (daemon->dhcp && peer.sa.sa_family == AF_INET)
{
/* Check if the client IP is in our lease database */
struct dhcp_lease *lease = lease_find_by_addr(peer.in.sin_addr);
if (lease && lease->hwaddr_type == ARPHRD_ETHER && lease->hwaddr_len == ETHER_ADDR_LEN)
macaddr = lease->hwaddr;
}
#endif
/* If no luck, try to find in ARP table. This only works if client is in same (V)LAN */
if (!macaddr && find_mac(&peer, macbuf, 1, now) > 0)
macaddr = macbuf;
if (macaddr)
{
size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf;
snprintf(daemon->namebuff + oldlen, (MAXDNAME-1) - oldlen, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x/",
macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
/* remove unique-directory if it doesn't exist */
if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
daemon->namebuff[oldlen] = 0;
}
}
/* Absolute pathnames OK if they match prefix */
if (filename[0] == '/')
{
if (strstr(filename, daemon->namebuff) == filename)
daemon->namebuff[0] = 0;
else
filename++;
}
}
else if (filename[0] == '/')
daemon->namebuff[0] = 0;
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
/* Absolute pathnames OK if they match prefix */
if (filename[0] == '/')
/* check permissions and open file */
if ((transfer->file = check_tftp_fileperm(&len, prefix, daemon->addrbuff)))
{
if (strstr(filename, daemon->namebuff) == filename)
daemon->namebuff[0] = 0;
transfer->lastack = transfer->block;
transfer->retransmit = now + transfer->timeout;
/* This packet is may be the first data packet, but only if windowsize == 1
To get windowsize greater then one requires an option negotiation,
in which case this packet is the OACK. */
if ((len = get_block(packet, transfer)) == -1)
len = tftp_err_oops(packet, daemon->namebuff);
else
filename++;
is_err = 0;
}
}
else if (filename[0] == '/')
daemon->namebuff[0] = 0;
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
/* check permissions and open file */
if ((transfer->file = check_tftp_fileperm(&len, prefix, daemon->addrbuff)))
{
if ((len = get_block(packet, transfer)) == -1)
len = tftp_err_oops(packet, daemon->namebuff);
else
is_err = 0;
}
}
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), packet, len, &peer, &addra, if_index);
if (len)
{
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), packet, len, &peer, &addra, if_index);
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_TFTP, (void *)packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd);
dump_packet_udp(DUMP_TFTP, (void *)packet, len, NULL, (union mysockaddr *)&peer, transfer->sockfd);
#endif
}
if (is_err)
free_transfer(transfer);
@@ -610,6 +637,10 @@ void check_tftp_listeners(time_t now)
if ((len = recvfrom(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0, &peer.sa, &addr_len)) > 0)
{
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, (union mysockaddr *)&peer, NULL, transfer->sockfd);
#endif
if (sockaddr_isequal(&peer, &transfer->peer))
handle_tftp(now, transfer, len);
else
@@ -628,66 +659,90 @@ void check_tftp_listeners(time_t now)
for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
{
tmp = transfer->next;
int endcon = 0, error = 0, timeout = 0;
if (difftime(now, transfer->timeout) >= 0.0)
tmp = transfer->next;
/* ->start set to zero in handle_tftp() when we recv an error packet. */
if (transfer->start == 0)
endcon = error = 1;
else if (difftime(now, transfer->start) > TFTP_TRANSFER_TIME)
{
int endcon = 0;
endcon = 1;
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
if (get_block(daemon->packet, transfer) > 0)
error = timeout = 1;
}
else if (difftime(now, transfer->retransmit) >= 0.0)
{
/* 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)
here. */
ssize_t len;
/* timeout, retransmit */
transfer->timeout += 1 + (1<<(transfer->backoff/2));
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if ((len = get_block(daemon->packet, transfer)) == -1)
{
len = tftp_err_oops(daemon->packet, transfer->file->filename);
endcon = 1;
}
else if (++transfer->backoff > 7)
{
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
if ((unsigned)len == transfer->blocksize + 4)
endcon = 1;
len = 0;
}
if (len != 0)
{
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
&transfer->peer, &transfer->source, transfer->if_index);
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, transfer->sockfd);
#endif
}
if (endcon || len == 0)
transfer->retransmit += transfer->timeout + (1<<(transfer->backoff/2));
transfer->backoff++;
transfer->block = transfer->lastack;
if ((len = get_block(daemon->packet, transfer)) == 0)
endcon = 1; /* got last ACK */
else
{
strcpy(daemon->namebuff, transfer->file->filename);
sanitise(daemon->namebuff);
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
/* unlink */
*up = tmp;
if (endcon)
free_transfer(transfer);
else
/* send a window'a worth of blocks unless we're retransmitting OACK */
unsigned int i, winsize = transfer->block ? transfer->windowsize : 1;
for (i = 0; i < winsize && !endcon; i++, transfer->block++)
{
/* put on queue to be sent to script and deleted */
transfer->next = daemon->tftp_done_trans;
daemon->tftp_done_trans = transfer;
if (i != 0)
len = get_block(daemon->packet, transfer);
if (len == 0)
break;
if (len == -1)
{
len = tftp_err_oops(daemon->packet, transfer->file->filename);
endcon = error = 1;
}
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
&transfer->peer, &transfer->source, transfer->if_index);
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, transfer->sockfd);
#endif
}
continue;
}
}
up = &transfer->next;
}
}
if (endcon)
{
strcpy(daemon->namebuff, transfer->file->filename);
sanitise(daemon->namebuff);
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
if (timeout)
my_syslog(MS_TFTP | LOG_ERR, _("timeout sending %s to %s"), daemon->namebuff, daemon->addrbuff);
else if (error)
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"), daemon->namebuff, daemon->addrbuff);
else
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
/* unlink */
*up = tmp;
if (error)
free_transfer(transfer);
else
{
/* put on queue to be sent to script and deleted */
transfer->next = daemon->tftp_done_trans;
daemon->tftp_done_trans = transfer;
}
}
else
up = &transfer->next;
}
}
/* packet in daemon->packet as this is called. */
static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
{
@@ -697,13 +752,30 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
if (len >= (ssize_t)sizeof(struct ack))
{
if (ntohs(mess->op) == OP_ACK && ntohs(mess->block) == (unsigned short)transfer->block)
if (ntohs(mess->op) == OP_ACK)
{
/* Got ack, ensure we take the (re)transmit path */
transfer->timeout = now;
transfer->backoff = 0;
if (transfer->block++ != 0)
transfer->offset += transfer->blocksize - transfer->expansion;
/* try and handle 16-bit blockno wrap-around */
unsigned int block = (unsigned short)ntohs(mess->block);
if (block < transfer->lastack)
block |= transfer->block & 0xffff0000;
/* ignore duplicate ACKs and ACKs for blocks we've not yet sent. */
if (block >= transfer->lastack &&
block <= transfer->block)
{
/* Got ack, move forward and ensure we take the (re)transmit path */
transfer->retransmit = transfer->start = now;
transfer->backoff = 0;
transfer->lastack = block + 1;
/* We have no easy function from block no. to file offset when
expanding line breaks in netascii mode, so we update the offset here
as each block is acknowledged. This explains why the window size must be
one for a netascii transfer; to avoid the block no. doing anything
other than incrementing by one. */
if (transfer->netascii && block != 0)
transfer->offset += transfer->blocksize - transfer->expansion;
}
}
else if (ntohs(mess->op) == OP_ERR)
{
@@ -724,8 +796,7 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
daemon->addrbuff);
/* Got err, ensure we take abort */
transfer->timeout = now;
transfer->backoff = 100;
transfer->start = 0;
}
}
}
@@ -785,7 +856,10 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *
char message[];
} *mess = (struct errmess *)packet;
ssize_t len, ret = 4;
/* we overwrote the buffer... */
daemon->srv_save = NULL;
memset(packet, 0, daemon->packet_buff_sz);
if (file)
sanitise(file);
@@ -813,7 +887,10 @@ static ssize_t tftp_err_oops(char *packet, const char *file)
static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
{
memset(packet, 0, daemon->packet_buff_sz);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if (transfer->block == 0)
{
/* send OACK */
@@ -835,7 +912,17 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
p += (sprintf(p,"tsize") + 1);
p += (sprintf(p, "%u", (unsigned int)transfer->file->size) + 1);
}
if (transfer->opt_timeout)
{
p += (sprintf(p,"timeout") + 1);
p += (sprintf(p, "%u", transfer->timeout) + 1);
}
if (transfer->opt_windowsize)
{
p += (sprintf(p,"windowsize") + 1);
p += (sprintf(p, "%u", (unsigned int)transfer->windowsize) + 1);
}
return p - packet;
}
else
@@ -846,31 +933,35 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
unsigned char data[];
} *mess = (struct datamess *)packet;
size_t size = transfer->file->size - transfer->offset;
size_t size;
if (!transfer->netascii)
transfer->offset = (transfer->block - 1) * transfer->blocksize;
if (transfer->offset > transfer->file->size)
return 0; /* finished */
if (size > transfer->blocksize)
if ((size = transfer->file->size - transfer->offset) > transfer->blocksize)
size = transfer->blocksize;
mess->op = htons(OP_DATA);
mess->block = htons((unsigned short)(transfer->block));
if (lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
!read_write(transfer->file->fd, mess->data, size, RW_READ))
if (size != 0 &&
(lseek(transfer->file->fd, transfer->offset, SEEK_SET) == (off_t)-1 ||
!read_write(transfer->file->fd, mess->data, size, RW_READ)))
return -1;
transfer->expansion = 0;
/* Map '\n' to CR-LF in netascii mode */
if (transfer->netascii)
{
size_t i;
int newcarrylf;
transfer->expansion = 0;
for (i = 0, newcarrylf = 0; i < size; i++)
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
if (mess->data[i] == '\n' && (i != 0 || !transfer->carrylf))
{
transfer->expansion++;
@@ -885,8 +976,8 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
i++;
}
transfer->carrylf = newcarrylf;
}
return size + 4;
+5
View File
@@ -213,6 +213,11 @@ static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct u
size_t num_patterns = 0;
struct blob_attr *tb[policy_len];
struct blob_attr *attr;
(void)ctx;
(void)obj;
(void)req;
(void)method;
if (blobmsg_parse(policy, policy_len, tb, blob_data(msg), blob_len(msg)))
return UBUS_STATUS_INVALID_ARGUMENT;
+33 -4
View File
@@ -34,6 +34,10 @@
#include <sys/utsname.h>
#endif
#ifdef HAVE_BSD_NETWORK
#include <libgen.h>
#endif
/* SURF random number generator */
static u32 seed[32];
@@ -831,9 +835,34 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
#endif
#ifdef FDESCFS
DIR *d;
DIR *d = NULL;
if ((d = opendir(FDESCFS)))
# ifdef HAVE_BSD_NETWORK
dev_t dirdev = 0;
char fdescfs[] = FDESCFS; /* string must be writable */
struct stat statbuf;
/* On BSD, fdescfs is normally mounted at /dev/fd. However
if it is NOT mounted, devfs creates a directory at /dev/fd
which contains (only) the file descriptors 0,1 and 2.
Under these conditions, opendir() will succeed, and
if we proceed we will fail to close extant
file descriptors which should be closed.
Check that there is a filesystem mounted at /dev/fd
by checking that the device changes between /dev/fd
and /dev. If if doesn't, fall back to the dumb path. */
if (stat(fdescfs, &statbuf) != -1)
dirdev = statbuf.st_dev;
if (stat(dirname(fdescfs), &statbuf) != -1 &&
dirdev != statbuf.st_dev)
# endif
d = opendir(FDESCFS);
if (d)
{
struct dirent *de;
@@ -855,9 +884,9 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3)
closedir(d);
return;
}
}
#endif
/* fallback, dumb code. */
for (max_fd--; max_fd >= 0; max_fd--)
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO && max_fd != STDIN_FILENO &&