echo.go 3.9 KB

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