mockicmp_test.go 2.7 KB

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