connection.go raw

   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  
   5  package ssh
   6  
   7  import (
   8  	"fmt"
   9  	"net"
  10  )
  11  
  12  // OpenChannelError is returned if the other side rejects an
  13  // OpenChannel request.
  14  type OpenChannelError struct {
  15  	Reason  RejectionReason
  16  	Message string
  17  }
  18  
  19  func (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.
  24  type 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.
  50  type 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 RFC 4254, 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  // AlgorithmsConnMetadata is a ConnMetadata that can return the algorithms
  78  // negotiated between client and server.
  79  type AlgorithmsConnMetadata interface {
  80  	ConnMetadata
  81  	Algorithms() NegotiatedAlgorithms
  82  }
  83  
  84  // DiscardRequests consumes and rejects all requests from the
  85  // passed-in channel.
  86  func DiscardRequests(in <-chan *Request) {
  87  	for req := range in {
  88  		if req.WantReply {
  89  			req.Reply(false, nil)
  90  		}
  91  	}
  92  }
  93  
  94  // A connection represents an incoming connection.
  95  type connection struct {
  96  	transport *handshakeTransport
  97  	sshConn
  98  
  99  	// The connection protocol.
 100  	*mux
 101  }
 102  
 103  func (c *connection) Close() error {
 104  	return c.sshConn.conn.Close()
 105  }
 106  
 107  // sshConn provides net.Conn metadata, but disallows direct reads and
 108  // writes.
 109  type sshConn struct {
 110  	conn net.Conn
 111  
 112  	user          string
 113  	sessionID     []byte
 114  	clientVersion []byte
 115  	serverVersion []byte
 116  	algorithms    NegotiatedAlgorithms
 117  }
 118  
 119  func dup(src []byte) []byte {
 120  	dst := make([]byte, len(src))
 121  	copy(dst, src)
 122  	return dst
 123  }
 124  
 125  func (c *sshConn) User() string {
 126  	return c.user
 127  }
 128  
 129  func (c *sshConn) RemoteAddr() net.Addr {
 130  	return c.conn.RemoteAddr()
 131  }
 132  
 133  func (c *sshConn) Close() error {
 134  	return c.conn.Close()
 135  }
 136  
 137  func (c *sshConn) LocalAddr() net.Addr {
 138  	return c.conn.LocalAddr()
 139  }
 140  
 141  func (c *sshConn) SessionID() []byte {
 142  	return dup(c.sessionID)
 143  }
 144  
 145  func (c *sshConn) ClientVersion() []byte {
 146  	return dup(c.clientVersion)
 147  }
 148  
 149  func (c *sshConn) ServerVersion() []byte {
 150  	return dup(c.serverVersion)
 151  }
 152  
 153  func (c *sshConn) Algorithms() NegotiatedAlgorithms {
 154  	return c.algorithms
 155  }
 156