From 5733d3c59a5651f64357ac11c98b4f39895c8d25 Mon Sep 17 00:00:00 2001
From: Roy Marples <roy@marples.name>
Date: Tue, 23 Jun 2026 02:17:10 +0100
Subject: [PATCH] DHCPv6: When deprecating addresses, restart on prefix
 deletions

As that might invalidate the next address to iterate on.

Reported-by: CuB3y0nd <root@cubeyond.net>
---
 src/dhcp6.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/src/dhcp6.c b/src/dhcp6.c
index 460040bd..02464eb3 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -2561,12 +2561,13 @@ dhcp6_findia(struct interface *ifp, struct dhcp6_message *m, size_t l,
 }
 
 #ifndef SMALL
-static void
+static bool
 dhcp6_deprecatedele(struct ipv6_addr *ia)
 {
 	struct ipv6_addr *da, *dan, *dda;
 	struct timespec now;
 	struct dhcp6_state *state;
+	bool freed = false;
 
 	timespecclear(&now);
 	TAILQ_FOREACH_SAFE(da, &ia->pd_pfxs, pd_next, dan) {
@@ -2595,11 +2596,14 @@ dhcp6_deprecatedele(struct ipv6_addr *ia)
 			if (IN6_ARE_ADDR_EQUAL(&dda->addr, &da->addr))
 				break;
 		}
-		if (dda != NULL) {
+		if (dda != ia && dda != NULL) {
 			TAILQ_REMOVE(&state->addrs, dda, next);
 			ipv6_freeaddr(dda);
+			freed = true;
 		}
 	}
+
+	return freed;
 }
 #endif
 
@@ -2607,7 +2611,11 @@ static void
 dhcp6_deprecateaddrs(struct ipv6_addrhead *addrs)
 {
 	struct ipv6_addr *ia, *ian;
+#ifndef SMALL
+	bool again;
+#endif
 
+again:
 	TAILQ_FOREACH_SAFE(ia, addrs, next, ian) {
 		if (ia->flags & IPV6_AF_EXTENDED)
 			;
@@ -2629,7 +2637,9 @@ dhcp6_deprecateaddrs(struct ipv6_addrhead *addrs)
 		/* If we delegated from this prefix, deprecate or remove
 		 * the delegations. */
 		if (ia->flags & IPV6_AF_PFXDELEGATION)
-			dhcp6_deprecatedele(ia);
+			again = dhcp6_deprecatedele(ia);
+		else
+			again = false;
 #endif
 
 		if (ia->flags & IPV6_AF_REQUEST) {
@@ -2642,6 +2652,11 @@ dhcp6_deprecateaddrs(struct ipv6_addrhead *addrs)
 		if (!(ia->flags & IPV6_AF_EXTENDED))
 			ipv6_deleteaddr(ia);
 		ipv6_freeaddr(ia);
+#ifndef SMALL
+		/* Deletion may invalidate the next pointer so restart */
+		if (again)
+			goto again;
+#endif
 	}
 }
 
