From 46aa794b10bcf8f1128abda063768afa90ac44b5 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Apr 05 2022 09:58:40 +0000 Subject: import dnsmasq-2.85-3.el9 --- diff --git a/SOURCES/dnsmasq-2.79-server-domain-rh1919894.patch b/SOURCES/dnsmasq-2.79-server-domain-rh1919894.patch new file mode 100644 index 0000000..b8869a8 --- /dev/null +++ b/SOURCES/dnsmasq-2.79-server-domain-rh1919894.patch @@ -0,0 +1,471 @@ +From 5747d7b3dffdcd45d4410bb380e466818734cb27 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +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 + diff --git a/SOURCES/dnsmasq-2.86-alternative-lease.patch b/SOURCES/dnsmasq-2.86-alternative-lease.patch new file mode 100644 index 0000000..e51d2b3 --- /dev/null +++ b/SOURCES/dnsmasq-2.86-alternative-lease.patch @@ -0,0 +1,107 @@ +From 268080fc19990711a1d1e1acd68a50aa2f6cb5fb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +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 + diff --git a/SOURCES/dnsmasq-2.86-dhcpv6-client-arch.patch b/SOURCES/dnsmasq-2.86-dhcpv6-client-arch.patch new file mode 100644 index 0000000..5177207 --- /dev/null +++ b/SOURCES/dnsmasq-2.86-dhcpv6-client-arch.patch @@ -0,0 +1,28 @@ +From 4272580bb586180e596e5ed30b68455826acc8c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +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 + diff --git a/SPECS/dnsmasq.spec b/SPECS/dnsmasq.spec index ea86868..b39f215 100644 --- a/SPECS/dnsmasq.spec +++ b/SPECS/dnsmasq.spec @@ -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 - 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 - 2.85-2 - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags Related: rhbz#1991688