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