github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/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  	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  }