Update dependencies

This commit is contained in:
bluepython508
2024-11-01 17:33:34 +00:00
parent 033ac0b400
commit 5cdfab398d
3596 changed files with 1033483 additions and 259 deletions

View File

@@ -0,0 +1,127 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
// ARPProtocolNumber is the ARP network protocol number.
ARPProtocolNumber tcpip.NetworkProtocolNumber = 0x0806
// ARPSize is the size of an IPv4-over-Ethernet ARP packet.
ARPSize = 28
)
// ARPHardwareType is the hardware type for LinkEndpoint in an ARP header.
type ARPHardwareType uint16
// Typical ARP HardwareType values. Some of the constants have to be specific
// values as they are egressed on the wire in the HTYPE field of an ARP header.
const (
ARPHardwareNone ARPHardwareType = 0
// ARPHardwareEther specifically is the HTYPE for Ethernet as specified
// in the IANA list here:
//
// https://www.iana.org/assignments/arp-parameters/arp-parameters.xhtml#arp-parameters-2
ARPHardwareEther ARPHardwareType = 1
ARPHardwareLoopback ARPHardwareType = 2
)
// ARPOp is an ARP opcode.
type ARPOp uint16
// Typical ARP opcodes defined in RFC 826.
const (
ARPRequest ARPOp = 1
ARPReply ARPOp = 2
)
// ARP is an ARP packet stored in a byte array as described in RFC 826.
type ARP []byte
const (
hTypeOffset = 0
protocolOffset = 2
haAddressSizeOffset = 4
protoAddressSizeOffset = 5
opCodeOffset = 6
senderHAAddressOffset = 8
senderProtocolAddressOffset = senderHAAddressOffset + EthernetAddressSize
targetHAAddressOffset = senderProtocolAddressOffset + IPv4AddressSize
targetProtocolAddressOffset = targetHAAddressOffset + EthernetAddressSize
)
func (a ARP) hardwareAddressType() ARPHardwareType {
return ARPHardwareType(binary.BigEndian.Uint16(a[hTypeOffset:]))
}
func (a ARP) protocolAddressSpace() uint16 { return binary.BigEndian.Uint16(a[protocolOffset:]) }
func (a ARP) hardwareAddressSize() int { return int(a[haAddressSizeOffset]) }
func (a ARP) protocolAddressSize() int { return int(a[protoAddressSizeOffset]) }
// Op is the ARP opcode.
func (a ARP) Op() ARPOp { return ARPOp(binary.BigEndian.Uint16(a[opCodeOffset:])) }
// SetOp sets the ARP opcode.
func (a ARP) SetOp(op ARPOp) {
binary.BigEndian.PutUint16(a[opCodeOffset:], uint16(op))
}
// SetIPv4OverEthernet configures the ARP packet for IPv4-over-Ethernet.
func (a ARP) SetIPv4OverEthernet() {
binary.BigEndian.PutUint16(a[hTypeOffset:], uint16(ARPHardwareEther))
binary.BigEndian.PutUint16(a[protocolOffset:], uint16(IPv4ProtocolNumber))
a[haAddressSizeOffset] = EthernetAddressSize
a[protoAddressSizeOffset] = uint8(IPv4AddressSize)
}
// HardwareAddressSender is the link address of the sender.
// It is a view on to the ARP packet so it can be used to set the value.
func (a ARP) HardwareAddressSender() []byte {
return a[senderHAAddressOffset : senderHAAddressOffset+EthernetAddressSize]
}
// ProtocolAddressSender is the protocol address of the sender.
// It is a view on to the ARP packet so it can be used to set the value.
func (a ARP) ProtocolAddressSender() []byte {
return a[senderProtocolAddressOffset : senderProtocolAddressOffset+IPv4AddressSize]
}
// HardwareAddressTarget is the link address of the target.
// It is a view on to the ARP packet so it can be used to set the value.
func (a ARP) HardwareAddressTarget() []byte {
return a[targetHAAddressOffset : targetHAAddressOffset+EthernetAddressSize]
}
// ProtocolAddressTarget is the protocol address of the target.
// It is a view on to the ARP packet so it can be used to set the value.
func (a ARP) ProtocolAddressTarget() []byte {
return a[targetProtocolAddressOffset : targetProtocolAddressOffset+IPv4AddressSize]
}
// IsValid reports whether this is an ARP packet for IPv4 over Ethernet.
func (a ARP) IsValid() bool {
if len(a) < ARPSize {
return false
}
return a.hardwareAddressType() == ARPHardwareEther &&
a.protocolAddressSpace() == uint16(IPv4ProtocolNumber) &&
a.hardwareAddressSize() == EthernetAddressSize &&
a.protocolAddressSize() == IPv4AddressSize
}

View File

@@ -0,0 +1,107 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package header provides the implementation of the encoding and decoding of
// network protocol headers.
package header
import (
"encoding/binary"
"fmt"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checksum"
)
// PseudoHeaderChecksum calculates the pseudo-header checksum for the given
// destination protocol and network address. Pseudo-headers are needed by
// transport layers when calculating their own checksum.
func PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, srcAddr tcpip.Address, dstAddr tcpip.Address, totalLen uint16) uint16 {
xsum := checksum.Checksum(srcAddr.AsSlice(), 0)
xsum = checksum.Checksum(dstAddr.AsSlice(), xsum)
// Add the length portion of the checksum to the pseudo-checksum.
var tmp [2]byte
binary.BigEndian.PutUint16(tmp[:], totalLen)
xsum = checksum.Checksum(tmp[:], xsum)
return checksum.Checksum([]byte{0, uint8(protocol)}, xsum)
}
// checksumUpdate2ByteAlignedUint16 updates a uint16 value in a calculated
// checksum.
//
// The value MUST begin at a 2-byte boundary in the original buffer.
func checksumUpdate2ByteAlignedUint16(xsum, old, new uint16) uint16 {
// As per RFC 1071 page 4,
// (4) Incremental Update
//
// ...
//
// To update the checksum, simply add the differences of the
// sixteen bit integers that have been changed. To see why this
// works, observe that every 16-bit integer has an additive inverse
// and that addition is associative. From this it follows that
// given the original value m, the new value m', and the old
// checksum C, the new checksum C' is:
//
// C' = C + (-m) + m' = C + (m' - m)
if old == new {
return xsum
}
return checksum.Combine(xsum, checksum.Combine(new, ^old))
}
// checksumUpdate2ByteAlignedAddress updates an address in a calculated
// checksum.
//
// The addresses must have the same length and must contain an even number
// of bytes. The address MUST begin at a 2-byte boundary in the original buffer.
func checksumUpdate2ByteAlignedAddress(xsum uint16, old, new tcpip.Address) uint16 {
const uint16Bytes = 2
if old.BitLen() != new.BitLen() {
panic(fmt.Sprintf("buffer lengths are different; old = %d, new = %d", old.BitLen()/8, new.BitLen()/8))
}
if oldBytes := old.BitLen() % 16; oldBytes != 0 {
panic(fmt.Sprintf("buffer has an odd number of bytes; got = %d", oldBytes))
}
oldAddr := old.AsSlice()
newAddr := new.AsSlice()
// As per RFC 1071 page 4,
// (4) Incremental Update
//
// ...
//
// To update the checksum, simply add the differences of the
// sixteen bit integers that have been changed. To see why this
// works, observe that every 16-bit integer has an additive inverse
// and that addition is associative. From this it follows that
// given the original value m, the new value m', and the old
// checksum C, the new checksum C' is:
//
// C' = C + (-m) + m' = C + (m' - m)
for len(oldAddr) != 0 {
// Convert the 2 byte sequences to uint16 values then apply the increment
// update.
xsum = checksumUpdate2ByteAlignedUint16(xsum, (uint16(oldAddr[0])<<8)+uint16(oldAddr[1]), (uint16(newAddr[0])<<8)+uint16(newAddr[1]))
oldAddr = oldAddr[uint16Bytes:]
newAddr = newAddr[uint16Bytes:]
}
return xsum
}

View File

@@ -0,0 +1,18 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
// DatagramMaximumSize is the maximum supported size of a single datagram.
const DatagramMaximumSize = 0xffff // 65KB.

View File

@@ -0,0 +1,192 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
dstMAC = 0
srcMAC = 6
ethType = 12
)
// EthernetFields contains the fields of an ethernet frame header. It is used to
// describe the fields of a frame that needs to be encoded.
type EthernetFields struct {
// SrcAddr is the "MAC source" field of an ethernet frame header.
SrcAddr tcpip.LinkAddress
// DstAddr is the "MAC destination" field of an ethernet frame header.
DstAddr tcpip.LinkAddress
// Type is the "ethertype" field of an ethernet frame header.
Type tcpip.NetworkProtocolNumber
}
// Ethernet represents an ethernet frame header stored in a byte array.
type Ethernet []byte
const (
// EthernetMinimumSize is the minimum size of a valid ethernet frame.
EthernetMinimumSize = 14
// EthernetMaximumSize is the maximum size of a valid ethernet frame.
EthernetMaximumSize = 18
// EthernetAddressSize is the size, in bytes, of an ethernet address.
EthernetAddressSize = 6
// UnspecifiedEthernetAddress is the unspecified ethernet address
// (all bits set to 0).
UnspecifiedEthernetAddress = tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00")
// EthernetBroadcastAddress is an ethernet address that addresses every node
// on a local link.
EthernetBroadcastAddress = tcpip.LinkAddress("\xff\xff\xff\xff\xff\xff")
// unicastMulticastFlagMask is the mask of the least significant bit in
// the first octet (in network byte order) of an ethernet address that
// determines whether the ethernet address is a unicast or multicast. If
// the masked bit is a 1, then the address is a multicast, unicast
// otherwise.
//
// See the IEEE Std 802-2001 document for more details. Specifically,
// section 9.2.1 of http://ieee802.org/secmail/pdfocSP2xXA6d.pdf:
// "A 48-bit universal address consists of two parts. The first 24 bits
// correspond to the OUI as assigned by the IEEE, expect that the
// assignee may set the LSB of the first octet to 1 for group addresses
// or set it to 0 for individual addresses."
unicastMulticastFlagMask = 1
// unicastMulticastFlagByteIdx is the byte that holds the
// unicast/multicast flag. See unicastMulticastFlagMask.
unicastMulticastFlagByteIdx = 0
)
const (
// EthernetProtocolAll is a catch-all for all protocols carried inside
// an ethernet frame. It is mainly used to create packet sockets that
// capture all traffic.
EthernetProtocolAll tcpip.NetworkProtocolNumber = 0x0003
// EthernetProtocolPUP is the PARC Universal Packet protocol ethertype.
EthernetProtocolPUP tcpip.NetworkProtocolNumber = 0x0200
)
// Ethertypes holds the protocol numbers describing the payload of an ethernet
// frame. These types aren't necessarily supported by netstack, but can be used
// to catch all traffic of a type via packet endpoints.
var Ethertypes = []tcpip.NetworkProtocolNumber{
EthernetProtocolAll,
EthernetProtocolPUP,
}
// SourceAddress returns the "MAC source" field of the ethernet frame header.
func (b Ethernet) SourceAddress() tcpip.LinkAddress {
return tcpip.LinkAddress(b[srcMAC:][:EthernetAddressSize])
}
// DestinationAddress returns the "MAC destination" field of the ethernet frame
// header.
func (b Ethernet) DestinationAddress() tcpip.LinkAddress {
return tcpip.LinkAddress(b[dstMAC:][:EthernetAddressSize])
}
// Type returns the "ethertype" field of the ethernet frame header.
func (b Ethernet) Type() tcpip.NetworkProtocolNumber {
return tcpip.NetworkProtocolNumber(binary.BigEndian.Uint16(b[ethType:]))
}
// Encode encodes all the fields of the ethernet frame header.
func (b Ethernet) Encode(e *EthernetFields) {
binary.BigEndian.PutUint16(b[ethType:], uint16(e.Type))
copy(b[srcMAC:][:EthernetAddressSize], e.SrcAddr)
copy(b[dstMAC:][:EthernetAddressSize], e.DstAddr)
}
// IsMulticastEthernetAddress returns true if the address is a multicast
// ethernet address.
func IsMulticastEthernetAddress(addr tcpip.LinkAddress) bool {
if len(addr) != EthernetAddressSize {
return false
}
return addr[unicastMulticastFlagByteIdx]&unicastMulticastFlagMask != 0
}
// IsValidUnicastEthernetAddress returns true if the address is a unicast
// ethernet address.
func IsValidUnicastEthernetAddress(addr tcpip.LinkAddress) bool {
if len(addr) != EthernetAddressSize {
return false
}
if addr == UnspecifiedEthernetAddress {
return false
}
if addr[unicastMulticastFlagByteIdx]&unicastMulticastFlagMask != 0 {
return false
}
return true
}
// EthernetAddressFromMulticastIPv4Address returns a multicast Ethernet address
// for a multicast IPv4 address.
//
// addr MUST be a multicast IPv4 address.
func EthernetAddressFromMulticastIPv4Address(addr tcpip.Address) tcpip.LinkAddress {
var linkAddrBytes [EthernetAddressSize]byte
// RFC 1112 Host Extensions for IP Multicasting
//
// 6.4. Extensions to an Ethernet Local Network Module:
//
// An IP host group address is mapped to an Ethernet multicast
// address by placing the low-order 23-bits of the IP address
// into the low-order 23 bits of the Ethernet multicast address
// 01-00-5E-00-00-00 (hex).
addrBytes := addr.As4()
linkAddrBytes[0] = 0x1
linkAddrBytes[2] = 0x5e
linkAddrBytes[3] = addrBytes[1] & 0x7F
copy(linkAddrBytes[4:], addrBytes[IPv4AddressSize-2:])
return tcpip.LinkAddress(linkAddrBytes[:])
}
// EthernetAddressFromMulticastIPv6Address returns a multicast Ethernet address
// for a multicast IPv6 address.
//
// addr MUST be a multicast IPv6 address.
func EthernetAddressFromMulticastIPv6Address(addr tcpip.Address) tcpip.LinkAddress {
// RFC 2464 Transmission of IPv6 Packets over Ethernet Networks
//
// 7. Address Mapping -- Multicast
//
// An IPv6 packet with a multicast destination address DST,
// consisting of the sixteen octets DST[1] through DST[16], is
// transmitted to the Ethernet multicast address whose first
// two octets are the value 3333 hexadecimal and whose last
// four octets are the last four octets of DST.
addrBytes := addr.As16()
linkAddrBytes := []byte(addrBytes[IPv6AddressSize-EthernetAddressSize:])
linkAddrBytes[0] = 0x33
linkAddrBytes[1] = 0x33
return tcpip.LinkAddress(linkAddrBytes[:])
}

View File

@@ -0,0 +1,73 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
const (
typeHLen = 0
encapProto = 1
)
// GUEFields contains the fields of a GUE packet. It is used to describe the
// fields of a packet that needs to be encoded.
type GUEFields struct {
// Type is the "type" field of the GUE header.
Type uint8
// Control is the "control" field of the GUE header.
Control bool
// HeaderLength is the "header length" field of the GUE header. It must
// be at least 4 octets, and a multiple of 4 as well.
HeaderLength uint8
// Protocol is the "protocol" field of the GUE header. This is one of
// the IPPROTO_* values.
Protocol uint8
}
// GUE represents a Generic UDP Encapsulation header stored in a byte array, the
// fields are described in https://tools.ietf.org/html/draft-ietf-nvo3-gue-01.
type GUE []byte
const (
// GUEMinimumSize is the minimum size of a valid GUE packet.
GUEMinimumSize = 4
)
// TypeAndControl returns the GUE packet type (top 3 bits of the first byte,
// which includes the control bit).
func (b GUE) TypeAndControl() uint8 {
return b[typeHLen] >> 5
}
// HeaderLength returns the total length of the GUE header.
func (b GUE) HeaderLength() uint8 {
return 4 + 4*(b[typeHLen]&0x1f)
}
// Protocol returns the protocol field of the GUE header.
func (b GUE) Protocol() uint8 {
return b[encapProto]
}
// Encode encodes all the fields of the GUE header.
func (b GUE) Encode(i *GUEFields) {
ctl := uint8(0)
if i.Control {
ctl = 1 << 5
}
b[typeHLen] = ctl | i.Type<<6 | (i.HeaderLength-4)/4
b[encapProto] = i.Protocol
}

View File

@@ -0,0 +1,120 @@
// automatically generated by stateify.
package header
import (
"context"
"gvisor.dev/gvisor/pkg/state"
)
func (t *TCPSynOptions) StateTypeName() string {
return "pkg/tcpip/header.TCPSynOptions"
}
func (t *TCPSynOptions) StateFields() []string {
return []string{
"MSS",
"WS",
"TS",
"TSVal",
"TSEcr",
"SACKPermitted",
"Flags",
}
}
func (t *TCPSynOptions) beforeSave() {}
// +checklocksignore
func (t *TCPSynOptions) StateSave(stateSinkObject state.Sink) {
t.beforeSave()
stateSinkObject.Save(0, &t.MSS)
stateSinkObject.Save(1, &t.WS)
stateSinkObject.Save(2, &t.TS)
stateSinkObject.Save(3, &t.TSVal)
stateSinkObject.Save(4, &t.TSEcr)
stateSinkObject.Save(5, &t.SACKPermitted)
stateSinkObject.Save(6, &t.Flags)
}
func (t *TCPSynOptions) afterLoad(context.Context) {}
// +checklocksignore
func (t *TCPSynOptions) StateLoad(ctx context.Context, stateSourceObject state.Source) {
stateSourceObject.Load(0, &t.MSS)
stateSourceObject.Load(1, &t.WS)
stateSourceObject.Load(2, &t.TS)
stateSourceObject.Load(3, &t.TSVal)
stateSourceObject.Load(4, &t.TSEcr)
stateSourceObject.Load(5, &t.SACKPermitted)
stateSourceObject.Load(6, &t.Flags)
}
func (r *SACKBlock) StateTypeName() string {
return "pkg/tcpip/header.SACKBlock"
}
func (r *SACKBlock) StateFields() []string {
return []string{
"Start",
"End",
}
}
func (r *SACKBlock) beforeSave() {}
// +checklocksignore
func (r *SACKBlock) StateSave(stateSinkObject state.Sink) {
r.beforeSave()
stateSinkObject.Save(0, &r.Start)
stateSinkObject.Save(1, &r.End)
}
func (r *SACKBlock) afterLoad(context.Context) {}
// +checklocksignore
func (r *SACKBlock) StateLoad(ctx context.Context, stateSourceObject state.Source) {
stateSourceObject.Load(0, &r.Start)
stateSourceObject.Load(1, &r.End)
}
func (t *TCPOptions) StateTypeName() string {
return "pkg/tcpip/header.TCPOptions"
}
func (t *TCPOptions) StateFields() []string {
return []string{
"TS",
"TSVal",
"TSEcr",
"SACKBlocks",
}
}
func (t *TCPOptions) beforeSave() {}
// +checklocksignore
func (t *TCPOptions) StateSave(stateSinkObject state.Sink) {
t.beforeSave()
stateSinkObject.Save(0, &t.TS)
stateSinkObject.Save(1, &t.TSVal)
stateSinkObject.Save(2, &t.TSEcr)
stateSinkObject.Save(3, &t.SACKBlocks)
}
func (t *TCPOptions) afterLoad(context.Context) {}
// +checklocksignore
func (t *TCPOptions) StateLoad(ctx context.Context, stateSourceObject state.Source) {
stateSourceObject.Load(0, &t.TS)
stateSourceObject.Load(1, &t.TSVal)
stateSourceObject.Load(2, &t.TSEcr)
stateSourceObject.Load(3, &t.SACKBlocks)
}
func init() {
state.Register((*TCPSynOptions)(nil))
state.Register((*SACKBlock)(nil))
state.Register((*TCPOptions)(nil))
}

View File

