import dnsmasq-2.85-3.el9

This commit is contained in:
CentOS Sources 2022-04-05 05:58:40 -04:00 committed by Stepan Oksanichenko
parent 55c18eae61
commit a02f208bef
4 changed files with 617 additions and 1 deletions

View File

@ -0,0 +1,471 @@
From 5747d7b3dffdcd45d4410bb380e466818734cb27 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Mon, 19 Apr 2021 13:56:23 +0200
Subject: [PATCH] Use load-balancing also for --server=/domains/
Do not (yet) move servers to server_domain structure. Instead use
separate server_domains to store just last_server and requests count and
time.
Introduces domain information duplicity, but minimizes required changes
to daemon->servers usage.
Optimize server domain record
Set pointer to domain record when struct server is created. When
searching for domain pointer, use this pointer to make it quick.
---
src/dnsmasq.h | 18 +++++++--
src/forward.c | 52 ++++++++++++++++----------
src/network.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++----
src/option.c | 5 +++
4 files changed, 146 insertions(+), 30 deletions(-)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 1e21005..b6dcc50 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -559,6 +559,17 @@ struct randfd_list {
struct randfd_list *next;
};
+/* contains domain specific set of servers.
+ * If domain is NULL, just normal servers. */
+struct server_domain {
+ char *domain;
+ struct server *last_server;
+ time_t forwardtime;
+ int forwardcount;
+ unsigned int flags; /* server.flags alternative */
+ struct server_domain *next;
+};
+
struct server {
union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1];
@@ -571,6 +582,7 @@ struct server {
#ifdef HAVE_LOOP
u32 uid;
#endif
+ struct server_domain *serv_domain;
struct server *next;
};
@@ -1053,6 +1065,7 @@ extern struct daemon {
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers;
+ struct server_domain *server_domains;
struct ipsets *ipsets;
int log_fac; /* log facility */
char *log_file; /* optional log file */
@@ -1121,9 +1134,6 @@ extern struct daemon {
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
- struct server *last_server;
- time_t forwardtime;
- int forwardcount;
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
int fd_save; /* " " */
@@ -1394,6 +1404,8 @@ int label_exception(int index, int family, union all_addr *addr);
int fix_fd(int fd);
int tcp_interface(int fd, int af);
int set_ipv6pktinfo(int fd);
+struct server_domain *server_domain_find_domain(const char *domain);
+struct server_domain *server_domain_new(struct server *serv);
#ifdef HAVE_DHCP6
void join_multicast(int dienow);
#endif
diff --git a/src/forward.c b/src/forward.c
index 9322b6a..b09dc96 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -107,7 +107,8 @@ int send_from(int fd, int nowild, char *packet, size_t len,
}
static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned int qtype,
- char *qdomain, int *type, char **domain, int *norebind)
+ char *qdomain, int *type, char **domain, int *norebind,
+ struct server_domain **serv_domain)
{
/* If the query ends in the domain in one of our servers, set
@@ -120,6 +121,9 @@ static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned
unsigned int flags = 0;
static union all_addr zero;
+ if (serv_domain)
+ *serv_domain = NULL;
+
for (serv = daemon->servers; serv; serv=serv->next)
if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
continue;
@@ -187,6 +191,8 @@ static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned
{
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
*domain = serv->domain;
+ if (serv_domain)
+ *serv_domain = serv->serv_domain;
matchlen = domainlen;
if (serv->flags & SERV_NO_ADDR)
flags = F_NXDOMAIN;
@@ -243,6 +249,8 @@ static unsigned int search_servers(time_t now, union all_addr **addrpp, unsigned
*type = 0; /* use normal servers for this domain */
*domain = NULL;
}
+ if (serv_domain && !*serv_domain)
+ *serv_domain = server_domain_find_domain(*domain);
return flags;
}
@@ -304,6 +312,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int flags = 0;
unsigned int fwd_flags = 0;
struct server *start = NULL;
+ struct server_domain *sd = NULL;
void *hash = hash_questions(header, plen, daemon->namebuff);
#ifdef HAVE_DNSSEC
int do_dnssec = 0;
@@ -422,8 +431,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->sentto->failed_queries++;
if (!option_bool(OPT_ORDER) && old_src)
{
+ sd = forward->sentto->serv_domain;
forward->forwardall = 1;
- daemon->last_server = NULL;
+ if (sd)
+ sd->last_server = NULL;
}
type = forward->sentto->flags & SERV_TYPE;
#ifdef HAVE_DNSSEC
@@ -439,8 +450,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* new query */
if (gotname)
- flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
-
+ flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
+
#ifdef HAVE_DNSSEC
do_dnssec = type & SERV_DO_DNSSEC;
#endif
@@ -482,18 +493,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
always try all the available servers,
otherwise, use the one last known to work. */
- if (type == 0)
+ if (sd)
{
if (option_bool(OPT_ORDER))
start = daemon->servers;
- else if (!(start = daemon->last_server) ||
- daemon->forwardcount++ > FORWARD_TEST ||
- difftime(now, daemon->forwardtime) > FORWARD_TIME)
+ else if (!(start = sd->last_server) ||
+ sd->forwardcount++ > FORWARD_TEST ||
+ difftime(now, sd->forwardtime) > FORWARD_TIME)
{
start = daemon->servers;
forward->forwardall = 1;
- daemon->forwardcount = 0;
- daemon->forwardtime = now;
+ sd->forwardcount = 0;
+ sd->forwardtime = now;
}
}
else
@@ -844,6 +855,7 @@ void reply_query(int fd, time_t now)
size_t nn;
struct server *server;
void *hash;
+ struct server_domain *sd;
/* packet buffer overwritten */
daemon->srv_save = NULL;
@@ -968,7 +980,8 @@ void reply_query(int fd, time_t now)
}
server = forward->sentto;
- if ((forward->sentto->flags & SERV_TYPE) == 0)
+ sd = server->serv_domain;
+ if (sd)
{
if (RCODE(header) == REFUSED)
server = NULL;
@@ -986,7 +999,7 @@ void reply_query(int fd, time_t now)
}
}
if (!option_bool(OPT_ALL_SERVERS))
- daemon->last_server = server;
+ sd->last_server = server;
}
/* We tried resending to this server with a smaller maximum size and got an answer.
@@ -1093,7 +1106,7 @@ void reply_query(int fd, time_t now)
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
- if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
+ if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL, &sd) == 0)
{
struct server *start, *new_server = NULL;
start = server = forward->sentto;
@@ -1664,7 +1677,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
- if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
+ if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL, NULL) != 0)
{
new_status = STAT_ABANDONED;
break;
@@ -1944,12 +1957,13 @@ unsigned char *tcp_request(int confd, time_t now,
union all_addr *addrp = NULL;
int type = SERV_DO_DNSSEC;
char *domain = NULL;
+ struct server_domain *sd = NULL;
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
if (gotname)
- flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
+ flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind, &sd);
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
@@ -1970,10 +1984,10 @@ unsigned char *tcp_request(int confd, time_t now,
type &= ~SERV_DO_DNSSEC;
- if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
+ if (!sd || option_bool(OPT_ORDER) || !sd->last_server)
last_server = daemon->servers;
else
- last_server = daemon->last_server;
+ last_server = sd->last_server;
if (!flags && last_server)
{
@@ -2567,9 +2581,7 @@ void server_gone(struct server *server)
if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
daemon->randomsocks[i].serv = NULL;
- if (daemon->last_server == server)
- daemon->last_server = NULL;
-
+ /* last_server cleared by server_domains_cleanup */
if (daemon->srv_save == server)
daemon->srv_save = NULL;
}
diff --git a/src/network.c b/src/network.c
index 3600250..1fa81ff 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1537,6 +1537,29 @@ void cleanup_servers(void)
#endif
}
+static void server_domains_cleanup(void)
+{
+ struct server_domain *sd, *tmp, **up;
+
+ /* unlink and free anything still marked. */
+ for (up = &daemon->server_domains, sd=*up; sd; sd = tmp)
+ {
+ tmp = sd->next;
+ if (sd->flags & SERV_MARK)
+ {
+ *up = sd->next;
+ if (sd->domain)
+ free(sd->domain);
+ free(sd);
+ }
+ else {
+ up = &sd->next;
+ if (sd->last_server && (sd->last_server->flags & SERV_MARK))
+ sd->last_server = NULL;
+ }
+ }
+}
+
void add_update_server(int flags,
union mysockaddr *addr,
union mysockaddr *source_addr,
@@ -1616,10 +1639,72 @@ void add_update_server(int flags,
}
}
+static const char *server_get_domain(const struct server *serv)
+{
+ const char *domain = serv->domain;
+
+ if (serv->flags & SERV_HAS_DOMAIN)
+ /* .example.com is valid */
+ while (*domain == '.')
+ domain++;
+
+ return domain;
+}
+
+struct server_domain *server_domain_find_domain(const char *domain)
+{
+ struct server_domain *sd;
+ for (sd = daemon->server_domains; sd; sd = sd->next)
+ if ((!domain && sd->domain == domain) || (domain && sd->domain && hostname_isequal(domain, sd->domain)))
+ return sd;
+ return NULL;
+}
+
+/**< Test structure has already set domain pointer.
+ *
+ * If not, create a new record. */
+struct server_domain *server_domain_new(struct server *serv)
+{
+ struct server_domain *sd;
+
+ if ((sd = whine_malloc(sizeof(struct server_domain))))
+ {
+ const char *domain = server_get_domain(serv);
+
+ /* Ensure all serv->domain values have own record in server_domain.
+ * Add a new record. */
+ if (domain)
+ {
+ size_t len = strlen(domain)+1;
+ sd->domain = whine_malloc(len);
+ if (sd->domain)
+ memcpy(sd->domain, domain, len);
+ }
+ sd->next = daemon->server_domains;
+ serv->serv_domain = sd;
+ daemon->server_domains = sd;
+ }
+ return sd;
+}
+
+/**< Test structure has already set domain pointer.
+ *
+ * If not, create a new record. */
+static void server_domain_check(struct server *serv)
+{
+ struct server_domain *sd = serv->serv_domain;
+
+ if (sd)
+ sd->flags &= (~SERV_MARK); /* found domain, mark active */
+ else
+ server_domain_new(serv);
+}
+
void check_servers(void)
{
struct irec *iface;
struct server *serv;
+ struct server_domain *sd;
struct serverfd *sfd, *tmp, **up;
int port = 0, count;
int locals = 0;
@@ -1632,10 +1717,14 @@ void check_servers(void)
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
sfd->used = sfd->preallocated;
+ for (sd = daemon->server_domains; sd; sd = sd->next)
+ sd->flags |= SERV_MARK;
+
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
{
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
{
+
/* Init edns_pktsz for newly created server records. */
if (serv->edns_pktsz == 0)
serv->edns_pktsz = daemon->edns_pktsz;
@@ -1651,12 +1740,8 @@ void check_servers(void)
if (serv->flags & SERV_HAS_DOMAIN)
{
struct ds_config *ds;
- char *domain = serv->domain;
-
- /* .example.com is valid */
- while (*domain == '.')
- domain++;
-
+ const char *domain = server_get_domain(serv);
+
for (ds = daemon->ds; ds; ds = ds->next)
if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
break;
@@ -1666,7 +1751,6 @@ void check_servers(void)
}
}
#endif
-
port = prettyprint_addr(&serv->addr, daemon->namebuff);
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
@@ -1701,6 +1785,8 @@ void check_servers(void)
if (serv->sfd)
serv->sfd->used = 1;
+
+ server_domain_check(serv);
}
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
@@ -1763,6 +1849,7 @@ void check_servers(void)
up = &sfd->next;
}
+ server_domains_cleanup();
cleanup_servers();
}
diff --git a/src/option.c b/src/option.c
index 6de5914..e4e3182 100644
--- a/src/option.c
+++ b/src/option.c
@@ -928,6 +928,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
p += sprintf(p, "in-addr.arpa");
serv->flags = SERV_HAS_DOMAIN;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
@@ -952,6 +953,7 @@ static struct server *add_rev6(struct in6_addr *addr, int msize)
p += sprintf(p, "ip6.arpa");
serv->flags = SERV_HAS_DOMAIN;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
@@ -2292,6 +2294,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
}
@@ -2335,6 +2338,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+ server_domain_new(serv);
serv->next = daemon->servers;
daemon->servers = serv;
}
@@ -2587,6 +2591,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
newlist = serv;
serv->domain = domain;
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
+ server_domain_new(serv);
arg = end;
if (rebind)
break;
--
2.34.1

