github.com/inflatablewoman/deis@v1.0.1-0.20141111034523-a4511c46a6ce/deisctl/Godeps/_workspace/src/code.google.com/p/go.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 func (l *forwardList) handleChannels(in <-chan NewChannel) { 158 for ch := range in { 159 laddr, rest, ok := parseTCPAddr(ch.ExtraData()) 160 if !ok { 161 // invalid request 162 ch.Reject(ConnectionFailed, "could not parse TCP address") 163 continue 164 } 165 166 raddr, rest, ok := parseTCPAddr(rest) 167 if !ok { 168 // invalid request 169 ch.Reject(ConnectionFailed, "could not parse TCP address") 170 continue 171 } 172 173 if ok := l.forward(*laddr, *raddr, ch); !ok { 174 // Section 7.2, implementations MUST reject spurious incoming 175 // connections. 176 ch.Reject(Prohibited, "no forward for address") 177 continue 178 } 179 } 180 } 181 182 // remove removes the forward entry, and the channel feeding its 183 // listener. 184 func (l *forwardList) remove(addr net.TCPAddr) { 185 l.Lock() 186 defer l.Unlock() 187 for i, f := range l.entries { 188 if addr.IP.Equal(f.laddr.IP) && addr.Port == f.laddr.Port { 189 l.entries = append(l.entries[:i], l.entries[i+1:]...) 190 close(f.c) 191 return 192 } 193 } 194 } 195 196 // closeAll closes and clears all forwards. 197 func (l *forwardList) closeAll() { 198 l.Lock() 199 defer l.Unlock() 200 for _, f := range l.entries { 201 close(f.c) 202 } 203 l.entries = nil 204 } 205 206 func (l *forwardList) forward(laddr, raddr net.TCPAddr, ch NewChannel) bool { 207 l.Lock() 208 defer l.Unlock() 209 for _, f := range l.entries { 210 if laddr.IP.Equal(f.laddr.IP) && laddr.Port == f.laddr.Port { 211 f.c <- forward{ch, &raddr} 212 return true 213 } 214 } 215 return false 216 } 217 218 type tcpListener struct { 219 laddr *net.TCPAddr 220 221 conn *Client 222 in <-chan forward 223 } 224 225 // Accept waits for and returns the next connection to the listener. 226 func (l *tcpListener) Accept() (net.Conn, error) { 227 s, ok := <-l.in 228 if !ok { 229 return nil, io.EOF 230 } 231 ch, incoming, err := s.newCh.Accept() 232 if err != nil { 233 return nil, err 234 } 235 go DiscardRequests(incoming) 236 237 return &tcpChanConn{ 238 Channel: ch, 239 laddr: l.laddr, 240 raddr: s.raddr, 241 }, nil 242 } 243 244 // Close closes the listener. 245 func (l *tcpListener) Close() error { 246 m := channelForwardMsg{ 247 l.laddr.IP.String(), 248 uint32(l.laddr.Port), 249 } 250 251 // this also closes the listener. 252 l.conn.forwards.remove(*l.laddr) 253 ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) 254 if err == nil && !ok { 255 err = errors.New("ssh: cancel-tcpip-forward failed") 256 } 257 return err 258 } 259 260 // Addr returns the listener's network address. 261 func (l *tcpListener) Addr() net.Addr { 262 return l.laddr 263 } 264 265 // Dial initiates a connection to the addr from the remote host. 266 // The resulting connection has a zero LocalAddr() and RemoteAddr(). 267 func (c *Client) Dial(n, addr string) (net.Conn, error) { 268 // Parse the address into host and numeric port. 269 host, portString, err := net.SplitHostPort(addr) 270 if err != nil { 271 return nil, err 272 } 273 port, err := strconv.ParseUint(portString, 10, 16) 274 if err != nil { 275 return nil, err 276 } 277 // Use a zero address for local and remote address. 278 zeroAddr := &net.TCPAddr{ 279 IP: net.IPv4zero, 280 Port: 0, 281 } 282 ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port)) 283 if err != nil { 284 return nil, err 285 } 286 return &tcpChanConn{ 287 Channel: ch, 288 laddr: zeroAddr, 289 raddr: zeroAddr, 290 }, nil 291 } 292 293 // DialTCP connects to the remote address raddr on the network net, 294 // which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used 295 // as the local address for the connection. 296 func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { 297 if laddr == nil { 298 laddr = &net.TCPAddr{ 299 IP: net.IPv4zero, 300 Port: 0, 301 } 302 } 303 ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) 304 if err != nil { 305 return nil, err 306 } 307 return &tcpChanConn{ 308 Channel: ch, 309 laddr: laddr, 310 raddr: raddr, 311 }, nil 312 } 313 314 // RFC 4254 7.2 315 type channelOpenDirectMsg struct { 316 raddr string 317 rport uint32 318 laddr string 319 lport uint32 320 } 321 322 func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { 323 msg := channelOpenDirectMsg{ 324 raddr: raddr, 325 rport: uint32(rport), 326 laddr: laddr, 327 lport: uint32(lport), 328 } 329 ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) 330 go DiscardRequests(in) 331 return ch, err 332 } 333 334 type tcpChan struct { 335 Channel // the backing channel 336 } 337 338 // tcpChanConn fulfills the net.Conn interface without 339 // the tcpChan having to hold laddr or raddr directly. 340 type tcpChanConn struct { 341 Channel 342 laddr, raddr net.Addr 343 } 344 345 // LocalAddr returns the local network address. 346 func (t *tcpChanConn) LocalAddr() net.Addr { 347 return t.laddr 348 } 349 350 // RemoteAddr returns the remote network address. 351 func (t *tcpChanConn) RemoteAddr() net.Addr { 352 return t.raddr 353 } 354 355 // SetDeadline sets the read and write deadlines associated 356 // with the connection. 357 func (t *tcpChanConn) SetDeadline(deadline time.Time) error { 358 if err := t.SetReadDeadline(deadline); err != nil { 359 return err 360 } 361 return t.SetWriteDeadline(deadline) 362 } 363 364 // SetReadDeadline sets the read deadline. 365 // A zero value for t means Read will not time out. 366 // After the deadline, the error from Read will implement net.Error 367 // with Timeout() == true. 368 func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error { 369 return errors.New("ssh: tcpChan: deadline not supported") 370 } 371 372 // SetWriteDeadline exists to satisfy the net.Conn interface 373 // but is not implemented by this type. It always returns an error. 374 func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error { 375 return errors.New("ssh: tcpChan: deadline not supported") 376 }