@@ -0,0 +1,228 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checksum"
)
// ICMPv4 represents an ICMPv4 header stored in a byte array.
type ICMPv4 []byte
const (
// ICMPv4PayloadOffset defines the start of ICMP payload.
ICMPv4PayloadOffset = 8
// ICMPv4MinimumSize is the minimum size of a valid ICMP packet.
ICMPv4MinimumSize = 8
// ICMPv4MinimumErrorPayloadSize Is the smallest number of bytes of an
// errant packet's transport layer that an ICMP error type packet should
// attempt to send as per RFC 792 (see each type) and RFC 1122
// section 3.2.2 which states:
// Every ICMP error message includes the Internet header and at
// least the first 8 data octets of the datagram that triggered
// the error; more than 8 octets MAY be sent; this header and data
// MUST be unchanged from the received datagram.
//
// RFC 792 shows:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | unused |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Internet Header + 64 bits of Original Data Datagram |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ICMPv4MinimumErrorPayloadSize = 8
// ICMPv4ProtocolNumber is the ICMP transport protocol number.
ICMPv4ProtocolNumber tcpip.TransportProtocolNumber = 1
// icmpv4ChecksumOffset is the offset of the checksum field
// in an ICMPv4 message.
icmpv4ChecksumOffset = 2
// icmpv4MTUOffset is the offset of the MTU field
// in an ICMPv4FragmentationNeeded message.
icmpv4MTUOffset = 6
// icmpv4IdentOffset is the offset of the ident field
// in an ICMPv4EchoRequest/Reply message.
icmpv4IdentOffset = 4
// icmpv4PointerOffset is the offset of the pointer field
// in an ICMPv4ParamProblem message.
icmpv4PointerOffset = 4
// icmpv4SequenceOffset is the offset of the sequence field
// in an ICMPv4EchoRequest/Reply message.
icmpv4SequenceOffset = 6
)
// ICMPv4Type is the ICMP type field described in RFC 792.
type ICMPv4Type byte
// ICMPv4Code is the ICMP code field described in RFC 792.
type ICMPv4Code byte
// Typical values of ICMPv4Type defined in RFC 792.
const (
ICMPv4EchoReply ICMPv4Type = 0
ICMPv4DstUnreachable ICMPv4Type = 3
ICMPv4SrcQuench ICMPv4Type = 4
ICMPv4Redirect ICMPv4Type = 5
ICMPv4Echo ICMPv4Type = 8
ICMPv4TimeExceeded ICMPv4Type = 11
ICMPv4ParamProblem ICMPv4Type = 12
ICMPv4Timestamp ICMPv4Type = 13
ICMPv4TimestampReply ICMPv4Type = 14
ICMPv4InfoRequest ICMPv4Type = 15
ICMPv4InfoReply ICMPv4Type = 16
)
// ICMP codes for ICMPv4 Time Exceeded messages as defined in RFC 792.
const (
ICMPv4TTLExceeded ICMPv4Code = 0
ICMPv4ReassemblyTimeout ICMPv4Code = 1
)
// ICMP codes for ICMPv4 Destination Unreachable messages as defined in RFC 792,
// RFC 1122 section 3.2.2.1 and RFC 1812 section 5.2.7.1.
const (
ICMPv4NetUnreachable ICMPv4Code = 0
ICMPv4HostUnreachable ICMPv4Code = 1
ICMPv4ProtoUnreachable ICMPv4Code = 2
ICMPv4PortUnreachable ICMPv4Code = 3
ICMPv4FragmentationNeeded ICMPv4Code = 4
ICMPv4SourceRouteFailed ICMPv4Code = 5
ICMPv4DestinationNetworkUnknown ICMPv4Code = 6
ICMPv4DestinationHostUnknown ICMPv4Code = 7
ICMPv4SourceHostIsolated ICMPv4Code = 8
ICMPv4NetProhibited ICMPv4Code = 9
ICMPv4HostProhibited ICMPv4Code = 10
ICMPv4NetUnreachableForTos ICMPv4Code = 11
ICMPv4HostUnreachableForTos ICMPv4Code = 12
ICMPv4AdminProhibited ICMPv4Code = 13
ICMPv4HostPrecedenceViolation ICMPv4Code = 14
ICMPv4PrecedenceCutInEffect ICMPv4Code = 15
)
// ICMPv4UnusedCode is a code to use in ICMP messages where no code is needed.
const ICMPv4UnusedCode ICMPv4Code = 0
// Type is the ICMP type field.
func (b ICMPv4) Type() ICMPv4Type { return ICMPv4Type(b[0]) }
// SetType sets the ICMP type field.
func (b ICMPv4) SetType(t ICMPv4Type) { b[0] = byte(t) }
// Code is the ICMP code field. Its meaning depends on the value of Type.
func (b ICMPv4) Code() ICMPv4Code { return ICMPv4Code(b[1]) }
// SetCode sets the ICMP code field.
func (b ICMPv4) SetCode(c ICMPv4Code) { b[1] = byte(c) }
// Pointer returns the pointer field in a Parameter Problem packet.
func (b ICMPv4) Pointer() byte { return b[icmpv4PointerOffset] }
// SetPointer sets the pointer field in a Parameter Problem packet.
func (b ICMPv4) SetPointer(c byte) { b[icmpv4PointerOffset] = c }
// Checksum is the ICMP checksum field.
func (b ICMPv4) Checksum() uint16 {
return binary.BigEndian.Uint16(b[icmpv4ChecksumOffset:])
}
// SetChecksum sets the ICMP checksum field.
func (b ICMPv4) SetChecksum(cs uint16) {
checksum.Put(b[icmpv4ChecksumOffset:], cs)
}
// SourcePort implements Transport.SourcePort.
func (ICMPv4) SourcePort() uint16 {
return 0
}
// DestinationPort implements Transport.DestinationPort.
func (ICMPv4) DestinationPort() uint16 {
return 0
}
// SetSourcePort implements Transport.SetSourcePort.
func (ICMPv4) SetSourcePort(uint16) {
}
// SetDestinationPort implements Transport.SetDestinationPort.
func (ICMPv4) SetDestinationPort(uint16) {
}
// Payload implements Transport.Payload.
func (b ICMPv4) Payload() []byte {
return b[ICMPv4PayloadOffset:]
}
// MTU retrieves the MTU field from an ICMPv4 message.
func (b ICMPv4) MTU() uint16 {
return binary.BigEndian.Uint16(b[icmpv4MTUOffset:])
}
// SetMTU sets the MTU field from an ICMPv4 message.
func (b ICMPv4) SetMTU(mtu uint16) {
binary.BigEndian.PutUint16(b[icmpv4MTUOffset:], mtu)
}
// Ident retrieves the Ident field from an ICMPv4 message.
func (b ICMPv4) Ident() uint16 {
return binary.BigEndian.Uint16(b[icmpv4IdentOffset:])
}
// SetIdent sets the Ident field from an ICMPv4 message.
func (b ICMPv4) SetIdent(ident uint16) {
binary.BigEndian.PutUint16(b[icmpv4IdentOffset:], ident)
}
// SetIdentWithChecksumUpdate sets the Ident field and updates the checksum.
func (b ICMPv4) SetIdentWithChecksumUpdate(new uint16) {
old := b.Ident()
b.SetIdent(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
}
// Sequence retrieves the Sequence field from an ICMPv4 message.
func (b ICMPv4) Sequence() uint16 {
return binary.BigEndian.Uint16(b[icmpv4SequenceOffset:])
}
// SetSequence sets the Sequence field from an ICMPv4 message.
func (b ICMPv4) SetSequence(sequence uint16) {
binary.BigEndian.PutUint16(b[icmpv4SequenceOffset:], sequence)
}
// ICMPv4Checksum calculates the ICMP checksum over the provided ICMP header,
// and payload.
func ICMPv4Checksum(h ICMPv4, payloadCsum uint16) uint16 {
xsum := payloadCsum
// h[2:4] is the checksum itself, skip it to avoid checksumming the checksum.
xsum = checksum.Checksum(h[:2], xsum)
xsum = checksum.Checksum(h[4:], xsum)
return ^xsum
}

View File

@@ -0,0 +1,304 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checksum"
)
// ICMPv6 represents an ICMPv6 header stored in a byte array.
type ICMPv6 []byte
const (
// ICMPv6HeaderSize is the size of the ICMPv6 header. That is, the
// sum of the size of the ICMPv6 Type, Code and Checksum fields, as
// per RFC 4443 section 2.1. After the ICMPv6 header, the ICMPv6
// message body begins.
ICMPv6HeaderSize = 4
// ICMPv6MinimumSize is the minimum size of a valid ICMP packet.
ICMPv6MinimumSize = 8
// ICMPv6PayloadOffset is the offset of the payload in an
// ICMP packet.
ICMPv6PayloadOffset = 8
// ICMPv6ProtocolNumber is the ICMP transport protocol number.
ICMPv6ProtocolNumber tcpip.TransportProtocolNumber = 58
// ICMPv6NeighborSolicitMinimumSize is the minimum size of a
// neighbor solicitation packet.
ICMPv6NeighborSolicitMinimumSize = ICMPv6HeaderSize + NDPNSMinimumSize
// ICMPv6NeighborAdvertMinimumSize is the minimum size of a
// neighbor advertisement packet.
ICMPv6NeighborAdvertMinimumSize = ICMPv6HeaderSize + NDPNAMinimumSize
// ICMPv6EchoMinimumSize is the minimum size of a valid echo packet.
ICMPv6EchoMinimumSize = 8
// ICMPv6ErrorHeaderSize is the size of an ICMP error packet header,
// as per RFC 4443, Appendix A, item 4 and the errata.
// ... all ICMP error messages shall have exactly
// 32 bits of type-specific data, so that receivers can reliably find
// the embedded invoking packet even when they don't recognize the
// ICMP message Type.
ICMPv6ErrorHeaderSize = 8
// ICMPv6DstUnreachableMinimumSize is the minimum size of a valid ICMP
// destination unreachable packet.
ICMPv6DstUnreachableMinimumSize = ICMPv6MinimumSize
// ICMPv6PacketTooBigMinimumSize is the minimum size of a valid ICMP
// packet-too-big packet.
ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize
// ICMPv6ChecksumOffset is the offset of the checksum field
// in an ICMPv6 message.
ICMPv6ChecksumOffset = 2
// icmpv6PointerOffset is the offset of the pointer
// in an ICMPv6 Parameter problem message.
icmpv6PointerOffset = 4
// icmpv6MTUOffset is the offset of the MTU field in an ICMPv6
// PacketTooBig message.
icmpv6MTUOffset = 4
// icmpv6IdentOffset is the offset of the ident field
// in a ICMPv6 Echo Request/Reply message.
icmpv6IdentOffset = 4
// icmpv6SequenceOffset is the offset of the sequence field
// in a ICMPv6 Echo Request/Reply message.
icmpv6SequenceOffset = 6
// NDPHopLimit is the expected IP hop limit value of 255 for received
// NDP packets, as per RFC 4861 sections 4.1 - 4.5, 6.1.1, 6.1.2, 7.1.1,
// 7.1.2 and 8.1. If the hop limit value is not 255, nodes MUST silently
// drop the NDP packet. All outgoing NDP packets must use this value for
// its IP hop limit field.
NDPHopLimit = 255
)
// ICMPv6Type is the ICMP type field described in RFC 4443.
type ICMPv6Type byte
// Values for use in the Type field of ICMPv6 packet from RFC 4433.
const (
ICMPv6DstUnreachable ICMPv6Type = 1
ICMPv6PacketTooBig ICMPv6Type = 2
ICMPv6TimeExceeded ICMPv6Type = 3
ICMPv6ParamProblem ICMPv6Type = 4
ICMPv6EchoRequest ICMPv6Type = 128
ICMPv6EchoReply ICMPv6Type = 129
// Neighbor Discovery Protocol (NDP) messages, see RFC 4861.
ICMPv6RouterSolicit ICMPv6Type = 133
ICMPv6RouterAdvert ICMPv6Type = 134
ICMPv6NeighborSolicit ICMPv6Type = 135
ICMPv6NeighborAdvert ICMPv6Type = 136
ICMPv6RedirectMsg ICMPv6Type = 137
// Multicast Listener Discovery (MLD) messages, see RFC 2710.
ICMPv6MulticastListenerQuery ICMPv6Type = 130
ICMPv6MulticastListenerReport ICMPv6Type = 131
ICMPv6MulticastListenerDone ICMPv6Type = 132
// Multicast Listener Discovert Version 2 (MLDv2) messages, see RFC 3810.
ICMPv6MulticastListenerV2Report ICMPv6Type = 143
)
// IsErrorType returns true if the receiver is an ICMP error type.
func (typ ICMPv6Type) IsErrorType() bool {
// Per RFC 4443 section 2.1:
// ICMPv6 messages are grouped into two classes: error messages and
// informational messages. Error messages are identified as such by a
// zero in the high-order bit of their message Type field values. Thus,
// error messages have message types from 0 to 127; informational
// messages have message types from 128 to 255.
return typ&0x80 == 0
}
// ICMPv6Code is the ICMP Code field described in RFC 4443.
type ICMPv6Code byte
// ICMP codes used with Destination Unreachable (Type 1). As per RFC 4443
// section 3.1.
const (
ICMPv6NetworkUnreachable ICMPv6Code = 0
ICMPv6Prohibited ICMPv6Code = 1
ICMPv6BeyondScope ICMPv6Code = 2
ICMPv6AddressUnreachable ICMPv6Code = 3
ICMPv6PortUnreachable ICMPv6Code = 4
ICMPv6Policy ICMPv6Code = 5
ICMPv6RejectRoute ICMPv6Code = 6
)
// ICMP codes used with Time Exceeded (Type 3). As per RFC 4443 section 3.3.
const (
ICMPv6HopLimitExceeded ICMPv6Code = 0
ICMPv6ReassemblyTimeout ICMPv6Code = 1
)
// ICMP codes used with Parameter Problem (Type 4). As per RFC 4443 section 3.4.
const (
// ICMPv6ErroneousHeader indicates an erroneous header field was encountered.
ICMPv6ErroneousHeader ICMPv6Code = 0
// ICMPv6UnknownHeader indicates an unrecognized Next Header type encountered.
ICMPv6UnknownHeader ICMPv6Code = 1
// ICMPv6UnknownOption indicates an unrecognized IPv6 option was encountered.
ICMPv6UnknownOption ICMPv6Code = 2
)
// ICMPv6UnusedCode is the code value used with ICMPv6 messages which don't use
// the code field. (Types not mentioned above.)
const ICMPv6UnusedCode ICMPv6Code = 0
// Type is the ICMP type field.
func (b ICMPv6) Type() ICMPv6Type { return ICMPv6Type(b[0]) }
// SetType sets the ICMP type field.
func (b ICMPv6) SetType(t ICMPv6Type) { b[0] = byte(t) }
// Code is the ICMP code field. Its meaning depends on the value of Type.
func (b ICMPv6) Code() ICMPv6Code { return ICMPv6Code(b[1]) }
// SetCode sets the ICMP code field.
func (b ICMPv6) SetCode(c ICMPv6Code) { b[1] = byte(c) }
// TypeSpecific returns the type specific data field.
func (b ICMPv6) TypeSpecific() uint32 {
return binary.BigEndian.Uint32(b[icmpv6PointerOffset:])
}
// SetTypeSpecific sets the type specific data field.
func (b ICMPv6) SetTypeSpecific(val uint32) {
binary.BigEndian.PutUint32(b[icmpv6PointerOffset:], val)
}
// Checksum is the ICMP checksum field.
func (b ICMPv6) Checksum() uint16 {
return binary.BigEndian.Uint16(b[ICMPv6ChecksumOffset:])
}
// SetChecksum sets the ICMP checksum field.
func (b ICMPv6) SetChecksum(cs uint16) {
checksum.Put(b[ICMPv6ChecksumOffset:], cs)
}
// SourcePort implements Transport.SourcePort.
func (ICMPv6) SourcePort() uint16 {
return 0
}
// DestinationPort implements Transport.DestinationPort.
func (ICMPv6) DestinationPort() uint16 {
return 0
}
// SetSourcePort implements Transport.SetSourcePort.
func (ICMPv6) SetSourcePort(uint16) {
}
// SetDestinationPort implements Transport.SetDestinationPort.
func (ICMPv6) SetDestinationPort(uint16) {
}
// MTU retrieves the MTU field from an ICMPv6 message.
func (b ICMPv6) MTU() uint32 {
return binary.BigEndian.Uint32(b[icmpv6MTUOffset:])
}
// SetMTU sets the MTU field from an ICMPv6 message.
func (b ICMPv6) SetMTU(mtu uint32) {
binary.BigEndian.PutUint32(b[icmpv6MTUOffset:], mtu)
}
// Ident retrieves the Ident field from an ICMPv6 message.
func (b ICMPv6) Ident() uint16 {
return binary.BigEndian.Uint16(b[icmpv6IdentOffset:])
}
// SetIdent sets the Ident field from an ICMPv6 message.
func (b ICMPv6) SetIdent(ident uint16) {
binary.BigEndian.PutUint16(b[icmpv6IdentOffset:], ident)
}
// SetIdentWithChecksumUpdate sets the Ident field and updates the checksum.
func (b ICMPv6) SetIdentWithChecksumUpdate(new uint16) {
old := b.Ident()
b.SetIdent(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
}
// Sequence retrieves the Sequence field from an ICMPv6 message.
func (b ICMPv6) Sequence() uint16 {
return binary.BigEndian.Uint16(b[icmpv6SequenceOffset:])
}
// SetSequence sets the Sequence field from an ICMPv6 message.
func (b ICMPv6) SetSequence(sequence uint16) {
binary.BigEndian.PutUint16(b[icmpv6SequenceOffset:], sequence)
}
// MessageBody returns the message body as defined by RFC 4443 section 2.1; the
// portion of the ICMPv6 buffer after the first ICMPv6HeaderSize bytes.
func (b ICMPv6) MessageBody() []byte {
return b[ICMPv6HeaderSize:]
}
// Payload implements Transport.Payload.
func (b ICMPv6) Payload() []byte {
return b[ICMPv6PayloadOffset:]
}
// ICMPv6ChecksumParams contains parameters to calculate ICMPv6 checksum.
type ICMPv6ChecksumParams struct {
Header ICMPv6
Src tcpip.Address
Dst tcpip.Address
PayloadCsum uint16
PayloadLen int
}
// ICMPv6Checksum calculates the ICMP checksum over the provided ICMPv6 header,
// IPv6 src/dst addresses and the payload.
func ICMPv6Checksum(params ICMPv6ChecksumParams) uint16 {
h := params.Header
xsum := PseudoHeaderChecksum(ICMPv6ProtocolNumber, params.Src, params.Dst, uint16(len(h)+params.PayloadLen))
xsum = checksum.Combine(xsum, params.PayloadCsum)
// h[2:4] is the checksum itself, skip it to avoid checksumming the checksum.
xsum = checksum.Checksum(h[:2], xsum)
xsum = checksum.Checksum(h[4:], xsum)
return ^xsum
}
// UpdateChecksumPseudoHeaderAddress updates the checksum to reflect an
// updated address in the pseudo header.
func (b ICMPv6) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address) {
b.SetChecksum(^checksumUpdate2ByteAlignedAddress(^b.Checksum(), old, new))
}

View File

@@ -0,0 +1,185 @@
// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"fmt"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checksum"
)
// IGMP represents an IGMP header stored in a byte array.
type IGMP []byte
// IGMP implements `Transport`.
var _ Transport = (*IGMP)(nil)
const (
// IGMPMinimumSize is the minimum size of a valid IGMP packet in bytes,
// as per RFC 2236, Section 2, Page 2.
IGMPMinimumSize = 8
// IGMPQueryMinimumSize is the minimum size of a valid Membership Query
// Message in bytes, as per RFC 2236, Section 2, Page 2.
IGMPQueryMinimumSize = 8
// IGMPReportMinimumSize is the minimum size of a valid Report Message in
// bytes, as per RFC 2236, Section 2, Page 2.
IGMPReportMinimumSize = 8
// IGMPLeaveMessageMinimumSize is the minimum size of a valid Leave Message
// in bytes, as per RFC 2236, Section 2, Page 2.
IGMPLeaveMessageMinimumSize = 8
// IGMPTTL is the TTL for all IGMP messages, as per RFC 2236, Section 3, Page
// 3.
IGMPTTL = 1
// igmpTypeOffset defines the offset of the type field in an IGMP message.
igmpTypeOffset = 0
// igmpMaxRespTimeOffset defines the offset of the MaxRespTime field in an
// IGMP message.
igmpMaxRespTimeOffset = 1
// igmpChecksumOffset defines the offset of the checksum field in an IGMP
// message.
igmpChecksumOffset = 2
// igmpGroupAddressOffset defines the offset of the Group Address field in an
// IGMP message.
igmpGroupAddressOffset = 4
// IGMPProtocolNumber is IGMP's transport protocol number.
IGMPProtocolNumber tcpip.TransportProtocolNumber = 2
)
// IGMPType is the IGMP type field as per RFC 2236.
type IGMPType byte
// Values for the IGMP Type described in RFC 2236 Section 2.1, Page 2.
// Descriptions below come from there.
const (
// IGMPMembershipQuery indicates that the message type is Membership Query.
// "There are two sub-types of Membership Query messages:
// - General Query, used to learn which groups have members on an
// attached network.
// - Group-Specific Query, used to learn if a particular group
// has any members on an attached network.
// These two messages are differentiated by the Group Address, as
// described in section 1.4 ."
IGMPMembershipQuery IGMPType = 0x11
// IGMPv1MembershipReport indicates that the message is a Membership Report
// generated by a host using the IGMPv1 protocol: "an additional type of
// message, for backwards-compatibility with IGMPv1"
IGMPv1MembershipReport IGMPType = 0x12
// IGMPv2MembershipReport indicates that the Message type is a Membership
// Report generated by a host using the IGMPv2 protocol.
IGMPv2MembershipReport IGMPType = 0x16
// IGMPLeaveGroup indicates that the message type is a Leave Group
// notification message.
IGMPLeaveGroup IGMPType = 0x17
// IGMPv3MembershipReport indicates that the message type is a IGMPv3 report.
IGMPv3MembershipReport IGMPType = 0x22
)
// Type is the IGMP type field.
func (b IGMP) Type() IGMPType { return IGMPType(b[igmpTypeOffset]) }
// SetType sets the IGMP type field.
func (b IGMP) SetType(t IGMPType) { b[igmpTypeOffset] = byte(t) }
// MaxRespTime gets the MaxRespTimeField. This is meaningful only in Membership
// Query messages, in other cases it is set to 0 by the sender and ignored by
// the receiver.
func (b IGMP) MaxRespTime() time.Duration {
// As per RFC 2236 section 2.2,
//
// The Max Response Time field is meaningful only in Membership Query
// messages, and specifies the maximum allowed time before sending a
// responding report in units of 1/10 second. In all other messages, it
// is set to zero by the sender and ignored by receivers.
return DecisecondToDuration(uint16(b[igmpMaxRespTimeOffset]))
}
// SetMaxRespTime sets the MaxRespTimeField.
func (b IGMP) SetMaxRespTime(m byte) { b[igmpMaxRespTimeOffset] = m }
// Checksum is the IGMP checksum field.
func (b IGMP) Checksum() uint16 {
return binary.BigEndian.Uint16(b[igmpChecksumOffset:])
}
// SetChecksum sets the IGMP checksum field.
func (b IGMP) SetChecksum(checksum uint16) {
binary.BigEndian.PutUint16(b[igmpChecksumOffset:], checksum)
}
// GroupAddress gets the Group Address field.
func (b IGMP) GroupAddress() tcpip.Address {
return tcpip.AddrFrom4([4]byte(b[igmpGroupAddressOffset:][:IPv4AddressSize]))
}
// SetGroupAddress sets the Group Address field.
func (b IGMP) SetGroupAddress(address tcpip.Address) {
addrBytes := address.As4()
if n := copy(b[igmpGroupAddressOffset:], addrBytes[:]); n != IPv4AddressSize {
panic(fmt.Sprintf("copied %d bytes, expected %d", n, IPv4AddressSize))
}
}
// SourcePort implements Transport.SourcePort.
func (IGMP) SourcePort() uint16 {
return 0
}
// DestinationPort implements Transport.DestinationPort.
func (IGMP) DestinationPort() uint16 {
return 0
}
// SetSourcePort implements Transport.SetSourcePort.
func (IGMP) SetSourcePort(uint16) {
}
// SetDestinationPort implements Transport.SetDestinationPort.
func (IGMP) SetDestinationPort(uint16) {
}
// Payload implements Transport.Payload.
func (IGMP) Payload() []byte {
return nil
}
// IGMPCalculateChecksum calculates the IGMP checksum over the provided IGMP
// header.
func IGMPCalculateChecksum(h IGMP) uint16 {
// The header contains a checksum itself, set it aside to avoid checksumming
// the checksum and replace it afterwards.
existingXsum := h.Checksum()
h.SetChecksum(0)
xsum := ^checksum.Checksum(h, 0)
h.SetChecksum(existingXsum)
return xsum
}
// DecisecondToDuration converts a value representing deci-seconds to a
// time.Duration.
func DecisecondToDuration(ds uint16) time.Duration {
return time.Duration(ds) * time.Second / 10
}

View File

