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