summaryrefslogtreecommitdiffhomepage
path: root/dhcpv4/bsdp
diff options
context:
space:
mode:
Diffstat (limited to 'dhcpv4/bsdp')
-rw-r--r--dhcpv4/bsdp/boot_image.go45
-rw-r--r--dhcpv4/bsdp/boot_image_test.go33
-rw-r--r--dhcpv4/bsdp/bsdp.go6
-rw-r--r--dhcpv4/bsdp/bsdp_option_boot_image_list.go34
-rw-r--r--dhcpv4/bsdp/bsdp_option_boot_image_list_test.go38
-rw-r--r--dhcpv4/bsdp/bsdp_option_default_boot_image_id.go23
-rw-r--r--dhcpv4/bsdp/bsdp_option_default_boot_image_id_test.go13
-rw-r--r--dhcpv4/bsdp/bsdp_option_generic.go19
-rw-r--r--dhcpv4/bsdp/bsdp_option_generic_test.go10
-rw-r--r--dhcpv4/bsdp/bsdp_option_machine_name.go19
-rw-r--r--dhcpv4/bsdp/bsdp_option_machine_name_test.go17
-rw-r--r--dhcpv4/bsdp/bsdp_option_message_type.go25
-rw-r--r--dhcpv4/bsdp/bsdp_option_message_type_test.go17
-rw-r--r--dhcpv4/bsdp/bsdp_option_reply_port.go20
-rw-r--r--dhcpv4/bsdp/bsdp_option_reply_port_test.go11
-rw-r--r--dhcpv4/bsdp/bsdp_option_selected_boot_image_id.go23
-rw-r--r--dhcpv4/bsdp/bsdp_option_selected_boot_image_id_test.go12
-rw-r--r--dhcpv4/bsdp/bsdp_option_server_identifier.go18
-rw-r--r--dhcpv4/bsdp/bsdp_option_server_identifier_test.go8
-rw-r--r--dhcpv4/bsdp/bsdp_option_server_priority.go20
-rw-r--r--dhcpv4/bsdp/bsdp_option_server_priority_test.go12
-rw-r--r--dhcpv4/bsdp/bsdp_option_version.go19
-rw-r--r--dhcpv4/bsdp/bsdp_option_version_test.go14
-rw-r--r--dhcpv4/bsdp/option_vendor_specific_information.go62
-rw-r--r--dhcpv4/bsdp/option_vendor_specific_information_test.go20
-rw-r--r--dhcpv4/bsdp/types.go4
26 files changed, 121 insertions, 421 deletions
diff --git a/dhcpv4/bsdp/boot_image.go b/dhcpv4/bsdp/boot_image.go
index 88a9404..fa9b1a6 100644
--- a/dhcpv4/bsdp/boot_image.go
+++ b/dhcpv4/bsdp/boot_image.go
@@ -3,6 +3,8 @@ package bsdp
import (
"encoding/binary"
"fmt"
+
+ "github.com/u-root/u-root/pkg/uio"
)
// BootImageType represents the different BSDP boot image types.
@@ -60,16 +62,14 @@ func (b BootImageID) String() string {
return s + " " + t + " image"
}
-// BootImageIDFromBytes deserializes a collection of 4 bytes to a BootImageID.
-func BootImageIDFromBytes(bytes []byte) (*BootImageID, error) {
- if len(bytes) < 4 {
- return nil, fmt.Errorf("not enough bytes to serialize BootImageID")
- }
- return &BootImageID{
- IsInstall: bytes[0]&0x80 != 0,
- ImageType: BootImageType(bytes[0] & 0x7f),
- Index: binary.BigEndian.Uint16(bytes[2:]),
- }, nil
+// Unmarshal reads b's binary representation from buf.
+func (b *BootImageID) Unmarshal(buf *uio.Lexer) error {
+ byte0 := buf.Read8()
+ _ = buf.Read8()
+ b.IsInstall = byte0&0x80 != 0
+ b.ImageType = BootImageType(byte0 & 0x7f)
+ b.Index = buf.Read16()
+ return buf.Error()
}
// BootImage describes a boot image - contains the boot image ID and the name.
@@ -87,25 +87,16 @@ func (b *BootImage) ToBytes() []byte {
}
// String converts a BootImage to a human-readable representation.
-func (b *BootImage) String() string {
+func (b BootImage) String() string {
return fmt.Sprintf("%v %v", b.Name, b.ID.String())
}
-// BootImageFromBytes returns a deserialized BootImage struct from bytes.
-func BootImageFromBytes(bytes []byte) (*BootImage, error) {
- // Should at least contain 4 bytes of BootImageID + byte for length of
- // boot image name.
- if len(bytes) < 5 {
- return nil, fmt.Errorf("not enough bytes to serialize BootImage")
- }
- imageID, err := BootImageIDFromBytes(bytes[:4])
- if err != nil {
- return nil, err
- }
- nameLength := int(bytes[4])
- if 5+nameLength > len(bytes) {
- return nil, fmt.Errorf("not enough bytes for BootImage")
+// Unmarshal reads data from buf into b.
+func (b *BootImage) Unmarshal(buf *uio.Lexer) error {
+ if err := (&b.ID).Unmarshal(buf); err != nil {
+ return err
}
- name := string(bytes[5 : 5+nameLength])
- return &BootImage{ID: *imageID, Name: name}, nil
+ nameLength := buf.Read8()
+ b.Name = string(buf.Consume(int(nameLength)))
+ return buf.Error()
}
diff --git a/dhcpv4/bsdp/boot_image_test.go b/dhcpv4/bsdp/boot_image_test.go
index 004aa30..d8e3aeb 100644
--- a/dhcpv4/bsdp/boot_image_test.go
+++ b/dhcpv4/bsdp/boot_image_test.go
@@ -4,6 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "github.com/u-root/u-root/pkg/uio"
)
func TestBootImageIDToBytes(t *testing.T) {
@@ -28,25 +29,23 @@ func TestBootImageIDFromBytes(t *testing.T) {
ImageType: BootImageTypeMacOSX,
Index: 0x1000,
}
- newBootImage, err := BootImageIDFromBytes(b.ToBytes())
- require.NoError(t, err)
- require.Equal(t, b, *newBootImage)
+ var newBootImage BootImageID
+ require.NoError(t, uio.FromBigEndian(&newBootImage, b.ToBytes()))
+ require.Equal(t, b, newBootImage)
b = BootImageID{
IsInstall: true,
ImageType: BootImageTypeMacOSX,
Index: 0x1011,
}
- newBootImage, err = BootImageIDFromBytes(b.ToBytes())
- require.NoError(t, err)
- require.Equal(t, b, *newBootImage)
+ require.NoError(t, uio.FromBigEndian(&newBootImage, b.ToBytes()))
+ require.Equal(t, b, newBootImage)
}
func TestBootImageIDFromBytesFail(t *testing.T) {
serialized := []byte{0x81, 0, 0x10} // intentionally left short
- deserialized, err := BootImageIDFromBytes(serialized)
- require.Nil(t, deserialized)
- require.Error(t, err)
+ var deserialized BootImageID
+ require.Error(t, uio.FromBigEndian(&deserialized, serialized))
}
func TestBootImageIDString(t *testing.T) {
@@ -97,8 +96,8 @@ func TestBootImageFromBytes(t *testing.T) {
7, // len(Name)
98, 115, 100, 112, 45, 50, 49, // byte-encoding of Name
}
- b, err := BootImageFromBytes(input)
- require.NoError(t, err)
+ var b BootImage
+ require.NoError(t, uio.FromBigEndian(&b, input))
expectedBootImage := BootImage{
ID: BootImageID{
IsInstall: false,
@@ -107,15 +106,14 @@ func TestBootImageFromBytes(t *testing.T) {
},
Name: "bsdp-21",
}
- require.Equal(t, expectedBootImage, *b)
+ require.Equal(t, expectedBootImage, b)
}
func TestBootImageFromBytesOnlyBootImageID(t *testing.T) {
// Only a BootImageID, nothing else.
input := []byte{0x1, 0, 0x10, 0x10}
- b, err := BootImageFromBytes(input)
- require.Nil(t, b)
- require.Error(t, err)
+ var b BootImage
+ require.Error(t, uio.FromBigEndian(&b, input))
}
func TestBootImageFromBytesShortBootImage(t *testing.T) {
@@ -124,9 +122,8 @@ func TestBootImageFromBytesShortBootImage(t *testing.T) {
7, // len(Name)
98, 115, 100, 112, 45, 50, // Name bytes (intentionally off-by-one)
}
- b, err := BootImageFromBytes(input)
- require.Nil(t, b)
- require.Error(t, err)
+ var b BootImage
+ require.Error(t, uio.FromBigEndian(&b, input))
}
func TestBootImageString(t *testing.T) {
diff --git a/dhcpv4/bsdp/bsdp.go b/dhcpv4/bsdp/bsdp.go
index 3f97602..6bc0cfd 100644
--- a/dhcpv4/bsdp/bsdp.go
+++ b/dhcpv4/bsdp/bsdp.go
@@ -23,7 +23,7 @@ const AppleVendorID = "AAPLBSDPC"
type ReplyConfig struct {
ServerIP net.IP
ServerHostname, BootFileName string
- ServerPriority int
+ ServerPriority uint16
Images []BootImage
DefaultImage, SelectedImage *BootImage
}
@@ -36,7 +36,7 @@ func ParseBootImageListFromAck(ack dhcpv4.DHCPv4) ([]BootImage, error) {
if opt == nil {
return nil, errors.New("ParseBootImageListFromAck: could not find vendor-specific option")
}
- vendorOpt, err := ParseOptVendorSpecificInformation(opt.ToBytes())
+ vendorOpt, err := ParseOptVendorSpecificInformation(opt.ToBytes()[2:])
if err != nil {
return nil, err
}
@@ -60,7 +60,7 @@ func MessageTypeFromPacket(packet *dhcpv4.DHCPv4) *MessageType {
err error
)
for _, opt := range packet.GetOption(dhcpv4.OptionVendorSpecificInformation) {
- if vendorOpts, err = ParseOptVendorSpecificInformation(opt.ToBytes()); err == nil {
+ if vendorOpts, err = ParseOptVendorSpecificInformation(opt.ToBytes()[2:]); err == nil {
if o := vendorOpts.GetOneOption(OptionMessageType); o != nil {
if optMessageType, ok := o.(*OptMessageType); ok {
return &optMessageType.Type
diff --git a/dhcpv4/bsdp/bsdp_option_boot_image_list.go b/dhcpv4/bsdp/bsdp_option_boot_image_list.go
index 6417221..d018655 100644
--- a/dhcpv4/bsdp/bsdp_option_boot_image_list.go
+++ b/dhcpv4/bsdp/bsdp_option_boot_image_list.go
@@ -1,9 +1,8 @@
package bsdp
import (
- "fmt"
-
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
// Implements the BSDP option listing the boot images.
@@ -17,34 +16,15 @@ type OptBootImageList struct {
// ParseOptBootImageList constructs an OptBootImageList struct from a sequence
// of bytes and returns it, or an error.
func ParseOptBootImageList(data []byte) (*OptBootImageList, error) {
- // Should have at least code + length
- if len(data) < 2 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionBootImageList {
- return nil, fmt.Errorf("expected option %v, got %v instead", OptionBootImageList, code)
- }
- length := int(data[1])
- if len(data) < length+2 {
- return nil, fmt.Errorf("expected length %d, got %d instead", length, len(data))
- }
+ buf := uio.NewBigEndianBuffer(data)
- // Offset from code + length byte
var bootImages []BootImage
- idx := 2
- for {
- if idx >= length+2 {
- break
- }
- image, err := BootImageFromBytes(data[idx:])
- if err != nil {
- return nil, fmt.Errorf("parsing bytes stream: %v", err)
+ for buf.Has(5) {
+ var image BootImage
+ if err := (&image).Unmarshal(buf); err != nil {
+ return nil, err
}
- bootImages = append(bootImages, *image)
-
- // 4 bytes of BootImageID, 1 byte of name length, name
- idx += 4 + 1 + len(image.Name)
+ bootImages = append(bootImages, image)
}
return &OptBootImageList{bootImages}, nil
diff --git a/dhcpv4/bsdp/bsdp_option_boot_image_list_test.go b/dhcpv4/bsdp/bsdp_option_boot_image_list_test.go
index d2784ae..0819d64 100644
--- a/dhcpv4/bsdp/bsdp_option_boot_image_list_test.go
+++ b/dhcpv4/bsdp/bsdp_option_boot_image_list_test.go
@@ -45,8 +45,6 @@ func TestOptBootImageListInterfaceMethods(t *testing.T) {
func TestParseOptBootImageList(t *testing.T) {
data := []byte{
- 9, // code
- 22, // length
// boot image 1
0x1, 0x0, 0x03, 0xe9, // ID
6, // name length
@@ -78,25 +76,8 @@ func TestParseOptBootImageList(t *testing.T) {
}
require.Equal(t, &OptBootImageList{expectedBootImages}, o)
- // Short byte stream
- data = []byte{9}
- _, err = ParseOptBootImageList(data)
- require.Error(t, err, "should get error from short byte stream")
-
- // Wrong code
- data = []byte{54, 1, 1}
- _, err = ParseOptBootImageList(data)
- require.Error(t, err, "should get error from wrong code")
-
- // Bad length
- data = []byte{9, 10, 1, 1, 1}
- _, err = ParseOptBootImageList(data)
- require.Error(t, err, "should get error from bad length")
-
// Error parsing boot image (malformed)
data = []byte{
- 9, // code
- 22, // length
// boot image 1
0x1, 0x0, 0x03, 0xe9, // ID
4, // name length
@@ -108,25 +89,6 @@ func TestParseOptBootImageList(t *testing.T) {
}
_, err = ParseOptBootImageList(data)
require.Error(t, err, "should get error from bad boot image")
-
- // Should not get error parsing boot image with excess length.
- data = []byte{
- 9, // code
- 22, // length
- // boot image 1
- 0x1, 0x0, 0x03, 0xe9, // ID
- 6, // name length
- 'b', 's', 'd', 'p', '-', '1',
- // boot image 2
- 0x80, 0x0, 0x23, 0x31, // ID
- 6, // name length
- 'b', 's', 'd', 'p', '-', '2',
-
- // Simulate another option after boot image list
- 7, 4, 0x80, 0x0, 0x23, 0x32,
- }
- _, err = ParseOptBootImageList(data)
- require.NoError(t, err, "should not get error from options after boot image list")
}
func TestOptBootImageListString(t *testing.T) {
diff --git a/dhcpv4/bsdp/bsdp_option_default_boot_image_id.go b/dhcpv4/bsdp/bsdp_option_default_boot_image_id.go
index 4c87df8..52f7780 100644
--- a/dhcpv4/bsdp/bsdp_option_default_boot_image_id.go
+++ b/dhcpv4/bsdp/bsdp_option_default_boot_image_id.go
@@ -4,12 +4,13 @@ import (
"fmt"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
+// OptDefaultBootImageID contains the selected boot image ID.
+//
// Implements the BSDP option default boot image ID, which tells the client
// which image is the default boot image if one is not selected.
-
-// OptDefaultBootImageID contains the selected boot image ID.
type OptDefaultBootImageID struct {
ID BootImageID
}
@@ -17,22 +18,12 @@ type OptDefaultBootImageID struct {
// ParseOptDefaultBootImageID constructs an OptDefaultBootImageID struct from a sequence of
// bytes and returns it, or an error.
func ParseOptDefaultBootImageID(data []byte) (*OptDefaultBootImageID, error) {
- if len(data) < 6 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionDefaultBootImageID {
- return nil, fmt.Errorf("expected option %v, got %v instead", OptionDefaultBootImageID, code)
- }
- length := int(data[1])
- if length != 4 {
- return nil, fmt.Errorf("expected length 4, got %d instead", length)
- }
- id, err := BootImageIDFromBytes(data[2:6])
- if err != nil {
+ var o OptDefaultBootImageID
+ buf := uio.NewBigEndianBuffer(data)
+ if err := o.ID.Unmarshal(buf); err != nil {
return nil, err
}
- return &OptDefaultBootImageID{*id}, nil
+ return &o, buf.FinError()
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_default_boot_image_id_test.go b/dhcpv4/bsdp/bsdp_option_default_boot_image_id_test.go
index e062e2d..ad29c30 100644
--- a/dhcpv4/bsdp/bsdp_option_default_boot_image_id_test.go
+++ b/dhcpv4/bsdp/bsdp_option_default_boot_image_id_test.go
@@ -17,24 +17,17 @@ func TestOptDefaultBootImageIDInterfaceMethods(t *testing.T) {
func TestParseOptDefaultBootImageID(t *testing.T) {
b := BootImageID{IsInstall: true, ImageType: BootImageTypeMacOSX, Index: 1001}
- bootImageBytes := b.ToBytes()
- data := append([]byte{byte(OptionDefaultBootImageID), 4}, bootImageBytes...)
- o, err := ParseOptDefaultBootImageID(data)
+ o, err := ParseOptDefaultBootImageID(b.ToBytes())
require.NoError(t, err)
require.Equal(t, &OptDefaultBootImageID{b}, o)
// Short byte stream
- data = []byte{byte(OptionDefaultBootImageID), 4}
+ data := []byte{}
_, err = ParseOptDefaultBootImageID(data)
require.Error(t, err, "should get error from short byte stream")
- // Wrong code
- data = []byte{54, 2, 1, 0, 0, 0}
- _, err = ParseOptDefaultBootImageID(data)
- require.Error(t, err, "should get error from wrong code")
-
// Bad length
- data = []byte{byte(OptionDefaultBootImageID), 5, 1, 0, 0, 0, 0}
+ data = []byte{1, 0, 0, 0, 0}
_, err = ParseOptDefaultBootImageID(data)
require.Error(t, err, "should get error from bad length")
}
diff --git a/dhcpv4/bsdp/bsdp_option_generic.go b/dhcpv4/bsdp/bsdp_option_generic.go
index 6a51e29..6702e9c 100644
--- a/dhcpv4/bsdp/bsdp_option_generic.go
+++ b/dhcpv4/bsdp/bsdp_option_generic.go
@@ -16,21 +16,8 @@ type OptGeneric struct {
// ParseOptGeneric parses a bytestream and creates a new OptGeneric from it,
// or an error.
-func ParseOptGeneric(data []byte) (*OptGeneric, error) {
- if len(data) == 0 {
- return nil, dhcpv4.ErrZeroLengthByteStream
- }
- var (
- length int
- optionData []byte
- )
- code := dhcpv4.OptionCode(data[0])
- length = int(data[1])
- if len(data) < length+2 {
- return nil, fmt.Errorf("invalid data length: declared %v, actual %v", length, len(data))
- }
- optionData = data[2 : length+2]
- return &OptGeneric{OptionCode: code, Data: optionData}, nil
+func ParseOptGeneric(code dhcpv4.OptionCode, data []byte) (*OptGeneric, error) {
+ return &OptGeneric{OptionCode: code, Data: data}, nil
}
// Code returns the generic option code.
@@ -45,7 +32,7 @@ func (o OptGeneric) ToBytes() []byte {
// String returns a human-readable representation of a generic option.
func (o OptGeneric) String() string {
- code, ok := OptionCodeToString[o.Code()]
+ code, ok := optionCodeToString[o.Code()]
if !ok {
code = "Unknown"
}
diff --git a/dhcpv4/bsdp/bsdp_option_generic_test.go b/dhcpv4/bsdp/bsdp_option_generic_test.go
index 27436dd..eae77e1 100644
--- a/dhcpv4/bsdp/bsdp_option_generic_test.go
+++ b/dhcpv4/bsdp/bsdp_option_generic_test.go
@@ -7,19 +7,11 @@ import (
)
func TestParseOptGeneric(t *testing.T) {
- // Empty bytestream produces error
- _, err := ParseOptGeneric([]byte{})
- require.Error(t, err, "error from empty bytestream")
-
// Good parse
- o, err := ParseOptGeneric([]byte{1, 1, 1})
+ o, err := ParseOptGeneric(OptionMessageType, []byte{1})
require.NoError(t, err)
require.Equal(t, OptionMessageType, o.Code())
require.Equal(t, MessageTypeList, MessageType(o.Data[0]))
-
- // Bad parse
- o, err = ParseOptGeneric([]byte{1, 2, 1})
- require.Error(t, err, "invalid length")
}
func TestOptGenericCode(t *testing.T) {
diff --git a/dhcpv4/bsdp/bsdp_option_machine_name.go b/dhcpv4/bsdp/bsdp_option_machine_name.go
index dc05378..cffba2e 100644
--- a/dhcpv4/bsdp/bsdp_option_machine_name.go
+++ b/dhcpv4/bsdp/bsdp_option_machine_name.go
@@ -1,15 +1,13 @@
package bsdp
import (
- "fmt"
-
"github.com/insomniacslk/dhcp/dhcpv4"
)
+// OptMachineName represents a BSDP message type.
+//
// Implements the BSDP option machine name, which gives the Netboot server's
// machine name.
-
-// OptMachineName represents a BSDP message type.
type OptMachineName struct {
Name string
}
@@ -17,18 +15,7 @@ type OptMachineName struct {
// ParseOptMachineName constructs an OptMachineName struct from a sequence of
// bytes and returns it, or an error.
func ParseOptMachineName(data []byte) (*OptMachineName, error) {
- if len(data) < 2 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionMachineName {
- return nil, fmt.Errorf("expected option %v, got %v instead", OptionMachineName, code)
- }
- length := int(data[1])
- if len(data) < length+2 {
- return nil, fmt.Errorf("expected length %d, got %d instead", length, len(data))
- }
- return &OptMachineName{Name: string(data[2 : length+2])}, nil
+ return &OptMachineName{Name: string(data)}, nil
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_machine_name_test.go b/dhcpv4/bsdp/bsdp_option_machine_name_test.go
index 9019020..712bc49 100644
--- a/dhcpv4/bsdp/bsdp_option_machine_name_test.go
+++ b/dhcpv4/bsdp/bsdp_option_machine_name_test.go
@@ -15,25 +15,10 @@ func TestOptMachineNameInterfaceMethods(t *testing.T) {
}
func TestParseOptMachineName(t *testing.T) {
- data := []byte{130, 7, 's', 'o', 'm', 'e', 'b', 'o', 'x'}
+ data := []byte{'s', 'o', 'm', 'e', 'b', 'o', 'x'}
o, err := ParseOptMachineName(data)
require.NoError(t, err)
require.Equal(t, &OptMachineName{"somebox"}, o)
-
- // Short byte stream
- data = []byte{130}
- _, err = ParseOptMachineName(data)
- require.Error(t, err, "should get error from short byte stream")
-
- // Wrong code
- data = []byte{54, 1, 1}
- _, err = ParseOptMachineName(data)
- require.Error(t, err, "should get error from wrong code")
-
- // Bad length
- data = []byte{130, 5, 1}
- _, err = ParseOptMachineName(data)
- require.Error(t, err, "should get error from bad length")
}
func TestOptMachineNameString(t *testing.T) {
diff --git a/dhcpv4/bsdp/bsdp_option_message_type.go b/dhcpv4/bsdp/bsdp_option_message_type.go
index c11b56b..8c3c3d4 100644
--- a/dhcpv4/bsdp/bsdp_option_message_type.go
+++ b/dhcpv4/bsdp/bsdp_option_message_type.go
@@ -4,12 +4,13 @@ import (
"fmt"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
+// MessageType represents the different BSDP message types.
+//
// Implements the BSDP option message type. Can be one of LIST, SELECT, or
// FAILED.
-
-// MessageType represents the different BSDP message types.
type MessageType byte
// BSDP Message types - e.g. LIST, SELECT, FAILED
@@ -20,14 +21,14 @@ const (
)
func (m MessageType) String() string {
- if s, ok := MessageTypeToString[m]; ok {
+ if s, ok := messageTypeToString[m]; ok {
return s
}
return "Unknown"
}
-// MessageTypeToString maps each BSDP message type to a human-readable string.
-var MessageTypeToString = map[MessageType]string{
+// messageTypeToString maps each BSDP message type to a human-readable string.
+var messageTypeToString = map[MessageType]string{
MessageTypeList: "LIST",
MessageTypeSelect: "SELECT",
MessageTypeFailed: "FAILED",
@@ -41,18 +42,8 @@ type OptMessageType struct {
// ParseOptMessageType constructs an OptMessageType struct from a sequence of
// bytes and returns it, or an error.
func ParseOptMessageType(data []byte) (*OptMessageType, error) {
- if len(data) < 3 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionMessageType {
- return nil, fmt.Errorf("expected option %v, got %v instead", OptionMessageType, code)
- }
- length := int(data[1])
- if length != 1 {
- return nil, fmt.Errorf("expected length 1, got %d instead", length)
- }
- return &OptMessageType{Type: MessageType(data[2])}, nil
+ buf := uio.NewBigEndianBuffer(data)
+ return &OptMessageType{Type: MessageType(buf.Read8())}, buf.FinError()
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_message_type_test.go b/dhcpv4/bsdp/bsdp_option_message_type_test.go
index 9b7564f..41652be 100644
--- a/dhcpv4/bsdp/bsdp_option_message_type_test.go
+++ b/dhcpv4/bsdp/bsdp_option_message_type_test.go
@@ -14,25 +14,10 @@ func TestOptMessageTypeInterfaceMethods(t *testing.T) {
}
func TestParseOptMessageType(t *testing.T) {
- data := []byte{1, 1, 1} // DISCOVER
+ data := []byte{1} // DISCOVER
o, err := ParseOptMessageType(data)
require.NoError(t, err)
require.Equal(t, &OptMessageType{MessageTypeList}, o)
-
- // Short byte stream
- data = []byte{1, 1}
- _, err = ParseOptMessageType(data)
- require.Error(t, err, "should get error from short byte stream")
-
- // Wrong code
- data = []byte{54, 1, 1}
- _, err = ParseOptMessageType(data)
- require.Error(t, err, "should get error from wrong code")
-
- // Bad length
- data = []byte{1, 5, 1}
- _, err = ParseOptMessageType(data)
- require.Error(t, err, "should get error from bad length")
}
func TestOptMessageTypeString(t *testing.T) {
diff --git a/dhcpv4/bsdp/bsdp_option_reply_port.go b/dhcpv4/bsdp/bsdp_option_reply_port.go
index f1cc49f..da5e9c4 100644
--- a/dhcpv4/bsdp/bsdp_option_reply_port.go
+++ b/dhcpv4/bsdp/bsdp_option_reply_port.go
@@ -5,14 +5,15 @@ import (
"fmt"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
+// OptReplyPort represents a BSDP protocol version.
+//
// Implements the BSDP option reply port. This is used when BSDP responses
// should be sent to a reply port other than the DHCP default. The macOS GUI
// "Startup Disk Select" sends this option since it's operating in an
// unprivileged context.
-
-// OptReplyPort represents a BSDP protocol version.
type OptReplyPort struct {
Port uint16
}
@@ -20,19 +21,8 @@ type OptReplyPort struct {
// ParseOptReplyPort constructs an OptReplyPort struct from a sequence of
// bytes and returns it, or an error.
func ParseOptReplyPort(data []byte) (*OptReplyPort, error) {
- if len(data) < 4 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionReplyPort {
- return nil, fmt.Errorf("expected option %v, got %v instead", OptionReplyPort, code)
- }
- length := int(data[1])
- if length != 2 {
- return nil, fmt.Errorf("expected length 2, got %d instead", length)
- }
- port := binary.BigEndian.Uint16(data[2:4])
- return &OptReplyPort{port}, nil
+ buf := uio.NewBigEndianBuffer(data)
+ return &OptReplyPort{buf.Read16()}, buf.FinError()
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_reply_port_test.go b/dhcpv4/bsdp/bsdp_option_reply_port_test.go
index c9906ff..719bbc8 100644
--- a/dhcpv4/bsdp/bsdp_option_reply_port_test.go
+++ b/dhcpv4/bsdp/bsdp_option_reply_port_test.go
@@ -14,23 +14,18 @@ func TestOptReplyPortInterfaceMethods(t *testing.T) {
}
func TestParseOptReplyPort(t *testing.T) {
- data := []byte{byte(OptionReplyPort), 2, 0, 1}
+ data := []byte{0, 1}
o, err := ParseOptReplyPort(data)
require.NoError(t, err)
require.Equal(t, &OptReplyPort{1}, o)
// Short byte stream
- data = []byte{byte(OptionReplyPort), 2}
+ data = []byte{}
_, err = ParseOptReplyPort(data)
require.Error(t, err, "should get error from short byte stream")
- // Wrong code
- data = []byte{54, 2, 1, 0}
- _, err = ParseOptReplyPort(data)
- require.Error(t, err, "should get error from wrong code")
-
// Bad length
- data = []byte{byte(OptionReplyPort), 4, 1, 0}
+ data = []byte{1}
_, err = ParseOptReplyPort(data)
require.Error(t, err, "should get error from bad length")
}
diff --git a/dhcpv4/bsdp/bsdp_option_selected_boot_image_id.go b/dhcpv4/bsdp/bsdp_option_selected_boot_image_id.go
index 5b00ded..52b6eab 100644
--- a/dhcpv4/bsdp/bsdp_option_selected_boot_image_id.go
+++ b/dhcpv4/bsdp/bsdp_option_selected_boot_image_id.go
@@ -4,12 +4,13 @@ import (
"fmt"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
+// OptSelectedBootImageID contains the selected boot image ID.
+//
// Implements the BSDP option selected boot image ID, which tells the server
// which boot image has been selected by the client.
-
-// OptSelectedBootImageID contains the selected boot image ID.
type OptSelectedBootImageID struct {
ID BootImageID
}
@@ -17,22 +18,12 @@ type OptSelectedBootImageID struct {
// ParseOptSelectedBootImageID constructs an OptSelectedBootImageID struct from a sequence of
// bytes and returns it, or an error.
func ParseOptSelectedBootImageID(data []byte) (*OptSelectedBootImageID, error) {
- if len(data) < 6 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionSelectedBootImageID {
- return nil, fmt.Errorf("expected option %v, got %v instead", OptionSelectedBootImageID, code)
- }
- length := int(data[1])
- if length != 4 {
- return nil, fmt.Errorf("expected length 4, got %d instead", length)
- }
- id, err := BootImageIDFromBytes(data[2:6])
- if err != nil {
+ var o OptSelectedBootImageID
+ buf := uio.NewBigEndianBuffer(data)
+ if err := o.ID.Unmarshal(buf); err != nil {
return nil, err
}
- return &OptSelectedBootImageID{*id}, nil
+ return &o, buf.FinError()
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_selected_boot_image_id_test.go b/dhcpv4/bsdp/bsdp_option_selected_boot_image_id_test.go
index 9529e41..a55fd9f 100644
--- a/dhcpv4/bsdp/bsdp_option_selected_boot_image_id_test.go
+++ b/dhcpv4/bsdp/bsdp_option_selected_boot_image_id_test.go
@@ -17,24 +17,18 @@ func TestOptSelectedBootImageIDInterfaceMethods(t *testing.T) {
func TestParseOptSelectedBootImageID(t *testing.T) {
b := BootImageID{IsInstall: true, ImageType: BootImageTypeMacOSX, Index: 1001}
- bootImageBytes := b.ToBytes()
- data := append([]byte{byte(OptionSelectedBootImageID), 4}, bootImageBytes...)
+ data := b.ToBytes()
o, err := ParseOptSelectedBootImageID(data)
require.NoError(t, err)
require.Equal(t, &OptSelectedBootImageID{b}, o)
// Short byte stream
- data = []byte{byte(OptionSelectedBootImageID), 4}
+ data = []byte{}
_, err = ParseOptSelectedBootImageID(data)
require.Error(t, err, "should get error from short byte stream")
- // Wrong code
- data = []byte{54, 2, 1, 0, 0, 0}
- _, err = ParseOptSelectedBootImageID(data)
- require.Error(t, err, "should get error from wrong code")
-
// Bad length
- data = []byte{byte(OptionSelectedBootImageID), 5, 1, 0, 0, 0, 0}
+ data = []byte{1, 0, 0, 0, 0}
_, err = ParseOptSelectedBootImageID(data)
require.Error(t, err, "should get error from bad length")
}
diff --git a/dhcpv4/bsdp/bsdp_option_server_identifier.go b/dhcpv4/bsdp/bsdp_option_server_identifier.go
index 252a0aa..26ec37a 100644
--- a/dhcpv4/bsdp/bsdp_option_server_identifier.go
+++ b/dhcpv4/bsdp/bsdp_option_server_identifier.go
@@ -5,6 +5,7 @@ import (
"net"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
// OptServerIdentifier represents an option encapsulating the server identifier.
@@ -15,21 +16,8 @@ type OptServerIdentifier struct {
// ParseOptServerIdentifier returns a new OptServerIdentifier from a byte
// stream, or error if any.
func ParseOptServerIdentifier(data []byte) (*OptServerIdentifier, error) {
- if len(data) < 2 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionServerIdentifier {
- return nil, fmt.Errorf("expected code %v, got %v", OptionServerIdentifier, code)
- }
- length := int(data[1])
- if length != 4 {
- return nil, fmt.Errorf("unexpected length: expected 4, got %v", length)
- }
- if len(data) < 6 {
- return nil, dhcpv4.ErrShortByteStream
- }
- return &OptServerIdentifier{ServerID: net.IP(data[2 : 2+length])}, nil
+ buf := uio.NewBigEndianBuffer(data)
+ return &OptServerIdentifier{ServerID: net.IP(buf.CopyN(net.IPv4len))}, buf.FinError()
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_server_identifier_test.go b/dhcpv4/bsdp/bsdp_option_server_identifier_test.go
index 5267caa..d832c40 100644
--- a/dhcpv4/bsdp/bsdp_option_server_identifier_test.go
+++ b/dhcpv4/bsdp/bsdp_option_server_identifier_test.go
@@ -26,15 +26,9 @@ func TestParseOptServerIdentifier(t *testing.T) {
require.Error(t, err, "empty byte stream")
o, err = ParseOptServerIdentifier([]byte{3, 4, 192})
- require.Error(t, err, "short byte stream")
-
- o, err = ParseOptServerIdentifier([]byte{3, 3, 192, 168, 0, 1})
require.Error(t, err, "wrong IP length")
- o, err = ParseOptServerIdentifier([]byte{53, 4, 192, 168, 1})
- require.Error(t, err, "wrong option code")
-
- o, err = ParseOptServerIdentifier([]byte{3, 4, 192, 168, 0, 1})
+ o, err = ParseOptServerIdentifier([]byte{192, 168, 0, 1})
require.NoError(t, err)
require.Equal(t, net.IP{192, 168, 0, 1}, o.ServerID)
}
diff --git a/dhcpv4/bsdp/bsdp_option_server_priority.go b/dhcpv4/bsdp/bsdp_option_server_priority.go
index 1952b7e..66bfa44 100644
--- a/dhcpv4/bsdp/bsdp_option_server_priority.go
+++ b/dhcpv4/bsdp/bsdp_option_server_priority.go
@@ -5,31 +5,19 @@ import (
"fmt"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
-// This option implements the server identifier option
-// https://tools.ietf.org/html/rfc2132
-
// OptServerPriority represents an option encapsulating the server priority.
type OptServerPriority struct {
- Priority int
+ Priority uint16
}
// ParseOptServerPriority returns a new OptServerPriority from a byte stream, or
// error if any.
func ParseOptServerPriority(data []byte) (*OptServerPriority, error) {
- if len(data) < 4 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionServerPriority {
- return nil, fmt.Errorf("expected code %v, got %v", OptionServerPriority, code)
- }
- length := int(data[1])
- if length != 2 {
- return nil, fmt.Errorf("unexpected length: expected 2, got %v", length)
- }
- return &OptServerPriority{Priority: int(binary.BigEndian.Uint16(data[2:4]))}, nil
+ buf := uio.NewBigEndianBuffer(data)
+ return &OptServerPriority{Priority: buf.Read16()}, buf.FinError()
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_server_priority_test.go b/dhcpv4/bsdp/bsdp_option_server_priority_test.go
index d12ad55..cbcef1d 100644
--- a/dhcpv4/bsdp/bsdp_option_server_priority_test.go
+++ b/dhcpv4/bsdp/bsdp_option_server_priority_test.go
@@ -22,16 +22,10 @@ func TestParseOptServerPriority(t *testing.T) {
o, err = ParseOptServerPriority([]byte{})
require.Error(t, err, "empty byte stream")
- o, err = ParseOptServerPriority([]byte{4, 2, 1})
+ o, err = ParseOptServerPriority([]byte{1})
require.Error(t, err, "short byte stream")
- o, err = ParseOptServerPriority([]byte{4, 3, 1, 1})
- require.Error(t, err, "wrong priority length")
-
- o, err = ParseOptServerPriority([]byte{53, 2, 168, 1})
- require.Error(t, err, "wrong option code")
-
- o, err = ParseOptServerPriority([]byte{4, 2, 0, 100})
+ o, err = ParseOptServerPriority([]byte{0, 100})
require.NoError(t, err)
- require.Equal(t, 100, o.Priority)
+ require.Equal(t, uint16(100), o.Priority)
}
diff --git a/dhcpv4/bsdp/bsdp_option_version.go b/dhcpv4/bsdp/bsdp_option_version.go
index 8431a94..38158d7 100644
--- a/dhcpv4/bsdp/bsdp_option_version.go
+++ b/dhcpv4/bsdp/bsdp_option_version.go
@@ -4,10 +4,9 @@ import (
"fmt"
"github.com/insomniacslk/dhcp/dhcpv4"
+ "github.com/u-root/u-root/pkg/uio"
)
-// Implements the BSDP option version. Can be one of 1.0 or 1.1
-
// Specific versions.
var (
Version1_0 = []byte{1, 0}
@@ -15,6 +14,8 @@ var (
)
// OptVersion represents a BSDP protocol version.
+//
+// Implements the BSDP option version. Can be one of 1.0 or 1.1
type OptVersion struct {
Version []byte
}
@@ -22,18 +23,8 @@ type OptVersion struct {
// ParseOptVersion constructs an OptVersion struct from a sequence of
// bytes and returns it, or an error.
func ParseOptVersion(data []byte) (*OptVersion, error) {
- if len(data) < 4 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != OptionVersion {
- return nil, fmt.Errorf("expected option %v, got %v instead", OptionVersion, code)
- }
- length := int(data[1])
- if length != 2 {
- return nil, fmt.Errorf("expected length 2, got %d instead", length)
- }
- return &OptVersion{data[2:4]}, nil
+ buf := uio.NewBigEndianBuffer(data)
+ return &OptVersion{buf.CopyN(2)}, buf.FinError()
}
// Code returns the option code.
diff --git a/dhcpv4/bsdp/bsdp_option_version_test.go b/dhcpv4/bsdp/bsdp_option_version_test.go
index c6a6afc..d28f243 100644
--- a/dhcpv4/bsdp/bsdp_option_version_test.go
+++ b/dhcpv4/bsdp/bsdp_option_version_test.go
@@ -14,25 +14,15 @@ func TestOptVersionInterfaceMethods(t *testing.T) {
}
func TestParseOptVersion(t *testing.T) {
- data := []byte{2, 2, 1, 1}
+ data := []byte{1, 1}
o, err := ParseOptVersion(data)
require.NoError(t, err)
require.Equal(t, &OptVersion{Version1_1}, o)
// Short byte stream
- data = []byte{2, 2}
+ data = []byte{2}
_, err = ParseOptVersion(data)
require.Error(t, err, "should get error from short byte stream")
-
- // Wrong code
- data = []byte{54, 2, 1, 0}
- _, err = ParseOptVersion(data)
- require.Error(t, err, "should get error from wrong code")
-
- // Bad length
- data = []byte{2, 4, 1, 0}
- _, err = ParseOptVersion(data)
- require.Error(t, err, "should get error from bad length")
}
func TestOptVersionString(t *testing.T) {
diff --git a/dhcpv4/bsdp/option_vendor_specific_information.go b/dhcpv4/bsdp/option_vendor_specific_information.go
index e735b57..1bd41a7 100644
--- a/dhcpv4/bsdp/option_vendor_specific_information.go
+++ b/dhcpv4/bsdp/option_vendor_specific_information.go
@@ -1,8 +1,6 @@
package bsdp
import (
- "errors"
- "fmt"
"strings"
"github.com/insomniacslk/dhcp/dhcpv4"
@@ -11,20 +9,17 @@ import (
// OptVendorSpecificInformation encapsulates the BSDP-specific options used for
// the protocol.
type OptVendorSpecificInformation struct {
- Options []dhcpv4.Option
+ Options dhcpv4.Options
}
// parseOption is similar to dhcpv4.ParseOption, except that it switches based
// on the BSDP specific options.
-func parseOption(data []byte) (dhcpv4.Option, error) {
- if len(data) == 0 {
- return nil, dhcpv4.ErrZeroLengthByteStream
- }
+func parseOption(code dhcpv4.OptionCode, data []byte) (dhcpv4.Option, error) {
var (
opt dhcpv4.Option
err error
)
- switch dhcpv4.OptionCode(data[0]) {
+ switch code {
case OptionBootImageList:
opt, err = ParseOptBootImageList(data)
case OptionDefaultBootImageID:
@@ -44,7 +39,7 @@ func parseOption(data []byte) (dhcpv4.Option, error) {
case OptionVersion:
opt, err = ParseOptVersion(data)
default:
- opt, err = ParseOptGeneric(data)
+ opt, err = ParseOptGeneric(code, data)
}
if err != nil {
return nil, err
@@ -55,39 +50,10 @@ func parseOption(data []byte) (dhcpv4.Option, error) {
// ParseOptVendorSpecificInformation constructs an OptVendorSpecificInformation struct from a sequence of
// bytes and returns it, or an error.
func ParseOptVendorSpecificInformation(data []byte) (*OptVendorSpecificInformation, error) {
- // Should at least have code + length
- if len(data) < 2 {
- return nil, dhcpv4.ErrShortByteStream
- }
- code := dhcpv4.OptionCode(data[0])
- if code != dhcpv4.OptionVendorSpecificInformation {
- return nil, fmt.Errorf("expected option %v, got %v instead", dhcpv4.OptionVendorSpecificInformation, code)
- }
- length := int(data[1])
- if len(data) < length+2 {
- return nil, fmt.Errorf("expected length 2, got %d instead", length)
- }
-
- options := make([]dhcpv4.Option, 0, 10)
- idx := 2
- for {
- if idx == len(data) {
- break
- }
- // This should never happen.
- if idx > len(data) {
- return nil, errors.New("read past the end of options")
- }
- opt, err := parseOption(data[idx:])
- if err != nil {
- return nil, err
- }
- options = append(options, opt)
-
- // Account for code + length bytes
- idx += 2 + opt.Length()
+ options, err := dhcpv4.OptionsFromBytesWithParser(data, parseOption, false /* don't check for OptionEnd tag */)
+ if err != nil {
+ return nil, err
}
-
return &OptVendorSpecificInformation{options}, nil
}
@@ -133,20 +99,10 @@ func (o *OptVendorSpecificInformation) Length() int {
// GetOption returns all suboptions that match the given OptionCode code.
func (o *OptVendorSpecificInformation) GetOption(code dhcpv4.OptionCode) []dhcpv4.Option {
- var opts []dhcpv4.Option
- for _, opt := range o.Options {
- if opt.Code() == code {
- opts = append(opts, opt)
- }
- }
- return opts
+ return o.Options.GetOption(code)
}
// GetOneOption returns the first suboption that matches the OptionCode code.
func (o *OptVendorSpecificInformation) GetOneOption(code dhcpv4.OptionCode) dhcpv4.Option {
- opts := o.GetOption(code)
- if len(opts) == 0 {
- return nil
- }
- return opts[0]
+ return o.Options.GetOneOption(code)
}
diff --git a/dhcpv4/bsdp/option_vendor_specific_information_test.go b/dhcpv4/bsdp/option_vendor_specific_information_test.go
index 8a4368f..8aa2bdf 100644
--- a/dhcpv4/bsdp/option_vendor_specific_information_test.go
+++ b/dhcpv4/bsdp/option_vendor_specific_information_test.go
@@ -34,19 +34,11 @@ func TestParseOptVendorSpecificInformation(t *testing.T) {
o *OptVendorSpecificInformation
err error
)
- o, err = ParseOptVendorSpecificInformation([]byte{})
- require.Error(t, err, "empty byte stream")
-
o, err = ParseOptVendorSpecificInformation([]byte{1, 2})
require.Error(t, err, "short byte stream")
- o, err = ParseOptVendorSpecificInformation([]byte{53, 2, 1, 1})
- require.Error(t, err, "wrong option code")
-
// Good byte stream
data := []byte{
- 43, // code
- 7, // length
1, 1, 1, // List option
2, 2, 1, 1, // Version option
}
@@ -59,13 +51,13 @@ func TestParseOptVendorSpecificInformation(t *testing.T) {
},
}
require.Equal(t, 2, len(o.Options), "number of parsed suboptions")
- require.Equal(t, expected.Options[0].Code(), o.Options[0].Code())
- require.Equal(t, expected.Options[1].Code(), o.Options[1].Code())
+ typ := o.GetOneOption(OptionMessageType)
+ version := o.GetOneOption(OptionVersion)
+ require.Equal(t, expected.Options[0].Code(), typ.Code())
+ require.Equal(t, expected.Options[1].Code(), version.Code())
// Short byte stream (length and data mismatch)
data = []byte{
- 43, // code
- 7, // length
1, 1, 1, // List option
2, 2, 1, // Version option
}
@@ -74,8 +66,6 @@ func TestParseOptVendorSpecificInformation(t *testing.T) {
// Bad option
data = []byte{
- 43, // code
- 7, // length
1, 1, 1, // List option
2, 2, 1, // Version option
5, 3, 1, 1, 1, // Reply port option
@@ -85,8 +75,6 @@ func TestParseOptVendorSpecificInformation(t *testing.T) {
// Boot images + default.
data = []byte{
- 43, // code
- 7, // length
1, 1, 1, // List option
2, 2, 1, 1, // Version option
5, 2, 1, 1, // Reply port option
diff --git a/dhcpv4/bsdp/types.go b/dhcpv4/bsdp/types.go
index ac4b05b..aa9a824 100644
--- a/dhcpv4/bsdp/types.go
+++ b/dhcpv4/bsdp/types.go
@@ -26,9 +26,9 @@ const (
OptionMachineName dhcpv4.OptionCode = 130
)
-// OptionCodeToString maps BSDP OptionCodes to human-readable strings
+// optionCodeToString maps BSDP OptionCodes to human-readable strings
// describing what they are.
-var OptionCodeToString = map[dhcpv4.OptionCode]string{
+var optionCodeToString = map[dhcpv4.OptionCode]string{
OptionMessageType: "BSDP Message Type",
OptionVersion: "BSDP Version",
OptionServerIdentifier: "BSDP Server Identifier",