@@ -0,0 +1,502 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"bytes"
"encoding/binary"
"fmt"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
)
var (
// IGMPv3RoutersAddress is the address to send IGMPv3 reports to.
//
// As per RFC 3376 section 4.2.14,
//
// Version 3 Reports are sent with an IP destination address of
// 224.0.0.22, to which all IGMPv3-capable multicast routers listen.
IGMPv3RoutersAddress = tcpip.AddrFrom4([4]byte{0xe0, 0x00, 0x00, 0x16})
)
const (
// IGMPv3QueryMinimumSize is the mimum size of a valid IGMPv3 query,
// as per RFC 3376 section 4.1.
IGMPv3QueryMinimumSize = 12
igmpv3QueryMaxRespCodeOffset = 1
igmpv3QueryGroupAddressOffset = 4
igmpv3QueryResvSQRVOffset = 8
igmpv3QueryQRVMask = 0b111
igmpv3QueryQQICOffset = 9
igmpv3QueryNumberOfSourcesOffset = 10
igmpv3QuerySourcesOffset = 12
)
// IGMPv3Query is an IGMPv3 query message.
//
// As per RFC 3376 section 4.1,
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 0x11 | Max Resp Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Group Address |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Resv |S| QRV | QQIC | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Source Address [1] |
// +- -+
// | Source Address [2] |
// +- . -+
// . . .
// . . .
// +- -+
// | Source Address [N] |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type IGMPv3Query IGMP
// MaximumResponseCode returns the Maximum Response Code.
func (i IGMPv3Query) MaximumResponseCode() uint8 {
return i[igmpv3QueryMaxRespCodeOffset]
}
// IGMPv3MaximumResponseDelay returns the Maximum Response Delay in an IGMPv3
// Maximum Response Code.
//
// As per RFC 3376 section 4.1.1,
//
// The Max Resp Code field specifies the maximum time allowed before
// sending a responding report. The actual time allowed, called the Max
// Resp Time, is represented in units of 1/10 second and is derived from
// the Max Resp Code as follows:
//
// If Max Resp Code < 128, Max Resp Time = Max Resp Code
//
// If Max Resp Code >= 128, Max Resp Code represents a floating-point
// value as follows:
//
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |1| exp | mant |
// +-+-+-+-+-+-+-+-+
//
// Max Resp Time = (mant | 0x10) << (exp + 3)
//
// Small values of Max Resp Time allow IGMPv3 routers to tune the "leave
// latency" (the time between the moment the last host leaves a group
// and the moment the routing protocol is notified that there are no
// more members). Larger values, especially in the exponential range,
// allow tuning of the burstiness of IGMP traffic on a network.
func IGMPv3MaximumResponseDelay(codeRaw uint8) time.Duration {
code := uint16(codeRaw)
if code < 128 {
return DecisecondToDuration(code)
}
const mantBits = 4
const expMask = 0b111
exp := (code >> mantBits) & expMask
mant := code & ((1 << mantBits) - 1)
return DecisecondToDuration((mant | 0x10) << (exp + 3))
}
// GroupAddress returns the group address.
func (i IGMPv3Query) GroupAddress() tcpip.Address {
return tcpip.AddrFrom4([4]byte(i[igmpv3QueryGroupAddressOffset:][:IPv4AddressSize]))
}
// QuerierRobustnessVariable returns the querier's robustness variable.
func (i IGMPv3Query) QuerierRobustnessVariable() uint8 {
return i[igmpv3QueryResvSQRVOffset] & igmpv3QueryQRVMask
}
// QuerierQueryInterval returns the querier's query interval.
func (i IGMPv3Query) QuerierQueryInterval() time.Duration {
return mldv2AndIGMPv3QuerierQueryCodeToInterval(i[igmpv3QueryQQICOffset])
}
// Sources returns an iterator over source addresses in the query.
//
// Returns false if the message cannot hold the expected number of sources.
func (i IGMPv3Query) Sources() (AddressIterator, bool) {
return makeAddressIterator(
i[igmpv3QuerySourcesOffset:],
binary.BigEndian.Uint16(i[igmpv3QueryNumberOfSourcesOffset:]),
IPv4AddressSize,
)
}
// IGMPv3ReportRecordType is the type of an IGMPv3 multicast address record
// found in an IGMPv3 report, as per RFC 3810 section 5.2.12.
type IGMPv3ReportRecordType int
// IGMPv3 multicast address record types, as per RFC 3810 section 5.2.12.
const (
IGMPv3ReportRecordModeIsInclude IGMPv3ReportRecordType = 1
IGMPv3ReportRecordModeIsExclude IGMPv3ReportRecordType = 2
IGMPv3ReportRecordChangeToIncludeMode IGMPv3ReportRecordType = 3
IGMPv3ReportRecordChangeToExcludeMode IGMPv3ReportRecordType = 4
IGMPv3ReportRecordAllowNewSources IGMPv3ReportRecordType = 5
IGMPv3ReportRecordBlockOldSources IGMPv3ReportRecordType = 6
)
const (
igmpv3ReportGroupAddressRecordMinimumSize = 8
igmpv3ReportGroupAddressRecordTypeOffset = 0
igmpv3ReportGroupAddressRecordAuxDataLenOffset = 1
igmpv3ReportGroupAddressRecordAuxDataLenUnits = 4
igmpv3ReportGroupAddressRecordNumberOfSourcesOffset = 2
igmpv3ReportGroupAddressRecordGroupAddressOffset = 4
igmpv3ReportGroupAddressRecordSourcesOffset = 8
)
// IGMPv3ReportGroupAddressRecordSerializer is an IGMPv3 Multicast Address
// Record serializer.
//
// As per RFC 3810 section 5.2, a Multicast Address Record has the following
// internal format:
//
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Record Type | Aux Data Len | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Multicast Address *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Source Address [1] *
// | |
// * *
// | |
// +- -+
// | |
// * *
// | |
// * Source Address [2] *
// | |
// * *
// | |
// +- -+
// . . .
// . . .
// . . .
// +- -+
// | |
// * *
// | |
// * Source Address [N] *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Auxiliary Data .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type IGMPv3ReportGroupAddressRecordSerializer struct {
RecordType IGMPv3ReportRecordType
GroupAddress tcpip.Address
Sources []tcpip.Address
}
// Length returns the number of bytes this serializer would occupy.
func (s *IGMPv3ReportGroupAddressRecordSerializer) Length() int {
return igmpv3ReportGroupAddressRecordSourcesOffset + len(s.Sources)*IPv4AddressSize
}
func copyIPv4Address(dst []byte, src tcpip.Address) {
srcBytes := src.As4()
if n := copy(dst, srcBytes[:]); n != IPv4AddressSize {
panic(fmt.Sprintf("got copy(...) = %d, want = %d", n, IPv4AddressSize))
}
}
// SerializeInto serializes the record into the buffer.
//
// Panics if the buffer does not have enough space to fit the record.
func (s *IGMPv3ReportGroupAddressRecordSerializer) SerializeInto(b []byte) {
b[igmpv3ReportGroupAddressRecordTypeOffset] = byte(s.RecordType)
b[igmpv3ReportGroupAddressRecordAuxDataLenOffset] = 0
binary.BigEndian.PutUint16(b[igmpv3ReportGroupAddressRecordNumberOfSourcesOffset:], uint16(len(s.Sources)))
copyIPv4Address(b[igmpv3ReportGroupAddressRecordGroupAddressOffset:], s.GroupAddress)
b = b[igmpv3ReportGroupAddressRecordSourcesOffset:]
for _, source := range s.Sources {
copyIPv4Address(b, source)
b = b[IPv4AddressSize:]
}
}
const (
igmpv3ReportTypeOffset = 0
igmpv3ReportReserved1Offset = 1
igmpv3ReportReserved2Offset = 4
igmpv3ReportNumberOfGroupAddressRecordsOffset = 6
igmpv3ReportGroupAddressRecordsOffset = 8
)
// IGMPv3ReportSerializer is an MLD Version 2 Report serializer.
//
// As per RFC 3810 section 5.2,
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 143 | Reserved | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved |Nr of Mcast Address Records (M)|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [1] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [2] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | . |
// . . .
// | . |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [M] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type IGMPv3ReportSerializer struct {
Records []IGMPv3ReportGroupAddressRecordSerializer
}
// Length returns the number of bytes this serializer would occupy.
func (s *IGMPv3ReportSerializer) Length() int {
ret := igmpv3ReportGroupAddressRecordsOffset
for _, record := range s.Records {
ret += record.Length()
}
return ret
}
// SerializeInto serializes the report into the buffer.
//
// Panics if the buffer does not have enough space to fit the report.
func (s *IGMPv3ReportSerializer) SerializeInto(b []byte) {
b[igmpv3ReportTypeOffset] = byte(IGMPv3MembershipReport)
b[igmpv3ReportReserved1Offset] = 0
binary.BigEndian.PutUint16(b[igmpv3ReportReserved2Offset:], 0)
binary.BigEndian.PutUint16(b[igmpv3ReportNumberOfGroupAddressRecordsOffset:], uint16(len(s.Records)))
recordsBytes := b[igmpv3ReportGroupAddressRecordsOffset:]
for _, record := range s.Records {
len := record.Length()
record.SerializeInto(recordsBytes[:len])
recordsBytes = recordsBytes[len:]
}
binary.BigEndian.PutUint16(b[igmpChecksumOffset:], IGMPCalculateChecksum(b))
}
// IGMPv3ReportGroupAddressRecord is an IGMPv3 record.
//
// As per RFC 3810 section 5.2, a Multicast Address Record has the following
// internal format:
//
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Record Type | Aux Data Len | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Multicast Address *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Source Address [1] *
// | |
// * *
// | |
// +- -+
// | |
// * *
// | |
// * Source Address [2] *
// | |
// * *
// | |
// +- -+
// . . .
// . . .
// . . .
// +- -+
// | |
// * *
// | |
// * Source Address [N] *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Auxiliary Data .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type IGMPv3ReportGroupAddressRecord []byte
// RecordType returns the type of this record.
func (r IGMPv3ReportGroupAddressRecord) RecordType() IGMPv3ReportRecordType {
return IGMPv3ReportRecordType(r[igmpv3ReportGroupAddressRecordTypeOffset])
}
// AuxDataLen returns the length of the auxiliary data in this record.
func (r IGMPv3ReportGroupAddressRecord) AuxDataLen() int {
return int(r[igmpv3ReportGroupAddressRecordAuxDataLenOffset]) * igmpv3ReportGroupAddressRecordAuxDataLenUnits
}
// numberOfSources returns the number of sources in this record.
func (r IGMPv3ReportGroupAddressRecord) numberOfSources() uint16 {
return binary.BigEndian.Uint16(r[igmpv3ReportGroupAddressRecordNumberOfSourcesOffset:])
}
// GroupAddress returns the multicast address this record targets.
func (r IGMPv3ReportGroupAddressRecord) GroupAddress() tcpip.Address {
return tcpip.AddrFrom4([4]byte(r[igmpv3ReportGroupAddressRecordGroupAddressOffset:][:IPv4AddressSize]))
}
// Sources returns an iterator over source addresses in the query.
//
// Returns false if the message cannot hold the expected number of sources.
func (r IGMPv3ReportGroupAddressRecord) Sources() (AddressIterator, bool) {
expectedLen := int(r.numberOfSources()) * IPv4AddressSize
b := r[igmpv3ReportGroupAddressRecordSourcesOffset:]
if len(b) < expectedLen {
return AddressIterator{}, false
}
return AddressIterator{addressSize: IPv4AddressSize, buf: bytes.NewBuffer(b[:expectedLen])}, true
}
// IGMPv3Report is an IGMPv3 Report.
//
// As per RFC 3810 section 5.2,
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 143 | Reserved | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved |Nr of Mcast Address Records (M)|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [1] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [2] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | . |
// . . .
// | . |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [M] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type IGMPv3Report []byte
// Checksum returns the checksum.
func (i IGMPv3Report) Checksum() uint16 {
return binary.BigEndian.Uint16(i[igmpChecksumOffset:])
}
// IGMPv3ReportGroupAddressRecordIterator is an iterator over IGMPv3 Multicast
// Address Records.
type IGMPv3ReportGroupAddressRecordIterator struct {
recordsLeft uint16
buf *bytes.Buffer
}
// IGMPv3ReportGroupAddressRecordIteratorNextDisposition is the possible
// return values from IGMPv3ReportGroupAddressRecordIterator.Next.
type IGMPv3ReportGroupAddressRecordIteratorNextDisposition int
const (
// IGMPv3ReportGroupAddressRecordIteratorNextOk indicates that a multicast
// address record was yielded.
IGMPv3ReportGroupAddressRecordIteratorNextOk IGMPv3ReportGroupAddressRecordIteratorNextDisposition = iota
// IGMPv3ReportGroupAddressRecordIteratorNextDone indicates that the iterator
// has been exhausted.
IGMPv3ReportGroupAddressRecordIteratorNextDone
// IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort indicates
// that the iterator expected another record, but the buffer ended
// prematurely.
IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort
)
// Next returns the next IGMPv3 Multicast Address Record.
func (it *IGMPv3ReportGroupAddressRecordIterator) Next() (IGMPv3ReportGroupAddressRecord, IGMPv3ReportGroupAddressRecordIteratorNextDisposition) {
if it.recordsLeft == 0 {
return IGMPv3ReportGroupAddressRecord{}, IGMPv3ReportGroupAddressRecordIteratorNextDone
}
if it.buf.Len() < igmpv3ReportGroupAddressRecordMinimumSize {
return IGMPv3ReportGroupAddressRecord{}, IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort
}
hdr := IGMPv3ReportGroupAddressRecord(it.buf.Bytes())
expectedLen := igmpv3ReportGroupAddressRecordMinimumSize +
int(hdr.AuxDataLen()) + int(hdr.numberOfSources())*IPv4AddressSize
bytes := it.buf.Next(expectedLen)
if len(bytes) < expectedLen {
return IGMPv3ReportGroupAddressRecord{}, IGMPv3ReportGroupAddressRecordIteratorNextErrBufferTooShort
}
it.recordsLeft--
return IGMPv3ReportGroupAddressRecord(bytes), IGMPv3ReportGroupAddressRecordIteratorNextOk
}
// GroupAddressRecords returns an iterator of IGMPv3 Multicast Address
// Records.
func (i IGMPv3Report) GroupAddressRecords() IGMPv3ReportGroupAddressRecordIterator {
return IGMPv3ReportGroupAddressRecordIterator{
recordsLeft: binary.BigEndian.Uint16(i[igmpv3ReportNumberOfGroupAddressRecordsOffset:]),
buf: bytes.NewBuffer(i[igmpv3ReportGroupAddressRecordsOffset:]),
}
}

View File

