github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/icmp/echo.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package icmp 6 7 import ( 8 "encoding/binary" 9 10 "github.com/hxx258456/ccgo/net/internal/iana" 11 "github.com/hxx258456/ccgo/net/ipv4" 12 "github.com/hxx258456/ccgo/net/ipv6" 13 ) 14 15 // An Echo represents an ICMP echo request or reply message body. 16 type Echo struct { 17 ID int // identifier 18 Seq int // sequence number 19 Data []byte // data 20 } 21 22 // Len implements the Len method of MessageBody interface. 23 func (p *Echo) Len(proto int) int { 24 if p == nil { 25 return 0 26 } 27 return 4 + len(p.Data) 28 } 29 30 // Marshal implements the Marshal method of MessageBody interface. 31 func (p *Echo) Marshal(proto int) ([]byte, error) { 32 b := make([]byte, 4+len(p.Data)) 33 binary.BigEndian.PutUint16(b[:2], uint16(p.ID)) 34 binary.BigEndian.PutUint16(b[2:4], uint16(p.Seq)) 35 copy(b[4:], p.Data) 36 return b, nil 37 } 38 39 // parseEcho parses b as an ICMP echo request or reply message body. 40 func parseEcho(proto int, _ Type, b []byte) (MessageBody, error) { 41 bodyLen := len(b) 42 if bodyLen < 4 { 43 return nil, errMessageTooShort 44 } 45 p := &Echo{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(binary.BigEndian.Uint16(b[2:4]))} 46 if bodyLen > 4 { 47 p.Data = make([]byte, bodyLen-4) 48 copy(p.Data, b[4:]) 49 } 50 return p, nil 51 } 52 53 // An ExtendedEchoRequest represents an ICMP extended echo request 54 // message body. 55 type ExtendedEchoRequest struct { 56 ID int // identifier 57 Seq int // sequence number 58 Local bool // must be true when identifying by name or index 59 Extensions []Extension // extensions 60 } 61 62 // Len implements the Len method of MessageBody interface. 63 func (p *ExtendedEchoRequest) Len(proto int) int { 64 if p == nil { 65 return 0 66 } 67 l, _ := multipartMessageBodyDataLen(proto, false, nil, p.Extensions) 68 return l 69 } 70 71 // Marshal implements the Marshal method of MessageBody interface. 72 func (p *ExtendedEchoRequest) Marshal(proto int) ([]byte, error) { 73 var typ Type 74 switch proto { 75 case iana.ProtocolICMP: 76 typ = ipv4.ICMPTypeExtendedEchoRequest 77 case iana.ProtocolIPv6ICMP: 78 typ = ipv6.ICMPTypeExtendedEchoRequest 79 default: 80 return nil, errInvalidProtocol 81 } 82 if !validExtensions(typ, p.Extensions) { 83 return nil, errInvalidExtension 84 } 85 b, err := marshalMultipartMessageBody(proto, false, nil, p.Extensions) 86 if err != nil { 87 return nil, err 88 } 89 binary.BigEndian.PutUint16(b[:2], uint16(p.ID)) 90 b[2] = byte(p.Seq) 91 if p.Local { 92 b[3] |= 0x01 93 } 94 return b, nil 95 } 96 97 // parseExtendedEchoRequest parses b as an ICMP extended echo request 98 // message body. 99 func parseExtendedEchoRequest(proto int, typ Type, b []byte) (MessageBody, error) { 100 if len(b) < 4 { 101 return nil, errMessageTooShort 102 } 103 p := &ExtendedEchoRequest{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(b[2])} 104 if b[3]&0x01 != 0 { 105 p.Local = true 106 } 107 var err error 108 _, p.Extensions, err = parseMultipartMessageBody(proto, typ, b) 109 if err != nil { 110 return nil, err 111 } 112 return p, nil 113 } 114 115 // An ExtendedEchoReply represents an ICMP extended echo reply message 116 // body. 117 type ExtendedEchoReply struct { 118 ID int // identifier 119 Seq int // sequence number 120 State int // 3-bit state working together with Message.Code 121 Active bool // probed interface is active 122 IPv4 bool // probed interface runs IPv4 123 IPv6 bool // probed interface runs IPv6 124 } 125 126 // Len implements the Len method of MessageBody interface. 127 func (p *ExtendedEchoReply) Len(proto int) int { 128 if p == nil { 129 return 0 130 } 131 return 4 132 } 133 134 // Marshal implements the Marshal method of MessageBody interface. 135 func (p *ExtendedEchoReply) Marshal(proto int) ([]byte, error) { 136 b := make([]byte, 4) 137 binary.BigEndian.PutUint16(b[:2], uint16(p.ID)) 138 b[2] = byte(p.Seq) 139 b[3] = byte(p.State<<5) & 0xe0 140 if p.Active { 141 b[3] |= 0x04 142 } 143 if p.IPv4 { 144 b[3] |= 0x02 145 } 146 if p.IPv6 { 147 b[3] |= 0x01 148 } 149 return b, nil 150 } 151 152 // parseExtendedEchoReply parses b as an ICMP extended echo reply 153 // message body. 154 func parseExtendedEchoReply(proto int, _ Type, b []byte) (MessageBody, error) { 155 if len(b) < 4 { 156 return nil, errMessageTooShort 157 } 158 p := &ExtendedEchoReply{ 159 ID: int(binary.BigEndian.Uint16(b[:2])), 160 Seq: int(b[2]), 161 State: int(b[3]) >> 5, 162 } 163 if b[3]&0x04 != 0 { 164 p.Active = true 165 } 166 if b[3]&0x02 != 0 { 167 p.IPv4 = true 168 } 169 if b[3]&0x01 != 0 { 170 p.IPv6 = true 171 } 172 return p, nil 173 }