github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/Godeps/_workspace/src/golang.org/x/crypto/ssh/tcpip.go (about) 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 go DiscardRequests(in) 359 return ch, err 360 } 361 362 type tcpChan struct { 363 Channel // the backing channel 364 } 365 366 // tcpChanConn fulfills the net.Conn interface without 367 // the tcpChan having to hold laddr or raddr directly. 368 type tcpChanConn struct { 369 Channel 370 laddr, raddr net.Addr 371 } 372 373 // LocalAddr returns the local network address. 374 func (t *tcpChanConn) LocalAddr() net.Addr { 375 return t.laddr 376 } 377 378 // RemoteAddr returns the remote network address. 379 func (t *tcpChanConn) RemoteAddr() net.Addr { 380 return t.raddr 381 } 382 383 // SetDeadline sets the read and write deadlines associated 384 // with the connection. 385 func (t *tcpChanConn) SetDeadline(deadline time.Time) error { 386 if err := t.SetReadDeadline(deadline); err != nil { 387 return err 388 } 389 return t.SetWriteDeadline(deadline) 390 } 391 392 // SetReadDeadline sets the read deadline. 393 // A zero value for t means Read will not time out. 394 // After the deadline, the error from Read will implement net.Error 395 // with Timeout() == true. 396 func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error { 397 return errors.New("ssh: tcpChan: deadline not supported") 398 } 399 400 // SetWriteDeadline exists to satisfy the net.Conn interface 401 // but is not implemented by this type. It always returns an error. 402 func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error { 403 return errors.New("ssh: tcpChan: deadline not supported") 404 }