@@ -0,0 +1,130 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
// MaxIPPacketSize is the maximum supported IP packet size, excluding
// jumbograms. The maximum IPv4 packet size is 64k-1 (total size must fit
// in 16 bits). For IPv6, the payload max size (excluding jumbograms) is
// 64k-1 (also needs to fit in 16 bits). So we use 64k - 1 + 2 * m, where
// m is the minimum IPv6 header size; we leave room for some potential
// IP options.
MaxIPPacketSize = 0xffff + 2*IPv6MinimumSize
)
// Transport offers generic methods to query and/or update the fields of the
// header of a transport protocol buffer.
type Transport interface {
// SourcePort returns the value of the "source port" field.
SourcePort() uint16
// Destination returns the value of the "destination port" field.
DestinationPort() uint16
// Checksum returns the value of the "checksum" field.
Checksum() uint16
// SetSourcePort sets the value of the "source port" field.
SetSourcePort(uint16)
// SetDestinationPort sets the value of the "destination port" field.
SetDestinationPort(uint16)
// SetChecksum sets the value of the "checksum" field.
SetChecksum(uint16)
// Payload returns the data carried in the transport buffer.
Payload() []byte
}
// ChecksummableTransport is a Transport that supports checksumming.
type ChecksummableTransport interface {
Transport
// SetSourcePortWithChecksumUpdate sets the source port and updates
// the checksum.
//
// The receiver's checksum must be a fully calculated checksum.
SetSourcePortWithChecksumUpdate(port uint16)
// SetDestinationPortWithChecksumUpdate sets the destination port and updates
// the checksum.
//
// The receiver's checksum must be a fully calculated checksum.
SetDestinationPortWithChecksumUpdate(port uint16)
// UpdateChecksumPseudoHeaderAddress updates the checksum to reflect an
// updated address in the pseudo header.
//
// If fullChecksum is true, the receiver's checksum field is assumed to hold a
// fully calculated checksum. Otherwise, it is assumed to hold a partially
// calculated checksum which only reflects the pseudo header.
UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullChecksum bool)
}
// Network offers generic methods to query and/or update the fields of the
// header of a network protocol buffer.
type Network interface {
// SourceAddress returns the value of the "source address" field.
SourceAddress() tcpip.Address
// DestinationAddress returns the value of the "destination address"
// field.
DestinationAddress() tcpip.Address
// Checksum returns the value of the "checksum" field.
Checksum() uint16
// SetSourceAddress sets the value of the "source address" field.
SetSourceAddress(tcpip.Address)
// SetDestinationAddress sets the value of the "destination address"
// field.
SetDestinationAddress(tcpip.Address)
// SetChecksum sets the value of the "checksum" field.
SetChecksum(uint16)
// TransportProtocol returns the number of the transport protocol
// stored in the payload.
TransportProtocol() tcpip.TransportProtocolNumber
// Payload returns a byte slice containing the payload of the network
// packet.
Payload() []byte
// TOS returns the values of the "type of service" and "flow label" fields.
TOS() (uint8, uint32)
// SetTOS sets the values of the "type of service" and "flow label" fields.
SetTOS(t uint8, l uint32)
}
// ChecksummableNetwork is a Network that supports checksumming.
type ChecksummableNetwork interface {
Network
// SetSourceAddressAndChecksum sets the source address and updates the
// checksum to reflect the new address.
SetSourceAddressWithChecksumUpdate(tcpip.Address)
// SetDestinationAddressAndChecksum sets the destination address and
// updates the checksum to reflect the new address.
SetDestinationAddressWithChecksumUpdate(tcpip.Address)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,597 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"crypto/sha256"
"encoding/binary"
"fmt"
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
versTCFL = 0
// IPv6PayloadLenOffset is the offset of the PayloadLength field in
// IPv6 header.
IPv6PayloadLenOffset = 4
// IPv6NextHeaderOffset is the offset of the NextHeader field in
// IPv6 header.
IPv6NextHeaderOffset = 6
hopLimit = 7
v6SrcAddr = 8
v6DstAddr = v6SrcAddr + IPv6AddressSize
// IPv6FixedHeaderSize is the size of the fixed header.
IPv6FixedHeaderSize = v6DstAddr + IPv6AddressSize
)
// IPv6Fields contains the fields of an IPv6 packet. It is used to describe the
// fields of a packet that needs to be encoded.
type IPv6Fields struct {
// TrafficClass is the "traffic class" field of an IPv6 packet.
TrafficClass uint8
// FlowLabel is the "flow label" field of an IPv6 packet.
FlowLabel uint32
// PayloadLength is the "payload length" field of an IPv6 packet, including
// the length of all extension headers.
PayloadLength uint16
// 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
// SrcAddr is the "source ip address" of an IPv6 packet.
SrcAddr tcpip.Address
// 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.
// Most of the methods of IPv6 access to the underlying slice without
// checking the boundaries and could panic because of 'index out of range'.
// Always call IsValid() to validate an instance of IPv6 before using other methods.
type IPv6 []byte
const (
// IPv6MinimumSize is the minimum size of a valid IPv6 packet.
IPv6MinimumSize = IPv6FixedHeaderSize
// IPv6AddressSize is the size, in bytes, of an IPv6 address.
IPv6AddressSize = 16
// IPv6AddressSizeBits is the size, in bits, of an IPv6 address.
IPv6AddressSizeBits = 128
// IPv6MaximumPayloadSize is the maximum size of a valid IPv6 payload per
// RFC 8200 Section 4.5.
IPv6MaximumPayloadSize = 65535
// IPv6ProtocolNumber is IPv6's network protocol number.
IPv6ProtocolNumber tcpip.NetworkProtocolNumber = 0x86dd
// IPv6Version is the version of the ipv6 protocol.
IPv6Version = 6
// IIDSize is the size of an interface identifier (IID), in bytes, as
// defined by RFC 4291 section 2.5.1.
IIDSize = 8
// IPv6MinimumMTU is the minimum MTU required by IPv6, per RFC 8200,
// section 5:
// IPv6 requires that every link in the Internet have an MTU of 1280 octets
// or greater. This is known as the IPv6 minimum link MTU.
IPv6MinimumMTU = 1280
// IIDOffsetInIPv6Address is the offset, in bytes, from the start
// of an IPv6 address to the beginning of the interface identifier
// (IID) for auto-generated addresses. That is, all bytes before
// the IIDOffsetInIPv6Address-th byte are the prefix bytes, and all
// bytes including and after the IIDOffsetInIPv6Address-th byte are
// for the IID.
IIDOffsetInIPv6Address = 8
// OpaqueIIDSecretKeyMinBytes is the recommended minimum number of bytes
// for the secret key used to generate an opaque interface identifier as
// outlined by RFC 7217.
OpaqueIIDSecretKeyMinBytes = 16
// ipv6MulticastAddressScopeByteIdx is the byte where the scope (scop) field
// is located within a multicast IPv6 address, as per RFC 4291 section 2.7.
ipv6MulticastAddressScopeByteIdx = 1
// ipv6MulticastAddressScopeMask is the mask for the scope (scop) field,
// within the byte holding the field, as per RFC 4291 section 2.7.
ipv6MulticastAddressScopeMask = 0xF
)
var (
// IPv6AllNodesMulticastAddress is a link-local multicast group that
// all IPv6 nodes MUST join, as per RFC 4291, section 2.8. Packets
// destined to this address will reach all nodes on a link.
//
// The address is ff02::1.
IPv6AllNodesMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
// IPv6AllRoutersInterfaceLocalMulticastAddress is an interface-local
// multicast group that all IPv6 routers MUST join, as per RFC 4291, section
// 2.8. Packets destined to this address will reach the router on an
// interface.
//
// The address is ff01::2.
IPv6AllRoutersInterfaceLocalMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})
// IPv6AllRoutersLinkLocalMulticastAddress is a link-local multicast group
// that all IPv6 routers MUST join, as per RFC 4291, section 2.8. Packets
// destined to this address will reach all routers on a link.
//
// The address is ff02::2.
IPv6AllRoutersLinkLocalMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})
// IPv6AllRoutersSiteLocalMulticastAddress is a site-local multicast group
// that all IPv6 routers MUST join, as per RFC 4291, section 2.8. Packets
// destined to this address will reach all routers in a site.
//
// The address is ff05::2.
IPv6AllRoutersSiteLocalMulticastAddress = tcpip.AddrFrom16([16]byte{0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02})
// IPv6Loopback is the IPv6 Loopback address.
IPv6Loopback = tcpip.AddrFrom16([16]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
// IPv6Any is the non-routable IPv6 "any" meta address. It is also
// known as the unspecified address.
IPv6Any = tcpip.AddrFrom16([16]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
)
// IPv6EmptySubnet is the empty IPv6 subnet. It may also be known as the
// catch-all or wildcard subnet. That is, all IPv6 addresses are considered to
// be contained within this subnet.
var IPv6EmptySubnet = tcpip.AddressWithPrefix{
Address: IPv6Any,
PrefixLen: 0,
}.Subnet()
// IPv4MappedIPv6Subnet is the prefix for an IPv4 mapped IPv6 address as defined
// by RFC 4291 section 2.5.5.
var IPv4MappedIPv6Subnet = tcpip.AddressWithPrefix{
Address: tcpip.AddrFrom16([16]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}),
PrefixLen: 96,
}.Subnet()
// IPv6LinkLocalPrefix is the prefix for IPv6 link-local addresses, as defined
// by RFC 4291 section 2.5.6.
//
// The prefix is fe80::/64
var IPv6LinkLocalPrefix = tcpip.AddressWithPrefix{
Address: tcpip.AddrFrom16([16]byte{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
PrefixLen: 64,
}
// PayloadLength returns the value of the "payload length" field of the ipv6
// header.
func (b IPv6) PayloadLength() uint16 {
return binary.BigEndian.Uint16(b[IPv6PayloadLenOffset:])
}
// HopLimit returns the value of the "Hop Limit" field of the ipv6 header.
func (b IPv6) HopLimit() uint8 {
return b[hopLimit]
}
// NextHeader returns the value of the "next header" field of the ipv6 header.
func (b IPv6) NextHeader() uint8 {
return b[IPv6NextHeaderOffset]
}
// TransportProtocol implements Network.TransportProtocol.
func (b IPv6) TransportProtocol() tcpip.TransportProtocolNumber {
return tcpip.TransportProtocolNumber(b.NextHeader())
}
// Payload implements Network.Payload.
func (b IPv6) Payload() []byte {
return b[IPv6MinimumSize:][:b.PayloadLength()]
}
// SourceAddress returns the "source address" field of the ipv6 header.
func (b IPv6) SourceAddress() tcpip.Address {
return tcpip.AddrFrom16([16]byte(b[v6SrcAddr:][:IPv6AddressSize]))
}
// DestinationAddress returns the "destination address" field of the ipv6
// header.
func (b IPv6) DestinationAddress() tcpip.Address {
return tcpip.AddrFrom16([16]byte(b[v6DstAddr:][:IPv6AddressSize]))
}
// SourceAddressSlice returns the "source address" field of the ipv6 header as a
// byte slice.
func (b IPv6) SourceAddressSlice() []byte {
return []byte(b[v6SrcAddr:][:IPv6AddressSize])
}
// DestinationAddressSlice returns the "destination address" field of the ipv6
// header as a byte slice.
func (b IPv6) DestinationAddressSlice() []byte {
return []byte(b[v6DstAddr:][:IPv6AddressSize])
}
// Checksum implements Network.Checksum. Given that IPv6 doesn't have a
// checksum, it just returns 0.
func (IPv6) Checksum() uint16 {
return 0
}
// TOS returns the "traffic class" and "flow label" fields of the ipv6 header.
func (b IPv6) TOS() (uint8, uint32) {
v := binary.BigEndian.Uint32(b[versTCFL:])
return uint8(v >> 20), v & 0xfffff
}
// SetTOS sets the "traffic class" and "flow label" fields of the ipv6 header.
func (b IPv6) SetTOS(t uint8, l uint32) {
vtf := (6 << 28) | (uint32(t) << 20) | (l & 0xfffff)
binary.BigEndian.PutUint32(b[versTCFL:], vtf)
}
// SetPayloadLength sets the "payload length" field of the ipv6 header.
func (b IPv6) SetPayloadLength(payloadLength uint16) {
binary.BigEndian.PutUint16(b[IPv6PayloadLenOffset:], payloadLength)
}
// SetSourceAddress sets the "source address" field of the ipv6 header.
func (b IPv6) SetSourceAddress(addr tcpip.Address) {
copy(b[v6SrcAddr:][:IPv6AddressSize], addr.AsSlice())
}
// SetDestinationAddress sets the "destination address" field of the ipv6
// header.
func (b IPv6) SetDestinationAddress(addr tcpip.Address) {
copy(b[v6DstAddr:][:IPv6AddressSize], addr.AsSlice())
}
// SetHopLimit sets the value of the "Hop Limit" field.
func (b IPv6) SetHopLimit(v uint8) {
b[hopLimit] = v
}
// SetNextHeader sets the value of the "next header" field of the ipv6 header.
func (b IPv6) SetNextHeader(v uint8) {
b[IPv6NextHeaderOffset] = v
}
// SetChecksum implements Network.SetChecksum. Given that IPv6 doesn't have a
// checksum, it is empty.
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[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.
func (b IPv6) IsValid(pktSize int) bool {
if len(b) < IPv6MinimumSize {
return false
}
dlen := int(b.PayloadLength())
if dlen > pktSize-IPv6MinimumSize {
return false
}
if IPVersion(b) != IPv6Version {
return false
}
return true
}
// IsV4MappedAddress determines if the provided address is an IPv4 mapped
// address by checking if its prefix is 0:0:0:0:0:ffff::/96.
func IsV4MappedAddress(addr tcpip.Address) bool {
if addr.BitLen() != IPv6AddressSizeBits {
return false
}
return IPv4MappedIPv6Subnet.Contains(addr)
}
// IsV6MulticastAddress determines if the provided address is an IPv6
// multicast address (anything starting with FF).
func IsV6MulticastAddress(addr tcpip.Address) bool {
if addr.BitLen() != IPv6AddressSizeBits {
return false
}
return addr.As16()[0] == 0xff
}
// IsV6UnicastAddress determines if the provided address is a valid IPv6
// unicast (and specified) address. That is, IsV6UnicastAddress returns
// true if addr contains IPv6AddressSize bytes, is not the unspecified
// address and is not a multicast address.
func IsV6UnicastAddress(addr tcpip.Address) bool {
if addr.BitLen() != IPv6AddressSizeBits {
return false
}
// Must not be unspecified
if addr == IPv6Any {
return false
}
// Return if not a multicast.
return addr.As16()[0] != 0xff
}
var solicitedNodeMulticastPrefix = [13]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff}
// SolicitedNodeAddr computes the solicited-node multicast address. This is
// used for NDP. Described in RFC 4291. The argument must be a full-length IPv6
// address.
func SolicitedNodeAddr(addr tcpip.Address) tcpip.Address {
addrBytes := addr.As16()
return tcpip.AddrFrom16([16]byte(append(solicitedNodeMulticastPrefix[:], addrBytes[len(addrBytes)-3:]...)))
}
// IsSolicitedNodeAddr determines whether the address is a solicited-node
// multicast address.
func IsSolicitedNodeAddr(addr tcpip.Address) bool {
addrBytes := addr.As16()
return solicitedNodeMulticastPrefix == [13]byte(addrBytes[:len(addrBytes)-3])
}
// EthernetAdddressToModifiedEUI64IntoBuf populates buf with a modified EUI-64
// from a 48-bit Ethernet/MAC address, as per RFC 4291 section 2.5.1.
//
// buf MUST be at least 8 bytes.
func EthernetAdddressToModifiedEUI64IntoBuf(linkAddr tcpip.LinkAddress, buf []byte) {
buf[0] = linkAddr[0] ^ 2
buf[1] = linkAddr[1]
buf[2] = linkAddr[2]
buf[3] = 0xFF
buf[4] = 0xFE
buf[5] = linkAddr[3]
buf[6] = linkAddr[4]
buf[7] = linkAddr[5]
}
// EthernetAddressToModifiedEUI64 computes a modified EUI-64 from a 48-bit
// Ethernet/MAC address, as per RFC 4291 section 2.5.1.
func EthernetAddressToModifiedEUI64(linkAddr tcpip.LinkAddress) [IIDSize]byte {
var buf [IIDSize]byte
EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, buf[:])
return buf
}
// LinkLocalAddr computes the default IPv6 link-local address from a link-layer
// (MAC) address.
func LinkLocalAddr(linkAddr tcpip.LinkAddress) tcpip.Address {
// Convert a 48-bit MAC to a modified EUI-64 and then prepend the
// link-local header, FE80::.
//
// The conversion is very nearly:
// aa:bb:cc:dd:ee:ff => FE80::Aabb:ccFF:FEdd:eeff
// Note the capital A. The conversion aa->Aa involves a bit flip.
lladdrb := [IPv6AddressSize]byte{
0: 0xFE,
1: 0x80,
}
EthernetAdddressToModifiedEUI64IntoBuf(linkAddr, lladdrb[IIDOffsetInIPv6Address:])
return tcpip.AddrFrom16(lladdrb)
}
// IsV6LinkLocalUnicastAddress returns true iff the provided address is an IPv6
// link-local unicast address, as defined by RFC 4291 section 2.5.6.
func IsV6LinkLocalUnicastAddress(addr tcpip.Address) bool {
if addr.BitLen() != IPv6AddressSizeBits {
return false
}
addrBytes := addr.As16()
return addrBytes[0] == 0xfe && (addrBytes[1]&0xc0) == 0x80
}
// IsV6LoopbackAddress returns true iff the provided address is an IPv6 loopback
// address, as defined by RFC 4291 section 2.5.3.
func IsV6LoopbackAddress(addr tcpip.Address) bool {
return addr == IPv6Loopback
}
// IsV6LinkLocalMulticastAddress returns true iff the provided address is an
// IPv6 link-local multicast address, as defined by RFC 4291 section 2.7.
func IsV6LinkLocalMulticastAddress(addr tcpip.Address) bool {
return IsV6MulticastAddress(addr) && V6MulticastScope(addr) == IPv6LinkLocalMulticastScope
}
// AppendOpaqueInterfaceIdentifier appends a 64 bit opaque interface identifier
// (IID) to buf as outlined by RFC 7217 and returns the extended buffer.
//
// The opaque IID is generated from the cryptographic hash of the concatenation
// of the prefix, NIC's name, DAD counter (DAD retry counter) and the secret
// key. The secret key SHOULD be at least OpaqueIIDSecretKeyMinBytes bytes and
// MUST be generated to a pseudo-random number. See RFC 4086 for randomness
// requirements for security.
//
// If buf has enough capacity for the IID (IIDSize bytes), a new underlying
// array for the buffer will not be allocated.
func AppendOpaqueInterfaceIdentifier(buf []byte, prefix tcpip.Subnet, nicName string, dadCounter uint8, secretKey []byte) []byte {
// As per RFC 7217 section 5, the opaque identifier can be generated as a
// cryptographic hash of the concatenation of each of the function parameters.
// Note, we omit the optional Network_ID field.
h := sha256.New()
// h.Write never returns an error.
prefixID := prefix.ID()
h.Write([]byte(prefixID.AsSlice()[:IIDOffsetInIPv6Address]))
h.Write([]byte(nicName))
h.Write([]byte{dadCounter})
h.Write(secretKey)
var sumBuf [sha256.Size]byte
sum := h.Sum(sumBuf[:0])
return append(buf, sum[:IIDSize]...)
}
// LinkLocalAddrWithOpaqueIID computes the default IPv6 link-local address with
// an opaque IID.
func LinkLocalAddrWithOpaqueIID(nicName string, dadCounter uint8, secretKey []byte) tcpip.Address {
lladdrb := [IPv6AddressSize]byte{
0: 0xFE,
1: 0x80,
}
return tcpip.AddrFrom16([16]byte(AppendOpaqueInterfaceIdentifier(lladdrb[:IIDOffsetInIPv6Address], IPv6LinkLocalPrefix.Subnet(), nicName, dadCounter, secretKey)))
}
// IPv6AddressScope is the scope of an IPv6 address.
type IPv6AddressScope int
const (
// LinkLocalScope indicates a link-local address.
LinkLocalScope IPv6AddressScope = iota
// GlobalScope indicates a global address.
GlobalScope
)
// ScopeForIPv6Address returns the scope for an IPv6 address.
func ScopeForIPv6Address(addr tcpip.Address) (IPv6AddressScope, tcpip.Error) {
if addr.BitLen() != IPv6AddressSizeBits {
return GlobalScope, &tcpip.ErrBadAddress{}
}
switch {
case IsV6LinkLocalMulticastAddress(addr):
return LinkLocalScope, nil
case IsV6LinkLocalUnicastAddress(addr):
return LinkLocalScope, nil
default:
return GlobalScope, nil
}
}
// InitialTempIID generates the initial temporary IID history value to generate
// temporary SLAAC addresses with.
//
// Panics if initialTempIIDHistory is not at least IIDSize bytes.
func InitialTempIID(initialTempIIDHistory []byte, seed []byte, nicID tcpip.NICID) {
h := sha256.New()
// h.Write never returns an error.
h.Write(seed)
var nicIDBuf [4]byte
binary.BigEndian.PutUint32(nicIDBuf[:], uint32(nicID))
h.Write(nicIDBuf[:])
var sumBuf [sha256.Size]byte
sum := h.Sum(sumBuf[:0])
if n := copy(initialTempIIDHistory, sum[sha256.Size-IIDSize:]); n != IIDSize {
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IIDSize))
}
}
// GenerateTempIPv6SLAACAddr generates a temporary SLAAC IPv6 address for an
// associated stable/permanent SLAAC address.
//
// GenerateTempIPv6SLAACAddr will update the temporary IID history value to be
// used when generating a new temporary IID.
//
// Panics if tempIIDHistory is not at least IIDSize bytes.
func GenerateTempIPv6SLAACAddr(tempIIDHistory []byte, stableAddr tcpip.Address) tcpip.AddressWithPrefix {
addrBytes := stableAddr.As16()
h := sha256.New()
h.Write(tempIIDHistory)
h.Write(addrBytes[IIDOffsetInIPv6Address:])
var sumBuf [sha256.Size]byte
sum := h.Sum(sumBuf[:0])
// The rightmost 64 bits of sum are saved for the next iteration.
if n := copy(tempIIDHistory, sum[sha256.Size-IIDSize:]); n != IIDSize {
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, IIDSize))
}
// The leftmost 64 bits of sum is used as the IID.
if n := copy(addrBytes[IIDOffsetInIPv6Address:], sum); n != IIDSize {
panic(fmt.Sprintf("copied %d IID bytes, expected %d bytes", n, IIDSize))
}
return tcpip.AddressWithPrefix{
Address: tcpip.AddrFrom16(addrBytes),
PrefixLen: IIDOffsetInIPv6Address * 8,
}
}
// IPv6MulticastScope is the scope of a multicast IPv6 address, as defined by
// RFC 7346 section 2.
type IPv6MulticastScope uint8
// The various values for IPv6 multicast scopes, as per RFC 7346 section 2:
//
// +------+--------------------------+-------------------------+
// | scop | NAME | REFERENCE |
// +------+--------------------------+-------------------------+
// | 0 | Reserved | [RFC4291], RFC 7346 |
// | 1 | Interface-Local scope | [RFC4291], RFC 7346 |
// | 2 | Link-Local scope | [RFC4291], RFC 7346 |
// | 3 | Realm-Local scope | [RFC4291], RFC 7346 |
// | 4 | Admin-Local scope | [RFC4291], RFC 7346 |
// | 5 | Site-Local scope | [RFC4291], RFC 7346 |
// | 6 | Unassigned | |
// | 7 | Unassigned | |
// | 8 | Organization-Local scope | [RFC4291], RFC 7346 |
// | 9 | Unassigned | |
// | A | Unassigned | |
// | B | Unassigned | |
// | C | Unassigned | |
// | D | Unassigned | |
// | E | Global scope | [RFC4291], RFC 7346 |
// | F | Reserved | [RFC4291], RFC 7346 |
// +------+--------------------------+-------------------------+
const (
IPv6Reserved0MulticastScope = IPv6MulticastScope(0x0)
IPv6InterfaceLocalMulticastScope = IPv6MulticastScope(0x1)
IPv6LinkLocalMulticastScope = IPv6MulticastScope(0x2)
IPv6RealmLocalMulticastScope = IPv6MulticastScope(0x3)
IPv6AdminLocalMulticastScope = IPv6MulticastScope(0x4)
IPv6SiteLocalMulticastScope = IPv6MulticastScope(0x5)
IPv6OrganizationLocalMulticastScope = IPv6MulticastScope(0x8)
IPv6GlobalMulticastScope = IPv6MulticastScope(0xE)
IPv6ReservedFMulticastScope = IPv6MulticastScope(0xF)
)
// V6MulticastScope returns the scope of a multicast address.
func V6MulticastScope(addr tcpip.Address) IPv6MulticastScope {
addrBytes := addr.As16()
return IPv6MulticastScope(addrBytes[ipv6MulticastAddressScopeByteIdx] & ipv6MulticastAddressScopeMask)
}

View File

