dhcp reads done, moving on to offers

This commit is contained in:
Kyle Isom 2023-05-09 07:28:54 +00:00
parent 6ba2bf3911
commit f66fbc0f6c
20 changed files with 196 additions and 58 deletions

View File

@ -9,7 +9,7 @@ go_library(
"//config", "//config",
"//server", "//server",
"@com_github_peterbourgon_ff_v3//ffcli", "@com_github_peterbourgon_ff_v3//ffcli",
"@dev_wntrmute_git_kyle_goutils//syslog", "@dev_wntrmute_git_kyle_goutils//log",
], ],
) )

View File

@ -6,7 +6,7 @@ import (
"os" "os"
"strings" "strings"
log "git.wntrmute.dev/kyle/goutils/syslog" "git.wntrmute.dev/kyle/goutils/log"
"git.wntrmute.dev/kyle/kdhcp/config" "git.wntrmute.dev/kyle/kdhcp/config"
"git.wntrmute.dev/kyle/kdhcp/server" "git.wntrmute.dev/kyle/kdhcp/server"
"github.com/peterbourgon/ff/v3/ffcli" "github.com/peterbourgon/ff/v3/ffcli"

View File

@ -10,7 +10,7 @@ go_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//iptools", "//iptools",
"@dev_wntrmute_git_kyle_goutils//syslog", "@dev_wntrmute_git_kyle_goutils//log",
"@in_gopkg_yaml_v2//:yaml_v2", "@in_gopkg_yaml_v2//:yaml_v2",
], ],
) )

View File

@ -6,7 +6,7 @@ import (
"io/ioutil" "io/ioutil"
"net" "net"
log "git.wntrmute.dev/kyle/goutils/syslog" log "git.wntrmute.dev/kyle/goutils/log"
"git.wntrmute.dev/kyle/kdhcp/iptools" "git.wntrmute.dev/kyle/kdhcp/iptools"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )

View File

