dhcp4d: implement permanent leases (no expiration)

This commit is contained in:
Michael Stapelberg 2018-06-09 15:25:42 +02:00
parent d21822f531
commit 4c69109db5
3 changed files with 52 additions and 5 deletions

View File

@ -27,7 +27,7 @@ func loadLeases(h *dhcp4d.Handler, fn string) error {
return err
}
var leases []*dhcp4d.Lease
if err := json.Unmarshal(b, leases); err != nil {
if err := json.Unmarshal(b, &leases); err != nil {
return err
}
h.SetLeases(leases)

View File

@ -21,6 +21,10 @@ type Lease struct {
Expiry time.Time `json:"expiry"`
}
func (l *Lease) Expired(at time.Time) bool {
return !l.Expiry.IsZero() && at.After(l.Expiry)
}
type Handler struct {
serverIP net.IP
start net.IP // first IP address to hand out
@ -80,11 +84,11 @@ func (h *Handler) findLease() int {
if len(h.leasesIP) < h.leaseRange {
// TODO: hash the hwaddr like dnsmasq
i := rand.Intn(h.leaseRange)
if l, ok := h.leasesIP[i]; !ok || now.After(l.Expiry) {
if l, ok := h.leasesIP[i]; !ok || l.Expired(now) {
return i
}
for i := 0; i < h.leaseRange; i++ {
if l, ok := h.leasesIP[i]; !ok || now.After(l.Expiry) {
if l, ok := h.leasesIP[i]; !ok || l.Expired(now) {
return i
}
}
@ -111,7 +115,7 @@ func (h *Handler) canLease(reqIP net.IP, hwaddr string) int {
return leaseNum // lease already owned by requestor
}
if h.timeNow().After(l.Expiry) {
if l.Expired(h.timeNow()) {
return leaseNum // lease expired
}
@ -174,8 +178,14 @@ func (h *Handler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options d
Hostname: string(options[dhcp4.OptionHostName]),
}
// Release any old leases for this client
if l, ok := h.leasesHW[lease.HardwareAddr]; ok {
if l.Expiry.IsZero() {
// Retain permanent lease properties
lease.Expiry = time.Time{}
lease.Hostname = l.Hostname
}
// Release any old leases for this client
delete(h.leasesIP, l.Num)
}

View File

@ -224,6 +224,43 @@ func TestPreviousLease(t *testing.T) {
}
}
func TestPermanentLease(t *testing.T) {
handler, cleanup := testHandler(t)
defer cleanup()
now := time.Now()
handler.timeNow = func() time.Time { return now }
var (
addr = net.IP{192, 168, 42, 23}
hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
)
handler.SetLeases([]*Lease{
{
Num: 2,
Addr: addr,
HardwareAddr: hardwareAddr.String(),
},
})
p := request(addr, hardwareAddr)
resp := handler.ServeDHCP(p, dhcp4.Request, p.ParseOptions())
if got, want := resp.YIAddr().To4(), addr.To4(); !bytes.Equal(got, want) {
t.Errorf("DHCPREQUEST resulted in wrong IP: got %v, want %v", got, want)
}
now = now.Add(3 * time.Hour)
hardwareAddr[len(hardwareAddr)-1] = 0x77
p = request(addr, hardwareAddr)
resp = handler.ServeDHCP(p, dhcp4.Request, p.ParseOptions())
opts := resp.ParseOptions()
if got, want := dhcp4.MessageType(opts[dhcp4.OptionDHCPMessageType][0]), dhcp4.NAK; got != want {
t.Errorf("DHCPREQUEST resulted in unexpected message type: got %v, want %v", got, want)
}
}
func TestExpiration(t *testing.T) {
handler, cleanup := testHandler(t)
defer cleanup()