@@ -0,0 +1,955 @@
// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"errors"
"fmt"
"io"
"math"
"gvisor.dev/gvisor/pkg/buffer"
"gvisor.dev/gvisor/pkg/tcpip"
)
// IPv6ExtensionHeaderIdentifier is an IPv6 extension header identifier.
type IPv6ExtensionHeaderIdentifier uint8
const (
// IPv6HopByHopOptionsExtHdrIdentifier is the header identifier of a Hop by
// Hop Options extension header, as per RFC 8200 section 4.3.
IPv6HopByHopOptionsExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 0
// IPv6RoutingExtHdrIdentifier is the header identifier of a Routing extension
// header, as per RFC 8200 section 4.4.
IPv6RoutingExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 43
// IPv6FragmentExtHdrIdentifier is the header identifier of a Fragment
// extension header, as per RFC 8200 section 4.5.
IPv6FragmentExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 44
// IPv6DestinationOptionsExtHdrIdentifier is the header identifier of a
// Destination Options extension header, as per RFC 8200 section 4.6.
IPv6DestinationOptionsExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 60
// IPv6NoNextHeaderIdentifier is the header identifier used to signify the end
// of an IPv6 payload, as per RFC 8200 section 4.7.
IPv6NoNextHeaderIdentifier IPv6ExtensionHeaderIdentifier = 59
// IPv6UnknownExtHdrIdentifier is reserved by IANA.
// https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml#extension-header
// "254 Use for experimentation and testing [RFC3692][RFC4727]"
IPv6UnknownExtHdrIdentifier IPv6ExtensionHeaderIdentifier = 254
)
const (
// ipv6UnknownExtHdrOptionActionMask is the mask of the action to take when
// a node encounters an unrecognized option.
ipv6UnknownExtHdrOptionActionMask = 192
// ipv6UnknownExtHdrOptionActionShift is the least significant bits to discard
// from the action value for an unrecognized option identifier.
ipv6UnknownExtHdrOptionActionShift = 6
// ipv6RoutingExtHdrSegmentsLeftIdx is the index to the Segments Left field
// within an IPv6RoutingExtHdr.
ipv6RoutingExtHdrSegmentsLeftIdx = 1
// IPv6FragmentExtHdrLength is the length of an IPv6 extension header, in
// bytes.
IPv6FragmentExtHdrLength = 8
// ipv6FragmentExtHdrFragmentOffsetOffset is the offset to the start of the
// Fragment Offset field within an IPv6FragmentExtHdr.
ipv6FragmentExtHdrFragmentOffsetOffset = 0
// 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
// IPv6FragmentExtHdr.
ipv6FragmentExtHdrFlagsIdx = 1
// ipv6FragmentExtHdrMFlagMask is the mask of the More (M) flag within the
// flags field of an IPv6FragmentExtHdr.
ipv6FragmentExtHdrMFlagMask = 1
// ipv6FragmentExtHdrIdentificationOffset is the offset to the Identification
// field within an IPv6FragmentExtHdr.
ipv6FragmentExtHdrIdentificationOffset = 2
// ipv6ExtHdrLenBytesPerUnit is the unit size of an extension header's length
// field. That is, given a Length field of 2, the extension header expects
// 16 bytes following the first 8 bytes (see ipv6ExtHdrLenBytesExcluded for
// details about the first 8 bytes' exclusion from the Length field).
ipv6ExtHdrLenBytesPerUnit = 8
// ipv6ExtHdrLenBytesExcluded is the number of bytes excluded from an
// extension header's Length field following the Length field.
//
// The Length field excludes the first 8 bytes, but the Next Header and Length
// field take up the first 2 of the 8 bytes so we expect (at minimum) 6 bytes
// after the Length field.
//
// This ensures that every extension header is at least 8 bytes.
ipv6ExtHdrLenBytesExcluded = 6
// IPv6FragmentExtHdrFragmentOffsetBytesPerUnit is the unit size of a Fragment
// extension header's Fragment Offset field. That is, given a Fragment Offset
// of 2, the extension header is indicating that the fragment's payload
// starts at the 16th byte in the reassembled packet.
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:]
clear(s)
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.
//
// These headers include IPv6 extension headers or upper layer data.
type IPv6PayloadHeader interface {
isIPv6PayloadHeader()
// Release frees all resources held by the header.
Release()
}
// IPv6RawPayloadHeader the remainder of an IPv6 payload after an iterator
// encounters a Next Header field it does not recognize as an IPv6 extension
// header. The caller is responsible for releasing the underlying buffer after
// it's no longer needed.
type IPv6RawPayloadHeader struct {
Identifier IPv6ExtensionHeaderIdentifier
Buf buffer.Buffer
}
// isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader.
func (IPv6RawPayloadHeader) isIPv6PayloadHeader() {}
// Release implements IPv6PayloadHeader.Release.
func (i IPv6RawPayloadHeader) Release() {
i.Buf.Release()
}
// ipv6OptionsExtHdr is an IPv6 extension header that holds options.
type ipv6OptionsExtHdr struct {
buf *buffer.View
}
// Release implements IPv6PayloadHeader.Release.
func (i ipv6OptionsExtHdr) Release() {
if i.buf != nil {
i.buf.Release()
}
}
// Iter returns an iterator over the IPv6 extension header options held in b.
func (i ipv6OptionsExtHdr) Iter() IPv6OptionsExtHdrOptionsIterator {
it := IPv6OptionsExtHdrOptionsIterator{}
it.reader = i.buf
return it
}
// IPv6OptionsExtHdrOptionsIterator is an iterator over IPv6 extension header
// options.
//
// Note, between when an IPv6OptionsExtHdrOptionsIterator is obtained and last
// used, no changes to the underlying buffer may happen. Doing so may cause
// undefined and unexpected behaviour. It is fine to obtain an
// IPv6OptionsExtHdrOptionsIterator, iterate over the first few options then
// modify the backing payload so long as the IPv6OptionsExtHdrOptionsIterator
// obtained before modification is no longer used.
type IPv6OptionsExtHdrOptionsIterator struct {
reader *buffer.View
// optionOffset is the number of bytes from the first byte of the
// options field to the beginning of the current option.
optionOffset uint32
// nextOptionOffset is the offset of the next option.
nextOptionOffset uint32
}
// OptionOffset returns the number of bytes parsed while processing the
// option field of the current Extension Header.
func (i *IPv6OptionsExtHdrOptionsIterator) OptionOffset() uint32 {
return i.optionOffset
}
// IPv6OptionUnknownAction is the action that must be taken if the processing
// IPv6 node does not recognize the option, as outlined in RFC 8200 section 4.2.
type IPv6OptionUnknownAction int
const (
// IPv6OptionUnknownActionSkip indicates that the unrecognized option must
// be skipped and the node should continue processing the header.
IPv6OptionUnknownActionSkip IPv6OptionUnknownAction = 0
// IPv6OptionUnknownActionDiscard indicates that the packet must be silently
// discarded.
IPv6OptionUnknownActionDiscard IPv6OptionUnknownAction = 1
// IPv6OptionUnknownActionDiscardSendICMP indicates that the packet must be
// discarded and the node must send an ICMP Parameter Problem, Code 2, message
// to the packet's source, regardless of whether or not the packet's
// Destination was a multicast address.
IPv6OptionUnknownActionDiscardSendICMP IPv6OptionUnknownAction = 2
// IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest indicates that the
// packet must be discarded and the node must send an ICMP Parameter Problem,
// Code 2, message to the packet's source only if the packet's Destination was
// not a multicast address.
IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest IPv6OptionUnknownAction = 3
)
// IPv6ExtHdrOption is implemented by the various IPv6 extension header options.
type IPv6ExtHdrOption interface {
// UnknownAction returns the action to take in response to an unrecognized
// option.
UnknownAction() IPv6OptionUnknownAction
// isIPv6ExtHdrOption is used to "lock" this interface so it is not
// implemented by other packages.
isIPv6ExtHdrOption()
}
// 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 IPv6ExtHdrOptionIdentifier = 0
// ipv6PadNExtHdrOptionIdentifier is the identifier for a padding option that
// provides variable length byte padding, as outlined in RFC 8200 section 4.2.
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)
}
// ErrMalformedIPv6ExtHdrOption indicates that an IPv6 extension header option
// is malformed.
var ErrMalformedIPv6ExtHdrOption = errors.New("malformed IPv6 extension header option")
// IPv6UnknownExtHdrOption holds the identifier and data for an IPv6 extension
// header option that is unknown by the parsing utilities.
type IPv6UnknownExtHdrOption struct {
Identifier IPv6ExtHdrOptionIdentifier
Data *buffer.View
}
// UnknownAction implements IPv6OptionUnknownAction.UnknownAction.
func (o *IPv6UnknownExtHdrOption) UnknownAction() IPv6OptionUnknownAction {
return ipv6UnknownActionFromIdentifier(o.Identifier)
}
// isIPv6ExtHdrOption implements IPv6ExtHdrOption.isIPv6ExtHdrOption.
func (*IPv6UnknownExtHdrOption) isIPv6ExtHdrOption() {}
// Next returns the next option in the options data.
//
// If the next item is not a known extension header option,
// IPv6UnknownExtHdrOption will be returned with the option identifier and data.
//
// The return is of the format (option, done, error). done will be true when
// Next is unable to return anything because the iterator has reached the end of
// the options data, or an error occurred.
func (i *IPv6OptionsExtHdrOptionsIterator) Next() (IPv6ExtHdrOption, bool, error) {
for {
i.optionOffset = i.nextOptionOffset
temp, err := i.reader.ReadByte()
if err != nil {
// If we can't read the first byte of a new option, then we know the
// options buffer has been exhausted and we are done iterating.
return nil, true, nil
}
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
// the Pad1 option and continue processing the buffer as a new option.
if id == ipv6Pad1ExtHdrOptionIdentifier {
i.nextOptionOffset = i.optionOffset + 1
continue
}
length, err := i.reader.ReadByte()
if err != nil {
if err != io.EOF {
// ReadByte should only ever return nil or io.EOF.
panic(fmt.Sprintf("unexpected error when reading the option's Length field for option with id = %d: %s", id, err))
}
// We use io.ErrUnexpectedEOF as exhausting the buffer is unexpected once
// we start parsing an option; we expect the reader to contain enough
// bytes for the whole option.
return nil, true, fmt.Errorf("error when reading the option's Length field for option with id = %d: %w", id, io.ErrUnexpectedEOF)
}
// Do we have enough bytes in the reader for the next option?
if n := i.reader.Size(); n < int(length) {
// Consume the remaining buffer.
i.reader.TrimFront(i.reader.Size())
// We return the same error as if we failed to read a non-padding option
// so consumers of this iterator don't need to differentiate between
// padding and non-padding options.
return nil, true, fmt.Errorf("read %d out of %d option data bytes for option with id = %d: %w", n, length, id, io.ErrUnexpectedEOF)
}
i.nextOptionOffset = i.optionOffset + uint32(length) + 1 /* option ID */ + 1 /* length byte */
switch id {
case ipv6PadNExtHdrOptionIdentifier:
// Special-case the variable length padding option to avoid a copy.
i.reader.TrimFront(int(length))
continue
case ipv6RouterAlertHopByHopOptionIdentifier:
var routerAlertValue [ipv6RouterAlertPayloadLength]byte
if n, err := io.ReadFull(i.reader, routerAlertValue[:]); err != nil {
switch err {
case io.EOF, io.ErrUnexpectedEOF:
return nil, true, fmt.Errorf("got invalid length (%d) for router alert option (want = %d): %w", length, ipv6RouterAlertPayloadLength, ErrMalformedIPv6ExtHdrOption)
default:
return nil, true, fmt.Errorf("read %d out of %d option data bytes for router alert option: %w", n, ipv6RouterAlertPayloadLength, err)
}
} else if n != int(length) {
return nil, true, fmt.Errorf("got invalid length (%d) for router alert option (want = %d): %w", length, ipv6RouterAlertPayloadLength, ErrMalformedIPv6ExtHdrOption)
}
return &IPv6RouterAlertOption{Value: IPv6RouterAlertValue(binary.BigEndian.Uint16(routerAlertValue[:]))}, false, nil
default:
bytes := buffer.NewView(int(length))
if n, err := io.CopyN(bytes, i.reader, int64(length)); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, true, fmt.Errorf("read %d out of %d option data bytes for option with id = %d: %w", n, length, id, err)
}
return &IPv6UnknownExtHdrOption{Identifier: id, Data: bytes}, false, nil
}
}
}
// IPv6HopByHopOptionsExtHdr is a buffer holding the Hop By Hop Options
// extension header.
type IPv6HopByHopOptionsExtHdr struct {
ipv6OptionsExtHdr
}
// isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader.
func (IPv6HopByHopOptionsExtHdr) isIPv6PayloadHeader() {}
// IPv6DestinationOptionsExtHdr is a buffer holding the Destination Options
// extension header.
type IPv6DestinationOptionsExtHdr struct {
ipv6OptionsExtHdr
}
// isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader.
func (IPv6DestinationOptionsExtHdr) isIPv6PayloadHeader() {}
// IPv6RoutingExtHdr is a buffer holding the Routing extension header specific
// data as outlined in RFC 8200 section 4.4.
type IPv6RoutingExtHdr struct {
Buf *buffer.View
}
// isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader.
func (IPv6RoutingExtHdr) isIPv6PayloadHeader() {}
// Release implements IPv6PayloadHeader.Release.
func (b IPv6RoutingExtHdr) Release() {
b.Buf.Release()
}
// SegmentsLeft returns the Segments Left field.
func (b IPv6RoutingExtHdr) SegmentsLeft() uint8 {
return b.Buf.AsSlice()[ipv6RoutingExtHdrSegmentsLeftIdx]
}
// IPv6FragmentExtHdr is a buffer holding the Fragment extension header specific
// data as outlined in RFC 8200 section 4.5.
//
// Note, the buffer does not include the Next Header and Reserved fields.
type IPv6FragmentExtHdr [6]byte
// isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader.
func (IPv6FragmentExtHdr) isIPv6PayloadHeader() {}
// Release implements IPv6PayloadHeader.Release.
func (IPv6FragmentExtHdr) Release() {}
// FragmentOffset returns the Fragment Offset field.
//
// This value indicates where the buffer following the Fragment extension header
// starts in the target (reassembled) packet.
func (b IPv6FragmentExtHdr) FragmentOffset() uint16 {
return binary.BigEndian.Uint16(b[ipv6FragmentExtHdrFragmentOffsetOffset:]) >> ipv6FragmentExtHdrFragmentOffsetShift
}
// More returns the More (M) flag.
//
// This indicates whether any fragments are expected to succeed b.
func (b IPv6FragmentExtHdr) More() bool {
return b[ipv6FragmentExtHdrFlagsIdx]&ipv6FragmentExtHdrMFlagMask != 0
}
// ID returns the Identification field.
//
// This value is used to uniquely identify the packet, between a
// source and destination.
func (b IPv6FragmentExtHdr) ID() uint32 {
return binary.BigEndian.Uint32(b[ipv6FragmentExtHdrIdentificationOffset:])
}
// IsAtomic returns whether the fragment header indicates an atomic fragment. An
// atomic fragment is a fragment that contains all the data required to
// reassemble a full packet.
func (b IPv6FragmentExtHdr) IsAtomic() bool {
return !b.More() && b.FragmentOffset() == 0
}
// IPv6PayloadIterator is an iterator over the contents of an IPv6 payload.
//
// The IPv6 payload may contain IPv6 extension headers before any upper layer
// data.
//
// Note, between when an IPv6PayloadIterator is obtained and last used, no
// changes to the payload may happen. Doing so may cause undefined and
// unexpected behaviour. It is fine to obtain an IPv6PayloadIterator, iterate
// over the first few headers then modify the backing payload so long as the
// IPv6PayloadIterator obtained before modification is no longer used.
type IPv6PayloadIterator struct {
// The identifier of the next header to parse.
nextHdrIdentifier IPv6ExtensionHeaderIdentifier
payload buffer.Buffer
// Indicates to the iterator that it should return the remaining payload as a
// raw payload on the next call to Next.
forceRaw bool
// headerOffset is the offset of the beginning of the current extension
// header starting from the beginning of the fixed header.
headerOffset uint32
// parseOffset is the byte offset into the current extension header of the
// field we are currently examining. It can be added to the header offset
// if the absolute offset within the packet is required.
parseOffset uint32
// nextOffset is the offset of the next header.
nextOffset uint32
}
// HeaderOffset returns the offset to the start of the extension
// header most recently processed.
func (i IPv6PayloadIterator) HeaderOffset() uint32 {
return i.headerOffset
}
// ParseOffset returns the number of bytes successfully parsed.
func (i IPv6PayloadIterator) ParseOffset() uint32 {
return i.headerOffset + i.parseOffset
}
// MakeIPv6PayloadIterator returns an iterator over the IPv6 payload containing
// extension headers, or a raw payload if the payload cannot be parsed. The
// iterator takes ownership of the payload.
func MakeIPv6PayloadIterator(nextHdrIdentifier IPv6ExtensionHeaderIdentifier, payload buffer.Buffer) IPv6PayloadIterator {
return IPv6PayloadIterator{
nextHdrIdentifier: nextHdrIdentifier,
payload: payload,
nextOffset: IPv6FixedHeaderSize,
}
}
// Release frees the resources owned by the iterator.
func (i *IPv6PayloadIterator) Release() {
i.payload.Release()
}
// AsRawHeader returns the remaining payload of i as a raw header and
// optionally consumes the iterator.
//
// If consume is true, calls to Next after calling AsRawHeader on i will
// indicate that the iterator is done. The returned header takes ownership of
// its payload.
func (i *IPv6PayloadIterator) AsRawHeader(consume bool) IPv6RawPayloadHeader {
identifier := i.nextHdrIdentifier
var buf buffer.Buffer
if consume {
// Since we consume the iterator, we return the payload as is.
buf = i.payload
// Mark i as done, but keep track of where we were for error reporting.
*i = IPv6PayloadIterator{
nextHdrIdentifier: IPv6NoNextHeaderIdentifier,
headerOffset: i.headerOffset,
nextOffset: i.nextOffset,
}
} else {
buf = i.payload.Clone()
}
return IPv6RawPayloadHeader{Identifier: identifier, Buf: buf}
}
// Next returns the next item in the payload.
//
// If the next item is not a known IPv6 extension header, IPv6RawPayloadHeader
// will be returned with the remaining bytes and next header identifier.
//
// The return is of the format (header, done, error). done will be true when
// Next is unable to return anything because the iterator has reached the end of
// the payload, or an error occurred.
func (i *IPv6PayloadIterator) Next() (IPv6PayloadHeader, bool, error) {
i.headerOffset = i.nextOffset
i.parseOffset = 0
// We could be forced to return i as a raw header when the previous header was
// a fragment extension header as the data following the fragment extension
// header may not be complete.
if i.forceRaw {
return i.AsRawHeader(true /* consume */), false, nil
}
// Is the header we are parsing a known extension header?
switch i.nextHdrIdentifier {
case IPv6HopByHopOptionsExtHdrIdentifier:
nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil)
if err != nil {
return nil, true, err
}
i.nextHdrIdentifier = nextHdrIdentifier
return IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{view}}, false, nil
case IPv6RoutingExtHdrIdentifier:
nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil)
if err != nil {
return nil, true, err
}
i.nextHdrIdentifier = nextHdrIdentifier
return IPv6RoutingExtHdr{view}, false, nil
case IPv6FragmentExtHdrIdentifier:
var data [6]byte
// We ignore the returned bytes because we know the fragment extension
// header specific data will fit in data.
nextHdrIdentifier, _, err := i.nextHeaderData(true /* fragmentHdr */, data[:])
if err != nil {
return nil, true, err
}
fragmentExtHdr := IPv6FragmentExtHdr(data)
// If the packet is not the first fragment, do not attempt to parse anything
// after the fragment extension header as the payload following the fragment
// extension header should not contain any headers; the first fragment must
// hold all the headers up to and including any upper layer headers, as per
// RFC 8200 section 4.5.
if fragmentExtHdr.FragmentOffset() != 0 {
i.forceRaw = true
}
i.nextHdrIdentifier = nextHdrIdentifier
return fragmentExtHdr, false, nil
case IPv6DestinationOptionsExtHdrIdentifier:
nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil)
if err != nil {
return nil, true, err
}
i.nextHdrIdentifier = nextHdrIdentifier
return IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr{view}}, false, nil
case IPv6NoNextHeaderIdentifier:
// This indicates the end of the IPv6 payload.
return nil, true, nil
default:
// The header we are parsing is not a known extension header. Return the
// raw payload.
return i.AsRawHeader(true /* consume */), false, nil
}
}
// NextHeaderIdentifier returns the identifier of the header next returned by
// it.Next().
func (i *IPv6PayloadIterator) NextHeaderIdentifier() IPv6ExtensionHeaderIdentifier {
return i.nextHdrIdentifier
}
// nextHeaderData returns the extension header's Next Header field and raw data.
//
// fragmentHdr indicates that the extension header being parsed is the Fragment
// extension header so the Length field should be ignored as it is Reserved
// for the Fragment extension header.
//
// If bytes is not nil, extension header specific data will be read into bytes
// if it has enough capacity. If bytes is provided but does not have enough
// capacity for the data, nextHeaderData will panic.
func (i *IPv6PayloadIterator) nextHeaderData(fragmentHdr bool, bytes []byte) (IPv6ExtensionHeaderIdentifier, *buffer.View, error) {
// We ignore the number of bytes read because we know we will only ever read
// at max 1 bytes since rune has a length of 1. If we read 0 bytes, the Read
// would return io.EOF to indicate that io.Reader has reached the end of the
// payload.
rdr := i.payload.AsBufferReader()
nextHdrIdentifier, err := rdr.ReadByte()
if err != nil {
return 0, nil, fmt.Errorf("error when reading the Next Header field for extension header with id = %d: %w", i.nextHdrIdentifier, err)
}
i.parseOffset++
var length uint8
length, err = rdr.ReadByte()
if err != nil {
if fragmentHdr {
return 0, nil, fmt.Errorf("error when reading the Length field for extension header with id = %d: %w", i.nextHdrIdentifier, err)
}
return 0, nil, fmt.Errorf("error when reading the Reserved field for extension header with id = %d: %w", i.nextHdrIdentifier, err)
}
if fragmentHdr {
length = 0
}
// Make parseOffset point to the first byte of the Extension Header
// specific data.
i.parseOffset++
// length is in 8 byte chunks but doesn't include the first one.
// See RFC 8200 for each header type, sections 4.3-4.6 and the requirement
// in section 4.8 for new extension headers at the top of page 24.
// [ Hdr Ext Len ] ... Length of the Destination Options header in 8-octet
// units, not including the first 8 octets.
i.nextOffset += uint32((length + 1) * ipv6ExtHdrLenBytesPerUnit)
bytesLen := int(length)*ipv6ExtHdrLenBytesPerUnit + ipv6ExtHdrLenBytesExcluded
if fragmentHdr {
if n := len(bytes); n < bytesLen {
panic(fmt.Sprintf("bytes only has space for %d bytes but need space for %d bytes (length = %d) for extension header with id = %d", n, bytesLen, length, i.nextHdrIdentifier))
}
if n, err := io.ReadFull(&rdr, bytes); err != nil {
return 0, nil, fmt.Errorf("read %d out of %d extension header data bytes (length = %d) for header with id = %d: %w", n, bytesLen, length, i.nextHdrIdentifier, err)
}
return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), nil, nil
}
v := buffer.NewView(bytesLen)
if n, err := io.CopyN(v, &rdr, int64(bytesLen)); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
v.Release()
return 0, nil, fmt.Errorf("read %d out of %d extension header data bytes (length = %d) for header with id = %d: %w", n, bytesLen, length, i.nextHdrIdentifier, err)
}
return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), v, 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
}

View File

@@ -0,0 +1,158 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
nextHdrFrag = 0
fragOff = 2
more = 3
idV6 = 4
)
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
// M is the "more" field of an IPv6 fragment.
M bool
// Identification is the "identification" field of an IPv6 fragment.
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'.
// Always call IsValid() to validate an instance of IPv6Fragment before using other methods.
type IPv6Fragment []byte
const (
// IPv6FragmentHeader header is the number used to specify that the next
// header is a fragment header, per RFC 2460.
IPv6FragmentHeader = 44
// IPv6FragmentHeaderSize is the size of the fragment header.
IPv6FragmentHeaderSize = 8
)
// IsValid performs basic validation on the fragment header.
func (b IPv6Fragment) IsValid() bool {
return len(b) >= IPv6FragmentHeaderSize
}
// NextHeader returns the value of the "next header" field of the ipv6 fragment.
func (b IPv6Fragment) NextHeader() uint8 {
return b[nextHdrFrag]
}
// FragmentOffset returns the "fragment offset" field of the ipv6 fragment.
func (b IPv6Fragment) FragmentOffset() uint16 {
return binary.BigEndian.Uint16(b[fragOff:]) >> 3
}
// More returns the "more" field of the ipv6 fragment.
func (b IPv6Fragment) More() bool {
return b[more]&1 > 0
}
// Payload implements Network.Payload.
func (b IPv6Fragment) Payload() []byte {
return b[IPv6FragmentHeaderSize:]
}
// ID returns the value of the identifier field of the ipv6 fragment.
func (b IPv6Fragment) ID() uint32 {
return binary.BigEndian.Uint32(b[idV6:])
}
// TransportProtocol implements Network.TransportProtocol.
func (b IPv6Fragment) TransportProtocol() tcpip.TransportProtocolNumber {
return tcpip.TransportProtocolNumber(b.NextHeader())
}
// The functions below have been added only to satisfy the Network interface.
// Checksum is not supported by IPv6Fragment.
func (b IPv6Fragment) Checksum() uint16 {
panic("not supported")
}
// SourceAddress is not supported by IPv6Fragment.
func (b IPv6Fragment) SourceAddress() tcpip.Address {
panic("not supported")
}
// DestinationAddress is not supported by IPv6Fragment.
func (b IPv6Fragment) DestinationAddress() tcpip.Address {
panic("not supported")
}
// SetSourceAddress is not supported by IPv6Fragment.
func (b IPv6Fragment) SetSourceAddress(tcpip.Address) {
panic("not supported")
}
// SetDestinationAddress is not supported by IPv6Fragment.
func (b IPv6Fragment) SetDestinationAddress(tcpip.Address) {
panic("not supported")
}
// SetChecksum is not supported by IPv6Fragment.
func (b IPv6Fragment) SetChecksum(uint16) {
panic("not supported")
}
// TOS is not supported by IPv6Fragment.
func (b IPv6Fragment) TOS() (uint8, uint32) {
panic("not supported")
}
// SetTOS is not supported by IPv6Fragment.
func (b IPv6Fragment) SetTOS(t uint8, l uint32) {
panic("not supported")
}

View File

@@ -0,0 +1,103 @@
// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"fmt"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
// MLDMinimumSize is the minimum size for an MLD message.
MLDMinimumSize = 20
// MLDHopLimit is the Hop Limit for all IPv6 packets with an MLD message, as
// per RFC 2710 section 3.
MLDHopLimit = 1
// mldMaximumResponseDelayOffset is the offset to the Maximum Response Delay
// field within MLD.
mldMaximumResponseDelayOffset = 0
// mldMulticastAddressOffset is the offset to the Multicast Address field
// within MLD.
mldMulticastAddressOffset = 4
)
// MLD is a Multicast Listener Discovery message in an ICMPv6 packet.
//
// MLD will only contain the body of an ICMPv6 packet.
//
// As per RFC 2710 section 3, MLD messages have the following format (MLD only
// holds the bytes after the first four bytes in the diagram below):
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Maximum Response Delay | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// + +
// | |
// + Multicast Address +
// | |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type MLD []byte
// MaximumResponseDelay returns the Maximum Response Delay.
func (m MLD) MaximumResponseDelay() time.Duration {
// As per RFC 2710 section 3.4:
//
// The Maximum Response Delay field is meaningful only in Query
// messages, and specifies the maximum allowed delay before sending a
// responding Report, in units of milliseconds. In all other messages,
// it is set to zero by the sender and ignored by receivers.
return time.Duration(binary.BigEndian.Uint16(m[mldMaximumResponseDelayOffset:])) * time.Millisecond
}
// SetMaximumResponseDelay sets the Maximum Response Delay field.
//
// maxRespDelayMS is the value in milliseconds.
func (m MLD) SetMaximumResponseDelay(maxRespDelayMS uint16) {
binary.BigEndian.PutUint16(m[mldMaximumResponseDelayOffset:], maxRespDelayMS)
}
// MulticastAddress returns the Multicast Address.
func (m MLD) MulticastAddress() tcpip.Address {
// As per RFC 2710 section 3.5:
//
// In a Query message, the Multicast Address field is set to zero when
// sending a General Query, and set to a specific IPv6 multicast address
// when sending a Multicast-Address-Specific Query.
//
// In a Report or Done message, the Multicast Address field holds a
// specific IPv6 multicast address to which the message sender is
// listening or is ceasing to listen, respectively.
return tcpip.AddrFrom16([16]byte(m[mldMulticastAddressOffset:][:IPv6AddressSize]))
}
// SetMulticastAddress sets the Multicast Address field.
func (m MLD) SetMulticastAddress(multicastAddress tcpip.Address) {
if n := copy(m[mldMulticastAddressOffset:], multicastAddress.AsSlice()); n != IPv6AddressSize {
panic(fmt.Sprintf("copied %d bytes, expected to copy %d bytes", n, IPv6AddressSize))
}
}

View File