@ -5,7 +5,7 @@ import (
"os/user" "os/user"
"path/filepath" "path/filepath"
log "git.wntrmute.dev/kyle/goutils/syslog" log "git.wntrmute.dev/kyle/goutils/log"
) )
func FindConfigPath() string { func FindConfigPath() string {

View File

@ -1,6 +1,13 @@
load("@bazel_gazelle//:deps.bzl", "go_repository") load("@bazel_gazelle//:deps.bzl", "go_repository")
def go_dependencies(): def go_dependencies():
go_repository(
name = "com_github_benbjohnson_clock",
importpath = "github.com/benbjohnson/clock",
sum = "h1:g+rSsSaAzhHJYcIQE78hJ3AhyjjtQvleKDjlhdBnIhc=",
version = "v1.3.3",
)
go_repository( go_repository(
name = "com_github_cloudflare_cfssl", name = "com_github_cloudflare_cfssl",
importpath = "github.com/cloudflare/cfssl", importpath = "github.com/cloudflare/cfssl",
@ -14,12 +21,32 @@ def go_dependencies():
sum = "h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=", sum = "h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=",
version = "v1.1.1", version = "v1.1.1",
) )
go_repository(
name = "com_github_google_certificate_transparency_go",
importpath = "github.com/google/certificate-transparency-go",
sum = "h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE=",
version = "v1.0.21",
)
go_repository( go_repository(
name = "com_github_hashicorp_go_syslog", name = "com_github_hashicorp_go_syslog",
importpath = "github.com/hashicorp/go-syslog", importpath = "github.com/hashicorp/go-syslog",
sum = "h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=", sum = "h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=",
version = "v1.0.0", version = "v1.0.0",
) )
go_repository(
name = "com_github_kr_fs",
importpath = "github.com/kr/fs",
sum = "h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=",
version = "v0.1.0",
)
go_repository(
name = "com_github_kr_pretty",
importpath = "github.com/kr/pretty",
sum = "h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=",
version = "v0.1.0",
)
go_repository( go_repository(
name = "com_github_kr_text", name = "com_github_kr_text",
importpath = "github.com/kr/text", importpath = "github.com/kr/text",
@ -51,6 +78,13 @@ def go_dependencies():
sum = "h1:/f3b24xrDhkhddlaobPe2JgBqfdt+gC/NYl0QY9IOuI=", sum = "h1:/f3b24xrDhkhddlaobPe2JgBqfdt+gC/NYl0QY9IOuI=",
version = "v1.12.0", version = "v1.12.0",
) )
go_repository(
name = "com_github_pmezard_go_difflib",
importpath = "github.com/pmezard/go-difflib",
sum = "h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=",
version = "v1.0.0",
)
go_repository( go_repository(
name = "com_github_stretchr_testify", name = "com_github_stretchr_testify",
importpath = "github.com/stretchr/testify", importpath = "github.com/stretchr/testify",
@ -60,15 +94,15 @@ def go_dependencies():
go_repository( go_repository(
name = "dev_wntrmute_git_kyle_goutils", name = "dev_wntrmute_git_kyle_goutils",
importpath = "git.wntrmute.dev/kyle/goutils", importpath = "git.wntrmute.dev/kyle/goutils",
sum = "h1:CRCBlmSXOTkShbqC6j9lgxh4lb+khzc2zpIJYGQJtnc=", sum = "h1:+lk6uUMcpJK49sEGEMCOns3WVd2ThH/htMWnsyXEGl8=",
version = "v1.6.6", version = "v1.7.0",
) )
go_repository( go_repository(
name = "in_gopkg_check_v1", name = "in_gopkg_check_v1",
importpath = "gopkg.in/check.v1", importpath = "gopkg.in/check.v1",
sum = "h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=", sum = "h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=",
version = "v0.0.0-20161208181325-20d25e280405", version = "v1.0.0-20180628173108-788fd7840127",
) )
go_repository( go_repository(
name = "in_gopkg_yaml_v2", name = "in_gopkg_yaml_v2",
@ -76,6 +110,13 @@ def go_dependencies():
sum = "h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=", sum = "h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=",
version = "v2.4.0", version = "v2.4.0",
) )
go_repository(
name = "in_gopkg_yaml_v3",
importpath = "gopkg.in/yaml.v3",
sum = "h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=",
version = "v3.0.0-20200313102051-9f266ea9e77c",
)
go_repository( go_repository(
name = "org_golang_x_crypto", name = "org_golang_x_crypto",
importpath = "golang.org/x/crypto", importpath = "golang.org/x/crypto",

View File

@ -9,5 +9,5 @@ go_library(
], ],
importpath = "git.wntrmute.dev/kyle/kdhcp/dhcp", importpath = "git.wntrmute.dev/kyle/kdhcp/dhcp",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = ["@dev_wntrmute_git_kyle_goutils//syslog"], deps = ["@dev_wntrmute_git_kyle_goutils//log"],
) )

View File

@ -33,6 +33,8 @@ const (
OptionTagNBScope OptionTag = 47 OptionTagNBScope OptionTag = 47
OptionTagMessageType OptionTag = 53 OptionTagMessageType OptionTag = 53
OptionTagParameterRequestList OptionTag = 55 OptionTagParameterRequestList OptionTag = 55
OptionTagDHCPMaxMessageSize OptionTag = 57
OptionTagClientID OptionTag = 61
OptionTagDomainSearch OptionTag = 119 OptionTagDomainSearch OptionTag = 119
OptionTagClasslessStaticRoute OptionTag = 121 OptionTagClasslessStaticRoute OptionTag = 121
OptionTagEnd OptionTag = 255 OptionTagEnd OptionTag = 255
@ -53,6 +55,8 @@ var optionStrings = map[OptionTag]string{
OptionTagNBScope: "NetBIOS scope", OptionTagNBScope: "NetBIOS scope",
OptionTagMessageType: "message type", OptionTagMessageType: "message type",
OptionTagParameterRequestList: "parameter request list", OptionTagParameterRequestList: "parameter request list",
OptionTagDHCPMaxMessageSize: "DHCP max message size",
OptionTagClientID: "client ID",
OptionTagDomainSearch: "search domain", OptionTagDomainSearch: "search domain",
OptionTagClasslessStaticRoute: "classless static route", OptionTagClasslessStaticRoute: "classless static route",
OptionTagEnd: "end", OptionTagEnd: "end",

View File

@ -8,7 +8,7 @@ import (
"net" "net"
"strings" "strings"
log "git.wntrmute.dev/kyle/goutils/syslog" log "git.wntrmute.dev/kyle/goutils/log"
) )
const ( const (
@ -46,6 +46,7 @@ type BootRequest struct {
DHCPType DHCPMessageType // option 53 DHCPType DHCPMessageType // option 53
HostName string // option 12 HostName string // option 12
ClientID string // option 61
ParameterRequests []OptionTag ParameterRequests []OptionTag
endOptions bool endOptions bool
} }

View File

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
log "git.wntrmute.dev/kyle/goutils/syslog" log "git.wntrmute.dev/kyle/goutils/log"
) )
var optionRegistry = map[OptionTag]Option{ var optionRegistry = map[OptionTag]Option{
@ -14,6 +14,7 @@ var optionRegistry = map[OptionTag]Option{
OptionTagHostName: OptionHostName, OptionTagHostName: OptionHostName,
OptionTagMessageType: OptionMessageType, OptionTagMessageType: OptionMessageType,
OptionTagParameterRequestList: OptionParameterRequestList, OptionTagParameterRequestList: OptionParameterRequestList,
OptionTagClientID: OptionClientID,
OptionTagEnd: OptionEnd, OptionTagEnd: OptionEnd,
} }
@ -22,6 +23,19 @@ func OptionPad(req *BootRequest, r io.Reader) error {
return nil return nil
} }
func getOptionLength(r io.Reader) (int, error) {
var length uint8
read := newPacketReaderFunc(r)
if err := read(&length); err != nil {
return -1, fmt.Errorf("dhcp: reading option length for DHCP Message Type")
} else if length == 0 {
return -1, errors.New("dhcp: read option length 0, but expected option length for DHCP Host Name is >= 1")
}
return int(length), nil
}
// OptionHostName reads a DHCP host name option. // OptionHostName reads a DHCP host name option.
// //
// 3.14. Host Name Option // 3.14. Host Name Option
@ -33,13 +47,9 @@ func OptionPad(req *BootRequest, r io.Reader) error {
// The code for this option is 12, and its minimum length is 1. // The code for this option is 12, and its minimum length is 1.
func OptionHostName(req *BootRequest, r io.Reader) error { func OptionHostName(req *BootRequest, r io.Reader) error {
read := newPacketReaderFunc(r) length, err := getOptionLength(r)
if err != nil {
var length uint8 return err
if err := read(&length); err != nil {
return fmt.Errorf("dhcp: reading option length for DHCP Message Type")
} else if length == 0 {
return errors.New("dhcp: read option length 0, but expected option length for DHCP Host Name is >= 1")
} }
hostName := make([]byte, int(length)) hostName := make([]byte, int(length))
@ -56,9 +66,8 @@ func OptionHostName(req *BootRequest, r io.Reader) error {
func OptionMessageType(req *BootRequest, r io.Reader) error { func OptionMessageType(req *BootRequest, r io.Reader) error {
read := newPacketReaderFunc(r) read := newPacketReaderFunc(r)
var length uint8 if length, err := getOptionLength(r); err != nil {
if err := read(&length); err != nil { return err
return fmt.Errorf("dhcp: reading option length for DHCP Message Type")
} else if length != 1 { } else if length != 1 {
return fmt.Errorf("dhcp: read option length %d, but expected option length for DHCP Message Type is 1", length) return fmt.Errorf("dhcp: read option length %d, but expected option length for DHCP Message Type is 1", length)
} }
@ -71,11 +80,9 @@ func OptionMessageType(req *BootRequest, r io.Reader) error {
} }
func OptionParameterRequestList(req *BootRequest, r io.Reader) error { func OptionParameterRequestList(req *BootRequest, r io.Reader) error {
read := newPacketReaderFunc(r) length, err := getOptionLength(r)
if err != nil {
var length uint8 return err
if err := read(&length); err != nil {
return fmt.Errorf("dhcp: reading option length for DHCP Message Type")
} else if length == 0 { } else if length == 0 {
return fmt.Errorf("dhcp: read option length %d, but expected option length for DHCP Parameter Request is >= 1", length) return fmt.Errorf("dhcp: read option length %d, but expected option length for DHCP Parameter Request is >= 1", length)
} }
@ -96,6 +103,25 @@ func OptionParameterRequestList(req *BootRequest, r io.Reader) error {
return nil return nil
} }
func OptionClientID(req *BootRequest, r io.Reader) error {
length, err := getOptionLength(r)
if err != nil {
return err
} else if length == 0 {
return fmt.Errorf("dhcp: read option length %d, but expected option length for DHCP Parameter Request is >= 1", length)
}
var clientID = make([]byte, int(length))
if n, err := r.Read(clientID); err != nil {
return fmt.Errorf("dhcp: while reading client ID: %w", err)
} else if n != int(length) {
return fmt.Errorf("dhcp: only read %d bytes of client ID, expected %d bytes", n, length)
}
req.ClientID = string(clientID)
return nil
}
func OptionEnd(req *BootRequest, r io.Reader) error { func OptionEnd(req *BootRequest, r io.Reader) error {
req.endOptions = true req.endOptions = true
return nil return nil
@ -108,7 +134,27 @@ func ReadOption(req *BootRequest, tag byte, r io.Reader) error {
return f(req, r) return f(req, r)
} }
return fmt.Errorf("dhcp: unknown/unhandled option %d", opt) return readUnknownOption(req, tag, r)
}
func readUnknownOption(req *BootRequest, tag byte, r io.Reader) error {
length, err := getOptionLength(r)
if err != nil {
return err
} else if length == 0 {
log.Debugf("skipped option %d/%02x with length 0", tag, tag)
return nil
}
var data = make([]byte, length)
if n, err := r.Read(data); err != nil {
return fmt.Errorf("dhcp: while skipping unknown tag %d/%02x: %w", tag, tag, err)
} else if n != int(length) {
return fmt.Errorf("dhcp: only read %d bytes of unknown tag %d/%02x, expected %d bytes", n, tag, tag, length)
}
log.Infof("skipped unknown tag %d/%02x with data %0x", tag, tag, data)
return nil
} }
const magicCookieLength = 4 const magicCookieLength = 4

10
go.mod
View File

@ -2,12 +2,16 @@ module git.wntrmute.dev/kyle/kdhcp
go 1.20 go 1.20
require github.com/hashicorp/go-syslog v1.0.0 require github.com/hashicorp/go-syslog v1.0.0 // indirect
require ( require (
github.com/davecgh/go-spew v1.1.1
github.com/peterbourgon/ff/v3 v3.3.0 github.com/peterbourgon/ff/v3 v3.3.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )
require git.wntrmute.dev/kyle/goutils v1.6.6 // indirect require github.com/davecgh/go-spew v1.1.1 // indirect
require (
git.wntrmute.dev/kyle/goutils v1.7.0
github.com/benbjohnson/clock v1.3.3
)

10
go.sum
View File

@ -1,12 +1,16 @@
git.wntrmute.dev/kyle/goutils v1.6.6 h1:CRCBlmSXOTkShbqC6j9lgxh4lb+khzc2zpIJYGQJtnc= git.wntrmute.dev/kyle/goutils v1.7.0 h1:+lk6uUMcpJK49sEGEMCOns3WVd2ThH/htMWnsyXEGl8=
git.wntrmute.dev/kyle/goutils v1.6.6/go.mod h1:p0m2YprqMXkqtxTPKCiRcmgYo/D/9DtAIRfNVFE3JBg= git.wntrmute.dev/kyle/goutils v1.7.0/go.mod h1:hMcPr+XSYXjQ/IRTziNVYmUmb9BPATZc+cyehSjBs0w=
github.com/benbjohnson/clock v1.3.3 h1:g+rSsSaAzhHJYcIQE78hJ3AhyjjtQvleKDjlhdBnIhc=
github.com/benbjohnson/clock v1.3.3/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/peterbourgon/ff/v3 v3.3.0 h1:PaKe7GW8orVFh8Unb5jNHS+JZBwWUMa2se0HM6/BI24= github.com/peterbourgon/ff/v3 v3.3.0 h1:PaKe7GW8orVFh8Unb5jNHS+JZBwWUMa2se0HM6/BI24=
github.com/peterbourgon/ff/v3 v3.3.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= github.com/peterbourgon/ff/v3 v3.3.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@ -11,7 +11,10 @@ go_library(
], ],
importpath = "git.wntrmute.dev/kyle/kdhcp/iptools", importpath = "git.wntrmute.dev/kyle/kdhcp/iptools",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = ["@dev_wntrmute_git_kyle_goutils//assert"], deps = [
"@dev_wntrmute_git_kyle_goutils//assert",
"@dev_wntrmute_git_kyle_goutils//log",
],
) )
go_test( go_test(

View File

@ -15,6 +15,10 @@ type LeaseInfo struct {
Expires time.Time `yaml:"expires"` Expires time.Time `yaml:"expires"`
} }
func (li *LeaseInfo) String() string {
return fmt.Sprintf("lease[hostname=%s addr=%s hw=%x expires=%s]", li.HostName, li.Addr, li.HardwareAddress, li.Expires)
}
type sortableLease []*LeaseInfo type sortableLease []*LeaseInfo
func (a sortableLease) Len() int { return len(a) } func (a sortableLease) Len() int { return len(a) }

View File

@ -7,6 +7,7 @@ import (
"time" "time"
"git.wntrmute.dev/kyle/goutils/assert" "git.wntrmute.dev/kyle/goutils/assert"
"git.wntrmute.dev/kyle/goutils/log"
) )
const DefaultExpiry = 168 * time.Hour const DefaultExpiry = 168 * time.Hour
@ -23,7 +24,7 @@ type Pool struct {
} }
func (p *Pool) lock() { func (p *Pool) lock() {
if p.lock == nil { if p.mtx == nil {
p.mtx = &sync.Mutex{} p.mtx = &sync.Mutex{}
} }
@ -48,6 +49,7 @@ func NewPool(name string, r *Range) (*Pool, error) {
Expiry: r.Expiry, Expiry: r.Expiry,
NoHostName: r.NoHostName, NoHostName: r.NoHostName,
Available: enumerateRange(name, r, true), Available: enumerateRange(name, r, true),
Limbo: map[netip.Addr]*LeaseInfo{},
} }
return p, nil return p, nil
@ -114,39 +116,40 @@ func (p *Pool) Accept(addr netip.Addr, t time.Time) error {
// Update checks expirations on leases, moving any expired leases back // Update checks expirations on leases, moving any expired leases back
// to the available pool and removing any limbo leases that are expired. // to the available pool and removing any limbo leases that are expired.
func (p *Pool) Update(t time.Time) { func (p *Pool) Update(t time.Time) bool {
p.lock() p.lock()
defer p.unlock() defer p.unlock()
p.update(t) return p.update(t)
} }
func (p *Pool) update(t time.Time) { func (p *Pool) update(t time.Time) bool {
evictedHosts := []netip.Addr{} var updated bool
for k, v := range p.Active { for k, v := range p.Active {
if v.IsExpired(t) { if v.IsExpired(t) {
evictedHosts = append(evictedHosts, k) updated = true
log.Infof("expiring active address %s for %x", v.Addr, v.HardwareAddress)
delete(p.Active, k)
v = v.Reset() v = v.Reset()
p.Available = append(p.Available, v) p.Available = append(p.Available, v)
} }
} }
for _, ip := range evictedHosts {
delete(p.Active, ip)
}
for k, v := range p.Limbo { for k, v := range p.Limbo {
if v.IsExpired(t) { if v.IsExpired(t) {
updated = true
log.Infof("expiring limbo address %s for %x", v.Addr, v.HardwareAddress)
delete(p.Limbo, k) delete(p.Limbo, k)
v = v.Reset() v = v.Reset()
p.Available = append(p.Available, v) p.Available = append(p.Available, v)
} }
} }
p.Sort() p.sort()
return updated
} }
func (p *Pool) Renew(lease LeaseInfo, t time.Time) { func (p *Pool) Renew(lease *LeaseInfo, t time.Time) {
p.Active[lease.Addr].ResetExpiry(t, p.Expiry)
} }

View File

@ -15,7 +15,8 @@ go_library(
"//config", "//config",
"//dhcp", "//dhcp",
"//iptools", "//iptools",
"@dev_wntrmute_git_kyle_goutils//syslog", "@com_github_benbjohnson_clock//:clock",
"@dev_wntrmute_git_kyle_goutils//log",
"@in_gopkg_yaml_v2//:yaml_v2", "@in_gopkg_yaml_v2//:yaml_v2",
], ],
) )

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
log "git.wntrmute.dev/kyle/goutils/syslog" log "git.wntrmute.dev/kyle/goutils/log"
"git.wntrmute.dev/kyle/kdhcp/iptools" "git.wntrmute.dev/kyle/kdhcp/iptools"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )

View File

@ -3,8 +3,9 @@ package server
import ( import (
"fmt" "fmt"
"net/netip" "net/netip"
"time"
log "git.wntrmute.dev/kyle/goutils/syslog" log "git.wntrmute.dev/kyle/goutils/log"
"git.wntrmute.dev/kyle/kdhcp/iptools" "git.wntrmute.dev/kyle/kdhcp/iptools"
) )
@ -35,3 +36,14 @@ func (srv *Server) loadPoolsFromConfig() error {
return nil return nil
} }
func (srv *Server) updatePoolLoop() {
for {
time.Sleep(time.Minute)
for _, p := range srv.Pools {
if p.Update(srv.clock.Now()) {
log.Debugln("pools updated")
}
}
}
}

View File

@ -5,10 +5,11 @@ import (
"net" "net"
"time" "time"
log "git.wntrmute.dev/kyle/goutils/syslog" log "git.wntrmute.dev/kyle/goutils/log"
"git.wntrmute.dev/kyle/kdhcp/config" "git.wntrmute.dev/kyle/kdhcp/config"
"git.wntrmute.dev/kyle/kdhcp/dhcp" "git.wntrmute.dev/kyle/kdhcp/dhcp"
"git.wntrmute.dev/kyle/kdhcp/iptools" "git.wntrmute.dev/kyle/kdhcp/iptools"
"github.com/benbjohnson/clock"
) )
const ( const (
@ -22,6 +23,8 @@ type Server struct {
Config *config.Config Config *config.Config
Pools map[string]*iptools.Pool Pools map[string]*iptools.Pool
Static map[string]*iptools.LeaseInfo Static map[string]*iptools.LeaseInfo
clock clock.Clock
} }
func (s *Server) Close() error { func (s *Server) Close() error {
@ -62,23 +65,34 @@ func (s *Server) WriteTo(b []byte, addr net.Addr) error {
return errors.New("server: not implemented") return errors.New("server: not implemented")
} }
func (s *Server) AcceptPacket() error { func (s *Server) AcceptPacket() (*dhcp.BootRequest, error) {
request, err := s.ReadDHCPRequest() request, err := s.ReadDHCPRequest()
if err != nil { if err != nil {
return err return nil, err
} }
log.Debugf("BOOTP request received from %x", request.HardwareAddress) log.Debugf("BOOTP request received from %x", request.HardwareAddress)
return nil return request, nil
} }
func (s *Server) Listen() { func (s *Server) Listen() {
go s.updatePoolLoop()
for { for {
if err := s.AcceptPacket(); err != nil { req, err := s.AcceptPacket()
if err != nil {
log.Errf("server: error reading packet: %s", err) log.Errf("server: error reading packet: %s", err)
continue continue
} }
break
lease := s.SelectLease(req, s.clock.Now())
if err != nil {
log.Err("server: couldn't find available lease")
continue
}
log.Infof("available lease: %s", lease)
continue
} }
} }
@ -87,6 +101,7 @@ func New(cfg *config.Config) (*Server, error) {
Config: cfg, Config: cfg,
Pools: map[string]*iptools.Pool{}, Pools: map[string]*iptools.Pool{},
Static: map[string]*iptools.LeaseInfo{}, Static: map[string]*iptools.LeaseInfo{},
clock: clock.New(),
} }
if err := srv.loadPoolsFromConfig(); err != nil { if err := srv.loadPoolsFromConfig(); err != nil {