-
-
Notifications
You must be signed in to change notification settings - Fork 0
Developer Guide
Internal API reference for developers who want to understand, modify, or extend the script. This page documents the function signatures, return codes, and calling conventions.
The script is organized into these function groups (in order of appearance):
- Utility — logging, colors, formatting
- Validation — input sanitization and normalization
- Session Management — register, read, find, cleanup
- Command Builders — construct socat command strings
- Launch Infrastructure — launch sessions, watchdog
- Mode Handlers — one per operational mode
- Help — per-mode help text
All validation functions return 0 on success, 1 on failure. They write normalized output to stdout where applicable.
validate_port <port>
# Returns: 0 if valid (1-65535, numeric), 1 if invalid
# Output: nonevalidate_port_range <range>
# Input: "8000-8010"
# Returns: 0 if valid (start < end, both valid ports, ≤1000 range), 1 if invalid
# Output: nonevalidate_port_list <list>
# Input: "8080,8081,8082" or "8080;8081;8082" (semicolons normalized to commas)
# Returns: 0 if at least one valid port, 1 if entirely invalid
# Output: cleaned, comma-separated list with invalid entries removedvalidate_hostname <host>
# Accepts: IPv4, IPv6, RFC 1123 hostnames
# Rejects: shell metacharacters (;|`$)
# Returns: 0 if valid, 1 if invalid
# Output: nonevalidate_protocol <proto>
# Input: tcp, tcp4, tcp6, udp, udp4, udp6 (case-insensitive)
# Returns: 0 if valid, 1 if invalid
# Output: normalized string (tcp → tcp4, udp → udp4)validate_socat_opts <opts>
# Whitelist: [a-zA-Z0-9=,.:/_-]
# Returns: 0 if safe, 1 if contains forbidden charactersvalidate_session_name <name>
# Whitelist: [a-zA-Z0-9._-], max 64 characters
# Returns: 0 if valid, 1 if invalidvalidate_file_path <path>
# Rejects: path traversal (..), shell metacharacters (;|`$)
# Returns: 0 if valid, 1 if invalid
# Output: nonevalidate_session_id <sid>
# Accepts: exactly 8 lowercase hex characters
# Returns: 0 if valid, 1 if invalid
# Output: nonegenerate_session_id
# Returns: 0 on success, 1 if collision limit exceeded
# Output: 8-character lowercase hex stringReads from /proc/sys/kernel/random/uuid, takes first 8 characters, lowercases. Retries up to 10 times on collision.
session_register <sid> <name> <pid> <pgid> <mode> <proto> <port> <socat_cmd> [rhost] [rport]
# Creates: sessions/<sid>.session with all metadata fields
# Permissions: 600 on the session file
# Returns: 0session_unregister <sid>
# Removes: sessions/<sid>.session, sessions/<sid>.stop, sessions/<sid>.launching
# Returns: 0 (idempotent — no error if files don't exist)session_read_field <sid> <field_name>
# Output: field value (empty string if field or file not found)
# Returns: 0
# Example: session_read_field "a1b2c3d4" "PID" → "12345"session_find_by_name <name>
# Output: space-separated list of matching session IDs
# Returns: 0session_find_by_port <port>
# Output: space-separated list of matching session IDs (may include both TCP and UDP)
# Returns: 0session_find_by_pid <pid>
# Output: matching session ID (or empty)
# Returns: 0session_is_alive <sid>
# Returns: 0 if PID from session file is running, 1 otherwisesession_get_all_ids
# Output: space-separated list of all registered session IDs
# Returns: 0session_cleanup_dead
# Removes session files for processes that are no longer running
# Output: log messages for each cleaned session
# Returns: 0Each builder constructs a socat command string. They do NOT execute it.
build_socat_listen_cmd <proto> <port> <logfile> [socat_opts] [capture]
# Output: complete socat command string
# Example output: "socat -v TCP4-LISTEN:8080,reuseaddr,fork OPEN:/tmp/log.txt,creat,append"build_socat_forward_cmd <proto> <lport> <rhost> <rport> [remote_proto] [capture]
# Output: complete socat command stringbuild_socat_tunnel_cmd <lport> <rhost> <rport> <cert> <key> [capture]
# Output: complete socat command string with SSL optionsbuild_socat_redirect_cmd <proto> <lport> <rhost> <rport> [capture]
# Output: complete socat command stringWhen capture is "true", the builder prepends -v to the socat command. This enables socat's verbose mode which produces bidirectional hex dump output on stderr.
launch_socat_session <name> <mode> <proto> <port> <socat_cmd> [rhost] [rport] [stderr_redirect]
# Sets: LAUNCH_SID global variable (session ID of the launched session)
# Creates: session file, PID staging file (cleaned up after launch)
# Returns: 0 on success, 1 on failureThis is the core launch function. It:
- Generates a session ID
- Creates a PID staging file
- Launches socat under
setsidwith PID-file handoff - Waits for the PID file to be written (up to 2 seconds)
- Registers the session with all metadata
- Sets
LAUNCH_SIDfor the caller
Important: Do NOT call this inside $() — it launches background processes. Use the LAUNCH_SID global variable instead.
get_alt_protocol <proto>
# Output: the "other" protocol (tcp4 → udp4, udp4 → tcp4, tcp6 → udp6, udp6 → tcp6)
# Returns: 0check_port_available <port> <proto>
# Returns: 0 if port is available, 1 if in use
# Uses: ss (preferred) or netstat (fallback)check_port_freed <port> <proto> [max_retries]
# Returns: 0 if port is freed, 1 if still in use after all retries
# Calls check_port_available in a retry loopTo add a new operational mode:
-
Create the mode handler function:
mode_mymode() { local port="" rhost="" ... # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in --port) port="$2"; shift 2 ;; --help|-h) show_mymode_help; return 0 ;; *) log_error "Unknown mymode option: $1"; return 1 ;; esac done # Validate inputs validate_port "${port}" || { log_error "Invalid port"; return 1; } # Build command local cmd cmd="$(build_socat_mymode_cmd ...)" # Launch launch_socat_session "mymode-${proto}-${port}" "mymode" "${proto}" "${port}" "${cmd}" }
-
Create the command builder:
build_socat_mymode_cmd() { ... echo "${cmd}"; }
-
Create the help function:
show_mymode_help() { cat << 'HELPEOF' ... HELPEOF }
-
Register in the main dispatcher (the
caseblock inmain()):mymode) mode_mymode "${@:2}" ;;
-
Add to main help (
show_main_help) -
Add tests in a new file or in
extended.bats -
Update documentation: README, USAGE_GUIDE, CHANGELOG, wiki
- Function headers: Every non-trivial function must have a comment block with Description, Parameters, Returns, and Output
-
Variable quoting: Quote every
${variable}expansion -
Error handling:
((count++)) || trueunderset -e -
No
$()for launch functions: Use global variables for functions that spawn background processes -
ShellCheck clean: No warnings at
--severity=warning
The menu system is implemented as a set of _menu_* functions that collect
and validate input, then call main() with the constructed argument array.
| Function | Purpose |
|---|---|
interactive_menu |
Root menu loop — displays options, dispatches to submenus |
_menu_listen, _menu_batch, etc. |
Per-mode submenus with guided input |
_menu_prompt |
Core input function — returns user input or _MENU_CANCEL on q/quit/cancel/back
|
_menu_prompt_port |
Port input with validation loop |
_menu_prompt_host |
Hostname input with validation loop |
_menu_prompt_protocol |
Protocol selection menu |
_menu_prompt_yn |
Yes/no prompt with default |
_menu_collect_common_flags |
Collects protocol, dual-stack, capture, watchdog, name for any mode |
_menu_check_deps |
Dependency checker with version detection |
All _menu_prompt* functions return exit code 2 on cancel. Submenus
catch code 2 and call _menu_cancelled to display feedback and return
to the root menu.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Expected failure (port in use, validation failed, session not found) |
| 2 | Usage error (missing required flag, unknown option) |
Socat Network Operations Manager · Repository · Releases · Report Bug · Request Feature · MIT License
Getting Started
Operations
Architecture
Development
Project