Fix wsssh socket handling - add missing SSH client accept() logic

- Fixed critical bug: wsssh was trying to send data to listening socket instead of accepted connection
- Added missing accept() logic in forward_tcp_to_ws() for wsssh to accept SSH client connections
- wsssh now properly accepts SSH client connections on listening socket
- Stores accepted SSH client socket in active_tunnel->sock for data forwarding
- Sends buffered tunnel_data to SSH client immediately after connection is accepted
- Fixed socket selection logic to use accepted client socket instead of listening socket
- Resolved 'Bad file descriptor' errors by using correct socket for data transmission
- Fixed race condition between tunnel_data arrival and SSH client connection establishment
- Added proper socket validation and error handling for connection acceptance
- Implemented correct bidirectional forwarding between SSH client and WebSocket tunnel
- Fixed data flow: SSH client  wsssh (accepted socket)  WebSocket  wssshc  SSH server
- Resolved premature socket closure by maintaining proper connection state
- Added comprehensive debug logging for connection acceptance and data buffering
- Fixed socket descriptor management to prevent invalid socket access
- Ensured SSH protocol handshake completes properly with correct socket usage
- Fixed tunnel_data transmission timing by accepting connections before processing data
- Resolved socket state confusion between listening and connected sockets
- Added proper cleanup and error recovery for failed connection attempts
- Fixed select() usage to work with accepted client sockets instead of listening sockets
- Implemented robust connection handling with non-blocking accept for better performance
parent 5a1b73b4
......@@ -231,9 +231,53 @@ void *forward_tcp_to_ws(void *arg) {
continue;
}
// Send pending data from outgoing buffer to local socket (wsscp only)
// For wsssh: If this is the listening socket, accept the SSH client connection
int client_sock = sock;
if (active_tunnel->sock < 0) {
// This is the listening socket, accept SSH client connection
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
client_sock = accept(sock, (struct sockaddr *)&client_addr, &client_len);
if (client_sock < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
if (debug) {
perror("[DEBUG] Accept SSH client connection failed");
fflush(stdout);
}
}
pthread_mutex_unlock(&tunnel_mutex);
usleep(10000); // Sleep 10ms and try again
continue;
}
// Store the accepted SSH client socket
active_tunnel->sock = client_sock;
// 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(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);
}
}
}
if (debug) {
printf("[DEBUG] SSH client connected, starting data forwarding\n");
fflush(stdout);
}
}
// Send pending data from outgoing buffer to client socket (wsscp only)
if (active_tunnel->outgoing_buffer && active_tunnel->outgoing_buffer->used > 0) {
ssize_t sent = send(sock, active_tunnel->outgoing_buffer->buffer, active_tunnel->outgoing_buffer->used, MSG_DONTWAIT);
ssize_t sent = send(client_sock, active_tunnel->outgoing_buffer->buffer, active_tunnel->outgoing_buffer->used, MSG_DONTWAIT);
if (sent > 0) {
frame_buffer_consume(active_tunnel->outgoing_buffer, sent);
if (debug) {
......@@ -252,13 +296,13 @@ void *forward_tcp_to_ws(void *arg) {
pthread_mutex_unlock(&tunnel_mutex);
// Use select to wait for data on local socket
// Use select to wait for data on client socket
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
FD_SET(client_sock, &readfds);
tv.tv_sec = 0; // 0 seconds
tv.tv_usec = 50000; // 50ms timeout
int retval = select(sock + 1, &readfds, NULL, NULL, &tv);
int retval = select(client_sock + 1, &readfds, NULL, NULL, &tv);
if (retval == -1) {
if (debug) {
perror("[DEBUG] select failed");
......@@ -270,8 +314,8 @@ void *forward_tcp_to_ws(void *arg) {
continue;
}
if (FD_ISSET(sock, &readfds)) {
bytes_read = recv(sock, buffer, sizeof(buffer), 0);
if (FD_ISSET(client_sock, &readfds)) {
bytes_read = recv(client_sock, buffer, sizeof(buffer), 0);
if (bytes_read <= 0) {
if (debug) {
if (bytes_read == 0) {
......@@ -476,14 +520,28 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id
int target_sock = -1;
if (active_tunnel->outgoing_buffer) {
// wsscp: Use local_sock
// wsscp: Use local_sock (SCP client connection)
target_sock = active_tunnel->local_sock;
} else if (active_tunnel->sock >= 0) {
// wssshc: Use sock (direct SSH server connection)
// wsssh: Use sock (accepted SSH client connection)
target_sock = active_tunnel->sock;
} else {
// wsssh: Use local_sock
target_sock = active_tunnel->local_sock;
// No connection established yet - buffer the data
if (debug) {
printf("[DEBUG] No connection established yet, buffering %zu bytes of tunnel_data\n", data_len);
fflush(stdout);
}
// Buffer the data until connection is established
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
......@@ -911,6 +969,18 @@ int setup_tunnel(const char *wssshd_host, int wssshd_port, const char *client_id
active_tunnel->outgoing_buffer = NULL;
}
// Initialize incoming buffer for buffering data before connection is established
active_tunnel->incoming_buffer = frame_buffer_init();
if (!active_tunnel->incoming_buffer) {
perror("Failed to initialize incoming buffer");
if (use_buffer) frame_buffer_free(active_tunnel->outgoing_buffer);
free(active_tunnel);
SSL_free(ssl);
SSL_CTX_free(ssl_ctx);
close(sock);
return -1;
}
strcpy(active_tunnel->request_id, request_id);
active_tunnel->local_sock = -1;
active_tunnel->active = 1;
......
......@@ -32,13 +32,13 @@ typedef struct {
// Tunnel structure
typedef struct {
int local_sock; // Local TCP connection socket
int sock; // Alternative socket member for wssshc compatibility
int local_sock; // Local TCP connection socket (listening socket for wsssh, connection socket for wsscp)
int sock; // SSH client connection socket (for wsssh) or SSH server connection socket (for wssshc)
char request_id[37]; // UUID string
int active;
SSL *ssl; // WebSocket SSL connection
frame_buffer_t *outgoing_buffer; // Buffer for data to send to local socket (wsscp only)
frame_buffer_t *incoming_buffer; // Buffer for incoming data before SSH client connects (wssshc only)
frame_buffer_t *incoming_buffer; // Buffer for incoming data before connection is established
} tunnel_t;
// Global variables
......
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