Function bodies 28 total
main function · go · L22-L95 (74 LOC)main.go
func main() {
// Define flags
versionFlag := flag.Bool("V", false, "print version and exit")
countFlag := flag.Int("c", 100, "number of echo characters to send")
timeFlag := flag.Duration("t", 0, "time limit for echo test")
echoTimeoutFlag := flag.Duration("w", 10*time.Second, "per-echo timeout")
sizeFlag := flag.Int("s", 8, "size in MB for speed test")
remoteFlag := flag.String("r", "/tmp/sshping-test", "remote test file path")
identFlag := flag.String("i", "", "identity/key file")
portFlag := flag.Int("p", 22, "SSH port")
userFlag := flag.String("u", "", "SSH user")
proxyFlag := flag.String("proxy", "", "SOCKS5 proxy address (e.g. 127.0.0.1:9050 for Tor)")
insecureFlag := flag.Bool("insecure", false, "skip host key verification")
echoOnlyFlag := flag.Bool("e", false, "echo test only")
speedOnlyFlag := flag.Bool("b", false, "speed test only")
humanFlag := flag.Bool("H", false, "human-readable output")
delimFlag := flag.Bool("d", false, "delimited numbers")
verboseFlagparseTarget function · go · L97-L120 (24 LOC)main.go
func parseTarget(target, userFlag string, portFlag int) (string, int, string) {
var host string
var port int = portFlag
var user string = userFlag
// Check for user@host
if strings.Contains(target, "@") {
parts := strings.SplitN(target, "@", 2)
user = parts[0]
target = parts[1]
}
// Check for host:port (handles IPv6 bracket notation via net.SplitHostPort)
if h, p, err := net.SplitHostPort(target); err == nil {
host = h
if pn, err := strconv.Atoi(p); err == nil {
port = pn
}
} else {
host = target
}
return host, port, user
}runEchoTest function · go · L122-L150 (29 LOC)main.go
func runEchoTest(sess *ssh.Session, count int, limit, echoTimeout time.Duration, verbosity int, human, delim bool) {
shell, err := sess.OpenShell()
if err != nil {
log.Fatalf("failed to open shell: %v", err)
}
result, err := ssh.RunEchoTest(shell, count, limit, echoTimeout, verbosity)
if err != nil {
log.Fatalf("echo test failed: %v", err)
}
fmt.Println("\nEcho results:")
fmt.Printf(" Sent: %d\n", result.Sent)
fmt.Printf(" Received: %d\n", result.Received)
if len(result.Latencies) > 0 {
min := stats.Min(result.Latencies)
max := stats.Max(result.Latencies)
mean := stats.Mean(result.Latencies)
median := stats.Median(result.Latencies)
stddev := stats.StdDev(result.Latencies)
fmt.Printf(" Min: %s\n", fmtDuration(min, human, delim))
fmt.Printf(" Max: %s\n", fmtDuration(max, human, delim))
fmt.Printf(" Mean: %s\n", fmtDuration(mean, human, delim))
fmt.Printf(" Median: %s\n", fmtDuration(median, human, delim))
fmt.Printf(" StdDerunSpeedTest function · go · L152-L168 (17 LOC)main.go
func runSpeedTest(client *gossh.Client, remotePath string, sizeMB int, human, delim bool) {
fmt.Println("\nSpeed test:")
upload, err := ssh.RunUploadTest(client, remotePath, sizeMB)
if err != nil {
log.Printf("upload test failed: %v", err)
} else {
fmt.Printf(" Upload: %s\n", fmtThroughput(upload, human, delim))
}
download, err := ssh.RunDownloadTest(client, remotePath, sizeMB)
if err != nil {
log.Printf("download test failed: %v", err)
} else {
fmt.Printf(" Download: %s\n", fmtThroughput(download, human, delim))
}
}fmtDuration function · go · L170-L187 (18 LOC)main.go
func fmtDuration(d time.Duration, human, delim bool) string {
if delim {
return fmt.Sprintf("%d", d.Nanoseconds())
}
if human {
ns := d.Nanoseconds()
if ns < 1000 {
return fmt.Sprintf("%d ns", ns)
} else if ns < 1000000 {
return fmt.Sprintf("%.2f µs", float64(ns)/1000)
} else if ns < 1000000000 {
return fmt.Sprintf("%.2f ms", float64(ns)/1000000)
} else {
return fmt.Sprintf("%.2f s", float64(ns)/1000000000)
}
}
return d.String()
}fmtThroughput function · go · L189-L202 (14 LOC)main.go
func fmtThroughput(mbps float64, human, delim bool) string {
if delim {
return fmt.Sprintf("%.6f", mbps)
}
if human {
if mbps >= 1024 {
return fmt.Sprintf("%.2f GB/s", mbps/1024)
} else if mbps >= 1 {
return fmt.Sprintf("%.2f MB/s", mbps)
}
return fmt.Sprintf("%.2f KB/s", mbps*1024)
}
return fmt.Sprintf("%.2f MB/s", mbps)
}RunEchoTest function · go · L21-L151 (131 LOC)ssh/echo.go
func RunEchoTest(shell io.ReadWriter, count int, limit, echoTimeout time.Duration, verbose int) (EchoResult, error) {
result := EchoResult{
Latencies: make([]time.Duration, 0, count),
}
// Set up raw mode on remote (no buffering, no echo), print a sentinel
// byte, then start cat. The sentinel (0x06 ACK) is printed by printf
// as part of the command chain, so it appears on stdout only after stty
// has run. Cat starts immediately after, so any stdin we send after
// seeing the sentinel is guaranteed to be read by cat.
const sentinel = 0x06
fmt.Fprintf(shell, "stty raw -echo && printf '\\006' && cat\n")
// Single persistent reader goroutine. The done channel lets it exit once
// ReadByte unblocks (which happens when the SSH session is closed by the
// caller). Between RunEchoTest returning and session close, the goroutine
// remains blocked in ReadByte — this is expected and harmless.
done := make(chan struct{})
defer close(done)
byteCh := make(chan readResult, 1)
About: code-quality intelligence by Repobility · https://repobility.com
Connect function · go · L40-L95 (56 LOC)ssh/session.go
func Connect(cfg Config) (*connectResult, error) {
addr := net.JoinHostPort(cfg.Host, fmt.Sprintf("%d", cfg.Port))
hostKeyCb, err := hostKeyCallback(cfg.Insecure)
if err != nil {
return nil, err
}
// Build auth methods in order: pubkey, keyboard-interactive, password
var authMethods []ssh.AuthMethod
var agentConn net.Conn
// Try public key authentication
if methods, conn, err := publicKeyAuth(cfg.IdentFile); err == nil {
authMethods = append(authMethods, methods...)
agentConn = conn
}
if cfg.Password != "" {
authMethods = append(authMethods, ssh.Password(cfg.Password))
}
clientConfig := &ssh.ClientConfig{
User: cfg.User,
Auth: authMethods,
HostKeyCallback: hostKeyCb,
Timeout: cfg.Timeout,
}
result, err := dial(addr, cfg.SOCKS5Proxy, cfg.Timeout, clientConfig)
if err == nil {
result.agentConn = agentConn
return result, nil
}
// If auth failed and we skipped a passphrase-protected -i key because
// the agent was dial function · go · L97-L120 (24 LOC)ssh/session.go
func dial(addr, socks5Proxy string, timeout time.Duration, clientConfig *ssh.ClientConfig) (*connectResult, error) {
if socks5Proxy != "" {
dialer, err := proxy.SOCKS5("tcp", socks5Proxy, nil, &net.Dialer{Timeout: timeout})
if err != nil {
return nil, fmt.Errorf("socks5 dialer: %w", err)
}
conn, err := dialer.Dial("tcp", addr)
if err != nil {
return nil, fmt.Errorf("socks5 dial failed: %w", err)
}
c, chans, reqs, err := ssh.NewClientConn(conn, addr, clientConfig)
if err != nil {
conn.Close()
return nil, fmt.Errorf("ssh handshake failed: %w", err)
}
return &connectResult{client: ssh.NewClient(c, chans, reqs)}, nil
}
client, err := ssh.Dial("tcp", addr, clientConfig)
if err != nil {
return nil, fmt.Errorf("dial failed: %w", err)
}
return &connectResult{client: client}, nil
}isAuthError function · go · L122-L126 (5 LOC)ssh/session.go
func isAuthError(err error) bool {
msg := err.Error()
return strings.Contains(msg, "unable to authenticate") ||
strings.Contains(msg, "no supported methods remain")
}publicKeyAuth function · go · L130-L172 (43 LOC)ssh/session.go
func publicKeyAuth(identFile string) ([]ssh.AuthMethod, net.Conn, error) {
var methods []ssh.AuthMethod
var agentConn net.Conn
// Try SSH agent
if agentSock := os.Getenv("SSH_AUTH_SOCK"); agentSock != "" {
conn, err := net.Dial("unix", agentSock)
if err == nil {
ag := agent.NewClient(conn)
methods = append(methods, ssh.PublicKeysCallback(ag.Signers))
agentConn = conn
}
}
// If a specific identity file is provided, try loading it.
// Only prompt for passphrase if no agent is available to fall back on.
if identFile != "" {
if method, err := loadPrivateKey(identFile, agentConn == nil); err == nil {
methods = append(methods, method)
}
}
// Try default SSH keys only if no agent and no explicit identity file
if len(methods) == 0 {
homeDir, err := os.UserHomeDir()
if err == nil {
for _, name := range []string{"id_rsa", "id_ecdsa", "id_ed25519"} {
keyPath := filepath.Join(homeDir, ".ssh", name)
method, err := loadPrivateKey(keyPath, true)
loadPrivateKey function · go · L174-L200 (27 LOC)ssh/session.go
func loadPrivateKey(path string, promptForPassphrase bool) (ssh.AuthMethod, error) {
keyBytes, err := os.ReadFile(path)
if err != nil {
return nil, err
}
signer, err := ssh.ParsePrivateKey(keyBytes)
if err == nil {
return ssh.PublicKeys(signer), nil
}
if !promptForPassphrase {
return nil, fmt.Errorf("key %s is passphrase-protected, skipping (agent available)", path)
}
passphrase, err := promptPassphrase(path)
if err != nil {
return nil, err
}
signer, err = ssh.ParsePrivateKeyWithPassphrase(keyBytes, []byte(passphrase))
if err != nil {
return nil, fmt.Errorf("failed to unlock key %s: %w", path, err)
}
return ssh.PublicKeys(signer), nil
}promptPassphrase function · go · L202-L237 (36 LOC)ssh/session.go
func promptPassphrase(keyPath string) (string, error) {
fmt.Fprintf(os.Stderr, "Enter passphrase for %s: ", keyPath)
// Read password without echo
fd := int(syscall.Stdin)
oldState, err := term.GetState(fd)
if err != nil {
// Fall back to unbuffered line reading if terminal mode unavailable.
// Avoid bufio.NewReader here — it would consume extra bytes from
// stdin that the TOFU host key prompt needs later.
var passphrase []byte
buf := make([]byte, 1)
for {
n, err := os.Stdin.Read(buf)
if n > 0 && buf[0] == '\n' {
break
}
if n > 0 {
passphrase = append(passphrase, buf[0])
}
if err != nil {
break
}
}
return string(passphrase), nil
}
defer term.Restore(fd, oldState)
password, err := term.ReadPassword(fd)
if err != nil {
return "", err
}
fmt.Fprintf(os.Stderr, "\n")
return string(password), nil
}hostKeyCallback function · go · L240-L339 (100 LOC)ssh/session.go
func hostKeyCallback(insecure bool) (ssh.HostKeyCallback, error) {
if insecure {
return ssh.InsecureIgnoreHostKey(), nil
}
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("cannot find home directory: %w", err)
}
knownHostsFile := filepath.Join(homeDir, ".ssh", "known_hosts")
// Create known_hosts if it doesn't exist.
if _, err := os.Stat(knownHostsFile); os.IsNotExist(err) {
if err := os.MkdirAll(filepath.Dir(knownHostsFile), 0700); err != nil {
return nil, fmt.Errorf("cannot create .ssh directory: %w", err)
}
f, err := os.OpenFile(knownHostsFile, os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return nil, fmt.Errorf("cannot create known_hosts: %w", err)
}
f.Close()
}
cb, err := knownhosts.New(knownHostsFile)
if err != nil {
return nil, fmt.Errorf("cannot read known_hosts (%s): %w", knownHostsFile, err)
}
// TOFU wrapper: prompt to accept unknown keys, reject changed keys.
return func(hostname string, remote net.Addr, key keyTypeName function · go · L341-L354 (14 LOC)ssh/session.go
func keyTypeName(keyType string) string {
switch keyType {
case "ssh-rsa":
return "RSA"
case "ssh-ed25519":
return "ED25519"
case "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521":
return "ECDSA"
case "ssh-dss":
return "DSA"
default:
return strings.ToUpper(keyType)
}
}Want this analysis on your repo? https://repobility.com/scan/
NewSession function · go · L362-L394 (33 LOC)ssh/session.go
func NewSession(cfg Config) (*Session, error) {
if cfg.User == "" {
currentUser, err := user.Current()
if err != nil {
return nil, fmt.Errorf("failed to get current user: %w", err)
}
cfg.User = currentUser.Username
}
if cfg.Timeout == 0 {
cfg.Timeout = 10 * time.Second
}
cr, err := Connect(cfg)
if err != nil {
return nil, err
}
sess, err := cr.client.NewSession()
if err != nil {
cr.client.Close()
if cr.agentConn != nil {
cr.agentConn.Close()
}
return nil, fmt.Errorf("new session failed: %w", err)
}
return &Session{
Client: cr.client,
Sess: sess,
agentConn: cr.agentConn,
}, nil
}OpenShell method · go · L396-L426 (31 LOC)ssh/session.go
func (s *Session) OpenShell() (io.ReadWriter, error) {
in, err := s.Sess.StdinPipe()
if err != nil {
return nil, fmt.Errorf("stdin pipe failed: %w", err)
}
out, err := s.Sess.StdoutPipe()
if err != nil {
in.Close()
return nil, fmt.Errorf("stdout pipe failed: %w", err)
}
// Request PTY for interactive shell
modes := ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
if err := s.Sess.RequestPty("xterm", 24, 80, modes); err != nil {
in.Close()
return nil, fmt.Errorf("pty request failed: %w", err)
}
if err := s.Sess.Shell(); err != nil {
in.Close()
return nil, fmt.Errorf("shell start failed: %w", err)
}
return &readWriter{in: in, out: out}, nil
}Close method · go · L428-L443 (16 LOC)ssh/session.go
func (s *Session) Close() error {
var err1, err2 error
if s.Sess != nil {
err1 = s.Sess.Close()
}
if s.Client != nil {
err2 = s.Client.Close()
}
if s.agentConn != nil {
s.agentConn.Close()
}
if err1 != nil {
return err1
}
return err2
}Read method · go · L450-L452 (3 LOC)ssh/session.go
func (rw *readWriter) Read(b []byte) (int, error) {
return rw.out.Read(b)
}Write method · go · L454-L456 (3 LOC)ssh/session.go
func (rw *readWriter) Write(b []byte) (int, error) {
return rw.in.Write(b)
}Close method · go · L458-L460 (3 LOC)ssh/session.go
func (rw *readWriter) Close() error {
return rw.in.Close()
}RunUploadTest function · go · L13-L65 (53 LOC)ssh/speed.go
func RunUploadTest(client *ssh.Client, remotePath string, sizeMB int) (float64, error) {
if sizeMB <= 0 {
return 0, fmt.Errorf("size must be > 0, got %d", sizeMB)
}
sfTPClient, err := sftp.NewClient(client)
if err != nil {
return 0, fmt.Errorf("sftp client creation failed: %w", err)
}
defer sfTPClient.Close()
// Create remote file
remoteFile, err := sfTPClient.Create(remotePath)
if err != nil {
return 0, fmt.Errorf("remote file creation failed: %w", err)
}
// Generate random data and write
bufSize := 1024 * 1024 // 1 MB chunks
totalBytes := int64(sizeMB) * 1024 * 1024
buf := make([]byte, bufSize)
// Fill with random data
rand.Read(buf)
written := int64(0)
start := time.Now()
for written < totalBytes {
remaining := totalBytes - written
if int64(bufSize) > remaining {
buf = make([]byte, remaining)
rand.Read(buf)
}
n, err := remoteFile.Write(buf)
if err != nil {
remoteFile.Close()
sfTPClient.Remove(remotePath)
return 0, fmt.Errorf("wRunDownloadTest function · go · L67-L137 (71 LOC)ssh/speed.go
func RunDownloadTest(client *ssh.Client, remotePath string, sizeMB int) (float64, error) {
if sizeMB <= 0 {
return 0, fmt.Errorf("size must be > 0, got %d", sizeMB)
}
sfTPClient, err := sftp.NewClient(client)
if err != nil {
return 0, fmt.Errorf("sftp client creation failed: %w", err)
}
defer sfTPClient.Close()
// First, create a file to download by uploading test data
remoteFile, err := sfTPClient.Create(remotePath)
if err != nil {
return 0, fmt.Errorf("remote file creation failed: %w", err)
}
bufSize := 1024 * 1024
totalBytes := int64(sizeMB) * 1024 * 1024
buf := make([]byte, bufSize)
rand.Read(buf)
written := int64(0)
for written < totalBytes {
remaining := totalBytes - written
if int64(bufSize) > remaining {
buf = make([]byte, remaining)
rand.Read(buf)
}
n, err := remoteFile.Write(buf)
if err != nil {
remoteFile.Close()
sfTPClient.Remove(remotePath)
return 0, fmt.Errorf("setup write failed: %w", err)
}
written += int64(n)
}
ifRepobility — the code-quality scanner for AI-generated software · https://repobility.com
Min function · go · L9-L20 (12 LOC)stats/stats.go
func Min(d []time.Duration) time.Duration {
if len(d) == 0 {
return 0
}
min := d[0]
for _, v := range d[1:] {
if v < min {
min = v
}
}
return min
}Max function · go · L22-L33 (12 LOC)stats/stats.go
func Max(d []time.Duration) time.Duration {
if len(d) == 0 {
return 0
}
max := d[0]
for _, v := range d[1:] {
if v > max {
max = v
}
}
return max
}Mean function · go · L35-L44 (10 LOC)stats/stats.go
func Mean(d []time.Duration) time.Duration {
if len(d) == 0 {
return 0
}
sum := int64(0)
for _, v := range d {
sum += v.Nanoseconds()
}
return time.Duration(sum / int64(len(d)))
}Median function · go · L46-L59 (14 LOC)stats/stats.go
func Median(d []time.Duration) time.Duration {
if len(d) == 0 {
return 0
}
sorted := make([]time.Duration, len(d))
copy(sorted, d)
sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] })
mid := len(sorted) / 2
if len(sorted)%2 == 1 {
return sorted[mid]
}
return (sorted[mid-1] + sorted[mid]) / 2
}StdDev function · go · L61-L73 (13 LOC)stats/stats.go
func StdDev(d []time.Duration) time.Duration {
if len(d) < 2 {
return 0
}
mean := Mean(d)
sumSq := 0.0
for _, v := range d {
diff := float64(v.Nanoseconds() - mean.Nanoseconds())
sumSq += diff * diff
}
variance := sumSq / float64(len(d)-1)
return time.Duration(math.Sqrt(variance))
}