Files
go-dhcp/pkg/leases/leases.go
2024-01-09 12:23:41 +01:00

137 lines
2.6 KiB
Go

package leases
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/adrianokf/go-dhcp/pkg/types"
"go.uber.org/zap"
)
type LeaseState uint8
const (
Offered LeaseState = iota
Requested
)
const DumpFile = "/var/lib/go-dhcp/leases.json"
type Lease struct {
TransactionId types.TxId `json:"TransactionID"`
TTL time.Time `json:"TTL"`
State LeaseState `json:"State"`
ClientAddr types.HwAddr `json:"ClientAddr"`
Address types.Ipv4Addr `json:"Address"`
}
type ILeaseManager interface {
Request(xid types.TxId, clientAddr types.HwAddr) (*Lease, error)
Release(l Lease) error
Lookup(xid types.TxId) error
}
type LeaseManager struct {
leases map[types.TxId]Lease
count byte
}
func (m LeaseManager) DumpLeases() {
err := os.MkdirAll(filepath.Dir(DumpFile), 0755)
if err != nil {
zap.S().Panic(err)
}
f, err := os.Create(DumpFile)
if err != nil {
zap.S().Panic(err)
}
defer f.Close()
leases := make([]Lease, len(m.leases))
for _, l := range m.leases {
leases = append(leases, l)
}
enc := json.NewEncoder(f)
enc.Encode(leases)
f.Sync()
}
func LoadLeases() (map[types.TxId]Lease, error) {
var leaseMap = make(map[types.TxId]Lease)
data, err := os.ReadFile(DumpFile)
if err != nil {
return leaseMap, err
}
var leases []Lease
json.Unmarshal(data, &leases)
for _, l := range leases {
leaseMap[l.TransactionId] = l
}
return leaseMap, nil
}
func NewLeaseManager() *LeaseManager {
leases, err := LoadLeases()
if err != nil {
zap.S().Warnf("Could not restore saved leases from %s: %s", DumpFile, err)
}
m := &LeaseManager{
leases: leases,
}
return m
}
func (m *LeaseManager) Request(xid types.TxId, clientAddr types.HwAddr) (*Lease, error) {
zap.S().Debugf("LeaseManager.Request(%v, %v)", xid, clientAddr)
if m.count > 254 {
return nil, errors.New("lease address pool exhausted")
}
assigned := [4]byte{10, 0, 0, m.count + 2}
lease := Lease{
TransactionId: xid,
TTL: time.Now().Add(1 * time.Hour),
State: Requested,
ClientAddr: clientAddr,
Address: assigned,
}
m.leases[xid] = lease
m.count += 1
zap.S().Debug("lease=", lease)
m.DumpLeases()
return &lease, nil
}
func (m LeaseManager) Release(l Lease) error {
_, found := m.leases[l.TransactionId]
if !found {
return fmt.Errorf("invalid lease %v", l)
}
delete(m.leases, l.TransactionId)
m.DumpLeases()
return nil
}
func (m LeaseManager) Lookup(xid types.TxId) (*Lease, error) {
lease, found := m.leases[xid]
if found {
return &lease, nil
}
return nil, fmt.Errorf("no lease found for xid %v", xid)
}