LEFT | RIGHT |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package ssh | 5 package ssh |
6 | 6 |
7 import ( | 7 import ( |
8 "crypto/rand" | 8 "crypto/rand" |
9 "encoding/binary" | 9 "encoding/binary" |
10 "errors" | 10 "errors" |
11 "fmt" | 11 "fmt" |
12 "io" | 12 "io" |
13 "net" | 13 "net" |
14 "sync" | 14 "sync" |
15 ) | 15 ) |
16 | 16 |
17 // ClientConn represents the client side of an SSH connection. | 17 // ClientConn represents the client side of an SSH connection. |
18 type ClientConn struct { | 18 type ClientConn struct { |
19 » *handshakeTransport | 19 » transport rekeyingTransport |
20 | 20 » config *ClientConfig |
21 sshConn | 21 sshConn |
22 config *ClientConfig | |
23 chanList // channels associated with this connection | 22 chanList // channels associated with this connection |
24 forwardList // forwarded tcpip connections from the remote side | 23 forwardList // forwarded tcpip connections from the remote side |
25 globalRequest | 24 globalRequest |
26 | 25 |
27 // Address as passed to the Dial function. | 26 // Address as passed to the Dial function. |
28 dialAddress string | 27 dialAddress string |
29 | 28 |
30 serverVersion string | 29 serverVersion string |
31 } | 30 } |
32 | 31 |
33 type globalRequest struct { | 32 type globalRequest struct { |
34 sync.Mutex | 33 sync.Mutex |
35 response chan interface{} | 34 response chan interface{} |
36 } | 35 } |
37 | 36 |
38 // Client returns a new SSH client connection using c as the underlying transpor
t. | 37 // Client returns a new SSH client connection using c as the underlying transpor
t. |
39 func Client(c net.Conn, config *ClientConfig) (*ClientConn, error) { | 38 func Client(c net.Conn, config *ClientConfig) (*ClientConn, error) { |
40 return clientWithAddress(c, "", config) | 39 return clientWithAddress(c, "", config) |
41 } | 40 } |
42 | 41 |
43 func clientWithAddress(c net.Conn, addr string, config *ClientConfig) (*ClientCo
nn, error) { | 42 func clientWithAddress(c net.Conn, addr string, config *ClientConfig) (*ClientCo
nn, error) { |
44 conn := &ClientConn{ | 43 conn := &ClientConn{ |
45 sshConn: sshConn{c}, | |
46 config: config, | 44 config: config, |
| 45 sshConn: sshConn{c, c}, |
47 globalRequest: globalRequest{response: make(chan interface{}, 1)
}, | 46 globalRequest: globalRequest{response: make(chan interface{}, 1)
}, |
48 dialAddress: addr, | 47 dialAddress: addr, |
49 } | 48 } |
50 | 49 |
51 if err := conn.handshake(); err != nil { | 50 if err := conn.handshake(); err != nil { |
52 return nil, fmt.Errorf("ssh: handshake failed: %v", err) | 51 return nil, fmt.Errorf("ssh: handshake failed: %v", err) |
53 } | 52 } |
54 go conn.mainLoop() | 53 go conn.mainLoop() |
55 return conn, nil | 54 return conn, nil |
56 } | |
57 | |
58 // Close closes the underlying network connection. | |
59 func (c *ClientConn) Close() error { | |
60 return c.sshConn.Conn.Close() | |
61 } | 55 } |
62 | 56 |
63 // handshake performs the client side key exchange. See RFC 4253 Section 7. | 57 // handshake performs the client side key exchange. See RFC 4253 Section 7. |
64 func (c *ClientConn) handshake() error { | 58 func (c *ClientConn) handshake() error { |
65 clientVersion := []byte(packageVersion) | 59 clientVersion := []byte(packageVersion) |
66 if c.config.ClientVersion != "" { | 60 if c.config.ClientVersion != "" { |
67 clientVersion = []byte(c.config.ClientVersion) | 61 clientVersion = []byte(c.config.ClientVersion) |
68 } | 62 } |
69 | 63 |
70 » serverVersion, err := exchangeVersions(c.sshConn.Conn, clientVersion) | 64 » serverVersion, err := exchangeVersions(c.sshConn.conn, clientVersion) |
71 if err != nil { | 65 if err != nil { |
72 return err | 66 return err |
73 } | 67 } |
74 c.serverVersion = string(serverVersion) | 68 c.serverVersion = string(serverVersion) |
75 | 69 |
76 » c.handshakeTransport = newHandshakeTransport( | 70 » c.transport = newClientTransport( |
77 » » newTransport(c.sshConn.Conn, c.config.rand(), true /* is client
*/), | 71 » » newTransport(c.sshConn.conn, c.config.rand(), true /* is client
*/), |
78 » » clientVersion, serverVersion) | 72 » » clientVersion, serverVersion, c.config, c.dialAddress, c.sshConn
.RemoteAddr()) |
79 | 73 » if err := c.transport.requestKeyChange(); err != nil { |
80 » c.handshakeTransport.setClient(c.config, c.dialAddress, c.sshConn.Remote
Addr()) | |
81 » _, _, err = c.sendKexInit() | |
82 » if err != nil { | |
83 return err | 74 return err |
84 } | 75 } |
85 | 76 |
86 » // discard newkeys packet. | 77 » if packet, err := c.transport.readPacket(); err != nil { |
87 » if _, err = c.readPacket(); err != nil { | |
88 return err | 78 return err |
89 » } | 79 » } else if packet[0] != msgNewKeys { |
90 » return c.authenticate(c.handshakeTransport.conn.SessionID()) | 80 » » return UnexpectedMessageError{msgNewKeys, packet[0]} |
| 81 » } |
| 82 » return c.authenticate() |
| 83 } |
| 84 |
| 85 // verifyHostKeySignature verifies the host key obtained in the key |
| 86 // exchange. |
| 87 func verifyHostKeySignature(hostKeyAlgo string, result *kexResult) error { |
| 88 » hostKey, rest, ok := ParsePublicKey(result.HostKey) |
| 89 » if len(rest) > 0 || !ok { |
| 90 » » return errors.New("ssh: could not parse hostkey") |
| 91 » } |
| 92 |
| 93 » sig, rest, ok := parseSignatureBody(result.Signature) |
| 94 » if len(rest) > 0 || !ok { |
| 95 » » return errors.New("ssh: signature parse error") |
| 96 » } |
| 97 » if sig.Format != hostKeyAlgo { |
| 98 » » return fmt.Errorf("ssh: got signature type %q, want %q", sig.For
mat, hostKeyAlgo) |
| 99 » } |
| 100 |
| 101 » if !hostKey.Verify(result.H, sig.Blob) { |
| 102 » » return errors.New("ssh: host key signature error") |
| 103 » } |
| 104 » return nil |
91 } | 105 } |
92 | 106 |
93 // mainLoop reads incoming messages and routes channel messages | 107 // mainLoop reads incoming messages and routes channel messages |
94 // to their respective ClientChans. | 108 // to their respective ClientChans. |
95 func (c *ClientConn) mainLoop() { | 109 func (c *ClientConn) mainLoop() { |
96 defer func() { | 110 defer func() { |
97 » » c.Close() | 111 » » c.transport.Close() |
98 c.chanList.closeAll() | 112 c.chanList.closeAll() |
99 c.forwardList.closeAll() | 113 c.forwardList.closeAll() |
100 }() | 114 }() |
101 | 115 |
102 for { | 116 for { |
103 » » packet, err := c.readPacket() | 117 » » packet, err := c.transport.readPacket() |
104 if err != nil { | 118 if err != nil { |
105 break | 119 break |
106 } | 120 } |
107 // TODO(dfc) A note on blocking channel use. | 121 // TODO(dfc) A note on blocking channel use. |
108 // The msg, data and dataExt channels of a clientChan can | 122 // The msg, data and dataExt channels of a clientChan can |
109 // cause this loop to block indefinitely if the consumer does | 123 // cause this loop to block indefinitely if the consumer does |
110 // not service them. | 124 // not service them. |
111 switch packet[0] { | 125 switch packet[0] { |
112 case msgChannelData: | 126 case msgChannelData: |
113 if len(packet) < 9 { | 127 if len(packet) < 9 { |
(...skipping 28 matching lines...) Expand all Loading... |
142 // RFC 4254 5.2 defines data_type_code 1 to be data dest
ined | 156 // RFC 4254 5.2 defines data_type_code 1 to be data dest
ined |
143 // for stderr on interactive sessions. Other data types
are | 157 // for stderr on interactive sessions. Other data types
are |
144 // silently discarded. | 158 // silently discarded. |
145 if datatype == 1 { | 159 if datatype == 1 { |
146 ch, ok := c.getChan(remoteId) | 160 ch, ok := c.getChan(remoteId) |
147 if !ok { | 161 if !ok { |
148 return | 162 return |
149 } | 163 } |
150 ch.stderr.write(packet) | 164 ch.stderr.write(packet) |
151 } | 165 } |
| 166 |
152 case msgNewKeys: | 167 case msgNewKeys: |
153 // A rekeying happened. | 168 // A rekeying happened. |
154 default: | 169 default: |
155 decoded, err := decode(packet) | 170 decoded, err := decode(packet) |
156 if err != nil { | 171 if err != nil { |
157 if _, ok := err.(UnexpectedMessageError); ok { | 172 if _, ok := err.(UnexpectedMessageError); ok { |
158 fmt.Printf("mainLoop: unexpected message
: %v\n", err) | 173 fmt.Printf("mainLoop: unexpected message
: %v\n", err) |
159 continue | 174 continue |
160 } | 175 } |
161 return | 176 return |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 return | 231 return |
217 } | 232 } |
218 if !ch.remoteWin.add(msg.AdditionalBytes) { | 233 if !ch.remoteWin.add(msg.AdditionalBytes) { |
219 // invalid window update | 234 // invalid window update |
220 return | 235 return |
221 } | 236 } |
222 case *globalRequestMsg: | 237 case *globalRequestMsg: |
223 // This handles keepalive messages and matches | 238 // This handles keepalive messages and matches |
224 // the behaviour of OpenSSH. | 239 // the behaviour of OpenSSH. |
225 if msg.WantReply { | 240 if msg.WantReply { |
226 » » » » » c.writePacket(marshal(msgRequestFailure,
globalRequestFailureMsg{})) | 241 » » » » » c.transport.writePacket(marshal(msgReque
stFailure, globalRequestFailureMsg{})) |
227 } | 242 } |
228 case *globalRequestSuccessMsg, *globalRequestFailureMsg: | 243 case *globalRequestSuccessMsg, *globalRequestFailureMsg: |
229 c.globalRequest.response <- msg | 244 c.globalRequest.response <- msg |
230 case *disconnectMsg: | 245 case *disconnectMsg: |
231 return | 246 return |
232 default: | 247 default: |
233 fmt.Printf("mainLoop: unhandled message %T: %v\n
", msg, msg) | 248 fmt.Printf("mainLoop: unhandled message %T: %v\n
", msg, msg) |
234 } | 249 } |
235 } | 250 } |
236 } | 251 } |
(...skipping 22 matching lines...) Expand all Loading... |
259 // connections. | 274 // connections. |
260 c.sendConnectionFailed(msg.PeersId) | 275 c.sendConnectionFailed(msg.PeersId) |
261 return | 276 return |
262 } | 277 } |
263 raddr, rest, ok := parseTCPAddr(rest) | 278 raddr, rest, ok := parseTCPAddr(rest) |
264 if !ok { | 279 if !ok { |
265 // invalid request | 280 // invalid request |
266 c.sendConnectionFailed(msg.PeersId) | 281 c.sendConnectionFailed(msg.PeersId) |
267 return | 282 return |
268 } | 283 } |
269 » » ch := c.newChan(c.handshakeTransport) | 284 » » ch := c.newChan(c.transport) |
270 ch.remoteId = msg.PeersId | 285 ch.remoteId = msg.PeersId |
271 ch.remoteWin.add(msg.PeersWindow) | 286 ch.remoteWin.add(msg.PeersWindow) |
272 ch.maxPacket = msg.MaxPacketSize | 287 ch.maxPacket = msg.MaxPacketSize |
273 | 288 |
274 m := channelOpenConfirmMsg{ | 289 m := channelOpenConfirmMsg{ |
275 PeersId: ch.remoteId, | 290 PeersId: ch.remoteId, |
276 MyId: ch.localId, | 291 MyId: ch.localId, |
277 MyWindow: 1 << 14, | 292 MyWindow: 1 << 14, |
278 | 293 |
279 // As per RFC 4253 6.1, 32k is also the minimum. | 294 // As per RFC 4253 6.1, 32k is also the minimum. |
280 MaxPacketSize: 1 << 15, | 295 MaxPacketSize: 1 << 15, |
281 } | 296 } |
282 | 297 |
283 » » c.writePacket(marshal(msgChannelOpenConfirm, m)) | 298 » » c.transport.writePacket(marshal(msgChannelOpenConfirm, m)) |
284 l <- forward{ch, raddr} | 299 l <- forward{ch, raddr} |
285 default: | 300 default: |
286 // unknown channel type | 301 // unknown channel type |
287 m := channelOpenFailureMsg{ | 302 m := channelOpenFailureMsg{ |
288 PeersId: msg.PeersId, | 303 PeersId: msg.PeersId, |
289 Reason: UnknownChannelType, | 304 Reason: UnknownChannelType, |
290 Message: fmt.Sprintf("unknown channel type: %v", msg.Ch
anType), | 305 Message: fmt.Sprintf("unknown channel type: %v", msg.Ch
anType), |
291 Language: "en_US.UTF-8", | 306 Language: "en_US.UTF-8", |
292 } | 307 } |
293 » » c.writePacket(marshal(msgChannelOpenFailure, m)) | 308 » » c.transport.writePacket(marshal(msgChannelOpenFailure, m)) |
294 } | 309 } |
295 } | 310 } |
296 | 311 |
297 // sendGlobalRequest sends a global request message as specified | 312 // sendGlobalRequest sends a global request message as specified |
298 // in RFC4254 section 4. To correctly synchronise messages, a lock | 313 // in RFC4254 section 4. To correctly synchronise messages, a lock |
299 // is held internally until a response is returned. | 314 // is held internally until a response is returned. |
300 func (c *ClientConn) sendGlobalRequest(m interface{}) (*globalRequestSuccessMsg,
error) { | 315 func (c *ClientConn) sendGlobalRequest(m interface{}) (*globalRequestSuccessMsg,
error) { |
301 c.globalRequest.Lock() | 316 c.globalRequest.Lock() |
302 defer c.globalRequest.Unlock() | 317 defer c.globalRequest.Unlock() |
303 » if err := c.writePacket(marshal(msgGlobalRequest, m)); err != nil { | 318 » if err := c.transport.writePacket(marshal(msgGlobalRequest, m)); err !=
nil { |
304 return nil, err | 319 return nil, err |
305 } | 320 } |
306 r := <-c.globalRequest.response | 321 r := <-c.globalRequest.response |
307 if r, ok := r.(*globalRequestSuccessMsg); ok { | 322 if r, ok := r.(*globalRequestSuccessMsg); ok { |
308 return r, nil | 323 return r, nil |
309 } | 324 } |
310 return nil, errors.New("request failed") | 325 return nil, errors.New("request failed") |
311 } | 326 } |
312 | 327 |
313 // sendConnectionFailed rejects an incoming channel identified | 328 // sendConnectionFailed rejects an incoming channel identified |
314 // by remoteId. | 329 // by remoteId. |
315 func (c *ClientConn) sendConnectionFailed(remoteId uint32) error { | 330 func (c *ClientConn) sendConnectionFailed(remoteId uint32) error { |
316 m := channelOpenFailureMsg{ | 331 m := channelOpenFailureMsg{ |
317 PeersId: remoteId, | 332 PeersId: remoteId, |
318 Reason: ConnectionFailed, | 333 Reason: ConnectionFailed, |
319 Message: "invalid request", | 334 Message: "invalid request", |
320 Language: "en_US.UTF-8", | 335 Language: "en_US.UTF-8", |
321 } | 336 } |
322 » return c.writePacket(marshal(msgChannelOpenFailure, m)) | 337 » return c.transport.writePacket(marshal(msgChannelOpenFailure, m)) |
323 } | 338 } |
324 | 339 |
325 // parseTCPAddr parses the originating address from the remote into a *net.TCPAd
dr. | 340 // parseTCPAddr parses the originating address from the remote into a *net.TCPAd
dr. |
326 // RFC 4254 section 7.2 is mute on what to do if parsing fails but the forwardli
st | 341 // RFC 4254 section 7.2 is mute on what to do if parsing fails but the forwardli
st |
327 // requires a valid *net.TCPAddr to operate, so we enforce that restriction here
. | 342 // requires a valid *net.TCPAddr to operate, so we enforce that restriction here
. |
328 func parseTCPAddr(b []byte) (*net.TCPAddr, []byte, bool) { | 343 func parseTCPAddr(b []byte) (*net.TCPAddr, []byte, bool) { |
329 addr, b, ok := parseString(b) | 344 addr, b, ok := parseString(b) |
330 if !ok { | 345 if !ok { |
331 return nil, b, false | 346 return nil, b, false |
332 } | 347 } |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 defer c.Unlock() | 448 defer c.Unlock() |
434 | 449 |
435 for _, ch := range c.chans { | 450 for _, ch := range c.chans { |
436 if ch == nil { | 451 if ch == nil { |
437 continue | 452 continue |
438 } | 453 } |
439 ch.Close() | 454 ch.Close() |
440 close(ch.msg) | 455 close(ch.msg) |
441 } | 456 } |
442 } | 457 } |
LEFT | RIGHT |