gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

streamlocal.go (2939B)


      1 package ssh
      2 
      3 import (
      4 	"errors"
      5 	"io"
      6 	"net"
      7 )
      8 
      9 // streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
     10 // with "direct-streamlocal@openssh.com" string.
     11 //
     12 // See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
     13 // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
     14 type streamLocalChannelOpenDirectMsg struct {
     15 	socketPath string
     16 	reserved0  string
     17 	reserved1  uint32
     18 }
     19 
     20 // forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
     21 // with "forwarded-streamlocal@openssh.com" string.
     22 type forwardedStreamLocalPayload struct {
     23 	SocketPath string
     24 	Reserved0  string
     25 }
     26 
     27 // streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
     28 // with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
     29 type streamLocalChannelForwardMsg struct {
     30 	socketPath string
     31 }
     32 
     33 // ListenUnix is similar to ListenTCP but uses a Unix domain socket.
     34 func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
     35 	c.handleForwardsOnce.Do(c.handleForwards)
     36 	m := streamLocalChannelForwardMsg{
     37 		socketPath,
     38 	}
     39 	// send message
     40 	ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
     41 	if err != nil {
     42 		return nil, err
     43 	}
     44 	if !ok {
     45 		return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
     46 	}
     47 	ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"})
     48 
     49 	return &unixListener{socketPath, c, ch}, nil
     50 }
     51 
     52 func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
     53 	msg := streamLocalChannelOpenDirectMsg{
     54 		socketPath: socketPath,
     55 	}
     56 	ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
     57 	if err != nil {
     58 		return nil, err
     59 	}
     60 	go DiscardRequests(in)
     61 	return ch, err
     62 }
     63 
     64 type unixListener struct {
     65 	socketPath string
     66 
     67 	conn *Client
     68 	in   <-chan forward
     69 }
     70 
     71 // Accept waits for and returns the next connection to the listener.
     72 func (l *unixListener) Accept() (net.Conn, error) {
     73 	s, ok := <-l.in
     74 	if !ok {
     75 		return nil, io.EOF
     76 	}
     77 	ch, incoming, err := s.newCh.Accept()
     78 	if err != nil {
     79 		return nil, err
     80 	}
     81 	go DiscardRequests(incoming)
     82 
     83 	return &chanConn{
     84 		Channel: ch,
     85 		laddr: &net.UnixAddr{
     86 			Name: l.socketPath,
     87 			Net:  "unix",
     88 		},
     89 		raddr: &net.UnixAddr{
     90 			Name: "@",
     91 			Net:  "unix",
     92 		},
     93 	}, nil
     94 }
     95 
     96 // Close closes the listener.
     97 func (l *unixListener) Close() error {
     98 	// this also closes the listener.
     99 	l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"})
    100 	m := streamLocalChannelForwardMsg{
    101 		l.socketPath,
    102 	}
    103 	ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
    104 	if err == nil && !ok {
    105 		err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
    106 	}
    107 	return err
    108 }
    109 
    110 // Addr returns the listener's network address.
    111 func (l *unixListener) Addr() net.Addr {
    112 	return &net.UnixAddr{
    113 		Name: l.socketPath,
    114 		Net:  "unix",
    115 	}
    116 }