working offers

This commit is contained in:
2023-05-15 13:09:12 +00:00
parent f4fca2ffd0
commit cec46e68e8
29 changed files with 745 additions and 180 deletions

19
leases/BUILD.bazel Normal file
View 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"],
)

View 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)
}

View 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
View 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
View 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
}