dhcp4d: implement lease expiration
This commit is contained in:
parent
ea476bbb04
commit
f9c3c23b16
@ -14,6 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Lease struct {
|
type Lease struct {
|
||||||
|
Num int
|
||||||
Addr net.IP
|
Addr net.IP
|
||||||
HardwareAddr string
|
HardwareAddr string
|
||||||
Hostname string
|
Hostname string
|
||||||
@ -29,6 +30,8 @@ type Handler struct {
|
|||||||
leasesHW map[string]*Lease
|
leasesHW map[string]*Lease
|
||||||
leasesIP map[int]*Lease
|
leasesIP map[int]*Lease
|
||||||
|
|
||||||
|
timeNow func() time.Time
|
||||||
|
|
||||||
// Leases is called whenever a new lease is handed out
|
// Leases is called whenever a new lease is handed out
|
||||||
Leases func([]*Lease)
|
Leases func([]*Lease)
|
||||||
}
|
}
|
||||||
@ -57,24 +60,24 @@ func NewHandler(dir string) (*Handler, error) {
|
|||||||
dhcp4.OptionDomainName: []byte("lan"),
|
dhcp4.OptionDomainName: []byte("lan"),
|
||||||
dhcp4.OptionDomainSearch: []byte{0x03, 'l', 'a', 'n', 0x00},
|
dhcp4.OptionDomainSearch: []byte{0x03, 'l', 'a', 'n', 0x00},
|
||||||
},
|
},
|
||||||
|
timeNow: time.Now,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) findLease() int {
|
func (h *Handler) findLease() int {
|
||||||
|
now := h.timeNow()
|
||||||
if len(h.leasesIP) < h.leaseRange {
|
if len(h.leasesIP) < h.leaseRange {
|
||||||
// Hand out a free lease
|
|
||||||
// TODO: hash the hwaddr like dnsmasq
|
// TODO: hash the hwaddr like dnsmasq
|
||||||
i := rand.Intn(h.leaseRange)
|
i := rand.Intn(h.leaseRange)
|
||||||
if _, ok := h.leasesIP[i]; !ok {
|
if l, ok := h.leasesIP[i]; !ok || now.After(l.Expiry) {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
for i := 0; i < h.leaseRange; i++ {
|
for i := 0; i < h.leaseRange; i++ {
|
||||||
if _, ok := h.leasesIP[i]; !ok {
|
if l, ok := h.leasesIP[i]; !ok || now.After(l.Expiry) {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: expire the oldest lease
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,16 +91,24 @@ func (h *Handler) canLease(reqIP net.IP, hwaddr string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
if l, exists := h.leasesIP[leaseNum]; exists && l.HardwareAddr != hwaddr {
|
l, ok := h.leasesIP[leaseNum]
|
||||||
return -1 // lease already in use
|
if !ok {
|
||||||
|
return leaseNum // lease available
|
||||||
}
|
}
|
||||||
|
|
||||||
return leaseNum
|
if l.HardwareAddr == hwaddr {
|
||||||
|
return leaseNum // lease already owned by requestor
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.timeNow().After(l.Expiry) {
|
||||||
|
return leaseNum // lease expired
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1 // lease unavailable
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: is ServeDHCP always run from the same goroutine, or do we need locking?
|
// TODO: is ServeDHCP always run from the same goroutine, or do we need locking?
|
||||||
func (h *Handler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) dhcp4.Packet {
|
func (h *Handler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options dhcp4.Options) dhcp4.Packet {
|
||||||
log.Printf("got DHCP packet: %+v, msgType: %v, options: %v", p, msgType, options)
|
|
||||||
reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
|
reqIP := net.IP(options[dhcp4.OptionRequestedIPAddress])
|
||||||
if reqIP == nil {
|
if reqIP == nil {
|
||||||
reqIP = net.IP(p.CIAddr())
|
reqIP = net.IP(p.CIAddr())
|
||||||
@ -105,26 +116,28 @@ func (h *Handler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options d
|
|||||||
|
|
||||||
switch msgType {
|
switch msgType {
|
||||||
case dhcp4.Discover:
|
case dhcp4.Discover:
|
||||||
// Find previous lease for this HardwareAddr, if any
|
|
||||||
// hwAddr := p.CHAddr().String()
|
|
||||||
// if lease, ok := h.leases[hwAddr]; ok {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
free := -1
|
free := -1
|
||||||
|
hwAddr := p.CHAddr().String()
|
||||||
|
|
||||||
|
// try to offer the requested IP, if any and available
|
||||||
if !bytes.Equal(reqIP.To4(), net.IPv4zero) {
|
if !bytes.Equal(reqIP.To4(), net.IPv4zero) {
|
||||||
free = h.canLease(reqIP, p.CHAddr().String())
|
free = h.canLease(reqIP, hwAddr)
|
||||||
log.Printf("canLease: %v", free)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// offer previous lease for this HardwareAddr, if any
|
||||||
|
if lease, ok := h.leasesHW[hwAddr]; ok {
|
||||||
|
free = lease.Num
|
||||||
|
}
|
||||||
|
|
||||||
if free == -1 {
|
if free == -1 {
|
||||||
free = h.findLease()
|
free = h.findLease()
|
||||||
}
|
}
|
||||||
|
|
||||||
if free == -1 {
|
if free == -1 {
|
||||||
log.Printf("Cannot reply with DHCPOFFER: no more leases available")
|
log.Printf("Cannot reply with DHCPOFFER: no more leases available")
|
||||||
return nil // no free leases
|
return nil // no free leases
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("start = %v, free = %v", h.start, free)
|
|
||||||
return dhcp4.ReplyPacket(p,
|
return dhcp4.ReplyPacket(p,
|
||||||
dhcp4.Offer,
|
dhcp4.Offer,
|
||||||
h.serverIP,
|
h.serverIP,
|
||||||
@ -143,11 +156,18 @@ func (h *Handler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options d
|
|||||||
}
|
}
|
||||||
|
|
||||||
lease := &Lease{
|
lease := &Lease{
|
||||||
|
Num: leaseNum,
|
||||||
Addr: reqIP,
|
Addr: reqIP,
|
||||||
HardwareAddr: p.CHAddr().String(),
|
HardwareAddr: p.CHAddr().String(),
|
||||||
Expiry: time.Now().Add(h.leasePeriod),
|
Expiry: time.Now().Add(h.leasePeriod),
|
||||||
Hostname: string(options[dhcp4.OptionHostName]),
|
Hostname: string(options[dhcp4.OptionHostName]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release any old leases for this client
|
||||||
|
if l, ok := h.leasesHW[lease.HardwareAddr]; ok {
|
||||||
|
delete(h.leasesIP, l.Num)
|
||||||
|
}
|
||||||
|
|
||||||
h.leasesIP[leaseNum] = lease
|
h.leasesIP[leaseNum] = lease
|
||||||
h.leasesHW[lease.HardwareAddr] = lease
|
h.leasesHW[lease.HardwareAddr] = lease
|
||||||
if h.Leases != nil {
|
if h.Leases != nil {
|
||||||
@ -161,7 +181,5 @@ func (h *Handler) ServeDHCP(p dhcp4.Packet, msgType dhcp4.MessageType, options d
|
|||||||
h.options.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]))
|
h.options.SelectOrderOrAll(options[dhcp4.OptionParameterRequestList]))
|
||||||
|
|
||||||
}
|
}
|
||||||
// 1970/01/01 01:00:04 got DHCP packet: [1 1 6 0 142 216 238 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 164 76 200 233 19 71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 99 130 83 99 53 1 3 54 4 192 168 42 1 50 4 192 168 42 33 12 3 120 112 115 55 18 1 28 2 3 15 6 119 12 44 47 26 121 42 121 249 33 252 42 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], msgType: Request, options: map[OptionDHCPMessageType:[3] OptionServerIdentifier:[192 168 42 1] OptionHostName:[120 112 115] OptionParameterRequestList:[1 28 2 3 15 6 119 12 44 47 26 121 42 121 249 33 252 42] OptionRequestedIPAddress:[192 168 42 33]]
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,30 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/krolaw/dhcp4"
|
"github.com/krolaw/dhcp4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func packet(mt dhcp4.MessageType, addr net.IP, hwaddr net.HardwareAddr, opts []dhcp4.Option) dhcp4.Packet {
|
||||||
|
return dhcp4.RequestPacket(
|
||||||
|
mt,
|
||||||
|
hwaddr, // MAC address
|
||||||
|
addr, // requested IP address
|
||||||
|
[]byte{0xaa, 0xbb, 0xcc, 0xdd}, // transaction ID
|
||||||
|
false, // broadcast,
|
||||||
|
opts,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func request(addr net.IP, hwaddr net.HardwareAddr, opts ...dhcp4.Option) dhcp4.Packet {
|
||||||
|
return packet(dhcp4.Request, addr, hwaddr, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func discover(addr net.IP, hwaddr net.HardwareAddr, opts ...dhcp4.Option) dhcp4.Packet {
|
||||||
|
return packet(dhcp4.Discover, addr, hwaddr, opts)
|
||||||
|
}
|
||||||
|
|
||||||
const goldenInterfaces = `
|
const goldenInterfaces = `
|
||||||
{
|
{
|
||||||
"interfaces":[
|
"interfaces":[
|
||||||
@ -27,24 +47,29 @@ const goldenInterfaces = `
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
func TestLease(t *testing.T) {
|
func testHandler(t *testing.T) (_ *Handler, cleanup func()) {
|
||||||
tmpdir, err := ioutil.TempDir("", "dhcp4dtest")
|
tmpdir, err := ioutil.TempDir("", "dhcp4dtest")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpdir)
|
|
||||||
if err := ioutil.WriteFile(filepath.Join(tmpdir, "interfaces.json"), []byte(goldenInterfaces), 0644); err != nil {
|
if err := ioutil.WriteFile(filepath.Join(tmpdir, "interfaces.json"), []byte(goldenInterfaces), 0644); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
handler, err := NewHandler(tmpdir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return handler, func() { os.RemoveAll(tmpdir) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLease(t *testing.T) {
|
||||||
|
handler, cleanup := testHandler(t)
|
||||||
|
defer cleanup()
|
||||||
var (
|
var (
|
||||||
addr = net.IP{192, 168, 42, 23}
|
addr = net.IP{192, 168, 42, 23}
|
||||||
hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
||||||
hostname = "xps"
|
hostname = "xps"
|
||||||
)
|
)
|
||||||
handler, err := NewHandler(tmpdir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
leasedCalled := false
|
leasedCalled := false
|
||||||
handler.Leases = func(leases []*Lease) {
|
handler.Leases = func(leases []*Lease) {
|
||||||
if got, want := len(leases), 1; got != want {
|
if got, want := len(leases), 1; got != want {
|
||||||
@ -82,38 +107,17 @@ func TestLease(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPreferredAddress(t *testing.T) {
|
func TestPreferredAddress(t *testing.T) {
|
||||||
tmpdir, err := ioutil.TempDir("", "dhcp4dtest")
|
handler, cleanup := testHandler(t)
|
||||||
if err != nil {
|
defer cleanup()
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tmpdir)
|
|
||||||
if err := ioutil.WriteFile(filepath.Join(tmpdir, "interfaces.json"), []byte(goldenInterfaces), 0644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
addr = net.IP{192, 168, 42, 23}
|
addr = net.IP{192, 168, 42, 23}
|
||||||
hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
||||||
hostname = "xps"
|
hostname = "xps"
|
||||||
)
|
)
|
||||||
handler, err := NewHandler(tmpdir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("no requested IP", func(t *testing.T) {
|
t.Run("no requested IP", func(t *testing.T) {
|
||||||
p := dhcp4.RequestPacket(
|
p := request(net.IPv4zero, hardwareAddr)
|
||||||
dhcp4.Discover,
|
|
||||||
hardwareAddr, // MAC address
|
|
||||||
net.IPv4zero, // requested IP address
|
|
||||||
[]byte{0xaa, 0xbb, 0xcc, 0xdd}, // transaction ID
|
|
||||||
false, // broadcast,
|
|
||||||
[]dhcp4.Option{
|
|
||||||
{
|
|
||||||
Code: dhcp4.OptionHostName,
|
|
||||||
Value: []byte(hostname),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
resp := handler.ServeDHCP(p, dhcp4.Discover, p.ParseOptions())
|
resp := handler.ServeDHCP(p, dhcp4.Discover, p.ParseOptions())
|
||||||
if got, want := resp.YIAddr().To4(), addr.To4(); bytes.Equal(got, want) {
|
if got, want := resp.YIAddr().To4(), addr.To4(); bytes.Equal(got, want) {
|
||||||
t.Errorf("DHCPOFFER for wrong IP: got %v, want %v", got, want)
|
t.Errorf("DHCPOFFER for wrong IP: got %v, want %v", got, want)
|
||||||
@ -121,19 +125,7 @@ func TestPreferredAddress(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("requested CIAddr", func(t *testing.T) {
|
t.Run("requested CIAddr", func(t *testing.T) {
|
||||||
p := dhcp4.RequestPacket(
|
p := request(addr, hardwareAddr)
|
||||||
dhcp4.Discover,
|
|
||||||
hardwareAddr, // MAC address
|
|
||||||
addr, // requested IP address
|
|
||||||
[]byte{0xaa, 0xbb, 0xcc, 0xdd}, // transaction ID
|
|
||||||
false, // broadcast,
|
|
||||||
[]dhcp4.Option{
|
|
||||||
{
|
|
||||||
Code: dhcp4.OptionHostName,
|
|
||||||
Value: []byte(hostname),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
resp := handler.ServeDHCP(p, dhcp4.Discover, p.ParseOptions())
|
resp := handler.ServeDHCP(p, dhcp4.Discover, p.ParseOptions())
|
||||||
if got, want := resp.YIAddr().To4(), addr.To4(); !bytes.Equal(got, want) {
|
if got, want := resp.YIAddr().To4(), addr.To4(); !bytes.Equal(got, want) {
|
||||||
t.Errorf("DHCPOFFER for wrong IP: got %v, want %v", got, want)
|
t.Errorf("DHCPOFFER for wrong IP: got %v, want %v", got, want)
|
||||||
@ -141,6 +133,7 @@ func TestPreferredAddress(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("requested option", func(t *testing.T) {
|
t.Run("requested option", func(t *testing.T) {
|
||||||
|
//p := request(net.IPv4zero, hardwareAddr)
|
||||||
p := dhcp4.RequestPacket(
|
p := dhcp4.RequestPacket(
|
||||||
dhcp4.Discover,
|
dhcp4.Discover,
|
||||||
hardwareAddr, // MAC address
|
hardwareAddr, // MAC address
|
||||||
@ -164,3 +157,163 @@ func TestPreferredAddress(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPoolBoundaries(t *testing.T) {
|
||||||
|
handler, cleanup := testHandler(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
var (
|
||||||
|
addr = net.IP{192, 168, 42, 23}
|
||||||
|
hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, last := range []byte{1, 202} {
|
||||||
|
addr[len(addr)-1] = last
|
||||||
|
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 TestPreviousLease(t *testing.T) {
|
||||||
|
handler, cleanup := testHandler(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
var (
|
||||||
|
addr1 = net.IP{192, 168, 42, 23}
|
||||||
|
addr2 = net.IP{192, 168, 42, 42}
|
||||||
|
hardwareAddr1 = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
||||||
|
hardwareAddr2 = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x77}
|
||||||
|
)
|
||||||
|
|
||||||
|
p := request(addr1, hardwareAddr1)
|
||||||
|
resp := handler.ServeDHCP(p, dhcp4.Request, p.ParseOptions())
|
||||||
|
if got, want := resp.YIAddr().To4(), addr1.To4(); !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("DHCPREQUEST resulted in wrong IP: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
p = request(addr1, hardwareAddr2)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
p = discover(net.IPv4zero, hardwareAddr1)
|
||||||
|
resp = handler.ServeDHCP(p, dhcp4.Discover, p.ParseOptions())
|
||||||
|
if got, want := resp.YIAddr().To4(), addr1.To4(); !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("DHCPOFFER for wrong IP: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free addr1 by requesting addr2
|
||||||
|
p = request(addr2, hardwareAddr1)
|
||||||
|
resp = handler.ServeDHCP(p, dhcp4.Request, p.ParseOptions())
|
||||||
|
if got, want := resp.YIAddr().To4(), addr2.To4(); !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("DHCPREQUEST resulted in wrong IP: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify addr1 is now available to other clients
|
||||||
|
p = request(addr1, hardwareAddr2)
|
||||||
|
resp = handler.ServeDHCP(p, dhcp4.Request, p.ParseOptions())
|
||||||
|
if got, want := resp.YIAddr().To4(), addr1.To4(); !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("DHCPREQUEST resulted in wrong IP: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpiration(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}
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Run("allocate entire pool", func(t *testing.T) {
|
||||||
|
// 1 is the DHCP server,
|
||||||
|
for i := 1; i < 1+200; i++ {
|
||||||
|
addr[len(addr)-1] = byte(1 + (i % 254)) // avoid .0 (net) and .255 (broadcast)
|
||||||
|
hardwareAddr[len(hardwareAddr)-1] = addr[len(addr)-1]
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("re-allocate", func(t *testing.T) {
|
||||||
|
// 1 is the DHCP server,
|
||||||
|
for i := 1; i < 1+200; i++ {
|
||||||
|
addr[len(addr)-1] = byte(1 + (i % 254)) // avoid .0 (net) and .255 (broadcast)
|
||||||
|
hardwareAddr[len(hardwareAddr)-1] = addr[len(addr)-1]
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("full", func(t *testing.T) {
|
||||||
|
// 1 is the DHCP server,
|
||||||
|
for i := 1; i < 1+200; i++ {
|
||||||
|
addr[len(addr)-1] = byte(1 + (i % 254)) // avoid .0 (net) and .255 (broadcast)
|
||||||
|
hardwareAddr[len(hardwareAddr)-1] = addr[len(addr)-1] - 1
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hardwareAddr[len(hardwareAddr)-1] = 0
|
||||||
|
p := discover(addr, hardwareAddr)
|
||||||
|
resp := handler.ServeDHCP(p, dhcp4.Discover, p.ParseOptions())
|
||||||
|
if resp != nil {
|
||||||
|
t.Errorf("DHCPDISCOVER(%v) resulted in unexpected offer of %v", addr, resp.YIAddr())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
now = now.Add(3 * time.Hour)
|
||||||
|
|
||||||
|
t.Run("re-allocate after expiration", func(t *testing.T) {
|
||||||
|
// 1 is the DHCP server,
|
||||||
|
for i := 1; i < 1+200; i++ {
|
||||||
|
addr[len(addr)-1] = byte(1 + (i % 254)) // avoid .0 (net) and .255 (broadcast)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerID(t *testing.T) {
|
||||||
|
handler, cleanup := testHandler(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
var (
|
||||||
|
addr = net.IP{192, 168, 42, 23}
|
||||||
|
hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}
|
||||||
|
)
|
||||||
|
|
||||||
|
p := request(addr, hardwareAddr, dhcp4.Option{
|
||||||
|
Code: dhcp4.OptionServerIdentifier,
|
||||||
|
Value: net.IP{192, 168, 1, 1},
|
||||||
|
})
|
||||||
|
resp := handler.ServeDHCP(p, dhcp4.Request, p.ParseOptions())
|
||||||
|
if resp != nil {
|
||||||
|
t.Errorf("DHCPDISCOVER(%v) resulted in unexpected offer of %v", addr, resp.YIAddr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test persistent storage
|
||||||
|
Loading…
x
Reference in New Issue
Block a user