@@ -0,0 +1,541 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"bytes"
"encoding/binary"
"fmt"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
// MLDv2QueryMinimumSize is the minimum size for an MLDv2 message.
MLDv2QueryMinimumSize = 24
mldv2QueryMaximumResponseCodeOffset = 0
mldv2QueryResvSQRVOffset = 20
mldv2QueryQRVMask = 0b111
mldv2QueryQQICOffset = 21
// mldv2QueryNumberOfSourcesOffset is the offset to the Number of Sources
// field within MLDv2Query.
mldv2QueryNumberOfSourcesOffset = 22
// MLDv2ReportMinimumSize is the minimum size of an MLDv2 report.
MLDv2ReportMinimumSize = 24
// mldv2QuerySourcesOffset is the offset to the Sources field within
// MLDv2Query.
mldv2QuerySourcesOffset = 24
)
var (
// MLDv2RoutersAddress is the address to send MLDv2 reports to.
//
// As per RFC 3810 section 5.2.14,
//
// Version 2 Multicast Listener Reports are sent with an IP destination
// address of FF02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
// routers listen (see section 11 for IANA considerations related to
// this special destination address).
MLDv2RoutersAddress = tcpip.AddrFrom16([16]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16})
)
// MLDv2Query is a Multicast Listener Discovery Version 2 Query message in an
// ICMPv6 packet.
//
// MLDv2Query will only contain the body of an ICMPv6 packet.
//
// As per RFC 3810 section 5.1, MLDv2 Query messages have the following format
// (MLDv2Query only holds the bytes after the first four bytes in the diagram
// below):
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 130 | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Maximum Response Code | Reserved |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Multicast Address *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Resv |S| QRV | QQIC | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Source Address [1] *
// | |
// * *
// | |
// +- -+
// | |
// * *
// | |
// * Source Address [2] *
// | |
// * *
// | |
// +- . -+
// . . .
// . . .
// +- -+
// | |
// * *
// | |
// * Source Address [N] *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type MLDv2Query MLD
// MaximumResponseCode returns the Maximum Response Code
func (m MLDv2Query) MaximumResponseCode() uint16 {
return binary.BigEndian.Uint16(m[mldv2QueryMaximumResponseCodeOffset:])
}
// MLDv2MaximumResponseDelay returns the Maximum Response Delay in an MLDv2
// Maximum Response Code.
//
// As per RFC 3810 section 5.1.3,
//
// The Maximum Response Code field specifies the maximum time allowed
// before sending a responding Report. The actual time allowed, called
// the Maximum Response Delay, is represented in units of milliseconds,
// and is derived from the Maximum Response Code as follows:
//
// If Maximum Response Code < 32768,
// Maximum Response Delay = Maximum Response Code
//
// If Maximum Response Code >=32768, Maximum Response Code represents a
// floating-point value as follows:
//
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |1| exp | mant |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Maximum Response Delay = (mant | 0x1000) << (exp+3)
//
// Small values of Maximum Response Delay allow MLDv2 routers to tune
// the "leave latency" (the time between the moment the last node on a
// link ceases to listen to a specific multicast address and the moment
// the routing protocol is notified that there are no more listeners for
// that address). Larger values, especially in the exponential range,
// allow the tuning of the burstiness of MLD traffic on a link.
func MLDv2MaximumResponseDelay(codeRaw uint16) time.Duration {
code := time.Duration(codeRaw)
if code < 32768 {
return code * time.Millisecond
}
const mantBits = 12
const expMask = 0b111
exp := (code >> mantBits) & expMask
mant := code & ((1 << mantBits) - 1)
return (mant | 0x1000) << (exp + 3) * time.Millisecond
}
// MulticastAddress returns the Multicast Address.
func (m MLDv2Query) MulticastAddress() tcpip.Address {
// As per RFC 2710 section 3.5:
//
// In a Query message, the Multicast Address field is set to zero when
// sending a General Query, and set to a specific IPv6 multicast address
// when sending a Multicast-Address-Specific Query.
//
// In a Report or Done message, the Multicast Address field holds a
// specific IPv6 multicast address to which the message sender is
// listening or is ceasing to listen, respectively.
return tcpip.AddrFrom16([16]byte(m[mldMulticastAddressOffset:][:IPv6AddressSize]))
}
// QuerierRobustnessVariable returns the querier's robustness variable.
func (m MLDv2Query) QuerierRobustnessVariable() uint8 {
return m[mldv2QueryResvSQRVOffset] & mldv2QueryQRVMask
}
// QuerierQueryInterval returns the querier's query interval.
func (m MLDv2Query) QuerierQueryInterval() time.Duration {
return mldv2AndIGMPv3QuerierQueryCodeToInterval(m[mldv2QueryQQICOffset])
}
// Sources returns an iterator over source addresses in the query.
//
// Returns false if the message cannot hold the expected number of sources.
func (m MLDv2Query) Sources() (AddressIterator, bool) {
return makeAddressIterator(
m[mldv2QuerySourcesOffset:],
binary.BigEndian.Uint16(m[mldv2QueryNumberOfSourcesOffset:]),
IPv6AddressSize,
)
}
// MLDv2ReportRecordType is the type of an MLDv2 multicast address record
// found in an MLDv2 report, as per RFC 3810 section 5.2.12.
type MLDv2ReportRecordType int
// MLDv2 multicast address record types, as per RFC 3810 section 5.2.12.
const (
MLDv2ReportRecordModeIsInclude MLDv2ReportRecordType = 1
MLDv2ReportRecordModeIsExclude MLDv2ReportRecordType = 2
MLDv2ReportRecordChangeToIncludeMode MLDv2ReportRecordType = 3
MLDv2ReportRecordChangeToExcludeMode MLDv2ReportRecordType = 4
MLDv2ReportRecordAllowNewSources MLDv2ReportRecordType = 5
MLDv2ReportRecordBlockOldSources MLDv2ReportRecordType = 6
)
const (
mldv2ReportMulticastAddressRecordMinimumSize = 20
mldv2ReportMulticastAddressRecordTypeOffset = 0
mldv2ReportMulticastAddressRecordAuxDataLenOffset = 1
mldv2ReportMulticastAddressRecordAuxDataLenUnits = 4
mldv2ReportMulticastAddressRecordNumberOfSourcesOffset = 2
mldv2ReportMulticastAddressRecordMulticastAddressOffset = 4
mldv2ReportMulticastAddressRecordSourcesOffset = 20
)
// MLDv2ReportMulticastAddressRecordSerializer is an MLDv2 Multicast Address
// Record serializer.
//
// As per RFC 3810 section 5.2, a Multicast Address Record has the following
// internal format:
//
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Record Type | Aux Data Len | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Multicast Address *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Source Address [1] *
// | |
// * *
// | |
// +- -+
// | |
// * *
// | |
// * Source Address [2] *
// | |
// * *
// | |
// +- -+
// . . .
// . . .
// . . .
// +- -+
// | |
// * *
// | |
// * Source Address [N] *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Auxiliary Data .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type MLDv2ReportMulticastAddressRecordSerializer struct {
RecordType MLDv2ReportRecordType
MulticastAddress tcpip.Address
Sources []tcpip.Address
}
// Length returns the number of bytes this serializer would occupy.
func (s *MLDv2ReportMulticastAddressRecordSerializer) Length() int {
return mldv2ReportMulticastAddressRecordSourcesOffset + len(s.Sources)*IPv6AddressSize
}
func copyIPv6Address(dst []byte, src tcpip.Address) {
if n := copy(dst, src.AsSlice()); n != IPv6AddressSize {
panic(fmt.Sprintf("got copy(...) = %d, want = %d", n, IPv6AddressSize))
}
}
// SerializeInto serializes the record into the buffer.
//
// Panics if the buffer does not have enough space to fit the record.
func (s *MLDv2ReportMulticastAddressRecordSerializer) SerializeInto(b []byte) {
b[mldv2ReportMulticastAddressRecordTypeOffset] = byte(s.RecordType)
b[mldv2ReportMulticastAddressRecordAuxDataLenOffset] = 0
binary.BigEndian.PutUint16(b[mldv2ReportMulticastAddressRecordNumberOfSourcesOffset:], uint16(len(s.Sources)))
copyIPv6Address(b[mldv2ReportMulticastAddressRecordMulticastAddressOffset:], s.MulticastAddress)
b = b[mldv2ReportMulticastAddressRecordSourcesOffset:]
for _, source := range s.Sources {
copyIPv6Address(b, source)
b = b[IPv6AddressSize:]
}
}
const (
mldv2ReportReservedOffset = 0
mldv2ReportNumberOfMulticastAddressRecordsOffset = 2
mldv2ReportMulticastAddressRecordsOffset = 4
)
// MLDv2ReportSerializer is an MLD Version 2 Report serializer.
//
// As per RFC 3810 section 5.2,
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 143 | Reserved | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved |Nr of Mcast Address Records (M)|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [1] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [2] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | . |
// . . .
// | . |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [M] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type MLDv2ReportSerializer struct {
Records []MLDv2ReportMulticastAddressRecordSerializer
}
// Length returns the number of bytes this serializer would occupy.
func (s *MLDv2ReportSerializer) Length() int {
ret := mldv2ReportMulticastAddressRecordsOffset
for _, record := range s.Records {
ret += record.Length()
}
return ret
}
// SerializeInto serializes the report into the buffer.
//
// Panics if the buffer does not have enough space to fit the report.
func (s *MLDv2ReportSerializer) SerializeInto(b []byte) {
binary.BigEndian.PutUint16(b[mldv2ReportReservedOffset:], 0)
binary.BigEndian.PutUint16(b[mldv2ReportNumberOfMulticastAddressRecordsOffset:], uint16(len(s.Records)))
b = b[mldv2ReportMulticastAddressRecordsOffset:]
for _, record := range s.Records {
len := record.Length()
record.SerializeInto(b[:len])
b = b[len:]
}
}
// MLDv2ReportMulticastAddressRecord is an MLDv2 record.
//
// As per RFC 3810 section 5.2, a Multicast Address Record has the following
// internal format:
//
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Record Type | Aux Data Len | Number of Sources (N) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Multicast Address *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// * *
// | |
// * Source Address [1] *
// | |
// * *
// | |
// +- -+
// | |
// * *
// | |
// * Source Address [2] *
// | |
// * *
// | |
// +- -+
// . . .
// . . .
// . . .
// +- -+
// | |
// * *
// | |
// * Source Address [N] *
// | |
// * *
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Auxiliary Data .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type MLDv2ReportMulticastAddressRecord []byte
// RecordType returns the type of this record.
func (r MLDv2ReportMulticastAddressRecord) RecordType() MLDv2ReportRecordType {
return MLDv2ReportRecordType(r[mldv2ReportMulticastAddressRecordTypeOffset])
}
// AuxDataLen returns the length of the auxiliary data in this record.
func (r MLDv2ReportMulticastAddressRecord) AuxDataLen() int {
return int(r[mldv2ReportMulticastAddressRecordAuxDataLenOffset]) * mldv2ReportMulticastAddressRecordAuxDataLenUnits
}
// numberOfSources returns the number of sources in this record.
func (r MLDv2ReportMulticastAddressRecord) numberOfSources() uint16 {
return binary.BigEndian.Uint16(r[mldv2ReportMulticastAddressRecordNumberOfSourcesOffset:])
}
// MulticastAddress returns the multicast address this record targets.
func (r MLDv2ReportMulticastAddressRecord) MulticastAddress() tcpip.Address {
return tcpip.AddrFrom16([16]byte(r[mldv2ReportMulticastAddressRecordMulticastAddressOffset:][:IPv6AddressSize]))
}
// Sources returns an iterator over source addresses in the query.
//
// Returns false if the message cannot hold the expected number of sources.
func (r MLDv2ReportMulticastAddressRecord) Sources() (AddressIterator, bool) {
expectedLen := int(r.numberOfSources()) * IPv6AddressSize
b := r[mldv2ReportMulticastAddressRecordSourcesOffset:]
if len(b) < expectedLen {
return AddressIterator{}, false
}
return AddressIterator{addressSize: IPv6AddressSize, buf: bytes.NewBuffer(b[:expectedLen])}, true
}
// MLDv2Report is an MLDv2 Report.
//
// As per RFC 3810 section 5.2,
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type = 143 | Reserved | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reserved |Nr of Mcast Address Records (M)|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [1] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [2] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | . |
// . . .
// | . |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// . .
// . Multicast Address Record [M] .
// . .
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type MLDv2Report []byte
// MLDv2ReportMulticastAddressRecordIterator is an iterator over MLDv2 Multicast
// Address Records.
type MLDv2ReportMulticastAddressRecordIterator struct {
recordsLeft uint16
buf *bytes.Buffer
}
// MLDv2ReportMulticastAddressRecordIteratorNextDisposition is the possible
// return values from MLDv2ReportMulticastAddressRecordIterator.Next.
type MLDv2ReportMulticastAddressRecordIteratorNextDisposition int
const (
// MLDv2ReportMulticastAddressRecordIteratorNextOk indicates that a multicast
// address record was yielded.
MLDv2ReportMulticastAddressRecordIteratorNextOk MLDv2ReportMulticastAddressRecordIteratorNextDisposition = iota
// MLDv2ReportMulticastAddressRecordIteratorNextDone indicates that the iterator
// has been exhausted.
MLDv2ReportMulticastAddressRecordIteratorNextDone
// MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort indicates
// that the iterator expected another record, but the buffer ended
// prematurely.
MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
)
// Next returns the next MLDv2 Multicast Address Record.
func (it *MLDv2ReportMulticastAddressRecordIterator) Next() (MLDv2ReportMulticastAddressRecord, MLDv2ReportMulticastAddressRecordIteratorNextDisposition) {
if it.recordsLeft == 0 {
return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextDone
}
if it.buf.Len() < mldv2ReportMulticastAddressRecordMinimumSize {
return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
}
hdr := MLDv2ReportMulticastAddressRecord(it.buf.Bytes())
expectedLen := mldv2ReportMulticastAddressRecordMinimumSize +
int(hdr.AuxDataLen()) + int(hdr.numberOfSources())*IPv6AddressSize
bytes := it.buf.Next(expectedLen)
if len(bytes) < expectedLen {
return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
}
it.recordsLeft--
return MLDv2ReportMulticastAddressRecord(bytes), MLDv2ReportMulticastAddressRecordIteratorNextOk
}
// MulticastAddressRecords returns an iterator of MLDv2 Multicast Address
// Records.
func (m MLDv2Report) MulticastAddressRecords() MLDv2ReportMulticastAddressRecordIterator {
return MLDv2ReportMulticastAddressRecordIterator{
recordsLeft: binary.BigEndian.Uint16(m[mldv2ReportNumberOfMulticastAddressRecordsOffset:]),
buf: bytes.NewBuffer(m[mldv2ReportMulticastAddressRecordsOffset:]),
}
}

View File

@@ -0,0 +1,124 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"bytes"
"fmt"
"time"
"gvisor.dev/gvisor/pkg/tcpip"
)
func mldv2AndIGMPv3QuerierQueryCodeToInterval(code uint8) time.Duration {
// MLDv2: As per RFC 3810 section 5.1.19,
//
// The Querier's Query Interval Code field specifies the [Query
// Interval] used by the Querier. The actual interval, called the
// Querier's Query Interval (QQI), is represented in units of seconds,
// and is derived from the Querier's Query Interval Code as follows:
//
// If QQIC < 128, QQI = QQIC
//
// If QQIC >= 128, QQIC represents a floating-point value as follows:
//
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |1| exp | mant |
// +-+-+-+-+-+-+-+-+
//
// QQI = (mant | 0x10) << (exp + 3)
//
// Multicast routers that are not the current Querier adopt the QQI
// value from the most recently received Query as their own [Query
// Interval] value, unless that most recently received QQI was zero, in
// which case the receiving routers use the default [Query Interval]
// value specified in section 9.2.
//
// IGMPv3: As per RFC 3376 section 4.1.7,
//
// The Querier's Query Interval Code field specifies the [Query
// Interval] used by the querier. The actual interval, called the
// Querier's Query Interval (QQI), is represented in units of seconds
// and is derived from the Querier's Query Interval Code as follows:
//
// If QQIC < 128, QQI = QQIC
//
// If QQIC >= 128, QQIC represents a floating-point value as follows:
//
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |1| exp | mant |
// +-+-+-+-+-+-+-+-+
//
// QQI = (mant | 0x10) << (exp + 3)
//
// Multicast routers that are not the current querier adopt the QQI
// value from the most recently received Query as their own [Query
// Interval] value, unless that most recently received QQI was zero, in
// which case the receiving routers use the default [Query Interval]
// value specified in section 8.2.
interval := time.Duration(code)
if interval < 128 {
return interval * time.Second
}
const expMask = 0b111
const mantBits = 4
mant := interval & ((1 << mantBits) - 1)
exp := (interval >> mantBits) & expMask
return (mant | 0x10) << (exp + 3) * time.Second
}
// MakeAddressIterator returns an AddressIterator.
func MakeAddressIterator(addressSize int, buf *bytes.Buffer) AddressIterator {
return AddressIterator{addressSize: addressSize, buf: buf}
}
// AddressIterator is an iterator over IPv6 addresses.
type AddressIterator struct {
addressSize int
buf *bytes.Buffer
}
// Done indicates that the iterator has been exhausted/has no more elements.
func (it *AddressIterator) Done() bool {
return it.buf.Len() == 0
}
// Next returns the next address in the iterator.
//
// Returns false if the iterator has been exhausted.
func (it *AddressIterator) Next() (tcpip.Address, bool) {
if it.Done() {
var emptyAddress tcpip.Address
return emptyAddress, false
}
b := it.buf.Next(it.addressSize)
if len(b) != it.addressSize {
panic(fmt.Sprintf("got len(buf.Next(%d)) = %d, want = %d", it.addressSize, len(b), it.addressSize))
}
return tcpip.AddrFromSlice(b), true
}
func makeAddressIterator(b []byte, expectedAddresses uint16, addressSize int) (AddressIterator, bool) {
expectedLen := int(expectedAddresses) * addressSize
if len(b) < expectedLen {
return AddressIterator{}, false
}
return MakeAddressIterator(addressSize, bytes.NewBuffer(b[:expectedLen])), true
}

View File

@@ -0,0 +1,110 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import "gvisor.dev/gvisor/pkg/tcpip"
// NDPNeighborAdvert is an NDP Neighbor Advertisement message. It will
// only contain the body of an ICMPv6 packet.
//
// See RFC 4861 section 4.4 for more details.
type NDPNeighborAdvert []byte
const (
// NDPNAMinimumSize is the minimum size of a valid NDP Neighbor
// Advertisement message (body of an ICMPv6 packet).
NDPNAMinimumSize = 20
// ndpNATargetAddressOffset is the start of the Target Address
// field within an NDPNeighborAdvert.
ndpNATargetAddressOffset = 4
// ndpNAOptionsOffset is the start of the NDP options in an
// NDPNeighborAdvert.
ndpNAOptionsOffset = ndpNATargetAddressOffset + IPv6AddressSize
// ndpNAFlagsOffset is the offset of the flags within an
// NDPNeighborAdvert
ndpNAFlagsOffset = 0
// ndpNARouterFlagMask is the mask of the Router Flag field in
// the flags byte within in an NDPNeighborAdvert.
ndpNARouterFlagMask = (1 << 7)
// ndpNASolicitedFlagMask is the mask of the Solicited Flag field in
// the flags byte within in an NDPNeighborAdvert.
ndpNASolicitedFlagMask = (1 << 6)
// ndpNAOverrideFlagMask is the mask of the Override Flag field in
// the flags byte within in an NDPNeighborAdvert.
ndpNAOverrideFlagMask = (1 << 5)
)
// TargetAddress returns the value within the Target Address field.
func (b NDPNeighborAdvert) TargetAddress() tcpip.Address {
return tcpip.AddrFrom16Slice(b[ndpNATargetAddressOffset:][:IPv6AddressSize])
}
// SetTargetAddress sets the value within the Target Address field.
func (b NDPNeighborAdvert) SetTargetAddress(addr tcpip.Address) {
copy(b[ndpNATargetAddressOffset:][:IPv6AddressSize], addr.AsSlice())
}
// RouterFlag returns the value of the Router Flag field.
func (b NDPNeighborAdvert) RouterFlag() bool {
return b[ndpNAFlagsOffset]&ndpNARouterFlagMask != 0
}
// SetRouterFlag sets the value in the Router Flag field.
func (b NDPNeighborAdvert) SetRouterFlag(f bool) {
if f {
b[ndpNAFlagsOffset] |= ndpNARouterFlagMask
} else {
b[ndpNAFlagsOffset] &^= ndpNARouterFlagMask
}
}
// SolicitedFlag returns the value of the Solicited Flag field.
func (b NDPNeighborAdvert) SolicitedFlag() bool {
return b[ndpNAFlagsOffset]&ndpNASolicitedFlagMask != 0
}
// SetSolicitedFlag sets the value in the Solicited Flag field.
func (b NDPNeighborAdvert) SetSolicitedFlag(f bool) {
if f {
b[ndpNAFlagsOffset] |= ndpNASolicitedFlagMask
} else {
b[ndpNAFlagsOffset] &^= ndpNASolicitedFlagMask
}
}
// OverrideFlag returns the value of the Override Flag field.
func (b NDPNeighborAdvert) OverrideFlag() bool {
return b[ndpNAFlagsOffset]&ndpNAOverrideFlagMask != 0
}
// SetOverrideFlag sets the value in the Override Flag field.
func (b NDPNeighborAdvert) SetOverrideFlag(f bool) {
if f {
b[ndpNAFlagsOffset] |= ndpNAOverrideFlagMask
} else {
b[ndpNAFlagsOffset] &^= ndpNAOverrideFlagMask
}
}
// Options returns an NDPOptions of the options body.
func (b NDPNeighborAdvert) Options() NDPOptions {
return NDPOptions(b[ndpNAOptionsOffset:])
}

View File

