~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/golang.org/x/crypto/ssh/tcpip.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2011 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
        "errors"
 
9
        "fmt"
 
10
        "io"
 
11
        "math/rand"
 
12
        "net"
 
13
        "strconv"
 
14
        "strings"
 
15
        "sync"
 
16
        "time"
 
17
)
 
18
 
 
19
// Listen requests the remote peer open a listening socket on
 
20
// addr. Incoming connections will be available by calling Accept on
 
21
// the returned net.Listener. The listener must be serviced, or the
 
22
// SSH connection may hang.
 
23
func (c *Client) Listen(n, addr string) (net.Listener, error) {
 
24
        laddr, err := net.ResolveTCPAddr(n, addr)
 
25
        if err != nil {
 
26
                return nil, err
 
27
        }
 
28
        return c.ListenTCP(laddr)
 
29
}
 
30
 
 
31
// Automatic port allocation is broken with OpenSSH before 6.0. See
 
32
// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017.  In
 
33
// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0,
 
34
// rather than the actual port number. This means you can never open
 
35
// two different listeners with auto allocated ports. We work around
 
36
// this by trying explicit ports until we succeed.
 
37
 
 
38
const openSSHPrefix = "OpenSSH_"
 
39
 
 
40
var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano()))
 
41
 
 
42
// isBrokenOpenSSHVersion returns true if the given version string
 
43
// specifies a version of OpenSSH that is known to have a bug in port
 
44
// forwarding.
 
45
func isBrokenOpenSSHVersion(versionStr string) bool {
 
46
        i := strings.Index(versionStr, openSSHPrefix)
 
47
        if i < 0 {
 
48
                return false
 
49
        }
 
50
        i += len(openSSHPrefix)
 
51
        j := i
 
52
        for ; j < len(versionStr); j++ {
 
53
                if versionStr[j] < '0' || versionStr[j] > '9' {
 
54
                        break
 
55
                }
 
56
        }
 
57
        version, _ := strconv.Atoi(versionStr[i:j])
 
58
        return version < 6
 
59
}
 
60
 
 
61
// autoPortListenWorkaround simulates automatic port allocation by
 
62
// trying random ports repeatedly.
 
63
func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) {
 
64
        var sshListener net.Listener
 
65
        var err error
 
66
        const tries = 10
 
67
        for i := 0; i < tries; i++ {
 
68
                addr := *laddr
 
69
                addr.Port = 1024 + portRandomizer.Intn(60000)
 
70
                sshListener, err = c.ListenTCP(&addr)
 
71
                if err == nil {
 
72
                        laddr.Port = addr.Port
 
73
                        return sshListener, err
 
74
                }
 
75
        }
 
76
        return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err)
 
77
}
 
78
 
 
79
// RFC 4254 7.1
 
80
type channelForwardMsg struct {
 
81
        addr  string
 
82
        rport uint32
 
83
}
 
84
 
 
85
// ListenTCP requests the remote peer open a listening socket
 
86
// on laddr. Incoming connections will be available by calling
 
87
// Accept on the returned net.Listener.
 
88
func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
 
89
        if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
 
90
                return c.autoPortListenWorkaround(laddr)
 
91
        }
 
92
 
 
93
        m := channelForwardMsg{
 
94
                laddr.IP.String(),
 
95
                uint32(laddr.Port),
 
96
        }
 
97
        // send message
 
98
        ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m))
 
99
        if err != nil {
 
100
                return nil, err
 
101
        }
 
102
        if !ok {
 
103
                return nil, errors.New("ssh: tcpip-forward request denied by peer")
 
104
        }
 
105
 
 
106
        // If the original port was 0, then the remote side will
 
107
        // supply a real port number in the response.
 
108
        if laddr.Port == 0 {
 
109
                var p struct {
 
110
                        Port uint32
 
111
                }
 
112
                if err := Unmarshal(resp, &p); err != nil {
 
113
                        return nil, err
 
114
                }
 
115
                laddr.Port = int(p.Port)
 
116
        }
 
117
 
 
118
        // Register this forward, using the port number we obtained.
 
119
        ch := c.forwards.add(*laddr)
 
120
 
 
121
        return &tcpListener{laddr, c, ch}, nil
 
122
}
 
123
 
 
124
// forwardList stores a mapping between remote
 
125
// forward requests and the tcpListeners.
 
126
type forwardList struct {
 
127
        sync.Mutex
 
128
        entries []forwardEntry
 
129
}
 
130
 
 
131
// forwardEntry represents an established mapping of a laddr on a
 
132
// remote ssh server to a channel connected to a tcpListener.
 
133
type forwardEntry struct {
 
134
        laddr net.TCPAddr
 
135
        c     chan forward
 
136
}
 
137
 
 
138
// forward represents an incoming forwarded tcpip connection. The
 
139
// arguments to add/remove/lookup should be address as specified in
 
