|
|
|
|
@@ -6,7 +6,7 @@ import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
|
|
|
|
|
log "git.wntrmute.dev/kyle/goutils/syslog"
|
|
|
|
|
log "git.wntrmute.dev/kyle/goutils/log"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var optionRegistry = map[OptionTag]Option{
|
|
|
|
|
@@ -14,6 +14,7 @@ var optionRegistry = map[OptionTag]Option{
|
|
|
|
|
OptionTagHostName: OptionHostName,
|
|
|
|
|
OptionTagMessageType: OptionMessageType,
|
|
|
|
|
OptionTagParameterRequestList: OptionParameterRequestList,
|
|
|
|
|
OptionTagClientID: OptionClientID,
|
|
|
|
|
OptionTagEnd: OptionEnd,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -22,6 +23,19 @@ func OptionPad(req *BootRequest, r io.Reader) error {
|
|
|
|
|
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.
|
|
|
|
|
//
|
|
|
|
|
// 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.
|
|
|
|
|
func OptionHostName(req *BootRequest, r io.Reader) error {
|
|
|
|
|
read := newPacketReaderFunc(r)
|
|
|
|
|
|
|
|
|
|
var length uint8
|
|
|
|
|
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")
|
|
|
|
|
length, err := getOptionLength(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 {
|
|
|
|
|
read := newPacketReaderFunc(r)
|
|
|
|
|
|
|
|
|
|
var length uint8
|
|
|
|
|
if err := read(&length); err != nil {
|
|
|
|
|
return fmt.Errorf("dhcp: reading option length for DHCP Message Type")
|
|
|
|
|
if length, err := getOptionLength(r); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
} else if length != 1 {
|
|
|
|
|
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 {
|
|
|
|
|
read := newPacketReaderFunc(r)
|
|
|
|
|
|
|
|
|
|
var length uint8
|
|
|
|
|
if err := read(&length); err != nil {
|
|
|
|
|
return fmt.Errorf("dhcp: reading option length for DHCP Message Type")
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
@@ -96,6 +103,25 @@ func OptionParameterRequestList(req *BootRequest, r io.Reader) error {
|
|
|
|
|
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 {
|
|
|
|
|
req.endOptions = true
|
|
|
|
|
return nil
|
|
|
|
|
@@ -108,7 +134,27 @@ func ReadOption(req *BootRequest, tag byte, r io.Reader) error {
|
|
|
|
|
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
|
|
|
|
|
|