summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGhanan Gowripalan <ghanan@google.com>2020-04-16 17:26:12 -0700
committergVisor bot <gvisor-bot@google.com>2020-04-16 17:27:19 -0700
commitb33c3bb4a73974bbae4274da5100a3cd3f5deef8 (patch)
treeb8944a624e88bcb4be7968f0a0898acd930eebca
parent0eda0104a5a7c95a36dd288199ec1e90be9d8be9 (diff)
Return detailed errors when iterating NDP options
Test: header_test.TestNDPOptionsIterCheck PiperOrigin-RevId: 306953867
-rw-r--r--pkg/tcpip/header/BUILD1
-rw-r--r--pkg/tcpip/header/ndp_options.go196
-rw-r--r--pkg/tcpip/header/ndp_test.go118
-rw-r--r--pkg/tcpip/header/ndpoptionidentifier_string.go50
-rw-r--r--pkg/tcpip/stack/ndp.go3
5 files changed, 228 insertions, 140 deletions
diff --git a/pkg/tcpip/header/BUILD b/pkg/tcpip/header/BUILD
index 7094f3f0b..0cde694dc 100644
--- a/pkg/tcpip/header/BUILD
+++ b/pkg/tcpip/header/BUILD
@@ -21,6 +21,7 @@ go_library(
"ndp_options.go",
"ndp_router_advert.go",
"ndp_router_solicit.go",
+ "ndpoptionidentifier_string.go",
"tcp.go",
"udp.go",
],
diff --git a/pkg/tcpip/header/ndp_options.go b/pkg/tcpip/header/ndp_options.go
index e6a6ad39b..444e90820 100644
--- a/pkg/tcpip/header/ndp_options.go
+++ b/pkg/tcpip/header/ndp_options.go
@@ -15,32 +15,43 @@
package header
import (
+ "bytes"
"encoding/binary"
"errors"
"fmt"
+ "io"
"math"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
)
+// NDPOptionIdentifier is an NDP option type identifier.
+type NDPOptionIdentifier uint8
+
const (
// NDPSourceLinkLayerAddressOptionType is the type of the Source Link Layer
// Address option, as per RFC 4861 section 4.6.1.
- NDPSourceLinkLayerAddressOptionType = 1
+ NDPSourceLinkLayerAddressOptionType NDPOptionIdentifier = 1
// NDPTargetLinkLayerAddressOptionType is the type of the Target Link Layer
// Address option, as per RFC 4861 section 4.6.1.
- NDPTargetLinkLayerAddressOptionType = 2
+ NDPTargetLinkLayerAddressOptionType NDPOptionIdentifier = 2
+
+ // NDPPrefixInformationType is the type of the Prefix Information
+ // option, as per RFC 4861 section 4.6.2.
+ NDPPrefixInformationType NDPOptionIdentifier = 3
+
+ // NDPRecursiveDNSServerOptionType is the type of the Recursive DNS
+ // Server option, as per RFC 8106 section 5.1.
+ NDPRecursiveDNSServerOptionType NDPOptionIdentifier = 25
+)
+const (
// NDPLinkLayerAddressSize is the size of a Source or Target Link Layer
// Address option for an Ethernet address.
NDPLinkLayerAddressSize = 8
- // NDPPrefixInformationType is the type of the Prefix Information
- // option, as per RFC 4861 section 4.6.2.
- NDPPrefixInformationType = 3
-
// ndpPrefixInformationLength is the expected length, in bytes, of the
// body of an NDP Prefix Information option, as per RFC 4861 section
// 4.6.2 which specifies that the Length field is 4. Given this, the
@@ -91,10 +102,6 @@ const (
// within an NDPPrefixInformation.
ndpPrefixInformationPrefixOffset = 14
- // NDPRecursiveDNSServerOptionType is the type of the Recursive DNS
- // Server option, as per RFC 8106 section 5.1.
- NDPRecursiveDNSServerOptionType = 25
-
// ndpRecursiveDNSServerLifetimeOffset is the start of the 4-byte
// Lifetime field within an NDPRecursiveDNSServer.
ndpRecursiveDNSServerLifetimeOffset = 2
@@ -103,10 +110,10 @@ const (
// for IPv6 Recursive DNS Servers within an NDPRecursiveDNSServer.
ndpRecursiveDNSServerAddressesOffset = 6
- // minNDPRecursiveDNSServerLength is the minimum NDP Recursive DNS
- // Server option's length field value when it contains at least one
- // IPv6 address.
- minNDPRecursiveDNSServerLength = 3
+ // minNDPRecursiveDNSServerLength is the minimum NDP Recursive DNS Server
+ // option's body size when it contains at least one IPv6 address, as per
+ // RFC 8106 section 5.3.1.
+ minNDPRecursiveDNSServerBodySize = 22
// lengthByteUnits is the multiplier factor for the Length field of an
// NDP option. That is, the length field for NDP options is in units of
@@ -132,16 +139,13 @@ var (
// few NDPOption then modify the backing NDPOptions so long as the
// NDPOptionIterator obtained before modification is no longer used.
type NDPOptionIterator struct {
- // The NDPOptions this NDPOptionIterator is iterating over.
- opts NDPOptions
+ opts *bytes.Buffer
}
// Potential errors when iterating over an NDPOptions.
var (
- ErrNDPOptBufExhausted = errors.New("Buffer unexpectedly exhausted")
- ErrNDPOptZeroLength = errors.New("NDP option has zero-valued Length field")
- ErrNDPOptMalformedBody = errors.New("NDP option has a malformed body")
- ErrNDPInvalidLength = errors.New("NDP option's Length value is invalid as per relevant RFC")
+ ErrNDPOptMalformedBody = errors.New("NDP option has a malformed body")
+ ErrNDPOptMalformedHeader = errors.New("NDP option has a malformed header")
)
// Next returns the next element in the backing NDPOptions, or true if we are
@@ -152,48 +156,50 @@ var (
func (i *NDPOptionIterator) Next() (NDPOption, bool, error) {
for {
// Do we still have elements to look at?
- if len(i.opts) == 0 {
+ if i.opts.Len() == 0 {
return nil, true, nil
}
- // Do we have enough bytes for an NDP option that has a Length
- // field of at least 1? Note, 0 in the Length field is invalid.
- if len(i.opts) < lengthByteUnits {
- return nil, true, ErrNDPOptBufExhausted
- }
-
// Get the Type field.
- t := i.opts[0]
-
- // Get the Length field.
- l := i.opts[1]
+ temp, err := i.opts.ReadByte()
+ if err != nil {
+ if err != io.EOF {
+ // ReadByte should only ever return nil or io.EOF.
+ panic(fmt.Sprintf("unexpected error when reading the option's Type field: %s", err))
+ }
- // This would indicate an erroneous NDP option as the Length
- // field should never be 0.
- if l == 0 {
- return nil, true, ErrNDPOptZeroLength
+ // We use io.ErrUnexpectedEOF as exhausting the buffer is unexpected once
+ // we start parsing an option; we expect the buffer to contain enough
+ // bytes for the whole option.
+ return nil, true, fmt.Errorf("unexpectedly exhausted buffer when reading the option's Type field: %w", io.ErrUnexpectedEOF)
}
+ kind := NDPOptionIdentifier(temp)
- // How many bytes are in the option body?
- numBytes := int(l) * lengthByteUnits
- numBodyBytes := numBytes - 2
-
- potentialBody := i.opts[2:]
+ // Get the Length field.
+ length, err := i.opts.ReadByte()
+ if err != nil {
+ if err != io.EOF {
+ panic(fmt.Sprintf("unexpected error when reading the option's Length field for %s: %s", kind, err))
+ }
- // This would indicate an erroenous NDPOptions buffer as we ran
- // out of the buffer in the middle of an NDP option.
- if left := len(potentialBody); left < numBodyBytes {
- return nil, true, ErrNDPOptBufExhausted
+ return nil, true, fmt.Errorf("unexpectedly exhausted buffer when reading the option's Length field for %s: %w", kind, io.ErrUnexpectedEOF)
}
- // Get only the options body, leaving the rest of the options
- // buffer alone.
- body := potentialBody[:numBodyBytes]
+ // This would indicate an erroneous NDP option as the Length field should
+ // never be 0.
+ if length == 0 {
+ return nil, true, fmt.Errorf("zero valued Length field for %s: %w", kind, ErrNDPOptMalformedHeader)
+ }
- // Update opts with the remaining options body.
- i.opts = i.opts[numBytes:]
+ // Get the body.
+ numBytes := int(length) * lengthByteUnits
+ numBodyBytes := numBytes - 2
+ body := i.opts.Next(numBodyBytes)
+ if len(body) < numBodyBytes {
+ return nil, true, fmt.Errorf("unexpectedly exhausted buffer when reading the option's Body for %s: %w", kind, io.ErrUnexpectedEOF)
+ }
- switch t {
+ switch kind {
case NDPSourceLinkLayerAddressOptionType:
return NDPSourceLinkLayerAddressOption(body), false, nil
@@ -205,22 +211,15 @@ func (i *NDPOptionIterator) Next() (NDPOption, bool, error) {
// body is ndpPrefixInformationLength, as per RFC 4861
// section 4.6.2.
if numBodyBytes != ndpPrefixInformationLength {
- return nil, true, ErrNDPOptMalformedBody
+ return nil, true, fmt.Errorf("got %d bytes for NDP Prefix Information option's body, expected %d bytes: %w", numBodyBytes, ndpPrefixInformationLength, ErrNDPOptMalformedBody)
}
return NDPPrefixInformation(body), false, nil
case NDPRecursiveDNSServerOptionType:
- // RFC 8106 section 5.3.1 outlines that the RDNSS option
- // must have a minimum length of 3 so it contains at
- // least one IPv6 address.
- if l < minNDPRecursiveDNSServerLength {
- return nil, true, ErrNDPInvalidLength
- }
-
opt := NDPRecursiveDNSServer(body)
- if len(opt.Addresses()) == 0 {
- return nil, true, ErrNDPOptMalformedBody
+ if err := opt.checkAddresses(); err != nil {
+ return nil, true, err
}
return opt, false, nil
@@ -247,10 +246,16 @@ type NDPOptions []byte
//
// See NDPOptionIterator for more information.
func (b NDPOptions) Iter(check bool) (NDPOptionIterator, error) {
- it := NDPOptionIterator{opts: b}
+ it := NDPOptionIterator{
+ opts: bytes.NewBuffer(b),
+ }
if check {
- for it2 := it; true; {
+ it2 := NDPOptionIterator{
+ opts: bytes.NewBuffer(b),
+ }
+
+ for {
if _, done, err := it2.Next(); err != nil || done {
return it, err
}
@@ -278,7 +283,7 @@ func (b NDPOptions) Serialize(s NDPOptionsSerializer) int {
continue
}
- b[0] = o.Type()
+ b[0] = byte(o.Type())
// We know this safe because paddedLength would have returned
// 0 if o had an invalid length (> 255 * lengthByteUnits).
@@ -304,7 +309,7 @@ type NDPOption interface {
fmt.Stringer
// Type returns the type of the receiver.
- Type() uint8
+ Type() NDPOptionIdentifier
// Length returns the length of the body of the receiver, in bytes.
Length() int
@@ -386,7 +391,7 @@ func (b NDPOptionsSerializer) Length() int {
type NDPSourceLinkLayerAddressOption tcpip.LinkAddress
// Type implements NDPOption.Type.
-func (o NDPSourceLinkLayerAddressOption) Type() uint8 {
+func (o NDPSourceLinkLayerAddressOption) Type() NDPOptionIdentifier {
return NDPSourceLinkLayerAddressOptionType
}
@@ -426,7 +431,7 @@ func (o NDPSourceLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress {
type NDPTargetLinkLayerAddressOption tcpip.LinkAddress
// Type implements NDPOption.Type.
-func (o NDPTargetLinkLayerAddressOption) Type() uint8 {
+func (o NDPTargetLinkLayerAddressOption) Type() NDPOptionIdentifier {
return NDPTargetLinkLayerAddressOptionType
}
@@ -466,7 +471,7 @@ func (o NDPTargetLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress {
type NDPPrefixInformation []byte
// Type implements NDPOption.Type.
-func (o NDPPrefixInformation) Type() uint8 {
+func (o NDPPrefixInformation) Type() NDPOptionIdentifier {
return NDPPrefixInformationType
}
@@ -590,7 +595,7 @@ type NDPRecursiveDNSServer []byte
// Type returns the type of an NDP Recursive DNS Server option.
//
// Type implements NDPOption.Type.
-func (NDPRecursiveDNSServer) Type() uint8 {
+func (NDPRecursiveDNSServer) Type() NDPOptionIdentifier {
return NDPRecursiveDNSServerOptionType
}
@@ -613,7 +618,12 @@ func (o NDPRecursiveDNSServer) serializeInto(b []byte) int {
// String implements fmt.Stringer.String.
func (o NDPRecursiveDNSServer) String() string {
- return fmt.Sprintf("%T(%s valid for %s)", o, o.Addresses(), o.Lifetime())
+ lt := o.Lifetime()
+ addrs, err := o.Addresses()
+ if err != nil {
+ return fmt.Sprintf("%T([] valid for %s; err = %s)", o, lt, err)
+ }
+ return fmt.Sprintf("%T(%s valid for %s)", o, addrs, lt)
}
// Lifetime returns the length of time that the DNS server addresses
@@ -632,29 +642,45 @@ func (o NDPRecursiveDNSServer) Lifetime() time.Duration {
// Addresses returns the recursive DNS server IPv6 addresses that may be
// used for name resolution.
//
-// Note, some of the addresses returned MAY be link-local addresses.
+// Note, the addresses MAY be link-local addresses.
+func (o NDPRecursiveDNSServer) Addresses() ([]tcpip.Address, error) {
+ var addrs []tcpip.Address
+ return addrs, o.iterAddresses(func(addr tcpip.Address) { addrs = append(addrs, addr) })
+}
+
+// checkAddresses iterates over the addresses in an NDP Recursive DNS Server
+// option and returns any error it encounters.
+func (o NDPRecursiveDNSServer) checkAddresses() error {
+ return o.iterAddresses(nil)
+}
+
+// iterAddresses iterates over the addresses in an NDP Recursive DNS Server
+// option and calls a function with each valid unicast IPv6 address.
//
-// Addresses may panic if o does not hold valid IPv6 addresses.
-func (o NDPRecursiveDNSServer) Addresses() []tcpip.Address {
- l := len(o)
- if l < ndpRecursiveDNSServerAddressesOffset {
- return nil
+// Note, the addresses MAY be link-local addresses.
+func (o NDPRecursiveDNSServer) iterAddresses(fn func(tcpip.Address)) error {
+ if l := len(o); l < minNDPRecursiveDNSServerBodySize {
+ return fmt.Errorf("got %d bytes for NDP Recursive DNS Server option's body, expected at least %d bytes: %w", l, minNDPRecursiveDNSServerBodySize, io.ErrUnexpectedEOF)
}
- l -= ndpRecursiveDNSServerAddressesOffset
+ o = o[ndpRecursiveDNSServerAddressesOffset:]
+ l := len(o)
if l%IPv6AddressSize != 0 {
- return nil
+ return fmt.Errorf("NDP Recursive DNS Server option's body ends in the middle of an IPv6 address (addresses body size = %d bytes): %w", l, ErrNDPOptMalformedBody)
}
- buf := o[ndpRecursiveDNSServerAddressesOffset:]
- var addrs []tcpip.Address
- for len(buf) > 0 {
- addr := tcpip.Address(buf[:IPv6AddressSize])
+ for i := 0; len(o) != 0; i++ {
+ addr := tcpip.Address(o[:IPv6AddressSize])
if !IsV6UnicastAddress(addr) {
- return nil
+ return fmt.Errorf("%d-th address (%s) in NDP Recursive DNS Server option is not a valid unicast IPv6 address: %w", i, addr, ErrNDPOptMalformedBody)
+ }
+
+ if fn != nil {
+ fn(addr)
}
- addrs = append(addrs, addr)
- buf = buf[IPv6AddressSize:]
+
+ o = o[IPv6AddressSize:]
}
- return addrs
+
+ return nil
}
diff --git a/pkg/tcpip/header/ndp_test.go b/pkg/tcpip/header/ndp_test.go
index 969f8f1e8..2341329c4 100644
--- a/pkg/tcpip/header/ndp_test.go
+++ b/pkg/tcpip/header/ndp_test.go
@@ -16,6 +16,8 @@ package header
import (
"bytes"
+ "errors"
+ "io"
"testing"
"time"
@@ -543,8 +545,12 @@ func TestNDPRecursiveDNSServerOptionSerialize(t *testing.T) {
want := []tcpip.Address{
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
}
- if got := opt.Addresses(); !cmp.Equal(got, want) {
- t.Errorf("got Addresses = %v, want = %v", got, want)
+ addrs, err := opt.Addresses()
+ if err != nil {
+ t.Errorf("opt.Addresses() = %s", err)
+ }
+ if diff := cmp.Diff(addrs, want); diff != "" {
+ t.Errorf("mismatched addresses (-want +got):\n%s", diff)
}
// Iterator should not return anything else.
@@ -638,8 +644,12 @@ func TestNDPRecursiveDNSServerOption(t *testing.T) {
if got := opt.Lifetime(); got != test.lifetime {
t.Errorf("got Lifetime = %d, want = %d", got, test.lifetime)
}
- if got := opt.Addresses(); !cmp.Equal(got, test.addrs) {
- t.Errorf("got Addresses = %v, want = %v", got, test.addrs)
+ addrs, err := opt.Addresses()
+ if err != nil {
+ t.Errorf("opt.Addresses() = %s", err)
+ }
+ if diff := cmp.Diff(addrs, test.addrs); diff != "" {
+ t.Errorf("mismatched addresses (-want +got):\n%s", diff)
}
// Iterator should not return anything else.
@@ -661,38 +671,38 @@ func TestNDPRecursiveDNSServerOption(t *testing.T) {
// the iterator was returned for is malformed.
func TestNDPOptionsIterCheck(t *testing.T) {
tests := []struct {
- name string
- buf []byte
- expected error
+ name string
+ buf []byte
+ expectedErr error
}{
{
- "ZeroLengthField",
- []byte{0, 0, 0, 0, 0, 0, 0, 0},
- ErrNDPOptZeroLength,
+ name: "ZeroLengthField",
+ buf: []byte{0, 0, 0, 0, 0, 0, 0, 0},
+ expectedErr: ErrNDPOptMalformedHeader,
},
{
- "ValidSourceLinkLayerAddressOption",
- []byte{1, 1, 1, 2, 3, 4, 5, 6},
- nil,
+ name: "ValidSourceLinkLayerAddressOption",
+ buf: []byte{1, 1, 1, 2, 3, 4, 5, 6},
+ expectedErr: nil,
},
{
- "TooSmallSourceLinkLayerAddressOption",
- []byte{1, 1, 1, 2, 3, 4, 5},
- ErrNDPOptBufExhausted,
+ name: "TooSmallSourceLinkLayerAddressOption",
+ buf: []byte{1, 1, 1, 2, 3, 4, 5},
+ expectedErr: io.ErrUnexpectedEOF,
},
{
- "ValidTargetLinkLayerAddressOption",
- []byte{2, 1, 1, 2, 3, 4, 5, 6},
- nil,
+ name: "ValidTargetLinkLayerAddressOption",
+ buf: []byte{2, 1, 1, 2, 3, 4, 5, 6},
+ expectedErr: nil,
},
{
- "TooSmallTargetLinkLayerAddressOption",
- []byte{2, 1, 1, 2, 3, 4, 5},
- ErrNDPOptBufExhausted,
+ name: "TooSmallTargetLinkLayerAddressOption",
+ buf: []byte{2, 1, 1, 2, 3, 4, 5},
+ expectedErr: io.ErrUnexpectedEOF,
},
{
- "ValidPrefixInformation",
- []byte{
+ name: "ValidPrefixInformation",
+ buf: []byte{
3, 4, 43, 64,
1, 2, 3, 4,
5, 6, 7, 8,
@@ -702,11 +712,11 @@ func TestNDPOptionsIterCheck(t *testing.T) {
17, 18, 19, 20,
21, 22, 23, 24,
},
- nil,
+ expectedErr: nil,
},
{
- "TooSmallPrefixInformation",
- []byte{
+ name: "TooSmallPrefixInformation",
+ buf: []byte{
3, 4, 43, 64,
1, 2, 3, 4,
5, 6, 7, 8,
@@ -716,11 +726,11 @@ func TestNDPOptionsIterCheck(t *testing.T) {
17, 18, 19, 20,
21, 22, 23,
},
- ErrNDPOptBufExhausted,
+ expectedErr: io.ErrUnexpectedEOF,
},
{
- "InvalidPrefixInformationLength",
- []byte{
+ name: "InvalidPrefixInformationLength",
+ buf: []byte{
3, 3, 43, 64,
1, 2, 3, 4,
5, 6, 7, 8,
@@ -728,11 +738,11 @@ func TestNDPOptionsIterCheck(t *testing.T) {
9, 10, 11, 12,
13, 14, 15, 16,
},
- ErrNDPOptMalformedBody,
+ expectedErr: ErrNDPOptMalformedBody,
},
{
- "ValidSourceAndTargetLinkLayerAddressWithPrefixInformation",
- []byte{
+ name: "ValidSourceAndTargetLinkLayerAddressWithPrefixInformation",
+ buf: []byte{
// Source Link-Layer Address.
1, 1, 1, 2, 3, 4, 5, 6,
@@ -749,11 +759,11 @@ func TestNDPOptionsIterCheck(t *testing.T) {
17, 18, 19, 20,
21, 22, 23, 24,
},
- nil,
+ expectedErr: nil,
},
{
- "ValidSourceAndTargetLinkLayerAddressWithPrefixInformationWithUnrecognized",
- []byte{
+ name: "ValidSourceAndTargetLinkLayerAddressWithPrefixInformationWithUnrecognized",
+ buf: []byte{
// Source Link-Layer Address.
1, 1, 1, 2, 3, 4, 5, 6,
@@ -775,52 +785,52 @@ func TestNDPOptionsIterCheck(t *testing.T) {
17, 18, 19, 20,
21, 22, 23, 24,
},
- nil,
+ expectedErr: nil,
},
{
- "InvalidRecursiveDNSServerCutsOffAddress",
- []byte{
+ name: "InvalidRecursiveDNSServerCutsOffAddress",
+ buf: []byte{
25, 4, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
0, 1, 2, 3, 4, 5, 6, 7,
},
- ErrNDPOptMalformedBody,
+ expectedErr: ErrNDPOptMalformedBody,
},
{
- "InvalidRecursiveDNSServerInvalidLengthField",
- []byte{
+ name: "InvalidRecursiveDNSServerInvalidLengthField",
+ buf: []byte{
25, 2, 0, 0,
0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8,
},
- ErrNDPInvalidLength,
+ expectedErr: io.ErrUnexpectedEOF,
},
{
- "RecursiveDNSServerTooSmall",
- []byte{
+ name: "RecursiveDNSServerTooSmall",
+ buf: []byte{
25, 1, 0, 0,
0, 0, 0,
},
- ErrNDPOptBufExhausted,
+ expectedErr: io.ErrUnexpectedEOF,
},
{
- "RecursiveDNSServerMulticast",
- []byte{
+ name: "RecursiveDNSServerMulticast",
+ buf: []byte{
25, 3, 0, 0,
0, 0, 0, 0,
255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
},
- ErrNDPOptMalformedBody,
+ expectedErr: ErrNDPOptMalformedBody,
},
{
- "RecursiveDNSServerUnspecified",
- []byte{
+ name: "RecursiveDNSServerUnspecified",
+ buf: []byte{
25, 3, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
},
- ErrNDPOptMalformedBody,
+ expectedErr: ErrNDPOptMalformedBody,
},
}
@@ -828,8 +838,8 @@ func TestNDPOptionsIterCheck(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
opts := NDPOptions(test.buf)
- if _, err := opts.Iter(true); err != test.expected {
- t.Fatalf("got Iter(true) = (_, %v), want = (_, %v)", err, test.expected)
+ if _, err := opts.Iter(true); !errors.Is(err, test.expectedErr) {
+ t.Fatalf("got Iter(true) = (_, %v), want = (_, %v)", err, test.expectedErr)
}
// test.buf may be malformed but we chose not to check
diff --git a/pkg/tcpip/header/ndpoptionidentifier_string.go b/pkg/tcpip/header/ndpoptionidentifier_string.go
new file mode 100644
index 000000000..6fe9a336b
--- /dev/null
+++ b/pkg/tcpip/header/ndpoptionidentifier_string.go
@@ -0,0 +1,50 @@
+// Copyright 2020 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by "stringer -type NDPOptionIdentifier ."; DO NOT EDIT.
+
+package header
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[NDPSourceLinkLayerAddressOptionType-1]
+ _ = x[NDPTargetLinkLayerAddressOptionType-2]
+ _ = x[NDPPrefixInformationType-3]
+ _ = x[NDPRecursiveDNSServerOptionType-25]
+}
+
+const (
+ _NDPOptionIdentifier_name_0 = "NDPSourceLinkLayerAddressOptionTypeNDPTargetLinkLayerAddressOptionTypeNDPPrefixInformationType"
+ _NDPOptionIdentifier_name_1 = "NDPRecursiveDNSServerOptionType"
+)
+
+var (
+ _NDPOptionIdentifier_index_0 = [...]uint8{0, 35, 70, 94}
+)
+
+func (i NDPOptionIdentifier) String() string {
+ switch {
+ case 1 <= i && i <= 3:
+ i -= 1
+ return _NDPOptionIdentifier_name_0[_NDPOptionIdentifier_index_0[i]:_NDPOptionIdentifier_index_0[i+1]]
+ case i == 25:
+ return _NDPOptionIdentifier_name_1
+ default:
+ return "NDPOptionIdentifier(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
diff --git a/pkg/tcpip/stack/ndp.go b/pkg/tcpip/stack/ndp.go
index 7f66c6c09..8140c6dd4 100644
--- a/pkg/tcpip/stack/ndp.go
+++ b/pkg/tcpip/stack/ndp.go
@@ -711,7 +711,8 @@ func (ndp *ndpState) handleRA(ip tcpip.Address, ra header.NDPRouterAdvert) {
continue
}
- ndp.nic.stack.ndpDisp.OnRecursiveDNSServerOption(ndp.nic.ID(), opt.Addresses(), opt.Lifetime())
+ addrs, _ := opt.Addresses()
+ ndp.nic.stack.ndpDisp.OnRecursiveDNSServerOption(ndp.nic.ID(), addrs, opt.Lifetime())
case header.NDPPrefixInformation:
prefix := opt.Subnet()