140
// the original forward-request.
 
141
type forward struct {
 
142
        newCh NewChannel   // the ssh client channel underlying this forward
 
143
        raddr *net.TCPAddr // the raddr of the incoming connection
 
144
}
 
145
 
 
146
func (l *forwardList) add(addr net.TCPAddr) chan forward {
 
147
        l.Lock()
 
148
        defer l.Unlock()
 
149
        f := forwardEntry{
 
150
                addr,
 
151
                make(chan forward, 1),
 
152
        }
 
153
        l.entries = append(l.entries, f)
 
154
        return f.c
 
155
}
 
156
 
 
157
// See RFC 4254, section 7.2
 
158
type forwardedTCPPayload struct {
 
159
        Addr       string
 
160
        Port       uint32
 
161
        OriginAddr string
 
162
        OriginPort uint32
 
163
}
 
164
 
 
165
// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr.
 
166
func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
 
167
        if port == 0 || port > 65535 {
 
168
                return nil, fmt.Errorf("ssh: port number out of range: %d", port)
 
169
        }
 
170
        ip := net.ParseIP(string(addr))
 
171
        if ip == nil {
 
172
                return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr)
 
173
        }
 
174
        return &net.TCPAddr{IP: ip, Port: int(port)}, nil
 
175
}
 
176
 
 
177
func (l *forwardList) handleChannels(in <-chan NewChannel) {
 
178
        for ch := range in {
 
179
                var payload forwardedTCPPayload
 
180
                if err := Unmarshal(ch.ExtraData(), &payload); err != nil {
 
181
                        ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
 
182
                        continue
 
183
                }
 
184
 
 
185
                // RFC 4254 section 7.2 specifies that incoming
 
186
                // addresses should list the address, in string
 
187
                // format. It is implied that this should be an IP
 
188
                // address, as it would be impossible to connect to it
 
189
                // otherwise.
 
190
                laddr, err := parseTCPAddr(payload.Addr, payload.Port)
 
191
                if err != nil {
 
192
                        ch.Reject(ConnectionFailed, err.Error())
 
193
                        continue
 
194
                }
 
195
                raddr, err := parseTCPAddr(payload.OriginAddr, payload.OriginPort)
 
196
                if err != nil {
 
197
                        ch.Reject(ConnectionFailed, err.Error())
 
198
                        continue
 
199
                }
 
200
 
 
201
                if ok := l.forward(*laddr, *raddr, ch); !ok {
 
202
                        // Section 7.2, implementations MUST reject spurious incoming
 
203
                        // connections.
 
204
                        ch.Reject(Prohibited, "no forward for address")
 
205
                        continue
 
206
                }
 
207
        }
 
208
}
 
209
 
 
210
// remove removes the forward entry, and the channel feeding its
 
211
// listener.
 
212
func (l *forwardList) remove(addr net.TCPAddr) {
 
213
        l.Lock()
 
214
        defer l.Unlock()
 
215
        for i, f := range l.entries {
 
216
                if addr.IP.Equal(f.laddr.IP) && addr.Port == f.laddr.Port {
 
217
                        l.entries = append(l.entries[:i], l.entries[i+1:]...)
 
218
                        close(f.c)
 
219
                        return
 
220
                }
 
221
        }
 
222
}
 
223
 
 
224
// closeAll closes and clears all forwards.
 
225
func (l *forwardList) closeAll() {
 
226
        l.Lock()
 
227
        defer l.Unlock()
 
228
        for _, f := range l.entries {
 
229
                close(f.c)
 
230
        }
 
231
        l.entries = nil
 
232
}
 
233
 
 
234
func (l *forwardList) forward(laddr, raddr net.TCPAddr, ch NewChannel) bool {
 
235
        l.Lock()
 
236
        defer l.Unlock()
 
237
        for _, f := range l.entries {
 
238
                if laddr.IP.Equal(f.laddr.IP) && laddr.Port == f.laddr.Port {
 
239
                        f.c <- forward{ch, &raddr}
 
240
                        return true
 
241
                }
 
242
        }
 
243
        return false
 
244
}
 
245
 
 
246
type tcpListener struct {
 
247
        laddr *net.TCPAddr
 
248
 
 
249
        conn *Client
 
250
        in   <-chan forward
 
251
}
 
252
 
 
253
// Accept waits for and returns the next connection to the listener.
 
254
func (l *tcpListener) Accept() (net.Conn, error) {
 
255
        s, ok := <-l.in
 
256
        if !ok {
 
257
                return nil, io.EOF
 
258
        }
 
259
        ch, incoming, err := s.newCh.Accept()
 
260
        if err != nil {
 
261
                return nil, err
 
262
        }
 
263
        go DiscardRequests(incoming)
 
264
 
 
265
        return &tcpChanConn{
 
266
                Channel: ch,
 
267
                laddr:   l.laddr,
 
268
                raddr:   s.raddr,
 
269
        }, nil
 
270
}
 
