LEFT | RIGHT |
(no file at all) | |
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 "errors" | 8 "errors" |
9 "fmt" | 9 "fmt" |
10 "io" | 10 "io" |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 if err == nil { | 70 if err == nil { |
71 laddr.Port = addr.Port | 71 laddr.Port = addr.Port |
72 return sshListener, err | 72 return sshListener, err |
73 } | 73 } |
74 } | 74 } |
75 return nil, fmt.Errorf("ssh: listen on random port failed after %d tries
: %v", tries, err) | 75 return nil, fmt.Errorf("ssh: listen on random port failed after %d tries
: %v", tries, err) |
76 } | 76 } |
77 | 77 |
78 // RFC 4254 7.1 | 78 // RFC 4254 7.1 |
79 type channelForwardMsg struct { | 79 type channelForwardMsg struct { |
80 » Message string | 80 » addr string |
81 » WantReply bool | 81 » rport uint32 |
82 » raddr string | |
83 » rport uint32 | |
84 } | 82 } |
85 | 83 |
86 // ListenTCP requests the remote peer open a listening socket | 84 // ListenTCP requests the remote peer open a listening socket |
87 // on laddr. Incoming connections will be available by calling | 85 // on laddr. Incoming connections will be available by calling |
88 // Accept on the returned net.Listener. | 86 // Accept on the returned net.Listener. |
89 func (c *ClientConn) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { | 87 func (c *ClientConn) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { |
90 if laddr.Port == 0 && isBrokenOpenSSHVersion(c.serverVersion) { | 88 if laddr.Port == 0 && isBrokenOpenSSHVersion(c.serverVersion) { |
91 return c.autoPortListenWorkaround(laddr) | 89 return c.autoPortListenWorkaround(laddr) |
92 } | 90 } |
93 | 91 |
94 m := channelForwardMsg{ | 92 m := channelForwardMsg{ |
95 "tcpip-forward", | |
96 true, // sendGlobalRequest waits for a reply | |
97 laddr.IP.String(), | 93 laddr.IP.String(), |
98 uint32(laddr.Port), | 94 uint32(laddr.Port), |
99 } | 95 } |
100 // send message | 96 // send message |
101 » resp, err := c.sendGlobalRequest(m) | 97 » ok, resp, err := c.mux.SendRequest("tcpip-forward", true, marshal(0, m)) |
102 » if err != nil { | 98 » if err != nil { |
103 » » return nil, err | 99 » » return nil, err |
| 100 » } |
| 101 » if !ok { |
| 102 » » return nil, errors.New("tcpip-forward denied") |
104 } | 103 } |
105 | 104 |
106 // If the original port was 0, then the remote side will | 105 // If the original port was 0, then the remote side will |
107 // supply a real port number in the response. | 106 // supply a real port number in the response. |
108 if laddr.Port == 0 { | 107 if laddr.Port == 0 { |
109 » » port, _, ok := parseUint32(resp.Data) | 108 » » port, _, ok := parseUint32(resp) |
110 if !ok { | 109 if !ok { |
111 return nil, errors.New("unable to parse response") | 110 return nil, errors.New("unable to parse response") |
112 } | 111 } |
113 laddr.Port = int(port) | 112 laddr.Port = int(port) |
114 } | 113 } |
115 | 114 |
116 // Register this forward, using the port number we obtained. | 115 // Register this forward, using the port number we obtained. |
117 ch := c.forwardList.add(*laddr) | 116 ch := c.forwardList.add(*laddr) |
118 | 117 |
119 return &tcpListener{laddr, c, ch}, nil | 118 return &tcpListener{laddr, c, ch}, nil |
(...skipping 10 matching lines...) Expand all Loading... |
130 // remote ssh server to a channel connected to a tcpListener. | 129 // remote ssh server to a channel connected to a tcpListener. |
131 type forwardEntry struct { | 130 type forwardEntry struct { |
132 laddr net.TCPAddr | 131 laddr net.TCPAddr |
133 c chan forward | 132 c chan forward |
134 } | 133 } |
135 | 134 |
136 // forward represents an incoming forwarded tcpip connection. The | 135 // forward represents an incoming forwarded tcpip connection. The |
137 // arguments to add/remove/lookup should be address as specified in | 136 // arguments to add/remove/lookup should be address as specified in |
138 // the original forward-request. | 137 // the original forward-request. |
139 type forward struct { | 138 type forward struct { |
140 » c *clientChan // the ssh client channel underlying this forward | 139 » c *channel // the ssh client channel underlying this forward |
141 raddr *net.TCPAddr // the raddr of the incoming connection | 140 raddr *net.TCPAddr // the raddr of the incoming connection |
142 } | 141 } |
143 | 142 |
144 func (l *forwardList) add(addr net.TCPAddr) chan forward { | 143 func (l *forwardList) add(addr net.TCPAddr) chan forward { |
145 l.Lock() | 144 l.Lock() |
146 defer l.Unlock() | 145 defer l.Unlock() |
147 f := forwardEntry{ | 146 f := forwardEntry{ |
148 addr, | 147 addr, |
149 make(chan forward, 1), | 148 make(chan forward, 1), |
150 } | 149 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 in <-chan forward | 193 in <-chan forward |
195 } | 194 } |
196 | 195 |
197 // Accept waits for and returns the next connection to the listener. | 196 // Accept waits for and returns the next connection to the listener. |
198 func (l *tcpListener) Accept() (net.Conn, error) { | 197 func (l *tcpListener) Accept() (net.Conn, error) { |
199 s, ok := <-l.in | 198 s, ok := <-l.in |
200 if !ok { | 199 if !ok { |
201 return nil, io.EOF | 200 return nil, io.EOF |
202 } | 201 } |
203 return &tcpChanConn{ | 202 return &tcpChanConn{ |
204 » » tcpChan: &tcpChan{ | 203 » » channel: s.c, |
205 » » » clientChan: s.c, | 204 » » laddr: l.laddr, |
206 » » » Reader: s.c.stdout, | 205 » » raddr: s.raddr, |
207 » » » Writer: s.c.stdin, | |
208 » » }, | |
209 » » laddr: l.laddr, | |
210 » » raddr: s.raddr, | |
211 }, nil | 206 }, nil |
212 } | 207 } |
213 | 208 |
214 // Close closes the listener. | 209 // Close closes the listener. |
215 func (l *tcpListener) Close() error { | 210 func (l *tcpListener) Close() error { |
216 m := channelForwardMsg{ | 211 m := channelForwardMsg{ |
217 "cancel-tcpip-forward", | |
218 true, | |
219 l.laddr.IP.String(), | 212 l.laddr.IP.String(), |
220 uint32(l.laddr.Port), | 213 uint32(l.laddr.Port), |
221 } | 214 } |
| 215 |
| 216 // this also closes the listener. |
222 l.conn.forwardList.remove(*l.laddr) | 217 l.conn.forwardList.remove(*l.laddr) |
223 » if _, err := l.conn.sendGlobalRequest(m); err != nil { | 218 » ok, _, err := l.conn.mux.SendRequest("cancel-tcpip-forward", true, marsh
al(0, m)) |
224 » » return err | 219 » if err == nil && !ok { |
225 » } | 220 » » err = errors.New("ssh: cancel-tcpip-forward failed") |
226 » return nil | 221 » } |
| 222 » return err |
227 } | 223 } |
228 | 224 |
229 // Addr returns the listener's network address. | 225 // Addr returns the listener's network address. |
230 func (l *tcpListener) Addr() net.Addr { | 226 func (l *tcpListener) Addr() net.Addr { |
231 return l.laddr | 227 return l.laddr |
232 } | 228 } |
233 | 229 |
234 // Dial initiates a connection to the addr from the remote host. | 230 // Dial initiates a connection to the addr from the remote host. |
235 // The resulting connection has a zero LocalAddr() and RemoteAddr(). | 231 // The resulting connection has a zero LocalAddr() and RemoteAddr(). |
236 func (c *ClientConn) Dial(n, addr string) (net.Conn, error) { | 232 func (c *ClientConn) Dial(n, addr string) (net.Conn, error) { |
237 // Parse the address into host and numeric port. | 233 // Parse the address into host and numeric port. |
238 host, portString, err := net.SplitHostPort(addr) | 234 host, portString, err := net.SplitHostPort(addr) |
239 if err != nil { | 235 if err != nil { |
240 return nil, err | 236 return nil, err |
241 } | 237 } |
242 port, err := strconv.ParseUint(portString, 10, 16) | 238 port, err := strconv.ParseUint(portString, 10, 16) |
243 if err != nil { | 239 if err != nil { |
244 return nil, err | 240 return nil, err |
245 } | 241 } |
246 // Use a zero address for local and remote address. | 242 // Use a zero address for local and remote address. |
247 zeroAddr := &net.TCPAddr{ | 243 zeroAddr := &net.TCPAddr{ |
248 IP: net.IPv4zero, | 244 IP: net.IPv4zero, |
249 Port: 0, | 245 Port: 0, |
250 } | 246 } |
251 ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port)) | 247 ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port)) |
252 if err != nil { | 248 if err != nil { |
253 return nil, err | 249 return nil, err |
254 } | 250 } |
255 return &tcpChanConn{ | 251 return &tcpChanConn{ |
256 » » tcpChan: ch, | 252 » » channel: ch, |
257 laddr: zeroAddr, | 253 laddr: zeroAddr, |
258 raddr: zeroAddr, | 254 raddr: zeroAddr, |
259 }, nil | 255 }, nil |
260 } | 256 } |
261 | 257 |
262 // DialTCP connects to the remote address raddr on the network net, | 258 // DialTCP connects to the remote address raddr on the network net, |
263 // which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used | 259 // which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used |
264 // as the local address for the connection. | 260 // as the local address for the connection. |
265 func (c *ClientConn) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, err
or) { | 261 func (c *ClientConn) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, err
or) { |
266 if laddr == nil { | 262 if laddr == nil { |
267 laddr = &net.TCPAddr{ | 263 laddr = &net.TCPAddr{ |
268 IP: net.IPv4zero, | 264 IP: net.IPv4zero, |
269 Port: 0, | 265 Port: 0, |
270 } | 266 } |
271 } | 267 } |
272 ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), radd
r.Port) | 268 ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), radd
r.Port) |
273 if err != nil { | 269 if err != nil { |
274 return nil, err | 270 return nil, err |
275 } | 271 } |
276 return &tcpChanConn{ | 272 return &tcpChanConn{ |
277 » » tcpChan: ch, | 273 » » channel: ch, |
278 laddr: laddr, | 274 laddr: laddr, |
279 raddr: raddr, | 275 raddr: raddr, |
280 }, nil | 276 }, nil |
281 } | 277 } |
282 | 278 |
283 // RFC 4254 7.2 | 279 // RFC 4254 7.2 |
284 type channelOpenDirectMsg struct { | 280 type channelOpenDirectMsg struct { |
285 » ChanType string | 281 » raddr string |
286 » PeersId uint32 | 282 » rport uint32 |
287 » PeersWindow uint32 | 283 » laddr string |
288 » MaxPacketSize uint32 | 284 » lport uint32 |
289 » raddr string | |
290 » rport uint32 | |
291 » laddr string | |
292 » lport uint32 | |
293 } | 285 } |
294 | 286 |
295 // dial opens a direct-tcpip connection to the remote server. laddr and raddr ar
e passed as | 287 // dial opens a direct-tcpip connection to the remote server. laddr and raddr ar
e passed as |
296 // strings and are expected to be resolvable at the remote end. | 288 // strings and are expected to be resolvable at the remote end. |
297 func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*tc
pChan, error) { | 289 func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*ch
annel, error) { |
298 » ch := c.newChan(c.transport) | 290 » msg := channelOpenDirectMsg{ |
299 » if err := c.transport.writePacket(marshal(msgChannelOpen, channelOpenDir
ectMsg{ | 291 » » raddr: raddr, |
300 » » ChanType: "direct-tcpip", | 292 » » rport: uint32(rport), |
301 » » PeersId: ch.localId, | 293 » » laddr: laddr, |
302 » » PeersWindow: 1 << 14, | 294 » » lport: uint32(lport), |
303 » » MaxPacketSize: 1 << 15, // RFC 4253 6.1 | 295 » } |
304 » » raddr: raddr, | 296 |
305 » » rport: uint32(rport), | 297 » return c.mux.OpenChannel("direct-tcpip", marshal(0, msg)) |
306 » » laddr: laddr, | |
307 » » lport: uint32(lport), | |
308 » })); err != nil { | |
309 » » c.chanList.remove(ch.localId) | |
310 » » return nil, err | |
311 » } | |
312 » if err := ch.waitForChannelOpenResponse(); err != nil { | |
313 » » c.chanList.remove(ch.localId) | |
314 » » return nil, fmt.Errorf("ssh: unable to open direct tcpip connect
ion: %v", err) | |
315 » } | |
316 » return &tcpChan{ | |
317 » » clientChan: ch, | |
318 » » Reader: ch.stdout, | |
319 » » Writer: ch.stdin, | |
320 » }, nil | |
321 } | |
322 | |
323 type tcpChan struct { | |
324 » *clientChan // the backing channel | |
325 » io.Reader | |
326 » io.Writer | |
327 } | 298 } |
328 | 299 |
329 // tcpChanConn fulfills the net.Conn interface without | 300 // tcpChanConn fulfills the net.Conn interface without |
330 // the tcpChan having to hold laddr or raddr directly. | 301 // the tcpChan having to hold laddr or raddr directly. |
331 type tcpChanConn struct { | 302 type tcpChanConn struct { |
332 » *tcpChan | 303 » *channel |
333 laddr, raddr net.Addr | 304 laddr, raddr net.Addr |
334 } | 305 } |
335 | 306 |
336 // LocalAddr returns the local network address. | 307 // LocalAddr returns the local network address. |
337 func (t *tcpChanConn) LocalAddr() net.Addr { | 308 func (t *tcpChanConn) LocalAddr() net.Addr { |
338 return t.laddr | 309 return t.laddr |
339 } | 310 } |
340 | 311 |
341 // RemoteAddr returns the remote network address. | 312 // RemoteAddr returns the remote network address. |
342 func (t *tcpChanConn) RemoteAddr() net.Addr { | 313 func (t *tcpChanConn) RemoteAddr() net.Addr { |
(...skipping 15 matching lines...) Expand all Loading... |
358 // with Timeout() == true. | 329 // with Timeout() == true. |
359 func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error { | 330 func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error { |
360 return errors.New("ssh: tcpChan: deadline not supported") | 331 return errors.New("ssh: tcpChan: deadline not supported") |
361 } | 332 } |
362 | 333 |
363 // SetWriteDeadline exists to satisfy the net.Conn interface | 334 // SetWriteDeadline exists to satisfy the net.Conn interface |
364 // but is not implemented by this type. It always returns an error. | 335 // but is not implemented by this type. It always returns an error. |
365 func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error { | 336 func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error { |
366 return errors.New("ssh: tcpChan: deadline not supported") | 337 return errors.New("ssh: tcpChan: deadline not supported") |
367 } | 338 } |
LEFT | RIGHT |