github.com/noisysockets/netstack@v0.6.0/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/noisysockets/netstack/pkg/tcpip" 23 "github.com/noisysockets/netstack/pkg/tcpip/header" 24 "github.com/noisysockets/netstack/pkg/tcpip/stack" 25 "github.com/noisysockets/netstack/pkg/tcpip/transport/raw" 26 "github.com/noisysockets/netstack/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 }