Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions dhcpv6/prettyprint_test.go → dhcpv6/bigmessage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/insomniacslk/dhcp/iana"
)

func TestPrint(t *testing.T) {
func makeBigMessage() (*Message, *RelayMessage) {
m4, _ := dhcpv4.NewDiscovery(net.HardwareAddr{0x1, 0x2, 0xde, 0xad, 0xbe, 0xef})

m, _ := NewSolicit(net.HardwareAddr{0x1, 0x2, 0xde, 0xad, 0xbe, 0xef}, WithRapidCommit)
Expand Down Expand Up @@ -80,17 +80,38 @@ func TestPrint(t *testing.T) {
WithOption(&OptVendorClass{EnterpriseNumber: 300, Data: [][]byte{[]byte("foo"), []byte("bar")}}),
WithOption(vendorOpts),
)
t.Log(adv.String())
t.Log(adv.Summary())

relayfw := RelayMessage{
relayfw := &RelayMessage{
MessageType: MessageTypeRelayForward,
}
relayfw.Options.Add(OptRelayMessage(adv))
relayfw.Options.Add(&OptRemoteID{
EnterpriseNumber: 0x123,
RemoteID: []byte{0x1, 0x2},
})
t.Log(relayfw.String())
t.Log(relayfw.Summary())
return adv, relayfw
}

func TestPrint(t *testing.T) {
m, r := makeBigMessage()
t.Log(m.String())
t.Log(m.Summary())

t.Log(r.String())
t.Log(r.Summary())
}

func BenchmarkToBytes(b *testing.B) {
_, r := makeBigMessage()
for i := 0; i < b.N; i++ {
_ = r.ToBytes()
}
}

func BenchmarkFromBytes(b *testing.B) {
_, r := makeBigMessage()
buf := r.ToBytes()
for i := 0; i < b.N; i++ {
_, _ = FromBytes(buf)
}
}
60 changes: 19 additions & 41 deletions dhcpv6/dhcpv6.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
)

type DHCPv6 interface {
Serializable

Type() MessageType
ToBytes() []byte
String() string
Summary() string
LongString(indent int) string
IsRelay() bool
Expand All @@ -35,50 +35,20 @@ type Modifier func(d DHCPv6)

// MessageFromBytes parses a DHCPv6 message from a byte stream.
func MessageFromBytes(data []byte) (*Message, error) {
buf := uio.NewBigEndianBuffer(data)
messageType := MessageType(buf.Read8())

if messageType == MessageTypeRelayForward || messageType == MessageTypeRelayReply {
return nil, fmt.Errorf("wrong message type")
}

d := &Message{
MessageType: messageType,
}
buf.ReadBytes(d.TransactionID[:])
if buf.Error() != nil {
return nil, fmt.Errorf("failed to parse DHCPv6 header: %w", buf.Error())
}
if err := d.Options.FromBytes(buf.Data()); err != nil {
var m Message
if err := m.FromBytes(data); err != nil {
return nil, err
}
return d, nil
return &m, nil
}

// RelayMessageFromBytes parses a relay message from a byte stream.
func RelayMessageFromBytes(data []byte) (*RelayMessage, error) {
buf := uio.NewBigEndianBuffer(data)
messageType := MessageType(buf.Read8())

if messageType != MessageTypeRelayForward && messageType != MessageTypeRelayReply {
return nil, fmt.Errorf("wrong message type")
}

d := &RelayMessage{
MessageType: messageType,
HopCount: buf.Read8(),
}
d.LinkAddr = net.IP(buf.CopyN(net.IPv6len))
d.PeerAddr = net.IP(buf.CopyN(net.IPv6len))

if buf.Error() != nil {
return nil, fmt.Errorf("Error parsing RelayMessage header: %v", buf.Error())
}
// TODO: fail if no OptRelayMessage is present.
if err := d.Options.FromBytes(buf.Data()); err != nil {
var r RelayMessage
if err := r.FromBytes(data); err != nil {
return nil, err
}
return d, nil
return &r, nil
}

// FromBytes reads a DHCPv6 message from a byte stream.
Expand All @@ -90,10 +60,18 @@ func FromBytes(data []byte) (DHCPv6, error) {
}

if messageType == MessageTypeRelayForward || messageType == MessageTypeRelayReply {
return RelayMessageFromBytes(data)
} else {
return MessageFromBytes(data)
r, err := RelayMessageFromBytes(data)
if err != nil {
return nil, err
}
return r, nil
}

m, err := MessageFromBytes(data)
if err != nil {
return nil, err
}
return m, nil
}

// NewMessage creates a new DHCPv6 message with default options
Expand Down
128 changes: 104 additions & 24 deletions dhcpv6/dhcpv6_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package dhcpv6

import (
"bytes"
"encoding/binary"
"errors"
"net"
"reflect"
"strconv"
"testing"

"github.com/insomniacslk/dhcp/iana"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/u-root/uio/rand"
"github.com/u-root/uio/uio"
)

func randomReadMock(value []byte, n int, err error) func([]byte) (int, error) {
Expand Down Expand Up @@ -130,32 +133,109 @@ func TestToBytes(t *testing.T) {
}

func TestFromAndToBytes(t *testing.T) {
expected := [][]byte{
{01, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00},
[]byte("0000\x00\x01\x00\x0e\x00\x01000000000000"),
}
t.Parallel()
for i, packet := range expected {
t.Run(strconv.Itoa(i), func(t *testing.T) {
d, err := FromBytes(packet)
require.NoError(t, err)
toBytes := d.ToBytes()
require.Equal(t, packet, toBytes)
})
}
}

func TestFromBytesInvalid(t *testing.T) {
expected := [][]byte{
{},
{30},
{12},
}
t.Parallel()
for i, packet := range expected {
for i, tt := range []struct {
buf []byte
want DHCPv6
err error
}{
{
buf: []byte{0x01, 0xab, 0xcd, 0xef},
want: &Message{
MessageType: MessageTypeSolicit,
TransactionID: [3]byte{0xab, 0xcd, 0xef},
Options: MessageOptions{Options: Options{}},
},
},
{
buf: []byte{0x01, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00},
want: &Message{
MessageType: MessageTypeSolicit,
TransactionID: [3]byte{0xab, 0xcd, 0xef},
Options: MessageOptions{Options: Options{
&OptionGeneric{OptionCode: 0},
}},
},
},
{
buf: []byte{
0, 0, 0, 0,
0, 1, // ClientID
0, 14, // Length
0, 1, // DUID_LLT
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
},
want: &Message{
MessageType: MessageTypeNone,
TransactionID: [3]byte{0, 0, 0},
Options: MessageOptions{Options: Options{
OptClientID(&DUIDLLT{HWType: 0, Time: 0, LinkLayerAddr: []byte{0, 0, 0, 0, 0, 0}}),
}},
},
},
{
buf: nil,
err: uio.ErrBufferTooShort,
},
{
buf: []byte{30}, // Message
err: uio.ErrBufferTooShort,
},
{
buf: []byte{12}, // RelayMessage
err: uio.ErrBufferTooShort,
},
{
buf: []byte{
0x0c,
0, // hopcount
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // LinkAddr
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // PeerAddr
0x00, 0x00, 0x00, 0x00,
},
want: &RelayMessage{
MessageType: MessageTypeRelayForward,
LinkAddr: net.ParseIP("::"),
PeerAddr: net.ParseIP("::"),
Options: RelayOptions{Options: Options{
&OptionGeneric{OptionCode: 0},
}},
},
},
{
// Message, option missing length.
buf: []byte{0x01, 0xab, 0xcd, 0xef, 0x00, 0x00},
err: uio.ErrUnreadBytes,
},
{
// RelayMessage, option missing length.
buf: []byte{
0x0c,
0, // hopcount
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // LinkAddr
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // PeerAddr
0x00, 0x00,
},
err: uio.ErrUnreadBytes,
},
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
_, err := FromBytes(packet)
require.Error(t, err)
got, err := FromBytes(tt.buf)
if !errors.Is(err, tt.err) {
t.Errorf("FromBytes = %v, want %v", err, tt.err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("FromBytes = %#v, want %#v", got, tt.want)
}

if tt.want != nil {
gotb := tt.want.ToBytes()
if !bytes.Equal(gotb, tt.buf) {
t.Errorf("ToBytes = %v, want %v", gotb, tt.buf)
}
}
})
}
}
Expand Down
20 changes: 20 additions & 0 deletions dhcpv6/dhcpv6message.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,26 @@ type Message struct {
Options MessageOptions
}

// FromBytes parses a DHCPv6 message from a byte stream.
func (m *Message) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
m.Unmarshal(buf)
return buf.FinError()
}

// Unmarshal parses a DHCPv6 message from buf.
func (m *Message) Unmarshal(buf *uio.Lexer) {
messageType := MessageType(buf.Read8())

if messageType == MessageTypeRelayForward || messageType == MessageTypeRelayReply {
buf.SetError(fmt.Errorf("wrong message type"))
}

m.MessageType = messageType
buf.ReadBytes(m.TransactionID[:])
m.Options.Unmarshal(buf)
}

var randomRead = rand.Read

// GenerateTransactionID generates a random 3-byte transaction ID.
Expand Down
24 changes: 24 additions & 0 deletions dhcpv6/dhcpv6relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,30 @@ type RelayMessage struct {
Options RelayOptions
}

// FromBytes parses a relay message from a byte stream.
func (r *RelayMessage) FromBytes(data []byte) error {
buf := uio.NewBigEndianBuffer(data)
r.Unmarshal(buf)
return buf.FinError()
}

// Unmarshal parses a relay message from a buf.
func (r *RelayMessage) Unmarshal(buf *uio.Lexer) {
messageType := MessageType(buf.Read8())

if messageType != MessageTypeRelayForward && messageType != MessageTypeRelayReply {
buf.SetError(fmt.Errorf("wrong message type"))
}

r.MessageType = messageType
r.HopCount = buf.Read8()
r.LinkAddr = net.IP(buf.CopyN(net.IPv6len))
r.PeerAddr = net.IP(buf.CopyN(net.IPv6len))

// TODO: fail if no OptRelayMessage is present.
r.Options.Unmarshal(buf)
}

func write16(b *uio.Lexer, ip net.IP) {
if ip == nil || ip.To16() == nil {
var zeros [net.IPv6len]byte
Expand Down
4 changes: 1 addition & 3 deletions dhcpv6/duid.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ import (

// DUID is the interface that all DUIDs adhere to.
type DUID interface {
fmt.Stringer
Serializable

ToBytes() []byte
FromBytes(p []byte) error
DUIDType() DUIDType
Equal(d DUID) bool
}
Expand Down
5 changes: 1 addition & 4 deletions dhcpv6/option_iaaddress.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,6 @@ func (op *OptIAAddress) FromBytes(data []byte) error {
t2.Unmarshal(buf)
op.PreferredLifetime = t1.Duration
op.ValidLifetime = t2.Duration

if err := op.Options.FromBytes(buf.ReadAll()); err != nil {
return err
}
op.Options.Unmarshal(buf)
return buf.FinError()
}
4 changes: 2 additions & 2 deletions dhcpv6/option_iaaddress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ func TestIAAddressParseAndGetter(t *testing.T) {
},
},
{
buf: []byte{0, 3, 0, 1, 0},
buf: []byte{0, 5, 0, 1, 0},
want: nil,
err: uio.ErrUnreadBytes,
err: uio.ErrBufferTooShort,
},
{
buf: []byte{
Expand Down
Loading