Fix SSH tunneling timing issue with proper data buffering

- Fixed critical timing issue where tunnel_data arrived before SSH client connection
- Added incoming_buffer to tunnel_t structure for buffering data before SSH client connects
- Modified handle_tunnel_data() to buffer data when SSH client hasn't connected yet
- Updated handle_ssh_server_connection() to send buffered data once SSH client connects
- Fixed socket selection logic to properly handle wssshc buffering scenario
- Resolved 'Bad file descriptor' errors caused by premature data transmission
- Implemented proper data flow: buffer → SSH client connection → send buffered data
- Added comprehensive debug logging for data buffering and transmission
- Fixed race condition between WebSocket data arrival and SSH client connection
- Ensured SSH protocol handshake completes properly with buffered data delivery
- Added proper cleanup for incoming_buffer in tunnel close operations
- Resolved premature socket disconnection by maintaining proper connection state
- Fixed SSH client timeout issues by ensuring timely data delivery
parent 14eef6e4
...@@ -160,6 +160,15 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) { ...@@ -160,6 +160,15 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug) {
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
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) {
...@@ -408,6 +417,23 @@ void *handle_ssh_server_connection(void *arg) { ...@@ -408,6 +417,23 @@ void *handle_ssh_server_connection(void *arg) {
pthread_mutex_lock(&tunnel_mutex); pthread_mutex_lock(&tunnel_mutex);
active_tunnel->sock = ssh_client_sock; // SSH client connection active_tunnel->sock = ssh_client_sock; // SSH client connection
active_tunnel->local_sock = target_sock; // Target SSH server 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); pthread_mutex_unlock(&tunnel_mutex);
if (debug) { if (debug) {
...@@ -632,16 +658,67 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id ...@@ -632,16 +658,67 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id
return; return;
} }
// Validate hex data length
size_t hex_len = strlen(data_hex);
if (hex_len % 2 != 0) {
if (debug) {
printf("[DEBUG] Invalid hex data length: %zu (must be even)\n", hex_len);
fflush(stdout);
}
pthread_mutex_unlock(&tunnel_mutex);
return;
}
// Decode hex data
size_t data_len = hex_len / 2;
char *data = malloc(data_len);
if (!data) {
if (debug) {
printf("[DEBUG] Failed to allocate memory for %zu bytes of decoded data\n", data_len);
fflush(stdout);
}
pthread_mutex_unlock(&tunnel_mutex);
return;
}
// Use more efficient hex decoding
for (size_t i = 0; i < data_len; i++) {
unsigned int byte_val;
if (sscanf(data_hex + i * 2, "%2x", &byte_val) != 1) {
if (debug) {
printf("[DEBUG] Failed to decode hex byte at position %zu\n", i * 2);
fflush(stdout);
}
free(data);
pthread_mutex_unlock(&tunnel_mutex);
return;
}
data[i] = (char)byte_val;
}
int target_sock = -1; int target_sock = -1;
if (active_tunnel->outgoing_buffer) { if (active_tunnel->outgoing_buffer) {
// 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 (local SSH server connection) // wssshc: Use sock (SSH client connection)
target_sock = active_tunnel->sock; target_sock = active_tunnel->sock;
} else { } else {
// wsssh: Use local_sock // wssshc: SSH client hasn't connected yet, buffer the data
target_sock = active_tunnel->local_sock; if (debug) {
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
...@@ -672,40 +749,7 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id ...@@ -672,40 +749,7 @@ void handle_tunnel_data(SSL *ssl __attribute__((unused)), const char *request_id
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
// Validate hex data length // Hex decoding is now done earlier in the function
size_t hex_len = strlen(data_hex);
if (hex_len % 2 != 0) {
if (debug) {
printf("[DEBUG] Invalid hex data length: %zu (must be even)\n", hex_len);
fflush(stdout);
}
return;
}
// Decode hex data
size_t data_len = hex_len / 2;
char *data = malloc(data_len);
if (!data) {
if (debug) {
printf("[DEBUG] Failed to allocate memory for %zu bytes of decoded data\n", data_len);
fflush(stdout);
}
return;
}
// Use more efficient hex decoding
for (size_t i = 0; i < data_len; i++) {
unsigned int byte_val;
if (sscanf(data_hex + i * 2, "%2x", &byte_val) != 1) {
if (debug) {
printf("[DEBUG] Failed to decode hex byte at position %zu\n", i * 2);
fflush(stdout);
}
free(data);
return;
}
data[i] = (char)byte_val;
}
if (active_tunnel->outgoing_buffer) { if (active_tunnel->outgoing_buffer) {
// wsscp: Append to outgoing buffer // wsscp: Append to outgoing buffer
...@@ -752,10 +796,18 @@ void handle_tunnel_close(SSL *ssl __attribute__((unused)), const char *request_i ...@@ -752,10 +796,18 @@ void handle_tunnel_close(SSL *ssl __attribute__((unused)), const char *request_i
pthread_mutex_lock(&tunnel_mutex); pthread_mutex_lock(&tunnel_mutex);
if (active_tunnel && strcmp(active_tunnel->request_id, request_id) == 0) { if (active_tunnel && strcmp(active_tunnel->request_id, request_id) == 0) {
active_tunnel->active = 0; active_tunnel->active = 0;
close(active_tunnel->local_sock); if (active_tunnel->local_sock >= 0) {
close(active_tunnel->local_sock);
}
if (active_tunnel->sock >= 0) {
close(active_tunnel->sock);
}
if (active_tunnel->outgoing_buffer) { if (active_tunnel->outgoing_buffer) {
frame_buffer_free(active_tunnel->outgoing_buffer); frame_buffer_free(active_tunnel->outgoing_buffer);
} }
if (active_tunnel->incoming_buffer) {
frame_buffer_free(active_tunnel->incoming_buffer);
}
free(active_tunnel); free(active_tunnel);
active_tunnel = NULL; active_tunnel = NULL;
if (debug) { if (debug) {
......
...@@ -38,6 +38,7 @@ typedef struct { ...@@ -38,6 +38,7 @@ typedef struct {
int active; int active;
SSL *ssl; // WebSocket SSL connection SSL *ssl; // WebSocket SSL connection
frame_buffer_t *outgoing_buffer; // Buffer for data to send to local socket (wsscp only) 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)
} tunnel_t; } tunnel_t;
// Global variables // 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