diff options
Diffstat (limited to 'pkg/tcpip/header/ndp_test.go')
-rw-r--r-- | pkg/tcpip/header/ndp_test.go | 1748 |
1 files changed, 0 insertions, 1748 deletions
diff --git a/pkg/tcpip/header/ndp_test.go b/pkg/tcpip/header/ndp_test.go deleted file mode 100644 index 2a897e938..000000000 --- a/pkg/tcpip/header/ndp_test.go +++ /dev/null @@ -1,1748 +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" - "strings" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/tcpip" - "gvisor.dev/gvisor/pkg/tcpip/testutil" -) - -// 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 := testutil.MustParse6("102:304:506:708:90a:b0c:d0e:f10") - if got := ns.TargetAddress(); got != addr { - t.Errorf("got ns.TargetAddress = %s, want %s", got, addr) - } - - // Test updating the Target Address. - addr2 := testutil.MustParse6("1112:1314:1516:1718:191a:1b1c:1d1e:1f11") - 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) - } -} - -func TestNDPRouteInformationOption(t *testing.T) { - tests := []struct { - name string - - length uint8 - prefixLength uint8 - prf NDPRoutePreference - lifetimeS uint32 - prefixBytes []byte - expectedPrefix tcpip.Subnet - - expectedErr error - }{ - { - name: "Length=1 with Prefix Length = 0", - length: 1, - prefixLength: 0, - prf: MediumRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: IPv6EmptySubnet, - }, - { - name: "Length=1 but Prefix Length > 0", - length: 1, - prefixLength: 1, - prf: MediumRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedErr: ErrNDPOptMalformedBody, - }, - { - name: "Length=2 with Prefix Length = 0", - length: 2, - prefixLength: 0, - prf: MediumRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: IPv6EmptySubnet, - }, - { - name: "Length=2 with Prefix Length in [1, 64] (1)", - length: 2, - prefixLength: 1, - prf: LowRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: tcpip.AddressWithPrefix{ - Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), - PrefixLen: 1, - }.Subnet(), - }, - { - name: "Length=2 with Prefix Length in [1, 64] (64)", - length: 2, - prefixLength: 64, - prf: HighRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: tcpip.AddressWithPrefix{ - Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), - PrefixLen: 64, - }.Subnet(), - }, - { - name: "Length=2 with Prefix Length > 64", - length: 2, - prefixLength: 65, - prf: HighRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedErr: ErrNDPOptMalformedBody, - }, - { - name: "Length=3 with Prefix Length = 0", - length: 3, - prefixLength: 0, - prf: MediumRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: IPv6EmptySubnet, - }, - { - name: "Length=3 with Prefix Length in [1, 64] (1)", - length: 3, - prefixLength: 1, - prf: LowRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: tcpip.AddressWithPrefix{ - Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), - PrefixLen: 1, - }.Subnet(), - }, - { - name: "Length=3 with Prefix Length in [1, 64] (64)", - length: 3, - prefixLength: 64, - prf: HighRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: tcpip.AddressWithPrefix{ - Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), - PrefixLen: 64, - }.Subnet(), - }, - { - name: "Length=3 with Prefix Length in [65, 128] (65)", - length: 3, - prefixLength: 65, - prf: HighRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: tcpip.AddressWithPrefix{ - Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), - PrefixLen: 65, - }.Subnet(), - }, - { - name: "Length=3 with Prefix Length in [65, 128] (128)", - length: 3, - prefixLength: 128, - prf: HighRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedPrefix: tcpip.AddressWithPrefix{ - Address: tcpip.Address(strings.Repeat("\x00", IPv6AddressSize)), - PrefixLen: 128, - }.Subnet(), - }, - { - name: "Length=3 with (invalid) Prefix Length > 128", - length: 3, - prefixLength: 129, - prf: HighRoutePreference, - lifetimeS: 1, - prefixBytes: nil, - expectedErr: ErrNDPOptMalformedBody, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - expectedRouteInformationBytes := [...]byte{ - // Type, Length - 24, test.length, - - // Prefix Length, Prf - uint8(test.prefixLength), uint8(test.prf) << 3, - - // Route Lifetime - 0, 0, 0, 0, - - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - } - binary.BigEndian.PutUint32(expectedRouteInformationBytes[4:], test.lifetimeS) - _ = copy(expectedRouteInformationBytes[8:], test.prefixBytes) - - opts := NDPOptions(expectedRouteInformationBytes[:test.length*lengthByteUnits]) - it, err := opts.Iter(false) - if err != nil { - t.Fatalf("got Iter(false) = (_, %s), want = (_, nil)", err) - } - opt, done, err := it.Next() - if !errors.Is(err, test.expectedErr) { - t.Fatalf("got Next() = (_, _, %s), want = (_, _, %s)", err, test.expectedErr) - } - if want := test.expectedErr != nil; done != want { - t.Fatalf("got Next() = (_, %t, _), want = (_, %t, _)", done, want) - } - if test.expectedErr != nil { - return - } - - if got := opt.kind(); got != ndpRouteInformationType { - t.Errorf("got kind() = %d, want = %d", got, ndpRouteInformationType) - } - - ri, ok := opt.(NDPRouteInformation) - if !ok { - t.Fatalf("got opt = %T, want = NDPRouteInformation", opt) - } - - if got := ri.PrefixLength(); got != test.prefixLength { - t.Errorf("got PrefixLength() = %d, want = %d", got, test.prefixLength) - } - if got := ri.RoutePreference(); got != test.prf { - t.Errorf("got RoutePreference() = %d, want = %d", got, test.prf) - } - if got, want := ri.RouteLifetime(), time.Duration(test.lifetimeS)*time.Second; got != want { - t.Errorf("got RouteLifetime() = %s, want = %s", got, want) - } - if got, err := ri.Prefix(); err != nil { - t.Errorf("Prefix(): %s", err) - } else if got != test.expectedPrefix { - t.Errorf("got Prefix() = %s, want = %s", got, test.expectedPrefix) - } - - // 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) - } - } - }) - } -} - -// 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 := testutil.MustParse6("102:304:506:708:90a:b0c:d0e:f10") - 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 := testutil.MustParse6("1112:1314:1516:1718:191a:1b1c:1d1e:1f11") - 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) { - tests := []struct { - hopLimit uint8 - managedFlag, otherConfFlag bool - prf NDPRoutePreference - routerLifetimeS uint16 - reachableTimeMS, retransTimerMS uint32 - }{ - { - hopLimit: 1, - managedFlag: false, - otherConfFlag: true, - prf: HighRoutePreference, - routerLifetimeS: 2, - reachableTimeMS: 3, - retransTimerMS: 4, - }, - { - hopLimit: 64, - managedFlag: true, - otherConfFlag: false, - prf: LowRoutePreference, - routerLifetimeS: 258, - reachableTimeMS: 78492, - retransTimerMS: 13213, - }, - } - - for i, test := range tests { - t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - flags := uint8(0) - if test.managedFlag { - flags |= 1 << 7 - } - if test.otherConfFlag { - flags |= 1 << 6 - } - flags |= uint8(test.prf) << 3 - - b := []byte{ - test.hopLimit, flags, 1, 2, - 3, 4, 5, 6, - 7, 8, 9, 10, - } - binary.BigEndian.PutUint16(b[2:], test.routerLifetimeS) - binary.BigEndian.PutUint32(b[4:], test.reachableTimeMS) - binary.BigEndian.PutUint32(b[8:], test.retransTimerMS) - - ra := NDPRouterAdvert(b) - - if got := ra.CurrHopLimit(); got != test.hopLimit { - t.Errorf("got ra.CurrHopLimit() = %d, want = %d", got, test.hopLimit) - } - - if got := ra.ManagedAddrConfFlag(); got != test.managedFlag { - t.Errorf("got ManagedAddrConfFlag() = %t, want = %t", got, test.managedFlag) - } - - if got := ra.OtherConfFlag(); got != test.otherConfFlag { - t.Errorf("got OtherConfFlag() = %t, want = %t", got, test.otherConfFlag) - } - - if got := ra.DefaultRouterPreference(); got != test.prf { - t.Errorf("got DefaultRouterPreference() = %d, want = %d", got, test.prf) - } - - if got, want := ra.RouterLifetime(), time.Second*time.Duration(test.routerLifetimeS); got != want { - t.Errorf("got ra.RouterLifetime() = %d, want = %d", got, want) - } - - if got, want := ra.ReachableTime(), time.Millisecond*time.Duration(test.reachableTimeMS); got != want { - t.Errorf("got ra.ReachableTime() = %d, want = %d", got, want) - } - - if got, want := ra.RetransTimer(), time.Millisecond*time.Duration(test.retransTimerMS); 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 - address := testutil.MustParse6("90a:b0c:d0e:f10:1112:1314:1516:1718") - - 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) - } -} - -func TestNDPRoutePreferenceStringer(t *testing.T) { - p := NDPRoutePreference(0) - for { - var wantStr string - switch p { - case 0b01: - wantStr = "HighRoutePreference" - case 0b00: - wantStr = "MediumRoutePreference" - case 0b11: - wantStr = "LowRoutePreference" - case 0b10: - wantStr = "ReservedRoutePreference" - default: - wantStr = fmt.Sprintf("NDPRoutePreference(%d)", p) - } - - if gotStr := p.String(); gotStr != wantStr { - t.Errorf("got NDPRoutePreference(%d).String() = %s, want = %s", p, gotStr, wantStr) - } - - p++ - if p == 0 { - // Overflowed, we hit all values. - break - } - } -} |