2023-03-28 01:05:24 +08:00
|
|
|
|
package sshfx
|
2021-03-19 01:01:58 +08:00
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"errors"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Various encoding errors.
|
|
|
|
|
var (
|
|
|
|
|
ErrShortPacket = errors.New("packet too short")
|
2021-03-21 22:07:30 +08:00
|
|
|
|
ErrLongPacket = errors.New("packet too long")
|
2021-03-19 01:01:58 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Buffer wraps up the various encoding details of the SSH format.
|
|
|
|
|
//
|
|
|
|
|
// Data types are encoded as per section 4 from https://tools.ietf.org/html/draft-ietf-secsh-architecture-09#page-8
|
|
|
|
|
type Buffer struct {
|
2021-03-21 22:07:30 +08:00
|
|
|
|
b []byte
|
|
|
|
|
off int
|
2023-03-28 01:05:24 +08:00
|
|
|
|
Err error
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// NewBuffer creates and initializes a new buffer using buf as its initial contents.
|
|
|
|
|
// The new buffer takes ownership of buf, and the caller should not use buf after this call.
|
2021-03-22 20:21:18 +08:00
|
|
|
|
//
|
|
|
|
|
// In most cases, new(Buffer) (or just declaring a Buffer variable) is sufficient to initialize a Buffer.
|
|
|
|
|
func NewBuffer(buf []byte) *Buffer {
|
2021-03-19 01:01:58 +08:00
|
|
|
|
return &Buffer{
|
2021-03-22 20:21:18 +08:00
|
|
|
|
b: buf,
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-23 00:12:42 +08:00
|
|
|
|
// NewMarshalBuffer creates a new Buffer ready to start marshaling a Packet into.
|
|
|
|
|
// It preallocates enough space for uint32(length), uint8(type), uint32(request-id) and size more bytes.
|
|
|
|
|
func NewMarshalBuffer(size int) *Buffer {
|
|
|
|
|
return NewBuffer(make([]byte, 4+1+4+size))
|
|
|
|
|
}
|
2021-03-20 05:19:45 +08:00
|
|
|
|
|
2021-03-19 01:01:58 +08:00
|
|
|
|
// Bytes returns a slice of length b.Len() holding the unconsumed bytes in the Buffer.
|
2021-03-22 20:21:18 +08:00
|
|
|
|
// The slice is valid for use only until the next buffer modification
|
|
|
|
|
// (that is, only until the next call to an Append or Consume method).
|
2021-03-19 01:01:58 +08:00
|
|
|
|
func (b *Buffer) Bytes() []byte {
|
2021-03-21 22:07:30 +08:00
|
|
|
|
return b.b[b.off:]
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// Len returns the number of unconsumed bytes in the buffer.
|
|
|
|
|
func (b *Buffer) Len() int { return len(b.b) - b.off }
|
|
|
|
|
|
|
|
|
|
// Cap returns the capacity of the buffer’s underlying byte slice,
|
|
|
|
|
// that is, the total space allocated for the buffer’s data.
|
|
|
|
|
func (b *Buffer) Cap() int { return cap(b.b) }
|
|
|
|
|
|
|
|
|
|
// Reset resets the buffer to be empty, but it retains the underlying storage for use by future Appends.
|
|
|
|
|
func (b *Buffer) Reset() {
|
2023-03-28 01:05:24 +08:00
|
|
|
|
*b = Buffer{
|
|
|
|
|
b: b.b[:0],
|
|
|
|
|
}
|
2021-03-25 04:29:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// StartPacket resets and initializes the buffer to be ready to start marshaling a packet into.
|
|
|
|
|
// It truncates the buffer, reserves space for uint32(length), then appends the given packetType and requestID.
|
|
|
|
|
func (b *Buffer) StartPacket(packetType PacketType, requestID uint32) {
|
2023-03-28 01:05:24 +08:00
|
|
|
|
*b = Buffer{
|
|
|
|
|
b: append(b.b[:0], make([]byte, 4)...),
|
|
|
|
|
}
|
2021-03-25 04:29:37 +08:00
|
|
|
|
|
|
|
|
|
b.AppendUint8(uint8(packetType))
|
|
|
|
|
b.AppendUint32(requestID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Packet finalizes the packet started from StartPacket.
|
2021-03-22 20:21:18 +08:00
|
|
|
|
// It is expected that this will end the ownership of the underlying byte-slice,
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// and so the returned byte-slices may be reused the same as any other byte-slice,
|
|
|
|
|
// the caller should not use this buffer after this call.
|
2021-03-20 05:19:45 +08:00
|
|
|
|
//
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// It writes the packet body length into the first four bytes of the buffer in network byte order (big endian).
|
|
|
|
|
// The packet body length is the length of this buffer less the 4-byte length itself, plus the length of payload.
|
2021-03-22 20:21:18 +08:00
|
|
|
|
//
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// It is assumed that no Consume methods have been called on this buffer,
|
2021-03-22 20:21:18 +08:00
|
|
|
|
// and so it returns the whole underlying slice.
|
|
|
|
|
func (b *Buffer) Packet(payload []byte) (header, payloadPassThru []byte, err error) {
|
2021-03-20 05:19:45 +08:00
|
|
|
|
b.PutLength(len(b.b) - 4 + len(payload))
|
|
|
|
|
|
|
|
|
|
return b.b, payload, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeUint8 consumes a single byte from the buffer.
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, it will set Err to ErrShortPacket.
|
|
|
|
|
func (b *Buffer) ConsumeUint8() uint8 {
|
|
|
|
|
if b.Err != nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
if b.Len() < 1 {
|
2023-03-28 01:05:24 +08:00
|
|
|
|
b.off = len(b.b)
|
|
|
|
|
b.Err = ErrShortPacket
|
|
|
|
|
return 0
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var v uint8
|
2021-03-21 22:07:30 +08:00
|
|
|
|
v, b.off = b.b[b.off], b.off+1
|
2023-03-28 01:05:24 +08:00
|
|
|
|
return v
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendUint8 appends a single byte into the buffer.
|
2021-03-19 01:01:58 +08:00
|
|
|
|
func (b *Buffer) AppendUint8(v uint8) {
|
|
|
|
|
b.b = append(b.b, v)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeBool consumes a single byte from the buffer, and returns true if that byte is non-zero.
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, it will set Err to ErrShortPacket.
|
|
|
|
|
func (b *Buffer) ConsumeBool() bool {
|
|
|
|
|
return b.ConsumeUint8() != 0
|
2021-03-21 22:07:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendBool appends a single bool into the buffer.
|
2021-03-21 22:07:30 +08:00
|
|
|
|
// It encodes it as a single byte, with false as 0, and true as 1.
|
|
|
|
|
func (b *Buffer) AppendBool(v bool) {
|
|
|
|
|
if v {
|
|
|
|
|
b.AppendUint8(1)
|
|
|
|
|
} else {
|
|
|
|
|
b.AppendUint8(0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeUint16 consumes a single uint16 from the buffer, in network byte order (big-endian).
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, it will set Err to ErrShortPacket.
|
|
|
|
|
func (b *Buffer) ConsumeUint16() uint16 {
|
|
|
|
|
if b.Err != nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
if b.Len() < 2 {
|
2023-03-28 01:05:24 +08:00
|
|
|
|
b.off = len(b.b)
|
|
|
|
|
b.Err = ErrShortPacket
|
|
|
|
|
return 0
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
v := binary.BigEndian.Uint16(b.b[b.off:])
|
|
|
|
|
b.off += 2
|
2023-03-28 01:05:24 +08:00
|
|
|
|
return v
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendUint16 appends single uint16 into the buffer, in network byte order (big-endian).
|
2021-03-19 01:01:58 +08:00
|
|
|
|
func (b *Buffer) AppendUint16(v uint16) {
|
|
|
|
|
b.b = append(b.b,
|
|
|
|
|
byte(v>>8),
|
|
|
|
|
byte(v>>0),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// unmarshalUint32 is used internally to read the packet length.
|
|
|
|
|
// It is unsafe, and so not exported.
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// Even within this package, its use should be avoided.
|
2021-03-21 22:07:30 +08:00
|
|
|
|
func unmarshalUint32(b []byte) uint32 {
|
2021-03-25 04:29:37 +08:00
|
|
|
|
return binary.BigEndian.Uint32(b[:4])
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeUint32 consumes a single uint32 from the buffer, in network byte order (big-endian).
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, it will set Err to ErrShortPacket.
|
|
|
|
|
func (b *Buffer) ConsumeUint32() uint32 {
|
|
|
|
|
if b.Err != nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
if b.Len() < 4 {
|
2023-03-28 01:05:24 +08:00
|
|
|
|
b.off = len(b.b)
|
|
|
|
|
b.Err = ErrShortPacket
|
|
|
|
|
return 0
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
v := binary.BigEndian.Uint32(b.b[b.off:])
|
|
|
|
|
b.off += 4
|
2023-03-28 01:05:24 +08:00
|
|
|
|
return v
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendUint32 appends a single uint32 into the buffer, in network byte order (big-endian).
|
2021-03-19 01:01:58 +08:00
|
|
|
|
func (b *Buffer) AppendUint32(v uint32) {
|
|
|
|
|
b.b = append(b.b,
|
|
|
|
|
byte(v>>24),
|
|
|
|
|
byte(v>>16),
|
|
|
|
|
byte(v>>8),
|
|
|
|
|
byte(v>>0),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// ConsumeCount consumes a single uint32 count from the buffer, in network byte order (big-endian) as an int.
|
|
|
|
|
// If the buffer does not have enough data, it will set Err to ErrShortPacket.
|
|
|
|
|
func (b *Buffer) ConsumeCount() int {
|
|
|
|
|
return int(b.ConsumeUint32())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AppendCount appends a single int length as a uint32 into the buffer, in network byte order (big-endian).
|
|
|
|
|
func (b *Buffer) AppendCount(v int) {
|
|
|
|
|
b.AppendUint32(uint32(v))
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeUint64 consumes a single uint64 from the buffer, in network byte order (big-endian).
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, it will set Err to ErrShortPacket.
|
|
|
|
|
func (b *Buffer) ConsumeUint64() uint64 {
|
|
|
|
|
if b.Err != nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
if b.Len() < 8 {
|
2023-03-28 01:05:24 +08:00
|
|
|
|
b.off = len(b.b)
|
|
|
|
|
b.Err = ErrShortPacket
|
|
|
|
|
return 0
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
v := binary.BigEndian.Uint64(b.b[b.off:])
|
|
|
|
|
b.off += 8
|
2023-03-28 01:05:24 +08:00
|
|
|
|
return v
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendUint64 appends a single uint64 into the buffer, in network byte order (big-endian).
|
2021-03-19 01:01:58 +08:00
|
|
|
|
func (b *Buffer) AppendUint64(v uint64) {
|
|
|
|
|
b.b = append(b.b,
|
|
|
|
|
byte(v>>56),
|
|
|
|
|
byte(v>>48),
|
|
|
|
|
byte(v>>40),
|
|
|
|
|
byte(v>>32),
|
|
|
|
|
byte(v>>24),
|
|
|
|
|
byte(v>>16),
|
|
|
|
|
byte(v>>8),
|
|
|
|
|
byte(v>>0),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeInt64 consumes a single int64 from the buffer, in network byte order (big-endian) with two’s complement.
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, it will set Err to ErrShortPacket.
|
|
|
|
|
func (b *Buffer) ConsumeInt64() int64 {
|
|
|
|
|
return int64(b.ConsumeUint64())
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendInt64 appends a single int64 into the buffer, in network byte order (big-endian) with two’s complement.
|
|
|
|
|
func (b *Buffer) AppendInt64(v int64) {
|
2021-03-19 01:01:58 +08:00
|
|
|
|
b.AppendUint64(uint64(v))
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeByteSlice consumes a single string of raw binary data from the buffer.
|
2021-03-19 01:01:58 +08:00
|
|
|
|
// A string is a uint32 length, followed by that number of raw bytes.
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket.
|
2021-03-25 04:29:37 +08:00
|
|
|
|
//
|
|
|
|
|
// The returned slice aliases the buffer contents, and is valid only as long as the buffer is not reused
|
|
|
|
|
// (that is, only until the next call to Reset, PutLength, StartPacket, or UnmarshalBinary).
|
|
|
|
|
//
|
|
|
|
|
// In no case will any Consume calls return overlapping slice aliases,
|
|
|
|
|
// and Append calls are guaranteed to not disturb this slice alias.
|
2023-03-28 01:05:24 +08:00
|
|
|
|
func (b *Buffer) ConsumeByteSlice() []byte {
|
|
|
|
|
length := int(b.ConsumeUint32())
|
|
|
|
|
if b.Err != nil {
|
|
|
|
|
return nil
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-28 01:05:24 +08:00
|
|
|
|
if b.Len() < length || length < 0 {
|
|
|
|
|
b.off = len(b.b)
|
|
|
|
|
b.Err = ErrShortPacket
|
|
|
|
|
return nil
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-21 22:07:30 +08:00
|
|
|
|
v := b.b[b.off:]
|
2023-03-28 01:05:24 +08:00
|
|
|
|
if len(v) > length || cap(v) > length {
|
2021-03-21 22:07:30 +08:00
|
|
|
|
v = v[:length:length]
|
|
|
|
|
}
|
|
|
|
|
b.off += int(length)
|
2023-03-28 01:05:24 +08:00
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ConsumeByteSliceCopy consumes a single string of raw binary data as a copy from the buffer.
|
|
|
|
|
// A string is a uint32 length, followed by that number of raw bytes.
|
|
|
|
|
// If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket.
|
|
|
|
|
//
|
|
|
|
|
// The returned slice does not alias any buffer contents,
|
|
|
|
|
// and will therefore be valid even if the buffer is later reused.
|
|
|
|
|
//
|
|
|
|
|
// If hint has sufficient capacity to hold the data, it will be reused and overwritten,
|
|
|
|
|
// otherwise a new backing slice will be allocated and returned.
|
|
|
|
|
func (b *Buffer) ConsumeByteSliceCopy(hint []byte) []byte {
|
|
|
|
|
data := b.ConsumeByteSlice()
|
|
|
|
|
|
|
|
|
|
if grow := len(data) - len(hint); grow > 0 {
|
|
|
|
|
hint = append(hint, make([]byte, grow)...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n := copy(hint, data)
|
|
|
|
|
hint = hint[:n]
|
|
|
|
|
return hint
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendByteSlice appends a single string of raw binary data into the buffer.
|
2021-03-19 01:01:58 +08:00
|
|
|
|
// A string is a uint32 length, followed by that number of raw bytes.
|
|
|
|
|
func (b *Buffer) AppendByteSlice(v []byte) {
|
|
|
|
|
b.AppendUint32(uint32(len(v)))
|
|
|
|
|
b.b = append(b.b, v...)
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// ConsumeString consumes a single string of binary data from the buffer.
|
2021-03-19 01:01:58 +08:00
|
|
|
|
// A string is a uint32 length, followed by that number of raw bytes.
|
2023-03-28 01:05:24 +08:00
|
|
|
|
// If the buffer does not have enough data, or defines a length larger than available, it will set Err to ErrShortPacket.
|
2021-03-22 20:31:05 +08:00
|
|
|
|
//
|
|
|
|
|
// NOTE: Go implicitly assumes that strings contain UTF-8 encoded data.
|
|
|
|
|
// All caveats on using arbitrary binary data in Go strings applies.
|
2023-03-28 01:05:24 +08:00
|
|
|
|
func (b *Buffer) ConsumeString() string {
|
|
|
|
|
return string(b.ConsumeByteSlice())
|
2021-03-19 01:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// AppendString appends a single string of binary data into the buffer.
|
2021-03-19 01:01:58 +08:00
|
|
|
|
// A string is a uint32 length, followed by that number of raw bytes.
|
|
|
|
|
func (b *Buffer) AppendString(v string) {
|
|
|
|
|
b.AppendByteSlice([]byte(v))
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// PutLength writes the given size into the first four bytes of the buffer in network byte order (big endian).
|
2021-03-19 01:01:58 +08:00
|
|
|
|
func (b *Buffer) PutLength(size int) {
|
|
|
|
|
if len(b.b) < 4 {
|
|
|
|
|
b.b = append(b.b, make([]byte, 4-len(b.b))...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
binary.BigEndian.PutUint32(b.b, uint32(size))
|
|
|
|
|
}
|
2021-03-20 03:45:41 +08:00
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// MarshalBinary returns a clone of the full internal buffer.
|
2021-03-20 03:45:41 +08:00
|
|
|
|
func (b *Buffer) MarshalBinary() ([]byte, error) {
|
2021-03-25 04:29:37 +08:00
|
|
|
|
clone := make([]byte, len(b.b))
|
|
|
|
|
n := copy(clone, b.b)
|
|
|
|
|
return clone[:n], nil
|
2021-03-20 03:45:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-03-25 04:29:37 +08:00
|
|
|
|
// UnmarshalBinary sets the internal buffer of b to be a clone of data, and zeros the internal offset.
|
2021-03-20 03:45:41 +08:00
|
|
|
|
func (b *Buffer) UnmarshalBinary(data []byte) error {
|
2021-03-25 04:29:37 +08:00
|
|
|
|
if grow := len(data) - len(b.b); grow > 0 {
|
|
|
|
|
b.b = append(b.b, make([]byte, grow)...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n := copy(b.b, data)
|
|
|
|
|
b.b = b.b[:n]
|
2021-03-22 20:21:18 +08:00
|
|
|
|
b.off = 0
|
2021-03-20 03:45:41 +08:00
|
|
|
|
return nil
|
|
|
|
|
}
|