multipart.go 3.6 KB

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