FILE / ScuroNeko/est
internal/ssh/args.go
Исходный файл и его история в репозитории.
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
// Package ssh builds and runs SSH port-forwarding commands.
|
|
package ssh
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.scuroneko.dev/ScuroNeko/est/internal/config"
|
|
)
|
|
|
|
func buildRemoteToLocalString(sourceIP, remoteIP string, sourcePort, remotePort uint16) string {
|
|
if sourceIP == "" {
|
|
sourceIP = "127.0.0.1"
|
|
}
|
|
if remoteIP == "" {
|
|
remoteIP = "127.0.0.1"
|
|
}
|
|
return fmt.Sprintf("%s:%d:%s:%d", sourceIP, sourcePort, remoteIP, remotePort)
|
|
}
|
|
func buildLocalToRemoteString(sourceIP, remoteIP string, sourcePort, remotePort uint16) string {
|
|
if sourceIP == "" {
|
|
sourceIP = "127.0.0.1"
|
|
}
|
|
if remoteIP == "" {
|
|
remoteIP = "127.0.0.1"
|
|
}
|
|
return fmt.Sprintf("%s:%d:%s:%d", remoteIP, remotePort, sourceIP, sourcePort)
|
|
}
|
|
|
|
var (
|
|
// ErrEmptyHost is returned when a tunnel has no SSH destination.
|
|
ErrEmptyHost = errors.New("empty host")
|
|
// ErrEmptyLocalPort is returned when a tunnel has no local port.
|
|
ErrEmptyLocalPort = errors.New("empty local port")
|
|
// ErrEmptyRemotePort is returned when a tunnel has no remote port.
|
|
ErrEmptyRemotePort = errors.New("empty remote port")
|
|
)
|
|
|
|
func validateArgs(entry config.ProxyEntry) error {
|
|
if entry.Host == "" {
|
|
return ErrEmptyHost
|
|
}
|
|
if entry.LocalPort == 0 {
|
|
return ErrEmptyLocalPort
|
|
}
|
|
if entry.RemotePort == 0 {
|
|
return ErrEmptyRemotePort
|
|
}
|
|
return nil
|
|
}
|
|
func prepareArgs(configPath string, entry config.ProxyEntry) ([]string, error) {
|
|
if err := validateArgs(entry); err != nil {
|
|
return nil, err
|
|
}
|
|
args := []string{"-N", "-T", "-o", "ExitOnForwardFailure=yes"}
|
|
if configPath != "" {
|
|
args = append(args, "-F", configPath)
|
|
} else if configPath = getConfigOrEmpty(); configPath != "" {
|
|
args = append(args, "-F", configPath)
|
|
}
|
|
if entry.IdentityFile != "" {
|
|
args = append(args, "-i", entry.IdentityFile)
|
|
}
|
|
switch entry.Direction {
|
|
case config.LocalToRemote:
|
|
args = append(args, "-R", buildLocalToRemoteString(entry.LocalIP, entry.RemoteIP, entry.LocalPort, entry.RemotePort))
|
|
case config.RemoteToLocal:
|
|
args = append(args, "-L", buildRemoteToLocalString(entry.LocalIP, entry.RemoteIP, entry.LocalPort, entry.RemotePort))
|
|
default:
|
|
return nil, fmt.Errorf("invalid direction: %v; should be ltr on rtl", entry.Direction)
|
|
}
|
|
if entry.Host != "" {
|
|
args = append(args, entry.Host)
|
|
}
|
|
return args, nil
|
|
}
|