github.com/FlowerWrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/network/ipv4/icmp.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 ipv4 16 17 import ( 18 "github.com/FlowerWrong/netstack/tcpip/buffer" 19 "github.com/FlowerWrong/netstack/tcpip/header" 20 "github.com/FlowerWrong/netstack/tcpip/stack" 21 ) 22 23 // handleControl handles the case when an ICMP packet contains the headers of 24 // the original packet that caused the ICMP one to be sent. This information is 25 // used to find out which transport endpoint must be notified about the ICMP 26 // packet. 27 func (e *endpoint) handleControl(typ stack.ControlType, extra uint32, vv buffer.VectorisedView) { 28 h := header.IPv4(vv.First()) 29 30 // We don't use IsValid() here because ICMP only requires that the IP 31 // header plus 8 bytes of the transport header be included. So it's 32 // likely that it is truncated, which would cause IsValid to return 33 // false. 34 // 35 // Drop packet if it doesn't have the basic IPv4 header or if the 36 // original source address doesn't match the endpoint's address. 37 if len(h) < header.IPv4MinimumSize || h.SourceAddress() != e.id.LocalAddress { 38 return 39 } 40 41 hlen := int(h.HeaderLength()) 42 if vv.Size() < hlen || h.FragmentOffset() != 0 { 43 // We won't be able to handle this if it doesn't contain the 44 // full IPv4 header, or if it's a fragment not at offset 0 45 // (because it won't have the transport header). 46 return 47 } 48 49 // Skip the ip header, then deliver control message. 50 vv.TrimFront(hlen) 51 p := h.TransportProtocol() 52 e.dispatcher.DeliverTransportControlPacket(e.id.LocalAddress, h.DestinationAddress(), ProtocolNumber, p, typ, extra, vv) 53 } 54 55 func (e *endpoint) handleICMP(r *stack.Route, netHeader buffer.View, vv buffer.VectorisedView) { 56 stats := r.Stats() 57 received := stats.ICMP.V4PacketsReceived 58 v := vv.First() 59 if len(v) < header.ICMPv4MinimumSize { 60 received.Invalid.Increment() 61 return 62 } 63 h := header.ICMPv4(v) 64 65 // TODO(b/112892170): Meaningfully handle all ICMP types. 66 switch h.Type() { 67 case header.ICMPv4Echo: 68 received.Echo.Increment() 69 70 // Only send a reply if the checksum is valid. 71 wantChecksum := h.Checksum() 72 // Reset the checksum field to 0 to can calculate the proper 73 // checksum. We'll have to reset this before we hand the packet 74 // off. 75 h.SetChecksum(0) 76 gotChecksum := ^header.ChecksumVV(vv, 0 /* initial */) 77 if gotChecksum != wantChecksum { 78 // It's possible that a raw socket expects to receive this. 79 h.SetChecksum(wantChecksum) 80 e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, netHeader, vv) 81 received.Invalid.Increment() 82 return 83 } 84 85 // It's possible that a raw socket expects to receive this. 86 h.SetChecksum(wantChecksum) 87 e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, netHeader, vv) 88 89 vv := vv.Clone(nil) 90 vv.TrimFront(header.ICMPv4MinimumSize) 91 hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.ICMPv4MinimumSize) 92 pkt := header.ICMPv4(hdr.Prepend(header.ICMPv4MinimumSize)) 93 copy(pkt, h) 94 pkt.SetType(header.ICMPv4EchoReply) 95 pkt.SetChecksum(0) 96 pkt.SetChecksum(^header.Checksum(pkt, header.ChecksumVV(vv, 0))) 97 sent := stats.ICMP.V4PacketsSent 98 if err := r.WritePacket(nil /* gso */, hdr, vv, header.ICMPv4ProtocolNumber, 0, true /* useDefaultTTL */); err != nil { 99 sent.Dropped.Increment() 100 return 101 } 102 sent.EchoReply.Increment() 103 104 case header.ICMPv4EchoReply: 105 received.EchoReply.Increment() 106 107 e.dispatcher.DeliverTransportPacket(r, header.ICMPv4ProtocolNumber, netHeader, vv) 108 109 case header.ICMPv4DstUnreachable: 110 received.DstUnreachable.Increment() 111 112 vv.TrimFront(header.ICMPv4MinimumSize) 113 switch h.Code() { 114 case header.ICMPv4PortUnreachable: 115 e.handleControl(stack.ControlPortUnreachable, 0, vv) 116 117 case header.ICMPv4FragmentationNeeded: 118 mtu := uint32(h.MTU()) 119 e.handleControl(stack.ControlPacketTooBig, calculateMTU(mtu), vv) 120 } 121 122 case header.ICMPv4SrcQuench: 123 received.SrcQuench.Increment() 124 125 case header.ICMPv4Redirect: 126 received.Redirect.Increment() 127 128 case header.ICMPv4TimeExceeded: 129 received.TimeExceeded.Increment() 130 131 case header.ICMPv4ParamProblem: 132 received.ParamProblem.Increment() 133 134 case header.ICMPv4Timestamp: 135 received.Timestamp.Increment() 136 137 case header.ICMPv4TimestampReply: 138 received.TimestampReply.Increment() 139 140 case header.ICMPv4InfoRequest: 141 received.InfoRequest.Increment() 142 143 case header.ICMPv4InfoReply: 144 received.InfoReply.Increment() 145 146 default: 147 received.Invalid.Increment() 148 } 149 }