a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
1package sshfx 2 3import ( 4 "errors" 5 "io" 6) 7 8// smallBufferSize is an initial allocation minimal capacity. 9const 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 21type 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. 29func (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. 36func (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. 43func (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. 58func (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(). 66func (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. 83func (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. 98func 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(). 157func (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 178type RequestPacket struct { 179 RequestID uint32 180 181 Request Packet 182} 183 184// Type returns the SSH_FXP_xy value associated with the underlying packet. 185func (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. 192func (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. 199func (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. 211func (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(). 219func (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. 244func (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(). 266func (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}