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