271
 
 
272
// Close closes the listener.
 
273
func (l *tcpListener) Close() error {
 
274
        m := channelForwardMsg{
 
275
                l.laddr.IP.String(),
 
276
                uint32(l.laddr.Port),
 
277
        }
 
278
 
 
279
        // this also closes the listener.
 
280
        l.conn.forwards.remove(*l.laddr)
 
281
        ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m))
 
282
        if err == nil && !ok {
 
283
                err = errors.New("ssh: cancel-tcpip-forward failed")
 
284
        }
 
285
        return err
 
286
}
 
287
 
 
288
// Addr returns the listener's network address.
 
289
func (l *tcpListener) Addr() net.Addr {
 
290
        return l.laddr
 
291
}
 
292
 
 
293
// Dial initiates a connection to the addr from the remote host.
 
294
// The resulting connection has a zero LocalAddr() and RemoteAddr().
 
295
func (c *Client) Dial(n, addr string) (net.Conn, error) {
 
296
        // Parse the address into host and numeric port.
 
297
        host, portString, err := net.SplitHostPort(addr)
 
298
        if err != nil {
 
299
                return nil, err
 
300
        }
 
301
        port, err := strconv.ParseUint(portString, 10, 16)
 
302
        if err != nil {
 
303
                return nil, err
 
304
        }
 
305
        // Use a zero address for local and remote address.
 
306
        zeroAddr := &net.TCPAddr{
 
307
                IP:   net.IPv4zero,
 
308
                Port: 0,
 
309
        }
 
310
        ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port))
 
311
        if err != nil {
 
312
                return nil, err
 
313
        }
 
314
        return &tcpChanConn{
 
315
                Channel: ch,
 
316
                laddr:   zeroAddr,
 
317
                raddr:   zeroAddr,
 
318
        }, nil
 
319
}
 
320
 
 
321
// DialTCP connects to the remote address raddr on the network net,
 
322
// which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is used
 
323
// as the local address for the connection.
 
324
func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) {
 
325
        if laddr == nil {
 
326
                laddr = &net.TCPAddr{
 
327
                        IP:   net.IPv4zero,
 
328
                        Port: 0,
 
329
                }
 
330
        }
 
331
        ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port)
 
332
        if err != nil {
 
333
                return nil, err
 
334
        }
 
335
        return &tcpChanConn{
 
336
                Channel: ch,
 
337
                laddr:   laddr,
 
338
                raddr:   raddr,
 
339
        }, nil
 
340
}
 
341
 
 
342
// RFC 4254 7.2
 
343
type channelOpenDirectMsg struct {
 
344
        raddr string
 
345
        rport uint32
 
346
        laddr string
 
347
        lport uint32
 
348
}
 
349
 
 
350
func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) {
 
351
        msg := channelOpenDirectMsg{
 
352
                raddr: raddr,
 
353
                rport: uint32(rport),
 
354
                laddr: laddr,
 
355
                lport: uint32(lport),
 
356
        }
 
357
        ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg))
 
358
        if err != nil {
 
359
                return nil, err
 
360
        }
 
361
        go DiscardRequests(in)
 
362
        return ch, err
 
363
}
 
364
 
 
365
type tcpChan struct {
 
366
        Channel // the backing channel
 
367
}
 
368
 
 
369
// tcpChanConn fulfills the net.Conn interface without
 
370
// the tcpChan having to hold laddr or raddr directly.
 
371
type tcpChanConn struct {
 
372
        Channel
 
373
        laddr, raddr net.Addr
 
374
}
 
375
 
 
376
// LocalAddr returns the local network address.
 
377
func (t *tcpChanConn) LocalAddr() net.Addr {
 
378
        return t.laddr
 
379
}
 
380
 
 
381
// RemoteAddr returns the remote network address.
 
382
func (t *tcpChanConn) RemoteAddr() net.Addr {
 
383
        return t.raddr
 
384
}
 
385
 
 
386
// SetDeadline sets the read and write deadlines associated
 
387
// with the connection.
 
388
func (t *tcpChanConn) SetDeadline(deadline time.Time) error {
 
389
        if err := t.SetReadDeadline(deadline); err != nil {
 
390
                return err
 
391
        }
 
392
        return t.SetWriteDeadline(deadline)
 
393
}
 
394
 
 
395
// SetReadDeadline sets the read deadline.
 
396
// A zero value for t means Read will not time out.
 
397
// After the deadline, the error from Read will implement net.Error
 
398
// with Timeout() == true.
 
399
func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error {
 
400
        return errors.New("ssh: tcpChan: deadline not supported")
 
401
}
 
402
 
 
403
// SetWriteDeadline exists to satisfy the net.Conn interface
 
404
// but is not implemented by this type.  It always returns an error.
 
405
func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error {
 
406
        return errors.New("ssh: tcpChan: deadline not supported")
 
407
}