diff --git a/tools/cmd/ssh/utils.go b/tools/cmd/ssh/utils.go new file mode 100644 index 000000000..3e5765124 --- /dev/null +++ b/tools/cmd/ssh/utils.go @@ -0,0 +1,82 @@ +// License: GPLv3 Copyright: 2023, Kovid Goyal, + +package ssh + +import ( + "fmt" + "io" + "kitty/tools/utils" + "os/exec" + "strings" + "sync" +) + +var _ = fmt.Print + +var ssh_options map[string]string +var query_ssh_for_options_once sync.Once + +func get_ssh_options() { + defer func() { + if ssh_options == nil { + ssh_options = map[string]string{ + "4": "", "6": "", "A": "", "a": "", "C": "", "f": "", "G": "", "g": "", "K": "", "k": "", + "M": "", "N": "", "n": "", "q": "", "s": "", "T": "", "t": "", "V": "", "v": "", "X": "", + "x": "", "Y": "", "y": "", "B": "bind_interface", "b": "bind_address", "c": "cipher_spec", + "D": "[bind_address:]port", "E": "log_file", "e": "escape_char", "F": "configfile", "I": "pkcs11", + "i": "identity_file", "J": "[user@]host[:port]", "L": "address", "l": "login_name", "m": "mac_spec", + "O": "ctl_cmd", "o": "option", "p": "port", "Q": "query_option", "R": "address", + "S": "ctl_path", "W": "host:port", "w": "local_tun[:remote_tun]", + } + } + }() + cmd := exec.Command("ssh") + stderr, err := cmd.StderrPipe() + if err != nil { + return + } + if err := cmd.Start(); err != nil { + return + } + raw, err := io.ReadAll(stderr) + if err != nil { + return + } + text := utils.UnsafeBytesToString(raw) + ssh_options = make(map[string]string, 32) + for { + pos := strings.IndexByte(text, '[') + if pos < 0 { + break + } + num := 1 + epos := pos + for num > 0 { + epos++ + switch text[epos] { + case '[': + num += 1 + case ']': + num -= 1 + } + } + q := text[pos+1 : epos] + text = text[epos:] + if len(q) < 2 || !strings.HasPrefix(q, "-") { + continue + } + opt, desc, found := strings.Cut(q, " ") + if found { + ssh_options[opt[1:]] = desc + } else { + for _, ch := range opt[1:] { + ssh_options[string(ch)] = "" + } + } + } +} + +func SSHOptions() map[string]string { + query_ssh_for_options_once.Do(get_ssh_options) + return ssh_options +} diff --git a/tools/cmd/ssh/utils_test.go b/tools/cmd/ssh/utils_test.go new file mode 100644 index 000000000..d7425a7ec --- /dev/null +++ b/tools/cmd/ssh/utils_test.go @@ -0,0 +1,17 @@ +// License: GPLv3 Copyright: 2023, Kovid Goyal, + +package ssh + +import ( + "fmt" + "testing" +) + +var _ = fmt.Print + +func TestGetSSHOptions(t *testing.T) { + m := SSHOptions() + if m["w"] != "local_tun[:remote_tun]" { + t.Fatalf("Unexpected set of SSH options: %#v", m) + } +}