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.

109 lines
3.0 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 "golang.org/x/net/internal/iana"
  6. // multipartMessageBodyDataLen takes b as an original datagram and
  7. // exts as extensions, and returns a required length for message body
  8. // and a required length for a padded original datagram in wire
  9. // format.
  10. func multipartMessageBodyDataLen(proto int, b []byte, exts []Extension) (bodyLen, dataLen int) {
  11. for _, ext := range exts {
  12. bodyLen += ext.Len(proto)
  13. }
  14. if bodyLen > 0 {
  15. dataLen = multipartMessageOrigDatagramLen(proto, b)
  16. bodyLen += 4 // length of extension header
  17. } else {
  18. dataLen = len(b)
  19. }
  20. bodyLen += dataLen
  21. return bodyLen, dataLen
  22. }
  23. // multipartMessageOrigDatagramLen takes b as an original datagram,
  24. // and returns a required length for a padded orignal datagram in wire
  25. // format.
  26. func multipartMessageOrigDatagramLen(proto int, b []byte) int {
  27. roundup := func(b []byte, align int) int {
  28. // According to RFC 4884, the padded original datagram
  29. // field must contain at least 128 octets.
  30. if len(b) < 128 {
  31. return 128
  32. }
  33. r := len(b)
  34. return (r + align - 1) & ^(align - 1)
  35. }
  36. switch proto {
  37. case iana.ProtocolICMP:
  38. return roundup(b, 4)
  39. case iana.ProtocolIPv6ICMP:
  40. return roundup(b, 8)
  41. default:
  42. return len(b)
  43. }
  44. }
  45. // marshalMultipartMessageBody takes data as an original datagram and
  46. // exts as extesnsions, and returns a binary encoding of message body.
  47. // It can be used for non-multipart message bodies when exts is nil.
  48. func marshalMultipartMessageBody(proto int, data []byte, exts []Extension) ([]byte, error) {
  49. bodyLen, dataLen := multipartMessageBodyDataLen(proto, data, exts)
  50. b := make([]byte, 4+bodyLen)
  51. copy(b[4:], data)
  52. off := dataLen + 4
  53. if len(exts) > 0 {
  54. b[dataLen+4] = byte(extensionVersion << 4)
  55. off += 4 // length of object header
  56. for _, ext := range exts {
  57. switch ext := ext.(type) {
  58. case *MPLSLabelStack:
  59. if err := ext.marshal(proto, b[off:]); err != nil {
  60. return nil, err
  61. }
  62. off += ext.Len(proto)
  63. case *InterfaceInfo:
  64. attrs, l := ext.attrsAndLen(proto)
  65. if err := ext.marshal(proto, b[off:], attrs, l); err != nil {
  66. return nil, err
  67. }
  68. off += ext.Len(proto)
  69. }
  70. }
  71. s := checksum(b[dataLen+4:])
  72. b[dataLen+4+2] ^= byte(s)
  73. b[dataLen+4+3] ^= byte(s >> 8)
  74. switch proto {
  75. case iana.ProtocolICMP:
  76. b[1] = byte(dataLen / 4)
  77. case iana.ProtocolIPv6ICMP:
  78. b[0] = byte(dataLen / 8)
  79. }
  80. }
  81. return b, nil
  82. }
  83. // parseMultipartMessageBody parses b as either a non-multipart
  84. // message body or a multipart message body.
  85. func parseMultipartMessageBody(proto int, b []byte) ([]byte, []Extension, error) {
  86. var l int
  87. switch proto {
  88. case iana.ProtocolICMP:
  89. l = 4 * int(b[1])
  90. case iana.ProtocolIPv6ICMP:
  91. l = 8 * int(b[0])
  92. }
  93. if len(b) == 4 {
  94. return nil, nil, nil
  95. }
  96. exts, l, err := parseExtensions(b[4:], l)
  97. if err != nil {
  98. l = len(b) - 4
  99. }
  100. data := make([]byte, l)
  101. copy(data, b[4:])
  102. return data, exts, nil
  103. }