summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/header
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/header')
-rw-r--r--pkg/tcpip/header/BUILD69
-rw-r--r--pkg/tcpip/header/checksum_test.go171
-rw-r--r--pkg/tcpip/header/eth_test.go149
-rw-r--r--pkg/tcpip/header/header_state_autogen.go70
-rw-r--r--pkg/tcpip/header/ipv6_extension_headers_test.go992
-rw-r--r--pkg/tcpip/header/ipv6_test.go417
-rw-r--r--pkg/tcpip/header/ipversion_test.go67
-rw-r--r--pkg/tcpip/header/ndp_test.go1521
-rw-r--r--pkg/tcpip/header/parse/BUILD15
-rw-r--r--pkg/tcpip/header/parse/parse_state_autogen.go3
-rw-r--r--pkg/tcpip/header/tcp_test.go148
11 files changed, 73 insertions, 3549 deletions
diff --git a/pkg/tcpip/header/BUILD b/pkg/tcpip/header/BUILD
deleted file mode 100644
index d87797617..000000000
--- a/pkg/tcpip/header/BUILD
+++ /dev/null
@@ -1,69 +0,0 @@
-load("//tools:defs.bzl", "go_library", "go_test")
-
-package(licenses = ["notice"])
-
-go_library(
- name = "header",
- srcs = [
- "arp.go",
- "checksum.go",
- "eth.go",
- "gue.go",
- "icmpv4.go",
- "icmpv6.go",
- "interfaces.go",
- "ipv4.go",
- "ipv6.go",
- "ipv6_extension_headers.go",
- "ipv6_fragment.go",
- "ndp_neighbor_advert.go",
- "ndp_neighbor_solicit.go",
- "ndp_options.go",
- "ndp_router_advert.go",
- "ndp_router_solicit.go",
- "ndpoptionidentifier_string.go",
- "tcp.go",
- "udp.go",
- ],
- visibility = ["//visibility:public"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/seqnum",
- "@com_github_google_btree//:go_default_library",
- ],
-)
-
-go_test(
- name = "header_x_test",
- size = "small",
- srcs = [
- "checksum_test.go",
- "ipv6_test.go",
- "ipversion_test.go",
- "tcp_test.go",
- ],
- deps = [
- ":header",
- "//pkg/rand",
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "@com_github_google_go_cmp//cmp:go_default_library",
- ],
-)
-
-go_test(
- name = "header_test",
- size = "small",
- srcs = [
- "eth_test.go",
- "ipv6_extension_headers_test.go",
- "ndp_test.go",
- ],
- library = ":header",
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "@com_github_google_go_cmp//cmp:go_default_library",
- ],
-)
diff --git a/pkg/tcpip/header/checksum_test.go b/pkg/tcpip/header/checksum_test.go
deleted file mode 100644
index 309403482..000000000
--- a/pkg/tcpip/header/checksum_test.go
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2019 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.
-
-// Package header provides the implementation of the encoding and decoding of
-// network protocol headers.
-package header_test
-
-import (
- "fmt"
- "math/rand"
- "testing"
-
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/header"
-)
-
-func TestChecksumVVWithOffset(t *testing.T) {
- testCases := []struct {
- name string
- vv buffer.VectorisedView
- off, size int
- initial uint16
- want uint16
- }{
- {
- name: "empty",
- vv: buffer.NewVectorisedView(0, []buffer.View{
- buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
- }),
- off: 0,
- size: 0,
- want: 0,
- },
- {
- name: "OneView",
- vv: buffer.NewVectorisedView(0, []buffer.View{
- buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
- }),
- off: 0,
- size: 5,
- want: 1294,
- },
- {
- name: "TwoViews",
- vv: buffer.NewVectorisedView(0, []buffer.View{
- buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
- buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
- }),
- off: 0,
- size: 11,
- want: 33819,
- },
- {
- name: "TwoViewsWithOffset",
- vv: buffer.NewVectorisedView(0, []buffer.View{
- buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
- buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
- }),
- off: 1,
- size: 11,
- want: 33819,
- },
- {
- name: "ThreeViewsWithOffset",
- vv: buffer.NewVectorisedView(0, []buffer.View{
- buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
- buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
- buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
- }),
- off: 7,
- size: 11,
- want: 33819,
- },
- {
- name: "ThreeViewsWithInitial",
- vv: buffer.NewVectorisedView(0, []buffer.View{
- buffer.NewViewFromBytes([]byte{77, 11, 33, 0, 55, 44}),
- buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
- buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123, 99}),
- }),
- initial: 77,
- off: 7,
- size: 11,
- want: 33896,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- if got, want := header.ChecksumVVWithOffset(tc.vv, tc.initial, tc.off, tc.size), tc.want; got != want {
- t.Errorf("header.ChecksumVVWithOffset(%v) = %v, want: %v", tc, got, tc.want)
- }
- v := tc.vv.ToView()
- v.TrimFront(tc.off)
- v.CapLength(tc.size)
- if got, want := header.Checksum(v, tc.initial), tc.want; got != want {
- t.Errorf("header.Checksum(%v) = %v, want: %v", tc, got, tc.want)
- }
- })
- }
-}
-
-func TestChecksum(t *testing.T) {
- var bufSizes = []int{0, 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128, 255, 256, 257, 1023, 1024}
- type testCase struct {
- buf []byte
- initial uint16
- csumOrig uint16
- csumNew uint16
- }
- testCases := make([]testCase, 100000)
- // Ensure same buffer generation for test consistency.
- rnd := rand.New(rand.NewSource(42))
- for i := range testCases {
- testCases[i].buf = make([]byte, bufSizes[i%len(bufSizes)])
- testCases[i].initial = uint16(rnd.Intn(65536))
- rnd.Read(testCases[i].buf)
- }
-
- for i := range testCases {
- testCases[i].csumOrig = header.ChecksumOld(testCases[i].buf, testCases[i].initial)
- testCases[i].csumNew = header.Checksum(testCases[i].buf, testCases[i].initial)
- if got, want := testCases[i].csumNew, testCases[i].csumOrig; got != want {
- t.Fatalf("new checksum for (buf = %x, initial = %d) does not match old got: %d, want: %d", testCases[i].buf, testCases[i].initial, got, want)
- }
- }
-}
-
-func BenchmarkChecksum(b *testing.B) {
- var bufSizes = []int{64, 128, 256, 512, 1024, 1500, 2048, 4096, 8192, 16384, 32767, 32768, 65535, 65536}
-
- checkSumImpls := []struct {
- fn func([]byte, uint16) uint16
- name string
- }{
- {header.ChecksumOld, fmt.Sprintf("checksum_old")},
- {header.Checksum, fmt.Sprintf("checksum")},
- }
-
- for _, csumImpl := range checkSumImpls {
- // Ensure same buffer generation for test consistency.
- rnd := rand.New(rand.NewSource(42))
- for _, bufSz := range bufSizes {
- b.Run(fmt.Sprintf("%s_%d", csumImpl.name, bufSz), func(b *testing.B) {
- tc := struct {
- buf []byte
- initial uint16
- csum uint16
- }{
- buf: make([]byte, bufSz),
- initial: uint16(rnd.Intn(65536)),
- }
- rnd.Read(tc.buf)
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- tc.csum = csumImpl.fn(tc.buf, tc.initial)
- }
- })
- }
- }
-}
diff --git a/pkg/tcpip/header/eth_test.go b/pkg/tcpip/header/eth_test.go
deleted file mode 100644
index 3bc8b2b21..000000000
--- a/pkg/tcpip/header/eth_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright 2018 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.
-
-package header
-
-import (
- "testing"
-
- "gvisor.dev/gvisor/pkg/tcpip"
-)
-
-func TestIsValidUnicastEthernetAddress(t *testing.T) {
- tests := []struct {
- name string
- addr tcpip.LinkAddress
- expected bool
- }{
- {
- "Nil",
- tcpip.LinkAddress([]byte(nil)),
- false,
- },
- {
- "Empty",
- tcpip.LinkAddress(""),
- false,
- },
- {
- "InvalidLength",
- tcpip.LinkAddress("\x01\x02\x03"),
- false,
- },
- {
- "Unspecified",
- unspecifiedEthernetAddress,
- false,
- },
- {
- "Multicast",
- tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
- false,
- },
- {
- "Valid",
- tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06"),
- true,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- if got := IsValidUnicastEthernetAddress(test.addr); got != test.expected {
- t.Fatalf("got IsValidUnicastEthernetAddress = %t, want = %t", got, test.expected)
- }
- })
- }
-}
-
-func TestIsMulticastEthernetAddress(t *testing.T) {
- tests := []struct {
- name string
- addr tcpip.LinkAddress
- expected bool
- }{
- {
- "Nil",
- tcpip.LinkAddress([]byte(nil)),
- false,
- },
- {
- "Empty",
- tcpip.LinkAddress(""),
- false,
- },
- {
- "InvalidLength",
- tcpip.LinkAddress("\x01\x02\x03"),
- false,
- },
- {
- "Unspecified",
- unspecifiedEthernetAddress,
- false,
- },
- {
- "Multicast",
- tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
- true,
- },
- {
- "Unicast",
- tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06"),
- false,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- if got := IsMulticastEthernetAddress(test.addr); got != test.expected {
- t.Fatalf("got IsMulticastEthernetAddress = %t, want = %t", got, test.expected)
- }
- })
- }
-}
-
-func TestEthernetAddressFromMulticastIPv4Address(t *testing.T) {
- tests := []struct {
- name string
- addr tcpip.Address
- expectedLinkAddr tcpip.LinkAddress
- }{
- {
- name: "IPv4 Multicast without 24th bit set",
- addr: "\xe0\x7e\xdc\xba",
- expectedLinkAddr: "\x01\x00\x5e\x7e\xdc\xba",
- },
- {
- name: "IPv4 Multicast with 24th bit set",
- addr: "\xe0\xfe\xdc\xba",
- expectedLinkAddr: "\x01\x00\x5e\x7e\xdc\xba",
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- if got := EthernetAddressFromMulticastIPv4Address(test.addr); got != test.expectedLinkAddr {
- t.Fatalf("got EthernetAddressFromMulticastIPv4Address(%s) = %s, want = %s", test.addr, got, test.expectedLinkAddr)
- }
- })
- }
-}
-
-func TestEthernetAddressFromMulticastIPv6Address(t *testing.T) {
- addr := tcpip.Address("\xff\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x1a")
- if got, want := EthernetAddressFromMulticastIPv6Address(addr), tcpip.LinkAddress("\x33\x33\x0d\x0e\x0f\x1a"); got != want {
- t.Fatalf("got EthernetAddressFromMulticastIPv6Address(%s) = %s, want = %s", addr, got, want)
- }
-}
diff --git a/pkg/tcpip/header/header_state_autogen.go b/pkg/tcpip/header/header_state_autogen.go
new file mode 100644
index 000000000..8e70640cd
--- /dev/null
+++ b/pkg/tcpip/header/header_state_autogen.go
@@ -0,0 +1,70 @@
+// automatically generated by stateify.
+
+package header
+
+import (
+ "gvisor.dev/gvisor/pkg/state"
+)
+
+func (s *SACKBlock) StateTypeName() string {
+ return "pkg/tcpip/header.SACKBlock"
+}
+
+func (s *SACKBlock) StateFields() []string {
+ return []string{
+ "Start",
+ "End",
+ }
+}
+
+func (s *SACKBlock) beforeSave() {}
+
+func (s *SACKBlock) StateSave(stateSinkObject state.Sink) {
+ s.beforeSave()
+ stateSinkObject.Save(0, &s.Start)
+ stateSinkObject.Save(1, &s.End)
+}
+
+func (s *SACKBlock) afterLoad() {}
+
+func (s *SACKBlock) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.Load(0, &s.Start)
+ stateSourceObject.Load(1, &s.End)
+}
+
+func (t *TCPOptions) StateTypeName() string {
+ return "pkg/tcpip/header.TCPOptions"
+}
+
+func (t *TCPOptions) StateFields() []string {
+ return []string{
+ "TS",
+ "TSVal",
+ "TSEcr",
+ "SACKBlocks",
+ }
+}
+
+func (t *TCPOptions) beforeSave() {}
+
+func (t *TCPOptions) StateSave(stateSinkObject state.Sink) {
+ t.beforeSave()
+ stateSinkObject.Save(0, &t.TS)
+ stateSinkObject.Save(1, &t.TSVal)
+ stateSinkObject.Save(2, &t.TSEcr)
+ stateSinkObject.Save(3, &t.SACKBlocks)
+}
+
+func (t *TCPOptions) afterLoad() {}
+
+func (t *TCPOptions) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.Load(0, &t.TS)
+ stateSourceObject.Load(1, &t.TSVal)
+ stateSourceObject.Load(2, &t.TSEcr)
+ stateSourceObject.Load(3, &t.SACKBlocks)
+}
+
+func init() {
+ state.Register((*SACKBlock)(nil))
+ state.Register((*TCPOptions)(nil))
+}
diff --git a/pkg/tcpip/header/ipv6_extension_headers_test.go b/pkg/tcpip/header/ipv6_extension_headers_test.go
deleted file mode 100644
index ab20c5f37..000000000
--- a/pkg/tcpip/header/ipv6_extension_headers_test.go
+++ /dev/null
@@ -1,992 +0,0 @@
-// 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.
-
-package header
-
-import (
- "bytes"
- "errors"
- "io"
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
-)
-
-// Equal returns true of a and b are equivalent.
-//
-// Note, Equal will return true if a and b hold the same Identifier value and
-// contain the same bytes in Buf, even if the bytes are split across views
-// differently.
-//
-// Needed to use cmp.Equal on IPv6RawPayloadHeader as it contains unexported
-// fields.
-func (a IPv6RawPayloadHeader) Equal(b IPv6RawPayloadHeader) bool {
- return a.Identifier == b.Identifier && bytes.Equal(a.Buf.ToView(), b.Buf.ToView())
-}
-
-// Equal returns true of a and b are equivalent.
-//
-// Note, Equal will return true if a and b hold equivalent ipv6OptionsExtHdrs.
-//
-// Needed to use cmp.Equal on IPv6RawPayloadHeader as it contains unexported
-// fields.
-func (a IPv6HopByHopOptionsExtHdr) Equal(b IPv6HopByHopOptionsExtHdr) bool {
- return bytes.Equal(a.ipv6OptionsExtHdr, b.ipv6OptionsExtHdr)
-}
-
-// Equal returns true of a and b are equivalent.
-//
-// Note, Equal will return true if a and b hold equivalent ipv6OptionsExtHdrs.
-//
-// Needed to use cmp.Equal on IPv6RawPayloadHeader as it contains unexported
-// fields.
-func (a IPv6DestinationOptionsExtHdr) Equal(b IPv6DestinationOptionsExtHdr) bool {
- return bytes.Equal(a.ipv6OptionsExtHdr, b.ipv6OptionsExtHdr)
-}
-
-func TestIPv6UnknownExtHdrOption(t *testing.T) {
- tests := []struct {
- name string
- identifier IPv6ExtHdrOptionIndentifier
- expectedUnknownAction IPv6OptionUnknownAction
- }{
- {
- name: "Skip with zero LSBs",
- identifier: 0,
- expectedUnknownAction: IPv6OptionUnknownActionSkip,
- },
- {
- name: "Discard with zero LSBs",
- identifier: 64,
- expectedUnknownAction: IPv6OptionUnknownActionDiscard,
- },
- {
- name: "Discard and ICMP with zero LSBs",
- identifier: 128,
- expectedUnknownAction: IPv6OptionUnknownActionDiscardSendICMP,
- },
- {
- name: "Discard and ICMP for non multicast destination with zero LSBs",
- identifier: 192,
- expectedUnknownAction: IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
- },
- {
- name: "Skip with non-zero LSBs",
- identifier: 63,
- expectedUnknownAction: IPv6OptionUnknownActionSkip,
- },
- {
- name: "Discard with non-zero LSBs",
- identifier: 127,
- expectedUnknownAction: IPv6OptionUnknownActionDiscard,
- },
- {
- name: "Discard and ICMP with non-zero LSBs",
- identifier: 191,
- expectedUnknownAction: IPv6OptionUnknownActionDiscardSendICMP,
- },
- {
- name: "Discard and ICMP for non multicast destination with non-zero LSBs",
- identifier: 255,
- expectedUnknownAction: IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- opt := &IPv6UnknownExtHdrOption{Identifier: test.identifier, Data: []byte{1, 2, 3, 4}}
- if a := opt.UnknownAction(); a != test.expectedUnknownAction {
- t.Fatalf("got UnknownAction() = %d, want = %d", a, test.expectedUnknownAction)
- }
- })
- }
-
-}
-
-func TestIPv6OptionsExtHdrIterErr(t *testing.T) {
- tests := []struct {
- name string
- bytes []byte
- err error
- }{
- {
- name: "Single unknown with zero length",
- bytes: []byte{255, 0},
- },
- {
- name: "Single unknown with non-zero length",
- bytes: []byte{255, 3, 1, 2, 3},
- },
- {
- name: "Two options",
- bytes: []byte{
- 255, 0,
- 254, 1, 1,
- },
- },
- {
- name: "Three options",
- bytes: []byte{
- 255, 0,
- 254, 1, 1,
- 253, 4, 2, 3, 4, 5,
- },
- },
- {
- name: "Single unknown only identifier",
- bytes: []byte{255},
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Single unknown too small with length = 1",
- bytes: []byte{255, 1},
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Single unknown too small with length = 2",
- bytes: []byte{255, 2, 1},
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Valid first with second unknown only identifier",
- bytes: []byte{
- 255, 0,
- 254,
- },
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Valid first with second unknown missing data",
- bytes: []byte{
- 255, 0,
- 254, 1,
- },
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Valid first with second unknown too small",
- bytes: []byte{
- 255, 0,
- 254, 2, 1,
- },
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "One Pad1",
- bytes: []byte{0},
- },
- {
- name: "Multiple Pad1",
- bytes: []byte{0, 0, 0},
- },
- {
- name: "Multiple PadN",
- bytes: []byte{
- // Pad3
- 1, 1, 1,
-
- // Pad5
- 1, 3, 1, 2, 3,
- },
- },
- {
- name: "Pad5 too small middle of data buffer",
- bytes: []byte{1, 3, 1, 2},
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Pad5 no data",
- bytes: []byte{1, 3},
- err: io.ErrUnexpectedEOF,
- },
- }
-
- check := func(t *testing.T, it IPv6OptionsExtHdrOptionsIterator, expectedErr error) {
- for i := 0; ; i++ {
- _, done, err := it.Next()
- if err != nil {
- // If we encountered a non-nil error while iterating, make sure it is
- // is the same error as expectedErr.
- if !errors.Is(err, expectedErr) {
- t.Fatalf("got %d-th Next() = %v, want = %v", i, err, expectedErr)
- }
-
- return
- }
- if done {
- // If we are done (without an error), make sure that we did not expect
- // an error.
- if expectedErr != nil {
- t.Fatalf("expected error when iterating; want = %s", expectedErr)
- }
-
- return
- }
- }
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- t.Run("Hop By Hop", func(t *testing.T) {
- extHdr := IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: test.bytes}
- check(t, extHdr.Iter(), test.err)
- })
-
- t.Run("Destination", func(t *testing.T) {
- extHdr := IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: test.bytes}
- check(t, extHdr.Iter(), test.err)
- })
- })
- }
-}
-
-func TestIPv6OptionsExtHdrIter(t *testing.T) {
- tests := []struct {
- name string
- bytes []byte
- expected []IPv6ExtHdrOption
- }{
- {
- name: "Single unknown with zero length",
- bytes: []byte{255, 0},
- expected: []IPv6ExtHdrOption{
- &IPv6UnknownExtHdrOption{Identifier: 255, Data: []byte{}},
- },
- },
- {
- name: "Single unknown with non-zero length",
- bytes: []byte{255, 3, 1, 2, 3},
- expected: []IPv6ExtHdrOption{
- &IPv6UnknownExtHdrOption{Identifier: 255, Data: []byte{1, 2, 3}},
- },
- },
- {
- name: "Single Pad1",
- bytes: []byte{0},
- },
- {
- name: "Two Pad1",
- bytes: []byte{0, 0},
- },
- {
- name: "Single Pad3",
- bytes: []byte{1, 1, 1},
- },
- {
- name: "Single Pad5",
- bytes: []byte{1, 3, 1, 2, 3},
- },
- {
- name: "Multiple Pad",
- bytes: []byte{
- // Pad1
- 0,
-
- // Pad2
- 1, 0,
-
- // Pad3
- 1, 1, 1,
-
- // Pad4
- 1, 2, 1, 2,
-
- // Pad5
- 1, 3, 1, 2, 3,
- },
- },
- {
- name: "Multiple options",
- bytes: []byte{
- // Pad1
- 0,
-
- // Unknown
- 255, 0,
-
- // Pad2
- 1, 0,
-
- // Unknown
- 254, 1, 1,
-
- // Pad3
- 1, 1, 1,
-
- // Unknown
- 253, 4, 2, 3, 4, 5,
-
- // Pad4
- 1, 2, 1, 2,
- },
- expected: []IPv6ExtHdrOption{
- &IPv6UnknownExtHdrOption{Identifier: 255, Data: []byte{}},
- &IPv6UnknownExtHdrOption{Identifier: 254, Data: []byte{1}},
- &IPv6UnknownExtHdrOption{Identifier: 253, Data: []byte{2, 3, 4, 5}},
- },
- },
- }
-
- checkIter := func(t *testing.T, it IPv6OptionsExtHdrOptionsIterator, expected []IPv6ExtHdrOption) {
- for i, e := range expected {
- opt, done, err := it.Next()
- if err != nil {
- t.Errorf("(i=%d) Next(): %s", i, err)
- }
- if done {
- t.Errorf("(i=%d) unexpectedly done iterating", i)
- }
- if diff := cmp.Diff(e, opt); diff != "" {
- t.Errorf("(i=%d) got option mismatch (-want +got):\n%s", i, diff)
- }
-
- if t.Failed() {
- t.FailNow()
- }
- }
-
- opt, done, err := it.Next()
- if err != nil {
- t.Errorf("(last) Next(): %s", err)
- }
- if !done {
- t.Errorf("(last) iterator unexpectedly not done")
- }
- if opt != nil {
- t.Errorf("(last) got Next() = %T, want = nil", opt)
- }
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- t.Run("Hop By Hop", func(t *testing.T) {
- extHdr := IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: test.bytes}
- checkIter(t, extHdr.Iter(), test.expected)
- })
-
- t.Run("Destination", func(t *testing.T) {
- extHdr := IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: test.bytes}
- checkIter(t, extHdr.Iter(), test.expected)
- })
- })
- }
-}
-
-func TestIPv6RoutingExtHdr(t *testing.T) {
- tests := []struct {
- name string
- bytes []byte
- segmentsLeft uint8
- }{
- {
- name: "Zeroes",
- bytes: []byte{0, 0, 0, 0, 0, 0},
- segmentsLeft: 0,
- },
- {
- name: "Ones",
- bytes: []byte{1, 1, 1, 1, 1, 1},
- segmentsLeft: 1,
- },
- {
- name: "Mixed",
- bytes: []byte{1, 2, 3, 4, 5, 6},
- segmentsLeft: 2,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- extHdr := IPv6RoutingExtHdr(test.bytes)
- if got := extHdr.SegmentsLeft(); got != test.segmentsLeft {
- t.Errorf("got SegmentsLeft() = %d, want = %d", got, test.segmentsLeft)
- }
- })
- }
-}
-
-func TestIPv6FragmentExtHdr(t *testing.T) {
- tests := []struct {
- name string
- bytes [6]byte
- fragmentOffset uint16
- more bool
- id uint32
- }{
- {
- name: "Zeroes",
- bytes: [6]byte{0, 0, 0, 0, 0, 0},
- fragmentOffset: 0,
- more: false,
- id: 0,
- },
- {
- name: "Ones",
- bytes: [6]byte{0, 9, 0, 0, 0, 1},
- fragmentOffset: 1,
- more: true,
- id: 1,
- },
- {
- name: "Mixed",
- bytes: [6]byte{68, 9, 128, 4, 2, 1},
- fragmentOffset: 2177,
- more: true,
- id: 2147746305,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- extHdr := IPv6FragmentExtHdr(test.bytes)
- if got := extHdr.FragmentOffset(); got != test.fragmentOffset {
- t.Errorf("got FragmentOffset() = %d, want = %d", got, test.fragmentOffset)
- }
- if got := extHdr.More(); got != test.more {
- t.Errorf("got More() = %t, want = %t", got, test.more)
- }
- if got := extHdr.ID(); got != test.id {
- t.Errorf("got ID() = %d, want = %d", got, test.id)
- }
- })
- }
-}
-
-func makeVectorisedViewFromByteBuffers(bs ...[]byte) buffer.VectorisedView {
- size := 0
- var vs []buffer.View
-
- for _, b := range bs {
- vs = append(vs, buffer.View(b))
- size += len(b)
- }
-
- return buffer.NewVectorisedView(size, vs)
-}
-
-func TestIPv6ExtHdrIterErr(t *testing.T) {
- tests := []struct {
- name string
- firstNextHdr IPv6ExtensionHeaderIdentifier
- payload buffer.VectorisedView
- err error
- }{
- {
- name: "Upper layer only without data",
- firstNextHdr: 255,
- },
- {
- name: "Upper layer only with data",
- firstNextHdr: 255,
- payload: makeVectorisedViewFromByteBuffers([]byte{1, 2, 3, 4}),
- },
- {
- name: "No next header",
- firstNextHdr: IPv6NoNextHeaderIdentifier,
- },
- {
- name: "No next header with data",
- firstNextHdr: IPv6NoNextHeaderIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{1, 2, 3, 4}),
- },
- {
- name: "Valid single hop by hop",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 1, 4, 1, 2, 3, 4}),
- },
- {
- name: "Hop by hop too small",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 1, 4, 1, 2, 3}),
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Valid single fragment",
- firstNextHdr: IPv6FragmentExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 68, 9, 128, 4, 2, 1}),
- },
- {
- name: "Fragment too small",
- firstNextHdr: IPv6FragmentExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 68, 9, 128, 4, 2}),
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Valid single destination",
- firstNextHdr: IPv6DestinationOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 1, 4, 1, 2, 3, 4}),
- },
- {
- name: "Destination too small",
- firstNextHdr: IPv6DestinationOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 1, 4, 1, 2, 3}),
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Valid single routing",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 1, 2, 3, 4, 5, 6}),
- },
- {
- name: "Valid single routing across views",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 1, 2}, []byte{3, 4, 5, 6}),
- },
- {
- name: "Routing too small with zero length field",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 0, 1, 2, 3, 4, 5}),
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Valid routing with non-zero length field",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8}),
- },
- {
- name: "Valid routing with non-zero length field across views",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 1, 1, 2, 3, 4, 5, 6}, []byte{1, 2, 3, 4, 5, 6, 7, 8}),
- },
- {
- name: "Routing too small with non-zero length field",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7}),
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Routing too small with non-zero length field across views",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{255, 1, 1, 2, 3, 4, 5, 6}, []byte{1, 2, 3, 4, 5, 6, 7}),
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "Mixed",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Hop By Hop Options extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4,
-
- // (Atomic) Fragment extension header.
- //
- // Reserved bits are 1 which should not affect anything.
- uint8(IPv6RoutingExtHdrIdentifier), 255, 0, 6, 128, 4, 2, 1,
-
- // Routing extension header.
- uint8(IPv6DestinationOptionsExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6,
-
- // Destination Options extension header.
- 255, 0, 255, 4, 1, 2, 3, 4,
-
- // Upper layer data.
- 1, 2, 3, 4,
- }),
- },
- {
- name: "Mixed without upper layer data",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Hop By Hop Options extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4,
-
- // (Atomic) Fragment extension header.
- //
- // Reserved bits are 1 which should not affect anything.
- uint8(IPv6RoutingExtHdrIdentifier), 255, 0, 6, 128, 4, 2, 1,
-
- // Routing extension header.
- uint8(IPv6DestinationOptionsExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6,
-
- // Destination Options extension header.
- 255, 0, 255, 4, 1, 2, 3, 4,
- }),
- },
- {
- name: "Mixed without upper layer data but last ext hdr too small",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Hop By Hop Options extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4,
-
- // (Atomic) Fragment extension header.
- //
- // Reserved bits are 1 which should not affect anything.
- uint8(IPv6RoutingExtHdrIdentifier), 255, 0, 6, 128, 4, 2, 1,
-
- // Routing extension header.
- uint8(IPv6DestinationOptionsExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6,
-
- // Destination Options extension header.
- 255, 0, 255, 4, 1, 2, 3,
- }),
- err: io.ErrUnexpectedEOF,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- it := MakeIPv6PayloadIterator(test.firstNextHdr, test.payload)
-
- for i := 0; ; i++ {
- _, done, err := it.Next()
- if err != nil {
- // If we encountered a non-nil error while iterating, make sure it is
- // is the same error as test.err.
- if !errors.Is(err, test.err) {
- t.Fatalf("got %d-th Next() = %v, want = %v", i, err, test.err)
- }
-
- return
- }
- if done {
- // If we are done (without an error), make sure that we did not expect
- // an error.
- if test.err != nil {
- t.Fatalf("expected error when iterating; want = %s", test.err)
- }
-
- return
- }
- }
- })
- }
-}
-
-func TestIPv6ExtHdrIter(t *testing.T) {
- routingExtHdrWithUpperLayerData := buffer.View([]byte{255, 0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4})
- upperLayerData := buffer.View([]byte{1, 2, 3, 4})
- tests := []struct {
- name string
- firstNextHdr IPv6ExtensionHeaderIdentifier
- payload buffer.VectorisedView
- expected []IPv6PayloadHeader
- }{
- // With a non-atomic fragment that is not the first fragment, the payload
- // after the fragment will not be parsed because the payload is expected to
- // only hold upper layer data.
- {
- name: "hopbyhop - fragment (not first) - routing - upper",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Hop By Hop extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4,
-
- // Fragment extension header.
- //
- // More = 1, Fragment Offset = 2117, ID = 2147746305
- uint8(IPv6RoutingExtHdrIdentifier), 0, 68, 9, 128, 4, 2, 1,
-
- // Routing extension header.
- //
- // Even though we have a routing ext header here, it should be
- // be interpretted as raw bytes as only the first fragment is expected
- // to hold headers.
- 255, 0, 1, 2, 3, 4, 5, 6,
-
- // Upper layer data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}},
- IPv6FragmentExtHdr([6]byte{68, 9, 128, 4, 2, 1}),
- IPv6RawPayloadHeader{
- Identifier: IPv6RoutingExtHdrIdentifier,
- Buf: routingExtHdrWithUpperLayerData.ToVectorisedView(),
- },
- },
- },
- {
- name: "hopbyhop - fragment (first) - routing - upper",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Hop By Hop extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4,
-
- // Fragment extension header.
- //
- // More = 1, Fragment Offset = 0, ID = 2147746305
- uint8(IPv6RoutingExtHdrIdentifier), 0, 0, 1, 128, 4, 2, 1,
-
- // Routing extension header.
- 255, 0, 1, 2, 3, 4, 5, 6,
-
- // Upper layer data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}},
- IPv6FragmentExtHdr([6]byte{0, 1, 128, 4, 2, 1}),
- IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}),
- IPv6RawPayloadHeader{
- Identifier: 255,
- Buf: upperLayerData.ToVectorisedView(),
- },
- },
- },
- {
- name: "fragment - routing - upper (across views)",
- firstNextHdr: IPv6FragmentExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Fragment extension header.
- uint8(IPv6RoutingExtHdrIdentifier), 0, 68, 9, 128, 4, 2, 1,
-
- // Routing extension header.
- 255, 0, 1, 2}, []byte{3, 4, 5, 6,
-
- // Upper layer data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6FragmentExtHdr([6]byte{68, 9, 128, 4, 2, 1}),
- IPv6RawPayloadHeader{
- Identifier: IPv6RoutingExtHdrIdentifier,
- Buf: routingExtHdrWithUpperLayerData.ToVectorisedView(),
- },
- },
- },
-
- // If we have an atomic fragment, the payload following the fragment
- // extension header should be parsed normally.
- {
- name: "atomic fragment - routing - destination - upper",
- firstNextHdr: IPv6FragmentExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Fragment extension header.
- //
- // Reserved bits are 1 which should not affect anything.
- uint8(IPv6RoutingExtHdrIdentifier), 255, 0, 6, 128, 4, 2, 1,
-
- // Routing extension header.
- uint8(IPv6DestinationOptionsExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6,
-
- // Destination Options extension header.
- 255, 0, 1, 4, 1, 2, 3, 4,
-
- // Upper layer data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}),
- IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}),
- IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}},
- IPv6RawPayloadHeader{
- Identifier: 255,
- Buf: upperLayerData.ToVectorisedView(),
- },
- },
- },
- {
- name: "atomic fragment - routing - upper (across views)",
- firstNextHdr: IPv6FragmentExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Fragment extension header.
- //
- // Reserved bits are 1 which should not affect anything.
- uint8(IPv6RoutingExtHdrIdentifier), 255, 0, 6}, []byte{128, 4, 2, 1,
-
- // Routing extension header.
- 255, 0, 1, 2}, []byte{3, 4, 5, 6,
-
- // Upper layer data.
- 1, 2}, []byte{3, 4}),
- expected: []IPv6PayloadHeader{
- IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}),
- IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}),
- IPv6RawPayloadHeader{
- Identifier: 255,
- Buf: makeVectorisedViewFromByteBuffers(upperLayerData[:2], upperLayerData[2:]),
- },
- },
- },
- {
- name: "atomic fragment - destination - no next header",
- firstNextHdr: IPv6FragmentExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Fragment extension header.
- //
- // Res (Reserved) bits are 1 which should not affect anything.
- uint8(IPv6DestinationOptionsExtHdrIdentifier), 0, 0, 6, 128, 4, 2, 1,
-
- // Destination Options extension header.
- uint8(IPv6NoNextHeaderIdentifier), 0, 1, 4, 1, 2, 3, 4,
-
- // Random data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}),
- IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}},
- },
- },
- {
- name: "routing - atomic fragment - no next header",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Routing extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6,
-
- // Fragment extension header.
- //
- // Reserved bits are 1 which should not affect anything.
- uint8(IPv6NoNextHeaderIdentifier), 0, 0, 6, 128, 4, 2, 1,
-
- // Random data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}),
- IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}),
- },
- },
- {
- name: "routing - atomic fragment - no next header (across views)",
- firstNextHdr: IPv6RoutingExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Routing extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6,
-
- // Fragment extension header.
- //
- // Reserved bits are 1 which should not affect anything.
- uint8(IPv6NoNextHeaderIdentifier), 255, 0, 6}, []byte{128, 4, 2, 1,
-
- // Random data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}),
- IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}),
- },
- },
- {
- name: "hopbyhop - routing - fragment - no next header",
- firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier,
- payload: makeVectorisedViewFromByteBuffers([]byte{
- // Hop By Hop Options extension header.
- uint8(IPv6RoutingExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4,
-
- // Routing extension header.
- uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6,
-
- // Fragment extension header.
- //
- // Fragment Offset = 32; Res = 6.
- uint8(IPv6NoNextHeaderIdentifier), 0, 1, 6, 128, 4, 2, 1,
-
- // Random data.
- 1, 2, 3, 4,
- }),
- expected: []IPv6PayloadHeader{
- IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}},
- IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}),
- IPv6FragmentExtHdr([6]byte{1, 6, 128, 4, 2, 1}),
- IPv6RawPayloadHeader{
- Identifier: IPv6NoNextHeaderIdentifier,
- Buf: upperLayerData.ToVectorisedView(),
- },
- },
- },
-
- // Test the raw payload for common transport layer protocol numbers.
- {
- name: "TCP raw payload",
- firstNextHdr: IPv6ExtensionHeaderIdentifier(TCPProtocolNumber),
- payload: makeVectorisedViewFromByteBuffers(upperLayerData),
- expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{
- Identifier: IPv6ExtensionHeaderIdentifier(TCPProtocolNumber),
- Buf: upperLayerData.ToVectorisedView(),
- }},
- },
- {
- name: "UDP raw payload",
- firstNextHdr: IPv6ExtensionHeaderIdentifier(UDPProtocolNumber),
- payload: makeVectorisedViewFromByteBuffers(upperLayerData),
- expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{
- Identifier: IPv6ExtensionHeaderIdentifier(UDPProtocolNumber),
- Buf: upperLayerData.ToVectorisedView(),
- }},
- },
- {
- name: "ICMPv4 raw payload",
- firstNextHdr: IPv6ExtensionHeaderIdentifier(ICMPv4ProtocolNumber),
- payload: makeVectorisedViewFromByteBuffers(upperLayerData),
- expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{
- Identifier: IPv6ExtensionHeaderIdentifier(ICMPv4ProtocolNumber),
- Buf: upperLayerData.ToVectorisedView(),
- }},
- },
- {
- name: "ICMPv6 raw payload",
- firstNextHdr: IPv6ExtensionHeaderIdentifier(ICMPv6ProtocolNumber),
- payload: makeVectorisedViewFromByteBuffers(upperLayerData),
- expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{
- Identifier: IPv6ExtensionHeaderIdentifier(ICMPv6ProtocolNumber),
- Buf: upperLayerData.ToVectorisedView(),
- }},
- },
- {
- name: "Unknwon next header raw payload",
- firstNextHdr: 255,
- payload: makeVectorisedViewFromByteBuffers(upperLayerData),
- expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{
- Identifier: 255,
- Buf: upperLayerData.ToVectorisedView(),
- }},
- },
- {
- name: "Unknwon next header raw payload (across views)",
- firstNextHdr: 255,
- payload: makeVectorisedViewFromByteBuffers(upperLayerData[:2], upperLayerData[2:]),
- expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{
- Identifier: 255,
- Buf: makeVectorisedViewFromByteBuffers(upperLayerData[:2], upperLayerData[2:]),
- }},
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- it := MakeIPv6PayloadIterator(test.firstNextHdr, test.payload)
-
- for i, e := range test.expected {
- extHdr, done, err := it.Next()
- if err != nil {
- t.Errorf("(i=%d) Next(): %s", i, err)
- }
- if done {
- t.Errorf("(i=%d) unexpectedly done iterating", i)
- }
- if diff := cmp.Diff(e, extHdr); diff != "" {
- t.Errorf("(i=%d) got ext hdr mismatch (-want +got):\n%s", i, diff)
- }
-
- if t.Failed() {
- t.FailNow()
- }
- }
-
- extHdr, done, err := it.Next()
- if err != nil {
- t.Errorf("(last) Next(): %s", err)
- }
- if !done {
- t.Errorf("(last) iterator unexpectedly not done")
- }
- if extHdr != nil {
- t.Errorf("(last) got Next() = %T, want = nil", extHdr)
- }
- })
- }
-}
diff --git a/pkg/tcpip/header/ipv6_test.go b/pkg/tcpip/header/ipv6_test.go
deleted file mode 100644
index 426a873b1..000000000
--- a/pkg/tcpip/header/ipv6_test.go
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright 2019 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.
-
-package header_test
-
-import (
- "bytes"
- "crypto/sha256"
- "fmt"
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/rand"
- "gvisor.dev/gvisor/pkg/tcpip"
- "gvisor.dev/gvisor/pkg/tcpip/header"
-)
-
-const (
- linkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06")
- linkLocalAddr = tcpip.Address("\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")
- linkLocalMulticastAddr = tcpip.Address("\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")
- uniqueLocalAddr1 = tcpip.Address("\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")
- uniqueLocalAddr2 = tcpip.Address("\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02")
- globalAddr = tcpip.Address("\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")
-)
-
-func TestEthernetAdddressToModifiedEUI64(t *testing.T) {
- expectedIID := [header.IIDSize]byte{0, 2, 3, 255, 254, 4, 5, 6}
-
- if diff := cmp.Diff(expectedIID, header.EthernetAddressToModifiedEUI64(linkAddr)); diff != "" {
- t.Errorf("EthernetAddressToModifiedEUI64(%s) mismatch (-want +got):\n%s", linkAddr, diff)
- }
-
- var buf [header.IIDSize]byte
- header.EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, buf[:])
- if diff := cmp.Diff(expectedIID, buf); diff != "" {
- t.Errorf("EthernetAddressToModifiedEUI64IntoBuf(%s, _) mismatch (-want +got):\n%s", linkAddr, diff)
- }
-}
-
-func TestLinkLocalAddr(t *testing.T) {
- if got, want := header.LinkLocalAddr(linkAddr), tcpip.Address("\xfe\x80\x00\x00\x00\x00\x00\x00\x00\x02\x03\xff\xfe\x04\x05\x06"); got != want {
- t.Errorf("got LinkLocalAddr(%s) = %s, want = %s", linkAddr, got, want)
- }
-}
-
-func TestAppendOpaqueInterfaceIdentifier(t *testing.T) {
- var secretKeyBuf [header.OpaqueIIDSecretKeyMinBytes * 2]byte
- if n, err := rand.Read(secretKeyBuf[:]); err != nil {
- t.Fatalf("rand.Read(_): %s", err)
- } else if want := header.OpaqueIIDSecretKeyMinBytes * 2; n != want {
- t.Fatalf("expected rand.Read to read %d bytes, read %d bytes", want, n)
- }
-
- tests := []struct {
- name string
- prefix tcpip.Subnet
- nicName string
- dadCounter uint8
- secretKey []byte
- }{
- {
- name: "SecretKey of minimum size",
- prefix: header.IPv6LinkLocalPrefix.Subnet(),
- nicName: "eth0",
- dadCounter: 0,
- secretKey: secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes],
- },
- {
- name: "SecretKey of less than minimum size",
- prefix: func() tcpip.Subnet {
- addrWithPrefix := tcpip.AddressWithPrefix{
- Address: "\x01\x02\x03\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
- PrefixLen: header.IIDOffsetInIPv6Address * 8,
- }
- return addrWithPrefix.Subnet()
- }(),
- nicName: "eth10",
- dadCounter: 1,
- secretKey: secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes/2],
- },
- {
- name: "SecretKey of more than minimum size",
- prefix: func() tcpip.Subnet {
- addrWithPrefix := tcpip.AddressWithPrefix{
- Address: "\x01\x02\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
- PrefixLen: header.IIDOffsetInIPv6Address * 8,
- }
- return addrWithPrefix.Subnet()
- }(),
- nicName: "eth11",
- dadCounter: 2,
- secretKey: secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes*2],
- },
- {
- name: "Nil SecretKey and empty nicName",
- prefix: func() tcpip.Subnet {
- addrWithPrefix := tcpip.AddressWithPrefix{
- Address: "\x01\x02\x03\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
- PrefixLen: header.IIDOffsetInIPv6Address * 8,
- }
- return addrWithPrefix.Subnet()
- }(),
- nicName: "",
- dadCounter: 3,
- secretKey: nil,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- h := sha256.New()
- h.Write([]byte(test.prefix.ID()[:header.IIDOffsetInIPv6Address]))
- h.Write([]byte(test.nicName))
- h.Write([]byte{test.dadCounter})
- if k := test.secretKey; k != nil {
- h.Write(k)
- }
- var hashSum [sha256.Size]byte
- h.Sum(hashSum[:0])
- want := hashSum[:header.IIDSize]
-
- // Passing a nil buffer should result in a new buffer returned with the
- // IID.
- if got := header.AppendOpaqueInterfaceIdentifier(nil, test.prefix, test.nicName, test.dadCounter, test.secretKey); !bytes.Equal(got, want) {
- t.Errorf("got AppendOpaqueInterfaceIdentifier(nil, %s, %s, %d, %x) = %x, want = %x", test.prefix, test.nicName, test.dadCounter, test.secretKey, got, want)
- }
-
- // Passing a buffer with sufficient capacity for the IID should populate
- // the buffer provided.
- var iidBuf [header.IIDSize]byte
- if got := header.AppendOpaqueInterfaceIdentifier(iidBuf[:0], test.prefix, test.nicName, test.dadCounter, test.secretKey); !bytes.Equal(got, want) {
- t.Errorf("got AppendOpaqueInterfaceIdentifier(iidBuf[:0], %s, %s, %d, %x) = %x, want = %x", test.prefix, test.nicName, test.dadCounter, test.secretKey, got, want)
- }
- if got := iidBuf[:]; !bytes.Equal(got, want) {
- t.Errorf("got iidBuf = %x, want = %x", got, want)
- }
- })
- }
-}
-
-func TestLinkLocalAddrWithOpaqueIID(t *testing.T) {
- var secretKeyBuf [header.OpaqueIIDSecretKeyMinBytes * 2]byte
- if n, err := rand.Read(secretKeyBuf[:]); err != nil {
- t.Fatalf("rand.Read(_): %s", err)
- } else if want := header.OpaqueIIDSecretKeyMinBytes * 2; n != want {
- t.Fatalf("expected rand.Read to read %d bytes, read %d bytes", want, n)
- }
-
- prefix := header.IPv6LinkLocalPrefix.Subnet()
-
- tests := []struct {
- name string
- prefix tcpip.Subnet
- nicName string
- dadCounter uint8
- secretKey []byte
- }{
- {
- name: "SecretKey of minimum size",
- nicName: "eth0",
- dadCounter: 0,
- secretKey: secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes],
- },
- {
- name: "SecretKey of less than minimum size",
- nicName: "eth10",
- dadCounter: 1,
- secretKey: secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes/2],
- },
- {
- name: "SecretKey of more than minimum size",
- nicName: "eth11",
- dadCounter: 2,
- secretKey: secretKeyBuf[:header.OpaqueIIDSecretKeyMinBytes*2],
- },
- {
- name: "Nil SecretKey and empty nicName",
- nicName: "",
- dadCounter: 3,
- secretKey: nil,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- addrBytes := [header.IPv6AddressSize]byte{
- 0: 0xFE,
- 1: 0x80,
- }
-
- want := tcpip.Address(header.AppendOpaqueInterfaceIdentifier(
- addrBytes[:header.IIDOffsetInIPv6Address],
- prefix,
- test.nicName,
- test.dadCounter,
- test.secretKey,
- ))
-
- if got := header.LinkLocalAddrWithOpaqueIID(test.nicName, test.dadCounter, test.secretKey); got != want {
- t.Errorf("got LinkLocalAddrWithOpaqueIID(%s, %d, %x) = %s, want = %s", test.nicName, test.dadCounter, test.secretKey, got, want)
- }
- })
- }
-}
-
-func TestIsV6UniqueLocalAddress(t *testing.T) {
- tests := []struct {
- name string
- addr tcpip.Address
- expected bool
- }{
- {
- name: "Valid Unique 1",
- addr: uniqueLocalAddr1,
- expected: true,
- },
- {
- name: "Valid Unique 2",
- addr: uniqueLocalAddr1,
- expected: true,
- },
- {
- name: "Link Local",
- addr: linkLocalAddr,
- expected: false,
- },
- {
- name: "Global",
- addr: globalAddr,
- expected: false,
- },
- {
- name: "IPv4",
- addr: "\x01\x02\x03\x04",
- expected: false,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- if got := header.IsV6UniqueLocalAddress(test.addr); got != test.expected {
- t.Errorf("got header.IsV6UniqueLocalAddress(%s) = %t, want = %t", test.addr, got, test.expected)
- }
- })
- }
-}
-
-func TestIsV6LinkLocalMulticastAddress(t *testing.T) {
- tests := []struct {
- name string
- addr tcpip.Address
- expected bool
- }{
- {
- name: "Valid Link Local Multicast",
- addr: linkLocalMulticastAddr,
- expected: true,
- },
- {
- name: "Valid Link Local Multicast with flags",
- addr: "\xff\xf2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
- expected: true,
- },
- {
- name: "Link Local Unicast",
- addr: linkLocalAddr,
- expected: false,
- },
- {
- name: "IPv4 Multicast",
- addr: "\xe0\x00\x00\x01",
- expected: false,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- if got := header.IsV6LinkLocalMulticastAddress(test.addr); got != test.expected {
- t.Errorf("got header.IsV6LinkLocalMulticastAddress(%s) = %t, want = %t", test.addr, got, test.expected)
- }
- })
- }
-}
-
-func TestIsV6LinkLocalAddress(t *testing.T) {
- tests := []struct {
- name string
- addr tcpip.Address
- expected bool
- }{
- {
- name: "Valid Link Local Unicast",
- addr: linkLocalAddr,
- expected: true,
- },
- {
- name: "Link Local Multicast",
- addr: linkLocalMulticastAddr,
- expected: false,
- },
- {
- name: "Unique Local",
- addr: uniqueLocalAddr1,
- expected: false,
- },
- {
- name: "Global",
- addr: globalAddr,
- expected: false,
- },
- {
- name: "IPv4 Link Local",
- addr: "\xa9\xfe\x00\x01",
- expected: false,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- if got := header.IsV6LinkLocalAddress(test.addr); got != test.expected {
- t.Errorf("got header.IsV6LinkLocalAddress(%s) = %t, want = %t", test.addr, got, test.expected)
- }
- })
- }
-}
-
-func TestScopeForIPv6Address(t *testing.T) {
- tests := []struct {
- name string
- addr tcpip.Address
- scope header.IPv6AddressScope
- err *tcpip.Error
- }{
- {
- name: "Unique Local",
- addr: uniqueLocalAddr1,
- scope: header.UniqueLocalScope,
- err: nil,
- },
- {
- name: "Link Local Unicast",
- addr: linkLocalAddr,
- scope: header.LinkLocalScope,
- err: nil,
- },
- {
- name: "Link Local Multicast",
- addr: linkLocalMulticastAddr,
- scope: header.LinkLocalScope,
- err: nil,
- },
- {
- name: "Global",
- addr: globalAddr,
- scope: header.GlobalScope,
- err: nil,
- },
- {
- name: "IPv4",
- addr: "\x01\x02\x03\x04",
- scope: header.GlobalScope,
- err: tcpip.ErrBadAddress,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- got, err := header.ScopeForIPv6Address(test.addr)
- if err != test.err {
- t.Errorf("got header.IsV6UniqueLocalAddress(%s) = (_, %v), want = (_, %v)", test.addr, err, test.err)
- }
- if got != test.scope {
- t.Errorf("got header.IsV6UniqueLocalAddress(%s) = (%d, _), want = (%d, _)", test.addr, got, test.scope)
- }
- })
- }
-}
-
-func TestSolicitedNodeAddr(t *testing.T) {
- tests := []struct {
- addr tcpip.Address
- want tcpip.Address
- }{
- {
- addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\xa0",
- want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x0e\x0f\xa0",
- },
- {
- addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\xdd\x0e\x0f\xa0",
- want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x0e\x0f\xa0",
- },
- {
- addr: "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\xdd\x01\x02\x03",
- want: "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x01\x02\x03",
- },
- }
-
- for _, test := range tests {
- t.Run(fmt.Sprintf("%s", test.addr), func(t *testing.T) {
- if got := header.SolicitedNodeAddr(test.addr); got != test.want {
- t.Fatalf("got header.SolicitedNodeAddr(%s) = %s, want = %s", test.addr, got, test.want)
- }
- })
- }
-}
diff --git a/pkg/tcpip/header/ipversion_test.go b/pkg/tcpip/header/ipversion_test.go
deleted file mode 100644
index 17a49d4fa..000000000
--- a/pkg/tcpip/header/ipversion_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 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.
-
-package header_test
-
-import (
- "testing"
-
- "gvisor.dev/gvisor/pkg/tcpip/header"
-)
-
-func TestIPv4(t *testing.T) {
- b := header.IPv4(make([]byte, header.IPv4MinimumSize))
- b.Encode(&header.IPv4Fields{IHL: header.IPv4MinimumSize})
-
- const want = header.IPv4Version
- if v := header.IPVersion(b); v != want {
- t.Fatalf("Bad version, want %v, got %v", want, v)
- }
-}
-
-func TestIPv6(t *testing.T) {
- b := header.IPv6(make([]byte, header.IPv6MinimumSize))
- b.Encode(&header.IPv6Fields{})
-
- const want = header.IPv6Version
- if v := header.IPVersion(b); v != want {
- t.Fatalf("Bad version, want %v, got %v", want, v)
- }
-}
-
-func TestOtherVersion(t *testing.T) {
- const want = header.IPv4Version + header.IPv6Version
- b := make([]byte, 1)
- b[0] = want << 4
-
- if v := header.IPVersion(b); v != want {
- t.Fatalf("Bad version, want %v, got %v", want, v)
- }
-}
-
-func TestTooShort(t *testing.T) {
- b := make([]byte, 1)
- b[0] = (header.IPv4Version + header.IPv6Version) << 4
-
- // Get the version of a zero-length slice.
- const want = -1
- if v := header.IPVersion(b[:0]); v != want {
- t.Fatalf("Bad version, want %v, got %v", want, v)
- }
-
- // Get the version of a nil slice.
- if v := header.IPVersion(nil); v != want {
- t.Fatalf("Bad version, want %v, got %v", want, v)
- }
-}
diff --git a/pkg/tcpip/header/ndp_test.go b/pkg/tcpip/header/ndp_test.go
deleted file mode 100644
index dc4591253..000000000
--- a/pkg/tcpip/header/ndp_test.go
+++ /dev/null
@@ -1,1521 +0,0 @@
-// Copyright 2019 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.
-
-package header
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "regexp"
- "testing"
- "time"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/tcpip"
-)
-
-// TestNDPNeighborSolicit tests the functions of NDPNeighborSolicit.
-func TestNDPNeighborSolicit(t *testing.T) {
- b := []byte{
- 0, 0, 0, 0,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- }
-
- // Test getting the Target Address.
- ns := NDPNeighborSolicit(b)
- addr := tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10")
- if got := ns.TargetAddress(); got != addr {
- t.Errorf("got ns.TargetAddress = %s, want %s", got, addr)
- }
-
- // Test updating the Target Address.
- addr2 := tcpip.Address("\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x11")
- ns.SetTargetAddress(addr2)
- if got := ns.TargetAddress(); got != addr2 {
- t.Errorf("got ns.TargetAddress = %s, want %s", got, addr2)
- }
- // Make sure the address got updated in the backing buffer.
- if got := tcpip.Address(b[ndpNSTargetAddessOffset:][:IPv6AddressSize]); got != addr2 {
- t.Errorf("got targetaddress buffer = %s, want %s", got, addr2)
- }
-}
-
-// TestNDPNeighborAdvert tests the functions of NDPNeighborAdvert.
-func TestNDPNeighborAdvert(t *testing.T) {
- b := []byte{
- 160, 0, 0, 0,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- }
-
- // Test getting the Target Address.
- na := NDPNeighborAdvert(b)
- addr := tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10")
- if got := na.TargetAddress(); got != addr {
- t.Errorf("got TargetAddress = %s, want %s", got, addr)
- }
-
- // Test getting the Router Flag.
- if got := na.RouterFlag(); !got {
- t.Errorf("got RouterFlag = false, want = true")
- }
-
- // Test getting the Solicited Flag.
- if got := na.SolicitedFlag(); got {
- t.Errorf("got SolicitedFlag = true, want = false")
- }
-
- // Test getting the Override Flag.
- if got := na.OverrideFlag(); !got {
- t.Errorf("got OverrideFlag = false, want = true")
- }
-
- // Test updating the Target Address.
- addr2 := tcpip.Address("\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x11")
- na.SetTargetAddress(addr2)
- if got := na.TargetAddress(); got != addr2 {
- t.Errorf("got TargetAddress = %s, want %s", got, addr2)
- }
- // Make sure the address got updated in the backing buffer.
- if got := tcpip.Address(b[ndpNATargetAddressOffset:][:IPv6AddressSize]); got != addr2 {
- t.Errorf("got targetaddress buffer = %s, want %s", got, addr2)
- }
-
- // Test updating the Router Flag.
- na.SetRouterFlag(false)
- if got := na.RouterFlag(); got {
- t.Errorf("got RouterFlag = true, want = false")
- }
-
- // Test updating the Solicited Flag.
- na.SetSolicitedFlag(true)
- if got := na.SolicitedFlag(); !got {
- t.Errorf("got SolicitedFlag = false, want = true")
- }
-
- // Test updating the Override Flag.
- na.SetOverrideFlag(false)
- if got := na.OverrideFlag(); got {
- t.Errorf("got OverrideFlag = true, want = false")
- }
-
- // Make sure flags got updated in the backing buffer.
- if got := b[ndpNAFlagsOffset]; got != 64 {
- t.Errorf("got flags byte = %d, want = 64", got)
- }
-}
-
-func TestNDPRouterAdvert(t *testing.T) {
- b := []byte{
- 64, 128, 1, 2,
- 3, 4, 5, 6,
- 7, 8, 9, 10,
- }
-
- ra := NDPRouterAdvert(b)
-
- if got := ra.CurrHopLimit(); got != 64 {
- t.Errorf("got ra.CurrHopLimit = %d, want = 64", got)
- }
-
- if got := ra.ManagedAddrConfFlag(); !got {
- t.Errorf("got ManagedAddrConfFlag = false, want = true")
- }
-
- if got := ra.OtherConfFlag(); got {
- t.Errorf("got OtherConfFlag = true, want = false")
- }
-
- if got, want := ra.RouterLifetime(), time.Second*258; got != want {
- t.Errorf("got ra.RouterLifetime = %d, want = %d", got, want)
- }
-
- if got, want := ra.ReachableTime(), time.Millisecond*50595078; got != want {
- t.Errorf("got ra.ReachableTime = %d, want = %d", got, want)
- }
-
- if got, want := ra.RetransTimer(), time.Millisecond*117967114; got != want {
- t.Errorf("got ra.RetransTimer = %d, want = %d", got, want)
- }
-}
-
-// TestNDPSourceLinkLayerAddressOptionEthernetAddress tests getting the
-// Ethernet address from an NDPSourceLinkLayerAddressOption.
-func TestNDPSourceLinkLayerAddressOptionEthernetAddress(t *testing.T) {
- tests := []struct {
- name string
- buf []byte
- expected tcpip.LinkAddress
- }{
- {
- "ValidMAC",
- []byte{1, 2, 3, 4, 5, 6},
- tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
- },
- {
- "SLLBodyTooShort",
- []byte{1, 2, 3, 4, 5},
- tcpip.LinkAddress([]byte(nil)),
- },
- {
- "SLLBodyLargerThanNeeded",
- []byte{1, 2, 3, 4, 5, 6, 7, 8},
- tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- sll := NDPSourceLinkLayerAddressOption(test.buf)
- if got := sll.EthernetAddress(); got != test.expected {
- t.Errorf("got sll.EthernetAddress = %s, want = %s", got, test.expected)
- }
- })
- }
-}
-
-// TestNDPSourceLinkLayerAddressOptionSerialize tests serializing a
-// NDPSourceLinkLayerAddressOption.
-func TestNDPSourceLinkLayerAddressOptionSerialize(t *testing.T) {
- tests := []struct {
- name string
- buf []byte
- expectedBuf []byte
- addr tcpip.LinkAddress
- }{
- {
- "Ethernet",
- make([]byte, 8),
- []byte{1, 1, 1, 2, 3, 4, 5, 6},
- "\x01\x02\x03\x04\x05\x06",
- },
- {
- "Padding",
- []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- []byte{1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0},
- "\x01\x02\x03\x04\x05\x06\x07\x08",
- },
- {
- "Empty",
- nil,
- nil,
- "",
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- opts := NDPOptions(test.buf)
- serializer := NDPOptionsSerializer{
- NDPSourceLinkLayerAddressOption(test.addr),
- }
- if got, want := int(serializer.Length()), len(test.expectedBuf); got != want {
- t.Fatalf("got Length = %d, want = %d", got, want)
- }
- opts.Serialize(serializer)
- if !bytes.Equal(test.buf, test.expectedBuf) {
- t.Fatalf("got b = %d, want = %d", test.buf, test.expectedBuf)
- }
-
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
- }
-
- if len(test.expectedBuf) > 0 {
- next, done, err := it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got := next.Type(); got != NDPSourceLinkLayerAddressOptionType {
- t.Fatalf("got Type = %d, want = %d", got, NDPSourceLinkLayerAddressOptionType)
- }
- sll := next.(NDPSourceLinkLayerAddressOption)
- if got, want := []byte(sll), test.expectedBuf[2:]; !bytes.Equal(got, want) {
- t.Fatalf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
- }
-
- if got, want := sll.EthernetAddress(), tcpip.LinkAddress(test.expectedBuf[2:][:EthernetAddressSize]); got != want {
- t.Errorf("got sll.EthernetAddress = %s, want = %s", got, want)
- }
- }
-
- // Iterator should not return anything else.
- next, done, err := it.Next()
- if err != nil {
- t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if !done {
- t.Error("got Next = (_, false, _), want = (_, true, _)")
- }
- if next != nil {
- t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
- }
- })
- }
-}
-
-// TestNDPTargetLinkLayerAddressOptionEthernetAddress tests getting the
-// Ethernet address from an NDPTargetLinkLayerAddressOption.
-func TestNDPTargetLinkLayerAddressOptionEthernetAddress(t *testing.T) {
- tests := []struct {
- name string
- buf []byte
- expected tcpip.LinkAddress
- }{
- {
- "ValidMAC",
- []byte{1, 2, 3, 4, 5, 6},
- tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
- },
- {
- "TLLBodyTooShort",
- []byte{1, 2, 3, 4, 5},
- tcpip.LinkAddress([]byte(nil)),
- },
- {
- "TLLBodyLargerThanNeeded",
- []byte{1, 2, 3, 4, 5, 6, 7, 8},
- tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06"),
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- tll := NDPTargetLinkLayerAddressOption(test.buf)
- if got := tll.EthernetAddress(); got != test.expected {
- t.Errorf("got tll.EthernetAddress = %s, want = %s", got, test.expected)
- }
- })
- }
-}
-
-// TestNDPTargetLinkLayerAddressOptionSerialize tests serializing a
-// NDPTargetLinkLayerAddressOption.
-func TestNDPTargetLinkLayerAddressOptionSerialize(t *testing.T) {
- tests := []struct {
- name string
- buf []byte
- expectedBuf []byte
- addr tcpip.LinkAddress
- }{
- {
- "Ethernet",
- make([]byte, 8),
- []byte{2, 1, 1, 2, 3, 4, 5, 6},
- "\x01\x02\x03\x04\x05\x06",
- },
- {
- "Padding",
- []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- []byte{2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0},
- "\x01\x02\x03\x04\x05\x06\x07\x08",
- },
- {
- "Empty",
- nil,
- nil,
- "",
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- opts := NDPOptions(test.buf)
- serializer := NDPOptionsSerializer{
- NDPTargetLinkLayerAddressOption(test.addr),
- }
- if got, want := int(serializer.Length()), len(test.expectedBuf); got != want {
- t.Fatalf("got Length = %d, want = %d", got, want)
- }
- opts.Serialize(serializer)
- if !bytes.Equal(test.buf, test.expectedBuf) {
- t.Fatalf("got b = %d, want = %d", test.buf, test.expectedBuf)
- }
-
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
- }
-
- if len(test.expectedBuf) > 0 {
- next, done, err := it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got := next.Type(); got != NDPTargetLinkLayerAddressOptionType {
- t.Fatalf("got Type = %d, want = %d", got, NDPTargetLinkLayerAddressOptionType)
- }
- tll := next.(NDPTargetLinkLayerAddressOption)
- if got, want := []byte(tll), test.expectedBuf[2:]; !bytes.Equal(got, want) {
- t.Fatalf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
- }
-
- if got, want := tll.EthernetAddress(), tcpip.LinkAddress(test.expectedBuf[2:][:EthernetAddressSize]); got != want {
- t.Errorf("got tll.EthernetAddress = %s, want = %s", got, want)
- }
- }
-
- // Iterator should not return anything else.
- next, done, err := it.Next()
- if err != nil {
- t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if !done {
- t.Error("got Next = (_, false, _), want = (_, true, _)")
- }
- if next != nil {
- t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
- }
- })
- }
-}
-
-// TestNDPPrefixInformationOption tests the field getters and serialization of a
-// NDPPrefixInformation.
-func TestNDPPrefixInformationOption(t *testing.T) {
- b := []byte{
- 43, 127,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 5, 5, 5, 5,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23, 24,
- }
-
- targetBuf := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- opts := NDPOptions(targetBuf)
- serializer := NDPOptionsSerializer{
- NDPPrefixInformation(b),
- }
- opts.Serialize(serializer)
- expectedBuf := []byte{
- 3, 4, 43, 64,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 0, 0, 0, 0,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23, 24,
- }
- if !bytes.Equal(targetBuf, expectedBuf) {
- t.Fatalf("got targetBuf = %x, want = %x", targetBuf, expectedBuf)
- }
-
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
- }
-
- next, done, err := it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got := next.Type(); got != NDPPrefixInformationType {
- t.Errorf("got Type = %d, want = %d", got, NDPPrefixInformationType)
- }
-
- pi := next.(NDPPrefixInformation)
-
- if got := pi.Type(); got != 3 {
- t.Errorf("got Type = %d, want = 3", got)
- }
-
- if got := pi.Length(); got != 30 {
- t.Errorf("got Length = %d, want = 30", got)
- }
-
- if got := pi.PrefixLength(); got != 43 {
- t.Errorf("got PrefixLength = %d, want = 43", got)
- }
-
- if pi.OnLinkFlag() {
- t.Error("got OnLinkFlag = true, want = false")
- }
-
- if !pi.AutonomousAddressConfigurationFlag() {
- t.Error("got AutonomousAddressConfigurationFlag = false, want = true")
- }
-
- if got, want := pi.ValidLifetime(), 16909060*time.Second; got != want {
- t.Errorf("got ValidLifetime = %d, want = %d", got, want)
- }
-
- if got, want := pi.PreferredLifetime(), 84281096*time.Second; got != want {
- t.Errorf("got PreferredLifetime = %d, want = %d", got, want)
- }
-
- if got, want := pi.Prefix(), tcpip.Address("\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18"); got != want {
- t.Errorf("got Prefix = %s, want = %s", got, want)
- }
-
- // Iterator should not return anything else.
- next, done, err = it.Next()
- if err != nil {
- t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if !done {
- t.Error("got Next = (_, false, _), want = (_, true, _)")
- }
- if next != nil {
- t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
- }
-}
-
-func TestNDPRecursiveDNSServerOptionSerialize(t *testing.T) {
- b := []byte{
- 9, 8,
- 1, 2, 4, 8,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- }
- targetBuf := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- expected := []byte{
- 25, 3, 0, 0,
- 1, 2, 4, 8,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- }
- opts := NDPOptions(targetBuf)
- serializer := NDPOptionsSerializer{
- NDPRecursiveDNSServer(b),
- }
- if got, want := opts.Serialize(serializer), len(expected); got != want {
- t.Errorf("got Serialize = %d, want = %d", got, want)
- }
- if !bytes.Equal(targetBuf, expected) {
- t.Fatalf("got targetBuf = %x, want = %x", targetBuf, expected)
- }
-
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
- }
-
- next, done, err := it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got := next.Type(); got != NDPRecursiveDNSServerOptionType {
- t.Errorf("got Type = %d, want = %d", got, NDPRecursiveDNSServerOptionType)
- }
-
- opt, ok := next.(NDPRecursiveDNSServer)
- if !ok {
- t.Fatalf("next (type = %T) cannot be casted to an NDPRecursiveDNSServer", next)
- }
- if got := opt.Type(); got != 25 {
- t.Errorf("got Type = %d, want = 31", got)
- }
- if got := opt.Length(); got != 22 {
- t.Errorf("got Length = %d, want = 22", got)
- }
- if got, want := opt.Lifetime(), 16909320*time.Second; got != want {
- t.Errorf("got Lifetime = %s, want = %s", got, want)
- }
- want := []tcpip.Address{
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
- }
- 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.
- next, done, err = it.Next()
- if err != nil {
- t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if !done {
- t.Error("got Next = (_, false, _), want = (_, true, _)")
- }
- if next != nil {
- t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
- }
-}
-
-func TestNDPRecursiveDNSServerOption(t *testing.T) {
- tests := []struct {
- name string
- buf []byte
- lifetime time.Duration
- addrs []tcpip.Address
- }{
- {
- "Valid1Addr",
- []byte{
- 25, 3, 0, 0,
- 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- },
- 0,
- []tcpip.Address{
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
- },
- },
- {
- "Valid2Addr",
- []byte{
- 25, 5, 0, 0,
- 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16,
- },
- 0,
- []tcpip.Address{
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
- "\x11\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x10",
- },
- },
- {
- "Valid3Addr",
- []byte{
- 25, 7, 0, 0,
- 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16,
- 17, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17,
- },
- 0,
- []tcpip.Address{
- "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
- "\x11\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x10",
- "\x11\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x11",
- },
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- opts := NDPOptions(test.buf)
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
- }
-
- // Iterator should get our option.
- next, done, err := it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got := next.Type(); got != NDPRecursiveDNSServerOptionType {
- t.Fatalf("got Type = %d, want = %d", got, NDPRecursiveDNSServerOptionType)
- }
-
- opt, ok := next.(NDPRecursiveDNSServer)
- if !ok {
- t.Fatalf("next (type = %T) cannot be casted to an NDPRecursiveDNSServer", next)
- }
- if got := opt.Lifetime(); got != test.lifetime {
- t.Errorf("got Lifetime = %d, want = %d", got, test.lifetime)
- }
- 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.
- next, done, err = it.Next()
- if err != nil {
- t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if !done {
- t.Error("got Next = (_, false, _), want = (_, true, _)")
- }
- if next != nil {
- t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
- }
- })
- }
-}
-
-// TestNDPDNSSearchListOption tests the getters of NDPDNSSearchList.
-func TestNDPDNSSearchListOption(t *testing.T) {
- tests := []struct {
- name string
- buf []byte
- lifetime time.Duration
- domainNames []string
- err error
- }{
- {
- name: "Valid1Label",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 1,
- 3, 'a', 'b', 'c',
- 0,
- 0, 0, 0,
- },
- lifetime: time.Second,
- domainNames: []string{
- "abc",
- },
- err: nil,
- },
- {
- name: "Valid2Label",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 5,
- 3, 'a', 'b', 'c',
- 4, 'a', 'b', 'c', 'd',
- 0,
- 0, 0, 0, 0, 0, 0,
- },
- lifetime: 5 * time.Second,
- domainNames: []string{
- "abc.abcd",
- },
- err: nil,
- },
- {
- name: "Valid3Label",
- buf: []byte{
- 0, 0,
- 1, 0, 0, 0,
- 3, 'a', 'b', 'c',
- 4, 'a', 'b', 'c', 'd',
- 1, 'e',
- 0,
- 0, 0, 0, 0,
- },
- lifetime: 16777216 * time.Second,
- domainNames: []string{
- "abc.abcd.e",
- },
- err: nil,
- },
- {
- name: "Valid2Domains",
- buf: []byte{
- 0, 0,
- 1, 2, 3, 4,
- 3, 'a', 'b', 'c',
- 0,
- 2, 'd', 'e',
- 3, 'x', 'y', 'z',
- 0,
- 0, 0, 0,
- },
- lifetime: 16909060 * time.Second,
- domainNames: []string{
- "abc",
- "de.xyz",
- },
- err: nil,
- },
- {
- name: "Valid3DomainsMixedCase",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 3, 'a', 'B', 'c',
- 0,
- 2, 'd', 'E',
- 3, 'X', 'y', 'z',
- 0,
- 1, 'J',
- 0,
- },
- lifetime: 0,
- domainNames: []string{
- "abc",
- "de.xyz",
- "j",
- },
- err: nil,
- },
- {
- name: "ValidDomainAfterNULL",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 3, 'a', 'B', 'c',
- 0, 0, 0, 0,
- 2, 'd', 'E',
- 3, 'X', 'y', 'z',
- 0,
- },
- lifetime: 0,
- domainNames: []string{
- "abc",
- "de.xyz",
- },
- err: nil,
- },
- {
- name: "Valid0Domains",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 0,
- 0, 0, 0, 0, 0, 0, 0,
- },
- lifetime: 0,
- domainNames: nil,
- err: nil,
- },
- {
- name: "NoTrailingNull",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 7, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
- },
- lifetime: 0,
- domainNames: nil,
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "IncorrectLength",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 8, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
- },
- lifetime: 0,
- domainNames: nil,
- err: io.ErrUnexpectedEOF,
- },
- {
- name: "IncorrectLengthWithNULL",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 7, 'a', 'b', 'c', 'd', 'e', 'f',
- 0,
- },
- lifetime: 0,
- domainNames: nil,
- err: ErrNDPOptMalformedBody,
- },
- {
- name: "LabelOfLength63",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 0,
- },
- lifetime: 0,
- domainNames: []string{
- "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk",
- },
- err: nil,
- },
- {
- name: "LabelOfLength64",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 64, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l',
- 0,
- },
- lifetime: 0,
- domainNames: nil,
- err: ErrNDPOptMalformedBody,
- },
- {
- name: "DomainNameOfLength255",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 62, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j',
- 0,
- },
- lifetime: 0,
- domainNames: []string{
- "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij",
- },
- err: nil,
- },
- {
- name: "DomainNameOfLength256",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 0,
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 0,
- },
- lifetime: 0,
- domainNames: nil,
- err: ErrNDPOptMalformedBody,
- },
- {
- name: "StartingDigitForLabel",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 1,
- 3, '9', 'b', 'c',
- 0,
- 0, 0, 0,
- },
- lifetime: time.Second,
- domainNames: nil,
- err: ErrNDPOptMalformedBody,
- },
- {
- name: "StartingHyphenForLabel",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 1,
- 3, '-', 'b', 'c',
- 0,
- 0, 0, 0,
- },
- lifetime: time.Second,
- domainNames: nil,
- err: ErrNDPOptMalformedBody,
- },
- {
- name: "EndingHyphenForLabel",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 1,
- 3, 'a', 'b', '-',
- 0,
- 0, 0, 0,
- },
- lifetime: time.Second,
- domainNames: nil,
- err: ErrNDPOptMalformedBody,
- },
- {
- name: "EndingDigitForLabel",
- buf: []byte{
- 0, 0,
- 0, 0, 0, 1,
- 3, 'a', 'b', '9',
- 0,
- 0, 0, 0,
- },
- lifetime: time.Second,
- domainNames: []string{
- "ab9",
- },
- err: nil,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- opt := NDPDNSSearchList(test.buf)
-
- if got := opt.Lifetime(); got != test.lifetime {
- t.Errorf("got Lifetime = %d, want = %d", got, test.lifetime)
- }
- domainNames, err := opt.DomainNames()
- if !errors.Is(err, test.err) {
- t.Errorf("opt.DomainNames() = %s", err)
- }
- if diff := cmp.Diff(domainNames, test.domainNames); diff != "" {
- t.Errorf("mismatched domain names (-want +got):\n%s", diff)
- }
- })
- }
-}
-
-func TestNDPSearchListOptionDomainNameLabelInvalidSymbols(t *testing.T) {
- for r := rune(0); r <= 255; r++ {
- t.Run(fmt.Sprintf("RuneVal=%d", r), func(t *testing.T) {
- buf := []byte{
- 0, 0,
- 0, 0, 0, 0,
- 3, 'a', 0 /* will be replaced */, 'c',
- 0,
- 0, 0, 0,
- }
- buf[8] = uint8(r)
- opt := NDPDNSSearchList(buf)
-
- // As per RFC 1035 section 2.3.1, the label must only include ASCII
- // letters, digits and hyphens (a-z, A-Z, 0-9, -).
- var expectedErr error
- re := regexp.MustCompile(`[a-zA-Z0-9-]`)
- if !re.Match([]byte{byte(r)}) {
- expectedErr = ErrNDPOptMalformedBody
- }
-
- if domainNames, err := opt.DomainNames(); !errors.Is(err, expectedErr) {
- t.Errorf("got opt.DomainNames() = (%s, %v), want = (_, %v)", domainNames, err, ErrNDPOptMalformedBody)
- }
- })
- }
-}
-
-func TestNDPDNSSearchListOptionSerialize(t *testing.T) {
- b := []byte{
- 9, 8,
- 1, 0, 0, 0,
- 3, 'a', 'b', 'c',
- 4, 'a', 'b', 'c', 'd',
- 1, 'e',
- 0,
- }
- targetBuf := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- expected := []byte{
- 31, 3, 0, 0,
- 1, 0, 0, 0,
- 3, 'a', 'b', 'c',
- 4, 'a', 'b', 'c', 'd',
- 1, 'e',
- 0,
- 0, 0, 0, 0,
- }
- opts := NDPOptions(targetBuf)
- serializer := NDPOptionsSerializer{
- NDPDNSSearchList(b),
- }
- if got, want := opts.Serialize(serializer), len(expected); got != want {
- t.Errorf("got Serialize = %d, want = %d", got, want)
- }
- if !bytes.Equal(targetBuf, expected) {
- t.Fatalf("got targetBuf = %x, want = %x", targetBuf, expected)
- }
-
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
- }
-
- next, done, err := it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got := next.Type(); got != NDPDNSSearchListOptionType {
- t.Errorf("got Type = %d, want = %d", got, NDPDNSSearchListOptionType)
- }
-
- opt, ok := next.(NDPDNSSearchList)
- if !ok {
- t.Fatalf("next (type = %T) cannot be casted to an NDPDNSSearchList", next)
- }
- if got := opt.Type(); got != 31 {
- t.Errorf("got Type = %d, want = 31", got)
- }
- if got := opt.Length(); got != 22 {
- t.Errorf("got Length = %d, want = 22", got)
- }
- if got, want := opt.Lifetime(), 16777216*time.Second; got != want {
- t.Errorf("got Lifetime = %s, want = %s", got, want)
- }
- domainNames, err := opt.DomainNames()
- if err != nil {
- t.Errorf("opt.DomainNames() = %s", err)
- }
- if diff := cmp.Diff(domainNames, []string{"abc.abcd.e"}); diff != "" {
- t.Errorf("domain names mismatch (-want +got):\n%s", diff)
- }
-
- // Iterator should not return anything else.
- next, done, err = it.Next()
- if err != nil {
- t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if !done {
- t.Error("got Next = (_, false, _), want = (_, true, _)")
- }
- if next != nil {
- t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
- }
-}
-
-// TestNDPOptionsIterCheck tests that Iter will return false if the NDPOptions
-// the iterator was returned for is malformed.
-func TestNDPOptionsIterCheck(t *testing.T) {
- tests := []struct {
- name string
- buf []byte
- expectedErr error
- }{
- {
- name: "ZeroLengthField",
- buf: []byte{0, 0, 0, 0, 0, 0, 0, 0},
- expectedErr: ErrNDPOptMalformedHeader,
- },
- {
- name: "ValidSourceLinkLayerAddressOption",
- buf: []byte{1, 1, 1, 2, 3, 4, 5, 6},
- expectedErr: nil,
- },
- {
- name: "TooSmallSourceLinkLayerAddressOption",
- buf: []byte{1, 1, 1, 2, 3, 4, 5},
- expectedErr: io.ErrUnexpectedEOF,
- },
- {
- name: "ValidTargetLinkLayerAddressOption",
- buf: []byte{2, 1, 1, 2, 3, 4, 5, 6},
- expectedErr: nil,
- },
- {
- name: "TooSmallTargetLinkLayerAddressOption",
- buf: []byte{2, 1, 1, 2, 3, 4, 5},
- expectedErr: io.ErrUnexpectedEOF,
- },
- {
- name: "ValidPrefixInformation",
- buf: []byte{
- 3, 4, 43, 64,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 0, 0, 0, 0,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23, 24,
- },
- expectedErr: nil,
- },
- {
- name: "TooSmallPrefixInformation",
- buf: []byte{
- 3, 4, 43, 64,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 0, 0, 0, 0,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23,
- },
- expectedErr: io.ErrUnexpectedEOF,
- },
- {
- name: "InvalidPrefixInformationLength",
- buf: []byte{
- 3, 3, 43, 64,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 0, 0, 0, 0,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- },
- expectedErr: ErrNDPOptMalformedBody,
- },
- {
- name: "ValidSourceAndTargetLinkLayerAddressWithPrefixInformation",
- buf: []byte{
- // Source Link-Layer Address.
- 1, 1, 1, 2, 3, 4, 5, 6,
-
- // Target Link-Layer Address.
- 2, 1, 7, 8, 9, 10, 11, 12,
-
- // Prefix information.
- 3, 4, 43, 64,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 0, 0, 0, 0,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23, 24,
- },
- expectedErr: nil,
- },
- {
- name: "ValidSourceAndTargetLinkLayerAddressWithPrefixInformationWithUnrecognized",
- buf: []byte{
- // Source Link-Layer Address.
- 1, 1, 1, 2, 3, 4, 5, 6,
-
- // Target Link-Layer Address.
- 2, 1, 7, 8, 9, 10, 11, 12,
-
- // 255 is an unrecognized type. If 255 ends up
- // being the type for some recognized type,
- // update 255 to some other unrecognized value.
- 255, 2, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8,
-
- // Prefix information.
- 3, 4, 43, 64,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 0, 0, 0, 0,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23, 24,
- },
- expectedErr: nil,
- },
- {
- 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,
- },
- expectedErr: ErrNDPOptMalformedBody,
- },
- {
- name: "InvalidRecursiveDNSServerInvalidLengthField",
- buf: []byte{
- 25, 2, 0, 0,
- 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8,
- },
- expectedErr: io.ErrUnexpectedEOF,
- },
- {
- name: "RecursiveDNSServerTooSmall",
- buf: []byte{
- 25, 1, 0, 0,
- 0, 0, 0,
- },
- expectedErr: io.ErrUnexpectedEOF,
- },
- {
- 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,
- },
- expectedErr: ErrNDPOptMalformedBody,
- },
- {
- 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,
- },
- expectedErr: ErrNDPOptMalformedBody,
- },
- {
- name: "DNSSearchListLargeCompliantRFC1035",
- buf: []byte{
- 31, 33, 0, 0,
- 0, 0, 0, 0,
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 62, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j',
- 0,
- },
- expectedErr: nil,
- },
- {
- name: "DNSSearchListNonCompliantRFC1035",
- buf: []byte{
- 31, 33, 0, 0,
- 0, 0, 0, 0,
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 63, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
- 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
- 'i', 'j', 'k',
- 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- },
- expectedErr: ErrNDPOptMalformedBody,
- },
- {
- name: "DNSSearchListValidSmall",
- buf: []byte{
- 31, 2, 0, 0,
- 0, 0, 0, 0,
- 6, 'a', 'b', 'c', 'd', 'e', 'f',
- 0,
- },
- expectedErr: nil,
- },
- {
- name: "DNSSearchListTooSmall",
- buf: []byte{
- 31, 1, 0, 0,
- 0, 0, 0,
- },
- expectedErr: io.ErrUnexpectedEOF,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- opts := NDPOptions(test.buf)
-
- 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
- // the iterator so it must return true.
- if _, err := opts.Iter(false); err != nil {
- t.Fatalf("got Iter(false) = (_, %s), want = (_, nil)", err)
- }
- })
- }
-}
-
-// TestNDPOptionsIter tests that we can iterator over a valid NDPOptions. Note,
-// this test does not actually check any of the option's getters, it simply
-// checks the option Type and Body. We have other tests that tests the option
-// field gettings given an option body and don't need to duplicate those tests
-// here.
-func TestNDPOptionsIter(t *testing.T) {
- buf := []byte{
- // Source Link-Layer Address.
- 1, 1, 1, 2, 3, 4, 5, 6,
-
- // Target Link-Layer Address.
- 2, 1, 7, 8, 9, 10, 11, 12,
-
- // 255 is an unrecognized type. If 255 ends up being the type
- // for some recognized type, update 255 to some other
- // unrecognized value. Note, this option should be skipped when
- // iterating.
- 255, 2, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8,
-
- // Prefix information.
- 3, 4, 43, 64,
- 1, 2, 3, 4,
- 5, 6, 7, 8,
- 0, 0, 0, 0,
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23, 24,
- }
-
- opts := NDPOptions(buf)
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter = (_, %s), want = (_, nil)", err)
- }
-
- // Test the first (Source Link-Layer) option.
- next, done, err := it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got, want := []byte(next.(NDPSourceLinkLayerAddressOption)), buf[2:][:6]; !bytes.Equal(got, want) {
- t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
- }
- if got := next.Type(); got != NDPSourceLinkLayerAddressOptionType {
- t.Errorf("got Type = %d, want = %d", got, NDPSourceLinkLayerAddressOptionType)
- }
-
- // Test the next (Target Link-Layer) option.
- next, done, err = it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got, want := []byte(next.(NDPTargetLinkLayerAddressOption)), buf[10:][:6]; !bytes.Equal(got, want) {
- t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
- }
- if got := next.Type(); got != NDPTargetLinkLayerAddressOptionType {
- t.Errorf("got Type = %d, want = %d", got, NDPTargetLinkLayerAddressOptionType)
- }
-
- // Test the next (Prefix Information) option.
- // Note, the unrecognized option should be skipped.
- next, done, err = it.Next()
- if err != nil {
- t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if done {
- t.Fatal("got Next = (_, true, _), want = (_, false, _)")
- }
- if got, want := next.(NDPPrefixInformation), buf[34:][:30]; !bytes.Equal(got, want) {
- t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want)
- }
- if got := next.Type(); got != NDPPrefixInformationType {
- t.Errorf("got Type = %d, want = %d", got, NDPPrefixInformationType)
- }
-
- // Iterator should not return anything else.
- next, done, err = it.Next()
- if err != nil {
- t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err)
- }
- if !done {
- t.Error("got Next = (_, false, _), want = (_, true, _)")
- }
- if next != nil {
- t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next)
- }
-}
diff --git a/pkg/tcpip/header/parse/BUILD b/pkg/tcpip/header/parse/BUILD
deleted file mode 100644
index 2adee9288..000000000
--- a/pkg/tcpip/header/parse/BUILD
+++ /dev/null
@@ -1,15 +0,0 @@
-load("//tools:defs.bzl", "go_library")
-
-package(licenses = ["notice"])
-
-go_library(
- name = "parse",
- srcs = ["parse.go"],
- visibility = ["//visibility:public"],
- deps = [
- "//pkg/tcpip",
- "//pkg/tcpip/buffer",
- "//pkg/tcpip/header",
- "//pkg/tcpip/stack",
- ],
-)
diff --git a/pkg/tcpip/header/parse/parse_state_autogen.go b/pkg/tcpip/header/parse/parse_state_autogen.go
new file mode 100644
index 000000000..ad047be32
--- /dev/null
+++ b/pkg/tcpip/header/parse/parse_state_autogen.go
@@ -0,0 +1,3 @@
+// automatically generated by stateify.
+
+package parse
diff --git a/pkg/tcpip/header/tcp_test.go b/pkg/tcpip/header/tcp_test.go
deleted file mode 100644
index 72563837b..000000000
--- a/pkg/tcpip/header/tcp_test.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2018 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.
-
-package header_test
-
-import (
- "reflect"
- "testing"
-
- "gvisor.dev/gvisor/pkg/tcpip/header"
-)
-
-func TestEncodeSACKBlocks(t *testing.T) {
- testCases := []struct {
- sackBlocks []header.SACKBlock
- want []header.SACKBlock
- bufSize int
- }{
- {
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}},
- 40,
- },
- {
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}},
- 30,
- },
- {
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
- []header.SACKBlock{{10, 20}, {22, 30}},
- 20,
- },
- {
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
- []header.SACKBlock{{10, 20}},
- 10,
- },
- {
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
- nil,
- 8,
- },
- {
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}, {52, 60}, {62, 70}},
- []header.SACKBlock{{10, 20}, {22, 30}, {32, 40}, {42, 50}},
- 60,
- },
- }
- for _, tc := range testCases {
- b := make([]byte, tc.bufSize)
- t.Logf("testing: %v", tc)
- header.EncodeSACKBlocks(tc.sackBlocks, b)
- opts := header.ParseTCPOptions(b)
- if got, want := opts.SACKBlocks, tc.want; !reflect.DeepEqual(got, want) {
- t.Errorf("header.EncodeSACKBlocks(%v, %v), encoded blocks got: %v, want: %v", tc.sackBlocks, b, got, want)
- }
- }
-}
-
-func TestTCPParseOptions(t *testing.T) {
- type tsOption struct {
- tsVal uint32
- tsEcr uint32
- }
-
- generateOptions := func(tsOpt *tsOption, sackBlocks []header.SACKBlock) []byte {
- l := 0
- if tsOpt != nil {
- l += 10
- }
- if len(sackBlocks) != 0 {
- l += len(sackBlocks)*8 + 2
- }
- b := make([]byte, l)
- offset := 0
- if tsOpt != nil {
- offset = header.EncodeTSOption(tsOpt.tsVal, tsOpt.tsEcr, b)
- }
- header.EncodeSACKBlocks(sackBlocks, b[offset:])
- return b
- }
-
- testCases := []struct {
- b []byte
- want header.TCPOptions
- }{
- // Trivial cases.
- {nil, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionNOP}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionNOP, header.TCPOptionNOP}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionEOL}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionNOP, header.TCPOptionEOL, header.TCPOptionTS, 10, 1, 1}, header.TCPOptions{false, 0, 0, nil}},
-
- // Test timestamp parsing.
- {[]byte{header.TCPOptionNOP, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}},
- {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}},
-
- // Test malformed timestamp option.
- {[]byte{header.TCPOptionTS, 8, 1, 1}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionNOP, header.TCPOptionTS, 8, 1, 1}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionNOP, header.TCPOptionTS, 8, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}},
-
- // Test SACKBlock parsing.
- {[]byte{header.TCPOptionSACK, 10, 0, 0, 0, 1, 0, 0, 0, 10}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{1, 10}}}},
- {[]byte{header.TCPOptionSACK, 18, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{1, 10}, {11, 12}}}},
-
- // Test malformed SACK option.
- {[]byte{header.TCPOptionSACK, 0}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionSACK, 8, 0, 0, 0, 1, 0, 0, 0, 10}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionSACK, 11, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionSACK, 17, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionSACK}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionSACK, 10}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionSACK, 10, 0, 0, 0, 1, 0, 0, 0}, header.TCPOptions{false, 0, 0, nil}},
-
- // Test Timestamp + SACK block parsing.
- {generateOptions(&tsOption{1, 1}, []header.SACKBlock{{1, 10}, {11, 12}}), header.TCPOptions{true, 1, 1, []header.SACKBlock{{1, 10}, {11, 12}}}},
- {generateOptions(&tsOption{1, 2}, []header.SACKBlock{{1, 10}, {11, 12}}), header.TCPOptions{true, 1, 2, []header.SACKBlock{{1, 10}, {11, 12}}}},
- {generateOptions(&tsOption{1, 3}, []header.SACKBlock{{1, 10}, {11, 12}, {13, 14}, {14, 15}, {15, 16}}), header.TCPOptions{true, 1, 3, []header.SACKBlock{{1, 10}, {11, 12}, {13, 14}, {14, 15}}}},
-
- // Test valid timestamp + malformed SACK block parsing.
- {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK}, header.TCPOptions{true, 1, 1, nil}},
- {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 10}, header.TCPOptions{true, 1, 1, nil}},
- {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 10, 0, 0, 0}, header.TCPOptions{true, 1, 1, nil}},
- {[]byte{header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionSACK, 11, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{true, 1, 1, nil}},
- {[]byte{header.TCPOptionSACK, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}},
- {[]byte{header.TCPOptionSACK, 10, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{134873088, 65536}}}},
- {[]byte{header.TCPOptionSACK, 10, 0, 0, 0, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, []header.SACKBlock{{8, 167772160}}}},
- {[]byte{header.TCPOptionSACK, 11, 0, 0, 0, 1, 0, 0, 0, 1, header.TCPOptionTS, 10, 0, 0, 0, 1, 0, 0, 0, 1}, header.TCPOptions{false, 0, 0, nil}},
- }
- for _, tc := range testCases {
- if got, want := header.ParseTCPOptions(tc.b), tc.want; !reflect.DeepEqual(got, want) {
- t.Errorf("ParseTCPOptions(%v) = %v, want: %v", tc.b, got, tc.want)
- }
- }
-}