multipart.go 3.3 KB

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