From d21822f531b186e64e117cadf24fed7c541f0f00 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sat, 9 Jun 2018 15:10:11 +0200 Subject: [PATCH] dhcp4d: implement loading leases files from persistent storage --- cmd/dhcp4d/dhcp4d.go | 25 ++++++++++++++++++++++--- internal/dhcp4d/dhcp4d.go | 23 +++++++++++++++++------ internal/dhcp4d/dhcp4d_test.go | 24 +++++++++++++++++++++++- 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/cmd/dhcp4d/dhcp4d.go b/cmd/dhcp4d/dhcp4d.go index 6936196..81413b9 100644 --- a/cmd/dhcp4d/dhcp4d.go +++ b/cmd/dhcp4d/dhcp4d.go @@ -4,19 +4,36 @@ package main import ( "encoding/json" "flag" - "fmt" "io/ioutil" - "log" "os" "syscall" "router7/internal/dhcp4d" "router7/internal/notify" + "router7/internal/teelogger" "github.com/krolaw/dhcp4" "github.com/krolaw/dhcp4/conn" ) +var log = teelogger.NewConsole() + +func loadLeases(h *dhcp4d.Handler, fn string) error { + b, err := ioutil.ReadFile(fn) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + var leases []*dhcp4d.Lease + if err := json.Unmarshal(b, leases); err != nil { + return err + } + h.SetLeases(leases) + return nil +} + func logic() error { if err := os.MkdirAll("/perm/dhcp4d", 0755); err != nil { return err @@ -26,6 +43,9 @@ func logic() error { if err != nil { return err } + if err := loadLeases(handler, "/perm/dhcp4d/leases.json"); err != nil { + return err + } handler.Leases = func(leases []*dhcp4d.Lease) { b, err := json.Marshal(leases) if err != nil { @@ -38,7 +58,6 @@ func logic() error { } if err := notify.Process("/user/dnsd", syscall.SIGUSR1); err != nil { log.Printf("notifying dnsd: %v", err) - ioutil.WriteFile("/dev/console", []byte(fmt.Sprintf("notifying dnsd: %+v\n", err)), 0600) } } conn, err := conn.NewUDP4BoundListener("lan0", ":67") // TODO: customizeable diff --git a/internal/dhcp4d/dhcp4d.go b/internal/dhcp4d/dhcp4d.go index fa5855d..c0d5153 100644 --- a/internal/dhcp4d/dhcp4d.go +++ b/internal/dhcp4d/dhcp4d.go @@ -14,11 +14,11 @@ import ( ) type Lease struct { - Num int - Addr net.IP - HardwareAddr string - Hostname string - Expiry time.Time + Num int `json:"num"` // relative to Handler.start + Addr net.IP `json:"addr"` + HardwareAddr string `json:"hardware_addr"` + Hostname string `json:"hostname"` + Expiry time.Time `json:"expiry"` } type Handler struct { @@ -36,7 +36,6 @@ type Handler struct { Leases func([]*Lease) } -// TODO: restore leases from permanent storage func NewHandler(dir string) (*Handler, error) { serverIP, err := netconfig.LinkAddress(dir, "lan0") if err != nil { @@ -64,6 +63,18 @@ func NewHandler(dir string) (*Handler, error) { }, nil } +// SetLeases overwrites the leases database with the specified leases, typically +// loaded from persistent storage. There is no locking, so SetLeases must be +// called before Serve. +func (h *Handler) SetLeases(leases []*Lease) { + h.leasesHW = make(map[string]*Lease) + h.leasesIP = make(map[int]*Lease) + for _, l := range leases { + h.leasesHW[l.HardwareAddr] = l + h.leasesIP[l.Num] = l + } +} + func (h *Handler) findLease() int { now := h.timeNow() if len(h.leasesIP) < h.leaseRange { diff --git a/internal/dhcp4d/dhcp4d_test.go b/internal/dhcp4d/dhcp4d_test.go index c619190..201f96b 100644 --- a/internal/dhcp4d/dhcp4d_test.go +++ b/internal/dhcp4d/dhcp4d_test.go @@ -316,4 +316,26 @@ func TestServerID(t *testing.T) { } } -// TODO: test persistent storage +func TestPersistentStorage(t *testing.T) { + handler, cleanup := testHandler(t) + defer cleanup() + + var ( + addr = net.IP{192, 168, 42, 4} + hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66} + ) + + handler.SetLeases([]*Lease{ + { + Num: 2, + Addr: addr, + HardwareAddr: hardwareAddr.String(), + }, + }) + + p := request(net.IPv4zero, hardwareAddr) + resp := handler.ServeDHCP(p, dhcp4.Discover, p.ParseOptions()) + if got, want := resp.YIAddr().To4(), addr.To4(); !bytes.Equal(got, want) { + t.Errorf("DHCPOFFER for wrong IP: got %v, want %v", got, want) + } +}