package dhcp4d import ( "bytes" "io/ioutil" "net" "os" "path/filepath" "testing" "github.com/krolaw/dhcp4" ) const goldenInterfaces = ` { "interfaces":[ { "hardware_addr": "02:73:53:00:ca:fe", "name": "uplink0" }, { "hardware_addr": "02:73:53:00:b0:0c", "name": "lan0", "addr": "192.168.42.1/24" } ] } ` func TestLease(t *testing.T) { tmpdir, err := ioutil.TempDir("", "dhcp4dtest") if err != nil { 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 ( addr = net.IP{192, 168, 42, 23} hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66} hostname = "xps" ) handler, err := NewHandler(tmpdir) if err != nil { t.Fatal(err) } leasedCalled := false handler.Leases = func(leases []*Lease) { if got, want := len(leases), 1; got != want { t.Fatalf("unexpected number of leases: got %d, want %d", got, want) } l := leases[0] if got, want := l.Addr, addr; !bytes.Equal(got, want) { t.Fatalf("unexpected lease.Addr: got %v, want %v", got, want) } if got, want := l.HardwareAddr, hardwareAddr.String(); got != want { t.Fatalf("unexpected lease.HardwareAddr: got %q, want %q", got, want) } if got, want := l.Hostname, hostname; got != want { t.Fatalf("unexpected lease.Hostname: got %q, want %q", got, want) } leasedCalled = true } p := dhcp4.RequestPacket( dhcp4.Request, hardwareAddr, // MAC address addr, // requested IP address []byte{0xaa, 0xbb, 0xcc, 0xdd}, // transaction ID false, // broadcast, []dhcp4.Option{ { Code: dhcp4.OptionHostName, Value: []byte(hostname), }, }, ) handler.ServeDHCP(p, dhcp4.Request, p.ParseOptions()) if !leasedCalled { t.Fatalf("leased callback not called") } } func TestPreferredAddress(t *testing.T) { tmpdir, err := ioutil.TempDir("", "dhcp4dtest") if err != nil { 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 ( addr = net.IP{192, 168, 42, 23} hardwareAddr = net.HardwareAddr{0x11, 0x22, 0x33, 0x44, 0x55, 0x66} hostname = "xps" ) handler, err := NewHandler(tmpdir) if err != nil { t.Fatal(err) } t.Run("no requested IP", func(t *testing.T) { p := dhcp4.RequestPacket( 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()) 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.Run("requested CIAddr", func(t *testing.T) { p := dhcp4.RequestPacket( 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()) 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.Run("requested option", func(t *testing.T) { p := dhcp4.RequestPacket( 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), }, { Code: dhcp4.OptionRequestedIPAddress, Value: addr, }, }, ) 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) } }) }