github.com/sagernet/gvisor@v0.0.0-20240428053021-e691de28565f/pkg/tcpip/transport/icmp/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 icmp contains the implementation of the ICMP and IPv6-ICMP transport
    16  // protocols for use in ping.
    17  package icmp
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/sagernet/gvisor/pkg/tcpip"
    23  	"github.com/sagernet/gvisor/pkg/tcpip/header"
    24  	"github.com/sagernet/gvisor/pkg/tcpip/stack"
    25  	"github.com/sagernet/gvisor/pkg/tcpip/transport/raw"
    26  	"github.com/sagernet/gvisor/pkg/waiter"
    27  )
    28  
    29  const (
    30  	// ProtocolNumber4 is the ICMP protocol number.
    31  	ProtocolNumber4 = header.ICMPv4ProtocolNumber
    32  
    33  	// ProtocolNumber6 is the IPv6-ICMP protocol number.
    34  	ProtocolNumber6 = header.ICMPv6ProtocolNumber
    35  )
    36  
    37  // protocol implements stack.TransportProtocol.
    38  type protocol struct {
    39  	stack *stack.Stack
    40  
    41  	number tcpip.TransportProtocolNumber
    42  }
    43  
    44  // Number returns the ICMP protocol number.
    45  func (p *protocol) Number() tcpip.TransportProtocolNumber {
    46  	return p.number
    47  }
    48  
    49  func (p *protocol) netProto() tcpip.NetworkProtocolNumber {
    50  	switch p.number {
    51  	case ProtocolNumber4:
    52  		return header.IPv4ProtocolNumber
    53  	case ProtocolNumber6:
    54  		return header.IPv6ProtocolNumber
    55  	}
    56  	panic(fmt.Sprint("unknown protocol number: ", p.number))
    57  }
    58  
    59  // NewEndpoint creates a new icmp endpoint. It implements
    60  // stack.TransportProtocol.NewEndpoint.
    61  func (p *protocol) NewEndpoint(netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
    62  	if netProto != p.netProto() {
    63  		return nil, &tcpip.ErrUnknownProtocol{}
    64  	}
    65  	return newEndpoint(p.stack, netProto, p.number, waiterQueue)
    66  }
    67  
    68  // NewRawEndpoint creates a new raw icmp endpoint. It implements
    69  // stack.TransportProtocol.NewRawEndpoint.
    70  func (p *protocol) NewRawEndpoint(netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
    71  	if netProto != p.netProto() {
    72  		return nil, &tcpip.ErrUnknownProtocol{}
    73  	}
    74  	return raw.NewEndpoint(p.stack, netProto, p.number, waiterQueue)
    75  }
    76  
    77  // MinimumPacketSize returns the minimum valid icmp packet size.
    78  func (p *protocol) MinimumPacketSize() int {
    79  	switch p.number {
    80  	case ProtocolNumber4:
    81  		return header.ICMPv4MinimumSize
    82  	case ProtocolNumber6:
    83  		return header.ICMPv6MinimumSize
    84  	}
    85  	panic(fmt.Sprint("unknown protocol number: ", p.number))
    86  }
    87  
    88  // ParsePorts in case of ICMP sets src to 0, dst to ICMP ID, and err to nil.
    89  func (p *protocol) ParsePorts(v []byte) (src, dst uint16, err tcpip.Error) {
    90  	switch p.number {
    91  	case ProtocolNumber4:
    92  		hdr := header.ICMPv4(v)
    93  		return 0, hdr.Ident(), nil
    94  	case ProtocolNumber6:
    95  		hdr := header.ICMPv6(v)
    96  		return 0, hdr.Ident(), nil
    97  	}
    98  	panic(fmt.Sprint("unknown protocol number: ", p.number))
    99  }
   100  
   101  // HandleUnknownDestinationPacket handles packets targeted at this protocol but
   102  // that don't match any existing endpoint.
   103  func (*protocol) HandleUnknownDestinationPacket(stack.TransportEndpointID, *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition {
   104  	return stack.UnknownDestinationPacketHandled
   105  }
   106  
   107  // SetOption implements stack.TransportProtocol.SetOption.
   108  func (*protocol) SetOption(tcpip.SettableTransportProtocolOption) tcpip.Error {
   109  	return &tcpip.ErrUnknownProtocolOption{}
   110  }
   111  
   112  // Option implements stack.TransportProtocol.Option.
   113  func (*protocol) Option(tcpip.GettableTransportProtocolOption) tcpip.Error {
   114  	return &tcpip.ErrUnknownProtocolOption{}
   115  }
   116  
   117  // Close implements stack.TransportProtocol.Close.
   118  func (*protocol) Close() {}
   119  
   120  // Wait implements stack.TransportProtocol.Wait.
   121  func (*protocol) Wait() {}
   122  
   123  // Pause implements stack.TransportProtocol.Pause.
   124  func (*protocol) Pause() {}
   125  
   126  // Resume implements stack.TransportProtocol.Resume.
   127  func (*protocol) Resume() {}
   128  
   129  // Parse implements stack.TransportProtocol.Parse.
   130  func (*protocol) Parse(pkt *stack.PacketBuffer) bool {
   131  	// Right now, the Parse() method is tied to enabled protocols passed into
   132  	// stack.New. This works for UDP and TCP, but we handle ICMP traffic even
   133  	// when netstack users don't pass ICMP as a supported protocol.
   134  	return false
   135  }
   136  
   137  // NewProtocol4 returns an ICMPv4 transport protocol.
   138  func NewProtocol4(s *stack.Stack) stack.TransportProtocol {
   139  	return &protocol{stack: s, number: ProtocolNumber4}
   140  }
   141  
   142  // NewProtocol6 returns an ICMPv6 transport protocol.
   143  func NewProtocol6(s *stack.Stack) stack.TransportProtocol {
   144  	return &protocol{stack: s, number: ProtocolNumber6}
   145  }