summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/header
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/header')
-rw-r--r--pkg/tcpip/header/BUILD74
-rw-r--r--pkg/tcpip/header/checksum_test.go258
-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/igmp_test.go110
-rw-r--r--pkg/tcpip/header/ipv4_test.go179
-rw-r--r--pkg/tcpip/header/ipv6_extension_headers_test.go1346
-rw-r--r--pkg/tcpip/header/ipv6_test.go375
-rw-r--r--pkg/tcpip/header/ipversion_test.go67
-rw-r--r--pkg/tcpip/header/mld_test.go61
-rw-r--r--pkg/tcpip/header/ndp_test.go1452
-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.go168
14 files changed, 73 insertions, 4254 deletions
diff --git a/pkg/tcpip/header/BUILD b/pkg/tcpip/header/BUILD
deleted file mode 100644
index 0bdc12d53..000000000
--- a/pkg/tcpip/header/BUILD
+++ /dev/null
@@ -1,74 +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",
- "igmp.go",
- "interfaces.go",
- "ipv4.go",
- "ipv6.go",
- "ipv6_extension_headers.go",
- "ipv6_fragment.go",
- "mld.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",
- "igmp_test.go",
- "ipv4_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",
- "mld_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 d267dabd0..000000000
--- a/pkg/tcpip/header/checksum_test.go
+++ /dev/null
@@ -1,258 +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 (
- "bytes"
- "fmt"
- "math/rand"
- "sync"
- "testing"
-
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/header"
-)
-
-func TestChecksumer(t *testing.T) {
- testCases := []struct {
- name string
- data [][]byte
- want uint16
- }{
- {
- name: "empty",
- want: 0,
- },
- {
- name: "OneOddView",
- data: [][]byte{
- []byte{1, 9, 0, 5, 4},
- },
- want: 1294,
- },
- {
- name: "TwoOddViews",
- data: [][]byte{
- []byte{1, 9, 0, 5, 4},
- []byte{4, 3, 7, 1, 2, 123},
- },
- want: 33819,
- },
- {
- name: "OneEvenView",
- data: [][]byte{
- []byte{1, 9, 0, 5},
- },
- want: 270,
- },
- {
- name: "TwoEvenViews",
- data: [][]byte{
- buffer.NewViewFromBytes([]byte{98, 1, 9, 0}),
- buffer.NewViewFromBytes([]byte{9, 0, 5, 4}),
- },
- want: 30981,
- },
- {
- name: "ThreeViews",
- data: [][]byte{
- []byte{77, 11, 33, 0, 55, 44},
- []byte{98, 1, 9, 0, 5, 4},
- []byte{4, 3, 7, 1, 2, 123, 99},
- },
- want: 34236,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- var all bytes.Buffer
- var c header.Checksumer
- for _, b := range tc.data {
- c.Add(b)
- // Append to the buffer. We will check the checksum as a whole later.
- if _, err := all.Write(b); err != nil {
- t.Fatalf("all.Write(b) = _, %s; want _, nil", err)
- }
- }
- if got, want := c.Checksum(), tc.want; got != want {
- t.Errorf("c.Checksum() = %d, want %d", got, want)
- }
- if got, want := header.Checksum(all.Bytes(), 0 /* initial */), tc.want; got != want {
- t.Errorf("Checksum(flatten tc.data) = %d, want %d", got, 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)
- }
- })
- }
- }
-}
-
-func testICMPChecksum(t *testing.T, headerChecksum func() uint16, icmpChecksum func() uint16, want uint16, pktStr string) {
- // icmpChecksum should not do any modifications of the header to
- // calculate its checksum. Let's call it from a few go-routines and the
- // race detector will trigger a warning if there are any concurrent
- // read/write accesses.
-
- const concurrency = 5
- start := make(chan int)
- ready := make(chan bool, concurrency)
- var wg sync.WaitGroup
- wg.Add(concurrency)
- defer wg.Wait()
-
- for i := 0; i < concurrency; i++ {
- go func() {
- defer wg.Done()
-
- ready <- true
- <-start
-
- if got := headerChecksum(); want != got {
- t.Errorf("new checksum for %s does not match old got: %x, want: %x", pktStr, got, want)
- }
- if got := icmpChecksum(); want != got {
- t.Errorf("new checksum for %s does not match old got: %x, want: %x", pktStr, got, want)
- }
- }()
- }
- for i := 0; i < concurrency; i++ {
- <-ready
- }
- close(start)
-}
-
-func TestICMPv4Checksum(t *testing.T) {
- rnd := rand.New(rand.NewSource(42))
-
- h := header.ICMPv4(make([]byte, header.ICMPv4MinimumSize))
- if _, err := rnd.Read(h); err != nil {
- t.Fatalf("rnd.Read failed: %v", err)
- }
- h.SetChecksum(0)
-
- buf := make([]byte, 13)
- if _, err := rnd.Read(buf); err != nil {
- t.Fatalf("rnd.Read failed: %v", err)
- }
- vv := buffer.NewVectorisedView(len(buf), []buffer.View{
- buffer.NewViewFromBytes(buf[:5]),
- buffer.NewViewFromBytes(buf[5:]),
- })
-
- want := header.Checksum(vv.ToView(), 0)
- want = ^header.Checksum(h, want)
- h.SetChecksum(want)
-
- testICMPChecksum(t, h.Checksum, func() uint16 {
- return header.ICMPv4Checksum(h, header.ChecksumVV(vv, 0))
- }, want, fmt.Sprintf("header: {% x} data {% x}", h, vv.ToView()))
-}
-
-func TestICMPv6Checksum(t *testing.T) {
- rnd := rand.New(rand.NewSource(42))
-
- h := header.ICMPv6(make([]byte, header.ICMPv6MinimumSize))
- if _, err := rnd.Read(h); err != nil {
- t.Fatalf("rnd.Read failed: %v", err)
- }
- h.SetChecksum(0)
-
- buf := make([]byte, 13)
- if _, err := rnd.Read(buf); err != nil {
- t.Fatalf("rnd.Read failed: %v", err)
- }
- vv := buffer.NewVectorisedView(len(buf), []buffer.View{
- buffer.NewViewFromBytes(buf[:7]),
- buffer.NewViewFromBytes(buf[7:10]),
- buffer.NewViewFromBytes(buf[10:]),
- })
-
- dst := header.IPv6Loopback
- src := header.IPv6Loopback
-
- want := header.PseudoHeaderChecksum(header.ICMPv6ProtocolNumber, src, dst, uint16(len(h)+vv.Size()))
- want = header.Checksum(vv.ToView(), want)
- want = ^header.Checksum(h, want)
- h.SetChecksum(want)
-
- testICMPChecksum(t, h.Checksum, func() uint16 {
- return header.ICMPv6Checksum(header.ICMPv6ChecksumParams{
- Header: h,
- Src: src,
- Dst: dst,
- PayloadCsum: header.ChecksumVV(vv, 0),
- PayloadLen: vv.Size(),
- })
- }, want, fmt.Sprintf("header: {% x} data {% x}", h, vv.ToView()))
-}
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..ddcc980e8
--- /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 (r *SACKBlock) StateTypeName() string {
+ return "pkg/tcpip/header.SACKBlock"
+}
+
+func (r *SACKBlock) StateFields() []string {
+ return []string{
+ "Start",
+ "End",
+ }
+}
+
+func (r *SACKBlock) beforeSave() {}
+
+func (r *SACKBlock) StateSave(stateSinkObject state.Sink) {
+ r.beforeSave()
+ stateSinkObject.Save(0, &r.Start)
+ stateSinkObject.Save(1, &r.End)
+}
+
+func (r *SACKBlock) afterLoad() {}
+
+func (r *SACKBlock) StateLoad(stateSourceObject state.Source) {
+ stateSourceObject.Load(0, &r.Start)
+ stateSourceObject.Load(1, &r.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/igmp_test.go b/pkg/tcpip/header/igmp_test.go
deleted file mode 100644
index b6126d29a..000000000
--- a/pkg/tcpip/header/igmp_test.go
+++ /dev/null
@@ -1,110 +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_test
-
-import (
- "testing"
- "time"
-
- "gvisor.dev/gvisor/pkg/tcpip"
- "gvisor.dev/gvisor/pkg/tcpip/header"
-)
-
-// TestIGMPHeader tests the functions within header.igmp
-func TestIGMPHeader(t *testing.T) {
- const maxRespTimeTenthSec = 0xF0
- b := []byte{
- 0x11, // IGMP Type, Membership Query
- maxRespTimeTenthSec, // Maximum Response Time
- 0xC0, 0xC0, // Checksum
- 0x01, 0x02, 0x03, 0x04, // Group Address
- }
-
- igmpHeader := header.IGMP(b)
-
- if got, want := igmpHeader.Type(), header.IGMPMembershipQuery; got != want {
- t.Errorf("got igmpHeader.Type() = %x, want = %x", got, want)
- }
-
- if got, want := igmpHeader.MaxRespTime(), header.DecisecondToDuration(maxRespTimeTenthSec); got != want {
- t.Errorf("got igmpHeader.MaxRespTime() = %s, want = %s", got, want)
- }
-
- if got, want := igmpHeader.Checksum(), uint16(0xC0C0); got != want {
- t.Errorf("got igmpHeader.Checksum() = %x, want = %x", got, want)
- }
-
- if got, want := igmpHeader.GroupAddress(), tcpip.Address("\x01\x02\x03\x04"); got != want {
- t.Errorf("got igmpHeader.GroupAddress() = %s, want = %s", got, want)
- }
-
- igmpType := header.IGMPv2MembershipReport
- igmpHeader.SetType(igmpType)
- if got := igmpHeader.Type(); got != igmpType {
- t.Errorf("got igmpHeader.Type() = %x, want = %x", got, igmpType)
- }
- if got := header.IGMPType(b[0]); got != igmpType {
- t.Errorf("got IGMPtype in backing buffer = %x, want %x", got, igmpType)
- }
-
- respTime := byte(0x02)
- igmpHeader.SetMaxRespTime(respTime)
- if got, want := igmpHeader.MaxRespTime(), header.DecisecondToDuration(respTime); got != want {
- t.Errorf("got igmpHeader.MaxRespTime() = %s, want = %s", got, want)
- }
-
- checksum := uint16(0x0102)
- igmpHeader.SetChecksum(checksum)
- if got := igmpHeader.Checksum(); got != checksum {
- t.Errorf("got igmpHeader.Checksum() = %x, want = %x", got, checksum)
- }
-
- groupAddress := tcpip.Address("\x04\x03\x02\x01")
- igmpHeader.SetGroupAddress(groupAddress)
- if got := igmpHeader.GroupAddress(); got != groupAddress {
- t.Errorf("got igmpHeader.GroupAddress() = %s, want = %s", got, groupAddress)
- }
-}
-
-// TestIGMPChecksum ensures that the checksum calculator produces the expected
-// checksum.
-func TestIGMPChecksum(t *testing.T) {
- b := []byte{
- 0x11, // IGMP Type, Membership Query
- 0xF0, // Maximum Response Time
- 0xC0, 0xC0, // Checksum
- 0x01, 0x02, 0x03, 0x04, // Group Address
- }
-
- igmpHeader := header.IGMP(b)
-
- // Calculate the initial checksum after setting the checksum temporarily to 0
- // to avoid checksumming the checksum.
- initialChecksum := igmpHeader.Checksum()
- igmpHeader.SetChecksum(0)
- checksum := ^header.Checksum(b, 0)
- igmpHeader.SetChecksum(initialChecksum)
-
- if got := header.IGMPCalculateChecksum(igmpHeader); got != checksum {
- t.Errorf("got IGMPCalculateChecksum = %x, want %x", got, checksum)
- }
-}
-
-func TestDecisecondToDuration(t *testing.T) {
- const valueInDeciseconds = 5
- if got, want := header.DecisecondToDuration(valueInDeciseconds), valueInDeciseconds*time.Second/10; got != want {
- t.Fatalf("got header.DecisecondToDuration(%d) = %s, want = %s", valueInDeciseconds, got, want)
- }
-}
diff --git a/pkg/tcpip/header/ipv4_test.go b/pkg/tcpip/header/ipv4_test.go
deleted file mode 100644
index 6475cd694..000000000
--- a/pkg/tcpip/header/ipv4_test.go
+++ /dev/null
@@ -1,179 +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_test
-
-import (
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "gvisor.dev/gvisor/pkg/tcpip/buffer"
- "gvisor.dev/gvisor/pkg/tcpip/header"
-)
-
-func TestIPv4OptionsSerializer(t *testing.T) {
- optCases := []struct {
- name string
- option []header.IPv4SerializableOption
- expect []byte
- }{
- {
- name: "NOP",
- option: []header.IPv4SerializableOption{
- &header.IPv4SerializableNOPOption{},
- },
- expect: []byte{1, 0, 0, 0},
- },
- {
- name: "ListEnd",
- option: []header.IPv4SerializableOption{
- &header.IPv4SerializableListEndOption{},
- },
- expect: []byte{0, 0, 0, 0},
- },
- {
- name: "RouterAlert",
- option: []header.IPv4SerializableOption{
- &header.IPv4SerializableRouterAlertOption{},
- },
- expect: []byte{148, 4, 0, 0},
- }, {
- name: "NOP and RouterAlert",
- option: []header.IPv4SerializableOption{
- &header.IPv4SerializableNOPOption{},
- &header.IPv4SerializableRouterAlertOption{},
- },
- expect: []byte{1, 148, 4, 0, 0, 0, 0, 0},
- },
- }
-
- for _, opt := range optCases {
- t.Run(opt.name, func(t *testing.T) {
- s := header.IPv4OptionsSerializer(opt.option)
- l := s.Length()
- if got := len(opt.expect); got != int(l) {
- t.Fatalf("s.Length() = %d, want = %d", got, l)
- }
- b := make([]byte, l)
- for i := range b {
- // Fill the buffer with full bytes to ensure padding is being set
- // correctly.
- b[i] = 0xFF
- }
- if serializedLength := s.Serialize(b); serializedLength != l {
- t.Fatalf("s.Serialize(_) = %d, want %d", serializedLength, l)
- }
- if diff := cmp.Diff(opt.expect, b); diff != "" {
- t.Errorf("mismatched serialized option (-want +got):\n%s", diff)
- }
- })
- }
-}
-
-// TestIPv4Encode checks that ipv4.Encode correctly fills out the requested
-// fields when options are supplied.
-func TestIPv4EncodeOptions(t *testing.T) {
- tests := []struct {
- name string
- numberOfNops int
- encodedOptions header.IPv4Options // reply should look like this
- wantIHL int
- }{
- {
- name: "valid no options",
- wantIHL: header.IPv4MinimumSize,
- },
- {
- name: "one byte options",
- numberOfNops: 1,
- encodedOptions: header.IPv4Options{1, 0, 0, 0},
- wantIHL: header.IPv4MinimumSize + 4,
- },
- {
- name: "two byte options",
- numberOfNops: 2,
- encodedOptions: header.IPv4Options{1, 1, 0, 0},
- wantIHL: header.IPv4MinimumSize + 4,
- },
- {
- name: "three byte options",
- numberOfNops: 3,
- encodedOptions: header.IPv4Options{1, 1, 1, 0},
- wantIHL: header.IPv4MinimumSize + 4,
- },
- {
- name: "four byte options",
- numberOfNops: 4,
- encodedOptions: header.IPv4Options{1, 1, 1, 1},
- wantIHL: header.IPv4MinimumSize + 4,
- },
- {
- name: "five byte options",
- numberOfNops: 5,
- encodedOptions: header.IPv4Options{1, 1, 1, 1, 1, 0, 0, 0},
- wantIHL: header.IPv4MinimumSize + 8,
- },
- {
- name: "thirty nine byte options",
- numberOfNops: 39,
- encodedOptions: header.IPv4Options{
- 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,
- 1, 1, 1, 1, 1, 1, 1, 0,
- },
- wantIHL: header.IPv4MinimumSize + 40,
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- serializeOpts := header.IPv4OptionsSerializer(make([]header.IPv4SerializableOption, test.numberOfNops))
- for i := range serializeOpts {
- serializeOpts[i] = &header.IPv4SerializableNOPOption{}
- }
- paddedOptionLength := serializeOpts.Length()
- ipHeaderLength := int(header.IPv4MinimumSize + paddedOptionLength)
- if ipHeaderLength > header.IPv4MaximumHeaderSize {
- t.Fatalf("IP header length too large: got = %d, want <= %d ", ipHeaderLength, header.IPv4MaximumHeaderSize)
- }
- totalLen := uint16(ipHeaderLength)
- hdr := buffer.NewPrependable(int(totalLen))
- ip := header.IPv4(hdr.Prepend(ipHeaderLength))
- // To check the padding works, poison the last byte of the options space.
- if paddedOptionLength != serializeOpts.Length() {
- ip.SetHeaderLength(uint8(ipHeaderLength))
- ip.Options()[paddedOptionLength-1] = 0xff
- ip.SetHeaderLength(0)
- }
- ip.Encode(&header.IPv4Fields{
- Options: serializeOpts,
- })
- options := ip.Options()
- wantOptions := test.encodedOptions
- if got, want := int(ip.HeaderLength()), test.wantIHL; got != want {
- t.Errorf("got IHL of %d, want %d", got, want)
- }
-
- // cmp.Diff does not consider nil slices equal to empty slices, but we do.
- if len(wantOptions) == 0 && len(options) == 0 {
- return
- }
-
- if diff := cmp.Diff(wantOptions, options); diff != "" {
- t.Errorf("options mismatch (-want +got):\n%s", diff)
- }
- })
- }
-}
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 65adc6250..000000000
--- a/pkg/tcpip/header/ipv6_extension_headers_test.go
+++ /dev/null
@@ -1,1346 +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"
- "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 IPv6ExtHdrOptionIdentifier
- 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,
- },
- {
- name: "Router alert without data",
- bytes: []byte{byte(ipv6RouterAlertHopByHopOptionIdentifier), 0},
- err: ErrMalformedIPv6ExtHdrOption,
- },
- {
- name: "Router alert with partial data",
- bytes: []byte{byte(ipv6RouterAlertHopByHopOptionIdentifier), 1, 1},
- err: ErrMalformedIPv6ExtHdrOption,
- },
- {
- name: "Router alert with partial data and Pad1",
- bytes: []byte{byte(ipv6RouterAlertHopByHopOptionIdentifier), 1, 1, 0},
- err: ErrMalformedIPv6ExtHdrOption,
- },
- {
- name: "Router alert with extra data",
- bytes: []byte{byte(ipv6RouterAlertHopByHopOptionIdentifier), 3, 1, 2, 3},
- err: ErrMalformedIPv6ExtHdrOption,
- },
- {
- name: "Router alert with missing data",
- bytes: []byte{byte(ipv6RouterAlertHopByHopOptionIdentifier), 1},
- 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)
- }
- })
- }
-}
-
-var _ IPv6SerializableHopByHopOption = (*dummyHbHOptionSerializer)(nil)
-
-// dummyHbHOptionSerializer provides a generic implementation of
-// IPv6SerializableHopByHopOption for use in tests.
-type dummyHbHOptionSerializer struct {
- id IPv6ExtHdrOptionIdentifier
- payload []byte
- align int
- alignOffset int
-}
-
-// identifier implements IPv6SerializableHopByHopOption.
-func (s *dummyHbHOptionSerializer) identifier() IPv6ExtHdrOptionIdentifier {
- return s.id
-}
-
-// length implements IPv6SerializableHopByHopOption.
-func (s *dummyHbHOptionSerializer) length() uint8 {
- return uint8(len(s.payload))
-}
-
-// alignment implements IPv6SerializableHopByHopOption.
-func (s *dummyHbHOptionSerializer) alignment() (int, int) {
- align := 1
- if s.align != 0 {
- align = s.align
- }
- return align, s.alignOffset
-}
-
-// serializeInto implements IPv6SerializableHopByHopOption.
-func (s *dummyHbHOptionSerializer) serializeInto(b []byte) uint8 {
- return uint8(copy(b, s.payload))
-}
-
-func TestIPv6HopByHopSerializer(t *testing.T) {
- validateDummies := func(t *testing.T, serializable IPv6SerializableHopByHopOption, deserialized IPv6ExtHdrOption) {
- t.Helper()
- dummy, ok := serializable.(*dummyHbHOptionSerializer)
- if !ok {
- t.Fatalf("got serializable = %T, want = *dummyHbHOptionSerializer", serializable)
- }
- unknown, ok := deserialized.(*IPv6UnknownExtHdrOption)
- if !ok {
- t.Fatalf("got deserialized = %T, want = %T", deserialized, &IPv6UnknownExtHdrOption{})
- }
- if dummy.id != unknown.Identifier {
- t.Errorf("got deserialized identifier = %d, want = %d", unknown.Identifier, dummy.id)
- }
- if diff := cmp.Diff(dummy.payload, unknown.Data); diff != "" {
- t.Errorf("option payload deserialization mismatch (-want +got):\n%s", diff)
- }
- }
- tests := []struct {
- name string
- nextHeader uint8
- options []IPv6SerializableHopByHopOption
- expect []byte
- validate func(*testing.T, IPv6SerializableHopByHopOption, IPv6ExtHdrOption)
- }{
- {
- name: "single option",
- nextHeader: 13,
- options: []IPv6SerializableHopByHopOption{
- &dummyHbHOptionSerializer{
- id: 15,
- payload: []byte{9, 8, 7, 6},
- },
- },
- expect: []byte{13, 0, 15, 4, 9, 8, 7, 6},
- validate: validateDummies,
- },
- {
- name: "short option padN zero",
- nextHeader: 88,
- options: []IPv6SerializableHopByHopOption{
- &dummyHbHOptionSerializer{
- id: 22,
- payload: []byte{4, 5},
- },
- },
- expect: []byte{88, 0, 22, 2, 4, 5, 1, 0},
- validate: validateDummies,
- },
- {
- name: "short option pad1",
- nextHeader: 11,
- options: []IPv6SerializableHopByHopOption{
- &dummyHbHOptionSerializer{
- id: 33,
- payload: []byte{1, 2, 3},
- },
- },
- expect: []byte{11, 0, 33, 3, 1, 2, 3, 0},
- validate: validateDummies,
- },
- {
- name: "long option padN",
- nextHeader: 55,
- options: []IPv6SerializableHopByHopOption{
- &dummyHbHOptionSerializer{
- id: 77,
- payload: []byte{1, 2, 3, 4, 5, 6, 7, 8},
- },
- },
- expect: []byte{55, 1, 77, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 0, 0},
- validate: validateDummies,
- },
- {
- name: "two options",
- nextHeader: 33,
- options: []IPv6SerializableHopByHopOption{
- &dummyHbHOptionSerializer{
- id: 11,
- payload: []byte{1, 2, 3},
- },
- &dummyHbHOptionSerializer{
- id: 22,
- payload: []byte{4, 5, 6},
- },
- },
- expect: []byte{33, 1, 11, 3, 1, 2, 3, 22, 3, 4, 5, 6, 1, 2, 0, 0},
- validate: validateDummies,
- },
- {
- name: "two options align 2n",
- nextHeader: 33,
- options: []IPv6SerializableHopByHopOption{
- &dummyHbHOptionSerializer{
- id: 11,
- payload: []byte{1, 2, 3},
- },
- &dummyHbHOptionSerializer{
- id: 22,
- payload: []byte{4, 5, 6},
- align: 2,
- },
- },
- expect: []byte{33, 1, 11, 3, 1, 2, 3, 0, 22, 3, 4, 5, 6, 1, 1, 0},
- validate: validateDummies,
- },
- {
- name: "two options align 8n+1",
- nextHeader: 33,
- options: []IPv6SerializableHopByHopOption{
- &dummyHbHOptionSerializer{
- id: 11,
- payload: []byte{1, 2},
- },
- &dummyHbHOptionSerializer{
- id: 22,
- payload: []byte{4, 5, 6},
- align: 8,
- alignOffset: 1,
- },
- },
- expect: []byte{33, 1, 11, 2, 1, 2, 1, 1, 0, 22, 3, 4, 5, 6, 1, 0},
- validate: validateDummies,
- },
- {
- name: "no options",
- nextHeader: 33,
- options: []IPv6SerializableHopByHopOption{},
- expect: []byte{33, 0, 1, 4, 0, 0, 0, 0},
- },
- {
- name: "Router Alert",
- nextHeader: 33,
- options: []IPv6SerializableHopByHopOption{&IPv6RouterAlertOption{Value: IPv6RouterAlertMLD}},
- expect: []byte{33, 0, 5, 2, 0, 0, 1, 0},
- validate: func(t *testing.T, _ IPv6SerializableHopByHopOption, deserialized IPv6ExtHdrOption) {
- t.Helper()
- routerAlert, ok := deserialized.(*IPv6RouterAlertOption)
- if !ok {
- t.Fatalf("got deserialized = %T, want = *IPv6RouterAlertOption", deserialized)
- }
- if routerAlert.Value != IPv6RouterAlertMLD {
- t.Errorf("got routerAlert.Value = %d, want = %d", routerAlert.Value, IPv6RouterAlertMLD)
- }
- },
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- s := IPv6SerializableHopByHopExtHdr(test.options)
- length := s.length()
- if length != len(test.expect) {
- t.Fatalf("got s.length() = %d, want = %d", length, len(test.expect))
- }
- b := make([]byte, length)
- for i := range b {
- // Fill the buffer with ones to ensure all padding is correctly set.
- b[i] = 0xFF
- }
- if got := s.serializeInto(test.nextHeader, b); got != length {
- t.Fatalf("got s.serializeInto(..) = %d, want = %d", got, length)
- }
- if diff := cmp.Diff(test.expect, b); diff != "" {
- t.Fatalf("serialization mismatch (-want +got):\n%s", diff)
- }
-
- // Deserialize the options and verify them.
- optLen := (b[ipv6HopByHopExtHdrLengthOffset] + ipv6HopByHopExtHdrUnaccountedLenWords) * ipv6ExtHdrLenBytesPerUnit
- iter := ipv6OptionsExtHdr(b[ipv6HopByHopExtHdrOptionsOffset:optLen]).Iter()
- for _, testOpt := range test.options {
- opt, done, err := iter.Next()
- if err != nil {
- t.Fatalf("iter.Next(): %s", err)
- }
- if done {
- t.Fatalf("got iter.Next() = (%T, %t, _), want = (_, false, _)", opt, done)
- }
- test.validate(t, testOpt, opt)
- }
- opt, done, err := iter.Next()
- if err != nil {
- t.Fatalf("iter.Next(): %s", err)
- }
- if !done {
- t.Fatalf("got iter.Next() = (%T, %t, _), want = (_, true, _)", opt, done)
- }
- })
- }
-}
-
-var _ IPv6SerializableExtHdr = (*dummyIPv6ExtHdrSerializer)(nil)
-
-// dummyIPv6ExtHdrSerializer provides a generic implementation of
-// IPv6SerializableExtHdr for use in tests.
-//
-// The dummy header always carries the nextHeader value in the first byte.
-type dummyIPv6ExtHdrSerializer struct {
- id IPv6ExtensionHeaderIdentifier
- headerContents []byte
-}
-
-// identifier implements IPv6SerializableExtHdr.
-func (s *dummyIPv6ExtHdrSerializer) identifier() IPv6ExtensionHeaderIdentifier {
- return s.id
-}
-
-// length implements IPv6SerializableExtHdr.
-func (s *dummyIPv6ExtHdrSerializer) length() int {
- return len(s.headerContents) + 1
-}
-
-// serializeInto implements IPv6SerializableExtHdr.
-func (s *dummyIPv6ExtHdrSerializer) serializeInto(nextHeader uint8, b []byte) int {
- b[0] = nextHeader
- return copy(b[1:], s.headerContents) + 1
-}
-
-func TestIPv6ExtHdrSerializer(t *testing.T) {
- tests := []struct {
- name string
- headers []IPv6SerializableExtHdr
- nextHeader tcpip.TransportProtocolNumber
- expectSerialized []byte
- expectNextHeader uint8
- }{
- {
- name: "one header",
- headers: []IPv6SerializableExtHdr{
- &dummyIPv6ExtHdrSerializer{
- id: 15,
- headerContents: []byte{1, 2, 3, 4},
- },
- },
- nextHeader: TCPProtocolNumber,
- expectSerialized: []byte{byte(TCPProtocolNumber), 1, 2, 3, 4},
- expectNextHeader: 15,
- },
- {
- name: "two headers",
- headers: []IPv6SerializableExtHdr{
- &dummyIPv6ExtHdrSerializer{
- id: 22,
- headerContents: []byte{1, 2, 3},
- },
- &dummyIPv6ExtHdrSerializer{
- id: 23,
- headerContents: []byte{4, 5, 6},
- },
- },
- nextHeader: ICMPv6ProtocolNumber,
- expectSerialized: []byte{
- 23, 1, 2, 3,
- byte(ICMPv6ProtocolNumber), 4, 5, 6,
- },
- expectNextHeader: 22,
- },
- {
- name: "no headers",
- headers: []IPv6SerializableExtHdr{},
- nextHeader: UDPProtocolNumber,
- expectSerialized: []byte{},
- expectNextHeader: byte(UDPProtocolNumber),
- },
- }
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- s := IPv6ExtHdrSerializer(test.headers)
- l := s.Length()
- if got, want := l, len(test.expectSerialized); got != want {
- t.Fatalf("got serialized length = %d, want = %d", got, want)
- }
- b := make([]byte, l)
- for i := range b {
- // Fill the buffer with garbage to make sure we're writing to all bytes.
- b[i] = 0xFF
- }
- nextHeader, serializedLen := s.Serialize(test.nextHeader, b)
- if serializedLen != len(test.expectSerialized) || nextHeader != test.expectNextHeader {
- t.Errorf(
- "got s.Serialize(..) = (%d, %d), want = (%d, %d)",
- nextHeader,
- serializedLen,
- test.expectNextHeader,
- len(test.expectSerialized),
- )
- }
- if diff := cmp.Diff(test.expectSerialized, b); diff != "" {
- t.Errorf("serialization mismatch (-want +got):\n%s", diff)
- }
- })
- }
-}
diff --git a/pkg/tcpip/header/ipv6_test.go b/pkg/tcpip/header/ipv6_test.go
deleted file mode 100644
index f10f446a6..000000000
--- a/pkg/tcpip/header/ipv6_test.go
+++ /dev/null
@@ -1,375 +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 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.GlobalScope,
- 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 diff := cmp.Diff(test.err, err); diff != "" {
- t.Errorf("unexpected error from header.IsV6UniqueLocalAddress(%s), (-want, +got):\n%s", test.addr, diff)
- }
- 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 b5540bf66..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{})
-
- 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/mld_test.go b/pkg/tcpip/header/mld_test.go
deleted file mode 100644
index 0cecf10d4..000000000
--- a/pkg/tcpip/header/mld_test.go
+++ /dev/null
@@ -1,61 +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 (
- "encoding/binary"
- "testing"
- "time"
-
- "gvisor.dev/gvisor/pkg/tcpip"
-)
-
-func TestMLD(t *testing.T) {
- b := []byte{
- // Maximum Response Delay
- 0, 0,
-
- // Reserved
- 0, 0,
-
- // MulticastAddress
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
- }
-
- const maxRespDelay = 513
- binary.BigEndian.PutUint16(b, maxRespDelay)
-
- mld := MLD(b)
-
- if got, want := mld.MaximumResponseDelay(), maxRespDelay*time.Millisecond; got != want {
- t.Errorf("got mld.MaximumResponseDelay() = %s, want = %s", got, want)
- }
-
- const newMaxRespDelay = 1234
- mld.SetMaximumResponseDelay(newMaxRespDelay)
- if got, want := mld.MaximumResponseDelay(), newMaxRespDelay*time.Millisecond; got != want {
- t.Errorf("got mld.MaximumResponseDelay() = %s, want = %s", got, want)
- }
-
- if got, want := mld.MulticastAddress(), tcpip.Address([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}); got != want {
- t.Errorf("got mld.MulticastAddress() = %s, want = %s", got, want)
- }
-
- multicastAddress := tcpip.Address([]byte{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0})
- mld.SetMulticastAddress(multicastAddress)
- if got := mld.MulticastAddress(); got != multicastAddress {
- t.Errorf("got mld.MulticastAddress() = %s, want = %s", got, multicastAddress)
- }
-}
diff --git a/pkg/tcpip/header/ndp_test.go b/pkg/tcpip/header/ndp_test.go
deleted file mode 100644
index d0a1a2492..000000000
--- a/pkg/tcpip/header/ndp_test.go
+++ /dev/null
@@ -1,1452 +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"
- "encoding/binary"
- "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)
- }
- })
- }
-}
-
-// 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)
- }
- })
- }
-}
-
-func TestOpts(t *testing.T) {
- const optionHeaderLen = 2
-
- checkNonce := func(expectedNonce []byte) func(*testing.T, NDPOption) {
- return func(t *testing.T, opt NDPOption) {
- if got := opt.kind(); got != ndpNonceOptionType {
- t.Errorf("got kind() = %d, want = %d", got, ndpNonceOptionType)
- }
- nonce, ok := opt.(NDPNonceOption)
- if !ok {
- t.Fatalf("got nonce = %T, want = NDPNonceOption", opt)
- }
- if diff := cmp.Diff(expectedNonce, nonce.Nonce()); diff != "" {
- t.Errorf("nonce mismatch (-want +got):\n%s", diff)
- }
- }
- }
-
- checkTLL := func(expectedAddr tcpip.LinkAddress) func(*testing.T, NDPOption) {
- return func(t *testing.T, opt NDPOption) {
- if got := opt.kind(); got != ndpTargetLinkLayerAddressOptionType {
- t.Errorf("got kind() = %d, want = %d", got, ndpTargetLinkLayerAddressOptionType)
- }
- tll, ok := opt.(NDPTargetLinkLayerAddressOption)
- if !ok {
- t.Fatalf("got tll = %T, want = NDPTargetLinkLayerAddressOption", opt)
- }
- if got, want := tll.EthernetAddress(), expectedAddr; got != want {
- t.Errorf("got tll.EthernetAddress = %s, want = %s", got, want)
- }
- }
- }
-
- checkSLL := func(expectedAddr tcpip.LinkAddress) func(*testing.T, NDPOption) {
- return func(t *testing.T, opt NDPOption) {
- if got := opt.kind(); got != ndpSourceLinkLayerAddressOptionType {
- t.Errorf("got kind() = %d, want = %d", got, ndpSourceLinkLayerAddressOptionType)
- }
- sll, ok := opt.(NDPSourceLinkLayerAddressOption)
- if !ok {
- t.Fatalf("got sll = %T, want = NDPSourceLinkLayerAddressOption", opt)
- }
- if got, want := sll.EthernetAddress(), expectedAddr; got != want {
- t.Errorf("got sll.EthernetAddress = %s, want = %s", got, want)
- }
- }
- }
-
- const validLifetimeSeconds = 16909060
- const address = tcpip.Address("\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18")
-
- expectedRDNSSBytes := [...]byte{
- // Type, Length
- 25, 3,
-
- // Reserved
- 0, 0,
-
- // Lifetime
- 1, 2, 4, 8,
-
- // Address
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- }
- binary.BigEndian.PutUint32(expectedRDNSSBytes[4:], validLifetimeSeconds)
- if n := copy(expectedRDNSSBytes[8:], address); n != IPv6AddressSize {
- t.Fatalf("got copy(...) = %d, want = %d", n, IPv6AddressSize)
- }
- // Update reserved fields to non zero values to make sure serializing sets
- // them to zero.
- rdnssBytes := expectedRDNSSBytes
- rdnssBytes[1] = 1
- rdnssBytes[2] = 2
-
- const searchListPaddingBytes = 3
- const domainName = "abc.abcd.e"
- expectedSearchListBytes := [...]byte{
- // Type, Length
- 31, 3,
-
- // Reserved
- 0, 0,
-
- // Lifetime
- 1, 0, 0, 0,
-
- // Domain names
- 3, 'a', 'b', 'c',
- 4, 'a', 'b', 'c', 'd',
- 1, 'e',
- 0,
- 0, 0, 0, 0,
- }
- binary.BigEndian.PutUint32(expectedSearchListBytes[4:], validLifetimeSeconds)
- // Update reserved fields to non zero values to make sure serializing sets
- // them to zero.
- searchListBytes := expectedSearchListBytes
- searchListBytes[2] = 1
- searchListBytes[3] = 2
-
- const prefixLength = 43
- const onLinkFlag = false
- const slaacFlag = true
- const preferredLifetimeSeconds = 84281096
- const onLinkFlagBit = 7
- const slaacFlagBit = 6
- boolToByte := func(v bool) byte {
- if v {
- return 1
- }
- return 0
- }
- flags := boolToByte(onLinkFlag)<<onLinkFlagBit | boolToByte(slaacFlag)<<slaacFlagBit
- expectedPrefixInformationBytes := [...]byte{
- // Type, Length
- 3, 4,
-
- prefixLength, flags,
-
- // Valid Lifetime
- 1, 2, 3, 4,
-
- // Preferred Lifetime
- 5, 6, 7, 8,
-
- // Reserved2
- 0, 0, 0, 0,
-
- // Address
- 9, 10, 11, 12,
- 13, 14, 15, 16,
- 17, 18, 19, 20,
- 21, 22, 23, 24,
- }
- binary.BigEndian.PutUint32(expectedPrefixInformationBytes[4:], validLifetimeSeconds)
- binary.BigEndian.PutUint32(expectedPrefixInformationBytes[8:], preferredLifetimeSeconds)
- if n := copy(expectedPrefixInformationBytes[16:], address); n != IPv6AddressSize {
- t.Fatalf("got copy(...) = %d, want = %d", n, IPv6AddressSize)
- }
- // Update reserved fields to non zero values to make sure serializing sets
- // them to zero.
- prefixInformationBytes := expectedPrefixInformationBytes
- prefixInformationBytes[3] |= (1 << slaacFlagBit) - 1
- binary.BigEndian.PutUint32(prefixInformationBytes[12:], validLifetimeSeconds+1)
- tests := []struct {
- name string
- buf []byte
- opt NDPOption
- expectedBuf []byte
- check func(*testing.T, NDPOption)
- }{
- {
- name: "Nonce",
- buf: make([]byte, 8),
- opt: NDPNonceOption([]byte{1, 2, 3, 4, 5, 6}),
- expectedBuf: []byte{14, 1, 1, 2, 3, 4, 5, 6},
- check: checkNonce([]byte{1, 2, 3, 4, 5, 6}),
- },
- {
- name: "Nonce with padding",
- buf: []byte{1, 1, 1, 1, 1, 1, 1, 1},
- opt: NDPNonceOption([]byte{1, 2, 3, 4, 5}),
- expectedBuf: []byte{14, 1, 1, 2, 3, 4, 5, 0},
- check: checkNonce([]byte{1, 2, 3, 4, 5, 0}),
- },
-
- {
- name: "TLL Ethernet",
- buf: make([]byte, 8),
- opt: NDPTargetLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06"),
- expectedBuf: []byte{2, 1, 1, 2, 3, 4, 5, 6},
- check: checkTLL("\x01\x02\x03\x04\x05\x06"),
- },
- {
- name: "TLL Padding",
- buf: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- opt: NDPTargetLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06\x07\x08"),
- expectedBuf: []byte{2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0},
- check: checkTLL("\x01\x02\x03\x04\x05\x06"),
- },
- {
- name: "TLL Empty",
- buf: nil,
- opt: NDPTargetLinkLayerAddressOption(""),
- expectedBuf: nil,
- },
-
- {
- name: "SLL Ethernet",
- buf: make([]byte, 8),
- opt: NDPSourceLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06"),
- expectedBuf: []byte{1, 1, 1, 2, 3, 4, 5, 6},
- check: checkSLL("\x01\x02\x03\x04\x05\x06"),
- },
- {
- name: "SLL Padding",
- buf: []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- opt: NDPSourceLinkLayerAddressOption("\x01\x02\x03\x04\x05\x06\x07\x08"),
- expectedBuf: []byte{1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0},
- check: checkSLL("\x01\x02\x03\x04\x05\x06"),
- },
- {
- name: "SLL Empty",
- buf: nil,
- opt: NDPSourceLinkLayerAddressOption(""),
- expectedBuf: nil,
- },
-
- {
- name: "RDNSS",
- buf: []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},
- // NDPRecursiveDNSServer holds the option after the header bytes.
- opt: NDPRecursiveDNSServer(rdnssBytes[optionHeaderLen:]),
- expectedBuf: expectedRDNSSBytes[:],
- check: func(t *testing.T, opt NDPOption) {
- if got := opt.kind(); got != ndpRecursiveDNSServerOptionType {
- t.Errorf("got kind() = %d, want = %d", got, ndpRecursiveDNSServerOptionType)
- }
- rdnss, ok := opt.(NDPRecursiveDNSServer)
- if !ok {
- t.Fatalf("got opt = %T, want = NDPRecursiveDNSServer", opt)
- }
- if got, want := rdnss.length(), len(expectedRDNSSBytes[optionHeaderLen:]); got != want {
- t.Errorf("got length() = %d, want = %d", got, want)
- }
- if got, want := rdnss.Lifetime(), validLifetimeSeconds*time.Second; got != want {
- t.Errorf("got Lifetime() = %s, want = %s", got, want)
- }
- if addrs, err := rdnss.Addresses(); err != nil {
- t.Errorf("Addresses(): %s", err)
- } else if diff := cmp.Diff([]tcpip.Address{address}, addrs); diff != "" {
- t.Errorf("mismatched addresses (-want +got):\n%s", diff)
- }
- },
- },
-
- {
- name: "Search list",
- buf: []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},
- opt: NDPDNSSearchList(searchListBytes[optionHeaderLen:]),
- expectedBuf: expectedSearchListBytes[:],
- check: func(t *testing.T, opt NDPOption) {
- if got := opt.kind(); got != ndpDNSSearchListOptionType {
- t.Errorf("got kind() = %d, want = %d", got, ndpDNSSearchListOptionType)
- }
-
- dnssl, ok := opt.(NDPDNSSearchList)
- if !ok {
- t.Fatalf("got opt = %T, want = NDPDNSSearchList", opt)
- }
- if got, want := dnssl.length(), len(expectedRDNSSBytes[optionHeaderLen:]); got != want {
- t.Errorf("got length() = %d, want = %d", got, want)
- }
- if got, want := dnssl.Lifetime(), validLifetimeSeconds*time.Second; got != want {
- t.Errorf("got Lifetime() = %s, want = %s", got, want)
- }
-
- if domainNames, err := dnssl.DomainNames(); err != nil {
- t.Errorf("DomainNames(): %s", err)
- } else if diff := cmp.Diff([]string{domainName}, domainNames); diff != "" {
- t.Errorf("domain names mismatch (-want +got):\n%s", diff)
- }
- },
- },
-
- {
- name: "Prefix Information",
- buf: []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},
- // NDPPrefixInformation holds the option after the header bytes.
- opt: NDPPrefixInformation(prefixInformationBytes[optionHeaderLen:]),
- expectedBuf: expectedPrefixInformationBytes[:],
- check: func(t *testing.T, opt NDPOption) {
- if got := opt.kind(); got != ndpPrefixInformationType {
- t.Errorf("got kind() = %d, want = %d", got, ndpPrefixInformationType)
- }
-
- pi, ok := opt.(NDPPrefixInformation)
- if !ok {
- t.Fatalf("got opt = %T, want = NDPPrefixInformation", opt)
- }
-
- if got, want := pi.length(), len(expectedPrefixInformationBytes[optionHeaderLen:]); got != want {
- t.Errorf("got length() = %d, want = %d", got, want)
- }
- if got := pi.PrefixLength(); got != prefixLength {
- t.Errorf("got PrefixLength() = %d, want = %d", got, prefixLength)
- }
- if got := pi.OnLinkFlag(); got != onLinkFlag {
- t.Errorf("got OnLinkFlag() = %t, want = %t", got, onLinkFlag)
- }
- if got := pi.AutonomousAddressConfigurationFlag(); got != slaacFlag {
- t.Errorf("got AutonomousAddressConfigurationFlag() = %t, want = %t", got, slaacFlag)
- }
- if got, want := pi.ValidLifetime(), validLifetimeSeconds*time.Second; got != want {
- t.Errorf("got ValidLifetime() = %s, want = %s", got, want)
- }
- if got, want := pi.PreferredLifetime(), preferredLifetimeSeconds*time.Second; got != want {
- t.Errorf("got PreferredLifetime() = %s, want = %s", got, want)
- }
- if got := pi.Prefix(); got != address {
- t.Errorf("got Prefix() = %s, want = %s", got, address)
- }
- },
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- opts := NDPOptions(test.buf)
- serializer := NDPOptionsSerializer{
- test.opt,
- }
- if got, want := int(serializer.Length()), len(test.expectedBuf); got != want {
- t.Fatalf("got Length() = %d, want = %d", got, want)
- }
- opts.Serialize(serializer)
- if diff := cmp.Diff(test.expectedBuf, test.buf); diff != "" {
- t.Fatalf("serialized buffer mismatch (-want +got):\n%s", diff)
- }
-
- it, err := opts.Iter(true)
- if err != nil {
- t.Fatalf("got Iter(true) = (_, %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, _)")
- }
- test.check(t, next)
- }
-
- // 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.kind(); 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)
- }
- })
- }
-}
-
-// 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.kind(); 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.kind(); 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.kind(); 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 96db8460f..000000000
--- a/pkg/tcpip/header/tcp_test.go
+++ /dev/null
@@ -1,168 +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)
- }
- }
-}
-
-func TestTCPFlags(t *testing.T) {
- for _, tt := range []struct {
- flags header.TCPFlags
- want string
- }{
- {header.TCPFlagFin, "F "},
- {header.TCPFlagSyn, " S "},
- {header.TCPFlagRst, " R "},
- {header.TCPFlagPsh, " P "},
- {header.TCPFlagAck, " A "},
- {header.TCPFlagUrg, " U"},
- {header.TCPFlagSyn | header.TCPFlagAck, " S A "},
- {header.TCPFlagFin | header.TCPFlagAck, "F A "},
- } {
- if got := tt.flags.String(); got != tt.want {
- t.Errorf("got TCPFlags(%#b).String() = %s, want = %s", tt.flags, got, tt.want)
- }
- }
-}