github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/crypto/ssh/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 "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 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. 79 func 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. 88 type connection struct { 89 transport *handshakeTransport 90 sshConn 91 92 // The connection protocol. 93 *mux 94 } 95 96 func (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. 102 type sshConn struct { 103 conn net.Conn 104 105 user string 106 sessionID []byte 107 clientVersion []byte 108 serverVersion []byte 109 } 110 111 func dup(src []byte) []byte { 112 dst := make([]byte, len(src)) 113 copy(dst, src) 114 return dst 115 } 116 117 func (c *sshConn) User() string { 118 return c.user 119 } 120 121 func (c *sshConn) RemoteAddr() net.Addr { 122 return c.conn.RemoteAddr() 123 } 124 125 func (c *sshConn) Close() error { 126 return c.conn.Close() 127 } 128 129 func (c *sshConn) LocalAddr() net.Addr { 130 return c.conn.LocalAddr() 131 } 132 133 func (c *sshConn) SessionID() []byte { 134 return dup(c.sessionID) 135 } 136 137 func (c *sshConn) ClientVersion() []byte { 138 return dup(c.clientVersion) 139 } 140 141 func (c *sshConn) ServerVersion() []byte { 142 return dup(c.serverVersion) 143 }