diff options
-rw-r--r-- | dhcpv6/dhcpv6.go | 9 | ||||
-rw-r--r-- | dhcpv6/dhcpv6_test.go | 34 | ||||
-rw-r--r-- | dhcpv6/fuzz.go | 33 | ||||
-rw-r--r-- | iana/hwtypes.go | 2 |
4 files changed, 72 insertions, 6 deletions
diff --git a/dhcpv6/dhcpv6.go b/dhcpv6/dhcpv6.go index 7505dfc..4f7fbbb 100644 --- a/dhcpv6/dhcpv6.go +++ b/dhcpv6/dhcpv6.go @@ -46,6 +46,9 @@ func MessageFromBytes(data []byte) (*Message, error) { MessageType: messageType, } buf.ReadBytes(d.TransactionID[:]) + if buf.Error() != nil { + return nil, fmt.Errorf("Error parsing DHCPv6 header: %v", buf.Error()) + } if err := d.Options.FromBytes(buf.Data()); err != nil { return nil, err } @@ -68,6 +71,9 @@ func RelayMessageFromBytes(data []byte) (*RelayMessage, error) { 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 { return nil, err @@ -79,6 +85,9 @@ func RelayMessageFromBytes(data []byte) (*RelayMessage, error) { func FromBytes(data []byte) (DHCPv6, error) { buf := uio.NewBigEndianBuffer(data) messageType := MessageType(buf.Read8()) + if buf.Error() != nil { + return nil, buf.Error() + } if messageType == MessageTypeRelayForward || messageType == MessageTypeRelayReply { return RelayMessageFromBytes(data) diff --git a/dhcpv6/dhcpv6_test.go b/dhcpv6/dhcpv6_test.go index fbf7761..d097095 100644 --- a/dhcpv6/dhcpv6_test.go +++ b/dhcpv6/dhcpv6_test.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "errors" "net" + "strconv" "testing" "github.com/insomniacslk/dhcp/iana" @@ -129,11 +130,34 @@ func TestToBytes(t *testing.T) { } func TestFromAndToBytes(t *testing.T) { - expected := []byte{01, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00} - d, err := FromBytes(expected) - require.NoError(t, err) - toBytes := d.ToBytes() - require.Equal(t, expected, toBytes) + 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 { + t.Run(strconv.Itoa(i), func(t *testing.T) { + _, err := FromBytes(packet) + require.Error(t, err) + }) + } } func TestNewAdvertiseFromSolicit(t *testing.T) { diff --git a/dhcpv6/fuzz.go b/dhcpv6/fuzz.go new file mode 100644 index 0000000..3f5afef --- /dev/null +++ b/dhcpv6/fuzz.go @@ -0,0 +1,33 @@ +// +build gofuzz + +package dhcpv6 + +import ( + "bytes" + "fmt" +) + +// Fuzz is an entrypoint for go-fuzz (github.com/dvyukov/go-fuzz) +func Fuzz(data []byte) int { + msg, err := FromBytes(data) + if err != nil { + return 0 + } + + serialized := msg.ToBytes() + if !bytes.Equal(data, serialized) { + rtMsg, err := FromBytes(serialized) + fmt.Printf("Input: %x\n", data) + fmt.Printf("Round-trip: %x\n", serialized) + fmt.Println("Message: ", msg.Summary()) + fmt.Printf("Go repr: %#v\n", msg) + fmt.Println("round-trip reserialized: ", rtMsg.Summary()) + fmt.Printf("Go repr: %#v\n", rtMsg) + if err != nil { + fmt.Printf("failed to parse after deserialize-serialize: %v\n", err) + } + panic("round-trip different") + } + + return 1 +} diff --git a/iana/hwtypes.go b/iana/hwtypes.go index bbb3188..e6fb38b 100644 --- a/iana/hwtypes.go +++ b/iana/hwtypes.go @@ -1,7 +1,7 @@ package iana // HWType is a hardware type as per RFC 2132 and defined by the IANA. -type HWType uint8 +type HWType uint16 // See IANA for values. const ( |