mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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()
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user