func Unmarshal(data []byte, out interface{}) error {
	v := reflect.ValueOf(out).Elem()
	structType := v.Type()
	expectedTypes := typeTags(structType)
	var expectedType byte
	if len(expectedTypes) > 0 {
		expectedType = expectedTypes[0]
	}
	if len(data) == 0 {
		return parseError(expectedType)
	}
	if len(expectedTypes) > 0 {
		goodType := false
		for _, e := range expectedTypes {
			if e > 0 && data[0] == e {
				goodType = true
				break
			}
		}
		if !goodType {
			return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
		}
		data = data[1:]
	}
	var ok bool
	for i := 0; i < v.NumField(); i++ {
		field := v.Field(i)
		t := field.Type()
		switch t.Kind() {
		case reflect.Bool:
			if len(data) < 1 {
				return errShortRead
			}
			field.SetBool(data[0] != 0)
			data = data[1:]
		case reflect.Array:
			if t.Elem().Kind() != reflect.Uint8 {
				return fieldError(structType, i, "array of unsupported type")
			}
			if len(data) < t.Len() {
				return errShortRead
			}
			for j, n := 0, t.Len(); j < n; j++ {
				field.Index(j).Set(reflect.ValueOf(data[j]))
			}
			data = data[t.Len():]
		case reflect.Uint64:
			var u64 uint64
			if u64, data, ok = parseUint64(data); !ok {
				return errShortRead
			}
			field.SetUint(u64)
		case reflect.Uint32:
			var u32 uint32
			if u32, data, ok = parseUint32(data); !ok {
				return errShortRead
			}
			field.SetUint(uint64(u32))
		case reflect.Uint8:
			if len(data) < 1 {
				return errShortRead
			}
			field.SetUint(uint64(data[0]))
			data = data[1:]
		case reflect.String:
			var s []byte
			if s, data, ok = parseString(data); !ok {
				return fieldError(structType, i, "")
			}
			field.SetString(string(s))
		case reflect.Slice:
			switch t.Elem().Kind() {
			case reflect.Uint8:
				if structType.Field(i).Tag.Get("ssh") == "rest" {
					field.Set(reflect.ValueOf(data))
					data = nil
				} else {
					var s []byte
					if s, data, ok = parseString(data); !ok {
						return errShortRead
					}
					field.Set(reflect.ValueOf(s))
				}
			case reflect.String:
				var nl []string
				if nl, data, ok = parseNameList(data); !ok {
					return errShortRead
				}
				field.Set(reflect.ValueOf(nl))
			default:
				return fieldError(structType, i, "slice of unsupported type")
			}
		case reflect.Ptr:
			if t == bigIntType {
				var n *big.Int
				if n, data, ok = parseInt(data); !ok {
					return errShortRead
				}
				field.Set(reflect.ValueOf(n))
			} else {
				return fieldError(structType, i, "pointer to unsupported type")
			}
		default:
			return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
		}
	}
	if len(data) != 0 {
		return parseError(expectedType)
	}
	return nil
}
Unmarshal parses data in SSH wire format into a structure. The out
argument should be a pointer to struct. If the first member of the
struct has the "sshtype" tag set to a '|'-separated set of numbers
in decimal, the packet must start with one of those numbers. In
case of error, Unmarshal returns a ParseError or
UnexpectedMessageError.
package ssh
import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math/big"
	"reflect"
	"strconv"
	"strings"
)
const (
	msgIgnore        = 2
	msgUnimplemented = 3
	msgDebug         = 4
	msgNewKeys       = 21
	msgUserAuthSuccess = 52
	msgUserAuthBanner  = 53
)
const msgDisconnect = 1
type disconnectMsg struct {
	Reason   uint32 `sshtype:"1"`
	Message  string
	Language string
}
func (d *disconnectMsg) Error() string {
	return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
}
const msgKexInit = 20
type kexInitMsg struct {
	Cookie                  [16]byte `sshtype:"20"`
	KexAlgos                []string
	ServerHostKeyAlgos      []string
	CiphersClientServer     []string
	CiphersServerClient     []string
	MACsClientServer        []string
	MACsServerClient        []string
	CompressionClientServer []string
	CompressionServerClient []string
	LanguagesClientServer   []string
	LanguagesServerClient   []string
	FirstKexFollows         bool
	Reserved                uint32
}
const msgKexDHInit = 30
type kexDHInitMsg struct {
	X *big.Int `sshtype:"30"`
}
const msgKexECDHInit = 30
type kexECDHInitMsg struct {
	ClientPubKey []byte `sshtype:"30"`
}
const msgKexECDHReply = 31
type kexECDHReplyMsg struct {
	HostKey         []byte `sshtype:"31"`
	EphemeralPubKey []byte
	Signature       []byte
}
const msgKexDHReply = 31
type kexDHReplyMsg struct {
	HostKey   []byte `sshtype:"31"`
	Y         *big.Int
	Signature []byte
}
const msgServiceRequest = 5
type serviceRequestMsg struct {
	Service string `sshtype:"5"`
}
const msgServiceAccept = 6
type serviceAcceptMsg struct {
	Service string `sshtype:"6"`
}
const msgUserAuthRequest = 50
type userAuthRequestMsg struct {
	User    string `sshtype:"50"`
	Service string
	Method  string
	Payload []byte `ssh:"rest"`
}
type userAuthSuccessMsg struct {
}
const msgUserAuthFailure = 51
type userAuthFailureMsg struct {
	Methods        []string `sshtype:"51"`
	PartialSuccess bool
}
const msgUserAuthInfoRequest = 60
const msgUserAuthInfoResponse = 61
type userAuthInfoRequestMsg struct {
	User               string `sshtype:"60"`
	Instruction        string
	DeprecatedLanguage string
	NumPrompts         uint32
	Prompts            []byte `ssh:"rest"`
}
const msgChannelOpen = 90
type channelOpenMsg struct {
	ChanType         string `sshtype:"90"`
	PeersId          uint32
	PeersWindow      uint32
	MaxPacketSize    uint32
	TypeSpecificData []byte `ssh:"rest"`
}
const msgChannelExtendedData = 95
const msgChannelData = 94
type channelDataMsg struct {
	PeersId uint32 `sshtype:"94"`
	Length  uint32
	Rest    []byte `ssh:"rest"`
}
const msgChannelOpenConfirm = 91
type channelOpenConfirmMsg struct {
	PeersId          uint32 `sshtype:"91"`
	MyId             uint32
	MyWindow         uint32
	MaxPacketSize    uint32
	TypeSpecificData []byte `ssh:"rest"`
}
const msgChannelOpenFailure = 92
type channelOpenFailureMsg struct {
	PeersId  uint32 `sshtype:"92"`
	Reason   RejectionReason
	Message  string
	Language string
}
const msgChannelRequest = 98
type channelRequestMsg struct {
	PeersId             uint32 `sshtype:"98"`
	Request             string
	WantReply           bool
	RequestSpecificData []byte `ssh:"rest"`
}
const msgChannelSuccess = 99
type channelRequestSuccessMsg struct {
	PeersId uint32 `sshtype:"99"`
}
const msgChannelFailure = 100
type channelRequestFailureMsg struct {
	PeersId uint32 `sshtype:"100"`
}
const msgChannelClose = 97
type channelCloseMsg struct {
	PeersId uint32 `sshtype:"97"`
}
const msgChannelEOF = 96
type channelEOFMsg struct {
	PeersId uint32 `sshtype:"96"`
}
const msgGlobalRequest = 80
type globalRequestMsg struct {
	Type      string `sshtype:"80"`
	WantReply bool
	Data      []byte `ssh:"rest"`
}
const msgRequestSuccess = 81
type globalRequestSuccessMsg struct {
	Data []byte `ssh:"rest" sshtype:"81"`
}
const msgRequestFailure = 82
type globalRequestFailureMsg struct {
	Data []byte `ssh:"rest" sshtype:"82"`
}
const msgChannelWindowAdjust = 93
type windowAdjustMsg struct {
	PeersId         uint32 `sshtype:"93"`
	AdditionalBytes uint32
}
const msgUserAuthPubKeyOk = 60
type userAuthPubKeyOkMsg struct {
	Algo   string `sshtype:"60"`
	PubKey []byte
}
func typeTags(structType reflect.Type) (tags []byte) {
	tagStr := structType.Field(0).Tag.Get("sshtype")
	for _, tag := range strings.Split(tagStr, "|") {
		i, err := strconv.Atoi(tag)
		if err == nil {
			tags = append(tags, byte(i))
		}
	}
	return tags
}
func fieldError(t reflect.Type, field int, problem string) error {
	if problem != "" {
		problem = ": " + problem
	}
	return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
}
var errShortRead = errors.New("ssh: short read")