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