dhcp reads done, moving on to offers
This commit is contained in:
parent
6ba2bf3911
commit
f66fbc0f6c
|
@ -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",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
49
deps.bzl
49
deps.bzl
|
@ -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",
|
||||||
|
|
|
@ -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"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
10
go.mod
|
@ -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
10
go.sum
|
@ -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=
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -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"
|
||||||
)
|
)
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue