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 }