github.com/glycerine/xcryptossh@v7.0.4+incompatible/connection.go (about)

     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  	"context"
     9  	"fmt"
    10  	"io"
    11  	"net"
    12  )
    13  
    14  // OpenChannelError is returned if the other side rejects an
    15  // OpenChannel request.
    16  type OpenChannelError struct {
    17  	Reason  RejectionReason
    18  	Message string
    19  }
    20  
    21  func (e *OpenChannelError) Error() string {
    22  	return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
    23  }
    24  
    25  // ConnMetadata holds metadata for the connection.
    26  type ConnMetadata interface {
    27  	// User returns the user ID for this connection.
    28  	User() string
    29  
    30  	// SessionID returns the session hash, also denoted by H.
    31  	SessionID() []byte
    32  
    33  	// ClientVersion returns the client's version string as hashed
    34  	// into the session ID.
    35  	ClientVersion() []byte
    36  
    37  	// ServerVersion returns the server's version string as hashed
    38  	// into the session ID.
    39  	ServerVersion() []byte
    40  
    41  	// RemoteAddr returns the remote address for this connection.
    42  	RemoteAddr() net.Addr
    43  
    44  	// LocalAddr returns the local address for this connection.
    45  	LocalAddr() net.Addr
    46  }
    47  
    48  // Conn represents an SSH connection for both server and client roles.
    49  // Conn is the basis for implementing an application layer, such
    50  // as ClientConn, which implements the traditional shell access for
    51  // clients.
    52  type Conn interface {
    53  	ConnMetadata
    54  
    55  	// SendRequest sends a global request, and returns the
    56  	// reply. If wantReply is true, it returns the response status
    57  	// and payload. See also RFC4254, section 4.
    58  	SendRequest(ctx context.Context, name string, wantReply bool, payload []byte) (bool, []byte, error)
    59  
    60  	// OpenChannel tries to open an channel. If the request is
    61  	// rejected, it returns *OpenChannelError. On success it returns
    62  	// the SSH Channel and a Go channel for incoming, out-of-band
    63  	// requests. The Go channel must be serviced, or the
    64  	// connection will hang.
    65  	OpenChannel(ctx context.Context, name string, data []byte, parHalt *Halter) (Channel, <-chan *Request, error)
    66  
    67  	// Close closes the underlying network connection
    68  	Close() error
    69  
    70  	// Wait blocks until the connection has shut down, and returns the
    71  	// error causing the shutdown.
    72  	Wait() error
    73  
    74  	// Done can be used to await connection shutdown. The
    75  	// returned channel will be closed when the Conn is
    76  	// shutting down.
    77  	Done() <-chan struct{}
    78  
    79  	// NcCloser retreives the underlying net.Conn so
    80  	// that it can be closed.
    81  	NcCloser() io.Closer
    82  
    83  	// TODO(hanwen): consider exposing:
    84  	//   RequestKeyChange
    85  	//   Disconnect
    86  }
    87  
    88  // DiscardRequests consumes and rejects all requests from the
    89  // passed-in channel.
    90  func DiscardRequests(ctx context.Context, in <-chan *Request, halt *Halter) {
    91  
    92  	var reqStop chan struct{}
    93  	if halt != nil {
    94  		reqStop = halt.ReqStopChan()
    95  	}
    96  	for {
    97  		select {
    98  		case req := <-in:
    99  			if req != nil && req.WantReply {
   100  				req.Reply(false, nil)
   101  			}
   102  		case <-reqStop:
   103  			return
   104  		case <-ctx.Done():
   105  			return
   106  		}
   107  	}
   108  }
   109  
   110  // A connection represents an incoming connection.
   111  type connection struct {
   112  	transport *handshakeTransport
   113  	sshConn
   114  
   115  	// the Config used
   116  	cfg *Config
   117  
   118  	// for client connections, provides the User, HostPort
   119  	clicfg *ClientConfig
   120  
   121  	// clean shutdown mechanism
   122  	halt *Halter
   123  
   124  	// The connection protocol.
   125  	*mux
   126  }
   127  
   128  func newConnection(nc net.Conn, cfg *Config, clicfg *ClientConfig) *connection {
   129  	// clicfg will be nil for server side.
   130  
   131  	if cfg.Halt == nil {
   132  		panic("assert: cfg.Halt cannot be nil in newConnection()")
   133  	}
   134  	conn := &connection{
   135  		sshConn: sshConn{conn: nc},
   136  		halt:    cfg.Halt,
   137  		cfg:     cfg,
   138  		clicfg:  clicfg,
   139  	}
   140  
   141  	return conn
   142  }
   143  
   144  func (c *connection) Close() error {
   145  	c.halt.RequestStop()
   146  	return c.sshConn.conn.Close()
   147  }
   148  
   149  func (c *connection) Done() <-chan struct{} {
   150  	return c.halt.ReqStopChan()
   151  }
   152  
   153  // sshconn provides net.Conn metadata, but disallows direct reads and
   154  // writes.
   155  type sshConn struct {
   156  	conn net.Conn
   157  
   158  	user          string
   159  	sessionID     []byte
   160  	clientVersion []byte
   161  	serverVersion []byte
   162  }
   163  
   164  func dup(src []byte) []byte {
   165  	dst := make([]byte, len(src))
   166  	copy(dst, src)
   167  	return dst
   168  }
   169  
   170  func (c *sshConn) NcCloser() io.Closer {
   171  	return c.conn
   172  }
   173  
   174  func (c *sshConn) User() string {
   175  	return c.user
   176  }
   177  
   178  func (c *sshConn) RemoteAddr() net.Addr {
   179  	return c.conn.RemoteAddr()
   180  }
   181  
   182  func (c *sshConn) Close() error {
   183  	return c.conn.Close()
   184  }
   185  
   186  func (c *sshConn) LocalAddr() net.Addr {
   187  	return c.conn.LocalAddr()
   188  }
   189  
   190  func (c *sshConn) SessionID() []byte {
   191  	return dup(c.sessionID)
   192  }
   193  
   194  func (c *sshConn) ClientVersion() []byte {
   195  	return dup(c.clientVersion)
   196  }
   197  
   198  func (c *sshConn) ServerVersion() []byte {
   199  	return dup(c.serverVersion)
   200  }