extension.go 2.7 KB

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