Hello Simon and everyone,

I am sending this patch on behalf of Tomáš Korbař, who worked on debugging the 
issue and even written a test [1] to verify it works. Test is written in our 
shell based beakerlib, but I think is readable enough even in basic form.

Currentdhcp-range does not work well in case DHCP client would refuse the offered address. When this happens, current dnsmasq does not even stop at maximal address specified. This change adds similar check like when no dhcp-sequential-ip is used. Tomáš tested it already, but would anyone mind testing it also? If there is no regression or need to adjust it, would you mind merging it? Thank you in advance! Cheers, Petr
1. https://gitlab.com/redhat/centos-stream/tests/dnsmasq/-/merge_requests/6

--
Petr Menšík
Senior Software Engieer, RHEL
Red Hat, https://www.redhat.com/
PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB
From 913472864bdcd5b7bb01c31ff27706b6dfbb99a2 Mon Sep 17 00:00:00 2001
From: Tomas Korbar <[email protected]>
Date: Tue, 7 Oct 2025 19:12:00 +0200
Subject: [PATCH] Fix obeying dhcp-range if dhcp-sequential-ip and IPV6 is used

Previously starting position for searching the next free address
in IPV6 range was no checked whether it is in bounds. This
commit adds modulo operation like when dhcp-sequential-ip is
not used to ensure dnsmasq does not offer out of range address.
---
 src/dhcp6.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/src/dhcp6.c b/src/dhcp6.c
index 482caf7d..99cc77b2 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -522,27 +522,26 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context,  unsigned c
 	continue;
       else
 	{ 
+	  u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
+	  u64 offset = c->addr_epoch;
 	  if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
 	    {
 	      /* seed is largest extant lease addr in this context,
 		 skip addresses equal to the number of addresses rejected
 		 by clients. This should avoid the same client being offered the same
 		 address after it has rjected it. */
-	      start = lease_find_max_addr6(c) + 1 + serial + c->addr_epoch;
+	      offset += lease_find_max_addr6(c) - addr6part(&c->start6) + 1 + serial;
 	      if (c->addr_epoch)
 		c->addr_epoch--;
 	    }
 	  else
 	    {
-	      u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
-	      u64 offset = j + c->addr_epoch;
-
-	      /* don't divide by zero if range is whole 2^64 */
-	      if (range != 0)
-		offset = offset % range;
-
-	      start = addr6part(&c->start6) + offset;
+	      offset += j;
 	    }
+	  /* don't divide by zero if range is whole 2^64 */
+	  if (range != 0)
+		offset = offset % range;
+	  start = addr6part(&c->start6) + offset;
 
 	  /* iterate until we find a free address. */
 	  addr = start;
-- 
2.51.0

_______________________________________________
Dnsmasq-discuss mailing list
[email protected]
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to