|
- 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) {
- c.handleForwardsOnce.Do(c.handleForwards)
- 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",
- }
- }
|