Introduce IPv6 extension header serialization facilities

Adds IPv6 extension header serializer and Hop by Hop options serializer.
Add RouterAlert option serializer and use it in MLD.

Fixed #4996

Startblock:
  has LGTM from marinaciocea
  and then
  add reviewer ghanan
PiperOrigin-RevId: 347174537
This commit is contained in:
Bruno Dal Bo
2020-12-12 09:07:44 -08:00
committed by gVisor bot
parent 4b697aae55
commit 4aef908c92
20 changed files with 1249 additions and 371 deletions
+190
View File
@@ -117,6 +117,10 @@ func TTL(ttl uint8) NetworkChecker {
v = ip.TTL()
case header.IPv6:
v = ip.HopLimit()
case *ipv6HeaderWithExtHdr:
v = ip.HopLimit()
default:
t.Fatalf("unrecognized header type %T for TTL evaluation", ip)
}
if v != ttl {
t.Fatalf("Bad TTL, got = %d, want = %d", v, ttl)
@@ -1413,3 +1417,189 @@ func IGMPGroupAddress(want tcpip.Address) TransportChecker {
}
}
}
// IPv6ExtHdrChecker is a function to check an extension header.
type IPv6ExtHdrChecker func(*testing.T, header.IPv6PayloadHeader)
// IPv6WithExtHdr is like IPv6 but allows IPv6 packets with extension headers.
func IPv6WithExtHdr(t *testing.T, b []byte, checkers ...NetworkChecker) {
t.Helper()
ipv6 := header.IPv6(b)
if !ipv6.IsValid(len(b)) {
t.Error("not a valid IPv6 packet")
return
}
payloadIterator := header.MakeIPv6PayloadIterator(
header.IPv6ExtensionHeaderIdentifier(ipv6.NextHeader()),
buffer.View(ipv6.Payload()).ToVectorisedView(),
)
var rawPayloadHeader header.IPv6RawPayloadHeader
for {
h, done, err := payloadIterator.Next()
if err != nil {
t.Errorf("payloadIterator.Next(): %s", err)
return
}
if done {
t.Errorf("got payloadIterator.Next() = (%T, %t, _), want = (_, true, _)", h, done)
return
}
r, ok := h.(header.IPv6RawPayloadHeader)
if ok {
rawPayloadHeader = r
break
}
}
networkHeader := ipv6HeaderWithExtHdr{
IPv6: ipv6,
transport: tcpip.TransportProtocolNumber(rawPayloadHeader.Identifier),
payload: rawPayloadHeader.Buf.ToView(),
}
for _, checker := range checkers {
checker(t, []header.Network{&networkHeader})
}
}
// IPv6ExtHdr checks for the presence of extension headers.
//
// All the extension headers in headers will be checked exhaustively in the
// order provided.
func IPv6ExtHdr(headers ...IPv6ExtHdrChecker) NetworkChecker {
return func(t *testing.T, h []header.Network) {
t.Helper()
extHdrs, ok := h[0].(*ipv6HeaderWithExtHdr)
if !ok {
t.Errorf("got network header = %T, want = *ipv6HeaderWithExtHdr", h[0])
return
}
payloadIterator := header.MakeIPv6PayloadIterator(
header.IPv6ExtensionHeaderIdentifier(extHdrs.IPv6.NextHeader()),
buffer.View(extHdrs.IPv6.Payload()).ToVectorisedView(),
)
for _, check := range headers {
h, done, err := payloadIterator.Next()
if err != nil {
t.Errorf("payloadIterator.Next(): %s", err)
return
}
if done {
t.Errorf("got payloadIterator.Next() = (%T, %t, _), want = (_, false, _)", h, done)
return
}
check(t, h)
}
// Validate we consumed all headers.
//
// The next one over should be a raw payload and then iterator should
// terminate.
wantDone := false
for {
h, done, err := payloadIterator.Next()
if err != nil {
t.Errorf("payloadIterator.Next(): %s", err)
return
}
if done != wantDone {
t.Errorf("got payloadIterator.Next() = (%T, %t, _), want = (_, %t, _)", h, done, wantDone)
return
}
if done {
break
}
if _, ok := h.(header.IPv6RawPayloadHeader); !ok {
t.Errorf("got payloadIterator.Next() = (%T, _, _), want = (header.IPv6RawPayloadHeader, _, _)", h)
continue
}
wantDone = true
}
}
}
var _ header.Network = (*ipv6HeaderWithExtHdr)(nil)
// ipv6HeaderWithExtHdr provides a header.Network implementation that takes
// extension headers into consideration, which is not the case with vanilla
// header.IPv6.
type ipv6HeaderWithExtHdr struct {
header.IPv6
transport tcpip.TransportProtocolNumber
payload []byte
}
// TransportProtocol implements header.Network.
func (h *ipv6HeaderWithExtHdr) TransportProtocol() tcpip.TransportProtocolNumber {
return h.transport
}
// Payload implements header.Network.
func (h *ipv6HeaderWithExtHdr) Payload() []byte {
return h.payload
}
// IPv6ExtHdrOptionChecker is a function to check an extension header option.
type IPv6ExtHdrOptionChecker func(*testing.T, header.IPv6ExtHdrOption)
// IPv6HopByHopExtensionHeader checks the extension header is a Hop by Hop
// extension header and validates the containing options with checkers.
//
// checkers must exhaustively contain all the expected options.
func IPv6HopByHopExtensionHeader(checkers ...IPv6ExtHdrOptionChecker) IPv6ExtHdrChecker {
return func(t *testing.T, payloadHeader header.IPv6PayloadHeader) {
t.Helper()
hbh, ok := payloadHeader.(header.IPv6HopByHopOptionsExtHdr)
if !ok {
t.Errorf("unexpected IPv6 payload header, got = %T, want = header.IPv6HopByHopOptionsExtHdr", payloadHeader)
return
}
optionsIterator := hbh.Iter()
for _, f := range checkers {
opt, done, err := optionsIterator.Next()
if err != nil {
t.Errorf("optionsIterator.Next(): %s", err)
return
}
if done {
t.Errorf("got optionsIterator.Next() = (%T, %t, _), want = (_, false, _)", opt, done)
}
f(t, opt)
}
// Validate all options were consumed.
for {
opt, done, err := optionsIterator.Next()
if err != nil {
t.Errorf("optionsIterator.Next(): %s", err)
return
}
if !done {
t.Errorf("got optionsIterator.Next() = (%T, %t, _), want = (_, true, _)", opt, done)
}
if done {
break
}
}
}
}
// IPv6RouterAlert validates that an extension header option is the RouterAlert
// option and matches on its value.
func IPv6RouterAlert(want header.IPv6RouterAlertValue) IPv6ExtHdrOptionChecker {
return func(t *testing.T, opt header.IPv6ExtHdrOption) {
routerAlert, ok := opt.(*header.IPv6RouterAlertOption)
if !ok {
t.Errorf("unexpected extension header option, got = %T, want = header.IPv6RouterAlertOption", opt)
return
}
if routerAlert.Value != want {
t.Errorf("got routerAlert.Value = %d, want = %d", routerAlert.Value, want)
}
}
}
+11 -4
View File
@@ -48,11 +48,13 @@ type IPv6Fields struct {
// FlowLabel is the "flow label" field of an IPv6 packet.
FlowLabel uint32
// PayloadLength is the "payload length" field of an IPv6 packet.
// PayloadLength is the "payload length" field of an IPv6 packet, including
// the length of all extension headers.
PayloadLength uint16
// NextHeader is the "next header" field of an IPv6 packet.
NextHeader uint8
// TransportProtocol is the transport layer protocol number. Serialized in the
// last "next header" field of the IPv6 header + extension headers.
TransportProtocol tcpip.TransportProtocolNumber
// HopLimit is the "Hop Limit" field of an IPv6 packet.
HopLimit uint8
@@ -62,6 +64,9 @@ type IPv6Fields struct {
// DstAddr is the "destination ip address" of an IPv6 packet.
DstAddr tcpip.Address
// ExtensionHeaders are the extension headers following the IPv6 header.
ExtensionHeaders IPv6ExtHdrSerializer
}
// IPv6 represents an ipv6 header stored in a byte array.
@@ -253,12 +258,14 @@ func (IPv6) SetChecksum(uint16) {
// Encode encodes all the fields of the ipv6 header.
func (b IPv6) Encode(i *IPv6Fields) {
extHdr := b[IPv6MinimumSize:]
b.SetTOS(i.TrafficClass, i.FlowLabel)
b.SetPayloadLength(i.PayloadLength)
b[IPv6NextHeaderOffset] = i.NextHeader
b[hopLimit] = i.HopLimit
b.SetSourceAddress(i.SrcAddr)
b.SetDestinationAddress(i.DstAddr)
nextHeader, _ := i.ExtensionHeaders.Serialize(i.TransportProtocol, extHdr)
b[IPv6NextHeaderOffset] = nextHeader
}
// IsValid performs basic validation on the packet.
+317 -9
View File
@@ -20,7 +20,9 @@ import (
"encoding/binary"
"fmt"
"io"
"math"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
)
@@ -75,8 +77,8 @@ const (
// Fragment Offset field within an IPv6FragmentExtHdr.
ipv6FragmentExtHdrFragmentOffsetOffset = 0
// ipv6FragmentExtHdrFragmentOffsetShift is the least significant bits to
// discard from the Fragment Offset.
// ipv6FragmentExtHdrFragmentOffsetShift is the bit offset of the Fragment
// Offset field within an IPv6FragmentExtHdr.
ipv6FragmentExtHdrFragmentOffsetShift = 3
// ipv6FragmentExtHdrFlagsIdx is the index to the flags field within an
@@ -114,6 +116,37 @@ const (
IPv6FragmentExtHdrFragmentOffsetBytesPerUnit = 8
)
// padIPv6OptionsLength returns the total length for IPv6 options of length l
// considering the 8-octet alignment as stated in RFC 8200 Section 4.2.
func padIPv6OptionsLength(length int) int {
return (length + ipv6ExtHdrLenBytesPerUnit - 1) & ^(ipv6ExtHdrLenBytesPerUnit - 1)
}
// padIPv6Option fills b with the appropriate padding options depending on its
// length.
func padIPv6Option(b []byte) {
switch len(b) {
case 0: // No padding needed.
case 1: // Pad with Pad1.
b[ipv6ExtHdrOptionTypeOffset] = uint8(ipv6Pad1ExtHdrOptionIdentifier)
default: // Pad with PadN.
s := b[ipv6ExtHdrOptionPayloadOffset:]
for i := range s {
s[i] = 0
}
b[ipv6ExtHdrOptionTypeOffset] = uint8(ipv6PadNExtHdrOptionIdentifier)
b[ipv6ExtHdrOptionLengthOffset] = uint8(len(s))
}
}
// ipv6OptionsAlignmentPadding returns the number of padding bytes needed to
// serialize an option at headerOffset with alignment requirements
// [align]n + alignOffset.
func ipv6OptionsAlignmentPadding(headerOffset int, align int, alignOffset int) int {
padLen := headerOffset - alignOffset
return ((padLen + align - 1) & ^(align - 1)) - padLen
}
// IPv6PayloadHeader is implemented by the various headers that can be found
// in an IPv6 payload.
//
@@ -206,29 +239,51 @@ type IPv6ExtHdrOption interface {
isIPv6ExtHdrOption()
}
// IPv6ExtHdrOptionIndentifier is an IPv6 extension header option identifier.
type IPv6ExtHdrOptionIndentifier uint8
// IPv6ExtHdrOptionIdentifier is an IPv6 extension header option identifier.
type IPv6ExtHdrOptionIdentifier uint8
const (
// ipv6Pad1ExtHdrOptionIdentifier is the identifier for a padding option that
// provides 1 byte padding, as outlined in RFC 8200 section 4.2.
ipv6Pad1ExtHdrOptionIdentifier IPv6ExtHdrOptionIndentifier = 0
ipv6Pad1ExtHdrOptionIdentifier IPv6ExtHdrOptionIdentifier = 0
// ipv6PadBExtHdrOptionIdentifier is the identifier for a padding option that
// provides variable length byte padding, as outlined in RFC 8200 section 4.2.
ipv6PadNExtHdrOptionIdentifier IPv6ExtHdrOptionIndentifier = 1
ipv6PadNExtHdrOptionIdentifier IPv6ExtHdrOptionIdentifier = 1
// ipv6RouterAlertHopByHopOptionIdentifier is the identifier for the Router
// Alert Hop by Hop option as defined in RFC 2711 section 2.1.
ipv6RouterAlertHopByHopOptionIdentifier IPv6ExtHdrOptionIdentifier = 5
// ipv6ExtHdrOptionTypeOffset is the option type offset in an extension header
// option as defined in RFC 8200 section 4.2.
ipv6ExtHdrOptionTypeOffset = 0
// ipv6ExtHdrOptionLengthOffset is the option length offset in an extension
// header option as defined in RFC 8200 section 4.2.
ipv6ExtHdrOptionLengthOffset = 1
// ipv6ExtHdrOptionPayloadOffset is the option payload offset in an extension
// header option as defined in RFC 8200 section 4.2.
ipv6ExtHdrOptionPayloadOffset = 2
)
// ipv6UnknownActionFromIdentifier maps an extension header option's
// identifier's high bits to the action to take when the identifier is unknown.
func ipv6UnknownActionFromIdentifier(id IPv6ExtHdrOptionIdentifier) IPv6OptionUnknownAction {
return IPv6OptionUnknownAction((id & ipv6UnknownExtHdrOptionActionMask) >> ipv6UnknownExtHdrOptionActionShift)
}
// IPv6UnknownExtHdrOption holds the identifier and data for an IPv6 extension
// header option that is unknown by the parsing utilities.
type IPv6UnknownExtHdrOption struct {
Identifier IPv6ExtHdrOptionIndentifier
Identifier IPv6ExtHdrOptionIdentifier
Data []byte
}
// UnknownAction implements IPv6OptionUnknownAction.UnknownAction.
func (o *IPv6UnknownExtHdrOption) UnknownAction() IPv6OptionUnknownAction {
return IPv6OptionUnknownAction((o.Identifier & ipv6UnknownExtHdrOptionActionMask) >> ipv6UnknownExtHdrOptionActionShift)
return ipv6UnknownActionFromIdentifier(o.Identifier)
}
// isIPv6ExtHdrOption implements IPv6ExtHdrOption.isIPv6ExtHdrOption.
@@ -251,7 +306,7 @@ func (i *IPv6OptionsExtHdrOptionsIterator) Next() (IPv6ExtHdrOption, bool, error
// options buffer has been exhausted and we are done iterating.
return nil, true, nil
}
id := IPv6ExtHdrOptionIndentifier(temp)
id := IPv6ExtHdrOptionIdentifier(temp)
// If the option identifier indicates the option is a Pad1 option, then we
// know the option does not have Length and Data fields. End processing of
@@ -294,6 +349,14 @@ func (i *IPv6OptionsExtHdrOptionsIterator) Next() (IPv6ExtHdrOption, bool, error
panic(fmt.Sprintf("error when skipping PadN (N = %d) option's data bytes: %s", length, err))
}
continue
case ipv6RouterAlertHopByHopOptionIdentifier:
var routerAlertValue [ipv6RouterAlertPayloadLength]byte
if n, err := i.reader.Read(routerAlertValue[:]); err != nil {
panic(fmt.Sprintf("error when reading RouterAlert option's data bytes: %s", err))
} else if n != ipv6RouterAlertPayloadLength {
return nil, true, fmt.Errorf("read %d bytes for RouterAlert option, expected %d", n, ipv6RouterAlertPayloadLength)
}
return &IPv6RouterAlertOption{Value: IPv6RouterAlertValue(binary.BigEndian.Uint16(routerAlertValue[:]))}, false, nil
default:
bytes := make([]byte, length)
if n, err := io.ReadFull(&i.reader, bytes); err != nil {
@@ -609,3 +672,248 @@ func (i *IPv6PayloadIterator) nextHeaderData(fragmentHdr bool, bytes []byte) (IP
return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), bytes, nil
}
// IPv6SerializableExtHdr provides serialization for IPv6 extension
// headers.
type IPv6SerializableExtHdr interface {
// identifier returns the assigned IPv6 header identifier for this extension
// header.
identifier() IPv6ExtensionHeaderIdentifier
// length returns the total serialized length in bytes of this extension
// header, including the common next header and length fields.
length() int
// serializeInto serializes the receiver into the provided byte
// buffer and with the provided nextHeader value.
//
// Note, the caller MUST provide a byte buffer with size of at least
// length. Implementers of this function may assume that the byte buffer
// is of sufficient size. serializeInto MAY panic if the provided byte
// buffer is not of sufficient size.
//
// serializeInto returns the number of bytes that was used to serialize the
// receiver. Implementers must only use the number of bytes required to
// serialize the receiver. Callers MAY provide a larger buffer than required
// to serialize into.
serializeInto(nextHeader uint8, b []byte) int
}
var _ IPv6SerializableExtHdr = (*IPv6SerializableHopByHopExtHdr)(nil)
// IPv6SerializableHopByHopExtHdr implements serialization of the Hop by Hop
// options extension header.
type IPv6SerializableHopByHopExtHdr []IPv6SerializableHopByHopOption
const (
// ipv6HopByHopExtHdrNextHeaderOffset is the offset of the next header field
// in a hop by hop extension header as defined in RFC 8200 section 4.3.
ipv6HopByHopExtHdrNextHeaderOffset = 0
// ipv6HopByHopExtHdrLengthOffset is the offset of the length field in a hop
// by hop extension header as defined in RFC 8200 section 4.3.
ipv6HopByHopExtHdrLengthOffset = 1
// ipv6HopByHopExtHdrPayloadOffset is the offset of the options in a hop by
// hop extension header as defined in RFC 8200 section 4.3.
ipv6HopByHopExtHdrOptionsOffset = 2
// ipv6HopByHopExtHdrUnaccountedLenWords is the implicit number of 8-octet
// words in a hop by hop extension header's length field, as stated in RFC
// 8200 section 4.3:
// Length of the Hop-by-Hop Options header in 8-octet units,
// not including the first 8 octets.
ipv6HopByHopExtHdrUnaccountedLenWords = 1
)
// identifier implements IPv6SerializableExtHdr.
func (IPv6SerializableHopByHopExtHdr) identifier() IPv6ExtensionHeaderIdentifier {
return IPv6HopByHopOptionsExtHdrIdentifier
}
// length implements IPv6SerializableExtHdr.
func (h IPv6SerializableHopByHopExtHdr) length() int {
var total int
for _, opt := range h {
align, alignOffset := opt.alignment()
total += ipv6OptionsAlignmentPadding(total, align, alignOffset)
total += ipv6ExtHdrOptionPayloadOffset + int(opt.length())
}
// Account for next header and total length fields and add padding.
return padIPv6OptionsLength(ipv6HopByHopExtHdrOptionsOffset + total)
}
// serializeInto implements IPv6SerializableExtHdr.
func (h IPv6SerializableHopByHopExtHdr) serializeInto(nextHeader uint8, b []byte) int {
optBuffer := b[ipv6HopByHopExtHdrOptionsOffset:]
totalLength := ipv6HopByHopExtHdrOptionsOffset
for _, opt := range h {
// Calculate alignment requirements and pad buffer if necessary.
align, alignOffset := opt.alignment()
padLen := ipv6OptionsAlignmentPadding(totalLength, align, alignOffset)
if padLen != 0 {
padIPv6Option(optBuffer[:padLen])
totalLength += padLen
optBuffer = optBuffer[padLen:]
}
l := opt.serializeInto(optBuffer[ipv6ExtHdrOptionPayloadOffset:])
optBuffer[ipv6ExtHdrOptionTypeOffset] = uint8(opt.identifier())
optBuffer[ipv6ExtHdrOptionLengthOffset] = l
l += ipv6ExtHdrOptionPayloadOffset
totalLength += int(l)
optBuffer = optBuffer[l:]
}
padded := padIPv6OptionsLength(totalLength)
if padded != totalLength {
padIPv6Option(optBuffer[:padded-totalLength])
totalLength = padded
}
wordsLen := totalLength/ipv6ExtHdrLenBytesPerUnit - ipv6HopByHopExtHdrUnaccountedLenWords
if wordsLen > math.MaxUint8 {
panic(fmt.Sprintf("IPv6 hop by hop options too large: %d+1 64-bit words", wordsLen))
}
b[ipv6HopByHopExtHdrNextHeaderOffset] = nextHeader
b[ipv6HopByHopExtHdrLengthOffset] = uint8(wordsLen)
return totalLength
}
// IPv6SerializableHopByHopOption provides serialization for hop by hop options.
type IPv6SerializableHopByHopOption interface {
// identifier returns the option identifier of this Hop by Hop option.
identifier() IPv6ExtHdrOptionIdentifier
// length returns the *payload* size of the option (not considering the type
// and length fields).
length() uint8
// alignment returns the alignment requirements from this option.
//
// Alignment requirements take the form [align]n + offset as specified in
// RFC 8200 section 4.2. The alignment requirement is on the offset between
// the option type byte and the start of the hop by hop header.
//
// align must be a power of 2.
alignment() (align int, offset int)
// serializeInto serializes the receiver into the provided byte
// buffer.
//
// Note, the caller MUST provide a byte buffer with size of at least
// length. Implementers of this function may assume that the byte buffer
// is of sufficient size. serializeInto MAY panic if the provided byte
// buffer is not of sufficient size.
//
// serializeInto will return the number of bytes that was used to
// serialize the receiver. Implementers must only use the number of
// bytes required to serialize the receiver. Callers MAY provide a
// larger buffer than required to serialize into.
serializeInto([]byte) uint8
}
var _ IPv6SerializableHopByHopOption = (*IPv6RouterAlertOption)(nil)
// IPv6RouterAlertOption is the IPv6 Router alert Hop by Hop option defined in
// RFC 2711 section 2.1.
type IPv6RouterAlertOption struct {
Value IPv6RouterAlertValue
}
// IPv6RouterAlertValue is the payload of an IPv6 Router Alert option.
type IPv6RouterAlertValue uint16
const (
// IPv6RouterAlertMLD indicates a datagram containing a Multicast Listener
// Discovery message as defined in RFC 2711 section 2.1.
IPv6RouterAlertMLD IPv6RouterAlertValue = 0
// IPv6RouterAlertRSVP indicates a datagram containing an RSVP message as
// defined in RFC 2711 section 2.1.
IPv6RouterAlertRSVP IPv6RouterAlertValue = 1
// IPv6RouterAlertActiveNetworks indicates a datagram containing an Active
// Networks message as defined in RFC 2711 section 2.1.
IPv6RouterAlertActiveNetworks IPv6RouterAlertValue = 2
// ipv6RouterAlertPayloadLength is the length of the Router Alert payload
// as defined in RFC 2711.
ipv6RouterAlertPayloadLength = 2
// ipv6RouterAlertAlignmentRequirement is the alignment requirement for the
// Router Alert option defined as 2n+0 in RFC 2711.
ipv6RouterAlertAlignmentRequirement = 2
// ipv6RouterAlertAlignmentOffsetRequirement is the alignment offset
// requirement for the Router Alert option defined as 2n+0 in RFC 2711 section
// 2.1.
ipv6RouterAlertAlignmentOffsetRequirement = 0
)
// UnknownAction implements IPv6ExtHdrOption.
func (*IPv6RouterAlertOption) UnknownAction() IPv6OptionUnknownAction {
return ipv6UnknownActionFromIdentifier(ipv6RouterAlertHopByHopOptionIdentifier)
}
// isIPv6ExtHdrOption implements IPv6ExtHdrOption.
func (*IPv6RouterAlertOption) isIPv6ExtHdrOption() {}
// identifier implements IPv6SerializableHopByHopOption.
func (*IPv6RouterAlertOption) identifier() IPv6ExtHdrOptionIdentifier {
return ipv6RouterAlertHopByHopOptionIdentifier
}
// length implements IPv6SerializableHopByHopOption.
func (*IPv6RouterAlertOption) length() uint8 {
return ipv6RouterAlertPayloadLength
}
// alignment implements IPv6SerializableHopByHopOption.
func (*IPv6RouterAlertOption) alignment() (int, int) {
// From RFC 2711 section 2.1:
// Alignment requirement: 2n+0.
return ipv6RouterAlertAlignmentRequirement, ipv6RouterAlertAlignmentOffsetRequirement
}
// serializeInto implements IPv6SerializableHopByHopOption.
func (o *IPv6RouterAlertOption) serializeInto(b []byte) uint8 {
binary.BigEndian.PutUint16(b, uint16(o.Value))
return ipv6RouterAlertPayloadLength
}
// IPv6ExtHdrSerializer provides serialization of IPv6 extension headers.
type IPv6ExtHdrSerializer []IPv6SerializableExtHdr
// Serialize serializes the provided list of IPv6 extension headers into b.
//
// Note, b must be of sufficient size to hold all the headers in s. See
// IPv6ExtHdrSerializer.Length for details on the getting the total size of a
// serialized IPv6ExtHdrSerializer.
//
// Serialize may panic if b is not of sufficient size to hold all the options
// in s.
//
// Serialize takes the transportProtocol value to be used as the last extension
// header's Next Header value and returns the header identifier of the first
// serialized extension header and the total serialized length.
func (s IPv6ExtHdrSerializer) Serialize(transportProtocol tcpip.TransportProtocolNumber, b []byte) (uint8, int) {
nextHeader := uint8(transportProtocol)
if len(s) == 0 {
return nextHeader, 0
}
var totalLength int
for i, h := range s[:len(s)-1] {
length := h.serializeInto(uint8(s[i+1].identifier()), b)
b = b[length:]
totalLength += length
}
totalLength += s[len(s)-1].serializeInto(nextHeader, b)
return uint8(s[0].identifier()), totalLength
}
// Length returns the total number of bytes required to serialize the extension
// headers.
func (s IPv6ExtHdrSerializer) Length() int {
var totalLength int
for _, h := range s {
totalLength += h.length()
}
return totalLength
}
+330 -1
View File
@@ -21,6 +21,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
)
@@ -59,7 +60,7 @@ func (a IPv6DestinationOptionsExtHdr) Equal(b IPv6DestinationOptionsExtHdr) bool
func TestIPv6UnknownExtHdrOption(t *testing.T) {
tests := []struct {
name string
identifier IPv6ExtHdrOptionIndentifier
identifier IPv6ExtHdrOptionIdentifier
expectedUnknownAction IPv6OptionUnknownAction
}{
{
@@ -990,3 +991,331 @@ func TestIPv6ExtHdrIter(t *testing.T) {
})
}
}
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)
}
})
}
}
+27 -15
View File
@@ -27,12 +27,11 @@ const (
idV6 = 4
)
// IPv6FragmentFields contains the fields of an IPv6 fragment. It is used to describe the
// fields of a packet that needs to be encoded.
type IPv6FragmentFields struct {
// NextHeader is the "next header" field of an IPv6 fragment.
NextHeader uint8
var _ IPv6SerializableExtHdr = (*IPv6SerializableFragmentExtHdr)(nil)
// IPv6SerializableFragmentExtHdr is used to serialize an IPv6 fragment
// extension header as defined in RFC 8200 section 4.5.
type IPv6SerializableFragmentExtHdr struct {
// FragmentOffset is the "fragment offset" field of an IPv6 fragment.
FragmentOffset uint16
@@ -43,6 +42,29 @@ type IPv6FragmentFields struct {
Identification uint32
}
// identifier implements IPv6SerializableFragmentExtHdr.
func (h *IPv6SerializableFragmentExtHdr) identifier() IPv6ExtensionHeaderIdentifier {
return IPv6FragmentHeader
}
// length implements IPv6SerializableFragmentExtHdr.
func (h *IPv6SerializableFragmentExtHdr) length() int {
return IPv6FragmentHeaderSize
}
// serializeInto implements IPv6SerializableFragmentExtHdr.
func (h *IPv6SerializableFragmentExtHdr) serializeInto(nextHeader uint8, b []byte) int {
// Prevent too many bounds checks.
_ = b[IPv6FragmentHeaderSize:]
binary.BigEndian.PutUint32(b[idV6:], h.Identification)
binary.BigEndian.PutUint16(b[fragOff:], h.FragmentOffset<<ipv6FragmentExtHdrFragmentOffsetShift)
b[nextHdrFrag] = nextHeader
if h.M {
b[more] |= ipv6FragmentExtHdrMFlagMask
}
return IPv6FragmentHeaderSize
}
// IPv6Fragment represents an ipv6 fragment header stored in a byte array.
// Most of the methods of IPv6Fragment access to the underlying slice without
// checking the boundaries and could panic because of 'index out of range'.
@@ -58,16 +80,6 @@ const (
IPv6FragmentHeaderSize = 8
)
// Encode encodes all the fields of the ipv6 fragment.
func (b IPv6Fragment) Encode(i *IPv6FragmentFields) {
b[nextHdrFrag] = i.NextHeader
binary.BigEndian.PutUint16(b[fragOff:], i.FragmentOffset<<3)
if i.M {
b[more] |= 1
}
binary.BigEndian.PutUint32(b[idV6:], i.Identification)
}
// IsValid performs basic validation on the fragment header.
func (b IPv6Fragment) IsValid() bool {
return len(b) >= IPv6FragmentHeaderSize
+46 -45
View File
@@ -344,11 +344,11 @@ func TestSourceAddressValidation(t *testing.T) {
pkt.SetChecksum(header.ICMPv6Checksum(pkt, src, localIPv6Addr, buffer.VectorisedView{}))
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: header.ICMPv6MinimumSize,
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: localIPv6Addr,
PayloadLength: header.ICMPv6MinimumSize,
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: localIPv6Addr,
})
e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
@@ -619,11 +619,11 @@ func TestReceive(t *testing.T) {
view := buffer.NewView(header.IPv6MinimumSize + payloadLen)
ip := header.IPv6(view)
ip.Encode(&header.IPv6Fields{
PayloadLength: payloadLen,
NextHeader: 10,
HopLimit: ipv6.DefaultTTL,
SrcAddr: remoteIPv6Addr,
DstAddr: localIPv6Addr,
PayloadLength: payloadLen,
TransportProtocol: 10,
HopLimit: ipv6.DefaultTTL,
SrcAddr: remoteIPv6Addr,
DstAddr: localIPv6Addr,
})
// Make payload be non-zero.
@@ -993,11 +993,11 @@ func TestIPv6ReceiveControl(t *testing.T) {
// Create the outer IPv6 header.
ip := header.IPv6(view)
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(len(view) - header.IPv6MinimumSize - c.trunc),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: 20,
SrcAddr: outerSrcAddr,
DstAddr: localIPv6Addr,
PayloadLength: uint16(len(view) - header.IPv6MinimumSize - c.trunc),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: 20,
SrcAddr: outerSrcAddr,
DstAddr: localIPv6Addr,
})
// Create the ICMP header.
@@ -1007,28 +1007,27 @@ func TestIPv6ReceiveControl(t *testing.T) {
icmp.SetIdent(0xdead)
icmp.SetSequence(0xbeef)
// Create the inner IPv6 header.
ip = header.IPv6(view[header.IPv6MinimumSize+header.ICMPv6PayloadOffset:])
ip.Encode(&header.IPv6Fields{
PayloadLength: 100,
NextHeader: 10,
HopLimit: 20,
SrcAddr: localIPv6Addr,
DstAddr: remoteIPv6Addr,
})
var extHdrs header.IPv6ExtHdrSerializer
// Build the fragmentation header if needed.
if c.fragmentOffset != nil {
ip.SetNextHeader(header.IPv6FragmentHeader)
frag := header.IPv6Fragment(view[2*header.IPv6MinimumSize+header.ICMPv6MinimumSize:])
frag.Encode(&header.IPv6FragmentFields{
NextHeader: 10,
extHdrs = append(extHdrs, &header.IPv6SerializableFragmentExtHdr{
FragmentOffset: *c.fragmentOffset,
M: true,
Identification: 0x12345678,
})
}
// Create the inner IPv6 header.
ip = header.IPv6(view[header.IPv6MinimumSize+header.ICMPv6PayloadOffset:])
ip.Encode(&header.IPv6Fields{
PayloadLength: 100,
TransportProtocol: 10,
HopLimit: 20,
SrcAddr: localIPv6Addr,
DstAddr: remoteIPv6Addr,
ExtensionHeaders: extHdrs,
})
// Make payload be non-zero.
for i := dataOffset; i < len(view); i++ {
view[i] = uint8(i)
@@ -1344,10 +1343,10 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
}
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
NextHeader: transportProto,
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
TransportProtocol: transportProto,
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
})
return hdr.View().ToVectorisedView()
},
@@ -1387,10 +1386,12 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
}
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
NextHeader: uint8(header.IPv6FragmentExtHdrIdentifier),
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
// NB: we're lying about transport protocol here to verify the raw
// fragment header bytes.
TransportProtocol: tcpip.TransportProtocolNumber(header.IPv6FragmentExtHdrIdentifier),
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
})
return hdr.View().ToVectorisedView()
},
@@ -1422,10 +1423,10 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
ip := header.IPv6(make([]byte, header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
NextHeader: transportProto,
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
TransportProtocol: transportProto,
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
})
return buffer.View(ip).ToVectorisedView()
},
@@ -1457,10 +1458,10 @@ func TestWriteHeaderIncludedPacket(t *testing.T) {
pktGen: func(t *testing.T, src tcpip.Address) buffer.VectorisedView {
ip := header.IPv6(make([]byte, header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
NextHeader: transportProto,
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
TransportProtocol: transportProto,
HopLimit: ipv6.DefaultTTL,
SrcAddr: src,
DstAddr: header.IPv4Any,
})
return buffer.View(ip[:len(ip)-1]).ToVectorisedView()
},
+55 -55
View File
@@ -296,11 +296,11 @@ func TestICMPCounts(t *testing.T) {
})
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(len(icmp)),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(len(icmp)),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
ep.HandlePacket(pkt)
}
@@ -454,11 +454,11 @@ func TestICMPCountsWithNeighborCache(t *testing.T) {
})
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(len(icmp)),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(len(icmp)),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
ep.HandlePacket(pkt)
}
@@ -853,11 +853,11 @@ func TestICMPChecksumValidationSimple(t *testing.T) {
}
ip := header.IPv6(buffer.NewView(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(len(icmp)),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(len(icmp)),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: buffer.NewVectorisedView(len(ip)+len(icmp), []buffer.View{buffer.View(ip), buffer.View(icmp)}),
@@ -930,11 +930,11 @@ func TestICMPChecksumValidationWithPayload(t *testing.T) {
errorICMPBody := func(view buffer.View) {
ip := header.IPv6(view)
ip.Encode(&header.IPv6Fields{
PayloadLength: simpleBodySize,
NextHeader: 10,
HopLimit: 20,
SrcAddr: lladdr0,
DstAddr: lladdr1,
PayloadLength: simpleBodySize,
TransportProtocol: 10,
HopLimit: 20,
SrcAddr: lladdr0,
DstAddr: lladdr1,
})
simpleBody(view[header.IPv6MinimumSize:])
}
@@ -1048,11 +1048,11 @@ func TestICMPChecksumValidationWithPayload(t *testing.T) {
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(icmpSize),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(icmpSize),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
@@ -1108,11 +1108,11 @@ func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) {
errorICMPBody := func(view buffer.View) {
ip := header.IPv6(view)
ip.Encode(&header.IPv6Fields{
PayloadLength: simpleBodySize,
NextHeader: 10,
HopLimit: 20,
SrcAddr: lladdr0,
DstAddr: lladdr1,
PayloadLength: simpleBodySize,
TransportProtocol: 10,
HopLimit: 20,
SrcAddr: lladdr0,
DstAddr: lladdr1,
})
simpleBody(view[header.IPv6MinimumSize:])
}
@@ -1227,11 +1227,11 @@ func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) {
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(size + payloadSize),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(size + payloadSize),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: header.NDPHopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: buffer.NewVectorisedView(header.IPv6MinimumSize+size+payloadSize, []buffer.View{hdr.View(), payload}),
@@ -1445,11 +1445,11 @@ func TestPacketQueing(t *testing.T) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(udp.ProtocolNumber),
HopLimit: DefaultTTL,
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
PayloadLength: uint16(payloadLength),
TransportProtocol: udp.ProtocolNumber,
HopLimit: DefaultTTL,
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
})
e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
@@ -1487,11 +1487,11 @@ func TestPacketQueing(t *testing.T) {
pkt.SetChecksum(header.ICMPv6Checksum(pkt, host2IPv6Addr.AddressWithPrefix.Address, host1IPv6Addr.AddressWithPrefix.Address, buffer.VectorisedView{}))
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: header.ICMPv6MinimumSize,
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: DefaultTTL,
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
PayloadLength: header.ICMPv6MinimumSize,
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: DefaultTTL,
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
})
e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
@@ -1586,11 +1586,11 @@ func TestPacketQueing(t *testing.T) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: header.NDPHopLimit,
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
PayloadLength: uint16(payloadLength),
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: header.NDPHopLimit,
SrcAddr: host2IPv6Addr.AddressWithPrefix.Address,
DstAddr: host1IPv6Addr.AddressWithPrefix.Address,
})
e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
@@ -1828,11 +1828,11 @@ func TestCallsToNeighborCache(t *testing.T) {
})
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(len(icmp)),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: header.NDPHopLimit,
SrcAddr: test.source,
DstAddr: test.destination,
PayloadLength: uint16(len(icmp)),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: header.NDPHopLimit,
SrcAddr: test.source,
DstAddr: test.destination,
})
ep.HandlePacket(pkt)
+32 -22
View File
@@ -19,6 +19,7 @@ import (
"encoding/binary"
"fmt"
"hash/fnv"
"math"
"sort"
"sync/atomic"
"time"
@@ -431,19 +432,27 @@ func (e *endpoint) MTU() uint32 {
// MaxHeaderLength returns the maximum length needed by ipv6 headers (and
// underlying protocols).
func (e *endpoint) MaxHeaderLength() uint16 {
// TODO(gvisor.dev/issues/5035): The maximum header length returned here does
// not open the possibility for the caller to know about size required for
// extension headers.
return e.nic.MaxHeaderLength() + header.IPv6MinimumSize
}
func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt *stack.PacketBuffer, params stack.NetworkHeaderParams) {
length := uint16(pkt.Size())
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize))
func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt *stack.PacketBuffer, params stack.NetworkHeaderParams, extensionHeaders header.IPv6ExtHdrSerializer) {
extHdrsLen := extensionHeaders.Length()
length := pkt.Size() + extensionHeaders.Length()
if length > math.MaxUint16 {
panic(fmt.Sprintf("IPv6 payload too large: %d, must be <= %d", length, math.MaxUint16))
}
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize + extHdrsLen))
ip.Encode(&header.IPv6Fields{
PayloadLength: length,
NextHeader: uint8(params.Protocol),
HopLimit: params.TTL,
TrafficClass: params.TOS,
SrcAddr: srcAddr,
DstAddr: dstAddr,
PayloadLength: uint16(length),
TransportProtocol: params.Protocol,
HopLimit: params.TTL,
TrafficClass: params.TOS,
SrcAddr: srcAddr,
DstAddr: dstAddr,
ExtensionHeaders: extensionHeaders,
})
pkt.NetworkProtocolNumber = ProtocolNumber
}
@@ -498,7 +507,7 @@ func (e *endpoint) handleFragments(r *stack.Route, gso *stack.GSO, networkMTU ui
// WritePacket writes a packet to the given destination address and protocol.
func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, params stack.NetworkHeaderParams, pkt *stack.PacketBuffer) *tcpip.Error {
e.addIPHeader(r.LocalAddress, r.RemoteAddress, pkt, params)
e.addIPHeader(r.LocalAddress, r.RemoteAddress, pkt, params, nil /* extensionHeaders */)
// iptables filtering. All packets that reach here are locally
// generated.
@@ -587,7 +596,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
linkMTU := e.nic.MTU()
for pb := pkts.Front(); pb != nil; pb = pb.Next() {
e.addIPHeader(r.LocalAddress, r.RemoteAddress, pb, params)
e.addIPHeader(r.LocalAddress, r.RemoteAddress, pb, params, nil /* extensionHeaders */)
networkMTU, err := calculateNetworkMTU(linkMTU, uint32(pb.NetworkHeader().View().Size()))
if err != nil {
@@ -1793,24 +1802,25 @@ func buildNextFragment(pf *fragmentation.PacketFragmenter, originalIPHeaders hea
fragPkt.NetworkProtocolNumber = ProtocolNumber
originalIPHeadersLength := len(originalIPHeaders)
fragmentIPHeadersLength := originalIPHeadersLength + header.IPv6FragmentHeaderSize
s := header.IPv6ExtHdrSerializer{&header.IPv6SerializableFragmentExtHdr{
FragmentOffset: uint16(offset / header.IPv6FragmentExtHdrFragmentOffsetBytesPerUnit),
M: more,
Identification: id,
}}
fragmentIPHeadersLength := originalIPHeadersLength + s.Length()
fragmentIPHeaders := header.IPv6(fragPkt.NetworkHeader().Push(fragmentIPHeadersLength))
fragPkt.NetworkProtocolNumber = ProtocolNumber
// Copy the IPv6 header and any extension headers already populated.
if copied := copy(fragmentIPHeaders, originalIPHeaders); copied != originalIPHeadersLength {
panic(fmt.Sprintf("wrong number of bytes copied into fragmentIPHeaders: got %d, want %d", copied, originalIPHeadersLength))
}
fragmentIPHeaders.SetNextHeader(header.IPv6FragmentHeader)
fragmentIPHeaders.SetPayloadLength(uint16(copied + fragmentIPHeadersLength - header.IPv6MinimumSize))
fragmentHeader := header.IPv6Fragment(fragmentIPHeaders[originalIPHeadersLength:])
fragmentHeader.Encode(&header.IPv6FragmentFields{
M: more,
FragmentOffset: uint16(offset / header.IPv6FragmentExtHdrFragmentOffsetBytesPerUnit),
Identification: id,
NextHeader: uint8(transportProto),
})
nextHeader, _ := s.Serialize(transportProto, fragmentIPHeaders[originalIPHeadersLength:])
fragmentIPHeaders.SetNextHeader(nextHeader)
fragmentIPHeaders.SetPayloadLength(uint16(copied + fragmentIPHeadersLength - header.IPv6MinimumSize))
return fragPkt, more
}
+95 -101
View File
@@ -69,11 +69,11 @@ func testReceiveICMP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: 255,
SrcAddr: src,
DstAddr: dst,
PayloadLength: uint16(payloadLength),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: 255,
SrcAddr: src,
DstAddr: dst,
})
e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
@@ -127,11 +127,11 @@ func testReceiveUDP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(udp.ProtocolNumber),
HopLimit: 255,
SrcAddr: src,
DstAddr: dst,
PayloadLength: uint16(payloadLength),
TransportProtocol: udp.ProtocolNumber,
HopLimit: 255,
SrcAddr: src,
DstAddr: dst,
})
e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
@@ -915,10 +915,12 @@ func TestReceiveIPv6ExtHdrs(t *testing.T) {
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: ipv6NextHdr,
HopLimit: 255,
SrcAddr: addr1,
DstAddr: dstAddr,
// We're lying about transport protocol here to be able to generate
// raw extension headers from the test definitions.
TransportProtocol: tcpip.TransportProtocolNumber(ipv6NextHdr),
HopLimit: 255,
SrcAddr: addr1,
DstAddr: dstAddr,
})
e.InjectInbound(ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
@@ -1947,10 +1949,12 @@ func TestReceiveIPv6Fragments(t *testing.T) {
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(f.data.Size()),
NextHeader: f.nextHdr,
HopLimit: 255,
SrcAddr: f.srcAddr,
DstAddr: f.dstAddr,
// We're lying about transport protocol here so that we can generate
// raw extension headers for the tests.
TransportProtocol: tcpip.TransportProtocolNumber(f.nextHdr),
HopLimit: 255,
SrcAddr: f.srcAddr,
DstAddr: f.dstAddr,
})
vv := hdr.View().ToVectorisedView()
@@ -1995,7 +1999,7 @@ func TestInvalidIPv6Fragments(t *testing.T) {
type fragmentData struct {
ipv6Fields header.IPv6Fields
ipv6FragmentFields header.IPv6FragmentFields
ipv6FragmentFields header.IPv6SerializableFragmentExtHdr
payload []byte
}
@@ -2014,14 +2018,13 @@ func TestInvalidIPv6Fragments(t *testing.T) {
fragments: []fragmentData{
{
ipv6Fields: header.IPv6Fields{
PayloadLength: header.IPv6FragmentHeaderSize + 9,
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: header.IPv6FragmentHeaderSize + 9,
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 0 >> 3,
M: true,
Identification: ident,
@@ -2041,14 +2044,13 @@ func TestInvalidIPv6Fragments(t *testing.T) {
fragments: []fragmentData{
{
ipv6Fields: header.IPv6Fields{
PayloadLength: header.IPv6FragmentHeaderSize + 16,
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: header.IPv6FragmentHeaderSize + 16,
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: ((header.IPv6MaximumPayloadSize + 1) - 16) >> 3,
M: false,
Identification: ident,
@@ -2089,10 +2091,9 @@ func TestInvalidIPv6Fragments(t *testing.T) {
hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize)
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize))
ip.Encode(&f.ipv6Fields)
fragHDR := header.IPv6Fragment(hdr.View()[header.IPv6MinimumSize:])
fragHDR.Encode(&f.ipv6FragmentFields)
encodeArgs := f.ipv6Fields
encodeArgs.ExtensionHeaders = append(encodeArgs.ExtensionHeaders, &f.ipv6FragmentFields)
ip.Encode(&encodeArgs)
vv := hdr.View().ToVectorisedView()
vv.AppendView(f.payload)
@@ -2154,7 +2155,7 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
type fragmentData struct {
ipv6Fields header.IPv6Fields
ipv6FragmentFields header.IPv6FragmentFields
ipv6FragmentFields header.IPv6SerializableFragmentExtHdr
payload []byte
}
@@ -2168,14 +2169,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
fragments: []fragmentData{
{
ipv6Fields: header.IPv6Fields{
PayloadLength: header.IPv6FragmentHeaderSize + 16,
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: header.IPv6FragmentHeaderSize + 16,
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 0,
M: true,
Identification: ident,
@@ -2190,14 +2190,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
fragments: []fragmentData{
{
ipv6Fields: header.IPv6Fields{
PayloadLength: header.IPv6FragmentHeaderSize + 16,
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: header.IPv6FragmentHeaderSize + 16,
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 0,
M: true,
Identification: ident,
@@ -2206,14 +2205,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
},
{
ipv6Fields: header.IPv6Fields{
PayloadLength: header.IPv6FragmentHeaderSize + 16,
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: header.IPv6FragmentHeaderSize + 16,
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 0,
M: true,
Identification: ident,
@@ -2228,14 +2226,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
fragments: []fragmentData{
{
ipv6Fields: header.IPv6Fields{
PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 8,
M: false,
Identification: ident,
@@ -2250,14 +2247,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
fragments: []fragmentData{
{
ipv6Fields: header.IPv6Fields{
PayloadLength: header.IPv6FragmentHeaderSize + 16,
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: header.IPv6FragmentHeaderSize + 16,
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 0,
M: true,
Identification: ident,
@@ -2266,14 +2262,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
},
{
ipv6Fields: header.IPv6Fields{
PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 8,
M: false,
Identification: ident,
@@ -2288,14 +2283,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
fragments: []fragmentData{
{
ipv6Fields: header.IPv6Fields{
PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: uint16(header.IPv6FragmentHeaderSize + len(data) - 16),
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 8,
M: false,
Identification: ident,
@@ -2304,14 +2298,13 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
},
{
ipv6Fields: header.IPv6Fields{
PayloadLength: header.IPv6FragmentHeaderSize + 16,
NextHeader: header.IPv6FragmentHeader,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
PayloadLength: header.IPv6FragmentHeaderSize + 16,
TransportProtocol: header.UDPProtocolNumber,
HopLimit: hoplimit,
SrcAddr: addr1,
DstAddr: addr2,
},
ipv6FragmentFields: header.IPv6FragmentFields{
NextHeader: uint8(header.UDPProtocolNumber),
ipv6FragmentFields: header.IPv6SerializableFragmentExtHdr{
FragmentOffset: 0,
M: true,
Identification: ident,
@@ -2350,10 +2343,11 @@ func TestFragmentReassemblyTimeout(t *testing.T) {
hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize)
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize + header.IPv6FragmentHeaderSize))
ip.Encode(&f.ipv6Fields)
encodeArgs := f.ipv6Fields
encodeArgs.ExtensionHeaders = append(encodeArgs.ExtensionHeaders, &f.ipv6FragmentFields)
ip.Encode(&encodeArgs)
fragHDR := header.IPv6Fragment(hdr.View()[header.IPv6MinimumSize:])
fragHDR.Encode(&f.ipv6FragmentFields)
vv := hdr.View().ToVectorisedView()
vv.AppendView(f.payload)
@@ -2994,11 +2988,11 @@ func TestForwarding(t *testing.T) {
icmp.SetChecksum(header.ICMPv6Checksum(icmp, remoteIPv6Addr1, remoteIPv6Addr2, buffer.VectorisedView{}))
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: header.ICMPv6MinimumSize,
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: test.TTL,
SrcAddr: remoteIPv6Addr1,
DstAddr: remoteIPv6Addr2,
PayloadLength: header.ICMPv6MinimumSize,
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: test.TTL,
SrcAddr: remoteIPv6Addr1,
DstAddr: remoteIPv6Addr2,
})
requestPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
+8 -4
View File
@@ -234,17 +234,21 @@ func (mld *mldState) writePacket(destAddress, groupAddress tcpip.Address, mldTyp
icmp.SetChecksum(header.ICMPv6Checksum(icmp, localAddress, destAddress, buffer.VectorisedView{}))
extensionHeaders := header.IPv6ExtHdrSerializer{
header.IPv6SerializableHopByHopExtHdr{
&header.IPv6RouterAlertOption{Value: header.IPv6RouterAlertMLD},
},
}
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(mld.ep.MaxHeaderLength()),
ReserveHeaderBytes: int(mld.ep.MaxHeaderLength()) + extensionHeaders.Length(),
Data: buffer.View(icmp).ToVectorisedView(),
})
mld.ep.addIPHeader(localAddress, destAddress, pkt, stack.NetworkHeaderParams{
Protocol: header.ICMPv6ProtocolNumber,
TTL: header.MLDHopLimit,
})
// TODO(b/162198658): set the ROUTER_ALERT option when sending Host
// Membership Reports.
}, extensionHeaders)
if err := mld.ep.nic.WritePacketToRemote(header.EthernetAddressFromMulticastIPv6Address(destAddress), nil /* gso */, ProtocolNumber, pkt); err != nil {
sentStats.Dropped.Increment()
return false, err
+4 -1
View File
@@ -42,7 +42,10 @@ var (
func validateMLDPacket(t *testing.T, p buffer.View, localAddress, remoteAddress tcpip.Address, mldType header.ICMPv6Type, groupAddress tcpip.Address) {
t.Helper()
checker.IPv6(t, p,
checker.IPv6WithExtHdr(t, p,
checker.IPv6ExtHdr(
checker.IPv6HopByHopExtensionHeader(checker.IPv6RouterAlert(header.IPv6RouterAlertMLD)),
),
checker.SrcAddr(localAddress),
checker.DstAddr(remoteAddress),
// Hop Limit for an MLD message must be 1 as per RFC 2710 section 3.
+2 -2
View File
@@ -735,7 +735,7 @@ func (ndp *ndpState) sendDADPacket(addr tcpip.Address, addressEndpoint stack.Add
ndp.ep.addIPHeader(header.IPv6Any, snmc, pkt, stack.NetworkHeaderParams{
Protocol: header.ICMPv6ProtocolNumber,
TTL: header.NDPHopLimit,
})
}, nil /* extensionHeaders */)
if err := ndp.ep.nic.WritePacketToRemote(header.EthernetAddressFromMulticastIPv6Address(snmc), nil /* gso */, ProtocolNumber, pkt); err != nil {
sent.Dropped.Increment()
@@ -1857,7 +1857,7 @@ func (ndp *ndpState) startSolicitingRouters() {
ndp.ep.addIPHeader(localAddr, header.IPv6AllRoutersMulticastAddress, pkt, stack.NetworkHeaderParams{
Protocol: header.ICMPv6ProtocolNumber,
TTL: header.NDPHopLimit,
})
}, nil /* extensionHeaders */)
if err := ndp.ep.nic.WritePacketToRemote(header.EthernetAddressFromMulticastIPv6Address(header.IPv6AllRoutersMulticastAddress), nil /* gso */, ProtocolNumber, pkt); err != nil {
sent.Dropped.Increment()
+46 -50
View File
@@ -213,11 +213,11 @@ func TestNeighorSolicitationWithSourceLinkLayerOption(t *testing.T) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(payloadLength),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
@@ -319,11 +319,11 @@ func TestNeighorSolicitationWithSourceLinkLayerOptionUsingNeighborCache(t *testi
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(payloadLength),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
@@ -599,11 +599,11 @@ func TestNeighorSolicitationResponse(t *testing.T) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: 255,
SrcAddr: test.nsSrc,
DstAddr: test.nsDst,
PayloadLength: uint16(payloadLength),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: 255,
SrcAddr: test.nsSrc,
DstAddr: test.nsDst,
})
invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
@@ -681,11 +681,11 @@ func TestNeighorSolicitationResponse(t *testing.T) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: header.NDPHopLimit,
SrcAddr: test.nsSrc,
DstAddr: nicAddr,
PayloadLength: uint16(payloadLength),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: header.NDPHopLimit,
SrcAddr: test.nsSrc,
DstAddr: nicAddr,
})
e.InjectLinkAddr(ProtocolNumber, "", stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: hdr.View().ToVectorisedView(),
@@ -785,11 +785,11 @@ func TestNeighorAdvertisementWithTargetLinkLayerOption(t *testing.T) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(payloadLength),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
@@ -898,11 +898,11 @@ func TestNeighorAdvertisementWithTargetLinkLayerOptionUsingNeighborCache(t *test
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(header.ICMPv6ProtocolNumber),
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(payloadLength),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: 255,
SrcAddr: lladdr1,
DstAddr: lladdr0,
})
invalid := s.Stats().ICMP.V6.PacketsReceived.Invalid
@@ -979,29 +979,25 @@ func TestNDPValidation(t *testing.T) {
}
handleIPv6Payload := func(payload buffer.View, hopLimit uint8, atomicFragment bool, ep stack.NetworkEndpoint) {
nextHdr := uint8(header.ICMPv6ProtocolNumber)
var extensions buffer.View
var extHdrs header.IPv6ExtHdrSerializer
if atomicFragment {
extensions = buffer.NewView(header.IPv6FragmentExtHdrLength)
extensions[0] = nextHdr
nextHdr = uint8(header.IPv6FragmentExtHdrIdentifier)
extHdrs = append(extHdrs, &header.IPv6SerializableFragmentExtHdr{})
}
extHdrsLen := extHdrs.Length()
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: header.IPv6MinimumSize + len(extensions),
ReserveHeaderBytes: header.IPv6MinimumSize + extHdrsLen,
Data: payload.ToVectorisedView(),
})
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize + len(extensions)))
ip := header.IPv6(pkt.NetworkHeader().Push(header.IPv6MinimumSize + extHdrsLen))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(len(payload) + len(extensions)),
NextHeader: nextHdr,
HopLimit: hopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
PayloadLength: uint16(len(payload) + extHdrsLen),
TransportProtocol: header.ICMPv6ProtocolNumber,
HopLimit: hopLimit,
SrcAddr: lladdr1,
DstAddr: lladdr0,
ExtensionHeaders: extHdrs,
})
if n := copy(ip[header.IPv6MinimumSize:], extensions); n != len(extensions) {
t.Fatalf("expected to write %d bytes of extensions, but wrote %d", len(extensions), n)
}
ep.HandlePacket(pkt)
}
@@ -1351,11 +1347,11 @@ func TestRouterAdvertValidation(t *testing.T) {
pkt.SetChecksum(header.ICMPv6Checksum(pkt, test.src, header.IPv6AllNodesMulticastAddress, buffer.VectorisedView{}))
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: test.hopLimit,
SrcAddr: test.src,
DstAddr: header.IPv6AllNodesMulticastAddress,
PayloadLength: uint16(payloadLength),
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: test.hopLimit,
SrcAddr: test.src,
DstAddr: header.IPv6AllNodesMulticastAddress,
})
stats := s.Stats().ICMP.V6.PacketsReceived
+32 -8
View File
@@ -77,7 +77,10 @@ func validateMLDPacket(t *testing.T, p channel.PacketInfo, remoteAddress tcpip.A
t.Helper()
payload := header.IPv6(stack.PayloadSince(p.Pkt.NetworkHeader()))
checker.IPv6(t, payload,
checker.IPv6WithExtHdr(t, payload,
checker.IPv6ExtHdr(
checker.IPv6HopByHopExtensionHeader(checker.IPv6RouterAlert(header.IPv6RouterAlertMLD)),
),
checker.SrcAddr(ipv6Addr),
checker.DstAddr(remoteAddress),
// Hop Limit for an MLD message must be 1 as per RFC 2710 section 3.
@@ -239,11 +242,11 @@ func createAndInjectMLDPacket(e *channel.Endpoint, mldType uint8, maxRespDelay b
ip := header.IPv6(buf)
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(icmpSize),
HopLimit: header.MLDHopLimit,
NextHeader: uint8(header.ICMPv6ProtocolNumber),
SrcAddr: header.IPv4Any,
DstAddr: header.IPv6AllNodesMulticastAddress,
PayloadLength: uint16(icmpSize),
HopLimit: header.MLDHopLimit,
TransportProtocol: header.ICMPv6ProtocolNumber,
SrcAddr: header.IPv4Any,
DstAddr: header.IPv6AllNodesMulticastAddress,
})
icmp := header.ICMPv6(buf[header.IPv6MinimumSize:])
@@ -1004,10 +1007,31 @@ func TestMGPWithNICLifecycle(t *testing.T) {
t.Helper()
ipv6 := header.IPv6(stack.PayloadSince(p.Pkt.NetworkHeader()))
if got := tcpip.TransportProtocolNumber(ipv6.NextHeader()); got != header.ICMPv6ProtocolNumber {
ipv6HeaderIter := header.MakeIPv6PayloadIterator(
header.IPv6ExtensionHeaderIdentifier(ipv6.NextHeader()),
buffer.View(ipv6.Payload()).ToVectorisedView(),
)
var transport header.IPv6RawPayloadHeader
for {
h, done, err := ipv6HeaderIter.Next()
if err != nil {
t.Fatalf("ipv6HeaderIter.Next(): %s", err)
}
if done {
t.Fatalf("ipv6HeaderIter.Next() = (%T, %t, _), want = (_, false, _)", h, done)
}
if t, ok := h.(header.IPv6RawPayloadHeader); ok {
transport = t
break
}
}
if got := tcpip.TransportProtocolNumber(transport.Identifier); got != header.ICMPv6ProtocolNumber {
t.Fatalf("got ipv6.NextHeader() = %d, want = %d", got, header.ICMPv6ProtocolNumber)
}
icmpv6 := header.ICMPv6(ipv6.Payload())
icmpv6 := header.ICMPv6(transport.Buf.ToView())
if got := icmpv6.Type(); got != header.ICMPv6MulticastListenerReport && got != header.ICMPv6MulticastListenerDone {
t.Fatalf("got icmpv6.Type() = %d, want = %d or %d", got, header.ICMPv6MulticastListenerReport, header.ICMPv6MulticastListenerDone)
}
+15 -15
View File
@@ -577,11 +577,11 @@ func rxNDPSolicit(e *channel.Endpoint, tgt tcpip.Address) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: 255,
SrcAddr: header.IPv6Any,
DstAddr: snmc,
PayloadLength: uint16(payloadLength),
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: 255,
SrcAddr: header.IPv6Any,
DstAddr: snmc,
})
e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{Data: hdr.View().ToVectorisedView()}))
}
@@ -623,11 +623,11 @@ func TestDADFail(t *testing.T) {
payloadLength := hdr.UsedLength()
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: 255,
SrcAddr: tgt,
DstAddr: header.IPv6AllNodesMulticastAddress,
PayloadLength: uint16(payloadLength),
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: 255,
SrcAddr: tgt,
DstAddr: header.IPv6AllNodesMulticastAddress,
})
e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{Data: hdr.View().ToVectorisedView()}))
},
@@ -1011,11 +1011,11 @@ func raBufWithOptsAndDHCPv6(ip tcpip.Address, rl uint16, managedAddress, otherCo
payloadLength := hdr.UsedLength()
iph := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
iph.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLength),
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: header.NDPHopLimit,
SrcAddr: ip,
DstAddr: header.IPv6AllNodesMulticastAddress,
PayloadLength: uint16(payloadLength),
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: header.NDPHopLimit,
SrcAddr: ip,
DstAddr: header.IPv6AllNodesMulticastAddress,
})
return stack.NewPacketBuffer(stack.PacketBufferOptions{
+5 -5
View File
@@ -141,11 +141,11 @@ func (c *testContext) sendV6Packet(payload []byte, h *headers, linkEpID tcpip.NI
// Initialize the IP header.
ip := header.IPv6(buf)
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(header.UDPMinimumSize + len(payload)),
NextHeader: uint8(udp.ProtocolNumber),
HopLimit: 65,
SrcAddr: testSrcAddrV6,
DstAddr: testDstAddrV6,
PayloadLength: uint16(header.UDPMinimumSize + len(payload)),
TransportProtocol: udp.ProtocolNumber,
HopLimit: 65,
SrcAddr: testSrcAddrV6,
DstAddr: testDstAddrV6,
})
// Initialize the UDP header.
@@ -96,11 +96,11 @@ func TestPingMulticastBroadcast(t *testing.T) {
pkt.SetChecksum(header.ICMPv6Checksum(pkt, remoteIPv6Addr, dst, buffer.VectorisedView{}))
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: header.ICMPv6MinimumSize,
NextHeader: uint8(icmp.ProtocolNumber6),
HopLimit: ttl,
SrcAddr: remoteIPv6Addr,
DstAddr: dst,
PayloadLength: header.ICMPv6MinimumSize,
TransportProtocol: icmp.ProtocolNumber6,
HopLimit: ttl,
SrcAddr: remoteIPv6Addr,
DstAddr: dst,
})
e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
@@ -272,11 +272,11 @@ func TestIncomingMulticastAndBroadcast(t *testing.T) {
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(payloadLen),
NextHeader: uint8(udp.ProtocolNumber),
HopLimit: ttl,
SrcAddr: remoteIPv6Addr,
DstAddr: dst,
PayloadLength: uint16(payloadLen),
TransportProtocol: udp.ProtocolNumber,
HopLimit: ttl,
SrcAddr: remoteIPv6Addr,
DstAddr: dst,
})
e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
@@ -635,11 +635,11 @@ func (c *Context) SendV6PacketWithAddrs(payload []byte, h *Headers, src, dst tcp
// Initialize the IP header.
ip := header.IPv6(buf)
ip.Encode(&header.IPv6Fields{
PayloadLength: uint16(header.TCPMinimumSize + len(payload)),
NextHeader: uint8(tcp.ProtocolNumber),
HopLimit: 65,
SrcAddr: src,
DstAddr: dst,
PayloadLength: uint16(header.TCPMinimumSize + len(payload)),
TransportProtocol: tcp.ProtocolNumber,
HopLimit: 65,
SrcAddr: src,
DstAddr: dst,
})
// Initialize the TCP header.
+17 -17
View File
@@ -453,12 +453,12 @@ func (c *testContext) buildV6Packet(payload []byte, h *header4Tuple) buffer.View
// Initialize the IP header.
ip := header.IPv6(buf)
ip.Encode(&header.IPv6Fields{
TrafficClass: testTOS,
PayloadLength: uint16(header.UDPMinimumSize + len(payload)),
NextHeader: uint8(udp.ProtocolNumber),
HopLimit: 65,
SrcAddr: h.srcAddr.Addr,
DstAddr: h.dstAddr.Addr,
TrafficClass: testTOS,
PayloadLength: uint16(header.UDPMinimumSize + len(payload)),
TransportProtocol: udp.ProtocolNumber,
HopLimit: 65,
SrcAddr: h.srcAddr.Addr,
DstAddr: h.dstAddr.Addr,
})
// Initialize the UDP header.
@@ -1494,7 +1494,7 @@ func TestReadRecvOriginalDstAddr(t *testing.T) {
bindAddr := tcpip.FullAddress{Port: stackPort}
if err := c.ep.Bind(bindAddr); err != nil {
t.Fatalf("Bind(%+v): %s", bindAddr, err)
t.Fatalf("Bind(%#v): %s", bindAddr, err)
}
if test.flow.isMulticast() {
@@ -2029,8 +2029,8 @@ func TestV6UnknownDestination(t *testing.T) {
}
// Correct UDP length to access payload.
origDgram.SetLength(uint16(wantPayloadLen + header.UDPMinimumSize))
if got, want := origDgram.Payload(), payload[:wantPayloadLen]; !bytes.Equal(got, want) {
t.Fatalf("got origDgram.Payload() = %x, want = %x", got, want)
if diff := cmp.Diff(payload[:wantPayloadLen], origDgram.Payload()); diff != "" {
t.Fatalf("origDgram.Payload() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -2089,12 +2089,12 @@ func TestShortHeader(t *testing.T) {
// Initialize the IP header.
ip := header.IPv6(buf)
ip.Encode(&header.IPv6Fields{
TrafficClass: testTOS,
PayloadLength: uint16(udpSize),
NextHeader: uint8(udp.ProtocolNumber),
HopLimit: 65,
SrcAddr: h.srcAddr.Addr,
DstAddr: h.dstAddr.Addr,
TrafficClass: testTOS,
PayloadLength: uint16(udpSize),
TransportProtocol: udp.ProtocolNumber,
HopLimit: 65,
SrcAddr: h.srcAddr.Addr,
DstAddr: h.dstAddr.Addr,
})
// Initialize the UDP header.
@@ -2597,12 +2597,12 @@ func TestReceiveShortLength(t *testing.T) {
// Try to receive the data.
v, _, err := c.ep.Read(nil)
if err != nil {
t.Fatalf("c.ep.Read(..): %s", err)
t.Fatalf("c.ep.Read(nil): %s", err)
}
// Check the payload is read back without extra bytes.
if diff := cmp.Diff(buffer.View(payload), v); diff != "" {
t.Errorf("c.ep.Read(..) mismatch (-want +got):\n%s", diff)
t.Errorf("c.ep.Read(nil) mismatch (-want +got):\n%s", diff)
}
})
}
+2 -2
View File
@@ -505,13 +505,13 @@ func (l *IPv6) ToBytes() ([]byte, error) {
}
}
if l.NextHeader != nil {
fields.NextHeader = *l.NextHeader
fields.TransportProtocol = tcpip.TransportProtocolNumber(*l.NextHeader)
} else {
nh, err := nextHeaderByLayer(l.next())
if err != nil {
return nil, err
}
fields.NextHeader = nh
fields.TransportProtocol = tcpip.TransportProtocolNumber(nh)
}
if l.HopLimit != nil {
fields.HopLimit = *l.HopLimit