Refactor wsssht: remove user@domain parsing, add --clientid and --wssshd-port options

- Remove parsing of user@domain format from wsssht
- Add --clientid option for specifying client ID
- Add --wssshd-port option (replacing -p/--port)
- Update wssshd-host default to mbetter.nexlab.net
- Add client_id field to wsssh_config_t struct
- Update config reading to include clientid and wssshd-port
- Update wssht.conf.example with new options
- Update man page wsssht.1 with new options and examples
- Ensure --wssshd-host is required if not in config
- Update all usage messages and documentation
parent 42365291
......@@ -5,21 +5,19 @@
# and modify the settings as needed.
#
# Configuration options:
# port: Default WebSocket server port
# domain: Default domain suffix for hostname parsing
# tunnel-port: Local tunnel port (0 = auto)
# tunnel-host: Local IP address to bind tunnel to (default: 127.0.0.1)
# wssshd-host: Default wssshd server hostname
# clientid: Default client ID for the tunnel
# tunnel: Default transport types for data channel (comma-separated or 'any')
# tunnel-control: Default transport types for control channel (comma-separated or 'any')
# service: Default service type (default: ssh)
# tunnel-host: Local IP address to bind tunnel to (default: 127.0.0.1)
# interval: Connection retry interval in seconds (default: 5)
[default]
port=9898
domain=example.com
tunnel-port=0
tunnel-host=127.0.0.1
wssshd-host=mbetter.nexlab.net
wssshd-port=9898
clientid=myclient
tunnel=websocket
tunnel-control=websocket
service=ssh
tunnel-host=127.0.0.1
interval=5
\ No newline at end of file
......@@ -9,6 +9,17 @@
# tunnel-control = websocket
# service = ssh
# WebSocket SSH (wsssh) Configuration Example
#
# This is an example configuration file for wsssh.
# Copy this file to ~/.config/wsssh/wsssh.conf and modify the settings as needed.
#
# Configuration options:
# domain = wssshd.example.com
# tunnel = websocket
# tunnel-control = websocket
# service = ssh
[wsssh]
# WebSocket SSH Daemon domain (used for hostname parsing)
domain = example.com
......
......@@ -58,12 +58,12 @@ LDFLAGS = $(shell pkg-config --libs openssl)
# Source files
LIB_SRCS = wssshlib.c websocket.c wssh_ssl.c tunnel.c
LIB_OBJS = $(LIB_SRCS:.c=.o)
SRCS = wssshc.c wsssh.c wsscp.c
SRCS = wssshc.c wsssh.c wsscp.c wsssht.c
OBJS = $(SRCS:.c=.o)
TARGETS = wssshc wsssh wsscp
TARGETS = wssshc wsssh wsscp wsssht
# Man pages
MANPAGES = man/wssshc.1 man/wsssh.1 man/wsscp.1
MANPAGES = man/wssshc.1 man/wsssh.1 man/wsscp.1 man/wsssht.1
# Default target
all: $(TARGETS)
......@@ -78,6 +78,9 @@ wsssh: wsssh.o $(LIB_OBJS)
wsscp: wsscp.o $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
wsssht: wsssht.o $(LIB_OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
# Object files
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
......@@ -107,15 +110,19 @@ uninstall:
rm -f $(DESTDIR)/usr/local/bin/wssshc
rm -f $(DESTDIR)/usr/local/bin/wsssh
rm -f $(DESTDIR)/usr/local/bin/wsscp
rm -f $(DESTDIR)/usr/local/bin/wsssht
rm -f $(DESTDIR)/usr/local/share/man/man1/wssshc.1
rm -f $(DESTDIR)/usr/local/share/man/man1/wsssh.1
rm -f $(DESTDIR)/usr/local/share/man/man1/wsscp.1
rm -f $(DESTDIR)/usr/local/share/man/man1/wsssht.1
rm -f $(DESTDIR)/usr/bin/wssshc
rm -f $(DESTDIR)/usr/bin/wsssh
rm -f $(DESTDIR)/usr/bin/wsscp
rm -f $(DESTDIR)/usr/bin/wsssht
rm -f $(DESTDIR)/usr/share/man/man1/wssshc.1
rm -f $(DESTDIR)/usr/share/man/man1/wsssh.1
rm -f $(DESTDIR)/usr/share/man/man1/wsscp.1
rm -f $(DESTDIR)/usr/share/man/man1/wsssht.1
.PHONY: all clean install uninstall
EOF
......
......@@ -3,16 +3,17 @@
wsssht \- WebSocket SSH Tunnel Setup Tool
.SH SYNOPSIS
.B wsssht
[\fB\-\-local\-port\fR \fIPORT\fR]
[\fB\-\-clientid\fR \fIID\fR]
[\fB\-\-tunnel\-port\fR \fIPORT\fR]
[\fB\-\-tunnel\-host\fR \fIHOST\fR]
[\fB\-\-wssshd\-host\fR \fIHOST\fR]
[\fB\-\-wssshd\-port\fR \fIPORT\fR]
[\fB\-\-interval\fR \fISEC\fR]
[\fB\-\-debug\fR]
[\fB\-\-tunnel\fR \fITYPES\fR]
[\fB\-\-tunnel\-control\fR \fITYPES\fR]
[\fB\-\-service\fR \fISERVICE\fR]
[\fB\-\-help\fR]
[\fB\-p\fR \fIPORT\fR]
[\fB\-\-port\fR \fIPORT\fR]
\fIuser\fR@\fIclient\fR.\fIdomain\fR
.SH DESCRIPTION
.B wsssht
is a WebSocket SSH tunnel setup tool that establishes secure tunnels through WebSocket connections without automatically executing SSH/SCP commands. It provides connection information for manual use with any TCP client.
......@@ -25,12 +26,18 @@ and
does not fork and execute external commands. Instead, it sets up the tunnel and displays connection instructions for manual use.
.SH OPTIONS
.TP
.BR \-\-clientid " \fIID\fR"
Specify the client ID for the tunnel (default: from config)
.TP
.BR \-\-tunnel\-port " \fIPORT\fR"
Specify the local port for the tunnel (default: auto\-assigned)
.TP
.BR \-\-tunnel\-host " \fIHOST\fR"
Specify the local IP address to bind the tunnel to (default: 127.0.0.1)
.TP
.BR \-\-wssshd\-host " \fIHOST\fR"
Specify the wssshd server hostname (required if not in config)
.TP
.BR \-\-interval " \fISEC\fR"
Connection retry interval in seconds (default: 5)
.TP
......@@ -49,21 +56,21 @@ Service type (default: ssh)
.BR \-\-help
Display help message and exit
.TP
.BR \-p ", " \-\-port " \fIPORT\fR"
.BR \-\-wssshd\-port " \fIPORT\fR"
WebSocket SSH daemon server port (default: 9898)
.SH EXAMPLES
.TP
Basic tunnel setup:
.B wsssht user@myclient.example.com
.B wsssht \-\-clientid myclient \-\-wssshd\-host mbetter.nexlab.net \-\-wssshd\-port 9898
.TP
Specify local port:
.B wsssht \-\-tunnel\-port 2222 user@myclient.example.com
.B wsssht \-\-tunnel\-port 2222 \-\-clientid myclient \-\-wssshd\-host mbetter.nexlab.net
.TP
Use specific transport:
.B wsssht \-\-tunnel websocket user@myclient.example.com
.B wsssht \-\-tunnel websocket \-\-clientid myclient \-\-wssshd\-host mbetter.nexlab.net
.TP
Debug mode:
.B wsssht \-\-debug user@myclient.example.com
.B wsssht \-\-debug \-\-clientid myclient \-\-wssshd\-host mbetter.nexlab.net
.SH MANUAL CONNECTION
Once the tunnel is established,
.B wsssht
......@@ -76,7 +83,7 @@ displays connection information:
========================================
Tunnel established successfully!
Local port: 49234
Target: user@myclient.example.com
Target: myclient@mbetter.nexlab.net
Connect manually using one of these commands:
......@@ -101,19 +108,20 @@ Press Ctrl+C to close the tunnel and exit.
.RE
.SH CONFIGURATION
.B wsssht
supports a separate configuration file at
supports a configuration file at
.I ~/.config/wsssh/wssht.conf
with the following options:
.PP
.RS
.nf
[default]
port=9898
domain=example.com
wssshd-host=mbetter.nexlab.net
wssshd-port=9898
clientid=myclient
tunnel=websocket
tunnel-control=websocket
service=ssh
interval=30
tunnel-host=127.0.0.1
interval=5
.fi
.RE
.PP
......
......@@ -1015,7 +1015,7 @@ int reconnect_websocket(tunnel_t *tunnel, const char *wssshd_host, int wssshd_po
return 0;
}
int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id, int local_port, int debug, int use_buffer) {
int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id, int local_port, int debug, int use_buffer, const char *tunnel_host) {
struct sockaddr_in server_addr;
struct hostent *he;
int sock;
......@@ -1292,7 +1292,30 @@ int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(local_port);
local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
// Use specified tunnel_host or default to 127.0.0.1
if (tunnel_host && strcmp(tunnel_host, "127.0.0.1") != 0) {
// Resolve the tunnel_host
struct hostent *tunnel_he;
if ((tunnel_he = gethostbyname(tunnel_host)) == NULL) {
if (debug) {
fprintf(stderr, "[DEBUG] Failed to resolve tunnel_host '%s', using 127.0.0.1\n", tunnel_host);
}
local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
} else {
local_addr.sin_addr = *((struct in_addr *)tunnel_he->h_addr);
if (debug) {
printf("[DEBUG] Binding tunnel to %s:%d\n", tunnel_host, local_port);
fflush(stdout);
}
}
} else {
local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (debug) {
printf("[DEBUG] Binding tunnel to 127.0.0.1:%d\n", local_port);
fflush(stdout);
}
}
if (bind(listen_sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
perror("Local bind failed");
......
......@@ -76,7 +76,7 @@ void handle_tunnel_close(SSL *ssl, const char *request_id, int debug);
void send_tunnel_close(SSL *ssl, const char *request_id, int debug);
void cleanup_tunnel(int debug);
int reconnect_websocket(tunnel_t *tunnel, const char *wssshd_host, int wssshd_port, const char *client_id, const char *request_id, int debug);
int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id, int local_port, int debug, int use_buffer);
int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id, int local_port, int debug, int use_buffer, const char *tunnel_host);
// CPU affinity functions
void init_cpu_affinity(void);
......
......@@ -422,7 +422,7 @@ int main(int argc, char *argv[]) {
fflush(stdout);
}
listen_sock = setup_tunnel(wssshd_host, wssshd_port, client_id, local_port, config.debug, 1);
listen_sock = setup_tunnel(wssshd_host, wssshd_port, client_id, local_port, config.debug, 1, NULL);
if (listen_sock < 0) {
setup_attempts++;
......
......@@ -405,7 +405,7 @@ int main(int argc, char *argv[]) {
fflush(stdout);
}
listen_sock = setup_tunnel(wssshd_host, wssshd_port, client_id, local_port, config.debug, 0);
listen_sock = setup_tunnel(wssshd_host, wssshd_port, client_id, local_port, config.debug, 0, NULL);
if (listen_sock < 0) {
setup_attempts++;
......
......@@ -55,6 +55,9 @@ extern pthread_mutex_t ssl_mutex;
// Config structures
typedef struct {
char *local_port;
char *tunnel_host; // Local IP address to bind tunnel to (default: 127.0.0.1)
char *wssshd_host; // wssshd server hostname
char *client_id; // Client ID for the tunnel
int wssshd_port; // wssshd server port
int debug;
int interval; // Reconnection interval in seconds
......
......@@ -41,24 +41,25 @@
void print_usage(const char *program_name) {
fprintf(stderr, "Usage: %s [options] user@client.domain\n", program_name);
fprintf(stderr, "Usage: %s [options]\n", program_name);
fprintf(stderr, "WebSocket SSH Tunnel - Setup WebSocket tunnels for manual connections\n\n");
fprintf(stderr, "Protect the dolls!\n\n");
fprintf(stderr, "Options:\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-host HOST Local IP address to bind tunnel to (default: 127.0.0.1)\n");
fprintf(stderr, " --wssshd-host HOST wssshd server hostname (required if not in config)\n");
fprintf(stderr, " --interval SEC Connection retry interval in seconds (default: 5)\n");
fprintf(stderr, " --debug Enable debug output\n");
fprintf(stderr, " --tunnel TYPES Transport types for data 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, " --help Show this help\n");
fprintf(stderr, " -p PORT wssshd server port (default: 9898)\n");
fprintf(stderr, " --port PORT Same as -p\n");
fprintf(stderr, " --wssshd-port PORT wssshd server port (default: 9898)\n");
fprintf(stderr, "\nExamples:\n");
fprintf(stderr, " %s user@myclient.example.com -p 9898\n", program_name);
fprintf(stderr, " %s --tunnel-port 2222 user@myclient.example.com\n", program_name);
fprintf(stderr, " %s --tunnel websocket --debug user@myclient.example.com\n", program_name);
fprintf(stderr, " %s --clientid myclient --wssshd-host mbetter.nexlab.net --wssshd-port 9898\n", program_name);
fprintf(stderr, " %s --tunnel-port 2222 --clientid myclient --wssshd-host mbetter.nexlab.net\n", program_name);
fprintf(stderr, " %s --tunnel websocket --debug --clientid myclient --wssshd-host mbetter.nexlab.net\n", program_name);
fprintf(stderr, "\nDonations:\n");
fprintf(stderr, " BTC: bc1q3zlkpu95amtcltsk85y0eacyzzk29v68tgc5hx\n");
fprintf(stderr, " ETH: 0xdA6dAb526515b5cb556d20269207D43fcc760E51\n");
......@@ -69,17 +70,22 @@ int parse_args(int argc, char *argv[], wsssh_config_t *config, int *remaining_ar
int target_start = 1; // Skip argv[0]
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--tunnel-port") == 0 && i + 1 < argc) {
if (strcmp(argv[i], "--clientid") == 0 && i + 1 < argc) {
if (config->client_id) free(config->client_id);
config->client_id = strdup(argv[i + 1]);
i++; // Skip the argument
} else if (strcmp(argv[i], "--tunnel-port") == 0 && i + 1 < argc) {
config->local_port = strdup(argv[i + 1]);
i++; // Skip the argument
} else if (strcmp(argv[i], "--tunnel-host") == 0 && i + 1 < argc) {
if (config->tunnel_host) free(config->tunnel_host);
config->tunnel_host = strdup(argv[i + 1]);
i++; // Skip the argument
} else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
config->wssshd_port = atoi(argv[i + 1]);
} else if (strcmp(argv[i], "--wssshd-host") == 0 && i + 1 < argc) {
if (config->wssshd_host) free(config->wssshd_host);
config->wssshd_host = strdup(argv[i + 1]);
i++; // Skip the argument
} else if (strcmp(argv[i], "--port") == 0 && i + 1 < argc) {
} else if (strcmp(argv[i], "--wssshd-port") == 0 && i + 1 < argc) {
config->wssshd_port = atoi(argv[i + 1]);
i++; // Skip the argument
} else if (strcmp(argv[i], "--interval") == 0 && i + 1 < argc) {
......@@ -188,7 +194,9 @@ int parse_target_args(int argc, char *argv[], char **host, int debug) {
int main(int argc, char *argv[]) {
// Read config from wssht.conf
char *config_domain = read_config_value_from_file("domain", "wssht");
char *config_domain = read_config_value_from_file("wssshd-host", "wssht");
char *config_clientid = read_config_value_from_file("clientid", "wssht");
char *config_wssshd_port = read_config_value_from_file("wssshd-port", "wssht");
char *config_tunnel = read_config_value_from_file("tunnel", "wssht");
char *config_tunnel_control = read_config_value_from_file("tunnel-control", "wssht");
char *config_service = read_config_value_from_file("service", "wssht");
......@@ -198,7 +206,9 @@ int main(int argc, char *argv[]) {
wsssh_config_t config = {
.local_port = NULL,
.tunnel_host = config_tunnel_host,
.wssshd_port = 9898,
.wssshd_host = config_domain,
.client_id = config_clientid,
.wssshd_port = config_wssshd_port ? atoi(config_wssshd_port) : 9898,
.debug = 0,
.interval = 5,
.dev_tunnel = 0,
......@@ -229,6 +239,8 @@ int main(int argc, char *argv[]) {
if (argc == 2 && strcmp(argv[1], "--support") == 0) {
print_trans_flag();
free(config_domain);
free(config_clientid);
free(config_wssshd_port);
return 0;
}
......@@ -237,10 +249,14 @@ int main(int argc, char *argv[]) {
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
print_usage(argv[0]);
free(config_domain);
free(config_clientid);
free(config_wssshd_port);
return 0;
} else if (strcmp(argv[i], "--free") == 0) {
print_palestinian_flag();
free(config_domain);
free(config_clientid);
free(config_wssshd_port);
return 0;
}
}
......@@ -257,35 +273,43 @@ int main(int argc, char *argv[]) {
return 1;
}
// Need at least one target argument
if (remaining_argc == 0) {
fprintf(stderr, "Error: No target specified\n");
// No positional arguments expected
if (remaining_argc > 0) {
fprintf(stderr, "Error: Unexpected arguments\n");
print_usage(argv[0]);
pthread_mutex_destroy(&tunnel_mutex);
free(config_domain);
free(config_clientid);
free(config_wssshd_port);
return 1;
}
// Parse target arguments to extract host
char *target_host = NULL;
if (!parse_target_args(remaining_argc, remaining_argv, &target_host, config.debug)) {
// Check if client_id and wssshd_host are provided
if (!config.client_id) {
fprintf(stderr, "Error: Client ID not specified. Use --clientid or set in config\n");
print_usage(argv[0]);
pthread_mutex_destroy(&tunnel_mutex);
free(config_domain);
free(config_clientid);
free(config_wssshd_port);
return 1;
}
// Parse the target host to extract client_id and wssshd_host
char *client_id = NULL;
char *wssshd_host = NULL;
int wssshd_port = config.wssshd_port;
if (!parse_hostname(target_host, &client_id, &wssshd_host, config_domain)) {
if (!config.wssshd_host) {
fprintf(stderr, "Error: wssshd host not specified. Use --wssshd-host or set in config\n");
print_usage(argv[0]);
pthread_mutex_destroy(&tunnel_mutex);
free(config_domain);
free(config_clientid);
free(config_wssshd_port);
return 1;
}
char *client_id = config.client_id;
char *wssshd_host = config.wssshd_host;
int wssshd_port = config.wssshd_port;
if (config.debug) {
printf("[DEBUG - Tunnel] Target Host: %s\n", target_host);
printf("[DEBUG - Tunnel] Client ID: %s\n", client_id);
printf("[DEBUG - Tunnel] WSSSHD Host: %s\n", wssshd_host);
printf("[DEBUG - Tunnel] WSSSHD Port: %d\n", wssshd_port);
......@@ -296,8 +320,6 @@ int main(int argc, char *argv[]) {
int local_port = config.local_port ? atoi(config.local_port) : find_available_port();
if (local_port == 0) {
fprintf(stderr, "Error: Could not find available local port\n");
free(client_id);
free(wssshd_host);
free(config.local_port);
free(config.tunnel_host);
pthread_mutex_destroy(&tunnel_mutex);
......@@ -342,8 +364,6 @@ int main(int argc, char *argv[]) {
if (listen_sock < 0) {
fprintf(stderr, "Error: Failed to establish tunnel after %d attempts\n", max_setup_attempts);
free(client_id);
free(wssshd_host);
free(config.local_port);
pthread_mutex_destroy(&tunnel_mutex);
return 1;
......@@ -394,8 +414,6 @@ int main(int argc, char *argv[]) {
close(listen_sock);
free(active_tunnel);
active_tunnel = NULL;
free(client_id);
free(wssshd_host);
free(config.local_port);
pthread_mutex_destroy(&tunnel_mutex);
return 1;
......@@ -442,8 +460,6 @@ int main(int argc, char *argv[]) {
close(active_tunnel->local_sock);
free(active_tunnel);
active_tunnel = NULL;
free(client_id);
free(wssshd_host);
free(config.local_port);
pthread_mutex_destroy(&tunnel_mutex);
return 1;
......@@ -864,13 +880,13 @@ cleanup_and_exit:
active_tunnel = NULL;
}
free(client_id);
free(wssshd_host);
free(config.local_port);
free(config.tunnel);
free(config.tunnel_control);
free(config.service);
free(config_domain);
free(config_clientid);
free(config_wssshd_port);
free(config_tunnel);
free(config_tunnel_control);
free(config_service);
......
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