Reservation lease time; reservations by MAC address or client ID
- A reservation can have its own lease time (--lease-time, the reservation dialog), over the subnet's. Schema migration 6. - A reservation with a MAC address and a client ID matches either one (a dual-boot machine sends two client IDs from one MAC); before, it was found by MAC and then refused. A lease of the reserved address by the client's other identity counts as its own. - The Leases page shows a client's client ID; reserving a lease uses both, or one with --by / the dialog's choice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
abb2ee0fd7
commit
4fd72998ec
20 files changed
+252
-65
No files matched your search
@@ -2,6 +2,7 @@ package dhcpd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
@@ -115,9 +116,9 @@ func (h *harness) discover(iface string, m net.HardwareAddr, opts ...dhcp4.Optio
|
||||
}
|
||||
|
||||
// lease runs DISCOVER and REQUEST and returns the ACK.
|
||||
func (h *harness) lease(iface string, m net.HardwareAddr) *dhcp4.Packet {
|
||||
func (h *harness) lease(iface string, m net.HardwareAddr, opts ...dhcp4.Option) *dhcp4.Packet {
|
||||
h.t.Helper()
|
||||
off := h.discover(iface, m)
|
||||
off := h.discover(iface, m, opts...)
|
||||
if off == nil || off.Packet.Type() != dhcp4.Offer {
|
||||
h.t.Fatalf("no offer for %s on %s", m, iface)
|
||||
}
|
||||
@@ -126,6 +127,9 @@ func (h *harness) lease(iface string, m net.HardwareAddr) *dhcp4.Packet {
|
||||
req.Set(dhcp4.OptServerID, dhcp4.IP(sid))
|
||||
req.Set(dhcp4.OptRequestedIP, dhcp4.IP(off.Packet.YIAddr))
|
||||
req.Set(dhcp4.OptHostName, []byte("client"+m.String()[15:]))
|
||||
for _, o := range opts {
|
||||
req.Set(o.Code, o.Data)
|
||||
}
|
||||
ack := h.send(iface, req)
|
||||
if ack == nil || ack.Packet.Type() != dhcp4.Ack {
|
||||
h.t.Fatalf("no ACK for %s: %+v", m, ack)
|
||||
@@ -580,3 +584,31 @@ func TestAddressOrder(t *testing.T) {
|
||||
t.Errorf("a full subnet offered %s", out.Packet.YIAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReservationLeaseTimeAndClientID(t *testing.T) {
|
||||
h := newHarness(t, func(st *model.State) {
|
||||
st.Reservations[0].LeaseTime = 600
|
||||
st.Reservations[0].ClientID = "ff0102"
|
||||
})
|
||||
u32 := func(p *dhcp4.Packet) uint32 { return binary.BigEndian.Uint32(p.Get(dhcp4.OptLeaseTime)) }
|
||||
id := func(hex ...byte) dhcp4.Option { return dhcp4.Option{Code: dhcp4.OptClientID, Data: hex} }
|
||||
// By its client ID, from any MAC address, with its own lease time.
|
||||
ack := h.lease("eth0", mac(0x50), id(0xff, 1, 2))
|
||||
if ack.YIAddr.String() != "10.0.10.20" || u32(ack) != 600 {
|
||||
t.Errorf("by client id: %s %d", ack.YIAddr, u32(ack))
|
||||
}
|
||||
if l := h.s.Lease(ack.YIAddr); !l.End.Equal(h.clock.Add(10 * time.Minute)) {
|
||||
t.Errorf("lease end %v", l.End)
|
||||
}
|
||||
// By its MAC address with another client ID (the machine's other OS):
|
||||
// the same address, though the first identity's lease is still on.
|
||||
ack = h.lease("eth0", mac(0x99), id(1, 0xaa, 0, 0, 0, 0, 0x99))
|
||||
if ack.YIAddr.String() != "10.0.10.20" {
|
||||
t.Errorf("by MAC: %s", ack.YIAddr)
|
||||
}
|
||||
// Anyone else gets a pool address, with the subnet's lease time.
|
||||
ack = h.lease("eth0", mac(0x51), id(0xff, 9, 9))
|
||||
if ack.YIAddr.String() == "10.0.10.20" || u32(ack) != 43200 {
|
||||
t.Errorf("stranger: %s %d", ack.YIAddr, u32(ack))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user