echo.go 4.2 KB

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