-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DHCP6: IPv6 Ready Logo test fixes #397
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -186,7 +186,6 @@ static const char * const dhcp6_statuses[] = { | |
}; | ||
|
||
static void dhcp6_bind(struct interface *, const char *, const char *); | ||
static void dhcp6_failinform(void *); | ||
static void dhcp6_startrebind(void *arg); | ||
static void dhcp6_recvaddr(void *, unsigned short); | ||
static void dhcp6_startdecline(struct interface *); | ||
|
@@ -984,6 +983,15 @@ dhcp6_makemessage(struct interface *ifp) | |
ia_na.t2 = 0; | ||
COPYIN(ifia->ia_type, &ia_na, ia_na_len); | ||
TAILQ_FOREACH(ap, &state->addrs, next) { | ||
/* A bit of a corner case, but tested by IPv6 Ready Logo: | ||
* Don't attempt to renew expired leases. This can | ||
* really only happen if the server is poorly configured and | ||
* doesn't allow enough time for lease renewal per the | ||
* T1 and valid lifetime parameters it sent. | ||
*/ | ||
if ((state->state == DH6S_RENEW) && | ||
(ap->prefix_vltime <= state->renew)) | ||
continue; | ||
if (ap->flags & IPV6_AF_STALE) | ||
continue; | ||
if (!(ap->flags & IPV6_AF_REQUEST) && | ||
|
@@ -1412,7 +1420,7 @@ dhcp6_sendmessage(struct interface *ifp, void (*callback)(void *)) | |
state->RT = RT * 2; | ||
if (state->RT < RT) /* Check overflow */ | ||
state->RT = RT; | ||
if (state->MRC == 0 || state->RTC < state->MRC) | ||
if (state->MRC == 0 || state->RTC <= state->MRC) | ||
eloop_timeout_add_msec(ctx->eloop, | ||
RT, callback, ifp); | ||
else if (state->MRC != 0 && state->MRCcallback) | ||
|
@@ -1677,7 +1685,6 @@ dhcp6_startdiscover(void *arg) | |
state->IRT = SOL_TIMEOUT; | ||
state->MRT = state->sol_max_rt; | ||
state->MRC = SOL_MAX_RC; | ||
|
||
/* If we fail to renew or confirm, our requested addreses will | ||
* be marked as stale. | ||
To re-request them, just mark them as not stale. */ | ||
|
@@ -1714,14 +1721,8 @@ dhcp6_startinform(void *arg) | |
logerr("%s: %s", __func__, ifp->name); | ||
return; | ||
} | ||
dhcp6_sendinform(ifp); | ||
/* RFC3315 18.1.2 says that if CONFIRM failed then the prior addresses | ||
* SHOULD be used. The wording here is poor, because the addresses are | ||
* merely one facet of the lease as a whole. | ||
* This poor wording might explain the lack of similar text for INFORM | ||
* in 18.1.5 because there are no addresses in the INFORM message. */ | ||
eloop_timeout_add_sec(ifp->ctx->eloop, | ||
INF_MAX_RD, dhcp6_failinform, ifp); | ||
else | ||
dhcp6_sendinform(ifp); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I see what you're trying to fix here. We want to drop through to failinform so we can use the lastlease code, but only on the first failure. So I think what we need to do is after we have logged the message we want to guard the state timing changes like so
Then we change failinform to do dhcp6_fail(ifp, false) - ie we don't force a drop. |
||
} | ||
|
||
static bool | ||
|
@@ -1810,17 +1811,6 @@ dhcp6_failrequest(void *arg) | |
dhcp6_fail(ifp, true); | ||
} | ||
|
||
static void | ||
dhcp6_failinform(void *arg) | ||
{ | ||
struct interface *ifp = arg; | ||
int llevel = dhcp6_failloglevel(ifp); | ||
|
||
logmessage(llevel, "%s: failed to request DHCPv6 information", | ||
ifp->name); | ||
dhcp6_fail(ifp, true); | ||
} | ||
|
||
#ifndef SMALL | ||
static void | ||
dhcp6_failrebindpd(void *arg) | ||
|
@@ -2104,6 +2094,17 @@ dhcp6_checkstatusok(const struct interface *ifp, | |
free(sbuf); | ||
state->lerror = code; | ||
errno = 0; | ||
if (code == D6_STATUS_USEMULTICAST) { | ||
/* RFC 8415 18.2.10 | ||
* If the client receives a Reply message with a status code of | ||
* UseMulticast, the client records the receipt of the message and sends | ||
* subsequent messages to the server through the interface on which the | ||
* message was received using multicast. The client resends the | ||
* original message using multicast. | ||
*/ | ||
logdebugx("%s: server sent UseMulticast", ifp->name); | ||
state->unicast = in6addr_any; | ||
} | ||
|
||
/* code cannot be D6_STATUS_OK, so there is a failure */ | ||
if (ifp->ctx->options & DHCPCD_TEST) | ||
|
@@ -3301,6 +3302,51 @@ dhcp6_bind(struct interface *ifp, const char *op, const char *sfrom) | |
} | ||
} | ||
|
||
static void | ||
dhcp6_adjust_max_rt(struct interface *ifp, const char *sfrom, | ||
struct dhcp6_message *r, size_t len) | ||
{ | ||
struct dhcp6_state *state; | ||
uint8_t *o; | ||
uint16_t ol; | ||
|
||
state = D6_STATE(ifp); | ||
/* RFC8415 */ | ||
o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol); | ||
if (o && ol == sizeof(uint32_t)) { | ||
uint32_t max_rt; | ||
|
||
memcpy(&max_rt, o, sizeof(max_rt)); | ||
max_rt = ntohl(max_rt); | ||
if (max_rt >= 60 && max_rt <= 86400) { | ||
logdebugx("%s: SOL_MAX_RT %llu -> %u", | ||
ifp->name, | ||
(unsigned long long)state->sol_max_rt, | ||
max_rt); | ||
state->sol_max_rt = max_rt; | ||
state->MRT = max_rt; | ||
} else | ||
logerr("%s: invalid SOL_MAX_RT %u", | ||
ifp->name, max_rt); | ||
} | ||
o = dhcp6_findmoption(r, len, D6_OPTION_INF_MAX_RT, &ol); | ||
if (o && ol == sizeof(uint32_t)) { | ||
uint32_t max_rt; | ||
|
||
memcpy(&max_rt, o, sizeof(max_rt)); | ||
max_rt = ntohl(max_rt); | ||
if (max_rt >= 60 && max_rt <= 86400) { | ||
logdebugx("%s: INF_MAX_RT %llu -> %u", | ||
ifp->name, | ||
(unsigned long long)state->inf_max_rt, | ||
max_rt); | ||
state->inf_max_rt = max_rt; | ||
} else | ||
logerrx("%s: invalid INF_MAX_RT %u", | ||
ifp->name, max_rt); | ||
} | ||
} | ||
|
||
static void | ||
dhcp6_recvif(struct interface *ifp, const char *sfrom, | ||
struct dhcp6_message *r, size_t len) | ||
|
@@ -3419,6 +3465,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, | |
/* Validate lease before setting state to REQUEST. */ | ||
/* FALLTHROUGH */ | ||
case DH6S_REQUEST: /* FALLTHROUGH */ | ||
dhcp6_adjust_max_rt(ifp, sfrom, r, len); | ||
case DH6S_RENEW: /* FALLTHROUGH */ | ||
case DH6S_REBIND: | ||
if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) | ||
|
@@ -3427,7 +3474,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, | |
* If we can't use the lease, fallback to | ||
* DISCOVER and try and get a new one. | ||
* | ||
* This is needed become some servers | ||
* This is needed because some servers | ||
* renumber the prefix or address | ||
* and deny the current one before it expires | ||
* rather than sending it back with a zero | ||
|
@@ -3439,16 +3486,20 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, | |
* The currently held lease is still valid | ||
* until a new one is found. | ||
*/ | ||
if (state->state != DH6S_DISCOVER) | ||
dhcp6_startdiscoinform(ifp); | ||
return; | ||
} | ||
/* RFC8415 18.2.10.1 */ | ||
if ((state->state == DH6S_RENEW || | ||
state->state == DH6S_REBIND) && | ||
state->has_no_binding) | ||
{ | ||
dhcp6_startrequest(ifp); | ||
/* RFC 8415 18.2.10 calls out various behaviors | ||
* for some of the status codes a client might receive: | ||
* UnspecFail, and NotOnLink. Handle those here. | ||
*/ | ||
if ((state->state == DH6S_RENEW || | ||
state->state == DH6S_REBIND) && | ||
state->has_no_binding) { | ||
dhcp6_startrequest(ifp); | ||
} | ||
else if (state->state == DH6S_REQUEST && | ||
state->lerror == D6_STATUS_NOTONLINK) { | ||
eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); | ||
dhcp6_startdiscover(ifp); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are no longer handling the state where we got a reply without an error but it didn't contain any addresses with error codes either. |
||
return; | ||
} | ||
if (state->state == DH6S_DISCOVER) | ||
|
@@ -3488,40 +3539,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, | |
return; | ||
} | ||
} | ||
|
||
/* RFC7083 */ | ||
o = dhcp6_findmoption(r, len, D6_OPTION_SOL_MAX_RT, &ol); | ||
if (o && ol == sizeof(uint32_t)) { | ||
uint32_t max_rt; | ||
|
||
memcpy(&max_rt, o, sizeof(max_rt)); | ||
max_rt = ntohl(max_rt); | ||
if (max_rt >= 60 && max_rt <= 86400) { | ||
logdebugx("%s: SOL_MAX_RT %llu -> %u", | ||
ifp->name, | ||
(unsigned long long)state->sol_max_rt, | ||
max_rt); | ||
state->sol_max_rt = max_rt; | ||
} else | ||
logerr("%s: invalid SOL_MAX_RT %u", | ||
ifp->name, max_rt); | ||
} | ||
o = dhcp6_findmoption(r, len, D6_OPTION_INF_MAX_RT, &ol); | ||
if (o && ol == sizeof(uint32_t)) { | ||
uint32_t max_rt; | ||
|
||
memcpy(&max_rt, o, sizeof(max_rt)); | ||
max_rt = ntohl(max_rt); | ||
if (max_rt >= 60 && max_rt <= 86400) { | ||
logdebugx("%s: INF_MAX_RT %llu -> %u", | ||
ifp->name, | ||
(unsigned long long)state->inf_max_rt, | ||
max_rt); | ||
state->inf_max_rt = max_rt; | ||
} else | ||
logerrx("%s: invalid INF_MAX_RT %u", | ||
ifp->name, max_rt); | ||
} | ||
dhcp6_adjust_max_rt(ifp, sfrom, r, len); | ||
if (dhcp6_validatelease(ifp, r, len, sfrom, NULL) == -1) | ||
return; | ||
break; | ||
|
@@ -3614,7 +3632,7 @@ dhcp6_recvif(struct interface *ifp, const char *sfrom, | |
ifp->name, ia->saddr, sfrom, preference); | ||
|
||
/* | ||
* RFC 8415 18.2.1 says we must collect until ADVERTISEMENTs | ||
* RFC 8415 18.2.1 says we must collect ADVERTISEMENTs | ||
* until we get one with a preference of 255 or | ||
* the initial RT has elpased. | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment does not match the code. vltime and renew values don't actually change - when we add an address we adjust the vltime at that point based on the acquisition time vs now time.
This change makes the assumption that RENEW only happens when t1 expires, but that isn't always the case.
So the address could still be valid and therefore should be renewed.
When an address does expire it is removed from the array, unless it's been requested via config.
So what is this code really trying to achieve?