From 4fade3f6321777379b3ddf2b341fd7f1005c1a98 Mon Sep 17 00:00:00 2001 From: Miguel Duarte Barroso Date: Tue, 21 Jul 2026 13:52:54 +0100 Subject: [PATCH] dhcp: send DHCPRELEASE with the client IP addr as ciaddr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dhcp IPAM plugin sends DHCPRELEASE packets with 0.0.0.0 as the IP source address instead of the client's assigned IP. This violates RFC 2131 section 4.4.4 and causes DHCP servers (e.g. dnsmasq) to silently ignore the release. Leases are never freed — they only expire via timeout. By using the `nclient4.WithUnicast()` option, the client will stop using a raw packet socket which constructs IP headers with 0.0.0.0 as the source. Using src IP 0.0.0.0 is appropriate for DHCPDISCOVER (no address assigned yet) but wrong for DHCPRELEASE. Signed-off-by: Miguel Duarte Barroso --- plugins/ipam/dhcp/lease.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/ipam/dhcp/lease.go b/plugins/ipam/dhcp/lease.go index 302f95dc0..413ed3789 100644 --- a/plugins/ipam/dhcp/lease.go +++ b/plugins/ipam/dhcp/lease.go @@ -428,7 +428,14 @@ func (l *DHCPLease) renew() error { func (l *DHCPLease) release() error { log.Printf("%v: releasing lease", l.clientID) - c, err := newDHCPClient(l.link, l.timeout) + c, err := newDHCPClient( + l.link, + l.timeout, + nclient4.WithUnicast(&net.UDPAddr{ + IP: l.latestLease.ACK.YourIPAddr, + Port: nclient4.ClientPort, + }), + ) if err != nil { return err }