summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Lochmann2025-11-03 00:00:00 +0000
committerÁlvaro Fernández Rojas2025-11-17 07:57:45 +0000
commit5492f09ec07514cf8543bc06c34556e24b590852 (patch)
treebea9a41c698ef3e8f5b09dafc6fbe54b62955546
parent38a31eb29a48da6c219cbbe49df30e36dba1d5db (diff)
downloadodhcp6c-5492f09ec07514cf8543bc06c34556e24b590852.tar.gz
odhcp6c: apply draft-ietf-6man-slaac-renum-11 lifetime rules
Instead of applying the complicated ruleset from RFC 4862, just use the new address information as described in the draft draft-ietf-6man-slaac-renum-11. Signed-off-by: Jonas Lochmann <git@inkompetenz.org> Link: https://github.com/openwrt/odhcp6c/pull/114 Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
-rw-r--r--src/dhcpv6.c4
-rw-r--r--src/odhcp6c.c54
-rw-r--r--src/odhcp6c.h2
-rw-r--r--src/ra.c22
4 files changed, 24 insertions, 58 deletions
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index 7f73699..872f169 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -1742,7 +1742,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
}
if (update_state) {
- if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0, 0))
+ if (odhcp6c_update_entry(STATE_IA_PD, &entry, 0))
updated_IAs++;
syslog(LOG_INFO, "%s/%d preferred %d valid %d",
@@ -1797,7 +1797,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
}
if (update_state) {
- if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0, 0))
+ if (odhcp6c_update_entry(STATE_IA_NA, &entry, 0))
updated_IAs++;
syslog(LOG_INFO, "%s preferred %d valid %d",
diff --git a/src/odhcp6c.c b/src/odhcp6c.c
index 8b880e3..7b1a387 100644
--- a/src/odhcp6c.c
+++ b/src/odhcp6c.c
@@ -939,64 +939,20 @@ static struct odhcp6c_entry* odhcp6c_find_entry(enum odhcp6c_state state, const
}
bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
- uint32_t safe, unsigned int holdoff_interval)
+ unsigned int holdoff_interval)
{
struct odhcp6c_entry *x = odhcp6c_find_entry(state, new);
- uint32_t new_valid;
-
- /*
- * "safe" refers to https://www.rfc-editor.org/rfc/rfc4862#section-5.5.3
- * section e; it is either the two hours in seconds or zero when (e)
- * does not apply.
- *
- * The base condition for applying safe is that there is already a
- * matching prefix (and safe itself must be set).
- */
- if (safe && x) {
- if (new->valid > safe || new->valid > x->valid) {
- /*
- * 1: If the received Valid Lifetime is greater than 2 hours or
- * greater than RemainingLifetime, set the valid lifetime of the
- * corresponding address to the advertised Valid Lifetime.
- */
- new_valid = new->valid;
- } else if (x->valid <= safe) {
- /*
- * 2: If RemainingLifetime is less than or equal
- * to 2 hours, ignore the Prefix Information option with
- * regards to the valid lifetime, unless the Router
- * Advertisement from which this option was obtained has
- * been authenticated (e.g., via Secure Neighbor
- * Discovery [RFC3971]). If the Router Advertisement
- * was authenticated, the valid lifetime of the
- * corresponding address should be set to the Valid
- * Lifetime in the received option.
- *
- * Since authenticated advertisements aren't supported we
- * always keep the old value.
- */
- new_valid = x->valid;
- } else {
- /*
- * 3: Otherwise, reset the valid lifetime of the corresponding
- * address to 2 hours.
- */
- new_valid = safe;
- }
- } else {
- new_valid = new->valid;
- }
if (x) {
- if (holdoff_interval && new_valid >= x->valid &&
- new_valid != UINT32_MAX &&
- new_valid - x->valid < holdoff_interval &&
+ if (holdoff_interval && new->valid >= x->valid &&
+ new->valid != UINT32_MAX &&
+ new->valid - x->valid < holdoff_interval &&
new->preferred >= x->preferred &&
new->preferred != UINT32_MAX &&
new->preferred - x->preferred < holdoff_interval)
return false;
- x->valid = new_valid;
+ x->valid = new->valid;
x->preferred = new->preferred;
x->t1 = new->t1;
x->t2 = new->t2;
diff --git a/src/odhcp6c.h b/src/odhcp6c.h
index 42c645d..b229412 100644
--- a/src/odhcp6c.h
+++ b/src/odhcp6c.h
@@ -576,7 +576,7 @@ void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len);
// Entry manipulation
bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
- uint32_t safe, unsigned int holdoff_interval);
+ unsigned int holdoff_interval);
void odhcp6c_expire(bool expire_ia_pd);
uint32_t odhcp6c_elapsed(void);
diff --git a/src/ra.c b/src/ra.c
index dcc5fd6..ca9e691 100644
--- a/src/ra.c
+++ b/src/ra.c
@@ -437,7 +437,7 @@ bool ra_process(void)
entry->valid = router_valid;
entry->preferred = entry->valid;
changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
// Parse hop limit
changed |= ra_set_hoplimit(adv->nd_ra_curhoplimit);
@@ -478,8 +478,18 @@ bool ra_process(void)
if (entry->priority > 0)
changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
} else if (opt->type == ND_OPT_PREFIX_INFORMATION && opt->len == 4) {
+ /*
+ * We implement draft-ietf-6man-slaac-renum-11 here:
+ * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-11#section-5.4
+ *
+ * This removes the two hour magic and instead just uses the new
+ * data. If the lifetime is zero, then the prefix is removed.
+ *
+ * An entry with lifetime zero is added. odhcp6c_expire will remove
+ * it again. odhcp6c_expire is called at the end of this function.
+ */
struct nd_opt_prefix_info *pinfo = (struct nd_opt_prefix_info*)opt;
entry->router = any;
entry->target = pinfo->nd_opt_pi_prefix;
@@ -497,7 +507,7 @@ bool ra_process(void)
if ((pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
!ptp_link)
changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
- 7200, ra_holdoff_interval);
+ ra_holdoff_interval);
if (!(pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) ||
pinfo->nd_opt_pi_prefix_len != 64)
@@ -507,7 +517,7 @@ bool ra_process(void)
entry->target.s6_addr32[3] = lladdr.s6_addr32[3];
changed |= odhcp6c_update_entry(STATE_RA_PREFIX, entry,
- 7200, ra_holdoff_interval);
+ ra_holdoff_interval);
} else if (opt->type == ND_OPT_RECURSIVE_DNS && opt->len > 2) {
entry->router = from.sin6_addr;
entry->priority = 0;
@@ -520,7 +530,7 @@ bool ra_process(void)
memcpy(&entry->target, &opt->data[6 + i * sizeof(entry->target)],
sizeof(entry->target));
changed |= odhcp6c_update_entry(STATE_RA_DNS, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
}
} else if (opt->type == ND_OPT_DNSSL && opt->len > 1) {
uint32_t *valid = (uint32_t*)&opt->data[2];
@@ -542,7 +552,7 @@ bool ra_process(void)
continue;
changed |= odhcp6c_update_entry(STATE_RA_SEARCH, entry,
- 0, ra_holdoff_interval);
+ ra_holdoff_interval);
entry->auxlen = 0;
}
}