Skip to content

Commit

Permalink
support token %j(ProxyJump)
Browse files Browse the repository at this point in the history
  • Loading branch information
lonnywong committed Apr 20, 2024
1 parent 44c1371 commit 1e6121f
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 21 deletions.
2 changes: 1 addition & 1 deletion tssh/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func getAgentAddr(args *sshArgs, param *sshParam) (string, error) {
if strings.ToLower(addr) == "none" {
return "", nil
}
expandedAddr, err := expandTokens(addr, args, param, "%CdhikLlnpru")
expandedAddr, err := expandTokens(addr, args, param, "%CdhijkLlnpru")
if err != nil {
return "", fmt.Errorf("expand IdentityAgent [%s] failed: %v", addr, err)
}
Expand Down
42 changes: 31 additions & 11 deletions tssh/ctrl_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"regexp"
"strconv"
"strings"
"sync/atomic"
Expand Down Expand Up @@ -226,24 +227,29 @@ func getRealPath(path string) string {
return realPath
}

func getOpenSSH() (string, error) {
func getOpenSSH() (string, int, error) {
sshPath := "/usr/bin/ssh"
tsshPath, err := os.Executable()
if err != nil {
return "", err
return "", 0, err
}
if getRealPath(tsshPath) == getRealPath(sshPath) {
return "", fmt.Errorf("%s is the current program", sshPath)
return "", 0, fmt.Errorf("%s is the current program", sshPath)
}
return sshPath, nil
}

func startControlMaster(args *sshArgs) error {
sshPath, err := getOpenSSH()
out, err := exec.Command(sshPath, "-V").CombinedOutput()
if err != nil {
return fmt.Errorf("can't find openssh program: %v", err)
return "", 0, err
}
re := regexp.MustCompile(`OpenSSH_(\d+)\.(\d+)`)
matches := re.FindStringSubmatch(string(out))
majorVersion := -1
if len(matches) >= 3 {
majorVersion, _ = strconv.Atoi(matches[1])
}
return sshPath, majorVersion, nil
}

func startControlMaster(args *sshArgs, sshPath string) error {
cmdArgs := []string{"-T", "-oRemoteCommand=none", "-oConnectTimeout=10"}

if args.Debug {
Expand Down Expand Up @@ -320,7 +326,21 @@ func connectViaControl(args *sshArgs, param *sshParam) *ssh.Client {
return nil
}

socket, err := expandTokens(ctrlPath, args, param, "%CdhikLlnpru")
sshPath, sshVersion, err := getOpenSSH()
if err != nil {
warning("can't find openssh program: %v", err)
return nil
}
if sshVersion < 0 {
warning("can't get openssh version of %s", sshPath)
return nil
}

tokens := "%CdhijkLlnpru"
if sshVersion < 9 {
tokens = "%CdhikLlnpru"
}
socket, err := expandTokens(ctrlPath, args, param, tokens)
if err != nil {
warning("expand ControlPath [%s] failed: %v", socket, err)
return nil
Expand All @@ -335,7 +355,7 @@ func connectViaControl(args *sshArgs, param *sshParam) *ssh.Client {
}
fallthrough
case "auto", "autoask":
if err := startControlMaster(args); err != nil {
if err := startControlMaster(args, sshPath); err != nil {
warning("start control master failed: %v", err)
}
}
Expand Down
4 changes: 2 additions & 2 deletions tssh/forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ func sshForward(client *ssh.Client, args *sshArgs, param *sshParam) error {
localForward(client, f, args)
}
for _, s := range getAllOptionConfig(args, "LocalForward") {
es, err := expandTokens(s, args, param, "%CdhikLlnpru")
es, err := expandTokens(s, args, param, "%CdhijkLlnpru")
if err != nil {
warning("expand LocalForward [%s] failed: %v", s, err)
continue
Expand All @@ -424,7 +424,7 @@ func sshForward(client *ssh.Client, args *sshArgs, param *sshParam) error {
remoteForward(client, f, args)
}
for _, s := range getAllOptionConfig(args, "RemoteForward") {
es, err := expandTokens(s, args, param, "%CdhikLlnpru")
es, err := expandTokens(s, args, param, "%CdhijkLlnpru")
if err != nil {
warning("expand RemoteForward [%s] failed: %v", s, err)
continue
Expand Down
8 changes: 4 additions & 4 deletions tssh/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ func getHostKeyCallback(args *sshArgs, param *sshParam) (ssh.HostKeyCallback, kn
for _, path := range strings.Fields(knownHostsFiles) {
var resolvedPath string
if user {
expandedPath, err := expandTokens(path, args, param, "%CdhikLlnpru")
expandedPath, err := expandTokens(path, args, param, "%CdhijkLlnpru")
if err != nil {
return fmt.Errorf("expand UserKnownHostsFile [%s] failed: %v", path, err)
}
Expand Down Expand Up @@ -709,7 +709,7 @@ func getPublicKeysAuthMethod(args *sshArgs, param *sshParam) ssh.AuthMethod {

identities := args.Identity.values
for _, identity := range getAllOptionConfig(args, "IdentityFile") {
expandedIdentity, err := expandTokens(identity, args, param, "%CdhikLlnpru")
expandedIdentity, err := expandTokens(identity, args, param, "%CdhijkLlnpru")
if err != nil {
warning("expand IdentityFile [%s] failed: %v", identity, err)
continue
Expand Down Expand Up @@ -847,7 +847,7 @@ func execLocalCommand(args *sshArgs, param *sshParam) {
if localCmd == "" {
return
}
expandedCmd, err := expandTokens(localCmd, args, param, "%CdfHhIiKkLlnprTtu")
expandedCmd, err := expandTokens(localCmd, args, param, "%CdfHhIijKkLlnprTtu")
if err != nil {
warning("expand LocalCommand [%s] failed: %v", localCmd, err)
return
Expand Down Expand Up @@ -891,7 +891,7 @@ func parseRemoteCommand(args *sshArgs, param *sshParam) (string, error) {
if command == "" {
command = getConfig(args.Destination, "RemoteCommand")
}
expandedCmd, err := expandTokens(command, args, param, "%CdhikLlnpru")
expandedCmd, err := expandTokens(command, args, param, "%CdhijkLlnpru")
if err != nil {
return "", fmt.Errorf("expand RemoteCommand [%s] failed: %v", command, err)
}
Expand Down
7 changes: 7 additions & 0 deletions tssh/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,15 @@ func expandTokens(str string, args *sshArgs, param *sshParam, tokens string) (st
hostname = hostname[:idx]
}
buf.WriteString(hostname)
case 'j':
if len(param.proxy) > 0 {
buf.WriteString(param.proxy[len(param.proxy)-1])
}
case 'C':
hashStr := fmt.Sprintf("%s%s%s%s", getHostname(), param.host, param.port, param.user)
if len(param.proxy) > 0 && strings.ContainsRune(tokens, 'j') {
hashStr += param.proxy[len(param.proxy)-1]
}
buf.WriteString(fmt.Sprintf("%x", sha1.Sum([]byte(hashStr))))
default:
return "", fmt.Errorf("token [%%%c] in [%s] is not supported yet", c, str)
Expand Down
47 changes: 44 additions & 3 deletions tssh/tokens_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ func TestExpandTokens(t *testing.T) {
Destination: "dest",
}
param := &sshParam{
host: "127.0.0.1",
port: "1337",
user: "penny",
host: "127.0.0.1",
port: "1337",
user: "penny",
proxy: []string{"jump"},
}
assertProxyCommand := func(original, expanded, errMsg string) {
t.Helper()
Expand Down Expand Up @@ -94,6 +95,46 @@ func TestExpandTokens(t *testing.T) {
assertControlPath("h%", "h%", "[h%] ends with % is invalid")
}

func TestProxyJumpToken(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
originalGetHostname := getHostname
defer func() {
getHostname = originalGetHostname
}()
getHostname = func() string { return "myhostname.mydomain.com" }

args := &sshArgs{
Destination: "dest",
}
param := &sshParam{
host: "127.0.0.1",
port: "1337",
user: "penny",
}

assertProxyJumpToken := func(original, expanded string) {
t.Helper()
result, err := expandTokens(original, args, param, "%CdhijkLlnpru")
require.Nil(err)
assert.Equal(expanded, result)
}

assertProxyJumpToken("%j", "")
assertProxyJumpToken("_%j_", "__")
assertProxyJumpToken("%C", "07f25c03a322b120bcaa54d2dd0a618f2673cb1c")

param.proxy = []string{"jump"}
assertProxyJumpToken("%j", "jump")
assertProxyJumpToken("_%j_", "_jump_")
assertProxyJumpToken("%C", "5fa1bcd29f7fd4f17b669ffb83deb4243d52b1fa")

param.proxy = []string{"jump", "server"}
assertProxyJumpToken("%j", "server")
assertProxyJumpToken("_%j_", "_server_")
assertProxyJumpToken("/%C/", "/dc78bc912643b984e78d7d80f9912dbc794d2455/")
}

func TestInvalidHost(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
Expand Down

0 comments on commit 1e6121f

Please sign in to comment.