mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-08-04 06:36:24 +00:00
ssh kitten: Easily forward the remote control socket tot he remote host
This commit is contained in:
parent
bde4a41ed4
commit
1f9852d76c
4 changed files with 88 additions and 7 deletions
|
|
@ -40,6 +40,8 @@ Detailed list of changes
|
|||
|
||||
- A new :doc:`transfer kitten </kittens/transfer>` that can be used to transfer files efficiently over the TTY device
|
||||
|
||||
- ssh kitten: A new configuration directive `to automatically forward the kitty remote control socket <kitten-ssh.forward_remote_control>`
|
||||
|
||||
- kitten @ set-user-vars: New remote control command to set user variables on a
|
||||
window (:iss:`6502`)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,14 @@ Truly convenient SSH
|
|||
|
||||
* Easily :opt:`change terminal colors <kitten-ssh.color_scheme>` when connecting to remote hosts
|
||||
|
||||
* Automatically :opt:`forward the kitty remote control socket <kitten-ssh.forward_remote_control>` to configured hosts
|
||||
|
||||
.. versionadded:: 0.25.0
|
||||
Automatic shell integration, file transfer and reuse of connections
|
||||
|
||||
.. versionadded:: 0.30.0
|
||||
Automatic forwarding of remote control sockets
|
||||
|
||||
The ssh kitten allows you to login easily to remote hosts, and automatically
|
||||
setup the environment there to be as comfortable as your local shell. You can
|
||||
specify environment variables to set on the remote host and files to copy there,
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ type connection_data struct {
|
|||
echo_on bool
|
||||
request_data bool
|
||||
literal_env map[string]string
|
||||
listen_on string
|
||||
test_script string
|
||||
dont_create_shm bool
|
||||
|
||||
|
|
@ -246,6 +247,9 @@ func serialize_env(cd *connection_data, get_local_env func(string) (string, bool
|
|||
add_env("KITTY_REMOTE", cd.host_opts.Remote_kitty.String())
|
||||
}
|
||||
add_env("KITTY_PUBLIC_KEY", os.Getenv("KITTY_PUBLIC_KEY"))
|
||||
if cd.listen_on != "" {
|
||||
add_env("KITTY_LISTEN_ON", cd.listen_on)
|
||||
}
|
||||
return final_env_instructions(cd.script_type == "py", get_local_env, env...), ksi
|
||||
}
|
||||
|
||||
|
|
@ -622,28 +626,88 @@ func run_ssh(ssh_args, server_args, found_extra_args []string) (rc int, err erro
|
|||
}
|
||||
return 1, unix.Exec(utils.FindExe(delegate_cmd[0]), utils.Concat(delegate_cmd, ssh_args, server_args), os.Environ())
|
||||
}
|
||||
master_is_alive, master_checked := false, false
|
||||
var control_master_args []string
|
||||
if host_opts.Share_connections {
|
||||
kpid, err := strconv.Atoi(os.Getenv("KITTY_PID"))
|
||||
if err != nil {
|
||||
return 1, fmt.Errorf("Invalid KITTY_PID env var not an integer: %#v", os.Getenv("KITTY_PID"))
|
||||
}
|
||||
cpargs, err := connection_sharing_args(kpid)
|
||||
control_master_args, err = connection_sharing_args(kpid)
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
cmd = slices.Insert(cmd, insertion_point, cpargs...)
|
||||
cmd = slices.Insert(cmd, insertion_point, control_master_args...)
|
||||
}
|
||||
use_kitty_askpass := host_opts.Askpass == Askpass_native || (host_opts.Askpass == Askpass_unless_set && os.Getenv("SSH_ASKPASS") == "")
|
||||
need_to_request_data := true
|
||||
if use_kitty_askpass {
|
||||
need_to_request_data = set_askpass()
|
||||
}
|
||||
if need_to_request_data && host_opts.Share_connections {
|
||||
check_cmd := slices.Insert(cmd, 1, "-O", "check")
|
||||
err = exec.Command(check_cmd[0], check_cmd[1:]...).Run()
|
||||
if err == nil {
|
||||
need_to_request_data = false
|
||||
master_is_functional := func() bool {
|
||||
if master_checked {
|
||||
return master_is_alive
|
||||
}
|
||||
master_checked = true
|
||||
check_cmd := slices.Insert(cmd, 1, "-O", "check")
|
||||
master_is_alive = exec.Command(check_cmd[0], check_cmd[1:]...).Run() == nil
|
||||
return master_is_alive
|
||||
}
|
||||
|
||||
if need_to_request_data && host_opts.Share_connections && master_is_functional() {
|
||||
need_to_request_data = false
|
||||
}
|
||||
run_control_master := func() error {
|
||||
cmcmd := slices.Clone(cmd[:insertion_point])
|
||||
cmcmd = append(cmcmd, control_master_args...)
|
||||
cmcmd = append(cmcmd, "-N", "-f")
|
||||
cmcmd = append(cmcmd, "--", hostname)
|
||||
c := exec.Command(cmcmd[0], cmcmd[1:]...)
|
||||
c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
err := c.Run()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed to start SSH ControlMaster with cmdline: %s and error: %w", strings.Join(cmcmd, " "), err)
|
||||
}
|
||||
master_checked = false
|
||||
master_is_alive = false
|
||||
return err
|
||||
}
|
||||
if host_opts.Forward_remote_control && os.Getenv("KITTY_LISTEN_ON") != "" {
|
||||
if !host_opts.Share_connections {
|
||||
return 1, fmt.Errorf("Cannot use forward_remote_control=yes without share_connections=yes as it relies on SSH Controlmasters")
|
||||
}
|
||||
if !master_is_functional() {
|
||||
if err = run_control_master(); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
if !master_is_functional() {
|
||||
return 1, fmt.Errorf("SSH ControlMaster not functional after being started explicitly")
|
||||
}
|
||||
}
|
||||
protocol, listen_on, found := strings.Cut(os.Getenv("KITTY_LISTEN_ON"), ":")
|
||||
if !found {
|
||||
return 1, fmt.Errorf("Invalid KITTY_LISTEN_ON: %#v", os.Getenv("KITTY_LISTEN_ON"))
|
||||
}
|
||||
if protocol == "unix" && strings.HasPrefix(listen_on, "@") {
|
||||
return 1, fmt.Errorf("Cannot forward kitty remote control socket when an abstract UNIX socket (%s) is used, due to limitations in OpenSSH. Use either a path based one or a TCP socket", listen_on)
|
||||
}
|
||||
cmcmd := slices.Clone(cmd[:insertion_point])
|
||||
cmcmd = append(cmcmd, control_master_args...)
|
||||
cmcmd = append(cmcmd, "-R", "0:"+listen_on, "-O", "forward")
|
||||
cmcmd = append(cmcmd, "--", hostname)
|
||||
c := exec.Command(cmcmd[0], cmcmd[1:]...)
|
||||
b := bytes.Buffer{}
|
||||
c.Stdout = &b
|
||||
c.Stderr = os.Stderr
|
||||
if err := c.Run(); err != nil {
|
||||
return 1, fmt.Errorf("%s\nSetup of port forward in SSH ControlMaster failed with error: %w", string(b.Bytes()), err)
|
||||
}
|
||||
port, err := strconv.Atoi(strings.TrimSpace(string(b.Bytes())))
|
||||
if err != nil {
|
||||
os.Stderr.Write(b.Bytes())
|
||||
return 1, fmt.Errorf("Setup of port forward in SSH ControlMaster failed with error: invalid resolved port returned: %s", b.String())
|
||||
}
|
||||
cd.listen_on = "tcp:localhost:" + strconv.Itoa(port)
|
||||
}
|
||||
term, err := tty.OpenControllingTerm(tty.SetNoEcho)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -208,6 +208,16 @@ For example using :code:`delegate ssh` will run the ssh command with all argumen
|
|||
to the kitten, except kitten specific ones. This is useful if some hosts are not capable
|
||||
of supporting the ssh kitten.
|
||||
''')
|
||||
|
||||
opt('forward_remote_control', 'no', option_type='to_bool', long_text='''
|
||||
Forward the kitty remote control socket to the remote host. This allows using the kitty
|
||||
remote control facilities from the remote host. WARNING: This allows any software
|
||||
on the remote host full access to the local computer, so only do it for trusted remote hosts.
|
||||
Note that this does not work with abstract UNIX sockets such as :file:`@mykitty` because of SSH limitations.
|
||||
This option uses SSH socket forwarding to forward the socket pointed to by the :envvar:`KITTY_LISTEN_ON`
|
||||
environment variable.
|
||||
''')
|
||||
|
||||
egr() # }}}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue