github.com/pkg/sftp@v1.13.6/internal/encoding/ssh/filexfer/packets.go (about) 1 package sshfx 2 3 import ( 4 "errors" 5 "io" 6 ) 7 8 // smallBufferSize is an initial allocation minimal capacity. 9 const smallBufferSize = 64 10 11 // RawPacket implements the general packet format from draft-ietf-secsh-filexfer-02 12 // 13 // RawPacket is intended for use in clients receiving responses, 14 // where a response will be expected to be of a limited number of types, 15 // and unmarshaling unknown/unexpected response packets is unnecessary. 16 // 17 // For servers expecting to receive arbitrary request packet types, 18 // use RequestPacket. 19 // 20 // Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3 21 type RawPacket struct { 22 PacketType PacketType 23 RequestID uint32 24 25 Data Buffer 26 } 27 28 // Type returns the Type field defining the SSH_FXP_xy type for this packet. 29 func (p *RawPacket) Type() PacketType { 30 return p.PacketType 31 } 32 33 // Reset clears the pointers and reference-semantic variables of RawPacket, 34 // releasing underlying resources, and making them and the RawPacket suitable to be reused, 35 // so long as no other references have been kept. 36 func (p *RawPacket) Reset() { 37 p.Data = Buffer{} 38 } 39 40 // MarshalPacket returns p as a two-part binary encoding of p. 41 // 42 // The internal p.RequestID is overridden by the reqid argument. 43 func (p *RawPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) { 44 buf := NewBuffer(b) 45 if buf.Cap() < 9 { 46 buf = NewMarshalBuffer(0) 47 } 48 49 buf.StartPacket(p.PacketType, reqid) 50 51 return buf.Packet(p.Data.Bytes()) 52 } 53 54 // MarshalBinary returns p as the binary encoding of p. 55 // 56 // This is a convenience implementation primarily intended for tests, 57 // because it is inefficient with allocations. 58 func (p *RawPacket) MarshalBinary() ([]byte, error) { 59 return ComposePacket(p.MarshalPacket(p.RequestID, nil)) 60 } 61 62 // UnmarshalFrom decodes a RawPacket from the given Buffer into p. 63 // 64 // The Data field will alias the passed in Buffer, 65 // so the buffer passed in should not be reused before RawPacket.Reset(). 66 func (p *RawPacket) UnmarshalFrom(buf *Buffer) error { 67 *p = RawPacket{ 68 PacketType: PacketType(buf.ConsumeUint8()), 69 RequestID: buf.ConsumeUint32(), 70 } 71 72 p.Data = *buf 73 74 return buf.Err 75 } 76 77 // UnmarshalBinary decodes a full raw packet out of the given data. 78 // It is assumed that the uint32(length) has already been consumed to receive the data. 79 // 80 // This is a convenience implementation primarily intended for tests, 81 // because this must clone the given data byte slice, 82 // as Data is not allowed to alias any part of the data byte slice. 83 func (p *RawPacket) UnmarshalBinary(data []byte) error { 84 clone := make([]byte, len(data)) 85 n := copy(clone, data) 86 return p.UnmarshalFrom(NewBuffer(clone[:n])) 87 } 88 89 // readPacket reads a uint32 length-prefixed binary data packet from r. 90 // using the given byte slice as a backing array. 91 // 92 // If the packet length read from r is bigger than maxPacketLength, 93 // or greater than math.MaxInt32 on a 32-bit implementation, 94 // then a `ErrLongPacket` error will be returned. 95 // 96 // If the given byte slice is insufficient to hold the packet, 97 // then it will be extended to fill the packet size. 98 func readPacket(r io.Reader, b []byte, maxPacketLength uint32) ([]byte, error) { 99 if cap(b) < 4 { 100 // We will need allocate our own buffer just for reading the packet length. 101 102 // However, we don’t really want to allocate an extremely narrow buffer (4-bytes), 103 // and cause unnecessary allocation churn from both length reads and small packet reads, 104 // so we use smallBufferSize from the bytes package as a reasonable guess. 105 106 // But if callers really do want to force narrow throw-away allocation of every packet body, 107 // they can do so with a buffer of capacity 4. 108 b = make([]byte, smallBufferSize) 109 } 110 111 if _, err := io.ReadFull(r, b[:4]); err != nil { 112 return nil, err 113 } 114 115 length := unmarshalUint32(b) 116 if int(length) < 5 { 117 // Must have at least uint8(type) and uint32(request-id) 118 119 if int(length) < 0 { 120 // Only possible when strconv.IntSize == 32, 121 // the packet length is longer than math.MaxInt32, 122 // and thus longer than any possible slice. 123 return nil, ErrLongPacket 124 } 125 126 return nil, ErrShortPacket 127 } 128 if length > maxPacketLength { 129 return nil, ErrLongPacket 130 } 131 132 if int(length) > cap(b) { 133 // We know int(length) must be positive, because of tests above. 134 b = make([]byte, length) 135 } 136 137 n, err := io.ReadFull(r, b[:length]) 138 return b[:n], err 139 } 140 141 // ReadFrom provides a simple functional packet reader, 142 // using the given byte slice as a backing array. 143 // 144 // To protect against potential denial of service attacks, 145 // if the read packet length is longer than maxPacketLength, 146 // then no packet data will be read, and ErrLongPacket will be returned. 147 // (On 32-bit int architectures, all packets >= 2^31 in length 148 // will return ErrLongPacket regardless of maxPacketLength.) 149 // 150 // If the read packet length is longer than cap(b), 151 // then a throw-away slice will allocated to meet the exact packet length. 152 // This can be used to limit the length of reused buffers, 153 // while still allowing reception of occasional large packets. 154 // 155 // The Data field may alias the passed in byte slice, 156 // so the byte slice passed in should not be reused before RawPacket.Reset(). 157 func (p *RawPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error { 158 b, err := readPacket(r, b, maxPacketLength) 159 if err != nil { 160 return err 161 } 162 163 return p.UnmarshalFrom(NewBuffer(b)) 164 } 165 166 // RequestPacket implements the general packet format from draft-ietf-secsh-filexfer-02 167 // but also automatically decode/encodes valid request packets (2 < type < 100 || type == 200). 168 // 169 // RequestPacket is intended for use in servers receiving requests, 170 // where any arbitrary request may be received, and so decoding them automatically 171 // is useful. 172 // 173 // For clients expecting to receive specific response packet types, 174 // where automatic unmarshaling of the packet body does not make sense, 175 // use RawPacket. 176 // 177 // Defined in https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-3 178 type RequestPacket struct { 179 RequestID uint32 180 181 Request Packet 182 } 183 184 // Type returns the SSH_FXP_xy value associated with the underlying packet. 185 func (p *RequestPacket) Type() PacketType { 186 return p.Request.Type() 187 } 188 189 // Reset clears the pointers and reference-semantic variables in RequestPacket, 190 // releasing underlying resources, and making them and the RequestPacket suitable to be reused, 191 // so long as no other references have been kept. 192 func (p *RequestPacket) Reset() { 193 p.Request = nil 194 } 195 196 // MarshalPacket returns p as a two-part binary encoding of p. 197 // 198 // The internal p.RequestID is overridden by the reqid argument. 199 func (p *RequestPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) { 200 if p.Request == nil { 201 return nil, nil, errors.New("empty request packet") 202 } 203 204 return p.Request.MarshalPacket(reqid, b) 205 } 206 207 // MarshalBinary returns p as the binary encoding of p. 208 // 209 // This is a convenience implementation primarily intended for tests, 210 // because it is inefficient with allocations. 211 func (p *RequestPacket) MarshalBinary() ([]byte, error) { 212 return ComposePacket(p.MarshalPacket(p.RequestID, nil)) 213 } 214 215 // UnmarshalFrom decodes a RequestPacket from the given Buffer into p. 216 // 217 // The Request field may alias the passed in Buffer, (e.g. SSH_FXP_WRITE), 218 // so the buffer passed in should not be reused before RequestPacket.Reset(). 219 func (p *RequestPacket) UnmarshalFrom(buf *Buffer) error { 220 typ := PacketType(buf.ConsumeUint8()) 221 if buf.Err != nil { 222 return buf.Err 223 } 224 225 req, err := newPacketFromType(typ) 226 if err != nil { 227 return err 228 } 229 230 *p = RequestPacket{ 231 RequestID: buf.ConsumeUint32(), 232 Request: req, 233 } 234 235 return p.Request.UnmarshalPacketBody(buf) 236 } 237 238 // UnmarshalBinary decodes a full request packet out of the given data. 239 // It is assumed that the uint32(length) has already been consumed to receive the data. 240 // 241 // This is a convenience implementation primarily intended for tests, 242 // because this must clone the given data byte slice, 243 // as Request is not allowed to alias any part of the data byte slice. 244 func (p *RequestPacket) UnmarshalBinary(data []byte) error { 245 clone := make([]byte, len(data)) 246 n := copy(clone, data) 247 return p.UnmarshalFrom(NewBuffer(clone[:n])) 248 } 249 250 // ReadFrom provides a simple functional packet reader, 251 // using the given byte slice as a backing array. 252 // 253 // To protect against potential denial of service attacks, 254 // if the read packet length is longer than maxPacketLength, 255 // then no packet data will be read, and ErrLongPacket will be returned. 256 // (On 32-bit int architectures, all packets >= 2^31 in length 257 // will return ErrLongPacket regardless of maxPacketLength.) 258 // 259 // If the read packet length is longer than cap(b), 260 // then a throw-away slice will allocated to meet the exact packet length. 261 // This can be used to limit the length of reused buffers, 262 // while still allowing reception of occasional large packets. 263 // 264 // The Request field may alias the passed in byte slice, 265 // so the byte slice passed in should not be reused before RawPacket.Reset(). 266 func (p *RequestPacket) ReadFrom(r io.Reader, b []byte, maxPacketLength uint32) error { 267 b, err := readPacket(r, b, maxPacketLength) 268 if err != nil { 269 return err 270 } 271 272 return p.UnmarshalFrom(NewBuffer(b)) 273 }