How witr Detects and Identifies SSH Sessions and Remote Terminal Connections from Source Code
witr detects SSH sessions by combining process ancestry inspection (checking for sshd in parent processes) with fallback environment variable checks (SSH_CONNECTION, SSH_CLIENT, SSH_TTY) to reliably identify remote terminal connections even when environment data is partially stripped.
The witr project implements a robust source detection system written in Go that answers the question "Where am I running?" The SSH detection logic in this repository demonstrates how to programmatically distinguish local shells from remote sessions. This article examines the actual implementation in pranshuparmar/witr, revealing how the tool inspects process trees and environment variables to build accurate session descriptions.
Core SSH Detection Strategy
The detection algorithm follows a two-tier approach designed for reliability across different execution contexts:
- Primary check: Walk the process ancestry looking for
sshd - Secondary check: Parse SSH-specific environment variables when ancestry fails
This dual-method design handles common scenarios where sudo, su, or containerization might strip environment variables while preserving enough process metadata for detection.
How Process Ancestry Detection Works
The detectSSH function in internal/source/ssh.go implements the primary detection mechanism by examining the process tree that launched the current program.
Ancestry Walking Implementation
// Conceptual flow based on witr's internal/source/ssh.go
func detectSSH(ancestry []model.Process) *model.Source {
hasSSHD := false
for _, proc := range ancestry {
if proc.Executable == "sshd" {
hasSSHD = true
break
}
}
if !hasSSHD {
// Fall back to environment variable detection
return detectSSHEnv()
}
// Build source description from SSH connection data
return &model.Source{
Type: model.SourceSSH,
Description: buildSSHDescription(),
}
}
The ancestry slice is populated by proc.GetAncestry(), implemented in internal/proc/process.go with operating-system-specific variants. This function walks from the current process ID up to the init system, collecting executable names at each step.
Why Ancestry Detection Matters
| Scenario | Environment Variables | Ancestry Detection |
|---|---|---|
| Direct SSH login | Present | ✓ Works |
ssh → sudo -i |
Stripped | ✓ Still detects sshd parent |
ssh → su |
Modified | ✓ Still detects sshd parent |
Container with --pid=host |
Missing | ✓ Detects host's sshd |
| Container without host PID | Missing | ✗ Falls back to env vars |
Environment Variable Fallback Detection
When process ancestry does not reveal sshd, the detection logic examines three environment variables defined by OpenSSH:
| Variable | Format | Information Extracted |
|---|---|---|
SSH_CONNECTION |
client_ip server_ip client_port server_port |
Remote IP address, connection endpoints |
SSH_CLIENT |
client_ip client_port server_port |
Remote IP address (simpler format) |
SSH_TTY |
/dev/pts/N |
Pseudo-terminal device name |
According to the source code analysis, detectSSH uses SSH_CONNECTION preferentially when building session descriptions because it provides the most complete connection metadata, including the remote IP address that witr displays to users.
Environment Parsing Logic
// Based on detection flow in internal/source/ssh.go
func detectSSHEnv() *model.Source {
conn := os.Getenv("SSH_CONNECTION")
client := os.Getenv("SSH_CLIENT")
tty := os.Getenv("SSH_TTY")
// Must have at least one SSH indicator
if conn == "" && client == "" && tty == "" {
return nil
}
// Prefer SSH_CONNECTION for IP extraction
remoteIP := extractIP(conn)
if remoteIP == "" {
remoteIP = extractIP(client)
}
user := os.Getenv("USER")
host, _ := os.Hostname()
return &model.Source{
Type: model.SourceSSH,
Description: fmt.Sprintf("SSH session from %s (%s@%s)",
remoteIP, user, host),
}
}
Integration with the Detection Pipeline
The SSH detector integrates into witr's broader source detection system through internal/source/detect.go. This orchestration file calls multiple specialized detectors in priority order and returns the first successful match.
Detection Orchestration
// Representative structure from internal/source/detect.go
func Detect(ancestry []model.Process) *model.Source {
// Priority-ordered detection attempts
detectors := []func([]model.Process) *model.Source{
detectContainer, // Docker, containerd, etc.
detectSSH, // SSH sessions
detectSystemd, // systemd units
detectWSL, // Windows Subsystem for Linux
// ... additional detectors
}
for _, detector := range detectors {
if src := detector(ancestry); src != nil {
return src
}
}
return nil // Unknown source
}
SSH detection typically executes after container detection because containers propagated over SSH may want to identify as the container environment rather than the SSH transport.
Source Model and Type Constants
The detection results are typed through model.Source, defined in pkg/model/source.go. This structure standardizes how witr represents execution contexts across all detector implementations.
// From pkg/model/source.go
package model
type SourceType string
const (
SourceSSH SourceType = "ssh"
SourceDocker SourceType = "docker"
SourceSystemd SourceType = "systemd"
SourceWSL SourceType = "wsl"
// ... additional types
)
type Source struct {
Type SourceType
Description string
// Additional metadata fields
}
The SourceSSH constant enables type-safe switching throughout the codebase, while the Description field carries human-readable context like "SSH session from 203.0.113.42 (alice@myhost)".
Practical Usage and Verification
CLI Output Example
When running witr with verbose output, users see automatically detected session information:
$ ssh alice@remote-server
alice@remote-server:~$ witr --verbose
...
Source: SSH session from 198.51.100.22 (alice@remote-server)
Programmatic Verification
For applications building on witr's detection logic:
package main
import (
"fmt"
"log"
"os"
"github.com/pranshuparmar/witr/internal/proc"
"github.com/pranshuparmar/witr/internal/source"
)
func main() {
ancestry, err := proc.GetAncestry()
if err != nil {
log.Fatalf("Failed to get process ancestry: %v", err)
}
src := source.Detect(ancestry)
if src == nil {
fmt.Println("Running in unknown/localhost environment")
os.Exit(0)
}
fmt.Printf("Detected source type: %s\n", src.Type)
fmt.Printf("Description: %s\n", src.Description)
if src.Type == "ssh" {
fmt.Println("⚠️ Running via remote connection - " +
"consider connection stability for long operations")
}
}
Platform Coverage and Edge Cases
The detection implementation accounts for platform differences in process inspection:
- Linux: Parses
/proc/[pid]/statand/proc/[pid]/statusfor parent relationships - macOS: Uses
sysctlwithKERN_PROCINFOandlibproc - Windows: Implements alternative detection primarily through environment variables due to different process semantics
- BSD variants: Similar to Linux with
/procorkvminterfaces
The environment variable fallback proves especially valuable on Windows, where OpenSSH's native port sets the same SSH_CONNECTION and SSH_CLIENT variables as Unix systems.
Summary
- Process ancestry is the primary detection method:
internal/source/ssh.gowalks parent processes seekingsshd, making detection resilient againstsudoandsuenvironment stripping. - Environment variables provide reliable fallback:
SSH_CONNECTION,SSH_CLIENT, andSSH_TTYsupply session metadata when process inspection is unavailable or inconclusive. internal/source/detect.goorchestrates priority-ordered detection: SSH detection integrates into a broader system that prioritizes more specific contexts like containers.model.Sourcestandardizes results: The type system inpkg/model/source.goensures consistent handling across witr's CLI, API, and library interfaces.
Frequently Asked Questions
How does witr handle SSH sessions inside containers?
When a container runs with --pid=host or equivalent, witr's process ancestry detection can see the host's sshd and identify the SSH context. Without host PID namespace access, the container appears isolated and detection falls back to environment variable inspection, which will fail if variables were not propagated during docker exec or similar operations.
Can witr detect other remote terminal protocols like Mosh or Telnet?
The current implementation specifically targets OpenSSH's process and environment signatures. Mosh uses different environment variables (MOSH_CONNECTION) and a distinct wrapper architecture that would require separate detection logic. Telnet sessions lack standardized environment markers, making reliable programmatic detection substantially more difficult.
What happens when SSH_CONNECTION contains IPv6 addresses?
According to the source structure, witr extracts the remote IP component from SSH_CONNECTION using standard string parsing. IPv6 addresses in bracketed notation (e.g., [2001:db8::1]) are handled by the formatting logic in buildSSHDescription(), ensuring the display description remains readable regardless of address family.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →