108 lines
3.8 KiB
Diff
108 lines
3.8 KiB
Diff
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
|
|
|