mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Extract ICMP error sender from UDP
Store transport protocol number on packet buffers for use in ICMP error generation. Updates #2211. PiperOrigin-RevId: 333252762
This commit is contained in:
committed by
gVisor bot
parent
b54dbdfdc6
commit
99decaadd6
@@ -31,6 +31,27 @@ const (
|
||||
// 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
|
||||
|
||||
@@ -39,15 +60,19 @@ const (
|
||||
icmpv4ChecksumOffset = 2
|
||||
|
||||
// icmpv4MTUOffset is the offset of the MTU field
|
||||
// in a ICMPv4FragmentationNeeded message.
|
||||
// in an ICMPv4FragmentationNeeded message.
|
||||
icmpv4MTUOffset = 6
|
||||
|
||||
// icmpv4IdentOffset is the offset of the ident field
|
||||
// in a ICMPv4EchoRequest/Reply message.
|
||||
// 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 a ICMPv4EchoRequest/Reply message.
|
||||
// in an ICMPv4EchoRequest/Reply message.
|
||||
icmpv4SequenceOffset = 6
|
||||
)
|
||||
|
||||
@@ -72,15 +97,23 @@ const (
|
||||
ICMPv4InfoReply ICMPv4Type = 16
|
||||
)
|
||||
|
||||
// ICMP codes for ICMPv4 Time Exceeded messages as defined in RFC 792.
|
||||
const (
|
||||
ICMPv4TTLExceeded ICMPv4Code = 0
|
||||
)
|
||||
|
||||
// ICMP codes for ICMPv4 Destination Unreachable messages as defined in RFC 792.
|
||||
const (
|
||||
ICMPv4TTLExceeded ICMPv4Code = 0
|
||||
ICMPv4NetUnreachable ICMPv4Code = 0
|
||||
ICMPv4HostUnreachable ICMPv4Code = 1
|
||||
ICMPv4ProtoUnreachable ICMPv4Code = 2
|
||||
ICMPv4PortUnreachable ICMPv4Code = 3
|
||||
ICMPv4FragmentationNeeded ICMPv4Code = 4
|
||||
)
|
||||
|
||||
// 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]) }
|
||||
|
||||
@@ -93,6 +126,15 @@ 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) }
|
||||
|
||||
// SetPointer sets the pointer field in a Parameter error packet.
|
||||
// This is the first byte of the type specific data field.
|
||||
func (b ICMPv4) SetPointer(c byte) { b[icmpv4PointerOffset] = c }
|
||||
|
||||
// SetTypeSpecific sets the full 32 bit type specific data field.
|
||||
func (b ICMPv4) SetTypeSpecific(val uint32) {
|
||||
binary.BigEndian.PutUint32(b[icmpv4PointerOffset:], val)
|
||||
}
|
||||
|
||||
// Checksum is the ICMP checksum field.
|
||||
func (b ICMPv4) Checksum() uint16 {
|
||||
return binary.BigEndian.Uint16(b[icmpv4ChecksumOffset:])
|
||||
|
||||
@@ -54,9 +54,17 @@ const (
|
||||
// address.
|
||||
ICMPv6NeighborAdvertSize = ICMPv6HeaderSize + NDPNAMinimumSize + NDPLinkLayerAddressSize
|
||||
|
||||
// ICMPv6EchoMinimumSize is the minimum size of a valid ICMP echo packet.
|
||||
// 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, Apendix 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
|
||||
@@ -69,6 +77,10 @@ const (
|
||||
// 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
|
||||
@@ -89,9 +101,10 @@ const (
|
||||
NDPHopLimit = 255
|
||||
)
|
||||
|
||||
// ICMPv6Type is the ICMP type field described in RFC 4443 and friends.
|
||||
// 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
|
||||
@@ -109,7 +122,18 @@ const (
|
||||
ICMPv6RedirectMsg ICMPv6Type = 137
|
||||
)
|
||||
|
||||
// ICMPv6Code is the ICMP code field described in RFC 4443.
|
||||
// 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
|
||||
@@ -153,6 +177,11 @@ 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) }
|
||||
|
||||
// SetTypeSpecific sets the full 32 bit 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:])
|
||||
|
||||
@@ -80,7 +80,8 @@ type IPv4Fields struct {
|
||||
type IPv4 []byte
|
||||
|
||||
const (
|
||||
// IPv4MinimumSize is the minimum size of a valid IPv4 packet.
|
||||
// IPv4MinimumSize is the minimum size of a valid IPv4 packet;
|
||||
// i.e. a packet header with no options.
|
||||
IPv4MinimumSize = 20
|
||||
|
||||
// IPv4MaximumHeaderSize is the maximum size of an IPv4 header. Given
|
||||
@@ -327,7 +328,7 @@ func IsV4MulticastAddress(addr tcpip.Address) bool {
|
||||
}
|
||||
|
||||
// IsV4LoopbackAddress determines if the provided address is an IPv4 loopback
|
||||
// address (belongs to 127.0.0.1/8 subnet).
|
||||
// address (belongs to 127.0.0.0/8 subnet). See RFC 1122 section 3.2.1.3.
|
||||
func IsV4LoopbackAddress(addr tcpip.Address) bool {
|
||||
if len(addr) != IPv4AddressSize {
|
||||
return false
|
||||
|
||||
@@ -238,6 +238,12 @@ func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNu
|
||||
return 0, false, parse.ARP(pkt)
|
||||
}
|
||||
|
||||
// ReturnError implements stack.TransportProtocol.ReturnError.
|
||||
func (*protocol) ReturnError(*stack.Route, tcpip.ICMPReason, *stack.PacketBuffer) *tcpip.Error {
|
||||
// In ARP, there is no such response so do nothing.
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewProtocol returns an ARP network protocol.
|
||||
func NewProtocol() stack.NetworkProtocol {
|
||||
return &protocol{}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package ipv4
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
@@ -105,7 +106,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
// source address MUST be one of its own IP addresses (but not a broadcast
|
||||
// or multicast address).
|
||||
localAddr := r.LocalAddress
|
||||
if r.IsInboundBroadcast() || header.IsV4MulticastAddress(r.LocalAddress) {
|
||||
if r.IsInboundBroadcast() || header.IsV4MulticastAddress(localAddr) {
|
||||
localAddr = ""
|
||||
}
|
||||
|
||||
@@ -131,7 +132,10 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
ReserveHeaderBytes: int(r.MaxHeaderLength()),
|
||||
Data: dataVV,
|
||||
})
|
||||
|
||||
// TODO(gvisor.dev/issue/3810): When adding protocol numbers into the header
|
||||
// information we will have to change this code to handle the ICMP header
|
||||
// no longer being in the data buffer.
|
||||
replyPkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber
|
||||
// Send out the reply packet.
|
||||
sent := stats.ICMP.V4PacketsSent
|
||||
if err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{
|
||||
@@ -193,3 +197,175 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
received.Invalid.Increment()
|
||||
}
|
||||
}
|
||||
|
||||
// ======= ICMP Error packet generation =========
|
||||
|
||||
// ReturnError implements stack.TransportProtocol.ReturnError.
|
||||
func (p *protocol) ReturnError(r *stack.Route, reason tcpip.ICMPReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
switch reason.(type) {
|
||||
case *tcpip.ICMPReasonPortUnreachable:
|
||||
return returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
default:
|
||||
return tcpip.ErrNotSupported
|
||||
}
|
||||
}
|
||||
|
||||
// icmpReason is a marker interface for IPv4 specific ICMP errors.
|
||||
type icmpReason interface {
|
||||
isICMPReason()
|
||||
}
|
||||
|
||||
// icmpReasonPortUnreachable is an error where the transport protocol has no
|
||||
// listener and no alternative means to inform the sender.
|
||||
type icmpReasonPortUnreachable struct{}
|
||||
|
||||
func (*icmpReasonPortUnreachable) isICMPReason() {}
|
||||
|
||||
// returnError takes an error descriptor and generates the appropriate ICMP
|
||||
// error packet for IPv4 and sends it back to the remote device that sent
|
||||
// the problematic packet. It incorporates as much of that packet as
|
||||
// possible as well as any error metadata as is available. returnError
|
||||
// expects pkt to hold a valid IPv4 packet as per the wire format.
|
||||
func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
sent := r.Stats().ICMP.V4PacketsSent
|
||||
if !r.Stack().AllowICMPMessage() {
|
||||
sent.RateLimited.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
// We check we are responding only when we are allowed to.
|
||||
// See RFC 1812 section 4.3.2.7 (shown below).
|
||||
//
|
||||
// =========
|
||||
// 4.3.2.7 When Not to Send ICMP Errors
|
||||
//
|
||||
// An ICMP error message MUST NOT be sent as the result of receiving:
|
||||
//
|
||||
// o An ICMP error message, or
|
||||
//
|
||||
// o A packet which fails the IP header validation tests described in
|
||||
// Section [5.2.2] (except where that section specifically permits
|
||||
// the sending of an ICMP error message), or
|
||||
//
|
||||
// o A packet destined to an IP broadcast or IP multicast address, or
|
||||
//
|
||||
// o A packet sent as a Link Layer broadcast or multicast, or
|
||||
//
|
||||
// o Any fragment of a datagram other then the first fragment (i.e., a
|
||||
// packet for which the fragment offset in the IP header is nonzero).
|
||||
//
|
||||
// TODO(gvisor.dev/issues/4058): Make sure we don't send ICMP errors in
|
||||
// response to a non-initial fragment, but it currently can not happen.
|
||||
|
||||
if r.IsInboundBroadcast() || header.IsV4MulticastAddress(r.LocalAddress) || r.RemoteAddress == header.IPv4Any {
|
||||
return nil
|
||||
}
|
||||
|
||||
networkHeader := pkt.NetworkHeader().View()
|
||||
transportHeader := pkt.TransportHeader().View()
|
||||
|
||||
// Don't respond to icmp error packets.
|
||||
if header.IPv4(networkHeader).Protocol() == uint8(header.ICMPv4ProtocolNumber) {
|
||||
// TODO(gvisor.dev/issue/3810):
|
||||
// Unfortunately the current stack pretty much always has ICMPv4 headers
|
||||
// in the Data section of the packet but there is no guarantee that is the
|
||||
// case. If this is the case grab the header to make it like all other
|
||||
// packet types. When this is cleaned up the Consume should be removed.
|
||||
if transportHeader.IsEmpty() {
|
||||
var ok bool
|
||||
transportHeader, ok = pkt.TransportHeader().Consume(header.ICMPv4MinimumSize)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
} else if transportHeader.Size() < header.ICMPv4MinimumSize {
|
||||
return nil
|
||||
}
|
||||
// We need to decide to explicitly name the packets we can respond to or
|
||||
// the ones we can not respond to. The decision is somewhat arbitrary and
|
||||
// if problems arise this could be reversed. It was judged less of a breach
|
||||
// of protocol to not respond to unknown non-error packets than to respond
|
||||
// to unknown error packets so we take the first approach.
|
||||
switch header.ICMPv4(transportHeader).Type() {
|
||||
case
|
||||
header.ICMPv4EchoReply,
|
||||
header.ICMPv4Echo,
|
||||
header.ICMPv4Timestamp,
|
||||
header.ICMPv4TimestampReply,
|
||||
header.ICMPv4InfoRequest,
|
||||
header.ICMPv4InfoReply:
|
||||
default:
|
||||
// Assume any type we don't know about may be an error type.
|
||||
return nil
|
||||
}
|
||||
} else if transportHeader.IsEmpty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Now work out how much of the triggering packet we should return.
|
||||
// As per RFC 1812 Section 4.3.2.3
|
||||
//
|
||||
// ICMP datagram SHOULD contain as much of the original
|
||||
// datagram as possible without the length of the ICMP
|
||||
// datagram exceeding 576 bytes.
|
||||
//
|
||||
// NOTE: The above RFC referenced is different from the original
|
||||
// recommendation in RFC 1122 and RFC 792 where it mentioned that at
|
||||
// least 8 bytes of the payload must be included. Today linux and other
|
||||
// systems implement the RFC 1812 definition and not the original
|
||||
// requirement. We treat 8 bytes as the minimum but will try send more.
|
||||
mtu := int(r.MTU())
|
||||
if mtu > header.IPv4MinimumProcessableDatagramSize {
|
||||
mtu = header.IPv4MinimumProcessableDatagramSize
|
||||
}
|
||||
headerLen := int(r.MaxHeaderLength()) + header.ICMPv4MinimumSize
|
||||
available := int(mtu) - headerLen
|
||||
|
||||
if available < header.IPv4MinimumSize+header.ICMPv4MinimumErrorPayloadSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
payloadLen := networkHeader.Size() + transportHeader.Size() + pkt.Data.Size()
|
||||
if payloadLen > available {
|
||||
payloadLen = available
|
||||
}
|
||||
|
||||
// The buffers used by pkt may be used elsewhere in the system.
|
||||
// For example, an AF_RAW or AF_PACKET socket may use what the transport
|
||||
// protocol considers an unreachable destination. Thus we deep copy pkt to
|
||||
// prevent multiple ownership and SR errors. The new copy is a vectorized
|
||||
// view with the entire incoming IP packet reassembled and truncated as
|
||||
// required. This is now the payload of the new ICMP packet and no longer
|
||||
// considered a packet in its own right.
|
||||
newHeader := append(buffer.View(nil), networkHeader...)
|
||||
newHeader = append(newHeader, transportHeader...)
|
||||
payload := newHeader.ToVectorisedView()
|
||||
payload.AppendView(pkt.Data.ToView())
|
||||
payload.CapLength(payloadLen)
|
||||
|
||||
icmpPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: headerLen,
|
||||
Data: payload,
|
||||
})
|
||||
icmpPkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber
|
||||
|
||||
icmpHdr := header.ICMPv4(icmpPkt.TransportHeader().Push(header.ICMPv4MinimumSize))
|
||||
icmpHdr.SetType(header.ICMPv4DstUnreachable)
|
||||
icmpHdr.SetCode(header.ICMPv4PortUnreachable)
|
||||
counter := sent.DstUnreachable
|
||||
icmpHdr.SetChecksum(header.ICMPv4Checksum(icmpHdr, icmpPkt.Data))
|
||||
|
||||
if err := r.WritePacket(
|
||||
nil, /* gso */
|
||||
stack.NetworkHeaderParams{
|
||||
Protocol: header.ICMPv4ProtocolNumber,
|
||||
TTL: r.DefaultTTL(),
|
||||
TOS: stack.DefaultTOS,
|
||||
},
|
||||
icmpPkt,
|
||||
); err != nil {
|
||||
sent.Dropped.Increment()
|
||||
return err
|
||||
}
|
||||
counter.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -455,6 +455,10 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
}
|
||||
p := h.TransportProtocol()
|
||||
if p == header.ICMPv4ProtocolNumber {
|
||||
// TODO(gvisor.dev/issues/3810): when we sort out ICMP and transport
|
||||
// headers, the setting of the transport number here should be
|
||||
// unnecessary and removed.
|
||||
pkt.TransportProtocolNumber = p
|
||||
e.handleICMP(r, pkt)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -318,6 +318,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
ReserveHeaderBytes: int(r.MaxHeaderLength()) + header.ICMPv6NeighborAdvertMinimumSize + int(optsSerializer.Length()),
|
||||
})
|
||||
packet := header.ICMPv6(pkt.TransportHeader().Push(header.ICMPv6NeighborAdvertSize))
|
||||
pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
packet.SetType(header.ICMPv6NeighborAdvert)
|
||||
na := header.NDPNeighborAdvert(packet.NDPPayload())
|
||||
na.SetSolicitedFlag(solicited)
|
||||
@@ -438,6 +439,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
|
||||
Data: pkt.Data,
|
||||
})
|
||||
packet := header.ICMPv6(replyPkt.TransportHeader().Push(header.ICMPv6EchoMinimumSize))
|
||||
pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
copy(packet, icmpHdr)
|
||||
packet.SetType(header.ICMPv6EchoReply)
|
||||
packet.SetChecksum(header.ICMPv6Checksum(packet, r.LocalAddress, r.RemoteAddress, pkt.Data))
|
||||
@@ -637,6 +639,7 @@ func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAdd
|
||||
ReserveHeaderBytes: int(linkEP.MaxHeaderLength()) + header.IPv6MinimumSize + header.ICMPv6NeighborAdvertSize,
|
||||
})
|
||||
icmpHdr := header.ICMPv6(pkt.TransportHeader().Push(header.ICMPv6NeighborAdvertSize))
|
||||
pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
icmpHdr.SetType(header.ICMPv6NeighborSolicit)
|
||||
copy(icmpHdr[icmpV6OptOffset-len(addr):], addr)
|
||||
icmpHdr[icmpV6OptOffset] = ndpOptSrcLinkAddr
|
||||
@@ -665,3 +668,123 @@ func (*protocol) ResolveStaticAddress(addr tcpip.Address) (tcpip.LinkAddress, bo
|
||||
}
|
||||
return tcpip.LinkAddress([]byte(nil)), false
|
||||
}
|
||||
|
||||
// ======= ICMP Error packet generation =========
|
||||
|
||||
// ReturnError implements stack.TransportProtocol.ReturnError.
|
||||
func (p *protocol) ReturnError(r *stack.Route, reason tcpip.ICMPReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
switch reason.(type) {
|
||||
case *tcpip.ICMPReasonPortUnreachable:
|
||||
return returnError(r, &icmpReasonPortUnreachable{}, pkt)
|
||||
default:
|
||||
return tcpip.ErrNotSupported
|
||||
}
|
||||
}
|
||||
|
||||
// icmpReason is a marker interface for IPv6 specific ICMP errors.
|
||||
type icmpReason interface {
|
||||
isICMPReason()
|
||||
}
|
||||
|
||||
// icmpReasonPortUnreachable is an error where the transport protocol has no
|
||||
// listener and no alternative means to inform the sender.
|
||||
type icmpReasonPortUnreachable struct{}
|
||||
|
||||
func (*icmpReasonPortUnreachable) isICMPReason() {}
|
||||
|
||||
// returnError takes an error descriptor and generates the appropriate ICMP
|
||||
// error packet for IPv6 and sends it.
|
||||
func returnError(r *stack.Route, reason icmpReason, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
stats := r.Stats().ICMP
|
||||
sent := stats.V6PacketsSent
|
||||
if !r.Stack().AllowICMPMessage() {
|
||||
sent.RateLimited.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only send ICMP error if the address is not a multicast v6
|
||||
// address and the source is not the unspecified address.
|
||||
//
|
||||
// TODO(b/164522993) There are exceptions to this rule.
|
||||
// See: point e.3) RFC 4443 section-2.4
|
||||
//
|
||||
// (e) An ICMPv6 error message MUST NOT be originated as a result of
|
||||
// receiving the following:
|
||||
//
|
||||
// (e.1) An ICMPv6 error message.
|
||||
//
|
||||
// (e.2) An ICMPv6 redirect message [IPv6-DISC].
|
||||
//
|
||||
// (e.3) A packet destined to an IPv6 multicast address. (There are
|
||||
// two exceptions to this rule: (1) the Packet Too Big Message
|
||||
// (Section 3.2) to allow Path MTU discovery to work for IPv6
|
||||
// multicast, and (2) the Parameter Problem Message, Code 2
|
||||
// (Section 3.4) reporting an unrecognized IPv6 option (see
|
||||
// Section 4.2 of [IPv6]) that has the Option Type highest-
|
||||
// order two bits set to 10).
|
||||
//
|
||||
if header.IsV6MulticastAddress(r.LocalAddress) || r.RemoteAddress == header.IPv6Any {
|
||||
return nil
|
||||
}
|
||||
|
||||
network, transport := pkt.NetworkHeader().View(), pkt.TransportHeader().View()
|
||||
|
||||
if pkt.TransportProtocolNumber == header.ICMPv6ProtocolNumber {
|
||||
// TODO(gvisor.dev/issues/3810): Sort this out when ICMP headers are stored.
|
||||
// Unfortunately at this time ICMP Packets do not have a transport
|
||||
// header separated out. It is in the Data part so we need to
|
||||
// separate it out now. We will just pretend it is a minimal length
|
||||
// ICMP packet as we don't really care if any later bits of a
|
||||
// larger ICMP packet are in the header view or in the Data view.
|
||||
transport, ok := pkt.TransportHeader().Consume(header.ICMPv6MinimumSize)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
typ := header.ICMPv6(transport).Type()
|
||||
if typ.IsErrorType() || typ == header.ICMPv6RedirectMsg {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// As per RFC 4443 section 2.4
|
||||
//
|
||||
// (c) Every ICMPv6 error message (type < 128) MUST include
|
||||
// as much of the IPv6 offending (invoking) packet (the
|
||||
// packet that caused the error) as possible without making
|
||||
// the error message packet exceed the minimum IPv6 MTU
|
||||
// [IPv6].
|
||||
mtu := int(r.MTU())
|
||||
if mtu > header.IPv6MinimumMTU {
|
||||
mtu = header.IPv6MinimumMTU
|
||||
}
|
||||
headerLen := int(r.MaxHeaderLength()) + header.ICMPv6ErrorHeaderSize
|
||||
available := int(mtu) - headerLen
|
||||
if available < header.IPv6MinimumSize {
|
||||
return nil
|
||||
}
|
||||
payloadLen := network.Size() + transport.Size() + pkt.Data.Size()
|
||||
if payloadLen > available {
|
||||
payloadLen = available
|
||||
}
|
||||
payload := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
|
||||
payload.CapLength(payloadLen)
|
||||
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: headerLen,
|
||||
Data: payload,
|
||||
})
|
||||
newPkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
|
||||
icmpHdr := header.ICMPv6(newPkt.TransportHeader().Push(header.ICMPv6DstUnreachableMinimumSize))
|
||||
icmpHdr.SetCode(header.ICMPv6PortUnreachable)
|
||||
icmpHdr.SetType(header.ICMPv6DstUnreachable)
|
||||
icmpHdr.SetChecksum(header.ICMPv6Checksum(icmpHdr, r.LocalAddress, r.RemoteAddress, newPkt.Data))
|
||||
counter := sent.DstUnreachable
|
||||
err := r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: r.DefaultTTL(), TOS: stack.DefaultTOS}, newPkt)
|
||||
if err != nil {
|
||||
sent.Dropped.Increment()
|
||||
return err
|
||||
}
|
||||
counter.Increment()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
it, done, err := it.Next()
|
||||
if err != nil {
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedPacketsReceived.Increment()
|
||||
r.Stats().IP.MalformedFragmentsReceived.Increment()
|
||||
return
|
||||
}
|
||||
if done {
|
||||
@@ -476,6 +476,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
pkt.Data = extHdr.Buf
|
||||
|
||||
if p := tcpip.TransportProtocolNumber(extHdr.Identifier); p == header.ICMPv6ProtocolNumber {
|
||||
pkt.TransportProtocolNumber = p
|
||||
e.handleICMP(r, pkt, hasFragmentHeader)
|
||||
} else {
|
||||
r.Stats().IP.PacketsDelivered.Increment()
|
||||
|
||||
@@ -145,6 +145,10 @@ func (*fwdTestNetworkProtocol) Parse(pkt *PacketBuffer) (tcpip.TransportProtocol
|
||||
return tcpip.TransportProtocolNumber(netHeader[protocolNumberOffset]), true, true
|
||||
}
|
||||
|
||||
func (*fwdTestNetworkProtocol) ReturnError(*Route, tcpip.ICMPReason, *PacketBuffer) *tcpip.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fwdTestNetworkProtocol) NewEndpoint(nicID tcpip.NICID, _ LinkAddressCache, _ NUDHandler, dispatcher TransportDispatcher, ep LinkEndpoint, _ *Stack) NetworkEndpoint {
|
||||
return &fwdTestNetworkEndpoint{
|
||||
nicID: nicID,
|
||||
|
||||
+24
-5
@@ -1242,9 +1242,9 @@ func (n *NIC) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcp
|
||||
local = n.linkEP.LinkAddress()
|
||||
}
|
||||
|
||||
// Are any packet sockets listening for this network protocol?
|
||||
// Are any packet type sockets listening for this network protocol?
|
||||
packetEPs := n.mu.packetEPs[protocol]
|
||||
// Add any other packet sockets that maybe listening for all protocols.
|
||||
// Add any other packet type sockets that may be listening for all protocols.
|
||||
packetEPs = append(packetEPs, n.mu.packetEPs[header.EthernetProtocolAll]...)
|
||||
n.mu.RUnlock()
|
||||
for _, ep := range packetEPs {
|
||||
@@ -1265,6 +1265,7 @@ func (n *NIC) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcp
|
||||
return
|
||||
}
|
||||
if hasTransportHdr {
|
||||
pkt.TransportProtocolNumber = transProtoNum
|
||||
// Parse the transport header if present.
|
||||
if state, ok := n.stack.transportProtocols[transProtoNum]; ok {
|
||||
state.proto.Parse(pkt)
|
||||
@@ -1453,10 +1454,28 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN
|
||||
}
|
||||
}
|
||||
|
||||
// We could not find an appropriate destination for this packet, so
|
||||
// deliver it to the global handler.
|
||||
if !transProto.HandleUnknownDestinationPacket(r, id, pkt) {
|
||||
// We could not find an appropriate destination for this packet so
|
||||
// give the protocol specific error handler a chance to handle it.
|
||||
// If it doesn't handle it then we should do so.
|
||||
switch transProto.HandleUnknownDestinationPacket(r, id, pkt) {
|
||||
case UnknownDestinationPacketMalformed:
|
||||
n.stack.stats.MalformedRcvdPackets.Increment()
|
||||
case UnknownDestinationPacketUnhandled:
|
||||
// As per RFC: 1122 Section 3.2.2.1 A host SHOULD generate Destination
|
||||
// Unreachable messages with code:
|
||||
// 3 (Port Unreachable), when the designated transport protocol
|
||||
// (e.g., UDP) is unable to demultiplex the datagram but has no
|
||||
// protocol mechanism to inform the sender.
|
||||
np, ok := n.stack.networkProtocols[r.NetProto]
|
||||
if !ok {
|
||||
// For this to happen stack.makeRoute() must have been called with the
|
||||
// incorrect protocol number. Since we have successfully completed
|
||||
// network layer processing this should be impossible.
|
||||
panic(fmt.Sprintf("expected stack to have a NetworkProtocol for proto = %d", r.NetProto))
|
||||
}
|
||||
|
||||
_ = np.ReturnError(r, &tcpip.ICMPReasonPortUnreachable{}, pkt)
|
||||
case UnknownDestinationPacketHandled:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,6 +221,11 @@ func (*testIPv6Protocol) Parse(*PacketBuffer) (tcpip.TransportProtocolNumber, bo
|
||||
return 0, false, false
|
||||
}
|
||||
|
||||
// ReturnError implements NetworkProtocol.ReturnError.
|
||||
func (*testIPv6Protocol) ReturnError(*Route, tcpip.ICMPReason, *PacketBuffer) *tcpip.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ LinkAddressResolver = (*testIPv6Protocol)(nil)
|
||||
|
||||
// LinkAddressProtocol implements LinkAddressResolver.
|
||||
|
||||
@@ -80,11 +80,17 @@ type PacketBuffer struct {
|
||||
// data are held in the same underlying buffer storage.
|
||||
header buffer.Prependable
|
||||
|
||||
// NetworkProtocolNumber is only valid when NetworkHeader is set.
|
||||
// NetworkProtocolNumber is only valid when NetworkHeader().View().IsEmpty()
|
||||
// returns false.
|
||||
// TODO(gvisor.dev/issue/3574): Remove the separately passed protocol
|
||||
// numbers in registration APIs that take a PacketBuffer.
|
||||
NetworkProtocolNumber tcpip.NetworkProtocolNumber
|
||||
|
||||
// TransportProtocol is only valid if it is non zero.
|
||||
// TODO(gvisor.dev/issue/3810): This and the network protocol number should
|
||||
// be moved into the headerinfo. This should resolve the validity issue.
|
||||
TransportProtocolNumber tcpip.TransportProtocolNumber
|
||||
|
||||
// Hash is the transport layer hash of this packet. A value of zero
|
||||
// indicates no valid hash has been set.
|
||||
Hash uint32
|
||||
@@ -234,16 +240,17 @@ func (pk *PacketBuffer) consume(typ headerType, size int) (v buffer.View, consum
|
||||
// underlying packet payload.
|
||||
func (pk *PacketBuffer) Clone() *PacketBuffer {
|
||||
newPk := &PacketBuffer{
|
||||
PacketBufferEntry: pk.PacketBufferEntry,
|
||||
Data: pk.Data.Clone(nil),
|
||||
headers: pk.headers,
|
||||
header: pk.header,
|
||||
Hash: pk.Hash,
|
||||
Owner: pk.Owner,
|
||||
EgressRoute: pk.EgressRoute,
|
||||
GSOOptions: pk.GSOOptions,
|
||||
NetworkProtocolNumber: pk.NetworkProtocolNumber,
|
||||
NatDone: pk.NatDone,
|
||||
PacketBufferEntry: pk.PacketBufferEntry,
|
||||
Data: pk.Data.Clone(nil),
|
||||
headers: pk.headers,
|
||||
header: pk.header,
|
||||
Hash: pk.Hash,
|
||||
Owner: pk.Owner,
|
||||
EgressRoute: pk.EgressRoute,
|
||||
GSOOptions: pk.GSOOptions,
|
||||
NetworkProtocolNumber: pk.NetworkProtocolNumber,
|
||||
NatDone: pk.NatDone,
|
||||
TransportProtocolNumber: pk.TransportProtocolNumber,
|
||||
}
|
||||
return newPk
|
||||
}
|
||||
|
||||
@@ -125,6 +125,26 @@ type PacketEndpoint interface {
|
||||
HandlePacket(nicID tcpip.NICID, addr tcpip.LinkAddress, netProto tcpip.NetworkProtocolNumber, pkt *PacketBuffer)
|
||||
}
|
||||
|
||||
// UnknownDestinationPacketDisposition enumerates the possible return vaues from
|
||||
// HandleUnknownDestinationPacket().
|
||||
type UnknownDestinationPacketDisposition int
|
||||
|
||||
const (
|
||||
// UnknownDestinationPacketMalformed denotes that the packet was malformed
|
||||
// and no further processing should be attempted other than updating
|
||||
// statistics.
|
||||
UnknownDestinationPacketMalformed UnknownDestinationPacketDisposition = iota
|
||||
|
||||
// UnknownDestinationPacketUnhandled tells the caller that the packet was
|
||||
// well formed but that the issue was not handled and the stack should take
|
||||
// the default action.
|
||||
UnknownDestinationPacketUnhandled
|
||||
|
||||
// UnknownDestinationPacketHandled tells the caller that it should do
|
||||
// no further processing.
|
||||
UnknownDestinationPacketHandled
|
||||
)
|
||||
|
||||
// TransportProtocol is the interface that needs to be implemented by transport
|
||||
// protocols (e.g., tcp, udp) that want to be part of the networking stack.
|
||||
type TransportProtocol interface {
|
||||
@@ -147,14 +167,12 @@ type TransportProtocol interface {
|
||||
ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error)
|
||||
|
||||
// HandleUnknownDestinationPacket handles packets targeted at this
|
||||
// protocol but that don't match any existing endpoint. For example,
|
||||
// it is targeted at a port that have no listeners.
|
||||
// protocol that don't match any existing endpoint. For example,
|
||||
// it is targeted at a port that has no listeners.
|
||||
//
|
||||
// The return value indicates whether the packet was well-formed (for
|
||||
// stats purposes only).
|
||||
//
|
||||
// HandleUnknownDestinationPacket takes ownership of pkt.
|
||||
HandleUnknownDestinationPacket(r *Route, id TransportEndpointID, pkt *PacketBuffer) bool
|
||||
// HandleUnknownDestinationPacket takes ownership of pkt if it handles
|
||||
// the issue.
|
||||
HandleUnknownDestinationPacket(r *Route, id TransportEndpointID, pkt *PacketBuffer) UnknownDestinationPacketDisposition
|
||||
|
||||
// SetOption allows enabling/disabling protocol specific features.
|
||||
// SetOption returns an error if the option is not supported or the
|
||||
@@ -324,6 +342,19 @@ type NetworkProtocol interface {
|
||||
// does not encapsulate anything).
|
||||
// - Whether pkt.Data was large enough to parse and set pkt.NetworkHeader.
|
||||
Parse(pkt *PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool)
|
||||
|
||||
// ReturnError attempts to send a suitable error message to the sender
|
||||
// of a received packet.
|
||||
// - pkt holds the problematic packet.
|
||||
// - reason indicates what the reason for wanting a message is.
|
||||
// - route is the routing information for the received packet
|
||||
// ReturnError returns an error if the send failed and nil on success.
|
||||
// Note that deciding to deliberately send no message is a success.
|
||||
//
|
||||
// TODO(gvisor.dev/issues/3871): This method should be removed or simplified
|
||||
// after all (or all but one) of the ICMP error dispatch occurs through the
|
||||
// protocol specific modules. May become SendPortNotFound(r, pkt).
|
||||
ReturnError(r *Route, reason tcpip.ICMPReason, pkt *PacketBuffer) *tcpip.Error
|
||||
}
|
||||
|
||||
// NetworkDispatcher contains the methods used by the network stack to deliver
|
||||
|
||||
@@ -216,13 +216,18 @@ func (f *fakeNetworkProtocol) Option(option tcpip.GettableNetworkProtocolOption)
|
||||
}
|
||||
}
|
||||
|
||||
// Close implements TransportProtocol.Close.
|
||||
// ReturnError implements NetworkProtocol.ReturnError
|
||||
func (*fakeNetworkProtocol) ReturnError(*stack.Route, tcpip.ICMPReason, *stack.PacketBuffer) *tcpip.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements NetworkProtocol.Close.
|
||||
func (*fakeNetworkProtocol) Close() {}
|
||||
|
||||
// Wait implements TransportProtocol.Wait.
|
||||
// Wait implements NetworkProtocol.Wait.
|
||||
func (*fakeNetworkProtocol) Wait() {}
|
||||
|
||||
// Parse implements TransportProtocol.Parse.
|
||||
// Parse implements NetworkProtocol.Parse.
|
||||
func (*fakeNetworkProtocol) Parse(pkt *stack.PacketBuffer) (tcpip.TransportProtocolNumber, bool, bool) {
|
||||
hdr, ok := pkt.NetworkHeader().Consume(fakeNetHeaderLen)
|
||||
if !ok {
|
||||
|
||||
@@ -287,8 +287,8 @@ func (*fakeTransportProtocol) ParsePorts(buffer.View) (src, dst uint16, err *tcp
|
||||
return 0, 0, nil
|
||||
}
|
||||
|
||||
func (*fakeTransportProtocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, *stack.PacketBuffer) bool {
|
||||
return true
|
||||
func (*fakeTransportProtocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition {
|
||||
return stack.UnknownDestinationPacketHandled
|
||||
}
|
||||
|
||||
func (f *fakeTransportProtocol) SetOption(option tcpip.SettableTransportProtocolOption) *tcpip.Error {
|
||||
|
||||
@@ -1987,3 +1987,14 @@ func DeleteDanglingEndpoint(e Endpoint) {
|
||||
// AsyncLoading is the global barrier for asynchronous endpoint loading
|
||||
// activities.
|
||||
var AsyncLoading sync.WaitGroup
|
||||
|
||||
// ICMPReason is a marker interface for network protocol agnostic ICMP errors.
|
||||
type ICMPReason interface {
|
||||
isICMP()
|
||||
}
|
||||
|
||||
// ICMPReasonPortUnreachable is an error where the transport protocol has no
|
||||
// listener and no alternative means to inform the sender.
|
||||
type ICMPReasonPortUnreachable struct{}
|
||||
|
||||
func (*ICMPReasonPortUnreachable) isICMP() {}
|
||||
|
||||
@@ -446,6 +446,7 @@ func send4(r *stack.Route, ident uint16, data buffer.View, ttl uint8, owner tcpi
|
||||
pkt.Owner = owner
|
||||
|
||||
icmpv4 := header.ICMPv4(pkt.TransportHeader().Push(header.ICMPv4MinimumSize))
|
||||
pkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber
|
||||
copy(icmpv4, data)
|
||||
// Set the ident to the user-specified port. Sequence number should
|
||||
// already be set by the user.
|
||||
@@ -478,6 +479,7 @@ func send6(r *stack.Route, ident uint16, data buffer.View, ttl uint8) *tcpip.Err
|
||||
})
|
||||
|
||||
icmpv6 := header.ICMPv6(pkt.TransportHeader().Push(header.ICMPv6MinimumSize))
|
||||
pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber
|
||||
copy(icmpv6, data)
|
||||
// Set the ident. Sequence number is provided by the user.
|
||||
icmpv6.SetIdent(ident)
|
||||
|
||||
@@ -104,8 +104,8 @@ func (p *protocol) ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error)
|
||||
|
||||
// HandleUnknownDestinationPacket handles packets targeted at this protocol but
|
||||
// that don't match any existing endpoint.
|
||||
func (*protocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, *stack.PacketBuffer) bool {
|
||||
return true
|
||||
func (*protocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition {
|
||||
return stack.UnknownDestinationPacketHandled
|
||||
}
|
||||
|
||||
// SetOption implements stack.TransportProtocol.SetOption.
|
||||
|
||||
@@ -747,6 +747,7 @@ func (e *endpoint) sendTCP(r *stack.Route, tf tcpFields, data buffer.VectorisedV
|
||||
func buildTCPHdr(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso *stack.GSO) {
|
||||
optLen := len(tf.opts)
|
||||
tcp := header.TCP(pkt.TransportHeader().Push(header.TCPMinimumSize + optLen))
|
||||
pkt.TransportProtocolNumber = header.TCPProtocolNumber
|
||||
tcp.Encode(&header.TCPFields{
|
||||
SrcPort: tf.id.LocalPort,
|
||||
DstPort: tf.id.RemotePort,
|
||||
|
||||
@@ -201,21 +201,20 @@ func (p *protocol) QueuePacket(r *stack.Route, ep stack.TransportEndpoint, id st
|
||||
// a reset is sent in response to any incoming segment except another reset. In
|
||||
// particular, SYNs addressed to a non-existent connection are rejected by this
|
||||
// means."
|
||||
func (*protocol) HandleUnknownDestinationPacket(r *stack.Route, id stack.TransportEndpointID, pkt *stack.PacketBuffer) bool {
|
||||
|
||||
func (*protocol) HandleUnknownDestinationPacket(r *stack.Route, id stack.TransportEndpointID, pkt *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition {
|
||||
s := newSegment(r, id, pkt)
|
||||
defer s.decRef()
|
||||
|
||||
if !s.parse() || !s.csumValid {
|
||||
return false
|
||||
return stack.UnknownDestinationPacketMalformed
|
||||
}
|
||||
|
||||
// There's nothing to do if this is already a reset packet.
|
||||
if s.flagIsSet(header.TCPFlagRst) {
|
||||
return true
|
||||
if !s.flagIsSet(header.TCPFlagRst) {
|
||||
replyWithReset(s, stack.DefaultTOS, s.route.DefaultTTL())
|
||||
}
|
||||
|
||||
replyWithReset(s, stack.DefaultTOS, s.route.DefaultTTL())
|
||||
return true
|
||||
return stack.UnknownDestinationPacketHandled
|
||||
}
|
||||
|
||||
// replyWithReset replies to the given segment with a reset segment.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user