aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/golang.org/x/crypto/ssh/streamlocal.go
blob: a2dccc64c7efd70c57fff8003fd938169e522bae (plain) (tree)


















































































































                                                                                                     
package ssh

import (
    "errors"
    "io"
    "net"
)

// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
// with "direct-streamlocal@openssh.com" string.
//
// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
type streamLocalChannelOpenDirectMsg struct {
    socketPath string
    reserved0  string
    reserved1  uint32
}

// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
// with "forwarded-streamlocal@openssh.com" string.
type forwardedStreamLocalPayload struct {
    SocketPath string
    Reserved0  string
}

// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
type streamLocalChannelForwardMsg struct {
    socketPath string
}

// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
    m := streamLocalChannelForwardMsg{
        socketPath,
    }
    // send message
    ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
    if err != nil {
        return nil, err
    }
    if !ok {
        return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
    }
    ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"})

    return &unixListener{socketPath, c, ch}, nil
}

func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
    msg := streamLocalChannelOpenDirectMsg{
        socketPath: socketPath,
    }
    ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
    if err != nil {
        return nil, err
    }
    go DiscardRequests(in)
    return ch, err
}

type unixListener struct {
    socketPath string

    conn *Client
    in   <-chan forward
}

// Accept waits for and returns the next connection to the listener.
func (l *unixListener) Accept() (net.Conn, error) {
    s, ok := <-l.in
    if !ok {
        return nil, io.EOF
    }
    ch, incoming, err := s.newCh.Accept()
    if err != nil {
        return nil, err
    }
    go DiscardRequests(incoming)

    return &chanConn{
        Channel: ch,
        laddr: &net.UnixAddr{
            Name: l.socketPath,
            Net:  "unix",
        },
        raddr: &net.UnixAddr{
            Name: "@",
            Net:  "unix",
        },
    }, nil
}

// Close closes the listener.
func (l *unixListener) Close() error {
    // this also closes the listener.
    l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"})
    m := streamLocalChannelForwardMsg{
        l.socketPath,
    }
    ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
    if err == nil && !ok {
        err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
    }
    return err
}

// Addr returns the listener's network address.
func (l *unixListener) Addr() net.Addr {
    return &net.UnixAddr{
        Name: l.socketPath,
        Net:  "unix",
    }
}