From 8b606543a3fb687f0e49d4e832f98be9a08924d0 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Mon, 9 Oct 2023 21:00:11 +0100 Subject: [PATCH 1/9] Fix memory leak in arbitrary-RR caching. If the cache insertion process fails for any reason, any blockdata storage allocated needs to be freed. Thanks to Damian Sawicki for spotting the problem and supplying patches against earlier releases. This patch by SRK, and any bugs are his. --- src/rfc1035.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/rfc1035.c b/src/rfc1035.c index da8713a..ae6b46a 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -847,11 +847,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t int len; if (!extract_name(header, qlen, &p1, name, 1, 0)) - return 2; + { + blockdata_free(addr.rrblock.rrdata); + return 2; + } len = to_wire(name); if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, name, len)) - return 0; + { + blockdata_free(addr.rrblock.rrdata); + return 0; + } + addr.rrblock.datalen += len; } else @@ -859,8 +866,13 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t /* desc is length of a block of data to be used as-is */ if (desc > endrr - p1) desc = endrr - p1; + if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, desc)) - return 0; + { + blockdata_free(addr.rrblock.rrdata); + return 0; + } + addr.rrblock.datalen += desc; p1 += desc; } @@ -868,7 +880,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t /* we overwrote the original name, so get it back here. */ if (!extract_name(header, qlen, &tmp, name, 1, 0)) - return 2; + { + blockdata_free(addr.rrblock.rrdata); + return 2; + } } } else if (flags & (F_IPV4 | F_IPV6)) @@ -914,6 +929,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t cpp->addr.cname.uid = newc->uid; } cpp = NULL; + + /* cache insert failed, don't leak blockdata. */ + if (!newc && (flags & F_RR) && (flags & F_KEYTAG)) + blockdata_free(addr.rrblock.rrdata); } if (aqtype == T_TXT) From ca8d04a8ff951896578c1f1026a014955a0b40a7 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Mon, 9 Oct 2023 21:15:13 +0100 Subject: [PATCH 2/9] Cache zero-TTL DNS replies when stale-caching is enabled. --- src/cache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cache.c b/src/cache.c index 1c0e250..9f64a05 100644 --- a/src/cache.c +++ b/src/cache.c @@ -629,8 +629,8 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho if (insert_error) return NULL; - /* we don't cache zero-TTL records. */ - if (ttl == 0) + /* we don't cache zero-TTL records unless we're doing stale-caching. */ + if (daemon->cache_max_expiry == 0 && ttl == 0) { insert_error = 1; return NULL; From a889c554a7df71ff93a8299ef96037fbe05f2f55 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Mon, 9 Oct 2023 21:50:15 +0100 Subject: [PATCH 3/9] Work around possible Linux bug with VRF interfaces and DHCPv6. The scope_id in the source address of recieved packets gets set to the index of the VRF interface, not the slave. Fortunately, the interface index returned by packetinfo is correct so we use instead. Thanks to Luci Stanescu for characterising this. Ref: https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2023q4/017276.html --- src/dhcp6.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/dhcp6.c b/src/dhcp6.c index 7eeef03..a0266f7 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -118,11 +118,6 @@ void dhcp6_packet(time_t now) if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1) return; -#ifdef HAVE_DUMPFILE - dump_packet_udp(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz, - (union mysockaddr *)&from, NULL, daemon->dhcp6fd); -#endif - for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo) { @@ -138,6 +133,34 @@ void dhcp6_packet(time_t now) if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name)) return; + +#ifdef HAVE_LINUX_NETWORK + /* This works around a possible Linux kernel bug when using interfaces + enslaved to a VRF. The scope_id in the source address gets set + to the index of the VRF interface, not the slave. Fortunately, + the interface index returned by packetinfo is correct so we use + that instead. Log this once, so if it triggers in other circumstances + we've not anticipated and breaks things, we get some clues. */ + if (from.sin6_scope_id != if_index) + { + static int logged = 0; + + if (!logged) + { + my_syslog(MS_DHCP | LOG_WARNING, + _("Working around kernel bug: faulty source address scope for VRF slave %s"), + ifr.ifr_name); + logged = 1; + } + + from.sin6_scope_id = if_index; + } +#endif + +#ifdef HAVE_DUMPFILE + dump_packet_udp(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz, + (union mysockaddr *)&from, NULL, daemon->dhcp6fd); +#endif if (relay_reply6(&from, sz, ifr.ifr_name)) { From 3868066085f4f73055d303ad2af59ad66245cf27 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 11 Oct 2023 22:33:17 +0100 Subject: [PATCH 4/9] Fix bad reply to DHCPCONFIRM messages (wrong message type). Thanks to renmingshuai for spotting the error, and making the initial patch. --- src/rfc3315.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/rfc3315.c b/src/rfc3315.c index c2e2692..bd448c7 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -1074,7 +1074,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu case DHCP6CONFIRM: { - int good_addr = 0; + int good_addr = 0, bad_addr = 0; /* set reply message type */ outmsgtype = DHCP6REPLY; @@ -1096,26 +1096,24 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu if (!address6_valid(state->context, &req_addr, tagif, 1)) { - o1 = new_opt6(OPTION6_STATUS_CODE); - put_opt6_short(DHCP6NOTONLINK); - put_opt6_string(_("confirm failed")); - end_opt6(o1); + bad_addr = 1; log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed")); - return 1; } - - good_addr = 1; - log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname); + else + { + good_addr = 1; + log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname); + } } } /* No addresses, no reply: RFC 3315 18.2.2 */ - if (!good_addr) + if (!good_addr && !bad_addr) return 0; o1 = new_opt6(OPTION6_STATUS_CODE); - put_opt6_short(DHCP6SUCCESS ); - put_opt6_string(_("all addresses still on link")); + put_opt6_short(bad_addr ? DHCP6NOTONLINK : DHCP6SUCCESS); + put_opt6_string(bad_addr ? (_("confirm failed")) : (_("all addresses still on link"))); end_opt6(o1); break; } From 1fe9d2ba450fbb4aba2823c6fe210fe3c64ac652 Mon Sep 17 00:00:00 2001 From: Dominik Derigs Date: Sat, 4 Nov 2023 16:52:09 +0000 Subject: [PATCH 5/9] Add RESINFO RR-type to the table of RR-type names. --- src/cache.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cache.c b/src/cache.c index 9f64a05..e28fad4 100644 --- a/src/cache.c +++ b/src/cache.c @@ -124,6 +124,7 @@ static const struct { { 258, "AVC" }, /* Application Visibility and Control [Wolfgang_Riedel] AVC/avc-completed-template 2016-02-26*/ { 259, "DOA" }, /* Digital Object Architecture [draft-durand-doa-over-dns] DOA/doa-completed-template 2017-08-30*/ { 260, "AMTRELAY" }, /* Automatic Multicast Tunneling Relay [RFC8777] AMTRELAY/amtrelay-completed-template 2019-02-06*/ + { 261, "RESINFO" }, /* Resolver Information as Key/Value Pairs https://datatracker.ietf.org/doc/draft-ietf-add-resolver-info/06/ */ { 32768, "TA" }, /* DNSSEC Trust Authorities [Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.] 2005-12-13*/ { 32769, "DLV" }, /* DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431] */ }; From 24804b7431f6ace109e91876aef859a751bf3147 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Sat, 4 Nov 2023 16:58:30 +0000 Subject: [PATCH 6/9] Fix compile warning introduced by a889c554a7df71ff93a8299ef96037fbe05f2f55 --- src/dhcp6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dhcp6.c b/src/dhcp6.c index a0266f7..87ad50b 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -92,7 +92,7 @@ void dhcp6_packet(time_t now) struct iface_param parm; struct cmsghdr *cmptr; struct msghdr msg; - int if_index = 0; + uint32_t if_index = 0; union { struct cmsghdr align; /* this ensures alignment */ char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; From 416390f9962e455769aa8ab6df0e105cae07ae55 Mon Sep 17 00:00:00 2001 From: Damian Sawicki Date: Sat, 4 Nov 2023 23:33:28 +0000 Subject: [PATCH 7/9] Add --max-tcp-connections option to make this dynamically configurable. --- man/dnsmasq.8 | 4 ++++ src/config.h | 2 +- src/dnsmasq.c | 23 ++++++++++++++++------- src/dnsmasq.h | 5 +++-- src/option.c | 16 +++++++++++++++- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 30429df..6d37360 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -2254,6 +2254,10 @@ example command to query this, using the utility would be dig +short chaos txt cachesize.bind +.TP +.B --max-tcp-connections= +The maximum number of concurrent TCP connections. The application forks to +handle each TCP request. The default maximum is 20. .SH CONFIG FILE At startup, dnsmasq reads diff --git a/src/config.h b/src/config.h index 88cf72e..cc1c465 100644 --- a/src/config.h +++ b/src/config.h @@ -15,7 +15,7 @@ */ #define FTABSIZ 150 /* max number of outstanding requests (default) */ -#define MAX_PROCS 20 /* max no children for TCP requests */ +#define MAX_PROCS 20 /* default max no children for TCP requests */ #define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */ #define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */ #define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */ diff --git a/src/dnsmasq.c b/src/dnsmasq.c index bc6644c..112dbe5 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -36,6 +36,7 @@ static void async_event(int pipe, time_t now); static void fatal_event(struct event_desc *ev, char *msg); static int read_event(int fd, struct event_desc *evp, char **msg); static void poll_resolv(int force, int do_reload, time_t now); +static void tcp_init(void); int main (int argc, char **argv) { @@ -415,6 +416,8 @@ int main (int argc, char **argv) daemon->numrrand = max_fd/3; /* safe_malloc returns zero'd memory */ daemon->randomsocks = safe_malloc(daemon->numrrand * sizeof(struct randfd)); + + tcp_init(); } #ifdef HAVE_INOTIFY @@ -1043,7 +1046,7 @@ int main (int argc, char **argv) pid = getpid(); daemon->pipe_to_parent = -1; - for (i = 0; i < MAX_PROCS; i++) + for (i = 0; i < daemon->max_procs; i++) daemon->tcp_pipes[i] = -1; #ifdef HAVE_INOTIFY @@ -1520,7 +1523,7 @@ static void async_event(int pipe, time_t now) break; } else - for (i = 0 ; i < MAX_PROCS; i++) + for (i = 0 ; i < daemon->max_procs; i++) if (daemon->tcp_pids[i] == p) daemon->tcp_pids[i] = 0; break; @@ -1584,7 +1587,7 @@ static void async_event(int pipe, time_t now) case EVENT_TERM: /* Knock all our children on the head. */ - for (i = 0; i < MAX_PROCS; i++) + for (i = 0; i < daemon->max_procs; i++) if (daemon->tcp_pids[i] != 0) kill(daemon->tcp_pids[i], SIGALRM); @@ -1761,7 +1764,7 @@ static void set_dns_listeners(void) poll_listen(rfl->rfd->fd, POLLIN); /* check to see if we have free tcp process slots. */ - for (i = MAX_PROCS - 1; i >= 0; i--) + for (i = daemon->max_procs - 1; i >= 0; i--) if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) break; @@ -1785,7 +1788,7 @@ static void set_dns_listeners(void) } if (!option_bool(OPT_DEBUG)) - for (i = 0; i < MAX_PROCS; i++) + for (i = 0; i < daemon->max_procs; i++) if (daemon->tcp_pipes[i] != -1) poll_listen(daemon->tcp_pipes[i], POLLIN); } @@ -1820,7 +1823,7 @@ static void check_dns_listeners(time_t now) to free the process slot. Once the child process has gone, poll() returns POLLHUP, not POLLIN, so have to check for both here. */ if (!option_bool(OPT_DEBUG)) - for (i = 0; i < MAX_PROCS; i++) + for (i = 0; i < daemon->max_procs; i++) if (daemon->tcp_pipes[i] != -1 && poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) && !cache_recv_insert(now, daemon->tcp_pipes[i])) @@ -1844,7 +1847,7 @@ static void check_dns_listeners(time_t now) at least one a poll() time, that we still do. There may be more waiting connections after poll() returns then free process slots. */ - for (i = MAX_PROCS - 1; i >= 0; i--) + for (i = daemon->max_procs - 1; i >= 0; i--) if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) break; @@ -2186,3 +2189,9 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id) return 0; } #endif /* HAVE_DHCP */ + +void tcp_init(void) +{ + daemon->tcp_pids = safe_malloc(daemon->max_procs*sizeof(pid_t)); + daemon->tcp_pipes = safe_malloc(daemon->max_procs*sizeof(int)); +} diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 2f95c12..67c083b 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1252,8 +1252,8 @@ extern struct daemon { struct server *srv_save; /* Used for resend on DoD */ size_t packet_len; /* " " */ int fd_save; /* " " */ - pid_t tcp_pids[MAX_PROCS]; - int tcp_pipes[MAX_PROCS]; + pid_t *tcp_pids; + int *tcp_pipes; int pipe_to_parent; int numrrand; struct randfd *randomsocks; @@ -1313,6 +1313,7 @@ extern struct daemon { /* file for packet dumps. */ int dumpfd; #endif + int max_procs; } *daemon; struct server_details { diff --git a/src/option.c b/src/option.c index 286f06b..9423582 100644 --- a/src/option.c +++ b/src/option.c @@ -190,6 +190,7 @@ struct myoption { #define LOPT_FILTER_RR 381 #define LOPT_NO_DHCP6 382 #define LOPT_NO_DHCP4 383 +#define LOPT_MAX_PROCS 384 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -384,6 +385,7 @@ static const struct myoption opts[] = { "fast-dns-retry", 2, 0, LOPT_FAST_RETRY }, { "use-stale-cache", 2, 0 , LOPT_STALE_CACHE }, { "no-ident", 0, 0, LOPT_NO_IDENT }, + { "max-tcp-connections", 1, 0, LOPT_MAX_PROCS }, { NULL, 0, 0, 0 } }; @@ -585,6 +587,7 @@ static struct { { LOPT_NORR, OPT_NORR, NULL, gettext_noop("Suppress round-robin ordering of DNS records."), NULL }, { LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL }, { LOPT_CACHE_RR, ARG_DUP, "", gettext_noop("Cache this DNS resource record type."), NULL }, + { LOPT_MAX_PROCS, ARG_ONE, "", gettext_noop("Maximum number of concurrent tcp connections."), NULL }, { 0, 0, NULL, NULL, NULL } }; @@ -5313,7 +5316,17 @@ err: break; } #endif - + + case LOPT_MAX_PROCS: /* --max-tcp-connections */ + { + int max_procs; + /* Don't accept numbers less than 1. */ + if (!atoi_check(arg, &max_procs) || max_procs < 1) + ret_err(gen_err); + daemon->max_procs = max_procs; + break; + } + default: ret_err(_("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DNSSEC/DBus support)")); @@ -5841,6 +5854,7 @@ void read_opts(int argc, char **argv, char *compile_opts) daemon->soa_expiry = SOA_EXPIRY; daemon->randport_limit = 1; daemon->host_index = SRC_AH; + daemon->max_procs = MAX_PROCS; /* See comment above make_servers(). Optimises server-read code. */ mark_servers(0); From 77ef9b260352c7820b6fee7d91c73415a41cbf1d Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 10 Nov 2023 23:13:46 +0000 Subject: [PATCH 8/9] Fix crash when DNS disabled, introduced in 416390f9962e455769aa8ab6df0e105cae07ae55 --- src/dnsmasq.c | 72 ++++++++++++++++++++++++++++++--------------------- src/tftp.c | 5 ++++ 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 112dbe5..65ba334 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -30,6 +30,7 @@ static volatile pid_t pid = 0; static volatile int pipewrite; static void set_dns_listeners(void); +static void set_tftp_listeners(void); static void check_dns_listeners(time_t now); static void sig_handler(int sig); static void async_event(int pipe, time_t now); @@ -1046,8 +1047,10 @@ int main (int argc, char **argv) pid = getpid(); daemon->pipe_to_parent = -1; - for (i = 0; i < daemon->max_procs; i++) - daemon->tcp_pipes[i] = -1; + + if (daemon->port != 0) + for (i = 0; i < daemon->max_procs; i++) + daemon->tcp_pipes[i] = -1; #ifdef HAVE_INOTIFY /* Using inotify, have to select a resolv file at startup */ @@ -1070,7 +1073,12 @@ int main (int argc, char **argv) (timeout == -1 || timeout > 1000)) timeout = 1000; - set_dns_listeners(); + if (daemon->port != 0) + set_dns_listeners(); + +#ifdef HAVE_TFTP + set_tftp_listeners(); +#endif #ifdef HAVE_DBUS if (option_bool(OPT_DBUS)) @@ -1255,8 +1263,9 @@ int main (int argc, char **argv) check_ubus_listeners(); } #endif - - check_dns_listeners(now); + + if (daemon->port != 0) + check_dns_listeners(now); #ifdef HAVE_TFTP check_tftp_listeners(now); @@ -1522,7 +1531,7 @@ static void async_event(int pipe, time_t now) if (errno != EINTR) break; } - else + else if (daemon->port != 0) for (i = 0 ; i < daemon->max_procs; i++) if (daemon->tcp_pids[i] == p) daemon->tcp_pids[i] = 0; @@ -1587,9 +1596,10 @@ static void async_event(int pipe, time_t now) case EVENT_TERM: /* Knock all our children on the head. */ - for (i = 0; i < daemon->max_procs; i++) - if (daemon->tcp_pids[i] != 0) - kill(daemon->tcp_pids[i], SIGALRM); + if (daemon->port != 0) + for (i = 0; i < daemon->max_procs; i++) + if (daemon->tcp_pids[i] != 0) + kill(daemon->tcp_pids[i], SIGALRM); #if defined(HAVE_SCRIPT) && defined(HAVE_DHCP) /* handle pending lease transitions */ @@ -1734,23 +1744,33 @@ void clear_cache_and_reload(time_t now) #endif } -static void set_dns_listeners(void) -{ - struct serverfd *serverfdp; - struct listener *listener; - struct randfd_list *rfl; - int i; - #ifdef HAVE_TFTP +static void set_tftp_listeners(void) +{ int tftp = 0; struct tftp_transfer *transfer; + struct listener *listener; + if (!option_bool(OPT_SINGLE_PORT)) for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next) { tftp++; poll_listen(transfer->sockfd, POLLIN); } + + for (listener = daemon->listeners; listener; listener = listener->next) + /* tftp == 0 in single-port mode. */ + if (tftp <= daemon->tftp_max && listener->tftpfd != -1) + poll_listen(listener->tftpfd, POLLIN); +} #endif + +static void set_dns_listeners(void) +{ + struct serverfd *serverfdp; + struct listener *listener; + struct randfd_list *rfl; + int i; for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) poll_listen(serverfdp->fd, POLLIN); @@ -1779,12 +1799,6 @@ static void set_dns_listeners(void) we'll be called again when a slot becomes available. */ if (listener->tcpfd != -1 && i >= 0) poll_listen(listener->tcpfd, POLLIN); - -#ifdef HAVE_TFTP - /* tftp == 0 in single-port mode. */ - if (tftp <= daemon->tftp_max && listener->tftpfd != -1) - poll_listen(listener->tftpfd, POLLIN); -#endif } if (!option_bool(OPT_DEBUG)) @@ -1837,11 +1851,6 @@ static void check_dns_listeners(time_t now) if (listener->fd != -1 && poll_check(listener->fd, POLLIN)) receive_query(listener, now); -#ifdef HAVE_TFTP - if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN)) - tftp_request(listener, now); -#endif - /* check to see if we have a free tcp process slot. Note that we can't assume that because we had at least one a poll() time, that we still do. @@ -2138,7 +2147,11 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id) poll_reset(); if (fd != -1) poll_listen(fd, POLLIN); - set_dns_listeners(); + if (daemon->port != 0) + set_dns_listeners(); +#ifdef HAVE_TFTP + set_tftp_listeners(); +#endif set_log_writer(); #ifdef HAVE_DHCP6 @@ -2156,7 +2169,8 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id) now = dnsmasq_time(); check_log_writer(0); - check_dns_listeners(now); + if (daemon->port != 0) + check_dns_listeners(now); #ifdef HAVE_DHCP6 if (daemon->doing_ra && poll_check(daemon->icmp6fd, POLLIN)) diff --git a/src/tftp.c b/src/tftp.c index f036297..d98bfca 100644 --- a/src/tftp.c +++ b/src/tftp.c @@ -585,8 +585,13 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *c void check_tftp_listeners(time_t now) { + struct listener *listener; struct tftp_transfer *transfer, *tmp, **up; + for (listener = daemon->listeners; listener; listener = listener->next) + if (listener->tftpfd != -1 && poll_check(listener->tftpfd, POLLIN)) + tftp_request(listener, now); + /* In single port mode, all packets come via port 69 and tftp_request() */ if (!option_bool(OPT_SINGLE_PORT)) for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next) From 568fb02449a8b43cce7c8da212558ecf022a5f40 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Mon, 13 Nov 2023 22:08:08 +0000 Subject: [PATCH 9/9] Fix use-after-free in cache_remove_uid(). Thanks to Kevin Darbyshire-Bryant for the bug report. --- src/cache.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/cache.c b/src/cache.c index e28fad4..5342ce2 100644 --- a/src/cache.c +++ b/src/cache.c @@ -425,18 +425,21 @@ unsigned int cache_remove_uid(const unsigned int uid) { int i; unsigned int removed = 0; - struct crec *crecp, **up; + struct crec *crecp, *tmp, **up; for (i = 0; i < hash_size; i++) - for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next) - if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid) - { - *up = crecp->hash_next; - free(crecp); - removed++; - } - else - up = &crecp->hash_next; + for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = tmp) + { + tmp = crecp->hash_next; + if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) && crecp->uid == uid) + { + *up = tmp; + free(crecp); + removed++; + } + else + up = &crecp->hash_next; + } return removed; }