View File

@ -0,0 +1,107 @@
From 268080fc19990711a1d1e1acd68a50aa2f6cb5fb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Fri, 17 Sep 2021 20:12:21 +0200
Subject: [PATCH] Offer alternative DHCPv6 address if requested is taken
In some cases multiple requests might arrive from single DUID. It may
happen just one address is offered to different IAID requests. When
the first request confirms lease, another would be offered alternative
address instead of address in use error.
Includes check on such Rapid commit equivalents and returns NotOnLink
error, required by RFC 8145, if requested address were not on any
supported prefix.
---
src/rfc3315.c | 39 ++++++++++++++++++++++++++++-----------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 5c2ff97..d1534ad 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -614,7 +614,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
case DHCP6SOLICIT:
{
- int address_assigned = 0;
+ int address_assigned = 0, ia_invalid = 0;
/* tags without all prefix-class tags */
struct dhcp_netid *solicit_tags;
struct dhcp_context *c;
@@ -697,6 +697,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
get_context_tag(state, c);
address_assigned = 1;
}
+ else
+ ia_invalid++;
}
/* Suggest configured address(es) */
@@ -782,11 +784,26 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
tagif = add_options(state, 0);
}
else
- {
+ {
+ char *errmsg;
/* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
- put_opt6_short(DHCP6NOADDRS);
- put_opt6_string(_("no addresses available"));
+ if (state->lease_allocate && ia_invalid)
+ {
+ /* RFC 8415, Section 18.3.2:
+ If any of the prefixes of the included addresses are not
+ appropriate for the link to which the client is connected,
+ the server MUST return the IA to the client with a Status
+ Code option with the value NotOnLink. */
+ put_opt6_short(DHCP6NOTONLINK);
+ errmsg = _("not on link");
+ }
+ else
+ {
+ put_opt6_short(DHCP6NOADDRS);
+ errmsg = _("no addresses available");
+ }
+ put_opt6_string(errmsg);
end_opt6(o1);
/* Some clients will ask repeatedly when we're not giving
@@ -795,7 +812,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (c = state->context; c; c = c->current)
if (!(c->flags & CONTEXT_RA_STATELESS))
{
- log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
+ log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, errmsg);
break;
}
}
@@ -831,7 +848,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
/* If we get a request with an IA_*A without addresses, treat it exactly like
a SOLICT with rapid commit set. */
save_counter(start);
- goto request_no_address;
+ goto request_no_address;
}
o = build_ia(state, &t1cntr);
@@ -861,11 +878,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
else if (!check_address(state, &req_addr))
{
- /* Address leased to another DUID/IAID */
- o1 = new_opt6(OPTION6_STATUS_CODE);
- put_opt6_short(DHCP6UNSPEC);
- put_opt6_string(_("address in use"));
- end_opt6(o1);
+ /* Address leased to another DUID/IAID.
+ Find another address for the client, treat it exactly like
+ a SOLICT with rapid commit set. */
+ save_counter(start);
+ goto request_no_address;
}
else
{
--
2.31.1

View File

@ -0,0 +1,28 @@
From 4272580bb586180e596e5ed30b68455826acc8c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
Date: Wed, 22 Sep 2021 14:54:01 +0200
Subject: [PATCH] Add support for option6 names of RFC 5970
Client Network Interface Identifier and Client System Architecture Type
options were not understood by dnsmasq. Add it to supported option
types.
---
src/dhcp-common.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index 36bc38a..528e8e7 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -659,6 +659,8 @@ static const struct opttab_t opttab6[] = {
{ "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
+ { "client-arch", 61, 2 | OT_DEC }, /* RFC 5970 */
+ { "client-interface-id", 62, 1 | OT_DEC }, /* RFC 5970 */
{ NULL, 0, 0 }
};
#endif
--
2.31.1

View File

@ -20,7 +20,7 @@
Name: dnsmasq
Version: 2.85
Release: 2%{?extraversion:.%{extraversion}}%{?dist}
Release: 3%{?extraversion:.%{extraversion}}%{?dist}
Summary: A lightweight DHCP/caching DNS server
License: GPLv2 or GPLv3
@ -41,6 +41,12 @@ Patch1: dnsmasq-2.77-underflow.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1852373
Patch2: dnsmasq-2.81-configuration.patch
Patch3: dnsmasq-2.78-fips.patch
# Downstream only patch; https://bugzilla.redhat.com/show_bug.cgi?id=1919894
# Similar functionality is implemented since 2.86 in upstream, but introduced
Patch4: dnsmasq-2.79-server-domain-rh1919894.patch
# https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q3/015640.html
Patch5: dnsmasq-2.86-alternative-lease.patch
Patch6: dnsmasq-2.86-dhcpv6-client-arch.patch
# This is workaround to nettle bug #1549190
# https://bugzilla.redhat.com/show_bug.cgi?id=1549190
@ -184,6 +190,10 @@ install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/%{name}.conf
%{_mandir}/man1/dhcp_*
%changelog
* Thu Jan 27 2022 Petr Menšík <pemensik@redhat.com> - 2.85-3
- Send queries only to best domain-specific server (#2047510)
- Offer alternate DHCPv6 address if requested is already leased (#1998448)
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.85-2
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688