137 lines
2.6 KiB
Go
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)
|
|
}
|