You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.8 KiB
115 lines
2.8 KiB
package ssh |
|
|
|
import ( |
|
"errors" |
|
"io" |
|
"net" |
|
) |
|
|
|
// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message |
|
// with "[email protected]" 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 "[email protected]" string. |
|
type forwardedStreamLocalPayload struct { |
|
SocketPath string |
|
Reserved0 string |
|
} |
|
|
|
// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message |
|
// with "[email protected]"/"[email protected]" 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("[email protected]", true, Marshal(&m)) |
|
if err != nil { |
|
return nil, err |
|
} |
|
if !ok { |
|
return nil, errors.New("ssh: [email protected] 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("[email protected]", 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("[email protected]", true, Marshal(&m)) |
|
if err == nil && !ok { |
|
err = errors.New("ssh: [email protected] failed") |
|
} |
|
return err |
|
} |
|
|
|
// Addr returns the listener's network address. |
|
func (l *unixListener) Addr() net.Addr { |
|
return &net.UnixAddr{ |
|
Name: l.socketPath, |
|
Net: "unix", |
|
} |
|
}
|
|
|