extension.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // Copyright 2015 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/ipv4"
  8. "golang.org/x/net/ipv6"
  9. )
  10. // An Extension represents an ICMP extension.
  11. type Extension interface {
  12. // Len returns the length of ICMP extension.
  13. // Proto must be either the ICMPv4 or ICMPv6 protocol number.
  14. Len(proto int) int
  15. // Marshal returns the binary encoding of ICMP extension.
  16. // Proto must be either the ICMPv4 or ICMPv6 protocol number.
  17. Marshal(proto int) ([]byte, error)
  18. }
  19. const extensionVersion = 2
  20. func validExtensionHeader(b []byte) bool {
  21. v := int(b[0]&0xf0) >> 4
  22. s := binary.BigEndian.Uint16(b[2:4])
  23. if s != 0 {
  24. s = checksum(b)
  25. }
  26. if v != extensionVersion || s != 0 {
  27. return false
  28. }
  29. return true
  30. }
  31. // parseExtensions parses b as a list of ICMP extensions.
  32. // The length attribute l must be the length attribute field in
  33. // received icmp messages.
  34. //
  35. // It will return a list of ICMP extensions and an adjusted length
  36. // attribute that represents the length of the padded original
  37. // datagram field. Otherwise, it returns an error.
  38. func parseExtensions(typ Type, b []byte, l int) ([]Extension, int, error) {
  39. // Still a lot of non-RFC 4884 compliant implementations are
  40. // out there. Set the length attribute l to 128 when it looks
  41. // inappropriate for backwards compatibility.
  42. //
  43. // A minimal extension at least requires 8 octets; 4 octets
  44. // for an extension header, and 4 octets for a single object
  45. // header.
  46. //
  47. // See RFC 4884 for further information.
  48. switch typ {
  49. case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
  50. if len(b) < 8 || !validExtensionHeader(b) {
  51. return nil, -1, errNoExtension
  52. }
  53. l = 0
  54. default:
  55. if 128 > l || l+8 > len(b) {
  56. l = 128
  57. }
  58. if l+8 > len(b) {
  59. return nil, -1, errNoExtension
  60. }
  61. if !validExtensionHeader(b[l:]) {
  62. if l == 128 {
  63. return nil, -1, errNoExtension
  64. }
  65. l = 128
  66. if !validExtensionHeader(b[l:]) {
  67. return nil, -1, errNoExtension
  68. }
  69. }
  70. }
  71. var exts []Extension
  72. for b = b[l+4:]; len(b) >= 4; {
  73. ol := int(binary.BigEndian.Uint16(b[:2]))
  74. if 4 > ol || ol > len(b) {
  75. break
  76. }
  77. switch b[2] {
  78. case classMPLSLabelStack:
  79. ext, err := parseMPLSLabelStack(b[:ol])
  80. if err != nil {
  81. return nil, -1, err
  82. }
  83. exts = append(exts, ext)
  84. case classInterfaceInfo:
  85. ext, err := parseInterfaceInfo(b[:ol])
  86. if err != nil {
  87. return nil, -1, err
  88. }
  89. exts = append(exts, ext)
  90. case classInterfaceIdent:
  91. ext, err := parseInterfaceIdent(b[:ol])
  92. if err != nil {
  93. return nil, -1, err
  94. }
  95. exts = append(exts, ext)
  96. }
  97. b = b[ol:]
  98. }
  99. return exts, l, nil
  100. }