@@ -0,0 +1,52 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import "gvisor.dev/gvisor/pkg/tcpip"
// NDPNeighborSolicit is an NDP Neighbor Solicitation message. It will only
// contain the body of an ICMPv6 packet.
//
// See RFC 4861 section 4.3 for more details.
type NDPNeighborSolicit []byte
const (
// NDPNSMinimumSize is the minimum size of a valid NDP Neighbor
// Solicitation message (body of an ICMPv6 packet).
NDPNSMinimumSize = 20
// ndpNSTargetAddessOffset is the start of the Target Address
// field within an NDPNeighborSolicit.
ndpNSTargetAddessOffset = 4
// ndpNSOptionsOffset is the start of the NDP options in an
// NDPNeighborSolicit.
ndpNSOptionsOffset = ndpNSTargetAddessOffset + IPv6AddressSize
)
// TargetAddress returns the value within the Target Address field.
func (b NDPNeighborSolicit) TargetAddress() tcpip.Address {
return tcpip.AddrFrom16Slice(b[ndpNSTargetAddessOffset:][:IPv6AddressSize])
}
// SetTargetAddress sets the value within the Target Address field.
func (b NDPNeighborSolicit) SetTargetAddress(addr tcpip.Address) {
copy(b[ndpNSTargetAddessOffset:][:IPv6AddressSize], addr.AsSlice())
}
// Options returns an NDPOptions of the options body.
func (b NDPNeighborSolicit) Options() NDPOptions {
return NDPOptions(b[ndpNSOptionsOffset:])
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,204 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"fmt"
"time"
)
var _ fmt.Stringer = NDPRoutePreference(0)
// NDPRoutePreference is the preference values for default routers or
// more-specific routes.
//
// As per RFC 4191 section 2.1,
//
// Default router preferences and preferences for more-specific routes
// are encoded the same way.
//
// Preference values are encoded as a two-bit signed integer, as
// follows:
//
// 01 High
// 00 Medium (default)
// 11 Low
// 10 Reserved - MUST NOT be sent
//
// Note that implementations can treat the value as a two-bit signed
// integer.
//
// Having just three values reinforces that they are not metrics and
// more values do not appear to be necessary for reasonable scenarios.
type NDPRoutePreference uint8
const (
// HighRoutePreference indicates a high preference, as per
// RFC 4191 section 2.1.
HighRoutePreference NDPRoutePreference = 0b01
// MediumRoutePreference indicates a medium preference, as per
// RFC 4191 section 2.1.
//
// This is the default preference value.
MediumRoutePreference = 0b00
// LowRoutePreference indicates a low preference, as per
// RFC 4191 section 2.1.
LowRoutePreference = 0b11
// ReservedRoutePreference is a reserved preference value, as per
// RFC 4191 section 2.1.
//
// It MUST NOT be sent.
ReservedRoutePreference = 0b10
)
// String implements fmt.Stringer.
func (p NDPRoutePreference) String() string {
switch p {
case HighRoutePreference:
return "HighRoutePreference"
case MediumRoutePreference:
return "MediumRoutePreference"
case LowRoutePreference:
return "LowRoutePreference"
case ReservedRoutePreference:
return "ReservedRoutePreference"
default:
return fmt.Sprintf("NDPRoutePreference(%d)", p)
}
}
// NDPRouterAdvert is an NDP Router Advertisement message. It will only contain
// the body of an ICMPv6 packet.
//
// See RFC 4861 section 4.2 and RFC 4191 section 2.2 for more details.
type NDPRouterAdvert []byte
// As per RFC 4191 section 2.2,
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Type | Code | Checksum |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Cur Hop Limit |M|O|H|Prf|Resvd| Router Lifetime |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Reachable Time |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Retrans Timer |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Options ...
// +-+-+-+-+-+-+-+-+-+-+-+-
const (
// NDPRAMinimumSize is the minimum size of a valid NDP Router
// Advertisement message (body of an ICMPv6 packet).
NDPRAMinimumSize = 12
// ndpRACurrHopLimitOffset is the byte of the Curr Hop Limit field
// within an NDPRouterAdvert.
ndpRACurrHopLimitOffset = 0
// ndpRAFlagsOffset is the byte with the NDP RA bit-fields/flags
// within an NDPRouterAdvert.
ndpRAFlagsOffset = 1
// ndpRAManagedAddrConfFlagMask is the mask of the Managed Address
// Configuration flag within the bit-field/flags byte of an
// NDPRouterAdvert.
ndpRAManagedAddrConfFlagMask = (1 << 7)
// ndpRAOtherConfFlagMask is the mask of the Other Configuration flag
// within the bit-field/flags byte of an NDPRouterAdvert.
ndpRAOtherConfFlagMask = (1 << 6)
// ndpDefaultRouterPreferenceShift is the shift of the Prf (Default Router
// Preference) field within the flags byte of an NDPRouterAdvert.
ndpDefaultRouterPreferenceShift = 3
// ndpDefaultRouterPreferenceMask is the mask of the Prf (Default Router
// Preference) field within the flags byte of an NDPRouterAdvert.
ndpDefaultRouterPreferenceMask = (0b11 << ndpDefaultRouterPreferenceShift)
// ndpRARouterLifetimeOffset is the start of the 2-byte Router Lifetime
// field within an NDPRouterAdvert.
ndpRARouterLifetimeOffset = 2
// ndpRAReachableTimeOffset is the start of the 4-byte Reachable Time
// field within an NDPRouterAdvert.
ndpRAReachableTimeOffset = 4
// ndpRARetransTimerOffset is the start of the 4-byte Retrans Timer
// field within an NDPRouterAdvert.
ndpRARetransTimerOffset = 8
// ndpRAOptionsOffset is the start of the NDP options in an
// NDPRouterAdvert.
ndpRAOptionsOffset = 12
)
// CurrHopLimit returns the value of the Curr Hop Limit field.
func (b NDPRouterAdvert) CurrHopLimit() uint8 {
return b[ndpRACurrHopLimitOffset]
}
// ManagedAddrConfFlag returns the value of the Managed Address Configuration
// flag.
func (b NDPRouterAdvert) ManagedAddrConfFlag() bool {
return b[ndpRAFlagsOffset]&ndpRAManagedAddrConfFlagMask != 0
}
// OtherConfFlag returns the value of the Other Configuration flag.
func (b NDPRouterAdvert) OtherConfFlag() bool {
return b[ndpRAFlagsOffset]&ndpRAOtherConfFlagMask != 0
}
// DefaultRouterPreference returns the Default Router Preference field.
func (b NDPRouterAdvert) DefaultRouterPreference() NDPRoutePreference {
return NDPRoutePreference((b[ndpRAFlagsOffset] & ndpDefaultRouterPreferenceMask) >> ndpDefaultRouterPreferenceShift)
}
// RouterLifetime returns the lifetime associated with the default router. A
// value of 0 means the source of the Router Advertisement is not a default
// router and SHOULD NOT appear on the default router list. Note, a value of 0
// only means that the router should not be used as a default router, it does
// not apply to other information contained in the Router Advertisement.
func (b NDPRouterAdvert) RouterLifetime() time.Duration {
// The field is the time in seconds, as per RFC 4861 section 4.2.
return time.Second * time.Duration(binary.BigEndian.Uint16(b[ndpRARouterLifetimeOffset:]))
}
// ReachableTime returns the time that a node assumes a neighbor is reachable
// after having received a reachability confirmation. A value of 0 means
// that it is unspecified by the source of the Router Advertisement message.
func (b NDPRouterAdvert) ReachableTime() time.Duration {
// The field is the time in milliseconds, as per RFC 4861 section 4.2.
return time.Millisecond * time.Duration(binary.BigEndian.Uint32(b[ndpRAReachableTimeOffset:]))
}
// RetransTimer returns the time between retransmitted Neighbor Solicitation
// messages. A value of 0 means that it is unspecified by the source of the
// Router Advertisement message.
func (b NDPRouterAdvert) RetransTimer() time.Duration {
// The field is the time in milliseconds, as per RFC 4861 section 4.2.
return time.Millisecond * time.Duration(binary.BigEndian.Uint32(b[ndpRARetransTimerOffset:]))
}
// Options returns an NDPOptions of the options body.
func (b NDPRouterAdvert) Options() NDPOptions {
return NDPOptions(b[ndpRAOptionsOffset:])
}

View File

@@ -0,0 +1,36 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
// NDPRouterSolicit is an NDP Router Solicitation message. It will only contain
// the body of an ICMPv6 packet.
//
// See RFC 4861 section 4.1 for more details.
type NDPRouterSolicit []byte
const (
// NDPRSMinimumSize is the minimum size of a valid NDP Router
// Solicitation message (body of an ICMPv6 packet).
NDPRSMinimumSize = 4
// ndpRSOptionsOffset is the start of the NDP options in an
// NDPRouterSolicit.
ndpRSOptionsOffset = 4
)
// Options returns an NDPOptions of the options body.
func (b NDPRouterSolicit) Options() NDPOptions {
return NDPOptions(b[ndpRSOptionsOffset:])
}

View File

@@ -0,0 +1,58 @@
// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by "stringer -type ndpOptionIdentifier"; DO NOT EDIT.
package header
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ndpSourceLinkLayerAddressOptionType-1]
_ = x[ndpTargetLinkLayerAddressOptionType-2]
_ = x[ndpPrefixInformationType-3]
_ = x[ndpNonceOptionType-14]
_ = x[ndpRecursiveDNSServerOptionType-25]
_ = x[ndpDNSSearchListOptionType-31]
}
const (
_ndpOptionIdentifier_name_0 = "ndpSourceLinkLayerAddressOptionTypendpTargetLinkLayerAddressOptionTypendpPrefixInformationType"
_ndpOptionIdentifier_name_1 = "ndpNonceOptionType"
_ndpOptionIdentifier_name_2 = "ndpRecursiveDNSServerOptionType"
_ndpOptionIdentifier_name_3 = "ndpDNSSearchListOptionType"
)
var (
_ndpOptionIdentifier_index_0 = [...]uint8{0, 35, 70, 94}
)
func (i ndpOptionIdentifier) String() string {
switch {
case 1 <= i && i <= 3:
i -= 1
return _ndpOptionIdentifier_name_0[_ndpOptionIdentifier_index_0[i]:_ndpOptionIdentifier_index_0[i+1]]
case i == 14:
return _ndpOptionIdentifier_name_1
case i == 25:
return _ndpOptionIdentifier_name_2
case i == 31:
return _ndpOptionIdentifier_name_3
default:
return "ndpOptionIdentifier(" + strconv.FormatInt(int64(i), 10) + ")"
}
}

View File

@@ -0,0 +1,243 @@
// Copyright 2020 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package parse provides utilities to parse packets.
package parse
import (
"fmt"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
// ARP populates pkt's network header with an ARP header found in
// pkt.Data.
//
// Returns true if the header was successfully parsed.
func ARP(pkt *stack.PacketBuffer) bool {
_, ok := pkt.NetworkHeader().Consume(header.ARPSize)
if ok {
pkt.NetworkProtocolNumber = header.ARPProtocolNumber
}
return ok
}
// IPv4 parses an IPv4 packet found in pkt.Data and populates pkt's network
// header with the IPv4 header.
//
// Returns true if the header was successfully parsed.
func IPv4(pkt *stack.PacketBuffer) bool {
hdr, ok := pkt.Data().PullUp(header.IPv4MinimumSize)
if !ok {
return false
}
ipHdr := header.IPv4(hdr)
// Header may have options, determine the true header length.
headerLen := int(ipHdr.HeaderLength())
if headerLen < header.IPv4MinimumSize {
// TODO(gvisor.dev/issue/2404): Per RFC 791, IHL needs to be at least 5 in
// order for the packet to be valid. Figure out if we want to reject this
// case.
headerLen = header.IPv4MinimumSize
}
hdr, ok = pkt.NetworkHeader().Consume(headerLen)
if !ok {
return false
}
ipHdr = header.IPv4(hdr)
length := int(ipHdr.TotalLength()) - len(hdr)
if length < 0 {
return false
}
pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber
pkt.Data().CapLength(length)
return true
}
// IPv6 parses an IPv6 packet found in pkt.Data and populates pkt's network
// header with the IPv6 header.
func IPv6(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, fragID uint32, fragOffset uint16, fragMore bool, ok bool) {
hdr, ok := pkt.Data().PullUp(header.IPv6MinimumSize)
if !ok {
return 0, 0, 0, false, false
}
ipHdr := header.IPv6(hdr)
// Create a VV to parse the packet. We don't plan to modify anything here.
// dataVV consists of:
// - Any IPv6 header bytes after the first 40 (i.e. extensions).
// - The transport header, if present.
// - Any other payload data.
dataBuf := pkt.Data().ToBuffer()
dataBuf.TrimFront(header.IPv6MinimumSize)
it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(ipHdr.NextHeader()), dataBuf)
defer it.Release()
// Iterate over the IPv6 extensions to find their length.
var nextHdr tcpip.TransportProtocolNumber
var extensionsSize int64
traverseExtensions:
for {
extHdr, done, err := it.Next()
if err != nil {
break
}
// If we exhaust the extension list, the entire packet is the IPv6 header
// and (possibly) extensions.
if done {
extensionsSize = dataBuf.Size()
break
}
switch extHdr := extHdr.(type) {
case header.IPv6FragmentExtHdr:
if extHdr.IsAtomic() {
// This fragment extension header indicates that this packet is an
// atomic fragment. An atomic fragment is a fragment that contains
// all the data required to reassemble a full packet. As per RFC 6946,
// atomic fragments must not interfere with "normal" fragmented traffic
// so we skip processing the fragment instead of feeding it through the
// reassembly process below.
continue
}
if fragID == 0 && fragOffset == 0 && !fragMore {
fragID = extHdr.ID()
fragOffset = extHdr.FragmentOffset()
fragMore = extHdr.More()
}
rawPayload := it.AsRawHeader(true /* consume */)
extensionsSize = dataBuf.Size() - rawPayload.Buf.Size()
rawPayload.Release()
extHdr.Release()
break traverseExtensions
case header.IPv6RawPayloadHeader:
// We've found the payload after any extensions.
extensionsSize = dataBuf.Size() - extHdr.Buf.Size()
nextHdr = tcpip.TransportProtocolNumber(extHdr.Identifier)
extHdr.Release()
break traverseExtensions
default:
extHdr.Release()
// Any other extension is a no-op, keep looping until we find the payload.
}
}
// Put the IPv6 header with extensions in pkt.NetworkHeader().
hdr, ok = pkt.NetworkHeader().Consume(header.IPv6MinimumSize + int(extensionsSize))
if !ok {
panic(fmt.Sprintf("pkt.Data should have at least %d bytes, but only has %d.", header.IPv6MinimumSize+extensionsSize, pkt.Data().Size()))
}
ipHdr = header.IPv6(hdr)
pkt.Data().CapLength(int(ipHdr.PayloadLength()))
pkt.NetworkProtocolNumber = header.IPv6ProtocolNumber
return nextHdr, fragID, fragOffset, fragMore, true
}
// UDP parses a UDP packet found in pkt.Data and populates pkt's transport
// header with the UDP header.
//
// Returns true if the header was successfully parsed.
func UDP(pkt *stack.PacketBuffer) bool {
_, ok := pkt.TransportHeader().Consume(header.UDPMinimumSize)
pkt.TransportProtocolNumber = header.UDPProtocolNumber
return ok
}
// TCP parses a TCP packet found in pkt.Data and populates pkt's transport
// header with the TCP header.
//
// Returns true if the header was successfully parsed.
func TCP(pkt *stack.PacketBuffer) bool {
// TCP header is variable length, peek at it first.
hdrLen := header.TCPMinimumSize
hdr, ok := pkt.Data().PullUp(hdrLen)
if !ok {
return false
}
// If the header has options, pull those up as well.
if offset := int(header.TCP(hdr).DataOffset()); offset > header.TCPMinimumSize && offset <= pkt.Data().Size() {
// TODO(gvisor.dev/issue/2404): Figure out whether to reject this kind of
// packets.
hdrLen = offset
}
_, ok = pkt.TransportHeader().Consume(hdrLen)
pkt.TransportProtocolNumber = header.TCPProtocolNumber
return ok
}
// ICMPv4 populates the packet buffer's transport header with an ICMPv4 header,
// if present.
//
// Returns true if an ICMPv4 header was successfully parsed.
func ICMPv4(pkt *stack.PacketBuffer) bool {
if _, ok := pkt.TransportHeader().Consume(header.ICMPv4MinimumSize); ok {
pkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber
return true
}
return false
}
// ICMPv6 populates the packet buffer's transport header with an ICMPv4 header,
// if present.
//
// Returns true if an ICMPv6 header was successfully parsed.
func ICMPv6(pkt *stack.PacketBuffer) bool {
hdr, ok := pkt.Data().PullUp(header.ICMPv6MinimumSize)
if !ok {
return false
}
h := header.ICMPv6(hdr)
switch h.Type() {
case header.ICMPv6RouterSolicit,
header.ICMPv6RouterAdvert,
header.ICMPv6NeighborSolicit,
header.ICMPv6NeighborAdvert,
header.ICMPv6RedirectMsg,
header.ICMPv6MulticastListenerQuery,
header.ICMPv6MulticastListenerReport,
header.ICMPv6MulticastListenerV2Report,
header.ICMPv6MulticastListenerDone:
size := pkt.Data().Size()
if _, ok := pkt.TransportHeader().Consume(size); !ok {
panic(fmt.Sprintf("expected to consume the full data of size = %d bytes into transport header", size))
}
case header.ICMPv6DstUnreachable,
header.ICMPv6PacketTooBig,
header.ICMPv6TimeExceeded,
header.ICMPv6ParamProblem,
header.ICMPv6EchoRequest,
header.ICMPv6EchoReply:
fallthrough
default:
if _, ok := pkt.TransportHeader().Consume(header.ICMPv6MinimumSize); !ok {
// Checked above if the packet buffer holds at least the minimum size for
// an ICMPv6 packet.
panic(fmt.Sprintf("expected to consume %d bytes", header.ICMPv6MinimumSize))
}
}
pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
return true
}

View File

@@ -0,0 +1,3 @@
// automatically generated by stateify.
package parse

View File

