You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.3 KiB

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