diff options
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/tcpip.go')
-rw-r--r-- | vendor/golang.org/x/crypto/ssh/tcpip.go | 407 |
1 files changed, 0 insertions, 407 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go deleted file mode 100644 index 6151241..0000000 --- a/vendor/golang.org/x/crypto/ssh/tcpip.go +++ /dev/null | |||
@@ -1,407 +0,0 @@ | |||
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 | } | ||