From a172c6c1235680cb014f5f5f5e0bb5b904c4e031 Mon Sep 17 00:00:00 2001 From: Matthew Harkness Date: Mon, 21 Sep 2026 09:48:57 -0700 Subject: [PATCH] dhcp: add dhcp-hold-offered to reserve offered addresses briefly --- man/dnsmasq.8 | 4 ++++ src/dnsmasq.h | 3 ++- src/option.c | 3 +++ src/rfc2131.c | 9 ++++++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 8923325..7e5ac0e 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -1801,6 +1801,10 @@ option with a DHCPACK including a Rapid Commit option and fully committed address and configuration information. Should only be enabled if either the server is the only server for the subnet, or multiple servers are present and they each commit a binding for all clients. .TP +.B --dhcp-hold-offered +Create a 30s lease when sending DHCPOFFER so the address is not offered +to another client before DHCPREQUEST. +.TP .B --dhcp-alternate-port[=[,]] (IPv4 only) Change the ports used for DHCP from the default. If this option is given alone, without arguments, it changes the ports used for DHCP diff --git a/src/dnsmasq.h b/src/dnsmasq.h index ecff18d..2288557 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -296,7 +296,8 @@ struct event_desc { #define OPT_LEASEQUERY 77 #define OPT_LOG_ONLY_FAILED 78 #define OPT_LOG_MALLOC 79 -#define OPT_LAST 80 +#define OPT_HOLD_OFFERED 80 +#define OPT_LAST 81 #define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) diff --git a/src/option.c b/src/option.c index 44bd522..61c91ed 100644 --- a/src/option.c +++ b/src/option.c @@ -201,6 +201,7 @@ struct myoption { #define LOPT_LEASEQUERY 389 #define LOPT_SPLIT_RELAY 390 #define LOPT_LOG_MALLOC 391 +#define LOPT_HOLD_OFFERED 392 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -389,6 +390,7 @@ static const struct myoption opts[] = { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL }, { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY }, { "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT }, + { "dhcp-hold-offered", 0, 0, LOPT_HOLD_OFFERED }, { "dumpfile", 1, 0, LOPT_DUMPFILE }, { "dumpmask", 1, 0, LOPT_DUMPMASK }, { "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID }, @@ -600,6 +602,7 @@ static struct { { LOPT_DHCPTTL, ARG_ONE, "", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, { LOPT_REPLY_DELAY, ARG_ONE, "", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL }, { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL }, + { LOPT_HOLD_OFFERED, OPT_HOLD_OFFERED, NULL, gettext_noop("Hold DHCPOFFER addresses until REQUEST."), NULL }, { LOPT_DUMPFILE, ARG_ONE, "", gettext_noop("Path to debug packet dump file."), NULL }, { LOPT_DUMPMASK, ARG_ONE, "", gettext_noop("Mask which packets to dump."), NULL }, { LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL }, diff --git a/src/rfc2131.c b/src/rfc2131.c index ec0194b..5d0094f 100644 --- a/src/rfc2131.c +++ b/src/rfc2131.c @@ -1376,7 +1376,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, daemon->metrics[METRIC_DHCPOFFER]++; log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid); - + if (!lease && option_bool(OPT_HOLD_OFFERED)) + { + if (!(lease = lease4_allocate(mess->yiaddr))) + return 0; + lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now, 0); + lease_set_expires(lease, 30, now); + } + time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4)); clear_packet(mess, end); option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER); -- 2.52.0