mockicmp_test.go 3.1 KB

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