@@ -0,0 +1,726 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"github.com/google/btree"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checksum"
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
)
// These constants are the offsets of the respective fields in the TCP header.
const (
TCPSrcPortOffset = 0
TCPDstPortOffset = 2
TCPSeqNumOffset = 4
TCPAckNumOffset = 8
TCPDataOffset = 12
TCPFlagsOffset = 13
TCPWinSizeOffset = 14
TCPChecksumOffset = 16
TCPUrgentPtrOffset = 18
)
const (
// MaxWndScale is maximum allowed window scaling, as described in
// RFC 1323, section 2.3, page 11.
MaxWndScale = 14
// TCPMaxSACKBlocks is the maximum number of SACK blocks that can
// be encoded in a TCP option field.
TCPMaxSACKBlocks = 4
)
// TCPFlags is the dedicated type for TCP flags.
type TCPFlags uint8
// Intersects returns true iff there are flags common to both f and o.
func (f TCPFlags) Intersects(o TCPFlags) bool {
return f&o != 0
}
// Contains returns true iff all the flags in o are contained within f.
func (f TCPFlags) Contains(o TCPFlags) bool {
return f&o == o
}
// String implements Stringer.String.
func (f TCPFlags) String() string {
flagsStr := []byte("FSRPAUEC")
for i := range flagsStr {
if f&(1<<uint(i)) == 0 {
flagsStr[i] = ' '
}
}
return string(flagsStr)
}
// Flags that may be set in a TCP segment.
const (
TCPFlagFin TCPFlags = 1 << iota
TCPFlagSyn
TCPFlagRst
TCPFlagPsh
TCPFlagAck
TCPFlagUrg
TCPFlagEce
TCPFlagCwr
)
// Options that may be present in a TCP segment.
const (
TCPOptionEOL = 0
TCPOptionNOP = 1
TCPOptionMSS = 2
TCPOptionWS = 3
TCPOptionTS = 8
TCPOptionSACKPermitted = 4
TCPOptionSACK = 5
)
// Option Lengths.
const (
TCPOptionMSSLength = 4
TCPOptionTSLength = 10
TCPOptionWSLength = 3
TCPOptionSackPermittedLength = 2
)
// TCPFields contains the fields of a TCP packet. It is used to describe the
// fields of a packet that needs to be encoded.
type TCPFields struct {
// SrcPort is the "source port" field of a TCP packet.
SrcPort uint16
// DstPort is the "destination port" field of a TCP packet.
DstPort uint16
// SeqNum is the "sequence number" field of a TCP packet.
SeqNum uint32
// AckNum is the "acknowledgement number" field of a TCP packet.
AckNum uint32
// DataOffset is the "data offset" field of a TCP packet. It is the length of
// the TCP header in bytes.
DataOffset uint8
// Flags is the "flags" field of a TCP packet.
Flags TCPFlags
// WindowSize is the "window size" field of a TCP packet.
WindowSize uint16
// Checksum is the "checksum" field of a TCP packet.
Checksum uint16
// UrgentPointer is the "urgent pointer" field of a TCP packet.
UrgentPointer uint16
}
// TCPSynOptions is used to return the parsed TCP Options in a syn
// segment.
//
// +stateify savable
type TCPSynOptions struct {
// MSS is the maximum segment size provided by the peer in the SYN.
MSS uint16
// WS is the window scale option provided by the peer in the SYN.
//
// Set to -1 if no window scale option was provided.
WS int
// TS is true if the timestamp option was provided in the syn/syn-ack.
TS bool
// TSVal is the value of the TSVal field in the timestamp option.
TSVal uint32
// TSEcr is the value of the TSEcr field in the timestamp option.
TSEcr uint32
// SACKPermitted is true if the SACK option was provided in the SYN/SYN-ACK.
SACKPermitted bool
// Flags if specified are set on the outgoing SYN. The SYN flag is
// always set.
Flags TCPFlags
}
// SACKBlock represents a single contiguous SACK block.
//
// +stateify savable
type SACKBlock struct {
// Start indicates the lowest sequence number in the block.
Start seqnum.Value
// End indicates the sequence number immediately following the last
// sequence number of this block.
End seqnum.Value
}
// Less returns true if r.Start < b.Start.
func (r SACKBlock) Less(b btree.Item) bool {
return r.Start.LessThan(b.(SACKBlock).Start)
}
// Contains returns true if b is completely contained in r.
func (r SACKBlock) Contains(b SACKBlock) bool {
return r.Start.LessThanEq(b.Start) && b.End.LessThanEq(r.End)
}
// TCPOptions are used to parse and cache the TCP segment options for a non
// syn/syn-ack segment.
//
// +stateify savable
type TCPOptions struct {
// TS is true if the TimeStamp option is enabled.
TS bool
// TSVal is the value in the TSVal field of the segment.
TSVal uint32
// TSEcr is the value in the TSEcr field of the segment.
TSEcr uint32
// SACKBlocks are the SACK blocks specified in the segment.
SACKBlocks []SACKBlock
}
// TCP represents a TCP header stored in a byte array.
type TCP []byte
const (
// TCPMinimumSize is the minimum size of a valid TCP packet.
TCPMinimumSize = 20
// TCPOptionsMaximumSize is the maximum size of TCP options.
TCPOptionsMaximumSize = 40
// TCPHeaderMaximumSize is the maximum header size of a TCP packet.
TCPHeaderMaximumSize = TCPMinimumSize + TCPOptionsMaximumSize
// TCPTotalHeaderMaximumSize is the maximum size of headers from all layers in
// a TCP packet. It analogous to MAX_TCP_HEADER in Linux.
//
// TODO(b/319936470): Investigate why this needs to be at least 140 bytes. In
// Linux this value is at least 160, but in theory we should be able to use
// 138. In practice anything less than 140 starts to break GSO on gVNIC
// hardware.
TCPTotalHeaderMaximumSize = 160
// TCPProtocolNumber is TCP's transport protocol number.
TCPProtocolNumber tcpip.TransportProtocolNumber = 6
// TCPMinimumMSS is the minimum acceptable value for MSS. This is the
// same as the value TCP_MIN_MSS defined net/tcp.h.
TCPMinimumMSS = IPv4MaximumHeaderSize + TCPHeaderMaximumSize + MinIPFragmentPayloadSize - IPv4MinimumSize - TCPMinimumSize
// TCPMinimumSendMSS is the minimum value for MSS in a sender. This is the
// same as the value TCP_MIN_SND_MSS in net/tcp.h.
TCPMinimumSendMSS = TCPOptionsMaximumSize + MinIPFragmentPayloadSize
// TCPMaximumMSS is the maximum acceptable value for MSS.
TCPMaximumMSS = 0xffff
// TCPDefaultMSS is the MSS value that should be used if an MSS option
// is not received from the peer. It's also the value returned by
// TCP_MAXSEG option for a socket in an unconnected state.
//
// Per RFC 1122, page 85: "If an MSS option is not received at
// connection setup, TCP MUST assume a default send MSS of 536."
TCPDefaultMSS = 536
)
// SourcePort returns the "source port" field of the TCP header.
func (b TCP) SourcePort() uint16 {
return binary.BigEndian.Uint16(b[TCPSrcPortOffset:])
}
// DestinationPort returns the "destination port" field of the TCP header.
func (b TCP) DestinationPort() uint16 {
return binary.BigEndian.Uint16(b[TCPDstPortOffset:])
}
// SequenceNumber returns the "sequence number" field of the TCP header.
func (b TCP) SequenceNumber() uint32 {
return binary.BigEndian.Uint32(b[TCPSeqNumOffset:])
}
// AckNumber returns the "ack number" field of the TCP header.
func (b TCP) AckNumber() uint32 {
return binary.BigEndian.Uint32(b[TCPAckNumOffset:])
}
// DataOffset returns the "data offset" field of the TCP header. The return
// value is the length of the TCP header in bytes.
func (b TCP) DataOffset() uint8 {
return (b[TCPDataOffset] >> 4) * 4
}
// Payload returns the data in the TCP packet.
func (b TCP) Payload() []byte {
return b[b.DataOffset():]
}
// Flags returns the flags field of the TCP header.
func (b TCP) Flags() TCPFlags {
return TCPFlags(b[TCPFlagsOffset])
}
// WindowSize returns the "window size" field of the TCP header.
func (b TCP) WindowSize() uint16 {
return binary.BigEndian.Uint16(b[TCPWinSizeOffset:])
}
// Checksum returns the "checksum" field of the TCP header.
func (b TCP) Checksum() uint16 {
return binary.BigEndian.Uint16(b[TCPChecksumOffset:])
}
// UrgentPointer returns the "urgent pointer" field of the TCP header.
func (b TCP) UrgentPointer() uint16 {
return binary.BigEndian.Uint16(b[TCPUrgentPtrOffset:])
}
// SetSourcePort sets the "source port" field of the TCP header.
func (b TCP) SetSourcePort(port uint16) {
binary.BigEndian.PutUint16(b[TCPSrcPortOffset:], port)
}
// SetDestinationPort sets the "destination port" field of the TCP header.
func (b TCP) SetDestinationPort(port uint16) {
binary.BigEndian.PutUint16(b[TCPDstPortOffset:], port)
}
// SetChecksum sets the checksum field of the TCP header.
func (b TCP) SetChecksum(xsum uint16) {
checksum.Put(b[TCPChecksumOffset:], xsum)
}
// SetDataOffset sets the data offset field of the TCP header. headerLen should
// be the length of the TCP header in bytes.
func (b TCP) SetDataOffset(headerLen uint8) {
b[TCPDataOffset] = (headerLen / 4) << 4
}
// SetSequenceNumber sets the sequence number field of the TCP header.
func (b TCP) SetSequenceNumber(seqNum uint32) {
binary.BigEndian.PutUint32(b[TCPSeqNumOffset:], seqNum)
}
// SetAckNumber sets the ack number field of the TCP header.
func (b TCP) SetAckNumber(ackNum uint32) {
binary.BigEndian.PutUint32(b[TCPAckNumOffset:], ackNum)
}
// SetFlags sets the flags field of the TCP header.
func (b TCP) SetFlags(flags uint8) {
b[TCPFlagsOffset] = flags
}
// SetWindowSize sets the window size field of the TCP header.
func (b TCP) SetWindowSize(rcvwnd uint16) {
binary.BigEndian.PutUint16(b[TCPWinSizeOffset:], rcvwnd)
}
// SetUrgentPointer sets the window size field of the TCP header.
func (b TCP) SetUrgentPointer(urgentPointer uint16) {
binary.BigEndian.PutUint16(b[TCPUrgentPtrOffset:], urgentPointer)
}
// CalculateChecksum calculates the checksum of the TCP segment.
// partialChecksum is the checksum of the network-layer pseudo-header
// and the checksum of the segment data.
func (b TCP) CalculateChecksum(partialChecksum uint16) uint16 {
// Calculate the rest of the checksum.
return checksum.Checksum(b[:b.DataOffset()], partialChecksum)
}
// IsChecksumValid returns true iff the TCP header's checksum is valid.
func (b TCP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum, payloadLength uint16) bool {
xsum := PseudoHeaderChecksum(TCPProtocolNumber, src, dst, uint16(b.DataOffset())+payloadLength)
xsum = checksum.Combine(xsum, payloadChecksum)
return b.CalculateChecksum(xsum) == 0xffff
}
// Options returns a slice that holds the unparsed TCP options in the segment.
func (b TCP) Options() []byte {
return b[TCPMinimumSize:b.DataOffset()]
}
// ParsedOptions returns a TCPOptions structure which parses and caches the TCP
// option values in the TCP segment. NOTE: Invoking this function repeatedly is
// expensive as it reparses the options on each invocation.
func (b TCP) ParsedOptions() TCPOptions {
return ParseTCPOptions(b.Options())
}
func (b TCP) encodeSubset(seq, ack uint32, flags TCPFlags, rcvwnd uint16) {
binary.BigEndian.PutUint32(b[TCPSeqNumOffset:], seq)
binary.BigEndian.PutUint32(b[TCPAckNumOffset:], ack)
b[TCPFlagsOffset] = uint8(flags)
binary.BigEndian.PutUint16(b[TCPWinSizeOffset:], rcvwnd)
}
// Encode encodes all the fields of the TCP header.
func (b TCP) Encode(t *TCPFields) {
b.encodeSubset(t.SeqNum, t.AckNum, t.Flags, t.WindowSize)
b.SetSourcePort(t.SrcPort)
b.SetDestinationPort(t.DstPort)
b.SetDataOffset(t.DataOffset)
b.SetChecksum(t.Checksum)
b.SetUrgentPointer(t.UrgentPointer)
}
// EncodePartial updates a subset of the fields of the TCP header. It is useful
// in cases when similar segments are produced.
func (b TCP) EncodePartial(partialChecksum, length uint16, seqnum, acknum uint32, flags TCPFlags, rcvwnd uint16) {
// Add the total length and "flags" field contributions to the checksum.
// We don't use the flags field directly from the header because it's a
// one-byte field with an odd offset, so it would be accounted for
// incorrectly by the Checksum routine.
tmp := make([]byte, 4)
binary.BigEndian.PutUint16(tmp, length)
binary.BigEndian.PutUint16(tmp[2:], uint16(flags))
xsum := checksum.Checksum(tmp, partialChecksum)
// Encode the passed-in fields.
b.encodeSubset(seqnum, acknum, flags, rcvwnd)
// Add the contributions of the passed-in fields to the checksum.
xsum = checksum.Checksum(b[TCPSeqNumOffset:TCPSeqNumOffset+8], xsum)
xsum = checksum.Checksum(b[TCPWinSizeOffset:TCPWinSizeOffset+2], xsum)
// Encode the checksum.
b.SetChecksum(^xsum)
}
// SetSourcePortWithChecksumUpdate implements ChecksummableTransport.
func (b TCP) SetSourcePortWithChecksumUpdate(new uint16) {
old := b.SourcePort()
b.SetSourcePort(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
}
// SetDestinationPortWithChecksumUpdate implements ChecksummableTransport.
func (b TCP) SetDestinationPortWithChecksumUpdate(new uint16) {
old := b.DestinationPort()
b.SetDestinationPort(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
}
// UpdateChecksumPseudoHeaderAddress implements ChecksummableTransport.
func (b TCP) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullChecksum bool) {
xsum := b.Checksum()
if fullChecksum {
xsum = ^xsum
}
xsum = checksumUpdate2ByteAlignedAddress(xsum, old, new)
if fullChecksum {
xsum = ^xsum
}
b.SetChecksum(xsum)
}
// ParseSynOptions parses the options received in a SYN segment and returns the
// relevant ones. opts should point to the option part of the TCP header.
func ParseSynOptions(opts []byte, isAck bool) TCPSynOptions {
limit := len(opts)
synOpts := TCPSynOptions{
// Per RFC 1122, page 85: "If an MSS option is not received at
// connection setup, TCP MUST assume a default send MSS of 536."
MSS: TCPDefaultMSS,
// If no window scale option is specified, WS in options is
// returned as -1; this is because the absence of the option
// indicates that the we cannot use window scaling on the
// receive end either.
WS: -1,
}
for i := 0; i < limit; {
switch opts[i] {
case TCPOptionEOL:
i = limit
case TCPOptionNOP:
i++
case TCPOptionMSS:
if i+4 > limit || opts[i+1] != 4 {
return synOpts
}
mss := uint16(opts[i+2])<<8 | uint16(opts[i+3])
if mss == 0 {
return synOpts
}
synOpts.MSS = mss
if mss < TCPMinimumSendMSS {
synOpts.MSS = TCPMinimumSendMSS
}
i += 4
case TCPOptionWS:
if i+3 > limit || opts[i+1] != 3 {
return synOpts
}
ws := int(opts[i+2])
if ws > MaxWndScale {
ws = MaxWndScale
}
synOpts.WS = ws
i += 3
case TCPOptionTS:
if i+10 > limit || opts[i+1] != 10 {
return synOpts
}
synOpts.TSVal = binary.BigEndian.Uint32(opts[i+2:])
if isAck {
// If the segment is a SYN-ACK then store the Timestamp Echo Reply
// in the segment.
synOpts.TSEcr = binary.BigEndian.Uint32(opts[i+6:])
}
synOpts.TS = true
i += 10
case TCPOptionSACKPermitted:
if i+2 > limit || opts[i+1] != 2 {
return synOpts
}
synOpts.SACKPermitted = true
i += 2
default:
// We don't recognize this option, just skip over it.
if i+2 > limit {
return synOpts
}
l := int(opts[i+1])
// If the length is incorrect or if l+i overflows the
// total options length then return false.
if l < 2 || i+l > limit {
return synOpts
}
i += l
}
}
return synOpts
}
// ParseTCPOptions extracts and stores all known options in the provided byte
// slice in a TCPOptions structure.
func ParseTCPOptions(b []byte) TCPOptions {
opts := TCPOptions{}
limit := len(b)
for i := 0; i < limit; {
switch b[i] {
case TCPOptionEOL:
i = limit
case TCPOptionNOP:
i++
case TCPOptionTS:
if i+10 > limit || (b[i+1] != 10) {
return opts
}
opts.TS = true
opts.TSVal = binary.BigEndian.Uint32(b[i+2:])
opts.TSEcr = binary.BigEndian.Uint32(b[i+6:])
i += 10
case TCPOptionSACK:
if i+2 > limit {
// Malformed SACK block, just return and stop parsing.
return opts
}
sackOptionLen := int(b[i+1])
if i+sackOptionLen > limit || (sackOptionLen-2)%8 != 0 {
// Malformed SACK block, just return and stop parsing.
return opts
}
numBlocks := (sackOptionLen - 2) / 8
opts.SACKBlocks = []SACKBlock{}
for j := 0; j < numBlocks; j++ {
start := binary.BigEndian.Uint32(b[i+2+j*8:])
end := binary.BigEndian.Uint32(b[i+2+j*8+4:])
opts.SACKBlocks = append(opts.SACKBlocks, SACKBlock{
Start: seqnum.Value(start),
End: seqnum.Value(end),
})
}
i += sackOptionLen
default:
// We don't recognize this option, just skip over it.
if i+2 > limit {
return opts
}
l := int(b[i+1])
// If the length is incorrect or if l+i overflows the
// total options length then return false.
if l < 2 || i+l > limit {
return opts
}
i += l
}
}
return opts
}
// EncodeMSSOption encodes the MSS TCP option with the provided MSS values in
// the supplied buffer. If the provided buffer is not large enough then it just
// returns without encoding anything. It returns the number of bytes written to
// the provided buffer.
func EncodeMSSOption(mss uint32, b []byte) int {
if len(b) < TCPOptionMSSLength {
return 0
}
b[0], b[1], b[2], b[3] = TCPOptionMSS, TCPOptionMSSLength, byte(mss>>8), byte(mss)
return TCPOptionMSSLength
}
// EncodeWSOption encodes the WS TCP option with the WS value in the
// provided buffer. If the provided buffer is not large enough then it just
// returns without encoding anything. It returns the number of bytes written to
// the provided buffer.
func EncodeWSOption(ws int, b []byte) int {
if len(b) < TCPOptionWSLength {
return 0
}
b[0], b[1], b[2] = TCPOptionWS, TCPOptionWSLength, uint8(ws)
return int(b[1])
}
// EncodeTSOption encodes the provided tsVal and tsEcr values as a TCP timestamp
// option into the provided buffer. If the buffer is smaller than expected it
// just returns without encoding anything. It returns the number of bytes
// written to the provided buffer.
func EncodeTSOption(tsVal, tsEcr uint32, b []byte) int {
if len(b) < TCPOptionTSLength {
return 0
}
b[0], b[1] = TCPOptionTS, TCPOptionTSLength
binary.BigEndian.PutUint32(b[2:], tsVal)
binary.BigEndian.PutUint32(b[6:], tsEcr)
return int(b[1])
}
// EncodeSACKPermittedOption encodes a SACKPermitted option into the provided
// buffer. If the buffer is smaller than required it just returns without
// encoding anything. It returns the number of bytes written to the provided
// buffer.
func EncodeSACKPermittedOption(b []byte) int {
if len(b) < TCPOptionSackPermittedLength {
return 0
}
b[0], b[1] = TCPOptionSACKPermitted, TCPOptionSackPermittedLength
return int(b[1])
}
// EncodeSACKBlocks encodes the provided SACK blocks as a TCP SACK option block
// in the provided slice. It tries to fit in as many blocks as possible based on
// number of bytes available in the provided buffer. It returns the number of
// bytes written to the provided buffer.
func EncodeSACKBlocks(sackBlocks []SACKBlock, b []byte) int {
if len(sackBlocks) == 0 {
return 0
}
l := len(sackBlocks)
if l > TCPMaxSACKBlocks {
l = TCPMaxSACKBlocks
}
if ll := (len(b) - 2) / 8; ll < l {
l = ll
}
if l == 0 {
// There is not enough space in the provided buffer to add
// any SACK blocks.
return 0
}
b[0] = TCPOptionSACK
b[1] = byte(l*8 + 2)
for i := 0; i < l; i++ {
binary.BigEndian.PutUint32(b[i*8+2:], uint32(sackBlocks[i].Start))
binary.BigEndian.PutUint32(b[i*8+6:], uint32(sackBlocks[i].End))
}
return int(b[1])
}
// EncodeNOP adds an explicit NOP to the option list.
func EncodeNOP(b []byte) int {
if len(b) == 0 {
return 0
}
b[0] = TCPOptionNOP
return 1
}
// AddTCPOptionPadding adds the required number of TCPOptionNOP to quad align
// the option buffer. It adds padding bytes after the offset specified and
// returns the number of padding bytes added. The passed in options slice
// must have space for the padding bytes.
func AddTCPOptionPadding(options []byte, offset int) int {
paddingToAdd := -offset & 3
// Now add any padding bytes that might be required to quad align the
// options.
for i := offset; i < offset+paddingToAdd; i++ {
options[i] = TCPOptionNOP
}
return paddingToAdd
}
// Acceptable checks if a segment that starts at segSeq and has length segLen is
// "acceptable" for arriving in a receive window that starts at rcvNxt and ends
// before rcvAcc, according to the table on page 26 and 69 of RFC 793.
func Acceptable(segSeq seqnum.Value, segLen seqnum.Size, rcvNxt, rcvAcc seqnum.Value) bool {
if rcvNxt == rcvAcc {
return segLen == 0 && segSeq == rcvNxt
}
if segLen == 0 {
// rcvWnd is incremented by 1 because that is Linux's behavior despite the
// RFC.
return segSeq.InRange(rcvNxt, rcvAcc.Add(1))
}
// Page 70 of RFC 793 allows packets that can be made "acceptable" by trimming
// the payload, so we'll accept any payload that overlaps the receive window.
// segSeq < rcvAcc is more correct according to RFC, however, Linux does it
// differently, it uses segSeq <= rcvAcc, we'd want to keep the same behavior
// as Linux.
return rcvNxt.LessThan(segSeq.Add(segLen)) && segSeq.LessThanEq(rcvAcc)
}
// TCPValid returns true if the pkt has a valid TCP header. It checks whether:
// - The data offset is too small.
// - The data offset is too large.
// - The checksum is invalid.
//
// TCPValid corresponds to net/netfilter/nf_conntrack_proto_tcp.c:tcp_error.
func TCPValid(hdr TCP, payloadChecksum func() uint16, payloadSize uint16, srcAddr, dstAddr tcpip.Address, skipChecksumValidation bool) (csum uint16, csumValid, ok bool) {
if offset := int(hdr.DataOffset()); offset < TCPMinimumSize || offset > len(hdr) {
return
}
if skipChecksumValidation {
csumValid = true
} else {
csum = hdr.Checksum()
csumValid = hdr.IsChecksumValid(srcAddr, dstAddr, payloadChecksum(), payloadSize)
}
return csum, csumValid, true
}

View File

@@ -0,0 +1,195 @@
// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import (
"encoding/binary"
"math"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checksum"
)
const (
udpSrcPort = 0
udpDstPort = 2
udpLength = 4
udpChecksum = 6
)
const (
// UDPMaximumPacketSize is the largest possible UDP packet.
UDPMaximumPacketSize = 0xffff
)
// UDPFields contains the fields of a UDP packet. It is used to describe the
// fields of a packet that needs to be encoded.
type UDPFields struct {
// SrcPort is the "source port" field of a UDP packet.
SrcPort uint16
// DstPort is the "destination port" field of a UDP packet.
DstPort uint16
// Length is the "length" field of a UDP packet.
Length uint16
// Checksum is the "checksum" field of a UDP packet.
Checksum uint16
}
// UDP represents a UDP header stored in a byte array.
type UDP []byte
const (
// UDPMinimumSize is the minimum size of a valid UDP packet.
UDPMinimumSize = 8
// UDPMaximumSize is the maximum size of a valid UDP packet. The length field
// in the UDP header is 16 bits as per RFC 768.
UDPMaximumSize = math.MaxUint16
// UDPProtocolNumber is UDP's transport protocol number.
UDPProtocolNumber tcpip.TransportProtocolNumber = 17
)
// SourcePort returns the "source port" field of the UDP header.
func (b UDP) SourcePort() uint16 {
return binary.BigEndian.Uint16(b[udpSrcPort:])
}
// DestinationPort returns the "destination port" field of the UDP header.
func (b UDP) DestinationPort() uint16 {
return binary.BigEndian.Uint16(b[udpDstPort:])
}
// Length returns the "length" field of the UDP header.
func (b UDP) Length() uint16 {
return binary.BigEndian.Uint16(b[udpLength:])
}
// Payload returns the data contained in the UDP datagram.
func (b UDP) Payload() []byte {
return b[UDPMinimumSize:]
}
// Checksum returns the "checksum" field of the UDP header.
func (b UDP) Checksum() uint16 {
return binary.BigEndian.Uint16(b[udpChecksum:])
}
// SetSourcePort sets the "source port" field of the UDP header.
func (b UDP) SetSourcePort(port uint16) {
binary.BigEndian.PutUint16(b[udpSrcPort:], port)
}
// SetDestinationPort sets the "destination port" field of the UDP header.
func (b UDP) SetDestinationPort(port uint16) {
binary.BigEndian.PutUint16(b[udpDstPort:], port)
}
// SetChecksum sets the "checksum" field of the UDP header.
func (b UDP) SetChecksum(xsum uint16) {
checksum.Put(b[udpChecksum:], xsum)
}
// SetLength sets the "length" field of the UDP header.
func (b UDP) SetLength(length uint16) {
binary.BigEndian.PutUint16(b[udpLength:], length)
}
// CalculateChecksum calculates the checksum of the UDP packet, given the
// checksum of the network-layer pseudo-header and the checksum of the payload.
func (b UDP) CalculateChecksum(partialChecksum uint16) uint16 {
// Calculate the rest of the checksum.
return checksum.Checksum(b[:UDPMinimumSize], partialChecksum)
}
// IsChecksumValid returns true iff the UDP header's checksum is valid.
func (b UDP) IsChecksumValid(src, dst tcpip.Address, payloadChecksum uint16) bool {
xsum := PseudoHeaderChecksum(UDPProtocolNumber, dst, src, b.Length())
xsum = checksum.Combine(xsum, payloadChecksum)
return b.CalculateChecksum(xsum) == 0xffff
}
// Encode encodes all the fields of the UDP header.
func (b UDP) Encode(u *UDPFields) {
b.SetSourcePort(u.SrcPort)
b.SetDestinationPort(u.DstPort)
b.SetLength(u.Length)
b.SetChecksum(u.Checksum)
}
// SetSourcePortWithChecksumUpdate implements ChecksummableTransport.
func (b UDP) SetSourcePortWithChecksumUpdate(new uint16) {
old := b.SourcePort()
b.SetSourcePort(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
}
// SetDestinationPortWithChecksumUpdate implements ChecksummableTransport.
func (b UDP) SetDestinationPortWithChecksumUpdate(new uint16) {
old := b.DestinationPort()
b.SetDestinationPort(new)
b.SetChecksum(^checksumUpdate2ByteAlignedUint16(^b.Checksum(), old, new))
}
// UpdateChecksumPseudoHeaderAddress implements ChecksummableTransport.
func (b UDP) UpdateChecksumPseudoHeaderAddress(old, new tcpip.Address, fullChecksum bool) {
xsum := b.Checksum()
if fullChecksum {
xsum = ^xsum
}
xsum = checksumUpdate2ByteAlignedAddress(xsum, old, new)
if fullChecksum {
xsum = ^xsum
}
b.SetChecksum(xsum)
}
// UDPValid returns true if the pkt has a valid UDP header. It checks whether:
// - The length field is too small.
// - The length field is too large.
// - The checksum is invalid.
//
// UDPValid corresponds to net/netfilter/nf_conntrack_proto_udp.c:udp_error.
func UDPValid(hdr UDP, payloadChecksum func() uint16, payloadSize uint16, netProto tcpip.NetworkProtocolNumber, srcAddr, dstAddr tcpip.Address, skipChecksumValidation bool) (lengthValid, csumValid bool) {
if length := hdr.Length(); length > payloadSize+UDPMinimumSize || length < UDPMinimumSize {
return false, false
}
if skipChecksumValidation {
return true, true
}
// On IPv4, UDP checksum is optional, and a zero value means the transmitter
// omitted the checksum generation, as per RFC 768:
//
// An all zero transmitted checksum value means that the transmitter
// generated no checksum (for debugging or for higher level protocols that
// don't care).
//
// On IPv6, UDP checksum is not optional, as per RFC 2460 Section 8.1:
//
// Unlike IPv4, when UDP packets are originated by an IPv6 node, the UDP
// checksum is not optional.
if netProto == IPv4ProtocolNumber && hdr.Checksum() == 0 {
return true, true
}
return true, hdr.IsChecksumValid(srcAddr, dstAddr, payloadChecksum())
}

View File

@@ -0,0 +1,94 @@
// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package header
import "encoding/binary"
// These constants are declared in linux/virtio_net.h.
const (
_VIRTIO_NET_HDR_F_NEEDS_CSUM = 1
_VIRTIO_NET_HDR_GSO_NONE = 0
_VIRTIO_NET_HDR_GSO_TCPV4 = 1
_VIRTIO_NET_HDR_GSO_TCPV6 = 4
)
const (
// VirtioNetHeaderSize is the size of VirtioNetHeader in bytes.
VirtioNetHeaderSize = 10
)
// Offsets for fields in the virtio net header.
const (
flags = 0
gsoType = 1
hdrLen = 2
gsoSize = 4
csumStart = 6
csumOffset = 8
)
// VirtioNetHeaderFields is the Go equivalent of the struct declared in
// linux/virtio_net.h.
type VirtioNetHeaderFields struct {
Flags uint8
GSOType uint8
HdrLen uint16
GSOSize uint16
CSumStart uint16
CSumOffset uint16
}
// VirtioNetHeader represents a virtio net header stored in a byte array.
type VirtioNetHeader []byte
// Flags returns the "flags" field of the virtio net header.
func (v VirtioNetHeader) Flags() uint8 {
return uint8(v[flags])
}
// GSOType returns the "gsoType" field of the virtio net header.
func (v VirtioNetHeader) GSOType() uint8 {
return uint8(v[gsoType])
}
// HdrLen returns the "hdrLen" field of the virtio net header.
func (v VirtioNetHeader) HdrLen() uint16 {
return binary.BigEndian.Uint16(v[hdrLen:])
}
// GSOSize returns the "gsoSize" field of the virtio net header.
func (v VirtioNetHeader) GSOSize() uint16 {
return binary.BigEndian.Uint16(v[gsoSize:])
}
// CSumStart returns the "csumStart" field of the virtio net header.
func (v VirtioNetHeader) CSumStart() uint16 {
return binary.BigEndian.Uint16(v[csumStart:])
}
// CSumOffset returns the "csumOffset" field of the virtio net header.
func (v VirtioNetHeader) CSumOffset() uint16 {
return binary.BigEndian.Uint16(v[csumOffset:])
}
// Encode encodes all the fields of the virtio net header.
func (v VirtioNetHeader) Encode(f *VirtioNetHeaderFields) {
v[flags] = uint8(f.Flags)
v[gsoType] = uint8(f.GSOType)
binary.BigEndian.PutUint16(v[hdrLen:], f.HdrLen)
binary.BigEndian.PutUint16(v[gsoSize:], f.GSOSize)
binary.BigEndian.PutUint16(v[csumStart:], f.CSumStart)
binary.BigEndian.PutUint16(v[csumOffset:], f.CSumOffset)
}