github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/net/mockicmp_test.go (about) 1 // Copyright 2009 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 net 6 7 import "errors" 8 9 const ( 10 icmpv4EchoRequest = 8 11 icmpv4EchoReply = 0 12 icmpv6EchoRequest = 128 13 icmpv6EchoReply = 129 14 ) 15 16 // icmpMessage represents an ICMP message. 17 type icmpMessage struct { 18 Type int // type 19 Code int // code 20 Checksum int // checksum 21 Body icmpMessageBody // body 22 } 23 24 // icmpMessageBody represents an ICMP message body. 25 type icmpMessageBody interface { 26 Len() int 27 Marshal() ([]byte, error) 28 } 29 30 // Marshal returns the binary enconding of the ICMP echo request or 31 // reply message m. 32 func (m *icmpMessage) Marshal() ([]byte, error) { 33 b := []byte{byte(m.Type), byte(m.Code), 0, 0} 34 if m.Body != nil && m.Body.Len() != 0 { 35 mb, err := m.Body.Marshal() 36 if err != nil { 37 return nil, err 38 } 39 b = append(b, mb...) 40 } 41 switch m.Type { 42 case icmpv6EchoRequest, icmpv6EchoReply: 43 return b, nil 44 } 45 csumcv := len(b) - 1 // checksum coverage 46 s := uint32(0) 47 for i := 0; i < csumcv; i += 2 { 48 s += uint32(b[i+1])<<8 | uint32(b[i]) 49 } 50 if csumcv&1 == 0 { 51 s += uint32(b[csumcv]) 52 } 53 s = s>>16 + s&0xffff 54 s = s + s>>16 55 // Place checksum back in header; using ^= avoids the 56 // assumption the checksum bytes are zero. 57 b[2] ^= byte(^s) 58 b[3] ^= byte(^s >> 8) 59 return b, nil 60 } 61 62 // parseICMPMessage parses b as an ICMP message. 63 func parseICMPMessage(b []byte) (*icmpMessage, error) { 64 msglen := len(b) 65 if msglen < 4 { 66 return nil, errors.New("message too short") 67 } 68 m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} 69 if msglen > 4 { 70 var err error 71 switch m.Type { 72 case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply: 73 m.Body, err = parseICMPEcho(b[4:]) 74 if err != nil { 75 return nil, err 76 } 77 } 78 } 79 return m, nil 80 } 81 82 // imcpEcho represenets an ICMP echo request or reply message body. 83 type icmpEcho struct { 84 ID int // identifier 85 Seq int // sequence number 86 Data []byte // data 87 } 88 89 func (p *icmpEcho) Len() int { 90 if p == nil { 91 return 0 92 } 93 return 4 + len(p.Data) 94 } 95 96 // Marshal returns the binary enconding of the ICMP echo request or 97 // reply message body p. 98 func (p *icmpEcho) Marshal() ([]byte, error) { 99 b := make([]byte, 4+len(p.Data)) 100 b[0], b[1] = byte(p.ID>>8), byte(p.ID) 101 b[2], b[3] = byte(p.Seq>>8), byte(p.Seq) 102 copy(b[4:], p.Data) 103 return b, nil 104 } 105 106 // parseICMPEcho parses b as an ICMP echo request or reply message 107 // body. 108 func parseICMPEcho(b []byte) (*icmpEcho, error) { 109 bodylen := len(b) 110 p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])} 111 if bodylen > 4 { 112 p.Data = make([]byte, bodylen-4) 113 copy(p.Data, b[4:]) 114 } 115 return p, nil 116 }