working offers
This commit is contained in:
19
leases/BUILD.bazel
Normal file
19
leases/BUILD.bazel
Normal file
@@ -0,0 +1,19 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "leases",
|
||||
srcs = [
|
||||
"hardware_address.go",
|
||||
"lease_info.go",
|
||||
"server_info.go",
|
||||
],
|
||||
importpath = "git.wntrmute.dev/kyle/kdhcp/leases",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "leases_test",
|
||||
size = "small",
|
||||
srcs = ["hardware_address_test.go"],
|
||||
embed = [":leases"],
|
||||
)
|
||||
41
leases/hardware_address.go
Normal file
41
leases/hardware_address.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package leases
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type HardwareAddress []byte
|
||||
|
||||
func (mac HardwareAddress) String() string {
|
||||
marshalled := []string{}
|
||||
for i := 0; i < len(mac); i++ {
|
||||
marshalled = append(marshalled, fmt.Sprintf("%02x", []byte(mac[i:i+1])))
|
||||
}
|
||||
|
||||
return strings.Join(marshalled, ":")
|
||||
}
|
||||
|
||||
func (mac HardwareAddress) MarshalText() ([]byte, error) {
|
||||
return []byte(mac.String()), nil
|
||||
}
|
||||
|
||||
func (mac *HardwareAddress) UnmarshalText(b []byte) error {
|
||||
rb := bytes.Split(b, []byte(":"))
|
||||
for _, octet := range rb {
|
||||
n, err := strconv.ParseUint(string(octet), 16, 8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*mac = append(*mac, uint8(n))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mac HardwareAddress) Match(other HardwareAddress) bool {
|
||||
return bytes.Equal(mac, other)
|
||||
}
|
||||
31
leases/hardware_address_test.go
Normal file
31
leases/hardware_address_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package leases
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHardwareMacMarshalling(t *testing.T) {
|
||||
macString := "b8:27:eb:b6:a1:a7"
|
||||
mac := HardwareAddress([]byte{0xb8, 0x27, 0xeb, 0xb6, 0xa1, 0xa7})
|
||||
|
||||
b, err := mac.MarshalText()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := string(b)
|
||||
if s != macString {
|
||||
t.Fatalf("have %s, want %s", s, macString)
|
||||
}
|
||||
|
||||
mac2 := &HardwareAddress{}
|
||||
err = mac2.UnmarshalText(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(*mac2, mac) {
|
||||
t.Fatalf("have %x, want %x", *mac2, mac)
|
||||
}
|
||||
}
|
||||
73
leases/lease_info.go
Normal file
73
leases/lease_info.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package leases
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Info struct {
|
||||
HostName string `yaml:"hostname" json:"hostname,omitempty"`
|
||||
Addr netip.Addr `yaml:"addr" json:"addr,omitempty"`
|
||||
HardwareAddress HardwareAddress `yaml:"mac_addr" json:"hardware_address,omitempty"`
|
||||
Expires time.Time `yaml:"expires" json:"expires,omitempty"`
|
||||
}
|
||||
|
||||
func (li *Info) String() string {
|
||||
return fmt.Sprintf("lease[hostname=%s addr=%s hw=%s expires=%s]", li.HostName, li.Addr, li.HardwareAddress, li.Expires)
|
||||
}
|
||||
|
||||
type sortableLease []*Info
|
||||
|
||||
func (a sortableLease) Len() int { return len(a) }
|
||||
func (a sortableLease) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a sortableLease) Less(i, j int) bool { return a[i].Addr.Less(a[j].Addr) }
|
||||
|
||||
func (li *Info) ResetExpiry(t time.Time, dur time.Duration) {
|
||||
li.Expires = t.Add(dur)
|
||||
}
|
||||
|
||||
func (li *Info) IsExpired(t time.Time) bool {
|
||||
return t.After(li.Expires)
|
||||
}
|
||||
|
||||
func (li *Info) Expire() {
|
||||
li.Expires = time.Time{}
|
||||
}
|
||||
|
||||
func Sort(leases []*Info) []*Info {
|
||||
sortable := sortableLease(leases)
|
||||
sort.Sort(sortable)
|
||||
|
||||
return []*Info(sortable)
|
||||
}
|
||||
|
||||
func (lease *Info) Reset() *Info {
|
||||
lease.Expires = time.Time{}
|
||||
lease.HardwareAddress = nil
|
||||
return lease
|
||||
}
|
||||
|
||||
func (lease Info) Compare(other Info) error {
|
||||
susFields := []string{}
|
||||
|
||||
if lease.Addr != other.Addr {
|
||||
susFields = append(susFields, fmt.Sprintf("address is %s, but is recorded as %s", lease.Addr, other.Addr))
|
||||
}
|
||||
|
||||
if !lease.HardwareAddress.Match(other.HardwareAddress) {
|
||||
susFields = append(susFields, fmt.Sprintf("hardware address is %s, but is recorded as %s", lease.HardwareAddress, other.HardwareAddress))
|
||||
}
|
||||
|
||||
if lease.HostName != other.HostName {
|
||||
susFields = append(susFields, fmt.Sprintf("hostname is %s, but is recorded as %s", lease.HostName, other.HostName))
|
||||
}
|
||||
|
||||
if len(susFields) > 0 {
|
||||
return fmt.Errorf("suspicious lease: %s", strings.Join(susFields, ";"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
17
leases/server_info.go
Normal file
17
leases/server_info.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package leases
|
||||
|
||||
import "net/netip"
|
||||
|
||||
type Server struct {
|
||||
Addr netip.Addr
|
||||
HardwareAddress HardwareAddress
|
||||
Network *Network
|
||||
}
|
||||
|
||||
type Network struct {
|
||||
Mask netip.Addr
|
||||
Gateway netip.Addr
|
||||
Broadcast netip.Addr
|
||||
Domain string
|
||||
DNS []netip.Addr
|
||||
}
|
||||
Reference in New Issue
Block a user