Correct wssshc architecture - wssshc acts as SSH client, not SSH server

- Fixed fundamental misunderstanding of wssshc's role in the architecture
- wssshc now acts as SSH client connecting to target SSH server (localhost:22)
- Removed incorrect SSH server implementation that was listening for connections
- Implemented proper SSH client connection in handle_tunnel_request()
- Added forward_ws_to_ssh_server() for bidirectional forwarding
- Removed handle_ssh_server_connection() and related SSH server functions
- Fixed handle_tunnel_data() to send data directly to SSH server connection
- Eliminated need for data buffering since wssshc connects directly to SSH server
- Corrected tunnel flow: WebSocket → wssshc → SSH server (not SSH server → wssshc)
- Fixed socket management for direct SSH server connection
- Resolved 'waiting for SSH connection' issue by removing server listening code
- Implemented proper SSH client architecture matching original design intent
- Fixed race conditions by establishing SSH connection immediately on tunnel_request
- Removed unnecessary complexity from SSH server mode implementation
- Streamlined code by removing unused SSH server connection handling
- Fixed data flow to match intended architecture: wssshc receives from tunnel, forwards to SSH server
- Eliminated port binding conflicts by not listening on SSH port
- Corrected bidirectional forwarding between WebSocket and SSH server connection
parent 31c7eed6
...@@ -110,69 +110,42 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) { ...@@ -110,69 +110,42 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
return; return;
} }
// For wssshc: Act as SSH server - listen for SSH client connections // For wssshc: Act as SSH client - connect to target SSH server
// Use a high port to avoid conflicts with system SSH server struct sockaddr_in target_addr;
int ssh_port = find_available_port(); int ssh_sock = socket(AF_INET, SOCK_STREAM, 0);
if (ssh_port == 0) { if (ssh_sock < 0) {
fprintf(stderr, "Could not find available port for SSH server\n"); perror("SSH socket creation failed");
free(active_tunnel);
active_tunnel = NULL;
pthread_mutex_unlock(&tunnel_mutex);
return;
}
struct sockaddr_in local_addr;
int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sock < 0) {
perror("Listen socket creation failed");
free(active_tunnel); free(active_tunnel);
active_tunnel = NULL; active_tunnel = NULL;
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
return; return;
} }
memset(&local_addr, 0, sizeof(local_addr)); memset(&target_addr, 0, sizeof(target_addr));
local_addr.sin_family = AF_INET; target_addr.sin_family = AF_INET;
local_addr.sin_port = htons(ssh_port); target_addr.sin_port = htons(22); // Target SSH port
local_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); target_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // Target SSH host
if (bind(listen_sock, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
perror("Bind to available port failed");
close(listen_sock);
free(active_tunnel);
active_tunnel = NULL;
pthread_mutex_unlock(&tunnel_mutex);
return;
}
if (listen(listen_sock, 1) < 0) { if (connect(ssh_sock, (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) {
perror("Listen failed"); perror("Connection to target SSH server failed");
close(listen_sock); close(ssh_sock);
free(active_tunnel); free(active_tunnel);
active_tunnel = NULL; active_tunnel = NULL;
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
return; return;
} }
active_tunnel->sock = -1; // Will be set when SSH client connects active_tunnel->sock = ssh_sock; // SSH client connection to target
active_tunnel->local_sock = listen_sock; // Store listening socket active_tunnel->local_sock = -1; // Not used in wssshc
strcpy(active_tunnel->request_id, request_id); strcpy(active_tunnel->request_id, request_id);
active_tunnel->active = 1; active_tunnel->active = 1;
active_tunnel->ssl = ssl; active_tunnel->ssl = ssl;
active_tunnel->outgoing_buffer = NULL; // wssshc doesn't use buffer active_tunnel->outgoing_buffer = NULL; // wssshc doesn't use buffer
active_tunnel->incoming_buffer = frame_buffer_init(); // Buffer for data before SSH client connects active_tunnel->incoming_buffer = NULL; // wssshc doesn't need incoming buffer
if (!active_tunnel->incoming_buffer) {
perror("Failed to initialize incoming buffer");
close(listen_sock);
free(active_tunnel);
active_tunnel = NULL;
pthread_mutex_unlock(&tunnel_mutex);
return;
}
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
if (debug) { if (debug) {
printf("[DEBUG] wssshc listening for SSH connections on port %d\n", ssh_port); printf("[DEBUG] wssshc connected to target SSH server\n");
} }
// Send tunnel_ack back to server // Send tunnel_ack back to server
...@@ -188,14 +161,14 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) { ...@@ -188,14 +161,14 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
return; return;
} }
// Start thread to accept SSH connections and handle the tunnel // Start bidirectional forwarding between WebSocket and SSH server
thread_args_t *thread_args = malloc(sizeof(thread_args_t)); thread_args_t *thread_args = malloc(sizeof(thread_args_t));
if (thread_args) { if (thread_args) {
thread_args->ssl = ssl; thread_args->ssl = ssl;
thread_args->debug = debug; thread_args->debug = debug;
pthread_t thread; pthread_t thread;
pthread_create(&thread, NULL, handle_ssh_server_connection, thread_args); pthread_create(&thread, NULL, forward_ws_to_ssh_server, thread_args);
pthread_detach(thread); pthread_detach(thread);
} }
} }
...@@ -362,203 +335,8 @@ void *forward_tcp_to_ws(void *arg) { ...@@ -362,203 +335,8 @@ void *forward_tcp_to_ws(void *arg) {
return NULL; return NULL;
} }
void *handle_ssh_server_connection(void *arg) {
thread_args_t *args = (thread_args_t *)arg;
SSL *ssl = args->ssl;
int debug = args->debug;
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
if (debug) {
printf("[DEBUG] Waiting for SSH client connection...\n");
fflush(stdout);
}
// Accept SSH client connection
int ssh_client_sock = accept(active_tunnel->local_sock, (struct sockaddr *)&client_addr, &client_len);
if (ssh_client_sock < 0) {
if (debug) {
perror("[DEBUG] Accept SSH client connection failed");
fflush(stdout);
}
free(args);
return NULL;
}
if (debug) {
printf("[DEBUG] SSH client connected, connecting to target SSH server...\n");
fflush(stdout);
}
// Now connect to the target SSH server
struct sockaddr_in target_addr;
int target_sock = socket(AF_INET, SOCK_STREAM, 0);
if (target_sock < 0) {
perror("Target SSH socket creation failed");
close(ssh_client_sock);
free(args);
return NULL;
}
memset(&target_addr, 0, sizeof(target_addr));
target_addr.sin_family = AF_INET;
target_addr.sin_port = htons(22); // Target SSH port
target_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // Target SSH host
if (connect(target_sock, (struct sockaddr *)&target_addr, sizeof(target_addr)) < 0) {
perror("Connection to target SSH server failed");
close(ssh_client_sock);
close(target_sock);
free(args);
return NULL;
}
// Store both sockets
pthread_mutex_lock(&tunnel_mutex);
active_tunnel->sock = ssh_client_sock; // SSH client connection
active_tunnel->local_sock = target_sock; // Target SSH server connection
// Send any buffered data to the SSH client
if (active_tunnel->incoming_buffer && active_tunnel->incoming_buffer->used > 0) {
if (debug) {
printf("[DEBUG] Sending %zu bytes of buffered data to SSH client\n", active_tunnel->incoming_buffer->used);
fflush(stdout);
}
ssize_t sent = send(ssh_client_sock, active_tunnel->incoming_buffer->buffer, active_tunnel->incoming_buffer->used, 0);
if (sent > 0) {
frame_buffer_consume(active_tunnel->incoming_buffer, sent);
if (debug) {
printf("[DEBUG] Sent %zd bytes of buffered data to SSH client\n", sent);
fflush(stdout);
}
}
}
pthread_mutex_unlock(&tunnel_mutex);
if (debug) {
printf("[DEBUG] Connected to target SSH server, starting bidirectional forwarding\n");
fflush(stdout);
}
// Start bidirectional forwarding between SSH client and target SSH server
thread_args_t *forward_args = malloc(sizeof(thread_args_t));
if (forward_args) {
forward_args->ssl = ssl;
forward_args->debug = debug;
pthread_t thread;
pthread_create(&thread, NULL, forward_ssh_client_to_target, forward_args);
pthread_detach(thread);
}
free(args);
return NULL;
}
void *forward_ssh_client_to_target(void *arg) {
thread_args_t *args = (thread_args_t *)arg;
SSL *ssl = args->ssl;
int debug = args->debug;
char buffer[BUFFER_SIZE];
int bytes_read;
fd_set readfds;
struct timeval tv;
while (1) {
pthread_mutex_lock(&tunnel_mutex);
if (!active_tunnel || !active_tunnel->active) {
pthread_mutex_unlock(&tunnel_mutex);
break;
}
int ssh_client_sock = active_tunnel->sock;
int target_sock = active_tunnel->local_sock;
char request_id[37];
strcpy(request_id, active_tunnel->request_id);
pthread_mutex_unlock(&tunnel_mutex);
// Use select to wait for data on either socket
FD_ZERO(&readfds);
FD_SET(ssh_client_sock, &readfds);
FD_SET(target_sock, &readfds);
tv.tv_sec = 0;
tv.tv_usec = 50000; // 50ms timeout
int max_fd = (ssh_client_sock > target_sock) ? ssh_client_sock : target_sock;
int retval = select(max_fd + 1, &readfds, NULL, NULL, &tv);
if (retval == -1) {
if (debug) {
perror("[DEBUG] select failed");
fflush(stdout);
}
break;
} else if (retval == 0) {
continue; // Timeout
}
// Forward data from SSH client to target SSH server
if (FD_ISSET(ssh_client_sock, &readfds)) {
bytes_read = recv(ssh_client_sock, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) {
if (debug) {
printf("[DEBUG] SSH client connection closed\n");
fflush(stdout);
}
break;
}
if (debug) {
printf("[DEBUG] Forwarding %d bytes from SSH client to target\n", bytes_read);
fflush(stdout);
}
// Send to target SSH server
if (send(target_sock, buffer, bytes_read, 0) < 0) {
if (debug) {
perror("[DEBUG] Send to target SSH server failed");
fflush(stdout);
}
break;
}
}
// Forward data from target SSH server to SSH client
if (FD_ISSET(target_sock, &readfds)) {
bytes_read = recv(target_sock, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) {
if (debug) {
printf("[DEBUG] Target SSH server connection closed\n");
fflush(stdout);
}
break;
}
if (debug) {
printf("[DEBUG] Forwarding %d bytes from target to SSH client\n", bytes_read);
fflush(stdout);
}
// Send to SSH client
if (send(ssh_client_sock, buffer, bytes_read, 0) < 0) {
if (debug) {
perror("[DEBUG] Send to SSH client failed");
fflush(stdout);
}
break;
}
}
}
if (debug) { void *forward_ws_to_ssh_server(void *arg) {
printf("[DEBUG] SSH forwarding thread exiting\n");
fflush(stdout);
}
free(args);
return NULL;
}
void *forward_ws_to_ssh_client(void *arg) {
thread_args_t *args = (thread_args_t *)arg; thread_args_t *args = (thread_args_t *)arg;
SSL *ssl = args->ssl; SSL *ssl = args->ssl;
int debug = args->debug; int debug = args->debug;
...@@ -573,21 +351,21 @@ void *forward_ws_to_ssh_client(void *arg) { ...@@ -573,21 +351,21 @@ void *forward_ws_to_ssh_client(void *arg) {
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
break; break;
} }
int sock = active_tunnel->sock; // SSH client socket int ssh_sock = active_tunnel->sock; // SSH server connection
char request_id[37]; char request_id[37];
strcpy(request_id, active_tunnel->request_id); strcpy(request_id, active_tunnel->request_id);
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
// Use select to wait for data on SSH client socket // Use select to wait for data on SSH server connection
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_SET(sock, &readfds); FD_SET(ssh_sock, &readfds);
tv.tv_sec = 0; // 0 seconds tv.tv_sec = 0; // 0 seconds
tv.tv_usec = 50000; // 50ms timeout tv.tv_usec = 50000; // 50ms timeout
int retval = select(sock + 1, &readfds, NULL, NULL, &tv); int retval = select(ssh_sock + 1, &readfds, NULL, NULL, &tv);
if (retval == -1) { if (retval == -1) {
if (debug) { if (debug) {
perror("[DEBUG] select on SSH client socket failed"); perror("[DEBUG] select on SSH server socket failed");
fflush(stdout); fflush(stdout);
} }
break; break;
...@@ -596,18 +374,18 @@ void *forward_ws_to_ssh_client(void *arg) { ...@@ -596,18 +374,18 @@ void *forward_ws_to_ssh_client(void *arg) {
continue; continue;
} }
if (FD_ISSET(sock, &readfds)) { if (FD_ISSET(ssh_sock, &readfds)) {
bytes_read = recv(sock, buffer, sizeof(buffer), 0); bytes_read = recv(ssh_sock, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) { if (bytes_read <= 0) {
if (debug) { if (debug) {
printf("[DEBUG] SSH client connection closed or error\n"); printf("[DEBUG] SSH server connection closed or error\n");
fflush(stdout); fflush(stdout);
} }
break; break;
} }
if (debug) { if (debug) {
printf("[DEBUG] Forwarding %d bytes from SSH client to WebSocket\n", bytes_read); printf("[DEBUG] Forwarding %d bytes from SSH server to WebSocket\n", bytes_read);
fflush(stdout); fflush(stdout);
} }
...@@ -626,7 +404,7 @@ void *forward_ws_to_ssh_client(void *arg) { ...@@ -626,7 +404,7 @@ void *forward_ws_to_ssh_client(void *arg) {
} }
hex_data[bytes_read * 2] = '\0'; hex_data[bytes_read * 2] = '\0';
// Send as tunnel_response (from SSH client back to wsssh) // Send as tunnel_response (from SSH server back to wsssh/wsscp)
char message[BUFFER_SIZE]; char message[BUFFER_SIZE];
snprintf(message, sizeof(message), snprintf(message, sizeof(message),
"{\"type\":\"tunnel_response\",\"request_id\":\"%s\",\"data\":\"%s\"}", "{\"type\":\"tunnel_response\",\"request_id\":\"%s\",\"data\":\"%s\"}",
...@@ -643,7 +421,7 @@ void *forward_ws_to_ssh_client(void *arg) { ...@@ -643,7 +421,7 @@ void *forward_ws_to_ssh_client(void *arg) {
} }
if (debug) { if (debug) {
printf("[DEBUG] SSH client to WebSocket forwarding thread exiting\n"); printf("[DEBUG] SSH server to WebSocket forwarding thread exiting\n");
fflush(stdout); fflush(stdout);
} }
...@@ -701,24 +479,11 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id ...@@ -701,24 +479,11 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id
// wsscp: Use local_sock // wsscp: Use local_sock
target_sock = active_tunnel->local_sock; target_sock = active_tunnel->local_sock;
} else if (active_tunnel->sock >= 0) { } else if (active_tunnel->sock >= 0) {
// wssshc: Use sock (SSH client connection) // wssshc: Use sock (direct SSH server connection)
target_sock = active_tunnel->sock; target_sock = active_tunnel->sock;
} else { } else {
// wssshc: SSH client hasn't connected yet, buffer the data // wsssh: Use local_sock
if (debug) { target_sock = active_tunnel->local_sock;
printf("[DEBUG] SSH client not connected yet, buffering %zu bytes of tunnel_data\n", data_len);
fflush(stdout);
}
// Buffer the data for wssshc
if (!frame_buffer_append(active_tunnel->incoming_buffer, data, data_len)) {
if (debug) {
printf("[DEBUG] Failed to buffer incoming data, dropping %zu bytes\n", data_len);
fflush(stdout);
}
}
free(data);
pthread_mutex_unlock(&tunnel_mutex);
return;
} }
// Check if target socket is valid // Check if target socket is valid
......
...@@ -54,8 +54,7 @@ int frame_buffer_consume(frame_buffer_t *fb, size_t len); ...@@ -54,8 +54,7 @@ int frame_buffer_consume(frame_buffer_t *fb, size_t len);
void *forward_tcp_to_ws(void *arg); void *forward_tcp_to_ws(void *arg);
void *forward_ws_to_local(void *arg); void *forward_ws_to_local(void *arg);
void *handle_ssh_server_connection(void *arg); void *forward_ws_to_ssh_server(void *arg);
void *forward_ssh_client_to_target(void *arg);
void *tunnel_thread(void *arg); void *tunnel_thread(void *arg);
void handle_tunnel_request(SSL *ssl, const char *request_id, int debug); void handle_tunnel_request(SSL *ssl, const char *request_id, int debug);
void handle_tunnel_data(SSL *ssl, const char *request_id, const char *data_hex, int debug); void handle_tunnel_data(SSL *ssl, const char *request_id, const char *data_hex, int debug);
......
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