github.com/lightlus/netstack@v1.2.0/tcpip/transport/udp/protocol.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package udp contains the implementation of the UDP transport protocol. To use
    16  // it in the networking stack, this package must be added to the project, and
    17  // activated on the stack by passing udp.NewProtocol() as one of the
    18  // transport protocols when calling stack.New(). Then endpoints can be created
    19  // by passing udp.ProtocolNumber as the transport protocol number when calling
    20  // Stack.NewEndpoint().
    21  package udp
    22  
    23  import (
    24  	"github.com/lightlus/netstack/tcpip"
    25  	"github.com/lightlus/netstack/tcpip/buffer"
    26  	"github.com/lightlus/netstack/tcpip/header"
    27  	"github.com/lightlus/netstack/tcpip/stack"
    28  	"github.com/lightlus/netstack/tcpip/transport/raw"
    29  	"github.com/lightlus/netstack/waiter"
    30  )
    31  
    32  const (
    33  	// ProtocolNumber is the udp protocol number.
    34  	ProtocolNumber = header.UDPProtocolNumber
    35  )
    36  
    37  type protocol struct{}
    38  
    39  // Number returns the udp protocol number.
    40  func (*protocol) Number() tcpip.TransportProtocolNumber {
    41  	return ProtocolNumber
    42  }
    43  
    44  // NewEndpoint creates a new udp endpoint.
    45  func (*protocol) NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
    46  	return newEndpoint(stack, netProto, waiterQueue), nil
    47  }
    48  
    49  // NewRawEndpoint creates a new raw UDP endpoint. It implements
    50  // stack.TransportProtocol.NewRawEndpoint.
    51  func (p *protocol) NewRawEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
    52  	return raw.NewEndpoint(stack, netProto, header.UDPProtocolNumber, waiterQueue)
    53  }
    54  
    55  // MinimumPacketSize returns the minimum valid udp packet size.
    56  func (*protocol) MinimumPacketSize() int {
    57  	return header.UDPMinimumSize
    58  }
    59  
    60  // ParsePorts returns the source and destination ports stored in the given udp
    61  // packet.
    62  func (*protocol) ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error) {
    63  	h := header.UDP(v)
    64  	return h.SourcePort(), h.DestinationPort(), nil
    65  }
    66  
    67  // HandleUnknownDestinationPacket handles packets targeted at this protocol but
    68  // that don't match any existing endpoint.
    69  func (p *protocol) HandleUnknownDestinationPacket(r *stack.Route, id stack.TransportEndpointID, pkt tcpip.PacketBuffer) bool {
    70  	// Get the header then trim it from the view.
    71  	hdr := header.UDP(pkt.Data.First())
    72  	if int(hdr.Length()) > pkt.Data.Size() {
    73  		// Malformed packet.
    74  		r.Stack().Stats().UDP.MalformedPacketsReceived.Increment()
    75  		return true
    76  	}
    77  	// TODO(b/129426613): only send an ICMP message if UDP checksum is valid.
    78  
    79  	// Only send ICMP error if the address is not a multicast/broadcast
    80  	// v4/v6 address or the source is not the unspecified address.
    81  	//
    82  	// See: point e) in https://tools.ietf.org/html/rfc4443#section-2.4
    83  	if id.LocalAddress == header.IPv4Broadcast || header.IsV4MulticastAddress(id.LocalAddress) || header.IsV6MulticastAddress(id.LocalAddress) || id.RemoteAddress == header.IPv6Any || id.RemoteAddress == header.IPv4Any {
    84  		return true
    85  	}
    86  
    87  	// As per RFC: 1122 Section 3.2.2.1 A host SHOULD generate Destination
    88  	//   Unreachable messages with code:
    89  	//
    90  	//     2 (Protocol Unreachable), when the designated transport protocol
    91  	//     is not supported; or
    92  	//
    93  	//     3 (Port Unreachable), when the designated transport protocol
    94  	//     (e.g., UDP) is unable to demultiplex the datagram but has no
    95  	//     protocol mechanism to inform the sender.
    96  	switch len(id.LocalAddress) {
    97  	case header.IPv4AddressSize:
    98  		if !r.Stack().AllowICMPMessage() {
    99  			r.Stack().Stats().ICMP.V4PacketsSent.RateLimited.Increment()
   100  			return true
   101  		}
   102  		// As per RFC 1812 Section 4.3.2.3
   103  		//
   104  		//   ICMP datagram SHOULD contain as much of the original
   105  		//   datagram as possible without the length of the ICMP
   106  		//   datagram exceeding 576 bytes
   107  		//
   108  		// NOTE: The above RFC referenced is different from the original
   109  		// recommendation in RFC 1122 where it mentioned that at least 8
   110  		// bytes of the payload must be included. Today linux and other
   111  		// systems implement the] RFC1812 definition and not the original
   112  		// RFC 1122 requirement.
   113  		mtu := int(r.MTU())
   114  		if mtu > header.IPv4MinimumProcessableDatagramSize {
   115  			mtu = header.IPv4MinimumProcessableDatagramSize
   116  		}
   117  		headerLen := int(r.MaxHeaderLength()) + header.ICMPv4MinimumSize
   118  		available := int(mtu) - headerLen
   119  		payloadLen := len(pkt.NetworkHeader) + pkt.Data.Size()
   120  		if payloadLen > available {
   121  			payloadLen = available
   122  		}
   123  
   124  		// The buffers used by pkt may be used elsewhere in the system.
   125  		// For example, a raw or packet socket may use what UDP
   126  		// considers an unreachable destination. Thus we deep copy pkt
   127  		// to prevent multiple ownership and SR errors.
   128  		newNetHeader := append(buffer.View(nil), pkt.NetworkHeader...)
   129  		payload := newNetHeader.ToVectorisedView()
   130  		payload.Append(pkt.Data.ToView().ToVectorisedView())
   131  		payload.CapLength(payloadLen)
   132  
   133  		hdr := buffer.NewPrependable(headerLen)
   134  		pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize))
   135  		pkt.SetType(header.ICMPv4DstUnreachable)
   136  		pkt.SetCode(header.ICMPv4PortUnreachable)
   137  		pkt.SetChecksum(header.ICMPv4Checksum(pkt, payload))
   138  		r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{Protocol: header.ICMPv4ProtocolNumber, TTL: r.DefaultTTL(), TOS: stack.DefaultTOS}, tcpip.PacketBuffer{
   139  			Header: hdr,
   140  			Data:   payload,
   141  		})
   142  
   143  	case header.IPv6AddressSize:
   144  		if !r.Stack().AllowICMPMessage() {
   145  			r.Stack().Stats().ICMP.V6PacketsSent.RateLimited.Increment()
   146  			return true
   147  		}
   148  
   149  		// As per RFC 4443 section 2.4
   150  		//
   151  		//    (c) Every ICMPv6 error message (type < 128) MUST include
   152  		//    as much of the IPv6 offending (invoking) packet (the
   153  		//    packet that caused the error) as possible without making
   154  		//    the error message packet exceed the minimum IPv6 MTU
   155  		//    [IPv6].
   156  		mtu := int(r.MTU())
   157  		if mtu > header.IPv6MinimumMTU {
   158  			mtu = header.IPv6MinimumMTU
   159  		}
   160  		headerLen := int(r.MaxHeaderLength()) + header.ICMPv6DstUnreachableMinimumSize
   161  		available := int(mtu) - headerLen
   162  		payloadLen := len(pkt.NetworkHeader) + pkt.Data.Size()
   163  		if payloadLen > available {
   164  			payloadLen = available
   165  		}
   166  		payload := buffer.NewVectorisedView(len(pkt.NetworkHeader), []buffer.View{pkt.NetworkHeader})
   167  		payload.Append(pkt.Data)
   168  		payload.CapLength(payloadLen)
   169  
   170  		hdr := buffer.NewPrependable(headerLen)
   171  		pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6DstUnreachableMinimumSize))
   172  		pkt.SetType(header.ICMPv6DstUnreachable)
   173  		pkt.SetCode(header.ICMPv6PortUnreachable)
   174  		pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, payload))
   175  		r.WritePacket(nil /* gso */, stack.NetworkHeaderParams{Protocol: header.ICMPv6ProtocolNumber, TTL: r.DefaultTTL(), TOS: stack.DefaultTOS}, tcpip.PacketBuffer{
   176  			Header: hdr,
   177  			Data:   payload,
   178  		})
   179  	}
   180  	return true
   181  }
   182  
   183  // SetOption implements TransportProtocol.SetOption.
   184  func (p *protocol) SetOption(option interface{}) *tcpip.Error {
   185  	return tcpip.ErrUnknownProtocolOption
   186  }
   187  
   188  // Option implements TransportProtocol.Option.
   189  func (p *protocol) Option(option interface{}) *tcpip.Error {
   190  	return tcpip.ErrUnknownProtocolOption
   191  }
   192  
   193  // NewProtocol returns a UDP transport protocol.
   194  func NewProtocol() stack.TransportProtocol {
   195  	return &protocol{}
   196  }