diff options
Diffstat (limited to 'pkg/tcpip/header')
-rw-r--r-- | pkg/tcpip/header/ndp_options.go | 156 | ||||
-rw-r--r-- | pkg/tcpip/header/ndp_test.go | 695 | ||||
-rw-r--r-- | pkg/tcpip/header/ndpoptionidentifier_string.go | 32 |
3 files changed, 430 insertions, 453 deletions
diff --git a/pkg/tcpip/header/ndp_options.go b/pkg/tcpip/header/ndp_options.go index 554242f0c..3d1bccd15 100644 --- a/pkg/tcpip/header/ndp_options.go +++ b/pkg/tcpip/header/ndp_options.go @@ -26,29 +26,33 @@ import ( "gvisor.dev/gvisor/pkg/tcpip" ) -// NDPOptionIdentifier is an NDP option type identifier. -type NDPOptionIdentifier uint8 +// ndpOptionIdentifier is an NDP option type identifier. +type ndpOptionIdentifier uint8 const ( - // NDPSourceLinkLayerAddressOptionType is the type of the Source Link Layer + // ndpSourceLinkLayerAddressOptionType is the type of the Source Link Layer // Address option, as per RFC 4861 section 4.6.1. - NDPSourceLinkLayerAddressOptionType NDPOptionIdentifier = 1 + ndpSourceLinkLayerAddressOptionType ndpOptionIdentifier = 1 - // NDPTargetLinkLayerAddressOptionType is the type of the Target Link Layer + // ndpTargetLinkLayerAddressOptionType is the type of the Target Link Layer // Address option, as per RFC 4861 section 4.6.1. - NDPTargetLinkLayerAddressOptionType NDPOptionIdentifier = 2 + ndpTargetLinkLayerAddressOptionType ndpOptionIdentifier = 2 - // NDPPrefixInformationType is the type of the Prefix Information + // ndpPrefixInformationType is the type of the Prefix Information // option, as per RFC 4861 section 4.6.2. - NDPPrefixInformationType NDPOptionIdentifier = 3 + ndpPrefixInformationType ndpOptionIdentifier = 3 - // NDPRecursiveDNSServerOptionType is the type of the Recursive DNS + // ndpNonceOptionType is the type of the Nonce option, as per + // RFC 3971 section 5.3.2. + ndpNonceOptionType ndpOptionIdentifier = 14 + + // ndpRecursiveDNSServerOptionType is the type of the Recursive DNS // Server option, as per RFC 8106 section 5.1. - NDPRecursiveDNSServerOptionType NDPOptionIdentifier = 25 + ndpRecursiveDNSServerOptionType ndpOptionIdentifier = 25 - // NDPDNSSearchListOptionType is the type of the DNS Search List option, + // ndpDNSSearchListOptionType is the type of the DNS Search List option, // as per RFC 8106 section 5.2. - NDPDNSSearchListOptionType = 31 + ndpDNSSearchListOptionType ndpOptionIdentifier = 31 ) const ( @@ -198,7 +202,7 @@ func (i *NDPOptionIterator) Next() (NDPOption, bool, error) { // bytes for the whole option. return nil, true, fmt.Errorf("unexpectedly exhausted buffer when reading the option's Type field: %w", io.ErrUnexpectedEOF) } - kind := NDPOptionIdentifier(temp) + kind := ndpOptionIdentifier(temp) // Get the Length field. length, err := i.opts.ReadByte() @@ -225,13 +229,16 @@ func (i *NDPOptionIterator) Next() (NDPOption, bool, error) { } switch kind { - case NDPSourceLinkLayerAddressOptionType: + case ndpSourceLinkLayerAddressOptionType: return NDPSourceLinkLayerAddressOption(body), false, nil - case NDPTargetLinkLayerAddressOptionType: + case ndpTargetLinkLayerAddressOptionType: return NDPTargetLinkLayerAddressOption(body), false, nil - case NDPPrefixInformationType: + case ndpNonceOptionType: + return NDPNonceOption(body), false, nil + + case ndpPrefixInformationType: // Make sure the length of a Prefix Information option // body is ndpPrefixInformationLength, as per RFC 4861 // section 4.6.2. @@ -241,7 +248,7 @@ func (i *NDPOptionIterator) Next() (NDPOption, bool, error) { return NDPPrefixInformation(body), false, nil - case NDPRecursiveDNSServerOptionType: + case ndpRecursiveDNSServerOptionType: opt := NDPRecursiveDNSServer(body) if err := opt.checkAddresses(); err != nil { return nil, true, err @@ -249,7 +256,7 @@ func (i *NDPOptionIterator) Next() (NDPOption, bool, error) { return opt, false, nil - case NDPDNSSearchListOptionType: + case ndpDNSSearchListOptionType: opt := NDPDNSSearchList(body) if err := opt.checkDomainNames(); err != nil { return nil, true, err @@ -316,7 +323,7 @@ func (b NDPOptions) Serialize(s NDPOptionsSerializer) int { continue } - b[0] = byte(o.Type()) + b[0] = byte(o.kind()) // We know this safe because paddedLength would have returned // 0 if o had an invalid length (> 255 * lengthByteUnits). @@ -341,11 +348,11 @@ func (b NDPOptions) Serialize(s NDPOptionsSerializer) int { type NDPOption interface { fmt.Stringer - // Type returns the type of the receiver. - Type() NDPOptionIdentifier + // kind returns the type of the receiver. + kind() ndpOptionIdentifier - // Length returns the length of the body of the receiver, in bytes. - Length() int + // length returns the length of the body of the receiver, in bytes. + length() int // serializeInto serializes the receiver into the provided byte // buffer. @@ -365,7 +372,7 @@ type NDPOption interface { // paddedLength returns the length of o, in bytes, with any padding bytes, if // required. func paddedLength(o NDPOption) int { - l := o.Length() + l := o.length() if l == 0 { return 0 @@ -416,6 +423,37 @@ func (b NDPOptionsSerializer) Length() int { return l } +// NDPNonceOption is the NDP Nonce Option as defined by RFC 3971 section 5.3.2. +// +// It is the first X bytes following the NDP option's Type and Length field +// where X is the value in Length multiplied by lengthByteUnits - 2 bytes. +type NDPNonceOption []byte + +// kind implements NDPOption. +func (o NDPNonceOption) kind() ndpOptionIdentifier { + return ndpNonceOptionType +} + +// length implements NDPOption. +func (o NDPNonceOption) length() int { + return len(o) +} + +// serializeInto implements NDPOption. +func (o NDPNonceOption) serializeInto(b []byte) int { + return copy(b, o) +} + +// String implements fmt.Stringer. +func (o NDPNonceOption) String() string { + return fmt.Sprintf("%T(%x)", o, []byte(o)) +} + +// Nonce returns the nonce value this option holds. +func (o NDPNonceOption) Nonce() []byte { + return []byte(o) +} + // NDPSourceLinkLayerAddressOption is the NDP Source Link Layer Option // as defined by RFC 4861 section 4.6.1. // @@ -423,22 +461,22 @@ func (b NDPOptionsSerializer) Length() int { // where X is the value in Length multiplied by lengthByteUnits - 2 bytes. type NDPSourceLinkLayerAddressOption tcpip.LinkAddress -// Type implements NDPOption.Type. -func (o NDPSourceLinkLayerAddressOption) Type() NDPOptionIdentifier { - return NDPSourceLinkLayerAddressOptionType +// kind implements NDPOption. +func (o NDPSourceLinkLayerAddressOption) kind() ndpOptionIdentifier { + return ndpSourceLinkLayerAddressOptionType } -// Length implements NDPOption.Length. -func (o NDPSourceLinkLayerAddressOption) Length() int { +// length implements NDPOption. +func (o NDPSourceLinkLayerAddressOption) length() int { return len(o) } -// serializeInto implements NDPOption.serializeInto. +// serializeInto implements NDPOption. func (o NDPSourceLinkLayerAddressOption) serializeInto(b []byte) int { return copy(b, o) } -// String implements fmt.Stringer.String. +// String implements fmt.Stringer. func (o NDPSourceLinkLayerAddressOption) String() string { return fmt.Sprintf("%T(%s)", o, tcpip.LinkAddress(o)) } @@ -463,22 +501,22 @@ func (o NDPSourceLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress { // where X is the value in Length multiplied by lengthByteUnits - 2 bytes. type NDPTargetLinkLayerAddressOption tcpip.LinkAddress -// Type implements NDPOption.Type. -func (o NDPTargetLinkLayerAddressOption) Type() NDPOptionIdentifier { - return NDPTargetLinkLayerAddressOptionType +// kind implements NDPOption. +func (o NDPTargetLinkLayerAddressOption) kind() ndpOptionIdentifier { + return ndpTargetLinkLayerAddressOptionType } -// Length implements NDPOption.Length. -func (o NDPTargetLinkLayerAddressOption) Length() int { +// length implements NDPOption. +func (o NDPTargetLinkLayerAddressOption) length() int { return len(o) } -// serializeInto implements NDPOption.serializeInto. +// serializeInto implements NDPOption. func (o NDPTargetLinkLayerAddressOption) serializeInto(b []byte) int { return copy(b, o) } -// String implements fmt.Stringer.String. +// String implements fmt.Stringer. func (o NDPTargetLinkLayerAddressOption) String() string { return fmt.Sprintf("%T(%s)", o, tcpip.LinkAddress(o)) } @@ -503,17 +541,17 @@ func (o NDPTargetLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress { // ndpPrefixInformationLength bytes. type NDPPrefixInformation []byte -// Type implements NDPOption.Type. -func (o NDPPrefixInformation) Type() NDPOptionIdentifier { - return NDPPrefixInformationType +// kind implements NDPOption. +func (o NDPPrefixInformation) kind() ndpOptionIdentifier { + return ndpPrefixInformationType } -// Length implements NDPOption.Length. -func (o NDPPrefixInformation) Length() int { +// length implements NDPOption. +func (o NDPPrefixInformation) length() int { return ndpPrefixInformationLength } -// serializeInto implements NDPOption.serializeInto. +// serializeInto implements NDPOption. func (o NDPPrefixInformation) serializeInto(b []byte) int { used := copy(b, o) @@ -529,7 +567,7 @@ func (o NDPPrefixInformation) serializeInto(b []byte) int { return used } -// String implements fmt.Stringer.String. +// String implements fmt.Stringer. func (o NDPPrefixInformation) String() string { return fmt.Sprintf("%T(O=%t, A=%t, PL=%s, VL=%s, Prefix=%s)", o, @@ -627,17 +665,17 @@ type NDPRecursiveDNSServer []byte // Type returns the type of an NDP Recursive DNS Server option. // -// Type implements NDPOption.Type. -func (NDPRecursiveDNSServer) Type() NDPOptionIdentifier { - return NDPRecursiveDNSServerOptionType +// kind implements NDPOption. +func (NDPRecursiveDNSServer) kind() ndpOptionIdentifier { + return ndpRecursiveDNSServerOptionType } -// Length implements NDPOption.Length. -func (o NDPRecursiveDNSServer) Length() int { +// length implements NDPOption. +func (o NDPRecursiveDNSServer) length() int { return len(o) } -// serializeInto implements NDPOption.serializeInto. +// serializeInto implements NDPOption. func (o NDPRecursiveDNSServer) serializeInto(b []byte) int { used := copy(b, o) @@ -649,7 +687,7 @@ func (o NDPRecursiveDNSServer) serializeInto(b []byte) int { return used } -// String implements fmt.Stringer.String. +// String implements fmt.Stringer. func (o NDPRecursiveDNSServer) String() string { lt := o.Lifetime() addrs, err := o.Addresses() @@ -722,17 +760,17 @@ func (o NDPRecursiveDNSServer) iterAddresses(fn func(tcpip.Address)) error { // RFC 8106 section 5.2. type NDPDNSSearchList []byte -// Type implements NDPOption.Type. -func (o NDPDNSSearchList) Type() NDPOptionIdentifier { - return NDPDNSSearchListOptionType +// kind implements NDPOption. +func (o NDPDNSSearchList) kind() ndpOptionIdentifier { + return ndpDNSSearchListOptionType } -// Length implements NDPOption.Length. -func (o NDPDNSSearchList) Length() int { +// length implements NDPOption. +func (o NDPDNSSearchList) length() int { return len(o) } -// serializeInto implements NDPOption.serializeInto. +// serializeInto implements NDPOption. func (o NDPDNSSearchList) serializeInto(b []byte) int { used := copy(b, o) @@ -744,7 +782,7 @@ func (o NDPDNSSearchList) serializeInto(b []byte) int { return used } -// String implements fmt.Stringer.String. +// String implements fmt.Stringer. func (o NDPDNSSearchList) String() string { lt := o.Lifetime() domainNames, err := o.DomainNames() diff --git a/pkg/tcpip/header/ndp_test.go b/pkg/tcpip/header/ndp_test.go index dc4591253..d0a1a2492 100644 --- a/pkg/tcpip/header/ndp_test.go +++ b/pkg/tcpip/header/ndp_test.go @@ -16,6 +16,7 @@ package header import ( "bytes" + "encoding/binary" "errors" "fmt" "io" @@ -192,90 +193,6 @@ func TestNDPSourceLinkLayerAddressOptionEthernetAddress(t *testing.T) { } } -// TestNDPSourceLinkLayerAddressOptionSerialize tests serializing a -// NDPSourceLinkLayerAddressOption. -func TestNDPSourceLinkLayerAddressOptionSerialize(t *testing.T) { - tests := []struct { - name string - buf []byte - expectedBuf []byte - addr tcpip.LinkAddress - }{ - { - "Ethernet", - make([]byte, 8), - []byte{1, 1, 1, 2, 3, 4, 5, 6}, - "\x01\x02\x03\x04\x05\x06", - }, - { - "Padding", - []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - []byte{1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0}, - "\x01\x02\x03\x04\x05\x06\x07\x08", - }, - { - "Empty", - nil, - nil, - "", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - opts := NDPOptions(test.buf) - serializer := NDPOptionsSerializer{ - NDPSourceLinkLayerAddressOption(test.addr), - } - if got, want := int(serializer.Length()), len(test.expectedBuf); got != want { - t.Fatalf("got Length = %d, want = %d", got, want) - } - opts.Serialize(serializer) - if !bytes.Equal(test.buf, test.expectedBuf) { - t.Fatalf("got b = %d, want = %d", test.buf, test.expectedBuf) - } - - it, err := opts.Iter(true) - if err != nil { - t.Fatalf("got Iter = (_, %s), want = (_, nil)", err) - } - - if len(test.expectedBuf) > 0 { - next, done, err := it.Next() - if err != nil { - t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if done { - t.Fatal("got Next = (_, true, _), want = (_, false, _)") - } - if got := next.Type(); got != NDPSourceLinkLayerAddressOptionType { - t.Fatalf("got Type = %d, want = %d", got, NDPSourceLinkLayerAddressOptionType) - } - sll := next.(NDPSourceLinkLayerAddressOption) - if got, want := []byte(sll), test.expectedBuf[2:]; !bytes.Equal(got, want) { - t.Fatalf("got Next = (%x, _, _), want = (%x, _, _)", got, want) - } - - if got, want := sll.EthernetAddress(), tcpip.LinkAddress(test.expectedBuf[2:][:EthernetAddressSize]); got != want { - t.Errorf("got sll.EthernetAddress = %s, want = %s", got, want) - } - } - - // Iterator should not return anything else. - next, done, err := it.Next() - if err != nil { - t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if !done { - t.Error("got Next = (_, false, _), want = (_, true, _)") - } - if next != nil { - t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next) - } - }) - } -} - // TestNDPTargetLinkLayerAddressOptionEthernetAddress tests getting the // Ethernet address from an NDPTargetLinkLayerAddressOption. func TestNDPTargetLinkLayerAddressOptionEthernetAddress(t *testing.T) { @@ -311,32 +228,309 @@ func TestNDPTargetLinkLayerAddressOptionEthernetAddress(t *testing.T) { } } -// TestNDPTargetLinkLayerAddressOptionSerialize tests serializing a -// NDPTargetLinkLayerAddressOption. -func TestNDPTargetLinkLayerAddressOptionSerialize(t *testing.T) { +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 - addr tcpip.LinkAddress + check func(*testing.T, NDPOption) }{ { - "Ethernet", - make([]byte, 8), - []byte{2, 1, 1, 2, 3, 4, 5, 6}, - "\x01\x02\x03\x04\x05\x06", + 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, }, + { - "Padding", - []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, - []byte{2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0}, - "\x01\x02\x03\x04\x05\x06\x07\x08", + 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"), }, { - "Empty", - nil, - nil, - "", + 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) + } + }, }, } @@ -344,230 +538,47 @@ func TestNDPTargetLinkLayerAddressOptionSerialize(t *testing.T) { t.Run(test.name, func(t *testing.T) { opts := NDPOptions(test.buf) serializer := NDPOptionsSerializer{ - NDPTargetLinkLayerAddressOption(test.addr), + test.opt, } if got, want := int(serializer.Length()), len(test.expectedBuf); got != want { - t.Fatalf("got Length = %d, want = %d", got, want) + t.Fatalf("got Length() = %d, want = %d", got, want) } opts.Serialize(serializer) - if !bytes.Equal(test.buf, test.expectedBuf) { - t.Fatalf("got b = %d, want = %d", test.buf, test.expectedBuf) + 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 = (_, %s), want = (_, nil)", err) + 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) + t.Fatalf("got Next() = (_, _, %s), want = (_, _, nil)", err) } if done { - t.Fatal("got Next = (_, true, _), want = (_, false, _)") - } - if got := next.Type(); got != NDPTargetLinkLayerAddressOptionType { - t.Fatalf("got Type = %d, want = %d", got, NDPTargetLinkLayerAddressOptionType) - } - tll := next.(NDPTargetLinkLayerAddressOption) - if got, want := []byte(tll), test.expectedBuf[2:]; !bytes.Equal(got, want) { - t.Fatalf("got Next = (%x, _, _), want = (%x, _, _)", got, want) - } - - if got, want := tll.EthernetAddress(), tcpip.LinkAddress(test.expectedBuf[2:][:EthernetAddressSize]); got != want { - t.Errorf("got tll.EthernetAddress = %s, want = %s", got, want) + 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) + t.Errorf("got Next() = (_, _, %s), want = (_, _, nil)", err) } if !done { - t.Error("got Next = (_, false, _), want = (_, true, _)") + t.Error("got Next() = (_, false, _), want = (_, true, _)") } if next != nil { - t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next) + t.Errorf("got Next() = (%x, _, _), want = (nil, _, _)", next) } }) } } -// TestNDPPrefixInformationOption tests the field getters and serialization of a -// NDPPrefixInformation. -func TestNDPPrefixInformationOption(t *testing.T) { - b := []byte{ - 43, 127, - 1, 2, 3, 4, - 5, 6, 7, 8, - 5, 5, 5, 5, - 9, 10, 11, 12, - 13, 14, 15, 16, - 17, 18, 19, 20, - 21, 22, 23, 24, - } - - targetBuf := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - opts := NDPOptions(targetBuf) - serializer := NDPOptionsSerializer{ - NDPPrefixInformation(b), - } - opts.Serialize(serializer) - expectedBuf := []byte{ - 3, 4, 43, 64, - 1, 2, 3, 4, - 5, 6, 7, 8, - 0, 0, 0, 0, - 9, 10, 11, 12, - 13, 14, 15, 16, - 17, 18, 19, 20, - 21, 22, 23, 24, - } - if !bytes.Equal(targetBuf, expectedBuf) { - t.Fatalf("got targetBuf = %x, want = %x", targetBuf, expectedBuf) - } - - it, err := opts.Iter(true) - if err != nil { - t.Fatalf("got Iter = (_, %s), want = (_, nil)", err) - } - - next, done, err := it.Next() - if err != nil { - t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if done { - t.Fatal("got Next = (_, true, _), want = (_, false, _)") - } - if got := next.Type(); got != NDPPrefixInformationType { - t.Errorf("got Type = %d, want = %d", got, NDPPrefixInformationType) - } - - pi := next.(NDPPrefixInformation) - - if got := pi.Type(); got != 3 { - t.Errorf("got Type = %d, want = 3", got) - } - - if got := pi.Length(); got != 30 { - t.Errorf("got Length = %d, want = 30", got) - } - - if got := pi.PrefixLength(); got != 43 { - t.Errorf("got PrefixLength = %d, want = 43", got) - } - - if pi.OnLinkFlag() { - t.Error("got OnLinkFlag = true, want = false") - } - - if !pi.AutonomousAddressConfigurationFlag() { - t.Error("got AutonomousAddressConfigurationFlag = false, want = true") - } - - if got, want := pi.ValidLifetime(), 16909060*time.Second; got != want { - t.Errorf("got ValidLifetime = %d, want = %d", got, want) - } - - if got, want := pi.PreferredLifetime(), 84281096*time.Second; got != want { - t.Errorf("got PreferredLifetime = %d, want = %d", got, want) - } - - if got, want := pi.Prefix(), tcpip.Address("\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18"); got != want { - t.Errorf("got Prefix = %s, want = %s", got, want) - } - - // Iterator should not return anything else. - next, done, err = it.Next() - if err != nil { - t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if !done { - t.Error("got Next = (_, false, _), want = (_, true, _)") - } - if next != nil { - t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next) - } -} - -func TestNDPRecursiveDNSServerOptionSerialize(t *testing.T) { - b := []byte{ - 9, 8, - 1, 2, 4, 8, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - } - targetBuf := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - expected := []byte{ - 25, 3, 0, 0, - 1, 2, 4, 8, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - } - opts := NDPOptions(targetBuf) - serializer := NDPOptionsSerializer{ - NDPRecursiveDNSServer(b), - } - if got, want := opts.Serialize(serializer), len(expected); got != want { - t.Errorf("got Serialize = %d, want = %d", got, want) - } - if !bytes.Equal(targetBuf, expected) { - t.Fatalf("got targetBuf = %x, want = %x", targetBuf, expected) - } - - it, err := opts.Iter(true) - if err != nil { - t.Fatalf("got Iter = (_, %s), want = (_, nil)", err) - } - - next, done, err := it.Next() - if err != nil { - t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if done { - t.Fatal("got Next = (_, true, _), want = (_, false, _)") - } - if got := next.Type(); got != NDPRecursiveDNSServerOptionType { - t.Errorf("got Type = %d, want = %d", got, NDPRecursiveDNSServerOptionType) - } - - opt, ok := next.(NDPRecursiveDNSServer) - if !ok { - t.Fatalf("next (type = %T) cannot be casted to an NDPRecursiveDNSServer", next) - } - if got := opt.Type(); got != 25 { - t.Errorf("got Type = %d, want = 31", got) - } - if got := opt.Length(); got != 22 { - t.Errorf("got Length = %d, want = 22", got) - } - if got, want := opt.Lifetime(), 16909320*time.Second; got != want { - t.Errorf("got Lifetime = %s, want = %s", got, want) - } - want := []tcpip.Address{ - "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - } - addrs, err := opt.Addresses() - if err != nil { - t.Errorf("opt.Addresses() = %s", err) - } - if diff := cmp.Diff(addrs, want); diff != "" { - t.Errorf("mismatched addresses (-want +got):\n%s", diff) - } - - // Iterator should not return anything else. - next, done, err = it.Next() - if err != nil { - t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if !done { - t.Error("got Next = (_, false, _), want = (_, true, _)") - } - if next != nil { - t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next) - } -} - func TestNDPRecursiveDNSServerOption(t *testing.T) { tests := []struct { name string @@ -635,8 +646,8 @@ func TestNDPRecursiveDNSServerOption(t *testing.T) { if done { t.Fatal("got Next = (_, true, _), want = (_, false, _)") } - if got := next.Type(); got != NDPRecursiveDNSServerOptionType { - t.Fatalf("got Type = %d, want = %d", got, NDPRecursiveDNSServerOptionType) + if got := next.kind(); got != ndpRecursiveDNSServerOptionType { + t.Fatalf("got Type = %d, want = %d", got, ndpRecursiveDNSServerOptionType) } opt, ok := next.(NDPRecursiveDNSServer) @@ -1060,86 +1071,6 @@ func TestNDPSearchListOptionDomainNameLabelInvalidSymbols(t *testing.T) { } } -func TestNDPDNSSearchListOptionSerialize(t *testing.T) { - b := []byte{ - 9, 8, - 1, 0, 0, 0, - 3, 'a', 'b', 'c', - 4, 'a', 'b', 'c', 'd', - 1, 'e', - 0, - } - targetBuf := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - expected := []byte{ - 31, 3, 0, 0, - 1, 0, 0, 0, - 3, 'a', 'b', 'c', - 4, 'a', 'b', 'c', 'd', - 1, 'e', - 0, - 0, 0, 0, 0, - } - opts := NDPOptions(targetBuf) - serializer := NDPOptionsSerializer{ - NDPDNSSearchList(b), - } - if got, want := opts.Serialize(serializer), len(expected); got != want { - t.Errorf("got Serialize = %d, want = %d", got, want) - } - if !bytes.Equal(targetBuf, expected) { - t.Fatalf("got targetBuf = %x, want = %x", targetBuf, expected) - } - - it, err := opts.Iter(true) - if err != nil { - t.Fatalf("got Iter = (_, %s), want = (_, nil)", err) - } - - next, done, err := it.Next() - if err != nil { - t.Fatalf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if done { - t.Fatal("got Next = (_, true, _), want = (_, false, _)") - } - if got := next.Type(); got != NDPDNSSearchListOptionType { - t.Errorf("got Type = %d, want = %d", got, NDPDNSSearchListOptionType) - } - - opt, ok := next.(NDPDNSSearchList) - if !ok { - t.Fatalf("next (type = %T) cannot be casted to an NDPDNSSearchList", next) - } - if got := opt.Type(); got != 31 { - t.Errorf("got Type = %d, want = 31", got) - } - if got := opt.Length(); got != 22 { - t.Errorf("got Length = %d, want = 22", got) - } - if got, want := opt.Lifetime(), 16777216*time.Second; got != want { - t.Errorf("got Lifetime = %s, want = %s", got, want) - } - domainNames, err := opt.DomainNames() - if err != nil { - t.Errorf("opt.DomainNames() = %s", err) - } - if diff := cmp.Diff(domainNames, []string{"abc.abcd.e"}); diff != "" { - t.Errorf("domain names mismatch (-want +got):\n%s", diff) - } - - // Iterator should not return anything else. - next, done, err = it.Next() - if err != nil { - t.Errorf("got Next = (_, _, %s), want = (_, _, nil)", err) - } - if !done { - t.Error("got Next = (_, false, _), want = (_, true, _)") - } - if next != nil { - t.Errorf("got Next = (%x, _, _), want = (nil, _, _)", next) - } -} - // TestNDPOptionsIterCheck tests that Iter will return false if the NDPOptions // the iterator was returned for is malformed. func TestNDPOptionsIterCheck(t *testing.T) { @@ -1472,8 +1403,8 @@ func TestNDPOptionsIter(t *testing.T) { if got, want := []byte(next.(NDPSourceLinkLayerAddressOption)), buf[2:][:6]; !bytes.Equal(got, want) { t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want) } - if got := next.Type(); got != NDPSourceLinkLayerAddressOptionType { - t.Errorf("got Type = %d, want = %d", got, NDPSourceLinkLayerAddressOptionType) + if got := next.kind(); got != ndpSourceLinkLayerAddressOptionType { + t.Errorf("got Type = %d, want = %d", got, ndpSourceLinkLayerAddressOptionType) } // Test the next (Target Link-Layer) option. @@ -1487,8 +1418,8 @@ func TestNDPOptionsIter(t *testing.T) { if got, want := []byte(next.(NDPTargetLinkLayerAddressOption)), buf[10:][:6]; !bytes.Equal(got, want) { t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want) } - if got := next.Type(); got != NDPTargetLinkLayerAddressOptionType { - t.Errorf("got Type = %d, want = %d", got, NDPTargetLinkLayerAddressOptionType) + if got := next.kind(); got != ndpTargetLinkLayerAddressOptionType { + t.Errorf("got Type = %d, want = %d", got, ndpTargetLinkLayerAddressOptionType) } // Test the next (Prefix Information) option. @@ -1503,8 +1434,8 @@ func TestNDPOptionsIter(t *testing.T) { if got, want := next.(NDPPrefixInformation), buf[34:][:30]; !bytes.Equal(got, want) { t.Errorf("got Next = (%x, _, _), want = (%x, _, _)", got, want) } - if got := next.Type(); got != NDPPrefixInformationType { - t.Errorf("got Type = %d, want = %d", got, NDPPrefixInformationType) + if got := next.kind(); got != ndpPrefixInformationType { + t.Errorf("got Type = %d, want = %d", got, ndpPrefixInformationType) } // Iterator should not return anything else. diff --git a/pkg/tcpip/header/ndpoptionidentifier_string.go b/pkg/tcpip/header/ndpoptionidentifier_string.go index 6fe9a336b..55ab1d7cf 100644 --- a/pkg/tcpip/header/ndpoptionidentifier_string.go +++ b/pkg/tcpip/header/ndpoptionidentifier_string.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by "stringer -type NDPOptionIdentifier ."; DO NOT EDIT. +// Code generated by "stringer -type ndpOptionIdentifier"; DO NOT EDIT. package header @@ -22,29 +22,37 @@ func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} - _ = x[NDPSourceLinkLayerAddressOptionType-1] - _ = x[NDPTargetLinkLayerAddressOptionType-2] - _ = x[NDPPrefixInformationType-3] - _ = x[NDPRecursiveDNSServerOptionType-25] + _ = x[ndpSourceLinkLayerAddressOptionType-1] + _ = x[ndpTargetLinkLayerAddressOptionType-2] + _ = x[ndpPrefixInformationType-3] + _ = x[ndpNonceOptionType-14] + _ = x[ndpRecursiveDNSServerOptionType-25] + _ = x[ndpDNSSearchListOptionType-31] } const ( - _NDPOptionIdentifier_name_0 = "NDPSourceLinkLayerAddressOptionTypeNDPTargetLinkLayerAddressOptionTypeNDPPrefixInformationType" - _NDPOptionIdentifier_name_1 = "NDPRecursiveDNSServerOptionType" + _ndpOptionIdentifier_name_0 = "ndpSourceLinkLayerAddressOptionTypendpTargetLinkLayerAddressOptionTypendpPrefixInformationType" + _ndpOptionIdentifier_name_1 = "ndpNonceOptionType" + _ndpOptionIdentifier_name_2 = "ndpRecursiveDNSServerOptionType" + _ndpOptionIdentifier_name_3 = "ndpDNSSearchListOptionType" ) var ( - _NDPOptionIdentifier_index_0 = [...]uint8{0, 35, 70, 94} + _ndpOptionIdentifier_index_0 = [...]uint8{0, 35, 70, 94} ) -func (i NDPOptionIdentifier) String() string { +func (i ndpOptionIdentifier) String() string { switch { case 1 <= i && i <= 3: i -= 1 - return _NDPOptionIdentifier_name_0[_NDPOptionIdentifier_index_0[i]:_NDPOptionIdentifier_index_0[i+1]] + return _ndpOptionIdentifier_name_0[_ndpOptionIdentifier_index_0[i]:_ndpOptionIdentifier_index_0[i+1]] + case i == 14: + return _ndpOptionIdentifier_name_1 case i == 25: - return _NDPOptionIdentifier_name_1 + return _ndpOptionIdentifier_name_2 + case i == 31: + return _ndpOptionIdentifier_name_3 default: - return "NDPOptionIdentifier(" + strconv.FormatInt(int64(i), 10) + ")" + return "ndpOptionIdentifier(" + strconv.FormatInt(int64(i), 10) + ")" } } |