1// Copyright 2013 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 5package ssh 6 7import ( 8 "fmt" 9 "net" 10) 11 12// OpenChannelError is returned if the other side rejects an 13// OpenChannel request. 14type OpenChannelError struct { 15 Reason RejectionReason 16 Message string 17} 18 19func (e *OpenChannelError) Error() string { 20 return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) 21} 22 23// ConnMetadata holds metadata for the connection. 24type ConnMetadata interface { 25 // User returns the user ID for this connection. 26 User() string 27 28 // SessionID returns the session hash, also denoted by H. 29 SessionID() []byte 30 31 // ClientVersion returns the client's version string as hashed 32 // into the session ID. 33 ClientVersion() []byte 34 35 // ServerVersion returns the server's version string as hashed 36 // into the session ID. 37 ServerVersion() []byte 38 39 // RemoteAddr returns the remote address for this connection. 40 RemoteAddr() net.Addr 41 42 // LocalAddr returns the local address for this connection. 43 LocalAddr() net.Addr 44} 45 46// Conn represents an SSH connection for both server and client roles. 47// Conn is the basis for implementing an application layer, such 48// as ClientConn, which implements the traditional shell access for 49// clients. 50type Conn interface { 51 ConnMetadata 52 53 // SendRequest sends a global request, and returns the 54 // reply. If wantReply is true, it returns the response status 55 // and payload. See also RFC4254, section 4. 56 SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) 57 58 // OpenChannel tries to open an channel. If the request is 59 // rejected, it returns *OpenChannelError. On success it returns 60 // the SSH Channel and a Go channel for incoming, out-of-band 61 // requests. The Go channel must be serviced, or the 62 // connection will hang. 63 OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) 64 65 // Close closes the underlying network connection 66 Close() error 67 68 // Wait blocks until the connection has shut down, and returns the 69 // error causing the shutdown. 70 Wait() error 71 72 // TODO(hanwen): consider exposing: 73 // RequestKeyChange 74 // Disconnect 75} 76 77// DiscardRequests consumes and rejects all requests from the 78// passed-in channel. 79func DiscardRequests(in <-chan *Request) { 80 for req := range in { 81 if req.WantReply { 82 req.Reply(false, nil) 83 } 84 } 85} 86 87// A connection represents an incoming connection. 88type connection struct { 89 transport *handshakeTransport 90 sshConn 91 92 // The connection protocol. 93 *mux 94} 95 96func (c *connection) Close() error { 97 return c.sshConn.conn.Close() 98} 99 100// sshconn provides net.Conn metadata, but disallows direct reads and 101// writes. 102type sshConn struct { 103 conn net.Conn 104 105 user string 106 sessionID []byte 107 clientVersion []byte 108 serverVersion []byte 109} 110 111func dup(src []byte) []byte { 112 dst := make([]byte, len(src)) 113 copy(dst, src) 114 return dst 115} 116 117func (c *sshConn) User() string { 118 return c.user 119} 120 121func (c *sshConn) RemoteAddr() net.Addr { 122 return c.conn.RemoteAddr() 123} 124 125func (c *sshConn) Close() error { 126 return c.conn.Close() 127} 128 129func (c *sshConn) LocalAddr() net.Addr { 130 return c.conn.LocalAddr() 131} 132 133func (c *sshConn) SessionID() []byte { 134 return dup(c.sessionID) 135} 136 137func (c *sshConn) ClientVersion() []byte { 138 return dup(c.clientVersion) 139} 140 141func (c *sshConn) ServerVersion() []byte { 142 return dup(c.serverVersion) 143} 144