Add --config option and update config files

- Added --config FILE option to specify custom config file path
- Removed [wssht] section from wsssh.conf.example (legacy)
- Created separate wsssht.conf.example with wssht-specific options
- Updated man page with new --config option and mode options
- Updated usage message to include all new options
- Config file validation: errors if specified file doesn't exist
parent 2ed32275
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
# service = ssh # service = ssh
[wsssh] [wsssh]
# WebSocket SSH Daemon domain (used for hostname parsing) # WebSocket SSH Daemon domain (legacy, used for hostname parsing in wsssh)
domain = example.com domain = example.com
# Transport types for data channel (comma-separated or 'any') # Transport types for data channel (comma-separated or 'any')
......
# WebSocket SSH Tunnel (wsssht) Configuration Example # WebSocket SSH Tunnel (wsssht) Configuration Example
# #
# This is an example configuration file for wsssht. # This is an example configuration file for wsssht.
# Copy this file to ~/.config/wsssh/wssht.conf # Copy this file to ~/.config/wsssh/wsssht.conf and modify the settings as needed.
# and modify the settings as needed.
# #
# Configuration options: # Configuration options:
# wssshd-host: Default wssshd server hostname
# wssshd-port: Default wssshd server port [wssht]
# clientid: Default client ID for the tunnel # wssshd server hostname
# tunnel-port: Default local tunnel port (0 = auto-assign) wssshd-host = mbetter.nexlab.net
# tunnel-host: Local IP address to bind tunnel to (default: 127.0.0.1)
# tunnel: Default transport for data channel (comma-separated or 'any', or 'websocket') # Client ID for the tunnel
# tunnel-control: Default transport for control channel (comma-separated or 'any', or 'websocket') clientid = myclient
# service: Default service type (default: ssh)
# interval: Connection retry interval in seconds (default: 5) # Operating mode: interactive, silent, bridge, script
mode = interactive
wssshd-host=mbetter.nexlab.net
wssshd-port=9898 # Enable daemon mode (true/false)
clientid=myclient daemon = false
tunnel-port=0
tunnel-host=127.0.0.1 # Transport types for data channel (comma-separated or 'any')
tunnel=websocket # Available transports: websocket
tunnel-control=websocket tunnel = any
service=ssh
interval=5 # Transport types for control channel (comma-separated or 'any')
\ No newline at end of file # Only transports with is_relay=true can be used for control
tunnel-control = any
# Service type (default: ssh)
service = ssh
# Local tunnel host (default: 127.0.0.1)
tunnel-host = 127.0.0.1
# Connection retry interval in seconds (default: 5)
interval = 5
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
wsssht \- WebSocket SSH Tunnel Setup Tool wsssht \- WebSocket SSH Tunnel Setup Tool
.SH SYNOPSIS .SH SYNOPSIS
.B wsssht .B wsssht
[\fB\-\-config\fR \fIFILE\fR]
[\fB\-\-clientid\fR \fIID\fR] [\fB\-\-clientid\fR \fIID\fR]
[\fB\-\-tunnel\-port\fR \fIPORT\fR] [\fB\-\-tunnel\-port\fR \fIPORT\fR]
[\fB\-\-tunnel\-host\fR \fIHOST\fR] [\fB\-\-tunnel\-host\fR \fIHOST\fR]
...@@ -13,6 +14,11 @@ wsssht \- WebSocket SSH Tunnel Setup Tool ...@@ -13,6 +14,11 @@ wsssht \- WebSocket SSH Tunnel Setup Tool
[\fB\-\-tunnel\fR \fITRANSPORT\fR] [\fB\-\-tunnel\fR \fITRANSPORT\fR]
[\fB\-\-tunnel\-control\fR \fITYPES\fR] [\fB\-\-tunnel\-control\fR \fITYPES\fR]
[\fB\-\-service\fR \fISERVICE\fR] [\fB\-\-service\fR \fISERVICE\fR]
[\fB\-\-mode\fR \fIMODE\fR]
[\fB\-\-silent\fR]
[\fB\-\-bridge\fR]
[\fB\-\-script\fR]
[\fB\-\-daemon\fR]
[\fB\-\-help\fR] [\fB\-\-help\fR]
[\fIservice://\fR]\fIclientid\fR[\fI@wssshd-host\fR][\fI:wssshd-port\fR] [\fIservice://\fR]\fIclientid\fR[\fI@wssshd-host\fR][\fI:wssshd-port\fR]
.SH DESCRIPTION .SH DESCRIPTION
...@@ -27,6 +33,9 @@ and ...@@ -27,6 +33,9 @@ and
does not fork and execute external commands. Instead, it sets up the tunnel and displays connection instructions for manual use. does not fork and execute external commands. Instead, it sets up the tunnel and displays connection instructions for manual use.
.SH OPTIONS .SH OPTIONS
.TP .TP
.BR \-\-config " \fIFILE\fR"
Use custom config file (takes precedence over default)
.TP
.BR \-\-clientid " \fIID\fR" .BR \-\-clientid " \fIID\fR"
Specify the client ID for the tunnel (default: from config) Specify the client ID for the tunnel (default: from config)
.TP .TP
...@@ -57,6 +66,21 @@ Transport types for control channel (comma\-separated or 'any', default: any) ...@@ -57,6 +66,21 @@ Transport types for control channel (comma\-separated or 'any', default: any)
.BR \-\-service " \fISERVICE\fR" .BR \-\-service " \fISERVICE\fR"
Service type (default: ssh) Service type (default: ssh)
.TP .TP
.BR \-\-mode " \fIMODE\fR"
Operating mode: interactive, silent, bridge, script (default: interactive)
.TP
.BR \-\-silent
Shortcut for --mode silent
.TP
.BR \-\-bridge
Shortcut for --mode bridge
.TP
.BR \-\-script
Shortcut for --mode script
.TP
.BR \-\-daemon
Enable daemon mode for lazy initialization
.TP
.BR \-\-help .BR \-\-help
Display help message and exit Display help message and exit
.SH CONNECTION STRING FORMAT .SH CONNECTION STRING FORMAT
......
...@@ -52,6 +52,14 @@ extern volatile sig_atomic_t sigint_received; ...@@ -52,6 +52,14 @@ extern volatile sig_atomic_t sigint_received;
// SSL mutex for thread-safe SSL operations // SSL mutex for thread-safe SSL operations
extern pthread_mutex_t ssl_mutex; extern pthread_mutex_t ssl_mutex;
// Operating modes
typedef enum {
MODE_INTERACTIVE = 0, // Default: current functionality
MODE_SILENT, // Same as interactive but no output
MODE_BRIDGE, // JSON stdin/stdout bridge
MODE_SCRIPT // JSON protocol for scripting
} wsssh_mode_t;
// Config structures // Config structures
typedef struct { typedef struct {
char *local_port; char *local_port;
...@@ -65,6 +73,8 @@ typedef struct { ...@@ -65,6 +73,8 @@ typedef struct {
char *tunnel; // Transport types for data channel (comma-separated or "any") char *tunnel; // Transport types for data channel (comma-separated or "any")
char *tunnel_control; // Transport types for control channel (comma-separated or "any") char *tunnel_control; // Transport types for control channel (comma-separated or "any")
char *service; // Service type (default: "ssh") char *service; // Service type (default: "ssh")
wsssh_mode_t mode; // Operating mode
int daemon; // Daemon mode: lazy initialization
} wsssh_config_t; } wsssh_config_t;
typedef struct { typedef struct {
......
No preview for this file type
...@@ -45,6 +45,7 @@ void print_usage(const char *program_name) { ...@@ -45,6 +45,7 @@ void print_usage(const char *program_name) {
fprintf(stderr, "WebSocket SSH Tunnel - Setup WebSocket tunnels for manual connections\n\n"); fprintf(stderr, "WebSocket SSH Tunnel - Setup WebSocket tunnels for manual connections\n\n");
fprintf(stderr, "Protect the dolls!\n\n"); fprintf(stderr, "Protect the dolls!\n\n");
fprintf(stderr, "Options:\n"); fprintf(stderr, "Options:\n");
fprintf(stderr, " --config FILE Use custom config file (takes precedence over default)\n");
fprintf(stderr, " --clientid ID Client ID for the tunnel (default: from config)\n"); fprintf(stderr, " --clientid ID Client ID for the tunnel (default: from config)\n");
fprintf(stderr, " --tunnel-port PORT Local tunnel port (default: auto)\n"); fprintf(stderr, " --tunnel-port PORT Local tunnel port (default: auto)\n");
fprintf(stderr, " --tunnel-host HOST Local IP address to bind tunnel to (default: 127.0.0.1)\n"); fprintf(stderr, " --tunnel-host HOST Local IP address to bind tunnel to (default: 127.0.0.1)\n");
...@@ -55,12 +56,19 @@ void print_usage(const char *program_name) { ...@@ -55,12 +56,19 @@ void print_usage(const char *program_name) {
fprintf(stderr, " --tunnel TRANSPORT Transport for data channel (comma-separated or 'any', or 'websocket' default: any)\n"); fprintf(stderr, " --tunnel TRANSPORT Transport for data channel (comma-separated or 'any', or 'websocket' default: any)\n");
fprintf(stderr, " --tunnel-control TYPES Transport types for control channel (comma-separated or 'any', default: any)\n"); fprintf(stderr, " --tunnel-control TYPES Transport types for control channel (comma-separated or 'any', default: any)\n");
fprintf(stderr, " --service SERVICE Service type (default: ssh)\n"); fprintf(stderr, " --service SERVICE Service type (default: ssh)\n");
fprintf(stderr, " --mode MODE Operating mode: interactive, silent, bridge, script (default: interactive)\n");
fprintf(stderr, " --silent Shortcut for --mode silent\n");
fprintf(stderr, " --bridge Shortcut for --mode bridge\n");
fprintf(stderr, " --script Shortcut for --mode script\n");
fprintf(stderr, " --daemon Enable daemon mode for lazy initialization\n");
fprintf(stderr, " --help Show this help\n"); fprintf(stderr, " --help Show this help\n");
fprintf(stderr, "\nExamples:\n"); fprintf(stderr, "\nExamples:\n");
fprintf(stderr, " %s --clientid myclient --wssshd-host mbetter.nexlab.net\n", program_name); fprintf(stderr, " %s --clientid myclient --wssshd-host mbetter.nexlab.net\n", program_name);
fprintf(stderr, " %s myclient@mbetter.nexlab.net:9898\n", program_name); fprintf(stderr, " %s myclient@mbetter.nexlab.net:9898\n", program_name);
fprintf(stderr, " %s ssh://myclient@mbetter.nexlab.net\n", program_name); fprintf(stderr, " %s ssh://myclient@mbetter.nexlab.net\n", program_name);
fprintf(stderr, " %s --tunnel websocket myclient@mbetter.nexlab.net\n", program_name); fprintf(stderr, " %s --tunnel websocket myclient@mbetter.nexlab.net\n", program_name);
fprintf(stderr, " %s --silent myclient@mbetter.nexlab.net\n", program_name);
fprintf(stderr, " %s --daemon --clientid myclient --wssshd-host mbetter.nexlab.net\n", program_name);
fprintf(stderr, "\nDonations:\n"); fprintf(stderr, "\nDonations:\n");
fprintf(stderr, " BTC: bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx\n"); fprintf(stderr, " BTC: bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx\n");
fprintf(stderr, " ETH: 0xdA6dAb526515b5cb556d20269207D43fcc760E51\n"); fprintf(stderr, " ETH: 0xdA6dAb526515b5cb556d20269207D43fcc760E51\n");
...@@ -114,9 +122,13 @@ int parse_connection_string(const char *conn_str, char **service, char **client_ ...@@ -114,9 +122,13 @@ int parse_connection_string(const char *conn_str, char **service, char **client_
int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_argc, char ***remaining_argv) { int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_argc, char ***remaining_argv) {
// Parse wsssht options and optional connection string // Parse wsssht options and optional connection string
int target_start = -1; int target_start = -1;
char *custom_config = NULL;
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--clientid") == 0 && i + 1 < argc) { if (strcmp(argv[i], "--config") == 0 && i + 1 < argc) {
custom_config = strdup(argv[i + 1]);
i++; // Skip the argument
} else if (strcmp(argv[i], "--clientid") == 0 && i + 1 < argc) {
if (config->client_id) free(config->client_id); if (config->client_id) free(config->client_id);
config->client_id = strdup(argv[i + 1]); config->client_id = strdup(argv[i + 1]);
i++; // Skip the argument i++; // Skip the argument
...@@ -151,6 +163,29 @@ int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_ar ...@@ -151,6 +163,29 @@ int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_ar
i++; // Skip the argument i++; // Skip the argument
} else if (strcmp(argv[i], "--debug") == 0) { } else if (strcmp(argv[i], "--debug") == 0) {
config->debug = 1; config->debug = 1;
} else if (strcmp(argv[i], "--mode") == 0 && i + 1 < argc) {
if (strcmp(argv[i + 1], "interactive") == 0) {
config->mode = MODE_INTERACTIVE;
} else if (strcmp(argv[i + 1], "silent") == 0) {
config->mode = MODE_SILENT;
} else if (strcmp(argv[i + 1], "bridge") == 0) {
config->mode = MODE_BRIDGE;
} else if (strcmp(argv[i + 1], "script") == 0) {
config->mode = MODE_SCRIPT;
} else {
fprintf(stderr, "Error: Invalid mode: %s\n", argv[i + 1]);
print_usage(argv[0]);
return 0;
}
i++; // Skip the argument
} else if (strcmp(argv[i], "--daemon") == 0) {
config->daemon = 1;
} else if (strcmp(argv[i], "--silent") == 0) {
config->mode = MODE_SILENT;
} else if (strcmp(argv[i], "--bridge") == 0) {
config->mode = MODE_BRIDGE;
} else if (strcmp(argv[i], "--script") == 0) {
config->mode = MODE_SCRIPT;
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
print_usage(argv[0]); print_usage(argv[0]);
return 0; return 0;
...@@ -172,6 +207,21 @@ int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_ar ...@@ -172,6 +207,21 @@ int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_ar
} }
} }
// Handle custom config file if specified
if (custom_config) {
// TODO: Implement custom config file loading
// For now, just validate the file exists
FILE *test = fopen(custom_config, "r");
if (!test) {
fprintf(stderr, "Error: Config file not found: %s\n", custom_config);
free(custom_config);
return 0;
}
fclose(test);
fprintf(stderr, "Warning: Custom config file support not yet implemented\n");
free(custom_config);
}
// Handle connection string if present // Handle connection string if present
if (target_start != -1) { if (target_start != -1) {
char *service = NULL; char *service = NULL;
...@@ -224,17 +274,75 @@ int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_ar ...@@ -224,17 +274,75 @@ int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_ar
int run_bridge_mode(wsssh_config_t *config, const char *client_id, const char *wssshd_host, int wssshd_port) {
// Bridge mode: JSON messages to/from stdin/stdout
if (config->debug) {
printf("[DEBUG] Starting bridge mode\n");
fflush(stdout);
}
// TODO: Implement bridge mode
// - Establish websocket connection
// - Forward JSON messages from wssshd to stdout
// - Forward JSON messages from stdin to wssshd
// - Handle tunnel_data and tunnel_response messages
fprintf(stderr, "Bridge mode not yet implemented\n");
return 1;
}
int run_script_mode(wsssh_config_t *config, const char *client_id, const char *wssshd_host, int wssshd_port) {
// Script mode: JSON protocol for scripting
if (config->debug) {
printf("[DEBUG] Starting script mode\n");
fflush(stdout);
}
// TODO: Implement script mode
// - Establish websocket connection
// - Send JSON status messages to stdout
// - Accept JSON commands from stdin
// - Handle tunnel lifecycle events
fprintf(stderr, "Script mode not yet implemented\n");
return 1;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Read config from wsssht.conf // Read config from wsssht.conf
char *config_domain = read_config_value_from_file("wssshd-host", "wsssht"); char *config_domain = read_config_value_from_file("wssshd-host", "wsssht");
char *config_clientid = read_config_value_from_file("clientid", "wsssht"); char *config_clientid = read_config_value_from_file("clientid", "wsssht");
char *config_wssshd_port = read_config_value_from_file("wssshd-port", "wsssht"); char *config_wssshd_port = read_config_value_from_file("wssshd-port", "wsssht");
char *config_mode = read_config_value_from_file("mode", "wsssht");
char *config_daemon = read_config_value_from_file("daemon", "wsssht");
char *config_tunnel = read_config_value_from_file("tunnel", "wsssht"); char *config_tunnel = read_config_value_from_file("tunnel", "wsssht");
char *config_tunnel_control = read_config_value_from_file("tunnel-control", "wsssht"); char *config_tunnel_control = read_config_value_from_file("tunnel-control", "wsssht");
char *config_service = read_config_value_from_file("service", "wsssht"); char *config_service = read_config_value_from_file("service", "wsssht");
char *config_tunnel_host = read_config_value_from_file("tunnel-host", "wsssht"); char *config_tunnel_host = read_config_value_from_file("tunnel-host", "wsssht");
char *config_interval = read_config_value_from_file("interval", "wsssht"); char *config_interval = read_config_value_from_file("interval", "wsssht");
// Parse mode from config
wsssh_mode_t initial_mode = MODE_INTERACTIVE;
if (config_mode) {
if (strcmp(config_mode, "silent") == 0) {
initial_mode = MODE_SILENT;
} else if (strcmp(config_mode, "bridge") == 0) {
initial_mode = MODE_BRIDGE;
} else if (strcmp(config_mode, "script") == 0) {
initial_mode = MODE_SCRIPT;
}
free(config_mode);
}
// Parse daemon from config
int initial_daemon = 0;
if (config_daemon) {
if (strcmp(config_daemon, "true") == 0 || strcmp(config_daemon, "1") == 0) {
initial_daemon = 1;
}
free(config_daemon);
}
wsssh_config_t config = { wsssh_config_t config = {
.local_port = NULL, .local_port = NULL,
.tunnel_host = config_tunnel_host, .tunnel_host = config_tunnel_host,
...@@ -246,7 +354,9 @@ int main(int argc, char *argv[]) { ...@@ -246,7 +354,9 @@ int main(int argc, char *argv[]) {
.dev_tunnel = 0, .dev_tunnel = 0,
.tunnel = config_tunnel, .tunnel = config_tunnel,
.tunnel_control = config_tunnel_control, .tunnel_control = config_tunnel_control,
.service = config_service .service = config_service,
.mode = initial_mode,
.daemon = initial_daemon
}; };
// Set defaults if not provided // Set defaults if not provided
...@@ -273,6 +383,8 @@ int main(int argc, char *argv[]) { ...@@ -273,6 +383,8 @@ int main(int argc, char *argv[]) {
free(config_domain); free(config_domain);
free(config_clientid); free(config_clientid);
free(config_wssshd_port); free(config_wssshd_port);
free(config_mode);
free(config_daemon);
return 0; return 0;
} }
...@@ -283,12 +395,16 @@ int main(int argc, char *argv[]) { ...@@ -283,12 +395,16 @@ int main(int argc, char *argv[]) {
free(config_domain); free(config_domain);
free(config_clientid); free(config_clientid);
free(config_wssshd_port); free(config_wssshd_port);
free(config_mode);
free(config_daemon);
return 0; return 0;
} else if (strcmp(argv[i], "--free") == 0) { } else if (strcmp(argv[i], "--free") == 0) {
print_palestinian_flag(); print_palestinian_flag();
free(config_domain); free(config_domain);
free(config_clientid); free(config_clientid);
free(config_wssshd_port); free(config_wssshd_port);
free(config_mode);
free(config_daemon);
return 0; return 0;
} }
} }
...@@ -348,6 +464,14 @@ int main(int argc, char *argv[]) { ...@@ -348,6 +464,14 @@ int main(int argc, char *argv[]) {
fflush(stdout); fflush(stdout);
} }
// Handle different operating modes
if (config.mode == MODE_BRIDGE) {
return run_bridge_mode(&config, client_id, wssshd_host, wssshd_port);
} else if (config.mode == MODE_SCRIPT) {
return run_script_mode(&config, client_id, wssshd_host, wssshd_port);
}
// MODE_INTERACTIVE and MODE_SILENT continue with normal flow
// Find available local port // Find available local port
int local_port = config.local_port ? atoi(config.local_port) : find_available_port(); int local_port = config.local_port ? atoi(config.local_port) : find_available_port();
if (local_port == 0) { if (local_port == 0) {
...@@ -401,35 +525,37 @@ int main(int argc, char *argv[]) { ...@@ -401,35 +525,37 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
// Print tunnel information and connection instructions // Print tunnel information and connection instructions (unless silent mode)
printf("\n"); if (config.mode != MODE_SILENT) {
printf("========================================\n"); printf("\n");
printf(" WEBSSH TUNNEL READY\n"); printf("========================================\n");
printf("========================================\n"); printf(" WEBSSH TUNNEL READY\n");
printf("Tunnel established successfully!\n"); printf("========================================\n");
printf("Local port: %d\n", local_port); printf("Tunnel established successfully!\n");
printf("Target: %s@%s\n", client_id, wssshd_host); printf("Local port: %d\n", local_port);
printf("\n"); printf("Target: %s@%s\n", client_id, wssshd_host);
printf("Connect manually using one of these commands:\n"); printf("\n");
printf("\n"); printf("Connect manually using one of these commands:\n");
printf(" Telnet:\n"); printf("\n");
printf(" telnet localhost %d\n", local_port); printf(" Telnet:\n");
printf("\n"); printf(" telnet localhost %d\n", local_port);
printf(" Netcat:\n"); printf("\n");
printf(" nc localhost %d\n", local_port); printf(" Netcat:\n");
printf("\n"); printf(" nc localhost %d\n", local_port);
printf(" SSH (if connecting to SSH server):\n"); printf("\n");
printf(" ssh -p %d user@localhost\n", local_port); printf(" SSH (if connecting to SSH server):\n");
printf("\n"); printf(" ssh -p %d user@localhost\n", local_port);
printf(" SCP (if connecting to SSH server):\n"); printf("\n");
printf(" scp -P %d user@localhost:/remote/path ./local/path\n", local_port); printf(" SCP (if connecting to SSH server):\n");
printf("\n"); printf(" scp -P %d user@localhost:/remote/path ./local/path\n", local_port);
printf(" Any TCP client:\n"); printf("\n");
printf(" Connect to localhost:%d\n", local_port); printf(" Any TCP client:\n");
printf("\n"); printf(" Connect to localhost:%d\n", local_port);
printf("Press Ctrl+C to close the tunnel and exit.\n"); printf("\n");
printf("========================================\n"); printf("Press Ctrl+C to close the tunnel and exit.\n");
printf("\n"); printf("========================================\n");
printf("\n");
}
// Start forwarding threads to handle bidirectional communication // Start forwarding threads to handle bidirectional communication
// Parent process: accept connection and start forwarding // Parent process: accept connection and start forwarding
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment