From c8b997fc6f076492e0d6b268251f59fc01ab48fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= Date: Mon, 20 Sep 2021 19:06:47 +0200 Subject: [PATCH] Offer alternative address if requested is leased In some cases booting firware requires multiple IPv6 addresses leased from DHCP. Dnsmasq offers the same address to different IAIDs requests. The first gets it successfully, but remaining requests would be denied with address in use error. Change behaviour and supply alternative address from the same range, just like Rapid Commit DHCP option allows. Reuse the same code. Resolves: rhbz#2002871 --- dnsmasq-2.86-alternative-lease.patch | 107 +++++++++++++++++++++++++++ dnsmasq.spec | 4 +- 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 dnsmasq-2.86-alternative-lease.patch diff --git a/dnsmasq-2.86-alternative-lease.patch b/dnsmasq-2.86-alternative-lease.patch new file mode 100644 index 0000000..e51d2b3 --- /dev/null +++ b/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/dnsmasq.spec b/dnsmasq.spec index a3d7eec..560afa2 100644 --- a/dnsmasq.spec +++ b/dnsmasq.spec @@ -43,8 +43,9 @@ 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 -# several regressions. This implements just limited change in different way. 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 # This is workaround to nettle bug #1549190 # https://bugzilla.redhat.com/show_bug.cgi?id=1549190 @@ -190,6 +191,7 @@ install -Dpm 644 %{SOURCE2} %{buildroot}%{_sysusersdir}/%{name}.conf %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